<commit_before>#pragma once
#ifndef AMFPACKET_HPP
#define AMFPACKET_HPP

#include "types/amfitem.hpp"

namespace amf {

enum Amf0Marker : u8 {
	AVMPLUS_OBJECT = 0x11
};

class PacketHeader : public AmfItem {
public:
	PacketHeader(std::string name, bool mustUnderstand, const AmfItem& value) :
		name(name), mustUnderstand(mustUnderstand), value(value.serialize()) { };

	bool operator==(const AmfItem& other) const {
		const PacketHeader* p = dynamic_cast<const PacketHeader*>(&other);
		return p != nullptr && mustUnderstand == p->mustUnderstand &&
			name == p->name && value == p->value;
	}

	v8 serialize() const {
		v8 buf;
		buf.reserve(2 + name.size() + 1 + 5 + value.size());
		// Strings in AMF packets are always serialized as AMF0 UTF-8, i.e.
		// U16 length (in network order) U8* value
		// even though AMF3 encodes strings in a different format
		v8 name_length = network_bytes<uint16_t>(name.size());
		buf.insert(buf.end(), name_length.begin(), name_length.end());
		buf.insert(buf.end(), name.begin(), name.end());

		buf.push_back(mustUnderstand ? 0x01 : 0x00);

		// we have to mark the value as AMF3 value, which is achieved by adding
		// an AVMPLUS_OBJECT marker in front of the value. note that this counts
		// towards the value's length.
		v8 value_length = network_bytes<uint32_t>(value.size() + 1);
		buf.insert(buf.end(), value_length.begin(), value_length.end());
		buf.push_back(AVMPLUS_OBJECT);
		buf.insert(buf.end(), value.begin(), value.end());

		return buf;
	}

private:
	std::string name;
	bool mustUnderstand;
	v8 value;
};

class PacketMessage : public AmfItem {
public:
	PacketMessage(std::string targetUri, std::string responseUri, const AmfItem& value) :
		target(targetUri), response(responseUri), value(value.serialize()) { };

	bool operator==(const AmfItem& other) const {
		const PacketMessage* p = dynamic_cast<const PacketMessage*>(&other);
		return p != nullptr && target == p->target && response == p->response &&
			value == p->value;
	}

	v8 serialize() const {
		v8 buf;
		buf.reserve(2 + target.size() + 2 + response.size() + 5 + value.size());

		v8 target_length = network_bytes<uint16_t>(target.size());
		buf.insert(buf.end(), target_length.begin(), target_length.end());
		buf.insert(buf.end(), target.begin(), target.end());

		v8 response_length = network_bytes<uint16_t>(response.size());
		buf.insert(buf.end(), response_length.begin(), response_length.end());
		buf.insert(buf.end(), response.begin(), response.end());

		v8 value_length = network_bytes<uint32_t>(value.size() + 1);
		buf.insert(buf.end(), value_length.begin(), value_length.end());
		buf.push_back(AVMPLUS_OBJECT);
		buf.insert(buf.end(), value.begin(), value.end());

		return buf;
	}

private:
	std::string target;
	std::string response;
	v8 value;
};

class AmfPacket : public AmfItem {
public:<commit_msg>Don't immediately serialize packet header/message values.<commit_after>#pragma once
#ifndef AMFPACKET_HPP
#define AMFPACKET_HPP

#include "types/amfitem.hpp"
#include "types/amfnull.hpp"

namespace amf {

enum Amf0Marker : u8 {
	AVMPLUS_OBJECT = 0x11
};

class PacketHeader : public AmfItem {
public:
	template<typename T>
	PacketHeader(std::string name, bool mustUnderstand, const T& value) :
		name(name), mustUnderstand(mustUnderstand), value(new T(value)) { }

	bool operator==(const AmfItem& other) const {
		const PacketHeader* p = dynamic_cast<const PacketHeader*>(&other);
		return p != nullptr && mustUnderstand == p->mustUnderstand &&
			name == p->name && value == p->value;
	}

	v8 serialize() const {
		v8 buf;
		v8 value_data = value->serialize();
		buf.reserve(2 + name.size() + 1 + 5 + value_data.size());
		// Strings in AMF packets are always serialized as AMF0 UTF-8, i.e.
		// U16 length (in network order) U8* value
		// even though AMF3 encodes strings in a different format
		v8 name_length = network_bytes<uint16_t>(name.size());
		buf.insert(buf.end(), name_length.begin(), name_length.end());
		buf.insert(buf.end(), name.begin(), name.end());

		buf.push_back(mustUnderstand ? 0x01 : 0x00);

		// we have to mark the value as AMF3 value, which is achieved by adding
		// an AVMPLUS_OBJECT marker in front of the value. note that this counts
		// towards the value's length.
		v8 value_length = network_bytes<uint32_t>(value_data.size() + 1);
		buf.insert(buf.end(), value_length.begin(), value_length.end());
		buf.push_back(AVMPLUS_OBJECT);
		buf.insert(buf.end(), value_data.begin(), value_data.end());

		return buf;
	}

	template<typename T>
	T& getValue() {
		return value.as<T>();
	}

	std::string name;
	bool mustUnderstand;

private:
	AmfItemPtr value;
};

class PacketMessage : public AmfItem {
public:
	template<typename T>
	PacketMessage(std::string targetUri, std::string responseUri, const T& value) :
		target(targetUri), response(responseUri), value(new T(value)) { }

	bool operator==(const AmfItem& other) const {
		const PacketMessage* p = dynamic_cast<const PacketMessage*>(&other);
		return p != nullptr && target == p->target && response == p->response &&
			value == p->value;
	}

	v8 serialize() const {
		v8 buf;
		v8 value_data = value->serialize();
		buf.reserve(2 + target.size() + 2 + response.size() + 5 + value_data.size());

		v8 target_length = network_bytes<uint16_t>(target.size());
		buf.insert(buf.end(), target_length.begin(), target_length.end());
		buf.insert(buf.end(), target.begin(), target.end());

		v8 response_length = network_bytes<uint16_t>(response.size());
		buf.insert(buf.end(), response_length.begin(), response_length.end());
		buf.insert(buf.end(), response.begin(), response.end());

		v8 value_length = network_bytes<uint32_t>(value_data.size() + 1);
		buf.insert(buf.end(), value_length.begin(), value_length.end());
		buf.push_back(AVMPLUS_OBJECT);
		buf.insert(buf.end(), value_data.begin(), value_data.end());

		return buf;
	}

	template<typename T>
	T& getValue() {
		return value.as<T>();
	}

	std::string target;
	std::string response;

private:
	AmfItemPtr value;
};

class AmfPacket : public AmfItem {
public:
{'fraction_non_alphanumeric': 0.15384615384615385, 'fraction_numerical': 0.01555004135649297, 'mean_word_length': 4.703773584905661, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 37, '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': '5958400', 'n_tokens_mistral': 2199, 'n_tokens_neox': 2023, 'n_words': 502}