#ifndef _HPROSE_ED_HPP_ #define _HPROSE_ED_HPP_ #include #include #include "hprose_tags.hpp" class HproseReader { public: HproseReader(const unsigned char* ptr, size_t len) : begin(ptr), end(ptr + len), current(ptr) {} HproseReader(const unsigned char* ptr, const unsigned char* end) : begin(ptr), end(end), current(ptr) {} unsigned char ReadByte() { if(current >= end) return 0; return *current++; } Tags ReadTag() { return static_cast(ReadByte()); } bool CheckTag(Tags tag, bool skip) { if(current >= end) return false; if(static_cast(*current) != tag) return false; if(skip) current++; return true; } void Skip(uint32_t len) { current += len; if(current >= end) current = end; } std::string ReadUntilAsString(Tags tag) { auto start = current; while(current != end && *current != static_cast(tag)) current++; if(current == end) { return std::string(start, current); } else { return std::string(start, current++); } } std::string ReadBytesAsString(size_t length) { auto start = current; current += length; if(current > end) current = end; return std::string(start, current); } std::string ReadUTF8String(size_t length) { auto start = current; for(size_t i = 0; i < length && current < end; ++i) { if(*current < 0x80) { // 0xxxxxxx current++; } else if(*current < 0xd0) { // 110xxxxx 10xxxxxx if(current + 2 > end) break; current += 2; } else if(*current < 0xf0) { // 1110xxxx 10xxxxxx 10xxxxxx if(current + 3 > end) break; current += 3; } else { // 11110xxx 10xxxxx 10xxxxxx 10xxxxxx if(current + 4 > end) break; current += 4; } } auto ptr = current; CheckTag(Tags::Quote, true); return std::string(start, ptr); } int64_t ReadInt64Raw(Tags end) { int64_t value = 0; auto b = ReadByte(); if(static_cast(b) == end) return value; bool neg = false; if(static_cast(b) == Tags::Neg) { neg = true; b = ReadByte(); } else if(static_cast(b) == Tags::Pos) { b = ReadByte(); } while(static_cast(b) != end) { value = value * 10 + int64_t(b - '0'); b = ReadByte(); } return neg ? -value : value; } void SkipValue() { SkipValue(ReadTag()); } void SkipValue(Tags tag) { switch(tag) { case Tags::Call: case Tags::Result: case Tags::Error: case Tags::End: case Tags::Argument: { current--; return; } case Tags::Null: case Tags::Empty: case Tags::Num0: case Tags::Num1: case Tags::Num2: case Tags::Num3: case Tags::Num4: case Tags::Num5: case Tags::Num6: case Tags::Num7: case Tags::Num8: case Tags::Num9: case Tags::False: case Tags::True: case Tags::NaN: return; case Tags::Infinity: { ReadTag(); return; } case Tags::Integer: case Tags::Long: { ReadInt64Raw(Tags::Semicolon); return; } case Tags::Double: { ReadUntilAsString(Tags::Semicolon); return; } case Tags::UTF8Char: { ReadUTF8String(1); return; } case Tags::String: { ReadUTF8String(ReadInt64Raw(Tags::Quote)); return; } case Tags::Bytes: { ReadBytesAsString(ReadInt64Raw(Tags::Quote)); return; } case Tags::List: { int64_t count = ReadInt64Raw(Tags::Openbrace); for(int64_t i = 0; i < count; ++i) SkipValue(); ReadTag(); // Tags::Closebrace return; } case Tags::Map: { int64_t count = ReadInt64Raw(Tags::Openbrace) * 2; for(int64_t i = 0; i < count; ++i) SkipValue(); ReadTag(); // Tags::Closebrace return; } case Tags::Date: { Skip(8); // year-4 m-2 d-2 if(!CheckTag(Tags::Time, true)) return; } case Tags::Time: { Skip(6); // h-2 m-2 s-2 if(CheckTag(Tags::Point, true)) { // nano seconds 1-9digits while(current < end && *current >= '0' && *current <= '9') current++; } CheckTag(Tags::UTC, true); return; } case Tags::GUID: { Skip(38); // '"' + 36 bytes string + '"' return; } case Tags::Class: { SkipValue(Tags::String); // name SkipValue(Tags::List); // list if(!CheckTag(Tags::Object, true)) return; } case Tags::Object: { SkipValue(); // index if(CheckTag(Tags::Openbrace, true)) { do { SkipValue(); } while(!CheckTag(Tags::Closebrace, true)); } } default: { return; } } } void PushFieldRefs(std::vector fields) { fieldRefs.emplace_back(std::move(fields)); } const std::vector& GetFieldRefs(int32_t idx) { return fieldRefs[idx]; } protected: const unsigned char* begin; const unsigned char* end; const unsigned char* current; std::vector> fieldRefs; }; class HproseWriter { public: HproseWriter(unsigned char* ptr, size_t len) : begin(ptr), end(ptr + len), current(ptr) {} void WriteByte(unsigned char byte) { *current++ = byte; } void WriteBytes(unsigned char* bytes, size_t len) { memcpy(current, bytes, len); current += len; } void WriteTag(Tags tag) { *current++ = static_cast(tag); } void WriteLength(uint32_t length) { auto len = sprintf((char*)current, "%u", length); current += len; } void WriteInteger(int64_t val) { auto len = sprintf((char*)current, "%ld", val); current += len; } void WriteDouble(double val) { auto len = sprintf((char*)current, "%lf", val); current += len; } void WriteString(const std::string& val) { memcpy(current, val.data(), val.length()); current += val.length(); } size_t Length() { return current - begin; } int32_t GetStructFieldsIndex(const std::string& name) { auto iter = fieldIds.find(name); if(iter == fieldIds.end()) return -1; return iter->second; } int32_t PushFieldRefs(const std::string& name) { int32_t index = fieldIds.size(); fieldIds[name] = index; return index; } protected: const unsigned char* begin; const unsigned char* end; unsigned char* current; std::map fieldIds; }; #endif