refactor: drop jsonsl in favour of RapidJSON (#6138)
This commit is contained in:
parent
0457dcb6a8
commit
2130eb941a
|
@ -50,3 +50,7 @@
|
||||||
[submodule "third-party/small"]
|
[submodule "third-party/small"]
|
||||||
path = third-party/small
|
path = third-party/small
|
||||||
url = https://github.com/transmission/small.git
|
url = https://github.com/transmission/small.git
|
||||||
|
[submodule "third-party/rapidjson"]
|
||||||
|
path = third-party/rapidjson
|
||||||
|
url = https://github.com/transmission/rapidjson.git
|
||||||
|
fetchRecurseSubmodules = false
|
||||||
|
|
|
@ -207,6 +207,7 @@ endif()
|
||||||
set(CMAKE_FOLDER "third-party")
|
set(CMAKE_FOLDER "third-party")
|
||||||
find_package(FastFloat)
|
find_package(FastFloat)
|
||||||
find_package(Fmt)
|
find_package(Fmt)
|
||||||
|
find_package(RapidJSON)
|
||||||
find_package(Small)
|
find_package(Small)
|
||||||
find_package(UtfCpp)
|
find_package(UtfCpp)
|
||||||
find_package(WideInteger)
|
find_package(WideInteger)
|
||||||
|
@ -507,7 +508,6 @@ target_compile_definitions(miniupnpc::libminiupnpc
|
||||||
SYSTEM_MINIUPNP
|
SYSTEM_MINIUPNP
|
||||||
$<$<VERSION_LESS:${MINIUPNPC_VERSION},1.7>:MINIUPNPC_API_VERSION=${MINIUPNPC_API_VERSION}>) # API version macro was only added in 1.7
|
$<$<VERSION_LESS:${MINIUPNPC_VERSION},1.7>:MINIUPNPC_API_VERSION=${MINIUPNPC_API_VERSION}>) # API version macro was only added in 1.7
|
||||||
|
|
||||||
add_subdirectory(third-party/jsonsl)
|
|
||||||
add_subdirectory(third-party/wildmat)
|
add_subdirectory(third-party/wildmat)
|
||||||
|
|
||||||
tr_add_external_auto_library(DHT dht dht
|
tr_add_external_auto_library(DHT dht dht
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 51;
|
objectVersion = 54;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
@ -350,11 +350,8 @@
|
||||||
C1639A7D1A55F57200E42033 /* cencode.h in Headers */ = {isa = PBXBuildFile; fileRef = C1639A7B1A55F57200E42033 /* cencode.h */; };
|
C1639A7D1A55F57200E42033 /* cencode.h in Headers */ = {isa = PBXBuildFile; fileRef = C1639A7B1A55F57200E42033 /* cencode.h */; };
|
||||||
C17740D5273A002C00E455D2 /* web-utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = C17740D3273A002C00E455D2 /* web-utils.cc */; };
|
C17740D5273A002C00E455D2 /* web-utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = C17740D3273A002C00E455D2 /* web-utils.cc */; };
|
||||||
C17740D6273A002C00E455D2 /* web-utils.h in Headers */ = {isa = PBXBuildFile; fileRef = C17740D4273A002C00E455D2 /* web-utils.h */; };
|
C17740D6273A002C00E455D2 /* web-utils.h in Headers */ = {isa = PBXBuildFile; fileRef = C17740D4273A002C00E455D2 /* web-utils.h */; };
|
||||||
C1846BA0294F7A6300A98F30 /* jsonsl.h in Headers */ = {isa = PBXBuildFile; fileRef = C1846B86294F780700A98F30 /* jsonsl.h */; };
|
|
||||||
C1846BA1294F7A6300A98F30 /* jsonsl.c in Sources */ = {isa = PBXBuildFile; fileRef = C1846B85294F780700A98F30 /* jsonsl.c */; };
|
|
||||||
C1846BA2294F7A6800A98F30 /* wildmat.c in Sources */ = {isa = PBXBuildFile; fileRef = C1846B88294F781800A98F30 /* wildmat.c */; };
|
C1846BA2294F7A6800A98F30 /* wildmat.c in Sources */ = {isa = PBXBuildFile; fileRef = C1846B88294F781800A98F30 /* wildmat.c */; };
|
||||||
C1846BA3294F7A6800A98F30 /* wildmat.h in Headers */ = {isa = PBXBuildFile; fileRef = C1846B87294F781800A98F30 /* wildmat.h */; };
|
C1846BA3294F7A6800A98F30 /* wildmat.h in Headers */ = {isa = PBXBuildFile; fileRef = C1846B87294F781800A98F30 /* wildmat.h */; };
|
||||||
C1846BA8294F7B5700A98F30 /* libjsonsl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C1846B91294F796A00A98F30 /* libjsonsl.a */; };
|
|
||||||
C1846BA9294F7B5A00A98F30 /* libwildmat.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C1846B9E294F7A3400A98F30 /* libwildmat.a */; };
|
C1846BA9294F7B5A00A98F30 /* libwildmat.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C1846B9E294F7A3400A98F30 /* libwildmat.a */; };
|
||||||
C1BF7BA81F2A3CB7008E88A7 /* upnpdev.c in Sources */ = {isa = PBXBuildFile; fileRef = C1BF7BA71F2A3CB7008E88A7 /* upnpdev.c */; };
|
C1BF7BA81F2A3CB7008E88A7 /* upnpdev.c in Sources */ = {isa = PBXBuildFile; fileRef = C1BF7BA71F2A3CB7008E88A7 /* upnpdev.c */; };
|
||||||
C1BF7BAA1F2A3CCE008E88A7 /* upnpdev.h in Headers */ = {isa = PBXBuildFile; fileRef = C1BF7BA91F2A3CCE008E88A7 /* upnpdev.h */; };
|
C1BF7BAA1F2A3CCE008E88A7 /* upnpdev.h in Headers */ = {isa = PBXBuildFile; fileRef = C1BF7BA91F2A3CCE008E88A7 /* upnpdev.h */; };
|
||||||
|
@ -548,13 +545,6 @@
|
||||||
remoteGlobalIDString = C1639A6E1A55F4D600E42033;
|
remoteGlobalIDString = C1639A6E1A55F4D600E42033;
|
||||||
remoteInfo = b64;
|
remoteInfo = b64;
|
||||||
};
|
};
|
||||||
C1846BA4294F7B1100A98F30 /* PBXContainerItemProxy */ = {
|
|
||||||
isa = PBXContainerItemProxy;
|
|
||||||
containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
|
|
||||||
proxyType = 1;
|
|
||||||
remoteGlobalIDString = C1846B90294F796A00A98F30;
|
|
||||||
remoteInfo = jsonsl;
|
|
||||||
};
|
|
||||||
C1846BA6294F7B1400A98F30 /* PBXContainerItemProxy */ = {
|
C1846BA6294F7B1400A98F30 /* PBXContainerItemProxy */ = {
|
||||||
isa = PBXContainerItemProxy;
|
isa = PBXContainerItemProxy;
|
||||||
containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
|
containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
|
||||||
|
@ -1163,11 +1153,8 @@
|
||||||
C1639A7B1A55F57200E42033 /* cencode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = cencode.h; path = include/b64/cencode.h; sourceTree = "<group>"; };
|
C1639A7B1A55F57200E42033 /* cencode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = cencode.h; path = include/b64/cencode.h; sourceTree = "<group>"; };
|
||||||
C17740D3273A002C00E455D2 /* web-utils.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "web-utils.cc"; sourceTree = "<group>"; };
|
C17740D3273A002C00E455D2 /* web-utils.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "web-utils.cc"; sourceTree = "<group>"; };
|
||||||
C17740D4273A002C00E455D2 /* web-utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "web-utils.h"; sourceTree = "<group>"; };
|
C17740D4273A002C00E455D2 /* web-utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "web-utils.h"; sourceTree = "<group>"; };
|
||||||
C1846B85294F780700A98F30 /* jsonsl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = jsonsl.c; sourceTree = "<group>"; };
|
|
||||||
C1846B86294F780700A98F30 /* jsonsl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = jsonsl.h; sourceTree = "<group>"; };
|
|
||||||
C1846B87294F781800A98F30 /* wildmat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wildmat.h; sourceTree = "<group>"; };
|
C1846B87294F781800A98F30 /* wildmat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wildmat.h; sourceTree = "<group>"; };
|
||||||
C1846B88294F781800A98F30 /* wildmat.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = wildmat.c; sourceTree = "<group>"; };
|
C1846B88294F781800A98F30 /* wildmat.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = wildmat.c; sourceTree = "<group>"; };
|
||||||
C1846B91294F796A00A98F30 /* libjsonsl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjsonsl.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
C1846B9E294F7A3400A98F30 /* libwildmat.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libwildmat.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
C1846B9E294F7A3400A98F30 /* libwildmat.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libwildmat.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
C1BF7BA71F2A3CB7008E88A7 /* upnpdev.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = upnpdev.c; sourceTree = "<group>"; };
|
C1BF7BA71F2A3CB7008E88A7 /* upnpdev.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = upnpdev.c; sourceTree = "<group>"; };
|
||||||
C1BF7BA91F2A3CCE008E88A7 /* upnpdev.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = upnpdev.h; sourceTree = "<group>"; };
|
C1BF7BA91F2A3CCE008E88A7 /* upnpdev.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = upnpdev.h; sourceTree = "<group>"; };
|
||||||
|
@ -1345,7 +1332,6 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
C1846BA9294F7B5A00A98F30 /* libwildmat.a in Frameworks */,
|
C1846BA9294F7B5A00A98F30 /* libwildmat.a in Frameworks */,
|
||||||
C1846BA8294F7B5700A98F30 /* libjsonsl.a in Frameworks */,
|
|
||||||
C3D9062F27B7F7E200EF2386 /* libpsl.a in Frameworks */,
|
C3D9062F27B7F7E200EF2386 /* libpsl.a in Frameworks */,
|
||||||
C3CEBBFC2794A12200683BE0 /* libdeflate.a in Frameworks */,
|
C3CEBBFC2794A12200683BE0 /* libdeflate.a in Frameworks */,
|
||||||
C1639A741A55F4E000E42033 /* libb64.a in Frameworks */,
|
C1639A741A55F4E000E42033 /* libb64.a in Frameworks */,
|
||||||
|
@ -1388,13 +1374,6 @@
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
C1846B8F294F796A00A98F30 /* Frameworks */ = {
|
|
||||||
isa = PBXFrameworksBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
C1846B99294F7A3400A98F30 /* Frameworks */ = {
|
C1846B99294F7A3400A98F30 /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
@ -1583,7 +1562,6 @@
|
||||||
C1639A6F1A55F4D600E42033 /* libb64.a */,
|
C1639A6F1A55F4D600E42033 /* libb64.a */,
|
||||||
C3CEBBA927949CA000683BE0 /* libdeflate.a */,
|
C3CEBBA927949CA000683BE0 /* libdeflate.a */,
|
||||||
C3D9062127B7E3C900EF2386 /* libpsl.a */,
|
C3D9062127B7E3C900EF2386 /* libpsl.a */,
|
||||||
C1846B91294F796A00A98F30 /* libjsonsl.a */,
|
|
||||||
C1846B9E294F7A3400A98F30 /* libwildmat.a */,
|
C1846B9E294F7A3400A98F30 /* libwildmat.a */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
|
@ -1607,7 +1585,6 @@
|
||||||
3C7A11880D0B2E6700B5701F /* libnatpmp */,
|
3C7A11880D0B2E6700B5701F /* libnatpmp */,
|
||||||
C3D9061627B7E12F00EF2386 /* libpsl */,
|
C3D9061627B7E12F00EF2386 /* libpsl */,
|
||||||
C1639A751A55F52800E42033 /* b64 */,
|
C1639A751A55F52800E42033 /* b64 */,
|
||||||
C1846B81294F774D00A98F30 /* jsonsl */,
|
|
||||||
C1846B82294F777000A98F30 /* wildmat */,
|
C1846B82294F777000A98F30 /* wildmat */,
|
||||||
4DDBB71509E16B3F00284745 /* Libraries */,
|
4DDBB71509E16B3F00284745 /* Libraries */,
|
||||||
A2F35BBA15C5A0A100EBF632 /* Frameworks */,
|
A2F35BBA15C5A0A100EBF632 /* Frameworks */,
|
||||||
|
@ -2085,16 +2062,6 @@
|
||||||
path = "third-party/libb64";
|
path = "third-party/libb64";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
C1846B81294F774D00A98F30 /* jsonsl */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
C1846B85294F780700A98F30 /* jsonsl.c */,
|
|
||||||
C1846B86294F780700A98F30 /* jsonsl.h */,
|
|
||||||
);
|
|
||||||
name = jsonsl;
|
|
||||||
path = "third-party/jsonsl";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
C1846B82294F777000A98F30 /* wildmat */ = {
|
C1846B82294F777000A98F30 /* wildmat */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -2402,14 +2369,6 @@
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
C1846B8D294F796A00A98F30 /* Headers */ = {
|
|
||||||
isa = PBXHeadersBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
C1846BA0294F7A6300A98F30 /* jsonsl.h in Headers */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
C1846B97294F7A3400A98F30 /* Headers */ = {
|
C1846B97294F7A3400A98F30 /* Headers */ = {
|
||||||
isa = PBXHeadersBuildPhase;
|
isa = PBXHeadersBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
@ -2493,7 +2452,6 @@
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
C1846BA7294F7B1400A98F30 /* PBXTargetDependency */,
|
C1846BA7294F7B1400A98F30 /* PBXTargetDependency */,
|
||||||
C1846BA5294F7B1100A98F30 /* PBXTargetDependency */,
|
|
||||||
C33E46A22794B3CC0090F2AA /* PBXTargetDependency */,
|
C33E46A22794B3CC0090F2AA /* PBXTargetDependency */,
|
||||||
A226FDB10D0CDF6E005A7F71 /* PBXTargetDependency */,
|
A226FDB10D0CDF6E005A7F71 /* PBXTargetDependency */,
|
||||||
BE1183760CE161040002D0F3 /* PBXTargetDependency */,
|
BE1183760CE161040002D0F3 /* PBXTargetDependency */,
|
||||||
|
@ -2688,23 +2646,6 @@
|
||||||
productReference = C1639A6F1A55F4D600E42033 /* libb64.a */;
|
productReference = C1639A6F1A55F4D600E42033 /* libb64.a */;
|
||||||
productType = "com.apple.product-type.library.static";
|
productType = "com.apple.product-type.library.static";
|
||||||
};
|
};
|
||||||
C1846B90294F796A00A98F30 /* jsonsl */ = {
|
|
||||||
isa = PBXNativeTarget;
|
|
||||||
buildConfigurationList = C1846B92294F796C00A98F30 /* Build configuration list for PBXNativeTarget "jsonsl" */;
|
|
||||||
buildPhases = (
|
|
||||||
C1846B8D294F796A00A98F30 /* Headers */,
|
|
||||||
C1846B8E294F796A00A98F30 /* Sources */,
|
|
||||||
C1846B8F294F796A00A98F30 /* Frameworks */,
|
|
||||||
);
|
|
||||||
buildRules = (
|
|
||||||
);
|
|
||||||
dependencies = (
|
|
||||||
);
|
|
||||||
name = jsonsl;
|
|
||||||
productName = jsonsl;
|
|
||||||
productReference = C1846B91294F796A00A98F30 /* libjsonsl.a */;
|
|
||||||
productType = "com.apple.product-type.library.static";
|
|
||||||
};
|
|
||||||
C1846B96294F7A3400A98F30 /* wildmat */ = {
|
C1846B96294F7A3400A98F30 /* wildmat */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = C1846B9A294F7A3400A98F30 /* Build configuration list for PBXNativeTarget "wildmat" */;
|
buildConfigurationList = C1846B9A294F7A3400A98F30 /* Build configuration list for PBXNativeTarget "wildmat" */;
|
||||||
|
@ -2718,7 +2659,7 @@
|
||||||
dependencies = (
|
dependencies = (
|
||||||
);
|
);
|
||||||
name = wildmat;
|
name = wildmat;
|
||||||
productName = jsonsl;
|
productName = wildmat;
|
||||||
productReference = C1846B9E294F7A3400A98F30 /* libwildmat.a */;
|
productReference = C1846B9E294F7A3400A98F30 /* libwildmat.a */;
|
||||||
productType = "com.apple.product-type.library.static";
|
productType = "com.apple.product-type.library.static";
|
||||||
};
|
};
|
||||||
|
@ -2827,9 +2768,6 @@
|
||||||
C1639A6E1A55F4D600E42033 = {
|
C1639A6E1A55F4D600E42033 = {
|
||||||
CreatedOnToolsVersion = 6.1.1;
|
CreatedOnToolsVersion = 6.1.1;
|
||||||
};
|
};
|
||||||
C1846B90294F796A00A98F30 = {
|
|
||||||
CreatedOnToolsVersion = 14.1;
|
|
||||||
};
|
|
||||||
C3D9062027B7E3C900EF2386 = {
|
C3D9062027B7E3C900EF2386 = {
|
||||||
CreatedOnToolsVersion = 13.0;
|
CreatedOnToolsVersion = 13.0;
|
||||||
};
|
};
|
||||||
|
@ -2874,7 +2812,6 @@
|
||||||
C1639A6E1A55F4D600E42033 /* b64 */,
|
C1639A6E1A55F4D600E42033 /* b64 */,
|
||||||
C3CEBB9F27949CA000683BE0 /* deflate */,
|
C3CEBB9F27949CA000683BE0 /* deflate */,
|
||||||
C3D9062027B7E3C900EF2386 /* psl */,
|
C3D9062027B7E3C900EF2386 /* psl */,
|
||||||
C1846B90294F796A00A98F30 /* jsonsl */,
|
|
||||||
C1846B96294F7A3400A98F30 /* wildmat */,
|
C1846B96294F7A3400A98F30 /* wildmat */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -3328,14 +3265,6 @@
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
C1846B8E294F796A00A98F30 /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
C1846BA1294F7A6300A98F30 /* jsonsl.c in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
C1846B98294F7A3400A98F30 /* Sources */ = {
|
C1846B98294F7A3400A98F30 /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
@ -3458,11 +3387,6 @@
|
||||||
target = C1639A6E1A55F4D600E42033 /* b64 */;
|
target = C1639A6E1A55F4D600E42033 /* b64 */;
|
||||||
targetProxy = C165AB8C1A55FAA900D37711 /* PBXContainerItemProxy */;
|
targetProxy = C165AB8C1A55FAA900D37711 /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
C1846BA5294F7B1100A98F30 /* PBXTargetDependency */ = {
|
|
||||||
isa = PBXTargetDependency;
|
|
||||||
target = C1846B90294F796A00A98F30 /* jsonsl */;
|
|
||||||
targetProxy = C1846BA4294F7B1100A98F30 /* PBXContainerItemProxy */;
|
|
||||||
};
|
|
||||||
C1846BA7294F7B1400A98F30 /* PBXTargetDependency */ = {
|
C1846BA7294F7B1400A98F30 /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
target = C1846B96294F7A3400A98F30 /* wildmat */;
|
target = C1846B96294F7A3400A98F30 /* wildmat */;
|
||||||
|
@ -3757,7 +3681,7 @@
|
||||||
"third-party/libpsl/include",
|
"third-party/libpsl/include",
|
||||||
"third-party/libutp/include",
|
"third-party/libutp/include",
|
||||||
"third-party/utfcpp/source",
|
"third-party/utfcpp/source",
|
||||||
"third-party/jsonsl",
|
"third-party/rapidjson/include",
|
||||||
"third-party/wildmat",
|
"third-party/wildmat",
|
||||||
);
|
);
|
||||||
OTHER_CFLAGS = (
|
OTHER_CFLAGS = (
|
||||||
|
@ -3766,6 +3690,7 @@
|
||||||
"-D__TRANSMISSION__",
|
"-D__TRANSMISSION__",
|
||||||
"-DWIDE_INTEGER_DISABLE_FLOAT_INTEROP",
|
"-DWIDE_INTEGER_DISABLE_FLOAT_INTEROP",
|
||||||
"-DWIDE_INTEGER_DISABLE_IOSTREAM",
|
"-DWIDE_INTEGER_DISABLE_IOSTREAM",
|
||||||
|
"-DRAPIDJSON_HAS_STDSTRING=1",
|
||||||
"-DHAVE_FLOCK",
|
"-DHAVE_FLOCK",
|
||||||
"-DHAVE_STRLCPY",
|
"-DHAVE_STRLCPY",
|
||||||
);
|
);
|
||||||
|
@ -3776,7 +3701,7 @@
|
||||||
"third-party/fast_float/include",
|
"third-party/fast_float/include",
|
||||||
"third-party/fmt/include",
|
"third-party/fmt/include",
|
||||||
"third-party/small/include",
|
"third-party/small/include",
|
||||||
"third-party/jsonsl",
|
"third-party/rapidjson/include",
|
||||||
"third-party/libb64/include",
|
"third-party/libb64/include",
|
||||||
"third-party/libdeflate",
|
"third-party/libdeflate",
|
||||||
"third-party/libevent/include",
|
"third-party/libevent/include",
|
||||||
|
@ -4016,7 +3941,7 @@
|
||||||
"third-party/libpsl/include",
|
"third-party/libpsl/include",
|
||||||
"third-party/libutp/include",
|
"third-party/libutp/include",
|
||||||
"third-party/utfcpp/source",
|
"third-party/utfcpp/source",
|
||||||
"third-party/jsonsl",
|
"third-party/rapidjson/include",
|
||||||
"third-party/wildmat",
|
"third-party/wildmat",
|
||||||
);
|
);
|
||||||
OTHER_CFLAGS = (
|
OTHER_CFLAGS = (
|
||||||
|
@ -4025,6 +3950,7 @@
|
||||||
"-D__TRANSMISSION__",
|
"-D__TRANSMISSION__",
|
||||||
"-DWIDE_INTEGER_DISABLE_FLOAT_INTEROP",
|
"-DWIDE_INTEGER_DISABLE_FLOAT_INTEROP",
|
||||||
"-DWIDE_INTEGER_DISABLE_IOSTREAM",
|
"-DWIDE_INTEGER_DISABLE_IOSTREAM",
|
||||||
|
"-DRAPIDJSON_HAS_STDSTRING=1",
|
||||||
"-DHAVE_FLOCK",
|
"-DHAVE_FLOCK",
|
||||||
"-DHAVE_STRLCPY",
|
"-DHAVE_STRLCPY",
|
||||||
);
|
);
|
||||||
|
@ -4035,7 +3961,7 @@
|
||||||
"third-party/fast_float/include",
|
"third-party/fast_float/include",
|
||||||
"third-party/fmt/include",
|
"third-party/fmt/include",
|
||||||
"third-party/small/include",
|
"third-party/small/include",
|
||||||
"third-party/jsonsl",
|
"third-party/rapidjson/include",
|
||||||
"third-party/libb64/include",
|
"third-party/libb64/include",
|
||||||
"third-party/libdeflate",
|
"third-party/libdeflate",
|
||||||
"third-party/libevent/include",
|
"third-party/libevent/include",
|
||||||
|
@ -4347,7 +4273,7 @@
|
||||||
"third-party/libpsl/include",
|
"third-party/libpsl/include",
|
||||||
"third-party/libutp/include",
|
"third-party/libutp/include",
|
||||||
"third-party/utfcpp/source",
|
"third-party/utfcpp/source",
|
||||||
"third-party/jsonsl",
|
"third-party/rapidjson/include",
|
||||||
"third-party/wildmat",
|
"third-party/wildmat",
|
||||||
);
|
);
|
||||||
OTHER_CFLAGS = (
|
OTHER_CFLAGS = (
|
||||||
|
@ -4356,6 +4282,7 @@
|
||||||
"-D__TRANSMISSION__",
|
"-D__TRANSMISSION__",
|
||||||
"-DWIDE_INTEGER_DISABLE_FLOAT_INTEROP",
|
"-DWIDE_INTEGER_DISABLE_FLOAT_INTEROP",
|
||||||
"-DWIDE_INTEGER_DISABLE_IOSTREAM",
|
"-DWIDE_INTEGER_DISABLE_IOSTREAM",
|
||||||
|
"-DRAPIDJSON_HAS_STDSTRING=1",
|
||||||
"-DHAVE_FLOCK",
|
"-DHAVE_FLOCK",
|
||||||
"-DHAVE_STRLCPY",
|
"-DHAVE_STRLCPY",
|
||||||
);
|
);
|
||||||
|
@ -4366,7 +4293,7 @@
|
||||||
"third-party/fast_float/include",
|
"third-party/fast_float/include",
|
||||||
"third-party/fmt/include",
|
"third-party/fmt/include",
|
||||||
"third-party/small/include",
|
"third-party/small/include",
|
||||||
"third-party/jsonsl",
|
"third-party/rapidjson/include",
|
||||||
"third-party/libb64/include",
|
"third-party/libb64/include",
|
||||||
"third-party/libdeflate",
|
"third-party/libdeflate",
|
||||||
"third-party/libevent/include",
|
"third-party/libevent/include",
|
||||||
|
@ -4695,36 +4622,6 @@
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
C1846B93294F796C00A98F30 /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
CLANG_ENABLE_OBJC_ARC = NO;
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
|
|
||||||
GENERATE_MASTER_OBJECT_FILE = YES;
|
|
||||||
PRODUCT_NAME = jsonsl;
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
C1846B94294F796C00A98F30 /* Release - Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
CLANG_ENABLE_OBJC_ARC = NO;
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
|
|
||||||
GENERATE_MASTER_OBJECT_FILE = YES;
|
|
||||||
PRODUCT_NAME = jsonsl;
|
|
||||||
};
|
|
||||||
name = "Release - Debug";
|
|
||||||
};
|
|
||||||
C1846B95294F796C00A98F30 /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
CLANG_ENABLE_OBJC_ARC = NO;
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
|
|
||||||
GENERATE_MASTER_OBJECT_FILE = YES;
|
|
||||||
PRODUCT_NAME = jsonsl;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
C1846B9B294F7A3400A98F30 /* Debug */ = {
|
C1846B9B294F7A3400A98F30 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
@ -5167,16 +5064,6 @@
|
||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Debug;
|
defaultConfigurationName = Debug;
|
||||||
};
|
};
|
||||||
C1846B92294F796C00A98F30 /* Build configuration list for PBXNativeTarget "jsonsl" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
C1846B93294F796C00A98F30 /* Debug */,
|
|
||||||
C1846B94294F796C00A98F30 /* Release - Debug */,
|
|
||||||
C1846B95294F796C00A98F30 /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Debug;
|
|
||||||
};
|
|
||||||
C1846B9A294F7A3400A98F30 /* Build configuration list for PBXNativeTarget "wildmat" */ = {
|
C1846B9A294F7A3400A98F30 /* Build configuration list for PBXNativeTarget "wildmat" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
add_library(RapidJSON INTERFACE IMPORTED)
|
||||||
|
|
||||||
|
target_include_directories(RapidJSON
|
||||||
|
INTERFACE
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../third-party/rapidjson/include)
|
||||||
|
|
||||||
|
target_compile_definitions(RapidJSON
|
||||||
|
INTERFACE
|
||||||
|
RAPIDJSON_HAS_STDSTRING=1)
|
|
@ -287,7 +287,7 @@ target_link_libraries(${TR_NAME}
|
||||||
${LIBM_LIBRARY}
|
${LIBM_LIBRARY}
|
||||||
${LIBQUOTA_LIBRARY}
|
${LIBQUOTA_LIBRARY}
|
||||||
${TR_NETWORK_LIBRARIES}
|
${TR_NETWORK_LIBRARIES}
|
||||||
jsonsl
|
RapidJSON
|
||||||
utf8::cpp
|
utf8::cpp
|
||||||
wildmat
|
wildmat
|
||||||
WideInteger::WideInteger
|
WideInteger::WideInteger
|
||||||
|
|
|
@ -5,435 +5,256 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cctype>
|
|
||||||
#include <cerrno> /* EILSEQ, EINVAL */
|
#include <cerrno> /* EILSEQ, EINVAL */
|
||||||
#include <cmath> /* fabs() */
|
|
||||||
#include <cstddef> // std::byte
|
#include <cstddef> // std::byte
|
||||||
#include <cstdint> // uint16_t
|
#include <cstdint> // uint16_t
|
||||||
#include <cstdlib>
|
#include <optional>
|
||||||
#include <cstring>
|
#include <stack>
|
||||||
#include <deque>
|
|
||||||
#include <iterator> // std::back_inserter
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <variant>
|
||||||
#define UTF_CPP_CPLUSPLUS 201703L
|
|
||||||
#include <utf8.h>
|
|
||||||
|
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <fmt/compile.h>
|
|
||||||
|
|
||||||
#include <jsonsl.h>
|
// RapidJSON SIMD optimisations
|
||||||
|
#ifdef __SSE2__
|
||||||
|
#define RAPIDJSON_SSE2
|
||||||
|
#endif
|
||||||
|
#ifdef __SSE4_2__
|
||||||
|
#define RAPIDJSON_SSE42
|
||||||
|
#endif
|
||||||
|
#ifdef __ARM_NEON
|
||||||
|
#define RAPIDJSON_NEON
|
||||||
|
#endif
|
||||||
|
#include <rapidjson/encodedstream.h>
|
||||||
|
#include <rapidjson/encodings.h>
|
||||||
|
#include <rapidjson/error/en.h>
|
||||||
|
#include <rapidjson/memorystream.h>
|
||||||
|
#include <rapidjson/prettywriter.h>
|
||||||
|
#include <rapidjson/reader.h>
|
||||||
|
#include <rapidjson/stringbuffer.h>
|
||||||
|
#include <rapidjson/writer.h>
|
||||||
|
|
||||||
#define LIBTRANSMISSION_VARIANT_MODULE
|
#define LIBTRANSMISSION_VARIANT_MODULE
|
||||||
|
|
||||||
#include "libtransmission/error.h"
|
#include "libtransmission/error.h"
|
||||||
#include "libtransmission/quark.h"
|
#include "libtransmission/quark.h"
|
||||||
#include "libtransmission/tr-assert.h"
|
#include "libtransmission/tr-assert.h"
|
||||||
#include "libtransmission/tr-buffer.h"
|
|
||||||
#include "libtransmission/utils.h"
|
#include "libtransmission/utils.h"
|
||||||
#include "libtransmission/variant.h"
|
#include "libtransmission/variant.h"
|
||||||
|
|
||||||
using namespace std::literals;
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
[[nodiscard]] constexpr size_t variant_size(tr_variant const& var) noexcept
|
|
||||||
{
|
|
||||||
switch (var.index())
|
|
||||||
{
|
|
||||||
case tr_variant::MapIndex:
|
|
||||||
return std::size(*var.get_if<tr_variant::Map>());
|
|
||||||
|
|
||||||
case tr_variant::VectorIndex:
|
|
||||||
return std::size(*var.get_if<tr_variant::Vector>());
|
|
||||||
|
|
||||||
default:
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace parse_helpers
|
namespace parse_helpers
|
||||||
{
|
{
|
||||||
/* arbitrary value... this is much deeper than our code goes */
|
struct json_to_variant_handler : public rapidjson::BaseReaderHandler<>
|
||||||
auto constexpr MaxDepth = size_t{ 64 };
|
|
||||||
|
|
||||||
struct json_wrapper_data
|
|
||||||
{
|
{
|
||||||
bool has_content;
|
static_assert(std::is_same_v<Ch, char>);
|
||||||
size_t size;
|
|
||||||
std::string_view key;
|
explicit json_to_variant_handler(tr_variant* const top)
|
||||||
std::string keybuf;
|
{
|
||||||
std::string strbuf;
|
stack_.emplace(top);
|
||||||
tr_error* error;
|
}
|
||||||
std::deque<tr_variant*> stack;
|
|
||||||
tr_variant* top;
|
bool Null()
|
||||||
bool inplace = false;
|
{
|
||||||
|
tr_variantInitQuark(get_leaf(), TR_KEY_NONE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bool(bool const val)
|
||||||
|
{
|
||||||
|
tr_variantInitBool(get_leaf(), val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Int(int const val)
|
||||||
|
{
|
||||||
|
return Int64(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Uint(unsigned const val)
|
||||||
|
{
|
||||||
|
return Uint64(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Int64(int64_t const val)
|
||||||
|
{
|
||||||
|
tr_variantInitInt(get_leaf(), val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Uint64(uint64_t const val)
|
||||||
|
{
|
||||||
|
return Int64(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Double(double const val)
|
||||||
|
{
|
||||||
|
tr_variantInitReal(get_leaf(), val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String(Ch const* const str, rapidjson::SizeType const len, bool const copy)
|
||||||
|
{
|
||||||
|
if (copy)
|
||||||
|
{
|
||||||
|
tr_variantInitStr(get_leaf(), { str, len });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tr_variantInitStrView(get_leaf(), { str, len });
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StartObject()
|
||||||
|
{
|
||||||
|
tr_variantInitDict(push_stack(), prealloc_guess());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Key(Ch const* const str, rapidjson::SizeType const len, bool const copy)
|
||||||
|
{
|
||||||
|
if (copy)
|
||||||
|
{
|
||||||
|
key_buf_.assign(str, len);
|
||||||
|
cur_key_ = key_buf_;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cur_key_ = std::string_view{ str, len };
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EndObject(rapidjson::SizeType const len)
|
||||||
|
{
|
||||||
|
pop_stack(len);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StartArray()
|
||||||
|
{
|
||||||
|
tr_variantInitList(push_stack(), prealloc_guess());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EndArray(rapidjson::SizeType const len)
|
||||||
|
{
|
||||||
|
pop_stack(len);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
[[nodiscard]] size_t prealloc_guess() const noexcept
|
||||||
|
{
|
||||||
|
auto const depth = std::size(stack_);
|
||||||
|
return depth < MaxDepth ? prealloc_guess_[depth] : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr_variant* push_stack() noexcept
|
||||||
|
{
|
||||||
|
return stack_.emplace(get_leaf());
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_stack(rapidjson::SizeType const len) noexcept
|
||||||
|
{
|
||||||
|
#ifdef TR_ENABLE_ASSERTS
|
||||||
|
if (auto* top = stack_.top(); top->holds_alternative<tr_variant::Vector>())
|
||||||
|
{
|
||||||
|
TR_ASSERT(std::size(*top->get_if<tr_variant::Vector>()) == len);
|
||||||
|
}
|
||||||
|
else if (top->holds_alternative<tr_variant::Map>())
|
||||||
|
{
|
||||||
|
TR_ASSERT(std::size(*top->get_if<tr_variant::Map>()) == len);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto const depth = std::size(stack_);
|
||||||
|
stack_.pop();
|
||||||
|
TR_ASSERT(!std::empty(stack_));
|
||||||
|
if (depth < MaxDepth)
|
||||||
|
{
|
||||||
|
prealloc_guess_[depth] = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tr_variant* get_leaf()
|
||||||
|
{
|
||||||
|
auto* const parent = stack_.top();
|
||||||
|
TR_ASSERT(parent != nullptr);
|
||||||
|
|
||||||
|
if (parent->holds_alternative<tr_variant::Vector>())
|
||||||
|
{
|
||||||
|
return tr_variantListAdd(parent);
|
||||||
|
}
|
||||||
|
if (parent->holds_alternative<tr_variant::Map>())
|
||||||
|
{
|
||||||
|
TR_ASSERT(!std::empty(cur_key_));
|
||||||
|
auto tmp = std::string_view{};
|
||||||
|
std::swap(cur_key_, tmp);
|
||||||
|
return tr_variantDictAdd(parent, tr_quark_new(tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* arbitrary value... this is much deeper than our code goes */
|
||||||
|
static auto constexpr MaxDepth = size_t{ 64 };
|
||||||
|
|
||||||
/* A very common pattern is for a container's children to be similar,
|
/* A very common pattern is for a container's children to be similar,
|
||||||
* e.g. they may all be objects with the same set of keys. So when
|
* e.g. they may all be objects with the same set of keys. So when
|
||||||
* a container is popped off the stack, remember its size to use as
|
* a container is popped off the stack, remember its size to use as
|
||||||
* a preallocation heuristic for the next container at that depth. */
|
* a preallocation heuristic for the next container at that depth. */
|
||||||
std::array<size_t, MaxDepth> preallocGuess;
|
std::array<size_t, MaxDepth> prealloc_guess_{};
|
||||||
|
|
||||||
|
std::string key_buf_;
|
||||||
|
std::string_view cur_key_;
|
||||||
|
std::stack<tr_variant*> stack_;
|
||||||
};
|
};
|
||||||
|
|
||||||
tr_variant* get_node(struct jsonsl_st* jsn)
|
|
||||||
{
|
|
||||||
auto* data = static_cast<struct json_wrapper_data*>(jsn->data);
|
|
||||||
|
|
||||||
auto* parent = std::empty(data->stack) ? nullptr : data->stack.back();
|
|
||||||
|
|
||||||
tr_variant* node = nullptr;
|
|
||||||
if (parent == nullptr)
|
|
||||||
{
|
|
||||||
node = data->top;
|
|
||||||
}
|
|
||||||
else if (parent->holds_alternative<tr_variant::Vector>())
|
|
||||||
{
|
|
||||||
node = tr_variantListAdd(parent);
|
|
||||||
}
|
|
||||||
else if (parent->holds_alternative<tr_variant::Map>() && !std::empty(data->key))
|
|
||||||
{
|
|
||||||
node = tr_variantDictAdd(parent, tr_quark_new(data->key));
|
|
||||||
data->key = ""sv;
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
void error_handler(jsonsl_t jsn, jsonsl_error_t error, jsonsl_state_st* /*state*/, jsonsl_char_t const* buf)
|
|
||||||
{
|
|
||||||
auto* data = static_cast<struct json_wrapper_data*>(jsn->data);
|
|
||||||
|
|
||||||
tr_error_set(
|
|
||||||
&data->error,
|
|
||||||
EILSEQ,
|
|
||||||
fmt::format(
|
|
||||||
_("Couldn't parse JSON at position {position} '{text}': {error} ({error_code})"),
|
|
||||||
fmt::arg("position", jsn->pos),
|
|
||||||
fmt::arg("text", std::string_view{ buf, std::min(size_t{ 16U }, data->size - jsn->pos) }),
|
|
||||||
fmt::arg("error", jsonsl_strerror(error)),
|
|
||||||
fmt::arg("error_code", static_cast<int>(error))));
|
|
||||||
}
|
|
||||||
|
|
||||||
int error_callback(jsonsl_t jsn, jsonsl_error_t error, struct jsonsl_state_st* state, jsonsl_char_t* at)
|
|
||||||
{
|
|
||||||
error_handler(jsn, error, state, at);
|
|
||||||
return 0; /* bail */
|
|
||||||
}
|
|
||||||
|
|
||||||
void action_callback_PUSH(jsonsl_t jsn, jsonsl_action_t /*action*/, struct jsonsl_state_st* state, jsonsl_char_t const* /*buf*/)
|
|
||||||
{
|
|
||||||
auto* const data = static_cast<json_wrapper_data*>(jsn->data);
|
|
||||||
|
|
||||||
if ((state->type == JSONSL_T_LIST) || (state->type == JSONSL_T_OBJECT))
|
|
||||||
{
|
|
||||||
data->has_content = true;
|
|
||||||
tr_variant* node = get_node(jsn);
|
|
||||||
data->stack.push_back(node);
|
|
||||||
|
|
||||||
size_t const depth = std::size(data->stack);
|
|
||||||
size_t const n = depth < MaxDepth ? data->preallocGuess[depth] : 0;
|
|
||||||
if (state->type == JSONSL_T_LIST)
|
|
||||||
{
|
|
||||||
tr_variantInitList(node, n);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tr_variantInitDict(node, n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* like sscanf(in+2, "%4x", &val) but less slow */
|
|
||||||
[[nodiscard]] constexpr bool decode_hex_string(char const* in, std::uint16_t& setme)
|
|
||||||
{
|
|
||||||
TR_ASSERT(in != nullptr);
|
|
||||||
|
|
||||||
unsigned int val = 0;
|
|
||||||
char const* const end = in + 6;
|
|
||||||
|
|
||||||
TR_ASSERT(in[0] == '\\');
|
|
||||||
TR_ASSERT(in[1] == 'u');
|
|
||||||
in += 2;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
val <<= 4;
|
|
||||||
|
|
||||||
if ('0' <= *in && *in <= '9')
|
|
||||||
{
|
|
||||||
val += *in - '0';
|
|
||||||
}
|
|
||||||
else if ('a' <= *in && *in <= 'f')
|
|
||||||
{
|
|
||||||
val += *in - 'a' + 10U;
|
|
||||||
}
|
|
||||||
else if ('A' <= *in && *in <= 'F')
|
|
||||||
{
|
|
||||||
val += *in - 'A' + 10U;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} while (++in != end);
|
|
||||||
|
|
||||||
setme = val;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Iter>
|
|
||||||
void decode_single_uchar(char const*& in, char const* const in_end, Iter& buf16_out_it)
|
|
||||||
{
|
|
||||||
static auto constexpr EscapedUcharLength = 6U;
|
|
||||||
if (in_end - in >= EscapedUcharLength && decode_hex_string(in, *buf16_out_it))
|
|
||||||
{
|
|
||||||
in += EscapedUcharLength;
|
|
||||||
++buf16_out_it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool decode_escaped_uchar_sequence(char const*& in, char const* const in_end, std::string& buf)
|
|
||||||
{
|
|
||||||
auto buf16 = std::array<std::uint16_t, 2>{};
|
|
||||||
auto buf16_out_it = std::begin(buf16);
|
|
||||||
|
|
||||||
decode_single_uchar(in, in_end, buf16_out_it);
|
|
||||||
if (in[0] == '\\' && in[1] == 'u')
|
|
||||||
{
|
|
||||||
decode_single_uchar(in, in_end, buf16_out_it);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buf16_out_it == std::begin(buf16))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
utf8::utf16to8(std::begin(buf16), buf16_out_it, std::back_inserter(buf));
|
|
||||||
}
|
|
||||||
catch (utf8::exception const&) // invalid codepoint
|
|
||||||
{
|
|
||||||
buf.push_back('?');
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] std::string_view extract_escaped_string(char const* in, size_t in_len, std::string& buf)
|
|
||||||
{
|
|
||||||
char const* const in_end = in + in_len;
|
|
||||||
|
|
||||||
buf.clear();
|
|
||||||
|
|
||||||
while (in < in_end)
|
|
||||||
{
|
|
||||||
bool unescaped = false;
|
|
||||||
|
|
||||||
if (*in == '\\' && in_end - in >= 2)
|
|
||||||
{
|
|
||||||
switch (in[1])
|
|
||||||
{
|
|
||||||
case 'b':
|
|
||||||
buf.push_back('\b');
|
|
||||||
in += 2;
|
|
||||||
unescaped = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'f':
|
|
||||||
buf.push_back('\f');
|
|
||||||
in += 2;
|
|
||||||
unescaped = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'n':
|
|
||||||
buf.push_back('\n');
|
|
||||||
in += 2;
|
|
||||||
unescaped = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'r':
|
|
||||||
buf.push_back('\r');
|
|
||||||
in += 2;
|
|
||||||
unescaped = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 't':
|
|
||||||
buf.push_back('\t');
|
|
||||||
in += 2;
|
|
||||||
unescaped = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '/':
|
|
||||||
buf.push_back('/');
|
|
||||||
in += 2;
|
|
||||||
unescaped = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '"':
|
|
||||||
buf.push_back('"');
|
|
||||||
in += 2;
|
|
||||||
unescaped = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\\':
|
|
||||||
buf.push_back('\\');
|
|
||||||
in += 2;
|
|
||||||
unescaped = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'u':
|
|
||||||
if (decode_escaped_uchar_sequence(in, in_end, buf))
|
|
||||||
{
|
|
||||||
unescaped = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!unescaped)
|
|
||||||
{
|
|
||||||
buf.push_back(*in);
|
|
||||||
++in;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] std::pair<std::string_view, bool> extract_string(jsonsl_t jsn, struct jsonsl_state_st* state, std::string& buf)
|
|
||||||
{
|
|
||||||
// figure out where the string is
|
|
||||||
char const* in_begin = jsn->base + state->pos_begin;
|
|
||||||
if (*in_begin == '"')
|
|
||||||
{
|
|
||||||
in_begin++;
|
|
||||||
}
|
|
||||||
|
|
||||||
char const* const in_end = jsn->base + state->pos_cur;
|
|
||||||
size_t const in_len = in_end - in_begin;
|
|
||||||
if (memchr(in_begin, '\\', in_len) == nullptr)
|
|
||||||
{
|
|
||||||
/* it's not escaped */
|
|
||||||
return std::make_pair(std::string_view{ in_begin, in_len }, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_pair(extract_escaped_string(in_begin, in_len, buf), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void action_callback_POP(jsonsl_t jsn, jsonsl_action_t /*action*/, struct jsonsl_state_st* state, jsonsl_char_t const* /*buf*/)
|
|
||||||
{
|
|
||||||
auto* data = static_cast<struct json_wrapper_data*>(jsn->data);
|
|
||||||
|
|
||||||
if (state->type == JSONSL_T_STRING)
|
|
||||||
{
|
|
||||||
auto const [str, inplace] = extract_string(jsn, state, data->strbuf);
|
|
||||||
if (inplace && data->inplace)
|
|
||||||
{
|
|
||||||
tr_variantInitStrView(get_node(jsn), str);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tr_variantInitStr(get_node(jsn), str);
|
|
||||||
}
|
|
||||||
data->has_content = true;
|
|
||||||
}
|
|
||||||
else if (state->type == JSONSL_T_HKEY)
|
|
||||||
{
|
|
||||||
data->has_content = true;
|
|
||||||
auto const [key, inplace] = extract_string(jsn, state, data->keybuf);
|
|
||||||
data->key = key;
|
|
||||||
}
|
|
||||||
else if (state->type == JSONSL_T_LIST || state->type == JSONSL_T_OBJECT)
|
|
||||||
{
|
|
||||||
auto const depth = std::size(data->stack);
|
|
||||||
auto const* const v = data->stack.back();
|
|
||||||
data->stack.pop_back();
|
|
||||||
if (depth < MaxDepth)
|
|
||||||
{
|
|
||||||
data->preallocGuess[depth] = variant_size(*v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (state->type == JSONSL_T_SPECIAL)
|
|
||||||
{
|
|
||||||
if ((state->special_flags & JSONSL_SPECIALf_NUMNOINT) != 0)
|
|
||||||
{
|
|
||||||
auto sv = std::string_view{ jsn->base + state->pos_begin, jsn->pos - state->pos_begin };
|
|
||||||
tr_variantInitReal(get_node(jsn), tr_num_parse<double>(sv).value_or(0.0));
|
|
||||||
}
|
|
||||||
else if ((state->special_flags & JSONSL_SPECIALf_NUMERIC) != 0)
|
|
||||||
{
|
|
||||||
char const* begin = jsn->base + state->pos_begin;
|
|
||||||
data->has_content = true;
|
|
||||||
tr_variantInitInt(get_node(jsn), std::strtoll(begin, nullptr, 10));
|
|
||||||
}
|
|
||||||
else if ((state->special_flags & JSONSL_SPECIALf_BOOLEAN) != 0)
|
|
||||||
{
|
|
||||||
bool const b = (state->special_flags & JSONSL_SPECIALf_TRUE) != 0;
|
|
||||||
data->has_content = true;
|
|
||||||
tr_variantInitBool(get_node(jsn), b);
|
|
||||||
}
|
|
||||||
else if ((state->special_flags & JSONSL_SPECIALf_NULL) != 0)
|
|
||||||
{
|
|
||||||
data->has_content = true;
|
|
||||||
tr_variantInitQuark(get_node(jsn), TR_KEY_NONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace parse_helpers
|
} // namespace parse_helpers
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::optional<tr_variant> tr_variant_serde::parse_json(std::string_view input)
|
std::optional<tr_variant> tr_variant_serde::parse_json(std::string_view input)
|
||||||
{
|
{
|
||||||
using namespace parse_helpers;
|
auto* const begin = std::data(input);
|
||||||
|
TR_ASSERT(begin != nullptr); // RapidJSON will dereference a nullptr if this is false
|
||||||
|
auto const size = std::size(input);
|
||||||
|
|
||||||
auto top = tr_variant{};
|
auto top = tr_variant{};
|
||||||
|
|
||||||
auto data = json_wrapper_data{};
|
auto handler = parse_helpers::json_to_variant_handler{ &top };
|
||||||
data.error = nullptr;
|
auto ms = rapidjson::MemoryStream{ begin, size };
|
||||||
data.size = std::size(input);
|
auto eis = rapidjson::AutoUTFInputStream<unsigned, rapidjson::MemoryStream>{ ms };
|
||||||
data.has_content = false;
|
auto reader = rapidjson::GenericReader<rapidjson::AutoUTF<unsigned>, rapidjson::UTF8<char>>{};
|
||||||
data.key = ""sv;
|
reader.Parse(eis, handler);
|
||||||
data.inplace = parse_inplace_;
|
|
||||||
data.preallocGuess = {};
|
|
||||||
data.stack = {};
|
|
||||||
data.top = ⊤
|
|
||||||
|
|
||||||
auto jsn = jsonsl_new(MaxDepth);
|
if (!reader.HasParseError())
|
||||||
jsn->action_callback_PUSH = action_callback_PUSH;
|
|
||||||
jsn->action_callback_POP = action_callback_POP;
|
|
||||||
jsn->error_callback = error_callback;
|
|
||||||
jsn->data = &data;
|
|
||||||
jsonsl_enable_all_callbacks(jsn);
|
|
||||||
|
|
||||||
// parse it
|
|
||||||
jsonsl_feed(jsn, static_cast<jsonsl_char_t const*>(std::data(input)), std::size(input));
|
|
||||||
|
|
||||||
// EINVAL if there was no content
|
|
||||||
if (data.error == nullptr && !data.has_content)
|
|
||||||
{
|
|
||||||
tr_error_set(&data.error, EINVAL, "No content");
|
|
||||||
}
|
|
||||||
|
|
||||||
end_ = std::data(input) + jsn->pos;
|
|
||||||
|
|
||||||
if (data.error != nullptr)
|
|
||||||
{
|
|
||||||
tr_error_propagate(&error_, &data.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// cleanup
|
|
||||||
jsonsl_destroy(jsn);
|
|
||||||
|
|
||||||
if (error_ == nullptr)
|
|
||||||
{
|
{
|
||||||
return std::optional<tr_variant>{ std::move(top) };
|
return std::optional<tr_variant>{ std::move(top) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auto err_code = reader.GetParseErrorCode(); err_code == rapidjson::kParseErrorDocumentEmpty)
|
||||||
|
{
|
||||||
|
tr_error_set(&error_, EINVAL, "No content");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto const err_offset = reader.GetErrorOffset();
|
||||||
|
tr_error_set(
|
||||||
|
&error_,
|
||||||
|
EILSEQ,
|
||||||
|
fmt::format(
|
||||||
|
_("Couldn't parse JSON at position {position} '{text}': {error} ({error_code})"),
|
||||||
|
fmt::arg("position", err_offset),
|
||||||
|
fmt::arg("text", std::string_view{ begin + err_offset, std::min(size_t{ 16U }, size - err_offset) }),
|
||||||
|
fmt::arg("error", rapidjson::GetParseError_En(err_code)),
|
||||||
|
fmt::arg("error_code", static_cast<std::underlying_type_t<decltype(err_code)>>(err_code))));
|
||||||
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,251 +264,105 @@ namespace
|
||||||
{
|
{
|
||||||
namespace to_string_helpers
|
namespace to_string_helpers
|
||||||
{
|
{
|
||||||
struct ParentState
|
// implements RapidJSON's Stream concept, so that the library can output
|
||||||
|
// directly to a std::string, and we can avoid some copying by copy elision
|
||||||
|
// http://rapidjson.org/md_doc_stream.html
|
||||||
|
struct string_output_stream
|
||||||
{
|
{
|
||||||
bool is_map = false;
|
using Ch = char;
|
||||||
bool is_list = false;
|
|
||||||
size_t child_index;
|
explicit string_output_stream(std::string& str)
|
||||||
size_t child_count;
|
: str_ref_(str)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static Ch Peek()
|
||||||
|
{
|
||||||
|
TR_ASSERT(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static Ch Take()
|
||||||
|
{
|
||||||
|
TR_ASSERT(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t Tell()
|
||||||
|
{
|
||||||
|
TR_ASSERT(false);
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Ch* PutBegin()
|
||||||
|
{
|
||||||
|
TR_ASSERT(false);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Put(Ch const c)
|
||||||
|
{
|
||||||
|
str_ref_ += c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Flush()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t PutEnd(Ch* /*begin*/)
|
||||||
|
{
|
||||||
|
TR_ASSERT(false);
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string& str_ref_;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct JsonWalk
|
using writer_var_t = std::variant<rapidjson::Writer<string_output_stream>, rapidjson::PrettyWriter<string_output_stream>>;
|
||||||
{
|
|
||||||
explicit JsonWalk(bool do_indent)
|
|
||||||
: doIndent{ do_indent }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::deque<ParentState> parents;
|
|
||||||
libtransmission::StackBuffer<1024U * 8U, std::byte> out;
|
|
||||||
bool doIndent;
|
|
||||||
};
|
|
||||||
|
|
||||||
void jsonIndent(struct JsonWalk* data)
|
|
||||||
{
|
|
||||||
static auto buf = std::array<char, 1024>{};
|
|
||||||
|
|
||||||
if (buf.front() == '\0')
|
|
||||||
{
|
|
||||||
memset(std::data(buf), ' ', std::size(buf));
|
|
||||||
buf[0] = '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data->doIndent)
|
|
||||||
{
|
|
||||||
data->out.add(std::data(buf), std::size(data->parents) * 4 + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void jsonChildFunc(struct JsonWalk* data)
|
|
||||||
{
|
|
||||||
if (std::empty(data->parents))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& parent_state = data->parents.back();
|
|
||||||
|
|
||||||
if (parent_state.is_map)
|
|
||||||
{
|
|
||||||
int const i = parent_state.child_index;
|
|
||||||
++parent_state.child_index;
|
|
||||||
|
|
||||||
if (i % 2 == 0)
|
|
||||||
{
|
|
||||||
data->out.add(data->doIndent ? ": "sv : ":"sv);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool const is_last = parent_state.child_index == parent_state.child_count;
|
|
||||||
if (!is_last)
|
|
||||||
{
|
|
||||||
data->out.push_back(',');
|
|
||||||
jsonIndent(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (parent_state.is_list)
|
|
||||||
{
|
|
||||||
++parent_state.child_index;
|
|
||||||
if (bool const is_last = parent_state.child_index == parent_state.child_count; !is_last)
|
|
||||||
{
|
|
||||||
data->out.push_back(',');
|
|
||||||
jsonIndent(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void jsonPushParent(struct JsonWalk* data, tr_variant const& v)
|
|
||||||
{
|
|
||||||
auto const is_dict = v.holds_alternative<tr_variant::Map>();
|
|
||||||
auto const is_list = v.holds_alternative<tr_variant::Vector>();
|
|
||||||
auto const n_children = variant_size(v) * (is_dict ? 2U : 1U);
|
|
||||||
data->parents.push_back({ is_dict, is_list, 0, n_children });
|
|
||||||
}
|
|
||||||
|
|
||||||
void jsonPopParent(struct JsonWalk* data)
|
|
||||||
{
|
|
||||||
data->parents.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
void jsonIntFunc(tr_variant const& /*var*/, int64_t const val, void* vdata)
|
void jsonIntFunc(tr_variant const& /*var*/, int64_t const val, void* vdata)
|
||||||
{
|
{
|
||||||
auto buf = std::array<char, 64>{};
|
std::visit([val](auto&& writer) { writer.Int64(val); }, *static_cast<writer_var_t*>(vdata));
|
||||||
auto const* const out = fmt::format_to(std::data(buf), FMT_COMPILE("{:d}"), val);
|
|
||||||
auto* const data = static_cast<JsonWalk*>(vdata);
|
|
||||||
data->out.add(std::data(buf), static_cast<size_t>(out - std::data(buf)));
|
|
||||||
jsonChildFunc(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void jsonBoolFunc(tr_variant const& /*var*/, bool const val, void* vdata)
|
void jsonBoolFunc(tr_variant const& /*var*/, bool const val, void* vdata)
|
||||||
{
|
{
|
||||||
auto* data = static_cast<struct JsonWalk*>(vdata);
|
std::visit([val](auto&& writer) { writer.Bool(val); }, *static_cast<writer_var_t*>(vdata));
|
||||||
data->out.add(val ? "true"sv : "false"sv);
|
|
||||||
jsonChildFunc(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void jsonRealFunc(tr_variant const& /*var*/, double const val, void* vdata)
|
void jsonRealFunc(tr_variant const& /*var*/, double const val, void* vdata)
|
||||||
{
|
{
|
||||||
auto* const data = static_cast<struct JsonWalk*>(vdata);
|
std::visit([val](auto&& writer) { writer.Double(val); }, *static_cast<writer_var_t*>(vdata));
|
||||||
|
|
||||||
auto const [buf, buflen] = data->out.reserve_space(64);
|
|
||||||
auto* walk = reinterpret_cast<char*>(buf);
|
|
||||||
auto const* const begin = walk;
|
|
||||||
|
|
||||||
if (fabs(val - (int)val) < 0.00001)
|
|
||||||
{
|
|
||||||
walk = fmt::format_to(walk, FMT_COMPILE("{:.0f}"), val);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
walk = fmt::format_to(walk, FMT_COMPILE("{:.4f}"), val);
|
|
||||||
}
|
|
||||||
|
|
||||||
data->out.commit_space(walk - begin);
|
|
||||||
|
|
||||||
jsonChildFunc(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://datatracker.ietf.org/doc/html/rfc8259#section-7
|
|
||||||
void jsonStringFunc(tr_variant const& /*var*/, std::string_view sv, void* vdata)
|
void jsonStringFunc(tr_variant const& /*var*/, std::string_view sv, void* vdata)
|
||||||
{
|
{
|
||||||
auto* const data = static_cast<struct JsonWalk*>(vdata);
|
std::visit([sv](auto&& writer) { writer.String(std::data(sv), std::size(sv)); }, *static_cast<writer_var_t*>(vdata));
|
||||||
|
|
||||||
auto const utf8_str = tr_strv_convert_utf8(sv);
|
|
||||||
auto utf8_sv = std::string_view{ utf8_str };
|
|
||||||
|
|
||||||
auto& out = data->out;
|
|
||||||
auto const [buf, buflen] = out.reserve_space(std::size(utf8_sv) * 6 + 2);
|
|
||||||
auto* walk = reinterpret_cast<char*>(buf);
|
|
||||||
auto const* const begin = walk;
|
|
||||||
auto const* const end = begin + buflen;
|
|
||||||
|
|
||||||
*walk++ = '"';
|
|
||||||
|
|
||||||
for (; !std::empty(utf8_sv); utf8_sv.remove_prefix(1))
|
|
||||||
{
|
|
||||||
switch (utf8_sv.front())
|
|
||||||
{
|
|
||||||
case '"':
|
|
||||||
*walk++ = '\\';
|
|
||||||
*walk++ = '"';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\\':
|
|
||||||
*walk++ = '\\';
|
|
||||||
*walk++ = '\\';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\b':
|
|
||||||
*walk++ = '\\';
|
|
||||||
*walk++ = 'b';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\f':
|
|
||||||
*walk++ = '\\';
|
|
||||||
*walk++ = 'f';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\n':
|
|
||||||
*walk++ = '\\';
|
|
||||||
*walk++ = 'n';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\r':
|
|
||||||
*walk++ = '\\';
|
|
||||||
*walk++ = 'r';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\t':
|
|
||||||
*walk++ = '\\';
|
|
||||||
*walk++ = 't';
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (utf8_sv.front() >= '\u0000' && utf8_sv.front() <= '\u001f')
|
|
||||||
{
|
|
||||||
walk = fmt::format_to_n(walk, end - walk - 1, "\\u{:04x}", utf8_sv.front()).out;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*walk++ = utf8_sv.front();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*walk++ = '"';
|
|
||||||
TR_ASSERT(walk <= end);
|
|
||||||
out.commit_space(walk - begin);
|
|
||||||
|
|
||||||
jsonChildFunc(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void jsonDictBeginFunc(tr_variant const& var, void* vdata)
|
void jsonDictBeginFunc(tr_variant const& /*var*/, void* vdata)
|
||||||
{
|
{
|
||||||
auto* const data = static_cast<struct JsonWalk*>(vdata);
|
std::visit([](auto&& writer) { writer.StartObject(); }, *static_cast<writer_var_t*>(vdata));
|
||||||
|
|
||||||
jsonPushParent(data, var);
|
|
||||||
data->out.push_back('{');
|
|
||||||
|
|
||||||
if (variant_size(var) != 0U)
|
|
||||||
{
|
|
||||||
jsonIndent(data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void jsonListBeginFunc(tr_variant const& var, void* vdata)
|
void jsonListBeginFunc(tr_variant const& /*var*/, void* vdata)
|
||||||
{
|
{
|
||||||
auto* const data = static_cast<struct JsonWalk*>(vdata);
|
std::visit([](auto&& writer) { writer.StartArray(); }, *static_cast<writer_var_t*>(vdata));
|
||||||
|
|
||||||
jsonPushParent(data, var);
|
|
||||||
data->out.push_back('[');
|
|
||||||
|
|
||||||
if (variant_size(var) != 0U)
|
|
||||||
{
|
|
||||||
jsonIndent(data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void jsonContainerEndFunc(tr_variant const& var, void* vdata)
|
void jsonContainerEndFunc(tr_variant const& var, void* vdata)
|
||||||
{
|
{
|
||||||
auto* const data = static_cast<struct JsonWalk*>(vdata);
|
auto& writer_var = *static_cast<writer_var_t*>(vdata);
|
||||||
|
|
||||||
jsonPopParent(data);
|
|
||||||
|
|
||||||
jsonIndent(data);
|
|
||||||
|
|
||||||
if (var.holds_alternative<tr_variant::Map>())
|
if (var.holds_alternative<tr_variant::Map>())
|
||||||
{
|
{
|
||||||
data->out.push_back('}');
|
std::visit([](auto&& writer) { writer.EndObject(); }, writer_var);
|
||||||
}
|
}
|
||||||
else /* list */
|
else /* list */
|
||||||
{
|
{
|
||||||
data->out.push_back(']');
|
std::visit([](auto&& writer) { writer.EndArray(); }, writer_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonChildFunc(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace to_string_helpers
|
} // namespace to_string_helpers
|
||||||
|
@ -707,13 +382,19 @@ std::string tr_variant_serde::to_json_string(tr_variant const& var) const
|
||||||
jsonContainerEndFunc, //
|
jsonContainerEndFunc, //
|
||||||
};
|
};
|
||||||
|
|
||||||
auto data = JsonWalk{ !compact_ };
|
auto out = std::string{};
|
||||||
walk(var, Funcs, &data, true);
|
out.reserve(rapidjson::StringBuffer::kDefaultCapacity);
|
||||||
|
auto stream = string_output_stream{ out };
|
||||||
auto& buf = data.out;
|
auto writer = writer_var_t{};
|
||||||
if (!compact_ && !std::empty(buf))
|
if (compact_)
|
||||||
{
|
{
|
||||||
buf.push_back('\n');
|
writer.emplace<0>(stream);
|
||||||
}
|
}
|
||||||
return buf.to_string();
|
else
|
||||||
|
{
|
||||||
|
writer.emplace<1>(stream);
|
||||||
|
}
|
||||||
|
walk(var, Funcs, &writer, true);
|
||||||
|
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,17 +26,7 @@
|
||||||
|
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
|
|
||||||
class VariantTest : public ::testing::Test
|
using VariantTest = ::testing::Test;
|
||||||
{
|
|
||||||
protected:
|
|
||||||
static std::string stripWhitespace(std::string const& in)
|
|
||||||
{
|
|
||||||
auto s = in;
|
|
||||||
s.erase(s.begin(), std::find_if_not(s.begin(), s.end(), ::isspace));
|
|
||||||
s.erase(std::find_if_not(s.rbegin(), s.rend(), ::isspace).base(), s.end());
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#define STACK_SMASH_DEPTH (1 * 1000 * 1000)
|
#define STACK_SMASH_DEPTH (1 * 1000 * 1000)
|
||||||
|
@ -363,7 +353,7 @@ TEST_F(VariantTest, bencToJson)
|
||||||
for (auto const& test : Tests)
|
for (auto const& test : Tests)
|
||||||
{
|
{
|
||||||
auto top = benc_serde.parse(test.benc).value_or(tr_variant{});
|
auto top = benc_serde.parse(test.benc).value_or(tr_variant{});
|
||||||
EXPECT_EQ(test.expected, stripWhitespace(json_serde.to_string(top)));
|
EXPECT_EQ(test.expected, json_serde.to_string(top));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
add_library(jsonsl STATIC
|
|
||||||
jsonsl.c
|
|
||||||
jsonsl.h)
|
|
||||||
|
|
||||||
target_include_directories(jsonsl
|
|
||||||
PUBLIC
|
|
||||||
${CMAKE_CURRENT_LIST_DIR})
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit f9d53419e912910fd8fa57d5705fa41425428c35
|
Loading…
Reference in New Issue