<commit_before>/*
 * validator.cpp
 *
 *  Created on: 15. 12. 2016
 *      Author: ondra
 */

#include <cstdarg>
#include "validator.h"
#include "array.h"
#include "string.h"
#include "operations.h"

namespace json {

StrViewA Validator::strString = "string";
StrViewA Validator::strNumber = "number";
StrViewA Validator::strBoolean = "boolean";
StrViewA Validator::strAny = "any";
StrViewA Validator::strBase64 = "base64";
StrViewA Validator::strBase64url = "base64url";
StrViewA Validator::strHex = "hex";
StrViewA Validator::strUppercase = "uppercase";
StrViewA Validator::strLowercase = "lowercase";
StrViewA Validator::strIdentifier = "identifier";
StrViewA Validator::strCamelCase = "camelcase";
StrViewA Validator::strAlpha = "alpha";
StrViewA Validator::strAlnum = "alnum";
StrViewA Validator::strDigits = "digits";
StrViewA Validator::strInteger = "integer";
StrViewA Validator::strUnsigned = "unsigned";
StrViewA Validator::strNative = "native";
StrViewA Validator::strMinSize = "minsize";
StrViewA Validator::strMaxSize = "maxsize";
StrViewA Validator::strKey = "key";
StrViewA Validator::strToString = "tostring";
StrViewA Validator::strToNumber = "tonumber";
StrViewA Validator::strPrefix = "prefix";
StrViewA Validator::strSuffix = "suffix";
StrViewA Validator::strSplit = "split";
StrViewA Validator::strExplode = "explode"; ///< ["explode","delimiter",rule,limit]
StrViewA Validator::strNull = "null";
StrViewA Validator::strOptional = "optional";
StrViewA Validator::strUndefined = "undefined";
StrViewA Validator::strObject = "object";
StrViewA Validator::strArray= "array";
StrViewA Validator::strGreater = ">";
StrViewA Validator::strGreaterEqual = ">=";
StrViewA Validator::strLess = "<";
StrViewA Validator::strLessEqual = "<=";
StrViewA Validator::strAll = "all";
StrViewA Validator::strAndSymb = "^";
StrViewA Validator::strNot = "not";
StrViewA Validator::strNotSymb = "!";
StrViewA Validator::strDateTime = "datetime";
StrViewA Validator::strDateTimeZ = "datetimez";
StrViewA Validator::strDate = "date";
StrViewA Validator::strTimeZ = "timez";
StrViewA Validator::strTime = "time";
StrViewA Validator::strSetVar = "setvar";
StrViewA Validator::strUseVar = "usevar";
StrViewA Validator::strEmit = "emit";
StrViewA Validator::strEmpty = "empty";
StrViewA Validator::strNonEmpty = "nonempty";

char Validator::valueEscape = '\'';
char Validator::charSetBegin = '[';
char Validator::charSetEnd = ']';
char Validator::commentEscape = '#';


bool Validator::validate(const Value& subject, const StrViewA& rule, const Path &path) {

	Value ver = def["_version"];
	if (ver.defined() && ver.getNumber() != 1.0) {
		addRejection(Path::root/"_version", ver);
		return false;
	}

	rejections.clear();
	emits.clear();
	curPath = &path;
	return validateInternal(subject,rule);
}

Validator::Validator(const Value& definition):def(definition),curPath(nullptr) {

}

Value Validator::getRejections() const {
	return StringView<Value>(rejections);
}

template<typename T>
class StackSave {
public:
	T value;
	T &var;
	StackSave(T &var):value(var),var(var) {}
	~StackSave() {var = value;}
};

static bool checkMaxSize(const Value &subject, std::size_t sz) {
	switch (subject.type()) {
	case array:
	case object: return subject.size() <= sz;
	case string: return subject.getString().length <= sz;
	default:return true;
	}
}

static bool checkMinSize(const Value &subject, std::size_t sz) {
	switch (subject.type()) {
	case array:
	case object: return subject.size() >= sz;
	case string: return subject.getString().length >= sz;
	default:return true;
	}
}

static bool isLess(const Value &a, const Value &b) {
	if (a.type() != b.type()) return false;
	switch (a.type()) {
	case number:
		if ((a.flags() & numberInteger) && (b.flags() & numberInteger))
			return a.getInt() < b.getInt();
		else if ((a.flags() & numberUnsignedInteger) && (b.flags() & numberUnsignedInteger))
			return a.getUInt() < b.getUInt();
		else
			return a.getNumber() < b.getNumber();
	case string:
		return a.getString() < b.getString();
		break;
	case boolean:
		return a.getBool() == false && b.getBool() == true;
	default:
		return false;
	}
}


static bool opHex(const Value &v) {
	StrViewA str = v.getString();
	if (str.empty()) return false;
	for (auto &v : str) {
		if (!isxdigit(v)) return false;
	}
	return true;
}

static bool opBase64(const Value &v) {
	StrViewA str = v.getString();
	if (str.empty()) return false;
	if (str.length % 4 != 0) return false;
	std::size_t len = str.length;
	if (str[len - 1] == '=') len--;
	if (str[len - 1] == '=') len--;
	for (std::size_t i = 0; i < len; i++) {
		char c = str[i];
		if (!isalnum(c) && c != '/' && c != '+') return false;
	}
	return true;
}

static bool opBase64url(const Value &v) {
	StrViewA str = v.getString();
	if (str.empty()) return false;
	if (str.length % 4 == 1) return false;
	std::size_t len = str.length;
	for (std::size_t i = 0; i < len; i++) {
		char c = str[i];
		if (!isalnum(c) && c != '-' && c != '_') return false;
	}
	return true;
}

static bool opUppercase(const Value &v) {
	StrViewA str = v.getString();
	if (str.empty()) return false;
	for (auto &v : str) {
		if (v < 'A' || v>'Z') return false;
	}
	return true;
}

static bool opLowercase(const Value &v) {
	StrViewA str = v.getString();
	if (str.empty()) return false;
	for (auto &v : str) {
		if (v < 'a' || v>'z') return false;
	}
	return true;
}

static bool opAlpha(const Value &v) {
	StrViewA str = v.getString();
	if (str.empty()) return false;
	for (auto &v : str) {
		if (!isalpha(v)) return false;
	}
	return true;
}

static bool opAlnum(const Value &v) {
	StrViewA str = v.getString();
	if (str.empty()) return false;
	for (auto &v : str) {
		if (!isalnum(v)) return false;
	}
	return true;
}

static bool opDigits(const Value &v) {
	StrViewA str = v.getString();
	if (str.empty()) return false;
	for (auto &v : str) {
		if (!isdigit(v)) return false;
	}
	return true;
}


/*static bool opCamelcase(const Value &v) {
	StrViewA str = v.getString();
	for (std::size_t i = 0; i < str.length; i++) {
		char c = str[i];
		if (!isalpha(c) || (i == 0 && c < 'a')) return false;
	}
	return true;
}*/

static bool opIsIdentifier(const Value &v) {
	StrViewA str = v.getString();
	for (std::size_t i = 0; i < str.length; i++) {
		char c = str[i];
		if ((!isalnum(c) || (i == 0 && !isalpha(c))) && c != '_') return false;
	}
	return true;
}

static bool opIsInteger(const Value &v) {
	return v.type() == number && ((v.flags() & (numberInteger | numberUnsignedInteger)) != 0);
}

static bool opIsUnsigned(const Value &v) {
	return v.type() == number && v.getNumber()>0;
}




static bool checkDateTimeGen(const StrViewA &format, const StrViewA &text) {
	if (format.length != text.length) return false;

	unsigned int D = 0, //day
	M = 0, //month
	Y = 0, //year
	h = 0, //hour
	m = 0, //minute
	s = 0, //second
//	c = 0, //milisec
	O = 0, //offset hour
	o = 0; //offset minute

	bool hasD = false, hasM = false, hasY = false;

	for (std::size_t cnt = format.length, i  = 0; i < cnt; i++) {
		char c = format[i];
		char d = text[i];
		char ac = d - '0';<commit_msg>fix validator - unsigned class<commit_after>/*
 * validator.cpp
 *
 *  Created on: 15. 12. 2016
 *      Author: ondra
 */

#include <cstdarg>
#include "validator.h"
#include "array.h"
#include "string.h"
#include "operations.h"

namespace json {

StrViewA Validator::strString = "string";
StrViewA Validator::strNumber = "number";
StrViewA Validator::strBoolean = "boolean";
StrViewA Validator::strAny = "any";
StrViewA Validator::strBase64 = "base64";
StrViewA Validator::strBase64url = "base64url";
StrViewA Validator::strHex = "hex";
StrViewA Validator::strUppercase = "uppercase";
StrViewA Validator::strLowercase = "lowercase";
StrViewA Validator::strIdentifier = "identifier";
StrViewA Validator::strCamelCase = "camelcase";
StrViewA Validator::strAlpha = "alpha";
StrViewA Validator::strAlnum = "alnum";
StrViewA Validator::strDigits = "digits";
StrViewA Validator::strInteger = "integer";
StrViewA Validator::strUnsigned = "unsigned";
StrViewA Validator::strNative = "native";
StrViewA Validator::strMinSize = "minsize";
StrViewA Validator::strMaxSize = "maxsize";
StrViewA Validator::strKey = "key";
StrViewA Validator::strToString = "tostring";
StrViewA Validator::strToNumber = "tonumber";
StrViewA Validator::strPrefix = "prefix";
StrViewA Validator::strSuffix = "suffix";
StrViewA Validator::strSplit = "split";
StrViewA Validator::strExplode = "explode"; ///< ["explode","delimiter",rule,limit]
StrViewA Validator::strNull = "null";
StrViewA Validator::strOptional = "optional";
StrViewA Validator::strUndefined = "undefined";
StrViewA Validator::strObject = "object";
StrViewA Validator::strArray= "array";
StrViewA Validator::strGreater = ">";
StrViewA Validator::strGreaterEqual = ">=";
StrViewA Validator::strLess = "<";
StrViewA Validator::strLessEqual = "<=";
StrViewA Validator::strAll = "all";
StrViewA Validator::strAndSymb = "^";
StrViewA Validator::strNot = "not";
StrViewA Validator::strNotSymb = "!";
StrViewA Validator::strDateTime = "datetime";
StrViewA Validator::strDateTimeZ = "datetimez";
StrViewA Validator::strDate = "date";
StrViewA Validator::strTimeZ = "timez";
StrViewA Validator::strTime = "time";
StrViewA Validator::strSetVar = "setvar";
StrViewA Validator::strUseVar = "usevar";
StrViewA Validator::strEmit = "emit";
StrViewA Validator::strEmpty = "empty";
StrViewA Validator::strNonEmpty = "nonempty";

char Validator::valueEscape = '\'';
char Validator::charSetBegin = '[';
char Validator::charSetEnd = ']';
char Validator::commentEscape = '#';


bool Validator::validate(const Value& subject, const StrViewA& rule, const Path &path) {

	Value ver = def["_version"];
	if (ver.defined() && ver.getNumber() != 1.0) {
		addRejection(Path::root/"_version", ver);
		return false;
	}

	rejections.clear();
	emits.clear();
	curPath = &path;
	return validateInternal(subject,rule);
}

Validator::Validator(const Value& definition):def(definition),curPath(nullptr) {

}

Value Validator::getRejections() const {
	return StringView<Value>(rejections);
}

template<typename T>
class StackSave {
public:
	T value;
	T &var;
	StackSave(T &var):value(var),var(var) {}
	~StackSave() {var = value;}
};

static bool checkMaxSize(const Value &subject, std::size_t sz) {
	switch (subject.type()) {
	case array:
	case object: return subject.size() <= sz;
	case string: return subject.getString().length <= sz;
	default:return true;
	}
}

static bool checkMinSize(const Value &subject, std::size_t sz) {
	switch (subject.type()) {
	case array:
	case object: return subject.size() >= sz;
	case string: return subject.getString().length >= sz;
	default:return true;
	}
}

static bool isLess(const Value &a, const Value &b) {
	if (a.type() != b.type()) return false;
	switch (a.type()) {
	case number:
		if ((a.flags() & numberInteger) && (b.flags() & numberInteger))
			return a.getInt() < b.getInt();
		else if ((a.flags() & numberUnsignedInteger) && (b.flags() & numberUnsignedInteger))
			return a.getUInt() < b.getUInt();
		else
			return a.getNumber() < b.getNumber();
	case string:
		return a.getString() < b.getString();
		break;
	case boolean:
		return a.getBool() == false && b.getBool() == true;
	default:
		return false;
	}
}


static bool opHex(const Value &v) {
	StrViewA str = v.getString();
	if (str.empty()) return false;
	for (auto &v : str) {
		if (!isxdigit(v)) return false;
	}
	return true;
}

static bool opBase64(const Value &v) {
	StrViewA str = v.getString();
	if (str.empty()) return false;
	if (str.length % 4 != 0) return false;
	std::size_t len = str.length;
	if (str[len - 1] == '=') len--;
	if (str[len - 1] == '=') len--;
	for (std::size_t i = 0; i < len; i++) {
		char c = str[i];
		if (!isalnum(c) && c != '/' && c != '+') return false;
	}
	return true;
}

static bool opBase64url(const Value &v) {
	StrViewA str = v.getString();
	if (str.empty()) return false;
	if (str.length % 4 == 1) return false;
	std::size_t len = str.length;
	for (std::size_t i = 0; i < len; i++) {
		char c = str[i];
		if (!isalnum(c) && c != '-' && c != '_') return false;
	}
	return true;
}

static bool opUppercase(const Value &v) {
	StrViewA str = v.getString();
	if (str.empty()) return false;
	for (auto &v : str) {
		if (v < 'A' || v>'Z') return false;
	}
	return true;
}

static bool opLowercase(const Value &v) {
	StrViewA str = v.getString();
	if (str.empty()) return false;
	for (auto &v : str) {
		if (v < 'a' || v>'z') return false;
	}
	return true;
}

static bool opAlpha(const Value &v) {
	StrViewA str = v.getString();
	if (str.empty()) return false;
	for (auto &v : str) {
		if (!isalpha(v)) return false;
	}
	return true;
}

static bool opAlnum(const Value &v) {
	StrViewA str = v.getString();
	if (str.empty()) return false;
	for (auto &v : str) {
		if (!isalnum(v)) return false;
	}
	return true;
}

static bool opDigits(const Value &v) {
	StrViewA str = v.getString();
	if (str.empty()) return false;
	for (auto &v : str) {
		if (!isdigit(v)) return false;
	}
	return true;
}


/*static bool opCamelcase(const Value &v) {
	StrViewA str = v.getString();
	for (std::size_t i = 0; i < str.length; i++) {
		char c = str[i];
		if (!isalpha(c) || (i == 0 && c < 'a')) return false;
	}
	return true;
}*/

static bool opIsIdentifier(const Value &v) {
	StrViewA str = v.getString();
	for (std::size_t i = 0; i < str.length; i++) {
		char c = str[i];
		if ((!isalnum(c) || (i == 0 && !isalpha(c))) && c != '_') return false;
	}
	return true;
}

static bool opIsInteger(const Value &v) {
	return v.type() == number && ((v.flags() & (numberInteger | numberUnsignedInteger)) != 0);
}

static bool opIsUnsigned(const Value &v) {
	return v.type() == number && v.getNumber()>=0;
}




static bool checkDateTimeGen(const StrViewA &format, const StrViewA &text) {
	if (format.length != text.length) return false;

	unsigned int D = 0, //day
	M = 0, //month
	Y = 0, //year
	h = 0, //hour
	m = 0, //minute
	s = 0, //second
//	c = 0, //milisec
	O = 0, //offset hour
	o = 0; //offset minute

	bool hasD = false, hasM = false, hasY = false;

	for (std::size_t cnt = format.length, i  = 0; i < cnt; i++) {
		char c = format[i];
		char d = text[i];
		char ac = d - '0';
{'fraction_non_alphanumeric': 0.17369832086919712, 'fraction_numerical': 0.006631861154226048, 'mean_word_length': 4.6294678316123905, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 23, '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': '7189073', 'n_tokens_mistral': 5308, 'n_tokens_neox': 5147, 'n_words': 1380}