| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992 |
- #pragma once
- #include <natBinary.h>
- #include <optional>
- #include "Utility.h"
- namespace YumeBot::Jce
- {
- DeclareException(JceException, NatsuLib::natException, u8"YumeBot::Jce::JceException");
- DeclareException(JceDecodeException, JceException, u8"YumeBot::Jce::JceDecodeException");
- DeclareException(JceEncodeException, JceException, u8"YumeBot::Jce::JceEncodeException");
- enum class JceCode;
- // Jce 中 Byte 是有符号的,此处表示为无符号,使用时需注意
- class JceStruct
- : public NatsuLib::natRefObj
- {
- public:
- #define JCE_FIELD_TYPE(OP)\
- OP(Byte, 0x00, std::uint8_t)\
- OP(Short, 0x01, std::int16_t)\
- OP(Int, 0x02, std::int32_t)\
- OP(Long, 0x03, std::int64_t)\
- OP(Float, 0x04, float)\
- OP(Double, 0x05, double)\
- OP(String1, 0x06, std::string)\
- OP(String4, 0x07, std::string)\
- OP(Map, 0x08, std::unordered_map)\
- OP(List, 0x09, std::vector)\
- OP(StructBegin, 0x0A, NatsuLib::natRefPointer)\
- OP(StructEnd, 0x0B, void)\
- OP(ZeroTag, 0x0C, (std::integral_constant<std::size_t, 0>))\
- OP(SimpleList, 0x0D, std::vector<std::uint8_t>)
- enum class TypeEnum : std::uint8_t
- {
- #define ENUM_OP(name, code, type) name = code,
- JCE_FIELD_TYPE(ENUM_OP)
- #undef ENUM_OP
- };
- static constexpr std::size_t MaxStringLength = 0x06400000;
- ~JceStruct();
- virtual std::string_view GetJceStructName() const noexcept = 0;
- virtual JceCode GetJceStructType() const noexcept = 0;
- };
- template <typename T>
- struct TlvDeserializer;
- template <typename T>
- struct TlvSerializer;
- struct NoOp
- {
- template <typename T>
- struct Apply
- : Utility::ResultType<T>
- {
- };
- };
- struct IsOptional
- {
- template <typename T>
- struct Apply
- : Utility::ResultType<std::conditional_t<Utility::IsTemplateOf<T, NatsuLib::natRefPointer>::value, T, std::optional<T>>>
- {
- };
- };
- template <typename... Args>
- struct TemplateArgs
- {
- template <template <typename...> class Template>
- struct Apply
- : Utility::ResultType<Template<Args...>>
- {
- };
- };
- template <JceStruct::TypeEnum Type, typename AttributeSet>
- struct FieldTypeBuilder;
- #define FIELD_TYPE_BUILDER_OP(name, code, type) \
- template <typename... Attributes>\
- struct FieldTypeBuilder<JceStruct::TypeEnum::name, std::tuple<Attributes...>>\
- : decltype(Utility::RecursiveApply<type, Attributes...>())\
- {\
- };
- JCE_FIELD_TYPE(FIELD_TYPE_BUILDER_OP)
- #undef FIELD_TYPE_BUILDER_OP
- namespace Detail
- {
- struct NoneType
- {
- };
- constexpr NoneType None{};
- }
- struct HeadData
- {
- std::uint32_t Tag;
- JceStruct::TypeEnum Type;
- };
- class JceInputStream
- : NatsuLib::noncopyable
- {
- public:
- explicit JceInputStream(NatsuLib::natRefPointer<NatsuLib::natBinaryReader> reader);
- ~JceInputStream();
- std::pair<HeadData, std::size_t> ReadHead() const
- {
- const auto byte = m_Reader->ReadPod<std::uint8_t>();
- const auto type = static_cast<JceStruct::TypeEnum>(static_cast<std::uint8_t>(byte & 0x0F));
- const auto tag = static_cast<std::uint32_t>((byte & 0xF0) >> 4);
- if (tag != 0x0F)
- {
- return { { tag, type }, 1 };
- }
- return { { m_Reader->ReadPod<std::uint8_t>(), type }, 2 };
- }
- std::pair<HeadData, std::size_t> PeekHead() const
- {
- const auto underlyingStream = m_Reader->GetUnderlyingStream();
- const auto pos = underlyingStream->GetPosition();
- const auto head = ReadHead();
- underlyingStream->SetPositionFromBegin(pos);
- return head;
- }
- void Skip(nLen len)
- {
- m_Reader->Skip(len);
- }
- void SkipToStructEnd()
- {
- while (true)
- {
- const auto [head, headSize] = ReadHead();
- SkipField(head.Type);
- if (head.Type == JceStruct::TypeEnum::StructEnd)
- {
- return;
- }
- }
- }
- void SkipField()
- {
- const auto [head, headSize] = ReadHead();
- SkipField(head.Type);
- }
- void SkipField(JceStruct::TypeEnum type)
- {
- switch (type)
- {
- case JceStruct::TypeEnum::Byte:
- Skip(1);
- break;
- case JceStruct::TypeEnum::Short:
- Skip(2);
- break;
- case JceStruct::TypeEnum::Int:
- Skip(4);
- break;
- case JceStruct::TypeEnum::Long:
- Skip(8);
- break;
- case JceStruct::TypeEnum::Float:
- Skip(4);
- break;
- case JceStruct::TypeEnum::Double:
- Skip(8);
- break;
- case JceStruct::TypeEnum::String1:
- Skip(m_Reader->ReadPod<std::uint8_t>());
- break;
- case JceStruct::TypeEnum::String4:
- Skip(m_Reader->ReadPod<std::uint32_t>());
- break;
- case JceStruct::TypeEnum::Map:
- {
- int size;
- if (!Read(0, size))
- {
- nat_Throw(JceDecodeException, u8"Read size failed.");
- }
- for (std::size_t i = 0, iterationTime = static_cast<std::size_t>(size) * 2; i < iterationTime; ++i)
- {
- SkipField();
- }
- break;
- }
- case JceStruct::TypeEnum::List:
- {
- int size;
- if (!Read(0, size))
- {
- nat_Throw(JceDecodeException, u8"Read size failed.");
- }
- for (std::size_t i = 0, iterationTime = static_cast<std::size_t>(size); i < iterationTime; ++i)
- {
- SkipField();
- }
- break;
- }
- case JceStruct::TypeEnum::StructBegin:
- SkipToStructEnd();
- break;
- case JceStruct::TypeEnum::StructEnd:
- case JceStruct::TypeEnum::ZeroTag:
- break;
- case JceStruct::TypeEnum::SimpleList:
- {
- const auto [head, headSize] = ReadHead();
- if (head.Type != JceStruct::TypeEnum::Byte)
- {
- nat_Throw(JceDecodeException, u8"Type mismatch, expected 0, got {0}", static_cast<std::uint32_t>(head.Type));
- }
- std::uint8_t size;
- if (!Read(0, size))
- {
- nat_Throw(JceDecodeException, u8"Read size failed.");
- }
- Skip(size);
- break;
- }
- default:
- nat_Throw(JceDecodeException, u8"Invalid type ({0}).", static_cast<std::uint32_t>(type));
- }
- }
- bool SkipToTag(std::uint32_t tag)
- try
- {
- HeadData head; // NOLINT
- while (true)
- {
- std::size_t headSize;
- std::tie(head, headSize) = PeekHead();
- if (head.Type == JceStruct::TypeEnum::StructEnd)
- {
- return false;
- }
- if (tag <= head.Tag)
- {
- break;
- }
- Skip(headSize);
- SkipField(head.Type);
- }
- return head.Tag == tag;
- }
- catch (JceDecodeException&)
- {
- return false;
- }
- template <typename T>
- bool Read(std::uint32_t tag, T& value, Detail::NoneType = Detail::None)
- {
- return Reader<T>::DoRead(*this, tag, value);
- }
- template <typename T, typename U>
- std::enable_if_t<std::is_assignable_v<T&, U&&>, std::true_type> Read(std::uint32_t tag, T& value, U&& defaultValue)
- {
- bool readSucceed;
- if constexpr (Utility::IsTemplateOf<T, std::optional>::value)
- {
- value.emplace();
- readSucceed = Read(tag, value.value());
- }
- else
- {
- readSucceed = Read(tag, value);
- }
- if (!readSucceed)
- {
- value = std::forward<U>(defaultValue);
- }
- return {};
- }
- private:
- NatsuLib::natRefPointer<NatsuLib::natBinaryReader> m_Reader;
- template <typename T, typename = void>
- struct Reader;
- template <>
- struct Reader<std::uint8_t>
- {
- static bool DoRead(JceInputStream& self, std::uint32_t tag, std::uint8_t& value)
- {
- if (self.SkipToTag(tag))
- {
- const auto [head, headSize] = self.ReadHead();
- switch (head.Type)
- {
- case JceStruct::TypeEnum::Byte:
- self.m_Reader->ReadPod(value);
- break;
- case JceStruct::TypeEnum::ZeroTag:
- value = 0;
- break;
- default:
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected {0}", static_cast<std::uint32_t>(head.Type));
- }
- return true;
- }
- return false;
- }
- };
- template <>
- struct Reader<std::int16_t>
- {
- static bool DoRead(JceInputStream& self, std::uint32_t tag, std::int16_t& value)
- {
- if (self.SkipToTag(tag))
- {
- const auto [head, headSize] = self.ReadHead();
- switch (head.Type)
- {
- case JceStruct::TypeEnum::Byte:
- value = self.m_Reader->ReadPod<std::int8_t>();
- break;
- case JceStruct::TypeEnum::Short:
- self.m_Reader->ReadPod(value);
- break;
- case JceStruct::TypeEnum::ZeroTag:
- value = 0;
- break;
- default:
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected {0}", static_cast<std::uint32_t>(head.Type));
- }
- return true;
- }
- return false;
- }
- };
- template <>
- struct Reader<std::int32_t>
- {
- static bool DoRead(JceInputStream& self, std::uint32_t tag, std::int32_t& value)
- {
- if (self.SkipToTag(tag))
- {
- const auto [head, headSize] = self.ReadHead();
- switch (head.Type)
- {
- case JceStruct::TypeEnum::Byte:
- value = self.m_Reader->ReadPod<std::int8_t>();
- break;
- case JceStruct::TypeEnum::Short:
- value = self.m_Reader->ReadPod<std::int16_t>();
- break;
- case JceStruct::TypeEnum::Int:
- self.m_Reader->ReadPod(value);
- break;
- case JceStruct::TypeEnum::ZeroTag:
- value = 0;
- break;
- default:
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected {0}", static_cast<std::uint32_t>(head.Type));
- }
- return true;
- }
- return false;
- }
- };
- template <>
- struct Reader<std::int64_t>
- {
- static bool DoRead(JceInputStream& self, std::uint32_t tag, std::int64_t& value)
- {
- if (self.SkipToTag(tag))
- {
- const auto[head, headSize] = self.ReadHead();
- switch (head.Type)
- {
- case JceStruct::TypeEnum::Byte:
- value = self.m_Reader->ReadPod<std::int8_t>();
- break;
- case JceStruct::TypeEnum::Short:
- value = self.m_Reader->ReadPod<std::int16_t>();
- break;
- case JceStruct::TypeEnum::Int:
- value = self.m_Reader->ReadPod<std::int32_t>();
- break;
- case JceStruct::TypeEnum::Long:
- self.m_Reader->ReadPod(value);
- break;
- case JceStruct::TypeEnum::ZeroTag:
- value = 0;
- break;
- default:
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected got {0}", static_cast<std::uint32_t>(head.Type));
- }
- return true;
- }
- return false;
- }
- };
- template <>
- struct Reader<float>
- {
- static bool DoRead(JceInputStream& self, std::uint32_t tag, float& value)
- {
- if (self.SkipToTag(tag))
- {
- const auto[head, headSize] = self.ReadHead();
- switch (head.Type)
- {
- case JceStruct::TypeEnum::Float:
- self.m_Reader->ReadPod(value);
- break;
- case JceStruct::TypeEnum::ZeroTag:
- value = 0;
- break;
- default:
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected {0}", static_cast<std::uint32_t>(head.Type));
- }
- return true;
- }
- return false;
- }
- };
- template <>
- struct Reader<double>
- {
- static bool DoRead(JceInputStream& self, std::uint32_t tag, double& value)
- {
- if (self.SkipToTag(tag))
- {
- const auto[head, headSize] = self.ReadHead();
- switch (head.Type)
- {
- case JceStruct::TypeEnum::Float:
- value = self.m_Reader->ReadPod<float>();
- break;
- case JceStruct::TypeEnum::Double:
- self.m_Reader->ReadPod(value);
- break;
- case JceStruct::TypeEnum::ZeroTag:
- value = 0;
- break;
- default:
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected {0}", static_cast<std::uint32_t>(head.Type));
- }
- return true;
- }
- return false;
- }
- };
- template <>
- struct Reader<std::string>
- {
- static bool DoRead(JceInputStream& self, std::uint32_t tag, std::string& value)
- {
- if (self.SkipToTag(tag))
- {
- const auto [head, headSize] = self.ReadHead();
- std::size_t strSize;
- switch (head.Type)
- {
- case JceStruct::TypeEnum::String1:
- strSize = self.m_Reader->ReadPod<std::uint8_t>();
- break;
- case JceStruct::TypeEnum::String4:
- strSize = self.m_Reader->ReadPod<std::uint32_t>();
- if (strSize > JceStruct::MaxStringLength)
- {
- nat_Throw(JceDecodeException, u8"String too long, {0} sizes requested.", strSize);
- }
- break;
- default:
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected {0}", static_cast<std::uint32_t>(head.Type));
- }
- // 为了异常安全,构造临时字符串而不是就地修改
- std::string tmpString(strSize, 0);
- self.m_Reader->GetUnderlyingStream()->ReadBytes(reinterpret_cast<nData>(tmpString.data()), strSize);
- value = std::move(tmpString);
- return true;
- }
- return false;
- }
- };
- template <typename Key, typename Value>
- struct Reader<std::unordered_map<Key, Value>>
- {
- static bool DoRead(JceInputStream& self, std::uint32_t tag, std::unordered_map<Key, Value>& value)
- {
- if (self.SkipToTag(tag))
- {
- const auto [head, headSize] = self.ReadHead();
- switch (head.Type)
- {
- case JceStruct::TypeEnum::Map:
- {
- std::int32_t size;
- if (!self.Read(0, size))
- {
- nat_Throw(JceDecodeException, u8"Read size failed.");
- }
- if (size < 0)
- {
- nat_Throw(JceDecodeException, u8"Invalid size({0}).", size);
- }
- // 为了异常安全,构造临时 map 而不是就地修改
- std::unordered_map<Key, Value> tmpMap;
- for (std::size_t i = 0; i < static_cast<std::size_t>(size); ++i)
- {
- Key entryKey;
- if (!self.Read(0, entryKey))
- {
- nat_Throw(JceDecodeException, u8"Read key failed.");
- }
- Value entryValue;
- if (!self.Read(1, entryValue))
- {
- nat_Throw(JceDecodeException, u8"Read value failed.");
- }
- tmpMap.emplace(std::move(entryKey), std::move(entryValue));
- }
- value = std::move(tmpMap);
- break;
- }
- default:
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected {0}", static_cast<std::uint32_t>(head.Type));
- }
- return true;
- }
- return false;
- }
- };
- template <typename T>
- struct Reader<std::vector<T>>
- {
- static bool DoRead(JceInputStream& self, std::uint32_t tag, std::vector<T>& value)
- {
- if (self.SkipToTag(tag))
- {
- const auto[head, headSize] = self.ReadHead();
- switch (head.Type)
- {
- case JceStruct::TypeEnum::List:
- {
- std::int32_t size;
- if (!self.Read(0, size))
- {
- nat_Throw(JceDecodeException, u8"Read size failed.");
- }
- // 为了异常安全,构造临时 vector 而不是就地修改
- std::vector<T> tmpList;
- tmpList.reserve(size);
- if (size > 0)
- {
- for (std::size_t i = 0; i < static_cast<std::size_t>(size); ++i)
- {
- T elemValue;
- if (!self.Read(0, elemValue))
- {
- nat_Throw(JceDecodeException, u8"Read element failed.");
- }
- tmpList.emplace_back(std::move(elemValue));
- }
- }
- value = std::move(tmpList);
- break;
- }
- case JceStruct::TypeEnum::SimpleList:
- if constexpr (std::is_same_v<T, std::uint8_t>)
- {
- const auto[sizeField, sizeFieldSize] = self.ReadHead();
- if (sizeField.Type != JceStruct::TypeEnum::Byte)
- {
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected {0}", static_cast<std::uint32_t>(sizeField.Type));
- }
- std::uint8_t size;
- if (!self.Read(0, size))
- {
- nat_Throw(JceDecodeException, u8"Read size failed.");
- }
- std::vector<std::uint8_t> tmpList(static_cast<std::size_t>(size));
- self.m_Reader->GetUnderlyingStream()->ReadBytes(tmpList.data(), size);
- value = std::move(tmpList);
- break;
- }
- else
- {
- [[fallthrough]];
- }
- default:
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected {0}", static_cast<std::uint32_t>(head.Type));
- }
- return true;
- }
- return false;
- }
- };
- template <typename T>
- struct Reader<NatsuLib::natRefPointer<T>, std::enable_if_t<std::is_base_of_v<JceStruct, T>>>
- {
- static bool DoRead(JceInputStream& self, std::uint32_t tag, NatsuLib::natRefPointer<T>& value)
- {
- if (self.SkipToTag(tag))
- {
- const auto[head, headSize] = self.ReadHead();
- if (head.Type != JceStruct::TypeEnum::StructBegin)
- {
- nat_Throw(JceDecodeException, u8"Type mismatch, got unexpected {0}", static_cast<std::uint32_t>(head.Type));
- }
- value = TlvDeserializer<T>::Deserialize(self);
- self.SkipToStructEnd();
- return true;
- }
- return false;
- }
- };
- };
- class JceOutputStream
- : NatsuLib::noncopyable
- {
- public:
- explicit JceOutputStream(NatsuLib::natRefPointer<NatsuLib::natBinaryWriter> writer);
- ~JceOutputStream();
- NatsuLib::natRefPointer<NatsuLib::natBinaryWriter> GetWriter() const noexcept
- {
- return m_Writer;
- }
- void WriteHead(HeadData head)
- {
- if (head.Tag < 15)
- {
- m_Writer->WritePod(static_cast<std::uint8_t>((head.Tag << 4) | static_cast<std::uint8_t>(head.Type)));
- }
- else if (head.Tag < 256)
- {
- m_Writer->WritePod(static_cast<std::uint8_t>(static_cast<std::uint8_t>(head.Type) | 0xF0));
- m_Writer->WritePod(static_cast<std::uint8_t>(head.Tag));
- }
- else
- {
- nat_Throw(JceEncodeException, u8"Tag is too big({0}).", head.Tag);
- }
- }
- template <typename T>
- void Write(std::uint32_t tag, T const& value)
- {
- Writer<T>::DoWrite(*this, tag, value);
- }
- template <typename T>
- void Write(std::uint32_t tag, std::optional<T> const& value)
- {
- if (value.has_value())
- {
- Write(tag, value.value());
- }
- }
- template <typename T>
- void Write(std::uint32_t tag, NatsuLib::natRefPointer<T> const& value)
- {
- if (value)
- {
- Writer<NatsuLib::natRefPointer<T>>::DoWrite(*this, tag, value);
- }
- }
- private:
- NatsuLib::natRefPointer<NatsuLib::natBinaryWriter> m_Writer;
- template <typename T, typename = void>
- struct Writer;
- template <>
- struct Writer<std::uint8_t>
- {
- static void DoWrite(JceOutputStream& self, std::uint32_t tag, std::uint8_t value)
- {
- if (!value)
- {
- self.WriteHead({ tag, JceStruct::TypeEnum::ZeroTag });
- }
- else
- {
- self.WriteHead({ tag, JceStruct::TypeEnum::Byte });
- self.m_Writer->WritePod(value);
- }
- }
- };
- template <>
- struct Writer<std::int16_t>
- {
- static void DoWrite(JceOutputStream& self, std::uint32_t tag, std::int16_t value)
- {
- if (Utility::InRangeOf<std::int8_t>(value))
- {
- self.Write(tag, static_cast<std::uint8_t>(value));
- }
- else
- {
- self.WriteHead({ tag, JceStruct::TypeEnum::Short });
- self.m_Writer->WritePod(value);
- }
- }
- };
- template <>
- struct Writer<std::int32_t>
- {
- static void DoWrite(JceOutputStream& self, std::uint32_t tag, std::int32_t value)
- {
- if (Utility::InRangeOf<std::int16_t>(value))
- {
- self.Write(tag, static_cast<std::int16_t>(value));
- }
- else
- {
- self.WriteHead({ tag, JceStruct::TypeEnum::Int });
- self.m_Writer->WritePod(value);
- }
- }
- };
- template <>
- struct Writer<std::int64_t>
- {
- static void DoWrite(JceOutputStream& self, std::uint32_t tag, std::int64_t value)
- {
- if (Utility::InRangeOf<std::int32_t>(value))
- {
- self.Write(tag, static_cast<std::int32_t>(value));
- }
- else
- {
- self.WriteHead({ tag, JceStruct::TypeEnum::Long });
- self.m_Writer->WritePod(value);
- }
- }
- };
- template <>
- struct Writer<float>
- {
- static void DoWrite(JceOutputStream& self, std::uint32_t tag, float value)
- {
- self.WriteHead({ tag, JceStruct::TypeEnum::Float });
- self.m_Writer->WritePod(value);
- }
- };
- template <>
- struct Writer<double>
- {
- static void DoWrite(JceOutputStream& self, std::uint32_t tag, double value)
- {
- self.WriteHead({ tag, JceStruct::TypeEnum::Double });
- self.m_Writer->WritePod(value);
- }
- };
- template <>
- struct Writer<std::string>
- {
- static void DoWrite(JceOutputStream& self, std::uint32_t tag, std::string const& value)
- {
- const auto strSize = value.size();
- if (strSize <= std::numeric_limits<std::uint8_t>::max())
- {
- self.WriteHead({ tag, JceStruct::TypeEnum::String1 });
- self.m_Writer->WritePod(static_cast<std::uint8_t>(strSize));
- }
- else
- {
- if (strSize > std::numeric_limits<std::uint32_t>::max())
- {
- nat_Throw(JceDecodeException, u8"String is too long({0} bytes).", strSize);
- }
- self.WriteHead({ tag, JceStruct::TypeEnum::String4 });
- self.m_Writer->WritePod(static_cast<std::uint32_t>(strSize));
- }
- self.m_Writer->GetUnderlyingStream()->WriteBytes(reinterpret_cast<ncData>(value.data()), strSize);
- }
- };
- template <typename Key, typename Value>
- struct Writer<std::unordered_map<Key, Value>>
- {
- static void DoWrite(JceOutputStream& self, std::uint32_t tag, std::unordered_map<Key, Value> const& value)
- {
- self.WriteHead({ tag, JceStruct::TypeEnum::Map });
- self.Write(0, static_cast<std::int32_t>(value.size()));
- for (const auto& item : value)
- {
- self.Write(0, item.first);
- self.Write(1, item.second);
- }
- }
- };
- template <typename T>
- struct Writer<std::vector<T>>
- {
- static void DoWrite(JceOutputStream& self, std::uint32_t tag, std::vector<T> const& value)
- {
- self.WriteHead({ tag, JceStruct::TypeEnum::List });
- self.Write(0, static_cast<std::int32_t>(value.size()));
- for (const auto& item : value)
- {
- self.Write(0, item);
- }
- }
- };
- template <typename T>
- struct Writer<NatsuLib::natRefPointer<T>, std::enable_if_t<std::is_base_of_v<JceStruct, T>>>
- {
- static void DoWrite(JceOutputStream& self, std::uint32_t tag, NatsuLib::natRefPointer<T> const& value)
- {
- self.WriteHead({ tag, JceStruct::TypeEnum::StructBegin });
- TlvSerializer<T>::Serialize(self, value);
- self.WriteHead({ 0, JceStruct::TypeEnum::StructEnd });
- }
- };
- };
- enum class JceCode
- {
- #define TLV_CODE(name, code) name = code,
- #include "TlvCodeDef.h"
- };
- #define NO_OP NoOp
- #define IS_OPTIONAL(defaultValue) IsOptional
- #define TEMPLATE_ARGUMENT(...) TemplateArgs<__VA_ARGS__>
- #define FIELD(name, tag, type, ...) \
- private:\
- typename FieldTypeBuilder<JceStruct::TypeEnum::type, std::tuple<__VA_ARGS__>>::Type m_##name;\
- \
- public:\
- const auto& Get##name() const noexcept\
- {\
- return m_##name;\
- }\
- \
- auto& Get##name() noexcept\
- {\
- return m_##name;\
- }\
- \
- template <typename T>\
- void Set##name(T&& arg)\
- {\
- m_##name = std::forward<T>(arg);\
- }\
- \
- static constexpr std::size_t Get##name##Tag() noexcept\
- {\
- return tag;\
- }
- #define TLV_CODE(name, code) \
- class name\
- : public NatsuLib::natRefObjImpl<name, JceStruct>\
- {\
- public:\
- ~name();\
- \
- std::string_view GetJceStructName() const noexcept override;\
- JceCode GetJceStructType() const noexcept override;
- #define END_TLV_CODE(name) \
- };
- #include "TlvCodeDef.h"
- #define NO_OP Detail::None
- #define IS_OPTIONAL(defaultValue) defaultValue
- // 读取 optional 的时候不会返回 false
- #define FIELD(name, tag, type, ...) \
- {\
- using FieldType = typename Utility::MayRemoveTemplate<Utility::RemoveCvRef<decltype(ret->Get##name())>, std::optional>::Type;\
- if (!stream.Read(tag, ret->Get##name(),\
- Utility::ReturnFirst<Utility::ConcatTrait<Utility::BindTrait<std::is_same, Detail::NoneType>::template Result, std::negation>::template Result, Detail::NoneType>(__VA_ARGS__)))\
- {\
- nat_Throw(JceDecodeException, u8"Deserializing failed : Failed to read field \"" #name "\" which is not optional.");\
- }\
- }
- #define TLV_CODE(name, code) \
- template <>\
- struct TlvDeserializer<name>\
- {\
- static NatsuLib::natRefPointer<name> Deserialize(JceInputStream& stream)\
- {\
- auto ret = NatsuLib::make_ref<name>();
- #define END_TLV_CODE(name) \
- return ret;\
- }\
- };
- #include "TlvCodeDef.h"
- #define FIELD(name, tag, type, ...) stream.Write(tag, value->Get##name());
- #define TLV_CODE(name, code) \
- template <>\
- struct TlvSerializer<name>\
- {\
- static void Serialize(JceOutputStream& stream, NatsuLib::natRefPointer<name> const& value)\
- {
- #define END_TLV_CODE(name) \
- }\
- };
- #include "TlvCodeDef.h"
- }
|