FCJson.h
#pragma once
#include <stdint.h>
#include <string>
#include <vector>
#include <map>// JSON规范: https://www.json.org/json-zh.html#ifdef _UNICODE#define __T(x) L ## x
using _tstring = std::wstring;
using _tchar = wchar_t;
using _utchar = _tchar;#else#define __T(x) x
using _tstring = std::string;
using _tchar = char;
using _utchar = unsigned char;#endif#define _T(x) __T(x)
#define _TEXT(x) __T(x)// JSON 解析
// FlameCyclone
namespace FCJson
{class JsonValue;using JsonNull = void*;using JsonBool = bool;using JsonInt = int64_t;using JsonFloat = double;using JsonString = _tstring;using JsonObject = std::map<_tstring, JsonValue>;using JsonArray = std::vector<JsonValue>;// 异常class JsonException{public:JsonException(const _tstring& msg, const _tchar* pStrPos = nullptr) :m_Message(msg){if (nullptr != pStrPos){m_TextPos = pStrPos;}}_tstring GetMessage() const{return m_Message;}_tstring GetTextPos() const{return m_Message;}private:_tstring m_Message; // 提示_tstring m_TextPos; // 异常起始文本};// JSON 数据类型enum JsonType{eNull, // 空值eString, // 字符串eInteger, // 整数eFloat, // 浮点数eBool, // 布尔eObject, // 对象eArray, // 数组};// JSON 编码enum JsonEncoding{eAuto, // 自动eUtf8, // Utf8eUtf16, // Utf16编码};// JSON 值类class JsonValue{public:// 构造JsonValue();JsonValue(JsonType type);JsonValue(const _tchar* val);JsonValue(const JsonBool val);JsonValue(const int val);JsonValue(const JsonInt val);JsonValue(const JsonFloat val);JsonValue(const JsonString& val);JsonValue(const JsonObject& val);JsonValue(const JsonArray& val);JsonValue(const JsonValue& r);JsonValue(JsonValue&& r) noexcept;// 运算符重载JsonValue& operator [] (const _tstring& name);JsonValue& operator [] (size_t index);JsonValue& operator = (const JsonValue& r);JsonValue& operator = (JsonBool val);JsonValue& operator = (int val);JsonValue& operator = (JsonInt val);JsonValue& operator = (JsonFloat val);JsonValue& operator = (const _tchar* val);JsonValue& operator = (const JsonString& val);JsonValue& operator = (const JsonObject& val);JsonValue& operator = (const JsonArray& val);void Clear();~JsonValue();// 检查与类型判断bool IsExists(const _tstring name) const;JsonType GetType() const;_tstring GetTypeName() const;// 类型判断bool IsNull() const;bool IsBool() const;bool IsInt() const;bool IsFloat() const;bool IsString() const;bool IsObject() const;bool IsArray() const;// 获取数据JsonBool AsBool() const;JsonInt AsInt() const;JsonFloat AsFloat() const;JsonString AsString() const;JsonObject AsObject() const;JsonArray AsArray() const;// // @brief: 从文件解析(仅支持 UTF8 或 UTF16编码的文本)// @param: strText 文本内容// @ret: JsonValue JSON值JsonValue Parse(const _tstring strText);// // @brief: 从文件解析(仅支持 UTF8 或 UTF16编码的文件)// @param: strPath 文件路径// @ret: JsonValue JSON值JsonValue ParseFromFile(const _tstring strPath);// // @brief: 转储// @param: indent 空白字符数量// @param: fEscapeCh 是否转义非Ascii字符// @ret: std::wstring 转储文本_tstring Dump(int indent = 0, bool fEscapeCh = false) const;// // @brief: 转储到文件// @param: strPath 文件路径// @param: indent 空白字符数量// @param: enc Unicode编码类型(UTF8或UTF16)// @param: fEscapeCh 是否转义非Ascii字符// @ret: std::wstring 转储文本bool DumpToFile(const _tstring strPath, int indent = 0, JsonEncoding enc = JsonEncoding::eAuto, bool fEscapeCh = false);private:JsonValue _ParseFromStringPtr(const _tchar* pData, bool fFromFile);JsonValue _ParseFromStringPtr(const _tchar* pData, const _tchar** pEnd, bool fFromFile);bool _ParseJsonString(const _tchar* pData, _tstring& val, const _tchar** pEnd, bool fFromFile);bool _ParseJsonValue(const _tchar* pData, JsonValue& val, const _tchar** pEnd, bool fFromFile);bool _ParseJsonNumberValue(const _tchar* pData, JsonValue& val, const _tchar** pEnd);_tstring _Dump(int depth, int indent, bool fEscapeCh) const;_tstring _GetDumpString(const _tstring strText, bool fEscapeCh) const;private:JsonArray m_Array; // 数组JsonObject m_Object; // 键值对JsonString m_String; // 字符串JsonFloat m_Float; // 浮点数JsonInt m_Integer; // 整数JsonBool m_Bool; // 布尔值JsonType m_Type; // 类型};
}
FCJson.cpp
#include "FCJson.h"
#include <cwctype>
#include <fstream>// UTF-8 编码标准
//
// 1字节 U+0000000 - U+0000007F 0xxxxxxx
// 2字节 U+0000080 - U+000007FF 110xxxxx 10xxxxxx
// 3字节 U+0000800 - U+0000FFFF 1110xxxx 10xxxxxx 10xxxxxx
// 4字节 U+0010000 - U+001FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
// 5字节 U+0200000 - U+03FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
// 6字节 U+4000000 - U+7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx// UTF16 编码标准
//
// 基本多语言平面(U+0000 - U+FFFF)
//
// 辅助平面(U+10000 - U+10FFFF)
// 1.码位减去 0x10000,得到20位的代理值(0x00 - 0xFFFFF)
// 2.高10位(范围0 - 0x3FF)加 0xD800 得到高位代理(0xD800 - 0xDBFF)
// 3.低10位(范围0 - 0x3FF)加 0xDC00 得到低位代理(0xDC00 - 0xDFFF)namespace FCJson
{
#ifdef _UNICODE#define _istxdigit std::iswxdigit
#define _istdigit std::iswdigit
#define _tcsnicmp _wcsnicmp
#define _tcsstr wcsstr
#define _tcstod std::wcstof
#define _tcstol std::wcstol
#define _tcstoll std::wcstoll
#define _stprintf_s swprintf_s
#define _tostring std::to_wstring
#else#define _istxdigit std::iswxdigit
#define _istdigit std::iswdigit
#define _tcsnicmp _strnicmp
#define _tcsstr strstr
#define _tcstod std::strtof
#define _tcstol std::strtol
#define _tcstoll std::strtoll
#define _stprintf_s sprintf_s
#define _tostring std::to_string#endifstatic std::string _CodePointToUtf8(uint32_t cp32);static bool _GetUnicodeCodePoint(const _tchar* pData, uint32_t* pCp, const _tchar** pEnd);static int32_t _Utf8ToUtf16(const void* pData, size_t size = -1, std::string* pUtf8 = nullptr, std::wstring* pUtf16 = nullptr);static int32_t _Utf16ToUtf8(const void* pData, size_t size = -1, std::string* pUtf8 = nullptr, std::wstring* pUtf16 = nullptr);const _tchar* _SkipStringWhitespace(const _tchar* pData);const _tchar* _SkipStringBom(const _tchar* pData);static bool _SkipDigit(const _tchar* pData, const _tchar** pEnd);JsonValue::JsonValue():m_Bool(false),m_Integer(0),m_Float(0.0f),m_Type(JsonType::eNull){}JsonValue::JsonValue(JsonType type) : JsonValue(){m_Type = type;}JsonValue::JsonValue(const _tchar* val) : JsonValue(_tstring(val)){}JsonValue::JsonValue(const JsonBool val) : JsonValue(){m_Type = JsonType::eBool;m_Bool = val;}JsonValue::JsonValue(const int val) : JsonValue(){m_Type = JsonType::eInteger;m_Integer = val;}JsonValue::JsonValue(const JsonInt val) : JsonValue(){m_Type = JsonType::eInteger;m_Integer = val;}JsonValue::JsonValue(const JsonFloat val) : JsonValue(){m_Type = JsonType::eFloat;m_Float = val;}JsonValue::JsonValue(const JsonString& val) : JsonValue(){m_Type = JsonType::eString;m_String = val;}JsonValue::JsonValue(const JsonObject& val) : JsonValue(){m_Type = JsonType::eObject;m_Object = val;}JsonValue::JsonValue(const JsonArray& val) : JsonValue(){m_Type = JsonType::eArray;m_Array = val;}JsonValue::JsonValue(const JsonValue& r) : JsonValue(){m_Type = r.m_Type;m_Bool = r.m_Bool;m_Integer = r.m_Integer;m_Float = r.m_Float;m_String = r.m_String;m_Object = r.m_Object;m_Array = r.m_Array;}JsonValue::JsonValue(JsonValue&& r) noexcept : JsonValue(){m_Type = r.m_Type;m_Bool = r.m_Bool;m_Integer = r.m_Integer;m_Float = r.m_Float;m_String = std::move(r.m_String);m_Object = std::move(r.m_Object);m_Array = std::move(r.m_Array);}JsonValue& JsonValue::operator[](const _tstring& name){if (!IsObject()){throw JsonException(_T("Type Error"), _T("operator[] JsonType::eObject == m_Type"));}auto itFind = m_Object.find(name);if (m_Object.end() == itFind){m_Object.insert(std::make_pair(name, JsonValue()));}itFind = m_Object.find(name);return itFind->second;}JsonValue& JsonValue::operator[](size_t index){if (JsonType::eArray != m_Type){throw JsonException(_T("Type Error"), _T("operator[] JsonType::eArray == m_Type"));}if (m_Array.size() <= index){m_Array.resize(index + 1);}return m_Array[index];}JsonValue& JsonValue::operator = (const JsonValue& r){if (&r != this){Clear();m_Type = r.m_Type;if (m_Type == JsonType::eBool) m_Bool = r.m_Bool;if (m_Type == JsonType::eInteger) m_Integer = r.m_Integer;if (m_Type == JsonType::eFloat) m_Float = r.m_Float;if (m_Type == JsonType::eString) m_String = r.m_String;if (m_Type == JsonType::eObject) m_Object = r.m_Object;if (m_Type == JsonType::eArray) m_Array = r.m_Array;}return *this;}JsonValue& JsonValue::operator = (JsonBool val){if (JsonType::eBool != m_Type){Clear();m_Type = JsonType::eBool;}m_Bool = val;return *this;}JsonValue& JsonValue::operator = (int val){if (JsonType::eInteger != m_Type){Clear();m_Type = JsonType::eInteger;}m_Integer = val;return *this;}JsonValue& JsonValue::operator = (JsonInt val){if (JsonType::eInteger != m_Type){Clear();m_Type = JsonType::eInteger;}m_Integer = val;return *this;}JsonValue& JsonValue::operator = (JsonFloat val){if (JsonType::eFloat != m_Type){Clear();m_Type = JsonType::eFloat;}m_Float = val;return *this;}JsonValue& JsonValue::operator = (const _tchar* val){if (JsonType::eString != m_Type){Clear();m_Type = JsonType::eString;}m_String = val;return *this;}JsonValue& JsonValue::operator = (const JsonString& val){if (JsonType::eString != m_Type){Clear();m_Type = JsonType::eString;}m_String = val;return *this;}JsonValue& JsonValue::operator = (const JsonObject& val){if (JsonType::eObject != m_Type){Clear();m_Type = JsonType::eObject;}m_Object = val;return *this;}JsonValue& JsonValue::operator = (const JsonArray& val){if (JsonType::eArray != m_Type){Clear();m_Type = JsonType::eArray;}m_Array = val;return *this;}JsonValue::~JsonValue(){}bool JsonValue::IsExists(const _tstring name) const{if (!IsObject()){return false;}auto itFind = m_Object.find(name);if (m_Object.end() == itFind){return false;}return true;}JsonType JsonValue::GetType() const{return m_Type;}_tstring JsonValue::GetTypeName() const{if (JsonType::eNull == m_Type)return _T("Null");if (JsonType::eBool == m_Type)return _T("Bool");if (JsonType::eInteger == m_Type)return _T("Integer");if (JsonType::eFloat == m_Type)return _T("Float");if (JsonType::eString == m_Type)return _T("String");if (JsonType::eObject == m_Type)return _T("Object");if (JsonType::eArray == m_Type)return _T("Array");return _T("None");}bool JsonValue::IsNull() const{return JsonType::eNull == m_Type;}bool JsonValue::IsBool() const{return JsonType::eBool == m_Type;}bool JsonValue::IsInt() const{return JsonType::eInteger == m_Type;}bool JsonValue::IsFloat() const{return JsonType::eFloat == m_Type;}bool JsonValue::IsString() const{return JsonType::eString == m_Type;}bool JsonValue::IsObject() const{return JsonType::eObject == m_Type;}bool JsonValue::IsArray() const{return JsonType::eArray == m_Type;}JsonBool JsonValue::AsBool() const{if (!JsonType::eBool == m_Type){throw JsonException(_T("Type Error"), _T("AsBool(): JsonType::eBool == m_Type"));}return m_Bool;}JsonInt JsonValue::AsInt() const{if (!JsonType::eInteger == m_Type){throw JsonException(_T("Type Error"), _T("AsInt(): JsonType::eInteger == m_Type"));}return m_Integer;}JsonFloat JsonValue::AsFloat() const{if (!JsonType::eFloat == m_Type){throw JsonException(_T("Type Error"), _T("AsFloat(): JsonType::eFloat == m_Type"));}return m_Float;}JsonString JsonValue::AsString() const{if (!JsonType::eString == m_Type){throw JsonException(_T("Type Error"), _T("AsString(): JsonType::eString == m_Type"));}return m_String;}JsonObject JsonValue::AsObject() const{if (!JsonType::eObject == m_Type){throw JsonException(_T("Type Error"), _T("AsObject(): JsonType::eObject == m_Type"));}return m_Object;}JsonArray JsonValue::AsArray() const{if (!JsonType::eArray == m_Type){throw JsonException(_T("Type Error"), _T("AsArray(): JsonType::eArray == m_Type"));}return m_Array;}void JsonValue::Clear(){m_Bool = false;m_Integer = 0;m_Float = 0.0f;m_String.clear();m_Object.clear();m_Array.clear();m_Type = JsonType::eNull;}_tstring JsonValue::_GetDumpString(const _tstring strText, bool fEscapeCh) const{const _tchar* pData = strText.c_str();_tstring strResult;strResult.reserve(strText.size());while (_T('\0') != *pData){_utchar ch = *pData;if (_T('\"') == ch){strResult += _T(R"(\")");}else if (_T('\\') == ch){strResult += _T(R"(\\)");}else if (_T('/') == ch){strResult += _T(R"(/)");}else if (_T('\b') == ch){strResult += _T(R"(\b)");}else if (_T('\f') == ch){strResult += _T(R"(\f)");}else if (_T('\n') == ch){strResult += _T(R"(\n)");}else if (_T('\r') == ch){strResult += _T(R"(\r)");}else if (_T('\t') == ch){strResult += _T(R"(\t)");}else{
#ifdef _UNICODE_tchar szBuf[32] = { 0 };if (ch < 0x80 || !fEscapeCh){strResult.push_back(ch);pData++;continue;}_stprintf_s(szBuf, sizeof(szBuf) / sizeof(_tchar), _T(R"(\u%0.4x)"), ch);strResult += szBuf;#elsebool fResult = true;if (ch < 0x80 || !fEscapeCh){strResult.push_back(ch);pData++;continue;}if (ch >= 0xC0){uint8_t u8CodeMask = 0xC0; // 11000000uint8_t u8DataMask = 0x1F; // 000xxxxxint nCount = 2; // 有效字节数量: 2-6// 检索字符使用的字节数量size_t nByteCount = 0;uint32_t cp32 = 0;while (u8CodeMask <= 0xFC){uint8_t u8MaskMax = u8CodeMask | u8DataMask;if (ch >= u8CodeMask && ch <= u8MaskMax){cp32 = ch & u8DataMask;nByteCount = nCount;break;}u8CodeMask = (u8CodeMask >> 1) | 0x80;u8DataMask = u8DataMask >> 1;nCount++;}if (0 == nByteCount){fResult = false;break;}for (size_t i = 1; i < nByteCount; i++){cp32 = cp32 << 6;cp32 |= pData[i] & 0x3F;}char szBuf[32] = { 0 };if (cp32 < 0x10000){sprintf_s(szBuf, sizeof(szBuf), R"(\u%0.4x)", cp32);strResult += szBuf;}else{uint32_t cp = (uint16_t)(cp32 - 0x10000);uint16_t cp32Hi = (uint16_t)(cp >> 10) + 0xD800;uint16_t cp32Lo = (uint16_t)(cp & 0x3FF) + 0xDC00;sprintf_s(szBuf, sizeof(szBuf), R"(\u%0.4x)", cp32Hi);strResult += szBuf;sprintf_s(szBuf, sizeof(szBuf), R"(\u%0.4x)", cp32Lo);strResult += szBuf;}pData += nByteCount;continue;}
#endif}pData++;}return strResult;}bool JsonValue::_ParseJsonString(const _tchar* pData, _tstring& val, const _tchar** pEnd, bool fFromFile){const _tchar* pStart = pData;bool fAbort = false;// 跳过空格pData = _SkipStringWhitespace(pData);// 检查双引号if (_T('\"') != *pData){return false;}pData++;pStart = pData;_tstring strResult;while (_T('\0') != *pData){_tchar ch = *pData;if (_T('\"') == ch){break;}if (fFromFile){if (_T('\\') == ch){pData++;ch = *pData;switch (ch){case _T('\"'):{strResult.push_back(_T('\"'));}break;case _T('\\'):{strResult.push_back(_T('\\'));}break;case _T('/'):{strResult.push_back(_T('/'));}break;case _T('b'):{strResult.push_back(_T('\b'));}break;case _T('n'):{strResult.push_back(_T('\n'));}break;case _T('r'):{strResult.push_back(_T('\r'));}break;case _T('t'):{strResult.push_back(_T('\t'));}break;case _T('u'):{pData++;uint32_t cp32 = 0;if (!_GetUnicodeCodePoint(pData, &cp32, &pData)){fAbort = true;break;}// 高位if (cp32 >= 0xD800 && cp32 <= 0xDBFF){cp32 -= 0xD800;if (0 != _tcsnicmp(_T(R"(\u)"), pData, 2)){fAbort = true;break;}pData += 2;uint32_t cpLo = 0;if (!_GetUnicodeCodePoint(pData, &cpLo, &pData)){fAbort = true;break;}// 低位if (cpLo >= 0xDC00 && cpLo <= 0xDFFF){cpLo -= 0xDC00;cp32 = 0x10000 + ((cp32 << 10) | cpLo);
#ifdef _UNICODEuint16_t cp = (uint16_t)(cp32 - 0x10000);uint16_t cp32Hi = (uint16_t)(cp >> 10) + 0xD800;uint16_t cp32Lo = (uint16_t)(cp & 0x3FF) + 0xDC00;strResult.push_back(cp32Hi);strResult.push_back(cp32Lo);
#elsestrResult += _CodePointToUtf8(cp32);
#endif}else{fAbort = true;break;}}else{
#ifdef _UNICODEstrResult.push_back((_tchar)cp32);
#elsestrResult += _CodePointToUtf8(cp32);
#endif}continue;}break;default:pData--;fAbort = true;break;}}else{strResult.push_back(ch);}}else{strResult.push_back(ch);}if (fAbort){break;}pData++;}// 检查双引号if (_T('\"') != *pData || fAbort){*pEnd = pData;return false;}pData++;val = strResult;if (pEnd){*pEnd = pData;}return true;}_tstring FloatToString(double fNumber){_tstring strResult;strResult = _tostring(fNumber);size_t posDot = strResult.find(_T('.'));if (_tstring::npos == posDot){strResult += _T(".0");}else{size_t nSize = strResult.size();for (auto it = strResult.rbegin(); strResult.rend() != it; it++){if (_T('0') == *it){nSize--;}else if (_T('.') == *it){strResult.resize(nSize);strResult += _T("0");break;}else{strResult.resize(nSize);break;}}}return strResult;}_tstring JsonValue::_Dump(int depth, int indent, bool fEscapeCh) const{if (indent < 0){indent = 0;}_tstring strResult;_tstring strKeyValInterval = _T("");_tstring strReturn = _T("");if (indent > 0){strKeyValInterval = _T(" ");strReturn = _T("\r\n");}if (IsNull()){strResult = _T("null");}else if (IsBool()){strResult = m_Bool ? _T("true") : _T("false");}else if (IsInt()){strResult = _tostring(m_Integer);}else if (IsFloat()){strResult = FloatToString(m_Float);}else if (IsString()){strResult += _T("\"");strResult += _GetDumpString(m_String, fEscapeCh);strResult += _T("\"");}else if (IsObject()){strResult = _T("{");strResult += strReturn;depth++;size_t size = m_Object.size();for (const auto& item : m_Object){strResult += _tstring(depth * indent, _T(' '));strResult += _T("\"");strResult += _GetDumpString(item.first, fEscapeCh);strResult += _T("\":");strResult += strKeyValInterval;strResult += item.second._Dump(depth, indent, fEscapeCh);size--;if (0 != size){strResult += _T(",");}strResult += strReturn;}depth--;strResult += _tstring(depth * indent, _T(' '));strResult += _T("}");}else if (IsArray()){strResult = _T("[");strResult += strReturn;depth++;size_t size = m_Array.size();for (const auto& item : m_Array){strResult += _tstring(depth * indent, _T(' '));strResult += item._Dump(depth, indent, fEscapeCh);size--;if (0 != size){strResult += _T(",");}strResult += strReturn;}depth--;strResult += _tstring(depth * indent, _T(' '));strResult += _T("]");}return strResult;}_tstring JsonValue::Dump(int indent/* = 0*/, bool fEscapeCh/* = false*/) const{return _Dump(0, indent, fEscapeCh);}bool JsonValue::DumpToFile(const _tstring strPath, int indent/* = 0*/, JsonEncoding encoding/* = JsonEncoding::eAuto*/, bool fEscapeCh/* = false*/){_tstring strResult;_tstring strText = _Dump(0, indent, fEscapeCh);std::string strUnicode8;std::wstring strUnicode16;strUnicode8.push_back((uint8_t)0xEF);strUnicode8.push_back((uint8_t)0xBB);strUnicode8.push_back((uint8_t)0xBF);strUnicode16.push_back((uint16_t)0xFEFF);std::ofstream outputFile(strPath, std::ios::binary | std::ios::out);if (!outputFile.is_open()){return false;}#ifdef _UNICODEstrResult = strUnicode16;if (JsonEncoding::eUtf16 == encoding || JsonEncoding::eAuto == encoding){strResult += strText;outputFile.write((const char*)strResult.data(), strResult.size() * sizeof(_tchar));outputFile.close();}if (JsonEncoding::eUtf8 == encoding){int32_t nU8Length = _Utf16ToUtf8(strText.c_str(), (size_t)-1, &strUnicode8, nullptr);if (nU8Length >= 0){outputFile.write((const char*)strUnicode8.data(), strUnicode8.size() * sizeof(char));outputFile.close();}}#elsestrResult = strUnicode8;if (JsonEncoding::eUtf8 == encoding || JsonEncoding::eAuto == encoding){strResult += strText;outputFile.write((const char*)strResult.data(), strResult.size() * sizeof(_tchar));outputFile.close();}if (JsonEncoding::eUtf16 == encoding){int32_t nU8Length = _Utf8ToUtf16(strText.c_str(), (size_t)-1, nullptr, &strUnicode16);if (nU8Length >= 0){outputFile.write((const char*)strUnicode16.data(), strUnicode16.size() * sizeof(wchar_t));outputFile.close();}}#endifreturn true;}JsonValue JsonValue::Parse(const _tstring strText){return _ParseFromStringPtr(strText.c_str(), false);}JsonValue JsonValue::ParseFromFile(const _tstring strPath){std::string strUnicode8;std::wstring strUnicode16;_tstring strText;do{std::ifstream inputFile(strPath, std::ios::binary | std::ios::in);if (!inputFile.is_open()){break;}//获取文件大小inputFile.seekg(0, std::ios::end);std::streamoff nSize = inputFile.tellg();inputFile.seekg(0, std::ios::beg);std::string strBuffer(nSize, 0);inputFile.read((char*)&strBuffer[0], nSize);size_t nByteSize = (size_t)inputFile.gcount();inputFile.close();if (0 == nByteSize){break;}int32_t nU8Length = _Utf8ToUtf16(strBuffer.data(), strBuffer.size(), &strUnicode8, &strUnicode16);#ifdef _UNICODEif (nU8Length > 0){strText = strUnicode16;break;}
#elseif (nU8Length > 0){strText = strUnicode8;break;}
#endifint32_t nU16Length = _Utf16ToUtf8(strBuffer.data(), strBuffer.size(), &strUnicode8, &strUnicode16);#ifdef _UNICODEif (nU16Length > 0){strText = strUnicode16;break;}
#elseif (nU16Length > 0){strText = strUnicode8;break;}
#endif} while (false);return _ParseFromStringPtr(strText.c_str(), true);}JsonValue JsonValue::_ParseFromStringPtr(const _tchar* pData, bool fFromFile){Clear();pData = _SkipStringBom(pData);pData = _SkipStringWhitespace(pData);const _tchar* pEnd = nullptr;*this = _ParseFromStringPtr(pData, &pEnd, fFromFile);return *this;}bool _SkipDigit(const _tchar* pData, const _tchar** pEnd){if (0 == _istdigit(*pData)){return false;}while (_istdigit(*pData)){pData++;}*pEnd = pData;return true;}bool JsonValue::_ParseJsonNumberValue(const _tchar* pData, JsonValue& val, const _tchar** pEnd){// [-]?[0-9]+\.[0-9]+[eE]?[-+]?[0-9]+const _tchar* pStart = pData;bool fDot = false;bool fExponent = false;bool fResult = false;do{// 符号if (_T('-') == *pData){pData++;}// 数字部分if (!_SkipDigit(pData, &pData)){fResult = false;break;}//小数点if (_T('.') == *pData){fDot = true;pData++;}// 小数部分if (fDot){if (!_SkipDigit(pData, &pData)){break;}}// 指数部分if (_T('E') == *pData || _T('e') == *pData){fExponent = true;pData++;}if (fExponent){// 指数符号if (_T('-') == *pData || _T('+') == *pData){pData++;}if (!_SkipDigit(pData, &pData)){break;}}_tstring strNumber(pStart, pData - pStart);double fNumber = 0.0f;fNumber = _tcstod(strNumber.c_str(), nullptr);if (fDot){val = fNumber;}else{val = (JsonInt)fNumber;}fResult = true;} while (false);if (pEnd){*pEnd = pData;}return fResult;}bool JsonValue::_ParseJsonValue(const _tchar* pData, JsonValue& val, const _tchar** pEnd, bool fFromFile){// 跳过空格pData = _SkipStringWhitespace(pData);bool fResult = true;do{_tchar ch = *pData;if (_T('{') == ch){val = _ParseFromStringPtr(pData, pEnd, fFromFile);return true;}else if (_T('[') == ch){val = _ParseFromStringPtr(pData, pEnd, fFromFile);return true;}else{pData = _SkipStringWhitespace(pData);if (0 == _tcsnicmp(_T("null"), pData, 4)){val = JsonValue(JsonType::eNull);pData += 4;}else if(0 == _tcsnicmp(_T("true"), pData, 4)){val = true;pData += 4;}else if(0 == _tcsnicmp(_T("false"), pData, 5)){val = false;pData += 5;}else if (_T('-') == *pData || _istdigit(*pData)){if (!_ParseJsonNumberValue(pData, val, &pData)){fResult = false;break;}}else if (_T('\"') == *pData){_tstring strName;if (!_ParseJsonString(pData, strName, &pData, fFromFile)){fResult = false;break;}val = strName;}else{fResult = false;break;}}} while (false);if (*pEnd){*pEnd = pData;}return fResult;}JsonValue JsonValue::_ParseFromStringPtr(const _tchar* pData, const _tchar** pEnd, bool fFromFile){JsonValue valResult;if (_T('[') == *pData) // 解析数组{pData++;valResult = JsonValue(JsonType::eArray);size_t nIndex = 0;while (_T('\0') != *pData){JsonValue val;pData = _SkipStringWhitespace(pData);if (!_ParseJsonValue(pData, val, &pData, fFromFile)){throw JsonException(_T("json content error"), pData);}// 获取值数据if (valResult.m_Array.size() <= nIndex){valResult.m_Array.resize(nIndex + 1);}valResult.m_Array[nIndex] = val;// 跳过空格pData = _SkipStringWhitespace(pData);// 下一个元素if (_T(',') == *pData){pData++;}else if (_T(']') == *pData) // 数组闭合{pData++;break;}else{throw JsonException(_T("json content error"), pData);}nIndex++;}}else if (_T('{') == *pData) // 解析对象{pData++;valResult = JsonValue(JsonType::eObject);while (_T('\0') != *pData){_tstring strName;JsonValue val;pData = _SkipStringWhitespace(pData);// 获取值名if (!_ParseJsonString(pData, strName, &pData, fFromFile)){throw JsonException(_T("json content error"), pData);}pData = _SkipStringWhitespace(pData);if (_T(':') != *pData){throw JsonException(_T("json content error"), pData);}pData++;if (!_ParseJsonValue(pData, val, &pData, fFromFile)){throw JsonException(_T("json content error"), pData);}// 获取值数据valResult[strName] = val;// 跳过空格pData = _SkipStringWhitespace(pData);// 下一个元素if (_T(',') == *pData){pData++;}else if (_T('}') == *pData) //对象闭合{pData++;break;}else{throw JsonException(_T("json content error"), pData);}}}else{throw JsonException(_T("json content error"), pData);}if (pEnd){*pEnd = pData;}return valResult;}const _tchar* _SkipStringWhitespace(const _tchar* pData){while (_T('\0') != *pData){if (_T(' ' == *pData) ||_T('\t' == *pData) ||_T('\r' == *pData) ||_T('\n' == *pData) ||_T('\f' == *pData)){pData++;}else{break;}}return pData;}const _tchar* _SkipStringBom(const _tchar* pData){
#ifdef _UNICODEwhile (0xFEFF == *pData){pData++;}#elsewhile (nullptr != _tcsstr(pData, "\xEF\xBB\xBF")){pData += 3;}#endifreturn pData;}bool _GetUnicodeCodePoint(const _tchar* pData, uint32_t* pCp, const _tchar** pEnd){_tchar szBuf[16] = { 0 };_tchar* pChEnd = nullptr;bool fResult = false;do{int count = 0;for (count = 0; count < 4; count++){_tchar ch = pData[count];if (0 == _istxdigit(ch)){break;}szBuf[count] = ch;}if (4 != count){break;}if (pCp){*pCp = _tcstol(szBuf, &pChEnd, 16);}fResult = true;} while (false);if (pEnd){*pEnd = pData;}return fResult;}std::string _CodePointToUtf8(uint32_t cp32){char szBuf[16] = { 0 };// 1字节 0xxxxxxxif (cp32 >= 0x00000000 && cp32 <= 0x0000007F){szBuf[0] = (uint8_t)cp32;szBuf[1] = 0;}// 2字节 110xxxxx 10xxxxxxif (cp32 >= 0x00000080 && cp32 <= 0x000007FF){szBuf[0] = ((cp32 >> 6) & 0x1F) | 0xC0;szBuf[1] = ((cp32 & 0x3F)) | 0x80;szBuf[2] = 0;}// 3字节 1110xxxx 10xxxxxx 10xxxxxxif (cp32 >= 0x00000800 && cp32 <= 0x0000FFFF){szBuf[0] = ((cp32 >> 12) & 0x0F) | 0xE0;szBuf[1] = ((cp32 >> 6) & 0x3F) | 0x80;szBuf[2] = ((cp32 & 0x3F)) | 0x80;szBuf[3] = 0;}// 4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxxif (cp32 >= 0x00010000 && cp32 <= 0x001FFFFF){szBuf[0] = ((cp32 >> 18) & 0x07) | 0xF0;szBuf[1] = ((cp32 >> 12) & 0x3F) | 0x80;szBuf[2] = ((cp32 >> 6) & 0x3F) | 0x80;szBuf[3] = ((cp32 & 0x3F)) | 0x80;szBuf[4] = 0;}// 5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxxif (cp32 >= 0x00200000 && cp32 <= 0x03FFFFFF){szBuf[0] = ((cp32 >> 24) & 0x03) | 0xF8;szBuf[1] = ((cp32 >> 18) & 0x3F) | 0x80;szBuf[2] = ((cp32 >> 12) & 0x3F) | 0x80;szBuf[3] = ((cp32 >> 6) & 0x3F) | 0x80;szBuf[4] = ((cp32 & 0x3F)) | 0x80;szBuf[5] = 0;}// 6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxxif (cp32 >= 0x04000000 && cp32 <= 0x7FFFFFFF){szBuf[0] = ((cp32 >> 30) & 0x01) | 0xFC;szBuf[1] = ((cp32 >> 24) & 0x3F) | 0x80;szBuf[2] = ((cp32 >> 18) & 0x3F) | 0x80;szBuf[3] = ((cp32 >> 12) & 0x3F) | 0x80;szBuf[4] = ((cp32 >> 6) & 0x3F) | 0x80;szBuf[5] = ((cp32 & 0x3F)) | 0x80;szBuf[6] = 0;}return szBuf;}int32_t _Utf8ToUtf16(const void* pData, size_t size/* = -1*/, std::string* pUtf8/* = nullptr*/, std::wstring* pUtf16/* = nullptr*/){const uint8_t* pCpData = (const uint8_t*)pData;std::wstring strOut16; // 输出UTF16std::string strOut8; // 输出UTF8uint32_t cp32 = 0; // UNICODE码点int32_t nByteCount = 0; // 字节计数int32_t nChCount = 0; // 字符计数bool fResult = true; // 操作结果bool fBom = true; // BOM(Byte Order Mark)if (pUtf8){strOut8 += *pUtf8;}if (pUtf16){strOut16 += *pUtf16;}while ((0 != *pCpData) && (0 != size)){uint8_t ch = *pCpData;// 普通 Ascii 也是 UTF-8 一部分if (ch < 0x7F){cp32 = ch;nChCount++;}else{// 检查 UTF-8 首字节if (0 == nByteCount){cp32 = 0;if (ch >= 0xC0){uint8_t u8CodeMask = 0xC0; // 11000000uint8_t u8DataMask = 0x1F; // 000xxxxxint nCount = 2; // 有效字节数量: 2-6// 检索字符使用的字节数量while(u8CodeMask <= 0xFC){uint8_t u8MaskMax = u8CodeMask | u8DataMask;if (ch >= u8CodeMask && ch <= u8MaskMax){cp32 = ch & u8DataMask;nByteCount = nCount;break;}u8CodeMask = (u8CodeMask >> 1) | 0x80;u8DataMask = u8DataMask >> 1;nCount++;}if (0 == nByteCount){fResult = false;break;}if (0xEF == ch && 3 == nByteCount){fBom = true;}nByteCount--;}else{fResult = false;break;}}else{// 非首字节掩码: 10xxxxxxif (0x80 != (ch & 0xC0)){fResult = false;break;}// BOM处理if (fBom){if (0xBB != ch && 2 == nByteCount){fBom = false;}if (0xBF != ch && 1 == nByteCount){fBom = false;}}cp32 = cp32 << 6;cp32 |= ch & 0x3F;nByteCount--;if (0 == nByteCount){// 跳过BOMif (fBom){fBom = false;pCpData++;continue;}nChCount++;}}}if (0 == nByteCount){if (pUtf8){strOut8 += _CodePointToUtf8(cp32);}if (pUtf16){if (cp32 < 0x10000){strOut16.push_back((uint16_t)(cp32 & 0xFFFF));}else{uint16_t cp = (uint16_t)(cp32 - 0x10000);uint16_t cp32Hi = (uint16_t)(cp >> 10) + 0xD800;uint16_t cp32Lo = (uint16_t)(cp & 0x3FF) + 0xDC00;strOut16.push_back(cp32Hi);strOut16.push_back(cp32Lo);}}}pCpData++;if (-1 != size){size--;}}if (!fResult){return -1;}if (pUtf8){*pUtf8 = std::move(strOut8);}if (pUtf16){*pUtf16 = std::move(strOut16);}return nChCount;}int32_t _Utf16ToUtf8(const void* pData, size_t size/* = -1*/, std::string* pUtf8/* = nullptr*/, std::wstring* pUtf16/* = nullptr*/){const uint16_t* pCpData = (const uint16_t*)pData;std::wstring strOut16; // 输出UTF16std::string strOut8; // 输出UTF8uint32_t cp32 = 0; // 32位码点uint16_t cp32Hi = 0; // 32位码点高10位uint16_t cp32Lo = 0; // 32位码点低10位uint16_t cp16 = 0; // 16位码点int32_t nByteCount = 0; // 字节计数int32_t nChCount = 0; // 字符计数bool fBigEndian = false; // 是否大端字节序bool fLittleEndian = false; // 是否小端字节序bool fResult = true; // 操作结果if (pUtf8){strOut8 += *pUtf8;}if (pUtf16){strOut16 += *pUtf16;}if (-1 != size){if ((size < 2) || (0 != (size % 2))){return -1;}}while ((0 != *pCpData) && (0 != size)){cp16 = *pCpData;// BOM检查if (0xFFFE == cp16 || 0xFEFF == cp16){if (0 == nByteCount){if (0xFFFE == cp16) // 大端字节序 (Big Endian){fBigEndian = true;}if (0xFEFF == cp16) // 小端字节序 (Little Endian){fLittleEndian = true;}}else{fResult = false;break;}// 不可能同时存在两种字节序if (fBigEndian && fLittleEndian){fResult = false;break;}pCpData++;if (-1 != size){size -= 2;}continue;}if (fBigEndian){cp16 = ((cp16 >> 8) | (cp16 << 8));}//检查是否为基本多语言平面(U+0000 - U+FFFF)if (!(cp16 >= 0xD800 && cp16 <= 0xDFFF)){if (cp32Hi > 0) // 高位码点后必须跟着低位码点{fResult = false;break;}cp32 = cp16;nChCount++;}else{if (0 == nByteCount){//检查是否为辅助平面(U+10000 - U+10FFFF)if (cp16 >= 0xD800 && cp16 <= 0xDBFF) //检查高位代理(0xD800 - 0xDBFF){cp32Hi = (cp16 - 0xD800);nByteCount = 1;}else{fResult = false;break;}}else{if (1 == nByteCount) // 高位码点后必须接着低位码点{if (cp16 >= 0xDC00 && cp16 <= 0xDFFF) //检查低位代理(0xDC00 - 0xDFFF){cp32Lo = (cp16 - 0xDC00);cp32 = 0x10000 + ((uint32_t)cp32Hi << 10 | cp32Lo);cp32Lo = 0;cp32Hi = 0;}else{fResult = false;break;}}nByteCount--;if (0 == nByteCount){nChCount++;}}}// 转换为 UTF 编码if (0 == nByteCount){if (pUtf8){strOut8 += _CodePointToUtf8(cp32);}if (pUtf16){if (cp32 < 0x10000){strOut16.push_back((uint16_t)(cp32 & 0xFFFF));}else{uint16_t cp = (uint16_t)(cp32 - 0x10000);uint16_t cpHi = (uint16_t)(cp >> 10) + 0xD800;uint16_t cpLo = (uint16_t)(cp & 0x3FF) + 0xDC00;strOut16.push_back(cpHi);strOut16.push_back(cpLo);}}}pCpData++;if (-1 != size){size -= 2;}}if (!fResult){return -1;}if (pUtf8){*pUtf8 = std::move(strOut8);}if (pUtf16){*pUtf16 = std::move(strOut16);}return nChCount;}
}
main.cpp
#include <iostream>
#include <tchar.h>
#include "FCJson.h"
#include <locale>#define TEST_TEXT _T(R"(
{"4": ["D:\\FC_Gitee\\fc-json\\FCJson","D:\\FC_Gitee\\fc-json\\FCJson","D:\\FC_Gitee\\fc-json\\FCJson","D:\\FC_Gitee\\fc-json\\FCJson","D:\\FC_Gitee\\fc-json\\FCJson","D:\\FC_Gitee\\fc-json\\FCJson","D:\\FC_Gitee\\fc-json\\FCJson","D:\\FC_Gitee\\fc-json\\FCJson","D:\\FC_Gitee\\fc-json\\FCJson","D:\\FC_Gitee\\fc-json\\FCJson"],"addr": "China","age": 30,"array": [true,1024,"FlameCyclone",{"FCJson": 256},[1,2,3]],"bool": true,"float": 3.1415,"int": 3.0,"name": "Flame\\Cyclone","null": null,"object": {"age": 30,"name": "Flame\\\\Cyclone"},"string": "string"
}
)")int main()
{setlocale(LC_ALL, "");FCJson::JsonValue val;val = 1024;val = 1024ll;try{val.ParseFromFile(_T("data.json"));}catch (const FCJson::JsonException e){return 0;}val.DumpToFile(_T("2.json"), 4, FCJson::JsonEncoding::eUtf8, 1);return 0;
}