<commit_before>//
//  AcornAnalyser.cpp
//  Clock Signal
//
//  Created by <NAME> on 29/08/2016.
//  Copyright © 2016 <NAME>. All rights reserved.
//

#include "AcornAnalyser.hpp"

#include "Tape.hpp"

using namespace StaticAnalyser::Acorn;

static std::list<std::shared_ptr<Storage::Cartridge::Cartridge>>
	AcornCartridgesFrom(const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges)
{
	std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> acorn_cartridges;

	for(std::shared_ptr<Storage::Cartridge::Cartridge> cartridge : cartridges)
	{
		const std::list<Storage::Cartridge::Cartridge::Segment> &segments = cartridge->get_segments();

		// only one mapped item is allowed
		if(segments.size() != 1) continue;

		// which must be 16 kb in size
		Storage::Cartridge::Cartridge::Segment segment = segments.front();
		if(segment.data.size() != 0x4000) continue;

		// is a copyright string present?
		uint8_t copyright_offset = segment.data[7];
		if(
			segment.data[copyright_offset] != 0x00 ||
			segment.data[copyright_offset+1] != 0x28 ||
			segment.data[copyright_offset+2] != 0x43 ||
			segment.data[copyright_offset+3] != 0x29
		) continue;

		// is the language entry point valid?
		if(!(
			(segment.data[0] == 0x00 && segment.data[1] == 0x00 && segment.data[2] == 0x00) ||
			(segment.data[0] != 0x00 && segment.data[2] >= 0x80 && segment.data[2] < 0xc0)
			)) continue;

		// is the service entry point valid?
		if(!(segment.data[5] >= 0x80 && segment.data[5] < 0xc0)) continue;

		// probability of a random binary blob that isn't an Acorn ROM proceeding to here:
		//		1/(2^32) *
		//		( ((2^24)-1)/(2^24)*(1/4)		+		1/(2^24)	) *
		//		1/4
		//	= something very improbable — around 1/16th of 1 in 2^32, but not exactly.
		acorn_cartridges.push_back(cartridge);
	}

	return acorn_cartridges;
}

void StaticAnalyser::Acorn::AddTargets(
	const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
	const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
	const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
	std::list<StaticAnalyser::Target> &destination)
{
	Target target;
	target.machine = Target::Electron;
	target.probability = 1.0; // TODO: a proper estimation

	// strip out inappropriate cartridges
	target.cartridges = AcornCartridgesFrom(cartridges);

	// if there are any tapes, attempt to get data from the first
	if(tapes.size() > 0)
	{
		std::shared_ptr<Storage::Tape::Tape> tape = tapes.front();
		tape->reset();
		std::list<File> files = GetFiles(tape);
		tape->reset();

		// continue if there are any files
		if(files.size())
		{
			bool is_basic = true;

			// protected files are always for *RUNning only
//			if(files.front().is_protected) is_basic = false;

			// check also for a continuous threading of BASIC lines; if none then this probably isn't BASIC code,
			// so that's also justification to *RUN
			size_t pointer = 0;
			uint8_t *data = &files.front().data[0];
			size_t data_size = files.front().data.size();
			while(1)
			{
				if(pointer >= data_size-1 || data[pointer] != 13)
				{
					is_basic = false;
					break;<commit_msg>I'm going back to believing in this test.<commit_after>//
//  AcornAnalyser.cpp
//  Clock Signal
//
//  Created by <NAME> on 29/08/2016.
//  Copyright © 2016 <NAME>. All rights reserved.
//

#include "AcornAnalyser.hpp"

#include "Tape.hpp"

using namespace StaticAnalyser::Acorn;

static std::list<std::shared_ptr<Storage::Cartridge::Cartridge>>
	AcornCartridgesFrom(const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges)
{
	std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> acorn_cartridges;

	for(std::shared_ptr<Storage::Cartridge::Cartridge> cartridge : cartridges)
	{
		const std::list<Storage::Cartridge::Cartridge::Segment> &segments = cartridge->get_segments();

		// only one mapped item is allowed
		if(segments.size() != 1) continue;

		// which must be 16 kb in size
		Storage::Cartridge::Cartridge::Segment segment = segments.front();
		if(segment.data.size() != 0x4000) continue;

		// is a copyright string present?
		uint8_t copyright_offset = segment.data[7];
		if(
			segment.data[copyright_offset] != 0x00 ||
			segment.data[copyright_offset+1] != 0x28 ||
			segment.data[copyright_offset+2] != 0x43 ||
			segment.data[copyright_offset+3] != 0x29
		) continue;

		// is the language entry point valid?
		if(!(
			(segment.data[0] == 0x00 && segment.data[1] == 0x00 && segment.data[2] == 0x00) ||
			(segment.data[0] != 0x00 && segment.data[2] >= 0x80 && segment.data[2] < 0xc0)
			)) continue;

		// is the service entry point valid?
		if(!(segment.data[5] >= 0x80 && segment.data[5] < 0xc0)) continue;

		// probability of a random binary blob that isn't an Acorn ROM proceeding to here:
		//		1/(2^32) *
		//		( ((2^24)-1)/(2^24)*(1/4)		+		1/(2^24)	) *
		//		1/4
		//	= something very improbable — around 1/16th of 1 in 2^32, but not exactly.
		acorn_cartridges.push_back(cartridge);
	}

	return acorn_cartridges;
}

void StaticAnalyser::Acorn::AddTargets(
	const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
	const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
	const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
	std::list<StaticAnalyser::Target> &destination)
{
	Target target;
	target.machine = Target::Electron;
	target.probability = 1.0; // TODO: a proper estimation

	// strip out inappropriate cartridges
	target.cartridges = AcornCartridgesFrom(cartridges);

	// if there are any tapes, attempt to get data from the first
	if(tapes.size() > 0)
	{
		std::shared_ptr<Storage::Tape::Tape> tape = tapes.front();
		tape->reset();
		std::list<File> files = GetFiles(tape);
		tape->reset();

		// continue if there are any files
		if(files.size())
		{
			bool is_basic = true;

			// protected files are always for *RUNning only
			if(files.front().is_protected) is_basic = false;

			// check also for a continuous threading of BASIC lines; if none then this probably isn't BASIC code,
			// so that's also justification to *RUN
			size_t pointer = 0;
			uint8_t *data = &files.front().data[0];
			size_t data_size = files.front().data.size();
			while(1)
			{
				if(pointer >= data_size-1 || data[pointer] != 13)
				{
					is_basic = false;
					break;
{'fraction_non_alphanumeric': 0.15712468193384224, 'fraction_numerical': 0.03276081424936387, 'mean_word_length': 4.1761316872427985, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2749556', 'n_tokens_mistral': 2545, 'n_tokens_neox': 2171, 'n_words': 512}