<commit_before>#include "SFZReader.h"
#include "SFZRegion.h"
#include "SFZSound.h"
#include "StringSlice.h"
#include "SFZDebug.h"


SFZReader::SFZReader(SFZSound* soundIn)
	: sound(soundIn), line(1)
{
}


SFZReader::~SFZReader()
{
}


void SFZReader::read(const File& file)
{
	MemoryBlock contents;
	bool ok = file.loadFileAsData(contents);
	if (!ok) {
		sound->addError("Couldn't read \"" + file.getFullPathName() + "\"");
		return;
		}

	read((const char*) contents.getData(), contents.getSize());
}


void SFZReader::read(const char* text, unsigned int length)
{
	const char* p = text;
	const char* end = text + length;
	char c;

	SFZRegion curGroup;
	SFZRegion curRegion;
	SFZRegion* buildingRegion = NULL;
	bool inControl = false;
	String defaultPath;

	while (p < end) {
		// We're at the start of a line; skip any whitespace.
		while (p < end) {
			c = *p;
			if (c != ' ' && c != '\t')
				break;
			p += 1;
			}
		if (p >= end)
			break;

		// Check if it's a comment line.
		if (c == '/') {
			// Skip to end of line.
			while (p < end) {
				c = *++p;
				if (c == '\n' || c == '\r')
					break;
				}
			p = handleLineEnd(p);
			continue;
			}

		// Check if it's a blank line.
		if (c == '\r' || c == '\n') {
			p = handleLineEnd(p);
			continue;
			}

		// Handle elements on the line.
		while (p < end) {
			c = *p;

			// Tag.
			if (c == '<') {
				p += 1;
				const char* tagStart = p;
				while (p < end) {
					c = *p++;
					if (c == '\n' || c == '\r') {
						error("Unterminated tag");
						goto fatalError;
						}
					else if (c == '>')
						break;
					}
				if (p >= end) {
					error("Unterminated tag");
					goto fatalError;
					}
				StringSlice tag(tagStart, p - 1);
				if (tag == "region") {
					if (buildingRegion && buildingRegion == &curRegion)
						finishRegion(&curRegion);
					curRegion = curGroup;
					buildingRegion = &curRegion;
					inControl = false;
					}
				else if (tag == "group") {
					if (buildingRegion && buildingRegion == &curRegion)
						finishRegion(&curRegion);
					curGroup.clear();
					buildingRegion = &curGroup;
					inControl = false;
					}
				else if (tag == "control") {
					if (buildingRegion && buildingRegion == &curRegion)
						finishRegion(&curRegion);
					curGroup.clear();
					buildingRegion = NULL;
					inControl = true;
					}
				else
					error("Illegal tag");
				}

			// Parameter.
			else {
				// Get the parameter name.
				const char* parameterStart = p;
				while (p < end) {
					c = *p++;
					if (c == '=' || c == ' ' || c == '\t' || c == '\r' || c == '\n')
						break;
					}
				if (p >= end || c != '=') {
					error("Malformed parameter");
					goto nextElement;
					}
				StringSlice opcode(parameterStart, p - 1);
				if (inControl) {
					if (opcode == "default_path")
						p = readPathInto(&defaultPath, p, end);
					else {
						String fauxOpcode =
							String(opcode.start, opcode.length()) + " (in <control>)";
						sound->addUnsupportedOpcode(fauxOpcode);
						}
					}
				else if (opcode == "sample") {
					String path;
					p = readPathInto(&path, p, end);<commit_msg>Better handling of unsupported opcodes in <control> sections.<commit_after>#include "SFZReader.h"
#include "SFZRegion.h"
#include "SFZSound.h"
#include "StringSlice.h"
#include "SFZDebug.h"


SFZReader::SFZReader(SFZSound* soundIn)
	: sound(soundIn), line(1)
{
}


SFZReader::~SFZReader()
{
}


void SFZReader::read(const File& file)
{
	MemoryBlock contents;
	bool ok = file.loadFileAsData(contents);
	if (!ok) {
		sound->addError("Couldn't read \"" + file.getFullPathName() + "\"");
		return;
		}

	read((const char*) contents.getData(), contents.getSize());
}


void SFZReader::read(const char* text, unsigned int length)
{
	const char* p = text;
	const char* end = text + length;
	char c;

	SFZRegion curGroup;
	SFZRegion curRegion;
	SFZRegion* buildingRegion = NULL;
	bool inControl = false;
	String defaultPath;

	while (p < end) {
		// We're at the start of a line; skip any whitespace.
		while (p < end) {
			c = *p;
			if (c != ' ' && c != '\t')
				break;
			p += 1;
			}
		if (p >= end)
			break;

		// Check if it's a comment line.
		if (c == '/') {
			// Skip to end of line.
			while (p < end) {
				c = *++p;
				if (c == '\n' || c == '\r')
					break;
				}
			p = handleLineEnd(p);
			continue;
			}

		// Check if it's a blank line.
		if (c == '\r' || c == '\n') {
			p = handleLineEnd(p);
			continue;
			}

		// Handle elements on the line.
		while (p < end) {
			c = *p;

			// Tag.
			if (c == '<') {
				p += 1;
				const char* tagStart = p;
				while (p < end) {
					c = *p++;
					if (c == '\n' || c == '\r') {
						error("Unterminated tag");
						goto fatalError;
						}
					else if (c == '>')
						break;
					}
				if (p >= end) {
					error("Unterminated tag");
					goto fatalError;
					}
				StringSlice tag(tagStart, p - 1);
				if (tag == "region") {
					if (buildingRegion && buildingRegion == &curRegion)
						finishRegion(&curRegion);
					curRegion = curGroup;
					buildingRegion = &curRegion;
					inControl = false;
					}
				else if (tag == "group") {
					if (buildingRegion && buildingRegion == &curRegion)
						finishRegion(&curRegion);
					curGroup.clear();
					buildingRegion = &curGroup;
					inControl = false;
					}
				else if (tag == "control") {
					if (buildingRegion && buildingRegion == &curRegion)
						finishRegion(&curRegion);
					curGroup.clear();
					buildingRegion = NULL;
					inControl = true;
					}
				else
					error("Illegal tag");
				}

			// Parameter.
			else {
				// Get the parameter name.
				const char* parameterStart = p;
				while (p < end) {
					c = *p++;
					if (c == '=' || c == ' ' || c == '\t' || c == '\r' || c == '\n')
						break;
					}
				if (p >= end || c != '=') {
					error("Malformed parameter");
					goto nextElement;
					}
				StringSlice opcode(parameterStart, p - 1);
				if (inControl) {
					if (opcode == "default_path")
						p = readPathInto(&defaultPath, p, end);
					else {
						const char* valueStart = p;
						while (p < end) {
							c = *p;
							if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
								break;
							p++;
							}
						String value(valueStart, p - valueStart);
						String fauxOpcode =
							String(opcode.start, opcode.length()) + " (in <control>)";
						sound->addUnsupportedOpcode(fauxOpcode);
						}
					}
				else if (opcode == "sample") {
					String path;
					p = readPathInto(&path, p, end);
{'fraction_non_alphanumeric': 0.17236577440816958, 'fraction_numerical': 0.0015472690700912889, 'mean_word_length': 2.2828847130523107, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 18, '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': '5962072', 'n_tokens_mistral': 2977, 'n_tokens_neox': 2272, 'n_words': 611}