hproselet/hprose_ed.hpp

272 lines
6.1 KiB
C++

#ifndef _HPROSE_ED_HPP_
#define _HPROSE_ED_HPP_
#include <string>
#include <memory>
#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<Tags>(ReadByte());
}
bool CheckTag(Tags tag, bool skip) {
if(current >= end)
return false;
if(static_cast<Tags>(*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<unsigned char>(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<Tags>(b) == end)
return value;
bool neg = false;
if(static_cast<Tags>(b) == Tags::Neg) {
neg = true;
b = ReadByte();
} else if(static_cast<Tags>(b) == Tags::Pos) {
b = ReadByte();
}
while(static_cast<Tags>(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<std::string> fields) { fieldRefs.emplace_back(std::move(fields)); }
const std::vector<std::string>& GetFieldRefs(int32_t idx) { return fieldRefs[idx]; }
protected:
const unsigned char* begin;
const unsigned char* end;
const unsigned char* current;
std::vector<std::vector<std::string>> 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<unsigned char>(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<std::string, int32_t> fieldIds;
};
#endif