diff --git a/CHAOSFramework.xcodeproj/project.pbxproj b/CHAOSFramework.xcodeproj/project.pbxproj index 2554304169a44397f21a9b525189c90bc2baf9cd..8f38ce928b66cb814cc181da5bf63b476470204a 100644 --- a/CHAOSFramework.xcodeproj/project.pbxproj +++ b/CHAOSFramework.xcodeproj/project.pbxproj @@ -265,10 +265,6 @@ 324D08B61F31D7F300836E29 /* AbstractUnitProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 324D08B41F31D7F300836E29 /* AbstractUnitProxy.h */; }; 324D08C51F31EC5000836E29 /* HTTPConnectionAdapter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 324D08C31F31EC5000836E29 /* HTTPConnectionAdapter.cpp */; }; 324D08C61F31EC5000836E29 /* HTTPConnectionAdapter.h in Headers */ = {isa = PBXBuildFile; fileRef = 324D08C41F31EC5000836E29 /* HTTPConnectionAdapter.h */; }; - 324D08CA1F31F26600836E29 /* DataPack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 324D08C81F31F26600836E29 /* DataPack.cpp */; }; - 324D08CB1F31F26600836E29 /* DataPack.h in Headers */ = {isa = PBXBuildFile; fileRef = 324D08C91F31F26600836E29 /* DataPack.h */; }; - 324D08D21F31F5A000836E29 /* json.h in Headers */ = {isa = PBXBuildFile; fileRef = 324D08CD1F31F5A000836E29 /* json.h */; }; - 324D08D31F31F5A000836E29 /* jsoncpp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 324D08CE1F31F5A000836E29 /* jsoncpp.cpp */; }; 324D08D41F31F5A000836E29 /* mongoose.c in Sources */ = {isa = PBXBuildFile; fileRef = 324D08CF1F31F5A000836E29 /* mongoose.c */; }; 324D08D51F31F5A000836E29 /* mongoose.h in Headers */ = {isa = PBXBuildFile; fileRef = 324D08D01F31F5A000836E29 /* mongoose.h */; }; 324D08E21F321B4800836E29 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 324D08E11F321B4800836E29 /* main.cpp */; }; @@ -422,6 +418,28 @@ 3265BF4615D1A9CA00C3CAC6 /* ChaosUIToolkitCWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 3265BF4515D1A9CA00C3CAC6 /* ChaosUIToolkitCWrapper.h */; }; 3265BF4915D1AA9F00C3CAC6 /* ChaosUIToolkitCWrapper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3265BF4815D1AA9F00C3CAC6 /* ChaosUIToolkitCWrapper.cc */; }; 3265F332197E626900F22FBC /* WorkUnitManagement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 32D72CA8197D196D00512B89 /* WorkUnitManagement.cpp */; }; + 3265F94B1FB899D400FEA246 /* DataPack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9491FB899D300FEA246 /* DataPack.cpp */; }; + 3265F94C1FB89F6B00FEA246 /* bson-context.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9111FB8997300FEA246 /* bson-context.c */; }; + 3265F94D1FB89F6B00FEA246 /* bson-oid.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9121FB8997300FEA246 /* bson-oid.c */; }; + 3265F94E1FB89F6B00FEA246 /* bson-error.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9141FB8997300FEA246 /* bson-error.c */; }; + 3265F94F1FB89F6B00FEA246 /* bson-atomic.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9151FB8997300FEA246 /* bson-atomic.c */; }; + 3265F9501FB89F6B00FEA246 /* bson-string.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9171FB8997300FEA246 /* bson-string.c */; }; + 3265F9511FB89F6B00FEA246 /* bson-keys.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9181FB8997300FEA246 /* bson-keys.c */; }; + 3265F9521FB89F6B00FEA246 /* bson-iter.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F91A1FB8997300FEA246 /* bson-iter.c */; }; + 3265F9531FB89F6B00FEA246 /* bson-iso8601.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F91B1FB8997300FEA246 /* bson-iso8601.c */; }; + 3265F9541FB89F6B00FEA246 /* bson-md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F91F1FB8997300FEA246 /* bson-md5.c */; }; + 3265F9551FB89F6B00FEA246 /* bson-memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9211FB8997300FEA246 /* bson-memory.c */; }; + 3265F9561FB89F6B00FEA246 /* bson-writer.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9221FB8997300FEA246 /* bson-writer.c */; }; + 3265F9571FB89F6B00FEA246 /* bson-value.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9251FB8997300FEA246 /* bson-value.c */; }; + 3265F9581FB89F6B00FEA246 /* bson-json.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9291FB8997300FEA246 /* bson-json.c */; }; + 3265F9591FB89F6B00FEA246 /* bson.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F92C1FB8997300FEA246 /* bson.c */; }; + 3265F95A1FB89F6B00FEA246 /* bcon.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9331FB8997300FEA246 /* bcon.c */; }; + 3265F95B1FB89F6B00FEA246 /* bson-decimal128.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F93C1FB8997300FEA246 /* bson-decimal128.c */; }; + 3265F95C1FB89F6B00FEA246 /* bson-timegm.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F93F1FB8997300FEA246 /* bson-timegm.c */; }; + 3265F95D1FB89F6B00FEA246 /* bson-utf8.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9401FB8997300FEA246 /* bson-utf8.c */; }; + 3265F95E1FB89F6B00FEA246 /* bson-reader.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9411FB8997300FEA246 /* bson-reader.c */; }; + 3265F95F1FB89F6B00FEA246 /* bson-clock.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9421FB8997300FEA246 /* bson-clock.c */; }; + 3265F9601FB8A12B00FEA246 /* jsonsl.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9481FB8997300FEA246 /* jsonsl.c */; }; 32661C6D1AA741D000F1A721 /* ChaosMetadataServiceClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 32661C6B1AA741D000F1A721 /* ChaosMetadataServiceClient.cpp */; }; 32661C6E1AA741D000F1A721 /* ChaosMetadataServiceClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 32661C6C1AA741D000F1A721 /* ChaosMetadataServiceClient.h */; }; 32661C711AA7606400F1A721 /* NodeMessageChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 32661C6F1AA74E4700F1A721 /* NodeMessageChannel.cpp */; }; @@ -1572,10 +1590,6 @@ 324D08B71F31DA5300836E29 /* connection_type.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = connection_type.h; sourceTree = "<group>"; }; 324D08C31F31EC5000836E29 /* HTTPConnectionAdapter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPConnectionAdapter.cpp; sourceTree = "<group>"; }; 324D08C41F31EC5000836E29 /* HTTPConnectionAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPConnectionAdapter.h; sourceTree = "<group>"; }; - 324D08C81F31F26600836E29 /* DataPack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DataPack.cpp; sourceTree = "<group>"; }; - 324D08C91F31F26600836E29 /* DataPack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataPack.h; sourceTree = "<group>"; }; - 324D08CD1F31F5A000836E29 /* json.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json.h; sourceTree = "<group>"; }; - 324D08CE1F31F5A000836E29 /* jsoncpp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsoncpp.cpp; sourceTree = "<group>"; }; 324D08CF1F31F5A000836E29 /* mongoose.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mongoose.c; sourceTree = "<group>"; }; 324D08D01F31F5A000836E29 /* mongoose.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mongoose.h; sourceTree = "<group>"; }; 324D08D61F31FFFE00836E29 /* micro_unit_toolkit_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = micro_unit_toolkit_types.h; sourceTree = "<group>"; }; @@ -1750,6 +1764,63 @@ 326573F218CCD365009E9B6B /* TemplatedKeyObjectContainer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TemplatedKeyObjectContainer.h; sourceTree = "<group>"; }; 3265BF4515D1A9CA00C3CAC6 /* ChaosUIToolkitCWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChaosUIToolkitCWrapper.h; sourceTree = "<group>"; }; 3265BF4815D1AA9F00C3CAC6 /* ChaosUIToolkitCWrapper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ChaosUIToolkitCWrapper.cc; sourceTree = "<group>"; }; + 3265F9101FB8997300FEA246 /* b64_ntop.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = b64_ntop.h; sourceTree = "<group>"; }; + 3265F9111FB8997300FEA246 /* bson-context.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-context.c"; sourceTree = "<group>"; }; + 3265F9121FB8997300FEA246 /* bson-oid.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-oid.c"; sourceTree = "<group>"; }; + 3265F9131FB8997300FEA246 /* bson.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bson.h; sourceTree = "<group>"; }; + 3265F9141FB8997300FEA246 /* bson-error.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-error.c"; sourceTree = "<group>"; }; + 3265F9151FB8997300FEA246 /* bson-atomic.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-atomic.c"; sourceTree = "<group>"; }; + 3265F9161FB8997300FEA246 /* bson-json.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-json.h"; sourceTree = "<group>"; }; + 3265F9171FB8997300FEA246 /* bson-string.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-string.c"; sourceTree = "<group>"; }; + 3265F9181FB8997300FEA246 /* bson-keys.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-keys.c"; sourceTree = "<group>"; }; + 3265F9191FB8997300FEA246 /* bson-timegm-private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-timegm-private.h"; sourceTree = "<group>"; }; + 3265F91A1FB8997300FEA246 /* bson-iter.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-iter.c"; sourceTree = "<group>"; }; + 3265F91B1FB8997300FEA246 /* bson-iso8601.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-iso8601.c"; sourceTree = "<group>"; }; + 3265F91C1FB8997300FEA246 /* bcon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bcon.h; sourceTree = "<group>"; }; + 3265F91D1FB8997300FEA246 /* bson-endian.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-endian.h"; sourceTree = "<group>"; }; + 3265F91E1FB8997300FEA246 /* bson-decimal128.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-decimal128.h"; sourceTree = "<group>"; }; + 3265F91F1FB8997300FEA246 /* bson-md5.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-md5.c"; sourceTree = "<group>"; }; + 3265F9201FB8997300FEA246 /* bson-config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-config.h"; sourceTree = "<group>"; }; + 3265F9211FB8997300FEA246 /* bson-memory.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-memory.c"; sourceTree = "<group>"; }; + 3265F9221FB8997300FEA246 /* bson-writer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-writer.c"; sourceTree = "<group>"; }; + 3265F9231FB8997300FEA246 /* bson-iso8601-private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-iso8601-private.h"; sourceTree = "<group>"; }; + 3265F9241FB8997300FEA246 /* bson-clock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-clock.h"; sourceTree = "<group>"; }; + 3265F9251FB8997300FEA246 /* bson-value.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-value.c"; sourceTree = "<group>"; }; + 3265F9261FB8997300FEA246 /* bson-reader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-reader.h"; sourceTree = "<group>"; }; + 3265F9271FB8997300FEA246 /* bson-utf8.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-utf8.h"; sourceTree = "<group>"; }; + 3265F9281FB8997300FEA246 /* bson-string.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-string.h"; sourceTree = "<group>"; }; + 3265F9291FB8997300FEA246 /* bson-json.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-json.c"; sourceTree = "<group>"; }; + 3265F92A1FB8997300FEA246 /* bson-atomic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-atomic.h"; sourceTree = "<group>"; }; + 3265F92B1FB8997300FEA246 /* bson-keys.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-keys.h"; sourceTree = "<group>"; }; + 3265F92C1FB8997300FEA246 /* bson.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = bson.c; sourceTree = "<group>"; }; + 3265F92D1FB8997300FEA246 /* bson-error.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-error.h"; sourceTree = "<group>"; }; + 3265F92E1FB8997300FEA246 /* bson-oid.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-oid.h"; sourceTree = "<group>"; }; + 3265F92F1FB8997300FEA246 /* bson-stdint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-stdint.h"; sourceTree = "<group>"; }; + 3265F9301FB8997300FEA246 /* bson-context.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-context.h"; sourceTree = "<group>"; }; + 3265F9311FB8997300FEA246 /* bson-private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-private.h"; sourceTree = "<group>"; }; + 3265F9321FB8997300FEA246 /* bson-context-private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-context-private.h"; sourceTree = "<group>"; }; + 3265F9331FB8997300FEA246 /* bcon.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = bcon.c; sourceTree = "<group>"; }; + 3265F9341FB8997300FEA246 /* bson-types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-types.h"; sourceTree = "<group>"; }; + 3265F9351FB8997300FEA246 /* bson-stdint-win32.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-stdint-win32.h"; sourceTree = "<group>"; }; + 3265F9361FB8997300FEA246 /* bson-iter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-iter.h"; sourceTree = "<group>"; }; + 3265F9371FB8997300FEA246 /* bson-thread-private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-thread-private.h"; sourceTree = "<group>"; }; + 3265F9381FB8997300FEA246 /* bson-writer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-writer.h"; sourceTree = "<group>"; }; + 3265F9391FB8997300FEA246 /* bson-memory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-memory.h"; sourceTree = "<group>"; }; + 3265F93A1FB8997300FEA246 /* b64_pton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = b64_pton.h; sourceTree = "<group>"; }; + 3265F93B1FB8997300FEA246 /* bson-compat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-compat.h"; sourceTree = "<group>"; }; + 3265F93C1FB8997300FEA246 /* bson-decimal128.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-decimal128.c"; sourceTree = "<group>"; }; + 3265F93D1FB8997300FEA246 /* bson-macros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-macros.h"; sourceTree = "<group>"; }; + 3265F93E1FB8997300FEA246 /* bson-md5.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-md5.h"; sourceTree = "<group>"; }; + 3265F93F1FB8997300FEA246 /* bson-timegm.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-timegm.c"; sourceTree = "<group>"; }; + 3265F9401FB8997300FEA246 /* bson-utf8.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-utf8.c"; sourceTree = "<group>"; }; + 3265F9411FB8997300FEA246 /* bson-reader.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-reader.c"; sourceTree = "<group>"; }; + 3265F9421FB8997300FEA246 /* bson-clock.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-clock.c"; sourceTree = "<group>"; }; + 3265F9431FB8997300FEA246 /* bson-value.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "bson-value.h"; sourceTree = "<group>"; }; + 3265F9441FB8997300FEA246 /* bson.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bson.h; sourceTree = "<group>"; }; + 3265F9471FB8997300FEA246 /* jsonsl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = jsonsl.h; sourceTree = "<group>"; }; + 3265F9481FB8997300FEA246 /* jsonsl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = jsonsl.c; sourceTree = "<group>"; }; + 3265F9491FB899D300FEA246 /* DataPack.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DataPack.cpp; sourceTree = "<group>"; }; + 3265F94A1FB899D400FEA246 /* DataPack.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataPack.h; sourceTree = "<group>"; }; 32661C661AA73D5B00F1A721 /* libchaos_metadata_service_client.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libchaos_metadata_service_client.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 32661C6B1AA741D000F1A721 /* ChaosMetadataServiceClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ChaosMetadataServiceClient.cpp; sourceTree = "<group>"; }; 32661C6C1AA741D000F1A721 /* ChaosMetadataServiceClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChaosMetadataServiceClient.h; sourceTree = "<group>"; }; @@ -3398,8 +3469,7 @@ 324D08A31F31CEB400836E29 /* external_lib */ = { isa = PBXGroup; children = ( - 324D08CD1F31F5A000836E29 /* json.h */, - 324D08CE1F31F5A000836E29 /* jsoncpp.cpp */, + 3265F90E1FB8997300FEA246 /* bson */, 324D08CF1F31F5A000836E29 /* mongoose.c */, 324D08D01F31F5A000836E29 /* mongoose.h */, 324BE8491F3CA31A00FFDA02 /* base64.cpp */, @@ -3456,8 +3526,8 @@ 324D08C71F31F25300836E29 /* data */ = { isa = PBXGroup; children = ( - 324D08C81F31F26600836E29 /* DataPack.cpp */, - 324D08C91F31F26600836E29 /* DataPack.h */, + 3265F9491FB899D300FEA246 /* DataPack.cpp */, + 3265F94A1FB899D400FEA246 /* DataPack.h */, ); path = data; sourceTree = "<group>"; @@ -3812,6 +3882,92 @@ path = api; sourceTree = "<group>"; }; + 3265F90E1FB8997300FEA246 /* bson */ = { + isa = PBXGroup; + children = ( + 3265F90F1FB8997300FEA246 /* bson */, + 3265F9441FB8997300FEA246 /* bson.h */, + 3265F9451FB8997300FEA246 /* util */, + 3265F9461FB8997300FEA246 /* jsonsl */, + ); + path = bson; + sourceTree = "<group>"; + }; + 3265F90F1FB8997300FEA246 /* bson */ = { + isa = PBXGroup; + children = ( + 3265F9101FB8997300FEA246 /* b64_ntop.h */, + 3265F9111FB8997300FEA246 /* bson-context.c */, + 3265F9121FB8997300FEA246 /* bson-oid.c */, + 3265F9131FB8997300FEA246 /* bson.h */, + 3265F9141FB8997300FEA246 /* bson-error.c */, + 3265F9151FB8997300FEA246 /* bson-atomic.c */, + 3265F9161FB8997300FEA246 /* bson-json.h */, + 3265F9171FB8997300FEA246 /* bson-string.c */, + 3265F9181FB8997300FEA246 /* bson-keys.c */, + 3265F9191FB8997300FEA246 /* bson-timegm-private.h */, + 3265F91A1FB8997300FEA246 /* bson-iter.c */, + 3265F91B1FB8997300FEA246 /* bson-iso8601.c */, + 3265F91C1FB8997300FEA246 /* bcon.h */, + 3265F91D1FB8997300FEA246 /* bson-endian.h */, + 3265F91E1FB8997300FEA246 /* bson-decimal128.h */, + 3265F91F1FB8997300FEA246 /* bson-md5.c */, + 3265F9201FB8997300FEA246 /* bson-config.h */, + 3265F9211FB8997300FEA246 /* bson-memory.c */, + 3265F9221FB8997300FEA246 /* bson-writer.c */, + 3265F9231FB8997300FEA246 /* bson-iso8601-private.h */, + 3265F9241FB8997300FEA246 /* bson-clock.h */, + 3265F9251FB8997300FEA246 /* bson-value.c */, + 3265F9261FB8997300FEA246 /* bson-reader.h */, + 3265F9271FB8997300FEA246 /* bson-utf8.h */, + 3265F9281FB8997300FEA246 /* bson-string.h */, + 3265F9291FB8997300FEA246 /* bson-json.c */, + 3265F92A1FB8997300FEA246 /* bson-atomic.h */, + 3265F92B1FB8997300FEA246 /* bson-keys.h */, + 3265F92C1FB8997300FEA246 /* bson.c */, + 3265F92D1FB8997300FEA246 /* bson-error.h */, + 3265F92E1FB8997300FEA246 /* bson-oid.h */, + 3265F92F1FB8997300FEA246 /* bson-stdint.h */, + 3265F9301FB8997300FEA246 /* bson-context.h */, + 3265F9311FB8997300FEA246 /* bson-private.h */, + 3265F9321FB8997300FEA246 /* bson-context-private.h */, + 3265F9331FB8997300FEA246 /* bcon.c */, + 3265F9341FB8997300FEA246 /* bson-types.h */, + 3265F9351FB8997300FEA246 /* bson-stdint-win32.h */, + 3265F9361FB8997300FEA246 /* bson-iter.h */, + 3265F9371FB8997300FEA246 /* bson-thread-private.h */, + 3265F9381FB8997300FEA246 /* bson-writer.h */, + 3265F9391FB8997300FEA246 /* bson-memory.h */, + 3265F93A1FB8997300FEA246 /* b64_pton.h */, + 3265F93B1FB8997300FEA246 /* bson-compat.h */, + 3265F93C1FB8997300FEA246 /* bson-decimal128.c */, + 3265F93D1FB8997300FEA246 /* bson-macros.h */, + 3265F93E1FB8997300FEA246 /* bson-md5.h */, + 3265F93F1FB8997300FEA246 /* bson-timegm.c */, + 3265F9401FB8997300FEA246 /* bson-utf8.c */, + 3265F9411FB8997300FEA246 /* bson-reader.c */, + 3265F9421FB8997300FEA246 /* bson-clock.c */, + 3265F9431FB8997300FEA246 /* bson-value.h */, + ); + path = bson; + sourceTree = "<group>"; + }; + 3265F9451FB8997300FEA246 /* util */ = { + isa = PBXGroup; + children = ( + ); + path = util; + sourceTree = "<group>"; + }; + 3265F9461FB8997300FEA246 /* jsonsl */ = { + isa = PBXGroup; + children = ( + 3265F9471FB8997300FEA246 /* jsonsl.h */, + 3265F9481FB8997300FEA246 /* jsonsl.c */, + ); + path = jsonsl; + sourceTree = "<group>"; + }; 32661C6A1AA73DA200F1A721 /* chaos_metadata_service_client */ = { isa = PBXGroup; children = ( @@ -5660,8 +5816,6 @@ 325F517F1F3C3E11000B842F /* RawDriverHandlerWrapper.h in Headers */, 325F51831F3C3E4D000B842F /* UnitProxyHandlerWrapper.h in Headers */, 324D08C61F31EC5000836E29 /* HTTPConnectionAdapter.h in Headers */, - 324D08D21F31F5A000836E29 /* json.h in Headers */, - 324D08CB1F31F26600836E29 /* DataPack.h in Headers */, 324BE84C1F3CA31A00FFDA02 /* base64.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -6663,15 +6817,35 @@ 324D08A11F30CE2B00836E29 /* ChaosMicroUnitToolkit.cpp in Sources */, 324D08AB1F31D5EA00836E29 /* ConnectionManager.cpp in Sources */, 324D08D41F31F5A000836E29 /* mongoose.c in Sources */, + 3265F9591FB89F6B00FEA246 /* bson.c in Sources */, + 3265F9521FB89F6B00FEA246 /* bson-iter.c in Sources */, 324D08B51F31D7F300836E29 /* AbstractUnitProxy.cpp in Sources */, + 3265F9571FB89F6B00FEA246 /* bson-value.c in Sources */, 324D08C51F31EC5000836E29 /* HTTPConnectionAdapter.cpp in Sources */, 325F517E1F3C3E11000B842F /* RawDriverHandlerWrapper.cpp in Sources */, - 324D08CA1F31F26600836E29 /* DataPack.cpp in Sources */, + 3265F9531FB89F6B00FEA246 /* bson-iso8601.c in Sources */, + 3265F95C1FB89F6B00FEA246 /* bson-timegm.c in Sources */, + 3265F94E1FB89F6B00FEA246 /* bson-error.c in Sources */, + 3265F95D1FB89F6B00FEA246 /* bson-utf8.c in Sources */, + 3265F9501FB89F6B00FEA246 /* bson-string.c in Sources */, + 3265F95F1FB89F6B00FEA246 /* bson-clock.c in Sources */, + 3265F95A1FB89F6B00FEA246 /* bcon.c in Sources */, + 3265F95E1FB89F6B00FEA246 /* bson-reader.c in Sources */, + 3265F9511FB89F6B00FEA246 /* bson-keys.c in Sources */, + 3265F94F1FB89F6B00FEA246 /* bson-atomic.c in Sources */, 325F51821F3C3E4D000B842F /* UnitProxyHandlerWrapper.cpp in Sources */, 324BE84B1F3CA31A00FFDA02 /* base64.cpp in Sources */, + 3265F9601FB8A12B00FEA246 /* jsonsl.c in Sources */, + 3265F94C1FB89F6B00FEA246 /* bson-context.c in Sources */, + 3265F94B1FB899D400FEA246 /* DataPack.cpp in Sources */, 324D08B01F31D70600836E29 /* AbstractConnectionAdapter.cpp in Sources */, + 3265F9561FB89F6B00FEA246 /* bson-writer.c in Sources */, + 3265F9541FB89F6B00FEA246 /* bson-md5.c in Sources */, 325F517A1F3C3DD2000B842F /* RawDriverUnitProxy.cpp in Sources */, - 324D08D31F31F5A000836E29 /* jsoncpp.cpp in Sources */, + 3265F9551FB89F6B00FEA246 /* bson-memory.c in Sources */, + 3265F94D1FB89F6B00FEA246 /* bson-oid.c in Sources */, + 3265F9581FB89F6B00FEA246 /* bson-json.c in Sources */, + 3265F95B1FB89F6B00FEA246 /* bson-decimal128.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -7443,6 +7617,7 @@ LIBRARY_SEARCH_PATHS = "$(SRCROOT)/usr/local/lib"; MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = "-lboost_system"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; }; @@ -7495,6 +7670,7 @@ LIBRARY_SEARCH_PATHS = "$(SRCROOT)/usr/local/lib"; MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = "-lboost_system"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; }; diff --git a/chaos_micro_unit_toolkit/CMakeLists.txt b/chaos_micro_unit_toolkit/CMakeLists.txt index c8fa153f40f756fa6442fb8ff9914cc553078213..273e796826e748e9f49d5f3543b24db511c76871 100644 --- a/chaos_micro_unit_toolkit/CMakeLists.txt +++ b/chaos_micro_unit_toolkit/CMakeLists.txt @@ -13,8 +13,29 @@ SET(source ${source} connection/unit_proxy/AbstractUnitProxy.cpp connection/unit_proxy/UnitProxyHandlerWrapper.cpp) SET(source ${source} connection/unit_proxy/raw_driver/RawDriverUnitProxy.cpp connection/unit_proxy/raw_driver/RawDriverHandlerWrapper.cpp) -SET(source ${source} external_lib/jsoncpp.cpp - external_lib/mongoose.c +SET(source ${source} + external_lib/bson/bcon.c + external_lib/bson/bson-atomic.c + external_lib/bson/bson-clock.c + external_lib/bson/bson-context.c + external_lib/bson/bson-decimal128.c + external_lib/bson/bson-error.c + external_lib/bson/bson-iso8601.c + external_lib/bson/bson-iter.c + external_lib/bson/bson-json.c + external_lib/bson/bson-keys.c + external_lib/bson/bson-md5.c + external_lib/bson/bson-memory.c + external_lib/bson/bson-oid.c + external_lib/bson/bson-reader.c + external_lib/bson/bson-string.c + external_lib/bson/bson-timegm.c + external_lib/bson/bson-utf8.c + external_lib/bson/bson-value.c + external_lib/bson/bson-writer.c + external_lib/bson/bson.c + external_lib/jsonsl/jsonsl.c) +SET(source ${source} external_lib/mongoose.c external_lib/base64.cpp) IF (BUILD_FORCE_STATIC) diff --git a/chaos_micro_unit_toolkit/connection/connection_adapter/AbstractConnectionAdapter.cpp b/chaos_micro_unit_toolkit/connection/connection_adapter/AbstractConnectionAdapter.cpp index a437f5cc30f54c841b97cf90b6711824e92d5593..10688c13b63cde0a8e2e31da7740d3bd602b409b 100644 --- a/chaos_micro_unit_toolkit/connection/connection_adapter/AbstractConnectionAdapter.cpp +++ b/chaos_micro_unit_toolkit/connection/connection_adapter/AbstractConnectionAdapter.cpp @@ -33,28 +33,28 @@ adapter_request_id(0){} AbstractConnectionAdapter::~AbstractConnectionAdapter() {} -void AbstractConnectionAdapter::handleReceivedMessage(data::DataPackSharedPtr& received_message) { +void AbstractConnectionAdapter::handleReceivedMessage(data::CDWShrdPtr& received_message) { //checn whenever the message is a response or spontaneus message if(received_message->hasKey("etx_request_id") && - received_message->isInt32("etx_request_id")) { - map_req_id_response.insert(MapRequestIDResponsePair((uint32_t)received_message->getInt32("etx_request_id"), + received_message->isInt32Value("etx_request_id")) { + map_req_id_response.insert(MapRequestIDResponsePair((uint32_t)received_message->getInt32Value("etx_request_id"), received_message)); } else { queue_received_messages.push(received_message); } } -int AbstractConnectionAdapter::sendMessage(data::DataPackUniquePtr& message) { +int AbstractConnectionAdapter::sendMessage(data::CDWUniquePtr& message) { if(connection_status != ConnectionStateAccepted){ return -1; } return sendRawMessage(message); } -int AbstractConnectionAdapter::sendRequest(data::DataPackUniquePtr& message, +int AbstractConnectionAdapter::sendRequest(data::CDWUniquePtr& message, uint32_t& request_id) { request_id = adapter_request_id++; - message->addInt32("ext_request_id", request_id); + message->addInt32Value("ext_request_id", request_id); return sendMessage(message); } @@ -62,11 +62,11 @@ bool AbstractConnectionAdapter::hasMoreMessage() { return queue_received_messages.size(); } -DataPackSharedPtr AbstractConnectionAdapter::getNextMessage() { +CDWShrdPtr AbstractConnectionAdapter::getNextMessage() { if(queue_received_messages.size() == 0) { - return DataPackSharedPtr(); + return CDWShrdPtr(); } else { - DataPackSharedPtr result = queue_received_messages.front(); + CDWShrdPtr result = queue_received_messages.front(); queue_received_messages.pop(); return result; } @@ -80,8 +80,8 @@ bool AbstractConnectionAdapter::hasResponseAvailable(uint32_t request_id) { return map_req_id_response.find(request_id) != map_req_id_response.end(); } -DataPackSharedPtr AbstractConnectionAdapter::retrieveRequestResponse(uint32_t request_id) { - return DataPackSharedPtr(); +CDWShrdPtr AbstractConnectionAdapter::retrieveRequestResponse(uint32_t request_id) { + return CDWShrdPtr(); } const ConnectionState& AbstractConnectionAdapter::getConnectionState() const { diff --git a/chaos_micro_unit_toolkit/connection/connection_adapter/AbstractConnectionAdapter.h b/chaos_micro_unit_toolkit/connection/connection_adapter/AbstractConnectionAdapter.h index 58789c00b65c68efe20732acf6f3a3f51e9485ce..8831cf8c617d1b657d0d86e720ed7ba451ec5d44 100644 --- a/chaos_micro_unit_toolkit/connection/connection_adapter/AbstractConnectionAdapter.h +++ b/chaos_micro_unit_toolkit/connection/connection_adapter/AbstractConnectionAdapter.h @@ -54,9 +54,9 @@ namespace chaos { //! Abstract base class for all protocols adapter class AbstractConnectionAdapter { protected: - virtual int sendRawMessage(chaos::micro_unit_toolkit::data::DataPackUniquePtr& message) = 0; + virtual int sendRawMessage(chaos::micro_unit_toolkit::data::CDWUniquePtr& message) = 0; - void handleReceivedMessage(chaos::micro_unit_toolkit::data::DataPackSharedPtr& received_message); + void handleReceivedMessage(chaos::micro_unit_toolkit::data::CDWShrdPtr& received_message); public: const std::string protocol_endpoint; const std::string protocol_option; @@ -88,14 +88,14 @@ namespace chaos { /*! \param message that will be sent to the remote endpoint */ - int sendMessage(data::DataPackUniquePtr& message); + int sendMessage(data::CDWUniquePtr& message); //!send a request to the remote endpoint /*! \param message that will be sent to the remote endpoint \param request_id the id associated to the new request */ - int sendRequest(data::DataPackUniquePtr& message, + int sendRequest(data::CDWUniquePtr& message, uint32_t& request_id); //!check if there are message from remote endpoint @@ -107,7 +107,7 @@ namespace chaos { bool hasMoreMessage(); //!return the message of top of the queue - data::DataPackSharedPtr getNextMessage(); + data::CDWShrdPtr getNextMessage(); //! Chekc if there are answer by remote endpoint /*! @@ -126,11 +126,11 @@ namespace chaos { /*! \param request_id the id associated to a request */ - data::DataPackSharedPtr retrieveRequestResponse(uint32_t request_id); + data::CDWShrdPtr retrieveRequestResponse(uint32_t request_id); protected: //!define the maps for the request response - typedef std::map<uint32_t, data::DataPackSharedPtr> MapRequestIDResponse; - typedef std::pair<uint32_t, data::DataPackSharedPtr> MapRequestIDResponsePair; + typedef std::map<uint32_t, data::CDWShrdPtr> MapRequestIDResponse; + typedef std::pair<uint32_t, data::CDWShrdPtr> MapRequestIDResponsePair; typedef MapRequestIDResponse::iterator MapRequestIDResponseIterator; //!the counter of the request id @@ -140,7 +140,7 @@ namespace chaos { //!define the map that asscoiate the request id to the reponse MapRequestIDResponse map_req_id_response; //!contains the received message in the order as the have been received - std::queue<data::DataPackSharedPtr> queue_received_messages; + std::queue<data::CDWShrdPtr> queue_received_messages; }; } } diff --git a/chaos_micro_unit_toolkit/connection/connection_adapter/http/HTTPConnectionAdapter.cpp b/chaos_micro_unit_toolkit/connection/connection_adapter/http/HTTPConnectionAdapter.cpp index 7bc556c41cccd44f12f07780b17a36b58a40a62e..144364d01328ee27b59d7d9d7accfe5a04ae9d84 100644 --- a/chaos_micro_unit_toolkit/connection/connection_adapter/http/HTTPConnectionAdapter.cpp +++ b/chaos_micro_unit_toolkit/connection/connection_adapter/http/HTTPConnectionAdapter.cpp @@ -68,8 +68,8 @@ int HTTPConnectionAdapter::close() { #pragma mark PrivateMethod -int HTTPConnectionAdapter::sendRawMessage(DataPackUniquePtr& message) { - std::string to_send = message->toUnformattedString(); +int HTTPConnectionAdapter::sendRawMessage(CDWUniquePtr& message) { + std::string to_send = message->toString(); mg_send_websocket_frame(root_conn, WEBSOCKET_OP_TEXT, to_send.c_str(), to_send.size()); return 0; } @@ -95,13 +95,14 @@ void HTTPConnectionAdapter::ev_handler(struct mg_connection *conn, case MG_EV_WEBSOCKET_FRAME: { struct websocket_message *wm = (struct websocket_message *) event_data; - data::DataPackSharedPtr received_msg_shrd_ptr(DataPack::newFromBuffer((const char*)wm->data, wm->size).release()); + std::string got_json((const char*)wm->data, wm->size); + data::CDWShrdPtr received_msg_shrd_ptr(DataPack::instanceFromJson(got_json).release()); if(http_instance->connection_status != ConnectionStateAccepted) { //at this time we need to manage the receivedm of the data unitl we not received //the dapack taht informa us for the connection accepted if(received_msg_shrd_ptr->hasKey(ACCEPTED_CONNECTION_KEY) && - received_msg_shrd_ptr->isInt32(ACCEPTED_CONNECTION_KEY)) { - int32_t accepted_value = received_msg_shrd_ptr->getInt32(ACCEPTED_CONNECTION_KEY); + received_msg_shrd_ptr->isInt32Value(ACCEPTED_CONNECTION_KEY)) { + int32_t accepted_value = received_msg_shrd_ptr->getInt32Value(ACCEPTED_CONNECTION_KEY); switch (accepted_value) { case 1: //ok diff --git a/chaos_micro_unit_toolkit/connection/connection_adapter/http/HTTPConnectionAdapter.h b/chaos_micro_unit_toolkit/connection/connection_adapter/http/HTTPConnectionAdapter.h index 0305949a7c99ca7296d60475f92a0b53decaf45a..c956a54ce638cddea1fb507107b5a9f69434b7d6 100644 --- a/chaos_micro_unit_toolkit/connection/connection_adapter/http/HTTPConnectionAdapter.h +++ b/chaos_micro_unit_toolkit/connection/connection_adapter/http/HTTPConnectionAdapter.h @@ -44,7 +44,7 @@ namespace chaos { int event, void *event_data); //!inherited method - int sendRawMessage(data::DataPackUniquePtr& message); + int sendRawMessage(chaos::micro_unit_toolkit::data::CDWUniquePtr& message); public: //! point to the protocol constant type define in @chaos::micro_unit_toolkit::connection::ConnectionType static const ConnectionType connection_type; diff --git a/chaos_micro_unit_toolkit/connection/unit_proxy/AbstractUnitProxy.cpp b/chaos_micro_unit_toolkit/connection/unit_proxy/AbstractUnitProxy.cpp index e62bb74987b2e814e3907ed4d7f06f55b3701cc6..5a860ac7acde4ecad3537231746e6b62c4a3b1b3 100644 --- a/chaos_micro_unit_toolkit/connection/unit_proxy/AbstractUnitProxy.cpp +++ b/chaos_micro_unit_toolkit/connection/unit_proxy/AbstractUnitProxy.cpp @@ -26,14 +26,14 @@ using namespace chaos::micro_unit_toolkit::data; using namespace chaos::micro_unit_toolkit::connection::unit_proxy; using namespace chaos::micro_unit_toolkit::connection::connection_adapter; -RemoteMessage::RemoteMessage(const DataPackSharedPtr& _message): +RemoteMessage::RemoteMessage(const CDWShrdPtr& _message): message(_message), -is_request((message->hasKey("req_id") && message->isInt32("req_id"))), -message_id(is_request?message->getInt32("req_id"):0){ +is_request((message->hasKey("req_id") && message->isInt32Value("req_id"))), +message_id(is_request?message->getInt32Value("req_id"):0){ if(is_request && message->hasKey("msg") && - message->isDataPack("msg")) { - request_message.reset(message->getDataPack("msg").release()); + message->isCDWValue("msg")) { + request_message.reset(message->getCDWValue("msg").release()); } } @@ -42,15 +42,15 @@ bool RemoteMessage::isError() const { } int32_t RemoteMessage::getErrorCode() const { - return message.get()?message->getInt32("error_code"):0; + return message.get()?message->getInt32Value("error_code"):0; } std::string RemoteMessage::getErrorMessage() const { - return message.get()?message->getString("error_message"):""; + return message.get()?message->getStringValue("error_message"):""; } std::string RemoteMessage::getErrorDomain() const { - return message.get()?message->getString("error_domain"):""; + return message.get()?message->getStringValue("error_domain"):""; } AbstractUnitProxy::AbstractUnitProxy(ChaosUniquePtr<connection_adapter::AbstractConnectionAdapter>& _protocol_adapter): @@ -61,7 +61,7 @@ AbstractUnitProxy::~AbstractUnitProxy() { std::cout <<"exit"; } -int AbstractUnitProxy::sendMessage(DataPackUniquePtr& message_data) { +int AbstractUnitProxy::sendMessage(CDWUniquePtr& message_data) { return connection_adapter->sendMessage(message_data); } diff --git a/chaos_micro_unit_toolkit/connection/unit_proxy/AbstractUnitProxy.h b/chaos_micro_unit_toolkit/connection/unit_proxy/AbstractUnitProxy.h index a66bdc40dbdd6bbbfe25626c905ceace34f726ec..31c5575ede7fef5d3581be4a0f2ddc0d115be8cf 100644 --- a/chaos_micro_unit_toolkit/connection/unit_proxy/AbstractUnitProxy.h +++ b/chaos_micro_unit_toolkit/connection/unit_proxy/AbstractUnitProxy.h @@ -36,11 +36,11 @@ namespace chaos { class RemoteMessage { bool is_error; public: - data::DataPackSharedPtr message; + data::CDWShrdPtr message; const bool is_request; const uint32_t message_id; - data::DataPackSharedPtr request_message; - RemoteMessage(const data::DataPackSharedPtr& _message); + data::CDWShrdPtr request_message; + RemoteMessage(const data::CDWShrdPtr& _message); bool isError() const; int32_t getErrorCode() const; @@ -63,7 +63,7 @@ namespace chaos { ChaosUniquePtr<connection_adapter::AbstractConnectionAdapter> connection_adapter; protected: AuthorizationState authorization_state; - virtual int sendMessage(data::DataPackUniquePtr& message_data); + virtual int sendMessage(data::CDWUniquePtr& message_data); bool hasMoreMessage(); diff --git a/chaos_micro_unit_toolkit/connection/unit_proxy/UnitProxyHandlerWrapper.h b/chaos_micro_unit_toolkit/connection/unit_proxy/UnitProxyHandlerWrapper.h index d3f750bcf151ae55f4a4b4fe80535d86a3338ab9..56dbe7d9a42428aef5e8396e35f008afa10a74b0 100644 --- a/chaos_micro_unit_toolkit/connection/unit_proxy/UnitProxyHandlerWrapper.h +++ b/chaos_micro_unit_toolkit/connection/unit_proxy/UnitProxyHandlerWrapper.h @@ -33,12 +33,12 @@ namespace chaos { namespace unit_proxy { struct UPMessage { - data::DataPackSharedPtr message; + data::CDWShrdPtr message; }; struct UPRequest { - data::DataPackSharedPtr message; - data::DataPackUniquePtr response; + data::CDWShrdPtr message; + data::CDWUniquePtr response; }; struct UPError { diff --git a/chaos_micro_unit_toolkit/connection/unit_proxy/raw_driver/RawDriverHandlerWrapper.cpp b/chaos_micro_unit_toolkit/connection/unit_proxy/raw_driver/RawDriverHandlerWrapper.cpp index 078a67761eb4f838e1d208984141f8261691cbd9..b6838dbd48d4f26e8b395d9f7d81b3d3c446cf84 100644 --- a/chaos_micro_unit_toolkit/connection/unit_proxy/raw_driver/RawDriverHandlerWrapper.cpp +++ b/chaos_micro_unit_toolkit/connection/unit_proxy/raw_driver/RawDriverHandlerWrapper.cpp @@ -44,7 +44,7 @@ authorized(false){} RawDriverHandlerWrapper::~RawDriverHandlerWrapper(){} -int RawDriverHandlerWrapper::sendMessage(data::DataPackUniquePtr& message_data) { +int RawDriverHandlerWrapper::sendMessage(data::CDWUniquePtr& message_data) { RawDriverUnitProxy * const rd = static_cast<RawDriverUnitProxy*>(base_unit.get()); return rd->sendMessage(message_data); } @@ -89,7 +89,7 @@ int RawDriverHandlerWrapper::manageRemoteMessage() { if(remote_message->is_request && remote_message->request_message.get()) { if(remote_message->request_message->hasKey("opcode") && - remote_message->request_message->isInt32("opcode")){ + remote_message->request_message->isInt32Value("opcode")){ UPRequest req = {remote_message->request_message, ChaosUniquePtr<DataPack>(new DataPack())}; if((err = callHandler(UP_EV_REQ_RECEIVED, &req)) == 0) { diff --git a/chaos_micro_unit_toolkit/connection/unit_proxy/raw_driver/RawDriverHandlerWrapper.h b/chaos_micro_unit_toolkit/connection/unit_proxy/raw_driver/RawDriverHandlerWrapper.h index 7f65576687318397fc77c4af1087c7699349dda5..069fec0fd12f9e48be876da6987cdce6d8abbbb5 100644 --- a/chaos_micro_unit_toolkit/connection/unit_proxy/raw_driver/RawDriverHandlerWrapper.h +++ b/chaos_micro_unit_toolkit/connection/unit_proxy/raw_driver/RawDriverHandlerWrapper.h @@ -47,7 +47,7 @@ namespace chaos { ~RawDriverHandlerWrapper(); //! send spontaneus message to the remote raw driver layer - int sendMessage(data::DataPackUniquePtr& message_data); + int sendMessage(data::CDWUniquePtr& message_data); }; } diff --git a/chaos_micro_unit_toolkit/connection/unit_proxy/raw_driver/RawDriverUnitProxy.cpp b/chaos_micro_unit_toolkit/connection/unit_proxy/raw_driver/RawDriverUnitProxy.cpp index 79b12d549f6c9a784fc0e9d336c27ea6685180c8..dd6e571d905eb6d4e479687c771f62c1653df253 100644 --- a/chaos_micro_unit_toolkit/connection/unit_proxy/raw_driver/RawDriverUnitProxy.cpp +++ b/chaos_micro_unit_toolkit/connection/unit_proxy/raw_driver/RawDriverUnitProxy.cpp @@ -40,8 +40,8 @@ RawDriverUnitProxy::~RawDriverUnitProxy() {} void RawDriverUnitProxy::authorization(const std::string& authorization_key) { authorization_state = AuthorizationStateRequested; - data::DataPackUniquePtr message(new data::DataPack()); - message->addString(AUTHORIZATION_KEY, authorization_key); + data::CDWUniquePtr message(new data::DataPack()); + message->addStringValue(AUTHORIZATION_KEY, authorization_key); AbstractUnitProxy::sendMessage(message); } @@ -51,8 +51,8 @@ bool RawDriverUnitProxy::manageAutorizationPhase() { //!check authentication state RemoteMessageUniquePtr result = getNextMessage(); if(result->message->hasKey(AUTHORIZATION_STATE) || - result->message->isBool(AUTHORIZATION_STATE)) { - authorization_state = (AuthorizationState)result->message->getBool(AUTHORIZATION_STATE); + result->message->isBoolValue(AUTHORIZATION_STATE)) { + authorization_state = (AuthorizationState)result->message->getBoolValue(AUTHORIZATION_STATE); } } return result; @@ -65,7 +65,7 @@ int RawDriverUnitProxy::sendMessage(DataPackUniquePtr& message_data) { } int RawDriverUnitProxy::sendAnswer(RemoteMessageUniquePtr& message, - DataPackUniquePtr& message_data) { + CDWUniquePtr& message_data) { if(message->is_request == false) return - 1; DataPackUniquePtr answer(new DataPack()); answer->addInt32(REQUEST_IDENTIFICATION, message->message_id); diff --git a/chaos_micro_unit_toolkit/connection/unit_proxy/raw_driver/RawDriverUnitProxy.h b/chaos_micro_unit_toolkit/connection/unit_proxy/raw_driver/RawDriverUnitProxy.h index 93221d986a2f00a6cee7a4a9269a5dd82c5232c7..2cc44dbf6ce02416b104f2c21ee8240616ec3895 100644 --- a/chaos_micro_unit_toolkit/connection/unit_proxy/raw_driver/RawDriverUnitProxy.h +++ b/chaos_micro_unit_toolkit/connection/unit_proxy/raw_driver/RawDriverUnitProxy.h @@ -39,8 +39,8 @@ namespace chaos { void authorization(const std::string& authorization_key); bool manageAutorizationPhase(); int sendAnswer(RemoteMessageUniquePtr& message, - data::DataPackUniquePtr& message_data); - int sendMessage(data::DataPackUniquePtr& message_data); + data::CDWUniquePtr& message_data); + int sendMessage(data::CDWUniquePtr& message_data); using AbstractUnitProxy::sendMessage; using AbstractUnitProxy::hasMoreMessage; using AbstractUnitProxy::getNextMessage; diff --git a/chaos_micro_unit_toolkit/data/DataPack.cpp b/chaos_micro_unit_toolkit/data/DataPack.cpp index 409466245c8ca718aaeb87d7c59ca8e64311a0e5..373bc7ce32c90c84bfcd3df79635c6276214eef0 100644 --- a/chaos_micro_unit_toolkit/data/DataPack.cpp +++ b/chaos_micro_unit_toolkit/data/DataPack.cpp @@ -1,165 +1,733 @@ /* - * Copyright 2012, 2017 INFN + * DataPack.cpp + * !CHAOS + * Created by Bisegni Claudio. * - * Licensed under the EUPL, Version 1.2 or – as soon they - * will be approved by the European Commission - subsequent - * versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the - * Licence. - * You may obtain a copy of the Licence at: + * Copyright 2012 INFN, National Institute of Nuclear Physics * - * https://joinup.ec.europa.eu/software/page/eupl + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Unless required by applicable law or agreed to in - * writing, software distributed under the Licence is - * distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. - * See the Licence for the specific language governing - * permissions and limitations under the Licence. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - #include <chaos_micro_unit_toolkit/data/DataPack.h> -#include <chaos_micro_unit_toolkit/external_lib/base64.h> - -using namespace Json; -using namespace chaos::micro_unit_toolkit; +#include <cassert> using namespace chaos::micro_unit_toolkit::data; -DataPackUniquePtr DataPack::newFromBuffer(const char *data, - const size_t data_len, - bool *parsed) { - DataPackUniquePtr new_dp(new DataPack()); - Reader reader; - bool parse_result = reader.parse(data, - data+data_len, - new_dp->root_json_object); - if(parsed){*parsed = parse_result;} - return new_dp; +#pragma mark Utility + +#define ALLOCATE_BSONT(x) ChaosBsonShrdPtr(x, &bsonDeallocator) + +#define ACCESS_BSON(x) static_cast<bson_t*>(x.get()) + +#define ENSURE_ARRAY(x) \ +if(x.get() == NULL) {array_index = 0; x = ALLOCATE_BSONT(bson_new());} + +#define FIND_AND_CHECK(k,c)\ +bson_iter_t element_found;\ +bson_iter_init(&element_found, ACCESS_BSON(bson));\ +if(bson_iter_find_case(&element_found, key.c_str()) && c(&element_found)) + +static void bsonDeallocator(bson_t* bson) {if(bson){bson_destroy(bson);}} + +#pragma mark DataPack +DataPack::DataPack(): +bson(ALLOCATE_BSONT(bson_new())), +array_index(0){ + assert(bson); +} + +DataPack::DataPack(const bson_t *copy_bson): +bson(ALLOCATE_BSONT(bson_copy(copy_bson))), +array_index(0){} + +DataPack::DataPack(const char* mem_ser, + uint32_t mem_size): +bson(ALLOCATE_BSONT(bson_new_from_data((const uint8_t*)mem_ser, + mem_size))), +array_index(0){ + assert(bson); +} + +DataPack::DataPack(const char* mem_ser): +array_index(0) { + uint32_t size = BSON_UINT32_FROM_LE(*reinterpret_cast<const uint32_t *>(mem_ser)); + bson = ALLOCATE_BSONT(bson_new_from_data((const uint8_t*)mem_ser, + size)); + assert(bson); +} + +DataPack::DataPack(const std::string& json_document): +array_index(0) { + bson_error_t err; + bson = ALLOCATE_BSONT(bson_new_from_json((const uint8_t*)json_document.c_str(), + json_document.size(), + &err)); + assert(bson); +} + +DataPack::~DataPack(){} + +CDWUniquePtr DataPack::instanceFromJson(const std::string& json_serialization) { + return CDWUniquePtr(new DataPack(json_serialization)); +} + +DataPack *DataPack::clone() { + return new DataPack(bson.get()); +} + + +//add a csdata value +void DataPack::addCDWValue(const std::string& key, + const DataPack& value) { + bson_append_document(ACCESS_BSON(bson), + key.c_str(), + (int)key.size(), + ACCESS_BSON(value.bson)); +} + +//add a string value +void DataPack::addStringValue(const std::string& key, const std::string& value) { + bson_append_utf8(ACCESS_BSON(bson), + key.c_str(), + (int)key.size(), + value.c_str(), + (int)value.size()); +} + +//append a strin gto an open array +void DataPack::appendStringToArray(const std::string& value) { + ENSURE_ARRAY(bson_tmp_array); + char str[12]; + sprintf(str, "%d", array_index++); + bson_append_utf8(ACCESS_BSON(bson_tmp_array), + str, + -1, + value.c_str(), + (int)value.size()); +} + +//append a strin gto an open array +void DataPack::appendInt32ToArray(int32_t value) { + ENSURE_ARRAY(bson_tmp_array); + char str[12]; + sprintf(str, "%d", array_index++); + bson_append_int32(ACCESS_BSON(bson_tmp_array), + str, + -1, + value); +} + +//append a strin gto an open array +void DataPack::appendInt64ToArray(int64_t value) { + ENSURE_ARRAY(bson_tmp_array); + char str[12]; + sprintf(str, "%d", array_index++); + bson_append_int64(ACCESS_BSON(bson_tmp_array), + str, + -1, + value); +} + +//append a strin gto an open array +void DataPack::appendDoubleToArray(double value) { + ENSURE_ARRAY(bson_tmp_array); + char str[12]; + sprintf(str, "%d", array_index++); + bson_append_double(ACCESS_BSON(bson_tmp_array), + str, + -1, + value); +} + +//appen a DataPack to an open array +void DataPack::appendDataPackToArray(DataPack& value) { + ENSURE_ARRAY(bson_tmp_array); + char str[12]; + sprintf(str, "%d", array_index++); + bson_append_document(ACCESS_BSON(bson_tmp_array), + str, + -1, + value.bson.get()); +} + +//finalize the array into a key for the current dataobject +void DataPack::finalizeArrayForKey(const std::string& key) { + ENSURE_ARRAY(bson_tmp_array); + bson_append_array(ACCESS_BSON(bson), + key.c_str(), + (int)key.size(), + bson_tmp_array.get()); + bson_tmp_array.reset(); +} + +//return a vectorvalue for a key +CMultiTypeDataArrayWrapper* DataPack::getVectorValue(const std::string& key) const{ + return new CMultiTypeDataArrayWrapper(bson, + key); +} + +void DataPack::addNullValue(const std::string& key) { + bson_append_null(ACCESS_BSON(bson), + key.c_str(), + (int)key.size()); +} +//add a long value +void DataPack::addInt32Value(const std::string& key, int32_t value) { + bson_append_int32(ACCESS_BSON(bson), + key.c_str(), + (int)key.size(), + value); +} +//add a long value +void DataPack::addInt32Value(const std::string& key, uint32_t value) { + bson_append_int32(ACCESS_BSON(bson), + key.c_str(), + (int)key.size(), + static_cast<int32_t>(value)); +} +//add a double value +void DataPack::addDoubleValue(const std::string& key, double value) { + bson_append_double(ACCESS_BSON(bson), + key.c_str(), + (int)key.size(), + value); +} + +//add a integer value +void DataPack::addInt64Value(const std::string& key, int64_t value) { + bson_append_int64(ACCESS_BSON(bson), + key.c_str(), + (int)key.size(), + value); +} + +//add a integer value +void DataPack::addInt64Value(const std::string& key, uint64_t value) { + bson_append_int64(ACCESS_BSON(bson), + key.c_str(), + (int)key.size(), + static_cast<int64_t>(value)); +} + +CDWUniquePtr DataPack::getCDWValue(const std::string& key) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_DOCUMENT){ + uint32_t document_len = 0; + const uint8_t *document = NULL; + bson_iter_document(&element_found, + &document_len, + &document); + return CDWUniquePtr(new DataPack((const char *)document,document_len)); + } else { + return CDWUniquePtr(new DataPack()); + } } -DataPack::DataPack() {} +//get string value +std::string DataPack::getStringValue(const std::string& key) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_UTF8){ + return std::string(bson_iter_utf8(&element_found, NULL)); + } + return std::string(); +} -DataPack::DataPack(const Value& src_root_json_object): -root_json_object(src_root_json_object){} +//get string value +const char * DataPack::getCStringValue(const std::string& key) const{ + return getRawValuePtr(key); +} -DataPack::~DataPack() {} +//add a integer value +int32_t DataPack::getInt32Value(const std::string& key, + int32_t default_value) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_INT32){ + return bson_iter_int32(&element_found); + } else { + return default_value; + } +} +//add a integer value +uint32_t DataPack::getUInt32Value(const std::string& key, + uint32_t default_value) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_INT32){ + return static_cast<uint32_t>(bson_iter_int32(&element_found)); + } else { + return default_value; + } +} +//add a integer value +int64_t DataPack::getInt64Value(const std::string& key, + int64_t default_value) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_INT64){ + return bson_iter_int64(&element_found); + } else { + return default_value; + } +} +//add a integer value +uint64_t DataPack::getUInt64Value(const std::string& key, + uint64_t default_value) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_INT64){ + return static_cast<uint64_t>(bson_iter_int64(&element_found)); + } else { + return default_value; + } +} +//add a integer value +double DataPack::getDoubleValue(const std::string& key, + double default_value) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_DOUBLE){ + return bson_iter_double(&element_found); + } else { + return default_value; + } +} -bool DataPack::hasKey(const std::string& key) { - return root_json_object.isMember(key); +//get a bool value +bool DataPack::getBoolValue(const std::string& key, + bool default_value) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_BOOL){ + return bson_iter_bool(&element_found); + } else { + return default_value; + } } -void DataPack::addBool(const std::string& key, bool value) { - root_json_object[key] = Value(value); +//set a binary data value +void DataPack::addBinaryValue(const std::string& key, + const char *buff, + int bufLen) { + bson_append_binary(ACCESS_BSON(bson), + key.c_str(), + (int)key.size(), + BSON_SUBTYPE_BINARY, + (const uint8_t *)buff, + bufLen); } -const bool DataPack::isBool(const std::string& key) const { - return root_json_object[key].isBool(); + +//return the binary data value +const char* DataPack::getBinaryValue(const std::string& key, uint32_t& bufLen) const{ + const uint8_t* ret = NULL; + unsigned int sub; + FIND_AND_CHECK(key, BSON_ITER_HOLDS_BINARY){ + bson_iter_binary(&element_found, + &sub, + &bufLen, + &ret); + } + return (const char*)ret; } -const bool DataPack::getBool(const std::string& key) const { - return root_json_object[key].asBool(); +//check if the key is present in data wrapper +bool DataPack::hasKey(const std::string& key) const{ + return bson_has_field(ACCESS_BSON(bson), key.c_str()); } -void DataPack::addInt32(const std::string& key, - int32_t value) { - root_json_object[key] = Value(value); + +bool DataPack::isVector(const std::string& key) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_ARRAY){ + return true; + } else { + return false; + } } -const bool DataPack::isInt32(const std::string& key) const { - return root_json_object[key].isInt(); + +//return all key contained into the object +void DataPack::getAllKey(std::vector<std::string>& contained_key) const { + bson_iter_t it; + bson_iter_init(&it, ACCESS_BSON(bson)); + while(bson_iter_next(&it)) { + contained_key.push_back(bson_iter_key(&it)); + } } -const int32_t DataPack::getInt32(const std::string& key) const { - return root_json_object[key].asInt(); + +//return all key contained into the object +void DataPack::getAllKey(std::set<std::string>& contained_key) const { + bson_iter_t it; + bson_iter_init(&it, ACCESS_BSON(bson)); + while(bson_iter_next(&it)) { + contained_key.insert(bson_iter_key(&it)); + } } -void DataPack::addInt64(const std::string& key, - int64_t value) { - root_json_object[key] = Value(value); + +//return all key contained into the object +uint32_t DataPack::getValueSize(const std::string& key) const{ + bson_iter_t it; + bson_iter_init(&it, ACCESS_BSON(bson)); + if(bson_iter_find_case(&it, key.c_str()) == false) return 0; + const bson_value_t *v = bson_iter_value(&it); + switch(v->value_type) { + case BSON_TYPE_INT64: + return sizeof(int64_t); + case BSON_TYPE_INT32: + return sizeof(int32_t); + case BSON_TYPE_BOOL: + return sizeof(bool); + case BSON_TYPE_DOUBLE: + return sizeof(double); + case BSON_TYPE_UTF8: + return v->value.v_utf8.len; + case BSON_TYPE_BINARY: + return v->value.v_binary.data_len; + case BSON_TYPE_ARRAY:{ + uint32_t array_len = 0; + const uint8_t *array = NULL; + bson_iter_array(&it, &array_len, &array); + return array_len; + } + case BSON_TYPE_DOCUMENT:{ + return v->value.v_doc.data_len; + } + default: + return 0; + break; + } + return 0; } -const bool DataPack::isInt64(const std::string& key) const { - return root_json_object[key].isInt64(); + +//! return the raw value ptr address +const char * DataPack::getRawValuePtr(const std::string& key) const{ + bson_iter_t it; + bson_iter_init(&it, ACCESS_BSON(bson)); + if(bson_iter_find_case(&it, key.c_str()) == false) return 0; + const bson_value_t *v = bson_iter_value(&it); + switch(v->value_type) { + case BSON_TYPE_INT64: + return reinterpret_cast<const char*>(&v->value.v_int64); + case BSON_TYPE_INT32: + return reinterpret_cast<const char*>(&v->value.v_int32); + case BSON_TYPE_BOOL: + return reinterpret_cast<const char*>(&v->value.v_bool); + case BSON_TYPE_DOUBLE: + return reinterpret_cast<const char*>(&v->value.v_double); + case BSON_TYPE_UTF8: + return static_cast<const char*>(v->value.v_utf8.str); + case BSON_TYPE_BINARY: + return reinterpret_cast<const char*>(v->value.v_binary.data); + case BSON_TYPE_ARRAY:{ + uint32_t array_len = 0; + const uint8_t *array = NULL; + bson_iter_array(&it, &array_len, &array); + return reinterpret_cast<const char*>(array); + } + case BSON_TYPE_DOCUMENT:{ + return reinterpret_cast<const char*>(v->value.v_doc.data); + } + default: + return NULL; + break; + } + } -const int64_t DataPack::getInt64(const std::string& key) const { - return root_json_object[key].asInt64(); + +void DataPack::addBoolValue(const std::string& key, bool value) { + bson_append_bool(ACCESS_BSON(bson), + key.c_str(), + (int)key.size(), + value); } -void DataPack::addDouble(const std::string& key, - double value) { - root_json_object[key] = Value(value); + +const char* DataPack::getBSONRawData() const{ + return reinterpret_cast<const char*>(bson_get_data(ACCESS_BSON(bson))); } -const bool DataPack::isDouble(const std::string& key) const { - return root_json_object[key].isDouble(); + +const int DataPack::getBSONRawSize() const{ + return bson->len; } -const double DataPack::getDouble(const std::string& key) const { - return root_json_object[key].asDouble(); + +//return the json data +std::string DataPack::toString() const{ + size_t str_size = 0; + char * str_c = bson_as_extended_json(ACCESS_BSON(bson), + &str_size); + std::string result(str_c); + bson_free(str_c); + return result; +} +//reinitialize the object with bson data +void DataPack::setSerializedData(const char* bson_data) { + bson_iter_t it; + size_t len = (size_t)BSON_UINT32_FROM_LE(*reinterpret_cast<const uint32_t *>(bson_data)); + if(!bson_iter_init_from_data(&it, + reinterpret_cast<const uint8_t *>(bson_data), + len)) return; + while(bson_iter_next(&it)){ + bson_append_value(ACCESS_BSON(bson), + bson_iter_key(&it), + -1, + bson_iter_value(&it)); + } + } -void DataPack::addString(const std::string& key, - const std::string& value) { - root_json_object[key] = Value(value); + +//reinitialize the object with bson data +void DataPack::setSerializedJsonData(const char* json_data) { + bson_error_t err; + size_t len = (size_t)strlen(json_data); + bson =ALLOCATE_BSONT(bson_new_from_json((const uint8_t*)json_data, + len, + &err)); + assert(bson); } -const bool DataPack::isString(const std::string& key) const { - return root_json_object[key].isString(); + +//append all elemento of an +void DataPack::appendAllElement(DataPack& src_cdw) { + bson_iter_t it; + bson_iter_init(&it, ACCESS_BSON(src_cdw.bson)); + while (bson_iter_next(&it)) { + bson_append_value(ACCESS_BSON(bson), + bson_iter_key(&it), + -1, + bson_iter_value(&it)); + } } -std::string DataPack::getString(const std::string& key) const { - return root_json_object[key].asString(); + +bool DataPack::copyKeyTo(const std::string& key_to_copy, + DataPack& destination) { + return copyKeyToNewKey(key_to_copy, + key_to_copy, + destination); } -void DataPack::addDataPack(const std::string& key, - DataPack& value) { - root_json_object[key] = value.root_json_object; + +//!copy a key(with value) from this instance to another DataPack witha new key +bool DataPack::copyKeyToNewKey(const std::string& key_to_copy, + const std::string& new_key, + DataPack& destination) { + bson_iter_t it; + bson_iter_init(&it, ACCESS_BSON(bson)); + if(bson_iter_find_case(&it, key_to_copy.c_str()) == false) return false; + bson_append_value(ACCESS_BSON(destination.bson), + new_key.c_str(), + (int)new_key.size(), + bson_iter_value(&it)); + return true; } -const bool DataPack::isDataPack(const std::string& key) const { - return root_json_object[key].isObject(); + +void DataPack::copyAllTo(DataPack& destination) { + bson_iter_t it; + bson_iter_init(&it, ACCESS_BSON(bson)); + while (bson_iter_next(&it)) { + bson_append_value(ACCESS_BSON(destination.bson), + bson_iter_key(&it), + -1, + bson_iter_value(&it)); + } } -DataPackUniquePtr DataPack::getDataPack(const std::string& key) const { - return DataPackUniquePtr(new DataPack(root_json_object[key])); + +//reset the datawrapper +void DataPack::reset() { + bson_reinit(ACCESS_BSON(bson)); + bson_tmp_array.reset(); } -void DataPack::addBinary(const std::string& key, - const char *s, - const unsigned int len) { - root_json_object[key] = Value(base64_encode(reinterpret_cast<const unsigned char*>(s), len)); +std::string DataPack::toHash() const{ + char ret[33]; + bson_md5_t m; + uint8_t digest[16]; + bson_md5_init(&m); + bson_md5_append(&m, + bson_get_data(ACCESS_BSON(bson)), + bson->len); + bson_md5_finish(&m, + digest); + memset(ret, 0, 33); + for(int i = 0; i < 16; ++i) { + sprintf(&ret[i*2], "%02x", (unsigned int)digest[i]); + } + return std::string(ret, 33); } -std::string DataPack::getBinary(const std::string& key) { - return base64_decode(root_json_object[key].asString()); + +//------------------------checking utility + +bool DataPack::isNullValue(const std::string& key) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_NULL){ + return true; + } + return false; } -void DataPack::createArrayForKey(const std::string& key) { - root_json_object[key] = Value(arrayValue); +bool DataPack::isBoolValue(const std::string& key) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_BOOL){ + return true; + } + return false; } -const bool DataPack::isArray(const std::string& key) const { - return root_json_object[key].isArray(); + +bool DataPack::isInt32Value(const std::string& key) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_INT32){ + return true; + } + return false; } -void DataPack::appendBool(const std::string& arr_key, - bool value) { - root_json_object[arr_key].append(Value(value)); + +bool DataPack::isInt64Value(const std::string& key) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_INT64){ + return true; + } + return false; } -void DataPack::appendInt32(const std::string& arr_key, - int32_t value) { - root_json_object[arr_key].append(Value(value)); +bool DataPack::isDoubleValue(const std::string& key) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_DOUBLE){ + return true; + } + return false; } -void DataPack::appendInt64(const std::string& arr_key, - int64_t value) { - root_json_object[arr_key].append(Value(value)); +bool DataPack::isStringValue(const std::string& key) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_UTF8){ + return true; + } + return false; } -void DataPack::appendDouble(const std::string& arr_key, - double value) { - root_json_object[arr_key].append(Value(value)); +bool DataPack::isBinaryValue(const std::string& key) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_BINARY){ + return true; + } + return false; } -void DataPack::appendString(const std::string& arr_key, - const std::string& value) { - root_json_object[arr_key].append(Value(value)); +bool DataPack::isCDWValue(const std::string& key) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_DOCUMENT){ + return true; + } + return false; } -void DataPack::appendDataPack(const std::string& arr_key, DataPack& value) { - root_json_object[arr_key].append(value.root_json_object); +bool DataPack::isVectorValue(const std::string& key) const{ + FIND_AND_CHECK(key, BSON_ITER_HOLDS_ARRAY){ + return true; + } + return false; } -std::string DataPack::toString() { - StyledWriter w; - return w.write(root_json_object); +DataPackType DataPack::getValueType(const std::string& key) const{ + DataPackType result = DataPackTypeNoType; + bson_iter_t it; + bson_iter_init(&it, ACCESS_BSON(bson)); + if(bson_iter_find_case(&it, key.c_str()) == false) return result; + switch(bson_iter_type(&it)) { + case BSON_TYPE_ARRAY: + result = DataPackTypeVector; + break; + case BSON_TYPE_DOCUMENT: + result = DataPackTypeObject; + break; + case BSON_TYPE_BINARY: + result = DataPackTypeBinary; + break; + case BSON_TYPE_UTF8: + result = DataPackTypeString; + break; + case BSON_TYPE_DOUBLE: + result = DataPackTypeDouble; + break; + case BSON_TYPE_INT32: + result = DataPackTypeInt32; + break; + case BSON_TYPE_INT64: + result = DataPackTypeInt64; + break; + case BSON_TYPE_BOOL: + result = DataPackTypeBool; + break; + case BSON_TYPE_NULL: + result = DataPackTypeNULL; + break; + default: + break; + + } + return result; } -std::string DataPack::toUnformattedString() { - FastWriter w; - return w.write(root_json_object); +bool DataPack::isEmpty() const { + return (bson_count_keys(ACCESS_BSON(bson)) == 0); +} + +#pragma mark CMultiTypeDataArrayWrapper +CMultiTypeDataArrayWrapper::CMultiTypeDataArrayWrapper(const ChaosBsonShrdPtr& _document_shrd_ptr, + const std::string& key): +document_shrd_ptr(_document_shrd_ptr) { + bson_iter_t element_found; + bson_iter_init(&element_found, ACCESS_BSON(_document_shrd_ptr)); + if(bson_iter_find_case(&element_found, key.c_str())&& + BSON_ITER_HOLDS_ARRAY(&element_found)) { + uint32_t array_len; + const uint8_t *array; + bson_iter_array(&element_found, + &array_len, + &array); + + if (bson_init_static(&array_doc, array, array_len)) { + bson_iter_t iter; + if(bson_iter_init(&iter, &array_doc)) { + while(bson_iter_next(&iter)) { + bson_value_t copy; + bson_value_copy(bson_iter_value(&iter), ©); + values.push_back(copy); + } + } + } + } +} + +CMultiTypeDataArrayWrapper::~CMultiTypeDataArrayWrapper() { + for(VectorBsonValuesIterator it = values.begin(), + end = values.end(); + it != end; + it++) { + bson_value_destroy(&(*it)); + } +} + +std::string CMultiTypeDataArrayWrapper::getStringElementAtIndex(const int pos) const{ + assert(values[pos].value_type == BSON_TYPE_UTF8); + return std::string(values[pos].value.v_utf8.str, values[pos].value.v_utf8.len); +} + +double CMultiTypeDataArrayWrapper::getDoubleElementAtIndex(const int pos) const{ + assert(values[pos].value_type == BSON_TYPE_DOUBLE); + return values[pos].value.v_double; +} +int32_t CMultiTypeDataArrayWrapper::getInt32ElementAtIndex(const int pos) const{ + return values[pos].value.v_int32; +} +int64_t CMultiTypeDataArrayWrapper::getint64ElementAtIndex(const int pos) const{ + assert(values[pos].value_type == BSON_TYPE_INT64); + return values[pos].value.v_int64; +} + +bool CMultiTypeDataArrayWrapper::isStringElementAtIndex(const int pos) const{ + return values[pos].value_type == BSON_TYPE_UTF8; +} + +bool CMultiTypeDataArrayWrapper::isDoubleElementAtIndex(const int pos) const{ + return values[pos].value_type == BSON_TYPE_DOUBLE; +} + +bool CMultiTypeDataArrayWrapper::isInt32ElementAtIndex(const int pos) const{ + return values[pos].value_type == BSON_TYPE_INT32; +} + +bool CMultiTypeDataArrayWrapper::isInt64ElementAtIndex(const int pos) const{ + return values[pos].value_type == BSON_TYPE_INT64; +} + +bool CMultiTypeDataArrayWrapper::isDataPackElementAtIndex(const int pos) const{ + return values[pos].value_type == BSON_TYPE_DOCUMENT; +} + +DataPack* CMultiTypeDataArrayWrapper::getDataPackElementAtIndex(const int pos) const{ + assert(values[pos].value_type == BSON_TYPE_DOCUMENT); + return new DataPack((const char *)values[pos].value.v_doc.data, values[pos].value.v_doc.data_len); +} +size_t CMultiTypeDataArrayWrapper::size() const{ + return values.size(); } diff --git a/chaos_micro_unit_toolkit/data/DataPack.h b/chaos_micro_unit_toolkit/data/DataPack.h index 8dbaa1a01d262043b2933a303b567610f9a86b3c..4d38fcc0111800d9b8ad83584b535b4cc7de428f 100644 --- a/chaos_micro_unit_toolkit/data/DataPack.h +++ b/chaos_micro_unit_toolkit/data/DataPack.h @@ -1,108 +1,285 @@ /* - * Copyright 2012, 2017 INFN + * DataPack.h + * !CHAOS + * Created by Bisegni Claudio. * - * Licensed under the EUPL, Version 1.2 or – as soon they - * will be approved by the European Commission - subsequent - * versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the - * Licence. - * You may obtain a copy of the Licence at: + * Copyright 2012 INFN, National Institute of Nuclear Physics * - * https://joinup.ec.europa.eu/software/page/eupl + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Unless required by applicable law or agreed to in - * writing, software distributed under the Licence is - * distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. - * See the Licence for the specific language governing - * permissions and limitations under the Licence. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ +#ifndef DataPack_H +#define DataPack_H -#ifndef __CHAOSFramework__FF18E47_E86B_4A8B_B5CA_7EA5C789F2FB_DataPack_h -#define __CHAOSFramework__FF18E47_E86B_4A8B_B5CA_7EA5C789F2FB_DataPack_h +#pragma GCC diagnostic ignored "-Wignored-attributes" +#include <chaos_micro_unit_toolkit/external_lib/bson/bson.h> #include <chaos_micro_unit_toolkit/micro_unit_toolkit_types.h> -#include <chaos_micro_unit_toolkit/external_lib/json.h> +#include <set> +#include <string> #include <vector> - namespace chaos { namespace micro_unit_toolkit { namespace data { + + typedef enum DataPackType { + DataPackTypeNoType, + DataPackTypeNULL, + DataPackTypeBool, + DataPackTypeInt32, + DataPackTypeInt64, + DataPackTypeDouble, + DataPackTypeString, + DataPackTypeBinary, + DataPackTypeObject, + DataPackTypeVector + } DataPackType; + class DataPack; - typedef ChaosUniquePtr<DataPack> DataPackUniquePtr; - typedef ChaosSharedPtr<DataPack> DataPackSharedPtr; - //! main singleton lab entrypoint + /*! + Class to read the and arry of multivalue + */ + class CMultiTypeDataArrayWrapper; + + typedef micro_unit_toolkit::ChaosSharedPtr<bson_t> ChaosBsonShrdPtr; + typedef micro_unit_toolkit::ChaosUniquePtr<DataPack> CDWUniquePtr; + typedef micro_unit_toolkit::ChaosSharedPtr<DataPack> CDWShrdPtr; + /*! + Class that wrap the serializaiton system for data storage + */ class DataPack { - //data pointer is not owned by this object - Json::Value root_json_object; - DataPack(const Json::Value& src_root_json_object); + ChaosBsonShrdPtr bson; + + int array_index; + ChaosBsonShrdPtr bson_tmp_array; + DataPack(const bson_t *copy_bson); + explicit DataPack(const std::string& json_document); public: + DataPack(); - virtual ~DataPack(); - static DataPackUniquePtr newFromBuffer(const char *data, - const size_t data_len, - bool *parsed = NULL); - - bool hasKey(const std::string& key); - - void addBool(const std::string& key, bool value); - const bool isBool(const std::string& key) const; - const bool getBool(const std::string& key) const; - - void addInt32(const std::string& key, int32_t value); - const bool isInt32(const std::string& key) const; - const int32_t getInt32(const std::string& key) const; - - void addInt64(const std::string& key, int64_t value); - const bool isInt64(const std::string& key) const; - const int64_t getInt64(const std::string& key) const; - - void addDouble(const std::string& key, double value); - const bool isDouble(const std::string& key) const; - const double getDouble(const std::string& key) const; - - void addString(const std::string& key, const std::string& value); - const bool isString(const std::string& key) const; - std::string getString(const std::string& key) const; - - void addDataPack(const std::string& key, DataPack& value); - const bool isDataPack(const std::string& key) const; - DataPackUniquePtr getDataPack(const std::string& key) const; - - void addBinary(const std::string& key, - const char *s, - const unsigned int len); - std::string getBinary(const std::string& key); - void createArrayForKey(const std::string& key); - const bool isArray(const std::string& key) const; - void appendBool(const std::string& arr_key, bool value); - void appendInt32(const std::string& arr_key, int32_t value); - void appendInt64(const std::string& arr_key, int64_t value); - void appendDouble(const std::string& arr_key, double value); - void appendString(const std::string& arr_key, const std::string& value); - void appendDataPack(const std::string& arr_key, DataPack& value); + explicit DataPack(const char* mem_ser, + uint32_t mem_size); + + explicit DataPack(const char* mem_ser); + ~DataPack(); + + static CDWUniquePtr instanceFromJson(const std::string& json_serialization); + + DataPack *clone(); + + //add a csdata value + void addCDWValue(const std::string& key, + const DataPack& value); + CDWUniquePtr getCDWValue(const std::string& key) const; + bool isCDWValue(const std::string& key) const; + + //add a string value + //void addStringValue(const char *, const char *); + + //add a string value + void addStringValue(const std::string&, const std::string&); + void appendStringToArray(const std::string &value); + std::string getStringValue(const std::string&) const; + + + void appendInt32ToArray(int32_t value); + void appendInt64ToArray(int64_t value); + void appendDoubleToArray(double value); + void appendDataPackToArray(DataPack& value); + //finalize the array into a key for the current dataobject + void finalizeArrayForKey(const std::string&); + + //get a string value + const char * getCStringValue(const std::string& key) const; + //return a vectorvalue for a key + CMultiTypeDataArrayWrapper* getVectorValue(const std::string&) const; + + void addNullValue(const std::string&); + + //add a integer value + void addInt32Value(const std::string&, int32_t); + + //add a integer value + void addInt32Value(const std::string&, uint32_t); + //add a integer value + void addInt64Value(const std::string&, int64_t); + //add a integer value + void addInt64Value(const std::string&, uint64_t); + + //add a double value + void addDoubleValue(const std::string&key, double dValue); + + //add a bool value + void addBoolValue(const std::string&, bool); + + //set a binary data value + void addBinaryValue(const std::string&, const char *, int); + const char* getBinaryValue(const std::string& key, uint32_t& bufLen) const; + //get a integer value + int32_t getInt32Value(const std::string& key, + int32_t default_value = 0) const; + + //get a integer value + int64_t getInt64Value(const std::string& key, + int64_t default_value = 0) const; + + //get a integer value + uint32_t getUInt32Value(const std::string& key, + uint32_t default_value = 0) const; + + //get a integer value + uint64_t getUInt64Value(const std::string& key, + uint64_t default_value = 0) const; + + //add a integer value + double getDoubleValue(const std::string& key, + double default_value = 0) const; + + //get a bool value + bool getBoolValue(const std::string&, + bool default_value = 0) const; + template<typename T> - void addArray(const std::string& key, const std::vector<T> &value) { - using namespace Json; - root_json_object[key] = Value(arrayValue); - Value& array_value = root_json_object[key]; - for(typename std::vector<T>::const_iterator it = value.begin(), - end = value.end(); - it != end; - it++) { - array_value.append(*it); + T getValue(const std::string& key) const{ + T v; + bson_iter_t element_found; + bson_iter_init(&element_found, bson.get()); + if(bson_iter_find_case(&element_found, key.c_str())){ + v = static_cast<T>(element_found.raw); } - + return v; } - std::string toString(); - std::string toUnformattedString(); + const char* getBSONRawData() const; + + const int getBSONRawSize() const; + + //return the json representation for this data wrapper + std::string toString() const; + + //reinitialize the object with bson data + void setSerializedData(const char* bsonData); + + //reinitialize the object with bson data + void setSerializedJsonData(const char* jsonData); + + //check if the key is present in data wrapper + bool hasKey(const std::string& key) const; + + bool isVector(const std::string& key) const; + + //return all key contained into the object + void getAllKey(std::vector<std::string>& contained_key) const; + + //return all key contained into the object + void getAllKey(std::set<std::string>& contained_key) const; + + //return all key contained into the object + uint32_t getValueSize(const std::string& key) const; + + //! get raw value ptr address + const char * getRawValuePtr(const std::string& key) const; + + //reset the datawrapper + void reset(); + + //append all element of an data wrapper + void appendAllElement(DataPack&); + + //!copy a key(with value) from this instance to another DataPack one + bool copyKeyTo(const std::string& key_to_copy, + DataPack& destination); + + //!copy a key(with value) from this instance to another DataPack witha new key + bool copyKeyToNewKey(const std::string& key_to_copy, + const std::string& new_key, + DataPack& destination); + + //!copy all key(with value) from this instance to another DataPack one + void copyAllTo(DataPack& destination); + + //! Return the Hashing represetnation of the DataPack + std::string toHash() const; + + //---checking funciton + + bool isNullValue(const std::string& key) const; + + bool isBoolValue(const std::string& key) const; + + bool isInt32Value(const std::string& key) const; + + bool isInt64Value(const std::string& key) const; + + bool isDoubleValue(const std::string& key) const; + + bool isStringValue(const std::string& key) const; + + bool isBinaryValue(const std::string& key) const; + + + bool isVectorValue(const std::string& key) const; + + bool isJsonValue(const std::string& key) const; + + DataPackType getValueType(const std::string& key) const; + + bool isEmpty() const; }; + + typedef std::vector<bson_value_t> VectorBsonValues; + typedef std::vector<bson_value_t>::iterator VectorBsonValuesIterator; + /*! + Class to read the and arry of multivalue + */ + class CMultiTypeDataArrayWrapper { + friend class DataPack; + const ChaosBsonShrdPtr document_shrd_ptr; + bson_t array_doc; + VectorBsonValues values; + CMultiTypeDataArrayWrapper(const ChaosBsonShrdPtr& _document_shrd_ptr, + const std::string& key); + public: + ~CMultiTypeDataArrayWrapper(); + std::string getStringElementAtIndex(const int) const; + + + double getDoubleElementAtIndex(const int) const; + int32_t getInt32ElementAtIndex(const int) const; + int64_t getint64ElementAtIndex(const int) const; + DataPack* getDataPackElementAtIndex(const int) const; + + bool isStringElementAtIndex(const int) const; + bool isDoubleElementAtIndex(const int) const; + bool isInt32ElementAtIndex(const int) const; + bool isInt64ElementAtIndex(const int) const; + bool isDataPackElementAtIndex(const int) const; + + size_t size() const; + }; + +#define CDW_GET_SRT_WITH_DEFAULT(c, k, d) ((c)->hasKey(k)?(c)->getStringValue(k):d) +#define CDW_GET_BOOL_WITH_DEFAULT(c, k, d) ((c)->hasKey(k)?(c)->getBoolValue(k):d) +#define CDW_GET_INT32_WITH_DEFAULT(c, k, d) ((c)->hasKey(k)?(c)->getInt32Value(k):d) +#define CDW_GET_INT64_WITH_DEFAULT(c, k, d) ((c)->hasKey(k)?(c)->getInt64Value(k):d) +#define CDW_GET_DOUBLE_WITH_DEFAULT(c, k, d) ((c)->hasKey(k)?(c)->getDoubleValue(k):d) +#define CDW_CHECK_AND_SET(chk, cdw, t, k, v) if(chk){cdw->t(k,v);} +#define CDW_GET_VALUE_WITH_DEFAULT(c, k, t, d) ((c)->hasKey(k)?(c)->t(k):d) + + + } } } - -#endif /* __CHAOSFramework__FF18E47_E86B_4A8B_B5CA_7EA5C789F2FB_DataPack_h */ +#endif diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson.h b/chaos_micro_unit_toolkit/external_lib/bson/bson.h new file mode 100644 index 0000000000000000000000000000000000000000..41e8d9490aae439095509feda337fc147c377fa0 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson.h @@ -0,0 +1,14 @@ +// +// bson.h +// CHAOSFramework +// +// Created by bisegni on 20/05/2017. +// Copyright © 2017 INFN. All rights reserved. +// + +#ifndef bson_h +#define bson_h +#include <chaos_micro_unit_toolkit/external_lib/bson/bson/bson-config.h> +#include <chaos_micro_unit_toolkit/external_lib/bson/bson/bson.h> + +#endif /* bson_h */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/b64_ntop.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/b64_ntop.h new file mode 100644 index 0000000000000000000000000000000000000000..ada76a5c80394de7d347a07c4d68edc74415caad --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/b64_ntop.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 1996, 1998 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include "bson-compat.h" +#include "bson-macros.h" +#include "bson-types.h" + +#define Assert(Cond) \ + if (!(Cond)) \ + abort () + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + * The following encoding technique is taken from RFC 1521 by Borenstein + * and Freed. It is reproduced here in a slightly edited form for + * convenience. + * + * A 65-character subset of US-ASCII is used, enabling 6 bits to be + * represented per printable character. (The extra 65th character, "=", + * is used to signify a special processing function.) + * + * The encoding process represents 24-bit groups of input bits as output + * strings of 4 encoded characters. Proceeding from left to right, a + * 24-bit input group is formed by concatenating 3 8-bit input groups. + * These 24 bits are then treated as 4 concatenated 6-bit groups, each + * of which is translated into a single digit in the base64 alphabet. + * + * Each 6-bit group is used as an index into an array of 64 printable + * characters. The character referenced by the index is placed in the + * output string. + * + * Table 1: The Base64 Alphabet + * + * Value Encoding Value Encoding Value Encoding Value Encoding + * 0 A 17 R 34 i 51 z + * 1 B 18 S 35 j 52 0 + * 2 C 19 T 36 k 53 1 + * 3 D 20 U 37 l 54 2 + * 4 E 21 V 38 m 55 3 + * 5 F 22 W 39 n 56 4 + * 6 G 23 X 40 o 57 5 + * 7 H 24 Y 41 p 58 6 + * 8 I 25 Z 42 q 59 7 + * 9 J 26 a 43 r 60 8 + * 10 K 27 b 44 s 61 9 + * 11 L 28 c 45 t 62 + + * 12 M 29 d 46 u 63 / + * 13 N 30 e 47 v + * 14 O 31 f 48 w (pad) = + * 15 P 32 g 49 x + * 16 Q 33 h 50 y + * + * Special processing is performed if fewer than 24 bits are available + * at the end of the data being encoded. A full encoding quantum is + * always completed at the end of a quantity. When fewer than 24 input + * bits are available in an input group, zero bits are added (on the + * right) to form an integral number of 6-bit groups. Padding at the + * end of the data is performed using the '=' character. + * + * Since all base64 input is an integral number of octets, only the + * following cases can arise: + * + * (1) the final quantum of encoding input is an integral + * multiple of 24 bits; here, the final unit of encoded + * output will be an integral multiple of 4 characters + * with no "=" padding, + * (2) the final quantum of encoding input is exactly 8 bits; + * here, the final unit of encoded output will be two + * characters followed by two "=" padding characters, or + * (3) the final quantum of encoding input is exactly 16 bits; + * here, the final unit of encoded output will be three + * characters followed by one "=" padding character. + */ + +static ssize_t +b64_ntop (uint8_t const *src, size_t srclength, char *target, size_t targsize) +{ + size_t datalength = 0; + uint8_t input[3]; + uint8_t output[4]; + size_t i; + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + Assert (output[0] < 64); + Assert (output[1] < 64); + Assert (output[2] < 64); + Assert (output[3] < 64); + + if (datalength + 4 > targsize) { + return -1; + } + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + + for (i = 0; i < srclength; i++) { + input[i] = *src++; + } + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + Assert (output[0] < 64); + Assert (output[1] < 64); + Assert (output[2] < 64); + + if (datalength + 4 > targsize) { + return -1; + } + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + + if (srclength == 1) { + target[datalength++] = Pad64; + } else { + target[datalength++] = Base64[output[2]]; + } + target[datalength++] = Pad64; + } + + if (datalength >= targsize) { + return -1; + } + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return datalength; +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/b64_pton.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/b64_pton.h new file mode 100644 index 0000000000000000000000000000000000000000..281df9220cc3c5c1dcdd2326e73acaa15ae018c8 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/b64_pton.h @@ -0,0 +1,382 @@ +/* + * Copyright (c) 1996, 1998 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include "bson-compat.h" + +#define Assert(Cond) \ + if (!(Cond)) \ + abort () + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +static int b64rmap_initialized = 0; +static uint8_t b64rmap[256]; + +static const uint8_t b64rmap_special = 0xf0; +static const uint8_t b64rmap_end = 0xfd; +static const uint8_t b64rmap_space = 0xfe; +static const uint8_t b64rmap_invalid = 0xff; + +/** + * Initializing the reverse map is not thread safe. + * Which is fine for NSD. For now... + **/ +static void +b64_initialize_rmap () +{ + int i; + unsigned char ch; + + /* Null: end of string, stop parsing */ + b64rmap[0] = b64rmap_end; + + for (i = 1; i < 256; ++i) { + ch = (unsigned char) i; + /* Whitespaces */ + if (isspace (ch)) + b64rmap[i] = b64rmap_space; + /* Padding: stop parsing */ + else if (ch == Pad64) + b64rmap[i] = b64rmap_end; + /* Non-base64 char */ + else + b64rmap[i] = b64rmap_invalid; + } + + /* Fill reverse mapping for base64 chars */ + for (i = 0; Base64[i] != '\0'; ++i) + b64rmap[(uint8_t) Base64[i]] = i; + + b64rmap_initialized = 1; +} + +static int +b64_pton_do (char const *src, uint8_t *target, size_t targsize) +{ + int tarindex, state, ch; + uint8_t ofs; + + state = 0; + tarindex = 0; + + while (1) { + ch = *src++; + ofs = b64rmap[ch]; + + if (ofs >= b64rmap_special) { + /* Ignore whitespaces */ + if (ofs == b64rmap_space) + continue; + /* End of base64 characters */ + if (ofs == b64rmap_end) + break; + /* A non-base64 character. */ + return (-1); + } + + switch (state) { + case 0: + if ((size_t) tarindex >= targsize) + return (-1); + target[tarindex] = ofs << 2; + state = 1; + break; + case 1: + if ((size_t) tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= ofs >> 4; + target[tarindex + 1] = (ofs & 0x0f) << 4; + tarindex++; + state = 2; + break; + case 2: + if ((size_t) tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= ofs >> 2; + target[tarindex + 1] = (ofs & 0x03) << 6; + tarindex++; + state = 3; + break; + case 3: + if ((size_t) tarindex >= targsize) + return (-1); + target[tarindex] |= ofs; + tarindex++; + state = 0; + break; + default: + abort (); + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for ((void) NULL; ch != '\0'; ch = *src++) + if (b64rmap[ch] != b64rmap_space) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for ((void) NULL; ch != '\0'; ch = *src++) + if (b64rmap[ch] != b64rmap_space) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target[tarindex] != 0) + return (-1); + default: + break; + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} + + +static int +b64_pton_len (char const *src) +{ + int tarindex, state, ch; + uint8_t ofs; + + state = 0; + tarindex = 0; + + while (1) { + ch = *src++; + ofs = b64rmap[ch]; + + if (ofs >= b64rmap_special) { + /* Ignore whitespaces */ + if (ofs == b64rmap_space) + continue; + /* End of base64 characters */ + if (ofs == b64rmap_end) + break; + /* A non-base64 character. */ + return (-1); + } + + switch (state) { + case 0: + state = 1; + break; + case 1: + tarindex++; + state = 2; + break; + case 2: + tarindex++; + state = 3; + break; + case 3: + tarindex++; + state = 0; + break; + default: + abort (); + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for ((void) NULL; ch != '\0'; ch = *src++) + if (b64rmap[ch] != b64rmap_space) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for ((void) NULL; ch != '\0'; ch = *src++) + if (b64rmap[ch] != b64rmap_space) + return (-1); + + default: + break; + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} + + +static int +b64_pton (char const *src, uint8_t *target, size_t targsize) +{ + if (!b64rmap_initialized) + b64_initialize_rmap (); + + if (target) + return b64_pton_do (src, target, targsize); + else + return b64_pton_len (src); +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bcon.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bcon.c new file mode 100644 index 0000000000000000000000000000000000000000..cab14ed9a568fc56ca08d66a8d55c54551a33df3 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bcon.c @@ -0,0 +1,1016 @@ +/* + * @file bcon.c + * @brief BCON (BSON C Object Notation) Implementation + */ + +/* Copyright 2009-2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include <stdio.h> + +#include "bcon.h" +#include "bson-config.h" + +/* These stack manipulation macros are used to manage append recursion in + * bcon_append_ctx_va(). They take care of some awkward dereference rules (the + * real bson object isn't in the stack, but accessed by pointer) and add in run + * time asserts to make sure we don't blow the stack in either direction */ + +#define STACK_ELE(_delta, _name) (ctx->stack[(_delta) + ctx->n]._name) + +#define STACK_BSON(_delta) \ + (((_delta) + ctx->n) == 0 ? bson : &STACK_ELE (_delta, bson)) + +#define STACK_ITER(_delta) \ + (((_delta) + ctx->n) == 0 ? &root_iter : &STACK_ELE (_delta, iter)) + +#define STACK_BSON_PARENT STACK_BSON (-1) +#define STACK_BSON_CHILD STACK_BSON (0) + +#define STACK_ITER_PARENT STACK_ITER (-1) +#define STACK_ITER_CHILD STACK_ITER (0) + +#define STACK_I STACK_ELE (0, i) +#define STACK_IS_ARRAY STACK_ELE (0, is_array) + +#define STACK_PUSH_ARRAY(statement) \ + do { \ + BSON_ASSERT (ctx->n < (BCON_STACK_MAX - 1)); \ + ctx->n++; \ + STACK_I = 0; \ + STACK_IS_ARRAY = 1; \ + statement; \ + } while (0) + +#define STACK_PUSH_DOC(statement) \ + do { \ + BSON_ASSERT (ctx->n < (BCON_STACK_MAX - 1)); \ + ctx->n++; \ + STACK_IS_ARRAY = 0; \ + statement; \ + } while (0) + +#define STACK_POP_ARRAY(statement) \ + do { \ + BSON_ASSERT (STACK_IS_ARRAY); \ + BSON_ASSERT (ctx->n != 0); \ + statement; \ + ctx->n--; \ + } while (0) + +#define STACK_POP_DOC(statement) \ + do { \ + BSON_ASSERT (!STACK_IS_ARRAY); \ + BSON_ASSERT (ctx->n != 0); \ + statement; \ + ctx->n--; \ + } while (0) + +/* This is a landing pad union for all of the types we can process with bcon. + * We need actual storage for this to capture the return value of va_arg, which + * takes multiple calls to get everything we need for some complex types */ +typedef union bcon_append { + char *UTF8; + double DOUBLE; + bson_t *DOCUMENT; + bson_t *ARRAY; + bson_t *BCON; + + struct { + bson_subtype_t subtype; + uint8_t *binary; + uint32_t length; + } BIN; + + bson_oid_t *OID; + bool BOOL; + int64_t DATE_TIME; + + struct { + char *regex; + char *flags; + } REGEX; + + struct { + char *collection; + bson_oid_t *oid; + } DBPOINTER; + + const char *CODE; + + char *SYMBOL; + + struct { + const char *js; + bson_t *scope; + } CODEWSCOPE; + + int32_t INT32; + + struct { + uint32_t timestamp; + uint32_t increment; + } TIMESTAMP; + + int64_t INT64; + bson_decimal128_t *DECIMAL128; + const bson_iter_t *ITER; +} bcon_append_t; + +/* same as bcon_append_t. Some extra symbols and varying types that handle the + * differences between bson_append and bson_iter */ +typedef union bcon_extract { + bson_type_t TYPE; + bson_iter_t *ITER; + const char *key; + const char **UTF8; + double *DOUBLE; + bson_t *DOCUMENT; + bson_t *ARRAY; + + struct { + bson_subtype_t *subtype; + const uint8_t **binary; + uint32_t *length; + } BIN; + + const bson_oid_t **OID; + bool *BOOL; + int64_t *DATE_TIME; + + struct { + const char **regex; + const char **flags; + } REGEX; + + struct { + const char **collection; + const bson_oid_t **oid; + } DBPOINTER; + + const char **CODE; + + const char **SYMBOL; + + struct { + const char **js; + bson_t *scope; + } CODEWSCOPE; + + int32_t *INT32; + + struct { + uint32_t *timestamp; + uint32_t *increment; + } TIMESTAMP; + + int64_t *INT64; + bson_decimal128_t *DECIMAL128; +} bcon_extract_t; + +static const char *gBconMagic = "BCON_MAGIC"; +static const char *gBconeMagic = "BCONE_MAGIC"; + +const char * +bson_bcon_magic (void) +{ + return gBconMagic; +} + + +const char * +bson_bcone_magic (void) +{ + return gBconeMagic; +} + +static void +_noop (void) +{ +} + +/* appends val to the passed bson object. Meant to be a super simple dispatch + * table */ +static void +_bcon_append_single (bson_t *bson, + bcon_type_t type, + const char *key, + bcon_append_t *val) +{ + switch ((int) type) { + case BCON_TYPE_UTF8: + bson_append_utf8 (bson, key, -1, val->UTF8, -1); + break; + case BCON_TYPE_DOUBLE: + bson_append_double (bson, key, -1, val->DOUBLE); + break; + case BCON_TYPE_BIN: { + bson_append_binary ( + bson, key, -1, val->BIN.subtype, val->BIN.binary, val->BIN.length); + break; + } + case BCON_TYPE_UNDEFINED: + bson_append_undefined (bson, key, -1); + break; + case BCON_TYPE_OID: + bson_append_oid (bson, key, -1, val->OID); + break; + case BCON_TYPE_BOOL: + bson_append_bool (bson, key, -1, (bool) val->BOOL); + break; + case BCON_TYPE_DATE_TIME: + bson_append_date_time (bson, key, -1, val->DATE_TIME); + break; + case BCON_TYPE_NULL: + bson_append_null (bson, key, -1); + break; + case BCON_TYPE_REGEX: { + bson_append_regex (bson, key, -1, val->REGEX.regex, val->REGEX.flags); + break; + } + case BCON_TYPE_DBPOINTER: { + bson_append_dbpointer ( + bson, key, -1, val->DBPOINTER.collection, val->DBPOINTER.oid); + break; + } + case BCON_TYPE_CODE: + bson_append_code (bson, key, -1, val->CODE); + break; + case BCON_TYPE_SYMBOL: + bson_append_symbol (bson, key, -1, val->SYMBOL, -1); + break; + case BCON_TYPE_CODEWSCOPE: + bson_append_code_with_scope ( + bson, key, -1, val->CODEWSCOPE.js, val->CODEWSCOPE.scope); + break; + case BCON_TYPE_INT32: + bson_append_int32 (bson, key, -1, val->INT32); + break; + case BCON_TYPE_TIMESTAMP: { + bson_append_timestamp ( + bson, key, -1, val->TIMESTAMP.timestamp, val->TIMESTAMP.increment); + break; + } + case BCON_TYPE_INT64: + bson_append_int64 (bson, key, -1, val->INT64); + break; + case BCON_TYPE_DECIMAL128: + bson_append_decimal128 (bson, key, -1, val->DECIMAL128); + break; + case BCON_TYPE_MAXKEY: + bson_append_maxkey (bson, key, -1); + break; + case BCON_TYPE_MINKEY: + bson_append_minkey (bson, key, -1); + break; + case BCON_TYPE_ARRAY: { + bson_append_array (bson, key, -1, val->ARRAY); + break; + } + case BCON_TYPE_DOCUMENT: { + bson_append_document (bson, key, -1, val->DOCUMENT); + break; + } + case BCON_TYPE_ITER: + bson_append_iter (bson, key, -1, val->ITER); + break; + default: + BSON_ASSERT (0); + break; + } +} + +#define CHECK_TYPE(_type) \ + do { \ + if (bson_iter_type (iter) != (_type)) { \ + return false; \ + } \ + } while (0) + +/* extracts the value under the iterator and writes it to val. returns false + * if the iterator type doesn't match the token type. + * + * There are two magic tokens: + * + * BCONE_SKIP - + * Let's us verify that a key has a type, without caring about its value. + * This allows for wider declarative BSON verification + * + * BCONE_ITER - + * Returns the underlying iterator. This could allow for more complicated, + * procedural verification (if a parameter could have multiple types). + * */ +static bool +_bcon_extract_single (const bson_iter_t *iter, + bcon_type_t type, + bcon_extract_t *val) +{ + switch ((int) type) { + case BCON_TYPE_UTF8: + CHECK_TYPE (BSON_TYPE_UTF8); + *val->UTF8 = bson_iter_utf8 (iter, NULL); + break; + case BCON_TYPE_DOUBLE: + CHECK_TYPE (BSON_TYPE_DOUBLE); + *val->DOUBLE = bson_iter_double (iter); + break; + case BCON_TYPE_BIN: + CHECK_TYPE (BSON_TYPE_BINARY); + bson_iter_binary ( + iter, val->BIN.subtype, val->BIN.length, val->BIN.binary); + break; + case BCON_TYPE_UNDEFINED: + CHECK_TYPE (BSON_TYPE_UNDEFINED); + break; + case BCON_TYPE_OID: + CHECK_TYPE (BSON_TYPE_OID); + *val->OID = bson_iter_oid (iter); + break; + case BCON_TYPE_BOOL: + CHECK_TYPE (BSON_TYPE_BOOL); + *val->BOOL = bson_iter_bool (iter); + break; + case BCON_TYPE_DATE_TIME: + CHECK_TYPE (BSON_TYPE_DATE_TIME); + *val->DATE_TIME = bson_iter_date_time (iter); + break; + case BCON_TYPE_NULL: + CHECK_TYPE (BSON_TYPE_NULL); + break; + case BCON_TYPE_REGEX: + CHECK_TYPE (BSON_TYPE_REGEX); + *val->REGEX.regex = bson_iter_regex (iter, val->REGEX.flags); + + break; + case BCON_TYPE_DBPOINTER: + CHECK_TYPE (BSON_TYPE_DBPOINTER); + bson_iter_dbpointer ( + iter, NULL, val->DBPOINTER.collection, val->DBPOINTER.oid); + break; + case BCON_TYPE_CODE: + CHECK_TYPE (BSON_TYPE_CODE); + *val->CODE = bson_iter_code (iter, NULL); + break; + case BCON_TYPE_SYMBOL: + CHECK_TYPE (BSON_TYPE_SYMBOL); + *val->SYMBOL = bson_iter_symbol (iter, NULL); + break; + case BCON_TYPE_CODEWSCOPE: { + const uint8_t *buf; + uint32_t len; + + CHECK_TYPE (BSON_TYPE_CODEWSCOPE); + + *val->CODEWSCOPE.js = bson_iter_codewscope (iter, NULL, &len, &buf); + + bson_init_static (val->CODEWSCOPE.scope, buf, len); + break; + } + case BCON_TYPE_INT32: + CHECK_TYPE (BSON_TYPE_INT32); + *val->INT32 = bson_iter_int32 (iter); + break; + case BCON_TYPE_TIMESTAMP: + CHECK_TYPE (BSON_TYPE_TIMESTAMP); + bson_iter_timestamp ( + iter, val->TIMESTAMP.timestamp, val->TIMESTAMP.increment); + break; + case BCON_TYPE_INT64: + CHECK_TYPE (BSON_TYPE_INT64); + *val->INT64 = bson_iter_int64 (iter); + break; + case BCON_TYPE_DECIMAL128: + CHECK_TYPE (BSON_TYPE_DECIMAL128); + bson_iter_decimal128 (iter, val->DECIMAL128); + break; + case BCON_TYPE_MAXKEY: + CHECK_TYPE (BSON_TYPE_MAXKEY); + break; + case BCON_TYPE_MINKEY: + CHECK_TYPE (BSON_TYPE_MINKEY); + break; + case BCON_TYPE_ARRAY: { + const uint8_t *buf; + uint32_t len; + + CHECK_TYPE (BSON_TYPE_ARRAY); + + bson_iter_array (iter, &len, &buf); + + bson_init_static (val->ARRAY, buf, len); + break; + } + case BCON_TYPE_DOCUMENT: { + const uint8_t *buf; + uint32_t len; + + CHECK_TYPE (BSON_TYPE_DOCUMENT); + + bson_iter_document (iter, &len, &buf); + + bson_init_static (val->DOCUMENT, buf, len); + break; + } + case BCON_TYPE_SKIP: + CHECK_TYPE (val->TYPE); + break; + case BCON_TYPE_ITER: + memcpy (val->ITER, iter, sizeof *iter); + break; + default: + BSON_ASSERT (0); + break; + } + + return true; +} + +/* Consumes ap, storing output values into u and returning the type of the + * captured token. + * + * The basic workflow goes like this: + * + * 1. Look at the current arg. It will be a char * + * a. If it's a NULL, we're done processing. + * b. If it's BCON_MAGIC (a symbol with storage in this module) + * I. The next token is the type + * II. The type specifies how many args to eat and their types + * c. Otherwise it's either recursion related or a raw string + * I. If the first byte is '{', '}', '[', or ']' pass back an + * appropriate recursion token + * II. If not, just call it a UTF8 token and pass that back + */ +static bcon_type_t +_bcon_append_tokenize (va_list *ap, bcon_append_t *u) +{ + char *mark; + bcon_type_t type; + + mark = va_arg (*ap, char *); + + BSON_ASSERT (mark != BCONE_MAGIC); + + if (mark == NULL) { + type = BCON_TYPE_END; + } else if (mark == BCON_MAGIC) { + type = va_arg (*ap, bcon_type_t); + + switch ((int) type) { + case BCON_TYPE_UTF8: + u->UTF8 = va_arg (*ap, char *); + break; + case BCON_TYPE_DOUBLE: + u->DOUBLE = va_arg (*ap, double); + break; + case BCON_TYPE_DOCUMENT: + u->DOCUMENT = va_arg (*ap, bson_t *); + break; + case BCON_TYPE_ARRAY: + u->ARRAY = va_arg (*ap, bson_t *); + break; + case BCON_TYPE_BIN: + u->BIN.subtype = va_arg (*ap, bson_subtype_t); + u->BIN.binary = va_arg (*ap, uint8_t *); + u->BIN.length = va_arg (*ap, uint32_t); + break; + case BCON_TYPE_UNDEFINED: + break; + case BCON_TYPE_OID: + u->OID = va_arg (*ap, bson_oid_t *); + break; + case BCON_TYPE_BOOL: + u->BOOL = va_arg (*ap, int); + break; + case BCON_TYPE_DATE_TIME: + u->DATE_TIME = va_arg (*ap, int64_t); + break; + case BCON_TYPE_NULL: + break; + case BCON_TYPE_REGEX: + u->REGEX.regex = va_arg (*ap, char *); + u->REGEX.flags = va_arg (*ap, char *); + break; + case BCON_TYPE_DBPOINTER: + u->DBPOINTER.collection = va_arg (*ap, char *); + u->DBPOINTER.oid = va_arg (*ap, bson_oid_t *); + break; + case BCON_TYPE_CODE: + u->CODE = va_arg (*ap, char *); + break; + case BCON_TYPE_SYMBOL: + u->SYMBOL = va_arg (*ap, char *); + break; + case BCON_TYPE_CODEWSCOPE: + u->CODEWSCOPE.js = va_arg (*ap, char *); + u->CODEWSCOPE.scope = va_arg (*ap, bson_t *); + break; + case BCON_TYPE_INT32: + u->INT32 = va_arg (*ap, int32_t); + break; + case BCON_TYPE_TIMESTAMP: + u->TIMESTAMP.timestamp = va_arg (*ap, uint32_t); + u->TIMESTAMP.increment = va_arg (*ap, uint32_t); + break; + case BCON_TYPE_INT64: + u->INT64 = va_arg (*ap, int64_t); + break; + case BCON_TYPE_DECIMAL128: + u->DECIMAL128 = va_arg (*ap, bson_decimal128_t *); + break; + case BCON_TYPE_MAXKEY: + break; + case BCON_TYPE_MINKEY: + break; + case BCON_TYPE_BCON: + u->BCON = va_arg (*ap, bson_t *); + break; + case BCON_TYPE_ITER: + u->ITER = va_arg (*ap, const bson_iter_t *); + break; + default: + BSON_ASSERT (0); + break; + } + } else { + switch (mark[0]) { + case '{': + type = BCON_TYPE_DOC_START; + break; + case '}': + type = BCON_TYPE_DOC_END; + break; + case '[': + type = BCON_TYPE_ARRAY_START; + break; + case ']': + type = BCON_TYPE_ARRAY_END; + break; + + default: + type = BCON_TYPE_UTF8; + u->UTF8 = mark; + break; + } + } + + return type; +} + + +/* Consumes ap, storing output values into u and returning the type of the + * captured token. + * + * The basic workflow goes like this: + * + * 1. Look at the current arg. It will be a char * + * a. If it's a NULL, we're done processing. + * b. If it's BCONE_MAGIC (a symbol with storage in this module) + * I. The next token is the type + * II. The type specifies how many args to eat and their types + * c. Otherwise it's either recursion related or a raw string + * I. If the first byte is '{', '}', '[', or ']' pass back an + * appropriate recursion token + * II. If not, just call it a UTF8 token and pass that back + */ +static bcon_type_t +_bcon_extract_tokenize (va_list *ap, bcon_extract_t *u) +{ + char *mark; + bcon_type_t type; + + mark = va_arg (*ap, char *); + + BSON_ASSERT (mark != BCON_MAGIC); + + if (mark == NULL) { + type = BCON_TYPE_END; + } else if (mark == BCONE_MAGIC) { + type = va_arg (*ap, bcon_type_t); + + switch ((int) type) { + case BCON_TYPE_UTF8: + u->UTF8 = va_arg (*ap, const char **); + break; + case BCON_TYPE_DOUBLE: + u->DOUBLE = va_arg (*ap, double *); + break; + case BCON_TYPE_DOCUMENT: + u->DOCUMENT = va_arg (*ap, bson_t *); + break; + case BCON_TYPE_ARRAY: + u->ARRAY = va_arg (*ap, bson_t *); + break; + case BCON_TYPE_BIN: + u->BIN.subtype = va_arg (*ap, bson_subtype_t *); + u->BIN.binary = va_arg (*ap, const uint8_t **); + u->BIN.length = va_arg (*ap, uint32_t *); + break; + case BCON_TYPE_UNDEFINED: + break; + case BCON_TYPE_OID: + u->OID = va_arg (*ap, const bson_oid_t **); + break; + case BCON_TYPE_BOOL: + u->BOOL = va_arg (*ap, bool *); + break; + case BCON_TYPE_DATE_TIME: + u->DATE_TIME = va_arg (*ap, int64_t *); + break; + case BCON_TYPE_NULL: + break; + case BCON_TYPE_REGEX: + u->REGEX.regex = va_arg (*ap, const char **); + u->REGEX.flags = va_arg (*ap, const char **); + break; + case BCON_TYPE_DBPOINTER: + u->DBPOINTER.collection = va_arg (*ap, const char **); + u->DBPOINTER.oid = va_arg (*ap, const bson_oid_t **); + break; + case BCON_TYPE_CODE: + u->CODE = va_arg (*ap, const char **); + break; + case BCON_TYPE_SYMBOL: + u->SYMBOL = va_arg (*ap, const char **); + break; + case BCON_TYPE_CODEWSCOPE: + u->CODEWSCOPE.js = va_arg (*ap, const char **); + u->CODEWSCOPE.scope = va_arg (*ap, bson_t *); + break; + case BCON_TYPE_INT32: + u->INT32 = va_arg (*ap, int32_t *); + break; + case BCON_TYPE_TIMESTAMP: + u->TIMESTAMP.timestamp = va_arg (*ap, uint32_t *); + u->TIMESTAMP.increment = va_arg (*ap, uint32_t *); + break; + case BCON_TYPE_INT64: + u->INT64 = va_arg (*ap, int64_t *); + break; + case BCON_TYPE_DECIMAL128: + u->DECIMAL128 = va_arg (*ap, bson_decimal128_t *); + break; + case BCON_TYPE_MAXKEY: + break; + case BCON_TYPE_MINKEY: + break; + case BCON_TYPE_SKIP: + u->TYPE = va_arg (*ap, bson_type_t); + break; + case BCON_TYPE_ITER: + u->ITER = va_arg (*ap, bson_iter_t *); + break; + default: + BSON_ASSERT (0); + break; + } + } else { + switch (mark[0]) { + case '{': + type = BCON_TYPE_DOC_START; + break; + case '}': + type = BCON_TYPE_DOC_END; + break; + case '[': + type = BCON_TYPE_ARRAY_START; + break; + case ']': + type = BCON_TYPE_ARRAY_END; + break; + + default: + type = BCON_TYPE_RAW; + u->key = mark; + break; + } + } + + return type; +} + + +/* This trivial utility function is useful for concatenating a bson object onto + * the end of another, ignoring the keys from the source bson object and + * continuing to use and increment the keys from the source. It's only useful + * when called from bcon_append_ctx_va */ +static void +_bson_concat_array (bson_t *dest, const bson_t *src, bcon_append_ctx_t *ctx) +{ + bson_iter_t iter; + const char *key; + char i_str[16]; + bool r; + + r = bson_iter_init (&iter, src); + + if (!r) { + fprintf (stderr, "Invalid BSON document, possible memory coruption.\n"); + return; + } + + STACK_I--; + + while (bson_iter_next (&iter)) { + bson_uint32_to_string (STACK_I, &key, i_str, sizeof i_str); + STACK_I++; + + bson_append_iter (dest, key, -1, &iter); + } +} + + +/* Append_ctx_va consumes the va_list until NULL is found, appending into bson + * as tokens are found. It can receive or return an in-progress bson object + * via the ctx param. It can also operate on the middle of a va_list, and so + * can be wrapped inside of another varargs function. + * + * Note that passing in a va_list that isn't perferectly formatted for BCON + * ingestion will almost certainly result in undefined behavior + * + * The workflow relies on the passed ctx object, which holds a stack of bson + * objects, along with metadata (if the emedded layer is an array, and which + * element it is on if so). We iterate, generating tokens from the va_list, + * until we reach an END token. If any errors occur, we just blow up (the + * var_args stuff is already incredibly fragile to mistakes, and we have no way + * of introspecting, so just don't screw it up). + * + * There are also a few STACK_* macros in here which manimpulate ctx that are + * defined up top. + * */ +void +bcon_append_ctx_va (bson_t *bson, bcon_append_ctx_t *ctx, va_list *ap) +{ + bcon_type_t type; + const char *key; + char i_str[16]; + + bcon_append_t u = {0}; + + while (1) { + if (STACK_IS_ARRAY) { + bson_uint32_to_string (STACK_I, &key, i_str, sizeof i_str); + STACK_I++; + } else { + type = _bcon_append_tokenize (ap, &u); + + if (type == BCON_TYPE_END) { + return; + } + + if (type == BCON_TYPE_DOC_END) { + STACK_POP_DOC ( + bson_append_document_end (STACK_BSON_PARENT, STACK_BSON_CHILD)); + continue; + } + + if (type == BCON_TYPE_BCON) { + bson_concat (STACK_BSON_CHILD, u.BCON); + continue; + } + + BSON_ASSERT (type == BCON_TYPE_UTF8); + + key = u.UTF8; + } + + type = _bcon_append_tokenize (ap, &u); + BSON_ASSERT (type != BCON_TYPE_END); + + switch ((int) type) { + case BCON_TYPE_BCON: + BSON_ASSERT (STACK_IS_ARRAY); + _bson_concat_array (STACK_BSON_CHILD, u.BCON, ctx); + + break; + case BCON_TYPE_DOC_START: + STACK_PUSH_DOC (bson_append_document_begin ( + STACK_BSON_PARENT, key, -1, STACK_BSON_CHILD)); + break; + case BCON_TYPE_DOC_END: + STACK_POP_DOC ( + bson_append_document_end (STACK_BSON_PARENT, STACK_BSON_CHILD)); + break; + case BCON_TYPE_ARRAY_START: + STACK_PUSH_ARRAY (bson_append_array_begin ( + STACK_BSON_PARENT, key, -1, STACK_BSON_CHILD)); + break; + case BCON_TYPE_ARRAY_END: + STACK_POP_ARRAY ( + bson_append_array_end (STACK_BSON_PARENT, STACK_BSON_CHILD)); + break; + default: + _bcon_append_single (STACK_BSON_CHILD, type, key, &u); + + break; + } + } +} + + +/* extract_ctx_va consumes the va_list until NULL is found, extracting values + * as tokens are found. It can receive or return an in-progress bson object + * via the ctx param. It can also operate on the middle of a va_list, and so + * can be wrapped inside of another varargs function. + * + * Note that passing in a va_list that isn't perferectly formatted for BCON + * ingestion will almost certainly result in undefined behavior + * + * The workflow relies on the passed ctx object, which holds a stack of iterator + * objects, along with metadata (if the emedded layer is an array, and which + * element it is on if so). We iterate, generating tokens from the va_list, + * until we reach an END token. If any errors occur, we just blow up (the + * var_args stuff is already incredibly fragile to mistakes, and we have no way + * of introspecting, so just don't screw it up). + * + * There are also a few STACK_* macros in here which manimpulate ctx that are + * defined up top. + * + * The function returns true if all tokens could be successfully matched, false + * otherwise. + * */ +bool +bcon_extract_ctx_va (bson_t *bson, bcon_extract_ctx_t *ctx, va_list *ap) +{ + bcon_type_t type; + const char *key; + bson_iter_t root_iter; + bson_iter_t current_iter; + char i_str[16]; + + bcon_extract_t u = {0}; + + bson_iter_init (&root_iter, bson); + + while (1) { + if (STACK_IS_ARRAY) { + bson_uint32_to_string (STACK_I, &key, i_str, sizeof i_str); + STACK_I++; + } else { + type = _bcon_extract_tokenize (ap, &u); + + if (type == BCON_TYPE_END) { + return true; + } + + if (type == BCON_TYPE_DOC_END) { + STACK_POP_DOC (_noop ()); + continue; + } + + BSON_ASSERT (type == BCON_TYPE_RAW); + + key = u.key; + } + + type = _bcon_extract_tokenize (ap, &u); + BSON_ASSERT (type != BCON_TYPE_END); + + if (type == BCON_TYPE_DOC_END) { + STACK_POP_DOC (_noop ()); + } else if (type == BCON_TYPE_ARRAY_END) { + STACK_POP_ARRAY (_noop ()); + } else { + memcpy (¤t_iter, STACK_ITER_CHILD, sizeof current_iter); + + if (!bson_iter_find (¤t_iter, key)) { + return false; + } + + switch ((int) type) { + case BCON_TYPE_DOC_START: + + if (bson_iter_type (¤t_iter) != BSON_TYPE_DOCUMENT) { + return false; + } + + STACK_PUSH_DOC ( + bson_iter_recurse (¤t_iter, STACK_ITER_CHILD)); + break; + case BCON_TYPE_ARRAY_START: + + if (bson_iter_type (¤t_iter) != BSON_TYPE_ARRAY) { + return false; + } + + STACK_PUSH_ARRAY ( + bson_iter_recurse (¤t_iter, STACK_ITER_CHILD)); + break; + default: + + if (!_bcon_extract_single (¤t_iter, type, &u)) { + return false; + } + + break; + } + } + } +} + +void +bcon_extract_ctx_init (bcon_extract_ctx_t *ctx) +{ + ctx->n = 0; + ctx->stack[0].is_array = false; +} + +bool +bcon_extract (bson_t *bson, ...) +{ + va_list ap; + bcon_extract_ctx_t ctx; + bool r; + + bcon_extract_ctx_init (&ctx); + + va_start (ap, bson); + + r = bcon_extract_ctx_va (bson, &ctx, &ap); + + va_end (ap); + + return r; +} + + +void +bcon_append (bson_t *bson, ...) +{ + va_list ap; + bcon_append_ctx_t ctx; + + bcon_append_ctx_init (&ctx); + + va_start (ap, bson); + + bcon_append_ctx_va (bson, &ctx, &ap); + + va_end (ap); +} + + +void +bcon_append_ctx (bson_t *bson, bcon_append_ctx_t *ctx, ...) +{ + va_list ap; + + va_start (ap, ctx); + + bcon_append_ctx_va (bson, ctx, &ap); + + va_end (ap); +} + + +void +bcon_extract_ctx (bson_t *bson, bcon_extract_ctx_t *ctx, ...) +{ + va_list ap; + + va_start (ap, ctx); + + bcon_extract_ctx_va (bson, ctx, &ap); + + va_end (ap); +} + +void +bcon_append_ctx_init (bcon_append_ctx_t *ctx) +{ + ctx->n = 0; + ctx->stack[0].is_array = 0; +} + + +bson_t * +bcon_new (void *unused, ...) +{ + va_list ap; + bcon_append_ctx_t ctx; + bson_t *bson; + + bcon_append_ctx_init (&ctx); + + bson = bson_new (); + + va_start (ap, unused); + + bcon_append_ctx_va (bson, &ctx, &ap); + + va_end (ap); + + return bson; +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bcon.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bcon.h new file mode 100644 index 0000000000000000000000000000000000000000..e8c08de6c15e9fb43aa14e34d6990c74878066ac --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bcon.h @@ -0,0 +1,293 @@ +/* + * @file bcon.h + * @brief BCON (BSON C Object Notation) Declarations + */ + +/* Copyright 2009-2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCON_H_ +#define BCON_H_ + +#include "bson.h" + + +BSON_BEGIN_DECLS + + +#define BCON_STACK_MAX 100 + +#define BCON_ENSURE_DECLARE(fun, type) \ + static BSON_INLINE type bcon_ensure_##fun (type _t) \ + { \ + return _t; \ + } + +#define BCON_ENSURE(fun, val) bcon_ensure_##fun (val) + +#define BCON_ENSURE_STORAGE(fun, val) bcon_ensure_##fun (&(val)) + +BCON_ENSURE_DECLARE (const_char_ptr, const char *) +BCON_ENSURE_DECLARE (const_char_ptr_ptr, const char **) +BCON_ENSURE_DECLARE (double, double) +BCON_ENSURE_DECLARE (double_ptr, double *) +BCON_ENSURE_DECLARE (const_bson_ptr, const bson_t *) +BCON_ENSURE_DECLARE (bson_ptr, bson_t *) +BCON_ENSURE_DECLARE (subtype, bson_subtype_t) +BCON_ENSURE_DECLARE (subtype_ptr, bson_subtype_t *) +BCON_ENSURE_DECLARE (const_uint8_ptr, const uint8_t *) +BCON_ENSURE_DECLARE (const_uint8_ptr_ptr, const uint8_t **) +BCON_ENSURE_DECLARE (uint32, uint32_t) +BCON_ENSURE_DECLARE (uint32_ptr, uint32_t *) +BCON_ENSURE_DECLARE (const_oid_ptr, const bson_oid_t *) +BCON_ENSURE_DECLARE (const_oid_ptr_ptr, const bson_oid_t **) +BCON_ENSURE_DECLARE (int32, int32_t) +BCON_ENSURE_DECLARE (int32_ptr, int32_t *) +BCON_ENSURE_DECLARE (int64, int64_t) +BCON_ENSURE_DECLARE (int64_ptr, int64_t *) +BCON_ENSURE_DECLARE (const_decimal128_ptr, const bson_decimal128_t *) +BCON_ENSURE_DECLARE (bool, bool) +BCON_ENSURE_DECLARE (bool_ptr, bool *) +BCON_ENSURE_DECLARE (bson_type, bson_type_t) +BCON_ENSURE_DECLARE (bson_iter_ptr, bson_iter_t *) +BCON_ENSURE_DECLARE (const_bson_iter_ptr, const bson_iter_t *) + +#define BCON_UTF8(_val) \ + BCON_MAGIC, BCON_TYPE_UTF8, BCON_ENSURE (const_char_ptr, (_val)) +#define BCON_DOUBLE(_val) \ + BCON_MAGIC, BCON_TYPE_DOUBLE, BCON_ENSURE (double, (_val)) +#define BCON_DOCUMENT(_val) \ + BCON_MAGIC, BCON_TYPE_DOCUMENT, BCON_ENSURE (const_bson_ptr, (_val)) +#define BCON_ARRAY(_val) \ + BCON_MAGIC, BCON_TYPE_ARRAY, BCON_ENSURE (const_bson_ptr, (_val)) +#define BCON_BIN(_subtype, _binary, _length) \ + BCON_MAGIC, BCON_TYPE_BIN, BCON_ENSURE (subtype, (_subtype)), \ + BCON_ENSURE (const_uint8_ptr, (_binary)), \ + BCON_ENSURE (uint32, (_length)) +#define BCON_UNDEFINED BCON_MAGIC, BCON_TYPE_UNDEFINED +#define BCON_OID(_val) \ + BCON_MAGIC, BCON_TYPE_OID, BCON_ENSURE (const_oid_ptr, (_val)) +#define BCON_BOOL(_val) BCON_MAGIC, BCON_TYPE_BOOL, BCON_ENSURE (bool, (_val)) +#define BCON_DATE_TIME(_val) \ + BCON_MAGIC, BCON_TYPE_DATE_TIME, BCON_ENSURE (int64, (_val)) +#define BCON_NULL BCON_MAGIC, BCON_TYPE_NULL +#define BCON_REGEX(_regex, _flags) \ + BCON_MAGIC, BCON_TYPE_REGEX, BCON_ENSURE (const_char_ptr, (_regex)), \ + BCON_ENSURE (const_char_ptr, (_flags)) +#define BCON_DBPOINTER(_collection, _oid) \ + BCON_MAGIC, BCON_TYPE_DBPOINTER, \ + BCON_ENSURE (const_char_ptr, (_collection)), \ + BCON_ENSURE (const_oid_ptr, (_oid)) +#define BCON_CODE(_val) \ + BCON_MAGIC, BCON_TYPE_CODE, BCON_ENSURE (const_char_ptr, (_val)) +#define BCON_SYMBOL(_val) \ + BCON_MAGIC, BCON_TYPE_SYMBOL, BCON_ENSURE (const_char_ptr, (_val)) +#define BCON_CODEWSCOPE(_js, _scope) \ + BCON_MAGIC, BCON_TYPE_CODEWSCOPE, BCON_ENSURE (const_char_ptr, (_js)), \ + BCON_ENSURE (const_bson_ptr, (_scope)) +#define BCON_INT32(_val) \ + BCON_MAGIC, BCON_TYPE_INT32, BCON_ENSURE (int32, (_val)) +#define BCON_TIMESTAMP(_timestamp, _increment) \ + BCON_MAGIC, BCON_TYPE_TIMESTAMP, BCON_ENSURE (int32, (_timestamp)), \ + BCON_ENSURE (int32, (_increment)) +#define BCON_INT64(_val) \ + BCON_MAGIC, BCON_TYPE_INT64, BCON_ENSURE (int64, (_val)) +#define BCON_DECIMAL128(_val) \ + BCON_MAGIC, BCON_TYPE_DECIMAL128, BCON_ENSURE (const_decimal128_ptr, (_val)) +#define BCON_MAXKEY BCON_MAGIC, BCON_TYPE_MAXKEY +#define BCON_MINKEY BCON_MAGIC, BCON_TYPE_MINKEY +#define BCON(_val) \ + BCON_MAGIC, BCON_TYPE_BCON, BCON_ENSURE (const_bson_ptr, (_val)) +#define BCON_ITER(_val) \ + BCON_MAGIC, BCON_TYPE_ITER, BCON_ENSURE (const_bson_iter_ptr, (_val)) + +#define BCONE_UTF8(_val) \ + BCONE_MAGIC, BCON_TYPE_UTF8, BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_val)) +#define BCONE_DOUBLE(_val) \ + BCONE_MAGIC, BCON_TYPE_DOUBLE, BCON_ENSURE_STORAGE (double_ptr, (_val)) +#define BCONE_DOCUMENT(_val) \ + BCONE_MAGIC, BCON_TYPE_DOCUMENT, BCON_ENSURE_STORAGE (bson_ptr, (_val)) +#define BCONE_ARRAY(_val) \ + BCONE_MAGIC, BCON_TYPE_ARRAY, BCON_ENSURE_STORAGE (bson_ptr, (_val)) +#define BCONE_BIN(subtype, binary, length) \ + BCONE_MAGIC, BCON_TYPE_BIN, BCON_ENSURE_STORAGE (subtype_ptr, (subtype)), \ + BCON_ENSURE_STORAGE (const_uint8_ptr_ptr, (binary)), \ + BCON_ENSURE_STORAGE (uint32_ptr, (length)) +#define BCONE_UNDEFINED BCONE_MAGIC, BCON_TYPE_UNDEFINED +#define BCONE_OID(_val) \ + BCONE_MAGIC, BCON_TYPE_OID, BCON_ENSURE_STORAGE (const_oid_ptr_ptr, (_val)) +#define BCONE_BOOL(_val) \ + BCONE_MAGIC, BCON_TYPE_BOOL, BCON_ENSURE_STORAGE (bool_ptr, (_val)) +#define BCONE_DATE_TIME(_val) \ + BCONE_MAGIC, BCON_TYPE_DATE_TIME, BCON_ENSURE_STORAGE (int64_ptr, (_val)) +#define BCONE_NULL BCONE_MAGIC, BCON_TYPE_NULL +#define BCONE_REGEX(_regex, _flags) \ + BCONE_MAGIC, BCON_TYPE_REGEX, \ + BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_regex)), \ + BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_flags)) +#define BCONE_DBPOINTER(_collection, _oid) \ + BCONE_MAGIC, BCON_TYPE_DBPOINTER, \ + BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_collection)), \ + BCON_ENSURE_STORAGE (const_oid_ptr_ptr, (_oid)) +#define BCONE_CODE(_val) \ + BCONE_MAGIC, BCON_TYPE_CODE, BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_val)) +#define BCONE_SYMBOL(_val) \ + BCONE_MAGIC, BCON_TYPE_SYMBOL, \ + BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_val)) +#define BCONE_CODEWSCOPE(_js, _scope) \ + BCONE_MAGIC, BCON_TYPE_CODEWSCOPE, \ + BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_js)), \ + BCON_ENSURE_STORAGE (bson_ptr, (_scope)) +#define BCONE_INT32(_val) \ + BCONE_MAGIC, BCON_TYPE_INT32, BCON_ENSURE_STORAGE (int32_ptr, (_val)) +#define BCONE_TIMESTAMP(_timestamp, _increment) \ + BCONE_MAGIC, BCON_TYPE_TIMESTAMP, \ + BCON_ENSURE_STORAGE (int32_ptr, (_timestamp)), \ + BCON_ENSURE_STORAGE (int32_ptr, (_increment)) +#define BCONE_INT64(_val) \ + BCONE_MAGIC, BCON_TYPE_INT64, BCON_ENSURE_STORAGE (int64_ptr, (_val)) +#define BCONE_DECIMAL128(_val) \ + BCONE_MAGIC, BCON_TYPE_DECIMAL128, \ + BCON_ENSURE_STORAGE (const_decimal128_ptr, (_val)) +#define BCONE_MAXKEY BCONE_MAGIC, BCON_TYPE_MAXKEY +#define BCONE_MINKEY BCONE_MAGIC, BCON_TYPE_MINKEY +#define BCONE_SKIP(_val) \ + BCONE_MAGIC, BCON_TYPE_SKIP, BCON_ENSURE (bson_type, (_val)) +#define BCONE_ITER(_val) \ + BCONE_MAGIC, BCON_TYPE_ITER, BCON_ENSURE_STORAGE (bson_iter_ptr, (_val)) + +#define BCON_MAGIC bson_bcon_magic () +#define BCONE_MAGIC bson_bcone_magic () + +typedef enum { + BCON_TYPE_UTF8, + BCON_TYPE_DOUBLE, + BCON_TYPE_DOCUMENT, + BCON_TYPE_ARRAY, + BCON_TYPE_BIN, + BCON_TYPE_UNDEFINED, + BCON_TYPE_OID, + BCON_TYPE_BOOL, + BCON_TYPE_DATE_TIME, + BCON_TYPE_NULL, + BCON_TYPE_REGEX, + BCON_TYPE_DBPOINTER, + BCON_TYPE_CODE, + BCON_TYPE_SYMBOL, + BCON_TYPE_CODEWSCOPE, + BCON_TYPE_INT32, + BCON_TYPE_TIMESTAMP, + BCON_TYPE_INT64, + BCON_TYPE_DECIMAL128, + BCON_TYPE_MAXKEY, + BCON_TYPE_MINKEY, + BCON_TYPE_BCON, + BCON_TYPE_ARRAY_START, + BCON_TYPE_ARRAY_END, + BCON_TYPE_DOC_START, + BCON_TYPE_DOC_END, + BCON_TYPE_END, + BCON_TYPE_RAW, + BCON_TYPE_SKIP, + BCON_TYPE_ITER, + BCON_TYPE_ERROR, +} bcon_type_t; + +typedef struct bcon_append_ctx_frame { + int i; + bool is_array; + bson_t bson; +} bcon_append_ctx_frame_t; + +typedef struct bcon_extract_ctx_frame { + int i; + bool is_array; + bson_iter_t iter; +} bcon_extract_ctx_frame_t; + +typedef struct _bcon_append_ctx_t { + bcon_append_ctx_frame_t stack[BCON_STACK_MAX]; + int n; +} bcon_append_ctx_t; + +typedef struct _bcon_extract_ctx_t { + bcon_extract_ctx_frame_t stack[BCON_STACK_MAX]; + int n; +} bcon_extract_ctx_t; + +BSON_EXPORT (void) +bcon_append (bson_t *bson, ...) BSON_GNUC_NULL_TERMINATED; +BSON_EXPORT (void) +bcon_append_ctx (bson_t *bson, + bcon_append_ctx_t *ctx, + ...) BSON_GNUC_NULL_TERMINATED; +BSON_EXPORT (void) +bcon_append_ctx_va (bson_t *bson, bcon_append_ctx_t *ctx, va_list *va); +BSON_EXPORT (void) +bcon_append_ctx_init (bcon_append_ctx_t *ctx); + +BSON_EXPORT (void) +bcon_extract_ctx_init (bcon_extract_ctx_t *ctx); + +BSON_EXPORT (void) +bcon_extract_ctx (bson_t *bson, + bcon_extract_ctx_t *ctx, + ...) BSON_GNUC_NULL_TERMINATED; + +BSON_EXPORT (bool) +bcon_extract_ctx_va (bson_t *bson, bcon_extract_ctx_t *ctx, va_list *ap); + +BSON_EXPORT (bool) +bcon_extract (bson_t *bson, ...) BSON_GNUC_NULL_TERMINATED; + +BSON_EXPORT (bool) +bcon_extract_va (bson_t *bson, + bcon_extract_ctx_t *ctx, + ...) BSON_GNUC_NULL_TERMINATED; + +BSON_EXPORT (bson_t *) +bcon_new (void *unused, ...) BSON_GNUC_NULL_TERMINATED; + +/** + * The bcon_..() functions are all declared with __attribute__((sentinel)). + * + * From GCC manual for "sentinel": "A valid NULL in this context is defined as + * zero with any pointer type. If your system defines the NULL macro with an + * integer type then you need to add an explicit cast." + * Case in point: GCC on Solaris (at least) + */ +#define BCON_APPEND(_bson, ...) \ + bcon_append ((_bson), __VA_ARGS__, (void *) NULL) +#define BCON_APPEND_CTX(_bson, _ctx, ...) \ + bcon_append_ctx ((_bson), (_ctx), __VA_ARGS__, (void *) NULL) + +#define BCON_EXTRACT(_bson, ...) \ + bcon_extract ((_bson), __VA_ARGS__, (void *) NULL) + +#define BCON_EXTRACT_CTX(_bson, _ctx, ...) \ + bcon_extract ((_bson), (_ctx), __VA_ARGS__, (void *) NULL) + +#define BCON_NEW(...) bcon_new (NULL, __VA_ARGS__, (void *) NULL) + +BSON_EXPORT (const char *) +bson_bcon_magic (void) BSON_GNUC_CONST; +BSON_EXPORT (const char *) +bson_bcone_magic (void) BSON_GNUC_CONST; + + +BSON_END_DECLS + + +#endif diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-atomic.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-atomic.c new file mode 100644 index 0000000000000000000000000000000000000000..2c8bfdaaa43e75d6c2e930202bf6e3d470ebaacf --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-atomic.c @@ -0,0 +1,73 @@ +/* + * Copyright 2014 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "bson-atomic.h" + + +/* + * We should only ever hit these on non-Windows systems, for which we require + * pthread support. Therefore, we will avoid making a threading portability + * for threads here and just use pthreads directly. + */ + + +#ifdef __BSON_NEED_BARRIER +#include <pthread.h> +static pthread_mutex_t gBarrier = PTHREAD_MUTEX_INITIALIZER; +void +bson_memory_barrier (void) +{ + pthread_mutex_lock (&gBarrier); + pthread_mutex_unlock (&gBarrier); +} +#endif + + +#ifdef __BSON_NEED_ATOMIC_32 +#include <pthread.h> +static pthread_mutex_t gSync32 = PTHREAD_MUTEX_INITIALIZER; +int32_t +bson_atomic_int_add (volatile int32_t *p, int32_t n) +{ + int ret; + + pthread_mutex_lock (&gSync32); + *p += n; + ret = *p; + pthread_mutex_unlock (&gSync32); + + return ret; +} +#endif + + +#ifdef __BSON_NEED_ATOMIC_64 +#include <pthread.h> +static pthread_mutex_t gSync64 = PTHREAD_MUTEX_INITIALIZER; +int64_t +bson_atomic_int64_add (volatile int64_t *p, int64_t n) +{ + int64_t ret; + + pthread_mutex_lock (&gSync64); + *p += n; + ret = *p; + pthread_mutex_unlock (&gSync64); + + return ret; +} +#endif diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-atomic.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-atomic.h new file mode 100644 index 0000000000000000000000000000000000000000..2ee6f2bd287ce3158b0ee9483a929fda0538c459 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-atomic.h @@ -0,0 +1,103 @@ +/* + * Copyright 2013-2014 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_ATOMIC_H +#define BSON_ATOMIC_H + + +#include "bson-config.h" +#include "bson-compat.h" +#include "bson-macros.h" + + +BSON_BEGIN_DECLS + + +#if defined(__sun) && defined(__SVR4) +/* Solaris */ +#include <atomic.h> +#define bson_atomic_int_add(p, v) \ + atomic_add_32_nv ((volatile uint32_t *) p, (v)) +#define bson_atomic_int64_add(p, v) \ + atomic_add_64_nv ((volatile uint64_t *) p, (v)) +#elif defined(_WIN32) +/* MSVC/MinGW */ +#define bson_atomic_int_add(p, v) \ + (InterlockedExchangeAdd ((volatile LONG *) (p), (LONG) (v)) + (LONG) (v)) +#define bson_atomic_int64_add(p, v) \ + (InterlockedExchangeAdd64 ((volatile LONGLONG *) (p), (LONGLONG) (v)) + \ + (LONGLONG) (v)) +#else +#ifdef BSON_HAVE_ATOMIC_32_ADD_AND_FETCH +#define bson_atomic_int_add(p, v) __sync_add_and_fetch ((p), (v)) +#else +#define __BSON_NEED_ATOMIC_32 +#endif +#ifdef BSON_HAVE_ATOMIC_64_ADD_AND_FETCH +#if BSON_GNUC_IS_VERSION(4, 1) +/* + * GCC 4.1 on i386 can generate buggy 64-bit atomic increment. + * So we will work around with a fallback. + * + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=40693 + */ +#define __BSON_NEED_ATOMIC_64 +#else +#define bson_atomic_int64_add(p, v) \ + __sync_add_and_fetch ((volatile int64_t *) (p), (int64_t) (v)) +#endif +#else +#define __BSON_NEED_ATOMIC_64 +#endif +#endif + +#ifdef __BSON_NEED_ATOMIC_32 +BSON_EXPORT (int32_t) +bson_atomic_int_add (volatile int32_t *p, int32_t n); +#endif +#ifdef __BSON_NEED_ATOMIC_64 +BSON_EXPORT (int64_t) +bson_atomic_int64_add (volatile int64_t *p, int64_t n); +#endif + + +#if defined(_WIN32) +#define bson_memory_barrier() MemoryBarrier () +#elif defined(__GNUC__) +#if BSON_GNUC_CHECK_VERSION(4, 1) +#define bson_memory_barrier() __sync_synchronize () +#else +#warning "GCC Pre-4.1 discovered, using inline assembly for memory barrier." +#define bson_memory_barrier() __asm__ volatile("" ::: "memory") +#endif +#elif defined(__SUNPRO_C) +#include <mbarrier.h> +#define bson_memory_barrier() __machine_rw_barrier () +#elif defined(__xlC__) +#define bson_memory_barrier() __sync () +#else +#define __BSON_NEED_BARRIER 1 +#warning "Unknown compiler, using lock for compiler barrier." +BSON_EXPORT (void) +bson_memory_barrier (void); +#endif + + +BSON_END_DECLS + + +#endif /* BSON_ATOMIC_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-clock.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-clock.c new file mode 100644 index 0000000000000000000000000000000000000000..5260eb1820b2a7ca15ff54fb14abc3206f948438 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-clock.c @@ -0,0 +1,153 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifdef __APPLE__ +#include <mach/clock.h> +#include <mach/mach.h> +#include <mach/mach_time.h> +#include <sys/time.h> +#endif + + +#include "bson-config.h" +#include "bson-compat.h" + + +#if defined(BSON_HAVE_CLOCK_GETTIME) +#include <time.h> +#include <sys/time.h> +#endif + +#include "bson-clock.h" + + +/* + *-------------------------------------------------------------------------- + * + * bson_gettimeofday -- + * + * A wrapper around gettimeofday() with fallback support for Windows. + * + * Returns: + * 0 if successful. + * + * Side effects: + * @tv is set. + * + *-------------------------------------------------------------------------- + */ + +int +bson_gettimeofday (struct timeval *tv) /* OUT */ +{ +#if defined(_WIN32) +#if defined(_MSC_VER) +#define DELTA_EPOCH_IN_MICROSEC 11644473600000000Ui64 +#else +#define DELTA_EPOCH_IN_MICROSEC 11644473600000000ULL +#endif + FILETIME ft; + uint64_t tmp = 0; + + /* + * The const value is shamelessy stolen from + * http://www.boost.org/doc/libs/1_55_0/boost/chrono/detail/inlined/win/chrono.hpp + * + * File times are the number of 100 nanosecond intervals elapsed since + * 12:00 am Jan 1, 1601 UTC. I haven't check the math particularly hard + * + * ... good luck + */ + + if (tv) { + GetSystemTimeAsFileTime (&ft); + + /* pull out of the filetime into a 64 bit uint */ + tmp |= ft.dwHighDateTime; + tmp <<= 32; + tmp |= ft.dwLowDateTime; + + /* convert from 100's of nanosecs to microsecs */ + tmp /= 10; + + /* adjust to unix epoch */ + tmp -= DELTA_EPOCH_IN_MICROSEC; + + tv->tv_sec = (long) (tmp / 1000000UL); + tv->tv_usec = (long) (tmp % 1000000UL); + } + + return 0; +#else + return gettimeofday (tv, NULL); +#endif +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_get_monotonic_time -- + * + * Returns the monotonic system time, if available. A best effort is + * made to use the monotonic clock. However, some systems may not + * support such a feature. + * + * Returns: + * The monotonic clock in microseconds. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +int64_t +bson_get_monotonic_time (void) +{ +#if defined(BSON_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + struct timespec ts; + clock_gettime (CLOCK_MONOTONIC, &ts); + return ((ts.tv_sec * 1000000UL) + (ts.tv_nsec / 1000UL)); +#elif defined(__APPLE__) + static mach_timebase_info_data_t info = {0}; + static double ratio = 0.0; + + if (!info.denom) { + /* the value from mach_absolute_time () * info.numer / info.denom + * is in nano seconds. So we have to divid by 1000.0 to get micro + * seconds*/ + mach_timebase_info (&info); + ratio = (double) info.numer / (double) info.denom / 1000.0; + } + + return mach_absolute_time () * ratio; +#elif defined(_WIN32) + /* Despite it's name, this is in milliseconds! */ + int64_t ticks = GetTickCount64 (); + return (ticks * 1000L); +#elif defined(__hpux__) + int64_t nanosec = gethrtime (); + return (nanosec / 1000UL); +#else +#warning "Monotonic clock is not yet supported on your platform." + struct timeval tv; + + bson_gettimeofday (&tv); + return (tv.tv_sec * 1000000UL) + tv.tv_usec; +#endif +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-clock.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-clock.h new file mode 100644 index 0000000000000000000000000000000000000000..652c14da604e0d6e5302ded6e677623538d28e87 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-clock.h @@ -0,0 +1,44 @@ +/* + * Copyright 2014 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_CLOCK_H +#define BSON_CLOCK_H + + +#if !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) +#error "Only <bson.h> can be included directly." +#endif + + +#include "bson-compat.h" +#include "bson-macros.h" +#include "bson-types.h" + + +BSON_BEGIN_DECLS + + +BSON_EXPORT (int64_t) +bson_get_monotonic_time (void); +BSON_EXPORT (int) +bson_gettimeofday (struct timeval *tv); + + +BSON_END_DECLS + + +#endif /* BSON_CLOCK_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-compat.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-compat.h new file mode 100644 index 0000000000000000000000000000000000000000..d82dd90afbc83dfd1c889d9a4b432d5f970342a1 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-compat.h @@ -0,0 +1,164 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_COMPAT_H +#define BSON_COMPAT_H + + +#if defined(__MINGW32__) +#if defined(__USE_MINGW_ANSI_STDIO) +#if __USE_MINGW_ANSI_STDIO < 1 +#error "__USE_MINGW_ANSI_STDIO > 0 is required for correct PRI* macros" +#endif +#else +#define __USE_MINGW_ANSI_STDIO 1 +#endif +#endif + +#include "bson-config.h" +#include "bson-macros.h" + + +#ifdef BSON_OS_WIN32 +#if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600) +#undef _WIN32_WINNT +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0600 +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include <winsock2.h> +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#undef WIN32_LEAN_AND_MEAN +#else +#include <windows.h> +#endif +#include <direct.h> +#include <io.h> +#endif + + +#ifdef BSON_OS_UNIX +#include <unistd.h> +#include <sys/time.h> +#endif + + +#include "bson-macros.h" + + +#include <errno.h> +#include <ctype.h> +#include <limits.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + + +BSON_BEGIN_DECLS + + +#ifdef _MSC_VER +#include "bson-stdint-win32.h" +#ifndef __cplusplus +/* benign redefinition of type */ +#pragma warning(disable : 4142) +#ifndef _SSIZE_T_DEFINED +#define _SSIZE_T_DEFINED +typedef SSIZE_T ssize_t; +#endif +#ifndef _SIZE_T_DEFINED +#define _SIZE_T_DEFINED +typedef SIZE_T size_t; +#endif +#pragma warning(default : 4142) +#else +/* + * MSVC++ does not include ssize_t, just size_t. + * So we need to synthesize that as well. + */ +#pragma warning(disable : 4142) +#ifndef _SSIZE_T_DEFINED +#define _SSIZE_T_DEFINED +typedef SSIZE_T ssize_t; +#endif +#pragma warning(default : 4142) +#endif +#define PRIi32 "d" +#define PRId32 "d" +#define PRIu32 "u" +#define PRIi64 "I64i" +#define PRId64 "I64i" +#define PRIu64 "I64u" +#else +#include "bson-stdint.h" +#include <inttypes.h> +#endif + +#if defined(__MINGW32__) && !defined(INIT_ONCE_STATIC_INIT) +#define INIT_ONCE_STATIC_INIT RTL_RUN_ONCE_INIT +typedef RTL_RUN_ONCE INIT_ONCE; +#endif + +#ifdef BSON_HAVE_STDBOOL_H +#include <stdbool.h> +#elif !defined(__bool_true_false_are_defined) +#ifndef __cplusplus +typedef signed char bool; +#define false 0 +#define true 1 +#endif +#define __bool_true_false_are_defined 1 +#endif + + +#if defined(__GNUC__) +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) +#define bson_sync_synchronize() __sync_synchronize () +#elif defined(__i386__) || defined(__i486__) || defined(__i586__) || \ + defined(__i686__) || defined(__x86_64__) +#define bson_sync_synchronize() asm volatile("mfence" ::: "memory") +#else +#define bson_sync_synchronize() asm volatile("sync" ::: "memory") +#endif +#elif defined(_MSC_VER) +#define bson_sync_synchronize() MemoryBarrier () +#endif + + +#if !defined(va_copy) && defined(__va_copy) +#define va_copy(dst, src) __va_copy (dst, src) +#endif + + +#if !defined(va_copy) +#define va_copy(dst, src) ((dst) = (src)) +#endif + + +BSON_END_DECLS + + +#endif /* BSON_COMPAT_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-config.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-config.h new file mode 100644 index 0000000000000000000000000000000000000000..bbd734675427b93566060208d428402e235b579b --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-config.h @@ -0,0 +1,128 @@ +#ifndef BSON_CONFIG_H +#define BSON_CONFIG_H + +#include <boost/detail/endian.hpp> + +/* + * Define to 1234 for Little Endian, 4321 for Big Endian. + */ +#if defined(BOOST_LITTLE_ENDIAN) +#define BSON_BYTE_ORDER 1234 +#elif defined(BOOST_BIG_ENDIAN) +#define BSON_BYTE_ORDER 4321 +#else +#error "unable to determine system endianness" +#endif + +#define BSON_INSIDE +#define BSON_COMPILATION + +/* + * Define to 1 if you have stdbool.h + */ +#define BSON_HAVE_STDBOOL_H 1 +#if BSON_HAVE_STDBOOL_H != 1 +# undef BSON_HAVE_STDBOOL_H +#endif + + +/* + * Define to 1 for POSIX-like systems, 2 for Windows. + */ +#define BSON_OS 1 + + +/* + * Define to 1 if we have access to GCC 32-bit atomic builtins. + * While this requires GCC 4.1+ in most cases, it is also architecture + * dependent. For example, some PPC or ARM systems may not have it even + * if it is a recent GCC version. + */ +#define BSON_HAVE_ATOMIC_32_ADD_AND_FETCH 1 +#if BSON_HAVE_ATOMIC_32_ADD_AND_FETCH != 1 +# undef BSON_HAVE_ATOMIC_32_ADD_AND_FETCH +#endif + +/* + * Similarly, define to 1 if we have access to GCC 64-bit atomic builtins. + */ +#define BSON_HAVE_ATOMIC_64_ADD_AND_FETCH 1 +#if BSON_HAVE_ATOMIC_64_ADD_AND_FETCH != 1 +# undef BSON_HAVE_ATOMIC_64_ADD_AND_FETCH +#endif + + +/* + * Define to 1 if your system requires {} around PTHREAD_ONCE_INIT. + * This is typically just Solaris 8-10. + */ +#define BSON_PTHREAD_ONCE_INIT_NEEDS_BRACES 0 +#if BSON_PTHREAD_ONCE_INIT_NEEDS_BRACES != 1 +# undef BSON_PTHREAD_ONCE_INIT_NEEDS_BRACES +#endif + + +/* + * Define to 1 if you have clock_gettime() available. + */ +#define BSON_HAVE_CLOCK_GETTIME 1 +#if BSON_HAVE_CLOCK_GETTIME != 1 +# undef BSON_HAVE_CLOCK_GETTIME +#endif + + +/* + * Define to 1 if you have strnlen available on your platform. + */ +#define BSON_HAVE_STRNLEN 1 +#if BSON_HAVE_STRNLEN != 1 +# undef BSON_HAVE_STRNLEN +#endif + + +/* + * Define to 1 if you have snprintf available on your platform. + */ +#define BSON_HAVE_SNPRINTF 1 +#if BSON_HAVE_SNPRINTF != 1 +# undef BSON_HAVE_SNPRINTF +#endif + + +/* + * Define to 1 if you have reallocf available on your platform. + */ +#define BSON_HAVE_REALLOCF 0 +#if BSON_HAVE_REALLOCF != 1 +# undef BSON_HAVE_REALLOCF +#endif + + +/* + * Define to 1 if you have struct timespec available on your platform. + */ +#define BSON_HAVE_TIMESPEC 1 +#if BSON_HAVE_TIMESPEC != 1 +# undef BSON_HAVE_TIMESPEC +#endif + + +/* + * Define to 1 if you want extra aligned types in libbson + */ +#define BSON_EXTRA_ALIGN 1 +#if BSON_EXTRA_ALIGN != 1 +# undef BSON_EXTRA_ALIGN +#endif + + +/* + * Define to 1 if you have SYS_gettid syscall + */ +#define BSON_HAVE_SYSCALL_TID 0 +#if BSON_HAVE_SYSCALL_TID != 1 +# undef BSON_HAVE_SYSCALL_TID +#endif + + +#endif /* BSON_CONFIG_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-context-private.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-context-private.h new file mode 100644 index 0000000000000000000000000000000000000000..26918984d01b4cb369ad7d3b436b759c993416f1 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-context-private.h @@ -0,0 +1,47 @@ +/* + * Copyright 2014 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_CONTEXT_PRIVATE_H +#define BSON_CONTEXT_PRIVATE_H + + +#include "bson-context.h" +#include "bson-thread-private.h" + + +BSON_BEGIN_DECLS + + +struct _bson_context_t { + bson_context_flags_t flags : 7; + bool pidbe_once : 1; + uint8_t pidbe[2]; + uint8_t md5[3]; + int32_t seq32; + int64_t seq64; + + void (*oid_get_host) (bson_context_t *context, bson_oid_t *oid); + void (*oid_get_pid) (bson_context_t *context, bson_oid_t *oid); + void (*oid_get_seq32) (bson_context_t *context, bson_oid_t *oid); + void (*oid_get_seq64) (bson_context_t *context, bson_oid_t *oid); +}; + + +BSON_END_DECLS + + +#endif /* BSON_CONTEXT_PRIVATE_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-context.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-context.c new file mode 100644 index 0000000000000000000000000000000000000000..763fbc6dfc014ec97eb631c9e802e4c0b74e41a9 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-context.c @@ -0,0 +1,502 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bson-compat.h" + +#include <limits.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "bson-atomic.h" +#include "bson-clock.h" +#include "bson-context.h" +#include "bson-context-private.h" +#include "bson-md5.h" +#include "bson-memory.h" +#include "bson-thread-private.h" + +#ifdef BSON_HAVE_SYSCALL_TID +#include <sys/syscall.h> +#endif + + +#ifndef HOST_NAME_MAX +#define HOST_NAME_MAX 256 +#endif + + +/* + * Globals. + */ +static bson_context_t gContextDefault; + + +#ifdef BSON_HAVE_SYSCALL_TID +static uint16_t +gettid (void) +{ + return syscall (SYS_gettid); +} +#endif + + +/* + *-------------------------------------------------------------------------- + * + * _bson_context_get_oid_host -- + * + * Retrieves the first three bytes of MD5(hostname) and assigns them + * to the host portion of oid. + * + * Returns: + * None. + * + * Side effects: + * @oid is modified. + * + *-------------------------------------------------------------------------- + */ + +static void +_bson_context_get_oid_host (bson_context_t *context, /* IN */ + bson_oid_t *oid) /* OUT */ +{ + uint8_t *bytes = (uint8_t *) oid; + uint8_t digest[16]; + bson_md5_t md5; + char hostname[HOST_NAME_MAX]; + + BSON_ASSERT (context); + BSON_ASSERT (oid); + + gethostname (hostname, sizeof hostname); + hostname[HOST_NAME_MAX - 1] = '\0'; + + bson_md5_init (&md5); + bson_md5_append ( + &md5, (const uint8_t *) hostname, (uint32_t) strlen (hostname)); + bson_md5_finish (&md5, &digest[0]); + + bytes[4] = digest[0]; + bytes[5] = digest[1]; + bytes[6] = digest[2]; +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_context_get_oid_host_cached -- + * + * Fetch the cached copy of the MD5(hostname). + * + * Returns: + * None. + * + * Side effects: + * @oid is modified. + * + *-------------------------------------------------------------------------- + */ + +static void +_bson_context_get_oid_host_cached (bson_context_t *context, /* IN */ + bson_oid_t *oid) /* OUT */ +{ + BSON_ASSERT (context); + BSON_ASSERT (oid); + + oid->bytes[4] = context->md5[0]; + oid->bytes[5] = context->md5[1]; + oid->bytes[6] = context->md5[2]; +} + + +static BSON_INLINE uint16_t +_bson_getpid (void) +{ + uint16_t pid; +#ifdef BSON_OS_WIN32 + DWORD real_pid; + + real_pid = GetCurrentProcessId (); + pid = (real_pid & 0xFFFF) ^ ((real_pid >> 16) & 0xFFFF); +#else + pid = getpid (); +#endif + + return pid; +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_context_get_oid_pid -- + * + * Initialize the pid field of @oid. + * + * The pid field is 2 bytes, big-endian for memcmp(). + * + * Returns: + * None. + * + * Side effects: + * @oid is modified. + * + *-------------------------------------------------------------------------- + */ + +static void +_bson_context_get_oid_pid (bson_context_t *context, /* IN */ + bson_oid_t *oid) /* OUT */ +{ + uint16_t pid = _bson_getpid (); + uint8_t *bytes = (uint8_t *) &pid; + + BSON_ASSERT (context); + BSON_ASSERT (oid); + + pid = BSON_UINT16_TO_BE (pid); + + oid->bytes[7] = bytes[0]; + oid->bytes[8] = bytes[1]; +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_context_get_oid_pid_cached -- + * + * Fetch the cached copy of the current pid. + * This helps avoid multiple calls to getpid() which is slower + * on some systems. + * + * Returns: + * None. + * + * Side effects: + * @oid is modified. + * + *-------------------------------------------------------------------------- + */ + +static void +_bson_context_get_oid_pid_cached (bson_context_t *context, /* IN */ + bson_oid_t *oid) /* OUT */ +{ + oid->bytes[7] = context->pidbe[0]; + oid->bytes[8] = context->pidbe[1]; +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_context_get_oid_seq32 -- + * + * 32-bit sequence generator, non-thread-safe version. + * + * Returns: + * None. + * + * Side effects: + * @oid is modified. + * + *-------------------------------------------------------------------------- + */ + +static void +_bson_context_get_oid_seq32 (bson_context_t *context, /* IN */ + bson_oid_t *oid) /* OUT */ +{ + uint32_t seq = context->seq32++; + + seq = BSON_UINT32_TO_BE (seq); + memcpy (&oid->bytes[9], ((uint8_t *) &seq) + 1, 3); +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_context_get_oid_seq32_threadsafe -- + * + * Thread-safe version of 32-bit sequence generator. + * + * Returns: + * None. + * + * Side effects: + * @oid is modified. + * + *-------------------------------------------------------------------------- + */ + +static void +_bson_context_get_oid_seq32_threadsafe (bson_context_t *context, /* IN */ + bson_oid_t *oid) /* OUT */ +{ + int32_t seq = bson_atomic_int_add (&context->seq32, 1); + + seq = BSON_UINT32_TO_BE (seq); + memcpy (&oid->bytes[9], ((uint8_t *) &seq) + 1, 3); +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_context_get_oid_seq64 -- + * + * 64-bit oid sequence generator, non-thread-safe version. + * + * Returns: + * None. + * + * Side effects: + * @oid is modified. + * + *-------------------------------------------------------------------------- + */ + +static void +_bson_context_get_oid_seq64 (bson_context_t *context, /* IN */ + bson_oid_t *oid) /* OUT */ +{ + uint64_t seq; + + BSON_ASSERT (context); + BSON_ASSERT (oid); + + seq = BSON_UINT64_TO_BE (context->seq64++); + memcpy (&oid->bytes[4], &seq, sizeof (seq)); +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_context_get_oid_seq64_threadsafe -- + * + * Thread-safe 64-bit sequence generator. + * + * Returns: + * None. + * + * Side effects: + * @oid is modified. + * + *-------------------------------------------------------------------------- + */ + +static void +_bson_context_get_oid_seq64_threadsafe (bson_context_t *context, /* IN */ + bson_oid_t *oid) /* OUT */ +{ + int64_t seq = bson_atomic_int64_add (&context->seq64, 1); + + seq = BSON_UINT64_TO_BE (seq); + memcpy (&oid->bytes[4], &seq, sizeof (seq)); +} + + +static void +_bson_context_init (bson_context_t *context, /* IN */ + bson_context_flags_t flags) /* IN */ +{ + struct timeval tv; + uint16_t pid; + unsigned int seed[3]; + unsigned int real_seed; + bson_oid_t oid; + + context->flags = flags; + context->oid_get_host = _bson_context_get_oid_host_cached; + context->oid_get_pid = _bson_context_get_oid_pid_cached; + context->oid_get_seq32 = _bson_context_get_oid_seq32; + context->oid_get_seq64 = _bson_context_get_oid_seq64; + + /* + * Generate a seed for our the random starting position of our increment + * bytes. We mask off the last nibble so that the last digit of the OID will + * start at zero. Just to be nice. + * + * The seed itself is made up of the current time in seconds, milliseconds, + * and pid xored together. I welcome better solutions if at all necessary. + */ + bson_gettimeofday (&tv); + seed[0] = (unsigned int) tv.tv_sec; + seed[1] = (unsigned int) tv.tv_usec; + seed[2] = _bson_getpid (); + real_seed = seed[0] ^ seed[1] ^ seed[2]; + +#ifdef BSON_OS_WIN32 + /* ms's runtime is multithreaded by default, so no rand_r */ + srand (real_seed); + context->seq32 = rand () & 0x007FFFF0; +#else + context->seq32 = rand_r (&real_seed) & 0x007FFFF0; +#endif + + if ((flags & BSON_CONTEXT_DISABLE_HOST_CACHE)) { + context->oid_get_host = _bson_context_get_oid_host; + } else { + _bson_context_get_oid_host (context, &oid); + context->md5[0] = oid.bytes[4]; + context->md5[1] = oid.bytes[5]; + context->md5[2] = oid.bytes[6]; + } + + if ((flags & BSON_CONTEXT_THREAD_SAFE)) { + context->oid_get_seq32 = _bson_context_get_oid_seq32_threadsafe; + context->oid_get_seq64 = _bson_context_get_oid_seq64_threadsafe; + } + + if ((flags & BSON_CONTEXT_DISABLE_PID_CACHE)) { + context->oid_get_pid = _bson_context_get_oid_pid; + } else { +#ifdef BSON_HAVE_SYSCALL_TID + if ((flags & BSON_CONTEXT_USE_TASK_ID)) { + int32_t tid; + + /* This call is always successful */ + tid = gettid (); + pid = BSON_UINT16_TO_BE (tid); + } else +#endif + pid = BSON_UINT16_TO_BE (_bson_getpid ()); + + memcpy (&context->pidbe[0], &pid, 2); + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_context_new -- + * + * Initializes a new context with the flags specified. + * + * In most cases, you want to call this with @flags set to + * BSON_CONTEXT_NONE. + * + * If you are running on Linux, %BSON_CONTEXT_USE_TASK_ID can result + * in a healthy speedup for multi-threaded scenarios. + * + * If you absolutely must have a single context for your application + * and use more than one thread, then %BSON_CONTEXT_THREAD_SAFE should + * be bitwise-or'd with your flags. This requires synchronization + * between threads. + * + * If you expect your hostname to change often, you may consider + * specifying %BSON_CONTEXT_DISABLE_HOST_CACHE so that gethostname() + * is called for every OID generated. This is much slower. + * + * If you expect your pid to change without notice, such as from an + * unexpected call to fork(), then specify + * %BSON_CONTEXT_DISABLE_PID_CACHE. + * + * Returns: + * A newly allocated bson_context_t that should be freed with + * bson_context_destroy(). + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bson_context_t * +bson_context_new (bson_context_flags_t flags) +{ + bson_context_t *context; + + context = bson_malloc0 (sizeof *context); + _bson_context_init (context, flags); + + return context; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_context_destroy -- + * + * Cleans up a bson_context_t and releases any associated resources. + * This should be called when you are done using @context. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_context_destroy (bson_context_t *context) /* IN */ +{ + if (context != &gContextDefault) { + memset (context, 0, sizeof *context); + bson_free (context); + } +} + + +static BSON_ONCE_FUN (_bson_context_init_default) +{ + _bson_context_init ( + &gContextDefault, + (BSON_CONTEXT_THREAD_SAFE | BSON_CONTEXT_DISABLE_PID_CACHE)); + BSON_ONCE_RETURN; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_context_get_default -- + * + * Fetches the default, thread-safe implementation of #bson_context_t. + * If you need faster generation, it is recommended you create your + * own #bson_context_t with bson_context_new(). + * + * Returns: + * A shared instance to the default #bson_context_t. This should not + * be modified or freed. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bson_context_t * +bson_context_get_default (void) +{ + static bson_once_t once = BSON_ONCE_INIT; + + bson_once (&once, _bson_context_init_default); + + return &gContextDefault; +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-context.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-context.h new file mode 100644 index 0000000000000000000000000000000000000000..5f1cb40cb4c7409df04d143de480761a6ec5ebd2 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-context.h @@ -0,0 +1,45 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_CONTEXT_H +#define BSON_CONTEXT_H + + +#if !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) +#error "Only <bson.h> can be included directly." +#endif + + +#include "bson-macros.h" +#include "bson-types.h" + + +BSON_BEGIN_DECLS + + +BSON_EXPORT (bson_context_t *) +bson_context_new (bson_context_flags_t flags); +BSON_EXPORT (void) +bson_context_destroy (bson_context_t *context); +BSON_EXPORT (bson_context_t *) +bson_context_get_default (void) BSON_GNUC_CONST; + + +BSON_END_DECLS + + +#endif /* BSON_CONTEXT_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-decimal128.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-decimal128.c new file mode 100644 index 0000000000000000000000000000000000000000..5f73df694d096857af00a2d359155de157bc555f --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-decimal128.c @@ -0,0 +1,734 @@ + +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "bson-decimal128.h" +#include "bson-types.h" +#include "bson-macros.h" +#include "bson-string.h" + + +#define BSON_DECIMAL128_EXPONENT_MAX 6111 +#define BSON_DECIMAL128_EXPONENT_MIN -6176 +#define BSON_DECIMAL128_EXPONENT_BIAS 6176 +#define BSON_DECIMAL128_MAX_DIGITS 34 + +#define BSON_DECIMAL128_SET_NAN(dec) \ + do { \ + (dec).high = 0x7c00000000000000ull; \ + (dec).low = 0; \ + } while (0); +#define BSON_DECIMAL128_SET_INF(dec, isneg) \ + do { \ + (dec).high = 0x7800000000000000ull + 0x8000000000000000ull * (isneg); \ + (dec).low = 0; \ + } while (0); + +/** + * _bson_uint128_t: + * + * This struct represents a 128 bit integer. + */ +typedef struct { + uint32_t parts[4]; /* 32-bit words stored high to low. */ +} _bson_uint128_t; + + +/** + *------------------------------------------------------------------------------ + * + * _bson_uint128_divide1B -- + * + * This function divides a #_bson_uint128_t by 1000000000 (1 billion) and + * computes the quotient and remainder. + * + * The remainder will contain 9 decimal digits for conversion to string. + * + * @value The #_bson_uint128_t operand. + * @quotient A pointer to store the #_bson_uint128_t quotient. + * @rem A pointer to store the #uint64_t remainder. + * + * Returns: + * The quotient at @quotient and the remainder at @rem. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------------ + */ +static void +_bson_uint128_divide1B (_bson_uint128_t value, /* IN */ + _bson_uint128_t *quotient, /* OUT */ + uint32_t *rem) /* OUT */ +{ + const uint32_t DIVISOR = 1000 * 1000 * 1000; + uint64_t _rem = 0; + int i = 0; + + if (!value.parts[0] && !value.parts[1] && !value.parts[2] && + !value.parts[3]) { + *quotient = value; + *rem = 0; + return; + } + + + for (i = 0; i <= 3; i++) { + _rem <<= 32; /* Adjust remainder to match value of next dividend */ + _rem += value.parts[i]; /* Add the divided to _rem */ + value.parts[i] = (uint32_t) (_rem / DIVISOR); + _rem %= DIVISOR; /* Store the remainder */ + } + + *quotient = value; + *rem = (uint32_t) _rem; +} + + +/** + *------------------------------------------------------------------------------ + * + * bson_decimal128_to_string -- + * + * This function converts a BID formatted decimal128 value to string, + * accepting a &bson_decimal128_t as @dec. The string is stored at @str. + * + * @dec : The BID formatted decimal to convert. + * @str : The output decimal128 string. At least %BSON_DECIMAL128_STRING + *characters. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------------ + */ +void +bson_decimal128_to_string (const bson_decimal128_t *dec, /* IN */ + char *str) /* OUT */ +{ + uint32_t COMBINATION_MASK = 0x1f; /* Extract least significant 5 bits */ + uint32_t EXPONENT_MASK = 0x3fff; /* Extract least significant 14 bits */ + uint32_t COMBINATION_INFINITY = 30; /* Value of combination field for Inf */ + uint32_t COMBINATION_NAN = 31; /* Value of combination field for NaN */ + uint32_t EXPONENT_BIAS = 6176; /* decimal128 exponent bias */ + + char *str_out = str; /* output pointer in string */ + char significand_str[35]; /* decoded significand digits */ + + + /* Note: bits in this routine are referred to starting at 0, */ + /* from the sign bit, towards the coefficient. */ + uint32_t high; /* bits 0 - 31 */ + uint32_t midh; /* bits 32 - 63 */ + uint32_t midl; /* bits 64 - 95 */ + uint32_t low; /* bits 96 - 127 */ + uint32_t combination; /* bits 1 - 5 */ + uint32_t biased_exponent; /* decoded biased exponent (14 bits) */ + uint32_t significand_digits = 0; /* the number of significand digits */ + uint32_t significand[36] = {0}; /* the base-10 digits in the significand */ + uint32_t *significand_read = significand; /* read pointer into significand */ + int32_t exponent; /* unbiased exponent */ + int32_t scientific_exponent; /* the exponent if scientific notation is + * used */ + bool is_zero = false; /* true if the number is zero */ + + uint8_t significand_msb; /* the most signifcant significand bits (50-46) */ + _bson_uint128_t + significand128; /* temporary storage for significand decoding */ + size_t i; /* indexing variables */ + int j, k; + + memset (significand_str, 0, sizeof (significand_str)); + + if ((int64_t) dec->high < 0) { /* negative */ + *(str_out++) = '-'; + } + + low = (uint32_t) dec->low, midl = (uint32_t) (dec->low >> 32), + midh = (uint32_t) dec->high, high = (uint32_t) (dec->high >> 32); + + /* Decode combination field and exponent */ + combination = (high >> 26) & COMBINATION_MASK; + + if (BSON_UNLIKELY ((combination >> 3) == 3)) { + /* Check for 'special' values */ + if (combination == COMBINATION_INFINITY) { /* Infinity */ + strcpy (str_out, BSON_DECIMAL128_INF); + return; + } else if (combination == COMBINATION_NAN) { /* NaN */ + /* str, not str_out, to erase the sign */ + strcpy (str, BSON_DECIMAL128_NAN); + /* we don't care about the NaN payload. */ + return; + } else { + biased_exponent = (high >> 15) & EXPONENT_MASK; + significand_msb = 0x8 + ((high >> 14) & 0x1); + } + } else { + significand_msb = (high >> 14) & 0x7; + biased_exponent = (high >> 17) & EXPONENT_MASK; + } + + exponent = biased_exponent - EXPONENT_BIAS; + /* Create string of significand digits */ + + /* Convert the 114-bit binary number represented by */ + /* (high, midh, midl, low) to at most 34 decimal */ + /* digits through modulo and division. */ + significand128.parts[0] = (high & 0x3fff) + ((significand_msb & 0xf) << 14); + significand128.parts[1] = midh; + significand128.parts[2] = midl; + significand128.parts[3] = low; + + if (significand128.parts[0] == 0 && significand128.parts[1] == 0 && + significand128.parts[2] == 0 && significand128.parts[3] == 0) { + is_zero = true; + } else if (significand128.parts[0] >= (1 << 17)) { + /* The significand is non-canonical or zero. + * In order to preserve compatability with the densely packed decimal + * format, the maximum value for the significand of decimal128 is + * 1e34 - 1. If the value is greater than 1e34 - 1, the IEEE 754 + * standard dictates that the significand is interpreted as zero. + */ + is_zero = true; + } else { + for (k = 3; k >= 0; k--) { + uint32_t least_digits = 0; + _bson_uint128_divide1B ( + significand128, &significand128, &least_digits); + + /* We now have the 9 least significant digits (in base 2). */ + /* Convert and output to string. */ + if (!least_digits) { + continue; + } + + for (j = 8; j >= 0; j--) { + significand[k * 9 + j] = least_digits % 10; + least_digits /= 10; + } + } + } + + /* Output format options: */ + /* Scientific - [-]d.dddE(+/-)dd or [-]dE(+/-)dd */ + /* Regular - ddd.ddd */ + + if (is_zero) { + significand_digits = 1; + *significand_read = 0; + } else { + significand_digits = 36; + while (!(*significand_read)) { + significand_digits--; + significand_read++; + } + } + + scientific_exponent = significand_digits - 1 + exponent; + + /* The scientific exponent checks are dictated by the string conversion + * specification and are somewhat arbitrary cutoffs. + * + * We must check exponent > 0, because if this is the case, the number + * has trailing zeros. However, we *cannot* output these trailing zeros, + * because doing so would change the precision of the value, and would + * change stored data if the string converted number is round tripped. + */ + if (scientific_exponent < -6 || exponent > 0) { + /* Scientific format */ + *(str_out++) = *(significand_read++) + '0'; + significand_digits--; + + if (significand_digits) { + *(str_out++) = '.'; + } + + for (i = 0; i < significand_digits; i++) { + *(str_out++) = *(significand_read++) + '0'; + } + /* Exponent */ + *(str_out++) = 'E'; + bson_snprintf (str_out, 6, "%+d", scientific_exponent); + } else { + /* Regular format with no decimal place */ + if (exponent >= 0) { + for (i = 0; i < significand_digits; i++) { + *(str_out++) = *(significand_read++) + '0'; + } + *str_out = '\0'; + } else { + int32_t radix_position = significand_digits + exponent; + + if (radix_position > 0) { /* non-zero digits before radix */ + for (i = 0; i < radix_position; i++) { + *(str_out++) = *(significand_read++) + '0'; + } + } else { /* leading zero before radix point */ + *(str_out++) = '0'; + } + + *(str_out++) = '.'; + while (radix_position++ < 0) { /* add leading zeros after radix */ + *(str_out++) = '0'; + } + + for (i = 0; i < significand_digits - BSON_MAX (radix_position - 1, 0); + i++) { + *(str_out++) = *(significand_read++) + '0'; + } + *str_out = '\0'; + } + } +} + +typedef struct { + uint64_t high, low; +} _bson_uint128_6464_t; + + +/** + *------------------------------------------------------------------------- + * + * mul64x64 -- + * + * This function multiplies two &uint64_t into a &_bson_uint128_6464_t. + * + * Returns: + * The product of @left and @right. + * + * Side Effects: + * None. + * + *------------------------------------------------------------------------- + */ +static void +_mul_64x64 (uint64_t left, /* IN */ + uint64_t right, /* IN */ + _bson_uint128_6464_t *product) /* OUT */ +{ + uint64_t left_high, left_low, right_high, right_low, product_high, + product_mid, product_mid2, product_low; + _bson_uint128_6464_t rt = {0}; + + if (!left && !right) { + *product = rt; + return; + } + + left_high = left >> 32; + left_low = (uint32_t) left; + right_high = right >> 32; + right_low = (uint32_t) right; + + product_high = left_high * right_high; + product_mid = left_high * right_low; + product_mid2 = left_low * right_high; + product_low = left_low * right_low; + + product_high += product_mid >> 32; + product_mid = (uint32_t) product_mid + product_mid2 + (product_low >> 32); + + product_high = product_high + (product_mid >> 32); + product_low = (product_mid << 32) + (uint32_t) product_low; + + rt.high = product_high; + rt.low = product_low; + *product = rt; +} + +/** + *------------------------------------------------------------------------------ + * + * _dec128_tolower -- + * + * This function converts the ASCII character @c to lowercase. It is locale + * insensitive (unlike the stdlib tolower). + * + * Returns: + * The lowercased character. + */ +char +_dec128_tolower (char c) +{ + if (isupper (c)) { + c += 32; + } + + return c; +} + +/** + *------------------------------------------------------------------------------ + * + * _dec128_istreq -- + * + * This function compares the null-terminated *ASCII* strings @a and @b + * for case-insensitive equality. + * + * Returns: + * true if the strings are equal, false otherwise. + */ +bool +_dec128_istreq (const char *a, /* IN */ + const char *b /* IN */) +{ + while (*a != '\0' || *b != '\0') { + /* strings are different lengths. */ + if (*a == '\0' || *b == '\0') { + return false; + } + + if (_dec128_tolower (*a) != _dec128_tolower (*b)) { + return false; + } + + a++; + b++; + } + + return true; +} + +/** + *------------------------------------------------------------------------------ + * + * bson_decimal128_from_string -- + * + * This function converts @string in the format [+-]ddd[.]ddd[E][+-]dddd to + * decimal128. Out of range values are converted to +/-Infinity. Invalid + * strings are converted to NaN. + * + * If more digits are provided than the available precision allows, + * round to the nearest expressable decimal128 with ties going to even will + * occur. + * + * Note: @string must be ASCII only! + * + * Returns: + * true on success, or false on failure. @dec will be NaN if @str was invalid + * The &bson_decimal128_t converted from @string at @dec. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------------ + */ +bool +bson_decimal128_from_string (const char *string, /* IN */ + bson_decimal128_t *dec) /* OUT */ +{ + _bson_uint128_6464_t significand = {0}; + + const char *str_read = string; /* Read pointer for consuming str. */ + + /* Parsing state tracking */ + bool is_negative = false; + bool saw_radix = false; + bool includes_sign = false; /* True if the input string contains a sign. */ + bool found_nonzero = false; + + size_t significant_digits = 0; /* Total number of significant digits + * (no leading or trailing zero) */ + size_t ndigits_read = 0; /* Total number of significand digits read */ + size_t ndigits = 0; /* Total number of digits (no leading zeros) */ + size_t radix_position = 0; /* The number of the digits after radix */ + size_t first_nonzero = 0; /* The index of the first non-zero in *str* */ + + uint16_t digits[BSON_DECIMAL128_MAX_DIGITS] = {0}; + uint16_t ndigits_stored = 0; /* The number of digits in digits */ + uint16_t *digits_insert = digits; /* Insertion pointer for digits */ + size_t first_digit = 0; /* The index of the first non-zero digit */ + size_t last_digit = 0; /* The index of the last digit */ + + int32_t exponent = 0; + uint64_t significand_high = 0; /* The high 17 digits of the significand */ + uint64_t significand_low = 0; /* The low 17 digits of the significand */ + uint16_t biased_exponent = 0; /* The biased exponent */ + + BSON_ASSERT (dec); + dec->high = 0; + dec->low = 0; + + if (*str_read == '+' || *str_read == '-') { + is_negative = *(str_read++) == '-'; + includes_sign = true; + } + + /* Check for Infinity or NaN */ + if (!isdigit (*str_read) && *str_read != '.') { + if (_dec128_istreq (str_read, "inf") || + _dec128_istreq (str_read, "infinity")) { + BSON_DECIMAL128_SET_INF (*dec, is_negative); + return true; + } else if (_dec128_istreq (str_read, "nan")) { + BSON_DECIMAL128_SET_NAN (*dec); + return true; + } + + BSON_DECIMAL128_SET_NAN (*dec); + return false; + } + + /* Read digits */ + while (isdigit (*str_read) || *str_read == '.') { + if (*str_read == '.') { + if (saw_radix) { + BSON_DECIMAL128_SET_NAN (*dec); + return false; + } + + saw_radix = true; + str_read++; + continue; + } + + if (ndigits_stored < 34) { + if (*str_read != '0' || found_nonzero) { + if (!found_nonzero) { + first_nonzero = ndigits_read; + } + + found_nonzero = true; + *(digits_insert++) = *(str_read) - '0'; /* Only store 34 digits */ + ndigits_stored++; + } + } + + if (found_nonzero) { + ndigits++; + } + + if (saw_radix) { + radix_position++; + } + + ndigits_read++; + str_read++; + } + + if (saw_radix && !ndigits_read) { + BSON_DECIMAL128_SET_NAN (*dec); + return false; + } + + /* Read exponent if exists */ + if (*str_read == 'e' || *str_read == 'E') { + int nread = 0; +#ifdef _MSC_VER +#define SSCANF sscanf_s +#else +#define SSCANF sscanf +#endif + int read_exponent = SSCANF (++str_read, "%d%n", &exponent, &nread); + str_read += nread; + + if (!read_exponent || nread == 0) { + BSON_DECIMAL128_SET_NAN (*dec); + return false; + } + +#undef SSCANF + } + + if (*str_read) { + BSON_DECIMAL128_SET_NAN (*dec); + return false; + } + + /* Done reading input. */ + /* Find first non-zero digit in digits */ + first_digit = 0; + + if (!ndigits_stored) { /* value is zero */ + first_digit = 0; + last_digit = 0; + digits[0] = 0; + ndigits = 1; + ndigits_stored = 1; + significant_digits = 0; + } else { + last_digit = ndigits_stored - 1; + significant_digits = ndigits; + /* Mark trailing zeros as non-significant */ + while (string[first_nonzero + significant_digits - 1 + includes_sign + + saw_radix] == '0') { + significant_digits--; + } + } + + + /* Normalization of exponent */ + /* Correct exponent based on radix position, and shift significand as needed + */ + /* to represent user input */ + + /* Overflow prevention */ + if (exponent <= radix_position && radix_position - exponent > (1 << 14)) { + exponent = BSON_DECIMAL128_EXPONENT_MIN; + } else { + exponent -= radix_position; + } + + /* Attempt to normalize the exponent */ + while (exponent > BSON_DECIMAL128_EXPONENT_MAX) { + /* Shift exponent to significand and decrease */ + last_digit++; + + if (last_digit - first_digit > BSON_DECIMAL128_MAX_DIGITS) { + /* The exponent is too great to shift into the significand. */ + if (significant_digits == 0) { + /* Value is zero, we are allowed to clamp the exponent. */ + exponent = BSON_DECIMAL128_EXPONENT_MAX; + break; + } + + /* Overflow is not permitted, error. */ + BSON_DECIMAL128_SET_NAN (*dec); + return false; + } + + exponent--; + } + + while (exponent < BSON_DECIMAL128_EXPONENT_MIN || ndigits_stored < ndigits) { + /* Shift last digit */ + if (last_digit == 0) { + /* underflow is not allowed, but zero clamping is */ + if (significant_digits == 0) { + exponent = BSON_DECIMAL128_EXPONENT_MIN; + break; + } + + BSON_DECIMAL128_SET_NAN (*dec); + return false; + } + + if (ndigits_stored < ndigits) { + if (string[ndigits - 1 + includes_sign + saw_radix] - '0' != 0 && + significant_digits != 0) { + BSON_DECIMAL128_SET_NAN (*dec); + return false; + } + + ndigits--; /* adjust to match digits not stored */ + } else { + if (digits[last_digit] != 0) { + /* Inexact rounding is not allowed. */ + BSON_DECIMAL128_SET_NAN (*dec); + return false; + } + + + last_digit--; /* adjust to round */ + } + + if (exponent < BSON_DECIMAL128_EXPONENT_MAX) { + exponent++; + } else { + BSON_DECIMAL128_SET_NAN (*dec); + return false; + } + } + + /* Round */ + /* We've normalized the exponent, but might still need to round. */ + if (last_digit - first_digit + 1 < significant_digits) { + uint8_t round_digit; + + /* There are non-zero digits after last_digit that need rounding. */ + /* We round to nearest, ties to even */ + round_digit = + string[first_nonzero + last_digit + includes_sign + saw_radix + 1] - + '0'; + + if (round_digit != 0) { + /* Inexact (non-zero) rounding is not allowed */ + BSON_DECIMAL128_SET_NAN (*dec); + return false; + } + } + + /* Encode significand */ + significand_high = 0, /* The high 17 digits of the significand */ + significand_low = 0; /* The low 17 digits of the significand */ + + if (significant_digits == 0) { /* read a zero */ + significand_high = 0; + significand_low = 0; + } else if (last_digit - first_digit < 17) { + size_t d_idx = first_digit; + significand_low = digits[d_idx++]; + + for (; d_idx <= last_digit; d_idx++) { + significand_low *= 10; + significand_low += digits[d_idx]; + significand_high = 0; + } + } else { + size_t d_idx = first_digit; + significand_high = digits[d_idx++]; + + for (; d_idx <= last_digit - 17; d_idx++) { + significand_high *= 10; + significand_high += digits[d_idx]; + } + + significand_low = digits[d_idx++]; + + for (; d_idx <= last_digit; d_idx++) { + significand_low *= 10; + significand_low += digits[d_idx]; + } + } + + _mul_64x64 (significand_high, 100000000000000000ull, &significand); + significand.low += significand_low; + + if (significand.low < significand_low) { + significand.high += 1; + } + + + biased_exponent = (exponent + (int16_t) BSON_DECIMAL128_EXPONENT_BIAS); + + /* Encode combination, exponent, and significand. */ + if ((significand.high >> 49) & 1) { + /* Encode '11' into bits 1 to 3 */ + dec->high |= (0x3ull << 61); + dec->high |= (biased_exponent & 0x3fffull) << 47; + dec->high |= significand.high & 0x7fffffffffffull; + } else { + dec->high |= (biased_exponent & 0x3fffull) << 49; + dec->high |= significand.high & 0x1ffffffffffffull; + } + + dec->low = significand.low; + + /* Encode sign */ + if (is_negative) { + dec->high |= 0x8000000000000000ull; + } + + return true; +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-decimal128.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-decimal128.h new file mode 100644 index 0000000000000000000000000000000000000000..e2c0a3327d41946e446cd0740a88d3d327a465ca --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-decimal128.h @@ -0,0 +1,57 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_DECIMAL128_H +#define BSON_DECIMAL128_H + +#include <string.h> + +#include "bson-macros.h" +#include "bson-config.h" +#include "bson-types.h" + + +/** + * BSON_DECIMAL128_STRING: + * + * The length of a decimal128 string (with null terminator). + * + * 1 for the sign + * 35 for digits and radix + * 2 for exponent indicator and sign + * 4 for exponent digits + */ +#define BSON_DECIMAL128_STRING 43 +#define BSON_DECIMAL128_INF "Infinity" +#define BSON_DECIMAL128_NAN "NaN" + + +BSON_BEGIN_DECLS + +BSON_EXPORT (void) +bson_decimal128_to_string (const bson_decimal128_t *dec, char *str); + + +/* Note: @string must be ASCII characters only! */ +BSON_EXPORT (bool) +bson_decimal128_from_string (const char *string, bson_decimal128_t *dec); + + +BSON_END_DECLS + + +#endif /* BSON_DECIMAL128_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-endian.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-endian.h new file mode 100644 index 0000000000000000000000000000000000000000..6bfe40530a34b15c578353ef6ca85f6574bdabc3 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-endian.h @@ -0,0 +1,230 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_ENDIAN_H +#define BSON_ENDIAN_H + + +#if !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) +#error "Only <bson.h> can be included directly." +#endif + + +#if defined(__sun) +#include <sys/byteorder.h> +#endif + +#include "bson-config.h" +#include "bson-macros.h" +#include "bson-compat.h" + + +BSON_BEGIN_DECLS + + +#define BSON_BIG_ENDIAN 4321 +#define BSON_LITTLE_ENDIAN 1234 + + +#if defined(__sun) +#define BSON_UINT16_SWAP_LE_BE(v) BSWAP_16 ((uint16_t) v) +#define BSON_UINT32_SWAP_LE_BE(v) BSWAP_32 ((uint32_t) v) +#define BSON_UINT64_SWAP_LE_BE(v) BSWAP_64 ((uint64_t) v) +#elif defined(__clang__) && defined(__clang_major__) && \ + defined(__clang_minor__) && (__clang_major__ >= 3) && \ + (__clang_minor__ >= 1) +#if __has_builtin(__builtin_bswap16) +#define BSON_UINT16_SWAP_LE_BE(v) __builtin_bswap16 (v) +#endif +#if __has_builtin(__builtin_bswap32) +#define BSON_UINT32_SWAP_LE_BE(v) __builtin_bswap32 (v) +#endif +#if __has_builtin(__builtin_bswap64) +#define BSON_UINT64_SWAP_LE_BE(v) __builtin_bswap64 (v) +#endif +#elif defined(__GNUC__) && (__GNUC__ >= 4) +#if __GNUC__ > 4 || (defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 3) +#define BSON_UINT32_SWAP_LE_BE(v) __builtin_bswap32 ((uint32_t) v) +#define BSON_UINT64_SWAP_LE_BE(v) __builtin_bswap64 ((uint64_t) v) +#endif +#if __GNUC__ > 4 || (defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 8) +#define BSON_UINT16_SWAP_LE_BE(v) __builtin_bswap16 ((uint32_t) v) +#endif +#endif + + +#ifndef BSON_UINT16_SWAP_LE_BE +#define BSON_UINT16_SWAP_LE_BE(v) __bson_uint16_swap_slow ((uint16_t) v) +#endif + + +#ifndef BSON_UINT32_SWAP_LE_BE +#define BSON_UINT32_SWAP_LE_BE(v) __bson_uint32_swap_slow ((uint32_t) v) +#endif + + +#ifndef BSON_UINT64_SWAP_LE_BE +#define BSON_UINT64_SWAP_LE_BE(v) __bson_uint64_swap_slow ((uint64_t) v) +#endif + + +#if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN +#define BSON_UINT16_FROM_LE(v) ((uint16_t) v) +#define BSON_UINT16_TO_LE(v) ((uint16_t) v) +#define BSON_UINT16_FROM_BE(v) BSON_UINT16_SWAP_LE_BE (v) +#define BSON_UINT16_TO_BE(v) BSON_UINT16_SWAP_LE_BE (v) +#define BSON_UINT32_FROM_LE(v) ((uint32_t) v) +#define BSON_UINT32_TO_LE(v) ((uint32_t) v) +#define BSON_UINT32_FROM_BE(v) BSON_UINT32_SWAP_LE_BE (v) +#define BSON_UINT32_TO_BE(v) BSON_UINT32_SWAP_LE_BE (v) +#define BSON_UINT64_FROM_LE(v) ((uint64_t) v) +#define BSON_UINT64_TO_LE(v) ((uint64_t) v) +#define BSON_UINT64_FROM_BE(v) BSON_UINT64_SWAP_LE_BE (v) +#define BSON_UINT64_TO_BE(v) BSON_UINT64_SWAP_LE_BE (v) +#define BSON_DOUBLE_FROM_LE(v) ((double) v) +#define BSON_DOUBLE_TO_LE(v) ((double) v) +#elif BSON_BYTE_ORDER == BSON_BIG_ENDIAN +#define BSON_UINT16_FROM_LE(v) BSON_UINT16_SWAP_LE_BE (v) +#define BSON_UINT16_TO_LE(v) BSON_UINT16_SWAP_LE_BE (v) +#define BSON_UINT16_FROM_BE(v) ((uint16_t) v) +#define BSON_UINT16_TO_BE(v) ((uint16_t) v) +#define BSON_UINT32_FROM_LE(v) BSON_UINT32_SWAP_LE_BE (v) +#define BSON_UINT32_TO_LE(v) BSON_UINT32_SWAP_LE_BE (v) +#define BSON_UINT32_FROM_BE(v) ((uint32_t) v) +#define BSON_UINT32_TO_BE(v) ((uint32_t) v) +#define BSON_UINT64_FROM_LE(v) BSON_UINT64_SWAP_LE_BE (v) +#define BSON_UINT64_TO_LE(v) BSON_UINT64_SWAP_LE_BE (v) +#define BSON_UINT64_FROM_BE(v) ((uint64_t) v) +#define BSON_UINT64_TO_BE(v) ((uint64_t) v) +#define BSON_DOUBLE_FROM_LE(v) (__bson_double_swap_slow (v)) +#define BSON_DOUBLE_TO_LE(v) (__bson_double_swap_slow (v)) +#else +#error "The endianness of target architecture is unknown." +#endif + + +/* + *-------------------------------------------------------------------------- + * + * __bson_uint16_swap_slow -- + * + * Fallback endianness conversion for 16-bit integers. + * + * Returns: + * The endian swapped version. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static BSON_INLINE uint16_t +__bson_uint16_swap_slow (uint16_t v) /* IN */ +{ + return ((v & 0x00FF) << 8) | ((v & 0xFF00) >> 8); +} + + +/* + *-------------------------------------------------------------------------- + * + * __bson_uint32_swap_slow -- + * + * Fallback endianness conversion for 32-bit integers. + * + * Returns: + * The endian swapped version. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static BSON_INLINE uint32_t +__bson_uint32_swap_slow (uint32_t v) /* IN */ +{ + return ((v & 0x000000FFU) << 24) | ((v & 0x0000FF00U) << 8) | + ((v & 0x00FF0000U) >> 8) | ((v & 0xFF000000U) >> 24); +} + + +/* + *-------------------------------------------------------------------------- + * + * __bson_uint64_swap_slow -- + * + * Fallback endianness conversion for 64-bit integers. + * + * Returns: + * The endian swapped version. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static BSON_INLINE uint64_t +__bson_uint64_swap_slow (uint64_t v) /* IN */ +{ + return ((v & 0x00000000000000FFULL) << 56) | + ((v & 0x000000000000FF00ULL) << 40) | + ((v & 0x0000000000FF0000ULL) << 24) | + ((v & 0x00000000FF000000ULL) << 8) | + ((v & 0x000000FF00000000ULL) >> 8) | + ((v & 0x0000FF0000000000ULL) >> 24) | + ((v & 0x00FF000000000000ULL) >> 40) | + ((v & 0xFF00000000000000ULL) >> 56); +} + + +/* + *-------------------------------------------------------------------------- + * + * __bson_double_swap_slow -- + * + * Fallback endianness conversion for double floating point. + * + * Returns: + * The endian swapped version. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +BSON_STATIC_ASSERT (sizeof (double) == sizeof (uint64_t)); + +static BSON_INLINE double +__bson_double_swap_slow (double v) /* IN */ +{ + uint64_t uv; + + memcpy (&uv, &v, sizeof (v)); + uv = BSON_UINT64_SWAP_LE_BE (uv); + memcpy (&v, &uv, sizeof (v)); + + return v; +} + +BSON_END_DECLS + + +#endif /* BSON_ENDIAN_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-error.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-error.c new file mode 100644 index 0000000000000000000000000000000000000000..d16b5faefcf6fe03f9a55f98903bf17f19d8bb4d --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-error.c @@ -0,0 +1,126 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include <stdio.h> +#include <stdarg.h> + +#include "bson-compat.h" +#include "bson-config.h" +#include "bson-error.h" +#include "bson-memory.h" +#include "bson-string.h" +#include "bson-types.h" + + +/* + *-------------------------------------------------------------------------- + * + * bson_set_error -- + * + * Initializes @error using the parameters specified. + * + * @domain is an application specific error domain which should + * describe which module initiated the error. Think of this as the + * exception type. + * + * @code is the @domain specific error code. + * + * @format is used to generate the format string. It uses vsnprintf() + * internally so the format should match what you would use there. + * + * Parameters: + * @error: A #bson_error_t. + * @domain: The error domain. + * @code: The error code. + * @format: A printf style format string. + * + * Returns: + * None. + * + * Side effects: + * @error is initialized. + * + *-------------------------------------------------------------------------- + */ + +void +bson_set_error (bson_error_t *error, /* OUT */ + uint32_t domain, /* IN */ + uint32_t code, /* IN */ + const char *format, /* IN */ + ...) /* IN */ +{ + va_list args; + + if (error) { + error->domain = domain; + error->code = code; + + va_start (args, format); + bson_vsnprintf (error->message, sizeof error->message, format, args); + va_end (args); + + error->message[sizeof error->message - 1] = '\0'; + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_strerror_r -- + * + * This is a reentrant safe macro for strerror. + * + * The resulting string may be stored in @buf. + * + * Returns: + * A pointer to a static string or @buf. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +char * +bson_strerror_r (int err_code, /* IN */ + char *buf, /* IN */ + size_t buflen) /* IN */ +{ + static const char *unknown_msg = "Unknown error"; + char *ret = NULL; + +#if defined(_WIN32) + if (strerror_s (buf, buflen, err_code) != 0) { + ret = buf; + } +#elif defined(__GNUC__) && defined(_GNU_SOURCE) + ret = strerror_r (err_code, buf, buflen); +#else /* XSI strerror_r */ + if (strerror_r (err_code, buf, buflen) == 0) { + ret = buf; + } +#endif + + if (!ret) { + bson_strncpy (buf, unknown_msg, buflen); + ret = buf; + } + + return ret; +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-error.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-error.h new file mode 100644 index 0000000000000000000000000000000000000000..044cd37a3507cf83036a8ec6f531e36fa1bbdf79 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-error.h @@ -0,0 +1,48 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_ERROR_H +#define BSON_ERROR_H + + +#include "bson-compat.h" +#include "bson-macros.h" +#include "bson-types.h" + + +BSON_BEGIN_DECLS + + +#define BSON_ERROR_JSON 1 +#define BSON_ERROR_READER 2 +#define BSON_ERROR_INVALID 3 + + +BSON_EXPORT (void) +bson_set_error (bson_error_t *error, + uint32_t domain, + uint32_t code, + const char *format, + ...) BSON_GNUC_PRINTF (4, 5); +BSON_EXPORT (char *) +bson_strerror_r (int err_code, char *buf, size_t buflen); + + +BSON_END_DECLS + + +#endif /* BSON_ERROR_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-iso8601-private.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-iso8601-private.h new file mode 100644 index 0000000000000000000000000000000000000000..1c587d73470a15d3fc25d26e632c5276d4a213bf --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-iso8601-private.h @@ -0,0 +1,37 @@ +/* + * Copyright 2014 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_ISO8601_PRIVATE_H +#define BSON_ISO8601_PRIVATE_H + + +#include "bson-compat.h" +#include "bson-macros.h" + + +BSON_BEGIN_DECLS + +bool +_bson_iso8601_date_parse (const char *str, + int32_t len, + int64_t *out, + bson_error_t *error); + +BSON_END_DECLS + + +#endif /* BSON_ISO8601_PRIVATE_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-iso8601.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-iso8601.c new file mode 100644 index 0000000000000000000000000000000000000000..153173586401f116905232a03cf6e51b3eccd3e4 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-iso8601.c @@ -0,0 +1,297 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "bson-compat.h" +#include "bson-macros.h" +#include "bson-error.h" +#include "bson-iso8601-private.h" +#include "bson-json.h" +#include "bson-timegm-private.h" + + +static bool +get_tok (const char *terminals, + const char **ptr, + int32_t *remaining, + const char **out, + int32_t *out_len) +{ + const char *terminal; + bool found_terminal = false; + + if (!*remaining) { + *out = ""; + *out_len = 0; + } + + *out = *ptr; + *out_len = -1; + + for (; *remaining && !found_terminal; + (*ptr)++, (*remaining)--, (*out_len)++) { + for (terminal = terminals; *terminal; terminal++) { + if (**ptr == *terminal) { + found_terminal = true; + break; + } + } + } + + if (!found_terminal) { + (*out_len)++; + } + + return found_terminal; +} + +static bool +digits_only (const char *str, int32_t len) +{ + int i; + + for (i = 0; i < len; i++) { + if (!isdigit (str[i])) { + return false; + } + } + + return true; +} + +static bool +parse_num (const char *str, + int32_t len, + int32_t digits, + int32_t min, + int32_t max, + int32_t *out) +{ + int i; + int magnitude = 1; + int32_t value = 0; + + if ((digits >= 0 && len != digits) || !digits_only (str, len)) { + return false; + } + + for (i = 1; i <= len; i++, magnitude *= 10) { + value += (str[len - i] - '0') * magnitude; + } + + if (value < min || value > max) { + return false; + } + + *out = value; + + return true; +} + +bool +_bson_iso8601_date_parse (const char *str, + int32_t len, + int64_t *out, + bson_error_t *error) +{ + const char *ptr; + int32_t remaining = len; + + const char *year_ptr; + const char *month_ptr; + const char *day_ptr; + const char *hour_ptr; + const char *min_ptr; + const char *sec_ptr; + const char *millis_ptr; + const char *tz_ptr; + + int32_t year_len = 0; + int32_t month_len = 0; + int32_t day_len = 0; + int32_t hour_len = 0; + int32_t min_len = 0; + int32_t sec_len = 0; + int32_t millis_len = 0; + int32_t tz_len = 0; + + int32_t year; + int32_t month; + int32_t day; + int32_t hour; + int32_t min; + int32_t sec = 0; + int64_t millis = 0; + int32_t tz_adjustment = 0; + + struct bson_tm posix_date = {0}; + +#define DATE_PARSE_ERR(msg) \ + bson_set_error (error, \ + BSON_ERROR_JSON, \ + BSON_JSON_ERROR_READ_INVALID_PARAM, \ + "Could not parse \"%s\" as date: " msg, \ + str); \ + return false + +#define DEFAULT_DATE_PARSE_ERR \ + DATE_PARSE_ERR ("use ISO8601 format yyyy-mm-ddThh:mm plus timezone, either" \ + " \"Z\" or like \"+0500\"") + + ptr = str; + + /* we have to match at least yyyy-mm-ddThh:mm */ + if (!(get_tok ("-", &ptr, &remaining, &year_ptr, &year_len) && + get_tok ("-", &ptr, &remaining, &month_ptr, &month_len) && + get_tok ("T", &ptr, &remaining, &day_ptr, &day_len) && + get_tok (":", &ptr, &remaining, &hour_ptr, &hour_len) && + get_tok (":+-Z", &ptr, &remaining, &min_ptr, &min_len))) { + DEFAULT_DATE_PARSE_ERR; + } + + /* if the minute has a ':' at the end look for seconds */ + if (min_ptr[min_len] == ':') { + if (remaining < 2) { + DATE_PARSE_ERR ("reached end of date while looking for seconds"); + } + + get_tok (".+-Z", &ptr, &remaining, &sec_ptr, &sec_len); + + if (!sec_len) { + DATE_PARSE_ERR ("minute ends in \":\" seconds is required"); + } + } + + /* if we had a second and it is followed by a '.' look for milliseconds */ + if (sec_len && sec_ptr[sec_len] == '.') { + if (remaining < 2) { + DATE_PARSE_ERR ("reached end of date while looking for milliseconds"); + } + + get_tok ("+-Z", &ptr, &remaining, &millis_ptr, &millis_len); + + if (!millis_len) { + DATE_PARSE_ERR ("seconds ends in \".\", milliseconds is required"); + } + } + + /* backtrack by 1 to put ptr on the timezone */ + ptr--; + remaining++; + + get_tok ("", &ptr, &remaining, &tz_ptr, &tz_len); + + if (!parse_num (year_ptr, year_len, 4, -9999, 9999, &year)) { + DATE_PARSE_ERR ("year must be an integer"); + } + + /* values are as in struct tm */ + year -= 1900; + + if (!parse_num (month_ptr, month_len, 2, 1, 12, &month)) { + DATE_PARSE_ERR ("month must be an integer"); + } + + /* values are as in struct tm */ + month -= 1; + + if (!parse_num (day_ptr, day_len, 2, 1, 31, &day)) { + DATE_PARSE_ERR ("day must be an integer"); + } + + if (!parse_num (hour_ptr, hour_len, 2, 0, 23, &hour)) { + DATE_PARSE_ERR ("hour must be an integer"); + } + + if (!parse_num (min_ptr, min_len, 2, 0, 59, &min)) { + DATE_PARSE_ERR ("minute must be an integer"); + } + + if (sec_len && !parse_num (sec_ptr, sec_len, 2, 0, 60, &sec)) { + DATE_PARSE_ERR ("seconds must be an integer"); + } + + if (tz_len > 0) { + if (tz_ptr[0] == 'Z' && tz_len == 1) { + /* valid */ + } else if (tz_ptr[0] == '+' || tz_ptr[0] == '-') { + int32_t tz_hour; + int32_t tz_min; + + if (tz_len != 5 || !digits_only (tz_ptr + 1, 4)) { + DATE_PARSE_ERR ("could not parse timezone"); + } + + if (!parse_num (tz_ptr + 1, 2, -1, -23, 23, &tz_hour)) { + DATE_PARSE_ERR ("timezone hour must be at most 23"); + } + + if (!parse_num (tz_ptr + 3, 2, -1, 0, 59, &tz_min)) { + DATE_PARSE_ERR ("timezone minute must be at most 59"); + } + + /* we inflect the meaning of a 'positive' timezone. Those are hours + * we have to substract, and vice versa */ + tz_adjustment = + (tz_ptr[0] == '-' ? 1 : -1) * ((tz_min * 60) + (tz_hour * 60 * 60)); + + if (!(tz_adjustment > -86400 && tz_adjustment < 86400)) { + DATE_PARSE_ERR ("timezone offset must be less than 24 hours"); + } + } else { + DATE_PARSE_ERR ("timezone is required"); + } + } + + if (millis_len > 0) { + int i; + int magnitude; + millis = 0; + + if (millis_len > 3 || !digits_only (millis_ptr, millis_len)) { + DATE_PARSE_ERR ("milliseconds must be an integer"); + } + + for (i = 1, magnitude = 1; i <= millis_len; i++, magnitude *= 10) { + millis += (millis_ptr[millis_len - i] - '0') * magnitude; + } + + if (millis_len == 1) { + millis *= 100; + } else if (millis_len == 2) { + millis *= 10; + } + + if (millis < 0 || millis > 1000) { + DATE_PARSE_ERR ("milliseconds must be at least 0 and less than 1000"); + } + } + + posix_date.tm_sec = sec; + posix_date.tm_min = min; + posix_date.tm_hour = hour; + posix_date.tm_mday = day; + posix_date.tm_mon = month; + posix_date.tm_year = year; + posix_date.tm_wday = 0; + posix_date.tm_yday = 0; + + millis = 1000 * _bson_timegm (&posix_date) + millis; + millis += tz_adjustment * 1000; + *out = millis; + + return true; +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-iter.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-iter.c new file mode 100644 index 0000000000000000000000000000000000000000..7d162e7101b2252694a924cf93faa160810aa0af --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-iter.c @@ -0,0 +1,2425 @@ +/* + * Copyright 2013-2014 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "bson-iter.h" +#include "bson-config.h" +#include "bson-decimal128.h" + + +#define ITER_TYPE(i) ((bson_type_t) * ((i)->raw + (i)->type)) + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_init -- + * + * Initializes @iter to be used to iterate @bson. + * + * Returns: + * true if bson_iter_t was initialized. otherwise false. + * + * Side effects: + * @iter is initialized. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_iter_init (bson_iter_t *iter, /* OUT */ + const bson_t *bson) /* IN */ +{ + BSON_ASSERT (iter); + BSON_ASSERT (bson); + + if (BSON_UNLIKELY (bson->len < 5)) { + memset (iter, 0, sizeof *iter); + return false; + } + + iter->raw = bson_get_data (bson); + iter->len = bson->len; + iter->off = 0; + iter->type = 0; + iter->key = 0; + iter->d1 = 0; + iter->d2 = 0; + iter->d3 = 0; + iter->d4 = 0; + iter->next_off = 4; + iter->err_off = 0; + + return true; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_init_from_data -- + * + * Initializes @iter to be used to iterate @data of length @length + * + * Returns: + * true if bson_iter_t was initialized. otherwise false. + * + * Side effects: + * @iter is initialized. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_iter_init_from_data (bson_iter_t *iter, /* OUT */ + const uint8_t *data, /* IN */ + size_t length) /* IN */ +{ + uint32_t len_le; + + BSON_ASSERT (iter); + BSON_ASSERT (data); + + if (BSON_UNLIKELY ((length < 5) || (length > INT_MAX))) { + memset (iter, 0, sizeof *iter); + return false; + } + + memcpy (&len_le, data, sizeof (len_le)); + + if (BSON_UNLIKELY ((size_t) BSON_UINT32_FROM_LE (len_le) != length)) { + memset (iter, 0, sizeof *iter); + return false; + } + + if (BSON_UNLIKELY (data[length - 1])) { + memset (iter, 0, sizeof *iter); + return false; + } + + iter->raw = (uint8_t *) data; + iter->len = length; + iter->off = 0; + iter->type = 0; + iter->key = 0; + iter->d1 = 0; + iter->d2 = 0; + iter->d3 = 0; + iter->d4 = 0; + iter->next_off = 4; + iter->err_off = 0; + + return true; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_recurse -- + * + * Creates a new sub-iter looking at the document or array that @iter + * is currently pointing at. + * + * Returns: + * true if successful and @child was initialized. + * + * Side effects: + * @child is initialized. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_iter_recurse (const bson_iter_t *iter, /* IN */ + bson_iter_t *child) /* OUT */ +{ + const uint8_t *data = NULL; + uint32_t len = 0; + + BSON_ASSERT (iter); + BSON_ASSERT (child); + + if (ITER_TYPE (iter) == BSON_TYPE_DOCUMENT) { + bson_iter_document (iter, &len, &data); + } else if (ITER_TYPE (iter) == BSON_TYPE_ARRAY) { + bson_iter_array (iter, &len, &data); + } else { + return false; + } + + child->raw = data; + child->len = len; + child->off = 0; + child->type = 0; + child->key = 0; + child->d1 = 0; + child->d2 = 0; + child->d3 = 0; + child->d4 = 0; + child->next_off = 4; + child->err_off = 0; + + return true; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_init_find -- + * + * Initializes a #bson_iter_t and moves the iter to the first field + * matching @key. + * + * Returns: + * true if the field named @key was found; otherwise false. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_iter_init_find (bson_iter_t *iter, /* INOUT */ + const bson_t *bson, /* IN */ + const char *key) /* IN */ +{ + BSON_ASSERT (iter); + BSON_ASSERT (bson); + BSON_ASSERT (key); + + return bson_iter_init (iter, bson) && bson_iter_find (iter, key); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_init_find_case -- + * + * A case-insensitive version of bson_iter_init_find(). + * + * Returns: + * true if the field was found and @iter is observing that field. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_iter_init_find_case (bson_iter_t *iter, /* INOUT */ + const bson_t *bson, /* IN */ + const char *key) /* IN */ +{ + BSON_ASSERT (iter); + BSON_ASSERT (bson); + BSON_ASSERT (key); + + return bson_iter_init (iter, bson) && bson_iter_find_case (iter, key); +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_iter_find_with_len -- + * + * Internal helper for finding an exact key. + * + * Returns: + * true if the field @key was found. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static bool +_bson_iter_find_with_len (bson_iter_t *iter, /* INOUT */ + const char *key, /* IN */ + int keylen) /* IN */ +{ + const char *ikey; + + if (keylen == 0) { + return false; + } + + if (keylen < 0) { + keylen = (int) strlen (key); + } + + while (bson_iter_next (iter)) { + ikey = bson_iter_key (iter); + + if ((0 == strncmp (key, ikey, keylen)) && (ikey[keylen] == '\0')) { + return true; + } + } + + return false; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_find -- + * + * Searches through @iter starting from the current position for a key + * matching @key. This is a case-sensitive search meaning "KEY" and + * "key" would NOT match. + * + * Returns: + * true if @key is found. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_iter_find (bson_iter_t *iter, /* INOUT */ + const char *key) /* IN */ +{ + BSON_ASSERT (iter); + BSON_ASSERT (key); + + return _bson_iter_find_with_len (iter, key, -1); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_find_case -- + * + * Searches through @iter starting from the current position for a key + * matching @key. This is a case-insensitive search meaning "KEY" and + * "key" would match. + * + * Returns: + * true if @key is found. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_iter_find_case (bson_iter_t *iter, /* INOUT */ + const char *key) /* IN */ +{ + BSON_ASSERT (iter); + BSON_ASSERT (key); + + while (bson_iter_next (iter)) { + if (!bson_strcasecmp (key, bson_iter_key (iter))) { + return true; + } + } + + return false; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_find_descendant -- + * + * Locates a descendant using the "parent.child.key" notation. This + * operates similar to bson_iter_find() except that it can recurse + * into children documents using the dot notation. + * + * Returns: + * true if the descendant was found and @descendant was initialized. + * + * Side effects: + * @descendant may be initialized. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_iter_find_descendant (bson_iter_t *iter, /* INOUT */ + const char *dotkey, /* IN */ + bson_iter_t *descendant) /* OUT */ +{ + bson_iter_t tmp; + const char *dot; + size_t sublen; + + BSON_ASSERT (iter); + BSON_ASSERT (dotkey); + BSON_ASSERT (descendant); + + if ((dot = strchr (dotkey, '.'))) { + sublen = dot - dotkey; + } else { + sublen = strlen (dotkey); + } + + if (_bson_iter_find_with_len (iter, dotkey, (int) sublen)) { + if (!dot) { + *descendant = *iter; + return true; + } + + if (BSON_ITER_HOLDS_DOCUMENT (iter) || BSON_ITER_HOLDS_ARRAY (iter)) { + if (bson_iter_recurse (iter, &tmp)) { + return bson_iter_find_descendant (&tmp, dot + 1, descendant); + } + } + } + + return false; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_key -- + * + * Retrieves the key of the current field. The resulting key is valid + * while @iter is valid. + * + * Returns: + * A string that should not be modified or freed. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +const char * +bson_iter_key (const bson_iter_t *iter) /* IN */ +{ + BSON_ASSERT (iter); + + return bson_iter_key_unsafe (iter); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_type -- + * + * Retrieves the type of the current field. It may be useful to check + * the type using the BSON_ITER_HOLDS_*() macros. + * + * Returns: + * A bson_type_t. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bson_type_t +bson_iter_type (const bson_iter_t *iter) /* IN */ +{ + BSON_ASSERT (iter); + BSON_ASSERT (iter->raw); + BSON_ASSERT (iter->len); + + return bson_iter_type_unsafe (iter); +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_iter_next_internal -- + * + * Internal function to advance @iter to the next field and retrieve + * the key and BSON type before error-checking. + * + * Return: + * true if an element was decoded, else false. + * + * Side effects: + * @key and @bson_type are set. + * + * If the return value is false: + * - @iter is invalidated: @iter->raw is NULLed + * - @unsupported is set to true if the bson type is unsupported + * - otherwise if the BSON is corrupt, @iter->err_off is nonzero + * - otherwise @bson_type is set to BSON_TYPE_EOD + * + *-------------------------------------------------------------------------- + */ + +static bool +_bson_iter_next_internal (bson_iter_t *iter, /* INOUT */ + const char **key, /* OUT */ + uint32_t *bson_type, /* OUT */ + bool *unsupported) /* OUT */ +{ + const uint8_t *data; + uint32_t o; + unsigned int len; + + BSON_ASSERT (iter); + + *unsupported = false; + + if (!iter->raw) { + *key = NULL; + *bson_type = BSON_TYPE_EOD; + return false; + } + + data = iter->raw; + len = iter->len; + + iter->off = iter->next_off; + iter->type = iter->off; + iter->key = iter->off + 1; + iter->d1 = 0; + iter->d2 = 0; + iter->d3 = 0; + iter->d4 = 0; + + /* iterate from start to end of NULL-terminated key string */ + for (o = iter->off + 1; o < len; o++) { + if (!data[o]) { + iter->d1 = ++o; + goto fill_data_fields; + } + } + + goto mark_invalid; + +fill_data_fields: + + *key = bson_iter_key_unsafe (iter); + *bson_type = ITER_TYPE (iter); + + switch (*bson_type) { + case BSON_TYPE_DATE_TIME: + case BSON_TYPE_DOUBLE: + case BSON_TYPE_INT64: + case BSON_TYPE_TIMESTAMP: + iter->next_off = o + 8; + break; + case BSON_TYPE_CODE: + case BSON_TYPE_SYMBOL: + case BSON_TYPE_UTF8: { + uint32_t l; + + if ((o + 4) >= len) { + iter->err_off = o; + goto mark_invalid; + } + + iter->d2 = o + 4; + memcpy (&l, iter->raw + iter->d1, sizeof (l)); + l = BSON_UINT32_FROM_LE (l); + + if (l > (len - (o + 4))) { + iter->err_off = o; + goto mark_invalid; + } + + iter->next_off = o + 4 + l; + + /* + * Make sure the string length includes the NUL byte. + */ + if (BSON_UNLIKELY ((l == 0) || (iter->next_off >= len))) { + iter->err_off = o; + goto mark_invalid; + } + + /* + * Make sure the last byte is a NUL byte. + */ + if (BSON_UNLIKELY ((iter->raw + iter->d2)[l - 1] != '\0')) { + iter->err_off = o + 4 + l - 1; + goto mark_invalid; + } + } break; + case BSON_TYPE_BINARY: { + bson_subtype_t subtype; + uint32_t l; + + if (o >= (len - 4)) { + iter->err_off = o; + goto mark_invalid; + } + + iter->d2 = o + 4; + iter->d3 = o + 5; + + memcpy (&l, iter->raw + iter->d1, sizeof (l)); + l = BSON_UINT32_FROM_LE (l); + + if (l >= (len - o)) { + iter->err_off = o; + goto mark_invalid; + } + + subtype = *(iter->raw + iter->d2); + + if (subtype == BSON_SUBTYPE_BINARY_DEPRECATED) { + int32_t binary_len; + + if (l < 4) { + iter->err_off = o; + goto mark_invalid; + } + + /* subtype 2 has a redundant length header in the data */ + memcpy (&binary_len, (iter->raw + iter->d3), sizeof (binary_len)); + binary_len = BSON_UINT32_FROM_LE (binary_len); + if (binary_len + 4 != l) { + iter->err_off = iter->d3; + goto mark_invalid; + } + } + + iter->next_off = o + 5 + l; + } break; + case BSON_TYPE_ARRAY: + case BSON_TYPE_DOCUMENT: { + uint32_t l; + + if (o >= (len - 4)) { + iter->err_off = o; + goto mark_invalid; + } + + memcpy (&l, iter->raw + iter->d1, sizeof (l)); + l = BSON_UINT32_FROM_LE (l); + + if ((l > len) || (l > (len - o))) { + iter->err_off = o; + goto mark_invalid; + } + + iter->next_off = o + l; + } break; + case BSON_TYPE_OID: + iter->next_off = o + 12; + break; + case BSON_TYPE_BOOL: { + char val; + + if (iter->d1 >= len) { + iter->err_off = o; + goto mark_invalid; + } + + memcpy (&val, iter->raw + iter->d1, 1); + if (val != 0x00 && val != 0x01) { + iter->err_off = o; + goto mark_invalid; + } + + iter->next_off = o + 1; + } break; + case BSON_TYPE_REGEX: { + bool eor = false; + bool eoo = false; + + for (; o < len; o++) { + if (!data[o]) { + iter->d2 = ++o; + eor = true; + break; + } + } + + if (!eor) { + iter->err_off = iter->next_off; + goto mark_invalid; + } + + for (; o < len; o++) { + if (!data[o]) { + eoo = true; + break; + } + } + + if (!eoo) { + iter->err_off = iter->next_off; + goto mark_invalid; + } + + iter->next_off = o + 1; + } break; + case BSON_TYPE_DBPOINTER: { + uint32_t l; + + if (o >= (len - 4)) { + iter->err_off = o; + goto mark_invalid; + } + + iter->d2 = o + 4; + memcpy (&l, iter->raw + iter->d1, sizeof (l)); + l = BSON_UINT32_FROM_LE (l); + + if ((l > len) || (l > (len - o))) { + iter->err_off = o; + goto mark_invalid; + } + + if (*(iter->raw + o + l + 3)) { + /* not null terminated */ + iter->err_off = o + l + 3; + goto mark_invalid; + } + + iter->d3 = o + 4 + l; + iter->next_off = o + 4 + l + 12; + } break; + case BSON_TYPE_CODEWSCOPE: { + uint32_t l; + uint32_t doclen; + + if ((len < 19) || (o >= (len - 14))) { + iter->err_off = o; + goto mark_invalid; + } + + iter->d2 = o + 4; + iter->d3 = o + 8; + + memcpy (&l, iter->raw + iter->d1, sizeof (l)); + l = BSON_UINT32_FROM_LE (l); + + if ((l < 14) || (l >= (len - o))) { + iter->err_off = o; + goto mark_invalid; + } + + iter->next_off = o + l; + + if (iter->next_off >= len) { + iter->err_off = o; + goto mark_invalid; + } + + memcpy (&l, iter->raw + iter->d2, sizeof (l)); + l = BSON_UINT32_FROM_LE (l); + + if (l >= (len - o - 4 - 4)) { + iter->err_off = o; + goto mark_invalid; + } + + if ((o + 4 + 4 + l + 4) >= iter->next_off) { + iter->err_off = o + 4; + goto mark_invalid; + } + + iter->d4 = o + 4 + 4 + l; + memcpy (&doclen, iter->raw + iter->d4, sizeof (doclen)); + doclen = BSON_UINT32_FROM_LE (doclen); + + if ((o + 4 + 4 + l + doclen) != iter->next_off) { + iter->err_off = o + 4 + 4 + l; + goto mark_invalid; + } + } break; + case BSON_TYPE_INT32: + iter->next_off = o + 4; + break; + case BSON_TYPE_DECIMAL128: + iter->next_off = o + 16; + break; + case BSON_TYPE_MAXKEY: + case BSON_TYPE_MINKEY: + case BSON_TYPE_NULL: + case BSON_TYPE_UNDEFINED: + iter->d1 = -1; + iter->next_off = o; + break; + default: + *unsupported = true; + /* FALL THROUGH */ + case BSON_TYPE_EOD: + iter->err_off = o; + goto mark_invalid; + } + + /* + * Check to see if any of the field locations would overflow the + * current BSON buffer. If so, set the error location to the offset + * of where the field starts. + */ + if (iter->next_off >= len) { + iter->err_off = o; + goto mark_invalid; + } + + iter->err_off = 0; + + return true; + +mark_invalid: + iter->raw = NULL; + iter->len = 0; + iter->next_off = 0; + + return false; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_next -- + * + * Advances @iter to the next field of the underlying BSON document. + * If all fields have been exhausted, then %false is returned. + * + * It is a programming error to use @iter after this function has + * returned false. + * + * Returns: + * true if the iter was advanced to the next record. + * otherwise false and @iter should be considered invalid. + * + * Side effects: + * @iter may be invalidated. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_iter_next (bson_iter_t *iter) /* INOUT */ +{ + uint32_t bson_type; + const char *key; + bool unsupported; + + return _bson_iter_next_internal (iter, &key, &bson_type, &unsupported); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_binary -- + * + * Retrieves the BSON_TYPE_BINARY field. The subtype is stored in + * @subtype. The length of @binary in bytes is stored in @binary_len. + * + * @binary should not be modified or freed and is only valid while + * @iter's bson_t is valid and unmodified. + * + * Parameters: + * @iter: A bson_iter_t + * @subtype: A location for the binary subtype. + * @binary_len: A location for the length of @binary. + * @binary: A location for a pointer to the binary data. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_iter_binary (const bson_iter_t *iter, /* IN */ + unsigned int *subtype, /* OUT */ + uint32_t *binary_len, /* OUT */ + const uint8_t **binary) /* OUT */ +{ + unsigned int backup; + + BSON_ASSERT (iter); + BSON_ASSERT (!binary || binary_len); + + if (ITER_TYPE (iter) == BSON_TYPE_BINARY) { + if (!subtype) { + subtype = &backup; + } + + *subtype = (unsigned int) * (iter->raw + iter->d2); + + if (binary) { + memcpy (binary_len, (iter->raw + iter->d1), sizeof (*binary_len)); + *binary_len = BSON_UINT32_FROM_LE (*binary_len); + *binary = iter->raw + iter->d3; + + if (*subtype == BSON_SUBTYPE_BINARY_DEPRECATED) { + *binary_len -= sizeof (int32_t); + *binary += sizeof (int32_t); + } + } + + return; + } + + if (binary) { + *binary = NULL; + } + + if (binary_len) { + *binary_len = 0; + } + + if (subtype) { + *subtype = BSON_SUBTYPE_BINARY; + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_bool -- + * + * Retrieves the current field of type BSON_TYPE_BOOL. + * + * Returns: + * true or false, dependent on bson document. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_iter_bool (const bson_iter_t *iter) /* IN */ +{ + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_BOOL) { + return bson_iter_bool_unsafe (iter); + } + + return false; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_as_bool -- + * + * If @iter is on a boolean field, returns the boolean. If it is on a + * non-boolean field such as int32, int64, or double, it will convert + * the value to a boolean. + * + * Zero is false, and non-zero is true. + * + * Returns: + * true or false, dependent on field type. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_iter_as_bool (const bson_iter_t *iter) /* IN */ +{ + BSON_ASSERT (iter); + + switch ((int) ITER_TYPE (iter)) { + case BSON_TYPE_BOOL: + return bson_iter_bool (iter); + case BSON_TYPE_DOUBLE: + return !(bson_iter_double (iter) == 0.0); + case BSON_TYPE_INT64: + return !(bson_iter_int64 (iter) == 0); + case BSON_TYPE_INT32: + return !(bson_iter_int32 (iter) == 0); + case BSON_TYPE_UTF8: + return true; + case BSON_TYPE_NULL: + case BSON_TYPE_UNDEFINED: + return false; + default: + return true; + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_double -- + * + * Retrieves the current field of type BSON_TYPE_DOUBLE. + * + * Returns: + * A double. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +double +bson_iter_double (const bson_iter_t *iter) /* IN */ +{ + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_DOUBLE) { + return bson_iter_double_unsafe (iter); + } + + return 0; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_as_double -- + * + * If @iter is on a field of type BSON_TYPE_DOUBLE, + * returns the double. If it is on an integer field + * such as int32, int64, or bool, it will convert + * the value to a double. + * + * + * Returns: + * A double. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +double +bson_iter_as_double (const bson_iter_t *iter) /* IN */ +{ + BSON_ASSERT (iter); + + switch ((int) ITER_TYPE (iter)) { + case BSON_TYPE_BOOL: + return (double) bson_iter_bool (iter); + case BSON_TYPE_DOUBLE: + return bson_iter_double (iter); + case BSON_TYPE_INT32: + return (double) bson_iter_int32 (iter); + case BSON_TYPE_INT64: + return (double) bson_iter_int64 (iter); + default: + return 0; + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_int32 -- + * + * Retrieves the value of the field of type BSON_TYPE_INT32. + * + * Returns: + * A 32-bit signed integer. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +int32_t +bson_iter_int32 (const bson_iter_t *iter) /* IN */ +{ + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_INT32) { + return bson_iter_int32_unsafe (iter); + } + + return 0; +} + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_int64 -- + * + * Retrieves a 64-bit signed integer for the current BSON_TYPE_INT64 + * field. + * + * Returns: + * A 64-bit signed integer. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +int64_t +bson_iter_int64 (const bson_iter_t *iter) /* IN */ +{ + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_INT64) { + return bson_iter_int64_unsafe (iter); + } + + return 0; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_as_int64 -- + * + * If @iter is not an int64 field, it will try to convert the value to + * an int64. Such field types include: + * + * - bool + * - double + * - int32 + * + * Returns: + * An int64_t. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +int64_t +bson_iter_as_int64 (const bson_iter_t *iter) /* IN */ +{ + BSON_ASSERT (iter); + + switch ((int) ITER_TYPE (iter)) { + case BSON_TYPE_BOOL: + return (int64_t) bson_iter_bool (iter); + case BSON_TYPE_DOUBLE: + return (int64_t) bson_iter_double (iter); + case BSON_TYPE_INT64: + return bson_iter_int64 (iter); + case BSON_TYPE_INT32: + return (int64_t) bson_iter_int32 (iter); + default: + return 0; + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_decimal128 -- + * + * This function retrieves the current field of type + *%BSON_TYPE_DECIMAL128. + * The result is valid while @iter is valid, and is stored in @dec. + * + * Returns: + * + * True on success, false on failure. + * + * Side Effects: + * None. + * + *-------------------------------------------------------------------------- + */ +bool +bson_iter_decimal128 (const bson_iter_t *iter, /* IN */ + bson_decimal128_t *dec) /* OUT */ +{ + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_DECIMAL128) { + bson_iter_decimal128_unsafe (iter, dec); + return true; + } + + return false; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_oid -- + * + * Retrieves the current field of type %BSON_TYPE_OID. The result is + * valid while @iter is valid. + * + * Returns: + * A bson_oid_t that should not be modified or freed. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +const bson_oid_t * +bson_iter_oid (const bson_iter_t *iter) /* IN */ +{ + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_OID) { + return bson_iter_oid_unsafe (iter); + } + + return NULL; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_regex -- + * + * Fetches the current field from the iter which should be of type + * BSON_TYPE_REGEX. + * + * Returns: + * Regex from @iter. This should not be modified or freed. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +const char * +bson_iter_regex (const bson_iter_t *iter, /* IN */ + const char **options) /* IN */ +{ + const char *ret = NULL; + const char *ret_options = NULL; + + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_REGEX) { + ret = (const char *) (iter->raw + iter->d1); + ret_options = (const char *) (iter->raw + iter->d2); + } + + if (options) { + *options = ret_options; + } + + return ret; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_utf8 -- + * + * Retrieves the current field of type %BSON_TYPE_UTF8 as a UTF-8 + * encoded string. + * + * Parameters: + * @iter: A bson_iter_t. + * @length: A location for the length of the string. + * + * Returns: + * A string that should not be modified or freed. + * + * Side effects: + * @length will be set to the result strings length if non-NULL. + * + *-------------------------------------------------------------------------- + */ + +const char * +bson_iter_utf8 (const bson_iter_t *iter, /* IN */ + uint32_t *length) /* OUT */ +{ + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_UTF8) { + if (length) { + *length = bson_iter_utf8_len_unsafe (iter); + } + + return (const char *) (iter->raw + iter->d2); + } + + if (length) { + *length = 0; + } + + return NULL; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_dup_utf8 -- + * + * Copies the current UTF-8 element into a newly allocated string. The + * string should be freed using bson_free() when the caller is + * finished with it. + * + * Returns: + * A newly allocated char* that should be freed with bson_free(). + * + * Side effects: + * @length will be set to the result strings length if non-NULL. + * + *-------------------------------------------------------------------------- + */ + +char * +bson_iter_dup_utf8 (const bson_iter_t *iter, /* IN */ + uint32_t *length) /* OUT */ +{ + uint32_t local_length = 0; + const char *str; + char *ret = NULL; + + BSON_ASSERT (iter); + + if ((str = bson_iter_utf8 (iter, &local_length))) { + ret = bson_malloc0 (local_length + 1); + memcpy (ret, str, local_length); + ret[local_length] = '\0'; + } + + if (length) { + *length = local_length; + } + + return ret; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_code -- + * + * Retrieves the current field of type %BSON_TYPE_CODE. The length of + * the resulting string is stored in @length. + * + * Parameters: + * @iter: A bson_iter_t. + * @length: A location for the code length. + * + * Returns: + * A NUL-terminated string containing the code which should not be + * modified or freed. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +const char * +bson_iter_code (const bson_iter_t *iter, /* IN */ + uint32_t *length) /* OUT */ +{ + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_CODE) { + if (length) { + *length = bson_iter_utf8_len_unsafe (iter); + } + + return (const char *) (iter->raw + iter->d2); + } + + if (length) { + *length = 0; + } + + return NULL; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_codewscope -- + * + * Similar to bson_iter_code() but with a scope associated encoded as + * a BSON document. @scope should not be modified or freed. It is + * valid while @iter is valid. + * + * Parameters: + * @iter: A #bson_iter_t. + * @length: A location for the length of resulting string. + * @scope_len: A location for the length of @scope. + * @scope: A location for the scope encoded as BSON. + * + * Returns: + * A NUL-terminated string that should not be modified or freed. + * + * Side effects: + * @length is set to the resulting string length in bytes. + * @scope_len is set to the length of @scope in bytes. + * @scope is set to the scope documents buffer which can be + * turned into a bson document with bson_init_static(). + * + *-------------------------------------------------------------------------- + */ + +const char * +bson_iter_codewscope (const bson_iter_t *iter, /* IN */ + uint32_t *length, /* OUT */ + uint32_t *scope_len, /* OUT */ + const uint8_t **scope) /* OUT */ +{ + uint32_t len; + + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_CODEWSCOPE) { + if (length) { + memcpy (&len, iter->raw + iter->d2, sizeof (len)); + *length = BSON_UINT32_FROM_LE (len) - 1; + } + + memcpy (&len, iter->raw + iter->d4, sizeof (len)); + *scope_len = BSON_UINT32_FROM_LE (len); + *scope = iter->raw + iter->d4; + return (const char *) (iter->raw + iter->d3); + } + + if (length) { + *length = 0; + } + + if (scope_len) { + *scope_len = 0; + } + + if (scope) { + *scope = NULL; + } + + return NULL; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_dbpointer -- + * + * Retrieves a BSON_TYPE_DBPOINTER field. @collection_len will be set + * to the length of the collection name. The collection name will be + * placed into @collection. The oid will be placed into @oid. + * + * @collection and @oid should not be modified. + * + * Parameters: + * @iter: A #bson_iter_t. + * @collection_len: A location for the length of @collection. + * @collection: A location for the collection name. + * @oid: A location for the oid. + * + * Returns: + * None. + * + * Side effects: + * @collection_len is set to the length of @collection in bytes + * excluding the null byte. + * @collection is set to the collection name, including a terminating + * null byte. + * @oid is initialized with the oid. + * + *-------------------------------------------------------------------------- + */ + +void +bson_iter_dbpointer (const bson_iter_t *iter, /* IN */ + uint32_t *collection_len, /* OUT */ + const char **collection, /* OUT */ + const bson_oid_t **oid) /* OUT */ +{ + BSON_ASSERT (iter); + + if (collection) { + *collection = NULL; + } + + if (oid) { + *oid = NULL; + } + + if (ITER_TYPE (iter) == BSON_TYPE_DBPOINTER) { + if (collection_len) { + memcpy ( + collection_len, (iter->raw + iter->d1), sizeof (*collection_len)); + *collection_len = BSON_UINT32_FROM_LE (*collection_len); + + if ((*collection_len) > 0) { + (*collection_len)--; + } + } + + if (collection) { + *collection = (const char *) (iter->raw + iter->d2); + } + + if (oid) { + *oid = (const bson_oid_t *) (iter->raw + iter->d3); + } + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_symbol -- + * + * Retrieves the symbol of the current field of type BSON_TYPE_SYMBOL. + * + * Parameters: + * @iter: A bson_iter_t. + * @length: A location for the length of the symbol. + * + * Returns: + * A string containing the symbol as UTF-8. The value should not be + * modified or freed. + * + * Side effects: + * @length is set to the resulting strings length in bytes, + * excluding the null byte. + * + *-------------------------------------------------------------------------- + */ + +const char * +bson_iter_symbol (const bson_iter_t *iter, /* IN */ + uint32_t *length) /* OUT */ +{ + const char *ret = NULL; + uint32_t ret_length = 0; + + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_SYMBOL) { + ret = (const char *) (iter->raw + iter->d2); + ret_length = bson_iter_utf8_len_unsafe (iter); + } + + if (length) { + *length = ret_length; + } + + return ret; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_date_time -- + * + * Fetches the number of milliseconds elapsed since the UNIX epoch. + * This value can be negative as times before 1970 are valid. + * + * Returns: + * A signed 64-bit integer containing the number of milliseconds. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +int64_t +bson_iter_date_time (const bson_iter_t *iter) /* IN */ +{ + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_DATE_TIME) { + return bson_iter_int64_unsafe (iter); + } + + return 0; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_time_t -- + * + * Retrieves the current field of type BSON_TYPE_DATE_TIME as a + * time_t. + * + * Returns: + * A #time_t of the number of seconds since UNIX epoch in UTC. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +time_t +bson_iter_time_t (const bson_iter_t *iter) /* IN */ +{ + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_DATE_TIME) { + return bson_iter_time_t_unsafe (iter); + } + + return 0; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_timestamp -- + * + * Fetches the current field if it is a BSON_TYPE_TIMESTAMP. + * + * Parameters: + * @iter: A #bson_iter_t. + * @timestamp: a location for the timestamp. + * @increment: A location for the increment. + * + * Returns: + * None. + * + * Side effects: + * @timestamp is initialized. + * @increment is initialized. + * + *-------------------------------------------------------------------------- + */ + +void +bson_iter_timestamp (const bson_iter_t *iter, /* IN */ + uint32_t *timestamp, /* OUT */ + uint32_t *increment) /* OUT */ +{ + uint64_t encoded; + uint32_t ret_timestamp = 0; + uint32_t ret_increment = 0; + + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_TIMESTAMP) { + memcpy (&encoded, iter->raw + iter->d1, sizeof (encoded)); + encoded = BSON_UINT64_FROM_LE (encoded); + ret_timestamp = (encoded >> 32) & 0xFFFFFFFF; + ret_increment = encoded & 0xFFFFFFFF; + } + + if (timestamp) { + *timestamp = ret_timestamp; + } + + if (increment) { + *increment = ret_increment; + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_timeval -- + * + * Retrieves the current field of type BSON_TYPE_DATE_TIME and stores + * it into the struct timeval provided. tv->tv_sec is set to the + * number of seconds since the UNIX epoch in UTC. + * + * Since BSON_TYPE_DATE_TIME does not support fractions of a second, + * tv->tv_usec will always be set to zero. + * + * Returns: + * None. + * + * Side effects: + * @tv is initialized. + * + *-------------------------------------------------------------------------- + */ + +void +bson_iter_timeval (const bson_iter_t *iter, /* IN */ + struct timeval *tv) /* OUT */ +{ + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_DATE_TIME) { + bson_iter_timeval_unsafe (iter, tv); + return; + } + + memset (tv, 0, sizeof *tv); +} + + +/** + * bson_iter_document: + * @iter: a bson_iter_t. + * @document_len: A location for the document length. + * @document: A location for a pointer to the document buffer. + * + */ +/* + *-------------------------------------------------------------------------- + * + * bson_iter_document -- + * + * Retrieves the data to the document BSON structure and stores the + * length of the document buffer in @document_len and the document + * buffer in @document. + * + * If you would like to iterate over the child contents, you might + * consider creating a bson_t on the stack such as the following. It + * allows you to call functions taking a const bson_t* only. + * + * bson_t b; + * uint32_t len; + * const uint8_t *data; + * + * bson_iter_document(iter, &len, &data); + * + * if (bson_init_static (&b, data, len)) { + * ... + * } + * + * There is no need to cleanup the bson_t structure as no data can be + * modified in the process of its use (as it is static/const). + * + * Returns: + * None. + * + * Side effects: + * @document_len is initialized. + * @document is initialized. + * + *-------------------------------------------------------------------------- + */ + +void +bson_iter_document (const bson_iter_t *iter, /* IN */ + uint32_t *document_len, /* OUT */ + const uint8_t **document) /* OUT */ +{ + BSON_ASSERT (iter); + BSON_ASSERT (document_len); + BSON_ASSERT (document); + + *document = NULL; + *document_len = 0; + + if (ITER_TYPE (iter) == BSON_TYPE_DOCUMENT) { + memcpy (document_len, (iter->raw + iter->d1), sizeof (*document_len)); + *document_len = BSON_UINT32_FROM_LE (*document_len); + *document = (iter->raw + iter->d1); + } +} + + +/** + * bson_iter_array: + * @iter: a #bson_iter_t. + * @array_len: A location for the array length. + * @array: A location for a pointer to the array buffer. + */ +/* + *-------------------------------------------------------------------------- + * + * bson_iter_array -- + * + * Retrieves the data to the array BSON structure and stores the + * length of the array buffer in @array_len and the array buffer in + * @array. + * + * If you would like to iterate over the child contents, you might + * consider creating a bson_t on the stack such as the following. It + * allows you to call functions taking a const bson_t* only. + * + * bson_t b; + * uint32_t len; + * const uint8_t *data; + * + * bson_iter_array (iter, &len, &data); + * + * if (bson_init_static (&b, data, len)) { + * ... + * } + * + * There is no need to cleanup the #bson_t structure as no data can be + * modified in the process of its use. + * + * Returns: + * None. + * + * Side effects: + * @array_len is initialized. + * @array is initialized. + * + *-------------------------------------------------------------------------- + */ + +void +bson_iter_array (const bson_iter_t *iter, /* IN */ + uint32_t *array_len, /* OUT */ + const uint8_t **array) /* OUT */ +{ + BSON_ASSERT (iter); + BSON_ASSERT (array_len); + BSON_ASSERT (array); + + *array = NULL; + *array_len = 0; + + if (ITER_TYPE (iter) == BSON_TYPE_ARRAY) { + memcpy (array_len, (iter->raw + iter->d1), sizeof (*array_len)); + *array_len = BSON_UINT32_FROM_LE (*array_len); + *array = (iter->raw + iter->d1); + } +} + + +#define VISIT_FIELD(name) visitor->visit_##name && visitor->visit_##name +#define VISIT_AFTER VISIT_FIELD (after) +#define VISIT_BEFORE VISIT_FIELD (before) +#define VISIT_CORRUPT \ + if (visitor->visit_corrupt) \ + visitor->visit_corrupt +#define VISIT_DOUBLE VISIT_FIELD (double) +#define VISIT_UTF8 VISIT_FIELD (utf8) +#define VISIT_DOCUMENT VISIT_FIELD (document) +#define VISIT_ARRAY VISIT_FIELD (array) +#define VISIT_BINARY VISIT_FIELD (binary) +#define VISIT_UNDEFINED VISIT_FIELD (undefined) +#define VISIT_OID VISIT_FIELD (oid) +#define VISIT_BOOL VISIT_FIELD (bool) +#define VISIT_DATE_TIME VISIT_FIELD (date_time) +#define VISIT_NULL VISIT_FIELD (null) +#define VISIT_REGEX VISIT_FIELD (regex) +#define VISIT_DBPOINTER VISIT_FIELD (dbpointer) +#define VISIT_CODE VISIT_FIELD (code) +#define VISIT_SYMBOL VISIT_FIELD (symbol) +#define VISIT_CODEWSCOPE VISIT_FIELD (codewscope) +#define VISIT_INT32 VISIT_FIELD (int32) +#define VISIT_TIMESTAMP VISIT_FIELD (timestamp) +#define VISIT_INT64 VISIT_FIELD (int64) +#define VISIT_DECIMAL128 VISIT_FIELD (decimal128) +#define VISIT_MAXKEY VISIT_FIELD (maxkey) +#define VISIT_MINKEY VISIT_FIELD (minkey) + + +/** + * bson_iter_visit_all: + * @iter: A #bson_iter_t. + * @visitor: A #bson_visitor_t containing the visitors. + * @data: User data for @visitor data parameters. + * + * + * Returns: true if the visitor was pre-maturely ended; otherwise false. + */ +/* + *-------------------------------------------------------------------------- + * + * bson_iter_visit_all -- + * + * Visits all fields forward from the current position of @iter. For + * each field found a function in @visitor will be called. Typically + * you will use this immediately after initializing a bson_iter_t. + * + * bson_iter_init (&iter, b); + * bson_iter_visit_all (&iter, my_visitor, NULL); + * + * @iter will no longer be valid after this function has executed and + * will need to be reinitialized if intending to reuse. + * + * Returns: + * true if successfully visited all fields or callback requested + * early termination, otherwise false. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_iter_visit_all (bson_iter_t *iter, /* INOUT */ + const bson_visitor_t *visitor, /* IN */ + void *data) /* IN */ +{ + uint32_t bson_type; + const char *key; + bool unsupported; + + BSON_ASSERT (iter); + BSON_ASSERT (visitor); + + while (_bson_iter_next_internal (iter, &key, &bson_type, &unsupported)) { + if (*key && !bson_utf8_validate (key, strlen (key), false)) { + iter->err_off = iter->off; + break; + } + + if (VISIT_BEFORE (iter, key, data)) { + return true; + } + + switch (bson_type) { + case BSON_TYPE_DOUBLE: + + if (VISIT_DOUBLE (iter, key, bson_iter_double (iter), data)) { + return true; + } + + break; + case BSON_TYPE_UTF8: { + uint32_t utf8_len; + const char *utf8; + + utf8 = bson_iter_utf8 (iter, &utf8_len); + + if (!bson_utf8_validate (utf8, utf8_len, true)) { + iter->err_off = iter->off; + return true; + } + + if (VISIT_UTF8 (iter, key, utf8_len, utf8, data)) { + return true; + } + } break; + case BSON_TYPE_DOCUMENT: { + const uint8_t *docbuf = NULL; + uint32_t doclen = 0; + bson_t b; + + bson_iter_document (iter, &doclen, &docbuf); + + if (bson_init_static (&b, docbuf, doclen) && + VISIT_DOCUMENT (iter, key, &b, data)) { + return true; + } + } break; + case BSON_TYPE_ARRAY: { + const uint8_t *docbuf = NULL; + uint32_t doclen = 0; + bson_t b; + + bson_iter_array (iter, &doclen, &docbuf); + + if (bson_init_static (&b, docbuf, doclen) && + VISIT_ARRAY (iter, key, &b, data)) { + return true; + } + } break; + case BSON_TYPE_BINARY: { + const uint8_t *binary = NULL; + bson_subtype_t subtype = BSON_SUBTYPE_BINARY; + uint32_t binary_len = 0; + + bson_iter_binary (iter, &subtype, &binary_len, &binary); + + if (VISIT_BINARY (iter, key, subtype, binary_len, binary, data)) { + return true; + } + } break; + case BSON_TYPE_UNDEFINED: + + if (VISIT_UNDEFINED (iter, key, data)) { + return true; + } + + break; + case BSON_TYPE_OID: + + if (VISIT_OID (iter, key, bson_iter_oid (iter), data)) { + return true; + } + + break; + case BSON_TYPE_BOOL: + + if (VISIT_BOOL (iter, key, bson_iter_bool (iter), data)) { + return true; + } + + break; + case BSON_TYPE_DATE_TIME: + + if (VISIT_DATE_TIME (iter, key, bson_iter_date_time (iter), data)) { + return true; + } + + break; + case BSON_TYPE_NULL: + + if (VISIT_NULL (iter, key, data)) { + return true; + } + + break; + case BSON_TYPE_REGEX: { + const char *regex = NULL; + const char *options = NULL; + regex = bson_iter_regex (iter, &options); + + if (!bson_utf8_validate (regex, strlen (regex), true)) { + iter->err_off = iter->off; + return true; + } + + if (VISIT_REGEX (iter, key, regex, options, data)) { + return true; + } + } break; + case BSON_TYPE_DBPOINTER: { + uint32_t collection_len = 0; + const char *collection = NULL; + const bson_oid_t *oid = NULL; + + bson_iter_dbpointer (iter, &collection_len, &collection, &oid); + + if (!bson_utf8_validate (collection, collection_len, true)) { + iter->err_off = iter->off; + return true; + } + + if (VISIT_DBPOINTER ( + iter, key, collection_len, collection, oid, data)) { + return true; + } + } break; + case BSON_TYPE_CODE: { + uint32_t code_len; + const char *code; + + code = bson_iter_code (iter, &code_len); + + if (!bson_utf8_validate (code, code_len, true)) { + iter->err_off = iter->off; + return true; + } + + if (VISIT_CODE (iter, key, code_len, code, data)) { + return true; + } + } break; + case BSON_TYPE_SYMBOL: { + uint32_t symbol_len; + const char *symbol; + + symbol = bson_iter_symbol (iter, &symbol_len); + + if (!bson_utf8_validate (symbol, symbol_len, true)) { + iter->err_off = iter->off; + return true; + } + + if (VISIT_SYMBOL (iter, key, symbol_len, symbol, data)) { + return true; + } + } break; + case BSON_TYPE_CODEWSCOPE: { + uint32_t length = 0; + const char *code; + const uint8_t *docbuf = NULL; + uint32_t doclen = 0; + bson_t b; + + code = bson_iter_codewscope (iter, &length, &doclen, &docbuf); + + if (!bson_utf8_validate (code, length, true)) { + iter->err_off = iter->off; + return true; + } + + if (bson_init_static (&b, docbuf, doclen) && + VISIT_CODEWSCOPE (iter, key, length, code, &b, data)) { + return true; + } + } break; + case BSON_TYPE_INT32: + + if (VISIT_INT32 (iter, key, bson_iter_int32 (iter), data)) { + return true; + } + + break; + case BSON_TYPE_TIMESTAMP: { + uint32_t timestamp; + uint32_t increment; + bson_iter_timestamp (iter, ×tamp, &increment); + + if (VISIT_TIMESTAMP (iter, key, timestamp, increment, data)) { + return true; + } + } break; + case BSON_TYPE_INT64: + + if (VISIT_INT64 (iter, key, bson_iter_int64 (iter), data)) { + return true; + } + + break; + case BSON_TYPE_DECIMAL128: { + bson_decimal128_t dec; + bson_iter_decimal128 (iter, &dec); + + if (VISIT_DECIMAL128 (iter, key, &dec, data)) { + return true; + } + } break; + case BSON_TYPE_MAXKEY: + + if (VISIT_MAXKEY (iter, bson_iter_key_unsafe (iter), data)) { + return true; + } + + break; + case BSON_TYPE_MINKEY: + + if (VISIT_MINKEY (iter, bson_iter_key_unsafe (iter), data)) { + return true; + } + + break; + case BSON_TYPE_EOD: + default: + break; + } + + if (VISIT_AFTER (iter, bson_iter_key_unsafe (iter), data)) { + return true; + } + } + + if (iter->err_off) { + if (unsupported && visitor->visit_unsupported_type && + bson_utf8_validate (key, strlen (key), false)) { + visitor->visit_unsupported_type (iter, key, bson_type, data); + return false; + } + + VISIT_CORRUPT (iter, data); + } + +#undef VISIT_FIELD + + return false; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_overwrite_bool -- + * + * Overwrites the current BSON_TYPE_BOOLEAN field with a new value. + * This is performed in-place and therefore no keys are moved. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_iter_overwrite_bool (bson_iter_t *iter, /* IN */ + bool value) /* IN */ +{ + BSON_ASSERT (iter); + value = !!value; + + if (ITER_TYPE (iter) == BSON_TYPE_BOOL) { + memcpy ((void *) (iter->raw + iter->d1), &value, 1); + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_overwrite_int32 -- + * + * Overwrites the current BSON_TYPE_INT32 field with a new value. + * This is performed in-place and therefore no keys are moved. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_iter_overwrite_int32 (bson_iter_t *iter, /* IN */ + int32_t value) /* IN */ +{ + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_INT32) { +#if BSON_BYTE_ORDER != BSON_LITTLE_ENDIAN + value = BSON_UINT32_TO_LE (value); +#endif + memcpy ((void *) (iter->raw + iter->d1), &value, sizeof (value)); + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_overwrite_int64 -- + * + * Overwrites the current BSON_TYPE_INT64 field with a new value. + * This is performed in-place and therefore no keys are moved. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_iter_overwrite_int64 (bson_iter_t *iter, /* IN */ + int64_t value) /* IN */ +{ + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_INT64) { +#if BSON_BYTE_ORDER != BSON_LITTLE_ENDIAN + value = BSON_UINT64_TO_LE (value); +#endif + memcpy ((void *) (iter->raw + iter->d1), &value, sizeof (value)); + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_overwrite_double -- + * + * Overwrites the current BSON_TYPE_DOUBLE field with a new value. + * This is performed in-place and therefore no keys are moved. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_iter_overwrite_double (bson_iter_t *iter, /* IN */ + double value) /* IN */ +{ + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_DOUBLE) { + value = BSON_DOUBLE_TO_LE (value); + memcpy ((void *) (iter->raw + iter->d1), &value, sizeof (value)); + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_overwrite_decimal128 -- + * + * Overwrites the current BSON_TYPE_DECIMAL128 field with a new value. + * This is performed in-place and therefore no keys are moved. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ +void +bson_iter_overwrite_decimal128 (bson_iter_t *iter, /* IN */ + bson_decimal128_t *value) /* IN */ +{ + BSON_ASSERT (iter); + + if (ITER_TYPE (iter) == BSON_TYPE_DECIMAL128) { +#if BSON_BYTE_ORDER != BSON_LITTLE_ENDIAN + uint64_t data[2]; + data[0] = BSON_UINT64_TO_LE (value->low); + data[1] = BSON_UINT64_TO_LE (value->high); + memcpy ((void *) (iter->raw + iter->d1), data, sizeof (data)); +#else + memcpy ((void *) (iter->raw + iter->d1), value, sizeof (*value)); +#endif + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_value -- + * + * Retrieves a bson_value_t containing the boxed value of the current + * element. The result of this function valid until the state of + * iter has been changed (through the use of bson_iter_next()). + * + * Returns: + * A bson_value_t that should not be modified or freed. If you need + * to hold on to the value, use bson_value_copy(). + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +const bson_value_t * +bson_iter_value (bson_iter_t *iter) /* IN */ +{ + bson_value_t *value; + + BSON_ASSERT (iter); + + value = &iter->value; + value->value_type = ITER_TYPE (iter); + + switch (value->value_type) { + case BSON_TYPE_DOUBLE: + value->value.v_double = bson_iter_double (iter); + break; + case BSON_TYPE_UTF8: + value->value.v_utf8.str = + (char *) bson_iter_utf8 (iter, &value->value.v_utf8.len); + break; + case BSON_TYPE_DOCUMENT: + bson_iter_document (iter, + &value->value.v_doc.data_len, + (const uint8_t **) &value->value.v_doc.data); + break; + case BSON_TYPE_ARRAY: + bson_iter_array (iter, + &value->value.v_doc.data_len, + (const uint8_t **) &value->value.v_doc.data); + break; + case BSON_TYPE_BINARY: + bson_iter_binary (iter, + &value->value.v_binary.subtype, + &value->value.v_binary.data_len, + (const uint8_t **) &value->value.v_binary.data); + break; + case BSON_TYPE_OID: + bson_oid_copy (bson_iter_oid (iter), &value->value.v_oid); + break; + case BSON_TYPE_BOOL: + value->value.v_bool = bson_iter_bool (iter); + break; + case BSON_TYPE_DATE_TIME: + value->value.v_datetime = bson_iter_date_time (iter); + break; + case BSON_TYPE_REGEX: + value->value.v_regex.regex = (char *) bson_iter_regex ( + iter, (const char **) &value->value.v_regex.options); + break; + case BSON_TYPE_DBPOINTER: { + const bson_oid_t *oid; + + bson_iter_dbpointer (iter, + &value->value.v_dbpointer.collection_len, + (const char **) &value->value.v_dbpointer.collection, + &oid); + bson_oid_copy (oid, &value->value.v_dbpointer.oid); + break; + } + case BSON_TYPE_CODE: + value->value.v_code.code = + (char *) bson_iter_code (iter, &value->value.v_code.code_len); + break; + case BSON_TYPE_SYMBOL: + value->value.v_symbol.symbol = + (char *) bson_iter_symbol (iter, &value->value.v_symbol.len); + break; + case BSON_TYPE_CODEWSCOPE: + value->value.v_codewscope.code = (char *) bson_iter_codewscope ( + iter, + &value->value.v_codewscope.code_len, + &value->value.v_codewscope.scope_len, + (const uint8_t **) &value->value.v_codewscope.scope_data); + break; + case BSON_TYPE_INT32: + value->value.v_int32 = bson_iter_int32 (iter); + break; + case BSON_TYPE_TIMESTAMP: + bson_iter_timestamp (iter, + &value->value.v_timestamp.timestamp, + &value->value.v_timestamp.increment); + break; + case BSON_TYPE_INT64: + value->value.v_int64 = bson_iter_int64 (iter); + break; + case BSON_TYPE_DECIMAL128: + bson_iter_decimal128 (iter, &(value->value.v_decimal128)); + break; + case BSON_TYPE_NULL: + case BSON_TYPE_UNDEFINED: + case BSON_TYPE_MAXKEY: + case BSON_TYPE_MINKEY: + break; + case BSON_TYPE_EOD: + default: + return NULL; + } + + return value; +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-iter.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-iter.h new file mode 100644 index 0000000000000000000000000000000000000000..42457816c65d4e3183d9cc08391d472b5ea4d2cb --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-iter.h @@ -0,0 +1,507 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_ITER_H +#define BSON_ITER_H + +#include "bson.h" +#include "bson-endian.h" +#include "bson-macros.h" +#include "bson-types.h" + + +BSON_BEGIN_DECLS + + +#define BSON_ITER_HOLDS_DOUBLE(iter) \ + (bson_iter_type ((iter)) == BSON_TYPE_DOUBLE) + +#define BSON_ITER_HOLDS_UTF8(iter) (bson_iter_type ((iter)) == BSON_TYPE_UTF8) + +#define BSON_ITER_HOLDS_DOCUMENT(iter) \ + (bson_iter_type ((iter)) == BSON_TYPE_DOCUMENT) + +#define BSON_ITER_HOLDS_ARRAY(iter) (bson_iter_type ((iter)) == BSON_TYPE_ARRAY) + +#define BSON_ITER_HOLDS_BINARY(iter) \ + (bson_iter_type ((iter)) == BSON_TYPE_BINARY) + +#define BSON_ITER_HOLDS_UNDEFINED(iter) \ + (bson_iter_type ((iter)) == BSON_TYPE_UNDEFINED) + +#define BSON_ITER_HOLDS_OID(iter) (bson_iter_type ((iter)) == BSON_TYPE_OID) + +#define BSON_ITER_HOLDS_BOOL(iter) (bson_iter_type ((iter)) == BSON_TYPE_BOOL) + +#define BSON_ITER_HOLDS_DATE_TIME(iter) \ + (bson_iter_type ((iter)) == BSON_TYPE_DATE_TIME) + +#define BSON_ITER_HOLDS_NULL(iter) (bson_iter_type ((iter)) == BSON_TYPE_NULL) + +#define BSON_ITER_HOLDS_REGEX(iter) (bson_iter_type ((iter)) == BSON_TYPE_REGEX) + +#define BSON_ITER_HOLDS_DBPOINTER(iter) \ + (bson_iter_type ((iter)) == BSON_TYPE_DBPOINTER) + +#define BSON_ITER_HOLDS_CODE(iter) (bson_iter_type ((iter)) == BSON_TYPE_CODE) + +#define BSON_ITER_HOLDS_SYMBOL(iter) \ + (bson_iter_type ((iter)) == BSON_TYPE_SYMBOL) + +#define BSON_ITER_HOLDS_CODEWSCOPE(iter) \ + (bson_iter_type ((iter)) == BSON_TYPE_CODEWSCOPE) + +#define BSON_ITER_HOLDS_INT32(iter) (bson_iter_type ((iter)) == BSON_TYPE_INT32) + +#define BSON_ITER_HOLDS_TIMESTAMP(iter) \ + (bson_iter_type ((iter)) == BSON_TYPE_TIMESTAMP) + +#define BSON_ITER_HOLDS_INT64(iter) (bson_iter_type ((iter)) == BSON_TYPE_INT64) + +#define BSON_ITER_HOLDS_DECIMAL128(iter) \ + (bson_iter_type ((iter)) == BSON_TYPE_DECIMAL128) + +#define BSON_ITER_HOLDS_MAXKEY(iter) \ + (bson_iter_type ((iter)) == BSON_TYPE_MAXKEY) + +#define BSON_ITER_HOLDS_MINKEY(iter) \ + (bson_iter_type ((iter)) == BSON_TYPE_MINKEY) + +#define BSON_ITER_HOLDS_INT(iter) \ + (BSON_ITER_HOLDS_INT32 (iter) || BSON_ITER_HOLDS_INT64 (iter)) + +#define BSON_ITER_HOLDS_NUMBER(iter) \ + (BSON_ITER_HOLDS_INT (iter) || BSON_ITER_HOLDS_DOUBLE (iter)) + +#define BSON_ITER_IS_KEY(iter, key) \ + (0 == strcmp ((key), bson_iter_key ((iter)))) + + +BSON_EXPORT (const bson_value_t *) +bson_iter_value (bson_iter_t *iter); + + +/** + * bson_iter_utf8_len_unsafe: + * @iter: a bson_iter_t. + * + * Returns the length of a string currently pointed to by @iter. This performs + * no validation so the is responsible for knowing the BSON is valid. Calling + * bson_validate() is one way to do this ahead of time. + */ +static BSON_INLINE uint32_t +bson_iter_utf8_len_unsafe (const bson_iter_t *iter) +{ + int32_t val; + + memcpy (&val, iter->raw + iter->d1, sizeof (val)); + val = BSON_UINT32_FROM_LE (val); + return BSON_MAX (0, val - 1); +} + + +BSON_EXPORT (void) +bson_iter_array (const bson_iter_t *iter, + uint32_t *array_len, + const uint8_t **array); + + +BSON_EXPORT (void) +bson_iter_binary (const bson_iter_t *iter, + unsigned int *subtype, + uint32_t *binary_len, + const uint8_t **binary); + + +BSON_EXPORT (const char *) +bson_iter_code (const bson_iter_t *iter, uint32_t *length); + + +/** + * bson_iter_code_unsafe: + * @iter: A bson_iter_t. + * @length: A location for the length of the resulting string. + * + * Like bson_iter_code() but performs no integrity checks. + * + * Returns: A string that should not be modified or freed. + */ +static BSON_INLINE const char * +bson_iter_code_unsafe (const bson_iter_t *iter, uint32_t *length) +{ + *length = bson_iter_utf8_len_unsafe (iter); + return (const char *) (iter->raw + iter->d2); +} + + +BSON_EXPORT (const char *) +bson_iter_codewscope (const bson_iter_t *iter, + uint32_t *length, + uint32_t *scope_len, + const uint8_t **scope); + + +BSON_EXPORT (void) +bson_iter_dbpointer (const bson_iter_t *iter, + uint32_t *collection_len, + const char **collection, + const bson_oid_t **oid); + + +BSON_EXPORT (void) +bson_iter_document (const bson_iter_t *iter, + uint32_t *document_len, + const uint8_t **document); + + +BSON_EXPORT (double) +bson_iter_double (const bson_iter_t *iter); + +BSON_EXPORT (double) +bson_iter_as_double (const bson_iter_t *iter); + +/** + * bson_iter_double_unsafe: + * @iter: A bson_iter_t. + * + * Similar to bson_iter_double() but does not perform an integrity checking. + * + * Returns: A double. + */ +static BSON_INLINE double +bson_iter_double_unsafe (const bson_iter_t *iter) +{ + double val; + + memcpy (&val, iter->raw + iter->d1, sizeof (val)); + return BSON_DOUBLE_FROM_LE (val); +} + + +BSON_EXPORT (bool) +bson_iter_init (bson_iter_t *iter, const bson_t *bson); + +BSON_EXPORT (bool) +bson_iter_init_from_data (bson_iter_t *iter, + const uint8_t *data, + size_t length); + + +BSON_EXPORT (bool) +bson_iter_init_find (bson_iter_t *iter, const bson_t *bson, const char *key); + + +BSON_EXPORT (bool) +bson_iter_init_find_case (bson_iter_t *iter, + const bson_t *bson, + const char *key); + + +BSON_EXPORT (int32_t) +bson_iter_int32 (const bson_iter_t *iter); + + +/** + * bson_iter_int32_unsafe: + * @iter: A bson_iter_t. + * + * Similar to bson_iter_int32() but with no integrity checking. + * + * Returns: A 32-bit signed integer. + */ +static BSON_INLINE int32_t +bson_iter_int32_unsafe (const bson_iter_t *iter) +{ + int32_t val; + + memcpy (&val, iter->raw + iter->d1, sizeof (val)); + return BSON_UINT32_FROM_LE (val); +} + + +BSON_EXPORT (int64_t) +bson_iter_int64 (const bson_iter_t *iter); + + +BSON_EXPORT (int64_t) +bson_iter_as_int64 (const bson_iter_t *iter); + + +/** + * bson_iter_int64_unsafe: + * @iter: a bson_iter_t. + * + * Similar to bson_iter_int64() but without integrity checking. + * + * Returns: A 64-bit signed integer. + */ +static BSON_INLINE int64_t +bson_iter_int64_unsafe (const bson_iter_t *iter) +{ + int64_t val; + + memcpy (&val, iter->raw + iter->d1, sizeof (val)); + return BSON_UINT64_FROM_LE (val); +} + + +BSON_EXPORT (bool) +bson_iter_find (bson_iter_t *iter, const char *key); + + +BSON_EXPORT (bool) +bson_iter_find_case (bson_iter_t *iter, const char *key); + + +BSON_EXPORT (bool) +bson_iter_find_descendant (bson_iter_t *iter, + const char *dotkey, + bson_iter_t *descendant); + + +BSON_EXPORT (bool) +bson_iter_next (bson_iter_t *iter); + + +BSON_EXPORT (const bson_oid_t *) +bson_iter_oid (const bson_iter_t *iter); + + +/** + * bson_iter_oid_unsafe: + * @iter: A #bson_iter_t. + * + * Similar to bson_iter_oid() but performs no integrity checks. + * + * Returns: A #bson_oid_t that should not be modified or freed. + */ +static BSON_INLINE const bson_oid_t * +bson_iter_oid_unsafe (const bson_iter_t *iter) +{ + return (const bson_oid_t *) (iter->raw + iter->d1); +} + + +BSON_EXPORT (bool) +bson_iter_decimal128 (const bson_iter_t *iter, bson_decimal128_t *dec); + + +/** + * bson_iter_decimal128_unsafe: + * @iter: A #bson_iter_t. + * + * Similar to bson_iter_decimal128() but performs no integrity checks. + * + * Returns: A #bson_decimal128_t. + */ +static BSON_INLINE void +bson_iter_decimal128_unsafe (const bson_iter_t *iter, bson_decimal128_t *dec) +{ + uint64_t low_le; + uint64_t high_le; + + memcpy (&low_le, iter->raw + iter->d1, sizeof (low_le)); + memcpy (&high_le, iter->raw + iter->d1 + 8, sizeof (high_le)); + + dec->low = BSON_UINT64_FROM_LE (low_le); + dec->high = BSON_UINT64_FROM_LE (high_le); +} + + +BSON_EXPORT (const char *) +bson_iter_key (const bson_iter_t *iter); + + +/** + * bson_iter_key_unsafe: + * @iter: A bson_iter_t. + * + * Similar to bson_iter_key() but performs no integrity checking. + * + * Returns: A string that should not be modified or freed. + */ +static BSON_INLINE const char * +bson_iter_key_unsafe (const bson_iter_t *iter) +{ + return (const char *) (iter->raw + iter->key); +} + + +BSON_EXPORT (const char *) +bson_iter_utf8 (const bson_iter_t *iter, uint32_t *length); + + +/** + * bson_iter_utf8_unsafe: + * + * Similar to bson_iter_utf8() but performs no integrity checking. + * + * Returns: A string that should not be modified or freed. + */ +static BSON_INLINE const char * +bson_iter_utf8_unsafe (const bson_iter_t *iter, size_t *length) +{ + *length = bson_iter_utf8_len_unsafe (iter); + return (const char *) (iter->raw + iter->d2); +} + + +BSON_EXPORT (char *) +bson_iter_dup_utf8 (const bson_iter_t *iter, uint32_t *length); + + +BSON_EXPORT (int64_t) +bson_iter_date_time (const bson_iter_t *iter); + + +BSON_EXPORT (time_t) +bson_iter_time_t (const bson_iter_t *iter); + + +/** + * bson_iter_time_t_unsafe: + * @iter: A bson_iter_t. + * + * Similar to bson_iter_time_t() but performs no integrity checking. + * + * Returns: A time_t containing the number of seconds since UNIX epoch + * in UTC. + */ +static BSON_INLINE time_t +bson_iter_time_t_unsafe (const bson_iter_t *iter) +{ + return (time_t) (bson_iter_int64_unsafe (iter) / 1000UL); +} + + +BSON_EXPORT (void) +bson_iter_timeval (const bson_iter_t *iter, struct timeval *tv); + + +/** + * bson_iter_timeval_unsafe: + * @iter: A bson_iter_t. + * @tv: A struct timeval. + * + * Similar to bson_iter_timeval() but performs no integrity checking. + */ +static BSON_INLINE void +bson_iter_timeval_unsafe (const bson_iter_t *iter, struct timeval *tv) +{ + int64_t value = bson_iter_int64_unsafe (iter); +#ifdef BSON_OS_WIN32 + tv->tv_sec = (long) (value / 1000); +#else + tv->tv_sec = (suseconds_t) (value / 1000); +#endif + tv->tv_usec = (value % 1000) * 1000; +} + + +BSON_EXPORT (void) +bson_iter_timestamp (const bson_iter_t *iter, + uint32_t *timestamp, + uint32_t *increment); + + +BSON_EXPORT (bool) +bson_iter_bool (const bson_iter_t *iter); + + +/** + * bson_iter_bool_unsafe: + * @iter: A bson_iter_t. + * + * Similar to bson_iter_bool() but performs no integrity checking. + * + * Returns: true or false. + */ +static BSON_INLINE bool +bson_iter_bool_unsafe (const bson_iter_t *iter) +{ + char val; + + memcpy (&val, iter->raw + iter->d1, 1); + return !!val; +} + + +BSON_EXPORT (bool) +bson_iter_as_bool (const bson_iter_t *iter); + + +BSON_EXPORT (const char *) +bson_iter_regex (const bson_iter_t *iter, const char **options); + + +BSON_EXPORT (const char *) +bson_iter_symbol (const bson_iter_t *iter, uint32_t *length); + + +BSON_EXPORT (bson_type_t) +bson_iter_type (const bson_iter_t *iter); + + +/** + * bson_iter_type_unsafe: + * @iter: A bson_iter_t. + * + * Similar to bson_iter_type() but performs no integrity checking. + * + * Returns: A bson_type_t. + */ +static BSON_INLINE bson_type_t +bson_iter_type_unsafe (const bson_iter_t *iter) +{ + return (bson_type_t) (iter->raw + iter->type)[0]; +} + + +BSON_EXPORT (bool) +bson_iter_recurse (const bson_iter_t *iter, bson_iter_t *child); + + +BSON_EXPORT (void) +bson_iter_overwrite_int32 (bson_iter_t *iter, int32_t value); + + +BSON_EXPORT (void) +bson_iter_overwrite_int64 (bson_iter_t *iter, int64_t value); + + +BSON_EXPORT (void) +bson_iter_overwrite_double (bson_iter_t *iter, double value); + + +BSON_EXPORT (void) +bson_iter_overwrite_decimal128 (bson_iter_t *iter, bson_decimal128_t *value); + + +BSON_EXPORT (void) +bson_iter_overwrite_bool (bson_iter_t *iter, bool value); + + +BSON_EXPORT (bool) +bson_iter_visit_all (bson_iter_t *iter, + const bson_visitor_t *visitor, + void *data); + + +BSON_END_DECLS + + +#endif /* BSON_ITER_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-json.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-json.c new file mode 100644 index 0000000000000000000000000000000000000000..66580761728bab073f1e026aab13d6bc00bc3a38 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-json.c @@ -0,0 +1,2061 @@ +/* + * Copyright 2014 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include <errno.h> +#include <fcntl.h> +#include <sys/types.h> +#include <math.h> + +#include "bson.h" +#include "bson-config.h" +#include "bson-json.h" +#include "bson-iso8601-private.h" +#include "b64_pton.h" + +#include <chaos/common/bson/jsonsl/jsonsl.h> + +#ifdef _WIN32 +#include <io.h> +#include <share.h> +#endif + +#ifndef _MSC_VER +#include <strings.h> +#endif + +#define STACK_MAX 100 +#define BSON_JSON_DEFAULT_BUF_SIZE (1 << 14) +#define AT_LEAST_0(x) ((x) >= 0 ? (x) : 0) + + +typedef enum { + BSON_JSON_REGULAR, + BSON_JSON_DONE, + BSON_JSON_ERROR, + BSON_JSON_IN_START_MAP, + BSON_JSON_IN_BSON_TYPE, + BSON_JSON_IN_BSON_TYPE_DATE_NUMBERLONG, + BSON_JSON_IN_BSON_TYPE_DATE_ENDMAP, + BSON_JSON_IN_BSON_TYPE_TIMESTAMP_STARTMAP, + BSON_JSON_IN_BSON_TYPE_TIMESTAMP_VALUES, + BSON_JSON_IN_BSON_TYPE_TIMESTAMP_ENDMAP, + BSON_JSON_IN_BSON_TYPE_SCOPE_STARTMAP, + BSON_JSON_IN_BSON_TYPE_DBPOINTER_STARTMAP, + BSON_JSON_IN_SCOPE, + BSON_JSON_IN_DBPOINTER, +} bson_json_read_state_t; + + +typedef enum { + BSON_JSON_LF_REGEX, + BSON_JSON_LF_OPTIONS, + BSON_JSON_LF_CODE, + BSON_JSON_LF_SCOPE, + BSON_JSON_LF_OID, + BSON_JSON_LF_BINARY, + BSON_JSON_LF_TYPE, + BSON_JSON_LF_DATE, + BSON_JSON_LF_TIMESTAMP_T, + BSON_JSON_LF_TIMESTAMP_I, + BSON_JSON_LF_UNDEFINED, + BSON_JSON_LF_MINKEY, + BSON_JSON_LF_MAXKEY, + BSON_JSON_LF_INT32, + BSON_JSON_LF_INT64, + BSON_JSON_LF_DOUBLE, + BSON_JSON_LF_DECIMAL128, + BSON_JSON_LF_DBPOINTER, + BSON_JSON_LF_SYMBOL +} bson_json_read_bson_state_t; + + +typedef struct { + uint8_t *buf; + size_t n_bytes; + size_t len; +} bson_json_buf_t; + + +typedef struct { + int i; + bool is_array; + bool is_scope; + bool is_dbpointer; + bson_t bson; +} bson_json_stack_frame_t; + + +typedef union { + struct { + bool has_regex; + bool has_options; + } regex; + struct { + bool has_oid; + bson_oid_t oid; + } oid; + struct { + bool has_binary; + bool has_subtype; + bson_subtype_t type; + } binary; + struct { + bool has_date; + int64_t date; + } date; + struct { + bool has_t; + bool has_i; + uint32_t t; + uint32_t i; + } timestamp; + struct { + bool has_undefined; + } undefined; + struct { + bool has_minkey; + } minkey; + struct { + bool has_maxkey; + } maxkey; + struct { + int32_t value; + } v_int32; + struct { + int64_t value; + } v_int64; + struct { + double value; + } v_double; + struct { + bson_decimal128_t value; + } v_decimal128; +} bson_json_bson_data_t; + + +/* collect info while parsing a {$code: "...", $scope: {...}} object */ +typedef struct { + bool has_code; + bool has_scope; + bool in_scope; + bson_json_buf_t key_buf; + bson_json_buf_t code_buf; +} bson_json_code_t; + + +static void +_bson_json_code_cleanup (bson_json_code_t *code_data) +{ + bson_free (code_data->key_buf.buf); + bson_free (code_data->code_buf.buf); +} + + +typedef struct { + bson_t *bson; + bson_json_stack_frame_t stack[STACK_MAX]; + int n; + const char *key; + bson_json_buf_t key_buf; + bson_json_buf_t unescaped; + bson_json_read_state_t read_state; + bson_json_read_bson_state_t bson_state; + bson_type_t bson_type; + bson_json_buf_t bson_type_buf[3]; + bson_json_bson_data_t bson_type_data; + bson_json_code_t code_data; + bson_json_buf_t dbpointer_key; +} bson_json_reader_bson_t; + + +typedef struct { + void *data; + bson_json_reader_cb cb; + bson_json_destroy_cb dcb; + uint8_t *buf; + size_t buf_size; + size_t bytes_read; + size_t bytes_parsed; + bool all_whitespace; +} bson_json_reader_producer_t; + + +struct _bson_json_reader_t { + bson_json_reader_producer_t producer; + bson_json_reader_bson_t bson; + jsonsl_t json; + ssize_t json_text_pos; + bool should_reset; + ssize_t advance; + bson_json_buf_t tok_accumulator; + bson_error_t *error; +}; + + +typedef struct { + int fd; + bool do_close; +} bson_json_reader_handle_fd_t; + + +static void +_noop (void) +{ +} + +#define STACK_ELE(_delta, _name) (bson->stack[(_delta) + bson->n]._name) +#define STACK_BSON(_delta) \ + (((_delta) + bson->n) == 0 ? bson->bson : &STACK_ELE (_delta, bson)) +#define STACK_BSON_PARENT STACK_BSON (-1) +#define STACK_BSON_CHILD STACK_BSON (0) +#define STACK_I STACK_ELE (0, i) +#define STACK_IS_ARRAY STACK_ELE (0, is_array) +#define STACK_IS_SCOPE STACK_ELE (0, is_scope) +#define STACK_IS_DBPOINTER STACK_ELE (0, is_dbpointer) +#define STACK_PUSH_ARRAY(statement) \ + do { \ + if (bson->n >= (STACK_MAX - 1)) { \ + return; \ + } \ + bson->n++; \ + STACK_I = 0; \ + STACK_IS_ARRAY = 1; \ + STACK_IS_SCOPE = 0; \ + STACK_IS_DBPOINTER = 0; \ + if (bson->n != 0) { \ + statement; \ + } \ + } while (0) +#define STACK_PUSH_DOC(statement) \ + do { \ + if (bson->n >= (STACK_MAX - 1)) { \ + return; \ + } \ + bson->n++; \ + STACK_IS_ARRAY = 0; \ + STACK_IS_SCOPE = 0; \ + STACK_IS_DBPOINTER = 0; \ + if (bson->n != 0) { \ + statement; \ + } \ + } while (0) +#define STACK_PUSH_SCOPE(statement) \ + do { \ + if (bson->n >= (STACK_MAX - 1)) { \ + return; \ + } \ + bson->n++; \ + STACK_IS_ARRAY = 0; \ + STACK_IS_SCOPE = 1; \ + STACK_IS_DBPOINTER = 0; \ + bson->code_data.in_scope = true; \ + if (bson->n != 0) { \ + statement; \ + } \ + } while (0) +#define STACK_PUSH_DBPOINTER(statement) \ + do { \ + if (bson->n >= (STACK_MAX - 1)) { \ + return; \ + } \ + bson->n++; \ + STACK_IS_ARRAY = 0; \ + STACK_IS_SCOPE = 0; \ + STACK_IS_DBPOINTER = 1; \ + if (bson->n != 0) { \ + statement; \ + } \ + } while (0) +#define STACK_POP_ARRAY(statement) \ + do { \ + if (!STACK_IS_ARRAY) { \ + return; \ + } \ + if (bson->n < 0) { \ + return; \ + } \ + if (bson->n > 0) { \ + statement; \ + } \ + bson->n--; \ + } while (0) +#define STACK_POP_DOC(statement) \ + do { \ + if (STACK_IS_ARRAY) { \ + return; \ + } \ + if (bson->n < 0) { \ + return; \ + } \ + if (bson->n > 0) { \ + statement; \ + } \ + bson->n--; \ + } while (0) +#define STACK_POP_SCOPE \ + do { \ + STACK_POP_DOC (_noop ()); \ + bson->code_data.in_scope = false; \ + } while (0); +#define STACK_POP_DBPOINTER STACK_POP_DOC (_noop ()) +#define BASIC_CB_PREAMBLE \ + const char *key; \ + size_t len; \ + bson_json_reader_bson_t *bson = &reader->bson; \ + _bson_json_read_fixup_key (bson); \ + key = bson->key; \ + len = bson->key_buf.len; +#define BASIC_CB_BAIL_IF_NOT_NORMAL(_type) \ + if (bson->read_state != BSON_JSON_REGULAR) { \ + _bson_json_read_set_error ( \ + reader, "Invalid read of %s in state %d", (_type), bson->read_state); \ + return; \ + } else if (!key) { \ + _bson_json_read_set_error (reader, \ + "Invalid read of %s without key in state %d", \ + (_type), \ + bson->read_state); \ + return; \ + } +#define HANDLE_OPTION(_key, _type, _state) \ + (len == strlen (_key) && strncmp ((const char *) val, (_key), len) == 0) \ + { \ + if (bson->bson_type && bson->bson_type != (_type)) { \ + _bson_json_read_set_error ( \ + reader, \ + "Invalid key %s. Looking for values for %d", \ + (_key), \ + bson->bson_type); \ + return; \ + } \ + bson->bson_type = (_type); \ + bson->bson_state = (_state); \ + } + + +static void +_bson_json_read_set_error (bson_json_reader_t *reader, const char *fmt, ...) + BSON_GNUC_PRINTF (2, 3); + + +static void +_bson_json_read_set_error (bson_json_reader_t *reader, /* IN */ + const char *fmt, /* IN */ + ...) +{ + va_list ap; + + if (reader->error) { + reader->error->domain = BSON_ERROR_JSON; + reader->error->code = BSON_JSON_ERROR_READ_INVALID_PARAM; + va_start (ap, fmt); + bson_vsnprintf ( + reader->error->message, sizeof reader->error->message, fmt, ap); + va_end (ap); + reader->error->message[sizeof reader->error->message - 1] = '\0'; + } + + reader->bson.read_state = BSON_JSON_ERROR; + jsonsl_stop (reader->json); +} + + +static void +_bson_json_read_corrupt (bson_json_reader_t *reader, const char *fmt, ...) + BSON_GNUC_PRINTF (2, 3); + + +static void +_bson_json_read_corrupt (bson_json_reader_t *reader, /* IN */ + const char *fmt, /* IN */ + ...) +{ + va_list ap; + + if (reader->error) { + reader->error->domain = BSON_ERROR_JSON; + reader->error->code = BSON_JSON_ERROR_READ_CORRUPT_JS; + va_start (ap, fmt); + bson_vsnprintf ( + reader->error->message, sizeof reader->error->message, fmt, ap); + va_end (ap); + reader->error->message[sizeof reader->error->message - 1] = '\0'; + } + + reader->bson.read_state = BSON_JSON_ERROR; + jsonsl_stop (reader->json); +} + + +static void +_bson_json_buf_ensure (bson_json_buf_t *buf, /* IN */ + size_t len) /* IN */ +{ + if (buf->n_bytes < len) { + bson_free (buf->buf); + + buf->n_bytes = bson_next_power_of_two (len); + buf->buf = bson_malloc (buf->n_bytes); + } +} + + +static void +_bson_json_buf_set (bson_json_buf_t *buf, const void *from, size_t len) +{ + _bson_json_buf_ensure (buf, len + 1); + memcpy (buf->buf, from, len); + buf->buf[len] = '\0'; + buf->len = len; +} + + +static void +_bson_json_buf_append (bson_json_buf_t *buf, const void *from, size_t len) +{ + size_t len_with_null = len + 1; + + if (buf->len == 0) { + _bson_json_buf_ensure (buf, len_with_null); + } else if (buf->n_bytes < buf->len + len_with_null) { + buf->n_bytes = bson_next_power_of_two (buf->len + len_with_null); + buf->buf = bson_realloc (buf->buf, buf->n_bytes); + } + + memcpy (buf->buf + buf->len, from, len); + buf->len += len; + buf->buf[buf->len] = '\0'; +} + + +static void +_bson_json_read_fixup_key (bson_json_reader_bson_t *bson) /* IN */ +{ + bson_json_read_state_t rs = bson->read_state; + + if (bson->n >= 0 && STACK_IS_ARRAY && rs == BSON_JSON_REGULAR) { + _bson_json_buf_ensure (&bson->key_buf, 12); + bson->key_buf.len = bson_uint32_to_string ( + STACK_I, &bson->key, (char *) bson->key_buf.buf, 12); + STACK_I++; + } +} + + +static void +_bson_json_read_null (bson_json_reader_t *reader) +{ + BASIC_CB_PREAMBLE; + BASIC_CB_BAIL_IF_NOT_NORMAL ("null"); + + bson_append_null (STACK_BSON_CHILD, key, (int) len); +} + + +static void +_bson_json_read_boolean (bson_json_reader_t *reader, /* IN */ + int val) /* IN */ +{ + BASIC_CB_PREAMBLE; + + if (bson->read_state == BSON_JSON_IN_BSON_TYPE && + bson->bson_state == BSON_JSON_LF_UNDEFINED) { + bson->bson_type_data.undefined.has_undefined = true; + return; + } + + BASIC_CB_BAIL_IF_NOT_NORMAL ("boolean"); + + bson_append_bool (STACK_BSON_CHILD, key, (int) len, val); +} + + +static void +_bson_json_read_integer (bson_json_reader_t *reader, /* IN */ + int64_t val) /* IN */ +{ + bson_json_read_state_t rs; + bson_json_read_bson_state_t bs; + + BASIC_CB_PREAMBLE; + + rs = bson->read_state; + bs = bson->bson_state; + + if (rs == BSON_JSON_REGULAR) { + BASIC_CB_BAIL_IF_NOT_NORMAL ("integer"); + + if (val <= INT32_MAX && val >= INT32_MIN) { + bson_append_int32 (STACK_BSON_CHILD, key, (int) len, (int) val); + } else { + bson_append_int64 (STACK_BSON_CHILD, key, (int) len, val); + } + } else if (rs == BSON_JSON_IN_BSON_TYPE || + rs == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_VALUES) { + switch (bs) { + case BSON_JSON_LF_DATE: + bson->bson_type_data.date.has_date = true; + bson->bson_type_data.date.date = val; + break; + case BSON_JSON_LF_TIMESTAMP_T: + bson->bson_type_data.timestamp.has_t = true; + bson->bson_type_data.timestamp.t = (uint32_t) val; + break; + case BSON_JSON_LF_TIMESTAMP_I: + bson->bson_type_data.timestamp.has_i = true; + bson->bson_type_data.timestamp.i = (uint32_t) val; + break; + case BSON_JSON_LF_MINKEY: + bson->bson_type_data.minkey.has_minkey = true; + break; + case BSON_JSON_LF_MAXKEY: + bson->bson_type_data.maxkey.has_maxkey = true; + break; + case BSON_JSON_LF_REGEX: + case BSON_JSON_LF_OPTIONS: + case BSON_JSON_LF_CODE: + case BSON_JSON_LF_SCOPE: + case BSON_JSON_LF_OID: + case BSON_JSON_LF_BINARY: + case BSON_JSON_LF_TYPE: + case BSON_JSON_LF_UNDEFINED: + case BSON_JSON_LF_INT32: + case BSON_JSON_LF_INT64: + case BSON_JSON_LF_DOUBLE: + case BSON_JSON_LF_DECIMAL128: + case BSON_JSON_LF_DBPOINTER: + case BSON_JSON_LF_SYMBOL: + default: + _bson_json_read_set_error ( + reader, "Invalid special type for integer read %d", bs); + } + } else { + _bson_json_read_set_error ( + reader, "Invalid state for integer read %d", rs); + } +} + + +static bool +_bson_json_parse_double (bson_json_reader_t *reader, + const char *val, + size_t vlen, + double *d) +{ + errno = 0; + *d = strtod (val, NULL); + +#ifdef _MSC_VER + /* Microsoft's strtod parses "NaN", "Infinity", "-Infinity" as 0 */ + if (*d == 0.0) { + if (!_strnicmp (val, "nan", vlen)) { +#ifdef NAN + *d = NAN; +#else + /* Visual Studio 2010 doesn't define NAN or INFINITY + * https://msdn.microsoft.com/en-us/library/w22adx1s(v=vs.100).aspx */ + unsigned long nan[2] = {0xffffffff, 0x7fffffff}; + *d = *(double *) nan; +#endif + return true; + } else if (!_strnicmp (val, "infinity", vlen)) { +#ifdef INFINITY + *d = INFINITY; +#else + unsigned long inf[2] = {0x00000000, 0x7ff00000}; + *d = *(double *) inf; +#endif + return true; + } else if (!_strnicmp (val, "-infinity", vlen)) { +#ifdef INFINITY + *d = -INFINITY; +#else + unsigned long inf[2] = {0x00000000, 0xfff00000}; + *d = *(double *) inf; +#endif + return true; + } + } + + if ((*d == HUGE_VAL || *d == -HUGE_VAL) && errno == ERANGE) { + _bson_json_read_set_error ( + reader, "Number \"%.*s\" is out of range", (int) vlen, val); + + return false; + } +#else + /* not MSVC - set err on overflow, but avoid err for infinity */ + if ((*d == HUGE_VAL || *d == -HUGE_VAL) + && errno == ERANGE + && strncasecmp (val, "infinity", vlen) + && strncasecmp (val, "-infinity", vlen)) { + _bson_json_read_set_error ( + reader, "Number \"%.*s\" is out of range", (int) vlen, val); + + return false; + } + +#endif /* _MSC_VER */ + return true; +} + + +static void +_bson_json_read_double (bson_json_reader_t *reader, /* IN */ + double val) /* IN */ +{ + BASIC_CB_PREAMBLE; + BASIC_CB_BAIL_IF_NOT_NORMAL ("double"); + + bson_append_double (STACK_BSON_CHILD, key, (int) len, val); +} + + +static bool +_bson_json_read_int64 (bson_json_reader_t *reader, /* IN */ + const unsigned char *val, /* IN */ + size_t vlen, /* IN */ + int64_t *v64 /* OUT */) +{ + bson_json_reader_bson_t *bson = &reader->bson; + char *endptr = NULL; + + _bson_json_read_fixup_key (bson); + errno = 0; + *v64 = bson_ascii_strtoll ((const char *) val, &endptr, 10); + + if (((*v64 == INT64_MIN) || (*v64 == INT64_MAX)) && (errno == ERANGE)) { + return false; + } + + if (endptr != ((const char *) val + vlen)) { + return false; + } + + return true; +} + + +static void +_bson_json_read_string (bson_json_reader_t *reader, /* IN */ + const unsigned char *val, /* IN */ + size_t vlen) /* IN */ +{ + bson_json_read_state_t rs; + bson_json_read_bson_state_t bs; + + BASIC_CB_PREAMBLE; + + rs = bson->read_state; + bs = bson->bson_state; + + if (!bson_utf8_validate ((const char *) val, vlen, true /*allow null*/)) { + _bson_json_read_corrupt (reader, "invalid bytes in UTF8 string"); + return; + } + + if (rs == BSON_JSON_REGULAR) { + BASIC_CB_BAIL_IF_NOT_NORMAL ("string"); + bson_append_utf8 ( + STACK_BSON_CHILD, key, (int) len, (const char *) val, (int) vlen); + } else if (rs == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_STARTMAP) { + /* new-style "key" : {"$timestamp": "180388626433" } */ + int64_t v64; + if (!_bson_json_read_int64 (reader, val, vlen, &v64)) { + _bson_json_read_corrupt (reader, "Invalid timestamp: \"%s\"", val); + return; + } + + bson->bson_type_data.timestamp.has_t = true; + bson->bson_type_data.timestamp.has_i = true; + bson->bson_type_data.timestamp.t = (uint32_t) (v64 >> 32); + bson->bson_type_data.timestamp.i = (uint32_t) v64; + } else if (rs == BSON_JSON_IN_BSON_TYPE_SCOPE_STARTMAP || + rs == BSON_JSON_IN_BSON_TYPE_DBPOINTER_STARTMAP) { + _bson_json_read_set_error ( + reader, "Invalid read of %s in state %d", val, rs); + } else if (rs == BSON_JSON_IN_BSON_TYPE || + rs == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_VALUES || + rs == BSON_JSON_IN_BSON_TYPE_DATE_NUMBERLONG) { + const char *val_w_null; + _bson_json_buf_set (&bson->bson_type_buf[2], val, vlen); + val_w_null = (const char *) bson->bson_type_buf[2].buf; + + switch (bs) { + case BSON_JSON_LF_REGEX: + bson->bson_type_data.regex.has_regex = true; + _bson_json_buf_set (&bson->bson_type_buf[0], val, vlen); + break; + case BSON_JSON_LF_OPTIONS: + bson->bson_type_data.regex.has_options = true; + _bson_json_buf_set (&bson->bson_type_buf[1], val, vlen); + break; + case BSON_JSON_LF_OID: + + if (vlen != 24) { + goto BAD_PARSE; + } + + bson->bson_type_data.oid.has_oid = true; + bson_oid_init_from_string (&bson->bson_type_data.oid.oid, val_w_null); + break; + case BSON_JSON_LF_TYPE: + bson->bson_type_data.binary.has_subtype = true; + +#ifdef _MSC_VER +#define SSCANF sscanf_s +#else +#define SSCANF sscanf +#endif + + if (SSCANF (val_w_null, "%02x", &bson->bson_type_data.binary.type) != + 1) { + goto BAD_PARSE; + } + +#undef SSCANF + + break; + case BSON_JSON_LF_BINARY: { + int binary_len; + bson->bson_type_data.binary.has_binary = true; + binary_len = b64_pton (val_w_null, NULL, 0); + if (binary_len < 0) { + goto BAD_PARSE; + } + + _bson_json_buf_ensure (&bson->bson_type_buf[0], + (size_t) binary_len + 1); + b64_pton ( + val_w_null, bson->bson_type_buf[0].buf, (size_t) binary_len + 1); + bson->bson_type_buf[0].len = (size_t) binary_len; + } break; + case BSON_JSON_LF_INT32: { + int64_t v64; + if (!_bson_json_read_int64 (reader, val, vlen, &v64)) { + goto BAD_PARSE; + } + + if (v64 < INT32_MIN || v64 > INT32_MAX) { + goto BAD_PARSE; + } + + if (bson->read_state == BSON_JSON_IN_BSON_TYPE) { + bson->bson_type_data.v_int32.value = (int32_t) v64; + } else { + goto BAD_PARSE; + } + } break; + case BSON_JSON_LF_INT64: { + int64_t v64; + if (!_bson_json_read_int64 (reader, val, vlen, &v64)) { + goto BAD_PARSE; + } + + if (bson->read_state == BSON_JSON_IN_BSON_TYPE) { + bson->bson_type_data.v_int64.value = v64; + } else if (bson->read_state == + BSON_JSON_IN_BSON_TYPE_DATE_NUMBERLONG) { + bson->bson_type_data.date.has_date = true; + bson->bson_type_data.date.date = v64; + } else { + goto BAD_PARSE; + } + } break; + case BSON_JSON_LF_DOUBLE: { + _bson_json_parse_double (reader, + (const char *) val, + vlen, + &bson->bson_type_data.v_double.value); + } break; + case BSON_JSON_LF_DATE: { + int64_t v64; + + if (!_bson_iso8601_date_parse ( + (char *) val, (int) vlen, &v64, reader->error)) { + jsonsl_stop (reader->json); + } else { + bson->bson_type_data.date.has_date = true; + bson->bson_type_data.date.date = v64; + } + } break; + case BSON_JSON_LF_DECIMAL128: { + bson_decimal128_t decimal128; + bson_decimal128_from_string (val_w_null, &decimal128); + + if (bson->read_state == BSON_JSON_IN_BSON_TYPE) { + bson->bson_type_data.v_decimal128.value = decimal128; + } else { + goto BAD_PARSE; + } + } break; + case BSON_JSON_LF_CODE: + _bson_json_buf_set (&bson->code_data.code_buf, val, vlen); + break; + case BSON_JSON_LF_SYMBOL: + bson_append_symbol ( + STACK_BSON_CHILD, key, (int) len, (const char *) val, (int) vlen); + break; + case BSON_JSON_LF_SCOPE: + case BSON_JSON_LF_TIMESTAMP_T: + case BSON_JSON_LF_TIMESTAMP_I: + case BSON_JSON_LF_UNDEFINED: + case BSON_JSON_LF_MINKEY: + case BSON_JSON_LF_MAXKEY: + case BSON_JSON_LF_DBPOINTER: + default: + goto BAD_PARSE; + } + + return; + BAD_PARSE: + _bson_json_read_set_error ( + reader, "Invalid input string %s, looking for %d", val_w_null, bs); + } else { + _bson_json_read_set_error ( + reader, "Invalid state to look for string %d", rs); + } +} + + +static void +_bson_json_read_start_map (bson_json_reader_t *reader) /* IN */ +{ + BASIC_CB_PREAMBLE; + + if (bson->read_state == BSON_JSON_IN_BSON_TYPE && + bson->bson_state == BSON_JSON_LF_DATE) { + bson->read_state = BSON_JSON_IN_BSON_TYPE_DATE_NUMBERLONG; + } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_STARTMAP) { + bson->read_state = BSON_JSON_IN_BSON_TYPE_TIMESTAMP_VALUES; + } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_SCOPE_STARTMAP) { + bson->read_state = BSON_JSON_IN_SCOPE; + } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_DBPOINTER_STARTMAP) { + bson->read_state = BSON_JSON_IN_DBPOINTER; + } else { + bson->read_state = BSON_JSON_IN_START_MAP; + } + + /* silence some warnings */ + (void) len; + (void) key; +} + + +static bool +_is_known_key (const char *key, size_t len) +{ + bool ret; + +#define IS_KEY(k) (len == strlen (k) && (0 == memcmp (k, key, len))) + + ret = (IS_KEY ("$regex") || IS_KEY ("$options") || IS_KEY ("$code") || + IS_KEY ("$scope") || IS_KEY ("$oid") || IS_KEY ("$binary") || + IS_KEY ("$type") || IS_KEY ("$date") || IS_KEY ("$undefined") || + IS_KEY ("$maxKey") || IS_KEY ("$minKey") || IS_KEY ("$timestamp") || + IS_KEY ("$numberInt") || IS_KEY ("$numberLong") || + IS_KEY ("$numberDouble") || IS_KEY ("$numberDecimal") || + IS_KEY ("$numberInt") || IS_KEY ("$numberLong") || + IS_KEY ("$numberDouble") || IS_KEY ("$numberDecimal") || + IS_KEY ("$dbPointer") || IS_KEY ("$symbol")); + +#undef IS_KEY + + return ret; +} + +static void +_bson_json_save_map_key (bson_json_reader_bson_t *bson, + const uint8_t *val, + size_t len) +{ + _bson_json_buf_set (&bson->key_buf, val, len); + bson->key = (const char *) bson->key_buf.buf; +} + + +static void +_bson_json_read_code_or_scope_key (bson_json_reader_bson_t *bson, + bool is_scope, + const uint8_t *val, + size_t len) +{ + bson_json_code_t *code = &bson->code_data; + + if (code->in_scope) { + /* we're reading something weirdly nested, e.g. we just read "$code" in + * "$scope: {x: {$code: {}}}". just create the subdoc within the scope. */ + bson->read_state = BSON_JSON_REGULAR; + STACK_PUSH_DOC (bson_append_document_begin (STACK_BSON_PARENT, + bson->key, + (int) bson->key_buf.len, + STACK_BSON_CHILD)); + _bson_json_save_map_key (bson, val, len); + } else { + if (!bson->code_data.key_buf.len) { + /* save the key, e.g. {"key": {"$code": "return x", "$scope":{"x":1}}}, + * in case it is overwritten while parsing scope sub-object */ + _bson_json_buf_set ( + &bson->code_data.key_buf, bson->key_buf.buf, bson->key_buf.len); + } + + if (is_scope) { + bson->bson_type = BSON_TYPE_CODEWSCOPE; + bson->read_state = BSON_JSON_IN_BSON_TYPE_SCOPE_STARTMAP; + bson->bson_state = BSON_JSON_LF_SCOPE; + bson->code_data.has_scope = true; + } else { + bson->bson_type = BSON_TYPE_CODE; + bson->bson_state = BSON_JSON_LF_CODE; + bson->code_data.has_code = true; + } + } +} + + +static void +_bson_json_read_map_key (bson_json_reader_t *reader, /* IN */ + const uint8_t *val, /* IN */ + size_t len) /* IN */ +{ + bson_json_reader_bson_t *bson = &reader->bson; + + if (!bson_utf8_validate ((const char *) val, len, true /* allow null */)) { + _bson_json_read_corrupt (reader, "invalid bytes in UTF8 string"); + return; + } + + if (bson->read_state == BSON_JSON_IN_START_MAP) { + if (len > 0 && val[0] == '$' && + _is_known_key ((const char *) val, len) && + bson->n >= 0 /* key is in subdocument */) { + bson->read_state = BSON_JSON_IN_BSON_TYPE; + bson->bson_type = (bson_type_t) 0; + memset (&bson->bson_type_data, 0, sizeof bson->bson_type_data); + } else { + bson->read_state = BSON_JSON_REGULAR; + STACK_PUSH_DOC (bson_append_document_begin (STACK_BSON_PARENT, + bson->key, + (int) bson->key_buf.len, + STACK_BSON_CHILD)); + } + } else if (bson->read_state == BSON_JSON_IN_SCOPE) { + /* we've read "key" in {$code: "", $scope: {key: ""}}*/ + bson->read_state = BSON_JSON_REGULAR; + STACK_PUSH_SCOPE (bson_init (STACK_BSON_CHILD)); + _bson_json_save_map_key (bson, val, len); + } else if (bson->read_state == BSON_JSON_IN_DBPOINTER) { + /* we've read "$ref" or "$id" in {$dbPointer: {$ref: ..., $id: ...}} */ + bson->read_state = BSON_JSON_REGULAR; + STACK_PUSH_DBPOINTER (bson_init (STACK_BSON_CHILD)); + _bson_json_save_map_key (bson, val, len); + } + + if (bson->read_state == BSON_JSON_IN_BSON_TYPE) { + if + HANDLE_OPTION ("$regex", BSON_TYPE_REGEX, BSON_JSON_LF_REGEX) + else if + HANDLE_OPTION ("$options", BSON_TYPE_REGEX, BSON_JSON_LF_OPTIONS) + else if + HANDLE_OPTION ("$oid", BSON_TYPE_OID, BSON_JSON_LF_OID) + else if + HANDLE_OPTION ("$binary", BSON_TYPE_BINARY, BSON_JSON_LF_BINARY) + else if + HANDLE_OPTION ("$type", BSON_TYPE_BINARY, BSON_JSON_LF_TYPE) + else if + HANDLE_OPTION ("$date", BSON_TYPE_DATE_TIME, BSON_JSON_LF_DATE) + else if + HANDLE_OPTION ( + "$undefined", BSON_TYPE_UNDEFINED, BSON_JSON_LF_UNDEFINED) + else if + HANDLE_OPTION ("$minKey", BSON_TYPE_MINKEY, BSON_JSON_LF_MINKEY) + else if + HANDLE_OPTION ("$maxKey", BSON_TYPE_MAXKEY, BSON_JSON_LF_MAXKEY) + else if + HANDLE_OPTION ("$numberInt", BSON_TYPE_INT32, BSON_JSON_LF_INT32) + else if + HANDLE_OPTION ("$numberLong", BSON_TYPE_INT64, BSON_JSON_LF_INT64) + else if + HANDLE_OPTION ("$numberDouble", BSON_TYPE_DOUBLE, BSON_JSON_LF_DOUBLE) + else if + HANDLE_OPTION ("$symbol", BSON_TYPE_SYMBOL, BSON_JSON_LF_SYMBOL) + else if + HANDLE_OPTION ( + "$numberDecimal", BSON_TYPE_DECIMAL128, BSON_JSON_LF_DECIMAL128) + else if (!strcmp ("$timestamp", (const char *) val)) { + bson->bson_type = BSON_TYPE_TIMESTAMP; + bson->read_state = BSON_JSON_IN_BSON_TYPE_TIMESTAMP_STARTMAP; + } else if (!strcmp ("$dbPointer", (const char *) val)) { + /* start parsing "key": {"$dbPointer": ...}, save "key" for later */ + _bson_json_buf_set ( + &bson->dbpointer_key, bson->key_buf.buf, bson->key_buf.len); + + bson->bson_type = BSON_TYPE_DBPOINTER; + bson->read_state = BSON_JSON_IN_BSON_TYPE_DBPOINTER_STARTMAP; + } else if (!strcmp ("$code", (const char *) val)) { + _bson_json_read_code_or_scope_key ( + bson, false /* is_scope */, val, len); + } else if (!strcmp ("$scope", (const char *) val)) { + _bson_json_read_code_or_scope_key ( + bson, true /* is_scope */, val, len); + } else { + _bson_json_read_set_error ( + reader, + "Invalid key %s. Looking for values for %d", + val, + bson->bson_type); + } + } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_DATE_NUMBERLONG) { + if + HANDLE_OPTION ("$numberLong", BSON_TYPE_DATE_TIME, BSON_JSON_LF_INT64) + else { + _bson_json_read_set_error ( + reader, + "Invalid key %s. Looking for values for %d", + val, + bson->bson_type); + } + } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_VALUES) { + if + HANDLE_OPTION ("t", BSON_TYPE_TIMESTAMP, BSON_JSON_LF_TIMESTAMP_T) + else if + HANDLE_OPTION ("i", BSON_TYPE_TIMESTAMP, BSON_JSON_LF_TIMESTAMP_I) + else { + _bson_json_read_set_error ( + reader, + "Invalid key %s. Looking for values for %d", + val, + bson->bson_type); + } + } else { + _bson_json_save_map_key (bson, val, len); + } +} + + +static void +_bson_json_read_append_binary (bson_json_reader_t *reader, /* IN */ + bson_json_reader_bson_t *bson) /* IN */ +{ + if (!bson->bson_type_data.binary.has_binary) { + _bson_json_read_set_error ( + reader, "Missing $binary after $type in BSON_TYPE_BINARY"); + } else if (!bson->bson_type_data.binary.has_subtype) { + _bson_json_read_set_error ( + reader, "Missing $type after $binary in BSON_TYPE_BINARY"); + } else { + if (!bson_append_binary (STACK_BSON_CHILD, + bson->key, + (int) bson->key_buf.len, + bson->bson_type_data.binary.type, + bson->bson_type_buf[0].buf, + (uint32_t) bson->bson_type_buf[0].len)) { + _bson_json_read_set_error (reader, "Error storing binary data"); + } + } +} + + +static void +_bson_json_read_append_regex (bson_json_reader_t *reader, /* IN */ + bson_json_reader_bson_t *bson) /* IN */ +{ + char *regex = NULL; + char *options = NULL; + + if (!bson->bson_type_data.regex.has_regex) { + _bson_json_read_set_error ( + reader, "Missing $regex after $options in BSON_TYPE_REGEX"); + return; + } + + regex = (char *) bson->bson_type_buf[0].buf; + + if (bson->bson_type_data.regex.has_options) { + options = (char *) bson->bson_type_buf[1].buf; + } + + if (!bson_append_regex (STACK_BSON_CHILD, + bson->key, + (int) bson->key_buf.len, + regex, + options)) { + _bson_json_read_set_error (reader, "Error storing regex"); + } +} + + +static void +_bson_json_read_append_code (bson_json_reader_t *reader, /* IN */ + bson_json_reader_bson_t *bson) /* IN */ +{ + bson_json_code_t *code_data; + char *code = NULL; + bson_t *scope = NULL; + bool r; + + code_data = &bson->code_data; + + BSON_ASSERT (!code_data->in_scope); + + if (!code_data->has_code) { + _bson_json_read_set_error (reader, "Missing $code after $scope"); + return; + } + + code = (char *) code_data->code_buf.buf; + + if (code_data->has_scope) { + scope = STACK_BSON (1); + } + + /* creates BSON "code" elem, or "code with scope" if scope is not NULL */ + r = bson_append_code_with_scope (STACK_BSON_CHILD, + (const char *) code_data->key_buf.buf, + (int) code_data->key_buf.len, + code, + scope); + + if (!r) { + _bson_json_read_set_error (reader, "Error storing Javascript code"); + } + + if (scope) { + bson_destroy (scope); + } + + /* keep the buffer but truncate it */ + code_data->key_buf.len = 0; + code_data->has_code = code_data->has_scope = false; +} + + +static void +_bson_json_read_append_dbpointer (bson_json_reader_t *reader, /* IN */ + bson_json_reader_bson_t *bson) /* IN */ +{ + bson_t *db_pointer; + bson_iter_t iter; + const char *ns = NULL; + const bson_oid_t *oid = NULL; + bool r; + + BSON_ASSERT (reader->bson.dbpointer_key.buf); + + db_pointer = STACK_BSON (1); + if (!bson_iter_init (&iter, db_pointer)) { + _bson_json_read_set_error (reader, "Error storing DBPointer"); + return; + } + + while (bson_iter_next (&iter)) { + if (!strcmp (bson_iter_key (&iter), "$id")) { + if (!BSON_ITER_HOLDS_OID (&iter)) { + _bson_json_read_set_error ( + reader, "$dbPointer.$id must be like {\"$oid\": ...\"}"); + return; + } + + oid = bson_iter_oid (&iter); + } else if (!strcmp (bson_iter_key (&iter), "$ref")) { + if (!BSON_ITER_HOLDS_UTF8 (&iter)) { + _bson_json_read_set_error ( + reader, + "$dbPointer.$ref must be a string like \"db.collection\""); + return; + } + + ns = bson_iter_utf8 (&iter, NULL); + } + } + + if (!oid || !ns) { + _bson_json_read_set_error (reader, + "$dbPointer requires both $id and $ref"); + return; + } + + r = bson_append_dbpointer (STACK_BSON_CHILD, + (char *) reader->bson.dbpointer_key.buf, + (int) reader->bson.dbpointer_key.len, + ns, + oid); + + if (!r) { + _bson_json_read_set_error (reader, "Error storing DBPointer"); + } +} + + +static void +_bson_json_read_append_oid (bson_json_reader_t *reader, /* IN */ + bson_json_reader_bson_t *bson) /* IN */ +{ + if (!bson_append_oid (STACK_BSON_CHILD, + bson->key, + (int) bson->key_buf.len, + &bson->bson_type_data.oid.oid)) { + _bson_json_read_set_error (reader, "Error storing ObjectId"); + } +} + + +static void +_bson_json_read_append_date_time (bson_json_reader_t *reader, /* IN */ + bson_json_reader_bson_t *bson) /* IN */ +{ + if (!bson_append_date_time (STACK_BSON_CHILD, + bson->key, + (int) bson->key_buf.len, + bson->bson_type_data.date.date)) { + _bson_json_read_set_error (reader, "Error storing datetime"); + } +} + + +static void +_bson_json_read_append_timestamp (bson_json_reader_t *reader, /* IN */ + bson_json_reader_bson_t *bson) /* IN */ +{ + if (!bson->bson_type_data.timestamp.has_t) { + _bson_json_read_set_error ( + reader, "Missing t after $timestamp in BSON_TYPE_TIMESTAMP"); + return; + } else if (!bson->bson_type_data.timestamp.has_i) { + _bson_json_read_set_error ( + reader, "Missing i after $timestamp in BSON_TYPE_TIMESTAMP"); + return; + } + + bson_append_timestamp (STACK_BSON_CHILD, + bson->key, + (int) bson->key_buf.len, + bson->bson_type_data.timestamp.t, + bson->bson_type_data.timestamp.i); +} + + +static void +_bad_extended_json (bson_json_reader_t *reader) +{ + _bson_json_read_corrupt (reader, "Invalid MongoDB extended JSON"); +} + + +static void +_bson_json_read_end_map (bson_json_reader_t *reader) /* IN */ +{ + bson_json_reader_bson_t *bson = &reader->bson; + + if (bson->read_state == BSON_JSON_IN_START_MAP) { + bson->read_state = BSON_JSON_REGULAR; + STACK_PUSH_DOC (bson_append_document_begin (STACK_BSON_PARENT, + bson->key, + (int) bson->key_buf.len, + STACK_BSON_CHILD)); + } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_SCOPE_STARTMAP) { + bson->read_state = BSON_JSON_REGULAR; + STACK_PUSH_SCOPE (bson_init (STACK_BSON_CHILD)); + } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_DBPOINTER_STARTMAP) { + /* we've read last "}" in "{$dbPointer: {$id: ..., $ref: ...}}" */ + _bson_json_read_append_dbpointer (reader, bson); + bson->read_state = BSON_JSON_REGULAR; + return; + } + + if (bson->read_state == BSON_JSON_IN_BSON_TYPE) { + if (!bson->key) { + /* invalid, like {$numberLong: "1"} at the document top level */ + _bad_extended_json (reader); + return; + } + + bson->read_state = BSON_JSON_REGULAR; + switch (bson->bson_type) { + case BSON_TYPE_REGEX: + _bson_json_read_append_regex (reader, bson); + break; + case BSON_TYPE_CODE: + case BSON_TYPE_CODEWSCOPE: + /* we've read the closing "}" in "{$code: ..., $scope: ...}" */ + _bson_json_read_append_code (reader, bson); + break; + case BSON_TYPE_OID: + _bson_json_read_append_oid (reader, bson); + break; + case BSON_TYPE_BINARY: + _bson_json_read_append_binary (reader, bson); + break; + case BSON_TYPE_DATE_TIME: + _bson_json_read_append_date_time (reader, bson); + break; + case BSON_TYPE_UNDEFINED: + bson_append_undefined ( + STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len); + break; + case BSON_TYPE_MINKEY: + bson_append_minkey ( + STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len); + break; + case BSON_TYPE_MAXKEY: + bson_append_maxkey ( + STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len); + break; + case BSON_TYPE_INT32: + bson_append_int32 (STACK_BSON_CHILD, + bson->key, + (int) bson->key_buf.len, + bson->bson_type_data.v_int32.value); + break; + case BSON_TYPE_INT64: + bson_append_int64 (STACK_BSON_CHILD, + bson->key, + (int) bson->key_buf.len, + bson->bson_type_data.v_int64.value); + break; + case BSON_TYPE_DOUBLE: + bson_append_double (STACK_BSON_CHILD, + bson->key, + (int) bson->key_buf.len, + bson->bson_type_data.v_double.value); + break; + case BSON_TYPE_DECIMAL128: + bson_append_decimal128 (STACK_BSON_CHILD, + bson->key, + (int) bson->key_buf.len, + &bson->bson_type_data.v_decimal128.value); + break; + case BSON_TYPE_DBPOINTER: + /* shouldn't set type to DBPointer unless inside $dbPointer: {...} */ + _bson_json_read_set_error ( + reader, + "Internal error: shouldn't be in state BSON_TYPE_DBPOINTER"); + break; + case BSON_TYPE_SYMBOL: + break; + case BSON_TYPE_EOD: + case BSON_TYPE_UTF8: + case BSON_TYPE_DOCUMENT: + case BSON_TYPE_ARRAY: + case BSON_TYPE_BOOL: + case BSON_TYPE_NULL: + case BSON_TYPE_TIMESTAMP: + default: + _bson_json_read_set_error (reader, "Unknown type %d", bson->bson_type); + break; + } + } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_VALUES) { + if (!bson->key) { + _bad_extended_json (reader); + return; + } + + bson->read_state = BSON_JSON_IN_BSON_TYPE_TIMESTAMP_ENDMAP; + + _bson_json_read_append_timestamp (reader, bson); + return; + } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_STARTMAP) { + bson_append_timestamp (STACK_BSON_CHILD, + bson->key, + (int) bson->key_buf.len, + bson->bson_type_data.timestamp.t, + bson->bson_type_data.timestamp.i); + bson->read_state = BSON_JSON_REGULAR; + } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_ENDMAP) { + bson->read_state = BSON_JSON_REGULAR; + } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_DATE_NUMBERLONG) { + if (!bson->key) { + _bad_extended_json (reader); + return; + } + + bson->read_state = BSON_JSON_IN_BSON_TYPE_DATE_ENDMAP; + + _bson_json_read_append_date_time (reader, bson); + return; + } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_DATE_ENDMAP) { + bson->read_state = BSON_JSON_REGULAR; + } else if (bson->read_state == BSON_JSON_REGULAR) { + if (STACK_IS_SCOPE) { + bson->read_state = BSON_JSON_IN_BSON_TYPE; + bson->bson_type = BSON_TYPE_CODE; + STACK_POP_SCOPE; + } else if (STACK_IS_DBPOINTER) { + bson->read_state = BSON_JSON_IN_BSON_TYPE_DBPOINTER_STARTMAP; + STACK_POP_DBPOINTER; + } else { + STACK_POP_DOC ( + bson_append_document_end (STACK_BSON_PARENT, STACK_BSON_CHILD)); + } + + if (bson->n == -1) { + bson->read_state = BSON_JSON_DONE; + } + } else if (bson->read_state == BSON_JSON_IN_SCOPE) { + /* empty $scope */ + BSON_ASSERT (bson->code_data.has_scope); + STACK_PUSH_SCOPE (bson_init (STACK_BSON_CHILD)); + STACK_POP_SCOPE; + bson->read_state = BSON_JSON_IN_BSON_TYPE; + bson->bson_type = BSON_TYPE_CODE; + } else if (bson->read_state == BSON_JSON_IN_DBPOINTER) { + /* empty $dbPointer??? */ + _bson_json_read_set_error (reader, "Empty $dbPointer"); + } else { + _bson_json_read_set_error (reader, "Invalid state %d", bson->read_state); + } +} + + +static void +_bson_json_read_start_array (bson_json_reader_t *reader) /* IN */ +{ + const char *key; + size_t len; + bson_json_reader_bson_t *bson = &reader->bson; + + if (bson->n < 0) { + STACK_PUSH_ARRAY (_noop ()); + } else { + _bson_json_read_fixup_key (bson); + key = bson->key; + len = bson->key_buf.len; + + BASIC_CB_BAIL_IF_NOT_NORMAL ("["); + + STACK_PUSH_ARRAY (bson_append_array_begin ( + STACK_BSON_PARENT, key, (int) len, STACK_BSON_CHILD)); + } +} + + +static void +_bson_json_read_end_array (bson_json_reader_t *reader) /* IN */ +{ + bson_json_reader_bson_t *bson = &reader->bson; + + if (bson->read_state != BSON_JSON_REGULAR) { + _bson_json_read_set_error ( + reader, "Invalid read of %s in state %d", "]", bson->read_state); + return; + } + + STACK_POP_ARRAY ( + bson_append_array_end (STACK_BSON_PARENT, STACK_BSON_CHILD)); + if (bson->n == -1) { + bson->read_state = BSON_JSON_DONE; + } +} + + +/* put unescaped text in reader->bson.unescaped, or set reader->error. + * json_text has length len and it is not null-terminated. */ +static bool +_bson_json_unescape (bson_json_reader_t *reader, + struct jsonsl_state_st *state, + const char *json_text, + ssize_t len) +{ + bson_json_reader_bson_t *reader_bson; + jsonsl_error_t err; + + reader_bson = &reader->bson; + + /* add 1 for NULL */ + _bson_json_buf_ensure (&reader_bson->unescaped, (size_t) len + 1); + + /* length of unescaped str is always <= len */ + reader_bson->unescaped.len = jsonsl_util_unescape ( + json_text, (char *) reader_bson->unescaped.buf, (size_t) len, NULL, &err); + + if (err != JSONSL_ERROR_SUCCESS) { + bson_set_error (reader->error, + BSON_ERROR_JSON, + BSON_JSON_ERROR_READ_CORRUPT_JS, + "error near position %d: %s", + (int) state->pos_begin, + jsonsl_strerror (err)); + return false; + } + + reader_bson->unescaped.buf[reader_bson->unescaped.len] = '\0'; + + return true; +} + + +/* read the buffered JSON plus new data, and fill out @len with its length */ +static const char * +_get_json_text (jsonsl_t json, /* IN */ + struct jsonsl_state_st *state, /* IN */ + const char *buf /* IN */, + ssize_t *len /* OUT */) +{ + bson_json_reader_t *reader; + ssize_t bytes_available; + + reader = (bson_json_reader_t *) json->data; + + BSON_ASSERT (state->pos_cur > state->pos_begin); + + *len = (ssize_t) (state->pos_cur - state->pos_begin); + + bytes_available = buf - json->base; + + if (*len <= bytes_available) { + /* read directly from stream, not from saved JSON */ + return buf - (size_t) *len; + } else { + /* combine saved text with new data from the jsonsl_t */ + ssize_t append = buf - json->base; + + if (append > 0) { + _bson_json_buf_append ( + &reader->tok_accumulator, buf - append, (size_t) append); + } + + return (const char *) reader->tok_accumulator.buf; + } +} + + +static void +_push_callback (jsonsl_t json, + jsonsl_action_t action, + struct jsonsl_state_st *state, + const char *buf) +{ + bson_json_reader_t *reader = (bson_json_reader_t *) json->data; + + switch (state->type) { + case JSONSL_T_STRING: + case JSONSL_T_HKEY: + case JSONSL_T_SPECIAL: + case JSONSL_T_UESCAPE: + reader->json_text_pos = state->pos_begin; + break; + case JSONSL_T_OBJECT: + _bson_json_read_start_map (reader); + break; + case JSONSL_T_LIST: + _bson_json_read_start_array (reader); + break; + default: + break; + } +} + + +static void +_pop_callback (jsonsl_t json, + jsonsl_action_t action, + struct jsonsl_state_st *state, + const char *buf) +{ + bson_json_reader_t *reader; + bson_json_reader_bson_t *reader_bson; + ssize_t len; + double d; + const char *obj_text; + + reader = (bson_json_reader_t *) json->data; + reader_bson = &reader->bson; + + switch (state->type) { + case JSONSL_T_HKEY: + case JSONSL_T_STRING: + obj_text = _get_json_text (json, state, buf, &len); + BSON_ASSERT (obj_text[0] == '"'); + + /* remove start/end quotes, replace backslash-escapes, null-terminate */ + /* you'd think it would be faster to check if state->nescapes > 0 first, + * but tests show no improvement */ + if (!_bson_json_unescape (reader, state, obj_text + 1, len - 1)) { + /* reader->error is set */ + jsonsl_stop (json); + break; + } + + if (state->type == JSONSL_T_HKEY) { + _bson_json_read_map_key ( + reader, reader_bson->unescaped.buf, reader_bson->unescaped.len); + } else { + _bson_json_read_string ( + reader, reader_bson->unescaped.buf, reader_bson->unescaped.len); + } + break; + case JSONSL_T_OBJECT: + _bson_json_read_end_map (reader); + break; + case JSONSL_T_LIST: + _bson_json_read_end_array (reader); + break; + case JSONSL_T_SPECIAL: + obj_text = _get_json_text (json, state, buf, &len); + if (state->special_flags & JSONSL_SPECIALf_NUMNOINT) { + if (_bson_json_parse_double (reader, obj_text, (size_t) len, &d)) { + _bson_json_read_double (reader, d); + } + } else if (state->special_flags & JSONSL_SPECIALf_NUMERIC) { + int64_t i = state->nelem; + /* jsonsl puts the unsigned value in state->nelem */ + if (state->special_flags & JSONSL_SPECIALf_SIGNED) { + i *= -1; + } + + _bson_json_read_integer (reader, i); + } else if (state->special_flags & JSONSL_SPECIALf_BOOLEAN) { + _bson_json_read_boolean (reader, obj_text[0] == 't' ? 1 : 0); + } else if (state->special_flags & JSONSL_SPECIALf_NULL) { + _bson_json_read_null (reader); + } + break; + default: + break; + } + + reader->json_text_pos = -1; + reader->tok_accumulator.len = 0; +} + + +static int +_error_callback (jsonsl_t json, + jsonsl_error_t err, + struct jsonsl_state_st *state, + char *errat) +{ + bson_json_reader_t *reader = (bson_json_reader_t *) json->data; + + if (err == JSONSL_ERROR_CANT_INSERT && *errat == '{') { + /* start the next document */ + reader->should_reset = true; + reader->advance = errat - json->base; + return 0; + } else if (err == JSONSL_ERROR_WEIRD_WHITESPACE && *errat == '\0') { + /* embedded NULL is ok */ + json->pos++; + return 1; + } + + bson_set_error (reader->error, + BSON_ERROR_JSON, + BSON_JSON_ERROR_READ_CORRUPT_JS, + "Got parse error at '%c', position %d: %s", + *errat, + (int) json->pos, + jsonsl_strerror (err)); + + return 0; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_json_reader_read -- + * + * Read the next json document from @reader and write its value + * into @bson. @bson will be allocated as part of this process. + * + * @bson MUST be initialized before calling this function as it + * will not be initialized automatically. The reasoning for this + * is so that you can chain together bson_json_reader_t with + * other components like bson_writer_t. + * + * Returns: + * 1 if successful and data was read. + * 0 if successful and no data was read. + * -1 if there was an error and @error is set. + * + * Side effects: + * @error may be set. + * + *-------------------------------------------------------------------------- + */ + +int +bson_json_reader_read (bson_json_reader_t *reader, /* IN */ + bson_t *bson, /* IN */ + bson_error_t *error) /* OUT */ +{ + bson_json_reader_producer_t *p; + ssize_t start_pos; + ssize_t r; + ssize_t buf_offset; + ssize_t accum; + bson_error_t error_tmp; + int ret = 0; + + BSON_ASSERT (reader); + BSON_ASSERT (bson); + + p = &reader->producer; + + reader->bson.bson = bson; + reader->bson.n = -1; + reader->bson.read_state = BSON_JSON_REGULAR; + reader->error = error ? error : &error_tmp; + memset (reader->error, 0, sizeof (bson_error_t)); + + for (;;) { + start_pos = reader->json->pos; + + if (p->bytes_read > 0) { + /* leftover data from previous JSON doc in the stream */ + r = p->bytes_read; + } else { + /* read a chunk of bytes by executing the callback */ + r = p->cb (p->data, p->buf, p->buf_size); + } + + if (r < 0) { + if (error) { + bson_set_error (error, + BSON_ERROR_JSON, + BSON_JSON_ERROR_READ_CB_FAILURE, + "reader cb failed"); + } + ret = -1; + goto cleanup; + } else if (r == 0) { + break; + } else { + ret = 1; + p->bytes_read = (size_t) r; + + jsonsl_feed (reader->json, (const jsonsl_char_t *) p->buf, (size_t) r); + + if (reader->should_reset) { + /* end of a document */ + jsonsl_reset (reader->json); + reader->should_reset = false; + + /* advance past already-parsed data */ + memmove (p->buf, p->buf + reader->advance, r - reader->advance); + p->bytes_read -= reader->advance; + ret = 1; + goto cleanup; + } + + if (reader->error->domain) { + ret = -1; + goto cleanup; + } + + /* accumulate a key or string value */ + if (reader->json_text_pos != -1) { + if (reader->json_text_pos < reader->json->pos) { + accum = BSON_MIN (reader->json->pos - reader->json_text_pos, r); + /* if this chunk stopped mid-token, buf_offset is how far into + * our current chunk the token begins. */ + buf_offset = AT_LEAST_0 (reader->json_text_pos - start_pos); + _bson_json_buf_append (&reader->tok_accumulator, + p->buf + buf_offset, + (size_t) accum); + } + } + + p->bytes_read = 0; + } + } + +cleanup: + if (ret == 1 && reader->bson.read_state != BSON_JSON_DONE) { + /* data ended in the middle */ + _bson_json_read_corrupt (reader, "%s", "Incomplete JSON"); + return -1; + } + + return ret; +} + + +bson_json_reader_t * +bson_json_reader_new (void *data, /* IN */ + bson_json_reader_cb cb, /* IN */ + bson_json_destroy_cb dcb, /* IN */ + bool allow_multiple, /* unused */ + size_t buf_size) /* IN */ +{ + bson_json_reader_t *r; + bson_json_reader_producer_t *p; + + r = bson_malloc0 (sizeof *r); + r->json = jsonsl_new (STACK_MAX); + r->json->error_callback = _error_callback; + r->json->action_callback_PUSH = _push_callback; + r->json->action_callback_POP = _pop_callback; + r->json->data = r; + r->json_text_pos = -1; + jsonsl_enable_all_callbacks (r->json); + + p = &r->producer; + + p->data = data; + p->cb = cb; + p->dcb = dcb; + p->buf_size = buf_size ? buf_size : BSON_JSON_DEFAULT_BUF_SIZE; + p->buf = bson_malloc (p->buf_size); + + return r; +} + + +void +bson_json_reader_destroy (bson_json_reader_t *reader) /* IN */ +{ + int i; + bson_json_reader_producer_t *p = &reader->producer; + bson_json_reader_bson_t *b = &reader->bson; + + if (reader->producer.dcb) { + reader->producer.dcb (reader->producer.data); + } + + bson_free (p->buf); + bson_free (b->key_buf.buf); + bson_free (b->unescaped.buf); + bson_free (b->dbpointer_key.buf); + + for (i = 0; i < 3; i++) { + bson_free (b->bson_type_buf[i].buf); + } + + _bson_json_code_cleanup (&b->code_data); + + jsonsl_destroy (reader->json); + bson_free (reader->tok_accumulator.buf); + bson_free (reader); +} + + +typedef struct { + const uint8_t *data; + size_t len; + size_t bytes_parsed; +} bson_json_data_reader_t; + + +static ssize_t +_bson_json_data_reader_cb (void *_ctx, uint8_t *buf, size_t len) +{ + size_t bytes; + bson_json_data_reader_t *ctx = (bson_json_data_reader_t *) _ctx; + + if (!ctx->data) { + return -1; + } + + bytes = BSON_MIN (len, ctx->len - ctx->bytes_parsed); + + memcpy (buf, ctx->data + ctx->bytes_parsed, bytes); + + ctx->bytes_parsed += bytes; + + return bytes; +} + + +bson_json_reader_t * +bson_json_data_reader_new (bool allow_multiple, /* IN */ + size_t size) /* IN */ +{ + bson_json_data_reader_t *dr = bson_malloc0 (sizeof *dr); + + return bson_json_reader_new ( + dr, &_bson_json_data_reader_cb, &bson_free, allow_multiple, size); +} + + +void +bson_json_data_reader_ingest (bson_json_reader_t *reader, /* IN */ + const uint8_t *data, /* IN */ + size_t len) /* IN */ +{ + bson_json_data_reader_t *ctx = + (bson_json_data_reader_t *) reader->producer.data; + + ctx->data = data; + ctx->len = len; + ctx->bytes_parsed = 0; +} + + +bson_t * +bson_new_from_json (const uint8_t *data, /* IN */ + ssize_t len, /* IN */ + bson_error_t *error) /* OUT */ +{ + bson_json_reader_t *reader; + bson_t *bson; + int r; + + BSON_ASSERT (data); + + if (len < 0) { + len = (ssize_t) strlen ((const char *) data); + } + + bson = bson_new (); + reader = bson_json_data_reader_new (false, BSON_JSON_DEFAULT_BUF_SIZE); + bson_json_data_reader_ingest (reader, data, len); + r = bson_json_reader_read (reader, bson, error); + bson_json_reader_destroy (reader); + + if (r == 0) { + bson_set_error (error, + BSON_ERROR_JSON, + BSON_JSON_ERROR_READ_INVALID_PARAM, + "Empty JSON string"); + } + + if (r != 1) { + bson_destroy (bson); + return NULL; + } + + return bson; +} + + +bool +bson_init_from_json (bson_t *bson, /* OUT */ + const char *data, /* IN */ + ssize_t len, /* IN */ + bson_error_t *error) /* OUT */ +{ + bson_json_reader_t *reader; + int r; + + BSON_ASSERT (bson); + BSON_ASSERT (data); + + if (len < 0) { + len = strlen (data); + } + + bson_init (bson); + + reader = bson_json_data_reader_new (false, BSON_JSON_DEFAULT_BUF_SIZE); + bson_json_data_reader_ingest (reader, (const uint8_t *) data, len); + r = bson_json_reader_read (reader, bson, error); + bson_json_reader_destroy (reader); + + if (r == 0) { + bson_set_error (error, + BSON_ERROR_JSON, + BSON_JSON_ERROR_READ_INVALID_PARAM, + "Empty JSON string"); + } + + if (r != 1) { + bson_destroy (bson); + return false; + } + + return true; +} + + +static void +_bson_json_reader_handle_fd_destroy (void *handle) /* IN */ +{ + bson_json_reader_handle_fd_t *fd = handle; + + if (fd) { + if ((fd->fd != -1) && fd->do_close) { +#ifdef _WIN32 + _close (fd->fd); +#else + close (fd->fd); +#endif + } + bson_free (fd); + } +} + + +static ssize_t +_bson_json_reader_handle_fd_read (void *handle, /* IN */ + uint8_t *buf, /* IN */ + size_t len) /* IN */ +{ + bson_json_reader_handle_fd_t *fd = handle; + ssize_t ret = -1; + + if (fd && (fd->fd != -1)) { + again: +#ifdef BSON_OS_WIN32 + ret = _read (fd->fd, buf, (unsigned int) len); +#else + ret = read (fd->fd, buf, len); +#endif + if ((ret == -1) && (errno == EAGAIN)) { + goto again; + } + } + + return ret; +} + + +bson_json_reader_t * +bson_json_reader_new_from_fd (int fd, /* IN */ + bool close_on_destroy) /* IN */ +{ + bson_json_reader_handle_fd_t *handle; + + BSON_ASSERT (fd != -1); + + handle = bson_malloc0 (sizeof *handle); + handle->fd = fd; + handle->do_close = close_on_destroy; + + return bson_json_reader_new (handle, + _bson_json_reader_handle_fd_read, + _bson_json_reader_handle_fd_destroy, + true, + BSON_JSON_DEFAULT_BUF_SIZE); +} + + +bson_json_reader_t * +bson_json_reader_new_from_file (const char *path, /* IN */ + bson_error_t *error) /* OUT */ +{ + char errmsg_buf[BSON_ERROR_BUFFER_SIZE]; + char *errmsg; + int fd = -1; + + BSON_ASSERT (path); + +#ifdef BSON_OS_WIN32 + _sopen_s (&fd, path, (_O_RDONLY | _O_BINARY), _SH_DENYNO, _S_IREAD); +#else + fd = open (path, O_RDONLY); +#endif + + if (fd == -1) { + errmsg = bson_strerror_r (errno, errmsg_buf, sizeof errmsg_buf); + bson_set_error ( + error, BSON_ERROR_READER, BSON_ERROR_READER_BADFD, "%s", errmsg); + return NULL; + } + + return bson_json_reader_new_from_fd (fd, true); +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-json.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-json.h new file mode 100644 index 0000000000000000000000000000000000000000..12ef995894ed96d5375062b234b5e508e911be11 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-json.h @@ -0,0 +1,76 @@ +/* + * Copyright 2014 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_JSON_H +#define BSON_JSON_H + + +#if !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) +#error "Only <bson.h> can be included directly." +#endif + + +#include "bson.h" + + +BSON_BEGIN_DECLS + + +typedef struct _bson_json_reader_t bson_json_reader_t; + + +typedef enum { + BSON_JSON_ERROR_READ_CORRUPT_JS = 1, + BSON_JSON_ERROR_READ_INVALID_PARAM, + BSON_JSON_ERROR_READ_CB_FAILURE, +} bson_json_error_code_t; + + +typedef ssize_t (*bson_json_reader_cb) (void *handle, + uint8_t *buf, + size_t count); +typedef void (*bson_json_destroy_cb) (void *handle); + + +BSON_EXPORT (bson_json_reader_t *) +bson_json_reader_new (void *data, + bson_json_reader_cb cb, + bson_json_destroy_cb dcb, + bool allow_multiple, + size_t buf_size); +BSON_EXPORT (bson_json_reader_t *) +bson_json_reader_new_from_fd (int fd, bool close_on_destroy); +BSON_EXPORT (bson_json_reader_t *) +bson_json_reader_new_from_file (const char *filename, bson_error_t *error); +BSON_EXPORT (void) +bson_json_reader_destroy (bson_json_reader_t *reader); +BSON_EXPORT (int) +bson_json_reader_read (bson_json_reader_t *reader, + bson_t *bson, + bson_error_t *error); +BSON_EXPORT (bson_json_reader_t *) +bson_json_data_reader_new (bool allow_multiple, size_t size); +BSON_EXPORT (void) +bson_json_data_reader_ingest (bson_json_reader_t *reader, + const uint8_t *data, + size_t len); + + +BSON_END_DECLS + + +#endif /* BSON_JSON_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-keys.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-keys.c new file mode 100644 index 0000000000000000000000000000000000000000..ce726093ea3d65931df0c9eb4d8705fb9f889c21 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-keys.c @@ -0,0 +1,170 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include <stdio.h> + +#include "bson-keys.h" +#include "bson-string.h" + + +static const char *gUint32Strs[] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", + "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", + "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", + "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", + "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", + "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", + "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", + "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", + "99", "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", + "110", "111", "112", "113", "114", "115", "116", "117", "118", "119", "120", + "121", "122", "123", "124", "125", "126", "127", "128", "129", "130", "131", + "132", "133", "134", "135", "136", "137", "138", "139", "140", "141", "142", + "143", "144", "145", "146", "147", "148", "149", "150", "151", "152", "153", + "154", "155", "156", "157", "158", "159", "160", "161", "162", "163", "164", + "165", "166", "167", "168", "169", "170", "171", "172", "173", "174", "175", + "176", "177", "178", "179", "180", "181", "182", "183", "184", "185", "186", + "187", "188", "189", "190", "191", "192", "193", "194", "195", "196", "197", + "198", "199", "200", "201", "202", "203", "204", "205", "206", "207", "208", + "209", "210", "211", "212", "213", "214", "215", "216", "217", "218", "219", + "220", "221", "222", "223", "224", "225", "226", "227", "228", "229", "230", + "231", "232", "233", "234", "235", "236", "237", "238", "239", "240", "241", + "242", "243", "244", "245", "246", "247", "248", "249", "250", "251", "252", + "253", "254", "255", "256", "257", "258", "259", "260", "261", "262", "263", + "264", "265", "266", "267", "268", "269", "270", "271", "272", "273", "274", + "275", "276", "277", "278", "279", "280", "281", "282", "283", "284", "285", + "286", "287", "288", "289", "290", "291", "292", "293", "294", "295", "296", + "297", "298", "299", "300", "301", "302", "303", "304", "305", "306", "307", + "308", "309", "310", "311", "312", "313", "314", "315", "316", "317", "318", + "319", "320", "321", "322", "323", "324", "325", "326", "327", "328", "329", + "330", "331", "332", "333", "334", "335", "336", "337", "338", "339", "340", + "341", "342", "343", "344", "345", "346", "347", "348", "349", "350", "351", + "352", "353", "354", "355", "356", "357", "358", "359", "360", "361", "362", + "363", "364", "365", "366", "367", "368", "369", "370", "371", "372", "373", + "374", "375", "376", "377", "378", "379", "380", "381", "382", "383", "384", + "385", "386", "387", "388", "389", "390", "391", "392", "393", "394", "395", + "396", "397", "398", "399", "400", "401", "402", "403", "404", "405", "406", + "407", "408", "409", "410", "411", "412", "413", "414", "415", "416", "417", + "418", "419", "420", "421", "422", "423", "424", "425", "426", "427", "428", + "429", "430", "431", "432", "433", "434", "435", "436", "437", "438", "439", + "440", "441", "442", "443", "444", "445", "446", "447", "448", "449", "450", + "451", "452", "453", "454", "455", "456", "457", "458", "459", "460", "461", + "462", "463", "464", "465", "466", "467", "468", "469", "470", "471", "472", + "473", "474", "475", "476", "477", "478", "479", "480", "481", "482", "483", + "484", "485", "486", "487", "488", "489", "490", "491", "492", "493", "494", + "495", "496", "497", "498", "499", "500", "501", "502", "503", "504", "505", + "506", "507", "508", "509", "510", "511", "512", "513", "514", "515", "516", + "517", "518", "519", "520", "521", "522", "523", "524", "525", "526", "527", + "528", "529", "530", "531", "532", "533", "534", "535", "536", "537", "538", + "539", "540", "541", "542", "543", "544", "545", "546", "547", "548", "549", + "550", "551", "552", "553", "554", "555", "556", "557", "558", "559", "560", + "561", "562", "563", "564", "565", "566", "567", "568", "569", "570", "571", + "572", "573", "574", "575", "576", "577", "578", "579", "580", "581", "582", + "583", "584", "585", "586", "587", "588", "589", "590", "591", "592", "593", + "594", "595", "596", "597", "598", "599", "600", "601", "602", "603", "604", + "605", "606", "607", "608", "609", "610", "611", "612", "613", "614", "615", + "616", "617", "618", "619", "620", "621", "622", "623", "624", "625", "626", + "627", "628", "629", "630", "631", "632", "633", "634", "635", "636", "637", + "638", "639", "640", "641", "642", "643", "644", "645", "646", "647", "648", + "649", "650", "651", "652", "653", "654", "655", "656", "657", "658", "659", + "660", "661", "662", "663", "664", "665", "666", "667", "668", "669", "670", + "671", "672", "673", "674", "675", "676", "677", "678", "679", "680", "681", + "682", "683", "684", "685", "686", "687", "688", "689", "690", "691", "692", + "693", "694", "695", "696", "697", "698", "699", "700", "701", "702", "703", + "704", "705", "706", "707", "708", "709", "710", "711", "712", "713", "714", + "715", "716", "717", "718", "719", "720", "721", "722", "723", "724", "725", + "726", "727", "728", "729", "730", "731", "732", "733", "734", "735", "736", + "737", "738", "739", "740", "741", "742", "743", "744", "745", "746", "747", + "748", "749", "750", "751", "752", "753", "754", "755", "756", "757", "758", + "759", "760", "761", "762", "763", "764", "765", "766", "767", "768", "769", + "770", "771", "772", "773", "774", "775", "776", "777", "778", "779", "780", + "781", "782", "783", "784", "785", "786", "787", "788", "789", "790", "791", + "792", "793", "794", "795", "796", "797", "798", "799", "800", "801", "802", + "803", "804", "805", "806", "807", "808", "809", "810", "811", "812", "813", + "814", "815", "816", "817", "818", "819", "820", "821", "822", "823", "824", + "825", "826", "827", "828", "829", "830", "831", "832", "833", "834", "835", + "836", "837", "838", "839", "840", "841", "842", "843", "844", "845", "846", + "847", "848", "849", "850", "851", "852", "853", "854", "855", "856", "857", + "858", "859", "860", "861", "862", "863", "864", "865", "866", "867", "868", + "869", "870", "871", "872", "873", "874", "875", "876", "877", "878", "879", + "880", "881", "882", "883", "884", "885", "886", "887", "888", "889", "890", + "891", "892", "893", "894", "895", "896", "897", "898", "899", "900", "901", + "902", "903", "904", "905", "906", "907", "908", "909", "910", "911", "912", + "913", "914", "915", "916", "917", "918", "919", "920", "921", "922", "923", + "924", "925", "926", "927", "928", "929", "930", "931", "932", "933", "934", + "935", "936", "937", "938", "939", "940", "941", "942", "943", "944", "945", + "946", "947", "948", "949", "950", "951", "952", "953", "954", "955", "956", + "957", "958", "959", "960", "961", "962", "963", "964", "965", "966", "967", + "968", "969", "970", "971", "972", "973", "974", "975", "976", "977", "978", + "979", "980", "981", "982", "983", "984", "985", "986", "987", "988", "989", + "990", "991", "992", "993", "994", "995", "996", "997", "998", "999"}; + + +/* + *-------------------------------------------------------------------------- + * + * bson_uint32_to_string -- + * + * Converts @value to a string. + * + * If @value is from 0 to 1000, it will use a constant string in the + * data section of the library. + * + * If not, a string will be formatted using @str and snprintf(). This + * is much slower, of course and therefore we try to optimize it out. + * + * @strptr will always be set. It will either point to @str or a + * constant string. You will want to use this as your key. + * + * Parameters: + * @value: A #uint32_t to convert to string. + * @strptr: (out): A pointer to the resulting string. + * @str: (out): Storage for a string made with snprintf. + * @size: Size of @str. + * + * Returns: + * The number of bytes in the resulting string. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +size_t +bson_uint32_to_string (uint32_t value, /* IN */ + const char **strptr, /* OUT */ + char *str, /* OUT */ + size_t size) /* IN */ +{ + if (value < 1000) { + *strptr = gUint32Strs[value]; + + if (value < 10) { + return 1; + } else if (value < 100) { + return 2; + } else { + return 3; + } + } + + *strptr = str; + + return bson_snprintf (str, size, "%u", value); +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-keys.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-keys.h new file mode 100644 index 0000000000000000000000000000000000000000..a8220ed462475ead10c992cc82bf52f41d1ac0a3 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-keys.h @@ -0,0 +1,39 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_KEYS_H +#define BSON_KEYS_H + + +#include "bson-macros.h" +#include "bson-types.h" + + +BSON_BEGIN_DECLS + + +BSON_EXPORT (size_t) +bson_uint32_to_string (uint32_t value, + const char **strptr, + char *str, + size_t size); + + +BSON_END_DECLS + + +#endif /* BSON_KEYS_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-macros.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-macros.h new file mode 100644 index 0000000000000000000000000000000000000000..e31c83000f62b74456bedfedbcf913596212a134 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-macros.h @@ -0,0 +1,273 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_MACROS_H +#define BSON_MACROS_H + +#include <stdio.h> + +#ifdef __cplusplus +#include <algorithm> +#endif + +#include "bson-config.h" + + +#if BSON_OS == 1 +#define BSON_OS_UNIX +#elif BSON_OS == 2 +#define BSON_OS_WIN32 +#else +#error "Unknown operating system." +#endif + + +#ifdef __cplusplus +#define BSON_BEGIN_DECLS extern "C" { +#define BSON_END_DECLS } +#else +#define BSON_BEGIN_DECLS +#define BSON_END_DECLS +#endif + + +#define BSON_GNUC_CHECK_VERSION(major, minor) \ + (defined (__GNUC__) && \ + ((__GNUC__ > (major)) || \ + ((__GNUC__ == (major)) && (__GNUC_MINOR__ >= (minor))))) + + +#define BSON_GNUC_IS_VERSION(major, minor) \ + (defined (__GNUC__) && (__GNUC__ == (major)) && (__GNUC_MINOR__ == (minor))) + + +/* Decorate public functions: + * - if BSON_STATIC, we're compiling a program that uses libbson as a static + * library, don't decorate functions + * - else if BSON_COMPILATION, we're compiling a static or shared libbson, mark + * public functions for export from the shared lib (which has no effect on + * the static lib) + * - else, we're compiling a program that uses libbson as a shared library, + * mark public functions as DLL imports for Microsoft Visual C + */ + +#ifdef _MSC_VER +/* + * Microsoft Visual C + */ +#ifdef BSON_STATIC +#define BSON_API +#elif defined(BSON_COMPILATION) +#define BSON_API __declspec(dllexport) +#else +#define BSON_API __declspec(dllimport) +#endif +#define BSON_CALL __cdecl + +#elif defined(__GNUC__) +/* + * GCC + */ +#ifdef BSON_STATIC +#define BSON_API +#elif defined(BSON_COMPILATION) +#define BSON_API __attribute__ ((visibility ("default"))) +#else +#define BSON_API +#endif +#define BSON_CALL + +#else +/* + * Other compilers + */ +#define BSON_API +#define BSON_CALL + +#endif + +#define BSON_EXPORT(type) BSON_API type BSON_CALL + + +#ifdef MIN +#define BSON_MIN MIN +#elif defined(__cplusplus) +#define BSON_MIN(a, b) ((std::min) (a, b)) +#elif defined(_MSC_VER) +#define BSON_MIN(a, b) ((a) < (b) ? (a) : (b)) +#else +#define BSON_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + + +#ifdef MAX +#define BSON_MAX MAX +#elif defined(__cplusplus) +#define BSON_MAX(a, b) ((std::max) (a, b)) +#elif defined(_MSC_VER) +#define BSON_MAX(a, b) ((a) > (b) ? (a) : (b)) +#else +#define BSON_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + + +#ifdef ABS +#define BSON_ABS ABS +#else +#define BSON_ABS(a) (((a) < 0) ? ((a) * -1) : (a)) +#endif + +#ifdef _MSC_VER +#ifdef _WIN64 +#define BSON_ALIGN_OF_PTR 8 +#else +#define BSON_ALIGN_OF_PTR 4 +#endif +#else +#define BSON_ALIGN_OF_PTR (sizeof (void *)) +#endif + +#ifdef BSON_EXTRA_ALIGN +#if defined(_MSC_VER) +#define BSON_ALIGNED_BEGIN(_N) __declspec(align (_N)) +#define BSON_ALIGNED_END(_N) +#else +#define BSON_ALIGNED_BEGIN(_N) +#define BSON_ALIGNED_END(_N) __attribute__ ((aligned (_N))) +#endif +#else +#if defined(_MSC_VER) +#define BSON_ALIGNED_BEGIN(_N) __declspec(align (BSON_ALIGN_OF_PTR)) +#define BSON_ALIGNED_END(_N) +#else +#define BSON_ALIGNED_BEGIN(_N) +#define BSON_ALIGNED_END(_N) \ + __attribute__ ( \ + (aligned ((_N) > BSON_ALIGN_OF_PTR ? BSON_ALIGN_OF_PTR : (_N)))) +#endif +#endif + + +#define bson_str_empty(s) (!s[0]) +#define bson_str_empty0(s) (!s || !s[0]) + + +#if defined(_WIN32) +#define BSON_FUNC __FUNCTION__ +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ < 199901L +#define BSON_FUNC __FUNCTION__ +#else +#define BSON_FUNC __func__ +#endif + +#define BSON_ASSERT(test) \ + do { \ + if (!(BSON_LIKELY (test))) { \ + fprintf (stderr, \ + "%s:%d %s(): precondition failed: %s\n", \ + __FILE__, \ + __LINE__, \ + BSON_FUNC, \ + #test); \ + abort (); \ + } \ + } while (0) + + +#define BSON_STATIC_ASSERT(s) BSON_STATIC_ASSERT_ (s, __LINE__) +#define BSON_STATIC_ASSERT_JOIN(a, b) BSON_STATIC_ASSERT_JOIN2 (a, b) +#define BSON_STATIC_ASSERT_JOIN2(a, b) a##b +#define BSON_STATIC_ASSERT_(s, l) \ + typedef char BSON_STATIC_ASSERT_JOIN (static_assert_test_, \ + __LINE__)[(s) ? 1 : -1] + + +#if defined(__GNUC__) +#define BSON_GNUC_CONST __attribute__ ((const)) +#define BSON_GNUC_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) +#else +#define BSON_GNUC_CONST +#define BSON_GNUC_WARN_UNUSED_RESULT +#endif + + +#if BSON_GNUC_CHECK_VERSION(4, 0) && !defined(_WIN32) +#define BSON_GNUC_NULL_TERMINATED __attribute__ ((sentinel)) +#define BSON_GNUC_INTERNAL __attribute__ ((visibility ("hidden"))) +#else +#define BSON_GNUC_NULL_TERMINATED +#define BSON_GNUC_INTERNAL +#endif + + +#if defined(__GNUC__) +#define BSON_LIKELY(x) __builtin_expect (!!(x), 1) +#define BSON_UNLIKELY(x) __builtin_expect (!!(x), 0) +#else +#define BSON_LIKELY(v) v +#define BSON_UNLIKELY(v) v +#endif + + +#if defined(__clang__) +#define BSON_GNUC_PRINTF(f, v) __attribute__ ((format (printf, f, v))) +#elif BSON_GNUC_CHECK_VERSION(4, 4) +#define BSON_GNUC_PRINTF(f, v) __attribute__ ((format (gnu_printf, f, v))) +#else +#define BSON_GNUC_PRINTF(f, v) +#endif + + +#if defined(__LP64__) || defined(_LP64) +#define BSON_WORD_SIZE 64 +#else +#define BSON_WORD_SIZE 32 +#endif + + +#if defined(_MSC_VER) +#define BSON_INLINE __inline +#else +#define BSON_INLINE __inline__ +#endif + + +#ifdef _MSC_VER +#define BSON_ENSURE_ARRAY_PARAM_SIZE(_n) +#define BSON_TYPEOF decltype +#else +#define BSON_ENSURE_ARRAY_PARAM_SIZE(_n) static(_n) +#define BSON_TYPEOF typeof +#endif + + +#if BSON_GNUC_CHECK_VERSION(3, 1) +#define BSON_GNUC_DEPRECATED __attribute__ ((__deprecated__)) +#else +#define BSON_GNUC_DEPRECATED +#endif + + +#if BSON_GNUC_CHECK_VERSION(4, 5) +#define BSON_GNUC_DEPRECATED_FOR(f) \ + __attribute__ ((deprecated ("Use " #f " instead"))) +#else +#define BSON_GNUC_DEPRECATED_FOR(f) BSON_GNUC_DEPRECATED +#endif + + +#endif /* BSON_MACROS_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-md5.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-md5.c new file mode 100644 index 0000000000000000000000000000000000000000..48cfd9c632e7d430179a4e52f05531dbfe7070ac --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-md5.c @@ -0,0 +1,397 @@ +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + <ghost@aladdin.com>. Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include <string.h> + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include <stdio.h> in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +/* + * The following MD5 implementation has been modified to use types as + * specified in libbson. + */ + +#include "bson-compat.h" + +#include <string.h> + +#include "bson-md5.h" + + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#if BSON_BYTE_ORDER == BSON_BIG_ENDIAN +#define BYTE_ORDER 1 +#else +#define BYTE_ORDER -1 +#endif + +#define T_MASK ((uint32_t) ~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +static void +bson_md5_process (bson_md5_t *md5, const uint8_t *data) +{ + uint32_t a = md5->abcd[0]; + uint32_t b = md5->abcd[1]; + uint32_t c = md5->abcd[2]; + uint32_t d = md5->abcd[3]; + uint32_t t; + +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + uint32_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + uint32_t xbuf[16]; + const uint32_t *X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const uint8_t *) &w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const uint8_t *) 0) & 3)) { +/* data are properly aligned */ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-align" +#endif + X = (const uint32_t *) data; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } else { + /* not aligned */ + memcpy (xbuf, data, sizeof (xbuf)); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const uint8_t *xp = data; + int i; + +#if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +#else +#define xbuf X /* (static only) */ +#endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +/* Round 1. */ +/* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + F (b, c, d) + X[k] + Ti; \ + a = ROTATE_LEFT (t, s) + b + /* Do the following 16 operations. */ + SET (a, b, c, d, 0, 7, T1); + SET (d, a, b, c, 1, 12, T2); + SET (c, d, a, b, 2, 17, T3); + SET (b, c, d, a, 3, 22, T4); + SET (a, b, c, d, 4, 7, T5); + SET (d, a, b, c, 5, 12, T6); + SET (c, d, a, b, 6, 17, T7); + SET (b, c, d, a, 7, 22, T8); + SET (a, b, c, d, 8, 7, T9); + SET (d, a, b, c, 9, 12, T10); + SET (c, d, a, b, 10, 17, T11); + SET (b, c, d, a, 11, 22, T12); + SET (a, b, c, d, 12, 7, T13); + SET (d, a, b, c, 13, 12, T14); + SET (c, d, a, b, 14, 17, T15); + SET (b, c, d, a, 15, 22, T16); +#undef SET + +/* Round 2. */ +/* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + G (b, c, d) + X[k] + Ti; \ + a = ROTATE_LEFT (t, s) + b + /* Do the following 16 operations. */ + SET (a, b, c, d, 1, 5, T17); + SET (d, a, b, c, 6, 9, T18); + SET (c, d, a, b, 11, 14, T19); + SET (b, c, d, a, 0, 20, T20); + SET (a, b, c, d, 5, 5, T21); + SET (d, a, b, c, 10, 9, T22); + SET (c, d, a, b, 15, 14, T23); + SET (b, c, d, a, 4, 20, T24); + SET (a, b, c, d, 9, 5, T25); + SET (d, a, b, c, 14, 9, T26); + SET (c, d, a, b, 3, 14, T27); + SET (b, c, d, a, 8, 20, T28); + SET (a, b, c, d, 13, 5, T29); + SET (d, a, b, c, 2, 9, T30); + SET (c, d, a, b, 7, 14, T31); + SET (b, c, d, a, 12, 20, T32); +#undef SET + +/* Round 3. */ +/* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + H (b, c, d) + X[k] + Ti; \ + a = ROTATE_LEFT (t, s) + b + /* Do the following 16 operations. */ + SET (a, b, c, d, 5, 4, T33); + SET (d, a, b, c, 8, 11, T34); + SET (c, d, a, b, 11, 16, T35); + SET (b, c, d, a, 14, 23, T36); + SET (a, b, c, d, 1, 4, T37); + SET (d, a, b, c, 4, 11, T38); + SET (c, d, a, b, 7, 16, T39); + SET (b, c, d, a, 10, 23, T40); + SET (a, b, c, d, 13, 4, T41); + SET (d, a, b, c, 0, 11, T42); + SET (c, d, a, b, 3, 16, T43); + SET (b, c, d, a, 6, 23, T44); + SET (a, b, c, d, 9, 4, T45); + SET (d, a, b, c, 12, 11, T46); + SET (c, d, a, b, 15, 16, T47); + SET (b, c, d, a, 2, 23, T48); +#undef SET + +/* Round 4. */ +/* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + I (b, c, d) + X[k] + Ti; \ + a = ROTATE_LEFT (t, s) + b + /* Do the following 16 operations. */ + SET (a, b, c, d, 0, 6, T49); + SET (d, a, b, c, 7, 10, T50); + SET (c, d, a, b, 14, 15, T51); + SET (b, c, d, a, 5, 21, T52); + SET (a, b, c, d, 12, 6, T53); + SET (d, a, b, c, 3, 10, T54); + SET (c, d, a, b, 10, 15, T55); + SET (b, c, d, a, 1, 21, T56); + SET (a, b, c, d, 8, 6, T57); + SET (d, a, b, c, 15, 10, T58); + SET (c, d, a, b, 6, 15, T59); + SET (b, c, d, a, 13, 21, T60); + SET (a, b, c, d, 4, 6, T61); + SET (d, a, b, c, 11, 10, T62); + SET (c, d, a, b, 2, 15, T63); + SET (b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + md5->abcd[0] += a; + md5->abcd[1] += b; + md5->abcd[2] += c; + md5->abcd[3] += d; +} + +void +bson_md5_init (bson_md5_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +bson_md5_append (bson_md5_t *pms, const uint8_t *data, uint32_t nbytes) +{ + const uint8_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + uint32_t nbits = (uint32_t) (nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy (pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + bson_md5_process (pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + bson_md5_process (pms, p); + + /* Process a final partial block. */ + if (left) + memcpy (pms->buf, p, left); +} + +void +bson_md5_finish (bson_md5_t *pms, uint8_t digest[16]) +{ + static const uint8_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (uint8_t) (pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + bson_md5_append (pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + bson_md5_append (pms, data, sizeof (data)); + for (i = 0; i < 16; ++i) + digest[i] = (uint8_t) (pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-md5.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-md5.h new file mode 100644 index 0000000000000000000000000000000000000000..f7f4f66bc1b73bb83022bb61a607c77f98c6ab16 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-md5.h @@ -0,0 +1,90 @@ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + <ghost@aladdin.com>. Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke <purschke@bnl.gov>. + 1999-05-03 lpd Original version. + */ + + +/* + * The following MD5 implementation has been modified to use types as + * specified in libbson. + */ + + +#ifndef BSON_MD5_H +#define BSON_MD5_H + + +#if !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) +#error "Only <bson.h> can be included directly." +#endif + + +#include "bson-endian.h" + + +BSON_BEGIN_DECLS + + +typedef struct { + uint32_t count[2]; /* message length in bits, lsw first */ + uint32_t abcd[4]; /* digest buffer */ + uint8_t buf[64]; /* accumulate block */ +} bson_md5_t; + + +BSON_EXPORT (void) +bson_md5_init (bson_md5_t *pms); +BSON_EXPORT (void) +bson_md5_append (bson_md5_t *pms, const uint8_t *data, uint32_t nbytes); +BSON_EXPORT (void) +bson_md5_finish (bson_md5_t *pms, uint8_t digest[16]); + + +BSON_END_DECLS + + +#endif /* BSON_MD5_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-memory.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-memory.c new file mode 100644 index 0000000000000000000000000000000000000000..9b1b49e8ab3cb112b1e07cbaa50def72de5cbf04 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-memory.c @@ -0,0 +1,306 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include <stdlib.h> +#include <string.h> + +#include "bson-atomic.h" +#include "bson-config.h" +#include "bson-memory.h" + + +static bson_mem_vtable_t gMemVtable = { + malloc, + calloc, +#ifdef BSON_HAVE_REALLOCF + reallocf, +#else + realloc, +#endif + free, +}; + + +/* + *-------------------------------------------------------------------------- + * + * bson_malloc -- + * + * Allocates @num_bytes of memory and returns a pointer to it. If + * malloc failed to allocate the memory, abort() is called. + * + * Libbson does not try to handle OOM conditions as it is beyond the + * scope of this library to handle so appropriately. + * + * Parameters: + * @num_bytes: The number of bytes to allocate. + * + * Returns: + * A pointer if successful; otherwise abort() is called and this + * function will never return. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void * +bson_malloc (size_t num_bytes) /* IN */ +{ + void *mem = NULL; + + if (BSON_LIKELY (num_bytes)) { + if (BSON_UNLIKELY (!(mem = gMemVtable.malloc (num_bytes)))) { + abort (); + } + } + + return mem; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_malloc0 -- + * + * Like bson_malloc() except the memory is zeroed first. This is + * similar to calloc() except that abort() is called in case of + * failure to allocate memory. + * + * Parameters: + * @num_bytes: The number of bytes to allocate. + * + * Returns: + * A pointer if successful; otherwise abort() is called and this + * function will never return. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void * +bson_malloc0 (size_t num_bytes) /* IN */ +{ + void *mem = NULL; + + if (BSON_LIKELY (num_bytes)) { + if (BSON_UNLIKELY (!(mem = gMemVtable.calloc (1, num_bytes)))) { + abort (); + } + } + + return mem; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_realloc -- + * + * This function behaves similar to realloc() except that if there is + * a failure abort() is called. + * + * Parameters: + * @mem: The memory to realloc, or NULL. + * @num_bytes: The size of the new allocation or 0 to free. + * + * Returns: + * The new allocation if successful; otherwise abort() is called and + * this function never returns. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void * +bson_realloc (void *mem, /* IN */ + size_t num_bytes) /* IN */ +{ + /* + * Not all platforms are guaranteed to free() the memory if a call to + * realloc() with a size of zero occurs. Windows, Linux, and FreeBSD do, + * however, OS X does not. + */ + if (BSON_UNLIKELY (num_bytes == 0)) { + gMemVtable.free (mem); + return NULL; + } + + mem = gMemVtable.realloc (mem, num_bytes); + + if (BSON_UNLIKELY (!mem)) { + abort (); + } + + return mem; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_realloc_ctx -- + * + * This wraps bson_realloc and provides a compatible api for similar + * functions with a context + * + * Parameters: + * @mem: The memory to realloc, or NULL. + * @num_bytes: The size of the new allocation or 0 to free. + * @ctx: Ignored + * + * Returns: + * The new allocation if successful; otherwise abort() is called and + * this function never returns. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + + +void * +bson_realloc_ctx (void *mem, /* IN */ + size_t num_bytes, /* IN */ + void *ctx) /* IN */ +{ + return bson_realloc (mem, num_bytes); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_free -- + * + * Frees @mem using the underlying allocator. + * + * Currently, this only calls free() directly, but that is subject to + * change. + * + * Parameters: + * @mem: An allocation to free. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_free (void *mem) /* IN */ +{ + gMemVtable.free (mem); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_zero_free -- + * + * Frees @mem using the underlying allocator. @size bytes of @mem will + * be zeroed before freeing the memory. This is useful in scenarios + * where @mem contains passwords or other sensitive information. + * + * Parameters: + * @mem: An allocation to free. + * @size: The number of bytes in @mem. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_zero_free (void *mem, /* IN */ + size_t size) /* IN */ +{ + if (BSON_LIKELY (mem)) { + memset (mem, 0, size); + gMemVtable.free (mem); + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_mem_set_vtable -- + * + * This function will change our allocationt vtable. + * + * It is imperitive that this is called at the beginning of the + * process before any memory has been allocated by the default + * allocator. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_mem_set_vtable (const bson_mem_vtable_t *vtable) +{ + BSON_ASSERT (vtable); + + if (!vtable->malloc || !vtable->calloc || !vtable->realloc || + !vtable->free) { + fprintf (stderr, + "Failure to install BSON vtable, " + "missing functions.\n"); + return; + } + + gMemVtable = *vtable; +} + +void +bson_mem_restore_vtable (void) +{ + bson_mem_vtable_t vtable = { + malloc, + calloc, +#ifdef BSON_HAVE_REALLOCF + reallocf, +#else + realloc, +#endif + free, + }; + + bson_mem_set_vtable (&vtable); +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-memory.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-memory.h new file mode 100644 index 0000000000000000000000000000000000000000..5a06dfb14594b5a37cb6dc5045f8e01ca957e61c --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-memory.h @@ -0,0 +1,61 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_MEMORY_H +#define BSON_MEMORY_H + +#include "bson-macros.h" +#include "bson-types.h" + + +BSON_BEGIN_DECLS + + +typedef void *(*bson_realloc_func) (void *mem, size_t num_bytes, void *ctx); + + +typedef struct _bson_mem_vtable_t { + void *(*malloc) (size_t num_bytes); + void *(*calloc) (size_t n_members, size_t num_bytes); + void *(*realloc) (void *mem, size_t num_bytes); + void (*free) (void *mem); + void *padding[4]; +} bson_mem_vtable_t; + + +BSON_EXPORT (void) +bson_mem_set_vtable (const bson_mem_vtable_t *vtable); +BSON_EXPORT (void) +bson_mem_restore_vtable (void); +BSON_EXPORT (void *) +bson_malloc (size_t num_bytes); +BSON_EXPORT (void *) +bson_malloc0 (size_t num_bytes); +BSON_EXPORT (void *) +bson_realloc (void *mem, size_t num_bytes); +BSON_EXPORT (void *) +bson_realloc_ctx (void *mem, size_t num_bytes, void *ctx); +BSON_EXPORT (void) +bson_free (void *mem); +BSON_EXPORT (void) +bson_zero_free (void *mem, size_t size); + + +BSON_END_DECLS + + +#endif /* BSON_MEMORY_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-oid.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-oid.c new file mode 100644 index 0000000000000000000000000000000000000000..bdd10a181ae58a4069cd90c655020e4e3448cb19 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-oid.c @@ -0,0 +1,517 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bson-compat.h" + +#include <limits.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include "bson-context-private.h" +#include "bson-md5.h" +#include "bson-oid.h" +#include "bson-string.h" + + +/* + * This table contains an array of two character pairs for every possible + * uint8_t. It is used as a lookup table when encoding a bson_oid_t + * to hex formatted ASCII. Performing two characters at a time roughly + * reduces the number of operations by one-half. + */ +static const uint16_t gHexCharPairs[] = { +#if BSON_BYTE_ORDER == BSON_BIG_ENDIAN + 12336, 12337, 12338, 12339, 12340, 12341, 12342, 12343, 12344, 12345, 12385, + 12386, 12387, 12388, 12389, 12390, 12592, 12593, 12594, 12595, 12596, 12597, + 12598, 12599, 12600, 12601, 12641, 12642, 12643, 12644, 12645, 12646, 12848, + 12849, 12850, 12851, 12852, 12853, 12854, 12855, 12856, 12857, 12897, 12898, + 12899, 12900, 12901, 12902, 13104, 13105, 13106, 13107, 13108, 13109, 13110, + 13111, 13112, 13113, 13153, 13154, 13155, 13156, 13157, 13158, 13360, 13361, + 13362, 13363, 13364, 13365, 13366, 13367, 13368, 13369, 13409, 13410, 13411, + 13412, 13413, 13414, 13616, 13617, 13618, 13619, 13620, 13621, 13622, 13623, + 13624, 13625, 13665, 13666, 13667, 13668, 13669, 13670, 13872, 13873, 13874, + 13875, 13876, 13877, 13878, 13879, 13880, 13881, 13921, 13922, 13923, 13924, + 13925, 13926, 14128, 14129, 14130, 14131, 14132, 14133, 14134, 14135, 14136, + 14137, 14177, 14178, 14179, 14180, 14181, 14182, 14384, 14385, 14386, 14387, + 14388, 14389, 14390, 14391, 14392, 14393, 14433, 14434, 14435, 14436, 14437, + 14438, 14640, 14641, 14642, 14643, 14644, 14645, 14646, 14647, 14648, 14649, + 14689, 14690, 14691, 14692, 14693, 14694, 24880, 24881, 24882, 24883, 24884, + 24885, 24886, 24887, 24888, 24889, 24929, 24930, 24931, 24932, 24933, 24934, + 25136, 25137, 25138, 25139, 25140, 25141, 25142, 25143, 25144, 25145, 25185, + 25186, 25187, 25188, 25189, 25190, 25392, 25393, 25394, 25395, 25396, 25397, + 25398, 25399, 25400, 25401, 25441, 25442, 25443, 25444, 25445, 25446, 25648, + 25649, 25650, 25651, 25652, 25653, 25654, 25655, 25656, 25657, 25697, 25698, + 25699, 25700, 25701, 25702, 25904, 25905, 25906, 25907, 25908, 25909, 25910, + 25911, 25912, 25913, 25953, 25954, 25955, 25956, 25957, 25958, 26160, 26161, + 26162, 26163, 26164, 26165, 26166, 26167, 26168, 26169, 26209, 26210, 26211, + 26212, 26213, 26214 +#else + 12336, 12592, 12848, 13104, 13360, 13616, 13872, 14128, 14384, 14640, 24880, + 25136, 25392, 25648, 25904, 26160, 12337, 12593, 12849, 13105, 13361, 13617, + 13873, 14129, 14385, 14641, 24881, 25137, 25393, 25649, 25905, 26161, 12338, + 12594, 12850, 13106, 13362, 13618, 13874, 14130, 14386, 14642, 24882, 25138, + 25394, 25650, 25906, 26162, 12339, 12595, 12851, 13107, 13363, 13619, 13875, + 14131, 14387, 14643, 24883, 25139, 25395, 25651, 25907, 26163, 12340, 12596, + 12852, 13108, 13364, 13620, 13876, 14132, 14388, 14644, 24884, 25140, 25396, + 25652, 25908, 26164, 12341, 12597, 12853, 13109, 13365, 13621, 13877, 14133, + 14389, 14645, 24885, 25141, 25397, 25653, 25909, 26165, 12342, 12598, 12854, + 13110, 13366, 13622, 13878, 14134, 14390, 14646, 24886, 25142, 25398, 25654, + 25910, 26166, 12343, 12599, 12855, 13111, 13367, 13623, 13879, 14135, 14391, + 14647, 24887, 25143, 25399, 25655, 25911, 26167, 12344, 12600, 12856, 13112, + 13368, 13624, 13880, 14136, 14392, 14648, 24888, 25144, 25400, 25656, 25912, + 26168, 12345, 12601, 12857, 13113, 13369, 13625, 13881, 14137, 14393, 14649, + 24889, 25145, 25401, 25657, 25913, 26169, 12385, 12641, 12897, 13153, 13409, + 13665, 13921, 14177, 14433, 14689, 24929, 25185, 25441, 25697, 25953, 26209, + 12386, 12642, 12898, 13154, 13410, 13666, 13922, 14178, 14434, 14690, 24930, + 25186, 25442, 25698, 25954, 26210, 12387, 12643, 12899, 13155, 13411, 13667, + 13923, 14179, 14435, 14691, 24931, 25187, 25443, 25699, 25955, 26211, 12388, + 12644, 12900, 13156, 13412, 13668, 13924, 14180, 14436, 14692, 24932, 25188, + 25444, 25700, 25956, 26212, 12389, 12645, 12901, 13157, 13413, 13669, 13925, + 14181, 14437, 14693, 24933, 25189, 25445, 25701, 25957, 26213, 12390, 12646, + 12902, 13158, 13414, 13670, 13926, 14182, 14438, 14694, 24934, 25190, 25446, + 25702, 25958, 26214 +#endif +}; + + +/* + *-------------------------------------------------------------------------- + * + * bson_oid_init_sequence -- + * + * Initializes @oid with the next oid in the sequence. The first 4 + * bytes contain the current time and the following 8 contain a 64-bit + * integer in big-endian format. + * + * The bson_oid_t generated by this function is not guaranteed to be + * globally unique. Only unique within this context. It is however, + * guaranteed to be sequential. + * + * Returns: + * None. + * + * Side effects: + * @oid is initialized. + * + *-------------------------------------------------------------------------- + */ + +void +bson_oid_init_sequence (bson_oid_t *oid, /* OUT */ + bson_context_t *context) /* IN */ +{ + uint32_t now = (uint32_t) (time (NULL)); + + if (!context) { + context = bson_context_get_default (); + } + + now = BSON_UINT32_TO_BE (now); + + memcpy (&oid->bytes[0], &now, sizeof (now)); + context->oid_get_seq64 (context, oid); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_oid_init -- + * + * Generates bytes for a new bson_oid_t and stores them in @oid. The + * bytes will be generated according to the specification and includes + * the current time, first 3 bytes of MD5(hostname), pid (or tid), and + * monotonic counter. + * + * The bson_oid_t generated by this function is not guaranteed to be + * globally unique. Only unique within this context. It is however, + * guaranteed to be sequential. + * + * Returns: + * None. + * + * Side effects: + * @oid is initialized. + * + *-------------------------------------------------------------------------- + */ + +void +bson_oid_init (bson_oid_t *oid, /* OUT */ + bson_context_t *context) /* IN */ +{ + uint32_t now = (uint32_t) (time (NULL)); + + BSON_ASSERT (oid); + + if (!context) { + context = bson_context_get_default (); + } + + now = BSON_UINT32_TO_BE (now); + memcpy (&oid->bytes[0], &now, sizeof (now)); + + context->oid_get_host (context, oid); + context->oid_get_pid (context, oid); + context->oid_get_seq32 (context, oid); +} + + +/** + * bson_oid_init_from_data: + * @oid: A bson_oid_t to initialize. + * @bytes: A 12-byte buffer to copy into @oid. + * + */ +/* + *-------------------------------------------------------------------------- + * + * bson_oid_init_from_data -- + * + * Initializes an @oid from @data. @data MUST be a buffer of at least + * 12 bytes. This method is analagous to memcpy()'ing data into @oid. + * + * Returns: + * None. + * + * Side effects: + * @oid is initialized. + * + *-------------------------------------------------------------------------- + */ + +void +bson_oid_init_from_data (bson_oid_t *oid, /* OUT */ + const uint8_t *data) /* IN */ +{ + BSON_ASSERT (oid); + BSON_ASSERT (data); + + memcpy (oid, data, 12); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_oid_init_from_string -- + * + * Parses @str containing hex formatted bytes of an object id and + * places the bytes in @oid. + * + * Parameters: + * @oid: A bson_oid_t + * @str: A string containing at least 24 characters. + * + * Returns: + * None. + * + * Side effects: + * @oid is initialized. + * + *-------------------------------------------------------------------------- + */ + +void +bson_oid_init_from_string (bson_oid_t *oid, /* OUT */ + const char *str) /* IN */ +{ + BSON_ASSERT (oid); + BSON_ASSERT (str); + + bson_oid_init_from_string_unsafe (oid, str); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_oid_get_time_t -- + * + * Fetches the time for which @oid was created. + * + * Returns: + * A time_t. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +time_t +bson_oid_get_time_t (const bson_oid_t *oid) /* IN */ +{ + BSON_ASSERT (oid); + + return bson_oid_get_time_t_unsafe (oid); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_oid_to_string -- + * + * Formats a bson_oid_t into a string. @str must contain enough bytes + * for the resulting string which is 25 bytes with a terminating + * NUL-byte. + * + * Parameters: + * @oid: A bson_oid_t. + * @str: A location to store the resulting string. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_oid_to_string (const bson_oid_t *oid, /* IN */ + char str[BSON_ENSURE_ARRAY_PARAM_SIZE (25)]) /* OUT */ +{ +#if !defined(__i386__) && !defined(__x86_64__) && !defined(_M_IX86) && \ + !defined(_M_X64) + BSON_ASSERT (oid); + BSON_ASSERT (str); + + bson_snprintf (str, + 25, + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + oid->bytes[0], + oid->bytes[1], + oid->bytes[2], + oid->bytes[3], + oid->bytes[4], + oid->bytes[5], + oid->bytes[6], + oid->bytes[7], + oid->bytes[8], + oid->bytes[9], + oid->bytes[10], + oid->bytes[11]); +#else + uint16_t *dst; + uint8_t *id = (uint8_t *) oid; + + BSON_ASSERT (oid); + BSON_ASSERT (str); + + dst = (uint16_t *) (void *) str; + dst[0] = gHexCharPairs[id[0]]; + dst[1] = gHexCharPairs[id[1]]; + dst[2] = gHexCharPairs[id[2]]; + dst[3] = gHexCharPairs[id[3]]; + dst[4] = gHexCharPairs[id[4]]; + dst[5] = gHexCharPairs[id[5]]; + dst[6] = gHexCharPairs[id[6]]; + dst[7] = gHexCharPairs[id[7]]; + dst[8] = gHexCharPairs[id[8]]; + dst[9] = gHexCharPairs[id[9]]; + dst[10] = gHexCharPairs[id[10]]; + dst[11] = gHexCharPairs[id[11]]; + str[24] = '\0'; +#endif +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_oid_hash -- + * + * Hashes the bytes of the provided bson_oid_t using DJB hash. This + * allows bson_oid_t to be used as keys in a hash table. + * + * Returns: + * A hash value corresponding to @oid. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +uint32_t +bson_oid_hash (const bson_oid_t *oid) /* IN */ +{ + BSON_ASSERT (oid); + + return bson_oid_hash_unsafe (oid); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_oid_compare -- + * + * A qsort() style compare function that will return less than zero if + * @oid1 is less than @oid2, zero if they are the same, and greater + * than zero if @oid2 is greater than @oid1. + * + * Returns: + * A qsort() style compare integer. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +int +bson_oid_compare (const bson_oid_t *oid1, /* IN */ + const bson_oid_t *oid2) /* IN */ +{ + BSON_ASSERT (oid1); + BSON_ASSERT (oid2); + + return bson_oid_compare_unsafe (oid1, oid2); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_oid_equal -- + * + * Compares for equality of @oid1 and @oid2. If they are equal, then + * true is returned, otherwise false. + * + * Returns: + * A boolean indicating the equality of @oid1 and @oid2. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_oid_equal (const bson_oid_t *oid1, /* IN */ + const bson_oid_t *oid2) /* IN */ +{ + BSON_ASSERT (oid1); + BSON_ASSERT (oid2); + + return bson_oid_equal_unsafe (oid1, oid2); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_oid_copy -- + * + * Copies the contents of @src to @dst. + * + * Parameters: + * @src: A bson_oid_t to copy from. + * @dst: A bson_oid_t to copy to. + * + * Returns: + * None. + * + * Side effects: + * @dst will contain a copy of the data in @src. + * + *-------------------------------------------------------------------------- + */ + +void +bson_oid_copy (const bson_oid_t *src, /* IN */ + bson_oid_t *dst) /* OUT */ +{ + BSON_ASSERT (src); + BSON_ASSERT (dst); + + bson_oid_copy_unsafe (src, dst); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_oid_is_valid -- + * + * Validates that @str is a valid OID string. @length MUST be 24, but + * is provided as a parameter to simplify calling code. + * + * Parameters: + * @str: A string to validate. + * @length: The length of @str. + * + * Returns: + * true if @str can be passed to bson_oid_init_from_string(). + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_oid_is_valid (const char *str, /* IN */ + size_t length) /* IN */ +{ + size_t i; + + BSON_ASSERT (str); + + if ((length == 25) && (str[24] == '\0')) { + length = 24; + } + + if (length == 24) { + for (i = 0; i < length; i++) { + switch (str[i]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + break; + default: + return false; + } + } + return true; + } + + return false; +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-oid.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-oid.h new file mode 100644 index 0000000000000000000000000000000000000000..1281601179685a0e8d3deab5e09ddd4a10e79cb1 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-oid.h @@ -0,0 +1,246 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_OID_H +#define BSON_OID_H + + +#if !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) +#error "Only <bson.h> can be included directly." +#endif + + +#include <time.h> + +#include "bson-context.h" +#include "bson-macros.h" +#include "bson-types.h" +#include "bson-endian.h" + + +BSON_BEGIN_DECLS + + +BSON_EXPORT (int) +bson_oid_compare (const bson_oid_t *oid1, const bson_oid_t *oid2); +BSON_EXPORT (void) +bson_oid_copy (const bson_oid_t *src, bson_oid_t *dst); +BSON_EXPORT (bool) +bson_oid_equal (const bson_oid_t *oid1, const bson_oid_t *oid2); +BSON_EXPORT (bool) +bson_oid_is_valid (const char *str, size_t length); +BSON_EXPORT (time_t) +bson_oid_get_time_t (const bson_oid_t *oid); +BSON_EXPORT (uint32_t) +bson_oid_hash (const bson_oid_t *oid); +BSON_EXPORT (void) +bson_oid_init (bson_oid_t *oid, bson_context_t *context); +BSON_EXPORT (void) +bson_oid_init_from_data (bson_oid_t *oid, const uint8_t *data); +BSON_EXPORT (void) +bson_oid_init_from_string (bson_oid_t *oid, const char *str); +BSON_EXPORT (void) +bson_oid_init_sequence (bson_oid_t *oid, bson_context_t *context); +BSON_EXPORT (void) +bson_oid_to_string (const bson_oid_t *oid, char str[25]); + + +/** + * bson_oid_compare_unsafe: + * @oid1: A bson_oid_t. + * @oid2: A bson_oid_t. + * + * Performs a qsort() style comparison between @oid1 and @oid2. + * + * This function is meant to be as fast as possible and therefore performs + * no argument validation. That is the callers responsibility. + * + * Returns: An integer < 0 if @oid1 is less than @oid2. Zero if they are equal. + * An integer > 0 if @oid1 is greater than @oid2. + */ +static BSON_INLINE int +bson_oid_compare_unsafe (const bson_oid_t *oid1, const bson_oid_t *oid2) +{ + return memcmp (oid1, oid2, sizeof *oid1); +} + + +/** + * bson_oid_equal_unsafe: + * @oid1: A bson_oid_t. + * @oid2: A bson_oid_t. + * + * Checks the equality of @oid1 and @oid2. + * + * This function is meant to be as fast as possible and therefore performs + * no checks for argument validity. That is the callers responsibility. + * + * Returns: true if @oid1 and @oid2 are equal; otherwise false. + */ +static BSON_INLINE bool +bson_oid_equal_unsafe (const bson_oid_t *oid1, const bson_oid_t *oid2) +{ + return !memcmp (oid1, oid2, sizeof *oid1); +} + +/** + * bson_oid_hash_unsafe: + * @oid: A bson_oid_t. + * + * This function performs a DJB style hash upon the bytes contained in @oid. + * The result is a hash key suitable for use in a hashtable. + * + * This function is meant to be as fast as possible and therefore performs no + * validation of arguments. The caller is responsible to ensure they are + * passing valid arguments. + * + * Returns: A uint32_t containing a hash code. + */ +static BSON_INLINE uint32_t +bson_oid_hash_unsafe (const bson_oid_t *oid) +{ + uint32_t hash = 5381; + uint32_t i; + + for (i = 0; i < sizeof oid->bytes; i++) { + hash = ((hash << 5) + hash) + oid->bytes[i]; + } + + return hash; +} + + +/** + * bson_oid_copy_unsafe: + * @src: A bson_oid_t to copy from. + * @dst: A bson_oid_t to copy into. + * + * Copies the contents of @src into @dst. This function is meant to be as + * fast as possible and therefore performs no argument checking. It is the + * callers responsibility to ensure they are passing valid data into the + * function. + */ +static BSON_INLINE void +bson_oid_copy_unsafe (const bson_oid_t *src, bson_oid_t *dst) +{ + memcpy (dst, src, sizeof *src); +} + + +/** + * bson_oid_parse_hex_char: + * @hex: A character to parse to its integer value. + * + * This function contains a jump table to return the integer value for a + * character containing a hexidecimal value (0-9, a-f, A-F). If the character + * is not a hexidecimal character then zero is returned. + * + * Returns: An integer between 0 and 15. + */ +static BSON_INLINE uint8_t +bson_oid_parse_hex_char (char hex) +{ + switch (hex) { + case '0': + return 0; + case '1': + return 1; + case '2': + return 2; + case '3': + return 3; + case '4': + return 4; + case '5': + return 5; + case '6': + return 6; + case '7': + return 7; + case '8': + return 8; + case '9': + return 9; + case 'a': + case 'A': + return 0xa; + case 'b': + case 'B': + return 0xb; + case 'c': + case 'C': + return 0xc; + case 'd': + case 'D': + return 0xd; + case 'e': + case 'E': + return 0xe; + case 'f': + case 'F': + return 0xf; + default: + return 0; + } +} + + +/** + * bson_oid_init_from_string_unsafe: + * @oid: A bson_oid_t to store the result. + * @str: A 24-character hexidecimal encoded string. + * + * Parses a string containing 24 hexidecimal encoded bytes into a bson_oid_t. + * This function is meant to be as fast as possible and inlined into your + * code. For that purpose, the function does not perform any sort of bounds + * checking and it is the callers responsibility to ensure they are passing + * valid input to the function. + */ +static BSON_INLINE void +bson_oid_init_from_string_unsafe (bson_oid_t *oid, const char *str) +{ + int i; + + for (i = 0; i < 12; i++) { + oid->bytes[i] = ((bson_oid_parse_hex_char (str[2 * i]) << 4) | + (bson_oid_parse_hex_char (str[2 * i + 1]))); + } +} + + +/** + * bson_oid_get_time_t_unsafe: + * @oid: A bson_oid_t. + * + * Fetches the time @oid was generated. + * + * Returns: A time_t containing the UNIX timestamp of generation. + */ +static BSON_INLINE time_t +bson_oid_get_time_t_unsafe (const bson_oid_t *oid) +{ + uint32_t t; + + memcpy (&t, oid, sizeof (t)); + return BSON_UINT32_FROM_BE (t); +} + + +BSON_END_DECLS + + +#endif /* BSON_OID_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-private.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-private.h new file mode 100644 index 0000000000000000000000000000000000000000..00267f240f520bcff69f9e31de504564b6a2f7de --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-private.h @@ -0,0 +1,92 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_PRIVATE_H +#define BSON_PRIVATE_H + + +#include "bson-macros.h" +#include "bson-memory.h" +#include "bson-types.h" + + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#define BEGIN_IGNORE_DEPRECATIONS \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#define END_IGNORE_DEPRECATIONS _Pragma ("GCC diagnostic pop") +#elif defined(__clang__) +#define BEGIN_IGNORE_DEPRECATIONS \ + _Pragma ("clang diagnostic push") \ + _Pragma ("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#define END_IGNORE_DEPRECATIONS _Pragma ("clang diagnostic pop") +#else +#define BEGIN_IGNORE_DEPRECATIONS +#define END_IGNORE_DEPRECATIONS +#endif + + +BSON_BEGIN_DECLS + + +typedef enum { + BSON_FLAG_NONE = 0, + BSON_FLAG_INLINE = (1 << 0), + BSON_FLAG_STATIC = (1 << 1), + BSON_FLAG_RDONLY = (1 << 2), + BSON_FLAG_CHILD = (1 << 3), + BSON_FLAG_IN_CHILD = (1 << 4), + BSON_FLAG_NO_FREE = (1 << 5), +} bson_flags_t; + + +#define BSON_INLINE_DATA_SIZE 120 + +BSON_ALIGNED_BEGIN (128) +typedef struct { + bson_flags_t flags; + uint32_t len; + uint8_t data[BSON_INLINE_DATA_SIZE]; +} bson_impl_inline_t BSON_ALIGNED_END (128); + + +BSON_STATIC_ASSERT (sizeof (bson_impl_inline_t) == 128); + + +BSON_ALIGNED_BEGIN (128) +typedef struct { + bson_flags_t flags; /* flags describing the bson_t */ + uint32_t len; /* length of bson document in bytes */ + bson_t *parent; /* parent bson if a child */ + uint32_t depth; /* Subdocument depth. */ + uint8_t **buf; /* pointer to buffer pointer */ + size_t *buflen; /* pointer to buffer length */ + size_t offset; /* our offset inside *buf */ + uint8_t *alloc; /* buffer that we own. */ + size_t alloclen; /* length of buffer that we own. */ + bson_realloc_func realloc; /* our realloc implementation */ + void *realloc_func_ctx; /* context for our realloc func */ +} bson_impl_alloc_t BSON_ALIGNED_END (128); + + +BSON_STATIC_ASSERT (sizeof (bson_impl_alloc_t) <= 128); + + +BSON_END_DECLS + + +#endif /* BSON_PRIVATE_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-reader.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-reader.c new file mode 100644 index 0000000000000000000000000000000000000000..8045254f04cae7e16c310c904ce999393ec1a3bc --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-reader.c @@ -0,0 +1,832 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bson.h" + +#include <errno.h> +#include <fcntl.h> +#ifdef BSON_OS_WIN32 +#include <io.h> +#include <share.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "bson-reader.h" +#include "bson-memory.h" + + +typedef enum { + BSON_READER_HANDLE = 1, + BSON_READER_DATA = 2, +} bson_reader_type_t; + + +typedef struct { + bson_reader_type_t type; + void *handle; + bool done : 1; + bool failed : 1; + size_t end; + size_t len; + size_t offset; + size_t bytes_read; + bson_t inline_bson; + uint8_t *data; + bson_reader_read_func_t read_func; + bson_reader_destroy_func_t destroy_func; +} bson_reader_handle_t; + + +typedef struct { + int fd; + bool do_close; +} bson_reader_handle_fd_t; + + +typedef struct { + bson_reader_type_t type; + const uint8_t *data; + size_t length; + size_t offset; + bson_t inline_bson; +} bson_reader_data_t; + + +/* + *-------------------------------------------------------------------------- + * + * _bson_reader_handle_fill_buffer -- + * + * Attempt to read as much as possible until the underlying buffer + * in @reader is filled or we have reached end-of-stream or + * read failure. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static void +_bson_reader_handle_fill_buffer (bson_reader_handle_t *reader) /* IN */ +{ + ssize_t ret; + + /* + * Handle first read specially. + */ + if ((!reader->done) && (!reader->offset) && (!reader->end)) { + ret = reader->read_func (reader->handle, &reader->data[0], reader->len); + + if (ret <= 0) { + reader->done = true; + return; + } + reader->bytes_read += ret; + + reader->end = ret; + return; + } + + /* + * Move valid data to head. + */ + memmove (&reader->data[0], + &reader->data[reader->offset], + reader->end - reader->offset); + reader->end = reader->end - reader->offset; + reader->offset = 0; + + /* + * Read in data to fill the buffer. + */ + ret = reader->read_func ( + reader->handle, &reader->data[reader->end], reader->len - reader->end); + + if (ret <= 0) { + reader->done = true; + reader->failed = (ret < 0); + } else { + reader->bytes_read += ret; + reader->end += ret; + } + + BSON_ASSERT (reader->offset == 0); + BSON_ASSERT (reader->end <= reader->len); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_reader_new_from_handle -- + * + * Allocates and initializes a new bson_reader_t using the opaque + * handle provided. + * + * Parameters: + * @handle: an opaque handle to use to read data. + * @rf: a function to perform reads on @handle. + * @df: a function to release @handle, or NULL. + * + * Returns: + * A newly allocated bson_reader_t if successful, otherwise NULL. + * Free the successful result with bson_reader_destroy(). + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bson_reader_t * +bson_reader_new_from_handle (void *handle, + bson_reader_read_func_t rf, + bson_reader_destroy_func_t df) +{ + bson_reader_handle_t *real; + + BSON_ASSERT (handle); + BSON_ASSERT (rf); + + real = bson_malloc0 (sizeof *real); + real->type = BSON_READER_HANDLE; + real->data = bson_malloc0 (1024); + real->handle = handle; + real->len = 1024; + real->offset = 0; + + bson_reader_set_read_func ((bson_reader_t *) real, rf); + + if (df) { + bson_reader_set_destroy_func ((bson_reader_t *) real, df); + } + + _bson_reader_handle_fill_buffer (real); + + return (bson_reader_t *) real; +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_reader_handle_fd_destroy -- + * + * Cleanup allocations associated with state created in + * bson_reader_new_from_fd(). + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static void +_bson_reader_handle_fd_destroy (void *handle) /* IN */ +{ + bson_reader_handle_fd_t *fd = handle; + + if (fd) { + if ((fd->fd != -1) && fd->do_close) { +#ifdef _WIN32 + _close (fd->fd); +#else + close (fd->fd); +#endif + } + bson_free (fd); + } +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_reader_handle_fd_read -- + * + * Perform read on opaque handle created in + * bson_reader_new_from_fd(). + * + * The underlying file descriptor is read from the current position + * using the bson_reader_handle_fd_t allocated. + * + * Returns: + * -1 on failure. + * 0 on end of stream. + * Greater than zero on success. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static ssize_t +_bson_reader_handle_fd_read (void *handle, /* IN */ + void *buf, /* IN */ + size_t len) /* IN */ +{ + bson_reader_handle_fd_t *fd = handle; + ssize_t ret = -1; + + if (fd && (fd->fd != -1)) { + again: +#ifdef BSON_OS_WIN32 + ret = _read (fd->fd, buf, (unsigned int) len); +#else + ret = read (fd->fd, buf, len); +#endif + if ((ret == -1) && (errno == EAGAIN)) { + goto again; + } + } + + return ret; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_reader_new_from_fd -- + * + * Create a new bson_reader_t using the file-descriptor provided. + * + * Parameters: + * @fd: a libc style file-descriptor. + * @close_on_destroy: if close() should be called on @fd when + * bson_reader_destroy() is called. + * + * Returns: + * A newly allocated bson_reader_t on success; otherwise NULL. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bson_reader_t * +bson_reader_new_from_fd (int fd, /* IN */ + bool close_on_destroy) /* IN */ +{ + bson_reader_handle_fd_t *handle; + + BSON_ASSERT (fd != -1); + + handle = bson_malloc0 (sizeof *handle); + handle->fd = fd; + handle->do_close = close_on_destroy; + + return bson_reader_new_from_handle ( + handle, _bson_reader_handle_fd_read, _bson_reader_handle_fd_destroy); +} + + +/** + * bson_reader_set_read_func: + * @reader: A bson_reader_t. + * + * Note that @reader must be initialized by bson_reader_init_from_handle(), or + * data + * will be destroyed. + */ +/* + *-------------------------------------------------------------------------- + * + * bson_reader_set_read_func -- + * + * Set the read func to be provided for @reader. + * + * You probably want to use bson_reader_new_from_handle() or + * bson_reader_new_from_fd() instead. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_reader_set_read_func (bson_reader_t *reader, /* IN */ + bson_reader_read_func_t func) /* IN */ +{ + bson_reader_handle_t *real = (bson_reader_handle_t *) reader; + + BSON_ASSERT (reader->type == BSON_READER_HANDLE); + + real->read_func = func; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_reader_set_destroy_func -- + * + * Set the function to cleanup state when @reader is destroyed. + * + * You probably want bson_reader_new_from_fd() or + * bson_reader_new_from_handle() instead. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_reader_set_destroy_func (bson_reader_t *reader, /* IN */ + bson_reader_destroy_func_t func) /* IN */ +{ + bson_reader_handle_t *real = (bson_reader_handle_t *) reader; + + BSON_ASSERT (reader->type == BSON_READER_HANDLE); + + real->destroy_func = func; +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_reader_handle_grow_buffer -- + * + * Grow the buffer to the next power of two. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static void +_bson_reader_handle_grow_buffer (bson_reader_handle_t *reader) /* IN */ +{ + size_t size; + + size = reader->len * 2; + reader->data = bson_realloc (reader->data, size); + reader->len = size; +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_reader_handle_tell -- + * + * Tell the current position within the underlying file-descriptor. + * + * Returns: + * An off_t containing the current offset. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static off_t +_bson_reader_handle_tell (bson_reader_handle_t *reader) /* IN */ +{ + off_t off; + + off = (off_t) reader->bytes_read; + off -= (off_t) reader->end; + off += (off_t) reader->offset; + + return off; +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_reader_handle_read -- + * + * Read the next chunk of data from the underlying file descriptor + * and return a bson_t which should not be modified. + * + * There was a failure if NULL is returned and @reached_eof is + * not set to true. + * + * Returns: + * NULL on failure or end of stream. + * + * Side effects: + * @reached_eof is set if non-NULL. + * + *-------------------------------------------------------------------------- + */ + +static const bson_t * +_bson_reader_handle_read (bson_reader_handle_t *reader, /* IN */ + bool *reached_eof) /* IN */ +{ + int32_t blen; + + if (reached_eof) { + *reached_eof = false; + } + + while (!reader->done) { + if ((reader->end - reader->offset) < 4) { + _bson_reader_handle_fill_buffer (reader); + continue; + } + + memcpy (&blen, &reader->data[reader->offset], sizeof blen); + blen = BSON_UINT32_FROM_LE (blen); + + if (blen < 5) { + return NULL; + } + + if (blen > (int32_t) (reader->end - reader->offset)) { + if (blen > (int32_t) reader->len) { + _bson_reader_handle_grow_buffer (reader); + } + + _bson_reader_handle_fill_buffer (reader); + continue; + } + + if (!bson_init_static (&reader->inline_bson, + &reader->data[reader->offset], + (uint32_t) blen)) { + return NULL; + } + + reader->offset += blen; + + return &reader->inline_bson; + } + + if (reached_eof) { + *reached_eof = reader->done && !reader->failed; + } + + return NULL; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_reader_new_from_data -- + * + * Allocates and initializes a new bson_reader_t that reads the memory + * provided as a stream of BSON documents. + * + * Parameters: + * @data: A buffer to read BSON documents from. + * @length: The length of @data. + * + * Returns: + * A newly allocated bson_reader_t that should be freed with + * bson_reader_destroy(). + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bson_reader_t * +bson_reader_new_from_data (const uint8_t *data, /* IN */ + size_t length) /* IN */ +{ + bson_reader_data_t *real; + + BSON_ASSERT (data); + + real = (bson_reader_data_t *) bson_malloc0 (sizeof *real); + real->type = BSON_READER_DATA; + real->data = data; + real->length = length; + real->offset = 0; + + return (bson_reader_t *) real; +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_reader_data_read -- + * + * Read the next document from the underlying buffer. + * + * Returns: + * NULL on failure or end of stream. + * a bson_t which should not be modified. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static const bson_t * +_bson_reader_data_read (bson_reader_data_t *reader, /* IN */ + bool *reached_eof) /* IN */ +{ + int32_t blen; + + if (reached_eof) { + *reached_eof = false; + } + + if ((reader->offset + 4) < reader->length) { + memcpy (&blen, &reader->data[reader->offset], sizeof blen); + blen = BSON_UINT32_FROM_LE (blen); + + if (blen < 5) { + return NULL; + } + + if (blen > (int32_t) (reader->length - reader->offset)) { + return NULL; + } + + if (!bson_init_static (&reader->inline_bson, + &reader->data[reader->offset], + (uint32_t) blen)) { + return NULL; + } + + reader->offset += blen; + + return &reader->inline_bson; + } + + if (reached_eof) { + *reached_eof = (reader->offset == reader->length); + } + + return NULL; +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_reader_data_tell -- + * + * Tell the current position in the underlying buffer. + * + * Returns: + * An off_t of the current offset. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static off_t +_bson_reader_data_tell (bson_reader_data_t *reader) /* IN */ +{ + return (off_t) reader->offset; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_reader_destroy -- + * + * Release a bson_reader_t created with bson_reader_new_from_data(), + * bson_reader_new_from_fd(), or bson_reader_new_from_handle(). + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_reader_destroy (bson_reader_t *reader) /* IN */ +{ + BSON_ASSERT (reader); + + switch (reader->type) { + case 0: + break; + case BSON_READER_HANDLE: { + bson_reader_handle_t *handle = (bson_reader_handle_t *) reader; + + if (handle->destroy_func) { + handle->destroy_func (handle->handle); + } + + bson_free (handle->data); + } break; + case BSON_READER_DATA: + break; + default: + fprintf (stderr, "No such reader type: %02x\n", reader->type); + break; + } + + reader->type = 0; + + bson_free (reader); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_reader_read -- + * + * Reads the next bson_t in the underlying memory or storage. The + * resulting bson_t should not be modified or freed. You may copy it + * and iterate over it. Functions that take a const bson_t* are safe + * to use. + * + * This structure does not survive calls to bson_reader_read() or + * bson_reader_destroy() as it uses memory allocated by the reader or + * underlying storage/memory. + * + * If NULL is returned then @reached_eof will be set to true if the + * end of the file or buffer was reached. This indicates if there was + * an error parsing the document stream. + * + * Returns: + * A const bson_t that should not be modified or freed. + * NULL on failure or end of stream. + * + * Side effects: + * @reached_eof is set if non-NULL. + * + *-------------------------------------------------------------------------- + */ + +const bson_t * +bson_reader_read (bson_reader_t *reader, /* IN */ + bool *reached_eof) /* OUT */ +{ + BSON_ASSERT (reader); + + switch (reader->type) { + case BSON_READER_HANDLE: + return _bson_reader_handle_read ((bson_reader_handle_t *) reader, + reached_eof); + + case BSON_READER_DATA: + return _bson_reader_data_read ((bson_reader_data_t *) reader, + reached_eof); + + default: + fprintf (stderr, "No such reader type: %02x\n", reader->type); + break; + } + + return NULL; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_reader_tell -- + * + * Return the current position in the underlying reader. This will + * always be at the beginning of a bson document or end of file. + * + * Returns: + * An off_t containing the current offset. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +off_t +bson_reader_tell (bson_reader_t *reader) /* IN */ +{ + BSON_ASSERT (reader); + + switch (reader->type) { + case BSON_READER_HANDLE: + return _bson_reader_handle_tell ((bson_reader_handle_t *) reader); + + case BSON_READER_DATA: + return _bson_reader_data_tell ((bson_reader_data_t *) reader); + + default: + fprintf (stderr, "No such reader type: %02x\n", reader->type); + return -1; + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_reader_new_from_file -- + * + * A convenience function to open a file containing sequential + * bson documents and read them using bson_reader_t. + * + * Returns: + * A new bson_reader_t if successful, otherwise NULL and + * @error is set. Free the non-NULL result with + * bson_reader_destroy(). + * + * Side effects: + * @error may be set. + * + *-------------------------------------------------------------------------- + */ + +bson_reader_t * +bson_reader_new_from_file (const char *path, /* IN */ + bson_error_t *error) /* OUT */ +{ + char errmsg_buf[BSON_ERROR_BUFFER_SIZE]; + char *errmsg; + int fd; + + BSON_ASSERT (path); + +#ifdef BSON_OS_WIN32 + if (_sopen_s (&fd, path, (_O_RDONLY | _O_BINARY), _SH_DENYNO, 0) != 0) { + fd = -1; + } +#else + fd = open (path, O_RDONLY); +#endif + + if (fd == -1) { + errmsg = bson_strerror_r (errno, errmsg_buf, sizeof errmsg_buf); + bson_set_error ( + error, BSON_ERROR_READER, BSON_ERROR_READER_BADFD, "%s", errmsg); + return NULL; + } + + return bson_reader_new_from_fd (fd, true); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_reader_reset -- + * + * Restore the reader to its initial state. Valid only for readers + * created with bson_reader_new_from_data. + * + *-------------------------------------------------------------------------- + */ + +void +bson_reader_reset (bson_reader_t *reader) +{ + bson_reader_data_t *real = (bson_reader_data_t *) reader; + + if (real->type != BSON_READER_DATA) { + fprintf (stderr, "Reader type cannot be reset\n"); + return; + } + + real->offset = 0; +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-reader.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-reader.h new file mode 100644 index 0000000000000000000000000000000000000000..084ecd10a421fc3f7dc92596f2c9cf551f4c8238 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-reader.h @@ -0,0 +1,120 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_READER_H +#define BSON_READER_H + + +#if !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) +#error "Only <bson.h> can be included directly." +#endif + + +#include "bson-compat.h" +#include "bson-oid.h" +#include "bson-types.h" + + +BSON_BEGIN_DECLS + + +#define BSON_ERROR_READER_BADFD 1 + + +/* + *-------------------------------------------------------------------------- + * + * bson_reader_read_func_t -- + * + * This function is a callback used by bson_reader_t to read the + * next chunk of data from the underlying opaque file descriptor. + * + * This function is meant to operate similar to the read() function + * as part of libc on UNIX-like systems. + * + * Parameters: + * @handle: The handle to read from. + * @buf: The buffer to read into. + * @count: The number of bytes to read. + * + * Returns: + * 0 for end of stream. + * -1 for read failure. + * Greater than zero for number of bytes read into @buf. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +typedef ssize_t (*bson_reader_read_func_t) (void *handle, /* IN */ + void *buf, /* IN */ + size_t count); /* IN */ + + +/* + *-------------------------------------------------------------------------- + * + * bson_reader_destroy_func_t -- + * + * Destroy callback to release any resources associated with the + * opaque handle. + * + * Parameters: + * @handle: the handle provided to bson_reader_new_from_handle(). + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +typedef void (*bson_reader_destroy_func_t) (void *handle); /* IN */ + + +BSON_EXPORT (bson_reader_t *) +bson_reader_new_from_handle (void *handle, + bson_reader_read_func_t rf, + bson_reader_destroy_func_t df); +BSON_EXPORT (bson_reader_t *) +bson_reader_new_from_fd (int fd, bool close_on_destroy); +BSON_EXPORT (bson_reader_t *) +bson_reader_new_from_file (const char *path, bson_error_t *error); +BSON_EXPORT (bson_reader_t *) +bson_reader_new_from_data (const uint8_t *data, size_t length); +BSON_EXPORT (void) +bson_reader_destroy (bson_reader_t *reader); +BSON_EXPORT (void) +bson_reader_set_read_func (bson_reader_t *reader, bson_reader_read_func_t func); +BSON_EXPORT (void) +bson_reader_set_destroy_func (bson_reader_t *reader, + bson_reader_destroy_func_t func); +BSON_EXPORT (const bson_t *) +bson_reader_read (bson_reader_t *reader, bool *reached_eof); +BSON_EXPORT (off_t) +bson_reader_tell (bson_reader_t *reader); +BSON_EXPORT (void) +bson_reader_reset (bson_reader_t *reader); + +BSON_END_DECLS + + +#endif /* BSON_READER_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-stdint-win32.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-stdint-win32.h new file mode 100644 index 0000000000000000000000000000000000000000..eff0cf1344211247f27c720f5c9f10b93b1022fe --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-stdint-win32.h @@ -0,0 +1,263 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#if _MSC_VER >= 1600 // [ +#include <stdint.h> +#else // ] _MSC_VER >= 1600 [ + +#include <limits.h> + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +#include <wchar.h> +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +#if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +#define _W64 __w64 +#else +#define _W64 +#endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#else +typedef signed __int8 int8_t; +typedef signed __int16 int16_t; +typedef signed __int32 int32_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ +typedef signed __int64 intptr_t; +typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ +typedef _W64 signed int intptr_t; +typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || \ + defined( \ + __STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote +// 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t) _I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t) _I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t) _I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t) _I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +#define INTPTR_MIN INT64_MIN +#define INTPTR_MAX INT64_MAX +#define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +#define INTPTR_MIN INT32_MIN +#define INTPTR_MAX INT32_MAX +#define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +#define PTRDIFF_MIN _I64_MIN +#define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +#define PTRDIFF_MIN _I32_MIN +#define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +#ifdef _WIN64 // [ +#define SIZE_MAX _UI64_MAX +#else // _WIN64 ][ +#define SIZE_MAX _UI32_MAX +#endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h> +#ifndef WCHAR_MIN // [ +#define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +#define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || \ + defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>. +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +#define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +#define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + +#endif // _MSC_VER >= 1600 ] + +#endif // _MSC_STDINT_H_ ] diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-stdint.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-stdint.h new file mode 100644 index 0000000000000000000000000000000000000000..9a6118bd8590ca341a8a0addbd21d74e51e51a28 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-stdint.h @@ -0,0 +1 @@ +#include <stdint.h> diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-string.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-string.c new file mode 100644 index 0000000000000000000000000000000000000000..8e38909da49b35761467519a0fbabd7493c8308d --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-string.c @@ -0,0 +1,818 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include <limits.h> +#include <stdarg.h> + +#include "bson-compat.h" +#include "bson-string.h" +#include "bson-memory.h" +#include "bson-utf8.h" + +#ifdef HAVE_STRINGS_H +#include <strings.h> +#else +#include <string.h> +#endif + +/* + *-------------------------------------------------------------------------- + * + * bson_string_new -- + * + * Create a new bson_string_t. + * + * bson_string_t is a power-of-2 allocation growing string. Every + * time data is appended the next power of two size is chosen for + * the allocation. Pretty standard stuff. + * + * It is UTF-8 aware through the use of bson_string_append_unichar(). + * The proper UTF-8 character sequence will be used. + * + * Parameters: + * @str: a string to copy or NULL. + * + * Returns: + * A newly allocated bson_string_t that should be freed with + * bson_string_free(). + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bson_string_t * +bson_string_new (const char *str) /* IN */ +{ + bson_string_t *ret; + + ret = bson_malloc0 (sizeof *ret); + ret->len = str ? (int) strlen (str) : 0; + ret->alloc = ret->len + 1; + + if (!bson_is_power_of_two (ret->alloc)) { + ret->alloc = (uint32_t) bson_next_power_of_two ((size_t) ret->alloc); + } + + BSON_ASSERT (ret->alloc >= 1); + + ret->str = bson_malloc (ret->alloc); + + if (str) { + memcpy (ret->str, str, ret->len); + } + ret->str[ret->len] = '\0'; + + ret->str[ret->len] = '\0'; + + return ret; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_string_free -- + * + * Free the bson_string_t @string and related allocations. + * + * If @free_segment is false, then the strings buffer will be + * returned and is not freed. Otherwise, NULL is returned. + * + * Returns: + * The string->str if free_segment is false. + * Otherwise NULL. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +char * +bson_string_free (bson_string_t *string, /* IN */ + bool free_segment) /* IN */ +{ + char *ret = NULL; + + BSON_ASSERT (string); + + if (!free_segment) { + ret = string->str; + } else { + bson_free (string->str); + } + + bson_free (string); + + return ret; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_string_append -- + * + * Append the UTF-8 string @str to @string. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_string_append (bson_string_t *string, /* IN */ + const char *str) /* IN */ +{ + uint32_t len; + + BSON_ASSERT (string); + BSON_ASSERT (str); + + len = (uint32_t) strlen (str); + + if ((string->alloc - string->len - 1) < len) { + string->alloc += len; + if (!bson_is_power_of_two (string->alloc)) { + string->alloc = + (uint32_t) bson_next_power_of_two ((size_t) string->alloc); + } + string->str = bson_realloc (string->str, string->alloc); + } + + memcpy (string->str + string->len, str, len); + string->len += len; + string->str[string->len] = '\0'; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_string_append_c -- + * + * Append the ASCII character @c to @string. + * + * Do not use this if you are working with UTF-8 sequences, + * use bson_string_append_unichar(). + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_string_append_c (bson_string_t *string, /* IN */ + char c) /* IN */ +{ + char cc[2]; + + BSON_ASSERT (string); + + if (BSON_UNLIKELY (string->alloc == (string->len + 1))) { + cc[0] = c; + cc[1] = '\0'; + bson_string_append (string, cc); + return; + } + + string->str[string->len++] = c; + string->str[string->len] = '\0'; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_string_append_unichar -- + * + * Append the bson_unichar_t @unichar to the string @string. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_string_append_unichar (bson_string_t *string, /* IN */ + bson_unichar_t unichar) /* IN */ +{ + uint32_t len; + char str[8]; + + BSON_ASSERT (string); + BSON_ASSERT (unichar); + + bson_utf8_from_unichar (unichar, str, &len); + + if (len <= 6) { + str[len] = '\0'; + bson_string_append (string, str); + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_string_append_printf -- + * + * Format a string according to @format and append it to @string. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_string_append_printf (bson_string_t *string, const char *format, ...) +{ + va_list args; + char *ret; + + BSON_ASSERT (string); + BSON_ASSERT (format); + + va_start (args, format); + ret = bson_strdupv_printf (format, args); + va_end (args); + bson_string_append (string, ret); + bson_free (ret); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_string_truncate -- + * + * Truncate the string @string to @len bytes. + * + * The underlying memory will be released via realloc() down to + * the minimum required size specified by @len. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_string_truncate (bson_string_t *string, /* IN */ + uint32_t len) /* IN */ +{ + uint32_t alloc; + + BSON_ASSERT (string); + BSON_ASSERT (len < INT_MAX); + + alloc = len + 1; + + if (alloc < 16) { + alloc = 16; + } + + if (!bson_is_power_of_two (alloc)) { + alloc = (uint32_t) bson_next_power_of_two ((size_t) alloc); + } + + string->str = bson_realloc (string->str, alloc); + string->alloc = alloc; + string->len = len; + + string->str[string->len] = '\0'; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_strdup -- + * + * Portable strdup(). + * + * Returns: + * A newly allocated string that should be freed with bson_free(). + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +char * +bson_strdup (const char *str) /* IN */ +{ + long len; + char *out; + + if (!str) { + return NULL; + } + + len = (long) strlen (str); + out = bson_malloc (len + 1); + + if (!out) { + return NULL; + } + + memcpy (out, str, len + 1); + + return out; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_strdupv_printf -- + * + * Like bson_strdup_printf() but takes a va_list. + * + * Returns: + * A newly allocated string that should be freed with bson_free(). + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +char * +bson_strdupv_printf (const char *format, /* IN */ + va_list args) /* IN */ +{ + va_list my_args; + char *buf; + int len = 32; + int n; + + BSON_ASSERT (format); + + buf = bson_malloc0 (len); + + while (true) { + va_copy (my_args, args); + n = bson_vsnprintf (buf, len, format, my_args); + va_end (my_args); + + if (n > -1 && n < len) { + return buf; + } + + if (n > -1) { + len = n + 1; + } else { + len *= 2; + } + + buf = bson_realloc (buf, len); + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_strdup_printf -- + * + * Convenience function that formats a string according to @format + * and returns a copy of it. + * + * Returns: + * A newly created string that should be freed with bson_free(). + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +char * +bson_strdup_printf (const char *format, /* IN */ + ...) /* IN */ +{ + va_list args; + char *ret; + + BSON_ASSERT (format); + + va_start (args, format); + ret = bson_strdupv_printf (format, args); + va_end (args); + + return ret; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_strndup -- + * + * A portable strndup(). + * + * Returns: + * A newly allocated string that should be freed with bson_free(). + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +char * +bson_strndup (const char *str, /* IN */ + size_t n_bytes) /* IN */ +{ + char *ret; + + BSON_ASSERT (str); + + ret = bson_malloc (n_bytes + 1); + bson_strncpy (ret, str, n_bytes + 1); + + return ret; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_strfreev -- + * + * Frees each string in a NULL terminated array of strings. + * This also frees the underlying array. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_strfreev (char **str) /* IN */ +{ + int i; + + if (str) { + for (i = 0; str[i]; i++) + bson_free (str[i]); + bson_free (str); + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_strnlen -- + * + * A portable strnlen(). + * + * Returns: + * The length of @s up to @maxlen. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +size_t +bson_strnlen (const char *s, /* IN */ + size_t maxlen) /* IN */ +{ +#ifdef BSON_HAVE_STRNLEN + return strnlen (s, maxlen); +#else + size_t i; + + for (i = 0; i < maxlen; i++) { + if (s[i] == '\0') { + return i; + } + } + + return maxlen; +#endif +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_strncpy -- + * + * A portable strncpy. + * + * Copies @src into @dst, which must be @size bytes or larger. + * The result is guaranteed to be \0 terminated. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_strncpy (char *dst, /* IN */ + const char *src, /* IN */ + size_t size) /* IN */ +{ +#ifdef _MSC_VER + strncpy_s (dst, size, src, _TRUNCATE); +#else + strncpy (dst, src, size); + dst[size - 1] = '\0'; +#endif +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_vsnprintf -- + * + * A portable vsnprintf. + * + * If more than @size bytes are required (exluding the null byte), + * then @size bytes will be written to @string and the return value + * is the number of bytes required. + * + * This function will always return a NULL terminated string. + * + * Returns: + * The number of bytes required for @format excluding the null byte. + * + * Side effects: + * @str is initialized with the formatted string. + * + *-------------------------------------------------------------------------- + */ + +int +bson_vsnprintf (char *str, /* IN */ + size_t size, /* IN */ + const char *format, /* IN */ + va_list ap) /* IN */ +{ +#ifdef _MSC_VER + int r = -1; + + BSON_ASSERT (str); + + if (size != 0) { + r = _vsnprintf_s (str, size, _TRUNCATE, format, ap); + } + + if (r == -1) { + r = _vscprintf (format, ap); + } + + str[size - 1] = '\0'; + + return r; +#else + int r; + + r = vsnprintf (str, size, format, ap); + str[size - 1] = '\0'; + return r; +#endif +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_snprintf -- + * + * A portable snprintf. + * + * If @format requires more than @size bytes, then @size bytes are + * written and the result is the number of bytes required (excluding + * the null byte). + * + * This function will always return a NULL terminated string. + * + * Returns: + * The number of bytes required for @format. + * + * Side effects: + * @str is initialized. + * + *-------------------------------------------------------------------------- + */ + +int +bson_snprintf (char *str, /* IN */ + size_t size, /* IN */ + const char *format, /* IN */ + ...) +{ + int r; + va_list ap; + + BSON_ASSERT (str); + + va_start (ap, format); + r = bson_vsnprintf (str, size, format, ap); + va_end (ap); + + return r; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_ascii_strtoll -- + * + * A portable strtoll. + * + * Convert a string to a 64-bit signed integer according to the given + * @base, which must be 16, 10, or 8. Leading whitespace will be ignored. + * + * If base is 0 is passed in, the base is inferred from the string's + * leading characters. Base-16 numbers start with "0x" or "0X", base-8 + * numbers start with "0", base-10 numbers start with a digit from 1 to 9. + * + * If @e is not NULL, it will be assigned the address of the first invalid + * character of @s, or its null terminating byte if the entire string was + * valid. + * + * If an invalid value is encountered, errno will be set to EINVAL and + * zero will be returned. If the number is out of range, errno is set to + * ERANGE and LLONG_MAX or LLONG_MIN is returned. + * + * Returns: + * The result of the conversion. + * + * Side effects: + * errno will be set on error. + * + *-------------------------------------------------------------------------- + */ + +int64_t +bson_ascii_strtoll (const char *s, char **e, int base) +{ + char *tok = (char *) s; + char *digits_start; + char c; + int64_t number = 0; + int64_t sign = 1; + int64_t cutoff; + int64_t cutlim; + + errno = 0; + + if (!s) { + errno = EINVAL; + return 0; + } + + c = *tok; + + while (isspace (c)) { + c = *++tok; + } + + if (c == '-') { + sign = -1; + c = *++tok; + } else if (c == '+') { + c = *++tok; + } else if (!isdigit (c)) { + errno = EINVAL; + return 0; + } + + /* from here down, inspired by NetBSD's strtoll */ + if ((base == 0 || base == 16) && c == '0' && + (tok[1] == 'x' || tok[1] == 'X')) { + tok += 2; + c = *tok; + base = 16; + } + + if (base == 0) { + base = c == '0' ? 8 : 10; + } + + /* Cutoff is the greatest magnitude we'll be able to multiply by base without + * range error. If the current number is past cutoff and we see valid digit, + * fail. If the number is *equal* to cutoff, then the next digit must be less + * than cutlim, otherwise fail. + */ + cutoff = sign == -1 ? INT64_MIN : INT64_MAX; + cutlim = (int) (cutoff % base); + cutoff /= base; + if (sign == -1) { + if (cutlim > 0) { + cutlim -= base; + cutoff += 1; + } + cutlim = -cutlim; + } + + digits_start = tok; + + while ((c = *tok)) { + if (isdigit (c)) { + c -= '0'; + } else if (isalpha (c)) { + c -= isupper (c) ? 'A' - 10 : 'a' - 10; + } else { + /* end of number string */ + break; + } + + if (c >= base) { + break; + } + + if (sign == -1) { + if (number < cutoff || (number == cutoff && c > cutlim)) { + number = INT64_MIN; + errno = ERANGE; + break; + } else { + number *= base; + number -= c; + } + } else { + if (number > cutoff || (number == cutoff && c > cutlim)) { + number = INT64_MAX; + errno = ERANGE; + break; + } else { + number *= base; + number += c; + } + } + + tok++; + } + + /* did we parse any digits at all? */ + if (e != NULL && tok > digits_start) { + *e = tok; + } + + return number; +} + + +int +bson_strcasecmp (const char *s1, const char *s2) +{ +#ifdef BSON_OS_WIN32 + return _stricmp (s1, s2); +#else + return strcasecmp (s1, s2); +#endif +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-string.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-string.h new file mode 100644 index 0000000000000000000000000000000000000000..fdcc58cca266853fd6788bed14c3b274ab45d930 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-string.h @@ -0,0 +1,87 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_STRING_H +#define BSON_STRING_H + + +#if !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) +#error "Only <bson.h> can be included directly." +#endif + + +#include <stdarg.h> + +#include "bson-macros.h" +#include "bson-types.h" + + +BSON_BEGIN_DECLS + + +typedef struct { + char *str; + uint32_t len; + uint32_t alloc; +} bson_string_t; + + +BSON_EXPORT (bson_string_t *) +bson_string_new (const char *str); +BSON_EXPORT (char *) +bson_string_free (bson_string_t *string, bool free_segment); +BSON_EXPORT (void) +bson_string_append (bson_string_t *string, const char *str); +BSON_EXPORT (void) +bson_string_append_c (bson_string_t *string, char str); +BSON_EXPORT (void) +bson_string_append_unichar (bson_string_t *string, bson_unichar_t unichar); +BSON_EXPORT (void) +bson_string_append_printf (bson_string_t *string, const char *format, ...) + BSON_GNUC_PRINTF (2, 3); +BSON_EXPORT (void) +bson_string_truncate (bson_string_t *string, uint32_t len); +BSON_EXPORT (char *) +bson_strdup (const char *str); +BSON_EXPORT (char *) +bson_strdup_printf (const char *format, ...) BSON_GNUC_PRINTF (1, 2); +BSON_EXPORT (char *) +bson_strdupv_printf (const char *format, va_list args) BSON_GNUC_PRINTF (1, 0); +BSON_EXPORT (char *) +bson_strndup (const char *str, size_t n_bytes); +BSON_EXPORT (void) +bson_strncpy (char *dst, const char *src, size_t size); +BSON_EXPORT (int) +bson_vsnprintf (char *str, size_t size, const char *format, va_list ap) + BSON_GNUC_PRINTF (3, 0); +BSON_EXPORT (int) +bson_snprintf (char *str, size_t size, const char *format, ...) + BSON_GNUC_PRINTF (3, 4); +BSON_EXPORT (void) +bson_strfreev (char **strv); +BSON_EXPORT (size_t) +bson_strnlen (const char *s, size_t maxlen); +BSON_EXPORT (int64_t) +bson_ascii_strtoll (const char *str, char **endptr, int base); +BSON_EXPORT (int) +bson_strcasecmp (const char *s1, const char *s2); + + +BSON_END_DECLS + + +#endif /* BSON_STRING_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-thread-private.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-thread-private.h new file mode 100644 index 0000000000000000000000000000000000000000..41d58d0a99fa254239a1b6a58110899a97e1810c --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-thread-private.h @@ -0,0 +1,79 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_THREAD_PRIVATE_H +#define BSON_THREAD_PRIVATE_H + + +#if !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) +#error "Only <bson.h> can be included directly." +#endif + + +#include "bson-compat.h" +#include "bson-config.h" +#include "bson-macros.h" + + +BSON_BEGIN_DECLS + + +#if defined(BSON_OS_UNIX) +#include <pthread.h> +#define bson_mutex_t pthread_mutex_t +#define bson_mutex_init(_n) pthread_mutex_init ((_n), NULL) +#define bson_mutex_lock pthread_mutex_lock +#define bson_mutex_unlock pthread_mutex_unlock +#define bson_mutex_destroy pthread_mutex_destroy +#define bson_thread_t pthread_t +#define bson_thread_create(_t, _f, _d) pthread_create ((_t), NULL, (_f), (_d)) +#define bson_thread_join(_n) pthread_join ((_n), NULL) +#define bson_once_t pthread_once_t +#define bson_once pthread_once +#define BSON_ONCE_FUN(n) void n (void) +#define BSON_ONCE_RETURN return +#ifdef BSON_PTHREAD_ONCE_INIT_NEEDS_BRACES +#define BSON_ONCE_INIT \ + { \ + PTHREAD_ONCE_INIT \ + } +#else +#define BSON_ONCE_INIT PTHREAD_ONCE_INIT +#endif +#else +#define bson_mutex_t CRITICAL_SECTION +#define bson_mutex_init InitializeCriticalSection +#define bson_mutex_lock EnterCriticalSection +#define bson_mutex_unlock LeaveCriticalSection +#define bson_mutex_destroy DeleteCriticalSection +#define bson_thread_t HANDLE +#define bson_thread_create(_t, _f, _d) \ + (!(*(_t) = CreateThread (NULL, 0, (void *) _f, _d, 0, NULL))) +#define bson_thread_join(_n) WaitForSingleObject ((_n), INFINITE) +#define bson_once_t INIT_ONCE +#define BSON_ONCE_INIT INIT_ONCE_STATIC_INIT +#define bson_once(o, c) InitOnceExecuteOnce (o, c, NULL, NULL) +#define BSON_ONCE_FUN(n) \ + BOOL CALLBACK n (PINIT_ONCE _ignored_a, PVOID _ignored_b, PVOID *_ignored_c) +#define BSON_ONCE_RETURN return true +#endif + + +BSON_END_DECLS + + +#endif /* BSON_THREAD_PRIVATE_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-timegm-private.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-timegm-private.h new file mode 100644 index 0000000000000000000000000000000000000000..c39207f39cf96f1e4e27491bce922d7b1ee074b1 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-timegm-private.h @@ -0,0 +1,49 @@ +/* + * Copyright 2014 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_TIMEGM_PRIVATE_H +#define BSON_TIMEGM_PRIVATE_H + + +#include "bson-compat.h" +#include "bson-macros.h" + + +BSON_BEGIN_DECLS + +/* avoid system-dependent struct tm definitions */ +struct bson_tm { + int64_t tm_sec; /* seconds after the minute [0-60] */ + int64_t tm_min; /* minutes after the hour [0-59] */ + int64_t tm_hour; /* hours since midnight [0-23] */ + int64_t tm_mday; /* day of the month [1-31] */ + int64_t tm_mon; /* months since January [0-11] */ + int64_t tm_year; /* years since 1900 */ + int64_t tm_wday; /* days since Sunday [0-6] */ + int64_t tm_yday; /* days since January 1 [0-365] */ + int64_t tm_isdst; /* Daylight Savings Time flag */ + int64_t tm_gmtoff; /* offset from CUT in seconds */ + char *tm_zone; /* timezone abbreviation */ +}; + +int64_t +_bson_timegm (struct bson_tm *const tmp); + +BSON_END_DECLS + + +#endif /* BSON_TIMEGM_PRIVATE_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-timegm.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-timegm.c new file mode 100644 index 0000000000000000000000000000000000000000..0f7090073f22d042d113148552d4c6d595c9d2b5 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-timegm.c @@ -0,0 +1,795 @@ +/* +** The original version of this file is in the public domain, so clarified as of +** 1996-06-05 by Arthur David Olson. +*/ + +/* +** Leap second handling from Bradley White. +** POSIX-style TZ environment variable handling from Guy Harris. +** Updated to use int64_t's instead of system-dependent definitions of int64_t +** and struct tm by A. Jesse Jiryu Davis for MongoDB, Inc. +*/ + +#include "bson-compat.h" +#include "bson-macros.h" +#include "bson-timegm-private.h" + +#include "errno.h" +#include "string.h" +#include <stdint.h> /* for INT64_MAX and INT64_MIN */ + +/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */ +#define is_digit(c) ((unsigned) (c) - '0' <= 9) + +#if 2 < __GNUC__ + (96 <= __GNUC_MINOR__) +#define ATTRIBUTE_CONST __attribute__ ((const)) +#define ATTRIBUTE_PURE __attribute__ ((__pure__)) +#define ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec)) +#else +#define ATTRIBUTE_CONST /* empty */ +#define ATTRIBUTE_PURE /* empty */ +#define ATTRIBUTE_FORMAT(spec) /* empty */ +#endif + +#if !defined _Noreturn && \ + (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112) +#if 2 < __GNUC__ + (8 <= __GNUC_MINOR__) +#define _Noreturn __attribute__((__noreturn__)) +#else +#define _Noreturn +#endif +#endif + +#if (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901) && \ + !defined restrict +#define restrict /* empty */ +#endif + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wshift-negative-value" +#endif + +/* The minimum and maximum finite time values. */ +static int64_t const time_t_min = INT64_MIN; +static int64_t const time_t_max = INT64_MAX; + +#ifdef __clang__ +#pragma clang diagnostic pop +#pragma clang diagnostic pop +#endif + +#ifndef TZ_MAX_TIMES +#define TZ_MAX_TIMES 2000 +#endif /* !defined TZ_MAX_TIMES */ + +#ifndef TZ_MAX_TYPES +/* This must be at least 17 for Europe/Samara and Europe/Vilnius. */ +#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ +#endif /* !defined TZ_MAX_TYPES */ + +#ifndef TZ_MAX_CHARS +#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ + /* (limited by what unsigned chars can hold) */ +#endif /* !defined TZ_MAX_CHARS */ + +#ifndef TZ_MAX_LEAPS +#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */ +#endif /* !defined TZ_MAX_LEAPS */ + +#define SECSPERMIN 60 +#define MINSPERHOUR 60 +#define HOURSPERDAY 24 +#define DAYSPERWEEK 7 +#define DAYSPERNYEAR 365 +#define DAYSPERLYEAR 366 +#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) +#define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY) +#define MONSPERYEAR 12 + +#define TM_SUNDAY 0 +#define TM_MONDAY 1 +#define TM_TUESDAY 2 +#define TM_WEDNESDAY 3 +#define TM_THURSDAY 4 +#define TM_FRIDAY 5 +#define TM_SATURDAY 6 + +#define TM_JANUARY 0 +#define TM_FEBRUARY 1 +#define TM_MARCH 2 +#define TM_APRIL 3 +#define TM_MAY 4 +#define TM_JUNE 5 +#define TM_JULY 6 +#define TM_AUGUST 7 +#define TM_SEPTEMBER 8 +#define TM_OCTOBER 9 +#define TM_NOVEMBER 10 +#define TM_DECEMBER 11 + +#define TM_YEAR_BASE 1900 + +#define EPOCH_YEAR 1970 +#define EPOCH_WDAY TM_THURSDAY + +#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) + +/* +** Since everything in isleap is modulo 400 (or a factor of 400), we know that +** isleap(y) == isleap(y % 400) +** and so +** isleap(a + b) == isleap((a + b) % 400) +** or +** isleap(a + b) == isleap(a % 400 + b % 400) +** This is true even if % means modulo rather than Fortran remainder +** (which is allowed by C89 but not C99). +** We use this to avoid addition overflow problems. +*/ + +#define isleap_sum(a, b) isleap ((a) % 400 + (b) % 400) + +#ifndef TZ_ABBR_MAX_LEN +#define TZ_ABBR_MAX_LEN 16 +#endif /* !defined TZ_ABBR_MAX_LEN */ + +#ifndef TZ_ABBR_CHAR_SET +#define TZ_ABBR_CHAR_SET \ + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._" +#endif /* !defined TZ_ABBR_CHAR_SET */ + +#ifndef TZ_ABBR_ERR_CHAR +#define TZ_ABBR_ERR_CHAR '_' +#endif /* !defined TZ_ABBR_ERR_CHAR */ + +#ifndef WILDABBR +/* +** Someone might make incorrect use of a time zone abbreviation: +** 1. They might reference tzname[0] before calling tzset (explicitly +** or implicitly). +** 2. They might reference tzname[1] before calling tzset (explicitly +** or implicitly). +** 3. They might reference tzname[1] after setting to a time zone +** in which Daylight Saving Time is never observed. +** 4. They might reference tzname[0] after setting to a time zone +** in which Standard Time is never observed. +** 5. They might reference tm.TM_ZONE after calling offtime. +** What's best to do in the above cases is open to debate; +** for now, we just set things up so that in any of the five cases +** WILDABBR is used. Another possibility: initialize tzname[0] to the +** string "tzname[0] used before set", and similarly for the other cases. +** And another: initialize tzname[0] to "ERA", with an explanation in the +** manual page of what this "time zone abbreviation" means (doing this so +** that tzname[0] has the "normal" length of three characters). +*/ +#define WILDABBR " " +#endif /* !defined WILDABBR */ + +#ifdef TM_ZONE +static const char wildabbr[] = WILDABBR; +static const char gmt[] = "GMT"; +#endif + +struct ttinfo { /* time type information */ + int_fast32_t tt_gmtoff; /* UT offset in seconds */ + int tt_isdst; /* used to set tm_isdst */ + int tt_abbrind; /* abbreviation list index */ + int tt_ttisstd; /* true if transition is std time */ + int tt_ttisgmt; /* true if transition is UT */ +}; + +struct lsinfo { /* leap second information */ + int64_t ls_trans; /* transition time */ + int_fast64_t ls_corr; /* correction to apply */ +}; + +#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) + +#ifdef TZNAME_MAX +#define MY_TZNAME_MAX TZNAME_MAX +#endif /* defined TZNAME_MAX */ +#ifndef TZNAME_MAX +#define MY_TZNAME_MAX 255 +#endif /* !defined TZNAME_MAX */ + +struct state { + int leapcnt; + int timecnt; + int typecnt; + int charcnt; + int goback; + int goahead; + int64_t ats[TZ_MAX_TIMES]; + unsigned char types[TZ_MAX_TIMES]; + struct ttinfo ttis[TZ_MAX_TYPES]; + char chars[BIGGEST (TZ_MAX_CHARS + 1, (2 * (MY_TZNAME_MAX + 1)))]; + struct lsinfo lsis[TZ_MAX_LEAPS]; + int defaulttype; /* for early times or if no transitions */ +}; + +struct rule { + int r_type; /* type of rule--see below */ + int r_day; /* day number of rule */ + int r_week; /* week number of rule */ + int r_mon; /* month number of rule */ + int_fast32_t r_time; /* transition time of rule */ +}; + +#define JULIAN_DAY 0 /* Jn - Julian day */ +#define DAY_OF_YEAR 1 /* n - day of year */ +#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ + +/* +** Prototypes for static functions. +*/ + +static void +gmtload (struct state *sp); +static struct bson_tm * +gmtsub (const int64_t *timep, int_fast32_t offset, struct bson_tm *tmp); +static int64_t +increment_overflow (int64_t *number, int64_t delta); +static int64_t +leaps_thru_end_of (int64_t y) ATTRIBUTE_PURE; +static int64_t +increment_overflow32 (int_fast32_t *number, int64_t delta); +static int64_t +normalize_overflow32 (int_fast32_t *tensptr, int64_t *unitsptr, int64_t base); +static int64_t +normalize_overflow (int64_t *tensptr, int64_t *unitsptr, int64_t base); +static int64_t +time1 (struct bson_tm *tmp, + struct bson_tm *(*funcp) (const int64_t *, int_fast32_t, struct bson_tm *), + int_fast32_t offset); +static int64_t +time2 (struct bson_tm *tmp, + struct bson_tm *(*funcp) (const int64_t *, int_fast32_t, struct bson_tm *), + int_fast32_t offset, + int64_t *okayp); +static int64_t +time2sub (struct bson_tm *tmp, + struct bson_tm *(*funcp) (const int64_t *, int_fast32_t, struct bson_tm *), + int_fast32_t offset, + int64_t *okayp, + int64_t do_norm_secs); +static struct bson_tm * +timesub (const int64_t *timep, + int_fast32_t offset, + const struct state *sp, + struct bson_tm *tmp); +static int64_t +tmcomp (const struct bson_tm *atmp, const struct bson_tm *btmp); + +static struct state gmtmem; +#define gmtptr (&gmtmem) + +static int gmt_is_set; + +static const int mon_lengths[2][MONSPERYEAR] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; + +static const int year_lengths[2] = {DAYSPERNYEAR, DAYSPERLYEAR}; + +static void +gmtload (struct state *const sp) +{ + memset (sp, 0, sizeof (struct state)); + sp->typecnt = 1; + sp->charcnt = 4; + sp->chars[0] = 'G'; + sp->chars[1] = 'M'; + sp->chars[2] = 'T'; +} + +/* +** gmtsub is to gmtime as localsub is to localtime. +*/ + +static struct bson_tm * +gmtsub (const int64_t *const timep, + const int_fast32_t offset, + struct bson_tm *const tmp) +{ + register struct bson_tm *result; + + if (!gmt_is_set) { + gmt_is_set = true; + gmtload (gmtptr); + } + result = timesub (timep, offset, gmtptr, tmp); +#ifdef TM_ZONE + /* + ** Could get fancy here and deliver something such as + ** "UT+xxxx" or "UT-xxxx" if offset is non-zero, + ** but this is no time for a treasure hunt. + */ + tmp->TM_ZONE = offset ? wildabbr : gmtptr ? gmtptr->chars : gmt; +#endif /* defined TM_ZONE */ + return result; +} + +/* +** Return the number of leap years through the end of the given year +** where, to make the math easy, the answer for year zero is defined as zero. +*/ + +static int64_t +leaps_thru_end_of (register const int64_t y) +{ + return (y >= 0) ? (y / 4 - y / 100 + y / 400) + : -(leaps_thru_end_of (-(y + 1)) + 1); +} + +static struct bson_tm * +timesub (const int64_t *const timep, + const int_fast32_t offset, + register const struct state *const sp, + register struct bson_tm *const tmp) +{ + register const struct lsinfo *lp; + register int64_t tdays; + register int64_t idays; /* unsigned would be so 2003 */ + register int_fast64_t rem; + int64_t y; + register const int *ip; + register int_fast64_t corr; + register int64_t hit; + register int64_t i; + + corr = 0; + hit = 0; + i = (sp == NULL) ? 0 : sp->leapcnt; + while (--i >= 0) { + lp = &sp->lsis[i]; + if (*timep >= lp->ls_trans) { + if (*timep == lp->ls_trans) { + hit = ((i == 0 && lp->ls_corr > 0) || + lp->ls_corr > sp->lsis[i - 1].ls_corr); + if (hit) + while (i > 0 && + sp->lsis[i].ls_trans == sp->lsis[i - 1].ls_trans + 1 && + sp->lsis[i].ls_corr == sp->lsis[i - 1].ls_corr + 1) { + ++hit; + --i; + } + } + corr = lp->ls_corr; + break; + } + } + y = EPOCH_YEAR; + tdays = *timep / SECSPERDAY; + rem = *timep - tdays * SECSPERDAY; + while (tdays < 0 || tdays >= year_lengths[isleap (y)]) { + int64_t newy; + register int64_t tdelta; + register int64_t idelta; + register int64_t leapdays; + + tdelta = tdays / DAYSPERLYEAR; + idelta = tdelta; + if (idelta == 0) + idelta = (tdays < 0) ? -1 : 1; + newy = y; + if (increment_overflow (&newy, idelta)) + return NULL; + leapdays = leaps_thru_end_of (newy - 1) - leaps_thru_end_of (y - 1); + tdays -= ((int64_t) newy - y) * DAYSPERNYEAR; + tdays -= leapdays; + y = newy; + } + { + register int_fast32_t seconds; + + seconds = (int_fast32_t) (tdays * SECSPERDAY); + tdays = seconds / SECSPERDAY; + rem += seconds - tdays * SECSPERDAY; + } + /* + ** Given the range, we can now fearlessly cast... + */ + idays = (int64_t) tdays; + rem += offset - corr; + while (rem < 0) { + rem += SECSPERDAY; + --idays; + } + while (rem >= SECSPERDAY) { + rem -= SECSPERDAY; + ++idays; + } + while (idays < 0) { + if (increment_overflow (&y, -1)) + return NULL; + idays += year_lengths[isleap (y)]; + } + while (idays >= year_lengths[isleap (y)]) { + idays -= year_lengths[isleap (y)]; + if (increment_overflow (&y, 1)) + return NULL; + } + tmp->tm_year = y; + if (increment_overflow (&tmp->tm_year, -TM_YEAR_BASE)) + return NULL; + tmp->tm_yday = idays; + /* + ** The "extra" mods below avoid overflow problems. + */ + tmp->tm_wday = + EPOCH_WDAY + + ((y - EPOCH_YEAR) % DAYSPERWEEK) * (DAYSPERNYEAR % DAYSPERWEEK) + + leaps_thru_end_of (y - 1) - leaps_thru_end_of (EPOCH_YEAR - 1) + idays; + tmp->tm_wday %= DAYSPERWEEK; + if (tmp->tm_wday < 0) + tmp->tm_wday += DAYSPERWEEK; + tmp->tm_hour = (int64_t) (rem / SECSPERHOUR); + rem %= SECSPERHOUR; + tmp->tm_min = (int64_t) (rem / SECSPERMIN); + /* + ** A positive leap second requires a special + ** representation. This uses "... ??:59:60" et seq. + */ + tmp->tm_sec = (int64_t) (rem % SECSPERMIN) + hit; + ip = mon_lengths[isleap (y)]; + for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon)) + idays -= ip[tmp->tm_mon]; + tmp->tm_mday = (int64_t) (idays + 1); + tmp->tm_isdst = 0; +#ifdef TM_GMTOFF + tmp->TM_GMTOFF = offset; +#endif /* defined TM_GMTOFF */ + return tmp; +} + +/* +** Adapted from code provided by Robert Elz, who writes: +** The "best" way to do mktime I think is based on an idea of Bob +** Kridle's (so its said...) from a long time ago. +** It does a binary search of the int64_t space. Since int64_t's are +** just 32 bits, its a max of 32 iterations (even at 64 bits it +** would still be very reasonable). +*/ + +#ifndef WRONG +#define WRONG (-1) +#endif /* !defined WRONG */ + +/* +** Normalize logic courtesy Paul Eggert. +*/ + +static int64_t +increment_overflow (int64_t *const ip, int64_t j) +{ + register int64_t const i = *ip; + + /* + ** If i >= 0 there can only be overflow if i + j > INT_MAX + ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow. + ** If i < 0 there can only be overflow if i + j < INT_MIN + ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow. + */ + if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i)) + return true; + *ip += j; + return false; +} + +static int64_t +increment_overflow32 (int_fast32_t *const lp, int64_t const m) +{ + register int_fast32_t const l = *lp; + + if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l)) + return true; + *lp += m; + return false; +} + +static int64_t +normalize_overflow (int64_t *const tensptr, int64_t *const unitsptr, const int64_t base) +{ + register int64_t tensdelta; + + tensdelta = + (*unitsptr >= 0) ? (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base); + *unitsptr -= tensdelta * base; + return increment_overflow (tensptr, tensdelta); +} + +static int64_t +normalize_overflow32 (int_fast32_t *const tensptr, + int64_t *const unitsptr, + const int64_t base) +{ + register int64_t tensdelta; + + tensdelta = + (*unitsptr >= 0) ? (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base); + *unitsptr -= tensdelta * base; + return increment_overflow32 (tensptr, tensdelta); +} + +static int64_t +tmcomp (register const struct bson_tm *const atmp, + register const struct bson_tm *const btmp) +{ + register int64_t result; + + if (atmp->tm_year != btmp->tm_year) + return atmp->tm_year < btmp->tm_year ? -1 : 1; + if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 && + (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && + (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && + (result = (atmp->tm_min - btmp->tm_min)) == 0) + result = atmp->tm_sec - btmp->tm_sec; + return result; +} + +static int64_t +time2sub (struct bson_tm *const tmp, + struct bson_tm *(*const funcp) (const int64_t *, int_fast32_t, struct bson_tm *), + const int_fast32_t offset, + int64_t *const okayp, + const int64_t do_norm_secs) +{ + register const struct state *sp; + register int64_t dir; + register int64_t i, j; + register int64_t saved_seconds; + register int_fast32_t li; + register int64_t lo; + register int64_t hi; + int_fast32_t y; + int64_t newt; + int64_t t; + struct bson_tm yourtm, mytm; + + *okayp = false; + yourtm = *tmp; + if (do_norm_secs) { + if (normalize_overflow (&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN)) + return WRONG; + } + if (normalize_overflow (&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) + return WRONG; + if (normalize_overflow (&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) + return WRONG; + y = (int_fast32_t) yourtm.tm_year; + if (normalize_overflow32 (&y, &yourtm.tm_mon, MONSPERYEAR)) + return WRONG; + /* + ** Turn y into an actual year number for now. + ** It is converted back to an offset from TM_YEAR_BASE later. + */ + if (increment_overflow32 (&y, TM_YEAR_BASE)) + return WRONG; + while (yourtm.tm_mday <= 0) { + if (increment_overflow32 (&y, -1)) + return WRONG; + li = y + (1 < yourtm.tm_mon); + yourtm.tm_mday += year_lengths[isleap (li)]; + } + while (yourtm.tm_mday > DAYSPERLYEAR) { + li = y + (1 < yourtm.tm_mon); + yourtm.tm_mday -= year_lengths[isleap (li)]; + if (increment_overflow32 (&y, 1)) + return WRONG; + } + for (;;) { + i = mon_lengths[isleap (y)][yourtm.tm_mon]; + if (yourtm.tm_mday <= i) + break; + yourtm.tm_mday -= i; + if (++yourtm.tm_mon >= MONSPERYEAR) { + yourtm.tm_mon = 0; + if (increment_overflow32 (&y, 1)) + return WRONG; + } + } + if (increment_overflow32 (&y, -TM_YEAR_BASE)) + return WRONG; + yourtm.tm_year = y; + if (yourtm.tm_year != y) + return WRONG; + if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) + saved_seconds = 0; + else if (y + TM_YEAR_BASE < EPOCH_YEAR) { + /* + ** We can't set tm_sec to 0, because that might push the + ** time below the minimum representable time. + ** Set tm_sec to 59 instead. + ** This assumes that the minimum representable time is + ** not in the same minute that a leap second was deleted from, + ** which is a safer assumption than using 58 would be. + */ + if (increment_overflow (&yourtm.tm_sec, 1 - SECSPERMIN)) + return WRONG; + saved_seconds = yourtm.tm_sec; + yourtm.tm_sec = SECSPERMIN - 1; + } else { + saved_seconds = yourtm.tm_sec; + yourtm.tm_sec = 0; + } + /* + ** Do a binary search. + */ + lo = INT64_MIN; + hi = INT64_MAX; + + for (;;) { + t = lo / 2 + hi / 2; + if (t < lo) + t = lo; + else if (t > hi) + t = hi; + if ((*funcp) (&t, offset, &mytm) == NULL) { + /* + ** Assume that t is too extreme to be represented in + ** a struct bson_tm; arrange things so that it is less + ** extreme on the next pass. + */ + dir = (t > 0) ? 1 : -1; + } else + dir = tmcomp (&mytm, &yourtm); + if (dir != 0) { + if (t == lo) { + if (t == time_t_max) + return WRONG; + ++t; + ++lo; + } else if (t == hi) { + if (t == time_t_min) + return WRONG; + --t; + --hi; + } + if (lo > hi) + return WRONG; + if (dir > 0) + hi = t; + else + lo = t; + continue; + } + if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) + break; + /* + ** Right time, wrong type. + ** Hunt for right time, right type. + ** It's okay to guess wrong since the guess + ** gets checked. + */ + sp = (const struct state *) gmtptr; + if (sp == NULL) + return WRONG; + for (i = sp->typecnt - 1; i >= 0; --i) { + if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) + continue; + for (j = sp->typecnt - 1; j >= 0; --j) { + if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) + continue; + newt = t + sp->ttis[j].tt_gmtoff - sp->ttis[i].tt_gmtoff; + if ((*funcp) (&newt, offset, &mytm) == NULL) + continue; + if (tmcomp (&mytm, &yourtm) != 0) + continue; + if (mytm.tm_isdst != yourtm.tm_isdst) + continue; + /* + ** We have a match. + */ + t = newt; + goto label; + } + } + return WRONG; + } +label: + newt = t + saved_seconds; + if ((newt < t) != (saved_seconds < 0)) + return WRONG; + t = newt; + if ((*funcp) (&t, offset, tmp)) + *okayp = true; + return t; +} + +static int64_t +time2 (struct bson_tm *const tmp, + struct bson_tm *(*const funcp) (const int64_t *, int_fast32_t, struct bson_tm *), + const int_fast32_t offset, + int64_t *const okayp) +{ + int64_t t; + + /* + ** First try without normalization of seconds + ** (in case tm_sec contains a value associated with a leap second). + ** If that fails, try with normalization of seconds. + */ + t = time2sub (tmp, funcp, offset, okayp, false); + return *okayp ? t : time2sub (tmp, funcp, offset, okayp, true); +} + +static int64_t +time1 (struct bson_tm *const tmp, + struct bson_tm *(*const funcp) (const int64_t *, int_fast32_t, struct bson_tm *), + const int_fast32_t offset) +{ + register int64_t t; + register const struct state *sp; + register int64_t samei, otheri; + register int64_t sameind, otherind; + register int64_t i; + register int64_t nseen; + int64_t seen[TZ_MAX_TYPES]; + int64_t types[TZ_MAX_TYPES]; + int64_t okay; + + if (tmp == NULL) { + errno = EINVAL; + return WRONG; + } + if (tmp->tm_isdst > 1) + tmp->tm_isdst = 1; + t = time2 (tmp, funcp, offset, &okay); + if (okay) + return t; + if (tmp->tm_isdst < 0) +#ifdef PCTS + /* + ** POSIX Conformance Test Suite code courtesy Grant Sullivan. + */ + tmp->tm_isdst = 0; /* reset to std and try again */ +#else + return t; +#endif /* !defined PCTS */ + /* + ** We're supposed to assume that somebody took a time of one type + ** and did some math on it that yielded a "struct tm" that's bad. + ** We try to divine the type they started from and adjust to the + ** type they need. + */ + sp = (const struct state *) gmtptr; + if (sp == NULL) + return WRONG; + for (i = 0; i < sp->typecnt; ++i) + seen[i] = false; + nseen = 0; + for (i = sp->timecnt - 1; i >= 0; --i) + if (!seen[sp->types[i]]) { + seen[sp->types[i]] = true; + types[nseen++] = sp->types[i]; + } + for (sameind = 0; sameind < nseen; ++sameind) { + samei = types[sameind]; + if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) + continue; + for (otherind = 0; otherind < nseen; ++otherind) { + otheri = types[otherind]; + if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) + continue; + tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff; + tmp->tm_isdst = !tmp->tm_isdst; + t = time2 (tmp, funcp, offset, &okay); + if (okay) + return t; + tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff; + tmp->tm_isdst = !tmp->tm_isdst; + } + } + return WRONG; +} + +int64_t +_bson_timegm (struct bson_tm *const tmp) +{ + if (tmp != NULL) + tmp->tm_isdst = 0; + return time1 (tmp, gmtsub, 0L); +} + diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-types.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-types.h new file mode 100644 index 0000000000000000000000000000000000000000..667054484f4d9cbcb7278701ad2e7964e142f4f6 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-types.h @@ -0,0 +1,540 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_TYPES_H +#define BSON_TYPES_H + +#include <stdlib.h> +#include <sys/types.h> + +#include "bson-macros.h" +#include "bson-config.h" +#include "bson-compat.h" +#include "bson-endian.h" + +BSON_BEGIN_DECLS + + +/* + *-------------------------------------------------------------------------- + * + * bson_unichar_t -- + * + * bson_unichar_t provides an unsigned 32-bit type for containing + * unicode characters. When iterating UTF-8 sequences, this should + * be used to avoid losing the high-bits of non-ascii characters. + * + * See also: + * bson_string_append_unichar() + * + *-------------------------------------------------------------------------- + */ + +typedef uint32_t bson_unichar_t; + + +/** + * bson_context_flags_t: + * + * This enumeration is used to configure a bson_context_t. + * + * %BSON_CONTEXT_NONE: Use default options. + * %BSON_CONTEXT_THREAD_SAFE: Context will be called from multiple threads. + * %BSON_CONTEXT_DISABLE_PID_CACHE: Call getpid() instead of caching the + * result of getpid() when initializing the context. + * %BSON_CONTEXT_DISABLE_HOST_CACHE: Call gethostname() instead of caching the + * result of gethostname() when initializing the context. + */ +typedef enum { + BSON_CONTEXT_NONE = 0, + BSON_CONTEXT_THREAD_SAFE = (1 << 0), + BSON_CONTEXT_DISABLE_HOST_CACHE = (1 << 1), + BSON_CONTEXT_DISABLE_PID_CACHE = (1 << 2), +#ifdef BSON_HAVE_SYSCALL_TID + BSON_CONTEXT_USE_TASK_ID = (1 << 3), +#endif +} bson_context_flags_t; + + +/** + * bson_context_t: + * + * This structure manages context for the bson library. It handles + * configuration for thread-safety and other performance related requirements. + * Consumers will create a context and may use multiple under a variety of + * situations. + * + * If your program calls fork(), you should initialize a new bson_context_t + * using bson_context_init(). + * + * If you are using threading, it is suggested that you use a bson_context_t + * per thread for best performance. Alternatively, you can initialize the + * bson_context_t with BSON_CONTEXT_THREAD_SAFE, although a performance penalty + * will be incurred. + * + * Many functions will require that you provide a bson_context_t such as OID + * generation. + * + * This structure is oqaque in that you cannot see the contents of the + * structure. However, it is stack allocatable in that enough padding is + * provided in _bson_context_t to hold the structure. + */ +typedef struct _bson_context_t bson_context_t; + + +/** + * bson_t: + * + * This structure manages a buffer whose contents are a properly formatted + * BSON document. You may perform various transforms on the BSON documents. + * Additionally, it can be iterated over using bson_iter_t. + * + * See bson_iter_init() for iterating the contents of a bson_t. + * + * When building a bson_t structure using the various append functions, + * memory allocations may occur. That is performed using power of two + * allocations and realloc(). + * + * See http://bsonspec.org for the BSON document spec. + * + * This structure is meant to fit in two sequential 64-byte cachelines. + */ +BSON_ALIGNED_BEGIN (128) +typedef struct _bson_t { + uint32_t flags; /* Internal flags for the bson_t. */ + uint32_t len; /* Length of BSON data. */ + uint8_t padding[120]; /* Padding for stack allocation. */ +} bson_t BSON_ALIGNED_END (128); + + +/** + * BSON_INITIALIZER: + * + * This macro can be used to initialize a #bson_t structure on the stack + * without calling bson_init(). + * + * |[ + * bson_t b = BSON_INITIALIZER; + * ]| + */ +#define BSON_INITIALIZER \ + { \ + 3, 5, \ + { \ + 5 \ + } \ + } + + +BSON_STATIC_ASSERT (sizeof (bson_t) == 128); + + +/** + * bson_oid_t: + * + * This structure contains the binary form of a BSON Object Id as specified + * on http://bsonspec.org. If you would like the bson_oid_t in string form + * see bson_oid_to_string() or bson_oid_to_string_r(). + */ +typedef struct { + uint8_t bytes[12]; +} bson_oid_t; + +BSON_STATIC_ASSERT (sizeof (bson_oid_t) == 12); + +/** + * bson_decimal128_t: + * + * @high The high-order bytes of the decimal128. This field contains sign, + * combination bits, exponent, and part of the coefficient continuation. + * @low The low-order bytes of the decimal128. This field contains the second + * part of the coefficient continuation. + * + * This structure is a boxed type containing the value for the BSON decimal128 + * type. The structure stores the 128 bits such that they correspond to the + * native format for the IEEE decimal128 type, if it is implemented. + **/ +typedef struct { +#if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN + uint64_t low; + uint64_t high; +#elif BSON_BYTE_ORDER == BSON_BIG_ENDIAN + uint64_t high; + uint64_t low; +#endif +} bson_decimal128_t; + + +/** + * bson_validate_flags_t: + * + * This enumeration is used for validation of BSON documents. It allows + * selective control on what you wish to validate. + * + * %BSON_VALIDATE_NONE: No additional validation occurs. + * %BSON_VALIDATE_UTF8: Check that strings are valid UTF-8. + * %BSON_VALIDATE_DOLLAR_KEYS: Check that keys do not start with $. + * %BSON_VALIDATE_DOT_KEYS: Check that keys do not contain a period. + * %BSON_VALIDATE_UTF8_ALLOW_NULL: Allow NUL bytes in UTF-8 text. + * %BSON_VALIDATE_EMPTY_KEYS: Prohibit zero-length field names + */ +typedef enum { + BSON_VALIDATE_NONE = 0, + BSON_VALIDATE_UTF8 = (1 << 0), + BSON_VALIDATE_DOLLAR_KEYS = (1 << 1), + BSON_VALIDATE_DOT_KEYS = (1 << 2), + BSON_VALIDATE_UTF8_ALLOW_NULL = (1 << 3), + BSON_VALIDATE_EMPTY_KEYS = (1 << 4), +} bson_validate_flags_t; + + +/** + * bson_type_t: + * + * This enumeration contains all of the possible types within a BSON document. + * Use bson_iter_type() to fetch the type of a field while iterating over it. + */ +typedef enum { + BSON_TYPE_EOD = 0x00, + BSON_TYPE_DOUBLE = 0x01, + BSON_TYPE_UTF8 = 0x02, + BSON_TYPE_DOCUMENT = 0x03, + BSON_TYPE_ARRAY = 0x04, + BSON_TYPE_BINARY = 0x05, + BSON_TYPE_UNDEFINED = 0x06, + BSON_TYPE_OID = 0x07, + BSON_TYPE_BOOL = 0x08, + BSON_TYPE_DATE_TIME = 0x09, + BSON_TYPE_NULL = 0x0A, + BSON_TYPE_REGEX = 0x0B, + BSON_TYPE_DBPOINTER = 0x0C, + BSON_TYPE_CODE = 0x0D, + BSON_TYPE_SYMBOL = 0x0E, + BSON_TYPE_CODEWSCOPE = 0x0F, + BSON_TYPE_INT32 = 0x10, + BSON_TYPE_TIMESTAMP = 0x11, + BSON_TYPE_INT64 = 0x12, + BSON_TYPE_DECIMAL128 = 0x13, + BSON_TYPE_MAXKEY = 0x7F, + BSON_TYPE_MINKEY = 0xFF, +} bson_type_t; + + +/** + * bson_subtype_t: + * + * This enumeration contains the various subtypes that may be used in a binary + * field. See http://bsonspec.org for more information. + */ +typedef enum { + BSON_SUBTYPE_BINARY = 0x00, + BSON_SUBTYPE_FUNCTION = 0x01, + BSON_SUBTYPE_BINARY_DEPRECATED = 0x02, + BSON_SUBTYPE_UUID_DEPRECATED = 0x03, + BSON_SUBTYPE_UUID = 0x04, + BSON_SUBTYPE_MD5 = 0x05, + BSON_SUBTYPE_USER = 0x80, +} bson_subtype_t; + + +/* + *-------------------------------------------------------------------------- + * + * bson_value_t -- + * + * A boxed type to contain various bson_type_t types. + * + * See also: + * bson_value_copy() + * bson_value_destroy() + * + *-------------------------------------------------------------------------- + */ + +BSON_ALIGNED_BEGIN (8) +typedef struct _bson_value_t { + bson_type_t value_type; + int32_t padding; + union { + bson_oid_t v_oid; + int64_t v_int64; + int32_t v_int32; + int8_t v_int8; + double v_double; + bool v_bool; + int64_t v_datetime; + struct { + uint32_t timestamp; + uint32_t increment; + } v_timestamp; + struct { + char *str; + uint32_t len; + } v_utf8; + struct { + uint8_t *data; + uint32_t data_len; + } v_doc; + struct { + uint8_t *data; + uint32_t data_len; + bson_subtype_t subtype; + } v_binary; + struct { + char *regex; + char *options; + } v_regex; + struct { + char *collection; + uint32_t collection_len; + bson_oid_t oid; + } v_dbpointer; + struct { + char *code; + uint32_t code_len; + } v_code; + struct { + char *code; + uint8_t *scope_data; + uint32_t code_len; + uint32_t scope_len; + } v_codewscope; + struct { + char *symbol; + uint32_t len; + } v_symbol; + bson_decimal128_t v_decimal128; + } value; +} bson_value_t BSON_ALIGNED_END (8); + + +/** + * bson_iter_t: + * + * This structure manages iteration over a bson_t structure. It keeps track + * of the location of the current key and value within the buffer. Using the + * various functions to get the value of the iter will read from these + * locations. + * + * This structure is safe to discard on the stack. No cleanup is necessary + * after using it. + */ +BSON_ALIGNED_BEGIN (128) +typedef struct { + const uint8_t *raw; /* The raw buffer being iterated. */ + uint32_t len; /* The length of raw. */ + uint32_t off; /* The offset within the buffer. */ + uint32_t type; /* The offset of the type byte. */ + uint32_t key; /* The offset of the key byte. */ + uint32_t d1; /* The offset of the first data byte. */ + uint32_t d2; /* The offset of the second data byte. */ + uint32_t d3; /* The offset of the third data byte. */ + uint32_t d4; /* The offset of the fourth data byte. */ + uint32_t next_off; /* The offset of the next field. */ + uint32_t err_off; /* The offset of the error. */ + bson_value_t value; /* Internal value for various state. */ +} bson_iter_t BSON_ALIGNED_END (128); + + +/** + * bson_reader_t: + * + * This structure is used to iterate over a sequence of BSON documents. It + * allows for them to be iterated with the possibility of no additional + * memory allocations under certain circumstances such as reading from an + * incoming mongo packet. + */ + +BSON_ALIGNED_BEGIN (BSON_ALIGN_OF_PTR) +typedef struct { + uint32_t type; + /*< private >*/ +} bson_reader_t BSON_ALIGNED_END (BSON_ALIGN_OF_PTR); + + +/** + * bson_visitor_t: + * + * This structure contains a series of pointers that can be executed for + * each field of a BSON document based on the field type. + * + * For example, if an int32 field is found, visit_int32 will be called. + * + * When visiting each field using bson_iter_visit_all(), you may provide a + * data pointer that will be provided with each callback. This might be useful + * if you are marshaling to another language. + * + * You may pre-maturely stop the visitation of fields by returning true in your + * visitor. Returning false will continue visitation to further fields. + */ +BSON_ALIGNED_BEGIN (8) +typedef struct { + /* run before / after descending into a document */ + bool (*visit_before) (const bson_iter_t *iter, const char *key, void *data); + bool (*visit_after) (const bson_iter_t *iter, const char *key, void *data); + /* corrupt BSON, or unsupported type and visit_unsupported_type not set */ + void (*visit_corrupt) (const bson_iter_t *iter, void *data); + /* normal bson field callbacks */ + bool (*visit_double) (const bson_iter_t *iter, + const char *key, + double v_double, + void *data); + bool (*visit_utf8) (const bson_iter_t *iter, + const char *key, + size_t v_utf8_len, + const char *v_utf8, + void *data); + bool (*visit_document) (const bson_iter_t *iter, + const char *key, + const bson_t *v_document, + void *data); + bool (*visit_array) (const bson_iter_t *iter, + const char *key, + const bson_t *v_array, + void *data); + bool (*visit_binary) (const bson_iter_t *iter, + const char *key, + bson_subtype_t v_subtype, + size_t v_binary_len, + const uint8_t *v_binary, + void *data); + /* normal field with deprecated "Undefined" BSON type */ + bool (*visit_undefined) (const bson_iter_t *iter, + const char *key, + void *data); + bool (*visit_oid) (const bson_iter_t *iter, + const char *key, + const bson_oid_t *v_oid, + void *data); + bool (*visit_bool) (const bson_iter_t *iter, + const char *key, + bool v_bool, + void *data); + bool (*visit_date_time) (const bson_iter_t *iter, + const char *key, + int64_t msec_since_epoch, + void *data); + bool (*visit_null) (const bson_iter_t *iter, const char *key, void *data); + bool (*visit_regex) (const bson_iter_t *iter, + const char *key, + const char *v_regex, + const char *v_options, + void *data); + bool (*visit_dbpointer) (const bson_iter_t *iter, + const char *key, + size_t v_collection_len, + const char *v_collection, + const bson_oid_t *v_oid, + void *data); + bool (*visit_code) (const bson_iter_t *iter, + const char *key, + size_t v_code_len, + const char *v_code, + void *data); + bool (*visit_symbol) (const bson_iter_t *iter, + const char *key, + size_t v_symbol_len, + const char *v_symbol, + void *data); + bool (*visit_codewscope) (const bson_iter_t *iter, + const char *key, + size_t v_code_len, + const char *v_code, + const bson_t *v_scope, + void *data); + bool (*visit_int32) (const bson_iter_t *iter, + const char *key, + int32_t v_int32, + void *data); + bool (*visit_timestamp) (const bson_iter_t *iter, + const char *key, + uint32_t v_timestamp, + uint32_t v_increment, + void *data); + bool (*visit_int64) (const bson_iter_t *iter, + const char *key, + int64_t v_int64, + void *data); + bool (*visit_maxkey) (const bson_iter_t *iter, const char *key, void *data); + bool (*visit_minkey) (const bson_iter_t *iter, const char *key, void *data); + /* if set, called instead of visit_corrupt when an apparently valid BSON + * includes an unrecognized field type (reading future version of BSON) */ + void (*visit_unsupported_type) (const bson_iter_t *iter, + const char *key, + uint32_t type_code, + void *data); + bool (*visit_decimal128) (const bson_iter_t *iter, + const char *key, + const bson_decimal128_t *v_decimal128, + void *data); + + void *padding[7]; +} bson_visitor_t BSON_ALIGNED_END (8); + +#define BSON_ERROR_BUFFER_SIZE 504 + +BSON_ALIGNED_BEGIN (8) +typedef struct _bson_error_t { + uint32_t domain; + uint32_t code; + char message[BSON_ERROR_BUFFER_SIZE]; +} bson_error_t BSON_ALIGNED_END (8); + + +BSON_STATIC_ASSERT (sizeof (bson_error_t) == 512); + + +/** + * bson_next_power_of_two: + * @v: A 32-bit unsigned integer of required bytes. + * + * Determines the next larger power of two for the value of @v + * in a constant number of operations. + * + * It is up to the caller to guarantee this will not overflow. + * + * Returns: The next power of 2 from @v. + */ +static BSON_INLINE size_t +bson_next_power_of_two (size_t v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; +#if BSON_WORD_SIZE == 64 + v |= v >> 32; +#endif + v++; + + return v; +} + + +static BSON_INLINE bool +bson_is_power_of_two (uint32_t v) +{ + return ((v != 0) && ((v & (v - 1)) == 0)); +} + + +BSON_END_DECLS + + +#endif /* BSON_TYPES_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-utf8.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-utf8.c new file mode 100644 index 0000000000000000000000000000000000000000..d0ce792848d055422851c84d531d2ec9ea022137 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-utf8.c @@ -0,0 +1,476 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include <string.h> + +#include "bson-memory.h" +#include "bson-string.h" +#include "bson-utf8.h" + + +/* + *-------------------------------------------------------------------------- + * + * _bson_utf8_get_sequence -- + * + * Determine the sequence length of the first UTF-8 character in + * @utf8. The sequence length is stored in @seq_length and the mask + * for the first character is stored in @first_mask. + * + * Returns: + * None. + * + * Side effects: + * @seq_length is set. + * @first_mask is set. + * + *-------------------------------------------------------------------------- + */ + +static BSON_INLINE void +_bson_utf8_get_sequence (const char *utf8, /* IN */ + uint8_t *seq_length, /* OUT */ + uint8_t *first_mask) /* OUT */ +{ + unsigned char c = *(const unsigned char *) utf8; + uint8_t m; + uint8_t n; + + /* + * See the following[1] for a description of what the given multi-byte + * sequences will be based on the bits set of the first byte. We also need + * to mask the first byte based on that. All subsequent bytes are masked + * against 0x3F. + * + * [1] http://www.joelonsoftware.com/articles/Unicode.html + */ + + if ((c & 0x80) == 0) { + n = 1; + m = 0x7F; + } else if ((c & 0xE0) == 0xC0) { + n = 2; + m = 0x1F; + } else if ((c & 0xF0) == 0xE0) { + n = 3; + m = 0x0F; + } else if ((c & 0xF8) == 0xF0) { + n = 4; + m = 0x07; + } else if ((c & 0xFC) == 0xF8) { + n = 5; + m = 0x03; + } else if ((c & 0xFE) == 0xFC) { + n = 6; + m = 0x01; + } else { + n = 0; + m = 0; + } + + *seq_length = n; + *first_mask = m; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_utf8_validate -- + * + * Validates that @utf8 is a valid UTF-8 string. + * + * If @allow_null is true, then \0 is allowed within @utf8_len bytes + * of @utf8. Generally, this is bad practice since the main point of + * UTF-8 strings is that they can be used with strlen() and friends. + * However, some languages such as Python can send UTF-8 encoded + * strings with NUL's in them. + * + * Parameters: + * @utf8: A UTF-8 encoded string. + * @utf8_len: The length of @utf8 in bytes. + * @allow_null: If \0 is allowed within @utf8, exclusing trailing \0. + * + * Returns: + * true if @utf8 is valid UTF-8. otherwise false. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_utf8_validate (const char *utf8, /* IN */ + size_t utf8_len, /* IN */ + bool allow_null) /* IN */ +{ + bson_unichar_t c; + uint8_t first_mask; + uint8_t seq_length; + unsigned i; + unsigned j; + + BSON_ASSERT (utf8); + + for (i = 0; i < utf8_len; i += seq_length) { + _bson_utf8_get_sequence (&utf8[i], &seq_length, &first_mask); + + /* + * Ensure we have a valid multi-byte sequence length. + */ + if (!seq_length) { + return false; + } + + /* + * Ensure we have enough bytes left. + */ + if ((utf8_len - i) < seq_length) { + return false; + } + + /* + * Also calculate the next char as a unichar so we can + * check code ranges for non-shortest form. + */ + c = utf8[i] & first_mask; + + /* + * Check the high-bits for each additional sequence byte. + */ + for (j = i + 1; j < (i + seq_length); j++) { + c = (c << 6) | (utf8[j] & 0x3F); + if ((utf8[j] & 0xC0) != 0x80) { + return false; + } + } + + /* + * Check for NULL bytes afterwards. + * + * Hint: if you want to optimize this function, starting here to do + * this in the same pass as the data above would probably be a good + * idea. You would add a branch into the inner loop, but save possibly + * on cache-line bouncing on larger strings. Just a thought. + */ + if (!allow_null) { + for (j = 0; j < seq_length; j++) { + if (((i + j) > utf8_len) || !utf8[i + j]) { + return false; + } + } + } + + /* + * Code point wont fit in utf-16, not allowed. + */ + if (c > 0x0010FFFF) { + return false; + } + + /* + * Byte is in reserved range for UTF-16 high-marks + * for surrogate pairs. + */ + if ((c & 0xFFFFF800) == 0xD800) { + return false; + } + + /* + * Check non-shortest form unicode. + */ + switch (seq_length) { + case 1: + if (c <= 0x007F) { + continue; + } + return false; + + case 2: + if ((c >= 0x0080) && (c <= 0x07FF)) { + continue; + } else if (c == 0) { + /* Two-byte representation for NULL. */ + continue; + } + return false; + + case 3: + if (((c >= 0x0800) && (c <= 0x0FFF)) || + ((c >= 0x1000) && (c <= 0xFFFF))) { + continue; + } + return false; + + case 4: + if (((c >= 0x10000) && (c <= 0x3FFFF)) || + ((c >= 0x40000) && (c <= 0xFFFFF)) || + ((c >= 0x100000) && (c <= 0x10FFFF))) { + continue; + } + return false; + + default: + return false; + } + } + + return true; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_utf8_escape_for_json -- + * + * Allocates a new string matching @utf8 except that special + * characters in JSON will be escaped. The resulting string is also + * UTF-8 encoded. + * + * Both " and \ characters will be escaped. Additionally, if a NUL + * byte is found before @utf8_len bytes, it will be converted to the + * two byte UTF-8 sequence. + * + * Parameters: + * @utf8: A UTF-8 encoded string. + * @utf8_len: The length of @utf8 in bytes or -1 if NUL terminated. + * + * Returns: + * A newly allocated string that should be freed with bson_free(). + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +char * +bson_utf8_escape_for_json (const char *utf8, /* IN */ + ssize_t utf8_len) /* IN */ +{ + bson_unichar_t c; + bson_string_t *str; + bool length_provided = true; + const char *end; + + BSON_ASSERT (utf8); + + str = bson_string_new (NULL); + + if (utf8_len < 0) { + length_provided = false; + utf8_len = strlen (utf8); + } + + end = utf8 + utf8_len; + + while (utf8 < end) { + c = bson_utf8_get_char (utf8); + + switch (c) { + case '\\': + case '"': + case '/': + bson_string_append_c (str, '\\'); + bson_string_append_unichar (str, c); + break; + case '\b': + bson_string_append (str, "\\b"); + break; + case '\f': + bson_string_append (str, "\\f"); + break; + case '\n': + bson_string_append (str, "\\n"); + break; + case '\r': + bson_string_append (str, "\\r"); + break; + case '\t': + bson_string_append (str, "\\t"); + break; + default: + if (c < ' ') { + bson_string_append_printf (str, "\\u%04u", (unsigned) c); + } else { + bson_string_append_unichar (str, c); + } + break; + } + + if (c) { + utf8 = bson_utf8_next_char (utf8); + } else { + if (length_provided && !*utf8) { + /* we escaped nil as '\u0000', now advance past it */ + utf8++; + } else { + /* invalid UTF-8 */ + bson_string_free (str, true); + return NULL; + } + } + } + + return bson_string_free (str, false); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_utf8_get_char -- + * + * Fetches the next UTF-8 character from the UTF-8 sequence. + * + * Parameters: + * @utf8: A string containing validated UTF-8. + * + * Returns: + * A 32-bit bson_unichar_t reprsenting the multi-byte sequence. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bson_unichar_t +bson_utf8_get_char (const char *utf8) /* IN */ +{ + bson_unichar_t c; + uint8_t mask; + uint8_t num; + int i; + + BSON_ASSERT (utf8); + + _bson_utf8_get_sequence (utf8, &num, &mask); + c = (*utf8) & mask; + + for (i = 1; i < num; i++) { + c = (c << 6) | (utf8[i] & 0x3F); + } + + return c; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_utf8_next_char -- + * + * Returns an incremented pointer to the beginning of the next + * multi-byte sequence in @utf8. + * + * Parameters: + * @utf8: A string containing validated UTF-8. + * + * Returns: + * An incremented pointer in @utf8. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +const char * +bson_utf8_next_char (const char *utf8) /* IN */ +{ + uint8_t mask; + uint8_t num; + + BSON_ASSERT (utf8); + + _bson_utf8_get_sequence (utf8, &num, &mask); + + return utf8 + num; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_utf8_from_unichar -- + * + * Converts the unichar to a sequence of utf8 bytes and stores those + * in @utf8. The number of bytes in the sequence are stored in @len. + * + * Parameters: + * @unichar: A bson_unichar_t. + * @utf8: A location for the multi-byte sequence. + * @len: A location for number of bytes stored in @utf8. + * + * Returns: + * None. + * + * Side effects: + * @utf8 is set. + * @len is set. + * + *-------------------------------------------------------------------------- + */ + +void +bson_utf8_from_unichar (bson_unichar_t unichar, /* IN */ + char utf8[BSON_ENSURE_ARRAY_PARAM_SIZE (6)], /* OUT */ + uint32_t *len) /* OUT */ +{ + BSON_ASSERT (utf8); + BSON_ASSERT (len); + + if (unichar <= 0x7F) { + utf8[0] = unichar; + *len = 1; + } else if (unichar <= 0x7FF) { + *len = 2; + utf8[0] = 0xC0 | ((unichar >> 6) & 0x3F); + utf8[1] = 0x80 | ((unichar) &0x3F); + } else if (unichar <= 0xFFFF) { + *len = 3; + utf8[0] = 0xE0 | ((unichar >> 12) & 0xF); + utf8[1] = 0x80 | ((unichar >> 6) & 0x3F); + utf8[2] = 0x80 | ((unichar) &0x3F); + } else if (unichar <= 0x1FFFFF) { + *len = 4; + utf8[0] = 0xF0 | ((unichar >> 18) & 0x7); + utf8[1] = 0x80 | ((unichar >> 12) & 0x3F); + utf8[2] = 0x80 | ((unichar >> 6) & 0x3F); + utf8[3] = 0x80 | ((unichar) &0x3F); + } else if (unichar <= 0x3FFFFFF) { + *len = 5; + utf8[0] = 0xF8 | ((unichar >> 24) & 0x3); + utf8[1] = 0x80 | ((unichar >> 18) & 0x3F); + utf8[2] = 0x80 | ((unichar >> 12) & 0x3F); + utf8[3] = 0x80 | ((unichar >> 6) & 0x3F); + utf8[4] = 0x80 | ((unichar) &0x3F); + } else if (unichar <= 0x7FFFFFFF) { + *len = 6; + utf8[0] = 0xFC | ((unichar >> 31) & 0x1); + utf8[1] = 0x80 | ((unichar >> 25) & 0x3F); + utf8[2] = 0x80 | ((unichar >> 19) & 0x3F); + utf8[3] = 0x80 | ((unichar >> 13) & 0x3F); + utf8[4] = 0x80 | ((unichar >> 7) & 0x3F); + utf8[5] = 0x80 | ((unichar) &0x1); + } else { + *len = 0; + } +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-utf8.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-utf8.h new file mode 100644 index 0000000000000000000000000000000000000000..72918acf5e3a7a7778333e61178945d409dbfcb5 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-utf8.h @@ -0,0 +1,49 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_UTF8_H +#define BSON_UTF8_H + + +#if !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) +#error "Only <bson.h> can be included directly." +#endif + + +#include "bson-macros.h" +#include "bson-types.h" + + +BSON_BEGIN_DECLS + + +BSON_EXPORT (bool) +bson_utf8_validate (const char *utf8, size_t utf8_len, bool allow_null); +BSON_EXPORT (char *) +bson_utf8_escape_for_json (const char *utf8, ssize_t utf8_len); +BSON_EXPORT (bson_unichar_t) +bson_utf8_get_char (const char *utf8); +BSON_EXPORT (const char *) +bson_utf8_next_char (const char *utf8); +BSON_EXPORT (void) +bson_utf8_from_unichar (bson_unichar_t unichar, char utf8[6], uint32_t *len); + + +BSON_END_DECLS + + +#endif /* BSON_UTF8_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-value.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-value.c new file mode 100644 index 0000000000000000000000000000000000000000..c491194f4cd6d84e4d99b4b8a248d18bbf71663f --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-value.c @@ -0,0 +1,189 @@ +/* + * Copyright 2014 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "bson-memory.h" +#include "bson-string.h" +#include "bson-value.h" +#include "bson-oid.h" + + +void +bson_value_copy (const bson_value_t *src, /* IN */ + bson_value_t *dst) /* OUT */ +{ + BSON_ASSERT (src); + BSON_ASSERT (dst); + + dst->value_type = src->value_type; + + switch (src->value_type) { + case BSON_TYPE_DOUBLE: + dst->value.v_double = src->value.v_double; + break; + case BSON_TYPE_UTF8: + dst->value.v_utf8.len = src->value.v_utf8.len; + dst->value.v_utf8.str = bson_malloc (src->value.v_utf8.len + 1); + memcpy ( + dst->value.v_utf8.str, src->value.v_utf8.str, dst->value.v_utf8.len); + dst->value.v_utf8.str[dst->value.v_utf8.len] = '\0'; + break; + case BSON_TYPE_DOCUMENT: + case BSON_TYPE_ARRAY: + dst->value.v_doc.data_len = src->value.v_doc.data_len; + dst->value.v_doc.data = bson_malloc (src->value.v_doc.data_len); + memcpy (dst->value.v_doc.data, + src->value.v_doc.data, + dst->value.v_doc.data_len); + break; + case BSON_TYPE_BINARY: + dst->value.v_binary.subtype = src->value.v_binary.subtype; + dst->value.v_binary.data_len = src->value.v_binary.data_len; + dst->value.v_binary.data = bson_malloc (src->value.v_binary.data_len); + memcpy (dst->value.v_binary.data, + src->value.v_binary.data, + dst->value.v_binary.data_len); + break; + case BSON_TYPE_OID: + bson_oid_copy (&src->value.v_oid, &dst->value.v_oid); + break; + case BSON_TYPE_BOOL: + dst->value.v_bool = src->value.v_bool; + break; + case BSON_TYPE_DATE_TIME: + dst->value.v_datetime = src->value.v_datetime; + break; + case BSON_TYPE_REGEX: + dst->value.v_regex.regex = bson_strdup (src->value.v_regex.regex); + dst->value.v_regex.options = bson_strdup (src->value.v_regex.options); + break; + case BSON_TYPE_DBPOINTER: + dst->value.v_dbpointer.collection_len = + src->value.v_dbpointer.collection_len; + dst->value.v_dbpointer.collection = + bson_malloc (src->value.v_dbpointer.collection_len + 1); + memcpy (dst->value.v_dbpointer.collection, + src->value.v_dbpointer.collection, + dst->value.v_dbpointer.collection_len); + dst->value.v_dbpointer.collection[dst->value.v_dbpointer.collection_len] = + '\0'; + bson_oid_copy (&src->value.v_dbpointer.oid, &dst->value.v_dbpointer.oid); + break; + case BSON_TYPE_CODE: + dst->value.v_code.code_len = src->value.v_code.code_len; + dst->value.v_code.code = bson_malloc (src->value.v_code.code_len + 1); + memcpy (dst->value.v_code.code, + src->value.v_code.code, + dst->value.v_code.code_len); + dst->value.v_code.code[dst->value.v_code.code_len] = '\0'; + break; + case BSON_TYPE_SYMBOL: + dst->value.v_symbol.len = src->value.v_symbol.len; + dst->value.v_symbol.symbol = bson_malloc (src->value.v_symbol.len + 1); + memcpy (dst->value.v_symbol.symbol, + src->value.v_symbol.symbol, + dst->value.v_symbol.len); + dst->value.v_symbol.symbol[dst->value.v_symbol.len] = '\0'; + break; + case BSON_TYPE_CODEWSCOPE: + dst->value.v_codewscope.code_len = src->value.v_codewscope.code_len; + dst->value.v_codewscope.code = + bson_malloc (src->value.v_codewscope.code_len + 1); + memcpy (dst->value.v_codewscope.code, + src->value.v_codewscope.code, + dst->value.v_codewscope.code_len); + dst->value.v_codewscope.code[dst->value.v_codewscope.code_len] = '\0'; + dst->value.v_codewscope.scope_len = src->value.v_codewscope.scope_len; + dst->value.v_codewscope.scope_data = + bson_malloc (src->value.v_codewscope.scope_len); + memcpy (dst->value.v_codewscope.scope_data, + src->value.v_codewscope.scope_data, + dst->value.v_codewscope.scope_len); + break; + case BSON_TYPE_INT32: + dst->value.v_int32 = src->value.v_int32; + break; + case BSON_TYPE_TIMESTAMP: + dst->value.v_timestamp.timestamp = src->value.v_timestamp.timestamp; + dst->value.v_timestamp.increment = src->value.v_timestamp.increment; + break; + case BSON_TYPE_INT64: + dst->value.v_int64 = src->value.v_int64; + break; + case BSON_TYPE_DECIMAL128: + dst->value.v_decimal128 = src->value.v_decimal128; + break; + case BSON_TYPE_UNDEFINED: + case BSON_TYPE_NULL: + case BSON_TYPE_MAXKEY: + case BSON_TYPE_MINKEY: + break; + case BSON_TYPE_EOD: + default: + BSON_ASSERT (false); + return; + } +} + + +void +bson_value_destroy (bson_value_t *value) /* IN */ +{ + switch (value->value_type) { + case BSON_TYPE_UTF8: + bson_free (value->value.v_utf8.str); + break; + case BSON_TYPE_DOCUMENT: + case BSON_TYPE_ARRAY: + bson_free (value->value.v_doc.data); + break; + case BSON_TYPE_BINARY: + bson_free (value->value.v_binary.data); + break; + case BSON_TYPE_REGEX: + bson_free (value->value.v_regex.regex); + bson_free (value->value.v_regex.options); + break; + case BSON_TYPE_DBPOINTER: + bson_free (value->value.v_dbpointer.collection); + break; + case BSON_TYPE_CODE: + bson_free (value->value.v_code.code); + break; + case BSON_TYPE_SYMBOL: + bson_free (value->value.v_symbol.symbol); + break; + case BSON_TYPE_CODEWSCOPE: + bson_free (value->value.v_codewscope.code); + bson_free (value->value.v_codewscope.scope_data); + break; + case BSON_TYPE_DOUBLE: + case BSON_TYPE_UNDEFINED: + case BSON_TYPE_OID: + case BSON_TYPE_BOOL: + case BSON_TYPE_DATE_TIME: + case BSON_TYPE_NULL: + case BSON_TYPE_INT32: + case BSON_TYPE_TIMESTAMP: + case BSON_TYPE_INT64: + case BSON_TYPE_DECIMAL128: + case BSON_TYPE_MAXKEY: + case BSON_TYPE_MINKEY: + case BSON_TYPE_EOD: + default: + break; + } +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-value.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-value.h new file mode 100644 index 0000000000000000000000000000000000000000..141bcee3e2612021ba4e44db5226f7ae3e4de664 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-value.h @@ -0,0 +1,38 @@ +/* + * Copyright 2014 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_VALUE_H +#define BSON_VALUE_H + + +#include "bson-macros.h" +#include "bson-types.h" + + +BSON_BEGIN_DECLS + + +BSON_EXPORT (void) +bson_value_copy (const bson_value_t *src, bson_value_t *dst); +BSON_EXPORT (void) +bson_value_destroy (bson_value_t *value); + + +BSON_END_DECLS + + +#endif /* BSON_VALUE_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-writer.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-writer.c new file mode 100644 index 0000000000000000000000000000000000000000..dcce06ade6da71a5425fe6d6d18481935d789f75 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-writer.c @@ -0,0 +1,271 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "bson-private.h" +#include "bson-writer.h" + + +struct _bson_writer_t { + bool ready; + uint8_t **buf; + size_t *buflen; + size_t offset; + bson_realloc_func realloc_func; + void *realloc_func_ctx; + bson_t b; +}; + + +/* + *-------------------------------------------------------------------------- + * + * bson_writer_new -- + * + * Creates a new instance of bson_writer_t using the buffer, length, + * offset, and realloc() function supplied. + * + * The caller is expected to clean up the structure when finished + * using bson_writer_destroy(). + * + * Parameters: + * @buf: (inout): A pointer to a target buffer. + * @buflen: (inout): A pointer to the buffer length. + * @offset: The offset in the target buffer to start from. + * @realloc_func: A realloc() style function or NULL. + * + * Returns: + * A newly allocated bson_writer_t that should be freed with + * bson_writer_destroy(). + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bson_writer_t * +bson_writer_new (uint8_t **buf, /* IN */ + size_t *buflen, /* IN */ + size_t offset, /* IN */ + bson_realloc_func realloc_func, /* IN */ + void *realloc_func_ctx) /* IN */ +{ + bson_writer_t *writer; + + writer = bson_malloc0 (sizeof *writer); + writer->buf = buf; + writer->buflen = buflen; + writer->offset = offset; + writer->realloc_func = realloc_func; + writer->realloc_func_ctx = realloc_func_ctx; + writer->ready = true; + + return writer; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_writer_destroy -- + * + * Cleanup after @writer and release any allocated memory. Note that + * the buffer supplied to bson_writer_new() is NOT freed from this + * method. The caller is responsible for that. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_writer_destroy (bson_writer_t *writer) /* IN */ +{ + bson_free (writer); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_writer_get_length -- + * + * Fetches the current length of the content written by the buffer + * (including the initial offset). This includes a partly written + * document currently being written. + * + * This is useful if you want to check to see if you've passed a given + * memory boundry that cannot be sent in a packet. See + * bson_writer_rollback() to abort the current document being written. + * + * Returns: + * The number of bytes written plus initial offset. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +size_t +bson_writer_get_length (bson_writer_t *writer) /* IN */ +{ + return writer->offset + writer->b.len; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_writer_begin -- + * + * Begins writing a new document. The caller may use the bson + * structure to write out a new BSON document. When completed, the + * caller must call either bson_writer_end() or + * bson_writer_rollback(). + * + * Parameters: + * @writer: A bson_writer_t. + * @bson: (out): A location for a bson_t*. + * + * Returns: + * true if the underlying realloc was successful; otherwise false. + * + * Side effects: + * @bson is initialized if true is returned. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_writer_begin (bson_writer_t *writer, /* IN */ + bson_t **bson) /* OUT */ +{ + bson_impl_alloc_t *b; + bool grown = false; + + BSON_ASSERT (writer); + BSON_ASSERT (writer->ready); + BSON_ASSERT (bson); + + writer->ready = false; + + memset (&writer->b, 0, sizeof (bson_t)); + + b = (bson_impl_alloc_t *) &writer->b; + b->flags = BSON_FLAG_STATIC | BSON_FLAG_NO_FREE; + b->len = 5; + b->parent = NULL; + b->buf = writer->buf; + b->buflen = writer->buflen; + b->offset = writer->offset; + b->alloc = NULL; + b->alloclen = 0; + b->realloc = writer->realloc_func; + b->realloc_func_ctx = writer->realloc_func_ctx; + + while ((writer->offset + writer->b.len) > *writer->buflen) { + if (!writer->realloc_func) { + memset (&writer->b, 0, sizeof (bson_t)); + writer->ready = true; + return false; + } + grown = true; + + if (!*writer->buflen) { + *writer->buflen = 64; + } else { + (*writer->buflen) *= 2; + } + } + + if (grown) { + *writer->buf = writer->realloc_func ( + *writer->buf, *writer->buflen, writer->realloc_func_ctx); + } + + memset ((*writer->buf) + writer->offset + 1, 0, 5); + (*writer->buf)[writer->offset] = 5; + + *bson = &writer->b; + + return true; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_writer_end -- + * + * Complete writing of a bson_writer_t to the buffer supplied. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_writer_end (bson_writer_t *writer) /* IN */ +{ + BSON_ASSERT (writer); + BSON_ASSERT (!writer->ready); + + writer->offset += writer->b.len; + memset (&writer->b, 0, sizeof (bson_t)); + writer->ready = true; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_writer_rollback -- + * + * Abort the appending of the current bson_t to the memory region + * managed by @writer. This is useful if you detected that you went + * past a particular memory limit. For example, MongoDB has 48MB + * message limits. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void +bson_writer_rollback (bson_writer_t *writer) /* IN */ +{ + BSON_ASSERT (writer); + + if (writer->b.len) { + memset (&writer->b, 0, sizeof (bson_t)); + } + + writer->ready = true; +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-writer.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-writer.h new file mode 100644 index 0000000000000000000000000000000000000000..9fd6548acdfc9e5290a6f057179dc713ebf8e447 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson-writer.h @@ -0,0 +1,63 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_WRITER_H +#define BSON_WRITER_H + + +#include "bson.h" + + +BSON_BEGIN_DECLS + + +/** + * bson_writer_t: + * + * The bson_writer_t structure is a helper for writing a series of BSON + * documents to a single malloc() buffer. You can provide a realloc() style + * function to grow the buffer as you go. + * + * This is useful if you want to build a series of BSON documents right into + * the target buffer for an outgoing packet. The offset parameter allows you to + * start at an offset of the target buffer. + */ +typedef struct _bson_writer_t bson_writer_t; + + +BSON_EXPORT (bson_writer_t *) +bson_writer_new (uint8_t **buf, + size_t *buflen, + size_t offset, + bson_realloc_func realloc_func, + void *realloc_func_ctx); +BSON_EXPORT (void) +bson_writer_destroy (bson_writer_t *writer); +BSON_EXPORT (size_t) +bson_writer_get_length (bson_writer_t *writer); +BSON_EXPORT (bool) +bson_writer_begin (bson_writer_t *writer, bson_t **bson); +BSON_EXPORT (void) +bson_writer_end (bson_writer_t *writer); +BSON_EXPORT (void) +bson_writer_rollback (bson_writer_t *writer); + + +BSON_END_DECLS + + +#endif /* BSON_WRITER_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson.c b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson.c new file mode 100644 index 0000000000000000000000000000000000000000..d5483d3e2dd6b659fba417cf55a9dbdd99c1abe1 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson.c @@ -0,0 +1,3565 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "bson.h" +#include "bson-config.h" +#include "b64_ntop.h" +#include "bson-private.h" +#include "bson-string.h" + +#include <string.h> +#include <math.h> + + +#ifndef BSON_MAX_RECURSION +#define BSON_MAX_RECURSION 200 +#endif + + +typedef enum { + BSON_VALIDATE_PHASE_START, + BSON_VALIDATE_PHASE_TOP, + BSON_VALIDATE_PHASE_LF_REF_KEY, + BSON_VALIDATE_PHASE_LF_REF_UTF8, + BSON_VALIDATE_PHASE_LF_ID_KEY, + BSON_VALIDATE_PHASE_LF_DB_KEY, + BSON_VALIDATE_PHASE_LF_DB_UTF8, + BSON_VALIDATE_PHASE_NOT_DBREF, +} bson_validate_phase_t; + + +/* + * Structures. + */ +typedef struct { + bson_validate_flags_t flags; + ssize_t err_offset; + bson_validate_phase_t phase; + bson_error_t error; +} bson_validate_state_t; + + +typedef struct { + uint32_t count; + bool keys; + ssize_t *err_offset; + uint32_t depth; + bson_string_t *str; +} bson_json_state_t; + + +/* + * Forward declarations. + */ +static bool +_bson_as_extended_json_visit_array (const bson_iter_t *iter, + const char *key, + const bson_t *v_array, + void *data); +static bool +_bson_as_json_visit_array (const bson_iter_t *iter, + const char *key, + const bson_t *v_array, + void *data); +static bool +_bson_as_extended_json_visit_document (const bson_iter_t *iter, + const char *key, + const bson_t *v_document, + void *data); +static bool +_bson_as_json_visit_document (const bson_iter_t *iter, + const char *key, + const bson_t *v_document, + void *data); + + +static uint64_t +_int64_timestamp (uint32_t timestamp, uint32_t increment) +{ + return (((uint64_t) timestamp) << 32) | (uint64_t) increment; +} + + +/* + * Globals. + */ +static const uint8_t gZero; + +/* + *-------------------------------------------------------------------------- + * + * _bson_impl_inline_grow -- + * + * Document growth implementation for documents that currently + * contain stack based buffers. The document may be switched to + * a malloc based buffer. + * + * Returns: + * true if successful; otherwise false indicating INT_MAX overflow. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static bool +_bson_impl_inline_grow (bson_impl_inline_t *impl, /* IN */ + size_t size) /* IN */ +{ + bson_impl_alloc_t *alloc = (bson_impl_alloc_t *) impl; + uint8_t *data; + size_t req; + + if (((size_t) impl->len + size) <= sizeof impl->data) { + return true; + } + + req = bson_next_power_of_two (impl->len + size); + + if (req <= INT32_MAX) { + data = bson_malloc (req); + + memcpy (data, impl->data, impl->len); + alloc->flags &= ~BSON_FLAG_INLINE; + alloc->parent = NULL; + alloc->depth = 0; + alloc->buf = &alloc->alloc; + alloc->buflen = &alloc->alloclen; + alloc->offset = 0; + alloc->alloc = data; + alloc->alloclen = req; + alloc->realloc = bson_realloc_ctx; + alloc->realloc_func_ctx = NULL; + + return true; + } + + return false; +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_impl_alloc_grow -- + * + * Document growth implementation for documents containing malloc + * based buffers. + * + * Returns: + * true if successful; otherwise false indicating INT_MAX overflow. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static bool +_bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */ + size_t size) /* IN */ +{ + size_t req; + + /* + * Determine how many bytes we need for this document in the buffer + * including necessary trailing bytes for parent documents. + */ + req = (impl->offset + impl->len + size + impl->depth); + + if (req <= *impl->buflen) { + return true; + } + + req = bson_next_power_of_two (req); + + if ((req <= INT32_MAX) && impl->realloc) { + *impl->buf = impl->realloc (*impl->buf, req, impl->realloc_func_ctx); + *impl->buflen = req; + return true; + } + + return false; +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_grow -- + * + * Grows the bson_t structure to be large enough to contain @size + * bytes. + * + * Returns: + * true if successful, false if the size would overflow. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static bool +_bson_grow (bson_t *bson, /* IN */ + uint32_t size) /* IN */ +{ + if ((bson->flags & BSON_FLAG_INLINE)) { + return _bson_impl_inline_grow ((bson_impl_inline_t *) bson, size); + } + + return _bson_impl_alloc_grow ((bson_impl_alloc_t *) bson, size); +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_data -- + * + * A helper function to return the contents of the bson document + * taking into account the polymorphic nature of bson_t. + * + * Returns: + * A buffer which should not be modified or freed. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static BSON_INLINE uint8_t * +_bson_data (const bson_t *bson) /* IN */ +{ + if ((bson->flags & BSON_FLAG_INLINE)) { + return ((bson_impl_inline_t *) bson)->data; + } else { + bson_impl_alloc_t *impl = (bson_impl_alloc_t *) bson; + return (*impl->buf) + impl->offset; + } +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_encode_length -- + * + * Helper to encode the length of the bson_t in the first 4 bytes + * of the bson document. Little endian format is used as specified + * by bsonspec. + * + * Returns: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static BSON_INLINE void +_bson_encode_length (bson_t *bson) /* IN */ +{ +#if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN + memcpy (_bson_data (bson), &bson->len, sizeof (bson->len)); +#else + uint32_t length_le = BSON_UINT32_TO_LE (bson->len); + memcpy (_bson_data (bson), &length_le, sizeof (length_le)); +#endif +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_append_va -- + * + * Appends the length,buffer pairs to the bson_t. @n_bytes is an + * optimization to perform one array growth rather than many small + * growths. + * + * @bson: A bson_t + * @n_bytes: The number of bytes to append to the document. + * @n_pairs: The number of length,buffer pairs. + * @first_len: Length of first buffer. + * @first_data: First buffer. + * @args: va_list of additional tuples. + * + * Returns: + * true if the bytes were appended successfully. + * false if it bson would overflow INT_MAX. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static BSON_INLINE bool +_bson_append_va (bson_t *bson, /* IN */ + uint32_t n_bytes, /* IN */ + uint32_t n_pairs, /* IN */ + uint32_t first_len, /* IN */ + const uint8_t *first_data, /* IN */ + va_list args) /* IN */ +{ + const uint8_t *data; + uint32_t data_len; + uint8_t *buf; + + BSON_ASSERT (!(bson->flags & BSON_FLAG_IN_CHILD)); + BSON_ASSERT (!(bson->flags & BSON_FLAG_RDONLY)); + + if (BSON_UNLIKELY (!_bson_grow (bson, n_bytes))) { + return false; + } + + data = first_data; + data_len = first_len; + + buf = _bson_data (bson) + bson->len - 1; + + do { + n_pairs--; + memcpy (buf, data, data_len); + bson->len += data_len; + buf += data_len; + + if (n_pairs) { + data_len = va_arg (args, uint32_t); + data = va_arg (args, const uint8_t *); + } + } while (n_pairs); + + _bson_encode_length (bson); + + *buf = '\0'; + + return true; +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_append -- + * + * Variadic function to append length,buffer pairs to a bson_t. If the + * append would cause the bson_t to overflow a 32-bit length, it will + * return false and no append will have occurred. + * + * Parameters: + * @bson: A bson_t. + * @n_pairs: Number of length,buffer pairs. + * @n_bytes: the total number of bytes being appended. + * @first_len: Length of first buffer. + * @first_data: First buffer. + * + * Returns: + * true if successful; otherwise false indicating INT_MAX overflow. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static bool +_bson_append (bson_t *bson, /* IN */ + uint32_t n_pairs, /* IN */ + uint32_t n_bytes, /* IN */ + uint32_t first_len, /* IN */ + const uint8_t *first_data, /* IN */ + ...) +{ + va_list args; + bool ok; + + BSON_ASSERT (n_pairs); + BSON_ASSERT (first_len); + BSON_ASSERT (first_data); + + /* + * Check to see if this append would overflow 32-bit signed integer. I know + * what you're thinking. BSON uses a signed 32-bit length field? Yeah. It + * does. + */ + if (BSON_UNLIKELY (n_bytes > (BSON_MAX_SIZE - bson->len))) { + return false; + } + + va_start (args, first_data); + ok = _bson_append_va (bson, n_bytes, n_pairs, first_len, first_data, args); + va_end (args); + + return ok; +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_append_bson_begin -- + * + * Begin appending a subdocument or subarray to the document using + * the key provided by @key. + * + * If @key_length is < 0, then strlen() will be called on @key + * to determine the length. + * + * @key_type MUST be either BSON_TYPE_DOCUMENT or BSON_TYPE_ARRAY. + * + * Returns: + * true if successful; otherwise false indicating INT_MAX overflow. + * + * Side effects: + * @child is initialized if true is returned. + * + *-------------------------------------------------------------------------- + */ + +static bool +_bson_append_bson_begin (bson_t *bson, /* IN */ + const char *key, /* IN */ + int key_length, /* IN */ + bson_type_t child_type, /* IN */ + bson_t *child) /* OUT */ +{ + const uint8_t type = child_type; + const uint8_t empty[5] = {5}; + bson_impl_alloc_t *aparent = (bson_impl_alloc_t *) bson; + bson_impl_alloc_t *achild = (bson_impl_alloc_t *) child; + + BSON_ASSERT (!(bson->flags & BSON_FLAG_RDONLY)); + BSON_ASSERT (!(bson->flags & BSON_FLAG_IN_CHILD)); + BSON_ASSERT (key); + BSON_ASSERT ((child_type == BSON_TYPE_DOCUMENT) || + (child_type == BSON_TYPE_ARRAY)); + BSON_ASSERT (child); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + /* + * If the parent is an inline bson_t, then we need to convert + * it to a heap allocated buffer. This makes extending buffers + * of child bson documents much simpler logic, as they can just + * realloc the *buf pointer. + */ + if ((bson->flags & BSON_FLAG_INLINE)) { + BSON_ASSERT (bson->len <= 120); + if (!_bson_grow (bson, 128 - bson->len)) { + return false; + } + BSON_ASSERT (!(bson->flags & BSON_FLAG_INLINE)); + } + + /* + * Append the type and key for the field. + */ + if (!_bson_append (bson, + 4, + (1 + key_length + 1 + 5), + 1, + &type, + key_length, + key, + 1, + &gZero, + 5, + empty)) { + return false; + } + + /* + * Mark the document as working on a child document so that no + * further modifications can happen until the caller has called + * bson_append_{document,array}_end(). + */ + bson->flags |= BSON_FLAG_IN_CHILD; + + /* + * Initialize the child bson_t structure and point it at the parents + * buffers. This allows us to realloc directly from the child without + * walking up to the parent bson_t. + */ + achild->flags = (BSON_FLAG_CHILD | BSON_FLAG_NO_FREE | BSON_FLAG_STATIC); + + if ((bson->flags & BSON_FLAG_CHILD)) { + achild->depth = ((bson_impl_alloc_t *) bson)->depth + 1; + } else { + achild->depth = 1; + } + + achild->parent = bson; + achild->buf = aparent->buf; + achild->buflen = aparent->buflen; + achild->offset = aparent->offset + aparent->len - 1 - 5; + achild->len = 5; + achild->alloc = NULL; + achild->alloclen = 0; + achild->realloc = aparent->realloc; + achild->realloc_func_ctx = aparent->realloc_func_ctx; + + return true; +} + + +/* + *-------------------------------------------------------------------------- + * + * _bson_append_bson_end -- + * + * Complete a call to _bson_append_bson_begin. + * + * Returns: + * true if successful. + * + * Side effects: + * @child is destroyed and no longer valid after calling this + * function. + * + *-------------------------------------------------------------------------- + */ + +static bool +_bson_append_bson_end (bson_t *bson, /* IN */ + bson_t *child) /* IN */ +{ + BSON_ASSERT (bson); + BSON_ASSERT ((bson->flags & BSON_FLAG_IN_CHILD)); + BSON_ASSERT (!(child->flags & BSON_FLAG_IN_CHILD)); + + /* + * Unmark the IN_CHILD flag. + */ + bson->flags &= ~BSON_FLAG_IN_CHILD; + + /* + * Now that we are done building the sub-document, add the size to the + * parent, not including the default 5 byte empty document already added. + */ + bson->len = (bson->len + child->len - 5); + + /* + * Ensure we have a \0 byte at the end and proper length encoded at + * the beginning of the document. + */ + _bson_data (bson)[bson->len - 1] = '\0'; + _bson_encode_length (bson); + + return true; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_append_array_begin -- + * + * Start appending a new array. + * + * Use @child to append to the data area for the given field. + * + * It is a programming error to call any other bson function on + * @bson until bson_append_array_end() has been called. It is + * valid to call bson_append*() functions on @child. + * + * This function is useful to allow building nested documents using + * a single buffer owned by the top-level bson document. + * + * Returns: + * true if successful; otherwise false and @child is invalid. + * + * Side effects: + * @child is initialized if true is returned. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_append_array_begin (bson_t *bson, /* IN */ + const char *key, /* IN */ + int key_length, /* IN */ + bson_t *child) /* IN */ +{ + BSON_ASSERT (bson); + BSON_ASSERT (key); + BSON_ASSERT (child); + + return _bson_append_bson_begin ( + bson, key, key_length, BSON_TYPE_ARRAY, child); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_append_array_end -- + * + * Complete a call to bson_append_array_begin(). + * + * It is safe to append other fields to @bson after calling this + * function. + * + * Returns: + * true if successful. + * + * Side effects: + * @child is invalid after calling this function. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_append_array_end (bson_t *bson, /* IN */ + bson_t *child) /* IN */ +{ + BSON_ASSERT (bson); + BSON_ASSERT (child); + + return _bson_append_bson_end (bson, child); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_append_document_begin -- + * + * Start appending a new document. + * + * Use @child to append to the data area for the given field. + * + * It is a programming error to call any other bson function on + * @bson until bson_append_document_end() has been called. It is + * valid to call bson_append*() functions on @child. + * + * This function is useful to allow building nested documents using + * a single buffer owned by the top-level bson document. + * + * Returns: + * true if successful; otherwise false and @child is invalid. + * + * Side effects: + * @child is initialized if true is returned. + * + *-------------------------------------------------------------------------- + */ +bool +bson_append_document_begin (bson_t *bson, /* IN */ + const char *key, /* IN */ + int key_length, /* IN */ + bson_t *child) /* IN */ +{ + BSON_ASSERT (bson); + BSON_ASSERT (key); + BSON_ASSERT (child); + + return _bson_append_bson_begin ( + bson, key, key_length, BSON_TYPE_DOCUMENT, child); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_append_document_end -- + * + * Complete a call to bson_append_document_begin(). + * + * It is safe to append new fields to @bson after calling this + * function, if true is returned. + * + * Returns: + * true if successful; otherwise false indicating INT_MAX overflow. + * + * Side effects: + * @child is destroyed and invalid after calling this function. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_append_document_end (bson_t *bson, /* IN */ + bson_t *child) /* IN */ +{ + BSON_ASSERT (bson); + BSON_ASSERT (child); + + return _bson_append_bson_end (bson, child); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_append_array -- + * + * Append an array to @bson. + * + * Generally, bson_append_array_begin() will result in faster code + * since few buffers need to be malloced. + * + * Returns: + * true if successful; otherwise false indicating INT_MAX overflow. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_append_array (bson_t *bson, /* IN */ + const char *key, /* IN */ + int key_length, /* IN */ + const bson_t *array) /* IN */ +{ + static const uint8_t type = BSON_TYPE_ARRAY; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + BSON_ASSERT (array); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + /* + * Let's be a bit pedantic and ensure the array has properly formatted key + * names. We will verify this simply by checking the first element for "0" + * if the array is non-empty. + */ + if (array && !bson_empty (array)) { + bson_iter_t iter; + + if (bson_iter_init (&iter, array) && bson_iter_next (&iter)) { + if (0 != strcmp ("0", bson_iter_key (&iter))) { + fprintf (stderr, + "%s(): invalid array detected. first element of array " + "parameter is not \"0\".\n", + BSON_FUNC); + } + } + } + + return _bson_append (bson, + 4, + (1 + key_length + 1 + array->len), + 1, + &type, + key_length, + key, + 1, + &gZero, + array->len, + _bson_data (array)); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_append_binary -- + * + * Append binary data to @bson. The field will have the + * BSON_TYPE_BINARY type. + * + * Parameters: + * @subtype: the BSON Binary Subtype. See bsonspec.org for more + * information. + * @binary: a pointer to the raw binary data. + * @length: the size of @binary in bytes. + * + * Returns: + * true if successful; otherwise false. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_append_binary (bson_t *bson, /* IN */ + const char *key, /* IN */ + int key_length, /* IN */ + unsigned int subtype, /* IN */ + const uint8_t *binary, /* IN */ + uint32_t length) /* IN */ +{ + static const uint8_t type = BSON_TYPE_BINARY; + uint32_t length_le; + uint32_t deprecated_length_le; + uint8_t subtype8 = 0; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + BSON_ASSERT (binary); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + subtype8 = subtype; + + if (subtype == BSON_SUBTYPE_BINARY_DEPRECATED) { + length_le = BSON_UINT32_TO_LE (length + 4); + deprecated_length_le = BSON_UINT32_TO_LE (length); + + return _bson_append (bson, + 7, + (1 + key_length + 1 + 4 + 1 + 4 + length), + 1, + &type, + key_length, + key, + 1, + &gZero, + 4, + &length_le, + 1, + &subtype8, + 4, + &deprecated_length_le, + length, + binary); + } else { + length_le = BSON_UINT32_TO_LE (length); + + return _bson_append (bson, + 6, + (1 + key_length + 1 + 4 + 1 + length), + 1, + &type, + key_length, + key, + 1, + &gZero, + 4, + &length_le, + 1, + &subtype8, + length, + binary); + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_append_bool -- + * + * Append a new field to @bson with the name @key. The value is + * a boolean indicated by @value. + * + * Returns: + * true if succesful; otherwise false. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_append_bool (bson_t *bson, /* IN */ + const char *key, /* IN */ + int key_length, /* IN */ + bool value) /* IN */ +{ + static const uint8_t type = BSON_TYPE_BOOL; + uint8_t abyte = !!value; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + return _bson_append (bson, + 4, + (1 + key_length + 1 + 1), + 1, + &type, + key_length, + key, + 1, + &gZero, + 1, + &abyte); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_append_code -- + * + * Append a new field to @bson containing javascript code. + * + * @javascript MUST be a zero terminated UTF-8 string. It MUST NOT + * containing embedded \0 characters. + * + * Returns: + * true if successful; otherwise false. + * + * Side effects: + * None. + * + * See also: + * bson_append_code_with_scope(). + * + *-------------------------------------------------------------------------- + */ + +bool +bson_append_code (bson_t *bson, /* IN */ + const char *key, /* IN */ + int key_length, /* IN */ + const char *javascript) /* IN */ +{ + static const uint8_t type = BSON_TYPE_CODE; + uint32_t length; + uint32_t length_le; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + BSON_ASSERT (javascript); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + length = (int) strlen (javascript) + 1; + length_le = BSON_UINT32_TO_LE (length); + + return _bson_append (bson, + 5, + (1 + key_length + 1 + 4 + length), + 1, + &type, + key_length, + key, + 1, + &gZero, + 4, + &length_le, + length, + javascript); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_append_code_with_scope -- + * + * Append a new field to @bson containing javascript code with + * supplied scope. + * + * Returns: + * true if successful; otherwise false. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_append_code_with_scope (bson_t *bson, /* IN */ + const char *key, /* IN */ + int key_length, /* IN */ + const char *javascript, /* IN */ + const bson_t *scope) /* IN */ +{ + static const uint8_t type = BSON_TYPE_CODEWSCOPE; + uint32_t codews_length_le; + uint32_t codews_length; + uint32_t js_length_le; + uint32_t js_length; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + BSON_ASSERT (javascript); + + if (scope == NULL) { + return bson_append_code (bson, key, key_length, javascript); + } + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + js_length = (int) strlen (javascript) + 1; + js_length_le = BSON_UINT32_TO_LE (js_length); + + codews_length = 4 + 4 + js_length + scope->len; + codews_length_le = BSON_UINT32_TO_LE (codews_length); + + return _bson_append (bson, + 7, + (1 + key_length + 1 + 4 + 4 + js_length + scope->len), + 1, + &type, + key_length, + key, + 1, + &gZero, + 4, + &codews_length_le, + 4, + &js_length_le, + js_length, + javascript, + scope->len, + _bson_data (scope)); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_append_dbpointer -- + * + * This BSON data type is DEPRECATED. + * + * Append a BSON dbpointer field to @bson. + * + * Returns: + * true if successful; otherwise false. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_append_dbpointer (bson_t *bson, /* IN */ + const char *key, /* IN */ + int key_length, /* IN */ + const char *collection, /* IN */ + const bson_oid_t *oid) +{ + static const uint8_t type = BSON_TYPE_DBPOINTER; + uint32_t length; + uint32_t length_le; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + BSON_ASSERT (collection); + BSON_ASSERT (oid); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + length = (int) strlen (collection) + 1; + length_le = BSON_UINT32_TO_LE (length); + + return _bson_append (bson, + 6, + (1 + key_length + 1 + 4 + length + 12), + 1, + &type, + key_length, + key, + 1, + &gZero, + 4, + &length_le, + length, + collection, + 12, + oid); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_append_document -- + * + * Append a new field to @bson containing a BSON document. + * + * In general, using bson_append_document_begin() results in faster + * code and less memory fragmentation. + * + * Returns: + * true if successful; otherwise false. + * + * Side effects: + * None. + * + * See also: + * bson_append_document_begin(). + * + *-------------------------------------------------------------------------- + */ + +bool +bson_append_document (bson_t *bson, /* IN */ + const char *key, /* IN */ + int key_length, /* IN */ + const bson_t *value) /* IN */ +{ + static const uint8_t type = BSON_TYPE_DOCUMENT; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + BSON_ASSERT (value); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + return _bson_append (bson, + 4, + (1 + key_length + 1 + value->len), + 1, + &type, + key_length, + key, + 1, + &gZero, + value->len, + _bson_data (value)); +} + + +bool +bson_append_double (bson_t *bson, const char *key, int key_length, double value) +{ + static const uint8_t type = BSON_TYPE_DOUBLE; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + +#if BSON_BYTE_ORDER == BSON_BIG_ENDIAN + value = BSON_DOUBLE_TO_LE (value); +#endif + + return _bson_append (bson, + 4, + (1 + key_length + 1 + 8), + 1, + &type, + key_length, + key, + 1, + &gZero, + 8, + &value); +} + + +bool +bson_append_int32 (bson_t *bson, const char *key, int key_length, int32_t value) +{ + static const uint8_t type = BSON_TYPE_INT32; + uint32_t value_le; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + value_le = BSON_UINT32_TO_LE (value); + + return _bson_append (bson, + 4, + (1 + key_length + 1 + 4), + 1, + &type, + key_length, + key, + 1, + &gZero, + 4, + &value_le); +} + + +bool +bson_append_int64 (bson_t *bson, const char *key, int key_length, int64_t value) +{ + static const uint8_t type = BSON_TYPE_INT64; + uint64_t value_le; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + value_le = BSON_UINT64_TO_LE (value); + + return _bson_append (bson, + 4, + (1 + key_length + 1 + 8), + 1, + &type, + key_length, + key, + 1, + &gZero, + 8, + &value_le); +} + + +bool +bson_append_decimal128 (bson_t *bson, + const char *key, + int key_length, + const bson_decimal128_t *value) +{ + static const uint8_t type = BSON_TYPE_DECIMAL128; + uint64_t value_le[2]; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + BSON_ASSERT (value); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + value_le[0] = BSON_UINT64_TO_LE (value->low); + value_le[1] = BSON_UINT64_TO_LE (value->high); + + return _bson_append (bson, + 4, + (1 + key_length + 1 + 16), + 1, + &type, + key_length, + key, + 1, + &gZero, + 16, + value_le); +} + + +bool +bson_append_iter (bson_t *bson, + const char *key, + int key_length, + const bson_iter_t *iter) +{ + bool ret = false; + + BSON_ASSERT (bson); + BSON_ASSERT (iter); + + if (!key) { + key = bson_iter_key (iter); + key_length = -1; + } + + switch (bson_iter_type_unsafe (iter)) { + case BSON_TYPE_EOD: + return false; + case BSON_TYPE_DOUBLE: + ret = bson_append_double (bson, key, key_length, bson_iter_double (iter)); + break; + case BSON_TYPE_UTF8: { + uint32_t len = 0; + const char *str; + + str = bson_iter_utf8 (iter, &len); + ret = bson_append_utf8 (bson, key, key_length, str, len); + } break; + case BSON_TYPE_DOCUMENT: { + const uint8_t *buf = NULL; + uint32_t len = 0; + bson_t doc; + + bson_iter_document (iter, &len, &buf); + + if (bson_init_static (&doc, buf, len)) { + ret = bson_append_document (bson, key, key_length, &doc); + bson_destroy (&doc); + } + } break; + case BSON_TYPE_ARRAY: { + const uint8_t *buf = NULL; + uint32_t len = 0; + bson_t doc; + + bson_iter_array (iter, &len, &buf); + + if (bson_init_static (&doc, buf, len)) { + ret = bson_append_array (bson, key, key_length, &doc); + bson_destroy (&doc); + } + } break; + case BSON_TYPE_BINARY: { + const uint8_t *binary = NULL; + bson_subtype_t subtype = BSON_SUBTYPE_BINARY; + uint32_t len = 0; + + bson_iter_binary (iter, &subtype, &len, &binary); + ret = bson_append_binary (bson, key, key_length, subtype, binary, len); + } break; + case BSON_TYPE_UNDEFINED: + ret = bson_append_undefined (bson, key, key_length); + break; + case BSON_TYPE_OID: + ret = bson_append_oid (bson, key, key_length, bson_iter_oid (iter)); + break; + case BSON_TYPE_BOOL: + ret = bson_append_bool (bson, key, key_length, bson_iter_bool (iter)); + break; + case BSON_TYPE_DATE_TIME: + ret = bson_append_date_time ( + bson, key, key_length, bson_iter_date_time (iter)); + break; + case BSON_TYPE_NULL: + ret = bson_append_null (bson, key, key_length); + break; + case BSON_TYPE_REGEX: { + const char *regex; + const char *options; + + regex = bson_iter_regex (iter, &options); + ret = bson_append_regex (bson, key, key_length, regex, options); + } break; + case BSON_TYPE_DBPOINTER: { + const bson_oid_t *oid; + uint32_t len; + const char *collection; + + bson_iter_dbpointer (iter, &len, &collection, &oid); + ret = bson_append_dbpointer (bson, key, key_length, collection, oid); + } break; + case BSON_TYPE_CODE: { + uint32_t len; + const char *code; + + code = bson_iter_code (iter, &len); + ret = bson_append_code (bson, key, key_length, code); + } break; + case BSON_TYPE_SYMBOL: { + uint32_t len; + const char *symbol; + + symbol = bson_iter_symbol (iter, &len); + ret = bson_append_symbol (bson, key, key_length, symbol, len); + } break; + case BSON_TYPE_CODEWSCOPE: { + const uint8_t *scope = NULL; + uint32_t scope_len = 0; + uint32_t len = 0; + const char *javascript = NULL; + bson_t doc; + + javascript = bson_iter_codewscope (iter, &len, &scope_len, &scope); + + if (bson_init_static (&doc, scope, scope_len)) { + ret = bson_append_code_with_scope ( + bson, key, key_length, javascript, &doc); + bson_destroy (&doc); + } + } break; + case BSON_TYPE_INT32: + ret = bson_append_int32 (bson, key, key_length, bson_iter_int32 (iter)); + break; + case BSON_TYPE_TIMESTAMP: { + uint32_t ts; + uint32_t inc; + + bson_iter_timestamp (iter, &ts, &inc); + ret = bson_append_timestamp (bson, key, key_length, ts, inc); + } break; + case BSON_TYPE_INT64: + ret = bson_append_int64 (bson, key, key_length, bson_iter_int64 (iter)); + break; + case BSON_TYPE_DECIMAL128: { + bson_decimal128_t dec; + + if (!bson_iter_decimal128 (iter, &dec)) { + return false; + } + + ret = bson_append_decimal128 (bson, key, key_length, &dec); + } break; + case BSON_TYPE_MAXKEY: + ret = bson_append_maxkey (bson, key, key_length); + break; + case BSON_TYPE_MINKEY: + ret = bson_append_minkey (bson, key, key_length); + break; + default: + break; + } + + return ret; +} + + +bool +bson_append_maxkey (bson_t *bson, const char *key, int key_length) +{ + static const uint8_t type = BSON_TYPE_MAXKEY; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + return _bson_append ( + bson, 3, (1 + key_length + 1), 1, &type, key_length, key, 1, &gZero); +} + + +bool +bson_append_minkey (bson_t *bson, const char *key, int key_length) +{ + static const uint8_t type = BSON_TYPE_MINKEY; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + return _bson_append ( + bson, 3, (1 + key_length + 1), 1, &type, key_length, key, 1, &gZero); +} + + +bool +bson_append_null (bson_t *bson, const char *key, int key_length) +{ + static const uint8_t type = BSON_TYPE_NULL; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + return _bson_append ( + bson, 3, (1 + key_length + 1), 1, &type, key_length, key, 1, &gZero); +} + + +bool +bson_append_oid (bson_t *bson, + const char *key, + int key_length, + const bson_oid_t *value) +{ + static const uint8_t type = BSON_TYPE_OID; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + BSON_ASSERT (value); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + return _bson_append (bson, + 4, + (1 + key_length + 1 + 12), + 1, + &type, + key_length, + key, + 1, + &gZero, + 12, + value); +} + + +bool +bson_append_regex (bson_t *bson, + const char *key, + int key_length, + const char *regex, + const char *options) +{ + static const uint8_t type = BSON_TYPE_REGEX; + uint32_t regex_len; + uint32_t options_len; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + if (!regex) { + regex = ""; + } + + if (!options) { + options = ""; + } + + regex_len = (int) strlen (regex) + 1; + options_len = (int) strlen (options) + 1; + + return _bson_append (bson, + 5, + (1 + key_length + 1 + regex_len + options_len), + 1, + &type, + key_length, + key, + 1, + &gZero, + regex_len, + regex, + options_len, + options); +} + + +bool +bson_append_utf8 ( + bson_t *bson, const char *key, int key_length, const char *value, int length) +{ + static const uint8_t type = BSON_TYPE_UTF8; + uint32_t length_le; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + + if (BSON_UNLIKELY (!value)) { + return bson_append_null (bson, key, key_length); + } + + if (BSON_UNLIKELY (key_length < 0)) { + key_length = (int) strlen (key); + } + + if (BSON_UNLIKELY (length < 0)) { + length = (int) strlen (value); + } + + length_le = BSON_UINT32_TO_LE (length + 1); + + return _bson_append (bson, + 6, + (1 + key_length + 1 + 4 + length + 1), + 1, + &type, + key_length, + key, + 1, + &gZero, + 4, + &length_le, + length, + value, + 1, + &gZero); +} + + +bool +bson_append_symbol ( + bson_t *bson, const char *key, int key_length, const char *value, int length) +{ + static const uint8_t type = BSON_TYPE_SYMBOL; + uint32_t length_le; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + + if (!value) { + return bson_append_null (bson, key, key_length); + } + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + if (length < 0) { + length = (int) strlen (value); + } + + length_le = BSON_UINT32_TO_LE (length + 1); + + return _bson_append (bson, + 6, + (1 + key_length + 1 + 4 + length + 1), + 1, + &type, + key_length, + key, + 1, + &gZero, + 4, + &length_le, + length, + value, + 1, + &gZero); +} + + +bool +bson_append_time_t (bson_t *bson, const char *key, int key_length, time_t value) +{ +#ifdef BSON_OS_WIN32 + struct timeval tv = {(long) value, 0}; +#else + struct timeval tv = {value, 0}; +#endif + + BSON_ASSERT (bson); + BSON_ASSERT (key); + + return bson_append_timeval (bson, key, key_length, &tv); +} + + +bool +bson_append_timestamp (bson_t *bson, + const char *key, + int key_length, + uint32_t timestamp, + uint32_t increment) +{ + static const uint8_t type = BSON_TYPE_TIMESTAMP; + uint64_t value; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + value = BSON_UINT64_TO_LE (_int64_timestamp (timestamp, increment)); + + return _bson_append (bson, + 4, + (1 + key_length + 1 + 8), + 1, + &type, + key_length, + key, + 1, + &gZero, + 8, + &value); +} + + +bool +bson_append_now_utc (bson_t *bson, const char *key, int key_length) +{ + BSON_ASSERT (bson); + BSON_ASSERT (key); + BSON_ASSERT (key_length >= -1); + + return bson_append_time_t (bson, key, key_length, time (NULL)); +} + + +bool +bson_append_date_time (bson_t *bson, + const char *key, + int key_length, + int64_t value) +{ + static const uint8_t type = BSON_TYPE_DATE_TIME; + uint64_t value_le; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + value_le = BSON_UINT64_TO_LE (value); + + return _bson_append (bson, + 4, + (1 + key_length + 1 + 8), + 1, + &type, + key_length, + key, + 1, + &gZero, + 8, + &value_le); +} + + +bool +bson_append_timeval (bson_t *bson, + const char *key, + int key_length, + struct timeval *value) +{ + uint64_t unix_msec; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + BSON_ASSERT (value); + + unix_msec = + (((uint64_t) value->tv_sec) * 1000UL) + (value->tv_usec / 1000UL); + return bson_append_date_time (bson, key, key_length, unix_msec); +} + + +bool +bson_append_undefined (bson_t *bson, const char *key, int key_length) +{ + static const uint8_t type = BSON_TYPE_UNDEFINED; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + + if (key_length < 0) { + key_length = (int) strlen (key); + } + + return _bson_append ( + bson, 3, (1 + key_length + 1), 1, &type, key_length, key, 1, &gZero); +} + + +bool +bson_append_value (bson_t *bson, + const char *key, + int key_length, + const bson_value_t *value) +{ + bson_t local; + bool ret = false; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + BSON_ASSERT (value); + + switch (value->value_type) { + case BSON_TYPE_DOUBLE: + ret = bson_append_double (bson, key, key_length, value->value.v_double); + break; + case BSON_TYPE_UTF8: + ret = bson_append_utf8 (bson, + key, + key_length, + value->value.v_utf8.str, + value->value.v_utf8.len); + break; + case BSON_TYPE_DOCUMENT: + if (bson_init_static ( + &local, value->value.v_doc.data, value->value.v_doc.data_len)) { + ret = bson_append_document (bson, key, key_length, &local); + bson_destroy (&local); + } + break; + case BSON_TYPE_ARRAY: + if (bson_init_static ( + &local, value->value.v_doc.data, value->value.v_doc.data_len)) { + ret = bson_append_array (bson, key, key_length, &local); + bson_destroy (&local); + } + break; + case BSON_TYPE_BINARY: + ret = bson_append_binary (bson, + key, + key_length, + value->value.v_binary.subtype, + value->value.v_binary.data, + value->value.v_binary.data_len); + break; + case BSON_TYPE_UNDEFINED: + ret = bson_append_undefined (bson, key, key_length); + break; + case BSON_TYPE_OID: + ret = bson_append_oid (bson, key, key_length, &value->value.v_oid); + break; + case BSON_TYPE_BOOL: + ret = bson_append_bool (bson, key, key_length, value->value.v_bool); + break; + case BSON_TYPE_DATE_TIME: + ret = + bson_append_date_time (bson, key, key_length, value->value.v_datetime); + break; + case BSON_TYPE_NULL: + ret = bson_append_null (bson, key, key_length); + break; + case BSON_TYPE_REGEX: + ret = bson_append_regex (bson, + key, + key_length, + value->value.v_regex.regex, + value->value.v_regex.options); + break; + case BSON_TYPE_DBPOINTER: + ret = bson_append_dbpointer (bson, + key, + key_length, + value->value.v_dbpointer.collection, + &value->value.v_dbpointer.oid); + break; + case BSON_TYPE_CODE: + ret = bson_append_code (bson, key, key_length, value->value.v_code.code); + break; + case BSON_TYPE_SYMBOL: + ret = bson_append_symbol (bson, + key, + key_length, + value->value.v_symbol.symbol, + value->value.v_symbol.len); + break; + case BSON_TYPE_CODEWSCOPE: + if (bson_init_static (&local, + value->value.v_codewscope.scope_data, + value->value.v_codewscope.scope_len)) { + ret = bson_append_code_with_scope ( + bson, key, key_length, value->value.v_codewscope.code, &local); + bson_destroy (&local); + } + break; + case BSON_TYPE_INT32: + ret = bson_append_int32 (bson, key, key_length, value->value.v_int32); + break; + case BSON_TYPE_TIMESTAMP: + ret = bson_append_timestamp (bson, + key, + key_length, + value->value.v_timestamp.timestamp, + value->value.v_timestamp.increment); + break; + case BSON_TYPE_INT64: + ret = bson_append_int64 (bson, key, key_length, value->value.v_int64); + break; + case BSON_TYPE_DECIMAL128: + ret = bson_append_decimal128 ( + bson, key, key_length, &(value->value.v_decimal128)); + break; + case BSON_TYPE_MAXKEY: + ret = bson_append_maxkey (bson, key, key_length); + break; + case BSON_TYPE_MINKEY: + ret = bson_append_minkey (bson, key, key_length); + break; + case BSON_TYPE_EOD: + default: + break; + } + + return ret; +} + + +void +bson_init (bson_t *bson) +{ + bson_impl_inline_t *impl = (bson_impl_inline_t *) bson; + + BSON_ASSERT (bson); + + impl->flags = BSON_FLAG_INLINE | BSON_FLAG_STATIC; + impl->len = 5; + impl->data[0] = 5; + impl->data[1] = 0; + impl->data[2] = 0; + impl->data[3] = 0; + impl->data[4] = 0; +} + + +void +bson_reinit (bson_t *bson) +{ + uint8_t *data; + + BSON_ASSERT (bson); + + data = _bson_data (bson); + + bson->len = 5; + + data[0] = 5; + data[1] = 0; + data[2] = 0; + data[3] = 0; + data[4] = 0; +} + + +bool +bson_init_static (bson_t *bson, const uint8_t *data, size_t length) +{ + bson_impl_alloc_t *impl = (bson_impl_alloc_t *) bson; + uint32_t len_le; + + BSON_ASSERT (bson); + BSON_ASSERT (data); + + if ((length < 5) || (length > INT_MAX)) { + return false; + } + + memcpy (&len_le, data, sizeof (len_le)); + + if ((size_t) BSON_UINT32_FROM_LE (len_le) != length) { + return false; + } + + if (data[length - 1]) { + return false; + } + + impl->flags = BSON_FLAG_STATIC | BSON_FLAG_RDONLY; + impl->len = (uint32_t) length; + impl->parent = NULL; + impl->depth = 0; + impl->buf = &impl->alloc; + impl->buflen = &impl->alloclen; + impl->offset = 0; + impl->alloc = (uint8_t *) data; + impl->alloclen = length; + impl->realloc = NULL; + impl->realloc_func_ctx = NULL; + + return true; +} + + +bson_t * +bson_new (void) +{ + bson_impl_inline_t *impl; + bson_t *bson; + + bson = bson_malloc (sizeof *bson); + + impl = (bson_impl_inline_t *) bson; + impl->flags = BSON_FLAG_INLINE; + impl->len = 5; + impl->data[0] = 5; + impl->data[1] = 0; + impl->data[2] = 0; + impl->data[3] = 0; + impl->data[4] = 0; + + return bson; +} + + +bson_t * +bson_sized_new (size_t size) +{ + bson_impl_alloc_t *impl_a; + bson_t *b; + + BSON_ASSERT (size <= INT32_MAX); + + b = bson_malloc (sizeof *b); + impl_a = (bson_impl_alloc_t *) b; + + if (size <= BSON_INLINE_DATA_SIZE) { + bson_init (b); + b->flags &= ~BSON_FLAG_STATIC; + } else { + impl_a->flags = BSON_FLAG_NONE; + impl_a->len = 5; + impl_a->parent = NULL; + impl_a->depth = 0; + impl_a->buf = &impl_a->alloc; + impl_a->buflen = &impl_a->alloclen; + impl_a->offset = 0; + impl_a->alloclen = BSON_MAX (5, size); + impl_a->alloc = bson_malloc (impl_a->alloclen); + impl_a->alloc[0] = 5; + impl_a->alloc[1] = 0; + impl_a->alloc[2] = 0; + impl_a->alloc[3] = 0; + impl_a->alloc[4] = 0; + impl_a->realloc = bson_realloc_ctx; + impl_a->realloc_func_ctx = NULL; + } + + return b; +} + + +bson_t * +bson_new_from_data (const uint8_t *data, size_t length) +{ + uint32_t len_le; + bson_t *bson; + + BSON_ASSERT (data); + + if ((length < 5) || (length > INT_MAX) || data[length - 1]) { + return NULL; + } + + memcpy (&len_le, data, sizeof (len_le)); + + if (length != (size_t) BSON_UINT32_FROM_LE (len_le)) { + return NULL; + } + + bson = bson_sized_new (length); + memcpy (_bson_data (bson), data, length); + bson->len = (uint32_t) length; + + return bson; +} + + +bson_t * +bson_new_from_buffer (uint8_t **buf, + size_t *buf_len, + bson_realloc_func realloc_func, + void *realloc_func_ctx) +{ + bson_impl_alloc_t *impl; + uint32_t len_le; + uint32_t length; + bson_t *bson; + + BSON_ASSERT (buf); + BSON_ASSERT (buf_len); + + if (!realloc_func) { + realloc_func = bson_realloc_ctx; + } + + bson = bson_malloc0 (sizeof *bson); + impl = (bson_impl_alloc_t *) bson; + + if (!*buf) { + length = 5; + len_le = BSON_UINT32_TO_LE (length); + *buf_len = 5; + *buf = realloc_func (*buf, *buf_len, realloc_func_ctx); + memcpy (*buf, &len_le, sizeof (len_le)); + (*buf)[4] = '\0'; + } else { + if ((*buf_len < 5) || (*buf_len > INT_MAX)) { + bson_free (bson); + return NULL; + } + + memcpy (&len_le, *buf, sizeof (len_le)); + length = BSON_UINT32_FROM_LE (len_le); + } + + if ((*buf)[length - 1]) { + bson_free (bson); + return NULL; + } + + impl->flags = BSON_FLAG_NO_FREE; + impl->len = length; + impl->buf = buf; + impl->buflen = buf_len; + impl->realloc = realloc_func; + impl->realloc_func_ctx = realloc_func_ctx; + + return bson; +} + + +bson_t * +bson_copy (const bson_t *bson) +{ + const uint8_t *data; + + BSON_ASSERT (bson); + + data = _bson_data (bson); + return bson_new_from_data (data, bson->len); +} + + +void +bson_copy_to (const bson_t *src, bson_t *dst) +{ + const uint8_t *data; + bson_impl_alloc_t *adst; + size_t len; + + BSON_ASSERT (src); + BSON_ASSERT (dst); + + if ((src->flags & BSON_FLAG_INLINE)) { + memcpy (dst, src, sizeof *dst); + dst->flags = (BSON_FLAG_STATIC | BSON_FLAG_INLINE); + return; + } + + data = _bson_data (src); + len = bson_next_power_of_two ((size_t) src->len); + + adst = (bson_impl_alloc_t *) dst; + adst->flags = BSON_FLAG_STATIC; + adst->len = src->len; + adst->parent = NULL; + adst->depth = 0; + adst->buf = &adst->alloc; + adst->buflen = &adst->alloclen; + adst->offset = 0; + adst->alloc = bson_malloc (len); + adst->alloclen = len; + adst->realloc = bson_realloc_ctx; + adst->realloc_func_ctx = NULL; + memcpy (adst->alloc, data, src->len); +} + + +static bool +should_ignore (const char *first_exclude, va_list args, const char *name) +{ + bool ret = false; + const char *exclude = first_exclude; + va_list args_copy; + + va_copy (args_copy, args); + + do { + if (!strcmp (name, exclude)) { + ret = true; + break; + } + } while ((exclude = va_arg (args_copy, const char *))); + + va_end (args_copy); + + return ret; +} + + +static void +_bson_copy_to_excluding_va (const bson_t *src, + bson_t *dst, + const char *first_exclude, + va_list args) +{ + bson_iter_t iter; + + if (bson_iter_init (&iter, src)) { + while (bson_iter_next (&iter)) { + if (!should_ignore (first_exclude, args, bson_iter_key (&iter))) { + if (!bson_append_iter (dst, NULL, 0, &iter)) { + /* + * This should not be able to happen since we are copying + * from within a valid bson_t. + */ + BSON_ASSERT (false); + return; + } + } + } + } +} + + +void +bson_copy_to_excluding (const bson_t *src, + bson_t *dst, + const char *first_exclude, + ...) +{ + va_list args; + + BSON_ASSERT (src); + BSON_ASSERT (dst); + BSON_ASSERT (first_exclude); + + bson_init (dst); + + va_start (args, first_exclude); + _bson_copy_to_excluding_va (src, dst, first_exclude, args); + va_end (args); +} + +void +bson_copy_to_excluding_noinit (const bson_t *src, + bson_t *dst, + const char *first_exclude, + ...) +{ + va_list args; + + BSON_ASSERT (src); + BSON_ASSERT (dst); + BSON_ASSERT (first_exclude); + + va_start (args, first_exclude); + _bson_copy_to_excluding_va (src, dst, first_exclude, args); + va_end (args); +} + + +void +bson_destroy (bson_t *bson) +{ + BSON_ASSERT (bson); + + if (!(bson->flags & + (BSON_FLAG_RDONLY | BSON_FLAG_INLINE | BSON_FLAG_NO_FREE))) { + bson_free (*((bson_impl_alloc_t *) bson)->buf); + } + + if (!(bson->flags & BSON_FLAG_STATIC)) { + bson_free (bson); + } +} + + +uint8_t * +bson_reserve_buffer (bson_t *bson, uint32_t size) +{ + if (bson->flags & + (BSON_FLAG_CHILD | BSON_FLAG_IN_CHILD | BSON_FLAG_RDONLY)) { + return NULL; + } + + if (!_bson_grow (bson, size)) { + return NULL; + } + + if (bson->flags & BSON_FLAG_INLINE) { + /* bson_grow didn't spill over */ + ((bson_impl_inline_t *) bson)->len = size; + } else { + ((bson_impl_alloc_t *) bson)->len = size; + } + + return _bson_data (bson); +} + + +bool +bson_steal (bson_t *dst, bson_t *src) +{ + bson_impl_inline_t *src_inline; + bson_impl_inline_t *dst_inline; + bson_impl_alloc_t *alloc; + + BSON_ASSERT (dst); + BSON_ASSERT (src); + + bson_init (dst); + + if (src->flags & (BSON_FLAG_CHILD | BSON_FLAG_IN_CHILD | BSON_FLAG_RDONLY)) { + return false; + } + + if (src->flags & BSON_FLAG_INLINE) { + src_inline = (bson_impl_inline_t *) src; + dst_inline = (bson_impl_inline_t *) dst; + dst_inline->len = src_inline->len; + memcpy (dst_inline->data, src_inline->data, sizeof src_inline->data); + + /* for consistency, src is always invalid after steal, even if inline */ + src->len = 0; + } else { + memcpy (dst, src, sizeof (bson_t)); + alloc = (bson_impl_alloc_t *) dst; + alloc->flags |= BSON_FLAG_STATIC; + alloc->buf = &alloc->alloc; + alloc->buflen = &alloc->alloclen; + } + + if (!(src->flags & BSON_FLAG_STATIC)) { + bson_free (src); + } else { + /* src is invalid after steal */ + src->len = 0; + } + + return true; +} + + +uint8_t * +bson_destroy_with_steal (bson_t *bson, bool steal, uint32_t *length) +{ + uint8_t *ret = NULL; + + BSON_ASSERT (bson); + + if (length) { + *length = bson->len; + } + + if (!steal) { + bson_destroy (bson); + return NULL; + } + + if ((bson->flags & + (BSON_FLAG_CHILD | BSON_FLAG_IN_CHILD | BSON_FLAG_RDONLY))) { + /* Do nothing */ + } else if ((bson->flags & BSON_FLAG_INLINE)) { + bson_impl_inline_t *inl; + + inl = (bson_impl_inline_t *) bson; + ret = bson_malloc (bson->len); + memcpy (ret, inl->data, bson->len); + } else { + bson_impl_alloc_t *alloc; + + alloc = (bson_impl_alloc_t *) bson; + ret = *alloc->buf; + *alloc->buf = NULL; + } + + bson_destroy (bson); + + return ret; +} + + +const uint8_t * +bson_get_data (const bson_t *bson) +{ + BSON_ASSERT (bson); + + return _bson_data (bson); +} + + +uint32_t +bson_count_keys (const bson_t *bson) +{ + uint32_t count = 0; + bson_iter_t iter; + + BSON_ASSERT (bson); + + if (bson_iter_init (&iter, bson)) { + while (bson_iter_next (&iter)) { + count++; + } + } + + return count; +} + + +bool +bson_has_field (const bson_t *bson, const char *key) +{ + bson_iter_t iter; + bson_iter_t child; + + BSON_ASSERT (bson); + BSON_ASSERT (key); + + if (NULL != strchr (key, '.')) { + return (bson_iter_init (&iter, bson) && + bson_iter_find_descendant (&iter, key, &child)); + } + + return bson_iter_init_find (&iter, bson, key); +} + + +int +bson_compare (const bson_t *bson, const bson_t *other) +{ + const uint8_t *data1; + const uint8_t *data2; + size_t len1; + size_t len2; + int64_t ret; + + data1 = _bson_data (bson) + 4; + len1 = bson->len - 4; + + data2 = _bson_data (other) + 4; + len2 = other->len - 4; + + if (len1 == len2) { + return memcmp (data1, data2, len1); + } + + ret = memcmp (data1, data2, BSON_MIN (len1, len2)); + + if (ret == 0) { + ret = (int64_t) (len1 - len2); + } + + return (ret < 0) ? -1 : (ret > 0); +} + + +bool +bson_equal (const bson_t *bson, const bson_t *other) +{ + return !bson_compare (bson, other); +} + + +static bool +_bson_as_json_visit_utf8 (const bson_iter_t *iter, + const char *key, + size_t v_utf8_len, + const char *v_utf8, + void *data) +{ + bson_json_state_t *state = data; + char *escaped; + + escaped = bson_utf8_escape_for_json (v_utf8, v_utf8_len); + + if (escaped) { + bson_string_append (state->str, "\""); + bson_string_append (state->str, escaped); + bson_string_append (state->str, "\""); + bson_free (escaped); + return false; + } + + return true; +} + + +static bool +_bson_as_extended_json_visit_int32 (const bson_iter_t *iter, + const char *key, + int32_t v_int32, + void *data) +{ + bson_json_state_t *state = data; + + bson_string_append_printf ( + state->str, "{ \"$numberInt\" : \"%" PRId32 "\" }", v_int32); + + return false; +} + + +static bool +_bson_as_json_visit_int32 (const bson_iter_t *iter, + const char *key, + int32_t v_int32, + void *data) +{ + bson_json_state_t *state = data; + + bson_string_append_printf (state->str, "%" PRId32, v_int32); + + return false; +} + + +static bool +_bson_as_extended_json_visit_int64 (const bson_iter_t *iter, + const char *key, + int64_t v_int64, + void *data) +{ + bson_json_state_t *state = data; + + bson_string_append_printf ( + state->str, "{ \"$numberLong\" : \"%" PRId64 "\"}", v_int64); + + return false; +} + + +static bool +_bson_as_json_visit_int64 (const bson_iter_t *iter, + const char *key, + int64_t v_int64, + void *data) +{ + bson_json_state_t *state = data; + + bson_string_append_printf (state->str, "%" PRId64, v_int64); + + return false; +} + + +static bool +_bson_as_json_visit_decimal128 (const bson_iter_t *iter, + const char *key, + const bson_decimal128_t *value, + void *data) +{ + bson_json_state_t *state = data; + char decimal128_string[BSON_DECIMAL128_STRING]; + bson_decimal128_to_string (value, decimal128_string); + + bson_string_append (state->str, "{ \"$numberDecimal\" : \""); + bson_string_append (state->str, decimal128_string); + bson_string_append (state->str, "\" }"); + + return false; +} + + +static bool +_bson_as_json_visit_double_common (const bson_iter_t *iter, + const char *key, + double v_double, + void *data, + bool legacy) +{ + bson_json_state_t *state = data; + bson_string_t *str = state->str; + uint32_t start_len; + + if (!legacy) { + bson_string_append (state->str, "{ \"$numberDouble\" : \""); + } + + /* portable: some old platforms have no isinf or isnan */ + if (v_double != v_double) { + bson_string_append (str, "NaN"); + } else if (v_double * 0 != 0) { + if (v_double > 0) { + bson_string_append (str, "Infinity"); + } else { + bson_string_append (str, "-Infinity"); + } + } else { + start_len = str->len; + bson_string_append_printf (str, "%.20g", v_double); + + /* ensure trailing ".0" to distinguish "3" from "3.0" */ + if (strspn (&str->str[start_len], "0123456789-") == + str->len - start_len) { + bson_string_append (str, ".0"); + } + } + + if (!legacy) { + bson_string_append (state->str, "\" }"); + } + + return false; +} + + +static bool +_bson_as_extended_json_visit_double (const bson_iter_t *iter, + const char *key, + double v_double, + void *data) +{ + return _bson_as_json_visit_double_common ( + iter, key, v_double, data, false /* legacy */); +} + + +static bool +_bson_as_json_visit_double (const bson_iter_t *iter, + const char *key, + double v_double, + void *data) +{ + return _bson_as_json_visit_double_common ( + iter, key, v_double, data, true /* legacy */); +} + + +static bool +_bson_as_json_visit_undefined (const bson_iter_t *iter, + const char *key, + void *data) +{ + bson_json_state_t *state = data; + + bson_string_append (state->str, "{ \"$undefined\" : true }"); + + return false; +} + + +static bool +_bson_as_json_visit_null (const bson_iter_t *iter, const char *key, void *data) +{ + bson_json_state_t *state = data; + + bson_string_append (state->str, "null"); + + return false; +} + + +static bool +_bson_as_json_visit_oid (const bson_iter_t *iter, + const char *key, + const bson_oid_t *oid, + void *data) +{ + bson_json_state_t *state = data; + char str[25]; + + bson_oid_to_string (oid, str); + bson_string_append (state->str, "{ \"$oid\" : \""); + bson_string_append (state->str, str); + bson_string_append (state->str, "\" }"); + + return false; +} + + +static bool +_bson_as_json_visit_binary (const bson_iter_t *iter, + const char *key, + bson_subtype_t v_subtype, + size_t v_binary_len, + const uint8_t *v_binary, + void *data) +{ + bson_json_state_t *state = data; + size_t b64_len; + char *b64; + + b64_len = (v_binary_len / 3 + 1) * 4 + 1; + b64 = bson_malloc0 (b64_len); + b64_ntop (v_binary, v_binary_len, b64, b64_len); + + bson_string_append (state->str, "{ \"$binary\" : \""); + bson_string_append (state->str, b64); + bson_string_append (state->str, "\", \"$type\" : \""); + bson_string_append_printf (state->str, "%02x", v_subtype); + bson_string_append (state->str, "\" }"); + bson_free (b64); + + return false; +} + + +static bool +_bson_as_json_visit_bool (const bson_iter_t *iter, + const char *key, + bool v_bool, + void *data) +{ + bson_json_state_t *state = data; + + bson_string_append (state->str, v_bool ? "true" : "false"); + + return false; +} + + +static bool +_bson_as_extended_json_visit_date_time (const bson_iter_t *iter, + const char *key, + int64_t msec_since_epoch, + void *data) +{ + bson_json_state_t *state = data; + + bson_string_append (state->str, "{ \"$date\" : { \"$numberLong\" : \""); + bson_string_append_printf (state->str, "%" PRId64, msec_since_epoch); + bson_string_append (state->str, "\" } }"); + + return false; +} + + +static bool +_bson_as_json_visit_date_time (const bson_iter_t *iter, + const char *key, + int64_t msec_since_epoch, + void *data) +{ + bson_json_state_t *state = data; + + bson_string_append (state->str, "{ \"$date\" : "); + bson_string_append_printf (state->str, "%" PRId64, msec_since_epoch); + bson_string_append (state->str, " }"); + + return false; +} + + +static bool +_bson_as_json_visit_regex (const bson_iter_t *iter, + const char *key, + const char *v_regex, + const char *v_options, + void *data) +{ + bson_json_state_t *state = data; + const char *c; + + bson_string_append (state->str, "{ \"$regex\" : \""); + bson_string_append (state->str, v_regex); + bson_string_append (state->str, "\", \"$options\" : \""); + + /* sort the options */ + for (c = "ilmsux"; *c; c++) { + if (strchr (v_options, *c)) { + bson_string_append_c (state->str, *c); + } + } + + bson_string_append (state->str, "\" }"); + + return false; +} + + +static bool +_bson_as_extended_json_visit_timestamp (const bson_iter_t *iter, + const char *key, + uint32_t v_timestamp, + uint32_t v_increment, + void *data) +{ + bson_json_state_t *state = data; + + bson_string_append_printf (state->str, + "{ \"$timestamp\" : \"%" PRIu64 "\" }", + _int64_timestamp (v_timestamp, v_increment)); + + return false; +} + + +static bool +_bson_as_json_visit_timestamp (const bson_iter_t *iter, + const char *key, + uint32_t v_timestamp, + uint32_t v_increment, + void *data) +{ + bson_json_state_t *state = data; + + bson_string_append (state->str, "{ \"$timestamp\" : { \"t\" : "); + bson_string_append_printf (state->str, "%u", v_timestamp); + bson_string_append (state->str, ", \"i\" : "); + bson_string_append_printf (state->str, "%u", v_increment); + bson_string_append (state->str, " } }"); + + return false; +} + + +static bool +_bson_as_extended_json_visit_dbpointer (const bson_iter_t *iter, + const char *key, + size_t v_collection_len, + const char *v_collection, + const bson_oid_t *v_oid, + void *data) +{ + bson_json_state_t *state = data; + char str[25]; + + bson_string_append (state->str, "{ \"$dbPointer\" : { \"$ref\" : \""); + bson_string_append (state->str, v_collection); + bson_string_append (state->str, "\""); + + if (v_oid) { + bson_oid_to_string (v_oid, str); + bson_string_append (state->str, ", \"$id\" : { \"$oid\" : \""); + bson_string_append (state->str, str); + bson_string_append (state->str, "\" }"); + } + + bson_string_append (state->str, " } }"); + + return false; +} + +static bool +_bson_as_json_visit_dbpointer (const bson_iter_t *iter, + const char *key, + size_t v_collection_len, + const char *v_collection, + const bson_oid_t *v_oid, + void *data) +{ + bson_json_state_t *state = data; + char str[25]; + + bson_string_append (state->str, "{ \"$ref\" : \""); + bson_string_append (state->str, v_collection); + bson_string_append (state->str, "\""); + + if (v_oid) { + bson_oid_to_string (v_oid, str); + bson_string_append (state->str, ", \"$id\" : \""); + bson_string_append (state->str, str); + bson_string_append (state->str, "\""); + } + + bson_string_append (state->str, " }"); + + return false; +} + + +static bool +_bson_as_json_visit_minkey (const bson_iter_t *iter, + const char *key, + void *data) +{ + bson_json_state_t *state = data; + + bson_string_append (state->str, "{ \"$minKey\" : 1 }"); + + return false; +} + + +static bool +_bson_as_json_visit_maxkey (const bson_iter_t *iter, + const char *key, + void *data) +{ + bson_json_state_t *state = data; + + bson_string_append (state->str, "{ \"$maxKey\" : 1 }"); + + return false; +} + + +static bool +_bson_as_json_visit_before (const bson_iter_t *iter, + const char *key, + void *data) +{ + bson_json_state_t *state = data; + char *escaped; + + if (state->count) { + bson_string_append (state->str, ", "); + } + + if (state->keys) { + escaped = bson_utf8_escape_for_json (key, -1); + if (escaped) { + bson_string_append (state->str, "\""); + bson_string_append (state->str, escaped); + bson_string_append (state->str, "\" : "); + bson_free (escaped); + } else { + return true; + } + } + + state->count++; + + return false; +} + + +static void +_bson_as_json_visit_corrupt (const bson_iter_t *iter, void *data) +{ + *(((bson_json_state_t *) data)->err_offset) = iter->off; +} + + +static bool +_bson_as_json_visit_code (const bson_iter_t *iter, + const char *key, + size_t v_code_len, + const char *v_code, + void *data) +{ + bson_json_state_t *state = data; + char *escaped; + + escaped = bson_utf8_escape_for_json (v_code, v_code_len); + + if (escaped) { + bson_string_append (state->str, "{ \"$code\" : \""); + bson_string_append (state->str, escaped); + bson_string_append (state->str, "\" }"); + bson_free (escaped); + return false; + } + + return true; +} + + +static bool +_bson_as_extended_json_visit_symbol (const bson_iter_t *iter, + const char *key, + size_t v_symbol_len, + const char *v_symbol, + void *data) +{ + bson_json_state_t *state = data; + + bson_string_append (state->str, "{ \"$symbol\" : \""); + bson_string_append (state->str, v_symbol); + bson_string_append (state->str, "\" }"); + + return false; +} + + +static bool +_bson_as_json_visit_symbol (const bson_iter_t *iter, + const char *key, + size_t v_symbol_len, + const char *v_symbol, + void *data) +{ + bson_json_state_t *state = data; + + bson_string_append (state->str, "\""); + bson_string_append (state->str, v_symbol); + bson_string_append (state->str, "\""); + + return false; +} + + +static bool +_bson_as_json_visit_codewscope_common (const bson_iter_t *iter, + const char *key, + size_t v_code_len, + const char *v_code, + const bson_t *v_scope, + void *data, + bool legacy) +{ + bson_json_state_t *state = data; + char *code_escaped; + char *scope; + + code_escaped = bson_utf8_escape_for_json (v_code, v_code_len); + if (!code_escaped) { + return true; + } + + if (legacy) { + scope = bson_as_json (v_scope, NULL); + } else { + scope = bson_as_extended_json (v_scope, NULL); + } + + if (!scope) { + bson_free (code_escaped); + return true; + } + + bson_string_append (state->str, "{ \"$code\" : \""); + bson_string_append (state->str, code_escaped); + bson_string_append (state->str, "\", \"$scope\" : "); + bson_string_append (state->str, scope); + bson_string_append (state->str, " }"); + + bson_free (code_escaped); + bson_free (scope); + + return false; +} + + +static bool +_bson_as_extended_json_visit_codewscope (const bson_iter_t *iter, + const char *key, + size_t v_code_len, + const char *v_code, + const bson_t *v_scope, + void *data) +{ + return _bson_as_json_visit_codewscope_common ( + iter, key, v_code_len, v_code, v_scope, data, false /* legacy */); +} + + +static bool +_bson_as_json_visit_codewscope (const bson_iter_t *iter, + const char *key, + size_t v_code_len, + const char *v_code, + const bson_t *v_scope, + void *data) +{ + return _bson_as_json_visit_codewscope_common ( + iter, key, v_code_len, v_code, v_scope, data, true /* legacy */); +} + + +/* canonical MongoDB Extended JSON format, complying with the spec */ +static const bson_visitor_t bson_as_extended_json_visitors = { + _bson_as_json_visit_before, + NULL, /* visit_after */ + _bson_as_json_visit_corrupt, + _bson_as_extended_json_visit_double, + _bson_as_json_visit_utf8, + _bson_as_extended_json_visit_document, + _bson_as_extended_json_visit_array, + _bson_as_json_visit_binary, + _bson_as_json_visit_undefined, + _bson_as_json_visit_oid, + _bson_as_json_visit_bool, + _bson_as_extended_json_visit_date_time, + _bson_as_json_visit_null, + _bson_as_json_visit_regex, + _bson_as_extended_json_visit_dbpointer, + _bson_as_json_visit_code, + _bson_as_extended_json_visit_symbol, + _bson_as_extended_json_visit_codewscope, + _bson_as_extended_json_visit_int32, + _bson_as_extended_json_visit_timestamp, + _bson_as_extended_json_visit_int64, + _bson_as_json_visit_maxkey, + _bson_as_json_visit_minkey, + NULL, /* visit_unsupported_type */ + _bson_as_json_visit_decimal128, +}; + +/* legacy JSON format */ +static const bson_visitor_t bson_as_json_visitors = { + _bson_as_json_visit_before, NULL, /* visit_after */ + _bson_as_json_visit_corrupt, _bson_as_json_visit_double, + _bson_as_json_visit_utf8, _bson_as_json_visit_document, + _bson_as_json_visit_array, _bson_as_json_visit_binary, + _bson_as_json_visit_undefined, _bson_as_json_visit_oid, + _bson_as_json_visit_bool, _bson_as_json_visit_date_time, + _bson_as_json_visit_null, _bson_as_json_visit_regex, + _bson_as_json_visit_dbpointer, _bson_as_json_visit_code, + _bson_as_json_visit_symbol, _bson_as_json_visit_codewscope, + _bson_as_json_visit_int32, _bson_as_json_visit_timestamp, + _bson_as_json_visit_int64, _bson_as_json_visit_maxkey, + _bson_as_json_visit_minkey, NULL, /* visit_unsupported_type */ + _bson_as_json_visit_decimal128, +}; + + +static bool +_bson_as_json_visit_document_with_visitors (const bson_iter_t *iter, + const char *key, + const bson_t *v_document, + void *data, + const bson_visitor_t *visitor) +{ + bson_json_state_t *state = data; + bson_json_state_t child_state = {0, true, state->err_offset}; + bson_iter_t child; + + if (state->depth >= BSON_MAX_RECURSION) { + bson_string_append (state->str, "{ ... }"); + return false; + } + + if (bson_iter_init (&child, v_document)) { + child_state.str = bson_string_new ("{ "); + child_state.depth = state->depth + 1; + if (bson_iter_visit_all (&child, visitor, &child_state)) { + return true; + } + + bson_string_append (child_state.str, " }"); + bson_string_append (state->str, child_state.str->str); + bson_string_free (child_state.str, true); + } + + return false; +} + + +static bool +_bson_as_json_visit_document (const bson_iter_t *iter, + const char *key, + const bson_t *v_document, + void *data) +{ + return _bson_as_json_visit_document_with_visitors ( + iter, key, v_document, data, &bson_as_json_visitors); +} + + +static bool +_bson_as_extended_json_visit_document (const bson_iter_t *iter, + const char *key, + const bson_t *v_document, + void *data) +{ + return _bson_as_json_visit_document_with_visitors ( + iter, key, v_document, data, &bson_as_extended_json_visitors); +} + + +static bool +_bson_as_json_visit_array_with_visitors (const bson_iter_t *iter, + const char *key, + const bson_t *v_array, + void *data, + const bson_visitor_t *visitor) +{ + bson_json_state_t *state = data; + bson_json_state_t child_state = {0, false, state->err_offset}; + bson_iter_t child; + + if (state->depth >= BSON_MAX_RECURSION) { + bson_string_append (state->str, "{ ... }"); + return false; + } + + if (bson_iter_init (&child, v_array)) { + child_state.str = bson_string_new ("[ "); + child_state.depth = state->depth + 1; + if (bson_iter_visit_all (&child, visitor, &child_state)) { + return true; + } + + bson_string_append (child_state.str, " ]"); + bson_string_append (state->str, child_state.str->str); + bson_string_free (child_state.str, true); + } + + return false; +} + + +static bool +_bson_as_json_visit_array (const bson_iter_t *iter, + const char *key, + const bson_t *v_array, + void *data) +{ + return _bson_as_json_visit_array_with_visitors ( + iter, key, v_array, data, &bson_as_json_visitors); +} + + +static bool +_bson_as_extended_json_visit_array (const bson_iter_t *iter, + const char *key, + const bson_t *v_array, + void *data) +{ + return _bson_as_json_visit_array_with_visitors ( + iter, key, v_array, data, &bson_as_extended_json_visitors); +} + + +static char * +_bson_as_json_visit_all (const bson_t *bson, + size_t *length, + const bson_visitor_t *visitors) +{ + bson_json_state_t state; + bson_iter_t iter; + ssize_t err_offset = -1; + + BSON_ASSERT (bson); + + if (length) { + *length = 0; + } + + if (bson_empty0 (bson)) { + if (length) { + *length = 3; + } + + return bson_strdup ("{ }"); + } + + if (!bson_iter_init (&iter, bson)) { + return NULL; + } + + state.count = 0; + state.keys = true; + state.str = bson_string_new ("{ "); + state.depth = 0; + state.err_offset = &err_offset; + + if (bson_iter_visit_all (&iter, visitors, &state) || err_offset != -1) { + /* + * We were prematurely exited due to corruption or failed visitor. + */ + bson_string_free (state.str, true); + if (length) { + *length = 0; + } + return NULL; + } + + bson_string_append (state.str, " }"); + + if (length) { + *length = state.str->len; + } + + return bson_string_free (state.str, false); +} + + +char * +bson_as_extended_json (const bson_t *bson, size_t *length) +{ + return _bson_as_json_visit_all ( + bson, length, &bson_as_extended_json_visitors); +} + + +char * +bson_as_json (const bson_t *bson, size_t *length) +{ + return _bson_as_json_visit_all (bson, length, &bson_as_json_visitors); +} + + +char * +bson_array_as_json (const bson_t *bson, size_t *length) +{ + bson_json_state_t state; + bson_iter_t iter; + ssize_t err_offset = -1; + + BSON_ASSERT (bson); + + if (length) { + *length = 0; + } + + if (bson_empty0 (bson)) { + if (length) { + *length = 3; + } + + return bson_strdup ("[ ]"); + } + + if (!bson_iter_init (&iter, bson)) { + return NULL; + } + + state.count = 0; + state.keys = false; + state.str = bson_string_new ("[ "); + state.depth = 0; + state.err_offset = &err_offset; + bson_iter_visit_all (&iter, &bson_as_json_visitors, &state); + + if (bson_iter_visit_all (&iter, &bson_as_json_visitors, &state) || + err_offset != -1) { + /* + * We were prematurely exited due to corruption or failed visitor. + */ + bson_string_free (state.str, true); + if (length) { + *length = 0; + } + return NULL; + } + + bson_string_append (state.str, " ]"); + + if (length) { + *length = state.str->len; + } + + return bson_string_free (state.str, false); +} + + +#define VALIDATION_ERR(_flag, _msg, ...) \ + bson_set_error (&state->error, BSON_ERROR_INVALID, _flag, _msg, __VA_ARGS__) + +static bool +_bson_iter_validate_utf8 (const bson_iter_t *iter, + const char *key, + size_t v_utf8_len, + const char *v_utf8, + void *data) +{ + bson_validate_state_t *state = data; + bool allow_null; + + if ((state->flags & BSON_VALIDATE_UTF8)) { + allow_null = !!(state->flags & BSON_VALIDATE_UTF8_ALLOW_NULL); + + if (!bson_utf8_validate (v_utf8, v_utf8_len, allow_null)) { + state->err_offset = iter->off; + VALIDATION_ERR ( + BSON_VALIDATE_UTF8, "invalid utf8 string for key \"%s\"", key); + return true; + } + } + + if ((state->flags & BSON_VALIDATE_DOLLAR_KEYS)) { + if (state->phase == BSON_VALIDATE_PHASE_LF_REF_UTF8) { + state->phase = BSON_VALIDATE_PHASE_LF_ID_KEY; + } else if (state->phase == BSON_VALIDATE_PHASE_LF_DB_UTF8) { + state->phase = BSON_VALIDATE_PHASE_NOT_DBREF; + } + } + + return false; +} + + +static void +_bson_iter_validate_corrupt (const bson_iter_t *iter, void *data) +{ + bson_validate_state_t *state = data; + + state->err_offset = iter->err_off; + VALIDATION_ERR (BSON_VALIDATE_NONE, "%s", "corrupt BSON"); +} + + +static bool +_bson_iter_validate_before (const bson_iter_t *iter, + const char *key, + void *data) +{ + bson_validate_state_t *state = data; + + if ((state->flags & BSON_VALIDATE_EMPTY_KEYS)) { + if (key[0] == '\0') { + state->err_offset = iter->off; + VALIDATION_ERR (BSON_VALIDATE_EMPTY_KEYS, "%s", "empty key"); + return true; + } + } + + if ((state->flags & BSON_VALIDATE_DOLLAR_KEYS)) { + if (key[0] == '$') { + if (state->phase == BSON_VALIDATE_PHASE_LF_REF_KEY && + strcmp (key, "$ref") == 0) { + state->phase = BSON_VALIDATE_PHASE_LF_REF_UTF8; + } else if (state->phase == BSON_VALIDATE_PHASE_LF_ID_KEY && + strcmp (key, "$id") == 0) { + state->phase = BSON_VALIDATE_PHASE_LF_DB_KEY; + } else if (state->phase == BSON_VALIDATE_PHASE_LF_DB_KEY && + strcmp (key, "$db") == 0) { + state->phase = BSON_VALIDATE_PHASE_LF_DB_UTF8; + } else { + state->err_offset = iter->off; + VALIDATION_ERR (BSON_VALIDATE_DOLLAR_KEYS, + "keys cannot begin with \"$\": \"%s\"", + key); + return true; + } + } else if (state->phase == BSON_VALIDATE_PHASE_LF_ID_KEY || + state->phase == BSON_VALIDATE_PHASE_LF_REF_UTF8 || + state->phase == BSON_VALIDATE_PHASE_LF_DB_UTF8) { + state->err_offset = iter->off; + VALIDATION_ERR (BSON_VALIDATE_DOLLAR_KEYS, + "invalid key within DBRef subdocument: \"%s\"", + key); + return true; + } else { + state->phase = BSON_VALIDATE_PHASE_NOT_DBREF; + } + } + + if ((state->flags & BSON_VALIDATE_DOT_KEYS)) { + if (strstr (key, ".")) { + state->err_offset = iter->off; + VALIDATION_ERR ( + BSON_VALIDATE_DOT_KEYS, "keys cannot contain \".\": \"%s\"", key); + return true; + } + } + + return false; +} + + +static bool +_bson_iter_validate_codewscope (const bson_iter_t *iter, + const char *key, + size_t v_code_len, + const char *v_code, + const bson_t *v_scope, + void *data) +{ + bson_validate_state_t *state = data; + size_t offset = 0; + + if (!bson_validate (v_scope, state->flags, &offset)) { + state->err_offset = iter->off + offset; + VALIDATION_ERR (BSON_VALIDATE_NONE, "%s", "corrupt code-with-scope"); + return false; + } + + return true; +} + + +static bool +_bson_iter_validate_document (const bson_iter_t *iter, + const char *key, + const bson_t *v_document, + void *data); + + +static const bson_visitor_t bson_validate_funcs = { + _bson_iter_validate_before, + NULL, /* visit_after */ + _bson_iter_validate_corrupt, + NULL, /* visit_double */ + _bson_iter_validate_utf8, + _bson_iter_validate_document, + _bson_iter_validate_document, /* visit_array */ + NULL, /* visit_binary */ + NULL, /* visit_undefined */ + NULL, /* visit_oid */ + NULL, /* visit_bool */ + NULL, /* visit_date_time */ + NULL, /* visit_null */ + NULL, /* visit_regex */ + NULL, /* visit_dbpoint */ + NULL, /* visit_code */ + NULL, /* visit_symbol */ + _bson_iter_validate_codewscope, +}; + + +static bool +_bson_iter_validate_document (const bson_iter_t *iter, + const char *key, + const bson_t *v_document, + void *data) +{ + bson_validate_state_t *state = data; + bson_iter_t child; + bson_validate_phase_t phase = state->phase; + + if (!bson_iter_init (&child, v_document)) { + state->err_offset = iter->off; + return true; + } + + if (state->phase == BSON_VALIDATE_PHASE_START) { + state->phase = BSON_VALIDATE_PHASE_TOP; + } else { + state->phase = BSON_VALIDATE_PHASE_LF_REF_KEY; + } + + bson_iter_visit_all (&child, &bson_validate_funcs, state); + + if (state->phase == BSON_VALIDATE_PHASE_LF_ID_KEY || + state->phase == BSON_VALIDATE_PHASE_LF_REF_UTF8 || + state->phase == BSON_VALIDATE_PHASE_LF_DB_UTF8) { + if (state->err_offset <= 0) { + state->err_offset = iter->off; + } + + return true; + } + + state->phase = phase; + + return false; +} + + +static void +_bson_validate_internal (const bson_t *bson, bson_validate_state_t *state) +{ + bson_iter_t iter; + + state->err_offset = -1; + state->phase = BSON_VALIDATE_PHASE_START; + memset (&state->error, 0, sizeof state->error); + + if (!bson_iter_init (&iter, bson)) { + state->err_offset = 0; + VALIDATION_ERR (BSON_VALIDATE_NONE, "%s", "corrupt BSON"); + } else { + _bson_iter_validate_document (&iter, NULL, bson, state); + } +} + + +bool +bson_validate (const bson_t *bson, bson_validate_flags_t flags, size_t *offset) +{ + bson_validate_state_t state; + + state.flags = flags; + _bson_validate_internal (bson, &state); + + if (state.err_offset > 0 && offset) { + *offset = (size_t) state.err_offset; + } + + return state.err_offset < 0; +} + + +bool +bson_validate_with_error (const bson_t *bson, + bson_validate_flags_t flags, + bson_error_t *error) +{ + bson_validate_state_t state; + + state.flags = flags; + _bson_validate_internal (bson, &state); + + if (state.err_offset > 0 && error) { + memcpy (error, &state.error, sizeof *error); + } + + return state.err_offset < 0; +} + + +bool +bson_concat (bson_t *dst, const bson_t *src) +{ + BSON_ASSERT (dst); + BSON_ASSERT (src); + + if (!bson_empty (src)) { + return _bson_append ( + dst, 1, src->len - 5, src->len - 5, _bson_data (src) + 4); + } + + return true; +} diff --git a/chaos_micro_unit_toolkit/external_lib/bson/bson/bson.h b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson.h new file mode 100644 index 0000000000000000000000000000000000000000..6d619f590c4d73f1369506bc6d528b43a288298c --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/bson/bson.h @@ -0,0 +1,1084 @@ +/* + * Copyright 2013 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef BSON_H +#define BSON_H + +#define BSON_INSIDE + +#include "bson-compat.h" + +#include <string.h> +#include <time.h> + +#include "bson-macros.h" +#include "bson-config.h" +#include "bson-atomic.h" +#include "bson-context.h" +#include "bson-clock.h" +#include "bson-decimal128.h" +#include "bson-error.h" +#include "bson-iter.h" +#include "bson-json.h" +#include "bson-keys.h" +#include "bson-md5.h" +#include "bson-memory.h" +#include "bson-oid.h" +#include "bson-reader.h" +#include "bson-string.h" +#include "bson-types.h" +#include "bson-utf8.h" +#include "bson-value.h" +#include "bson-writer.h" +#include "bcon.h" + +#undef BSON_INSIDE + + +BSON_BEGIN_DECLS + + +/** + * bson_empty: + * @b: a bson_t. + * + * Checks to see if @b is an empty BSON document. An empty BSON document is + * a 5 byte document which contains the length (4 bytes) and a single NUL + * byte indicating end of fields. + */ +#define bson_empty(b) (((b)->len == 5) || !bson_get_data ((b))[4]) + + +/** + * bson_empty0: + * + * Like bson_empty() but treats NULL the same as an empty bson_t document. + */ +#define bson_empty0(b) (!(b) || bson_empty (b)) + + +/** + * bson_clear: + * + * Easily free a bson document and set it to NULL. Use like: + * + * bson_t *doc = bson_new(); + * bson_clear (&doc); + * BSON_ASSERT (doc == NULL); + */ +#define bson_clear(bptr) \ + do { \ + if (*(bptr)) { \ + bson_destroy (*(bptr)); \ + *(bptr) = NULL; \ + } \ + } while (0) + + +/** + * BSON_MAX_SIZE: + * + * The maximum size in bytes of a BSON document. + */ +#define BSON_MAX_SIZE ((size_t) ((1U << 31) - 1)) + + +#define BSON_APPEND_ARRAY(b, key, val) \ + bson_append_array (b, key, (int) strlen (key), val) + +#define BSON_APPEND_ARRAY_BEGIN(b, key, child) \ + bson_append_array_begin (b, key, (int) strlen (key), child) + +#define BSON_APPEND_BINARY(b, key, subtype, val, len) \ + bson_append_binary (b, key, (int) strlen (key), subtype, val, len) + +#define BSON_APPEND_BOOL(b, key, val) \ + bson_append_bool (b, key, (int) strlen (key), val) + +#define BSON_APPEND_CODE(b, key, val) \ + bson_append_code (b, key, (int) strlen (key), val) + +#define BSON_APPEND_CODE_WITH_SCOPE(b, key, val, scope) \ + bson_append_code_with_scope (b, key, (int) strlen (key), val, scope) + +#define BSON_APPEND_DBPOINTER(b, key, coll, oid) \ + bson_append_dbpointer (b, key, (int) strlen (key), coll, oid) + +#define BSON_APPEND_DOCUMENT_BEGIN(b, key, child) \ + bson_append_document_begin (b, key, (int) strlen (key), child) + +#define BSON_APPEND_DOUBLE(b, key, val) \ + bson_append_double (b, key, (int) strlen (key), val) + +#define BSON_APPEND_DOCUMENT(b, key, val) \ + bson_append_document (b, key, (int) strlen (key), val) + +#define BSON_APPEND_INT32(b, key, val) \ + bson_append_int32 (b, key, (int) strlen (key), val) + +#define BSON_APPEND_INT64(b, key, val) \ + bson_append_int64 (b, key, (int) strlen (key), val) + +#define BSON_APPEND_MINKEY(b, key) \ + bson_append_minkey (b, key, (int) strlen (key)) + +#define BSON_APPEND_DECIMAL128(b, key, val) \ + bson_append_decimal128 (b, key, (int) strlen (key), val) + +#define BSON_APPEND_MAXKEY(b, key) \ + bson_append_maxkey (b, key, (int) strlen (key)) + +#define BSON_APPEND_NULL(b, key) bson_append_null (b, key, (int) strlen (key)) + +#define BSON_APPEND_OID(b, key, val) \ + bson_append_oid (b, key, (int) strlen (key), val) + +#define BSON_APPEND_REGEX(b, key, val, opt) \ + bson_append_regex (b, key, (int) strlen (key), val, opt) + +#define BSON_APPEND_UTF8(b, key, val) \ + bson_append_utf8 (b, key, (int) strlen (key), val, (int) strlen (val)) + +#define BSON_APPEND_SYMBOL(b, key, val) \ + bson_append_symbol (b, key, (int) strlen (key), val, (int) strlen (val)) + +#define BSON_APPEND_TIME_T(b, key, val) \ + bson_append_time_t (b, key, (int) strlen (key), val) + +#define BSON_APPEND_TIMEVAL(b, key, val) \ + bson_append_timeval (b, key, (int) strlen (key), val) + +#define BSON_APPEND_DATE_TIME(b, key, val) \ + bson_append_date_time (b, key, (int) strlen (key), val) + +#define BSON_APPEND_TIMESTAMP(b, key, val, inc) \ + bson_append_timestamp (b, key, (int) strlen (key), val, inc) + +#define BSON_APPEND_UNDEFINED(b, key) \ + bson_append_undefined (b, key, (int) strlen (key)) + +#define BSON_APPEND_VALUE(b, key, val) \ + bson_append_value (b, key, (int) strlen (key), (val)) + + +/** + * bson_new: + * + * Allocates a new bson_t structure. Call the various bson_append_*() + * functions to add fields to the bson. You can iterate the bson_t at any + * time using a bson_iter_t and bson_iter_init(). + * + * Returns: A newly allocated bson_t that should be freed with bson_destroy(). + */ +BSON_EXPORT (bson_t *) +bson_new (void); + + +BSON_EXPORT (bson_t *) +bson_new_from_json (const uint8_t *data, ssize_t len, bson_error_t *error); + + +BSON_EXPORT (bool) +bson_init_from_json (bson_t *bson, + const char *data, + ssize_t len, + bson_error_t *error); + + +/** + * bson_init_static: + * @b: A pointer to a bson_t. + * @data: The data buffer to use. + * @length: The length of @data. + * + * Initializes a bson_t using @data and @length. This is ideal if you would + * like to use a stack allocation for your bson and do not need to grow the + * buffer. @data must be valid for the life of @b. + * + * Returns: true if initialized successfully; otherwise false. + */ +BSON_EXPORT (bool) +bson_init_static (bson_t *b, const uint8_t *data, size_t length); + + +/** + * bson_init: + * @b: A pointer to a bson_t. + * + * Initializes a bson_t for use. This function is useful to those that want a + * stack allocated bson_t. The usefulness of a stack allocated bson_t is + * marginal as the target buffer for content will still require heap + * allocations. It can help reduce heap fragmentation on allocators that do + * not employ SLAB/magazine semantics. + * + * You must call bson_destroy() with @b to release resources when you are done + * using @b. + */ +BSON_EXPORT (void) +bson_init (bson_t *b); + + +/** + * bson_reinit: + * @b: (inout): A bson_t. + * + * This is equivalent to calling bson_destroy() and bson_init() on a #bson_t. + * However, it will try to persist the existing malloc'd buffer if one exists. + * This is useful in cases where you want to reduce malloc overhead while + * building many documents. + */ +BSON_EXPORT (void) +bson_reinit (bson_t *b); + + +/** + * bson_new_from_data: + * @data: A buffer containing a serialized bson document. + * @length: The length of the document in bytes. + * + * Creates a new bson_t structure using the data provided. @data should contain + * at least @length bytes that can be copied into the new bson_t structure. + * + * Returns: A newly allocated bson_t that should be freed with bson_destroy(). + * If the first four bytes (little-endian) of data do not match @length, + * then NULL will be returned. + */ +BSON_EXPORT (bson_t *) +bson_new_from_data (const uint8_t *data, size_t length); + + +/** + * bson_new_from_buffer: + * @buf: A pointer to a buffer containing a serialized bson document. + * @buf_len: The length of the buffer in bytes. + * @realloc_fun: a realloc like function + * @realloc_fun_ctx: a context for the realloc function + * + * Creates a new bson_t structure using the data provided. @buf should contain + * a bson document, or null pointer should be passed for new allocations. + * + * Returns: A newly allocated bson_t that should be freed with bson_destroy(). + * The underlying buffer will be used and not be freed in destroy. + */ +BSON_EXPORT (bson_t *) +bson_new_from_buffer (uint8_t **buf, + size_t *buf_len, + bson_realloc_func realloc_func, + void *realloc_func_ctx); + + +/** + * bson_sized_new: + * @size: A size_t containing the number of bytes to allocate. + * + * This will allocate a new bson_t with enough bytes to hold a buffer + * sized @size. @size must be smaller than INT_MAX bytes. + * + * Returns: A newly allocated bson_t that should be freed with bson_destroy(). + */ +BSON_EXPORT (bson_t *) +bson_sized_new (size_t size); + + +/** + * bson_copy: + * @bson: A bson_t. + * + * Copies @bson into a newly allocated bson_t. You must call bson_destroy() + * when you are done with the resulting value to free its resources. + * + * Returns: A newly allocated bson_t that should be free'd with bson_destroy() + */ +BSON_EXPORT (bson_t *) +bson_copy (const bson_t *bson); + + +/** + * bson_copy_to: + * @src: The source bson_t. + * @dst: The destination bson_t. + * + * Initializes @dst and copies the content from @src into @dst. + */ +BSON_EXPORT (void) +bson_copy_to (const bson_t *src, bson_t *dst); + + +/** + * bson_copy_to_excluding: + * @src: A bson_t. + * @dst: A bson_t to initialize and copy into. + * @first_exclude: First field name to exclude. + * + * Copies @src into @dst excluding any field that is provided. + * This is handy for situations when you need to remove one or + * more fields in a bson_t. Note that bson_init() will be called + * on dst. + */ +BSON_EXPORT (void) +bson_copy_to_excluding (const bson_t *src, + bson_t *dst, + const char *first_exclude, + ...) BSON_GNUC_NULL_TERMINATED + BSON_GNUC_DEPRECATED_FOR (bson_copy_to_excluding_noinit); + +/** + * bson_copy_to_excluding_noinit: + * @src: A bson_t. + * @dst: A bson_t to initialize and copy into. + * @first_exclude: First field name to exclude. + * + * The same as bson_copy_to_excluding, but does not call bson_init() + * on the dst. This version should be preferred in new code, but the + * old function is left for backwards compatibility. + */ +BSON_EXPORT (void) +bson_copy_to_excluding_noinit (const bson_t *src, + bson_t *dst, + const char *first_exclude, + ...) BSON_GNUC_NULL_TERMINATED; + +/** + * bson_destroy: + * @bson: A bson_t. + * + * Frees the resources associated with @bson. + */ +BSON_EXPORT (void) +bson_destroy (bson_t *bson); + +BSON_EXPORT (uint8_t *) +bson_reserve_buffer (bson_t *bson, uint32_t size); + +BSON_EXPORT (bool) +bson_steal (bson_t *dst, bson_t *src); + + +/** + * bson_destroy_with_steal: + * @bson: A #bson_t. + * @steal: If ownership of the data buffer should be transferred to caller. + * @length: (out): location for the length of the buffer. + * + * Destroys @bson similar to calling bson_destroy() except that the underlying + * buffer will be returned and ownership transferred to the caller if @steal + * is non-zero. + * + * If length is non-NULL, the length of @bson will be stored in @length. + * + * It is a programming error to call this function with any bson that has + * been initialized static, or is being used to create a subdocument with + * functions such as bson_append_document_begin() or bson_append_array_begin(). + * + * Returns: a buffer owned by the caller if @steal is true. Otherwise NULL. + * If there was an error, NULL is returned. + */ +BSON_EXPORT (uint8_t *) +bson_destroy_with_steal (bson_t *bson, bool steal, uint32_t *length); + + +/** + * bson_get_data: + * @bson: A bson_t. + * + * Fetched the data buffer for @bson of @bson->len bytes in length. + * + * Returns: A buffer that should not be modified or freed. + */ +BSON_EXPORT (const uint8_t *) +bson_get_data (const bson_t *bson); + + +/** + * bson_count_keys: + * @bson: A bson_t. + * + * Counts the number of elements found in @bson. + */ +BSON_EXPORT (uint32_t) +bson_count_keys (const bson_t *bson); + + +/** + * bson_has_field: + * @bson: A bson_t. + * @key: The key to lookup. + * + * Checks to see if @bson contains a field named @key. + * + * This function is case-sensitive. + * + * Returns: true if @key exists in @bson; otherwise false. + */ +BSON_EXPORT (bool) +bson_has_field (const bson_t *bson, const char *key); + + +/** + * bson_compare: + * @bson: A bson_t. + * @other: A bson_t. + * + * Compares @bson to @other in a qsort() style comparison. + * See qsort() for information on how this function works. + * + * Returns: Less than zero, zero, or greater than zero. + */ +BSON_EXPORT (int) +bson_compare (const bson_t *bson, const bson_t *other); + +/* + * bson_compare: + * @bson: A bson_t. + * @other: A bson_t. + * + * Checks to see if @bson and @other are equal. + * + * Returns: true if equal; otherwise false. + */ +BSON_EXPORT (bool) +bson_equal (const bson_t *bson, const bson_t *other); + + +/** + * bson_validate: + * @bson: A bson_t. + * @offset: A location for the error offset. + * + * Validates a BSON document by walking through the document and inspecting + * the fields for valid content. + * + * Returns: true if @bson is valid; otherwise false and @offset is set. + */ +BSON_EXPORT (bool) +bson_validate (const bson_t *bson, bson_validate_flags_t flags, size_t *offset); + + +/** + * bson_validate_with_error: + * @bson: A bson_t. + * @error: A location for the error info. + * + * Validates a BSON document by walking through the document and inspecting + * the fields for valid content. + * + * Returns: true if @bson is valid; otherwise false and @error is filled out. + */ +BSON_EXPORT (bool) +bson_validate_with_error (const bson_t *bson, + bson_validate_flags_t flags, + bson_error_t *error); + +/** + * bson_as_extended_json: + * @bson: A bson_t. + * @length: A location for the string length, or NULL. + * + * Creates a new string containing @bson in extended JSON format, conforming to + * the MongoDB Extended JSON Spec: + * + * github.com/mongodb/specifications/blob/master/source/extended-json.rst + * + * The caller is responsible for freeing the resulting string. If @length is + * non-NULL, then the length of the resulting string will be placed in @length. + * + * See http://docs.mongodb.org/manual/reference/mongodb-extended-json/ for + * more information on extended JSON. + * + * Returns: A newly allocated string that should be freed with bson_free(). + */ +BSON_EXPORT (char *) +bson_as_extended_json (const bson_t *bson, size_t *length); + + +/** + * bson_as_json: + * @bson: A bson_t. + * @length: A location for the string length, or NULL. + * + * Creates a new string containing @bson in libbson's legacy JSON format. + * Superseded by bson_as_extended_json. The caller is responsible for freeing + * the resulting string. If @length is non-NULL, then the length of the + * resulting string will be placed in @length. + * + * Returns: A newly allocated string that should be freed with bson_free(). + */ +BSON_EXPORT (char *) +bson_as_json (const bson_t *bson, size_t *length); + + +/* like bson_as_json() but for outermost arrays. */ +BSON_EXPORT (char *) +bson_array_as_json (const bson_t *bson, size_t *length); + + +BSON_EXPORT (bool) +bson_append_value (bson_t *bson, + const char *key, + int key_length, + const bson_value_t *value); + + +/** + * bson_append_array: + * @bson: A bson_t. + * @key: The key for the field. + * @array: A bson_t containing the array. + * + * Appends a BSON array to @bson. BSON arrays are like documents where the + * key is the string version of the index. For example, the first item of the + * array would have the key "0". The second item would have the index "1". + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_array (bson_t *bson, + const char *key, + int key_length, + const bson_t *array); + + +/** + * bson_append_binary: + * @bson: A bson_t to append. + * @key: The key for the field. + * @subtype: The bson_subtype_t of the binary. + * @binary: The binary buffer to append. + * @length: The length of @binary. + * + * Appends a binary buffer to the BSON document. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_binary (bson_t *bson, + const char *key, + int key_length, + unsigned int subtype, + const uint8_t *binary, + uint32_t length); + + +/** + * bson_append_bool: + * @bson: A bson_t. + * @key: The key for the field. + * @value: The boolean value. + * + * Appends a new field to @bson of type BSON_TYPE_BOOL. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_bool (bson_t *bson, const char *key, int key_length, bool value); + + +/** + * bson_append_code: + * @bson: A bson_t. + * @key: The key for the document. + * @javascript: JavaScript code to be executed. + * + * Appends a field of type BSON_TYPE_CODE to the BSON document. @javascript + * should contain a script in javascript to be executed. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_code (bson_t *bson, + const char *key, + int key_length, + const char *javascript); + + +/** + * bson_append_code_with_scope: + * @bson: A bson_t. + * @key: The key for the document. + * @javascript: JavaScript code to be executed. + * @scope: A bson_t containing the scope for @javascript. + * + * Appends a field of type BSON_TYPE_CODEWSCOPE to the BSON document. + * @javascript should contain a script in javascript to be executed. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_code_with_scope (bson_t *bson, + const char *key, + int key_length, + const char *javascript, + const bson_t *scope); + + +/** + * bson_append_dbpointer: + * @bson: A bson_t. + * @key: The key for the field. + * @collection: The collection name. + * @oid: The oid to the reference. + * + * Appends a new field of type BSON_TYPE_DBPOINTER. This datum type is + * deprecated in the BSON spec and should not be used in new code. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_dbpointer (bson_t *bson, + const char *key, + int key_length, + const char *collection, + const bson_oid_t *oid); + + +/** + * bson_append_double: + * @bson: A bson_t. + * @key: The key for the field. + * + * Appends a new field to @bson of the type BSON_TYPE_DOUBLE. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_double (bson_t *bson, + const char *key, + int key_length, + double value); + + +/** + * bson_append_document: + * @bson: A bson_t. + * @key: The key for the field. + * @value: A bson_t containing the subdocument. + * + * Appends a new field to @bson of the type BSON_TYPE_DOCUMENT. + * The documents contents will be copied into @bson. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_document (bson_t *bson, + const char *key, + int key_length, + const bson_t *value); + + +/** + * bson_append_document_begin: + * @bson: A bson_t. + * @key: The key for the field. + * @key_length: The length of @key in bytes not including NUL or -1 + * if @key_length is NUL terminated. + * @child: A location to an uninitialized bson_t. + * + * Appends a new field named @key to @bson. The field is, however, + * incomplete. @child will be initialized so that you may add fields to the + * child document. Child will use a memory buffer owned by @bson and + * therefore grow the parent buffer as additional space is used. This allows + * a single malloc'd buffer to be used when building documents which can help + * reduce memory fragmentation. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_document_begin (bson_t *bson, + const char *key, + int key_length, + bson_t *child); + + +/** + * bson_append_document_end: + * @bson: A bson_t. + * @child: A bson_t supplied to bson_append_document_begin(). + * + * Finishes the appending of a document to a @bson. @child is considered + * disposed after this call and should not be used any further. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_document_end (bson_t *bson, bson_t *child); + + +/** + * bson_append_array_begin: + * @bson: A bson_t. + * @key: The key for the field. + * @key_length: The length of @key in bytes not including NUL or -1 + * if @key_length is NUL terminated. + * @child: A location to an uninitialized bson_t. + * + * Appends a new field named @key to @bson. The field is, however, + * incomplete. @child will be initialized so that you may add fields to the + * child array. Child will use a memory buffer owned by @bson and + * therefore grow the parent buffer as additional space is used. This allows + * a single malloc'd buffer to be used when building arrays which can help + * reduce memory fragmentation. + * + * The type of @child will be BSON_TYPE_ARRAY and therefore the keys inside + * of it MUST be "0", "1", etc. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_array_begin (bson_t *bson, + const char *key, + int key_length, + bson_t *child); + + +/** + * bson_append_array_end: + * @bson: A bson_t. + * @child: A bson_t supplied to bson_append_array_begin(). + * + * Finishes the appending of a array to a @bson. @child is considered + * disposed after this call and should not be used any further. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_array_end (bson_t *bson, bson_t *child); + + +/** + * bson_append_int32: + * @bson: A bson_t. + * @key: The key for the field. + * @value: The int32_t 32-bit integer value. + * + * Appends a new field of type BSON_TYPE_INT32 to @bson. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_int32 (bson_t *bson, + const char *key, + int key_length, + int32_t value); + + +/** + * bson_append_int64: + * @bson: A bson_t. + * @key: The key for the field. + * @value: The int64_t 64-bit integer value. + * + * Appends a new field of type BSON_TYPE_INT64 to @bson. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_int64 (bson_t *bson, + const char *key, + int key_length, + int64_t value); + + +/** + * bson_append_decimal128: + * @bson: A bson_t. + * @key: The key for the field. + * @value: The bson_decimal128_t decimal128 value. + * + * Appends a new field of type BSON_TYPE_DECIMAL128 to @bson. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_decimal128 (bson_t *bson, + const char *key, + int key_length, + const bson_decimal128_t *value); + + +/** + * bson_append_iter: + * @bson: A bson_t to append to. + * @key: The key name or %NULL to take current key from @iter. + * @key_length: The key length or -1 to use strlen(). + * @iter: The iter located on the position of the element to append. + * + * Appends a new field to @bson that is equivalent to the field currently + * pointed to by @iter. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_iter (bson_t *bson, + const char *key, + int key_length, + const bson_iter_t *iter); + + +/** + * bson_append_minkey: + * @bson: A bson_t. + * @key: The key for the field. + * + * Appends a new field of type BSON_TYPE_MINKEY to @bson. This is a special + * type that compares lower than all other possible BSON element values. + * + * See http://bsonspec.org for more information on this type. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_minkey (bson_t *bson, const char *key, int key_length); + + +/** + * bson_append_maxkey: + * @bson: A bson_t. + * @key: The key for the field. + * + * Appends a new field of type BSON_TYPE_MAXKEY to @bson. This is a special + * type that compares higher than all other possible BSON element values. + * + * See http://bsonspec.org for more information on this type. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_maxkey (bson_t *bson, const char *key, int key_length); + + +/** + * bson_append_null: + * @bson: A bson_t. + * @key: The key for the field. + * + * Appends a new field to @bson with NULL for the value. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_null (bson_t *bson, const char *key, int key_length); + + +/** + * bson_append_oid: + * @bson: A bson_t. + * @key: The key for the field. + * @oid: bson_oid_t. + * + * Appends a new field to the @bson of type BSON_TYPE_OID using the contents of + * @oid. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_oid (bson_t *bson, + const char *key, + int key_length, + const bson_oid_t *oid); + + +/** + * bson_append_regex: + * @bson: A bson_t. + * @key: The key of the field. + * @regex: The regex to append to the bson. + * @options: Options for @regex. + * + * Appends a new field to @bson of type BSON_TYPE_REGEX. @regex should + * be the regex string. @options should contain the options for the regex. + * + * Valid options for @options are: + * + * 'i' for case-insensitive. + * 'm' for multiple matching. + * 'x' for verbose mode. + * 'l' to make \w and \W locale dependent. + * 's' for dotall mode ('.' matches everything) + * 'u' to make \w and \W match unicode. + * + * For more information on what comprimises a BSON regex, see bsonspec.org. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_regex (bson_t *bson, + const char *key, + int key_length, + const char *regex, + const char *options); + + +/** + * bson_append_utf8: + * @bson: A bson_t. + * @key: The key for the field. + * @value: A UTF-8 encoded string. + * @length: The length of @value or -1 if it is NUL terminated. + * + * Appends a new field to @bson using @key as the key and @value as the UTF-8 + * encoded value. + * + * It is the callers responsibility to ensure @value is valid UTF-8. You can + * use bson_utf8_validate() to perform this check. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_utf8 (bson_t *bson, + const char *key, + int key_length, + const char *value, + int length); + + +/** + * bson_append_symbol: + * @bson: A bson_t. + * @key: The key for the field. + * @value: The symbol as a string. + * @length: The length of @value or -1 if NUL-terminated. + * + * Appends a new field to @bson of type BSON_TYPE_SYMBOL. This BSON type is + * deprecated and should not be used in new code. + * + * See http://bsonspec.org for more information on this type. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_symbol (bson_t *bson, + const char *key, + int key_length, + const char *value, + int length); + + +/** + * bson_append_time_t: + * @bson: A bson_t. + * @key: The key for the field. + * @value: A time_t. + * + * Appends a BSON_TYPE_DATE_TIME field to @bson using the time_t @value for the + * number of seconds since UNIX epoch in UTC. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_time_t (bson_t *bson, + const char *key, + int key_length, + time_t value); + + +/** + * bson_append_timeval: + * @bson: A bson_t. + * @key: The key for the field. + * @value: A struct timeval containing the date and time. + * + * Appends a BSON_TYPE_DATE_TIME field to @bson using the struct timeval + * provided. The time is persisted in milliseconds since the UNIX epoch in UTC. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_timeval (bson_t *bson, + const char *key, + int key_length, + struct timeval *value); + + +/** + * bson_append_date_time: + * @bson: A bson_t. + * @key: The key for the field. + * @key_length: The length of @key in bytes or -1 if \0 terminated. + * @value: The number of milliseconds elapsed since UNIX epoch. + * + * Appends a new field to @bson of type BSON_TYPE_DATE_TIME. + * + * Returns: true if sucessful; otherwise false. + */ +BSON_EXPORT (bool) +bson_append_date_time (bson_t *bson, + const char *key, + int key_length, + int64_t value); + + +/** + * bson_append_now_utc: + * @bson: A bson_t. + * @key: The key for the field. + * @key_length: The length of @key or -1 if it is NULL terminated. + * + * Appends a BSON_TYPE_DATE_TIME field to @bson using the current time in UTC + * as the field value. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_now_utc (bson_t *bson, const char *key, int key_length); + +/** + * bson_append_timestamp: + * @bson: A bson_t. + * @key: The key for the field. + * @timestamp: 4 byte timestamp. + * @increment: 4 byte increment for timestamp. + * + * Appends a field of type BSON_TYPE_TIMESTAMP to @bson. This is a special type + * used by MongoDB replication and sharding. If you need generic time and date + * fields use bson_append_time_t() or bson_append_timeval(). + * + * Setting @increment and @timestamp to zero has special semantics. See + * http://bsonspec.org for more information on this field type. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_timestamp (bson_t *bson, + const char *key, + int key_length, + uint32_t timestamp, + uint32_t increment); + + +/** + * bson_append_undefined: + * @bson: A bson_t. + * @key: The key for the field. + * + * Appends a field of type BSON_TYPE_UNDEFINED. This type is deprecated in the + * spec and should not be used for new code. However, it is provided for those + * needing to interact with legacy systems. + * + * Returns: true if successful; false if append would overflow max size. + */ +BSON_EXPORT (bool) +bson_append_undefined (bson_t *bson, const char *key, int key_length); + + +BSON_EXPORT (bool) +bson_concat (bson_t *dst, const bson_t *src); + + +BSON_END_DECLS + + +#endif /* BSON_H */ diff --git a/chaos_micro_unit_toolkit/external_lib/bson/jsonsl/jsonsl.c b/chaos_micro_unit_toolkit/external_lib/bson/jsonsl/jsonsl.c new file mode 100644 index 0000000000000000000000000000000000000000..642a904a8d807562dfd65c5f85d4ec523388e051 --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/jsonsl/jsonsl.c @@ -0,0 +1,1669 @@ +/* Copyright (C) 2012-2015 Mark Nunberg. + * + * See included LICENSE file for license details. + */ + +#include "jsonsl.h" +#include "../bson/bson-memory.h" + +#include <limits.h> +#include <ctype.h> + +#ifdef JSONSL_USE_METRICS +#define XMETRICS \ + X(STRINGY_INSIGNIFICANT) \ + X(STRINGY_SLOWPATH) \ + X(ALLOWED_WHITESPACE) \ + X(QUOTE_FASTPATH) \ + X(SPECIAL_FASTPATH) \ + X(SPECIAL_WSPOP) \ + X(SPECIAL_SLOWPATH) \ + X(GENERIC) \ + X(STRUCTURAL_TOKEN) \ + X(SPECIAL_SWITCHFIRST) \ + X(STRINGY_CATCH) \ + X(NUMBER_FASTPATH) \ + X(ESCAPES) \ + X(TOTAL) \ + +struct jsonsl_metrics_st { +#define X(m) \ + unsigned long metric_##m; + XMETRICS +#undef X +}; + +static struct jsonsl_metrics_st GlobalMetrics = { 0 }; +static unsigned long GenericCounter[0x100] = { 0 }; +static unsigned long StringyCatchCounter[0x100] = { 0 }; + +#define INCR_METRIC(m) \ + GlobalMetrics.metric_##m++; + +#define INCR_GENERIC(c) \ + INCR_METRIC(GENERIC); \ + GenericCounter[c]++; \ + +#define INCR_STRINGY_CATCH(c) \ + INCR_METRIC(STRINGY_CATCH); \ + StringyCatchCounter[c]++; + +JSONSL_API +void jsonsl_dump_global_metrics(void) +{ + int ii; + printf("JSONSL Metrics:\n"); +#define X(m) \ + printf("\t%-30s %20lu (%0.2f%%)\n", #m, GlobalMetrics.metric_##m, \ + (float)((float)(GlobalMetrics.metric_##m/(float)GlobalMetrics.metric_TOTAL)) * 100); + XMETRICS +#undef X + printf("Generic Characters:\n"); + for (ii = 0; ii < 0xff; ii++) { + if (GenericCounter[ii]) { + printf("\t[ %c ] %lu\n", ii, GenericCounter[ii]); + } + } + printf("Weird string loop\n"); + for (ii = 0; ii < 0xff; ii++) { + if (StringyCatchCounter[ii]) { + printf("\t[ %c ] %lu\n", ii, StringyCatchCounter[ii]); + } + } +} + +#else +#define INCR_METRIC(m) +#define INCR_GENERIC(c) +#define INCR_STRINGY_CATCH(c) +JSONSL_API +void jsonsl_dump_global_metrics(void) { } +#endif /* JSONSL_USE_METRICS */ + +#define CASE_DIGITS \ +case '1': \ +case '2': \ +case '3': \ +case '4': \ +case '5': \ +case '6': \ +case '7': \ +case '8': \ +case '9': \ +case '0': + +static unsigned extract_special(unsigned); +static int is_special_end(unsigned); +static int is_allowed_whitespace(unsigned); +static int is_allowed_escape(unsigned); +static int is_simple_char(unsigned); +static char get_escape_equiv(unsigned); + +JSONSL_API +jsonsl_t jsonsl_new(int nlevels) +{ + unsigned int ii; + struct jsonsl_st * jsn; + + if (nlevels < 2) { + return NULL; + } + + jsn = (struct jsonsl_st *) + bson_malloc0(sizeof (*jsn) + + ( (nlevels-1) * sizeof (struct jsonsl_state_st) ) + ); + + jsn->levels_max = (unsigned int) nlevels; + jsn->max_callback_level = UINT_MAX; + jsonsl_reset(jsn); + for (ii = 0; ii < jsn->levels_max; ii++) { + jsn->stack[ii].level = ii; + } + return jsn; +} + +JSONSL_API +void jsonsl_reset(jsonsl_t jsn) +{ + jsn->tok_last = 0; + jsn->can_insert = 1; + jsn->pos = 0; + jsn->level = 0; + jsn->stopfl = 0; + jsn->in_escape = 0; + jsn->expecting = 0; +} + +JSONSL_API +void jsonsl_destroy(jsonsl_t jsn) +{ + if (jsn) { + bson_free(jsn); + } +} + + +#define FASTPARSE_EXHAUSTED 1 +#define FASTPARSE_BREAK 0 + +/* + * This function is meant to accelerate string parsing, reducing the main loop's + * check if we are indeed a string. + * + * @param jsn the parser + * @param[in,out] bytes_p A pointer to the current buffer (i.e. current position) + * @param[in,out] nbytes_p A pointer to the current size of the buffer + * @return true if all bytes have been exhausted (and thus the main loop can + * return), false if a special character was examined which requires greater + * examination. + */ +static int +jsonsl__str_fastparse(jsonsl_t jsn, + const jsonsl_uchar_t **bytes_p, size_t *nbytes_p) +{ + const jsonsl_uchar_t *bytes = *bytes_p; + const jsonsl_uchar_t *end; + for (end = bytes + *nbytes_p; bytes != end; bytes++) { + if ( +#ifdef JSONSL_USE_WCHAR + *bytes >= 0x100 || +#endif /* JSONSL_USE_WCHAR */ + (is_simple_char(*bytes))) { + INCR_METRIC(TOTAL); + INCR_METRIC(STRINGY_INSIGNIFICANT); + } else { + /* Once we're done here, re-calculate the position variables */ + jsn->pos += (bytes - *bytes_p); + *nbytes_p -= (bytes - *bytes_p); + *bytes_p = bytes; + return FASTPARSE_BREAK; + } + } + + /* Once we're done here, re-calculate the position variables */ + jsn->pos += (bytes - *bytes_p); + return FASTPARSE_EXHAUSTED; +} + +/* Functions exactly like str_fastparse, except it also accepts a 'state' + * argument, since the number's value is updated in the state. */ +static int +jsonsl__num_fastparse(jsonsl_t jsn, + const jsonsl_uchar_t **bytes_p, size_t *nbytes_p, + struct jsonsl_state_st *state) +{ + int exhausted = 1; + size_t nbytes = *nbytes_p; + const jsonsl_uchar_t *bytes = *bytes_p; + + for (; nbytes; nbytes--, bytes++) { + jsonsl_uchar_t c = *bytes; + if (isdigit(c)) { + INCR_METRIC(TOTAL); + INCR_METRIC(NUMBER_FASTPATH); + state->nelem = (state->nelem * 10) + (c - 0x30); + } else { + exhausted = 0; + break; + } + } + jsn->pos += (*nbytes_p - nbytes); + if (exhausted) { + return FASTPARSE_EXHAUSTED; + } + *nbytes_p = nbytes; + *bytes_p = bytes; + return FASTPARSE_BREAK; +} + +JSONSL_API +void +jsonsl_feed(jsonsl_t jsn, const jsonsl_char_t *bytes, size_t nbytes) +{ + +#define INVOKE_ERROR(eb) \ + if (jsn->error_callback(jsn, JSONSL_ERROR_##eb, state, (char*)c)) { \ + goto GT_AGAIN; \ + } \ + return; + +#define STACK_PUSH \ + if (jsn->level >= (levels_max-1)) { \ + jsn->error_callback(jsn, JSONSL_ERROR_LEVELS_EXCEEDED, state, (char*)c); \ + return; \ + } \ + state = jsn->stack + (++jsn->level); \ + state->ignore_callback = jsn->stack[jsn->level-1].ignore_callback; \ + state->pos_begin = jsn->pos; + +#define STACK_POP_NOPOS \ + state->pos_cur = jsn->pos; \ + state = jsn->stack + (--jsn->level); + + +#define STACK_POP \ + STACK_POP_NOPOS; \ + state->pos_cur = jsn->pos; + +#define CALLBACK_AND_POP_NOPOS(T) \ + state->pos_cur = jsn->pos; \ + DO_CALLBACK(T, POP); \ + state->nescapes = 0; \ + state = jsn->stack + (--jsn->level); + +#define CALLBACK_AND_POP(T) \ + CALLBACK_AND_POP_NOPOS(T); \ + state->pos_cur = jsn->pos; + +#define SPECIAL_POP \ + CALLBACK_AND_POP(SPECIAL); \ + jsn->expecting = 0; \ + jsn->tok_last = 0; \ + +#define CUR_CHAR (*(jsonsl_uchar_t*)c) + +#define DO_CALLBACK(T, action) \ + if (jsn->call_##T && \ + jsn->max_callback_level > state->level && \ + state->ignore_callback == 0) { \ + \ + if (jsn->action_callback_##action) { \ + jsn->action_callback_##action(jsn, JSONSL_ACTION_##action, state, (jsonsl_char_t*)c); \ + } else if (jsn->action_callback) { \ + jsn->action_callback(jsn, JSONSL_ACTION_##action, state, (jsonsl_char_t*)c); \ + } \ + if (jsn->stopfl) { return; } \ + } + + /** + * Verifies that we are able to insert the (non-string) item into a hash. + */ +#define ENSURE_HVAL \ + if (state->nelem % 2 == 0 && state->type == JSONSL_T_OBJECT) { \ + INVOKE_ERROR(HKEY_EXPECTED); \ + } + +#define VERIFY_SPECIAL(lit) \ + if (CUR_CHAR != (lit)[jsn->pos - state->pos_begin]) { \ + INVOKE_ERROR(SPECIAL_EXPECTED); \ + } + +#define VERIFY_SPECIAL_CI(lit) \ + if (tolower(CUR_CHAR) != (lit)[jsn->pos - state->pos_begin]) { \ + INVOKE_ERROR(SPECIAL_EXPECTED); \ + } + +#define STATE_SPECIAL_LENGTH \ + (state)->nescapes + +#define IS_NORMAL_NUMBER \ + ((state)->special_flags == JSONSL_SPECIALf_UNSIGNED || \ + (state)->special_flags == JSONSL_SPECIALf_SIGNED) + +#define STATE_NUM_LAST jsn->tok_last + +#define CONTINUE_NEXT_CHAR() continue + + const jsonsl_uchar_t *c = (jsonsl_uchar_t*)bytes; + size_t levels_max = jsn->levels_max; + struct jsonsl_state_st *state = jsn->stack + jsn->level; + jsn->base = bytes; + + for (; nbytes; nbytes--, jsn->pos++, c++) { + unsigned state_type; + INCR_METRIC(TOTAL); + + GT_AGAIN: + state_type = state->type; + /* Most common type is typically a string: */ + if (state_type & JSONSL_Tf_STRINGY) { + /* Special escape handling for some stuff */ + if (jsn->in_escape) { + jsn->in_escape = 0; + if (!is_allowed_escape(CUR_CHAR)) { + INVOKE_ERROR(ESCAPE_INVALID); + } else if (CUR_CHAR == 'u') { + DO_CALLBACK(UESCAPE, UESCAPE); + if (jsn->return_UESCAPE) { + return; + } + } + CONTINUE_NEXT_CHAR(); + } + + if (jsonsl__str_fastparse(jsn, &c, &nbytes) == + FASTPARSE_EXHAUSTED) { + /* No need to readjust variables as we've exhausted the iterator */ + return; + } else { + if (CUR_CHAR == '"') { + goto GT_QUOTE; + } else if (CUR_CHAR == '\\') { + goto GT_ESCAPE; + } else { + INVOKE_ERROR(WEIRD_WHITESPACE); + } + } + INCR_METRIC(STRINGY_SLOWPATH); + + } else if (state_type == JSONSL_T_SPECIAL) { + /* Fast track for signed/unsigned */ + if (IS_NORMAL_NUMBER) { + if (jsonsl__num_fastparse(jsn, &c, &nbytes, state) == + FASTPARSE_EXHAUSTED) { + return; + } else { + goto GT_SPECIAL_NUMERIC; + } + } else if (state->special_flags == JSONSL_SPECIALf_DASH) { +#ifdef JSONSL_PARSE_NAN + if (CUR_CHAR == 'I' || CUR_CHAR == 'i') { + /* parsing -Infinity? */ + state->special_flags = JSONSL_SPECIALf_NEG_INF; + CONTINUE_NEXT_CHAR(); + } +#endif + + if (!isdigit(CUR_CHAR)) { + INVOKE_ERROR(INVALID_NUMBER); + } + + if (CUR_CHAR == '0') { + state->special_flags = JSONSL_SPECIALf_ZERO|JSONSL_SPECIALf_SIGNED; + } else if (isdigit(CUR_CHAR)) { + state->special_flags = JSONSL_SPECIALf_SIGNED; + state->nelem = CUR_CHAR - 0x30; + } else { + INVOKE_ERROR(INVALID_NUMBER); + } + CONTINUE_NEXT_CHAR(); + + } else if (state->special_flags == JSONSL_SPECIALf_ZERO) { + if (isdigit(CUR_CHAR)) { + /* Following a zero! */ + INVOKE_ERROR(INVALID_NUMBER); + } + /* Unset the 'zero' flag: */ + if (state->special_flags & JSONSL_SPECIALf_SIGNED) { + state->special_flags = JSONSL_SPECIALf_SIGNED; + } else { + state->special_flags = JSONSL_SPECIALf_UNSIGNED; + } + goto GT_SPECIAL_NUMERIC; + } + + if ((state->special_flags & JSONSL_SPECIALf_NUMERIC) && + !(state->special_flags & JSONSL_SPECIALf_INF)) { + GT_SPECIAL_NUMERIC: + switch (CUR_CHAR) { + CASE_DIGITS + STATE_NUM_LAST = '1'; + CONTINUE_NEXT_CHAR(); + + case '.': + if (state->special_flags & JSONSL_SPECIALf_FLOAT) { + INVOKE_ERROR(INVALID_NUMBER); + } + state->special_flags |= JSONSL_SPECIALf_FLOAT; + STATE_NUM_LAST = '.'; + CONTINUE_NEXT_CHAR(); + + case 'e': + case 'E': + if (state->special_flags & JSONSL_SPECIALf_EXPONENT) { + INVOKE_ERROR(INVALID_NUMBER); + } + state->special_flags |= JSONSL_SPECIALf_EXPONENT; + STATE_NUM_LAST = 'e'; + CONTINUE_NEXT_CHAR(); + + case '-': + case '+': + if (STATE_NUM_LAST != 'e') { + INVOKE_ERROR(INVALID_NUMBER); + } + STATE_NUM_LAST = '-'; + CONTINUE_NEXT_CHAR(); + + default: + if (is_special_end(CUR_CHAR)) { + goto GT_SPECIAL_POP; + } + INVOKE_ERROR(INVALID_NUMBER); + break; + } + } + /* else if (!NUMERIC) */ + if (!is_special_end(CUR_CHAR)) { + STATE_SPECIAL_LENGTH++; + + /* Verify TRUE, FALSE, NULL */ + if (state->special_flags == JSONSL_SPECIALf_TRUE) { + VERIFY_SPECIAL("true"); + } else if (state->special_flags == JSONSL_SPECIALf_FALSE) { + VERIFY_SPECIAL("false"); + } else if (state->special_flags == JSONSL_SPECIALf_NULL) { + VERIFY_SPECIAL("null"); +#ifdef JSONSL_PARSE_NAN + } else if (state->special_flags == JSONSL_SPECIALf_POS_INF) { + VERIFY_SPECIAL_CI("infinity"); + } else if (state->special_flags == JSONSL_SPECIALf_NEG_INF) { + VERIFY_SPECIAL_CI("-infinity"); + } else if (state->special_flags == JSONSL_SPECIALf_NAN) { + VERIFY_SPECIAL_CI("nan"); + } else if (state->special_flags & JSONSL_SPECIALf_NULL || + state->special_flags & JSONSL_SPECIALf_NAN) { + /* previous char was "n", are we parsing null or nan? */ + if (CUR_CHAR != 'u') { + state->special_flags &= ~JSONSL_SPECIALf_NULL; + } + + if (tolower(CUR_CHAR) != 'a') { + state->special_flags &= ~JSONSL_SPECIALf_NAN; + } +#endif + } + INCR_METRIC(SPECIAL_FASTPATH); + CONTINUE_NEXT_CHAR(); + } + + GT_SPECIAL_POP: + jsn->can_insert = 0; + if (IS_NORMAL_NUMBER) { + /* Nothing */ + } else if (state->special_flags == JSONSL_SPECIALf_ZERO || + state->special_flags == (JSONSL_SPECIALf_ZERO|JSONSL_SPECIALf_SIGNED)) { + /* 0 is unsigned! */ + state->special_flags = JSONSL_SPECIALf_UNSIGNED; + } else if (state->special_flags == JSONSL_SPECIALf_DASH) { + /* Still in dash! */ + INVOKE_ERROR(INVALID_NUMBER); + } else if (state->special_flags & JSONSL_SPECIALf_INF) { + if (STATE_SPECIAL_LENGTH != 8) { + INVOKE_ERROR(SPECIAL_INCOMPLETE); + } + state->nelem = 1; + } else if (state->special_flags & JSONSL_SPECIALf_NUMERIC) { + /* Check that we're not at the end of a token */ + if (STATE_NUM_LAST != '1') { + INVOKE_ERROR(INVALID_NUMBER); + } + } else if (state->special_flags == JSONSL_SPECIALf_TRUE) { + if (STATE_SPECIAL_LENGTH != 4) { + INVOKE_ERROR(SPECIAL_INCOMPLETE); + } + state->nelem = 1; + } else if (state->special_flags == JSONSL_SPECIALf_FALSE) { + if (STATE_SPECIAL_LENGTH != 5) { + INVOKE_ERROR(SPECIAL_INCOMPLETE); + } + } else if (state->special_flags == JSONSL_SPECIALf_NULL) { + if (STATE_SPECIAL_LENGTH != 4) { + INVOKE_ERROR(SPECIAL_INCOMPLETE); + } + } + SPECIAL_POP; + jsn->expecting = ','; + if (is_allowed_whitespace(CUR_CHAR)) { + CONTINUE_NEXT_CHAR(); + } + /** + * This works because we have a non-whitespace token + * which is not a special token. If this is a structural + * character then it will be gracefully handled by the + * switch statement. Otherwise it will default to the 'special' + * state again, + */ + goto GT_STRUCTURAL_TOKEN; + } else if (is_allowed_whitespace(CUR_CHAR)) { + INCR_METRIC(ALLOWED_WHITESPACE); + /* So we're not special. Harmless insignificant whitespace + * passthrough + */ + CONTINUE_NEXT_CHAR(); + } else if (extract_special(CUR_CHAR)) { + /* not a string, whitespace, or structural token. must be special */ + goto GT_SPECIAL_BEGIN; + } + + INCR_GENERIC(CUR_CHAR); + + if (CUR_CHAR == '"') { + GT_QUOTE: + jsn->can_insert = 0; + switch (state_type) { + + /* the end of a string or hash key */ + case JSONSL_T_STRING: + CALLBACK_AND_POP(STRING); + CONTINUE_NEXT_CHAR(); + case JSONSL_T_HKEY: + CALLBACK_AND_POP(HKEY); + CONTINUE_NEXT_CHAR(); + + case JSONSL_T_OBJECT: + state->nelem++; + if ( (state->nelem-1) % 2 ) { + /* Odd, this must be a hash value */ + if (jsn->tok_last != ':') { + INVOKE_ERROR(MISSING_TOKEN); + } + jsn->expecting = ','; /* Can't figure out what to expect next */ + jsn->tok_last = 0; + + STACK_PUSH; + state->type = JSONSL_T_STRING; + DO_CALLBACK(STRING, PUSH); + + } else { + /* hash key */ + if (jsn->expecting != '"') { + INVOKE_ERROR(STRAY_TOKEN); + } + jsn->tok_last = 0; + jsn->expecting = ':'; + + STACK_PUSH; + state->type = JSONSL_T_HKEY; + DO_CALLBACK(HKEY, PUSH); + } + CONTINUE_NEXT_CHAR(); + + case JSONSL_T_LIST: + state->nelem++; + STACK_PUSH; + state->type = JSONSL_T_STRING; + jsn->expecting = ','; + jsn->tok_last = 0; + DO_CALLBACK(STRING, PUSH); + CONTINUE_NEXT_CHAR(); + + case JSONSL_T_SPECIAL: + INVOKE_ERROR(STRAY_TOKEN); + break; + + default: + INVOKE_ERROR(STRING_OUTSIDE_CONTAINER); + break; + } /* switch(state->type) */ + } else if (CUR_CHAR == '\\') { + GT_ESCAPE: + INCR_METRIC(ESCAPES); + /* Escape */ + if ( (state->type & JSONSL_Tf_STRINGY) == 0 ) { + INVOKE_ERROR(ESCAPE_OUTSIDE_STRING); + } + state->nescapes++; + jsn->in_escape = 1; + CONTINUE_NEXT_CHAR(); + } /* " or \ */ + + GT_STRUCTURAL_TOKEN: + switch (CUR_CHAR) { + case ':': + INCR_METRIC(STRUCTURAL_TOKEN); + if (jsn->expecting != CUR_CHAR) { + INVOKE_ERROR(STRAY_TOKEN); + } + jsn->tok_last = ':'; + jsn->can_insert = 1; + jsn->expecting = '"'; + CONTINUE_NEXT_CHAR(); + + case ',': + INCR_METRIC(STRUCTURAL_TOKEN); + /** + * The comma is one of the more generic tokens. + * In the context of an OBJECT, the can_insert flag + * should never be set, and no other action is + * necessary. + */ + if (jsn->expecting != CUR_CHAR) { + /* make this branch execute only when we haven't manually + * just placed the ',' in the expecting register. + */ + INVOKE_ERROR(STRAY_TOKEN); + } + + if (state->type == JSONSL_T_OBJECT) { + /* end of hash value, expect a string as a hash key */ + jsn->expecting = '"'; + } else { + jsn->can_insert = 1; + } + + jsn->tok_last = ','; + jsn->expecting = '"'; + CONTINUE_NEXT_CHAR(); + + /* new list or object */ + /* hashes are more common */ + case '{': + case '[': + INCR_METRIC(STRUCTURAL_TOKEN); + if (!jsn->can_insert) { + INVOKE_ERROR(CANT_INSERT); + } + + ENSURE_HVAL; + state->nelem++; + + STACK_PUSH; + /* because the constants match the opening delimiters, we can do this: */ + state->type = CUR_CHAR; + state->nelem = 0; + jsn->can_insert = 1; + if (CUR_CHAR == '{') { + /* If we're a hash, we expect a key first, which is quouted */ + jsn->expecting = '"'; + } + if (CUR_CHAR == JSONSL_T_OBJECT) { + DO_CALLBACK(OBJECT, PUSH); + } else { + DO_CALLBACK(LIST, PUSH); + } + jsn->tok_last = 0; + CONTINUE_NEXT_CHAR(); + + /* closing of list or object */ + case '}': + case ']': + INCR_METRIC(STRUCTURAL_TOKEN); + if (jsn->tok_last == ',' && jsn->options.allow_trailing_comma == 0) { + INVOKE_ERROR(TRAILING_COMMA); + } + + jsn->can_insert = 0; + jsn->level--; + jsn->expecting = ','; + jsn->tok_last = 0; + if (CUR_CHAR == ']') { + if (state->type != '[') { + INVOKE_ERROR(BRACKET_MISMATCH); + } + DO_CALLBACK(LIST, POP); + } else { + if (state->type != '{') { + INVOKE_ERROR(BRACKET_MISMATCH); + } else if (state->nelem && state->nelem % 2 != 0) { + INVOKE_ERROR(VALUE_EXPECTED); + } + DO_CALLBACK(OBJECT, POP); + } + state = jsn->stack + jsn->level; + state->pos_cur = jsn->pos; + CONTINUE_NEXT_CHAR(); + + default: + GT_SPECIAL_BEGIN: + /** + * Not a string, not a structural token, and not benign whitespace. + * Technically we should iterate over the character always, but since + * we are not doing full numerical/value decoding anyway (but only hinting), + * we only check upon entry. + */ + if (state->type != JSONSL_T_SPECIAL) { + int special_flags = extract_special(CUR_CHAR); + if (!special_flags) { + /** + * Try to do some heuristics here anyway to figure out what kind of + * error this is. The 'special' case is a fallback scenario anyway. + */ + if (CUR_CHAR == '\0') { + INVOKE_ERROR(FOUND_NULL_BYTE); + } else if (CUR_CHAR < 0x20) { + INVOKE_ERROR(WEIRD_WHITESPACE); + } else { + INVOKE_ERROR(SPECIAL_EXPECTED); + } + } + ENSURE_HVAL; + state->nelem++; + if (!jsn->can_insert) { + INVOKE_ERROR(CANT_INSERT); + } + STACK_PUSH; + state->type = JSONSL_T_SPECIAL; + state->special_flags = special_flags; + STATE_SPECIAL_LENGTH = 1; + + if (special_flags == JSONSL_SPECIALf_UNSIGNED) { + state->nelem = CUR_CHAR - 0x30; + STATE_NUM_LAST = '1'; + } else { + STATE_NUM_LAST = '-'; + state->nelem = 0; + } + DO_CALLBACK(SPECIAL, PUSH); + } + CONTINUE_NEXT_CHAR(); + } + } +} + +JSONSL_API +const char* jsonsl_strerror(jsonsl_error_t err) +{ + if (err == JSONSL_ERROR_SUCCESS) { + return "SUCCESS"; + } +#define X(t) \ + if (err == JSONSL_ERROR_##t) \ + return #t; + JSONSL_XERR; +#undef X + return "<UNKNOWN_ERROR>"; +} + +JSONSL_API +const char *jsonsl_strtype(jsonsl_type_t type) +{ +#define X(o,c) \ + if (type == JSONSL_T_##o) \ + return #o; + JSONSL_XTYPE +#undef X + return "UNKNOWN TYPE"; + +} + +/* + * + * JPR/JSONPointer functions + * + * + */ +#ifndef JSONSL_NO_JPR +static +jsonsl_jpr_type_t +populate_component(char *in, + struct jsonsl_jpr_component_st *component, + char **next, + jsonsl_error_t *errp) +{ + unsigned long pctval; + char *c = NULL, *outp = NULL, *end = NULL; + size_t input_len; + jsonsl_jpr_type_t ret = JSONSL_PATH_NONE; + + if (*next == NULL || *(*next) == '\0') { + return JSONSL_PATH_NONE; + } + + /* Replace the next / with a NULL */ + *next = strstr(in, "/"); + if (*next != NULL) { + *(*next) = '\0'; /* drop the forward slash */ + input_len = *next - in; + end = *next; + *next += 1; /* next character after the '/' */ + } else { + input_len = strlen(in); + end = in + input_len + 1; + } + + component->pstr = in; + + /* Check for special components of interest */ + if (*in == JSONSL_PATH_WILDCARD_CHAR && input_len == 1) { + /* Lone wildcard */ + ret = JSONSL_PATH_WILDCARD; + goto GT_RET; + } else if (isdigit(*in)) { + /* ASCII Numeric */ + char *endptr; + component->idx = strtoul(in, &endptr, 10); + if (endptr && *endptr == '\0') { + ret = JSONSL_PATH_NUMERIC; + goto GT_RET; + } + } + + /* Default, it's a string */ + ret = JSONSL_PATH_STRING; + for (c = outp = in; c < end; c++, outp++) { + char origc; + if (*c != '%') { + goto GT_ASSIGN; + } + /* + * c = { [+0] = '%', [+1] = 'b', [+2] = 'e', [+3] = '\0' } + */ + + /* Need %XX */ + if (c+2 >= end) { + *errp = JSONSL_ERROR_PERCENT_BADHEX; + return JSONSL_PATH_INVALID; + } + if (! (isxdigit(*(c+1)) && isxdigit(*(c+2))) ) { + *errp = JSONSL_ERROR_PERCENT_BADHEX; + return JSONSL_PATH_INVALID; + } + + /* Temporarily null-terminate the characters */ + origc = *(c+3); + *(c+3) = '\0'; + pctval = strtoul(c+1, NULL, 16); + *(c+3) = origc; + + *outp = (char) pctval; + c += 2; + continue; + + GT_ASSIGN: + *outp = *c; + } + /* Null-terminate the string */ + for (; outp < c; outp++) { + *outp = '\0'; + } + + GT_RET: + component->ptype = ret; + if (ret != JSONSL_PATH_WILDCARD) { + component->len = strlen(component->pstr); + } + return ret; +} + +JSONSL_API +jsonsl_jpr_t +jsonsl_jpr_new(const char *path, jsonsl_error_t *errp) +{ + char *my_copy = NULL; + int count, curidx; + struct jsonsl_jpr_st *ret = NULL; + struct jsonsl_jpr_component_st *components = NULL; + size_t origlen; + jsonsl_error_t errstacked; + +#define JPR_BAIL(err) *errp = err; goto GT_ERROR; + + if (errp == NULL) { + errp = &errstacked; + } + + if (path == NULL || *path != '/') { + JPR_BAIL(JSONSL_ERROR_JPR_NOROOT); + } + + count = 1; + path++; + { + const char *c = path; + for (; *c; c++) { + if (*c == '/') { + count++; + if (*(c+1) == '/') { + JPR_BAIL(JSONSL_ERROR_JPR_DUPSLASH); + } + } + } + } + if(*path) { + count++; + } + + components = (struct jsonsl_jpr_component_st *) + malloc(sizeof(*components) * count); + if (!components) { + JPR_BAIL(JSONSL_ERROR_ENOMEM); + } + + my_copy = (char *)malloc(strlen(path) + 1); + if (!my_copy) { + JPR_BAIL(JSONSL_ERROR_ENOMEM); + } + + strcpy(my_copy, path); + + components[0].ptype = JSONSL_PATH_ROOT; + + if (*my_copy) { + char *cur = my_copy; + int pathret = JSONSL_PATH_STRING; + curidx = 1; + while (pathret > 0 && curidx < count) { + pathret = populate_component(cur, components + curidx, &cur, errp); + if (pathret > 0) { + curidx++; + } else { + break; + } + } + + if (pathret == JSONSL_PATH_INVALID) { + JPR_BAIL(JSONSL_ERROR_JPR_BADPATH); + } + } else { + curidx = 1; + } + + path--; /*revert path to leading '/' */ + origlen = strlen(path) + 1; + ret = (struct jsonsl_jpr_st *)malloc(sizeof(*ret)); + if (!ret) { + JPR_BAIL(JSONSL_ERROR_ENOMEM); + } + ret->orig = (char *)malloc(origlen); + if (!ret->orig) { + JPR_BAIL(JSONSL_ERROR_ENOMEM); + } + ret->components = components; + ret->ncomponents = curidx; + ret->basestr = my_copy; + ret->norig = origlen-1; + strcpy(ret->orig, path); + + return ret; + + GT_ERROR: + free(my_copy); + free(components); + if (ret) { + free(ret->orig); + } + free(ret); + return NULL; +#undef JPR_BAIL +} + +void jsonsl_jpr_destroy(jsonsl_jpr_t jpr) +{ + free(jpr->components); + free(jpr->basestr); + free(jpr->orig); + free(jpr); +} + +/** + * Call when there is a possibility of a match, either as a final match or + * as a path within a match + * @param jpr The JPR path + * @param component Component corresponding to the current element + * @param prlevel The level of the *parent* + * @param chtype The type of the child + * @return Match status + */ +static jsonsl_jpr_match_t +jsonsl__match_continue(jsonsl_jpr_t jpr, + const struct jsonsl_jpr_component_st *component, + unsigned prlevel, unsigned chtype) +{ + const struct jsonsl_jpr_component_st *next_comp = component + 1; + if (prlevel == jpr->ncomponents - 1) { + /* This is the match. Check the expected type of the match against + * the child */ + if (jpr->match_type == 0 || jpr->match_type == chtype) { + return JSONSL_MATCH_COMPLETE; + } else { + return JSONSL_MATCH_TYPE_MISMATCH; + } + } + if (chtype == JSONSL_T_LIST) { + if (next_comp->ptype == JSONSL_PATH_NUMERIC) { + return JSONSL_MATCH_POSSIBLE; + } else { + return JSONSL_MATCH_TYPE_MISMATCH; + } + } else if (chtype == JSONSL_T_OBJECT) { + if (next_comp->ptype == JSONSL_PATH_NUMERIC) { + return JSONSL_MATCH_TYPE_MISMATCH; + } else { + return JSONSL_MATCH_POSSIBLE; + } + } else { + return JSONSL_MATCH_TYPE_MISMATCH; + } +} + +JSONSL_API +jsonsl_jpr_match_t +jsonsl_path_match(jsonsl_jpr_t jpr, + const struct jsonsl_state_st *parent, + const struct jsonsl_state_st *child, + const char *key, size_t nkey) +{ + const struct jsonsl_jpr_component_st *comp; + if (!parent) { + /* No parent. Return immediately since it's always a match */ + return jsonsl__match_continue(jpr, jpr->components, 0, child->type); + } + + comp = jpr->components + parent->level; + + /* note that we don't need to verify the type of the match, this is + * always done through the previous call to jsonsl__match_continue. + * If we are in a POSSIBLE tree then we can be certain the types (at + * least at this level) are correct */ + if (parent->type == JSONSL_T_OBJECT) { + if (comp->len != nkey || strncmp(key, comp->pstr, nkey) != 0) { + return JSONSL_MATCH_NOMATCH; + } + } else { + if (comp->idx != parent->nelem - 1) { + return JSONSL_MATCH_NOMATCH; + } + } + return jsonsl__match_continue(jpr, comp, parent->level, child->type); +} + +JSONSL_API +jsonsl_jpr_match_t +jsonsl_jpr_match(jsonsl_jpr_t jpr, + unsigned int parent_type, + unsigned int parent_level, + const char *key, + size_t nkey) +{ + /* find our current component. This is the child level */ + int cmpret; + struct jsonsl_jpr_component_st *p_component; + p_component = jpr->components + parent_level; + + if (parent_level >= jpr->ncomponents) { + return JSONSL_MATCH_NOMATCH; + } + + /* Lone query for 'root' element. Always matches */ + if (parent_level == 0) { + if (jpr->ncomponents == 1) { + return JSONSL_MATCH_COMPLETE; + } else { + return JSONSL_MATCH_POSSIBLE; + } + } + + /* Wildcard, always matches */ + if (p_component->ptype == JSONSL_PATH_WILDCARD) { + if (parent_level == jpr->ncomponents-1) { + return JSONSL_MATCH_COMPLETE; + } else { + return JSONSL_MATCH_POSSIBLE; + } + } + + /* Check numeric array index. This gets its special block so we can avoid + * string comparisons */ + if (p_component->ptype == JSONSL_PATH_NUMERIC) { + if (parent_type == JSONSL_T_LIST) { + if (p_component->idx != nkey) { + /* Wrong index */ + return JSONSL_MATCH_NOMATCH; + } else { + if (parent_level == jpr->ncomponents-1) { + /* This is the last element of the path */ + return JSONSL_MATCH_COMPLETE; + } else { + /* Intermediate element */ + return JSONSL_MATCH_POSSIBLE; + } + } + } else if (p_component->is_arridx) { + /* Numeric and an array index (set explicitly by user). But not + * a list for a parent */ + return JSONSL_MATCH_TYPE_MISMATCH; + } + } else if (parent_type == JSONSL_T_LIST) { + return JSONSL_MATCH_TYPE_MISMATCH; + } + + /* Check lengths */ + if (p_component->len != nkey) { + return JSONSL_MATCH_NOMATCH; + } + + /* Check string comparison */ + cmpret = strncmp(p_component->pstr, key, nkey); + if (cmpret == 0) { + if (parent_level == jpr->ncomponents-1) { + return JSONSL_MATCH_COMPLETE; + } else { + return JSONSL_MATCH_POSSIBLE; + } + } + + return JSONSL_MATCH_NOMATCH; +} + +JSONSL_API +void jsonsl_jpr_match_state_init(jsonsl_t jsn, + jsonsl_jpr_t *jprs, + size_t njprs) +{ + size_t ii, *firstjmp; + if (njprs == 0) { + return; + } + jsn->jprs = (jsonsl_jpr_t *)malloc(sizeof(jsonsl_jpr_t) * njprs); + jsn->jpr_count = njprs; + jsn->jpr_root = (size_t*)calloc(1, sizeof(size_t) * njprs * jsn->levels_max); + memcpy(jsn->jprs, jprs, sizeof(jsonsl_jpr_t) * njprs); + /* Set the initial jump table values */ + + firstjmp = jsn->jpr_root; + for (ii = 0; ii < njprs; ii++) { + firstjmp[ii] = ii+1; + } +} + +JSONSL_API +void jsonsl_jpr_match_state_cleanup(jsonsl_t jsn) +{ + if (jsn->jpr_count == 0) { + return; + } + + free(jsn->jpr_root); + free(jsn->jprs); + jsn->jprs = NULL; + jsn->jpr_root = NULL; + jsn->jpr_count = 0; +} + +/** + * This function should be called exactly once on each element... + * This should also be called in recursive order, since we rely + * on the parent having been initalized for a match. + * + * Since the parent is checked for a match as well, we maintain a 'serial' counter. + * Whenever we traverse an element, we expect the serial to be the same as a global + * integer. If they do not match, we re-initialize the context, and set the serial. + * + * This ensures a type of consistency without having a proactive reset by the + * main lexer itself. + * + */ +JSONSL_API +jsonsl_jpr_t jsonsl_jpr_match_state(jsonsl_t jsn, + struct jsonsl_state_st *state, + const char *key, + size_t nkey, + jsonsl_jpr_match_t *out) +{ + struct jsonsl_state_st *parent_state; + jsonsl_jpr_t ret = NULL; + + /* Jump and JPR tables for our own state and the parent state */ + size_t *jmptable, *pjmptable; + size_t jmp_cur, ii, ourjmpidx; + + if (!jsn->jpr_root) { + *out = JSONSL_MATCH_NOMATCH; + return NULL; + } + + pjmptable = jsn->jpr_root + (jsn->jpr_count * (state->level-1)); + jmptable = pjmptable + jsn->jpr_count; + + /* If the parent cannot match, then invalidate it */ + if (*pjmptable == 0) { + *jmptable = 0; + *out = JSONSL_MATCH_NOMATCH; + return NULL; + } + + parent_state = jsn->stack + state->level - 1; + + if (parent_state->type == JSONSL_T_LIST) { + nkey = (size_t) parent_state->nelem; + } + + *jmptable = 0; + ourjmpidx = 0; + memset(jmptable, 0, sizeof(int) * jsn->jpr_count); + + for (ii = 0; ii < jsn->jpr_count; ii++) { + jmp_cur = pjmptable[ii]; + if (jmp_cur) { + jsonsl_jpr_t jpr = jsn->jprs[jmp_cur-1]; + *out = jsonsl_jpr_match(jpr, + parent_state->type, + parent_state->level, + key, nkey); + if (*out == JSONSL_MATCH_COMPLETE) { + ret = jpr; + *jmptable = 0; + return ret; + } else if (*out == JSONSL_MATCH_POSSIBLE) { + jmptable[ourjmpidx] = ii+1; + ourjmpidx++; + } + } else { + break; + } + } + if (!*jmptable) { + *out = JSONSL_MATCH_NOMATCH; + } + return NULL; +} + +JSONSL_API +const char *jsonsl_strmatchtype(jsonsl_jpr_match_t match) +{ +#define X(T,v) \ + if ( match == JSONSL_MATCH_##T ) \ + return #T; + JSONSL_XMATCH +#undef X + return "<UNKNOWN>"; +} + +#endif /* JSONSL_WITH_JPR */ + +static char * +jsonsl__writeutf8(uint32_t pt, char *out) +{ + #define ADD_OUTPUT(c) *out = (char)(c); out++; + + if (pt < 0x80) { + ADD_OUTPUT(pt); + } else if (pt < 0x800) { + ADD_OUTPUT((pt >> 6) | 0xC0); + ADD_OUTPUT((pt & 0x3F) | 0x80); + } else if (pt < 0x10000) { + ADD_OUTPUT((pt >> 12) | 0xE0); + ADD_OUTPUT(((pt >> 6) & 0x3F) | 0x80); + ADD_OUTPUT((pt & 0x3F) | 0x80); + } else { + ADD_OUTPUT((pt >> 18) | 0xF0); + ADD_OUTPUT(((pt >> 12) & 0x3F) | 0x80); + ADD_OUTPUT(((pt >> 6) & 0x3F) | 0x80); + ADD_OUTPUT((pt & 0x3F) | 0x80); + } + return out; + #undef ADD_OUTPUT +} + +/* Thanks snej (https://github.com/mnunberg/jsonsl/issues/9) */ +static int +jsonsl__digit2int(char ch) { + int d = ch - '0'; + if ((unsigned) d < 10) { + return d; + } + d = ch - 'a'; + if ((unsigned) d < 6) { + return d + 10; + } + d = ch - 'A'; + if ((unsigned) d < 6) { + return d + 10; + } + return -1; +} + +/* Assume 's' is at least 4 bytes long */ +static int +jsonsl__get_uescape_16(const char *s) +{ + int ret = 0; + int cur; + + #define GET_DIGIT(off) \ + cur = jsonsl__digit2int(s[off]); \ + if (cur == -1) { return -1; } \ + ret |= (cur << (12 - (off * 4))); + + GET_DIGIT(0); + GET_DIGIT(1); + GET_DIGIT(2); + GET_DIGIT(3); + #undef GET_DIGIT + return ret; +} + +/** + * Utility function to convert escape sequences + */ +JSONSL_API +size_t jsonsl_util_unescape_ex(const char *in, + char *out, + size_t len, + const int toEscape[128], + unsigned *oflags, + jsonsl_error_t *err, + const char **errat) +{ + const unsigned char *c = (const unsigned char*)in; + char *begin_p = out; + unsigned oflags_s; + uint16_t last_codepoint = 0; + + if (!oflags) { + oflags = &oflags_s; + } + *oflags = 0; + + #define UNESCAPE_BAIL(e,offset) \ + *err = JSONSL_ERROR_##e; \ + if (errat) { \ + *errat = (const char*)(c+ (ptrdiff_t)(offset)); \ + } \ + return 0; + + for (; len; len--, c++, out++) { + int uescval; + if (*c != '\\') { + /* Not an escape, so we don't care about this */ + goto GT_ASSIGN; + } + + if (len < 2) { + UNESCAPE_BAIL(ESCAPE_INVALID, 0); + } + if (!is_allowed_escape(c[1])) { + UNESCAPE_BAIL(ESCAPE_INVALID, 1) + } + if ((toEscape && toEscape[(unsigned char)c[1] & 0x7f] == 0 && + c[1] != '\\' && c[1] != '"')) { + /* if we don't want to unescape this string, write the escape sequence to the output */ + *out++ = *c++; + if (--len == 0) + break; + goto GT_ASSIGN; + } + + if (c[1] != 'u') { + /* simple skip-and-replace using pre-defined maps. + * TODO: should the maps actually reflect the desired + * replacement character in toEscape? + */ + char esctmp = get_escape_equiv(c[1]); + if (esctmp) { + /* Check if there is a corresponding replacement */ + *out = esctmp; + } else { + /* Just gobble up the 'reverse-solidus' */ + *out = c[1]; + } + len--; + c++; + /* do not assign, just continue */ + continue; + } + + /* next == 'u' */ + if (len < 6) { + /* Need at least six characters.. */ + UNESCAPE_BAIL(UESCAPE_TOOSHORT, 2); + } + + uescval = jsonsl__get_uescape_16((const char *)c + 2); + if (uescval == -1) { + UNESCAPE_BAIL(PERCENT_BADHEX, -1); + } + + if (last_codepoint) { + uint16_t w1 = last_codepoint, w2 = (uint16_t)uescval; + uint32_t cp; + + if (uescval < 0xDC00 || uescval > 0xDFFF) { + UNESCAPE_BAIL(INVALID_CODEPOINT, -1); + } + + cp = (w1 & 0x3FF) << 10; + cp |= (w2 & 0x3FF); + cp += 0x10000; + + out = jsonsl__writeutf8(cp, out) - 1; + last_codepoint = 0; + + } else if (uescval < 0xD800 || uescval > 0xDFFF) { + *oflags |= JSONSL_SPECIALf_NONASCII; + out = jsonsl__writeutf8(uescval, out) - 1; + + } else if (uescval > 0xD7FF && uescval < 0xDC00) { + *oflags |= JSONSL_SPECIALf_NONASCII; + last_codepoint = (uint16_t)uescval; + out--; + } else { + UNESCAPE_BAIL(INVALID_CODEPOINT, 2); + } + + /* Post uescape cleanup */ + len -= 5; /* Gobble up 5 chars after 'u' */ + c += 5; + continue; + + /* Only reached by previous branches */ + GT_ASSIGN: + *out = *c; + } + + if (last_codepoint) { + *err = JSONSL_ERROR_INVALID_CODEPOINT; + return 0; + } + + *err = JSONSL_ERROR_SUCCESS; + return out - begin_p; +} + +/** + * Character Table definitions. + * These were all generated via srcutil/genchartables.pl + */ + +/** + * This table contains the beginnings of non-string + * allowable (bareword) values. + */ +static unsigned short Special_Table[0x100] = { + /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */ + /* 0x20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x2c */ + /* 0x2d */ JSONSL_SPECIALf_DASH /* <-> */, /* 0x2d */ + /* 0x2e */ 0,0, /* 0x2f */ + /* 0x30 */ JSONSL_SPECIALf_ZERO /* <0> */, /* 0x30 */ + /* 0x31 */ JSONSL_SPECIALf_UNSIGNED /* <1> */, /* 0x31 */ + /* 0x32 */ JSONSL_SPECIALf_UNSIGNED /* <2> */, /* 0x32 */ + /* 0x33 */ JSONSL_SPECIALf_UNSIGNED /* <3> */, /* 0x33 */ + /* 0x34 */ JSONSL_SPECIALf_UNSIGNED /* <4> */, /* 0x34 */ + /* 0x35 */ JSONSL_SPECIALf_UNSIGNED /* <5> */, /* 0x35 */ + /* 0x36 */ JSONSL_SPECIALf_UNSIGNED /* <6> */, /* 0x36 */ + /* 0x37 */ JSONSL_SPECIALf_UNSIGNED /* <7> */, /* 0x37 */ + /* 0x38 */ JSONSL_SPECIALf_UNSIGNED /* <8> */, /* 0x38 */ + /* 0x39 */ JSONSL_SPECIALf_UNSIGNED /* <9> */, /* 0x39 */ + /* 0x3a */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x48 */ + /* 0x49 */ JSONSL__INF_PROXY /* <I> */, /* 0x49 */ + /* 0x4a */ 0,0,0,0, /* 0x4d */ + /* 0x4e */ JSONSL__NAN_PROXY /* <N> */, /* 0x4e */ + /* 0x4f */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x65 */ + /* 0x66 */ JSONSL_SPECIALf_FALSE /* <f> */, /* 0x66 */ + /* 0x67 */ 0,0, /* 0x68 */ + /* 0x69 */ JSONSL__INF_PROXY /* <i> */, /* 0x69 */ + /* 0x6a */ 0,0,0,0, /* 0x6d */ + /* 0x6e */ JSONSL_SPECIALf_NULL|JSONSL__NAN_PROXY /* <n> */, /* 0x6e */ + /* 0x6f */ 0,0,0,0,0, /* 0x73 */ + /* 0x74 */ JSONSL_SPECIALf_TRUE /* <t> */, /* 0x74 */ + /* 0x75 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x94 */ + /* 0x95 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb4 */ + /* 0xb5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xd4 */ + /* 0xd5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xf4 */ + /* 0xf5 */ 0,0,0,0,0,0,0,0,0,0, /* 0xfe */ +}; + +/** + * Contains characters which signal the termination of any of the 'special' bareword + * values. + */ +static int Special_Endings[0x100] = { + /* 0x00 */ 0,0,0,0,0,0,0,0,0, /* 0x08 */ + /* 0x09 */ 1 /* <TAB> */, /* 0x09 */ + /* 0x0a */ 1 /* <LF> */, /* 0x0a */ + /* 0x0b */ 0,0, /* 0x0c */ + /* 0x0d */ 1 /* <CR> */, /* 0x0d */ + /* 0x0e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */ + /* 0x20 */ 1 /* <SP> */, /* 0x20 */ + /* 0x21 */ 0, /* 0x21 */ + /* 0x22 */ 1 /* " */, /* 0x22 */ + /* 0x23 */ 0,0,0,0,0,0,0,0,0, /* 0x2b */ + /* 0x2c */ 1 /* , */, /* 0x2c */ + /* 0x2d */ 0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x39 */ + /* 0x3a */ 1 /* : */, /* 0x3a */ + /* 0x3b */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5a */ + /* 0x5b */ 1 /* [ */, /* 0x5b */ + /* 0x5c */ 1 /* \ */, /* 0x5c */ + /* 0x5d */ 1 /* ] */, /* 0x5d */ + /* 0x5e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x7a */ + /* 0x7b */ 1 /* { */, /* 0x7b */ + /* 0x7c */ 0, /* 0x7c */ + /* 0x7d */ 1 /* } */, /* 0x7d */ + /* 0x7e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x9d */ + /* 0x9e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xbd */ + /* 0xbe */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xdd */ + /* 0xde */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xfd */ + /* 0xfe */ 0 /* 0xfe */ +}; + +/** + * This table contains entries for the allowed whitespace as per RFC 4627 + */ +static int Allowed_Whitespace[0x100] = { + /* 0x00 */ 0,0,0,0,0,0,0,0,0, /* 0x08 */ + /* 0x09 */ 1 /* <TAB> */, /* 0x09 */ + /* 0x0a */ 1 /* <LF> */, /* 0x0a */ + /* 0x0b */ 0,0, /* 0x0c */ + /* 0x0d */ 1 /* <CR> */, /* 0x0d */ + /* 0x0e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */ + /* 0x20 */ 1 /* <SP> */, /* 0x20 */ + /* 0x21 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x40 */ + /* 0x41 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x60 */ + /* 0x61 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80 */ + /* 0x81 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xa0 */ + /* 0xa1 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xc0 */ + /* 0xc1 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xe0 */ + /* 0xe1 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* 0xfe */ +}; + +static const int String_No_Passthrough[0x100] = { + /* 0x00 */ 1 /* <NUL> */, /* 0x00 */ + /* 0x01 */ 1 /* <SOH> */, /* 0x01 */ + /* 0x02 */ 1 /* <STX> */, /* 0x02 */ + /* 0x03 */ 1 /* <ETX> */, /* 0x03 */ + /* 0x04 */ 1 /* <EOT> */, /* 0x04 */ + /* 0x05 */ 1 /* <ENQ> */, /* 0x05 */ + /* 0x06 */ 1 /* <ACK> */, /* 0x06 */ + /* 0x07 */ 1 /* <BEL> */, /* 0x07 */ + /* 0x08 */ 1 /* <BS> */, /* 0x08 */ + /* 0x09 */ 1 /* <HT> */, /* 0x09 */ + /* 0x0a */ 1 /* <LF> */, /* 0x0a */ + /* 0x0b */ 1 /* <VT> */, /* 0x0b */ + /* 0x0c */ 1 /* <FF> */, /* 0x0c */ + /* 0x0d */ 1 /* <CR> */, /* 0x0d */ + /* 0x0e */ 1 /* <SO> */, /* 0x0e */ + /* 0x0f */ 1 /* <SI> */, /* 0x0f */ + /* 0x10 */ 1 /* <DLE> */, /* 0x10 */ + /* 0x11 */ 1 /* <DC1> */, /* 0x11 */ + /* 0x12 */ 1 /* <DC2> */, /* 0x12 */ + /* 0x13 */ 1 /* <DC3> */, /* 0x13 */ + /* 0x14 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x21 */ + /* 0x22 */ 1 /* <"> */, /* 0x22 */ + /* 0x23 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x42 */ + /* 0x43 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5b */ + /* 0x5c */ 1 /* <\> */, /* 0x5c */ + /* 0x5d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x7c */ + /* 0x7d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x9c */ + /* 0x9d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xbc */ + /* 0xbd */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xdc */ + /* 0xdd */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xfc */ + /* 0xfd */ 0,0, /* 0xfe */ +}; + +/** + * Allowable two-character 'common' escapes: + */ +static int Allowed_Escapes[0x100] = { + /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */ + /* 0x20 */ 0,0, /* 0x21 */ + /* 0x22 */ 1 /* <"> */, /* 0x22 */ + /* 0x23 */ 0,0,0,0,0,0,0,0,0,0,0,0, /* 0x2e */ + /* 0x2f */ 1 /* </> */, /* 0x2f */ + /* 0x30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x4f */ + /* 0x50 */ 0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5b */ + /* 0x5c */ 1 /* <\> */, /* 0x5c */ + /* 0x5d */ 0,0,0,0,0, /* 0x61 */ + /* 0x62 */ 1 /* <b> */, /* 0x62 */ + /* 0x63 */ 0,0,0, /* 0x65 */ + /* 0x66 */ 1 /* <f> */, /* 0x66 */ + /* 0x67 */ 0,0,0,0,0,0,0, /* 0x6d */ + /* 0x6e */ 1 /* <n> */, /* 0x6e */ + /* 0x6f */ 0,0,0, /* 0x71 */ + /* 0x72 */ 1 /* <r> */, /* 0x72 */ + /* 0x73 */ 0, /* 0x73 */ + /* 0x74 */ 1 /* <t> */, /* 0x74 */ + /* 0x75 */ 1 /* <u> */, /* 0x75 */ + /* 0x76 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x95 */ + /* 0x96 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb5 */ + /* 0xb6 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xd5 */ + /* 0xd6 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xf5 */ + /* 0xf6 */ 0,0,0,0,0,0,0,0,0, /* 0xfe */ +}; + +/** + * This table contains the _values_ for a given (single) escaped character. + */ +static unsigned char Escape_Equivs[0x100] = { + /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */ + /* 0x20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x3f */ + /* 0x40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5f */ + /* 0x60 */ 0,0, /* 0x61 */ + /* 0x62 */ 8 /* <b> */, /* 0x62 */ + /* 0x63 */ 0,0,0, /* 0x65 */ + /* 0x66 */ 12 /* <f> */, /* 0x66 */ + /* 0x67 */ 0,0,0,0,0,0,0, /* 0x6d */ + /* 0x6e */ 10 /* <n> */, /* 0x6e */ + /* 0x6f */ 0,0,0, /* 0x71 */ + /* 0x72 */ 13 /* <r> */, /* 0x72 */ + /* 0x73 */ 0, /* 0x73 */ + /* 0x74 */ 9 /* <t> */, /* 0x74 */ + /* 0x75 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x94 */ + /* 0x95 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb4 */ + /* 0xb5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xd4 */ + /* 0xd5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xf4 */ + /* 0xf5 */ 0,0,0,0,0,0,0,0,0,0 /* 0xfe */ +}; + +/* Definitions of above-declared static functions */ +static char get_escape_equiv(unsigned c) { + return Escape_Equivs[c & 0xff]; +} +static unsigned extract_special(unsigned c) { + return Special_Table[c & 0xff]; +} +static int is_special_end(unsigned c) { + return Special_Endings[c & 0xff]; +} +static int is_allowed_whitespace(unsigned c) { + return c == ' ' || Allowed_Whitespace[c & 0xff]; +} +static int is_allowed_escape(unsigned c) { + return Allowed_Escapes[c & 0xff]; +} +static int is_simple_char(unsigned c) { + return !String_No_Passthrough[c & 0xff]; +} + +/* Clean up all our macros! */ +#undef INCR_METRIC +#undef INCR_GENERIC +#undef INCR_STRINGY_CATCH +#undef CASE_DIGITS +#undef INVOKE_ERROR +#undef STACK_PUSH +#undef STACK_POP_NOPOS +#undef STACK_POP +#undef CALLBACK_AND_POP_NOPOS +#undef CALLBACK_AND_POP +#undef SPECIAL_POP +#undef CUR_CHAR +#undef DO_CALLBACK +#undef ENSURE_HVAL +#undef VERIFY_SPECIAL +#undef STATE_SPECIAL_LENGTH +#undef IS_NORMAL_NUMBER +#undef STATE_NUM_LAST +#undef FASTPARSE_EXHAUSTED +#undef FASTPARSE_BREAK diff --git a/chaos_micro_unit_toolkit/external_lib/bson/jsonsl/jsonsl.h b/chaos_micro_unit_toolkit/external_lib/bson/jsonsl/jsonsl.h new file mode 100644 index 0000000000000000000000000000000000000000..ee1d39cbc4d96afca18ef58c1d6275e9d6f82f3d --- /dev/null +++ b/chaos_micro_unit_toolkit/external_lib/bson/jsonsl/jsonsl.h @@ -0,0 +1,1004 @@ +/** + * JSON Simple/Stacked/Stateful Lexer. + * - Does not buffer data + * - Maintains state + * - Callback oriented + * - Lightweight and fast. One source file and one header file + * + * Copyright (C) 2012-2015 Mark Nunberg + * See included LICENSE file for license details. + */ + +#ifndef JSONSL_H_ +#define JSONSL_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <sys/types.h> +#include <wchar.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef JSONSL_USE_WCHAR +typedef jsonsl_char_t wchar_t; +typedef jsonsl_uchar_t unsigned wchar_t; +#else +typedef char jsonsl_char_t; +typedef unsigned char jsonsl_uchar_t; +#endif /* JSONSL_USE_WCHAR */ + +#ifdef JSONSL_PARSE_NAN +#define JSONSL__NAN_PROXY JSONSL_SPECIALf_NAN +#define JSONSL__INF_PROXY JSONSL_SPECIALf_INF +#else +#define JSONSL__NAN_PROXY 0 +#define JSONSL__INF_PROXY 0 +#endif + +/* Stolen from http-parser.h, and possibly others */ +#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) +typedef __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#if !defined(_MSC_VER) || _MSC_VER<1400 +typedef unsigned int size_t; +typedef int ssize_t; +#endif +#else +#include <stdint.h> +#endif + + +#if (!defined(JSONSL_STATE_GENERIC)) && (!defined(JSONSL_STATE_USER_FIELDS)) +#define JSONSL_STATE_GENERIC +#endif /* !defined JSONSL_STATE_GENERIC */ + +#ifdef JSONSL_STATE_GENERIC +#define JSONSL_STATE_USER_FIELDS +#endif /* JSONSL_STATE_GENERIC */ + +/* Additional fields for component object */ +#ifndef JSONSL_JPR_COMPONENT_USER_FIELDS +#define JSONSL_JPR_COMPONENT_USER_FIELDS +#endif + +#ifndef JSONSL_API +/** + * We require a /DJSONSL_DLL so that users already using this as a static + * or embedded library don't get confused + */ +#if defined(_WIN32) && defined(JSONSL_DLL) +#define JSONSL_API __declspec(dllexport) +#else +#define JSONSL_API +#endif /* _WIN32 */ + +#endif /* !JSONSL_API */ + +#ifndef JSONSL_INLINE +#if defined(_MSC_VER) + #define JSONSL_INLINE __inline + #elif defined(__GNUC__) + #define JSONSL_INLINE __inline__ + #else + #define JSONSL_INLINE inline + #endif /* _MSC_VER or __GNUC__ */ +#endif /* JSONSL_INLINE */ + +#define JSONSL_MAX_LEVELS 512 + +struct jsonsl_st; +typedef struct jsonsl_st *jsonsl_t; + +typedef struct jsonsl_jpr_st* jsonsl_jpr_t; + +/** + * This flag is true when AND'd against a type whose value + * must be in "quoutes" i.e. T_HKEY and T_STRING + */ +#define JSONSL_Tf_STRINGY 0xffff00 + +/** + * Constant representing the special JSON types. + * The values are special and aid in speed (the OBJECT and LIST + * values are the char literals of their openings). + * + * Their actual value is a character which attempts to resemble + * some mnemonic reference to the actual type. + * + * If new types are added, they must fit into the ASCII printable + * range (so they should be AND'd with 0x7f and yield something + * meaningful) + */ +#define JSONSL_XTYPE \ + X(STRING, '"'|JSONSL_Tf_STRINGY) \ + X(HKEY, '#'|JSONSL_Tf_STRINGY) \ + X(OBJECT, '{') \ + X(LIST, '[') \ + X(SPECIAL, '^') \ + X(UESCAPE, 'u') +typedef enum { +#define X(o, c) \ + JSONSL_T_##o = c, + JSONSL_XTYPE + JSONSL_T_UNKNOWN = '?', + /* Abstract 'root' object */ + JSONSL_T_ROOT = 0 +#undef X +} jsonsl_type_t; + +/** + * Subtypes for T_SPECIAL. We define them as flags + * because more than one type can be applied to a + * given object. + */ + +#define JSONSL_XSPECIAL \ + X(NONE, 0) \ + X(SIGNED, 1<<0) \ + X(UNSIGNED, 1<<1) \ + X(TRUE, 1<<2) \ + X(FALSE, 1<<3) \ + X(NULL, 1<<4) \ + X(FLOAT, 1<<5) \ + X(EXPONENT, 1<<6) \ + X(NONASCII, 1<<7) \ + X(NAN, 1<<8) \ + X(INF, 1<<9) +typedef enum { +#define X(o,b) \ + JSONSL_SPECIALf_##o = b, + JSONSL_XSPECIAL +#undef X + /* Handy flags for checking */ + + JSONSL_SPECIALf_UNKNOWN = 1 << 8, + + /** @private Private */ + JSONSL_SPECIALf_ZERO = 1 << 9 | JSONSL_SPECIALf_UNSIGNED, + /** @private */ + JSONSL_SPECIALf_DASH = 1 << 10, + /** @private */ + JSONSL_SPECIALf_POS_INF = (JSONSL_SPECIALf_INF), + JSONSL_SPECIALf_NEG_INF = (JSONSL_SPECIALf_INF|JSONSL_SPECIALf_SIGNED), + + /** Type is numeric */ + JSONSL_SPECIALf_NUMERIC = (JSONSL_SPECIALf_SIGNED| JSONSL_SPECIALf_UNSIGNED), + + /** Type is a boolean */ + JSONSL_SPECIALf_BOOLEAN = (JSONSL_SPECIALf_TRUE|JSONSL_SPECIALf_FALSE), + + /** Type is an "extended", not integral type (but numeric) */ + JSONSL_SPECIALf_NUMNOINT = + (JSONSL_SPECIALf_FLOAT|JSONSL_SPECIALf_EXPONENT|JSONSL_SPECIALf_NAN + |JSONSL_SPECIALf_INF) +} jsonsl_special_t; + + +/** + * These are the various types of stack (or other) events + * which will trigger a callback. + * Like the type constants, this are also mnemonic + */ +#define JSONSL_XACTION \ + X(PUSH, '+') \ + X(POP, '-') \ + X(UESCAPE, 'U') \ + X(ERROR, '!') +typedef enum { +#define X(a,c) \ + JSONSL_ACTION_##a = c, + JSONSL_XACTION + JSONSL_ACTION_UNKNOWN = '?' +#undef X +} jsonsl_action_t; + + +/** + * Various errors which may be thrown while parsing JSON + */ +#define JSONSL_XERR \ +/* Trailing garbage characters */ \ + X(GARBAGE_TRAILING) \ +/* We were expecting a 'special' (numeric, true, false, null) */ \ + X(SPECIAL_EXPECTED) \ +/* The 'special' value was incomplete */ \ + X(SPECIAL_INCOMPLETE) \ +/* Found a stray token */ \ + X(STRAY_TOKEN) \ +/* We were expecting a token before this one */ \ + X(MISSING_TOKEN) \ +/* Cannot insert because the container is not ready */ \ + X(CANT_INSERT) \ +/* Found a '\' outside a string */ \ + X(ESCAPE_OUTSIDE_STRING) \ +/* Found a ':' outside of a hash */ \ + X(KEY_OUTSIDE_OBJECT) \ +/* found a string outside of a container */ \ + X(STRING_OUTSIDE_CONTAINER) \ +/* Found a null byte in middle of string */ \ + X(FOUND_NULL_BYTE) \ +/* Current level exceeds limit specified in constructor */ \ + X(LEVELS_EXCEEDED) \ +/* Got a } as a result of an opening [ or vice versa */ \ + X(BRACKET_MISMATCH) \ +/* We expected a key, but got something else instead */ \ + X(HKEY_EXPECTED) \ +/* We got an illegal control character (bad whitespace or something) */ \ + X(WEIRD_WHITESPACE) \ +/* Found a \u-escape, but there were less than 4 following hex digits */ \ + X(UESCAPE_TOOSHORT) \ +/* Invalid two-character escape */ \ + X(ESCAPE_INVALID) \ +/* Trailing comma */ \ + X(TRAILING_COMMA) \ +/* An invalid number was passed in a numeric field */ \ + X(INVALID_NUMBER) \ +/* Value is missing for object */ \ + X(VALUE_EXPECTED) \ +/* The following are for JPR Stuff */ \ + \ +/* Found a literal '%' but it was only followed by a single valid hex digit */ \ + X(PERCENT_BADHEX) \ +/* jsonpointer URI is malformed '/' */ \ + X(JPR_BADPATH) \ +/* Duplicate slash */ \ + X(JPR_DUPSLASH) \ +/* No leading root */ \ + X(JPR_NOROOT) \ +/* Allocation failure */ \ + X(ENOMEM) \ +/* Invalid unicode codepoint detected (in case of escapes) */ \ + X(INVALID_CODEPOINT) + +typedef enum { + JSONSL_ERROR_SUCCESS = 0, +#define X(e) \ + JSONSL_ERROR_##e, + JSONSL_XERR +#undef X + JSONSL_ERROR_GENERIC +} jsonsl_error_t; + + +/** + * A state is a single level of the stack. + * Non-private data (i.e. the 'data' field, see the STATE_GENERIC section) + * will remain in tact until the item is popped. + * + * As a result, it means a parent state object may be accessed from a child + * object, (the parents fields will all be valid). This allows a user to create + * an ad-hoc hierarchy on top of the JSON one. + * + */ +struct jsonsl_state_st { + /** + * The JSON object type + */ + unsigned type; + + /** If this element is special, then its extended type is here */ + unsigned special_flags; + + /** + * The position (in terms of number of bytes since the first call to + * jsonsl_feed()) at which the state was first pushed. This includes + * opening tokens, if applicable. + * + * @note For strings (i.e. type & JSONSL_Tf_STRINGY is nonzero) this will + * be the position of the first quote. + * + * @see jsonsl_st::pos which contains the _current_ position and can be + * used during a POP callback to get the length of the element. + */ + size_t pos_begin; + + /**FIXME: This is redundant as the same information can be derived from + * jsonsl_st::pos at pop-time */ + size_t pos_cur; + + /** + * Level of recursion into nesting. This is mainly a convenience + * variable, as this can technically be deduced from the lexer's + * level parameter (though the logic is not that simple) + */ + unsigned int level; + + + /** + * how many elements in the object/list. + * For objects (hashes), an element is either + * a key or a value. Thus for one complete pair, + * nelem will be 2. + * + * For special types, this will hold the sum of the digits. + * This only holds true for values which are simple signed/unsigned + * numbers. Otherwise a special flag is set, and extra handling is not + * performed. + */ + uint64_t nelem; + + + + /*TODO: merge this and special_flags into a union */ + + + /** + * Useful for an opening nest, this will prevent a callback from being + * invoked on this item or any of its children + */ + int ignore_callback; + + /** + * Counter which is incremented each time an escape ('\') is encountered. + * This is used internally for non-string types and should only be + * inspected by the user if the state actually represents a string + * type. + */ + unsigned int nescapes; + + /** + * Put anything you want here. if JSONSL_STATE_USER_FIELDS is here, then + * the macro expansion happens here. + * + * You can use these fields to store hierarchical or 'tagging' information + * for specific objects. + * + * See the documentation above for the lifetime of the state object (i.e. + * if the private data points to allocated memory, it should be freed + * when the object is popped, as the state object will be re-used) + */ +#ifndef JSONSL_STATE_GENERIC + JSONSL_STATE_USER_FIELDS +#else + + /** + * Otherwise, this is a simple void * pointer for anything you want + */ + void *data; +#endif /* JSONSL_STATE_USER_FIELDS */ +}; + +/**Gets the number of elements in the list. + * @param st The state. Must be of type JSONSL_T_LIST + * @return number of elements in the list + */ +#define JSONSL_LIST_SIZE(st) ((st)->nelem) + +/**Gets the number of key-value pairs in an object + * @param st The state. Must be of type JSONSL_T_OBJECT + * @return the number of key-value pairs in the object + */ +#define JSONSL_OBJECT_SIZE(st) ((st)->nelem / 2) + +/**Gets the numeric value. + * @param st The state. Must be of type JSONSL_T_SPECIAL and + * special_flags must have the JSONSL_SPECIALf_NUMERIC flag + * set. + * @return the numeric value of the state. + */ +#define JSONSL_NUMERIC_VALUE(st) ((st)->nelem) + +/* + * So now we need some special structure for keeping the + * JPR info in sync. Preferrably all in a single block + * of memory (there's no need for separate allocations. + * So we will define a 'table' with the following layout + * + * Level nPosbl JPR1_last JPR2_last JPR3_last + * + * 0 1 NOMATCH POSSIBLE POSSIBLE + * 1 0 NOMATCH NOMATCH COMPLETE + * [ table ends here because no further path is possible] + * + * Where the JPR..n corresponds to the number of JPRs + * requested, and nPosble is a quick flag to determine + * + * the number of possibilities. In the future this might + * be made into a proper 'jump' table, + * + * Since we always mark JPRs from the higher levels descending + * into the lower ones, a prospective child match would first + * look at the parent table to check the possibilities, and then + * see which ones were possible.. + * + * Thus, the size of this blob would be (and these are all ints here) + * nLevels * nJPR * 2. + * + * the 'Width' of the table would be nJPR*2, and the 'height' would be + * nlevels + */ + +/** + * This is called when a stack change ocurs. + * + * @param jsn The lexer + * @param action The type of action, this can be PUSH or POP + * @param state A pointer to the stack currently affected by the action + * @param at A pointer to the position of the input buffer which triggered + * this action. + */ +typedef void (*jsonsl_stack_callback)( + jsonsl_t jsn, + jsonsl_action_t action, + struct jsonsl_state_st* state, + const jsonsl_char_t *at); + + +/** + * This is called when an error is encountered. + * Sometimes it's possible to 'erase' characters (by replacing them + * with whitespace). If you think you have corrected the error, you + * can return a true value, in which case the parser will backtrack + * and try again. + * + * @param jsn The lexer + * @param error The error which was thrown + * @param state the current state + * @param a pointer to the position of the input buffer which triggered + * the error. Note that this is not const, this is because you have the + * possibility of modifying the character in an attempt to correct the + * error + * + * @return zero to bail, nonzero to try again (this only makes sense if + * the input buffer has been modified by this callback) + */ +typedef int (*jsonsl_error_callback)( + jsonsl_t jsn, + jsonsl_error_t error, + struct jsonsl_state_st* state, + jsonsl_char_t *at); + +struct jsonsl_st { + /** Public, read-only */ + + /** This is the current level of the stack */ + unsigned int level; + + /** Flag set to indicate we should stop processing */ + unsigned int stopfl; + + /** + * This is the current position, relative to the beginning + * of the stream. + */ + size_t pos; + + /** This is the 'bytes' variable passed to feed() */ + const jsonsl_char_t *base; + + /** Callback invoked for PUSH actions */ + jsonsl_stack_callback action_callback_PUSH; + + /** Callback invoked for POP actions */ + jsonsl_stack_callback action_callback_POP; + + /** Default callback for any action, if neither PUSH or POP callbacks are defined */ + jsonsl_stack_callback action_callback; + + /** + * Do not invoke callbacks for objects deeper than this level. + * NOTE: This field establishes the lower bound for ignored callbacks, + * and is thus misnamed. `min_ignore_level` would actually make more + * sense, but we don't want to break API. + */ + unsigned int max_callback_level; + + /** The error callback. Invoked when an error happens. Should not be NULL */ + jsonsl_error_callback error_callback; + + /* these are boolean flags you can modify. You will be called + * about notification for each of these types if the corresponding + * variable is true. + */ + + /** + * @name Callback Booleans. + * These determine whether a callback is to be invoked for certain types of objects + * @{*/ + + /** Boolean flag to enable or disable the invokcation for events on this type*/ + int call_SPECIAL; + int call_OBJECT; + int call_LIST; + int call_STRING; + int call_HKEY; + /*@}*/ + + /** + * @name u-Escape handling + * Special handling for the \\u-f00d type sequences. These are meant + * to be translated back into the corresponding octet(s). + * A special callback (if set) is invoked with *at=='u'. An application + * may wish to temporarily suspend parsing and handle the 'u-' sequence + * internally (or not). + */ + + /*@{*/ + + /** Callback to be invoked for a u-escape */ + jsonsl_stack_callback action_callback_UESCAPE; + + /** Boolean flag, whether to invoke the callback */ + int call_UESCAPE; + + /** Boolean flag, whether we should return after encountering a u-escape: + * the callback is invoked and then we return if this is true + */ + int return_UESCAPE; + /*@}*/ + + struct { + int allow_trailing_comma; + } options; + + /** Put anything here */ + void *data; + + /*@{*/ + /** Private */ + int in_escape; + char expecting; + char tok_last; + int can_insert; + unsigned int levels_max; + +#ifndef JSONSL_NO_JPR + size_t jpr_count; + jsonsl_jpr_t *jprs; + + /* Root pointer for JPR matching information */ + size_t *jpr_root; +#endif /* JSONSL_NO_JPR */ + /*@}*/ + + /** + * This is the stack. Its upper bound is levels_max, or the + * nlevels argument passed to jsonsl_new. If you modify this structure, + * make sure that this member is last. + */ + struct jsonsl_state_st stack[1]; +}; + + +/** + * Creates a new lexer object, with capacity for recursion up to nlevels + * + * @param nlevels maximum recursion depth + */ +JSONSL_API +jsonsl_t jsonsl_new(int nlevels); + +/** + * Feeds data into the lexer. + * + * @param jsn the lexer object + * @param bytes new data to be fed + * @param nbytes size of new data + */ +JSONSL_API +void jsonsl_feed(jsonsl_t jsn, const jsonsl_char_t *bytes, size_t nbytes); + +/** + * Resets the internal parser state. This does not free the parser + * but does clean it internally, so that the next time feed() is called, + * it will be treated as a new stream + * + * @param jsn the lexer + */ +JSONSL_API +void jsonsl_reset(jsonsl_t jsn); + +/** + * Frees the lexer, cleaning any allocated memory taken + * + * @param jsn the lexer + */ +JSONSL_API +void jsonsl_destroy(jsonsl_t jsn); + +/** + * Gets the 'parent' element, given the current one + * + * @param jsn the lexer + * @param cur the current nest, which should be a struct jsonsl_nest_st + */ +static JSONSL_INLINE +struct jsonsl_state_st *jsonsl_last_state(const jsonsl_t jsn, + const struct jsonsl_state_st *state) +{ + /* Don't complain about overriding array bounds */ + if (state->level > 1) { + return jsn->stack + state->level - 1; + } else { + return NULL; + } +} + +/** + * Gets the state of the last fully consumed child of this parent. This is + * only valid in the parent's POP callback. + * + * @param the lexer + * @return A pointer to the child. + */ +static JSONSL_INLINE +struct jsonsl_state_st *jsonsl_last_child(const jsonsl_t jsn, + const struct jsonsl_state_st *parent) +{ + return jsn->stack + (parent->level + 1); +} + +/**Call to instruct the parser to stop parsing and return. This is valid + * only from within a callback */ +static JSONSL_INLINE +void jsonsl_stop(jsonsl_t jsn) +{ + jsn->stopfl = 1; +} + +/** + * This enables receiving callbacks on all events. Doesn't do + * anything special but helps avoid some boilerplate. + * This does not touch the UESCAPE callbacks or flags. + */ +static JSONSL_INLINE +void jsonsl_enable_all_callbacks(jsonsl_t jsn) +{ + jsn->call_HKEY = 1; + jsn->call_STRING = 1; + jsn->call_OBJECT = 1; + jsn->call_SPECIAL = 1; + jsn->call_LIST = 1; +} + +/** + * A macro which returns true if the current state object can + * have children. This means a list type or an object type. + */ +#define JSONSL_STATE_IS_CONTAINER(state) \ + (state->type == JSONSL_T_OBJECT || state->type == JSONSL_T_LIST) + +/** + * These two functions, dump a string representation + * of the error or type, respectively. They will never + * return NULL + */ +JSONSL_API +const char* jsonsl_strerror(jsonsl_error_t err); +JSONSL_API +const char* jsonsl_strtype(jsonsl_type_t jt); + +/** + * Dumps global metrics to the screen. This is a noop unless + * jsonsl was compiled with JSONSL_USE_METRICS + */ +JSONSL_API +void jsonsl_dump_global_metrics(void); + +/* This macro just here for editors to do code folding */ +#ifndef JSONSL_NO_JPR + +/** + * @name JSON Pointer API + * + * JSONPointer API. This isn't really related to the lexer (at least not yet) + * JSONPointer provides an extremely simple specification for providing + * locations within JSON objects. We will extend it a bit and allow for + * providing 'wildcard' characters by which to be able to 'query' the stream. + * + * See http://tools.ietf.org/html/draft-pbryan-zyp-json-pointer-00 + * + * Currently I'm implementing the 'single query' API which can only use a single + * query component. In the future I will integrate my yet-to-be-published + * Boyer-Moore-esque prefix searching implementation, in order to allow + * multiple paths to be merged into one for quick and efficient searching. + * + * + * JPR (as we'll refer to it within the source) can be used by splitting + * the components into mutliple sections, and incrementally 'track' each + * component. When JSONSL delivers a 'pop' callback for a string, or a 'push' + * callback for an object, we will check to see whether the index matching + * the component corresponding to the current level contains a match + * for our path. + * + * In order to do this properly, a structure must be maintained within the + * parent indicating whether its children are possible matches. This flag + * will be 'inherited' by call children which may conform to the match + * specification, and discarded by all which do not (thereby eliminating + * their children from inheriting it). + * + * A successful match is a complete one. One can provide multiple paths with + * multiple levels of matches e.g. + * /foo/bar/baz/^/blah + * + * @{ + */ + +/** The wildcard character */ +#ifndef JSONSL_PATH_WILDCARD_CHAR +#define JSONSL_PATH_WILDCARD_CHAR '^' +#endif /* WILDCARD_CHAR */ + +#define JSONSL_XMATCH \ + X(COMPLETE,1) \ + X(POSSIBLE,0) \ + X(NOMATCH,-1) \ + X(TYPE_MISMATCH, -2) + +typedef enum { + +#define X(T,v) \ + JSONSL_MATCH_##T = v, + JSONSL_XMATCH + +#undef X + JSONSL_MATCH_UNKNOWN +} jsonsl_jpr_match_t; + +typedef enum { + JSONSL_PATH_STRING = 1, + JSONSL_PATH_WILDCARD, + JSONSL_PATH_NUMERIC, + JSONSL_PATH_ROOT, + + /* Special */ + JSONSL_PATH_INVALID = -1, + JSONSL_PATH_NONE = 0 +} jsonsl_jpr_type_t; + +struct jsonsl_jpr_component_st { + /** The string the component points to */ + char *pstr; + /** if this is a numeric type, the number is 'cached' here */ + unsigned long idx; + /** The length of the string */ + size_t len; + /** The type of component (NUMERIC or STRING) */ + jsonsl_jpr_type_t ptype; + + /** Set this to true to enforce type checking between dict keys and array + * indices. jsonsl_jpr_match() will return TYPE_MISMATCH if it detects + * that an array index is actually a child of a dictionary. */ + short is_arridx; + + /* Extra fields (for more advanced searches. Default is empty) */ + JSONSL_JPR_COMPONENT_USER_FIELDS +}; + +struct jsonsl_jpr_st { + /** Path components */ + struct jsonsl_jpr_component_st *components; + size_t ncomponents; + + /**Type of the match to be expected. If nonzero, will be compared against + * the actual type */ + unsigned match_type; + + /** Base of allocated string for components */ + char *basestr; + + /** The original match string. Useful for returning to the user */ + char *orig; + size_t norig; +}; + +/** + * Create a new JPR object. + * + * @param path the JSONPointer path specification. + * @param errp a pointer to a jsonsl_error_t. If this function returns NULL, + * then more details will be in this variable. + * + * @return a new jsonsl_jpr_t object, or NULL on error. + */ +JSONSL_API +jsonsl_jpr_t jsonsl_jpr_new(const char *path, jsonsl_error_t *errp); + +/** + * Destroy a JPR object + */ +JSONSL_API +void jsonsl_jpr_destroy(jsonsl_jpr_t jpr); + +/** + * Match a JSON object against a type and specific level + * + * @param jpr the JPR object + * @param parent_type the type of the parent (should be T_LIST or T_OBJECT) + * @param parent_level the level of the parent + * @param key the 'key' of the child. If the parent is an array, this should be + * empty. + * @param nkey - the length of the key. If the parent is an array (T_LIST), then + * this should be the current index. + * + * NOTE: The key of the child means any kind of associative data related to the + * element. Thus: <<< { "foo" : [ >>, + * the opening array's key is "foo". + * + * @return a status constant. This indicates whether a match was excluded, possible, + * or successful. + */ +JSONSL_API +jsonsl_jpr_match_t jsonsl_jpr_match(jsonsl_jpr_t jpr, + unsigned int parent_type, + unsigned int parent_level, + const char *key, size_t nkey); + +/** + * Alternate matching algorithm. This matching algorithm does not use + * JSONPointer but relies on a more structured searching mechanism. It + * assumes that there is a clear distinction between array indices and + * object keys. In this case, the jsonsl_path_component_st::ptype should + * be set to @ref JSONSL_PATH_NUMERIC for an array index (the + * jsonsl_path_comonent_st::is_arridx field will be removed in a future + * version). + * + * @param jpr The path + * @param parent The parent structure. Can be NULL if this is the root object + * @param child The child structure. Should not be NULL + * @param key Object key, if an object + * @param nkey Length of object key + * @return Status constant if successful + * + * @note + * For successful matching, both the key and the path itself should be normalized + * to contain 'proper' utf8 sequences rather than utf16 '\uXXXX' escapes. This + * should currently be done in the application. Another version of this function + * may use a temporary buffer in such circumstances (allocated by the application). + * + * Since this function also checks the state of the child, it should only + * be called on PUSH callbacks, and not POP callbacks + */ +JSONSL_API +jsonsl_jpr_match_t +jsonsl_path_match(jsonsl_jpr_t jpr, + const struct jsonsl_state_st *parent, + const struct jsonsl_state_st *child, + const char *key, size_t nkey); + + +/** + * Associate a set of JPR objects with a lexer instance. + * This should be called before the lexer has been fed any data (and + * behavior is undefined if you don't adhere to this). + * + * After using this function, you may subsequently call match_state() on + * given states (presumably from within the callbacks). + * + * Note that currently the first JPR is the quickest and comes + * pre-allocated with the state structure. Further JPR objects + * are chained. + * + * @param jsn The lexer + * @param jprs An array of jsonsl_jpr_t objects + * @param njprs How many elements in the jprs array. + */ +JSONSL_API +void jsonsl_jpr_match_state_init(jsonsl_t jsn, + jsonsl_jpr_t *jprs, + size_t njprs); + +/** + * This follows the same semantics as the normal match, + * except we infer parent and type information from the relevant state objects. + * The match status (for all possible JPR objects) is set in the *out parameter. + * + * If a match has succeeded, then its JPR object will be returned. In all other + * instances, NULL is returned; + * + * @param jpr The jsonsl_jpr_t handle + * @param state The jsonsl_state_st which is a candidate + * @param key The hash key (if applicable, can be NULL if parent is list) + * @param nkey Length of hash key (if applicable, can be zero if parent is list) + * @param out A pointer to a jsonsl_jpr_match_t. This will be populated with + * the match result + * + * @return If a match was completed in full, then the JPR object containing + * the matching path will be returned. Otherwise, the return is NULL (note, this + * does not mean matching has failed, it can still be part of the match: check + * the out parameter). + */ +JSONSL_API +jsonsl_jpr_t jsonsl_jpr_match_state(jsonsl_t jsn, + struct jsonsl_state_st *state, + const char *key, + size_t nkey, + jsonsl_jpr_match_t *out); + + +/** + * Cleanup any memory allocated and any states set by + * match_state_init() and match_state() + * @param jsn The lexer + */ +JSONSL_API +void jsonsl_jpr_match_state_cleanup(jsonsl_t jsn); + +/** + * Return a string representation of the match result returned by match() + */ +JSONSL_API +const char *jsonsl_strmatchtype(jsonsl_jpr_match_t match); + +/* @}*/ + +/** + * Utility function to convert escape sequences into their original form. + * + * The decoders I've sampled do not seem to specify a standard behavior of what + * to escape/unescape. + * + * RFC 4627 Mandates only that the quoute, backslash, and ASCII control + * characters (0x00-0x1f) be escaped. It is often common for applications + * to escape a '/' - however this may also be desired behavior. the JSON + * spec is not clear on this, and therefore jsonsl leaves it up to you. + * + * Additionally, sometimes you may wish to _normalize_ JSON. This is specifically + * true when dealing with 'u-escapes' which can be expressed perfectly fine + * as utf8. One use case for normalization is JPR string comparison, in which + * case two effectively equivalent strings may not match because one is using + * u-escapes and the other proper utf8. To normalize u-escapes only, pass in + * an empty `toEscape` table, enabling only the `u` index. + * + * @param in The input string. + * @param out An allocated output (should be the same size as in) + * @param len the size of the buffer + * @param toEscape - A sparse array of characters to unescape. Characters + * which are not present in this array, e.g. toEscape['c'] == 0 will be + * ignored and passed to the output in their original form. + * @param oflags If not null, and a \uXXXX escape expands to a non-ascii byte, + * then this variable will have the SPECIALf_NONASCII flag on. + * + * @param err A pointer to an error variable. If an error ocurrs, it will be + * set in this variable + * @param errat If not null and an error occurs, this will be set to point + * to the position within the string at which the offending character was + * encountered. + * + * @return The effective size of the output buffer. + * + * @note + * This function now encodes the UTF8 equivalents of utf16 escapes (i.e. + * 'u-escapes'). Previously this would encode the escapes as utf16 literals, + * which while still correct in some sense was confusing for many (especially + * considering that the inputs were variations of char). + * + * @note + * The output buffer will never be larger than the input buffer, since + * standard escape sequences (i.e. '\t') occupy two bytes in the source + * but only one byte (when unescaped) in the output. Likewise u-escapes + * (i.e. \uXXXX) will occupy six bytes in the source, but at the most + * two bytes when escaped. + */ +JSONSL_API +size_t jsonsl_util_unescape_ex(const char *in, + char *out, + size_t len, + const int toEscape[128], + unsigned *oflags, + jsonsl_error_t *err, + const char **errat); + +/** + * Convenience macro to avoid passing too many parameters + */ +#define jsonsl_util_unescape(in, out, len, toEscape, err) \ + jsonsl_util_unescape_ex(in, out, len, toEscape, NULL, err, NULL) + +#endif /* JSONSL_NO_JPR */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* JSONSL_H_ */ diff --git a/chaos_micro_unit_toolkit/external_lib/json.h b/chaos_micro_unit_toolkit/external_lib/json.h deleted file mode 100644 index 0738fd39065be0677e9012a3102161bdf37dc654..0000000000000000000000000000000000000000 --- a/chaos_micro_unit_toolkit/external_lib/json.h +++ /dev/null @@ -1,2176 +0,0 @@ -/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/). -/// It is intended to be used with #include "json/json.h" - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - -/* -The JsonCpp library's source code, including accompanying documentation, -tests and demonstration applications, are licensed under the following -conditions... - -Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all -jurisdictions which recognize such a disclaimer. In such jurisdictions, -this software is released into the Public Domain. - -In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and -The JsonCpp Authors, and is released under the terms of the MIT License (see below). - -In jurisdictions which recognize Public Domain property, the user of this -software may choose to accept it either as 1) Public Domain, 2) under the -conditions of the MIT License (see below), or 3) under the terms of dual -Public Domain/MIT License conditions described here, as they choose. - -The MIT License is about as close to Public Domain as a license can get, and is -described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - -The full text of the MIT License follows: - -======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, -modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -======================================================================== -(END LICENSE TEXT) - -The MIT license is compatible with both the GPL and commercial -software, affording one all of the rights of Public Domain with the -minor nuisance of being required to keep the above copyright notice -and license text in the source code. Note also that by accepting the -Public Domain "license" you can re-license your copy using whatever -license you like. - -*/ - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - - - - - -#ifndef JSON_AMALGATED_H_INCLUDED -# define JSON_AMALGATED_H_INCLUDED -/// If defined, indicates that the source file is amalgated -/// to prevent private header inclusion. -#define JSON_IS_AMALGAMATION - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/version.h -// ////////////////////////////////////////////////////////////////////// - -// DO NOT EDIT. This file (and "version") is generated by CMake. -// Run CMake configure step to update it. -#ifndef JSON_VERSION_H_INCLUDED -# define JSON_VERSION_H_INCLUDED - -# define JSONCPP_VERSION_STRING "1.8.1" -# define JSONCPP_VERSION_MAJOR 1 -# define JSONCPP_VERSION_MINOR 8 -# define JSONCPP_VERSION_PATCH 1 -# define JSONCPP_VERSION_QUALIFIER -# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) - -#ifdef JSONCPP_USING_SECURE_MEMORY -#undef JSONCPP_USING_SECURE_MEMORY -#endif -#define JSONCPP_USING_SECURE_MEMORY 0 -// If non-zero, the library zeroes any memory that it has allocated before -// it frees its memory. - -#endif // JSON_VERSION_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/version.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/config.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_CONFIG_H_INCLUDED -#define JSON_CONFIG_H_INCLUDED -#include <stddef.h> -#include <string> //typedef String -#include <stdint.h> //typedef int64_t, uint64_t - -/// If defined, indicates that json library is embedded in CppTL library. -//# define JSON_IN_CPPTL 1 - -/// If defined, indicates that json may leverage CppTL library -//# define JSON_USE_CPPTL 1 -/// If defined, indicates that cpptl vector based map should be used instead of -/// std::map -/// as Value container. -//# define JSON_USE_CPPTL_SMALLMAP 1 - -// If non-zero, the library uses exceptions to report bad input instead of C -// assertion macros. The default is to use exceptions. -#ifndef JSON_USE_EXCEPTION -#define JSON_USE_EXCEPTION 1 -#endif - -/// If defined, indicates that the source file is amalgated -/// to prevent private header inclusion. -/// Remarks: it is automatically defined in the generated amalgated header. -// #define JSON_IS_AMALGAMATION - -#ifdef JSON_IN_CPPTL -#include <cpptl/config.h> -#ifndef JSON_USE_CPPTL -#define JSON_USE_CPPTL 1 -#endif -#endif - -#ifdef JSON_IN_CPPTL -#define JSON_API CPPTL_API -#elif defined(JSON_DLL_BUILD) -#if defined(_MSC_VER) || defined(__MINGW32__) -#define JSON_API __declspec(dllexport) -#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING -#endif // if defined(_MSC_VER) -#elif defined(JSON_DLL) -#if defined(_MSC_VER) || defined(__MINGW32__) -#define JSON_API __declspec(dllimport) -#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING -#endif // if defined(_MSC_VER) -#endif // ifdef JSON_IN_CPPTL -#if !defined(JSON_API) -#define JSON_API -#endif - -// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for -// integer -// Storages, and 64 bits integer support is disabled. -// #define JSON_NO_INT64 1 - -#if defined(_MSC_VER) // MSVC -# if _MSC_VER <= 1200 // MSVC 6 - // Microsoft Visual Studio 6 only support conversion from __int64 to double - // (no conversion from unsigned __int64). -# define JSON_USE_INT64_DOUBLE_CONVERSION 1 - // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' - // characters in the debug information) - // All projects I've ever seen with VS6 were using this globally (not bothering - // with pragma push/pop). -# pragma warning(disable : 4786) -# endif // MSVC 6 - -# if _MSC_VER >= 1500 // MSVC 2008 - /// Indicates that the following function is deprecated. -# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) -# endif - -#endif // defined(_MSC_VER) - -// In c++11 the override keyword allows you to explicity define that a function -// is intended to override the base-class version. This makes the code more -// managable and fixes a set of common hard-to-find bugs. -#if __cplusplus >= 201103L -# define JSONCPP_OVERRIDE override -# define JSONCPP_NOEXCEPT noexcept -#elif defined(_MSC_VER) && _MSC_VER > 1600 && _MSC_VER < 1900 -# define JSONCPP_OVERRIDE override -# define JSONCPP_NOEXCEPT throw() -#elif defined(_MSC_VER) && _MSC_VER >= 1900 -# define JSONCPP_OVERRIDE override -# define JSONCPP_NOEXCEPT noexcept -#else -# define JSONCPP_OVERRIDE -# define JSONCPP_NOEXCEPT throw() -#endif - -#ifndef JSON_HAS_RVALUE_REFERENCES - -#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 -#define JSON_HAS_RVALUE_REFERENCES 1 -#endif // MSVC >= 2010 - -#ifdef __clang__ -#if __has_feature(cxx_rvalue_references) -#define JSON_HAS_RVALUE_REFERENCES 1 -#endif // has_feature - -#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) -#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) -#define JSON_HAS_RVALUE_REFERENCES 1 -#endif // GXX_EXPERIMENTAL - -#endif // __clang__ || __GNUC__ - -#endif // not defined JSON_HAS_RVALUE_REFERENCES - -#ifndef JSON_HAS_RVALUE_REFERENCES -#define JSON_HAS_RVALUE_REFERENCES 0 -#endif - -#ifdef __clang__ -#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) -# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) -# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) -# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) -# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) -# endif // GNUC version -#endif // __clang__ || __GNUC__ - -#if !defined(JSONCPP_DEPRECATED) -#define JSONCPP_DEPRECATED(message) -#endif // if !defined(JSONCPP_DEPRECATED) - -#if __GNUC__ >= 6 -# define JSON_USE_INT64_DOUBLE_CONVERSION 1 -#endif - -#if !defined(JSON_IS_AMALGAMATION) - -# include "version.h" - -# if JSONCPP_USING_SECURE_MEMORY -# include "allocator.h" //typedef Allocator -# endif - -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { -typedef int Int; -typedef unsigned int UInt; -#if defined(JSON_NO_INT64) -typedef int LargestInt; -typedef unsigned int LargestUInt; -#undef JSON_HAS_INT64 -#else // if defined(JSON_NO_INT64) -// For Microsoft Visual use specific types as long long is not supported -#if defined(_MSC_VER) // Microsoft Visual Studio -typedef __int64 Int64; -typedef unsigned __int64 UInt64; -#else // if defined(_MSC_VER) // Other platforms, use long long -typedef int64_t Int64; -typedef uint64_t UInt64; -#endif // if defined(_MSC_VER) -typedef Int64 LargestInt; -typedef UInt64 LargestUInt; -#define JSON_HAS_INT64 -#endif // if defined(JSON_NO_INT64) -#if JSONCPP_USING_SECURE_MEMORY -#define JSONCPP_STRING std::basic_string<char, std::char_traits<char>, Json::SecureAllocator<char> > -#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream<char, std::char_traits<char>, Json::SecureAllocator<char> > -#define JSONCPP_OSTREAM std::basic_ostream<char, std::char_traits<char>> -#define JSONCPP_ISTRINGSTREAM std::basic_istringstream<char, std::char_traits<char>, Json::SecureAllocator<char> > -#define JSONCPP_ISTREAM std::istream -#else -#define JSONCPP_STRING std::string -#define JSONCPP_OSTRINGSTREAM std::ostringstream -#define JSONCPP_OSTREAM std::ostream -#define JSONCPP_ISTRINGSTREAM std::istringstream -#define JSONCPP_ISTREAM std::istream -#endif // if JSONCPP_USING_SECURE_MEMORY -} // end namespace Json - -#endif // JSON_CONFIG_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/config.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/forwards.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_FORWARDS_H_INCLUDED -#define JSON_FORWARDS_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "config.h" -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { - -// writer.h -class FastWriter; -class StyledWriter; - -// reader.h -class Reader; - -// features.h -class Features; - -// value.h -typedef unsigned int ArrayIndex; -class StaticString; -class Path; -class PathArgument; -class Value; -class ValueIteratorBase; -class ValueIterator; -class ValueConstIterator; - -} // namespace Json - -#endif // JSON_FORWARDS_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/forwards.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/features.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef CPPTL_JSON_FEATURES_H_INCLUDED -#define CPPTL_JSON_FEATURES_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "forwards.h" -#endif // if !defined(JSON_IS_AMALGAMATION) - -#pragma pack(push, 8) - -namespace Json { - -/** \brief Configuration passed to reader and writer. - * This configuration object can be used to force the Reader or Writer - * to behave in a standard conforming way. - */ -class JSON_API Features { -public: - /** \brief A configuration that allows all features and assumes all strings - * are UTF-8. - * - C & C++ comments are allowed - * - Root object can be any JSON value - * - Assumes Value strings are encoded in UTF-8 - */ - static Features all(); - - /** \brief A configuration that is strictly compatible with the JSON - * specification. - * - Comments are forbidden. - * - Root object must be either an array or an object value. - * - Assumes Value strings are encoded in UTF-8 - */ - static Features strictMode(); - - /** \brief Initialize the configuration like JsonConfig::allFeatures; - */ - Features(); - - /// \c true if comments are allowed. Default: \c true. - bool allowComments_; - - /// \c true if root must be either an array or an object value. Default: \c - /// false. - bool strictRoot_; - - /// \c true if dropped null placeholders are allowed. Default: \c false. - bool allowDroppedNullPlaceholders_; - - /// \c true if numeric object key are allowed. Default: \c false. - bool allowNumericKeys_; -}; - -} // namespace Json - -#pragma pack(pop) - -#endif // CPPTL_JSON_FEATURES_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/features.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/value.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef CPPTL_JSON_H_INCLUDED -#define CPPTL_JSON_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "forwards.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include <string> -#include <vector> -#include <exception> - -#ifndef JSON_USE_CPPTL_SMALLMAP -#include <map> -#else -#include <cpptl/smallmap.h> -#endif -#ifdef JSON_USE_CPPTL -#include <cpptl/forwards.h> -#endif - -//Conditional NORETURN attribute on the throw functions would: -// a) suppress false positives from static code analysis -// b) possibly improve optimization opportunities. -#if !defined(JSONCPP_NORETURN) -# if defined(_MSC_VER) -# define JSONCPP_NORETURN __declspec(noreturn) -# elif defined(__GNUC__) -# define JSONCPP_NORETURN __attribute__ ((__noreturn__)) -# else -# define JSONCPP_NORETURN -# endif -#endif - -// Disable warning C4251: <data member>: <type> needs to have dll-interface to -// be used by... -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(push) -#pragma warning(disable : 4251) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#pragma pack(push, 8) - -/** \brief JSON (JavaScript Object Notation). - */ -namespace Json { - -/** Base class for all exceptions we throw. - * - * We use nothing but these internally. Of course, STL can throw others. - */ -class JSON_API Exception : public std::exception { -public: - Exception(JSONCPP_STRING const& msg); - ~Exception() JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; - char const* what() const JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; -protected: - JSONCPP_STRING msg_; -}; - -/** Exceptions which the user cannot easily avoid. - * - * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input - * - * \remark derived from Json::Exception - */ -class JSON_API RuntimeError : public Exception { -public: - RuntimeError(JSONCPP_STRING const& msg); -}; - -/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. - * - * These are precondition-violations (user bugs) and internal errors (our bugs). - * - * \remark derived from Json::Exception - */ -class JSON_API LogicError : public Exception { -public: - LogicError(JSONCPP_STRING const& msg); -}; - -/// used internally -JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg); -/// used internally -JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg); - -/** \brief Type of the value held by a Value object. - */ -enum ValueType { - nullValue = 0, ///< 'null' value - intValue, ///< signed integer value - uintValue, ///< unsigned integer value - realValue, ///< double value - stringValue, ///< UTF-8 string value - booleanValue, ///< bool value - arrayValue, ///< array value (ordered list) - objectValue ///< object value (collection of name/value pairs). -}; - -enum CommentPlacement { - commentBefore = 0, ///< a comment placed on the line before a value - commentAfterOnSameLine, ///< a comment just after a value on the same line - commentAfter, ///< a comment on the line after a value (only make sense for - /// root value) - numberOfCommentPlacement -}; - -//# ifdef JSON_USE_CPPTL -// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames; -// typedef CppTL::AnyEnumerator<const Value &> EnumValues; -//# endif - -/** \brief Lightweight wrapper to tag static string. - * - * Value constructor and objectValue member assignement takes advantage of the - * StaticString and avoid the cost of string duplication when storing the - * string or the member name. - * - * Example of usage: - * \code - * Json::Value aValue( StaticString("some text") ); - * Json::Value object; - * static const StaticString code("code"); - * object[code] = 1234; - * \endcode - */ -class JSON_API StaticString { -public: - explicit StaticString(const char* czstring) : c_str_(czstring) {} - - operator const char*() const { return c_str_; } - - const char* c_str() const { return c_str_; } - -private: - const char* c_str_; -}; - -/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value. - * - * This class is a discriminated union wrapper that can represents a: - * - signed integer [range: Value::minInt - Value::maxInt] - * - unsigned integer (range: 0 - Value::maxUInt) - * - double - * - UTF-8 string - * - boolean - * - 'null' - * - an ordered list of Value - * - collection of name/value pairs (javascript object) - * - * The type of the held value is represented by a #ValueType and - * can be obtained using type(). - * - * Values of an #objectValue or #arrayValue can be accessed using operator[]() - * methods. - * Non-const methods will automatically create the a #nullValue element - * if it does not exist. - * The sequence of an #arrayValue will be automatically resized and initialized - * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. - * - * The get() methods can be used to obtain default value in the case the - * required element does not exist. - * - * It is possible to iterate over the list of a #objectValue values using - * the getMemberNames() method. - * - * \note #Value string-length fit in size_t, but keys must be < 2^30. - * (The reason is an implementation detail.) A #CharReader will raise an - * exception if a bound is exceeded to avoid security holes in your app, - * but the Value API does *not* check bounds. That is the responsibility - * of the caller. - */ -class JSON_API Value { - friend class ValueIteratorBase; -public: - typedef std::vector<JSONCPP_STRING> Members; - typedef ValueIterator iterator; - typedef ValueConstIterator const_iterator; - typedef Json::UInt UInt; - typedef Json::Int Int; -#if defined(JSON_HAS_INT64) - typedef Json::UInt64 UInt64; - typedef Json::Int64 Int64; -#endif // defined(JSON_HAS_INT64) - typedef Json::LargestInt LargestInt; - typedef Json::LargestUInt LargestUInt; - typedef Json::ArrayIndex ArrayIndex; - - static const Value& null; ///< We regret this reference to a global instance; prefer the simpler Value(). - static const Value& nullRef; ///< just a kludge for binary-compatibility; same as null - static Value const& nullSingleton(); ///< Prefer this to null or nullRef. - - /// Minimum signed integer value that can be stored in a Json::Value. - static const LargestInt minLargestInt; - /// Maximum signed integer value that can be stored in a Json::Value. - static const LargestInt maxLargestInt; - /// Maximum unsigned integer value that can be stored in a Json::Value. - static const LargestUInt maxLargestUInt; - - /// Minimum signed int value that can be stored in a Json::Value. - static const Int minInt; - /// Maximum signed int value that can be stored in a Json::Value. - static const Int maxInt; - /// Maximum unsigned int value that can be stored in a Json::Value. - static const UInt maxUInt; - -#if defined(JSON_HAS_INT64) - /// Minimum signed 64 bits int value that can be stored in a Json::Value. - static const Int64 minInt64; - /// Maximum signed 64 bits int value that can be stored in a Json::Value. - static const Int64 maxInt64; - /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. - static const UInt64 maxUInt64; -#endif // defined(JSON_HAS_INT64) - -private: -#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - class CZString { - public: - enum DuplicationPolicy { - noDuplication = 0, - duplicate, - duplicateOnCopy - }; - CZString(ArrayIndex index); - CZString(char const* str, unsigned length, DuplicationPolicy allocate); - CZString(CZString const& other); -#if JSON_HAS_RVALUE_REFERENCES - CZString(CZString&& other); -#endif - ~CZString(); - CZString& operator=(const CZString& other); - -#if JSON_HAS_RVALUE_REFERENCES - CZString& operator=(CZString&& other); -#endif - - bool operator<(CZString const& other) const; - bool operator==(CZString const& other) const; - ArrayIndex index() const; - //const char* c_str() const; ///< \deprecated - char const* data() const; - unsigned length() const; - bool isStaticString() const; - - private: - void swap(CZString& other); - - struct StringStorage { - unsigned policy_: 2; - unsigned length_: 30; // 1GB max - }; - - char const* cstr_; // actually, a prefixed string, unless policy is noDup - union { - ArrayIndex index_; - StringStorage storage_; - }; - }; - -public: -#ifndef JSON_USE_CPPTL_SMALLMAP - typedef std::map<CZString, Value> ObjectValues; -#else - typedef CppTL::SmallMap<CZString, Value> ObjectValues; -#endif // ifndef JSON_USE_CPPTL_SMALLMAP -#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - -public: - /** \brief Create a default Value of the given type. - - This is a very useful constructor. - To create an empty array, pass arrayValue. - To create an empty object, pass objectValue. - Another Value can then be set to this one by assignment. -This is useful since clear() and resize() will not alter types. - - Examples: -\code -Json::Value null_value; // null -Json::Value arr_value(Json::arrayValue); // [] -Json::Value obj_value(Json::objectValue); // {} -\endcode - */ - Value(ValueType type = nullValue); - Value(Int value); - Value(UInt value); -#if defined(JSON_HAS_INT64) - Value(Int64 value); - Value(UInt64 value); -#endif // if defined(JSON_HAS_INT64) - Value(double value); - Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) - Value(const char* begin, const char* end); ///< Copy all, incl zeroes. - /** \brief Constructs a value from a static string. - - * Like other value string constructor but do not duplicate the string for - * internal storage. The given string must remain alive after the call to this - * constructor. - * \note This works only for null-terminated strings. (We cannot change the - * size of this class, so we have nowhere to store the length, - * which might be computed later for various operations.) - * - * Example of usage: - * \code - * static StaticString foo("some text"); - * Json::Value aValue(foo); - * \endcode - */ - Value(const StaticString& value); - Value(const JSONCPP_STRING& value); ///< Copy data() til size(). Embedded zeroes too. -#ifdef JSON_USE_CPPTL - Value(const CppTL::ConstString& value); -#endif - Value(bool value); - /// Deep copy. - Value(const Value& other); -#if JSON_HAS_RVALUE_REFERENCES - /// Move constructor - Value(Value&& other); -#endif - ~Value(); - - /// Deep copy, then swap(other). - /// \note Over-write existing comments. To preserve comments, use #swapPayload(). - Value& operator=(Value other); - - /// Swap everything. - void swap(Value& other); - /// Swap values but leave comments and source offsets in place. - void swapPayload(Value& other); - - /// copy everything. - void copy(const Value& other); - /// copy values but leave comments and source offsets in place. - void copyPayload(const Value& other); - - ValueType type() const; - - /// Compare payload only, not comments etc. - bool operator<(const Value& other) const; - bool operator<=(const Value& other) const; - bool operator>=(const Value& other) const; - bool operator>(const Value& other) const; - bool operator==(const Value& other) const; - bool operator!=(const Value& other) const; - int compare(const Value& other) const; - - const char* asCString() const; ///< Embedded zeroes could cause you trouble! -#if JSONCPP_USING_SECURE_MEMORY - unsigned getCStringLength() const; //Allows you to understand the length of the CString -#endif - JSONCPP_STRING asString() const; ///< Embedded zeroes are possible. - /** Get raw char* of string-value. - * \return false if !string. (Seg-fault if str or end are NULL.) - */ - bool getString( - char const** begin, char const** end) const; -#ifdef JSON_USE_CPPTL - CppTL::ConstString asConstString() const; -#endif - Int asInt() const; - UInt asUInt() const; -#if defined(JSON_HAS_INT64) - Int64 asInt64() const; - UInt64 asUInt64() const; -#endif // if defined(JSON_HAS_INT64) - LargestInt asLargestInt() const; - LargestUInt asLargestUInt() const; - float asFloat() const; - double asDouble() const; - bool asBool() const; - - bool isNull() const; - bool isBool() const; - bool isInt() const; - bool isInt64() const; - bool isUInt() const; - bool isUInt64() const; - bool isIntegral() const; - bool isDouble() const; - bool isNumeric() const; - bool isString() const; - bool isArray() const; - bool isObject() const; - - bool isConvertibleTo(ValueType other) const; - - /// Number of values in array or object - ArrayIndex size() const; - - /// \brief Return true if empty array, empty object, or null; - /// otherwise, false. - bool empty() const; - - /// Return isNull() - bool operator!() const; - - /// Remove all object members and array elements. - /// \pre type() is arrayValue, objectValue, or nullValue - /// \post type() is unchanged - void clear(); - - /// Resize the array to size elements. - /// New elements are initialized to null. - /// May only be called on nullValue or arrayValue. - /// \pre type() is arrayValue or nullValue - /// \post type() is arrayValue - void resize(ArrayIndex size); - - /// Access an array element (zero based index ). - /// If the array contains less than index element, then null value are - /// inserted - /// in the array so that its size is index+1. - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - Value& operator[](ArrayIndex index); - - /// Access an array element (zero based index ). - /// If the array contains less than index element, then null value are - /// inserted - /// in the array so that its size is index+1. - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - Value& operator[](int index); - - /// Access an array element (zero based index ) - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - const Value& operator[](ArrayIndex index) const; - - /// Access an array element (zero based index ) - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - const Value& operator[](int index) const; - - /// If the array contains at least index+1 elements, returns the element - /// value, - /// otherwise returns defaultValue. - Value get(ArrayIndex index, const Value& defaultValue) const; - /// Return true if index < size(). - bool isValidIndex(ArrayIndex index) const; - /// \brief Append value to array at the end. - /// - /// Equivalent to jsonvalue[jsonvalue.size()] = value; - Value& append(const Value& value); - -#if JSON_HAS_RVALUE_REFERENCES - Value& append(Value&& value); -#endif - - /// Access an object value by name, create a null member if it does not exist. - /// \note Because of our implementation, keys are limited to 2^30 -1 chars. - /// Exceeding that will cause an exception. - Value& operator[](const char* key); - /// Access an object value by name, returns null if there is no member with - /// that name. - const Value& operator[](const char* key) const; - /// Access an object value by name, create a null member if it does not exist. - /// \param key may contain embedded nulls. - Value& operator[](const JSONCPP_STRING& key); - /// Access an object value by name, returns null if there is no member with - /// that name. - /// \param key may contain embedded nulls. - const Value& operator[](const JSONCPP_STRING& key) const; - /** \brief Access an object value by name, create a null member if it does not - exist. - - * If the object has no entry for that name, then the member name used to store - * the new entry is not duplicated. - * Example of use: - * \code - * Json::Value object; - * static const StaticString code("code"); - * object[code] = 1234; - * \endcode - */ - Value& operator[](const StaticString& key); -#ifdef JSON_USE_CPPTL - /// Access an object value by name, create a null member if it does not exist. - Value& operator[](const CppTL::ConstString& key); - /// Access an object value by name, returns null if there is no member with - /// that name. - const Value& operator[](const CppTL::ConstString& key) const; -#endif - /// Return the member named key if it exist, defaultValue otherwise. - /// \note deep copy - Value get(const char* key, const Value& defaultValue) const; - /// Return the member named key if it exist, defaultValue otherwise. - /// \note deep copy - /// \note key may contain embedded nulls. - Value get(const char* begin, const char* end, const Value& defaultValue) const; - /// Return the member named key if it exist, defaultValue otherwise. - /// \note deep copy - /// \param key may contain embedded nulls. - Value get(const JSONCPP_STRING& key, const Value& defaultValue) const; -#ifdef JSON_USE_CPPTL - /// Return the member named key if it exist, defaultValue otherwise. - /// \note deep copy - Value get(const CppTL::ConstString& key, const Value& defaultValue) const; -#endif - /// Most general and efficient version of isMember()const, get()const, - /// and operator[]const - /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 - Value const* find(char const* begin, char const* end) const; - /// Most general and efficient version of object-mutators. - /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 - /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. - Value const* demand(char const* begin, char const* end); - /// \brief Remove and return the named member. - /// - /// Do nothing if it did not exist. - /// \return the removed Value, or null. - /// \pre type() is objectValue or nullValue - /// \post type() is unchanged - /// \deprecated - Value removeMember(const char* key); - /// Same as removeMember(const char*) - /// \param key may contain embedded nulls. - /// \deprecated - Value removeMember(const JSONCPP_STRING& key); - /// Same as removeMember(const char* begin, const char* end, Value* removed), - /// but 'key' is null-terminated. - bool removeMember(const char* key, Value* removed); - /** \brief Remove the named map member. - - Update 'removed' iff removed. - \param key may contain embedded nulls. - \return true iff removed (no exceptions) - */ - bool removeMember(JSONCPP_STRING const& key, Value* removed); - /// Same as removeMember(JSONCPP_STRING const& key, Value* removed) - bool removeMember(const char* begin, const char* end, Value* removed); - /** \brief Remove the indexed array element. - - O(n) expensive operations. - Update 'removed' iff removed. - \return true iff removed (no exceptions) - */ - bool removeIndex(ArrayIndex i, Value* removed); - - /// Return true if the object has a member named key. - /// \note 'key' must be null-terminated. - bool isMember(const char* key) const; - /// Return true if the object has a member named key. - /// \param key may contain embedded nulls. - bool isMember(const JSONCPP_STRING& key) const; - /// Same as isMember(JSONCPP_STRING const& key)const - bool isMember(const char* begin, const char* end) const; -#ifdef JSON_USE_CPPTL - /// Return true if the object has a member named key. - bool isMember(const CppTL::ConstString& key) const; -#endif - - /// \brief Return a list of the member names. - /// - /// If null, return an empty list. - /// \pre type() is objectValue or nullValue - /// \post if type() was nullValue, it remains nullValue - Members getMemberNames() const; - - //# ifdef JSON_USE_CPPTL - // EnumMemberNames enumMemberNames() const; - // EnumValues enumValues() const; - //# endif - - /// \deprecated Always pass len. - JSONCPP_DEPRECATED("Use setComment(JSONCPP_STRING const&) instead.") - void setComment(const char* comment, CommentPlacement placement); - /// Comments must be //... or /* ... */ - void setComment(const char* comment, size_t len, CommentPlacement placement); - /// Comments must be //... or /* ... */ - void setComment(const JSONCPP_STRING& comment, CommentPlacement placement); - bool hasComment(CommentPlacement placement) const; - /// Include delimiters and embedded newlines. - JSONCPP_STRING getComment(CommentPlacement placement) const; - - JSONCPP_STRING toStyledString() const; - - const_iterator begin() const; - const_iterator end() const; - - iterator begin(); - iterator end(); - - // Accessors for the [start, limit) range of bytes within the JSON text from - // which this value was parsed, if any. - void setOffsetStart(ptrdiff_t start); - void setOffsetLimit(ptrdiff_t limit); - ptrdiff_t getOffsetStart() const; - ptrdiff_t getOffsetLimit() const; - -private: - void initBasic(ValueType type, bool allocated = false); - - Value& resolveReference(const char* key); - Value& resolveReference(const char* key, const char* end); - - struct CommentInfo { - CommentInfo(); - ~CommentInfo(); - - void setComment(const char* text, size_t len); - - char* comment_; - }; - - // struct MemberNamesTransform - //{ - // typedef const char *result_type; - // const char *operator()( const CZString &name ) const - // { - // return name.c_str(); - // } - //}; - - union ValueHolder { - LargestInt int_; - LargestUInt uint_; - double real_; - bool bool_; - char* string_; // actually ptr to unsigned, followed by str, unless !allocated_ - ObjectValues* map_; - } value_; - ValueType type_ : 8; - unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. - // If not allocated_, string_ must be null-terminated. - CommentInfo* comments_; - - // [start, limit) byte offsets in the source JSON text from which this Value - // was extracted. - ptrdiff_t start_; - ptrdiff_t limit_; -}; - -/** \brief Experimental and untested: represents an element of the "path" to - * access a node. - */ -class JSON_API PathArgument { -public: - friend class Path; - - PathArgument(); - PathArgument(ArrayIndex index); - PathArgument(const char* key); - PathArgument(const JSONCPP_STRING& key); - -private: - enum Kind { - kindNone = 0, - kindIndex, - kindKey - }; - JSONCPP_STRING key_; - ArrayIndex index_; - Kind kind_; -}; - -/** \brief Experimental and untested: represents a "path" to access a node. - * - * Syntax: - * - "." => root node - * - ".[n]" => elements at index 'n' of root node (an array value) - * - ".name" => member named 'name' of root node (an object value) - * - ".name1.name2.name3" - * - ".[0][1][2].name1[3]" - * - ".%" => member name is provided as parameter - * - ".[%]" => index is provied as parameter - */ -class JSON_API Path { -public: - Path(const JSONCPP_STRING& path, - const PathArgument& a1 = PathArgument(), - const PathArgument& a2 = PathArgument(), - const PathArgument& a3 = PathArgument(), - const PathArgument& a4 = PathArgument(), - const PathArgument& a5 = PathArgument()); - - const Value& resolve(const Value& root) const; - Value resolve(const Value& root, const Value& defaultValue) const; - /// Creates the "path" to access the specified node and returns a reference on - /// the node. - Value& make(Value& root) const; - -private: - typedef std::vector<const PathArgument*> InArgs; - typedef std::vector<PathArgument> Args; - - void makePath(const JSONCPP_STRING& path, const InArgs& in); - void addPathInArg(const JSONCPP_STRING& path, - const InArgs& in, - InArgs::const_iterator& itInArg, - PathArgument::Kind kind); - void invalidPath(const JSONCPP_STRING& path, int location); - - Args args_; -}; - -/** \brief base class for Value iterators. - * - */ -class JSON_API ValueIteratorBase { -public: - typedef std::bidirectional_iterator_tag iterator_category; - typedef unsigned int size_t; - typedef int difference_type; - typedef ValueIteratorBase SelfType; - - bool operator==(const SelfType& other) const { return isEqual(other); } - - bool operator!=(const SelfType& other) const { return !isEqual(other); } - - difference_type operator-(const SelfType& other) const { - return other.computeDistance(*this); - } - - /// Return either the index or the member name of the referenced value as a - /// Value. - Value key() const; - - /// Return the index of the referenced Value, or -1 if it is not an arrayValue. - UInt index() const; - - /// Return the member name of the referenced Value, or "" if it is not an - /// objectValue. - /// \note Avoid `c_str()` on result, as embedded zeroes are possible. - JSONCPP_STRING name() const; - - /// Return the member name of the referenced Value. "" if it is not an - /// objectValue. - /// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls. - JSONCPP_DEPRECATED("Use `key = name();` instead.") - char const* memberName() const; - /// Return the member name of the referenced Value, or NULL if it is not an - /// objectValue. - /// \note Better version than memberName(). Allows embedded nulls. - char const* memberName(char const** end) const; - -protected: - Value& deref() const; - - void increment(); - - void decrement(); - - difference_type computeDistance(const SelfType& other) const; - - bool isEqual(const SelfType& other) const; - - void copy(const SelfType& other); - -private: - Value::ObjectValues::iterator current_; - // Indicates that iterator is for a null value. - bool isNull_; - -public: - // For some reason, BORLAND needs these at the end, rather - // than earlier. No idea why. - ValueIteratorBase(); - explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); -}; - -/** \brief const iterator for object and array value. - * - */ -class JSON_API ValueConstIterator : public ValueIteratorBase { - friend class Value; - -public: - typedef const Value value_type; - //typedef unsigned int size_t; - //typedef int difference_type; - typedef const Value& reference; - typedef const Value* pointer; - typedef ValueConstIterator SelfType; - - ValueConstIterator(); - ValueConstIterator(ValueIterator const& other); - -private: -/*! \internal Use by Value to create an iterator. - */ - explicit ValueConstIterator(const Value::ObjectValues::iterator& current); -public: - SelfType& operator=(const ValueIteratorBase& other); - - SelfType operator++(int) { - SelfType temp(*this); - ++*this; - return temp; - } - - SelfType operator--(int) { - SelfType temp(*this); - --*this; - return temp; - } - - SelfType& operator--() { - decrement(); - return *this; - } - - SelfType& operator++() { - increment(); - return *this; - } - - reference operator*() const { return deref(); } - - pointer operator->() const { return &deref(); } -}; - -/** \brief Iterator for object and array value. - */ -class JSON_API ValueIterator : public ValueIteratorBase { - friend class Value; - -public: - typedef Value value_type; - typedef unsigned int size_t; - typedef int difference_type; - typedef Value& reference; - typedef Value* pointer; - typedef ValueIterator SelfType; - - ValueIterator(); - explicit ValueIterator(const ValueConstIterator& other); - ValueIterator(const ValueIterator& other); - -private: -/*! \internal Use by Value to create an iterator. - */ - explicit ValueIterator(const Value::ObjectValues::iterator& current); -public: - SelfType& operator=(const SelfType& other); - - SelfType operator++(int) { - SelfType temp(*this); - ++*this; - return temp; - } - - SelfType operator--(int) { - SelfType temp(*this); - --*this; - return temp; - } - - SelfType& operator--() { - decrement(); - return *this; - } - - SelfType& operator++() { - increment(); - return *this; - } - - reference operator*() const { return deref(); } - - pointer operator->() const { return &deref(); } -}; - -} // namespace Json - - -namespace std { -/// Specialize std::swap() for Json::Value. -template<> -inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); } -} - -#pragma pack(pop) - -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(pop) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#endif // CPPTL_JSON_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/value.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/reader.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef CPPTL_JSON_READER_H_INCLUDED -#define CPPTL_JSON_READER_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "features.h" -#include "value.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include <deque> -#include <iosfwd> -#include <stack> -#include <string> -#include <istream> - -// Disable warning C4251: <data member>: <type> needs to have dll-interface to -// be used by... -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(push) -#pragma warning(disable : 4251) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#pragma pack(push, 8) - -namespace Json { - -/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a - *Value. - * - * \deprecated Use CharReader and CharReaderBuilder. - */ -class JSON_API Reader { -public: - typedef char Char; - typedef const Char* Location; - - /** \brief An error tagged with where in the JSON text it was encountered. - * - * The offsets give the [start, limit) range of bytes within the text. Note - * that this is bytes, not codepoints. - * - */ - struct StructuredError { - ptrdiff_t offset_start; - ptrdiff_t offset_limit; - JSONCPP_STRING message; - }; - - /** \brief Constructs a Reader allowing all features - * for parsing. - */ - Reader(); - - /** \brief Constructs a Reader allowing the specified feature set - * for parsing. - */ - Reader(const Features& features); - - /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> - * document. - * \param document UTF-8 encoded string containing the document to read. - * \param root [out] Contains the root value of the document if it was - * successfully parsed. - * \param collectComments \c true to collect comment and allow writing them - * back during - * serialization, \c false to discard comments. - * This parameter is ignored if - * Features::allowComments_ - * is \c false. - * \return \c true if the document was successfully parsed, \c false if an - * error occurred. - */ - bool - parse(const std::string& document, Value& root, bool collectComments = true); - - /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> - document. - * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the - document to read. - * \param endDoc Pointer on the end of the UTF-8 encoded string of the - document to read. - * Must be >= beginDoc. - * \param root [out] Contains the root value of the document if it was - * successfully parsed. - * \param collectComments \c true to collect comment and allow writing them - back during - * serialization, \c false to discard comments. - * This parameter is ignored if - Features::allowComments_ - * is \c false. - * \return \c true if the document was successfully parsed, \c false if an - error occurred. - */ - bool parse(const char* beginDoc, - const char* endDoc, - Value& root, - bool collectComments = true); - - /// \brief Parse from input stream. - /// \see Json::operator>>(std::istream&, Json::Value&). - bool parse(JSONCPP_ISTREAM& is, Value& root, bool collectComments = true); - - /** \brief Returns a user friendly string that list errors in the parsed - * document. - * \return Formatted error message with the list of errors with their location - * in - * the parsed document. An empty string is returned if no error - * occurred - * during parsing. - * \deprecated Use getFormattedErrorMessages() instead (typo fix). - */ - JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") - JSONCPP_STRING getFormatedErrorMessages() const; - - /** \brief Returns a user friendly string that list errors in the parsed - * document. - * \return Formatted error message with the list of errors with their location - * in - * the parsed document. An empty string is returned if no error - * occurred - * during parsing. - */ - JSONCPP_STRING getFormattedErrorMessages() const; - - /** \brief Returns a vector of structured erros encounted while parsing. - * \return A (possibly empty) vector of StructuredError objects. Currently - * only one error can be returned, but the caller should tolerate - * multiple - * errors. This can occur if the parser recovers from a non-fatal - * parse error and then encounters additional errors. - */ - std::vector<StructuredError> getStructuredErrors() const; - - /** \brief Add a semantic error message. - * \param value JSON Value location associated with the error - * \param message The error message. - * \return \c true if the error was successfully added, \c false if the - * Value offset exceeds the document size. - */ - bool pushError(const Value& value, const JSONCPP_STRING& message); - - /** \brief Add a semantic error message with extra context. - * \param value JSON Value location associated with the error - * \param message The error message. - * \param extra Additional JSON Value location to contextualize the error - * \return \c true if the error was successfully added, \c false if either - * Value offset exceeds the document size. - */ - bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); - - /** \brief Return whether there are any errors. - * \return \c true if there are no errors to report \c false if - * errors have occurred. - */ - bool good() const; - -private: - enum TokenType { - tokenEndOfStream = 0, - tokenObjectBegin, - tokenObjectEnd, - tokenArrayBegin, - tokenArrayEnd, - tokenString, - tokenNumber, - tokenTrue, - tokenFalse, - tokenNull, - tokenArraySeparator, - tokenMemberSeparator, - tokenComment, - tokenError - }; - - class Token { - public: - TokenType type_; - Location start_; - Location end_; - }; - - class ErrorInfo { - public: - Token token_; - JSONCPP_STRING message_; - Location extra_; - }; - - typedef std::deque<ErrorInfo> Errors; - - bool readToken(Token& token); - void skipSpaces(); - bool match(Location pattern, int patternLength); - bool readComment(); - bool readCStyleComment(); - bool readCppStyleComment(); - bool readString(); - void readNumber(); - bool readValue(); - bool readObject(Token& token); - bool readArray(Token& token); - bool decodeNumber(Token& token); - bool decodeNumber(Token& token, Value& decoded); - bool decodeString(Token& token); - bool decodeString(Token& token, JSONCPP_STRING& decoded); - bool decodeDouble(Token& token); - bool decodeDouble(Token& token, Value& decoded); - bool decodeUnicodeCodePoint(Token& token, - Location& current, - Location end, - unsigned int& unicode); - bool decodeUnicodeEscapeSequence(Token& token, - Location& current, - Location end, - unsigned int& unicode); - bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); - bool recoverFromError(TokenType skipUntilToken); - bool addErrorAndRecover(const JSONCPP_STRING& message, - Token& token, - TokenType skipUntilToken); - void skipUntilSpace(); - Value& currentValue(); - Char getNextChar(); - void - getLocationLineAndColumn(Location location, int& line, int& column) const; - JSONCPP_STRING getLocationLineAndColumn(Location location) const; - void addComment(Location begin, Location end, CommentPlacement placement); - void skipCommentTokens(Token& token); - - typedef std::stack<Value*> Nodes; - Nodes nodes_; - Errors errors_; - JSONCPP_STRING document_; - Location begin_; - Location end_; - Location current_; - Location lastValueEnd_; - Value* lastValue_; - JSONCPP_STRING commentsBefore_; - Features features_; - bool collectComments_; -}; // Reader - -/** Interface for reading JSON from a char array. - */ -class JSON_API CharReader { -public: - virtual ~CharReader() {} - /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> - document. - * The document must be a UTF-8 encoded string containing the document to read. - * - * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the - document to read. - * \param endDoc Pointer on the end of the UTF-8 encoded string of the - document to read. - * Must be >= beginDoc. - * \param root [out] Contains the root value of the document if it was - * successfully parsed. - * \param errs [out] Formatted error messages (if not NULL) - * a user friendly string that lists errors in the parsed - * document. - * \return \c true if the document was successfully parsed, \c false if an - error occurred. - */ - virtual bool parse( - char const* beginDoc, char const* endDoc, - Value* root, JSONCPP_STRING* errs) = 0; - - class JSON_API Factory { - public: - virtual ~Factory() {} - /** \brief Allocate a CharReader via operator new(). - * \throw std::exception if something goes wrong (e.g. invalid settings) - */ - virtual CharReader* newCharReader() const = 0; - }; // Factory -}; // CharReader - -/** \brief Build a CharReader implementation. - -Usage: -\code - using namespace Json; - CharReaderBuilder builder; - builder["collectComments"] = false; - Value value; - JSONCPP_STRING errs; - bool ok = parseFromStream(builder, std::cin, &value, &errs); -\endcode -*/ -class JSON_API CharReaderBuilder : public CharReader::Factory { -public: - // Note: We use a Json::Value so that we can add data-members to this class - // without a major version bump. - /** Configuration of this builder. - These are case-sensitive. - Available settings (case-sensitive): - - `"collectComments": false or true` - - true to collect comment and allow writing them - back during serialization, false to discard comments. - This parameter is ignored if allowComments is false. - - `"allowComments": false or true` - - true if comments are allowed. - - `"strictRoot": false or true` - - true if root must be either an array or an object value - - `"allowDroppedNullPlaceholders": false or true` - - true if dropped null placeholders are allowed. (See StreamWriterBuilder.) - - `"allowNumericKeys": false or true` - - true if numeric object keys are allowed. - - `"allowSingleQuotes": false or true` - - true if '' are allowed for strings (both keys and values) - - `"stackLimit": integer` - - Exceeding stackLimit (recursive depth of `readValue()`) will - cause an exception. - - This is a security issue (seg-faults caused by deeply nested JSON), - so the default is low. - - `"failIfExtra": false or true` - - If true, `parse()` returns false when extra non-whitespace trails - the JSON value in the input string. - - `"rejectDupKeys": false or true` - - If true, `parse()` returns false when a key is duplicated within an object. - - `"allowSpecialFloats": false or true` - - If true, special float values (NaNs and infinities) are allowed - and their values are lossfree restorable. - - You can examine 'settings_` yourself - to see the defaults. You can also write and read them just like any - JSON Value. - \sa setDefaults() - */ - Json::Value settings_; - - CharReaderBuilder(); - ~CharReaderBuilder() JSONCPP_OVERRIDE; - - CharReader* newCharReader() const JSONCPP_OVERRIDE; - - /** \return true if 'settings' are legal and consistent; - * otherwise, indicate bad settings via 'invalid'. - */ - bool validate(Json::Value* invalid) const; - - /** A simple way to update a specific setting. - */ - Value& operator[](JSONCPP_STRING key); - - /** Called by ctor, but you can use this to reset settings_. - * \pre 'settings' != NULL (but Json::null is fine) - * \remark Defaults: - * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults - */ - static void setDefaults(Json::Value* settings); - /** Same as old Features::strictMode(). - * \pre 'settings' != NULL (but Json::null is fine) - * \remark Defaults: - * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode - */ - static void strictMode(Json::Value* settings); -}; - -/** Consume entire stream and use its begin/end. - * Someday we might have a real StreamReader, but for now this - * is convenient. - */ -bool JSON_API parseFromStream( - CharReader::Factory const&, - JSONCPP_ISTREAM&, - Value* root, std::string* errs); - -/** \brief Read from 'sin' into 'root'. - - Always keep comments from the input JSON. - - This can be used to read a file into a particular sub-object. - For example: - \code - Json::Value root; - cin >> root["dir"]["file"]; - cout << root; - \endcode - Result: - \verbatim - { - "dir": { - "file": { - // The input stream JSON would be nested here. - } - } - } - \endverbatim - \throw std::exception on parse error. - \see Json::operator<<() -*/ -JSON_API JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM&, Value&); - -} // namespace Json - -#pragma pack(pop) - -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(pop) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#endif // CPPTL_JSON_READER_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/reader.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/writer.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_WRITER_H_INCLUDED -#define JSON_WRITER_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "value.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include <vector> -#include <string> -#include <ostream> - -// Disable warning C4251: <data member>: <type> needs to have dll-interface to -// be used by... -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(push) -#pragma warning(disable : 4251) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#pragma pack(push, 8) - -namespace Json { - -class Value; - -/** - -Usage: -\code - using namespace Json; - void writeToStdout(StreamWriter::Factory const& factory, Value const& value) { - std::unique_ptr<StreamWriter> const writer( - factory.newStreamWriter()); - writer->write(value, &std::cout); - std::cout << std::endl; // add lf and flush - } -\endcode -*/ -class JSON_API StreamWriter { -protected: - JSONCPP_OSTREAM* sout_; // not owned; will not delete -public: - StreamWriter(); - virtual ~StreamWriter(); - /** Write Value into document as configured in sub-class. - Do not take ownership of sout, but maintain a reference during function. - \pre sout != NULL - \return zero on success (For now, we always return zero, so check the stream instead.) - \throw std::exception possibly, depending on configuration - */ - virtual int write(Value const& root, JSONCPP_OSTREAM* sout) = 0; - - /** \brief A simple abstract factory. - */ - class JSON_API Factory { - public: - virtual ~Factory(); - /** \brief Allocate a CharReader via operator new(). - * \throw std::exception if something goes wrong (e.g. invalid settings) - */ - virtual StreamWriter* newStreamWriter() const = 0; - }; // Factory -}; // StreamWriter - -/** \brief Write into stringstream, then return string, for convenience. - * A StreamWriter will be created from the factory, used, and then deleted. - */ -JSONCPP_STRING JSON_API writeString(StreamWriter::Factory const& factory, Value const& root); - - -/** \brief Build a StreamWriter implementation. - -Usage: -\code - using namespace Json; - Value value = ...; - StreamWriterBuilder builder; - builder["commentStyle"] = "None"; - builder["indentation"] = " "; // or whatever you like - std::unique_ptr<Json::StreamWriter> writer( - builder.newStreamWriter()); - writer->write(value, &std::cout); - std::cout << std::endl; // add lf and flush -\endcode -*/ -class JSON_API StreamWriterBuilder : public StreamWriter::Factory { -public: - // Note: We use a Json::Value so that we can add data-members to this class - // without a major version bump. - /** Configuration of this builder. - Available settings (case-sensitive): - - "commentStyle": "None" or "All" - - "indentation": "<anything>" - - "enableYAMLCompatibility": false or true - - slightly change the whitespace around colons - - "dropNullPlaceholders": false or true - - Drop the "null" string from the writer's output for nullValues. - Strictly speaking, this is not valid JSON. But when the output is being - fed to a browser's Javascript, it makes for smaller output and the - browser can handle the output just fine. - - "useSpecialFloats": false or true - - If true, outputs non-finite floating point values in the following way: - NaN values as "NaN", positive infinity as "Infinity", and negative infinity - as "-Infinity". - - You can examine 'settings_` yourself - to see the defaults. You can also write and read them just like any - JSON Value. - \sa setDefaults() - */ - Json::Value settings_; - - StreamWriterBuilder(); - ~StreamWriterBuilder() JSONCPP_OVERRIDE; - - /** - * \throw std::exception if something goes wrong (e.g. invalid settings) - */ - StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE; - - /** \return true if 'settings' are legal and consistent; - * otherwise, indicate bad settings via 'invalid'. - */ - bool validate(Json::Value* invalid) const; - /** A simple way to update a specific setting. - */ - Value& operator[](JSONCPP_STRING key); - - /** Called by ctor, but you can use this to reset settings_. - * \pre 'settings' != NULL (but Json::null is fine) - * \remark Defaults: - * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults - */ - static void setDefaults(Json::Value* settings); -}; - -/** \brief Abstract class for writers. - * \deprecated Use StreamWriter. (And really, this is an implementation detail.) - */ -class JSON_API Writer { -public: - virtual ~Writer(); - - virtual JSONCPP_STRING write(const Value& root) = 0; -}; - -/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format - *without formatting (not human friendly). - * - * The JSON document is written in a single line. It is not intended for 'human' - *consumption, - * but may be usefull to support feature such as RPC where bandwith is limited. - * \sa Reader, Value - * \deprecated Use StreamWriterBuilder. - */ -class JSON_API FastWriter : public Writer { - -public: - FastWriter(); - ~FastWriter() JSONCPP_OVERRIDE {} - - void enableYAMLCompatibility(); - - /** \brief Drop the "null" string from the writer's output for nullValues. - * Strictly speaking, this is not valid JSON. But when the output is being - * fed to a browser's Javascript, it makes for smaller output and the - * browser can handle the output just fine. - */ - void dropNullPlaceholders(); - - void omitEndingLineFeed(); - -public: // overridden from Writer - JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; - -private: - void writeValue(const Value& value); - - JSONCPP_STRING document_; - bool yamlCompatiblityEnabled_; - bool dropNullPlaceholders_; - bool omitEndingLineFeed_; -}; - -/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a - *human friendly way. - * - * The rules for line break and indent are as follow: - * - Object value: - * - if empty then print {} without indent and line break - * - if not empty the print '{', line break & indent, print one value per - *line - * and then unindent and line break and print '}'. - * - Array value: - * - if empty then print [] without indent and line break - * - if the array contains no object value, empty array or some other value - *types, - * and all the values fit on one lines, then print the array on a single - *line. - * - otherwise, it the values do not fit on one line, or the array contains - * object or non empty array, then print one value per line. - * - * If the Value have comments then they are outputed according to their - *#CommentPlacement. - * - * \sa Reader, Value, Value::setComment() - * \deprecated Use StreamWriterBuilder. - */ -class JSON_API StyledWriter : public Writer { -public: - StyledWriter(); - ~StyledWriter() JSONCPP_OVERRIDE {} - -public: // overridden from Writer - /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. - * \param root Value to serialize. - * \return String containing the JSON document that represents the root value. - */ - JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; - -private: - void writeValue(const Value& value); - void writeArrayValue(const Value& value); - bool isMultineArray(const Value& value); - void pushValue(const JSONCPP_STRING& value); - void writeIndent(); - void writeWithIndent(const JSONCPP_STRING& value); - void indent(); - void unindent(); - void writeCommentBeforeValue(const Value& root); - void writeCommentAfterValueOnSameLine(const Value& root); - bool hasCommentForValue(const Value& value); - static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); - - typedef std::vector<JSONCPP_STRING> ChildValues; - - ChildValues childValues_; - JSONCPP_STRING document_; - JSONCPP_STRING indentString_; - unsigned int rightMargin_; - unsigned int indentSize_; - bool addChildValues_; -}; - -/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a - human friendly way, - to a stream rather than to a string. - * - * The rules for line break and indent are as follow: - * - Object value: - * - if empty then print {} without indent and line break - * - if not empty the print '{', line break & indent, print one value per - line - * and then unindent and line break and print '}'. - * - Array value: - * - if empty then print [] without indent and line break - * - if the array contains no object value, empty array or some other value - types, - * and all the values fit on one lines, then print the array on a single - line. - * - otherwise, it the values do not fit on one line, or the array contains - * object or non empty array, then print one value per line. - * - * If the Value have comments then they are outputed according to their - #CommentPlacement. - * - * \param indentation Each level will be indented by this amount extra. - * \sa Reader, Value, Value::setComment() - * \deprecated Use StreamWriterBuilder. - */ -class JSON_API StyledStreamWriter { -public: - StyledStreamWriter(JSONCPP_STRING indentation = "\t"); - ~StyledStreamWriter() {} - -public: - /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. - * \param out Stream to write to. (Can be ostringstream, e.g.) - * \param root Value to serialize. - * \note There is no point in deriving from Writer, since write() should not - * return a value. - */ - void write(JSONCPP_OSTREAM& out, const Value& root); - -private: - void writeValue(const Value& value); - void writeArrayValue(const Value& value); - bool isMultineArray(const Value& value); - void pushValue(const JSONCPP_STRING& value); - void writeIndent(); - void writeWithIndent(const JSONCPP_STRING& value); - void indent(); - void unindent(); - void writeCommentBeforeValue(const Value& root); - void writeCommentAfterValueOnSameLine(const Value& root); - bool hasCommentForValue(const Value& value); - static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); - - typedef std::vector<JSONCPP_STRING> ChildValues; - - ChildValues childValues_; - JSONCPP_OSTREAM* document_; - JSONCPP_STRING indentString_; - unsigned int rightMargin_; - JSONCPP_STRING indentation_; - bool addChildValues_ : 1; - bool indented_ : 1; -}; - -#if defined(JSON_HAS_INT64) -JSONCPP_STRING JSON_API valueToString(Int value); -JSONCPP_STRING JSON_API valueToString(UInt value); -#endif // if defined(JSON_HAS_INT64) -JSONCPP_STRING JSON_API valueToString(LargestInt value); -JSONCPP_STRING JSON_API valueToString(LargestUInt value); -JSONCPP_STRING JSON_API valueToString(double value); -JSONCPP_STRING JSON_API valueToString(bool value); -JSONCPP_STRING JSON_API valueToQuotedString(const char* value); - -/// \brief Output using the StyledStreamWriter. -/// \see Json::operator>>() -JSON_API JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM&, const Value& root); - -} // namespace Json - -#pragma pack(pop) - -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(pop) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#endif // JSON_WRITER_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/writer.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/assertions.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED -#define CPPTL_JSON_ASSERTIONS_H_INCLUDED - -#include <stdlib.h> -#include <sstream> - -#if !defined(JSON_IS_AMALGAMATION) -#include "config.h" -#endif // if !defined(JSON_IS_AMALGAMATION) - -/** It should not be possible for a maliciously designed file to - * cause an abort() or seg-fault, so these macros are used only - * for pre-condition violations and internal logic errors. - */ -#if JSON_USE_EXCEPTION - -// @todo <= add detail about condition in exception -# define JSON_ASSERT(condition) \ - {if (!(condition)) {Json::throwLogicError( "assert json failed" );}} - -# define JSON_FAIL_MESSAGE(message) \ - { \ - JSONCPP_OSTRINGSTREAM oss; oss << message; \ - Json::throwLogicError(oss.str()); \ - abort(); \ - } - -#else // JSON_USE_EXCEPTION - -# define JSON_ASSERT(condition) assert(condition) - -// The call to assert() will show the failure message in debug builds. In -// release builds we abort, for a core-dump or debugger. -# define JSON_FAIL_MESSAGE(message) \ - { \ - JSONCPP_OSTRINGSTREAM oss; oss << message; \ - assert(false && oss.str().c_str()); \ - abort(); \ - } - - -#endif - -#define JSON_ASSERT_MESSAGE(condition, message) \ - if (!(condition)) { \ - JSON_FAIL_MESSAGE(message); \ - } - -#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/assertions.h -// ////////////////////////////////////////////////////////////////////// - - - - - -#endif //ifndef JSON_AMALGATED_H_INCLUDED diff --git a/chaos_micro_unit_toolkit/external_lib/jsoncpp.cpp b/chaos_micro_unit_toolkit/external_lib/jsoncpp.cpp deleted file mode 100644 index 79e18b0f71797881aee3889d0bcc636251c0e31f..0000000000000000000000000000000000000000 --- a/chaos_micro_unit_toolkit/external_lib/jsoncpp.cpp +++ /dev/null @@ -1,5348 +0,0 @@ -/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). -/// It is intended to be used with #include "json/json.h" - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - -/* -The JsonCpp library's source code, including accompanying documentation, -tests and demonstration applications, are licensed under the following -conditions... - -Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all -jurisdictions which recognize such a disclaimer. In such jurisdictions, -this software is released into the Public Domain. - -In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and -The JsonCpp Authors, and is released under the terms of the MIT License (see below). - -In jurisdictions which recognize Public Domain property, the user of this -software may choose to accept it either as 1) Public Domain, 2) under the -conditions of the MIT License (see below), or 3) under the terms of dual -Public Domain/MIT License conditions described here, as they choose. - -The MIT License is about as close to Public Domain as a license can get, and is -described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - -The full text of the MIT License follows: - -======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, -modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -======================================================================== -(END LICENSE TEXT) - -The MIT license is compatible with both the GPL and commercial -software, affording one all of the rights of Public Domain with the -minor nuisance of being required to keep the above copyright notice -and license text in the source code. Note also that by accepting the -Public Domain "license" you can re-license your copy using whatever -license you like. - -*/ - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - - - - - - -#include <chaos_micro_unit_toolkit/external_lib/json.h> - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_tool.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED -#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED - - -// Also support old flag NO_LOCALE_SUPPORT -#ifdef NO_LOCALE_SUPPORT -#define JSONCPP_NO_LOCALE_SUPPORT -#endif - -#ifndef JSONCPP_NO_LOCALE_SUPPORT -#include <clocale> -#endif - -/* This header provides common string manipulation support, such as UTF-8, - * portable conversion from/to string... - * - * It is an internal header that must not be exposed. - */ - -namespace Json { -static char getDecimalPoint() { -#ifdef JSONCPP_NO_LOCALE_SUPPORT - return '\0'; -#else - struct lconv* lc = localeconv(); - return lc ? *(lc->decimal_point) : '\0'; -#endif -} - -/// Converts a unicode code-point to UTF-8. -static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) { - JSONCPP_STRING result; - - // based on description from http://en.wikipedia.org/wiki/UTF-8 - - if (cp <= 0x7f) { - result.resize(1); - result[0] = static_cast<char>(cp); - } else if (cp <= 0x7FF) { - result.resize(2); - result[1] = static_cast<char>(0x80 | (0x3f & cp)); - result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6))); - } else if (cp <= 0xFFFF) { - result.resize(3); - result[2] = static_cast<char>(0x80 | (0x3f & cp)); - result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); - result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12))); - } else if (cp <= 0x10FFFF) { - result.resize(4); - result[3] = static_cast<char>(0x80 | (0x3f & cp)); - result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); - result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12))); - result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18))); - } - - return result; -} - -/// Returns true if ch is a control character (in range [1,31]). -static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; } - -enum { - /// Constant that specify the size of the buffer that must be passed to - /// uintToString. - uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1 -}; - -// Defines a char buffer for use with uintToString(). -typedef char UIntToStringBuffer[uintToStringBufferSize]; - -/** Converts an unsigned integer to string. - * @param value Unsigned interger to convert to string - * @param current Input/Output string buffer. - * Must have at least uintToStringBufferSize chars free. - */ -static inline void uintToString(LargestUInt value, char*& current) { - *--current = 0; - do { - *--current = static_cast<char>(value % 10U + static_cast<unsigned>('0')); - value /= 10; - } while (value != 0); -} - -/** Change ',' to '.' everywhere in buffer. - * - * We had a sophisticated way, but it did not work in WinCE. - * @see https://github.com/open-source-parsers/jsoncpp/pull/9 - */ -static inline void fixNumericLocale(char* begin, char* end) { - while (begin < end) { - if (*begin == ',') { - *begin = '.'; - } - ++begin; - } -} - -static inline void fixNumericLocaleInput(char* begin, char* end) { - char decimalPoint = getDecimalPoint(); - if (decimalPoint != '\0' && decimalPoint != '.') { - while (begin < end) { - if (*begin == '.') { - *begin = decimalPoint; - } - ++begin; - } - } -} - -} // namespace Json { - -#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_tool.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_reader.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors -// Copyright (C) 2016 InfoTeCS JSC. All rights reserved. -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include <json/assertions.h> -#include <json/reader.h> -#include <json/value.h> -#include "json_tool.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include <utility> -#include <cstdio> -#include <cassert> -#include <cstring> -#include <istream> -#include <sstream> -#include <memory> -#include <set> -#include <limits> - -#if defined(_MSC_VER) -#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above -#define snprintf sprintf_s -#elif _MSC_VER >= 1900 // VC++ 14.0 and above -#define snprintf std::snprintf -#else -#define snprintf _snprintf -#endif -#elif defined(__ANDROID__) || defined(__QNXNTO__) -#define snprintf snprintf -#elif __cplusplus >= 201103L -#if !defined(__MINGW32__) && !defined(__CYGWIN__) -#define snprintf std::snprintf -#endif -#endif - -#if defined(__QNXNTO__) -#define sscanf std::sscanf -#endif - -#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 -// Disable warning about strdup being deprecated. -#pragma warning(disable : 4996) -#endif - -// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile time to change the stack limit -#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) -#define JSONCPP_DEPRECATED_STACK_LIMIT 1000 -#endif - -static size_t const stackLimit_g = JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue() - -namespace Json { - -#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) -typedef std::unique_ptr<CharReader> CharReaderPtr; -#else -typedef std::auto_ptr<CharReader> CharReaderPtr; -#endif - -// Implementation of class Features -// //////////////////////////////// - -Features::Features() - : allowComments_(true), strictRoot_(false), - allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} - -Features Features::all() { return Features(); } - -Features Features::strictMode() { - Features features; - features.allowComments_ = false; - features.strictRoot_ = true; - features.allowDroppedNullPlaceholders_ = false; - features.allowNumericKeys_ = false; - return features; -} - -// Implementation of class Reader -// //////////////////////////////// - -static bool containsNewLine(Reader::Location begin, Reader::Location end) { - for (; begin < end; ++begin) - if (*begin == '\n' || *begin == '\r') - return true; - return false; -} - -// Class Reader -// ////////////////////////////////////////////////////////////////// - -Reader::Reader() - : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), - lastValue_(), commentsBefore_(), features_(Features::all()), - collectComments_() {} - -Reader::Reader(const Features& features) - : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), - lastValue_(), commentsBefore_(), features_(features), collectComments_() { -} - -bool -Reader::parse(const std::string& document, Value& root, bool collectComments) { - JSONCPP_STRING documentCopy(document.data(), document.data() + document.capacity()); - std::swap(documentCopy, document_); - const char* begin = document_.c_str(); - const char* end = begin + document_.length(); - return parse(begin, end, root, collectComments); -} - -bool Reader::parse(std::istream& sin, Value& root, bool collectComments) { - // std::istream_iterator<char> begin(sin); - // std::istream_iterator<char> end; - // Those would allow streamed input from a file, if parse() were a - // template function. - - // Since JSONCPP_STRING is reference-counted, this at least does not - // create an extra copy. - JSONCPP_STRING doc; - std::getline(sin, doc, (char)EOF); - return parse(doc.data(), doc.data() + doc.size(), root, collectComments); -} - -bool Reader::parse(const char* beginDoc, - const char* endDoc, - Value& root, - bool collectComments) { - if (!features_.allowComments_) { - collectComments = false; - } - - begin_ = beginDoc; - end_ = endDoc; - collectComments_ = collectComments; - current_ = begin_; - lastValueEnd_ = 0; - lastValue_ = 0; - commentsBefore_.clear(); - errors_.clear(); - while (!nodes_.empty()) - nodes_.pop(); - nodes_.push(&root); - - bool successful = readValue(); - Token token; - skipCommentTokens(token); - if (collectComments_ && !commentsBefore_.empty()) - root.setComment(commentsBefore_, commentAfter); - if (features_.strictRoot_) { - if (!root.isArray() && !root.isObject()) { - // Set error location to start of doc, ideally should be first token found - // in doc - token.type_ = tokenError; - token.start_ = beginDoc; - token.end_ = endDoc; - addError( - "A valid JSON document must be either an array or an object value.", - token); - return false; - } - } - return successful; -} - -bool Reader::readValue() { - // readValue() may call itself only if it calls readObject() or ReadArray(). - // These methods execute nodes_.push() just before and nodes_.pop)() just after calling readValue(). - // parse() executes one nodes_.push(), so > instead of >=. - if (nodes_.size() > stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue()."); - - Token token; - skipCommentTokens(token); - bool successful = true; - - if (collectComments_ && !commentsBefore_.empty()) { - currentValue().setComment(commentsBefore_, commentBefore); - commentsBefore_.clear(); - } - - switch (token.type_) { - case tokenObjectBegin: - successful = readObject(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenArrayBegin: - successful = readArray(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenNumber: - successful = decodeNumber(token); - break; - case tokenString: - successful = decodeString(token); - break; - case tokenTrue: - { - Value v(true); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenFalse: - { - Value v(false); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNull: - { - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenArraySeparator: - case tokenObjectEnd: - case tokenArrayEnd: - if (features_.allowDroppedNullPlaceholders_) { - // "Un-read" the current token and mark the current value as a null - // token. - current_--; - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(current_ - begin_ - 1); - currentValue().setOffsetLimit(current_ - begin_); - break; - } // Else, fall through... - default: - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return addError("Syntax error: value, object or array expected.", token); - } - - if (collectComments_) { - lastValueEnd_ = current_; - lastValue_ = ¤tValue(); - } - - return successful; -} - -void Reader::skipCommentTokens(Token& token) { - if (features_.allowComments_) { - do { - readToken(token); - } while (token.type_ == tokenComment); - } else { - readToken(token); - } -} - -bool Reader::readToken(Token& token) { - skipSpaces(); - token.start_ = current_; - Char c = getNextChar(); - bool ok = true; - switch (c) { - case '{': - token.type_ = tokenObjectBegin; - break; - case '}': - token.type_ = tokenObjectEnd; - break; - case '[': - token.type_ = tokenArrayBegin; - break; - case ']': - token.type_ = tokenArrayEnd; - break; - case '"': - token.type_ = tokenString; - ok = readString(); - break; - case '/': - token.type_ = tokenComment; - ok = readComment(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - token.type_ = tokenNumber; - readNumber(); - break; - case 't': - token.type_ = tokenTrue; - ok = match("rue", 3); - break; - case 'f': - token.type_ = tokenFalse; - ok = match("alse", 4); - break; - case 'n': - token.type_ = tokenNull; - ok = match("ull", 3); - break; - case ',': - token.type_ = tokenArraySeparator; - break; - case ':': - token.type_ = tokenMemberSeparator; - break; - case 0: - token.type_ = tokenEndOfStream; - break; - default: - ok = false; - break; - } - if (!ok) - token.type_ = tokenError; - token.end_ = current_; - return true; -} - -void Reader::skipSpaces() { - while (current_ != end_) { - Char c = *current_; - if (c == ' ' || c == '\t' || c == '\r' || c == '\n') - ++current_; - else - break; - } -} - -bool Reader::match(Location pattern, int patternLength) { - if (end_ - current_ < patternLength) - return false; - int index = patternLength; - while (index--) - if (current_[index] != pattern[index]) - return false; - current_ += patternLength; - return true; -} - -bool Reader::readComment() { - Location commentBegin = current_ - 1; - Char c = getNextChar(); - bool successful = false; - if (c == '*') - successful = readCStyleComment(); - else if (c == '/') - successful = readCppStyleComment(); - if (!successful) - return false; - - if (collectComments_) { - CommentPlacement placement = commentBefore; - if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { - if (c != '*' || !containsNewLine(commentBegin, current_)) - placement = commentAfterOnSameLine; - } - - addComment(commentBegin, current_, placement); - } - return true; -} - -static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Location end) { - JSONCPP_STRING normalized; - normalized.reserve(static_cast<size_t>(end - begin)); - Reader::Location current = begin; - while (current != end) { - char c = *current++; - if (c == '\r') { - if (current != end && *current == '\n') - // convert dos EOL - ++current; - // convert Mac EOL - normalized += '\n'; - } else { - normalized += c; - } - } - return normalized; -} - -void -Reader::addComment(Location begin, Location end, CommentPlacement placement) { - assert(collectComments_); - const JSONCPP_STRING& normalized = normalizeEOL(begin, end); - if (placement == commentAfterOnSameLine) { - assert(lastValue_ != 0); - lastValue_->setComment(normalized, placement); - } else { - commentsBefore_ += normalized; - } -} - -bool Reader::readCStyleComment() { - while ((current_ + 1) < end_) { - Char c = getNextChar(); - if (c == '*' && *current_ == '/') - break; - } - return getNextChar() == '/'; -} - -bool Reader::readCppStyleComment() { - while (current_ != end_) { - Char c = getNextChar(); - if (c == '\n') - break; - if (c == '\r') { - // Consume DOS EOL. It will be normalized in addComment. - if (current_ != end_ && *current_ == '\n') - getNextChar(); - // Break on Moc OS 9 EOL. - break; - } - } - return true; -} - -void Reader::readNumber() { - const char *p = current_; - char c = '0'; // stopgap for already consumed character - // integral part - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - // fractional part - if (c == '.') { - c = (current_ = p) < end_ ? *p++ : '\0'; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - } - // exponential part - if (c == 'e' || c == 'E') { - c = (current_ = p) < end_ ? *p++ : '\0'; - if (c == '+' || c == '-') - c = (current_ = p) < end_ ? *p++ : '\0'; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - } -} - -bool Reader::readString() { - Char c = '\0'; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '"') - break; - } - return c == '"'; -} - -bool Reader::readObject(Token& tokenStart) { - Token tokenName; - JSONCPP_STRING name; - Value init(objectValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); - while (readToken(tokenName)) { - bool initialTokenOk = true; - while (tokenName.type_ == tokenComment && initialTokenOk) - initialTokenOk = readToken(tokenName); - if (!initialTokenOk) - break; - if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object - return true; - name.clear(); - if (tokenName.type_ == tokenString) { - if (!decodeString(tokenName, name)) - return recoverFromError(tokenObjectEnd); - } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { - Value numberName; - if (!decodeNumber(tokenName, numberName)) - return recoverFromError(tokenObjectEnd); - name = JSONCPP_STRING(numberName.asCString()); - } else { - break; - } - - Token colon; - if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { - return addErrorAndRecover( - "Missing ':' after object member name", colon, tokenObjectEnd); - } - Value& value = currentValue()[name]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenObjectEnd); - - Token comma; - if (!readToken(comma) || - (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment)) { - return addErrorAndRecover( - "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); - } - bool finalizeTokenOk = true; - while (comma.type_ == tokenComment && finalizeTokenOk) - finalizeTokenOk = readToken(comma); - if (comma.type_ == tokenObjectEnd) - return true; - } - return addErrorAndRecover( - "Missing '}' or object member name", tokenName, tokenObjectEnd); -} - -bool Reader::readArray(Token& tokenStart) { - Value init(arrayValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); - skipSpaces(); - if (current_ != end_ && *current_ == ']') // empty array - { - Token endArray; - readToken(endArray); - return true; - } - int index = 0; - for (;;) { - Value& value = currentValue()[index++]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenArrayEnd); - - Token token; - // Accept Comment after last item in the array. - ok = readToken(token); - while (token.type_ == tokenComment && ok) { - ok = readToken(token); - } - bool badTokenType = - (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); - if (!ok || badTokenType) { - return addErrorAndRecover( - "Missing ',' or ']' in array declaration", token, tokenArrayEnd); - } - if (token.type_ == tokenArrayEnd) - break; - } - return true; -} - -bool Reader::decodeNumber(Token& token) { - Value decoded; - if (!decodeNumber(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeNumber(Token& token, Value& decoded) { - // Attempts to parse the number as an integer. If the number is - // larger than the maximum supported value of an integer then - // we decode the number as a double. - Location current = token.start_; - bool isNegative = *current == '-'; - if (isNegative) - ++current; - // TODO: Help the compiler do the div and mod at compile time or get rid of them. - Value::LargestUInt maxIntegerValue = - isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 - : Value::maxLargestUInt; - Value::LargestUInt threshold = maxIntegerValue / 10; - Value::LargestUInt value = 0; - while (current < token.end_) { - Char c = *current++; - if (c < '0' || c > '9') - return decodeDouble(token, decoded); - Value::UInt digit(static_cast<Value::UInt>(c - '0')); - if (value >= threshold) { - // We've hit or exceeded the max value divided by 10 (rounded down). If - // a) we've only just touched the limit, b) this is the last digit, and - // c) it's small enough to fit in that rounding delta, we're okay. - // Otherwise treat this number as a double to avoid overflow. - if (value > threshold || current != token.end_ || - digit > maxIntegerValue % 10) { - return decodeDouble(token, decoded); - } - } - value = value * 10 + digit; - } - if (isNegative && value == maxIntegerValue) - decoded = Value::minLargestInt; - else if (isNegative) - decoded = -Value::LargestInt(value); - else if (value <= Value::LargestUInt(Value::maxInt)) - decoded = Value::LargestInt(value); - else - decoded = value; - return true; -} - -bool Reader::decodeDouble(Token& token) { - Value decoded; - if (!decodeDouble(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeDouble(Token& token, Value& decoded) { - double value = 0; - JSONCPP_STRING buffer(token.start_, token.end_); - JSONCPP_ISTRINGSTREAM is(buffer); - if (!(is >> value)) - return addError("'" + JSONCPP_STRING(token.start_, token.end_) + - "' is not a number.", - token); - decoded = value; - return true; -} - -bool Reader::decodeString(Token& token) { - JSONCPP_STRING decoded_string; - if (!decodeString(token, decoded_string)) - return false; - Value decoded(decoded_string); - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) { - decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2)); - Location current = token.start_ + 1; // skip '"' - Location end = token.end_ - 1; // do not include '"' - while (current != end) { - Char c = *current++; - if (c == '"') - break; - else if (c == '\\') { - if (current == end) - return addError("Empty escape sequence in string", token, current); - Char escape = *current++; - switch (escape) { - case '"': - decoded += '"'; - break; - case '/': - decoded += '/'; - break; - case '\\': - decoded += '\\'; - break; - case 'b': - decoded += '\b'; - break; - case 'f': - decoded += '\f'; - break; - case 'n': - decoded += '\n'; - break; - case 'r': - decoded += '\r'; - break; - case 't': - decoded += '\t'; - break; - case 'u': { - unsigned int unicode; - if (!decodeUnicodeCodePoint(token, current, end, unicode)) - return false; - decoded += codePointToUTF8(unicode); - } break; - default: - return addError("Bad escape sequence in string", token, current); - } - } else { - decoded += c; - } - } - return true; -} - -bool Reader::decodeUnicodeCodePoint(Token& token, - Location& current, - Location end, - unsigned int& unicode) { - - if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) - return false; - if (unicode >= 0xD800 && unicode <= 0xDBFF) { - // surrogate pairs - if (end - current < 6) - return addError( - "additional six characters expected to parse unicode surrogate pair.", - token, - current); - unsigned int surrogatePair; - if (*(current++) == '\\' && *(current++) == 'u') { - if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { - unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); - } else - return false; - } else - return addError("expecting another \\u token to begin the second half of " - "a unicode surrogate pair", - token, - current); - } - return true; -} - -bool Reader::decodeUnicodeEscapeSequence(Token& token, - Location& current, - Location end, - unsigned int& ret_unicode) { - if (end - current < 4) - return addError( - "Bad unicode escape sequence in string: four digits expected.", - token, - current); - int unicode = 0; - for (int index = 0; index < 4; ++index) { - Char c = *current++; - unicode *= 16; - if (c >= '0' && c <= '9') - unicode += c - '0'; - else if (c >= 'a' && c <= 'f') - unicode += c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - unicode += c - 'A' + 10; - else - return addError( - "Bad unicode escape sequence in string: hexadecimal digit expected.", - token, - current); - } - ret_unicode = static_cast<unsigned int>(unicode); - return true; -} - -bool -Reader::addError(const JSONCPP_STRING& message, Token& token, Location extra) { - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = extra; - errors_.push_back(info); - return false; -} - -bool Reader::recoverFromError(TokenType skipUntilToken) { - size_t const errorCount = errors_.size(); - Token skip; - for (;;) { - if (!readToken(skip)) - errors_.resize(errorCount); // discard errors caused by recovery - if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) - break; - } - errors_.resize(errorCount); - return false; -} - -bool Reader::addErrorAndRecover(const JSONCPP_STRING& message, - Token& token, - TokenType skipUntilToken) { - addError(message, token); - return recoverFromError(skipUntilToken); -} - -Value& Reader::currentValue() { return *(nodes_.top()); } - -Reader::Char Reader::getNextChar() { - if (current_ == end_) - return 0; - return *current_++; -} - -void Reader::getLocationLineAndColumn(Location location, - int& line, - int& column) const { - Location current = begin_; - Location lastLineStart = current; - line = 0; - while (current < location && current != end_) { - Char c = *current++; - if (c == '\r') { - if (*current == '\n') - ++current; - lastLineStart = current; - ++line; - } else if (c == '\n') { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int(location - lastLineStart) + 1; - ++line; -} - -JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const { - int line, column; - getLocationLineAndColumn(location, line, column); - char buffer[18 + 16 + 16 + 1]; - snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); - return buffer; -} - -// Deprecated. Preserved for backward compatibility -JSONCPP_STRING Reader::getFormatedErrorMessages() const { - return getFormattedErrorMessages(); -} - -JSONCPP_STRING Reader::getFormattedErrorMessages() const { - JSONCPP_STRING formattedMessage; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; - formattedMessage += - "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; - formattedMessage += " " + error.message_ + "\n"; - if (error.extra_) - formattedMessage += - "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; - } - return formattedMessage; -} - -std::vector<Reader::StructuredError> Reader::getStructuredErrors() const { - std::vector<Reader::StructuredError> allErrors; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; - Reader::StructuredError structured; - structured.offset_start = error.token_.start_ - begin_; - structured.offset_limit = error.token_.end_ - begin_; - structured.message = error.message_; - allErrors.push_back(structured); - } - return allErrors; -} - -bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) { - ptrdiff_t const length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = end_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = 0; - errors_.push_back(info); - return true; -} - -bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) { - ptrdiff_t const length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length - || extra.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = begin_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = begin_ + extra.getOffsetStart(); - errors_.push_back(info); - return true; -} - -bool Reader::good() const { - return !errors_.size(); -} - -// exact copy of Features -class OurFeatures { -public: - static OurFeatures all(); - bool allowComments_; - bool strictRoot_; - bool allowDroppedNullPlaceholders_; - bool allowNumericKeys_; - bool allowSingleQuotes_; - bool failIfExtra_; - bool rejectDupKeys_; - bool allowSpecialFloats_; - int stackLimit_; -}; // OurFeatures - -// exact copy of Implementation of class Features -// //////////////////////////////// - -OurFeatures OurFeatures::all() { return OurFeatures(); } - -// Implementation of class Reader -// //////////////////////////////// - -// exact copy of Reader, renamed to OurReader -class OurReader { -public: - typedef char Char; - typedef const Char* Location; - struct StructuredError { - ptrdiff_t offset_start; - ptrdiff_t offset_limit; - JSONCPP_STRING message; - }; - - OurReader(OurFeatures const& features); - bool parse(const char* beginDoc, - const char* endDoc, - Value& root, - bool collectComments = true); - JSONCPP_STRING getFormattedErrorMessages() const; - std::vector<StructuredError> getStructuredErrors() const; - bool pushError(const Value& value, const JSONCPP_STRING& message); - bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); - bool good() const; - -private: - OurReader(OurReader const&); // no impl - void operator=(OurReader const&); // no impl - - enum TokenType { - tokenEndOfStream = 0, - tokenObjectBegin, - tokenObjectEnd, - tokenArrayBegin, - tokenArrayEnd, - tokenString, - tokenNumber, - tokenTrue, - tokenFalse, - tokenNull, - tokenNaN, - tokenPosInf, - tokenNegInf, - tokenArraySeparator, - tokenMemberSeparator, - tokenComment, - tokenError - }; - - class Token { - public: - TokenType type_; - Location start_; - Location end_; - }; - - class ErrorInfo { - public: - Token token_; - JSONCPP_STRING message_; - Location extra_; - }; - - typedef std::deque<ErrorInfo> Errors; - - bool readToken(Token& token); - void skipSpaces(); - bool match(Location pattern, int patternLength); - bool readComment(); - bool readCStyleComment(); - bool readCppStyleComment(); - bool readString(); - bool readStringSingleQuote(); - bool readNumber(bool checkInf); - bool readValue(); - bool readObject(Token& token); - bool readArray(Token& token); - bool decodeNumber(Token& token); - bool decodeNumber(Token& token, Value& decoded); - bool decodeString(Token& token); - bool decodeString(Token& token, JSONCPP_STRING& decoded); - bool decodeDouble(Token& token); - bool decodeDouble(Token& token, Value& decoded); - bool decodeUnicodeCodePoint(Token& token, - Location& current, - Location end, - unsigned int& unicode); - bool decodeUnicodeEscapeSequence(Token& token, - Location& current, - Location end, - unsigned int& unicode); - bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); - bool recoverFromError(TokenType skipUntilToken); - bool addErrorAndRecover(const JSONCPP_STRING& message, - Token& token, - TokenType skipUntilToken); - void skipUntilSpace(); - Value& currentValue(); - Char getNextChar(); - void - getLocationLineAndColumn(Location location, int& line, int& column) const; - JSONCPP_STRING getLocationLineAndColumn(Location location) const; - void addComment(Location begin, Location end, CommentPlacement placement); - void skipCommentTokens(Token& token); - - typedef std::stack<Value*> Nodes; - Nodes nodes_; - Errors errors_; - JSONCPP_STRING document_; - Location begin_; - Location end_; - Location current_; - Location lastValueEnd_; - Value* lastValue_; - JSONCPP_STRING commentsBefore_; - - OurFeatures const features_; - bool collectComments_; -}; // OurReader - -// complete copy of Read impl, for OurReader - -OurReader::OurReader(OurFeatures const& features) - : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), - lastValue_(), commentsBefore_(), - features_(features), collectComments_() { -} - -bool OurReader::parse(const char* beginDoc, - const char* endDoc, - Value& root, - bool collectComments) { - if (!features_.allowComments_) { - collectComments = false; - } - - begin_ = beginDoc; - end_ = endDoc; - collectComments_ = collectComments; - current_ = begin_; - lastValueEnd_ = 0; - lastValue_ = 0; - commentsBefore_.clear(); - errors_.clear(); - while (!nodes_.empty()) - nodes_.pop(); - nodes_.push(&root); - - bool successful = readValue(); - Token token; - skipCommentTokens(token); - if (features_.failIfExtra_) { - if ((features_.strictRoot_ || token.type_ != tokenError) && token.type_ != tokenEndOfStream) { - addError("Extra non-whitespace after JSON value.", token); - return false; - } - } - if (collectComments_ && !commentsBefore_.empty()) - root.setComment(commentsBefore_, commentAfter); - if (features_.strictRoot_) { - if (!root.isArray() && !root.isObject()) { - // Set error location to start of doc, ideally should be first token found - // in doc - token.type_ = tokenError; - token.start_ = beginDoc; - token.end_ = endDoc; - addError( - "A valid JSON document must be either an array or an object value.", - token); - return false; - } - } - return successful; -} - -bool OurReader::readValue() { - // To preserve the old behaviour we cast size_t to int. - if (static_cast<int>(nodes_.size()) > features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); - Token token; - skipCommentTokens(token); - bool successful = true; - - if (collectComments_ && !commentsBefore_.empty()) { - currentValue().setComment(commentsBefore_, commentBefore); - commentsBefore_.clear(); - } - - switch (token.type_) { - case tokenObjectBegin: - successful = readObject(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenArrayBegin: - successful = readArray(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenNumber: - successful = decodeNumber(token); - break; - case tokenString: - successful = decodeString(token); - break; - case tokenTrue: - { - Value v(true); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenFalse: - { - Value v(false); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNull: - { - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNaN: - { - Value v(std::numeric_limits<double>::quiet_NaN()); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenPosInf: - { - Value v(std::numeric_limits<double>::infinity()); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNegInf: - { - Value v(-std::numeric_limits<double>::infinity()); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenArraySeparator: - case tokenObjectEnd: - case tokenArrayEnd: - if (features_.allowDroppedNullPlaceholders_) { - // "Un-read" the current token and mark the current value as a null - // token. - current_--; - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(current_ - begin_ - 1); - currentValue().setOffsetLimit(current_ - begin_); - break; - } // else, fall through ... - default: - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return addError("Syntax error: value, object or array expected.", token); - } - - if (collectComments_) { - lastValueEnd_ = current_; - lastValue_ = ¤tValue(); - } - - return successful; -} - -void OurReader::skipCommentTokens(Token& token) { - if (features_.allowComments_) { - do { - readToken(token); - } while (token.type_ == tokenComment); - } else { - readToken(token); - } -} - -bool OurReader::readToken(Token& token) { - skipSpaces(); - token.start_ = current_; - Char c = getNextChar(); - bool ok = true; - switch (c) { - case '{': - token.type_ = tokenObjectBegin; - break; - case '}': - token.type_ = tokenObjectEnd; - break; - case '[': - token.type_ = tokenArrayBegin; - break; - case ']': - token.type_ = tokenArrayEnd; - break; - case '"': - token.type_ = tokenString; - ok = readString(); - break; - case '\'': - if (features_.allowSingleQuotes_) { - token.type_ = tokenString; - ok = readStringSingleQuote(); - break; - } // else continue - case '/': - token.type_ = tokenComment; - ok = readComment(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - token.type_ = tokenNumber; - readNumber(false); - break; - case '-': - if (readNumber(true)) { - token.type_ = tokenNumber; - } else { - token.type_ = tokenNegInf; - ok = features_.allowSpecialFloats_ && match("nfinity", 7); - } - break; - case 't': - token.type_ = tokenTrue; - ok = match("rue", 3); - break; - case 'f': - token.type_ = tokenFalse; - ok = match("alse", 4); - break; - case 'n': - token.type_ = tokenNull; - ok = match("ull", 3); - break; - case 'N': - if (features_.allowSpecialFloats_) { - token.type_ = tokenNaN; - ok = match("aN", 2); - } else { - ok = false; - } - break; - case 'I': - if (features_.allowSpecialFloats_) { - token.type_ = tokenPosInf; - ok = match("nfinity", 7); - } else { - ok = false; - } - break; - case ',': - token.type_ = tokenArraySeparator; - break; - case ':': - token.type_ = tokenMemberSeparator; - break; - case 0: - token.type_ = tokenEndOfStream; - break; - default: - ok = false; - break; - } - if (!ok) - token.type_ = tokenError; - token.end_ = current_; - return true; -} - -void OurReader::skipSpaces() { - while (current_ != end_) { - Char c = *current_; - if (c == ' ' || c == '\t' || c == '\r' || c == '\n') - ++current_; - else - break; - } -} - -bool OurReader::match(Location pattern, int patternLength) { - if (end_ - current_ < patternLength) - return false; - int index = patternLength; - while (index--) - if (current_[index] != pattern[index]) - return false; - current_ += patternLength; - return true; -} - -bool OurReader::readComment() { - Location commentBegin = current_ - 1; - Char c = getNextChar(); - bool successful = false; - if (c == '*') - successful = readCStyleComment(); - else if (c == '/') - successful = readCppStyleComment(); - if (!successful) - return false; - - if (collectComments_) { - CommentPlacement placement = commentBefore; - if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { - if (c != '*' || !containsNewLine(commentBegin, current_)) - placement = commentAfterOnSameLine; - } - - addComment(commentBegin, current_, placement); - } - return true; -} - -void -OurReader::addComment(Location begin, Location end, CommentPlacement placement) { - assert(collectComments_); - const JSONCPP_STRING& normalized = normalizeEOL(begin, end); - if (placement == commentAfterOnSameLine) { - assert(lastValue_ != 0); - lastValue_->setComment(normalized, placement); - } else { - commentsBefore_ += normalized; - } -} - -bool OurReader::readCStyleComment() { - while ((current_ + 1) < end_) { - Char c = getNextChar(); - if (c == '*' && *current_ == '/') - break; - } - return getNextChar() == '/'; -} - -bool OurReader::readCppStyleComment() { - while (current_ != end_) { - Char c = getNextChar(); - if (c == '\n') - break; - if (c == '\r') { - // Consume DOS EOL. It will be normalized in addComment. - if (current_ != end_ && *current_ == '\n') - getNextChar(); - // Break on Moc OS 9 EOL. - break; - } - } - return true; -} - -bool OurReader::readNumber(bool checkInf) { - const char *p = current_; - if (checkInf && p != end_ && *p == 'I') { - current_ = ++p; - return false; - } - char c = '0'; // stopgap for already consumed character - // integral part - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - // fractional part - if (c == '.') { - c = (current_ = p) < end_ ? *p++ : '\0'; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - } - // exponential part - if (c == 'e' || c == 'E') { - c = (current_ = p) < end_ ? *p++ : '\0'; - if (c == '+' || c == '-') - c = (current_ = p) < end_ ? *p++ : '\0'; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - } - return true; -} -bool OurReader::readString() { - Char c = 0; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '"') - break; - } - return c == '"'; -} - - -bool OurReader::readStringSingleQuote() { - Char c = 0; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '\'') - break; - } - return c == '\''; -} - -bool OurReader::readObject(Token& tokenStart) { - Token tokenName; - JSONCPP_STRING name; - Value init(objectValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); - while (readToken(tokenName)) { - bool initialTokenOk = true; - while (tokenName.type_ == tokenComment && initialTokenOk) - initialTokenOk = readToken(tokenName); - if (!initialTokenOk) - break; - if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object - return true; - name.clear(); - if (tokenName.type_ == tokenString) { - if (!decodeString(tokenName, name)) - return recoverFromError(tokenObjectEnd); - } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { - Value numberName; - if (!decodeNumber(tokenName, numberName)) - return recoverFromError(tokenObjectEnd); - name = numberName.asString(); - } else { - break; - } - - Token colon; - if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { - return addErrorAndRecover( - "Missing ':' after object member name", colon, tokenObjectEnd); - } - if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30"); - if (features_.rejectDupKeys_ && currentValue().isMember(name)) { - JSONCPP_STRING msg = "Duplicate key: '" + name + "'"; - return addErrorAndRecover( - msg, tokenName, tokenObjectEnd); - } - Value& value = currentValue()[name]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenObjectEnd); - - Token comma; - if (!readToken(comma) || - (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment)) { - return addErrorAndRecover( - "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); - } - bool finalizeTokenOk = true; - while (comma.type_ == tokenComment && finalizeTokenOk) - finalizeTokenOk = readToken(comma); - if (comma.type_ == tokenObjectEnd) - return true; - } - return addErrorAndRecover( - "Missing '}' or object member name", tokenName, tokenObjectEnd); -} - -bool OurReader::readArray(Token& tokenStart) { - Value init(arrayValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); - skipSpaces(); - if (current_ != end_ && *current_ == ']') // empty array - { - Token endArray; - readToken(endArray); - return true; - } - int index = 0; - for (;;) { - Value& value = currentValue()[index++]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenArrayEnd); - - Token token; - // Accept Comment after last item in the array. - ok = readToken(token); - while (token.type_ == tokenComment && ok) { - ok = readToken(token); - } - bool badTokenType = - (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); - if (!ok || badTokenType) { - return addErrorAndRecover( - "Missing ',' or ']' in array declaration", token, tokenArrayEnd); - } - if (token.type_ == tokenArrayEnd) - break; - } - return true; -} - -bool OurReader::decodeNumber(Token& token) { - Value decoded; - if (!decodeNumber(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeNumber(Token& token, Value& decoded) { - // Attempts to parse the number as an integer. If the number is - // larger than the maximum supported value of an integer then - // we decode the number as a double. - Location current = token.start_; - bool isNegative = *current == '-'; - if (isNegative) - ++current; - // TODO: Help the compiler do the div and mod at compile time or get rid of them. - Value::LargestUInt maxIntegerValue = - isNegative ? Value::LargestUInt(-Value::minLargestInt) - : Value::maxLargestUInt; - Value::LargestUInt threshold = maxIntegerValue / 10; - Value::LargestUInt value = 0; - while (current < token.end_) { - Char c = *current++; - if (c < '0' || c > '9') - return decodeDouble(token, decoded); - Value::UInt digit(static_cast<Value::UInt>(c - '0')); - if (value >= threshold) { - // We've hit or exceeded the max value divided by 10 (rounded down). If - // a) we've only just touched the limit, b) this is the last digit, and - // c) it's small enough to fit in that rounding delta, we're okay. - // Otherwise treat this number as a double to avoid overflow. - if (value > threshold || current != token.end_ || - digit > maxIntegerValue % 10) { - return decodeDouble(token, decoded); - } - } - value = value * 10 + digit; - } - if (isNegative) - decoded = -Value::LargestInt(value); - else if (value <= Value::LargestUInt(Value::maxInt)) - decoded = Value::LargestInt(value); - else - decoded = value; - return true; -} - -bool OurReader::decodeDouble(Token& token) { - Value decoded; - if (!decodeDouble(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeDouble(Token& token, Value& decoded) { - double value = 0; - const int bufferSize = 32; - int count; - ptrdiff_t const length = token.end_ - token.start_; - - // Sanity check to avoid buffer overflow exploits. - if (length < 0) { - return addError("Unable to parse token length", token); - } - size_t const ulength = static_cast<size_t>(length); - - // Avoid using a string constant for the format control string given to - // sscanf, as this can cause hard to debug crashes on OS X. See here for more - // info: - // - // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html - char format[] = "%lf"; - - if (length <= bufferSize) { - Char buffer[bufferSize + 1]; - memcpy(buffer, token.start_, ulength); - buffer[length] = 0; - fixNumericLocaleInput(buffer, buffer + length); - count = sscanf(buffer, format, &value); - } else { - JSONCPP_STRING buffer(token.start_, token.end_); - count = sscanf(buffer.c_str(), format, &value); - } - - if (count != 1) - return addError("'" + JSONCPP_STRING(token.start_, token.end_) + - "' is not a number.", - token); - decoded = value; - return true; -} - -bool OurReader::decodeString(Token& token) { - JSONCPP_STRING decoded_string; - if (!decodeString(token, decoded_string)) - return false; - Value decoded(decoded_string); - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) { - decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2)); - Location current = token.start_ + 1; // skip '"' - Location end = token.end_ - 1; // do not include '"' - while (current != end) { - Char c = *current++; - if (c == '"') - break; - else if (c == '\\') { - if (current == end) - return addError("Empty escape sequence in string", token, current); - Char escape = *current++; - switch (escape) { - case '"': - decoded += '"'; - break; - case '/': - decoded += '/'; - break; - case '\\': - decoded += '\\'; - break; - case 'b': - decoded += '\b'; - break; - case 'f': - decoded += '\f'; - break; - case 'n': - decoded += '\n'; - break; - case 'r': - decoded += '\r'; - break; - case 't': - decoded += '\t'; - break; - case 'u': { - unsigned int unicode; - if (!decodeUnicodeCodePoint(token, current, end, unicode)) - return false; - decoded += codePointToUTF8(unicode); - } break; - default: - return addError("Bad escape sequence in string", token, current); - } - } else { - decoded += c; - } - } - return true; -} - -bool OurReader::decodeUnicodeCodePoint(Token& token, - Location& current, - Location end, - unsigned int& unicode) { - - if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) - return false; - if (unicode >= 0xD800 && unicode <= 0xDBFF) { - // surrogate pairs - if (end - current < 6) - return addError( - "additional six characters expected to parse unicode surrogate pair.", - token, - current); - unsigned int surrogatePair; - if (*(current++) == '\\' && *(current++) == 'u') { - if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { - unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); - } else - return false; - } else - return addError("expecting another \\u token to begin the second half of " - "a unicode surrogate pair", - token, - current); - } - return true; -} - -bool OurReader::decodeUnicodeEscapeSequence(Token& token, - Location& current, - Location end, - unsigned int& ret_unicode) { - if (end - current < 4) - return addError( - "Bad unicode escape sequence in string: four digits expected.", - token, - current); - int unicode = 0; - for (int index = 0; index < 4; ++index) { - Char c = *current++; - unicode *= 16; - if (c >= '0' && c <= '9') - unicode += c - '0'; - else if (c >= 'a' && c <= 'f') - unicode += c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - unicode += c - 'A' + 10; - else - return addError( - "Bad unicode escape sequence in string: hexadecimal digit expected.", - token, - current); - } - ret_unicode = static_cast<unsigned int>(unicode); - return true; -} - -bool -OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) { - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = extra; - errors_.push_back(info); - return false; -} - -bool OurReader::recoverFromError(TokenType skipUntilToken) { - size_t errorCount = errors_.size(); - Token skip; - for (;;) { - if (!readToken(skip)) - errors_.resize(errorCount); // discard errors caused by recovery - if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) - break; - } - errors_.resize(errorCount); - return false; -} - -bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message, - Token& token, - TokenType skipUntilToken) { - addError(message, token); - return recoverFromError(skipUntilToken); -} - -Value& OurReader::currentValue() { return *(nodes_.top()); } - -OurReader::Char OurReader::getNextChar() { - if (current_ == end_) - return 0; - return *current_++; -} - -void OurReader::getLocationLineAndColumn(Location location, - int& line, - int& column) const { - Location current = begin_; - Location lastLineStart = current; - line = 0; - while (current < location && current != end_) { - Char c = *current++; - if (c == '\r') { - if (*current == '\n') - ++current; - lastLineStart = current; - ++line; - } else if (c == '\n') { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int(location - lastLineStart) + 1; - ++line; -} - -JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const { - int line, column; - getLocationLineAndColumn(location, line, column); - char buffer[18 + 16 + 16 + 1]; - snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); - return buffer; -} - -JSONCPP_STRING OurReader::getFormattedErrorMessages() const { - JSONCPP_STRING formattedMessage; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; - formattedMessage += - "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; - formattedMessage += " " + error.message_ + "\n"; - if (error.extra_) - formattedMessage += - "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; - } - return formattedMessage; -} - -std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const { - std::vector<OurReader::StructuredError> allErrors; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; - OurReader::StructuredError structured; - structured.offset_start = error.token_.start_ - begin_; - structured.offset_limit = error.token_.end_ - begin_; - structured.message = error.message_; - allErrors.push_back(structured); - } - return allErrors; -} - -bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) { - ptrdiff_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = end_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = 0; - errors_.push_back(info); - return true; -} - -bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) { - ptrdiff_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length - || extra.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = begin_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = begin_ + extra.getOffsetStart(); - errors_.push_back(info); - return true; -} - -bool OurReader::good() const { - return !errors_.size(); -} - - -class OurCharReader : public CharReader { - bool const collectComments_; - OurReader reader_; -public: - OurCharReader( - bool collectComments, - OurFeatures const& features) - : collectComments_(collectComments) - , reader_(features) - {} - bool parse( - char const* beginDoc, char const* endDoc, - Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE { - bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); - if (errs) { - *errs = reader_.getFormattedErrorMessages(); - } - return ok; - } -}; - -CharReaderBuilder::CharReaderBuilder() -{ - setDefaults(&settings_); -} -CharReaderBuilder::~CharReaderBuilder() -{} -CharReader* CharReaderBuilder::newCharReader() const -{ - bool collectComments = settings_["collectComments"].asBool(); - OurFeatures features = OurFeatures::all(); - features.allowComments_ = settings_["allowComments"].asBool(); - features.strictRoot_ = settings_["strictRoot"].asBool(); - features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool(); - features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); - features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); - features.stackLimit_ = settings_["stackLimit"].asInt(); - features.failIfExtra_ = settings_["failIfExtra"].asBool(); - features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); - features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); - return new OurCharReader(collectComments, features); -} -static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys) -{ - valid_keys->clear(); - valid_keys->insert("collectComments"); - valid_keys->insert("allowComments"); - valid_keys->insert("strictRoot"); - valid_keys->insert("allowDroppedNullPlaceholders"); - valid_keys->insert("allowNumericKeys"); - valid_keys->insert("allowSingleQuotes"); - valid_keys->insert("stackLimit"); - valid_keys->insert("failIfExtra"); - valid_keys->insert("rejectDupKeys"); - valid_keys->insert("allowSpecialFloats"); -} -bool CharReaderBuilder::validate(Json::Value* invalid) const -{ - Json::Value my_invalid; - if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL - Json::Value& inv = *invalid; - std::set<JSONCPP_STRING> valid_keys; - getValidReaderKeys(&valid_keys); - Value::Members keys = settings_.getMemberNames(); - size_t n = keys.size(); - for (size_t i = 0; i < n; ++i) { - JSONCPP_STRING const& key = keys[i]; - if (valid_keys.find(key) == valid_keys.end()) { - inv[key] = settings_[key]; - } - } - return 0u == inv.size(); -} -Value& CharReaderBuilder::operator[](JSONCPP_STRING key) -{ - return settings_[key]; -} -// static -void CharReaderBuilder::strictMode(Json::Value* settings) -{ -//! [CharReaderBuilderStrictMode] - (*settings)["allowComments"] = false; - (*settings)["strictRoot"] = true; - (*settings)["allowDroppedNullPlaceholders"] = false; - (*settings)["allowNumericKeys"] = false; - (*settings)["allowSingleQuotes"] = false; - (*settings)["stackLimit"] = 1000; - (*settings)["failIfExtra"] = true; - (*settings)["rejectDupKeys"] = true; - (*settings)["allowSpecialFloats"] = false; -//! [CharReaderBuilderStrictMode] -} -// static -void CharReaderBuilder::setDefaults(Json::Value* settings) -{ -//! [CharReaderBuilderDefaults] - (*settings)["collectComments"] = true; - (*settings)["allowComments"] = true; - (*settings)["strictRoot"] = false; - (*settings)["allowDroppedNullPlaceholders"] = false; - (*settings)["allowNumericKeys"] = false; - (*settings)["allowSingleQuotes"] = false; - (*settings)["stackLimit"] = 1000; - (*settings)["failIfExtra"] = false; - (*settings)["rejectDupKeys"] = false; - (*settings)["allowSpecialFloats"] = false; -//! [CharReaderBuilderDefaults] -} - -////////////////////////////////// -// global functions - -bool parseFromStream( - CharReader::Factory const& fact, JSONCPP_ISTREAM& sin, - Value* root, JSONCPP_STRING* errs) -{ - JSONCPP_OSTRINGSTREAM ssin; - ssin << sin.rdbuf(); - JSONCPP_STRING doc = ssin.str(); - char const* begin = doc.data(); - char const* end = begin + doc.size(); - // Note that we do not actually need a null-terminator. - CharReaderPtr const reader(fact.newCharReader()); - return reader->parse(begin, end, root, errs); -} - -JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) { - CharReaderBuilder b; - JSONCPP_STRING errs; - bool ok = parseFromStream(b, sin, &root, &errs); - if (!ok) { - fprintf(stderr, - "Error from reader: %s", - errs.c_str()); - - throwRuntimeError(errs); - } - return sin; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_reader.cpp -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_valueiterator.inl -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -// included by json_value.cpp - -namespace Json { - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueIteratorBase -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueIteratorBase::ValueIteratorBase() - : current_(), isNull_(true) { -} - -ValueIteratorBase::ValueIteratorBase( - const Value::ObjectValues::iterator& current) - : current_(current), isNull_(false) {} - -Value& ValueIteratorBase::deref() const { - return current_->second; -} - -void ValueIteratorBase::increment() { - ++current_; -} - -void ValueIteratorBase::decrement() { - --current_; -} - -ValueIteratorBase::difference_type -ValueIteratorBase::computeDistance(const SelfType& other) const { -#ifdef JSON_USE_CPPTL_SMALLMAP - return other.current_ - current_; -#else - // Iterator for null value are initialized using the default - // constructor, which initialize current_ to the default - // std::map::iterator. As begin() and end() are two instance - // of the default std::map::iterator, they can not be compared. - // To allow this, we handle this comparison specifically. - if (isNull_ && other.isNull_) { - return 0; - } - - // Usage of std::distance is not portable (does not compile with Sun Studio 12 - // RogueWave STL, - // which is the one used by default). - // Using a portable hand-made version for non random iterator instead: - // return difference_type( std::distance( current_, other.current_ ) ); - difference_type myDistance = 0; - for (Value::ObjectValues::iterator it = current_; it != other.current_; - ++it) { - ++myDistance; - } - return myDistance; -#endif -} - -bool ValueIteratorBase::isEqual(const SelfType& other) const { - if (isNull_) { - return other.isNull_; - } - return current_ == other.current_; -} - -void ValueIteratorBase::copy(const SelfType& other) { - current_ = other.current_; - isNull_ = other.isNull_; -} - -Value ValueIteratorBase::key() const { - const Value::CZString czstring = (*current_).first; - if (czstring.data()) { - if (czstring.isStaticString()) - return Value(StaticString(czstring.data())); - return Value(czstring.data(), czstring.data() + czstring.length()); - } - return Value(czstring.index()); -} - -UInt ValueIteratorBase::index() const { - const Value::CZString czstring = (*current_).first; - if (!czstring.data()) - return czstring.index(); - return Value::UInt(-1); -} - -JSONCPP_STRING ValueIteratorBase::name() const { - char const* keey; - char const* end; - keey = memberName(&end); - if (!keey) return JSONCPP_STRING(); - return JSONCPP_STRING(keey, end); -} - -char const* ValueIteratorBase::memberName() const { - const char* cname = (*current_).first.data(); - return cname ? cname : ""; -} - -char const* ValueIteratorBase::memberName(char const** end) const { - const char* cname = (*current_).first.data(); - if (!cname) { - *end = NULL; - return NULL; - } - *end = cname + (*current_).first.length(); - return cname; -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueConstIterator -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueConstIterator::ValueConstIterator() {} - -ValueConstIterator::ValueConstIterator( - const Value::ObjectValues::iterator& current) - : ValueIteratorBase(current) {} - -ValueConstIterator::ValueConstIterator(ValueIterator const& other) - : ValueIteratorBase(other) {} - -ValueConstIterator& ValueConstIterator:: -operator=(const ValueIteratorBase& other) { - copy(other); - return *this; -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueIterator -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueIterator::ValueIterator() {} - -ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) - : ValueIteratorBase(current) {} - -ValueIterator::ValueIterator(const ValueConstIterator& other) - : ValueIteratorBase(other) { - throwRuntimeError("ConstIterator to Iterator should never be allowed."); -} - -ValueIterator::ValueIterator(const ValueIterator& other) - : ValueIteratorBase(other) {} - -ValueIterator& ValueIterator::operator=(const SelfType& other) { - copy(other); - return *this; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_valueiterator.inl -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_value.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include <json/assertions.h> -#include <json/value.h> -#include <json/writer.h> -#endif // if !defined(JSON_IS_AMALGAMATION) -#include <math.h> -#include <sstream> -#include <utility> -#include <cstring> -#include <cassert> -#ifdef JSON_USE_CPPTL -#include <cpptl/conststring.h> -#endif -#include <cstddef> // size_t -#include <algorithm> // min() - -#define JSON_ASSERT_UNREACHABLE assert(false) - -namespace Json { - -// This is a walkaround to avoid the static initialization of Value::null. -// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of -// 8 (instead of 4) as a bit of future-proofing. -#if defined(__ARMEL__) -#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) -#else -#define ALIGNAS(byte_alignment) -#endif -//static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; -//const unsigned char& kNullRef = kNull[0]; -//const Value& Value::null = reinterpret_cast<const Value&>(kNullRef); -//const Value& Value::nullRef = null; - -// static -Value const& Value::nullSingleton() -{ - static Value const nullStatic; - return nullStatic; -} - -// for backwards compatibility, we'll leave these global references around, but DO NOT -// use them in JSONCPP library code any more! -Value const& Value::null = Value::nullSingleton(); -Value const& Value::nullRef = Value::nullSingleton(); - -const Int Value::minInt = Int(~(UInt(-1) / 2)); -const Int Value::maxInt = Int(UInt(-1) / 2); -const UInt Value::maxUInt = UInt(-1); -#if defined(JSON_HAS_INT64) -const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2)); -const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2); -const UInt64 Value::maxUInt64 = UInt64(-1); -// The constant is hard-coded because some compiler have trouble -// converting Value::maxUInt64 to a double correctly (AIX/xlC). -// Assumes that UInt64 is a 64 bits integer. -static const double maxUInt64AsDouble = 18446744073709551615.0; -#endif // defined(JSON_HAS_INT64) -const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); -const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); -const LargestUInt Value::maxLargestUInt = LargestUInt(-1); - -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) -template <typename T, typename U> -static inline bool InRange(double d, T min, U max) { - // The casts can lose precision, but we are looking only for - // an approximate range. Might fail on edge cases though. ~cdunn - //return d >= static_cast<double>(min) && d <= static_cast<double>(max); - return d >= min && d <= max; -} -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) -static inline double integerToDouble(Json::UInt64 value) { - return static_cast<double>(Int64(value / 2)) * 2.0 + static_cast<double>(Int64(value & 1)); -} - -template <typename T> static inline double integerToDouble(T value) { - return static_cast<double>(value); -} - -template <typename T, typename U> -static inline bool InRange(double d, T min, U max) { - return d >= integerToDouble(min) && d <= integerToDouble(max); -} -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - -/** Duplicates the specified string value. - * @param value Pointer to the string to duplicate. Must be zero-terminated if - * length is "unknown". - * @param length Length of the value. if equals to unknown, then it will be - * computed using strlen(value). - * @return Pointer on the duplicate instance of string. - */ -static inline char* duplicateStringValue(const char* value, - size_t length) -{ - // Avoid an integer overflow in the call to malloc below by limiting length - // to a sane value. - if (length >= static_cast<size_t>(Value::maxInt)) - length = Value::maxInt - 1; - - char* newString = static_cast<char*>(malloc(length + 1)); - if (newString == NULL) { - throwRuntimeError( - "in Json::Value::duplicateStringValue(): " - "Failed to allocate string value buffer"); - } - memcpy(newString, value, length); - newString[length] = 0; - return newString; -} - -/* Record the length as a prefix. - */ -static inline char* duplicateAndPrefixStringValue( - const char* value, - unsigned int length) -{ - // Avoid an integer overflow in the call to malloc below by limiting length - // to a sane value. - JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) - sizeof(unsigned) - 1U, - "in Json::Value::duplicateAndPrefixStringValue(): " - "length too big for prefixing"); - unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U; - char* newString = static_cast<char*>(malloc(actualLength)); - if (newString == 0) { - throwRuntimeError( - "in Json::Value::duplicateAndPrefixStringValue(): " - "Failed to allocate string value buffer"); - } - *reinterpret_cast<unsigned*>(newString) = length; - memcpy(newString + sizeof(unsigned), value, length); - newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later - return newString; -} -inline static void decodePrefixedString( - bool isPrefixed, char const* prefixed, - unsigned* length, char const** value) -{ - if (!isPrefixed) { - *length = static_cast<unsigned>(strlen(prefixed)); - *value = prefixed; - } else { - *length = *reinterpret_cast<unsigned const*>(prefixed); - *value = prefixed + sizeof(unsigned); - } -} -/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue(). - */ -#if JSONCPP_USING_SECURE_MEMORY -static inline void releasePrefixedStringValue(char* value) { - unsigned length = 0; - char const* valueDecoded; - decodePrefixedString(true, value, &length, &valueDecoded); - size_t const size = sizeof(unsigned) + length + 1U; - memset(value, 0, size); - free(value); -} -static inline void releaseStringValue(char* value, unsigned length) { - // length==0 => we allocated the strings memory - size_t size = (length==0) ? strlen(value) : length; - memset(value, 0, size); - free(value); -} -#else // !JSONCPP_USING_SECURE_MEMORY -static inline void releasePrefixedStringValue(char* value) { - free(value); -} -static inline void releaseStringValue(char* value, unsigned) { - free(value); -} -#endif // JSONCPP_USING_SECURE_MEMORY - -} // namespace Json - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ValueInternals... -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -#if !defined(JSON_IS_AMALGAMATION) - -#include "json_valueiterator.inl" -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { - -Exception::Exception(JSONCPP_STRING const& msg) - : msg_(msg) -{} -Exception::~Exception() JSONCPP_NOEXCEPT -{} -char const* Exception::what() const JSONCPP_NOEXCEPT -{ - return msg_.c_str(); -} -RuntimeError::RuntimeError(JSONCPP_STRING const& msg) - : Exception(msg) -{} -LogicError::LogicError(JSONCPP_STRING const& msg) - : Exception(msg) -{} -JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) -{ - throw RuntimeError(msg); -} -JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) -{ - throw LogicError(msg); -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::CommentInfo -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -Value::CommentInfo::CommentInfo() : comment_(0) -{} - -Value::CommentInfo::~CommentInfo() { - if (comment_) - releaseStringValue(comment_, 0u); -} - -void Value::CommentInfo::setComment(const char* text, size_t len) { - if (comment_) { - releaseStringValue(comment_, 0u); - comment_ = 0; - } - JSON_ASSERT(text != 0); - JSON_ASSERT_MESSAGE( - text[0] == '\0' || text[0] == '/', - "in Json::Value::setComment(): Comments must start with /"); - // It seems that /**/ style comments are acceptable as well. - comment_ = duplicateStringValue(text, len); -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::CZString -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -// Notes: policy_ indicates if the string was allocated when -// a string is stored. - -Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {} - -Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate) - : cstr_(str) { - // allocate != duplicate - storage_.policy_ = allocate & 0x3; - storage_.length_ = ulength & 0x3FFFFFFF; -} - -Value::CZString::CZString(const CZString& other) { - cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != 0 - ? duplicateStringValue(other.cstr_, other.storage_.length_) - : other.cstr_); - storage_.policy_ = static_cast<unsigned>(other.cstr_ - ? (static_cast<DuplicationPolicy>(other.storage_.policy_) == noDuplication - ? noDuplication : duplicate) - : static_cast<DuplicationPolicy>(other.storage_.policy_)) & 3U; - storage_.length_ = other.storage_.length_; -} - -#if JSON_HAS_RVALUE_REFERENCES -Value::CZString::CZString(CZString&& other) - : cstr_(other.cstr_), index_(other.index_) { - other.cstr_ = nullptr; -} -#endif - -Value::CZString::~CZString() { - if (cstr_ && storage_.policy_ == duplicate) { - releaseStringValue(const_cast<char*>(cstr_), storage_.length_ + 1u); //+1 for null terminating character for sake of completeness but not actually necessary - } -} - -void Value::CZString::swap(CZString& other) { - std::swap(cstr_, other.cstr_); - std::swap(index_, other.index_); -} - -Value::CZString& Value::CZString::operator=(const CZString& other) { - cstr_ = other.cstr_; - index_ = other.index_; - return *this; -} - -#if JSON_HAS_RVALUE_REFERENCES -Value::CZString& Value::CZString::operator=(CZString&& other) { - cstr_ = other.cstr_; - index_ = other.index_; - other.cstr_ = nullptr; - return *this; -} -#endif - -bool Value::CZString::operator<(const CZString& other) const { - if (!cstr_) return index_ < other.index_; - //return strcmp(cstr_, other.cstr_) < 0; - // Assume both are strings. - unsigned this_len = this->storage_.length_; - unsigned other_len = other.storage_.length_; - unsigned min_len = std::min<unsigned>(this_len, other_len); - JSON_ASSERT(this->cstr_ && other.cstr_); - int comp = memcmp(this->cstr_, other.cstr_, min_len); - if (comp < 0) return true; - if (comp > 0) return false; - return (this_len < other_len); -} - -bool Value::CZString::operator==(const CZString& other) const { - if (!cstr_) return index_ == other.index_; - //return strcmp(cstr_, other.cstr_) == 0; - // Assume both are strings. - unsigned this_len = this->storage_.length_; - unsigned other_len = other.storage_.length_; - if (this_len != other_len) return false; - JSON_ASSERT(this->cstr_ && other.cstr_); - int comp = memcmp(this->cstr_, other.cstr_, this_len); - return comp == 0; -} - -ArrayIndex Value::CZString::index() const { return index_; } - -//const char* Value::CZString::c_str() const { return cstr_; } -const char* Value::CZString::data() const { return cstr_; } -unsigned Value::CZString::length() const { return storage_.length_; } -bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; } - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::Value -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -/*! \internal Default constructor initialization must be equivalent to: - * memset( this, 0, sizeof(Value) ) - * This optimization is used in ValueInternalMap fast allocator. - */ -Value::Value(ValueType vtype) { - static char const emptyString[] = ""; - initBasic(vtype); - switch (vtype) { - case nullValue: - break; - case intValue: - case uintValue: - value_.int_ = 0; - break; - case realValue: - value_.real_ = 0.0; - break; - case stringValue: - // allocated_ == false, so this is safe. - value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString)); - break; - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues(); - break; - case booleanValue: - value_.bool_ = false; - break; - default: - JSON_ASSERT_UNREACHABLE; - } -} - -Value::Value(Int value) { - initBasic(intValue); - value_.int_ = value; -} - -Value::Value(UInt value) { - initBasic(uintValue); - value_.uint_ = value; -} -#if defined(JSON_HAS_INT64) -Value::Value(Int64 value) { - initBasic(intValue); - value_.int_ = value; -} -Value::Value(UInt64 value) { - initBasic(uintValue); - value_.uint_ = value; -} -#endif // defined(JSON_HAS_INT64) - -Value::Value(double value) { - initBasic(realValue); - value_.real_ = value; -} - -Value::Value(const char* value) { - initBasic(stringValue, true); - JSON_ASSERT_MESSAGE(value != NULL, "Null Value Passed to Value Constructor"); - value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value))); -} - -Value::Value(const char* beginValue, const char* endValue) { - initBasic(stringValue, true); - value_.string_ = - duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue)); -} - -Value::Value(const JSONCPP_STRING& value) { - initBasic(stringValue, true); - value_.string_ = - duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length())); -} - -Value::Value(const StaticString& value) { - initBasic(stringValue); - value_.string_ = const_cast<char*>(value.c_str()); -} - -#ifdef JSON_USE_CPPTL -Value::Value(const CppTL::ConstString& value) { - initBasic(stringValue, true); - value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length())); -} -#endif - -Value::Value(bool value) { - initBasic(booleanValue); - value_.bool_ = value; -} - -Value::Value(Value const& other) - : type_(other.type_), allocated_(false) - , - comments_(0), start_(other.start_), limit_(other.limit_) -{ - switch (type_) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - value_ = other.value_; - break; - case stringValue: - if (other.value_.string_ && other.allocated_) { - unsigned len; - char const* str; - decodePrefixedString(other.allocated_, other.value_.string_, - &len, &str); - value_.string_ = duplicateAndPrefixStringValue(str, len); - allocated_ = true; - } else { - value_.string_ = other.value_.string_; - allocated_ = false; - } - break; - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues(*other.value_.map_); - break; - default: - JSON_ASSERT_UNREACHABLE; - } - if (other.comments_) { - comments_ = new CommentInfo[numberOfCommentPlacement]; - for (int comment = 0; comment < numberOfCommentPlacement; ++comment) { - const CommentInfo& otherComment = other.comments_[comment]; - if (otherComment.comment_) - comments_[comment].setComment( - otherComment.comment_, strlen(otherComment.comment_)); - } - } -} - -#if JSON_HAS_RVALUE_REFERENCES -// Move constructor -Value::Value(Value&& other) { - initBasic(nullValue); - swap(other); -} -#endif - -Value::~Value() { - switch (type_) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - break; - case stringValue: - if (allocated_) - releasePrefixedStringValue(value_.string_); - break; - case arrayValue: - case objectValue: - delete value_.map_; - break; - default: - JSON_ASSERT_UNREACHABLE; - } - - delete[] comments_; - - value_.uint_ = 0; -} - -Value& Value::operator=(Value other) { - swap(other); - return *this; -} - -void Value::swapPayload(Value& other) { - ValueType temp = type_; - type_ = other.type_; - other.type_ = temp; - std::swap(value_, other.value_); - int temp2 = allocated_; - allocated_ = other.allocated_; - other.allocated_ = temp2 & 0x1; -} - -void Value::copyPayload(const Value& other) { - type_ = other.type_; - value_ = other.value_; - allocated_ = other.allocated_; -} - -void Value::swap(Value& other) { - swapPayload(other); - std::swap(comments_, other.comments_); - std::swap(start_, other.start_); - std::swap(limit_, other.limit_); -} - -void Value::copy(const Value& other) { - copyPayload(other); - comments_ = other.comments_; - start_ = other.start_; - limit_ = other.limit_; -} - -ValueType Value::type() const { return type_; } - -int Value::compare(const Value& other) const { - if (*this < other) - return -1; - if (*this > other) - return 1; - return 0; -} - -bool Value::operator<(const Value& other) const { - int typeDelta = type_ - other.type_; - if (typeDelta) - return typeDelta < 0 ? true : false; - switch (type_) { - case nullValue: - return false; - case intValue: - return value_.int_ < other.value_.int_; - case uintValue: - return value_.uint_ < other.value_.uint_; - case realValue: - return value_.real_ < other.value_.real_; - case booleanValue: - return value_.bool_ < other.value_.bool_; - case stringValue: - { - if ((value_.string_ == 0) || (other.value_.string_ == 0)) { - if (other.value_.string_) return true; - else return false; - } - unsigned this_len; - unsigned other_len; - char const* this_str; - char const* other_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); - unsigned min_len = std::min<unsigned>(this_len, other_len); - JSON_ASSERT(this_str && other_str); - int comp = memcmp(this_str, other_str, min_len); - if (comp < 0) return true; - if (comp > 0) return false; - return (this_len < other_len); - } - case arrayValue: - case objectValue: { - int delta = int(value_.map_->size() - other.value_.map_->size()); - if (delta) - return delta < 0; - return (*value_.map_) < (*other.value_.map_); - } - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable -} - -bool Value::operator<=(const Value& other) const { return !(other < *this); } - -bool Value::operator>=(const Value& other) const { return !(*this < other); } - -bool Value::operator>(const Value& other) const { return other < *this; } - -bool Value::operator==(const Value& other) const { - // if ( type_ != other.type_ ) - // GCC 2.95.3 says: - // attempt to take address of bit-field structure member `Json::Value::type_' - // Beats me, but a temp solves the problem. - int temp = other.type_; - if (type_ != temp) - return false; - switch (type_) { - case nullValue: - return true; - case intValue: - return value_.int_ == other.value_.int_; - case uintValue: - return value_.uint_ == other.value_.uint_; - case realValue: - return value_.real_ == other.value_.real_; - case booleanValue: - return value_.bool_ == other.value_.bool_; - case stringValue: - { - if ((value_.string_ == 0) || (other.value_.string_ == 0)) { - return (value_.string_ == other.value_.string_); - } - unsigned this_len; - unsigned other_len; - char const* this_str; - char const* other_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); - if (this_len != other_len) return false; - JSON_ASSERT(this_str && other_str); - int comp = memcmp(this_str, other_str, this_len); - return comp == 0; - } - case arrayValue: - case objectValue: - return value_.map_->size() == other.value_.map_->size() && - (*value_.map_) == (*other.value_.map_); - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable -} - -bool Value::operator!=(const Value& other) const { return !(*this == other); } - -const char* Value::asCString() const { - JSON_ASSERT_MESSAGE(type_ == stringValue, - "in Json::Value::asCString(): requires stringValue"); - if (value_.string_ == 0) return 0; - unsigned this_len; - char const* this_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - return this_str; -} - -#if JSONCPP_USING_SECURE_MEMORY -unsigned Value::getCStringLength() const { - JSON_ASSERT_MESSAGE(type_ == stringValue, - "in Json::Value::asCString(): requires stringValue"); - if (value_.string_ == 0) return 0; - unsigned this_len; - char const* this_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - return this_len; -} -#endif - -bool Value::getString(char const** str, char const** cend) const { - if (type_ != stringValue) return false; - if (value_.string_ == 0) return false; - unsigned length; - decodePrefixedString(this->allocated_, this->value_.string_, &length, str); - *cend = *str + length; - return true; -} - -JSONCPP_STRING Value::asString() const { - switch (type_) { - case nullValue: - return ""; - case stringValue: - { - if (value_.string_ == 0) return ""; - unsigned this_len; - char const* this_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - return JSONCPP_STRING(this_str, this_len); - } - case booleanValue: - return value_.bool_ ? "true" : "false"; - case intValue: - return valueToString(value_.int_); - case uintValue: - return valueToString(value_.uint_); - case realValue: - return valueToString(value_.real_); - default: - JSON_FAIL_MESSAGE("Type is not convertible to string"); - } -} - -#ifdef JSON_USE_CPPTL -CppTL::ConstString Value::asConstString() const { - unsigned len; - char const* str; - decodePrefixedString(allocated_, value_.string_, - &len, &str); - return CppTL::ConstString(str, len); -} -#endif - -Value::Int Value::asInt() const { - switch (type_) { - case intValue: - JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); - return Int(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); - return Int(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), - "double out of Int range"); - return Int(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to Int."); -} - -Value::UInt Value::asUInt() const { - switch (type_) { - case intValue: - JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); - return UInt(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); - return UInt(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), - "double out of UInt range"); - return UInt(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to UInt."); -} - -#if defined(JSON_HAS_INT64) - -Value::Int64 Value::asInt64() const { - switch (type_) { - case intValue: - return Int64(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); - return Int64(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), - "double out of Int64 range"); - return Int64(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to Int64."); -} - -Value::UInt64 Value::asUInt64() const { - switch (type_) { - case intValue: - JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); - return UInt64(value_.int_); - case uintValue: - return UInt64(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), - "double out of UInt64 range"); - return UInt64(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); -} -#endif // if defined(JSON_HAS_INT64) - -LargestInt Value::asLargestInt() const { -#if defined(JSON_NO_INT64) - return asInt(); -#else - return asInt64(); -#endif -} - -LargestUInt Value::asLargestUInt() const { -#if defined(JSON_NO_INT64) - return asUInt(); -#else - return asUInt64(); -#endif -} - -double Value::asDouble() const { - switch (type_) { - case intValue: - return static_cast<double>(value_.int_); - case uintValue: -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return static_cast<double>(value_.uint_); -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return integerToDouble(value_.uint_); -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - case realValue: - return value_.real_; - case nullValue: - return 0.0; - case booleanValue: - return value_.bool_ ? 1.0 : 0.0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to double."); -} - -float Value::asFloat() const { - switch (type_) { - case intValue: - return static_cast<float>(value_.int_); - case uintValue: -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return static_cast<float>(value_.uint_); -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - // This can fail (silently?) if the value is bigger than MAX_FLOAT. - return static_cast<float>(integerToDouble(value_.uint_)); -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - case realValue: - return static_cast<float>(value_.real_); - case nullValue: - return 0.0; - case booleanValue: - return value_.bool_ ? 1.0f : 0.0f; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to float."); -} - -bool Value::asBool() const { - switch (type_) { - case booleanValue: - return value_.bool_; - case nullValue: - return false; - case intValue: - return value_.int_ ? true : false; - case uintValue: - return value_.uint_ ? true : false; - case realValue: - // This is kind of strange. Not recommended. - return (value_.real_ != 0.0) ? true : false; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to bool."); -} - -bool Value::isConvertibleTo(ValueType other) const { - switch (other) { - case nullValue: - return (isNumeric() && asDouble() == 0.0) || - (type_ == booleanValue && value_.bool_ == false) || - (type_ == stringValue && asString().empty()) || - (type_ == arrayValue && value_.map_->size() == 0) || - (type_ == objectValue && value_.map_->size() == 0) || - type_ == nullValue; - case intValue: - return isInt() || - (type_ == realValue && InRange(value_.real_, minInt, maxInt)) || - type_ == booleanValue || type_ == nullValue; - case uintValue: - return isUInt() || - (type_ == realValue && InRange(value_.real_, 0, maxUInt)) || - type_ == booleanValue || type_ == nullValue; - case realValue: - return isNumeric() || type_ == booleanValue || type_ == nullValue; - case booleanValue: - return isNumeric() || type_ == booleanValue || type_ == nullValue; - case stringValue: - return isNumeric() || type_ == booleanValue || type_ == stringValue || - type_ == nullValue; - case arrayValue: - return type_ == arrayValue || type_ == nullValue; - case objectValue: - return type_ == objectValue || type_ == nullValue; - } - JSON_ASSERT_UNREACHABLE; - return false; -} - -/// Number of values in array or object -ArrayIndex Value::size() const { - switch (type_) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - case stringValue: - return 0; - case arrayValue: // size of the array is highest index + 1 - if (!value_.map_->empty()) { - ObjectValues::const_iterator itLast = value_.map_->end(); - --itLast; - return (*itLast).first.index() + 1; - } - return 0; - case objectValue: - return ArrayIndex(value_.map_->size()); - } - JSON_ASSERT_UNREACHABLE; - return 0; // unreachable; -} - -bool Value::empty() const { - if (isNull() || isArray() || isObject()) - return size() == 0u; - else - return false; -} - -bool Value::operator!() const { return isNull(); } - -void Value::clear() { - JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || - type_ == objectValue, - "in Json::Value::clear(): requires complex value"); - start_ = 0; - limit_ = 0; - switch (type_) { - case arrayValue: - case objectValue: - value_.map_->clear(); - break; - default: - break; - } -} - -void Value::resize(ArrayIndex newSize) { - JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue, - "in Json::Value::resize(): requires arrayValue"); - if (type_ == nullValue) - *this = Value(arrayValue); - ArrayIndex oldSize = size(); - if (newSize == 0) - clear(); - else if (newSize > oldSize) - (*this)[newSize - 1]; - else { - for (ArrayIndex index = newSize; index < oldSize; ++index) { - value_.map_->erase(index); - } - JSON_ASSERT(size() == newSize); - } -} - -Value& Value::operator[](ArrayIndex index) { - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == arrayValue, - "in Json::Value::operator[](ArrayIndex): requires arrayValue"); - if (type_ == nullValue) - *this = Value(arrayValue); - CZString key(index); - ObjectValues::iterator it = value_.map_->lower_bound(key); - if (it != value_.map_->end() && (*it).first == key) - return (*it).second; - - ObjectValues::value_type defaultValue(key, nullSingleton()); - it = value_.map_->insert(it, defaultValue); - return (*it).second; -} - -Value& Value::operator[](int index) { - JSON_ASSERT_MESSAGE( - index >= 0, - "in Json::Value::operator[](int index): index cannot be negative"); - return (*this)[ArrayIndex(index)]; -} - -const Value& Value::operator[](ArrayIndex index) const { - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == arrayValue, - "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); - if (type_ == nullValue) - return nullSingleton(); - CZString key(index); - ObjectValues::const_iterator it = value_.map_->find(key); - if (it == value_.map_->end()) - return nullSingleton(); - return (*it).second; -} - -const Value& Value::operator[](int index) const { - JSON_ASSERT_MESSAGE( - index >= 0, - "in Json::Value::operator[](int index) const: index cannot be negative"); - return (*this)[ArrayIndex(index)]; -} - -void Value::initBasic(ValueType vtype, bool allocated) { - type_ = vtype; - allocated_ = allocated; - comments_ = 0; - start_ = 0; - limit_ = 0; -} - -// Access an object value by name, create a null member if it does not exist. -// @pre Type of '*this' is object or null. -// @param key is null-terminated. -Value& Value::resolveReference(const char* key) { - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == objectValue, - "in Json::Value::resolveReference(): requires objectValue"); - if (type_ == nullValue) - *this = Value(objectValue); - CZString actualKey( - key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE! - ObjectValues::iterator it = value_.map_->lower_bound(actualKey); - if (it != value_.map_->end() && (*it).first == actualKey) - return (*it).second; - - ObjectValues::value_type defaultValue(actualKey, nullSingleton()); - it = value_.map_->insert(it, defaultValue); - Value& value = (*it).second; - return value; -} - -// @param key is not null-terminated. -Value& Value::resolveReference(char const* key, char const* cend) -{ - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == objectValue, - "in Json::Value::resolveReference(key, end): requires objectValue"); - if (type_ == nullValue) - *this = Value(objectValue); - CZString actualKey( - key, static_cast<unsigned>(cend-key), CZString::duplicateOnCopy); - ObjectValues::iterator it = value_.map_->lower_bound(actualKey); - if (it != value_.map_->end() && (*it).first == actualKey) - return (*it).second; - - ObjectValues::value_type defaultValue(actualKey, nullSingleton()); - it = value_.map_->insert(it, defaultValue); - Value& value = (*it).second; - return value; -} - -Value Value::get(ArrayIndex index, const Value& defaultValue) const { - const Value* value = &((*this)[index]); - return value == &nullSingleton() ? defaultValue : *value; -} - -bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } - -Value const* Value::find(char const* key, char const* cend) const -{ - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == objectValue, - "in Json::Value::find(key, end, found): requires objectValue or nullValue"); - if (type_ == nullValue) return NULL; - CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication); - ObjectValues::const_iterator it = value_.map_->find(actualKey); - if (it == value_.map_->end()) return NULL; - return &(*it).second; -} -const Value& Value::operator[](const char* key) const -{ - Value const* found = find(key, key + strlen(key)); - if (!found) return nullSingleton(); - return *found; -} -Value const& Value::operator[](JSONCPP_STRING const& key) const -{ - Value const* found = find(key.data(), key.data() + key.length()); - if (!found) return nullSingleton(); - return *found; -} - -Value& Value::operator[](const char* key) { - return resolveReference(key, key + strlen(key)); -} - -Value& Value::operator[](const JSONCPP_STRING& key) { - return resolveReference(key.data(), key.data() + key.length()); -} - -Value& Value::operator[](const StaticString& key) { - return resolveReference(key.c_str()); -} - -#ifdef JSON_USE_CPPTL -Value& Value::operator[](const CppTL::ConstString& key) { - return resolveReference(key.c_str(), key.end_c_str()); -} -Value const& Value::operator[](CppTL::ConstString const& key) const -{ - Value const* found = find(key.c_str(), key.end_c_str()); - if (!found) return nullSingleton(); - return *found; -} -#endif - -Value& Value::append(const Value& value) { return (*this)[size()] = value; } - -#if JSON_HAS_RVALUE_REFERENCES - Value& Value::append(Value&& value) { return (*this)[size()] = value; } -#endif - -Value Value::get(char const* key, char const* cend, Value const& defaultValue) const -{ - Value const* found = find(key, cend); - return !found ? defaultValue : *found; -} -Value Value::get(char const* key, Value const& defaultValue) const -{ - return get(key, key + strlen(key), defaultValue); -} -Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue) const -{ - return get(key.data(), key.data() + key.length(), defaultValue); -} - - -bool Value::removeMember(const char* key, const char* cend, Value* removed) -{ - if (type_ != objectValue) { - return false; - } - CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication); - ObjectValues::iterator it = value_.map_->find(actualKey); - if (it == value_.map_->end()) - return false; - *removed = it->second; - value_.map_->erase(it); - return true; -} -bool Value::removeMember(const char* key, Value* removed) -{ - return removeMember(key, key + strlen(key), removed); -} -bool Value::removeMember(JSONCPP_STRING const& key, Value* removed) -{ - return removeMember(key.data(), key.data() + key.length(), removed); -} -Value Value::removeMember(const char* key) -{ - JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, - "in Json::Value::removeMember(): requires objectValue"); - if (type_ == nullValue) - return nullSingleton(); - - Value removed; // null - removeMember(key, key + strlen(key), &removed); - return removed; // still null if removeMember() did nothing -} -Value Value::removeMember(const JSONCPP_STRING& key) -{ - return removeMember(key.c_str()); -} - -bool Value::removeIndex(ArrayIndex index, Value* removed) { - if (type_ != arrayValue) { - return false; - } - CZString key(index); - ObjectValues::iterator it = value_.map_->find(key); - if (it == value_.map_->end()) { - return false; - } - *removed = it->second; - ArrayIndex oldSize = size(); - // shift left all items left, into the place of the "removed" - for (ArrayIndex i = index; i < (oldSize - 1); ++i){ - CZString keey(i); - (*value_.map_)[keey] = (*this)[i + 1]; - } - // erase the last one ("leftover") - CZString keyLast(oldSize - 1); - ObjectValues::iterator itLast = value_.map_->find(keyLast); - value_.map_->erase(itLast); - return true; -} - -#ifdef JSON_USE_CPPTL -Value Value::get(const CppTL::ConstString& key, - const Value& defaultValue) const { - return get(key.c_str(), key.end_c_str(), defaultValue); -} -#endif - -bool Value::isMember(char const* key, char const* cend) const -{ - Value const* value = find(key, cend); - return NULL != value; -} -bool Value::isMember(char const* key) const -{ - return isMember(key, key + strlen(key)); -} -bool Value::isMember(JSONCPP_STRING const& key) const -{ - return isMember(key.data(), key.data() + key.length()); -} - -#ifdef JSON_USE_CPPTL -bool Value::isMember(const CppTL::ConstString& key) const { - return isMember(key.c_str(), key.end_c_str()); -} -#endif - -Value::Members Value::getMemberNames() const { - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == objectValue, - "in Json::Value::getMemberNames(), value must be objectValue"); - if (type_ == nullValue) - return Value::Members(); - Members members; - members.reserve(value_.map_->size()); - ObjectValues::const_iterator it = value_.map_->begin(); - ObjectValues::const_iterator itEnd = value_.map_->end(); - for (; it != itEnd; ++it) { - members.push_back(JSONCPP_STRING((*it).first.data(), - (*it).first.length())); - } - return members; -} -// -//# ifdef JSON_USE_CPPTL -// EnumMemberNames -// Value::enumMemberNames() const -//{ -// if ( type_ == objectValue ) -// { -// return CppTL::Enum::any( CppTL::Enum::transform( -// CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ), -// MemberNamesTransform() ) ); -// } -// return EnumMemberNames(); -//} -// -// -// EnumValues -// Value::enumValues() const -//{ -// if ( type_ == objectValue || type_ == arrayValue ) -// return CppTL::Enum::anyValues( *(value_.map_), -// CppTL::Type<const Value &>() ); -// return EnumValues(); -//} -// -//# endif - -static bool IsIntegral(double d) { - double integral_part; - return modf(d, &integral_part) == 0.0; -} - -bool Value::isNull() const { return type_ == nullValue; } - -bool Value::isBool() const { return type_ == booleanValue; } - -bool Value::isInt() const { - switch (type_) { - case intValue: -#if defined(JSON_HAS_INT64) - return value_.int_ >= minInt && value_.int_ <= maxInt; -#else - return true; -#endif - case uintValue: - return value_.uint_ <= UInt(maxInt); - case realValue: - return value_.real_ >= minInt && value_.real_ <= maxInt && - IsIntegral(value_.real_); - default: - break; - } - return false; -} - -bool Value::isUInt() const { - switch (type_) { - case intValue: -#if defined(JSON_HAS_INT64) - return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); -#else - return value_.int_ >= 0; -#endif - case uintValue: -#if defined(JSON_HAS_INT64) - return value_.uint_ <= maxUInt; -#else - return true; -#endif - case realValue: - return value_.real_ >= 0 && value_.real_ <= maxUInt && - IsIntegral(value_.real_); - default: - break; - } - return false; -} - -bool Value::isInt64() const { -#if defined(JSON_HAS_INT64) - switch (type_) { - case intValue: - return true; - case uintValue: - return value_.uint_ <= UInt64(maxInt64); - case realValue: - // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a - // double, so double(maxInt64) will be rounded up to 2^63. Therefore we - // require the value to be strictly less than the limit. - return value_.real_ >= double(minInt64) && - value_.real_ < double(maxInt64) && IsIntegral(value_.real_); - default: - break; - } -#endif // JSON_HAS_INT64 - return false; -} - -bool Value::isUInt64() const { -#if defined(JSON_HAS_INT64) - switch (type_) { - case intValue: - return value_.int_ >= 0; - case uintValue: - return true; - case realValue: - // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a - // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we - // require the value to be strictly less than the limit. - return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && - IsIntegral(value_.real_); - default: - break; - } -#endif // JSON_HAS_INT64 - return false; -} - -bool Value::isIntegral() const { - switch (type_) { - case intValue: - case uintValue: - return true; - case realValue: -#if defined(JSON_HAS_INT64) - // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a - // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we - // require the value to be strictly less than the limit. - return value_.real_ >= double(minInt64) && value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_); -#else - return value_.real_ >= minInt && value_.real_ <= maxUInt && IsIntegral(value_.real_); -#endif // JSON_HAS_INT64 - default: - break; - } - return false; -} - -bool Value::isDouble() const { return type_ == intValue || type_ == uintValue || type_ == realValue; } - -bool Value::isNumeric() const { return isDouble(); } - -bool Value::isString() const { return type_ == stringValue; } - -bool Value::isArray() const { return type_ == arrayValue; } - -bool Value::isObject() const { return type_ == objectValue; } - -void Value::setComment(const char* comment, size_t len, CommentPlacement placement) { - if (!comments_) - comments_ = new CommentInfo[numberOfCommentPlacement]; - if ((len > 0) && (comment[len-1] == '\n')) { - // Always discard trailing newline, to aid indentation. - len -= 1; - } - comments_[placement].setComment(comment, len); -} - -void Value::setComment(const char* comment, CommentPlacement placement) { - setComment(comment, strlen(comment), placement); -} - -void Value::setComment(const JSONCPP_STRING& comment, CommentPlacement placement) { - setComment(comment.c_str(), comment.length(), placement); -} - -bool Value::hasComment(CommentPlacement placement) const { - return comments_ != 0 && comments_[placement].comment_ != 0; -} - -JSONCPP_STRING Value::getComment(CommentPlacement placement) const { - if (hasComment(placement)) - return comments_[placement].comment_; - return ""; -} - -void Value::setOffsetStart(ptrdiff_t start) { start_ = start; } - -void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; } - -ptrdiff_t Value::getOffsetStart() const { return start_; } - -ptrdiff_t Value::getOffsetLimit() const { return limit_; } - -JSONCPP_STRING Value::toStyledString() const { - StyledWriter writer; - return writer.write(*this); -} - -Value::const_iterator Value::begin() const { - switch (type_) { - case arrayValue: - case objectValue: - if (value_.map_) - return const_iterator(value_.map_->begin()); - break; - default: - break; - } - return const_iterator(); -} - -Value::const_iterator Value::end() const { - switch (type_) { - case arrayValue: - case objectValue: - if (value_.map_) - return const_iterator(value_.map_->end()); - break; - default: - break; - } - return const_iterator(); -} - -Value::iterator Value::begin() { - switch (type_) { - case arrayValue: - case objectValue: - if (value_.map_) - return iterator(value_.map_->begin()); - break; - default: - break; - } - return iterator(); -} - -Value::iterator Value::end() { - switch (type_) { - case arrayValue: - case objectValue: - if (value_.map_) - return iterator(value_.map_->end()); - break; - default: - break; - } - return iterator(); -} - -// class PathArgument -// ////////////////////////////////////////////////////////////////// - -PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {} - -PathArgument::PathArgument(ArrayIndex index) - : key_(), index_(index), kind_(kindIndex) {} - -PathArgument::PathArgument(const char* key) - : key_(key), index_(), kind_(kindKey) {} - -PathArgument::PathArgument(const JSONCPP_STRING& key) - : key_(key.c_str()), index_(), kind_(kindKey) {} - -// class Path -// ////////////////////////////////////////////////////////////////// - -Path::Path(const JSONCPP_STRING& path, - const PathArgument& a1, - const PathArgument& a2, - const PathArgument& a3, - const PathArgument& a4, - const PathArgument& a5) { - InArgs in; - in.reserve(5); - in.push_back(&a1); - in.push_back(&a2); - in.push_back(&a3); - in.push_back(&a4); - in.push_back(&a5); - makePath(path, in); -} - -void Path::makePath(const JSONCPP_STRING& path, const InArgs& in) { - const char* current = path.c_str(); - const char* end = current + path.length(); - InArgs::const_iterator itInArg = in.begin(); - while (current != end) { - if (*current == '[') { - ++current; - if (*current == '%') - addPathInArg(path, in, itInArg, PathArgument::kindIndex); - else { - ArrayIndex index = 0; - for (; current != end && *current >= '0' && *current <= '9'; ++current) - index = index * 10 + ArrayIndex(*current - '0'); - args_.push_back(index); - } - if (current == end || *++current != ']') - invalidPath(path, int(current - path.c_str())); - } else if (*current == '%') { - addPathInArg(path, in, itInArg, PathArgument::kindKey); - ++current; - } else if (*current == '.' || *current == ']') { - ++current; - } else { - const char* beginName = current; - while (current != end && !strchr("[.", *current)) - ++current; - args_.push_back(JSONCPP_STRING(beginName, current)); - } - } -} - -void Path::addPathInArg(const JSONCPP_STRING& /*path*/, - const InArgs& in, - InArgs::const_iterator& itInArg, - PathArgument::Kind kind) { - if (itInArg == in.end()) { - // Error: missing argument %d - } else if ((*itInArg)->kind_ != kind) { - // Error: bad argument type - } else { - args_.push_back(**itInArg++); - } -} - -void Path::invalidPath(const JSONCPP_STRING& /*path*/, int /*location*/) { - // Error: invalid path. -} - -const Value& Path::resolve(const Value& root) const { - const Value* node = &root; - for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { - const PathArgument& arg = *it; - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray() || !node->isValidIndex(arg.index_)) { - // Error: unable to resolve path (array value expected at position... - return Value::null; - } - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) { - // Error: unable to resolve path (object value expected at position...) - return Value::null; - } - node = &((*node)[arg.key_]); - if (node == &Value::nullSingleton()) { - // Error: unable to resolve path (object has no member named '' at - // position...) - return Value::null; - } - } - } - return *node; -} - -Value Path::resolve(const Value& root, const Value& defaultValue) const { - const Value* node = &root; - for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { - const PathArgument& arg = *it; - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray() || !node->isValidIndex(arg.index_)) - return defaultValue; - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) - return defaultValue; - node = &((*node)[arg.key_]); - if (node == &Value::nullSingleton()) - return defaultValue; - } - } - return *node; -} - -Value& Path::make(Value& root) const { - Value* node = &root; - for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { - const PathArgument& arg = *it; - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray()) { - // Error: node is not an array at position ... - } - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) { - // Error: node is not an object at position... - } - node = &((*node)[arg.key_]); - } - } - return *node; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_value.cpp -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_writer.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include <json/writer.h> -#include "json_tool.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include <iomanip> -#include <memory> -#include <sstream> -#include <utility> -#include <set> -#include <cassert> -#include <cstring> -#include <cstdio> - -#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0 -#include <float.h> -#define isfinite _finite -#elif defined(__sun) && defined(__SVR4) //Solaris -#if !defined(isfinite) -#include <ieeefp.h> -#define isfinite finite -#endif -#elif defined(_AIX) -#if !defined(isfinite) -#include <math.h> -#define isfinite finite -#endif -#elif defined(__hpux) -#if !defined(isfinite) -#if defined(__ia64) && !defined(finite) -#define isfinite(x) ((sizeof(x) == sizeof(float) ? \ - _Isfinitef(x) : _IsFinite(x))) -#else -#include <math.h> -#define isfinite finite -#endif -#endif -#else -#include <cmath> -#if !(defined(__QNXNTO__)) // QNX already defines isfinite -#define isfinite std::isfinite -#endif -#endif - -#if defined(_MSC_VER) -#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above -#define snprintf sprintf_s -#elif _MSC_VER >= 1900 // VC++ 14.0 and above -#define snprintf std::snprintf -#else -#define snprintf _snprintf -#endif -#elif defined(__ANDROID__) || defined(__QNXNTO__) -#define snprintf snprintf -#elif __cplusplus >= 201103L -#if !defined(__MINGW32__) && !defined(__CYGWIN__) -#define snprintf std::snprintf -#endif -#endif - -#if defined(__BORLANDC__) -#include <float.h> -#define isfinite _finite -#define snprintf _snprintf -#endif - -#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 -// Disable warning about strdup being deprecated. -#pragma warning(disable : 4996) -#endif - -namespace Json { - -#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) -typedef std::unique_ptr<StreamWriter> StreamWriterPtr; -#else -typedef std::auto_ptr<StreamWriter> StreamWriterPtr; -#endif - -static bool containsControlCharacter(const char* str) { - while (*str) { - if (isControlCharacter(*(str++))) - return true; - } - return false; -} - -static bool containsControlCharacter0(const char* str, unsigned len) { - char const* end = str + len; - while (end != str) { - if (isControlCharacter(*str) || 0==*str) - return true; - ++str; - } - return false; -} - -JSONCPP_STRING valueToString(LargestInt value) { - UIntToStringBuffer buffer; - char* current = buffer + sizeof(buffer); - if (value == Value::minLargestInt) { - uintToString(LargestUInt(Value::maxLargestInt) + 1, current); - *--current = '-'; - } else if (value < 0) { - uintToString(LargestUInt(-value), current); - *--current = '-'; - } else { - uintToString(LargestUInt(value), current); - } - assert(current >= buffer); - return current; -} - -JSONCPP_STRING valueToString(LargestUInt value) { - UIntToStringBuffer buffer; - char* current = buffer + sizeof(buffer); - uintToString(value, current); - assert(current >= buffer); - return current; -} - -#if defined(JSON_HAS_INT64) - -JSONCPP_STRING valueToString(Int value) { - return valueToString(LargestInt(value)); -} - -JSONCPP_STRING valueToString(UInt value) { - return valueToString(LargestUInt(value)); -} - -#endif // # if defined(JSON_HAS_INT64) - -namespace { -JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) { - // Allocate a buffer that is more than large enough to store the 16 digits of - // precision requested below. - char buffer[36]; - int len = -1; - - char formatString[15]; - snprintf(formatString, sizeof(formatString), "%%.%dg", precision); - - // Print into the buffer. We need not request the alternative representation - // that always has a decimal point because JSON doesn't distingish the - // concepts of reals and integers. - if (isfinite(value)) { - len = snprintf(buffer, sizeof(buffer), formatString, value); - fixNumericLocale(buffer, buffer + len); - - // try to ensure we preserve the fact that this was given to us as a double on input - if (!strchr(buffer, '.') && !strchr(buffer, 'e')) { - strcat(buffer, ".0"); - } - - } else { - // IEEE standard states that NaN values will not compare to themselves - if (value != value) { - len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null"); - } else if (value < 0) { - len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999"); - } else { - len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999"); - } - } - assert(len >= 0); - return buffer; -} -} - -JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); } - -JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; } - -JSONCPP_STRING valueToQuotedString(const char* value) { - if (value == NULL) - return ""; - // Not sure how to handle unicode... - if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && - !containsControlCharacter(value)) - return JSONCPP_STRING("\"") + value + "\""; - // We have to walk value and escape any special characters. - // Appending to JSONCPP_STRING is not efficient, but this should be rare. - // (Note: forward slashes are *not* rare, but I am not escaping them.) - JSONCPP_STRING::size_type maxsize = - strlen(value) * 2 + 3; // allescaped+quotes+NULL - JSONCPP_STRING result; - result.reserve(maxsize); // to avoid lots of mallocs - result += "\""; - for (const char* c = value; *c != 0; ++c) { - switch (*c) { - case '\"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - case '\b': - result += "\\b"; - break; - case '\f': - result += "\\f"; - break; - case '\n': - result += "\\n"; - break; - case '\r': - result += "\\r"; - break; - case '\t': - result += "\\t"; - break; - // case '/': - // Even though \/ is considered a legal escape in JSON, a bare - // slash is also legal, so I see no reason to escape it. - // (I hope I am not misunderstanding something. - // blep notes: actually escaping \/ may be useful in javascript to avoid </ - // sequence. - // Should add a flag to allow this compatibility mode and prevent this - // sequence from occurring. - default: - if (isControlCharacter(*c)) { - JSONCPP_OSTRINGSTREAM oss; - oss << "\\u" << std::hex << std::uppercase << std::setfill('0') - << std::setw(4) << static_cast<int>(*c); - result += oss.str(); - } else { - result += *c; - } - break; - } - } - result += "\""; - return result; -} - -// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp -static char const* strnpbrk(char const* s, char const* accept, size_t n) { - assert((s || !n) && accept); - - char const* const end = s + n; - for (char const* cur = s; cur < end; ++cur) { - int const c = *cur; - for (char const* a = accept; *a; ++a) { - if (*a == c) { - return cur; - } - } - } - return NULL; -} -static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { - if (value == NULL) - return ""; - // Not sure how to handle unicode... - if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL && - !containsControlCharacter0(value, length)) - return JSONCPP_STRING("\"") + value + "\""; - // We have to walk value and escape any special characters. - // Appending to JSONCPP_STRING is not efficient, but this should be rare. - // (Note: forward slashes are *not* rare, but I am not escaping them.) - JSONCPP_STRING::size_type maxsize = - length * 2 + 3; // allescaped+quotes+NULL - JSONCPP_STRING result; - result.reserve(maxsize); // to avoid lots of mallocs - result += "\""; - char const* end = value + length; - for (const char* c = value; c != end; ++c) { - switch (*c) { - case '\"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - case '\b': - result += "\\b"; - break; - case '\f': - result += "\\f"; - break; - case '\n': - result += "\\n"; - break; - case '\r': - result += "\\r"; - break; - case '\t': - result += "\\t"; - break; - // case '/': - // Even though \/ is considered a legal escape in JSON, a bare - // slash is also legal, so I see no reason to escape it. - // (I hope I am not misunderstanding something.) - // blep notes: actually escaping \/ may be useful in javascript to avoid </ - // sequence. - // Should add a flag to allow this compatibility mode and prevent this - // sequence from occurring. - default: - if ((isControlCharacter(*c)) || (*c == 0)) { - JSONCPP_OSTRINGSTREAM oss; - oss << "\\u" << std::hex << std::uppercase << std::setfill('0') - << std::setw(4) << static_cast<int>(*c); - result += oss.str(); - } else { - result += *c; - } - break; - } - } - result += "\""; - return result; -} - -// Class Writer -// ////////////////////////////////////////////////////////////////// -Writer::~Writer() {} - -// Class FastWriter -// ////////////////////////////////////////////////////////////////// - -FastWriter::FastWriter() - : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), - omitEndingLineFeed_(false) {} - -void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } - -void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } - -void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } - -JSONCPP_STRING FastWriter::write(const Value& root) { - document_.clear(); - writeValue(root); - if (!omitEndingLineFeed_) - document_ += "\n"; - return document_; -} - -void FastWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - if (!dropNullPlaceholders_) - document_ += "null"; - break; - case intValue: - document_ += valueToString(value.asLargestInt()); - break; - case uintValue: - document_ += valueToString(value.asLargestUInt()); - break; - case realValue: - document_ += valueToString(value.asDouble()); - break; - case stringValue: - { - // Is NULL possible for value.string_? No. - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str)); - break; - } - case booleanValue: - document_ += valueToString(value.asBool()); - break; - case arrayValue: { - document_ += '['; - ArrayIndex size = value.size(); - for (ArrayIndex index = 0; index < size; ++index) { - if (index > 0) - document_ += ','; - writeValue(value[index]); - } - document_ += ']'; - } break; - case objectValue: { - Value::Members members(value.getMemberNames()); - document_ += '{'; - for (Value::Members::iterator it = members.begin(); it != members.end(); - ++it) { - const JSONCPP_STRING& name = *it; - if (it != members.begin()) - document_ += ','; - document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())); - document_ += yamlCompatiblityEnabled_ ? ": " : ":"; - writeValue(value[name]); - } - document_ += '}'; - } break; - } -} - -// Class StyledWriter -// ////////////////////////////////////////////////////////////////// - -StyledWriter::StyledWriter() - : rightMargin_(74), indentSize_(3), addChildValues_() {} - -JSONCPP_STRING StyledWriter::write(const Value& root) { - document_.clear(); - addChildValues_ = false; - indentString_.clear(); - writeCommentBeforeValue(root); - writeValue(root); - writeCommentAfterValueOnSameLine(root); - document_ += "\n"; - return document_; -} - -void StyledWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - pushValue("null"); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble())); - break; - case stringValue: - { - // Is NULL possible for value.string_? No. - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); - else pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - Value::Members::iterator it = members.begin(); - for (;;) { - const JSONCPP_STRING& name = *it; - const Value& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedString(name.c_str())); - document_ += " : "; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - document_ += ','; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void StyledWriter::writeArrayValue(const Value& value) { - unsigned size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isArrayMultiLine = isMultineArray(value); - if (isArrayMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index = 0; - for (;;) { - const Value& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - writeIndent(); - writeValue(childValue); - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - document_ += ','; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - document_ += "[ "; - for (unsigned index = 0; index < size; ++index) { - if (index > 0) - document_ += ", "; - document_ += childValues_[index]; - } - document_ += " ]"; - } - } -} - -bool StyledWriter::isMultineArray(const Value& value) { - ArrayIndex const size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { - const Value& childValue = value[index]; - isMultiLine = ((childValue.isArray() || childValue.isObject()) && - childValue.size() > 0); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (ArrayIndex index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += static_cast<ArrayIndex>(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void StyledWriter::pushValue(const JSONCPP_STRING& value) { - if (addChildValues_) - childValues_.push_back(value); - else - document_ += value; -} - -void StyledWriter::writeIndent() { - if (!document_.empty()) { - char last = document_[document_.length() - 1]; - if (last == ' ') // already indented - return; - if (last != '\n') // Comments may add new-line - document_ += '\n'; - } - document_ += indentString_; -} - -void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) { - writeIndent(); - document_ += value; -} - -void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); } - -void StyledWriter::unindent() { - assert(indentString_.size() >= indentSize_); - indentString_.resize(indentString_.size() - indentSize_); -} - -void StyledWriter::writeCommentBeforeValue(const Value& root) { - if (!root.hasComment(commentBefore)) - return; - - document_ += "\n"; - writeIndent(); - const JSONCPP_STRING& comment = root.getComment(commentBefore); - JSONCPP_STRING::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - document_ += *iter; - if (*iter == '\n' && - (iter != comment.end() && *(iter + 1) == '/')) - writeIndent(); - ++iter; - } - - // Comments are stripped of trailing newlines, so add one here - document_ += "\n"; -} - -void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { - if (root.hasComment(commentAfterOnSameLine)) - document_ += " " + root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - document_ += "\n"; - document_ += root.getComment(commentAfter); - document_ += "\n"; - } -} - -bool StyledWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -// Class StyledStreamWriter -// ////////////////////////////////////////////////////////////////// - -StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation) - : document_(NULL), rightMargin_(74), indentation_(indentation), - addChildValues_() {} - -void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) { - document_ = &out; - addChildValues_ = false; - indentString_.clear(); - indented_ = true; - writeCommentBeforeValue(root); - if (!indented_) writeIndent(); - indented_ = true; - writeValue(root); - writeCommentAfterValueOnSameLine(root); - *document_ << "\n"; - document_ = NULL; // Forget the stream, for safety. -} - -void StyledStreamWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - pushValue("null"); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble())); - break; - case stringValue: - { - // Is NULL possible for value.string_? No. - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); - else pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - Value::Members::iterator it = members.begin(); - for (;;) { - const JSONCPP_STRING& name = *it; - const Value& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedString(name.c_str())); - *document_ << " : "; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void StyledStreamWriter::writeArrayValue(const Value& value) { - unsigned size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isArrayMultiLine = isMultineArray(value); - if (isArrayMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index = 0; - for (;;) { - const Value& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - if (!indented_) writeIndent(); - indented_ = true; - writeValue(childValue); - indented_ = false; - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - *document_ << "[ "; - for (unsigned index = 0; index < size; ++index) { - if (index > 0) - *document_ << ", "; - *document_ << childValues_[index]; - } - *document_ << " ]"; - } - } -} - -bool StyledStreamWriter::isMultineArray(const Value& value) { - ArrayIndex const size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { - const Value& childValue = value[index]; - isMultiLine = ((childValue.isArray() || childValue.isObject()) && - childValue.size() > 0); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (ArrayIndex index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += static_cast<ArrayIndex>(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) { - if (addChildValues_) - childValues_.push_back(value); - else - *document_ << value; -} - -void StyledStreamWriter::writeIndent() { - // blep intended this to look at the so-far-written string - // to determine whether we are already indented, but - // with a stream we cannot do that. So we rely on some saved state. - // The caller checks indented_. - *document_ << '\n' << indentString_; -} - -void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) { - if (!indented_) writeIndent(); - *document_ << value; - indented_ = false; -} - -void StyledStreamWriter::indent() { indentString_ += indentation_; } - -void StyledStreamWriter::unindent() { - assert(indentString_.size() >= indentation_.size()); - indentString_.resize(indentString_.size() - indentation_.size()); -} - -void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { - if (!root.hasComment(commentBefore)) - return; - - if (!indented_) writeIndent(); - const JSONCPP_STRING& comment = root.getComment(commentBefore); - JSONCPP_STRING::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - *document_ << *iter; - if (*iter == '\n' && - (iter != comment.end() && *(iter + 1) == '/')) - // writeIndent(); // would include newline - *document_ << indentString_; - ++iter; - } - indented_ = false; -} - -void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { - if (root.hasComment(commentAfterOnSameLine)) - *document_ << ' ' << root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - writeIndent(); - *document_ << root.getComment(commentAfter); - } - indented_ = false; -} - -bool StyledStreamWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -////////////////////////// -// BuiltStyledStreamWriter - -/// Scoped enums are not available until C++11. -struct CommentStyle { - /// Decide whether to write comments. - enum Enum { - None, ///< Drop all comments. - Most, ///< Recover odd behavior of previous versions (not implemented yet). - All ///< Keep all comments. - }; -}; - -struct BuiltStyledStreamWriter : public StreamWriter -{ - BuiltStyledStreamWriter( - JSONCPP_STRING const& indentation, - CommentStyle::Enum cs, - JSONCPP_STRING const& colonSymbol, - JSONCPP_STRING const& nullSymbol, - JSONCPP_STRING const& endingLineFeedSymbol, - bool useSpecialFloats, - unsigned int precision); - int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE; -private: - void writeValue(Value const& value); - void writeArrayValue(Value const& value); - bool isMultineArray(Value const& value); - void pushValue(JSONCPP_STRING const& value); - void writeIndent(); - void writeWithIndent(JSONCPP_STRING const& value); - void indent(); - void unindent(); - void writeCommentBeforeValue(Value const& root); - void writeCommentAfterValueOnSameLine(Value const& root); - static bool hasCommentForValue(const Value& value); - - typedef std::vector<JSONCPP_STRING> ChildValues; - - ChildValues childValues_; - JSONCPP_STRING indentString_; - unsigned int rightMargin_; - JSONCPP_STRING indentation_; - CommentStyle::Enum cs_; - JSONCPP_STRING colonSymbol_; - JSONCPP_STRING nullSymbol_; - JSONCPP_STRING endingLineFeedSymbol_; - bool addChildValues_ : 1; - bool indented_ : 1; - bool useSpecialFloats_ : 1; - unsigned int precision_; -}; -BuiltStyledStreamWriter::BuiltStyledStreamWriter( - JSONCPP_STRING const& indentation, - CommentStyle::Enum cs, - JSONCPP_STRING const& colonSymbol, - JSONCPP_STRING const& nullSymbol, - JSONCPP_STRING const& endingLineFeedSymbol, - bool useSpecialFloats, - unsigned int precision) - : rightMargin_(74) - , indentation_(indentation) - , cs_(cs) - , colonSymbol_(colonSymbol) - , nullSymbol_(nullSymbol) - , endingLineFeedSymbol_(endingLineFeedSymbol) - , addChildValues_(false) - , indented_(false) - , useSpecialFloats_(useSpecialFloats) - , precision_(precision) -{ -} -int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout) -{ - sout_ = sout; - addChildValues_ = false; - indented_ = true; - indentString_.clear(); - writeCommentBeforeValue(root); - if (!indented_) writeIndent(); - indented_ = true; - writeValue(root); - writeCommentAfterValueOnSameLine(root); - *sout_ << endingLineFeedSymbol_; - sout_ = NULL; - return 0; -} -void BuiltStyledStreamWriter::writeValue(Value const& value) { - switch (value.type()) { - case nullValue: - pushValue(nullSymbol_); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_)); - break; - case stringValue: - { - // Is NULL is possible for value.string_? No. - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); - else pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - Value::Members::iterator it = members.begin(); - for (;;) { - JSONCPP_STRING const& name = *it; - Value const& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()))); - *sout_ << colonSymbol_; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *sout_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { - unsigned size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value); - if (isMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index = 0; - for (;;) { - Value const& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - if (!indented_) writeIndent(); - indented_ = true; - writeValue(childValue); - indented_ = false; - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *sout_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - *sout_ << "["; - if (!indentation_.empty()) *sout_ << " "; - for (unsigned index = 0; index < size; ++index) { - if (index > 0) - *sout_ << ((!indentation_.empty()) ? ", " : ","); - *sout_ << childValues_[index]; - } - if (!indentation_.empty()) *sout_ << " "; - *sout_ << "]"; - } - } -} - -bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { - ArrayIndex const size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { - Value const& childValue = value[index]; - isMultiLine = ((childValue.isArray() || childValue.isObject()) && - childValue.size() > 0); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (ArrayIndex index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += static_cast<ArrayIndex>(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) { - if (addChildValues_) - childValues_.push_back(value); - else - *sout_ << value; -} - -void BuiltStyledStreamWriter::writeIndent() { - // blep intended this to look at the so-far-written string - // to determine whether we are already indented, but - // with a stream we cannot do that. So we rely on some saved state. - // The caller checks indented_. - - if (!indentation_.empty()) { - // In this case, drop newlines too. - *sout_ << '\n' << indentString_; - } -} - -void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) { - if (!indented_) writeIndent(); - *sout_ << value; - indented_ = false; -} - -void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } - -void BuiltStyledStreamWriter::unindent() { - assert(indentString_.size() >= indentation_.size()); - indentString_.resize(indentString_.size() - indentation_.size()); -} - -void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { - if (cs_ == CommentStyle::None) return; - if (!root.hasComment(commentBefore)) - return; - - if (!indented_) writeIndent(); - const JSONCPP_STRING& comment = root.getComment(commentBefore); - JSONCPP_STRING::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - *sout_ << *iter; - if (*iter == '\n' && - (iter != comment.end() && *(iter + 1) == '/')) - // writeIndent(); // would write extra newline - *sout_ << indentString_; - ++iter; - } - indented_ = false; -} - -void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) { - if (cs_ == CommentStyle::None) return; - if (root.hasComment(commentAfterOnSameLine)) - *sout_ << " " + root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - writeIndent(); - *sout_ << root.getComment(commentAfter); - } -} - -// static -bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -/////////////// -// StreamWriter - -StreamWriter::StreamWriter() - : sout_(NULL) -{ -} -StreamWriter::~StreamWriter() -{ -} -StreamWriter::Factory::~Factory() -{} -StreamWriterBuilder::StreamWriterBuilder() -{ - setDefaults(&settings_); -} -StreamWriterBuilder::~StreamWriterBuilder() -{} -StreamWriter* StreamWriterBuilder::newStreamWriter() const -{ - JSONCPP_STRING indentation = settings_["indentation"].asString(); - JSONCPP_STRING cs_str = settings_["commentStyle"].asString(); - bool eyc = settings_["enableYAMLCompatibility"].asBool(); - bool dnp = settings_["dropNullPlaceholders"].asBool(); - bool usf = settings_["useSpecialFloats"].asBool(); - unsigned int pre = settings_["precision"].asUInt(); - CommentStyle::Enum cs = CommentStyle::All; - if (cs_str == "All") { - cs = CommentStyle::All; - } else if (cs_str == "None") { - cs = CommentStyle::None; - } else { - throwRuntimeError("commentStyle must be 'All' or 'None'"); - } - JSONCPP_STRING colonSymbol = " : "; - if (eyc) { - colonSymbol = ": "; - } else if (indentation.empty()) { - colonSymbol = ":"; - } - JSONCPP_STRING nullSymbol = "null"; - if (dnp) { - nullSymbol.clear(); - } - if (pre > 17) pre = 17; - JSONCPP_STRING endingLineFeedSymbol; - return new BuiltStyledStreamWriter( - indentation, cs, - colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre); -} -static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys) -{ - valid_keys->clear(); - valid_keys->insert("indentation"); - valid_keys->insert("commentStyle"); - valid_keys->insert("enableYAMLCompatibility"); - valid_keys->insert("dropNullPlaceholders"); - valid_keys->insert("useSpecialFloats"); - valid_keys->insert("precision"); -} -bool StreamWriterBuilder::validate(Json::Value* invalid) const -{ - Json::Value my_invalid; - if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL - Json::Value& inv = *invalid; - std::set<JSONCPP_STRING> valid_keys; - getValidWriterKeys(&valid_keys); - Value::Members keys = settings_.getMemberNames(); - size_t n = keys.size(); - for (size_t i = 0; i < n; ++i) { - JSONCPP_STRING const& key = keys[i]; - if (valid_keys.find(key) == valid_keys.end()) { - inv[key] = settings_[key]; - } - } - return 0u == inv.size(); -} -Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) -{ - return settings_[key]; -} -// static -void StreamWriterBuilder::setDefaults(Json::Value* settings) -{ - //! [StreamWriterBuilderDefaults] - (*settings)["commentStyle"] = "All"; - (*settings)["indentation"] = "\t"; - (*settings)["enableYAMLCompatibility"] = false; - (*settings)["dropNullPlaceholders"] = false; - (*settings)["useSpecialFloats"] = false; - (*settings)["precision"] = 17; - //! [StreamWriterBuilderDefaults] -} - -JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) { - JSONCPP_OSTRINGSTREAM sout; - StreamWriterPtr const writer(builder.newStreamWriter()); - writer->write(root, &sout); - return sout.str(); -} - -JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) { - StreamWriterBuilder builder; - StreamWriterPtr const writer(builder.newStreamWriter()); - writer->write(root, &sout); - return sout; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_writer.cpp -// ////////////////////////////////////////////////////////////////////// - - - - -