diff --git a/README.md b/README.md index 2218debd..9ab7e388 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0) -[![Join the chat at https://gitter.im/efiXplorer/dev](https://badges.gitter.im/efiXplorer/efiXplorer.svg)](https://gitter.im/efiXplorer/dev?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) **efiXplorer** - IDA plugin for UEFI firmware analysis and reverse engineering automation :octocat: @@ -9,55 +8,90 @@ __Contributors__: * Philip Lebedev ([@p41l](https://github.com/p41l/)) * Yegor Vasilenko ([@yeggor](https://github.com/yeggor/)) -__Supported versions of Hex-Rays products:__ everytime we focus on last versions of IDA and Decompiler because trying to use most recent features from new SDK releases. That means we tested only on recent versions of Hex-Rays products and do not guarantee stable work on previous generations. +__Supported versions of Hex-Rays products:__ everytime we focus on last versions of IDA and Decompiler because we try to use most recent features from new SDK releases. That means we tested only on recent versions of Hex-Rays products and do not guarantee stable work on previous generations. __Why not IDApython:__ all code developed in C++ because it's a more stable and performant way to support a complex plugin and get full power of most recent SDK's features. -__Supported Platforms:__ Win, Linux and OSX (x86/x64). +__Supported Platforms:__ Windows, Linux and OSX (x86/x64). -![overview](img/overview.gif) +![overview](pics/efiXplorer_new_1.gif) -# Key features +# efiXplorer Key features ## Identify available Boot Services automatically -Annotate assembly code automatically with available Boot Services +Annotate Boot Services calls in assembly code automatically -![bs2](img/bs2.png) +![bs](pics/efiXplorer_new_2.gif) ## Identify available Runtime Services automatically -Annotate assembly code automatically with available Runtime Services +Annotate Runtime Services calls in assembly code automatically -![rt2](img/rt2.png) +![rt](pics/efiXplorer_new_3.gif) -## Identify available SMM Services automatically +## Identify available SMM services automatically + +Annotate SMM Services calls in assembly code automatically + +![efiXplorer_new_6](pics/efXplorer_new_6.gif) + +## Identify available PEI services automatically + +Annotate PEI Services calls in assembly code automatically + +![efiXplorer_new_6](pics/efXplorer_new_7.gif) -| Before analysis | After analysis | -| --- | --- | -| ![smm_before](img/smm_before.png) | ![smm_after](img/smm_after.png) | ## Identify available EFI Protocols automatically -* Build the list of available EFI Protocols +* Build the list of EFI Protocols firmware consumes and installes - ![protocols](img/protocols.png) +![protocols](pics/efiXplorer_new_4.gif) ## Identify known EFI GUID's -* Build the list of available EFI GUID's (including protocol name identification) +* Build the list of identified EFI GUID's (including protocol names for known GUIDS) + +![guids](pics/efiXplorer_new_5.gif) + +# efiXloader Key features + +* `efiXloader` is an IDA Pro loader module, responsible for processing UEFI drivers within single IDA Pro instance. + +![loader_1.gif](pics/loader_1.gif) + +## UEFI drivers entry points identification + +* During UEFI drivers analysis `efiXloader` identifies each driver's entry. + +![loader_2.gif](pics/loader_6.gif) + +## Navigation between different UEFI drivers + +* Each UEFI driver is accessible within single IDA Pro instance for reverse-engineering. + +![loader_3.gif](pics/loader_3.gif) + +## UEFI drivers extraction + +* All processed UEFI drivers are dropped into prepared folder. + +![loader_4.gif](pics/loader_4.gif) - ![guids](img/guids.png) +## efiXplorer + efiXloader in action -# efiXplorer Architecture +* All `efiXplorer` analysis capabilities can be applied to the whole UEFI firmware image (instead of reverse-engineering each single executable in a separate IDA session) -From the beginning of the project, we focus on building extensible architecture to make our life easier to support the current version and adding new features :rocket: +![loader_5.gif](pics/loader_5.gif) -![arch](img/arch.png) +## SMI handlers identification within the whole firmware + +![loader_5.gif](pics/loader_7.gif) # Build instruction -We try to make the build process for different platforms very simple, just use the build script to automate this process🐍 +We try to make the build process for all supported platforms very simple, just use the build script to automate this process. ## Build script @@ -65,8 +99,8 @@ We try to make the build process for different platforms very simple, just use t Usage: build.py [OPTIONS] IDASDK_DIR Options: - -c, --copy TEXT path to IDA plugins directory - --help Show this message and exit. + --copy TEXT path to IDA plugins directory + --help Show this message and exit. ``` example of build process: @@ -75,20 +109,52 @@ example of build process: ./build.py ``` +## Compilation with cmake + +``` +mkdir build +cd build +cmake .. -DIdaSdk_ROOT_DIR="/path/to/idasdk" +cmake --build . --config Release +``` + +## efiXloader compilation and installation + +The common steps are next. + +```bash +cd efiXloader +mkdir build +cd build +cmake .. -DIdaSdk_ROOT_DIR="/path/to/idasdk" +cmake --build . --config Release +``` + # Installation -Copy compiled binaries of efiXplorer plugin and `guids` directory to `/plugins`. Enjoy! +## efiXplorer -# Publications -* [How efiXplorer helping to solve challenges in reverse engineering of UEFI firmware](https://www.youtube.com/watch?v=FFGQJBmRkLw) +Copy compiled binaries of `efiXplorer` plugin and `guids` directory to `/plugins`. Enjoy! -# References -__For IDA:__ -* https://github.com/yeggor/UEFI_RETool -* https://github.com/gdbinit/EFISwissKnife -* https://github.com/snare/ida-efiutils +## efiXloader + +Copy `builds/efiXloader64.dll` to `/loaders`. + +# Features summary table -__For Ghidra:__ +| Feature \ Bitness | 32-bit | 64-bit | +| --- | --- | --- | +| Boot Services | + | + | +| Runtime Services | + | + | +| SMM services | - | + | +| PEI Services | + | - | +| Loader | - | + | + +# References + +* https://github.com/LongSoft/UEFITool +* https://github.com/yeggor/UEFI_RETool +* https://github.com/gdbinit/EFISwissKnife +* https://github.com/snare/ida-efiutils * https://github.com/al3xtjames/ghidra-firmware-utils * https://github.com/DSecurity/efiSeek - diff --git a/img/arch.png b/img/arch.png deleted file mode 100644 index d756d56b..00000000 Binary files a/img/arch.png and /dev/null differ diff --git a/img/bs1.png b/img/bs1.png deleted file mode 100644 index c6f3ce4e..00000000 Binary files a/img/bs1.png and /dev/null differ diff --git a/img/bs2.png b/img/bs2.png deleted file mode 100644 index de35741f..00000000 Binary files a/img/bs2.png and /dev/null differ diff --git a/img/guids.png b/img/guids.png deleted file mode 100644 index e7e16c3f..00000000 Binary files a/img/guids.png and /dev/null differ diff --git a/img/overview.gif b/img/overview.gif deleted file mode 100644 index 1f1b7b51..00000000 Binary files a/img/overview.gif and /dev/null differ diff --git a/img/protocols.png b/img/protocols.png deleted file mode 100644 index dd62b6d1..00000000 Binary files a/img/protocols.png and /dev/null differ diff --git a/img/rt1.png b/img/rt1.png deleted file mode 100644 index 98ea8dae..00000000 Binary files a/img/rt1.png and /dev/null differ diff --git a/img/rt2.png b/img/rt2.png deleted file mode 100644 index e5e8e555..00000000 Binary files a/img/rt2.png and /dev/null differ diff --git a/img/smm_after.png b/img/smm_after.png deleted file mode 100644 index bd960a41..00000000 Binary files a/img/smm_after.png and /dev/null differ diff --git a/img/smm_before.png b/img/smm_before.png deleted file mode 100644 index 95031c25..00000000 Binary files a/img/smm_before.png and /dev/null differ diff --git a/pics/efXplorer_new_6.gif b/pics/efXplorer_new_6.gif new file mode 100644 index 00000000..c4cef5a8 Binary files /dev/null and b/pics/efXplorer_new_6.gif differ diff --git a/pics/efXplorer_new_7.gif b/pics/efXplorer_new_7.gif new file mode 100644 index 00000000..d640a40e Binary files /dev/null and b/pics/efXplorer_new_7.gif differ diff --git a/pics/efiXplorer_new_1.gif b/pics/efiXplorer_new_1.gif new file mode 100644 index 00000000..d69e309a Binary files /dev/null and b/pics/efiXplorer_new_1.gif differ diff --git a/pics/efiXplorer_new_2.gif b/pics/efiXplorer_new_2.gif new file mode 100644 index 00000000..37539c1c Binary files /dev/null and b/pics/efiXplorer_new_2.gif differ diff --git a/pics/efiXplorer_new_3.gif b/pics/efiXplorer_new_3.gif new file mode 100644 index 00000000..91e836b8 Binary files /dev/null and b/pics/efiXplorer_new_3.gif differ diff --git a/pics/efiXplorer_new_4.gif b/pics/efiXplorer_new_4.gif new file mode 100644 index 00000000..9901e47b Binary files /dev/null and b/pics/efiXplorer_new_4.gif differ diff --git a/pics/efiXplorer_new_5.gif b/pics/efiXplorer_new_5.gif new file mode 100644 index 00000000..6e95164d Binary files /dev/null and b/pics/efiXplorer_new_5.gif differ diff --git a/pics/loader_1.gif b/pics/loader_1.gif new file mode 100644 index 00000000..03a32c51 Binary files /dev/null and b/pics/loader_1.gif differ diff --git a/pics/loader_2.gif b/pics/loader_2.gif new file mode 100644 index 00000000..0179b490 Binary files /dev/null and b/pics/loader_2.gif differ diff --git a/pics/loader_3.gif b/pics/loader_3.gif new file mode 100644 index 00000000..4043f0e8 Binary files /dev/null and b/pics/loader_3.gif differ diff --git a/pics/loader_4.gif b/pics/loader_4.gif new file mode 100644 index 00000000..a9550d6d Binary files /dev/null and b/pics/loader_4.gif differ diff --git a/pics/loader_5.gif b/pics/loader_5.gif new file mode 100644 index 00000000..4081098f Binary files /dev/null and b/pics/loader_5.gif differ diff --git a/pics/loader_6.gif b/pics/loader_6.gif new file mode 100644 index 00000000..a2d2b783 Binary files /dev/null and b/pics/loader_6.gif differ diff --git a/pics/loader_7.gif b/pics/loader_7.gif new file mode 100644 index 00000000..33888688 Binary files /dev/null and b/pics/loader_7.gif differ diff --git a/src/efiAnalysis.cpp b/src/efiAnalysis.cpp index 2eea1c21..30731c90 100644 --- a/src/efiAnalysis.cpp +++ b/src/efiAnalysis.cpp @@ -44,6 +44,11 @@ vector gBsList; vector gRtList; vector gSmstList; vector gImageHandleList; +vector gRtServicesList; + +/* all .text and .data segments for compatibility with the efiXloader */ +vector textSegments; +vector dataSegments; efiAnalysis::efiAnalyzer::efiAnalyzer() { /* get guids.json path */ @@ -95,7 +100,54 @@ efiAnalysis::efiAnalyzer::efiAnalyzer() { import_type(idati, -1, "EFI_PEI_SERVICES"); } -efiAnalysis::efiAnalyzer::~efiAnalyzer() {} +efiAnalysis::efiAnalyzer::~efiAnalyzer() { + gStList.clear(); + gPeiSvcList.clear(); + gBsList.clear(); + gRtList.clear(); + gSmstList.clear(); + gImageHandleList.clear(); + gRtServicesList.clear(); + textSegments.clear(); + dataSegments.clear(); +} + +//-------------------------------------------------------------------------- +// Get all .text and .data segments +void efiAnalysis::efiAnalyzer::getSegments() { + DEBUG_MSG("[%s] ========================================================\n", + plugin_name); + DEBUG_MSG("[%s] search for .text and .data segments\n", plugin_name); + for (segment_t *s = get_first_seg(); s != NULL; + s = get_next_seg(s->start_ea)) { + qstring seg_name; + get_segm_name(&seg_name, s); + size_t index = seg_name.find(".text"); + if (index != string::npos) { + /* found .text segment */ + textSegments.push_back(s); + continue; + } + index = seg_name.find(".data"); + if (index != string::npos) { + /* found .data segment */ + dataSegments.push_back(s); + continue; + } + } + /* print all .text segments addresses */ + for (vector::iterator seg = textSegments.begin(); + seg != textSegments.end(); ++seg) { + segment_t *s = *seg; + DEBUG_MSG("[%s] .text segment: 0x%016x\n", plugin_name, s->start_ea); + } + /* print all .data segments addresses */ + for (vector::iterator seg = dataSegments.begin(); + seg != dataSegments.end(); ++seg) { + segment_t *s = *seg; + DEBUG_MSG("[%s] .data segment: 0x%016x\n", plugin_name, s->start_ea); + } +} //-------------------------------------------------------------------------- // Find gImageHandle address for X64 modules @@ -104,7 +156,7 @@ bool efiAnalysis::efiAnalyzer::findImageHandleX64() { plugin_name); DEBUG_MSG("[%s] ImageHandle finding\n", plugin_name); insn_t insn; - for (auto idx = 0; idx < get_entry_qty(); idx++) { + for (int idx = 0; idx < get_entry_qty(); idx++) { /* get address of entry point */ uval_t ord = get_entry_ordinal(idx); ea_t ea = get_entry(ord); @@ -116,16 +168,20 @@ bool efiAnalysis::efiAnalyzer::findImageHandleX64() { DEBUG_MSG("[%s] found ImageHandle at 0x%016X, address = " "0x%016X\n", plugin_name, ea, insn.ops[0].addr); - /* with this name type will applied automatically */ - set_name(insn.ops[0].addr, "gImageHandle", SN_CHECK); - set_cmt(ea, "EFI_HANDLE gImageHandle", true); + char hexAddr[21] = {}; + snprintf(hexAddr, 21, "%llX", + static_cast(insn.ops[0].addr)); + set_cmt(ea, "EFI_IMAGE_HANDLE gImageHandle", true); + string name = "gImageHandle_" + static_cast(hexAddr); + /* set type and name */ + setTypeAndName(insn.ops[0].addr, name, "EFI_IMAGE_HANDLE"); gImageHandleList.push_back(insn.ops[0].addr); - return true; + break; } ea = next_head(ea, endAddress); } } - return false; + return true; } //-------------------------------------------------------------------------- @@ -147,9 +203,13 @@ bool efiAnalysis::efiAnalyzer::findSystemTableX64() { DEBUG_MSG("[%s] found SystemTable at 0x%016X, address = " "0x%016X\n", plugin_name, ea, insn.ops[0].addr); - /* with this name type will applied automatically */ - set_name(insn.ops[0].addr, "gST", SN_CHECK); - set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); + char hexAddr[21] = {}; + snprintf(hexAddr, 21, "%llX", + static_cast(insn.ops[0].addr)); + set_cmt(ea, "EFI_SYSTEM_TABLE gST", true); + string name = "gST_" + static_cast(hexAddr); + /* set type and name */ + setPtrTypeAndName(insn.ops[0].addr, name, "EFI_SYSTEM_TABLE"); gStList.push_back(insn.ops[0].addr); return true; } @@ -165,14 +225,14 @@ bool efiAnalysis::efiAnalyzer::findSmstX64() { DEBUG_MSG("[%s] ========================================================\n", plugin_name); DEBUG_MSG("[%s] SMST finding\n", plugin_name); - gSmstList = findSmstSmmBase(gBsList); - if (!gSmstList.size()) { - gSmstList = findSmstSwDispatch(gBsList); - if (!gSmstList.size()) { - return false; - } - } - return true; + vector gSmstListSmmBase = findSmstSmmBase(gBsList, dataSegments); + vector gSmstListSwDispatch = + findSmstSwDispatch(gBsList, dataSegments); + gSmstList.insert(gSmstList.end(), gSmstListSwDispatch.begin(), + gSmstListSwDispatch.end()); + gSmstList.insert(gSmstList.end(), gSmstListSmmBase.begin(), + gSmstListSmmBase.end()); + return gSmstList.size(); } //-------------------------------------------------------------------------- @@ -180,8 +240,7 @@ bool efiAnalysis::efiAnalyzer::findSmstX64() { bool efiAnalysis::efiAnalyzer::findBootServicesTables(uint8_t arch) { DEBUG_MSG("[%s] ========================================================\n", plugin_name); - DEBUG_MSG("[%s] BootServices table finding from 0x%016X to 0x%016X\n", - plugin_name, startAddress, endAddress); + DEBUG_MSG("[%s] BootServices tables finding\n", plugin_name); /* init architecture-specific constants */ auto BS_OFFSET = BS_OFFSET_X64; auto REG_SP = REG_RSP; @@ -189,90 +248,60 @@ bool efiAnalysis::efiAnalyzer::findBootServicesTables(uint8_t arch) { BS_OFFSET = BS_OFFSET_X86; REG_SP = REG_ESP; } - ea_t ea = startAddress; insn_t insn; - uint16_t bsRegister = 0; - uint16_t stRegister = 0; - while (ea <= endAddress) { - decode_insn(&insn, ea); - if (insn.itype == NN_mov && insn.ops[1].type == o_displ && - insn.ops[1].phrase != REG_SP) { - if (insn.ops[0].type == o_reg && insn.ops[1].addr == BS_OFFSET) { - bsRegister = insn.ops[0].reg; - stRegister = insn.ops[1].phrase; - auto bsFound = false; - auto stFound = false; - ea_t baseInsnAddr; - /* found BS_OFFSET, need to check 10 instructions below */ - for (auto i = 0; i < 10; i++) { - decode_insn(&insn, ea); - if (insn.itype == NN_mov && insn.ops[1].type == o_reg && - insn.ops[0].type == o_mem) { - if (insn.ops[1].reg == bsRegister && !bsFound) { - DEBUG_MSG( - "[%s] found BootServices table at 0x%016X, " - "address = " - "0x%016X\n", - plugin_name, ea, insn.ops[0].addr); - baseInsnAddr = ea; - if (find(gBsList.begin(), gBsList.end(), - insn.ops[0].addr) == gBsList.end()) { - char hexAddr[21] = {}; - snprintf( - hexAddr, 21, "%llX", - static_cast(insn.ops[0].addr)); - set_cmt(ea, "EFI_BOOT_SERVICES *gBS", true); - string name = - "gBS_" + static_cast(hexAddr); - setPtrTypeAndName(insn.ops[0].addr, name, - "EFI_BOOT_SERVICES"); - gBsList.push_back(insn.ops[0].addr); - } - bsFound = true; - } - /* here you can also find gST */ - if (insn.ops[1].reg == stRegister && !stFound && - stRegister != bsRegister) { - DEBUG_MSG("[%s] found SystemTable at 0x%016X, " - "address = " - "0x%016X\n", - plugin_name, ea, insn.ops[0].addr); - if (find(gStList.begin(), gStList.end(), - insn.ops[0].addr) == gStList.end() && - find(gBsList.begin(), gBsList.end(), - insn.ops[0].addr) == gBsList.end() && - find(gRtList.begin(), gRtList.end(), - insn.ops[0].addr) == gRtList.end()) { - char hexAddr[21] = {}; - snprintf( - hexAddr, 21, "%llX", - static_cast(insn.ops[0].addr)); - set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); - string name = - "gST_" + static_cast(hexAddr); - setPtrTypeAndName(insn.ops[0].addr, name, - "EFI_SYSTEM_TABLE"); - gStList.push_back(insn.ops[0].addr); + for (vector::iterator seg = textSegments.begin(); + seg != textSegments.end(); ++seg) { + segment_t *s = *seg; + DEBUG_MSG("[%s] BootServices tables finding from 0x%016X to 0x%016X\n", + plugin_name, s->start_ea, s->end_ea); + ea_t ea = s->start_ea; + uint16_t bsRegister = 0; + uint16_t stRegister = 0; + while (ea <= s->end_ea) { + decode_insn(&insn, ea); + if (insn.itype == NN_mov && insn.ops[1].type == o_displ && + insn.ops[1].phrase != REG_SP) { + if (insn.ops[0].type == o_reg && + insn.ops[1].addr == BS_OFFSET) { + bsRegister = insn.ops[0].reg; + stRegister = insn.ops[1].phrase; + auto bsFound = false; + auto stFound = false; + ea_t baseInsnAddr; + /* found BS_OFFSET, need to check 10 instructions below */ + for (auto i = 0; i < 10; i++) { + decode_insn(&insn, ea); + if (insn.itype == NN_mov && insn.ops[1].type == o_reg && + insn.ops[0].type == o_mem) { + if (insn.ops[1].reg == bsRegister && !bsFound) { + DEBUG_MSG( + "[%s] found BootServices table at 0x%016X, " + "address = " + "0x%016X\n", + plugin_name, ea, insn.ops[0].addr); + baseInsnAddr = ea; + if (find(gBsList.begin(), gBsList.end(), + insn.ops[0].addr) == gBsList.end()) { + char hexAddr[21] = {}; + snprintf(hexAddr, 21, "%llX", + static_cast( + insn.ops[0].addr)); + set_cmt(ea, "EFI_BOOT_SERVICES *gBS", true); + string name = + "gBS_" + static_cast(hexAddr); + setPtrTypeAndName(insn.ops[0].addr, name, + "EFI_BOOT_SERVICES"); + gBsList.push_back(insn.ops[0].addr); + } + bsFound = true; } - stFound = true; - } - } - if (bsFound && stFound) { - break; - } - if (bsFound && !stFound) { - /* check 8 instructions above baseInsnAddr */ - ea_t addr = prev_head(baseInsnAddr, startAddress); - for (auto i = 0; i < 8; i++) { - decode_insn(&insn, addr); - if (insn.itype == NN_mov && - insn.ops[1].type == o_reg && - insn.ops[1].reg == stRegister && - insn.ops[0].type == o_mem) { + /* here you can also find gST */ + if (insn.ops[1].reg == stRegister && !stFound && + stRegister != bsRegister) { DEBUG_MSG("[%s] found SystemTable at 0x%016X, " "address = " "0x%016X\n", - plugin_name, addr, insn.ops[0].addr); + plugin_name, ea, insn.ops[0].addr); if (find(gStList.begin(), gStList.end(), insn.ops[0].addr) == gStList.end() && find(gBsList.begin(), gBsList.end(), @@ -283,8 +312,7 @@ bool efiAnalysis::efiAnalyzer::findBootServicesTables(uint8_t arch) { snprintf(hexAddr, 21, "%llX", static_cast( insn.ops[0].addr)); - set_cmt(addr, "EFI_SYSTEM_TABLE *gST", - true); + set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); string name = "gST_" + static_cast(hexAddr); setPtrTypeAndName(insn.ops[0].addr, name, @@ -292,16 +320,60 @@ bool efiAnalysis::efiAnalyzer::findBootServicesTables(uint8_t arch) { gStList.push_back(insn.ops[0].addr); } stFound = true; - break; } - addr = prev_head(addr, startAddress); } + if (bsFound && stFound) { + break; + } + if (bsFound && !stFound) { + /* check 8 instructions above baseInsnAddr */ + ea_t addr = prev_head(baseInsnAddr, startAddress); + for (auto i = 0; i < 8; i++) { + decode_insn(&insn, addr); + if (insn.itype == NN_mov && + insn.ops[1].type == o_reg && + insn.ops[1].reg == stRegister && + insn.ops[0].type == o_mem) { + DEBUG_MSG( + "[%s] found SystemTable at 0x%016X, " + "address = " + "0x%016X\n", + plugin_name, addr, insn.ops[0].addr); + if (find(gStList.begin(), gStList.end(), + insn.ops[0].addr) == + gStList.end() && + find(gBsList.begin(), gBsList.end(), + insn.ops[0].addr) == + gBsList.end() && + find(gRtList.begin(), gRtList.end(), + insn.ops[0].addr) == + gRtList.end()) { + char hexAddr[21] = {}; + snprintf(hexAddr, 21, "%llX", + static_cast( + insn.ops[0].addr)); + set_cmt(addr, "EFI_SYSTEM_TABLE *gST", + true); + string name = + "gST_" + + static_cast(hexAddr); + setPtrTypeAndName(insn.ops[0].addr, + name, + "EFI_SYSTEM_TABLE"); + gStList.push_back(insn.ops[0].addr); + } + stFound = true; + break; + } + addr = prev_head(addr, startAddress); + } + } + ea = next_head(ea, endAddress); } - ea = next_head(ea, endAddress); } } + ea = next_head(ea, endAddress); } - ea = next_head(ea, endAddress); } return (gBsList.size() != 0); } @@ -311,8 +383,7 @@ bool efiAnalysis::efiAnalyzer::findBootServicesTables(uint8_t arch) { bool efiAnalysis::efiAnalyzer::findRuntimeServicesTables(uint8_t arch) { DEBUG_MSG("[%s] ========================================================\n", plugin_name); - DEBUG_MSG("[%s] RuntimeServices table finding from 0x%016X to 0x%016X\n", - plugin_name, startAddress, endAddress); + DEBUG_MSG("[%s] RuntimeServices tables finding\n", plugin_name); /* init architecture-specific constants */ auto RT_OFFSET = RT_OFFSET_X64; auto REG_SP = REG_RSP; @@ -320,85 +391,61 @@ bool efiAnalysis::efiAnalyzer::findRuntimeServicesTables(uint8_t arch) { RT_OFFSET = RT_OFFSET_X86; REG_SP = REG_ESP; } - ea_t ea = startAddress; insn_t insn; - uint16_t rtRegister = 0; - uint16_t stRegister = 0; - while (ea <= endAddress) { - decode_insn(&insn, ea); - if (insn.itype == NN_mov && insn.ops[1].type == o_displ && - insn.ops[1].phrase != REG_SP) { - if (insn.ops[0].type == o_reg && insn.ops[1].addr == RT_OFFSET) { - rtRegister = insn.ops[0].reg; - stRegister = insn.ops[1].phrase; - auto rtFound = false; - auto stFound = false; - ea_t baseInsnAddr; - /* found RT_OFFSET, need to check 10 instructions below */ - for (auto i = 0; i < 10; i++) { - decode_insn(&insn, ea); - if (insn.itype == NN_mov && insn.ops[1].type == o_reg && - insn.ops[0].type == o_mem) { - if (insn.ops[1].reg == rtRegister && !rtFound) { - DEBUG_MSG("[%s] found RuntimeServices table at " - "0x%016X, address " - "= 0x%016X\n", - plugin_name, ea, insn.ops[0].addr); - baseInsnAddr = ea; - if (find(gRtList.begin(), gRtList.end(), - insn.ops[0].addr) == gRtList.end()) { - char hexAddr[21] = {}; - snprintf( - hexAddr, 21, "%llX", - static_cast(insn.ops[0].addr)); - set_cmt(ea, "EFI_RUNTIME_SERVICES *gRT", true); - string name = - "gRT_" + static_cast(hexAddr); - setPtrTypeAndName(insn.ops[0].addr, name, - "EFI_RUNTIME_SERVICES"); - gRtList.push_back(insn.ops[0].addr); - } - rtFound = true; - } - /* here you can also find gST */ - if (insn.ops[1].reg == stRegister && !stFound && - stRegister != rtRegister) { - DEBUG_MSG("[%s] found SystemTable at 0x%016X, " - "address = " - "0x%016X\n", - plugin_name, ea, insn.ops[0].addr); - if (find(gStList.begin(), gStList.end(), - insn.ops[0].addr) == gStList.end()) { - char hexAddr[21] = {}; - snprintf( - hexAddr, 21, "%llX", - static_cast(insn.ops[0].addr)); - set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); - string name = - "gST_" + static_cast(hexAddr); - setPtrTypeAndName(insn.ops[0].addr, name, - "EFI_SYSTEM_TABLE"); - gStList.push_back(insn.ops[0].addr); + for (vector::iterator seg = textSegments.begin(); + seg != textSegments.end(); ++seg) { + segment_t *s = *seg; + DEBUG_MSG( + "[%s] RuntimeServices tables finding from 0x%016X to 0x%016X\n", + plugin_name, s->start_ea, s->end_ea); + ea_t ea = s->start_ea; + uint16_t rtRegister = 0; + uint16_t stRegister = 0; + while (ea <= s->end_ea) { + decode_insn(&insn, ea); + if (insn.itype == NN_mov && insn.ops[1].type == o_displ && + insn.ops[1].phrase != REG_SP) { + if (insn.ops[0].type == o_reg && + insn.ops[1].addr == RT_OFFSET) { + rtRegister = insn.ops[0].reg; + stRegister = insn.ops[1].phrase; + auto rtFound = false; + auto stFound = false; + ea_t baseInsnAddr; + /* found RT_OFFSET, need to check 10 instructions below */ + for (auto i = 0; i < 10; i++) { + decode_insn(&insn, ea); + if (insn.itype == NN_mov && insn.ops[1].type == o_reg && + insn.ops[0].type == o_mem) { + if (insn.ops[1].reg == rtRegister && !rtFound) { + DEBUG_MSG("[%s] found RuntimeServices table at " + "0x%016X, address " + "= 0x%016X\n", + plugin_name, ea, insn.ops[0].addr); + baseInsnAddr = ea; + if (find(gRtList.begin(), gRtList.end(), + insn.ops[0].addr) == gRtList.end()) { + char hexAddr[21] = {}; + snprintf(hexAddr, 21, "%llX", + static_cast( + insn.ops[0].addr)); + set_cmt(ea, "EFI_RUNTIME_SERVICES *gRT", + true); + string name = + "gRT_" + static_cast(hexAddr); + setPtrTypeAndName(insn.ops[0].addr, name, + "EFI_RUNTIME_SERVICES"); + gRtList.push_back(insn.ops[0].addr); + } + rtFound = true; } - stFound = true; - } - } - if (rtFound && stFound) { - break; - } - if (rtFound && !stFound) { - /* check 8 instructions above baseInsnAddr */ - ea_t addr = prev_head(baseInsnAddr, startAddress); - for (auto i = 0; i < 8; i++) { - decode_insn(&insn, addr); - if (insn.itype == NN_mov && - insn.ops[1].type == o_reg && - insn.ops[1].reg == stRegister && - insn.ops[0].type == o_mem) { + /* here you can also find gST */ + if (insn.ops[1].reg == stRegister && !stFound && + stRegister != rtRegister) { DEBUG_MSG("[%s] found SystemTable at 0x%016X, " "address = " "0x%016X\n", - plugin_name, addr, insn.ops[0].addr); + plugin_name, ea, insn.ops[0].addr); if (find(gStList.begin(), gStList.end(), insn.ops[0].addr) == gStList.end() && find(gBsList.begin(), gBsList.end(), @@ -409,8 +456,7 @@ bool efiAnalysis::efiAnalyzer::findRuntimeServicesTables(uint8_t arch) { snprintf(hexAddr, 21, "%llX", static_cast( insn.ops[0].addr)); - set_cmt(addr, "EFI_SYSTEM_TABLE *gST", - true); + set_cmt(ea, "EFI_SYSTEM_TABLE *gST", true); string name = "gST_" + static_cast(hexAddr); setPtrTypeAndName(insn.ops[0].addr, name, @@ -418,16 +464,60 @@ bool efiAnalysis::efiAnalyzer::findRuntimeServicesTables(uint8_t arch) { gStList.push_back(insn.ops[0].addr); } stFound = true; - break; } - addr = prev_head(addr, startAddress); } + if (rtFound && stFound) { + break; + } + if (rtFound && !stFound) { + /* check 8 instructions above baseInsnAddr */ + ea_t addr = prev_head(baseInsnAddr, startAddress); + for (auto i = 0; i < 8; i++) { + decode_insn(&insn, addr); + if (insn.itype == NN_mov && + insn.ops[1].type == o_reg && + insn.ops[1].reg == stRegister && + insn.ops[0].type == o_mem) { + DEBUG_MSG( + "[%s] found SystemTable at 0x%016X, " + "address = " + "0x%016X\n", + plugin_name, addr, insn.ops[0].addr); + if (find(gStList.begin(), gStList.end(), + insn.ops[0].addr) == + gStList.end() && + find(gBsList.begin(), gBsList.end(), + insn.ops[0].addr) == + gBsList.end() && + find(gRtList.begin(), gRtList.end(), + insn.ops[0].addr) == + gRtList.end()) { + char hexAddr[21] = {}; + snprintf(hexAddr, 21, "%llX", + static_cast( + insn.ops[0].addr)); + set_cmt(addr, "EFI_SYSTEM_TABLE *gST", + true); + string name = + "gST_" + + static_cast(hexAddr); + setPtrTypeAndName(insn.ops[0].addr, + name, + "EFI_SYSTEM_TABLE"); + gStList.push_back(insn.ops[0].addr); + } + stFound = true; + break; + } + addr = prev_head(addr, startAddress); + } + } + ea = next_head(ea, endAddress); } - ea = next_head(ea, endAddress); } } + ea = next_head(ea, endAddress); } - ea = next_head(ea, endAddress); } return (gRtList.size() != 0); } @@ -437,8 +527,7 @@ bool efiAnalysis::efiAnalyzer::findRuntimeServicesTables(uint8_t arch) { void efiAnalysis::efiAnalyzer::getAllBootServices(uint8_t arch) { DEBUG_MSG("[%s] ========================================================\n", plugin_name); - DEBUG_MSG("[%s] BootServices finding from 0x%016X to 0x%016X (all)\n", - plugin_name, startAddress, endAddress); + DEBUG_MSG("[%s] BootServices finding (all)\n", plugin_name) if (!gBsList.size()) { return; } @@ -447,71 +536,85 @@ void efiAnalysis::efiAnalyzer::getAllBootServices(uint8_t arch) { if (arch == X86) { REG_AX = REG_EAX; } - ea_t ea = startAddress; insn_t insn; + auto found = false; ft_table_t *table = ft_create_table(); ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER); ft_write_ln(table, " Address ", " Service "); - auto found = false; - while (ea <= endAddress) { - decode_insn(&insn, ea); - for (vector::iterator bs = gBsList.begin(); bs != gBsList.end(); - ++bs) { - if (insn.itype == NN_mov && insn.ops[0].reg == REG_AX && - insn.ops[1].type == o_mem && insn.ops[1].addr == *bs) { - ea_t addr = next_head(ea, BADADDR); - /* 16 instructions below */ - for (auto i = 0; i < 16; i++) { - decode_insn(&insn, addr); - if (insn.itype == NN_callni && insn.ops[0].reg == REG_AX) { - for (int j = 0; j < bootServicesTableAllLength; j++) { - /* architecture-specific variables */ - auto offset = bootServicesTableAll[j].offset64; - if (arch == X86) { - offset = bootServicesTableAll[j].offset86; - } - if (insn.ops[0].addr == static_cast(offset)) { - found = true; - string cmt = getBsComment( - static_cast(offset), arch); - set_cmt(addr, cmt.c_str(), true); - /* op_stroff */ - opStroff(addr, "EFI_BOOT_SERVICES"); - /* add line to table */ - ft_printf_ln( - table, " 0x%016X | %s ", - static_cast(addr), - static_cast( - bootServicesTableAll[j].service_name)); - DEBUG_MSG( - "[%s] 0x%016X : %s\n", plugin_name, addr, - static_cast( - bootServicesTableAll[j].service_name)); - bootServicesAll[static_cast( - bootServicesTableAll[j] - .service_name)] - .push_back(addr); - /* add item to allBootServices vector */ - json bsItem; - bsItem["address"] = addr; - bsItem["service_name"] = static_cast( - bootServicesTableAll[j].service_name); - bsItem["table_name"] = - static_cast("EFI_BOOT_SERVICES"); - bsItem["offset"] = offset; - if (find(allServices.begin(), allServices.end(), - bsItem) == allServices.end()) { - allServices.push_back(bsItem); + for (vector::iterator seg = textSegments.begin(); + seg != textSegments.end(); ++seg) { + segment_t *s = *seg; + DEBUG_MSG("[%s] BootServices finding from 0x%016X to 0x%016X (all)\n", + plugin_name, s->start_ea, s->end_ea); + ea_t ea = s->start_ea; + while (ea <= s->end_ea) { + decode_insn(&insn, ea); + for (vector::iterator bs = gBsList.begin(); + bs != gBsList.end(); ++bs) { + if (insn.itype == NN_mov && insn.ops[0].reg == REG_AX && + insn.ops[1].type == o_mem && insn.ops[1].addr == *bs) { + ea_t addr = next_head(ea, BADADDR); + /* 16 instructions below */ + for (auto i = 0; i < 16; i++) { + decode_insn(&insn, addr); + if (insn.itype == NN_callni && + insn.ops[0].reg == REG_AX) { + for (int j = 0; j < bootServicesTableAllLength; + j++) { + /* architecture-specific variables */ + auto offset = bootServicesTableAll[j].offset64; + if (arch == X86) { + offset = bootServicesTableAll[j].offset86; + } + if (insn.ops[0].addr == + static_cast(offset)) { + found = true; + string cmt = getBsComment( + static_cast(offset), arch); + set_cmt(addr, cmt.c_str(), true); + /* op_stroff */ + opStroff(addr, "EFI_BOOT_SERVICES"); + /* add line to table */ + ft_printf_ln( + table, " 0x%016X | %s ", + static_cast(addr), + static_cast( + bootServicesTableAll[j] + .service_name)); + DEBUG_MSG("[%s] 0x%016X : %s\n", + plugin_name, addr, + static_cast( + bootServicesTableAll[j] + .service_name)); + bootServicesAll[static_cast( + bootServicesTableAll[j] + .service_name)] + .push_back(addr); + /* add item to allBootServices vector */ + json bsItem; + bsItem["address"] = addr; + bsItem["service_name"] = + static_cast( + bootServicesTableAll[j] + .service_name); + bsItem["table_name"] = static_cast( + "EFI_BOOT_SERVICES"); + bsItem["offset"] = offset; + if (find(allServices.begin(), + allServices.end(), + bsItem) == allServices.end()) { + allServices.push_back(bsItem); + } + break; } - break; } } + addr = next_head(addr, BADADDR); } - addr = next_head(addr, BADADDR); } } + ea = next_head(ea, BADADDR); } - ea = next_head(ea, BADADDR); } if (found) { msg("[%s] Boot services (all):\n", plugin_name); @@ -525,79 +628,94 @@ void efiAnalysis::efiAnalyzer::getAllBootServices(uint8_t arch) { void efiAnalysis::efiAnalyzer::getAllRuntimeServices(uint8_t arch) { DEBUG_MSG("[%s] ========================================================\n", plugin_name); - DEBUG_MSG("[%s] RuntimeServices finding from 0x%016X to 0x%016X (all)\n", - plugin_name, startAddress, endAddress); + DEBUG_MSG("[%s] RuntimeServices finding (all)\n", plugin_name); if (!gRtList.size()) { return; } - ea_t ea = startAddress; insn_t insn; + auto found = false; ft_table_t *table = ft_create_table(); ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER); ft_write_ln(table, " Address ", " Service "); - auto found = false; - while (ea <= endAddress) { - decode_insn(&insn, ea); - for (vector::iterator rt = gRtList.begin(); rt != gRtList.end(); - ++rt) { - if (insn.itype == NN_mov && insn.ops[0].reg == REG_RAX && - insn.ops[1].type == o_mem && insn.ops[1].addr == *rt) { - ea_t addr = next_head(ea, BADADDR); - /* 16 instructions below */ - for (int i = 0; i < 16; i++) { - decode_insn(&insn, addr); - if (insn.itype == NN_callni && insn.ops[0].reg == REG_RAX) { - for (int j = 0; j < runtimeServicesTableAllLength; - j++) { - /* architecture-specific variables */ - auto offset = runtimeServicesTableAll[j].offset64; - if (arch == X86) { - offset = runtimeServicesTableAll[j].offset86; - } - if (insn.ops[0].addr == static_cast(offset)) { - found = true; - string cmt = getRtComment( - static_cast(offset), arch); - set_cmt(addr, cmt.c_str(), true); - /* op_stroff */ - opStroff(addr, "EFI_RUNTIME_SERVICES"); - /* add line to table */ - ft_printf_ln(table, " 0x%016X | %s ", - static_cast(addr), - static_cast( - runtimeServicesTableAll[j] - .service_name)); - DEBUG_MSG("[%s] 0x%016X : %s\n", plugin_name, - addr, - static_cast( - runtimeServicesTableAll[j] - .service_name)); - runtimeServicesAll - [static_cast( - runtimeServicesTableAll[j] - .service_name)] - .push_back(addr); - /* add item to allRuntimeServices vector */ - json rtItem; - rtItem["address"] = addr; - rtItem["service_name"] = static_cast( - runtimeServicesTableAll[j].service_name); - rtItem["table_name"] = - static_cast("EFI_RUNTIME_SERVICES"); - rtItem["offset"] = offset; - if (find(allServices.begin(), allServices.end(), - rtItem) == allServices.end()) { - allServices.push_back(rtItem); + for (vector::iterator seg = textSegments.begin(); + seg != textSegments.end(); ++seg) { + segment_t *s = *seg; + DEBUG_MSG( + "[%s] RuntimeServices finding from 0x%016X to 0x%016X (all)\n", + plugin_name, s->start_ea, s->end_ea); + ea_t ea = s->start_ea; + while (ea <= s->end_ea) { + decode_insn(&insn, ea); + for (vector::iterator rt = gRtList.begin(); + rt != gRtList.end(); ++rt) { + if (insn.itype == NN_mov && insn.ops[0].reg == REG_RAX && + insn.ops[1].type == o_mem && insn.ops[1].addr == *rt) { + ea_t addr = next_head(ea, BADADDR); + /* 16 instructions below */ + for (int i = 0; i < 16; i++) { + decode_insn(&insn, addr); + if (insn.itype == NN_callni && + insn.ops[0].reg == REG_RAX) { + for (int j = 0; j < runtimeServicesTableAllLength; + j++) { + /* architecture-specific variables */ + auto offset = + runtimeServicesTableAll[j].offset64; + if (arch == X86) { + offset = + runtimeServicesTableAll[j].offset86; + } + if (insn.ops[0].addr == + static_cast(offset)) { + found = true; + string cmt = getRtComment( + static_cast(offset), arch); + set_cmt(addr, cmt.c_str(), true); + /* op_stroff */ + opStroff(addr, "EFI_RUNTIME_SERVICES"); + /* add line to table */ + ft_printf_ln( + table, " 0x%016X | %s ", + static_cast(addr), + static_cast( + runtimeServicesTableAll[j] + .service_name)); + DEBUG_MSG("[%s] 0x%016X : %s\n", + plugin_name, addr, + static_cast( + runtimeServicesTableAll[j] + .service_name)); + runtimeServicesAll + [static_cast( + runtimeServicesTableAll[j] + .service_name)] + .push_back(addr); + /* add item to allRuntimeServices vector */ + json rtItem; + rtItem["address"] = addr; + rtItem["service_name"] = + static_cast( + runtimeServicesTableAll[j] + .service_name); + rtItem["table_name"] = static_cast( + "EFI_RUNTIME_SERVICES"); + rtItem["offset"] = offset; + if (find(allServices.begin(), + allServices.end(), + rtItem) == allServices.end()) { + allServices.push_back(rtItem); + } + gRtServicesList.push_back(addr); + break; } - break; } } + addr = next_head(addr, BADADDR); } - addr = next_head(addr, BADADDR); } } + ea = next_head(ea, BADADDR); } - ea = next_head(ea, BADADDR); } if (found) { msg("[%s] Runtime services (all):\n", plugin_name); @@ -611,85 +729,99 @@ void efiAnalysis::efiAnalyzer::getAllRuntimeServices(uint8_t arch) { void efiAnalysis::efiAnalyzer::getAllSmmServicesX64() { DEBUG_MSG("[%s] ========================================================\n", plugin_name); - DEBUG_MSG("[%s] SmmServices finding from 0x%016X to 0x%016X (all)\n", - plugin_name, startAddress, endAddress); + DEBUG_MSG("[%s] SmmServices finding (all)\n", plugin_name); if (!gSmstList.size()) { return; } - ea_t ea = startAddress; insn_t insn; + auto found = false; ft_table_t *table = ft_create_table(); ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER); ft_write_ln(table, " Address ", " Service "); - auto found = false; - while (ea <= endAddress) { - decode_insn(&insn, ea); - for (vector::iterator smms = gSmstList.begin(); - smms != gSmstList.end(); ++smms) { - if (insn.itype == NN_mov && insn.ops[0].reg == REG_RAX && - insn.ops[1].type == o_mem && insn.ops[1].addr == *smms) { - ea_t addr = ea; - /* 10 instructions below */ - for (auto i = 0; i < 10; i++) { - decode_insn(&insn, addr); - if (insn.itype == NN_callni && insn.ops[0].reg == REG_RAX) { - for (int j = 0; j < smmServicesTableAllLength; j++) { - if (insn.ops[0].addr == - static_cast( - smmServicesTableAll[j].offset64)) { - found = true; - string cmt = - "gSmst->" + - static_cast( - smmServicesTableAll[j].service_name); - set_cmt(addr, cmt.c_str(), true); - /* op_stroff */ - opStroff(addr, "_EFI_SMM_SYSTEM_TABLE2"); - /* add line to table */ - ft_printf_ln( - table, " 0x%016X | %s ", - static_cast(addr), - static_cast( - smmServicesTableAll[j].service_name)); - DEBUG_MSG( - "[%s] 0x%016X : %s\n", plugin_name, addr, - static_cast( - smmServicesTableAll[j].service_name)); - /* add address to smmServices[...] vector */ - if (find(protSmmNames.begin(), - protSmmNames.end(), - smmServicesTableAll[j].service_name) != - protSmmNames.end()) { - smmServices[smmServicesTableAll[j] - .service_name] + for (vector::iterator seg = textSegments.begin(); + seg != textSegments.end(); ++seg) { + segment_t *s = *seg; + DEBUG_MSG("[%s] SmmServices finding from 0x%016X to 0x%016X\n", + plugin_name, s->start_ea, s->end_ea); + ea_t ea = s->start_ea; + while (ea <= s->end_ea) { + decode_insn(&insn, ea); + for (vector::iterator smms = gSmstList.begin(); + smms != gSmstList.end(); ++smms) { + if (insn.itype == NN_mov && insn.ops[0].reg == REG_RAX && + insn.ops[1].type == o_mem && insn.ops[1].addr == *smms) { + ea_t addr = ea; + /* 10 instructions below */ + for (auto i = 0; i < 10; i++) { + decode_insn(&insn, addr); + if (insn.itype == NN_callni && + insn.ops[0].reg == REG_RAX) { + for (int j = 0; j < smmServicesTableAllLength; + j++) { + if (insn.ops[0].addr == + static_cast( + smmServicesTableAll[j].offset64)) { + found = true; + string cmt = + "gSmst->" + static_cast( + smmServicesTableAll[j] + .service_name); + set_cmt(addr, cmt.c_str(), true); + /* op_stroff */ + opStroff(addr, "_EFI_SMM_SYSTEM_TABLE2"); + /* add line to table */ + ft_printf_ln( + table, " 0x%016X | %s ", + static_cast(addr), + static_cast( + smmServicesTableAll[j] + .service_name)); + DEBUG_MSG("[%s] 0x%016X : %s\n", + plugin_name, addr, + static_cast( + smmServicesTableAll[j] + .service_name)); + /* add address to smmServices[...] vector */ + if (find(protSmmNames.begin(), + protSmmNames.end(), + smmServicesTableAll[j] + .service_name) != + protSmmNames.end()) { + smmServices[smmServicesTableAll[j] + .service_name] + .push_back(addr); + } + smmServicesAll[static_cast( + smmServicesTableAll[j] + .service_name)] .push_back(addr); + /* add item to allSmmServices vector */ + json smmsItem; + smmsItem["address"] = addr; + smmsItem["service_name"] = + static_cast( + smmServicesTableAll[j] + .service_name); + smmsItem["table_name"] = + static_cast( + "_EFI_SMM_SYSTEM_TABLE2"); + smmsItem["offset"] = + smmServicesTableAll[j].offset64; + if (find(allServices.begin(), + allServices.end(), + smmsItem) == allServices.end()) { + allServices.push_back(smmsItem); + } + break; } - smmServicesAll[static_cast( - smmServicesTableAll[j] - .service_name)] - .push_back(addr); - /* add item to allSmmServices vector */ - json smmsItem; - smmsItem["address"] = addr; - smmsItem["service_name"] = static_cast( - smmServicesTableAll[j].service_name); - smmsItem["table_name"] = static_cast( - "_EFI_SMM_SYSTEM_TABLE2"); - smmsItem["offset"] = - smmServicesTableAll[j].offset64; - if (find(allServices.begin(), allServices.end(), - smmsItem) == allServices.end()) { - allServices.push_back(smmsItem); - } - break; } } + addr = next_head(addr, BADADDR); } - addr = next_head(addr, BADADDR); } } + ea = next_head(ea, BADADDR); } - ea = next_head(ea, BADADDR); } if (found) { msg("[%s] SMM services (all):\n", plugin_name); @@ -766,8 +898,7 @@ void efiAnalysis::efiAnalyzer::getAllPeiServicesX86() { static_cast(ea), static_cast(pei_services_table[j].name)); DEBUG_MSG( - "[%s] 0x%016X : %s\n", - plugin_name, ea, + "[%s] 0x%016X : %s\n", plugin_name, ea, static_cast(pei_services_table[j].name)); peiServicesAll[static_cast( pei_services_table[j].name)] @@ -780,7 +911,7 @@ void efiAnalysis::efiAnalyzer::getAllPeiServicesX86() { static_cast("EFI_PEI_SERVICES"); psItem["offset"] = pei_services_table[j].offset; if (find(allServices.begin(), allServices.end(), - psItem) == allServices.end()) { + psItem) == allServices.end()) { allServices.push_back(psItem); } } @@ -802,54 +933,61 @@ void efiAnalysis::efiAnalyzer::getAllPeiServicesX86() { void efiAnalysis::efiAnalyzer::getProtBootServicesX64() { DEBUG_MSG("[%s] ========================================================\n", plugin_name); - DEBUG_MSG("[%s] BootServices finding from 0x%016X to 0x%016X (protocols)\n", - plugin_name, startAddress, endAddress); - ea_t ea = startAddress; + DEBUG_MSG("[%s] BootServices finding (protocols)\n", plugin_name) insn_t insn; - uint16_t bsRegister = 0; ft_table_t *table = ft_create_table(); ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER); ft_write_ln(table, " Address ", " Service "); - while (ea <= endAddress) { - decode_insn(&insn, ea); - if (insn.itype == NN_callni && insn.ops[0].reg == REG_RAX) { - for (auto i = 0; i < bootServicesTableX64Length; i++) { - if (insn.ops[0].addr == - static_cast(bootServicesTableX64[i].offset)) { - /* set comment */ - string cmt = getBsComment( - static_cast(bootServicesTableX64[i].offset), X64); - set_cmt(ea, cmt.c_str(), true); - /* op_stroff */ - opStroff(ea, "EFI_BOOT_SERVICES"); - /* add line to table */ - ft_printf_ln(table, " 0x%016X | %s ", - static_cast(ea), - static_cast( - bootServicesTableX64[i].service_name)); - DEBUG_MSG("[%s] 0x%016X : %s\n", plugin_name, ea, - static_cast( - bootServicesTableX64[i].service_name)); - bootServices[static_cast( - bootServicesTableX64[i].service_name)] - .push_back(ea); - /* add item to allBootServices vector */ - json bsItem; - bsItem["address"] = ea; - bsItem["service_name"] = static_cast( - bootServicesTableX64[i].service_name); - bsItem["table_name"] = - static_cast("EFI_BOOT_SERVICES"); - bsItem["offset"] = bootServicesTableX64[i].offset; - if (find(allServices.begin(), allServices.end(), bsItem) == - allServices.end()) { - allServices.push_back(bsItem); + for (vector::iterator seg = textSegments.begin(); + seg != textSegments.end(); ++seg) { + segment_t *s = *seg; + DEBUG_MSG( + "[%s] BootServices finding from 0x%016X to 0x%016X (protocols)\n", + plugin_name, s->start_ea, s->end_ea); + ea_t ea = s->start_ea; + uint16_t bsRegister = 0; + while (ea <= s->end_ea) { + decode_insn(&insn, ea); + if (insn.itype == NN_callni && insn.ops[0].reg == REG_RAX) { + for (auto i = 0; i < bootServicesTableX64Length; i++) { + if (insn.ops[0].addr == + static_cast(bootServicesTableX64[i].offset)) { + /* set comment */ + string cmt = getBsComment( + static_cast(bootServicesTableX64[i].offset), + X64); + set_cmt(ea, cmt.c_str(), true); + /* op_stroff */ + opStroff(ea, "EFI_BOOT_SERVICES"); + /* add line to table */ + ft_printf_ln(table, " 0x%016X | %s ", + static_cast(ea), + static_cast( + bootServicesTableX64[i].service_name)); + DEBUG_MSG("[%s] 0x%016X : %s\n", plugin_name, ea, + static_cast( + bootServicesTableX64[i].service_name)); + bootServices[static_cast( + bootServicesTableX64[i].service_name)] + .push_back(ea); + /* add item to allBootServices vector */ + json bsItem; + bsItem["address"] = ea; + bsItem["service_name"] = static_cast( + bootServicesTableX64[i].service_name); + bsItem["table_name"] = + static_cast("EFI_BOOT_SERVICES"); + bsItem["offset"] = bootServicesTableX64[i].offset; + if (find(allServices.begin(), allServices.end(), + bsItem) == allServices.end()) { + allServices.push_back(bsItem); + } + break; } - break; } } + ea = next_head(ea, endAddress); } - ea = next_head(ea, endAddress); } msg("[%s] Boot services (protocols):\n", plugin_name); msg(ft_to_string(table)); @@ -947,7 +1085,9 @@ void efiAnalysis::efiAnalyzer::findOtherBsTablesX64() { snprintf(hexAddr, 21, "%llX", static_cast(addrBs)); string name = "gBS_" + static_cast(hexAddr); setPtrTypeAndName(addrBs, name, "EFI_BOOT_SERVICES"); - gBsList.push_back(addrBs); + if (find(gRtList.begin(), gRtList.end(), addrBs) == gRtList.end()) { + gBsList.push_back(addrBs); + } } } @@ -956,12 +1096,14 @@ void efiAnalysis::efiAnalyzer::findOtherBsTablesX64() { void efiAnalysis::efiAnalyzer::getBsProtNamesX64() { DEBUG_MSG("[%s] ========================================================\n", plugin_name); - DEBUG_MSG("[%s] protocols finding (boot services)\n", plugin_name); - ea_t start = startAddress; - segment_t *seg_info = get_segm_by_name(".text"); - if (seg_info != nullptr) { - start = seg_info->start_ea; + if (!textSegments.size()) { + return; } + segment_t *s = textSegments.at(0); + ea_t start = s->start_ea; + DEBUG_MSG( + "[%s] protocols finding (boot services, start address = 0x%016X)\n", + plugin_name, start); for (int i = 0; i < bootServicesTableX64Length; i++) { vector addrs = bootServices[bootServicesTableX64[i].service_name]; vector::iterator ea; @@ -982,7 +1124,7 @@ void efiAnalysis::efiAnalyzer::getBsProtNamesX64() { insn.ops[0].reg == bootServicesTableX64[i].reg) { guidCodeAddress = address; guidDataAddress = insn.ops[1].addr; - if (insn.ops[1].addr > start and + if (insn.ops[1].addr > start && insn.ops[1].addr != BADADDR) { found = true; break; @@ -1005,10 +1147,10 @@ void efiAnalysis::efiAnalyzer::getBsProtNamesX64() { get_wide_byte(guidDataAddress + 14), get_wide_byte(guidDataAddress + 15)}); /* check guid */ - if ((static_cast(guid[0]) == 0x00000000 and - (uint16_t) guid[1] == 0x0000) or - (static_cast(guid[0]) == 0xffffffff and - (uint16_t) guid[1] == 0xffff)) { + if ((static_cast(guid[0]) == 0x00000000 && + (uint16_t)guid[1] == 0x0000) || + (static_cast(guid[0]) == 0xffffffff && + (uint16_t)guid[1] == 0xffff)) { DEBUG_MSG("[%s] Incorrect GUID at 0x%016X\n", plugin_name, guidCodeAddress); continue; @@ -1093,7 +1235,7 @@ void efiAnalysis::efiAnalyzer::getBsProtNamesX86() { if (pushCounter == pushNumber) { guidCodeAddress = address; guidDataAddress = insn.ops[0].value; - if (insn.ops[0].value > start and + if (insn.ops[0].value > start && insn.ops[0].value != BADADDR) { found = true; break; @@ -1117,10 +1259,10 @@ void efiAnalysis::efiAnalyzer::getBsProtNamesX86() { get_wide_byte(guidDataAddress + 14), get_wide_byte(guidDataAddress + 15)}); /* check guid */ - if ((static_cast(guid[0]) == 0x00000000 and - (uint16_t) guid[1] == 0x0000) or - (static_cast(guid[0]) == 0xffffffff and - (uint16_t) guid[1] == 0xffff)) { + if ((static_cast(guid[0]) == 0x00000000 && + (uint16_t)guid[1] == 0x0000) || + (static_cast(guid[0]) == 0xffffffff && + (uint16_t)guid[1] == 0xffff)) { DEBUG_MSG("[%s] Incorrect GUID at 0x%016X\n", plugin_name, guidCodeAddress); continue; @@ -1169,12 +1311,14 @@ void efiAnalysis::efiAnalyzer::getBsProtNamesX86() { void efiAnalysis::efiAnalyzer::getSmmProtNamesX64() { DEBUG_MSG("[%s] ========================================================\n", plugin_name); - DEBUG_MSG("[%s] protocols finding (smm services)\n", plugin_name); - ea_t start = startAddress; - segment_t *seg_info = get_segm_by_name(".text"); - if (seg_info != nullptr) { - start = seg_info->start_ea; + if (!textSegments.size()) { + return; } + segment_t *s = textSegments.at(0); + ea_t start = s->start_ea; + DEBUG_MSG( + "[%s] protocols finding (smm services, start address = 0x%016X)\n", + plugin_name, start); for (int i = 0; i < smmServicesProtX64Length; i++) { vector addrs = smmServices[smmServicesProtX64[i].service_name]; vector::iterator ea; @@ -1195,7 +1339,7 @@ void efiAnalysis::efiAnalyzer::getSmmProtNamesX64() { insn.ops[0].reg == smmServicesProtX64[i].reg) { guidCodeAddress = address; guidDataAddress = insn.ops[1].addr; - if (insn.ops[1].addr > start and + if (insn.ops[1].addr > start && insn.ops[1].addr != BADADDR) { found = true; break; @@ -1218,10 +1362,10 @@ void efiAnalysis::efiAnalyzer::getSmmProtNamesX64() { get_wide_byte(guidDataAddress + 14), get_wide_byte(guidDataAddress + 15)}); /* check guid */ - if ((static_cast(guid[0]) == 0x00000000 and - (uint16_t) guid[1] == 0x0000) or - (static_cast(guid[0]) == 0xffffffff and - (uint16_t) guid[1] == 0xffff)) { + if ((static_cast(guid[0]) == 0x00000000 && + (uint16_t)guid[1] == 0x0000) || + (static_cast(guid[0]) == 0xffffffff && + (uint16_t)guid[1] == 0xffff)) { DEBUG_MSG("[%s] Incorrect GUID at 0x%016X\n", plugin_name, guidCodeAddress); continue; @@ -1326,7 +1470,7 @@ void efiAnalysis::efiAnalyzer::markProtocols() { } char hexAddr[21] = {}; snprintf(hexAddr, 21, "%llX", static_cast(address)); - string protName = protItem["prot_name"].get(); + string protName = static_cast(protItem["prot_name"]); string name = protName + "_" + static_cast(hexAddr); set_name(address, name.c_str(), SN_CHECK); setGuidType(address); @@ -1344,22 +1488,13 @@ void efiAnalysis::efiAnalyzer::markProtocols() { void efiAnalysis::efiAnalyzer::markDataGuids() { DEBUG_MSG("[%s] ========================================================\n", plugin_name); - vector segments = {".data"}; - for (vector::iterator seg = segments.begin(); seg != segments.end(); - ++seg) { - string segName = *seg; - DEBUG_MSG("[%s] marking GUIDs from %s segment\n", plugin_name, - segName.c_str()); - segment_t *seg_info = get_segm_by_name(segName.c_str()); - if (seg_info == NULL) { - DEBUG_MSG("[%s] can't find a %s segment\n", plugin_name, - segName.c_str()); - continue; - } - DEBUG_MSG("[%s] start = 0x%016X, end = 0x%016X\n", plugin_name, - seg_info->start_ea, seg_info->end_ea); - ea_t ea = seg_info->start_ea; - while (ea != BADADDR && ea <= seg_info->end_ea - 15) { + for (vector::iterator seg = dataSegments.begin(); + seg != dataSegments.end(); ++seg) { + segment_t *s = *seg; + DEBUG_MSG("[%s] marking .data GUIDs from 0x%016X to 0x%016X\n", + plugin_name, s->start_ea, s->end_ea); + ea_t ea = s->start_ea; + while (ea != BADADDR && ea <= s->end_ea - 15) { if (get_wide_dword(ea) == 0x00000000 || get_wide_dword(ea) == 0xffffffff) { ea += 1; @@ -1421,88 +1556,94 @@ void efiAnalysis::efiAnalyzer::markDataGuids() { void efiAnalysis::efiAnalyzer::markLocalGuidsX64() { DEBUG_MSG("[%s] ========================================================\n", plugin_name); - DEBUG_MSG("[%s] local GUIDs finding from 0x%016X to 0x%016X\n", plugin_name, - startAddress, endAddress); - ea_t ea = startAddress; - insn_t insn; - insn_t insnNext; - while (ea <= endAddress) { - decode_insn(&insn, ea); - /* check if insn like 'mov dword ptr [...], gData1' */ - if (insn.itype == NN_mov && insn.ops[0].type == o_displ && - insn.ops[1].type == o_imm) { - /* get guid->data1 value */ - uint32_t gData1 = static_cast(insn.ops[1].value); - if (gData1 == 0x00000000 || gData1 == 0xffffffff) { - ea = next_head(ea, BADADDR); - continue; - } - ea_t eaNext = next_head(ea, BADADDR); - decode_insn(&insnNext, eaNext); - /* check if insn like 'mov dword ptr [...], gData2' */ - if (insnNext.itype == NN_mov && insnNext.ops[0].type == o_displ && - insnNext.ops[1].type == o_imm) { - /* get guid->data2 value */ - uint16_t gData2 = static_cast(insnNext.ops[1].value); - if (gData2 == 0x0000 || gData2 == 0xffff) { + for (vector::iterator seg = textSegments.begin(); + seg != textSegments.end(); ++seg) { + segment_t *s = *seg; + ea_t ea = s->start_ea; + insn_t insn; + insn_t insnNext; + DEBUG_MSG("[%s] local GUIDs finding from 0x%016X to 0x%016X\n", + plugin_name, s->start_ea, s->end_ea); + while (ea <= s->end_ea) { + decode_insn(&insn, ea); + /* check if insn like 'mov dword ptr [...], gData1' */ + if (insn.itype == NN_mov && insn.ops[0].type == o_displ && + insn.ops[1].type == o_imm) { + /* get guid->data1 value */ + uint32_t gData1 = static_cast(insn.ops[1].value); + if (gData1 == 0x00000000 || gData1 == 0xffffffff) { ea = next_head(ea, BADADDR); continue; } - /* found guid->data1 and guid->data2 values, try to get guid - * name */ - json::iterator dbItem; - for (dbItem = dbProtocols.begin(); dbItem != dbProtocols.end(); - ++dbItem) { - auto guid = dbItem.value(); - if (gData1 == static_cast(guid[0]) && - gData2 == static_cast(guid[1])) { - /* mark local guid */ - char hexAddr[21] = {}; - snprintf(hexAddr, 21, "%llX", - static_cast(ea)); - string name = - dbItem.key() + "_" + static_cast(hexAddr); - /* comment line */ - string comment = "EFI_GUID " + dbItem.key(); - DEBUG_MSG("[%s] address: 0x%016X, comment: %s\n", - plugin_name, ea, comment.c_str()); - /* set comment */ - set_cmt(ea, comment.c_str(), true); - json guidItem; - guidItem["address"] = ea; - guidItem["name"] = dbItem.key(); - char guidValue[37] = {0}; - snprintf(guidValue, 37, - "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%" - "02X%02X", - static_cast(guid[0]), - static_cast(guid[1]), - static_cast(guid[2]), - static_cast(guid[3]), - static_cast(guid[4]), - static_cast(guid[5]), - static_cast(guid[6]), - static_cast(guid[7]), - static_cast(guid[8]), - static_cast(guid[9]), - static_cast(guid[10])); - guidItem["guid"] = guidValue; - dataGuids.push_back(guidItem); - break; + ea_t eaNext = next_head(ea, BADADDR); + decode_insn(&insnNext, eaNext); + /* check if insn like 'mov dword ptr [...], gData2' */ + if (insnNext.itype == NN_mov && + insnNext.ops[0].type == o_displ && + insnNext.ops[1].type == o_imm) { + /* get guid->data2 value */ + uint16_t gData2 = + static_cast(insnNext.ops[1].value); + if (gData2 == 0x0000 || gData2 == 0xffff) { + ea = next_head(ea, BADADDR); + continue; + } + /* found guid->data1 and guid->data2 values, try to get guid + * name */ + json::iterator dbItem; + for (dbItem = dbProtocols.begin(); + dbItem != dbProtocols.end(); ++dbItem) { + auto guid = dbItem.value(); + if (gData1 == static_cast(guid[0]) && + gData2 == static_cast(guid[1])) { + /* mark local guid */ + char hexAddr[21] = {}; + snprintf(hexAddr, 21, "%llX", + static_cast(ea)); + string name = dbItem.key() + "_" + + static_cast(hexAddr); + /* comment line */ + string comment = "EFI_GUID " + dbItem.key(); + DEBUG_MSG("[%s] address: 0x%016X, comment: %s\n", + plugin_name, ea, comment.c_str()); + /* set comment */ + set_cmt(ea, comment.c_str(), true); + json guidItem; + guidItem["address"] = ea; + guidItem["name"] = dbItem.key(); + char guidValue[37] = {0}; + snprintf(guidValue, 37, + "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%" + "02X%02X", + static_cast(guid[0]), + static_cast(guid[1]), + static_cast(guid[2]), + static_cast(guid[3]), + static_cast(guid[4]), + static_cast(guid[5]), + static_cast(guid[6]), + static_cast(guid[7]), + static_cast(guid[8]), + static_cast(guid[9]), + static_cast(guid[10])); + guidItem["guid"] = guidValue; + dataGuids.push_back(guidItem); + break; + } } } } + ea = next_head(ea, BADADDR); } - ea = next_head(ea, BADADDR); } } //-------------------------------------------------------------------------- // Find SwSmiHandler function inside SMM drivers -func_t *efiAnalysis::efiAnalyzer::findSwSmiHandler() { +vector efiAnalysis::efiAnalyzer::findSwSmiHandlers() { DEBUG_MSG("[%s] ========================================================\n", plugin_name); - return findSmiHandlerSmmSwDispatch(); + return findSmiHandlersSmmSwDispatch(dataSegments); } //-------------------------------------------------------------------------- @@ -1535,6 +1676,9 @@ bool efiAnalysis::efiAnalyzerMainX64() { auto_wait(); }; + /* find .text and .data segments */ + analyzer.getSegments(); + /* find global vars for gImageHandle, gST, gBS, gRT, gSmst */ if (analyzer.fileType == FTYPE_DXE_AND_THE_LIKE) { analyzer.findImageHandleX64(); @@ -1544,14 +1688,12 @@ bool efiAnalysis::efiAnalyzerMainX64() { analyzer.findSmstX64(); /* find boot services and runtime services */ - analyzer.getAllRuntimeServices(X64); analyzer.getProtBootServicesX64(); - - /* other addresses of global gBS values finding */ analyzer.findOtherBsTablesX64(); analyzer.getAllBootServices(X64); + analyzer.getAllRuntimeServices(X64); - /* find smm services */ + /* find SMM services */ analyzer.getAllSmmServicesX64(); /* print and mark protocols */ @@ -1564,8 +1706,8 @@ bool efiAnalysis::efiAnalyzerMainX64() { analyzer.markDataGuids(); analyzer.markLocalGuidsX64(); - /* find SwSmiHandler function */ - analyzer.findSwSmiHandler(); + /* find software SMI handlers */ + analyzer.findSwSmiHandlers(); } /* show all choosers windows */ diff --git a/src/efiAnalysis.h b/src/efiAnalysis.h index f5dff048..a3aefb1e 100644 --- a/src/efiAnalysis.h +++ b/src/efiAnalysis.h @@ -32,12 +32,15 @@ #include "efiUtils.h" namespace efiAnalysis { + class efiAnalyzer { public: vector dataGuids; vector allProtocols; vector allServices; + void getSegments(); + bool findImageHandleX64(); bool findSystemTableX64(); bool findBootServicesTables(uint8_t arch); @@ -62,7 +65,7 @@ class efiAnalyzer { void markDataGuids(); void markLocalGuidsX64(); - func_t *findSwSmiHandler(); + vector findSwSmiHandlers(); efiAnalyzer(); ~efiAnalyzer(); @@ -73,7 +76,7 @@ class efiAnalyzer { ea_t base; ea_t startAddress = 0; ea_t endAddress = 0; - ea_t mainAddress; + ea_t mainAddress{}; path guidsJsonPath; json bootServices; json bootServicesAll; @@ -97,6 +100,7 @@ class efiAnalyzer { "LocateProtocol", "InstallMultipleProtocolInterfaces", "UninstallMultipleProtocolInterfaces"}; + /* set smm services that work with protocols */ vector protSmmNames = {"SmmInstallProtocolInterface", "SmmUninstallProtocolInterface", diff --git a/src/efiSmmUtils.cpp b/src/efiSmmUtils.cpp index 897ca644..9a148a27 100644 --- a/src/efiSmmUtils.cpp +++ b/src/efiSmmUtils.cpp @@ -36,7 +36,8 @@ static const char plugin_name[] = "efiXplorer"; //-------------------------------------------------------------------------- // Find and mark gSmst global variable via EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID -vector findSmstSwDispatch(vector gBsList) { +vector findSmstSwDispatch(vector gBsList, + vector dataSegments) { vector resAddrs; efiGuid efiSmmSwDispatch2ProtocolGuid = { 0x18a3c6dc, @@ -49,52 +50,59 @@ vector findSmstSwDispatch(vector gBsList) { 0x420c, {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, 0xbf}}; ea_t efiSmmSwDispatchProtocolGuidAddr = 0; - string segName = ".data"; - segment_t *seg_info = get_segm_by_name(segName.c_str()); - if (seg_info == nullptr) { - return resAddrs; - } - ea_t ea = seg_info->start_ea; - while (ea != BADADDR && ea <= seg_info->end_ea - 15) { - if (get_wide_dword(ea) == efiSmmSwDispatchProtocolGuid.data1) { - efiSmmSwDispatchProtocolGuidAddr = ea; - break; + for (vector::iterator seg = dataSegments.begin(); + seg != dataSegments.end(); ++seg) { + segment_t *seg_info = *seg; + if (seg_info == nullptr) { + return resAddrs; } - ea += 1; - } - if (!efiSmmSwDispatchProtocolGuidAddr) { - return resAddrs; - } - vector efiSmmSwDispatchProtocolGuidXrefs = - getXrefs(efiSmmSwDispatchProtocolGuidAddr); - for (vector::iterator guidXref = - efiSmmSwDispatchProtocolGuidXrefs.begin(); - guidXref != efiSmmSwDispatchProtocolGuidXrefs.end(); ++guidXref) { - ea_t resAddr = 0; - ea_t curAddr = prev_head(*guidXref, 0); - insn_t insn; - /* 4 instructions below */ - for (auto i = 0; i < 4; i++) { - decode_insn(&insn, curAddr); - /* check if insn like 'mov rax, cs:' */ - if (insn.itype == NN_mov && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RAX && insn.ops[1].type == o_mem) { - DEBUG_MSG("[%s] found gSmst at 0x%016X, address = 0x%016X\n", - plugin_name, curAddr, insn.ops[1].addr); - resAddr = insn.ops[1].addr; - if (find(gBsList.begin(), gBsList.end(), resAddr) != - gBsList.end()) { - continue; - } - char hexAddr[21] = {}; - snprintf(hexAddr, 21, "%llX", static_cast(resAddr)); - set_cmt(curAddr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); - string name = "gSmst_" + static_cast(hexAddr); - setPtrTypeAndName(resAddr, name, "_EFI_SMM_SYSTEM_TABLE2"); - resAddrs.push_back(resAddr); + DEBUG_MSG("[%s] gSmst finding from 0x%016X to 0x%016X (via " + "EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID)\n", + plugin_name, seg_info->start_ea, seg_info->end_ea); + ea_t ea = seg_info->start_ea; + while (ea != BADADDR && ea <= seg_info->end_ea - 15) { + if (get_wide_dword(ea) == efiSmmSwDispatchProtocolGuid.data1) { + efiSmmSwDispatchProtocolGuidAddr = ea; break; } - curAddr = prev_head(curAddr, 0); + ea += 1; + } + if (!efiSmmSwDispatchProtocolGuidAddr) { + continue; + } + vector efiSmmSwDispatchProtocolGuidXrefs = + getXrefs(efiSmmSwDispatchProtocolGuidAddr); + for (vector::iterator guidXref = + efiSmmSwDispatchProtocolGuidXrefs.begin(); + guidXref != efiSmmSwDispatchProtocolGuidXrefs.end(); ++guidXref) { + ea_t resAddr = 0; + ea_t curAddr = prev_head(*guidXref, 0); + insn_t insn; + /* 4 instructions below */ + for (auto i = 0; i < 4; i++) { + decode_insn(&insn, curAddr); + /* check if insn like 'mov rax, cs:' */ + if (insn.itype == NN_mov && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_RAX && insn.ops[1].type == o_mem) { + DEBUG_MSG( + "[%s] found gSmst at 0x%016X, address = 0x%016X\n", + plugin_name, curAddr, insn.ops[1].addr); + resAddr = insn.ops[1].addr; + if (find(gBsList.begin(), gBsList.end(), resAddr) != + gBsList.end()) { + continue; + } + char hexAddr[21] = {}; + snprintf(hexAddr, 21, "%llX", + static_cast(resAddr)); + set_cmt(curAddr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); + string name = "gSmst_" + static_cast(hexAddr); + setPtrTypeAndName(resAddr, name, "_EFI_SMM_SYSTEM_TABLE2"); + resAddrs.push_back(resAddr); + break; + } + curAddr = prev_head(curAddr, 0); + } } } return resAddrs; @@ -102,7 +110,8 @@ vector findSmstSwDispatch(vector gBsList) { //-------------------------------------------------------------------------- // Find and mark gSmst global variable via EFI_SMM_BASE2_PROTOCOL_GUID -vector findSmstSmmBase(vector gBsList) { +vector findSmstSmmBase(vector gBsList, + vector dataSegments) { vector resAddrs; efiGuid efiSmmBase2ProtocolGuid = { 0xf4ccbfb7, @@ -110,51 +119,59 @@ vector findSmstSmmBase(vector gBsList) { 0x47fd, {0x9d, 0xd4, 0x10, 0xa8, 0xf1, 0x50, 0xc1, 0x91}}; ea_t efiSmmBase2ProtocolGuidAddr = 0; - string segName = ".data"; - segment_t *seg_info = get_segm_by_name(segName.c_str()); - if (seg_info == nullptr) { - return resAddrs; - } - ea_t ea = seg_info->start_ea; - while (ea != BADADDR && ea <= seg_info->end_ea - 15) { - if (get_wide_dword(ea) == efiSmmBase2ProtocolGuid.data1) { - efiSmmBase2ProtocolGuidAddr = ea; - break; + for (vector::iterator seg = dataSegments.begin(); + seg != dataSegments.end(); ++seg) { + segment_t *seg_info = *seg; + if (seg_info == nullptr) { + return resAddrs; } - ea += 1; - } - if (!efiSmmBase2ProtocolGuidAddr) { - return resAddrs; - } - vector efiSmmBase2ProtocolGuidXrefs = - getXrefs(efiSmmBase2ProtocolGuidAddr); - for (vector::iterator guidXref = efiSmmBase2ProtocolGuidXrefs.begin(); - guidXref != efiSmmBase2ProtocolGuidXrefs.end(); ++guidXref) { - ea_t resAddr = 0; - ea_t curAddr = next_head(*guidXref, BADADDR); - insn_t insn; - /* 16 instructions below */ - for (auto i = 0; i < 16; i++) { - decode_insn(&insn, curAddr); - /* check if insn like 'lea rdx, ' */ - if (insn.itype == NN_lea && insn.ops[0].type == o_reg && - insn.ops[0].reg == REG_RDX && insn.ops[1].type == o_mem) { - DEBUG_MSG("[%s] found gSmst at 0x%016X, address = 0x%016X\n", - plugin_name, curAddr, insn.ops[1].addr); - resAddr = insn.ops[1].addr; - if (find(gBsList.begin(), gBsList.end(), resAddr) != - gBsList.end()) { - continue; - } - char hexAddr[21] = {}; - snprintf(hexAddr, 21, "%llX", static_cast(resAddr)); - set_cmt(curAddr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); - string name = "gSmst_" + static_cast(hexAddr); - setPtrTypeAndName(resAddr, name, "_EFI_SMM_SYSTEM_TABLE2"); - resAddrs.push_back(resAddr); + DEBUG_MSG("[%s] gSmst finding from 0x%016X to 0x%016X (via " + "EFI_SMM_BASE2_PROTOCOL_GUID)\n", + plugin_name, seg_info->start_ea, seg_info->end_ea); + ea_t ea = seg_info->start_ea; + while (ea != BADADDR && ea <= seg_info->end_ea - 15) { + if (get_wide_dword(ea) == efiSmmBase2ProtocolGuid.data1) { + efiSmmBase2ProtocolGuidAddr = ea; break; } - curAddr = next_head(curAddr, BADADDR); + ea += 1; + } + if (!efiSmmBase2ProtocolGuidAddr) { + continue; + } + vector efiSmmBase2ProtocolGuidXrefs = + getXrefs(efiSmmBase2ProtocolGuidAddr); + for (vector::iterator guidXref = + efiSmmBase2ProtocolGuidXrefs.begin(); + guidXref != efiSmmBase2ProtocolGuidXrefs.end(); ++guidXref) { + ea_t resAddr = 0; + ea_t curAddr = next_head(*guidXref, BADADDR); + insn_t insn; + /* 16 instructions below */ + for (auto i = 0; i < 16; i++) { + decode_insn(&insn, curAddr); + /* check if insn like 'lea rdx, ' */ + if (insn.itype == NN_lea && insn.ops[0].type == o_reg && + insn.ops[0].reg == REG_RDX && insn.ops[1].type == o_mem) { + DEBUG_MSG( + "[%s] found gSmst at 0x%016X, address = 0x%016X\n", + plugin_name, curAddr, insn.ops[1].addr); + resAddr = insn.ops[1].addr; + if (find(gBsList.begin(), gBsList.end(), resAddr) != + gBsList.end()) { + continue; + } + char hexAddr[21] = {}; + snprintf(hexAddr, 21, "%llX", + static_cast(resAddr)); + set_cmt(curAddr, "_EFI_SMM_SYSTEM_TABLE2 *gSmst;", true); + string name = "gSmst_" + static_cast(hexAddr); + setPtrTypeAndName(resAddr, name, "_EFI_SMM_SYSTEM_TABLE2"); + resAddrs.push_back(resAddr); + break; + } + curAddr = next_head(curAddr, BADADDR); + } } } return resAddrs; @@ -170,7 +187,8 @@ vector findSmstSmmBase(vector gBsList) { // lea r8, ... // lea rdx, // call qword ptr [...] -func_t *findSmiHandlerSmmSwDispatch() { +vector +findSmiHandlersSmmSwDispatch(vector dataSegments) { DEBUG_MSG("[%s] SwSmiHandler function finding (using " "EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID)\n", plugin_name); @@ -184,138 +202,142 @@ func_t *findSmiHandlerSmmSwDispatch() { 0xdd11, 0x420c, {0xb0, 0x26, 0xdf, 0x99, 0x36, 0x53, 0xf8, 0xbf}}; - ea_t efiSmmSwDispatchProtocolGuidAddr = 0; - string segName = ".data"; - segment_t *seg_info = get_segm_by_name(segName.c_str()); - if (seg_info == nullptr) { - DEBUG_MSG("[%s] can't find a %s segment\n", plugin_name, - segName.c_str()); - return nullptr; - } - ea_t ea = seg_info->start_ea; - while (ea != BADADDR && ea <= seg_info->end_ea - 15) { - if (get_wide_dword(ea) == efiSmmSwDispatchProtocolGuid.data1 || - get_wide_dword(ea) == efiSmmSwDispatch2ProtocolGuid.data1) { - efiSmmSwDispatchProtocolGuidAddr = ea; - break; - } - ea += 1; - } - if (!efiSmmSwDispatchProtocolGuidAddr) { + vector smiHandlers; + for (vector::iterator seg = dataSegments.begin(); + seg != dataSegments.end(); ++seg) { + segment_t *seg_info = *seg; DEBUG_MSG( - "[%s] can't find a EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID guid\n", - plugin_name); - return nullptr; - } - DEBUG_MSG("[%s] EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID address: 0x%016X\n", - plugin_name, efiSmmSwDispatchProtocolGuidAddr); - vector efiSmmSwDispatchProtocolGuidXrefs = - getXrefs(efiSmmSwDispatchProtocolGuidAddr); - for (vector::iterator guidXref = - efiSmmSwDispatchProtocolGuidXrefs.begin(); - guidXref != efiSmmSwDispatchProtocolGuidXrefs.end(); ++guidXref) { - DEBUG_MSG("[%s] EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID xref address: " - "0x%016X\n", - plugin_name, *guidXref); - /* get RegSwSmi function */ - func_t *regSmi = get_func(*guidXref); - ea_t start = 0; - insn_t insn; - if (regSmi == nullptr) { - DEBUG_MSG( - "[%s] can't get RegSwSmi function, will try to create it\n", - plugin_name) - /* try to create function */ - ea = *guidXref; - /* find function start */ - for (int i = 0; i < 100; i++) { - /* find 'retn' insn */ - ea = prev_head(ea, 0); - decode_insn(&insn, ea); - if (insn.itype == NN_retn) { - start = next_head(ea, BADADDR); - break; - } - } - /* create function */ - add_func(start); - regSmi = get_func(*guidXref); - if (regSmi == nullptr) { - continue; + "[%s] SwSmiHandler function finding from 0x%016X to 0x%016X\n", + plugin_name, seg_info->start_ea, seg_info->end_ea); + ea_t efiSmmSwDispatchProtocolGuidAddr = 0; + ea_t ea = seg_info->start_ea; + while (ea != BADADDR && ea <= seg_info->end_ea - 15) { + if (get_wide_dword(ea) == efiSmmSwDispatchProtocolGuid.data1 || + get_wide_dword(ea) == efiSmmSwDispatch2ProtocolGuid.data1) { + efiSmmSwDispatchProtocolGuidAddr = ea; + break; } + ea += 1; + } + if (!efiSmmSwDispatchProtocolGuidAddr) { + DEBUG_MSG( + "[%s] can't find a EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID guid\n", + plugin_name); + continue; } - /* find (SwDispath->Register)(SwDispath, SwSmiHandler, &SwSmiNum, - * Data) - */ - for (ea_t ea = regSmi->start_ea; ea <= regSmi->end_ea; - ea = next_head(ea, BADADDR)) { - decode_insn(&insn, ea); - if (insn.itype == NN_callni) { - /* find 'lea r9' */ - bool success = false; - ea_t addr = prev_head(ea, 0); - for (int i = 0; i < 12; i++) { - decode_insn(&insn, addr); - if (insn.itype == NN_lea && insn.ops[0].reg == REG_R9 && - insn.ops[1].type == o_displ) { - success = true; + DEBUG_MSG( + "[%s] EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID address: 0x%016X\n", + plugin_name, efiSmmSwDispatchProtocolGuidAddr); + vector efiSmmSwDispatchProtocolGuidXrefs = + getXrefs(efiSmmSwDispatchProtocolGuidAddr); + for (vector::iterator guidXref = + efiSmmSwDispatchProtocolGuidXrefs.begin(); + guidXref != efiSmmSwDispatchProtocolGuidXrefs.end(); ++guidXref) { + DEBUG_MSG("[%s] EFI_SMM_SW_DISPATCH(2)_PROTOCOL_GUID xref address: " + "0x%016X\n", + plugin_name, *guidXref); + /* get RegSwSmi function */ + func_t *regSmi = get_func(*guidXref); + ea_t start = 0; + insn_t insn; + if (regSmi == nullptr) { + DEBUG_MSG( + "[%s] can't get RegSwSmi function, will try to create it\n", + plugin_name) + /* try to create function */ + ea = *guidXref; + /* find function start */ + for (int i = 0; i < 100; i++) { + /* find 'retn' insn */ + ea = prev_head(ea, 0); + decode_insn(&insn, ea); + if (insn.itype == NN_retn) { + start = next_head(ea, BADADDR); break; } - addr = prev_head(addr, 0); } - if (!success) + /* create function */ + add_func(start); + regSmi = get_func(*guidXref); + if (regSmi == nullptr) { continue; - /* find 'lea r8' */ - success = false; - addr = prev_head(ea, 0); - for (int i = 0; i < 12; i++) { - decode_insn(&insn, addr); - if (insn.itype == NN_lea && insn.ops[0].reg == REG_R8 && - insn.ops[1].type == o_displ) { - success = true; - break; - } - addr = prev_head(addr, 0); } - if (!success) - continue; - /* find 'lea rdx' */ - success = false; - addr = prev_head(ea, 0); - for (int i = 0; i < 12; i++) { - decode_insn(&insn, addr); - if (insn.itype == NN_lea && insn.ops[0].reg == REG_RDX && - insn.ops[1].type == o_mem) { - success = true; - break; + } + /* find (SwDispath->Register)(SwDispath, SwSmiHandler, &SwSmiNum, + * Data) + */ + for (ea_t ea = regSmi->start_ea; ea <= regSmi->end_ea; + ea = next_head(ea, BADADDR)) { + decode_insn(&insn, ea); + if (insn.itype == NN_callni) { + /* find 'lea r9' */ + bool success = false; + ea_t addr = prev_head(ea, 0); + for (int i = 0; i < 12; i++) { + decode_insn(&insn, addr); + if (insn.itype == NN_lea && insn.ops[0].reg == REG_R9 && + insn.ops[1].type == o_displ) { + success = true; + break; + } + addr = prev_head(addr, 0); } - addr = prev_head(addr, 0); - } - if (!success) - continue; - ea_t smiHandlerAddr = insn.ops[1].addr; - func_t *smiHandler = get_func(smiHandlerAddr); - if (smiHandler == nullptr) { - DEBUG_MSG( - "[%s] can't get SwSmiHandler function, will try to " - "create it\n", - plugin_name); - /* create function */ - add_func(smiHandlerAddr); - smiHandler = get_func(smiHandlerAddr); - } - if (smiHandler == nullptr) { - continue; + if (!success) + continue; + /* find 'lea r8' */ + success = false; + addr = prev_head(ea, 0); + for (int i = 0; i < 12; i++) { + decode_insn(&insn, addr); + if (insn.itype == NN_lea && insn.ops[0].reg == REG_R8 && + insn.ops[1].type == o_displ) { + success = true; + break; + } + addr = prev_head(addr, 0); + } + if (!success) + continue; + /* find 'lea rdx' */ + success = false; + addr = prev_head(ea, 0); + for (int i = 0; i < 12; i++) { + decode_insn(&insn, addr); + if (insn.itype == NN_lea && + insn.ops[0].reg == REG_RDX && + insn.ops[1].type == o_mem) { + success = true; + break; + } + addr = prev_head(addr, 0); + } + if (!success) + continue; + ea_t smiHandlerAddr = insn.ops[1].addr; + func_t *smiHandler = get_func(smiHandlerAddr); + if (smiHandler == nullptr) { + DEBUG_MSG( + "[%s] can't get SwSmiHandler function, will try to " + "create it\n", + plugin_name); + /* create function */ + add_func(smiHandlerAddr); + smiHandler = get_func(smiHandlerAddr); + } + if (smiHandler == nullptr) { + continue; + } + /* make name for SwSmiHandler function */ + char hexAddr[21] = {0}; + snprintf(hexAddr, 21, "%llX", + static_cast(smiHandler->start_ea)); + string name = + "SwSmiHandler_" + static_cast(hexAddr); + set_name(smiHandler->start_ea, name.c_str(), SN_CHECK); + smiHandlers.push_back(smiHandler); } - /* make name for SwSmiHandler function */ - char hexAddr[21] = {0}; - snprintf(hexAddr, 21, "%llX", - static_cast(smiHandler->start_ea)); - string name = "SwSmiHandler_" + static_cast(hexAddr); - set_name(smiHandler->start_ea, name.c_str(), SN_CHECK); - return smiHandler; } } } - return nullptr; + return smiHandlers; } diff --git a/src/efiSmmUtils.h b/src/efiSmmUtils.h index f1b49ce0..faeb0111 100644 --- a/src/efiSmmUtils.h +++ b/src/efiSmmUtils.h @@ -37,6 +37,8 @@ struct efiGuid { uint8_t data4[8]; }; -vector findSmstSwDispatch(vector gBsList); -vector findSmstSmmBase(vector gBsList); -func_t *findSmiHandlerSmmSwDispatch(); +vector findSmstSwDispatch(vector gBsList, + vector dataSegments); +vector findSmstSmmBase(vector gBsList, + vector dataSegments); +vector findSmiHandlersSmmSwDispatch(vector dataSegments); diff --git a/src/efiUi.cpp b/src/efiUi.cpp index 980714f2..734d0e57 100644 --- a/src/efiUi.cpp +++ b/src/efiUi.cpp @@ -88,8 +88,8 @@ void idaapi guids_chooser_t::get_row(qstrvec_t *cols_, int *, /* generate the line */ qstrvec_t &cols = *cols_; json item = chooser_guids[n]; - string guid = item["guid"].get(); - string name = item["name"].get(); + string guid = static_cast(item["guid"]); + string name = static_cast(item["name"]); cols[0].sprnt("%016X", ea); cols[1].sprnt("%s", guid.c_str()); cols[2].sprnt("%s", name.c_str()); @@ -113,8 +113,8 @@ void idaapi protocols_chooser_t::get_row(qstrvec_t *cols_, int *, qstrvec_t &cols = *cols_; json item = chooser_protocols[n]; auto guid = item["guid"]; - string name = item["prot_name"].get(); - string service = item["service"].get(); + string name = static_cast(item["prot_name"]); + string service = static_cast(item["service"]); char protGuid[37] = {0}; snprintf(protGuid, 37, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", static_cast(guid[0]), static_cast(guid[1]), @@ -143,8 +143,8 @@ void idaapi s_chooser_t::get_row(qstrvec_t *cols_, int *, /* generate the line */ qstrvec_t &cols = *cols_; json item = chooser_s[n]; - string service_name = item["service_name"].get(); - string table_name = item["table_name"].get(); + string service_name = static_cast(item["service_name"]); + string table_name = static_cast(item["table_name"]); cols[0].sprnt("%016X", ea); cols[1].sprnt("%s", service_name.c_str()); cols[2].sprnt("%s", table_name.c_str()); diff --git a/src/efiUtils.cpp b/src/efiUtils.cpp index bea0bbc0..d07820be 100644 --- a/src/efiUtils.cpp +++ b/src/efiUtils.cpp @@ -71,6 +71,16 @@ void setGuidType(ea_t ea) { } } +//-------------------------------------------------------------------------- +// Set type and name +void setTypeAndName(ea_t ea, string name, string type) { + set_name(ea, name.c_str(), SN_CHECK); + tinfo_t tinfo; + if (tinfo.get_named_type(get_idati(), type.c_str())) { + apply_tinfo(ea, tinfo, TINFO_DEFINITE); + } +} + //-------------------------------------------------------------------------- // Get input file architecture (bit width X64 or X86) uint8_t getArch() { @@ -87,6 +97,11 @@ uint8_t getArch() { /* Portable executable for 80386 (PE) */ return X86; } + index = fileTypeStr.find("UEFI"); + if (index != string::npos) { + /* UEFI firmware */ + return UEFI; + } return 0; } @@ -95,6 +110,9 @@ uint8_t getArch() { // file type given only its PE/TE image section, so hello heuristics uint8_t getFileType() { uint8_t arch = getArch(); + if (arch == UEFI) { + return FTYPE_DXE_AND_THE_LIKE; + } segment_t *hdr_seg = get_segm_by_name("HEADER"); if (hdr_seg == NULL) { DEBUG_MSG("[%s] hdr_seg == NULL \n", plugin_name); @@ -252,7 +270,7 @@ bool guidsJsonExists() { guidsJsonPath /= idadir("plugins"); guidsJsonPath /= "guids"; guidsJsonPath /= "guids.json"; - return (stat(guidsJsonPath.u8string().c_str(), &buffer) == 0); + return std::filesystem::exists(guidsJsonPath); } //-------------------------------------------------------------------------- @@ -265,7 +283,7 @@ void setEntryArgToPeiSvc() { tinfo_t tif_ea; if (guess_tinfo(&tif_ea, start_ea) == GUESS_FUNC_FAILED) { DEBUG_MSG("[%s] guess_tinfo failed, start_ea = 0x%016X, idx=%d\n", - plugin_name, start_ea, idx); + plugin_name, start_ea, idx); continue; } @@ -278,7 +296,7 @@ void setEntryArgToPeiSvc() { bool res = tif_pei.get_named_type(get_idati(), "EFI_PEI_SERVICES"); if (!res) { DEBUG_MSG("[%s] get_named_type failed, res = %d, idx=%d\n", - plugin_name, res, idx); + plugin_name, res, idx); continue; } tinfo_t ptrTinfo; @@ -297,6 +315,6 @@ void setEntryArgToPeiSvc() { continue; } DEBUG_MSG("[%s] setEntryArgToPeiSvc finished, idx=%d\n", plugin_name, - idx); + idx); } -} \ No newline at end of file +} diff --git a/src/efiUtils.h b/src/efiUtils.h index 598143c8..0b21205f 100644 --- a/src/efiUtils.h +++ b/src/efiUtils.h @@ -28,10 +28,12 @@ * */ -#define _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS // TODO: need a fix in future +/* 3rd party */ #include "fort.h" #include "json.hpp" + #include #include #include @@ -49,6 +51,13 @@ #include #include +/* HexRays */ +#ifdef HEX_RAYS +#define HEX_RAYS 0 +/* support build without Hex-Rays Decompiler features */ +#include +#endif + using namespace nlohmann; using namespace std; using namespace std::filesystem; @@ -67,6 +76,7 @@ using namespace std::filesystem; /* architectures */ #define X86 32 #define X64 64 +#define UEFI 96 /* (FFS) file type */ #define FTYPE_DXE_AND_THE_LIKE 7 @@ -153,3 +163,5 @@ bool guidsJsonExists(); /* Change EFI_SYSTEM_TABLE *SystemTable to EFI_PEI_SERVICES **PeiService /* for ModuleEntryPoint */ void setEntryArgToPeiSvc(); +/* Set type and name */ +void setTypeAndName(ea_t ea, string name, string type); diff --git a/src/efiXplorer.cpp b/src/efiXplorer.cpp index d91d4472..4f9bf7d4 100644 --- a/src/efiXplorer.cpp +++ b/src/efiXplorer.cpp @@ -88,6 +88,10 @@ bool idaapi run(size_t) { plugin_name); efiAnalysis::efiAnalyzerMainX86(); } + if (arch == UEFI) { + DEBUG_MSG("[%s] input file is UEFI firmware\n", plugin_name); + efiAnalysis::efiAnalyzerMainX64(); + } return true; } diff --git a/src/thirdparty/nlohmann_json/json.hpp b/src/thirdparty/nlohmann_json/json.hpp index 06da8153..a70aaf8c 100644 --- a/src/thirdparty/nlohmann_json/json.hpp +++ b/src/thirdparty/nlohmann_json/json.hpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.7.3 +| | |__ | | | | | | version 3.9.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -31,12 +31,10 @@ SOFTWARE. #define INCLUDE_NLOHMANN_JSON_HPP_ #define NLOHMANN_JSON_VERSION_MAJOR 3 -#define NLOHMANN_JSON_VERSION_MINOR 7 -#define NLOHMANN_JSON_VERSION_PATCH 3 +#define NLOHMANN_JSON_VERSION_MINOR 9 +#define NLOHMANN_JSON_VERSION_PATCH 1 #include // all_of, find, for_each -#include // assert -#include // and, not, or #include // nullptr_t, ptrdiff_t, size_t #include // hash, less #include // initializer_list @@ -58,7 +56,6 @@ SOFTWARE. #include // transform #include // array -#include // and, not #include // forward_list #include // inserter, front_inserter, end #include // map @@ -122,11 +119,11 @@ struct position_t * SPDX-License-Identifier: CC0-1.0 */ -#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 11) +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 13) #if defined(JSON_HEDLEY_VERSION) #undef JSON_HEDLEY_VERSION #endif -#define JSON_HEDLEY_VERSION 11 +#define JSON_HEDLEY_VERSION 13 #if defined(JSON_HEDLEY_STRINGIFY_EX) #undef JSON_HEDLEY_STRINGIFY_EX @@ -148,6 +145,16 @@ struct position_t #endif #define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) +#if defined(JSON_HEDLEY_CONCAT3_EX) + #undef JSON_HEDLEY_CONCAT3_EX +#endif +#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c + +#if defined(JSON_HEDLEY_CONCAT3) + #undef JSON_HEDLEY_CONCAT3 +#endif +#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) + #if defined(JSON_HEDLEY_VERSION_ENCODE) #undef JSON_HEDLEY_VERSION_ENCODE #endif @@ -323,9 +330,17 @@ struct position_t #if defined(JSON_HEDLEY_TI_VERSION) #undef JSON_HEDLEY_TI_VERSION #endif -#if defined(__TI_COMPILER_VERSION__) +#if \ + defined(__TI_COMPILER_VERSION__) && \ + ( \ + defined(__TMS470__) || defined(__TI_ARM__) || \ + defined(__MSP430__) || \ + defined(__TMS320C2000__) \ + ) +#if (__TI_COMPILER_VERSION__ >= 16000000) #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) #endif +#endif #if defined(JSON_HEDLEY_TI_VERSION_CHECK) #undef JSON_HEDLEY_TI_VERSION_CHECK @@ -336,6 +351,102 @@ struct position_t #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) #endif +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #undef JSON_HEDLEY_TI_CL2000_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) + #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #undef JSON_HEDLEY_TI_CL430_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) + #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #undef JSON_HEDLEY_TI_ARMCL_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) + #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) + #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #undef JSON_HEDLEY_TI_CL6X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) + #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #undef JSON_HEDLEY_TI_CL7X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) + #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #undef JSON_HEDLEY_TI_CLPRU_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) + #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) +#endif + #if defined(JSON_HEDLEY_CRAY_VERSION) #undef JSON_HEDLEY_CRAY_VERSION #endif @@ -450,6 +561,12 @@ struct position_t !defined(JSON_HEDLEY_PGI_VERSION) && \ !defined(JSON_HEDLEY_ARM_VERSION) && \ !defined(JSON_HEDLEY_TI_VERSION) && \ + !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ !defined(__COMPCERT__) #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION #endif @@ -509,6 +626,7 @@ struct position_t #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) #elif \ !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION) && \ (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) @@ -674,14 +792,85 @@ struct position_t #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ #endif -#if defined(__cplusplus) && JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") -# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ xpr \ JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# endif +#endif +#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if defined(JSON_HEDLEY_CONST_CAST) + #undef JSON_HEDLEY_CONST_CAST +#endif +#if defined(__cplusplus) +# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ + JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_REINTERPRET_CAST) + #undef JSON_HEDLEY_REINTERPRET_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_STATIC_CAST) + #undef JSON_HEDLEY_STATIC_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#else + #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_CPP_CAST) + #undef JSON_HEDLEY_CPP_CAST +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ + ((T) (expr)) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("diag_suppress=Pe137") \ + JSON_HEDLEY_DIAGNOSTIC_POP \ +# else +# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) +# endif #else -# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +# define JSON_HEDLEY_CPP_CAST(T, expr) (expr) #endif #if \ @@ -692,7 +881,13 @@ struct position_t JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ @@ -725,7 +920,13 @@ struct position_t #elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") -#elif JSON_HEDLEY_TI_VERSION_CHECK(8,1,0) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") #elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) @@ -749,7 +950,18 @@ struct position_t #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) -#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") @@ -776,7 +988,13 @@ struct position_t #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) -#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") @@ -799,8 +1017,13 @@ struct position_t #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") -#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") #else #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES #endif @@ -824,7 +1047,10 @@ struct position_t #if defined(JSON_HEDLEY_DEPRECATED_FOR) #undef JSON_HEDLEY_DEPRECATED_FOR #endif -#if defined(__cplusplus) && (__cplusplus >= 201402L) +#if JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif defined(__cplusplus) && (__cplusplus >= 201402L) #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) #elif \ @@ -834,20 +1060,30 @@ struct position_t JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,3,0) + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) #elif \ JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) - #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) #elif \ JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) @@ -876,21 +1112,40 @@ struct position_t #if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) #undef JSON_HEDLEY_WARN_UNUSED_RESULT #endif -#if defined(__cplusplus) && (__cplusplus >= 201703L) +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#endif +#if (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) #elif \ JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) #elif defined(_Check_return_) /* SAL */ #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ #else #define JSON_HEDLEY_WARN_UNUSED_RESULT + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) #endif #if defined(JSON_HEDLEY_SENTINEL) @@ -923,14 +1178,23 @@ struct position_t JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(18,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(17,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") #elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) -#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") #elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) @@ -955,31 +1219,6 @@ struct position_t #if defined(JSON_HEDLEY_UNREACHABLE_RETURN) #undef JSON_HEDLEY_UNREACHABLE_RETURN #endif -#if \ - (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) - #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) - #define JSON_HEDLEY_UNREACHABLE() __assume(0) -#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) - #if defined(__cplusplus) - #define JSON_HEDLEY_UNREACHABLE() std::_nassert(0) - #else - #define JSON_HEDLEY_UNREACHABLE() _nassert(0) - #endif - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value -#elif defined(EXIT_FAILURE) - #define JSON_HEDLEY_UNREACHABLE() abort() -#else - #define JSON_HEDLEY_UNREACHABLE() - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value -#endif -#if !defined(JSON_HEDLEY_UNREACHABLE_RETURN) - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() -#endif - #if defined(JSON_HEDLEY_ASSUME) #undef JSON_HEDLEY_ASSUME #endif @@ -989,20 +1228,45 @@ struct position_t #define JSON_HEDLEY_ASSUME(expr) __assume(expr) #elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) -#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) +#elif \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) #if defined(__cplusplus) #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) #else #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) #endif -#elif \ - (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && !defined(JSON_HEDLEY_ARM_VERSION)) || \ +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) - #define JSON_HEDLEY_ASSUME(expr) ((void) ((expr) ? 1 : (__builtin_unreachable(), 1))) + #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif defined(JSON_HEDLEY_ASSUME) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif +#if !defined(JSON_HEDLEY_ASSUME) + #if defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) + #else + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) + #endif +#endif +#if defined(JSON_HEDLEY_UNREACHABLE) + #if \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) + #else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() + #endif #else - #define JSON_HEDLEY_ASSUME(expr) ((void) (expr)) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) #endif JSON_HEDLEY_DIAGNOSTIC_PUSH @@ -1046,8 +1310,17 @@ JSON_HEDLEY_DIAGNOSTIC_POP JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) #elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) @@ -1080,19 +1353,16 @@ JSON_HEDLEY_DIAGNOSTIC_POP #undef JSON_HEDLEY_UNPREDICTABLE #endif #if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) - #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable(!!(expr)) + #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) #endif #if \ JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || \ JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) -# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(expr, value, probability) -# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1, probability) -# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0, probability) -# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) -# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) -#if !defined(JSON_HEDLEY_BUILTIN_UNPREDICTABLE) - #define JSON_HEDLEY_BUILTIN_UNPREDICTABLE(expr) __builtin_expect_with_probability(!!(expr), 1, 0.5) -#endif +# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) #elif \ JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ @@ -1100,24 +1370,31 @@ JSON_HEDLEY_DIAGNOSTIC_POP (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) # define JSON_HEDLEY_PREDICT(expr, expected, probability) \ - (((probability) >= 0.9) ? __builtin_expect(!!(expr), (expected)) : (((void) (expected)), !!(expr))) + (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) # define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ (__extension__ ({ \ - JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ + double hedley_probability_ = (probability); \ ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ })) # define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ (__extension__ ({ \ - JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ + double hedley_probability_ = (probability); \ ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ })) # define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) # define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) #else -# define JSON_HEDLEY_PREDICT(expr, expected, probability) (((void) (expected)), !!(expr)) +# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) # define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) # define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) # define JSON_HEDLEY_LIKELY(expr) (!!(expr)) @@ -1137,8 +1414,17 @@ JSON_HEDLEY_DIAGNOSTIC_POP JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") @@ -1152,22 +1438,36 @@ JSON_HEDLEY_DIAGNOSTIC_POP #undef JSON_HEDLEY_PURE #endif #if \ - JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_PURE __attribute__((__pure__)) + JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) +# define JSON_HEDLEY_PURE __attribute__((__pure__)) #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) - #define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") -#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) - #define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ + ) +# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") #else - #define JSON_HEDLEY_PURE +# define JSON_HEDLEY_PURE #endif #if defined(JSON_HEDLEY_CONST) @@ -1180,8 +1480,17 @@ JSON_HEDLEY_DIAGNOSTIC_POP JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) #define JSON_HEDLEY_CONST __attribute__((__const__)) #elif \ @@ -1203,7 +1512,10 @@ JSON_HEDLEY_DIAGNOSTIC_POP JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ defined(__clang__) @@ -1228,7 +1540,12 @@ JSON_HEDLEY_DIAGNOSTIC_POP #elif \ JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) #define JSON_HEDLEY_INLINE __inline #else #define JSON_HEDLEY_INLINE @@ -1238,23 +1555,40 @@ JSON_HEDLEY_DIAGNOSTIC_POP #undef JSON_HEDLEY_ALWAYS_INLINE #endif #if \ - JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) - #define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE + JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) +# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE #elif JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) - #define JSON_HEDLEY_ALWAYS_INLINE __forceinline -#elif JSON_HEDLEY_TI_VERSION_CHECK(7,0,0) && defined(__cplusplus) - #define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +# define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ + ) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") #else - #define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE #endif #if defined(JSON_HEDLEY_NEVER_INLINE) @@ -1267,14 +1601,23 @@ JSON_HEDLEY_DIAGNOSTIC_POP JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) #elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) #elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") -#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") @@ -1296,26 +1639,31 @@ JSON_HEDLEY_DIAGNOSTIC_POP #undef JSON_HEDLEY_IMPORT #endif #if defined(_WIN32) || defined(__CYGWIN__) - #define JSON_HEDLEY_PRIVATE - #define JSON_HEDLEY_PUBLIC __declspec(dllexport) - #define JSON_HEDLEY_IMPORT __declspec(dllimport) +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC __declspec(dllexport) +# define JSON_HEDLEY_IMPORT __declspec(dllimport) #else - #if \ - JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_EABI__) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) - #define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) - #define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) - #else - #define JSON_HEDLEY_PRIVATE - #define JSON_HEDLEY_PUBLIC - #endif - #define JSON_HEDLEY_IMPORT extern +# if \ + JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + ( \ + defined(__TI_EABI__) && \ + ( \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ + ) \ + ) +# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +# else +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC +# endif +# define JSON_HEDLEY_IMPORT extern #endif #if defined(JSON_HEDLEY_NO_THROW) @@ -1337,7 +1685,9 @@ JSON_HEDLEY_DIAGNOSTIC_POP #if defined(JSON_HEDLEY_FALL_THROUGH) #undef JSON_HEDLEY_FALL_THROUGH #endif -#if JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(JSON_HEDLEY_PGI_VERSION) +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) #elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) @@ -1394,7 +1744,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) @@ -1415,7 +1765,11 @@ JSON_HEDLEY_DIAGNOSTIC_POP #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) #endif # elif \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(JSON_HEDLEY_SUNPRO_VERSION) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ + ( \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION)) || \ JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ @@ -1431,7 +1785,12 @@ JSON_HEDLEY_DIAGNOSTIC_POP defined(JSON_HEDLEY_GCC_VERSION) || \ defined(JSON_HEDLEY_INTEL_VERSION) || \ defined(JSON_HEDLEY_TINYC_VERSION) || \ - defined(JSON_HEDLEY_TI_VERSION) || \ + defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ + defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ + defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ + defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ + defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ defined(__clang__) # define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ sizeof(void) != \ @@ -1489,59 +1848,12 @@ JSON_HEDLEY_DIAGNOSTIC_POP # define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) #elif \ (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ - JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ - (defined(__cplusplus) && JSON_HEDLEY_TI_VERSION_CHECK(8,3,0)) + JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) # define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) #else # define JSON_HEDLEY_STATIC_ASSERT(expr, message) #endif -#if defined(JSON_HEDLEY_CONST_CAST) - #undef JSON_HEDLEY_CONST_CAST -#endif -#if defined(__cplusplus) -# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) -#elif \ - JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ - ((T) (expr)); \ - JSON_HEDLEY_DIAGNOSTIC_POP \ - })) -#else -# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) -#endif - -#if defined(JSON_HEDLEY_REINTERPRET_CAST) - #undef JSON_HEDLEY_REINTERPRET_CAST -#endif -#if defined(__cplusplus) - #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) -#else - #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (*((T*) &(expr))) -#endif - -#if defined(JSON_HEDLEY_STATIC_CAST) - #undef JSON_HEDLEY_STATIC_CAST -#endif -#if defined(__cplusplus) - #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) -#else - #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) -#endif - -#if defined(JSON_HEDLEY_CPP_CAST) - #undef JSON_HEDLEY_CPP_CAST -#endif -#if defined(__cplusplus) - #define JSON_HEDLEY_CPP_CAST(T, expr) static_cast(expr) -#else - #define JSON_HEDLEY_CPP_CAST(T, expr) (expr) -#endif - #if defined(JSON_HEDLEY_NULL) #undef JSON_HEDLEY_NULL #endif @@ -1593,7 +1905,8 @@ JSON_HEDLEY_DIAGNOSTIC_POP JSON_HEDLEY_DIAGNOSTIC_POP #elif \ JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) @@ -1724,7 +2037,11 @@ JSON_HEDLEY_DIAGNOSTIC_POP #endif // C++ language standard detection -#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 +#if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 #define JSON_HAS_CPP_17 #define JSON_HAS_CPP_14 #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) @@ -1777,6 +2094,12 @@ JSON_HEDLEY_DIAGNOSTIC_POP #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER #endif +// allow to override assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + /*! @brief macro to briefly define a mapping between an enum and JSON @def NLOHMANN_JSON_SERIALIZE_ENUM @@ -1817,12 +2140,177 @@ JSON_HEDLEY_DIAGNOSTIC_POP class StringType, class BooleanType, class NumberIntegerType, \ class NumberUnsignedType, class NumberFloatType, \ template class AllocatorType, \ - template class JSONSerializer> + template class JSONSerializer, \ + class BinaryType> #define NLOHMANN_BASIC_JSON_TPL \ basic_json + AllocatorType, JSONSerializer, BinaryType> + +// Macros to simplify conversion from/to types + +#define NLOHMANN_JSON_EXPAND( x ) x +#define NLOHMANN_JSON_GET_MACRO(_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, NAME,...) NAME +#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ + NLOHMANN_JSON_PASTE64, \ + NLOHMANN_JSON_PASTE63, \ + NLOHMANN_JSON_PASTE62, \ + NLOHMANN_JSON_PASTE61, \ + NLOHMANN_JSON_PASTE60, \ + NLOHMANN_JSON_PASTE59, \ + NLOHMANN_JSON_PASTE58, \ + NLOHMANN_JSON_PASTE57, \ + NLOHMANN_JSON_PASTE56, \ + NLOHMANN_JSON_PASTE55, \ + NLOHMANN_JSON_PASTE54, \ + NLOHMANN_JSON_PASTE53, \ + NLOHMANN_JSON_PASTE52, \ + NLOHMANN_JSON_PASTE51, \ + NLOHMANN_JSON_PASTE50, \ + NLOHMANN_JSON_PASTE49, \ + NLOHMANN_JSON_PASTE48, \ + NLOHMANN_JSON_PASTE47, \ + NLOHMANN_JSON_PASTE46, \ + NLOHMANN_JSON_PASTE45, \ + NLOHMANN_JSON_PASTE44, \ + NLOHMANN_JSON_PASTE43, \ + NLOHMANN_JSON_PASTE42, \ + NLOHMANN_JSON_PASTE41, \ + NLOHMANN_JSON_PASTE40, \ + NLOHMANN_JSON_PASTE39, \ + NLOHMANN_JSON_PASTE38, \ + NLOHMANN_JSON_PASTE37, \ + NLOHMANN_JSON_PASTE36, \ + NLOHMANN_JSON_PASTE35, \ + NLOHMANN_JSON_PASTE34, \ + NLOHMANN_JSON_PASTE33, \ + NLOHMANN_JSON_PASTE32, \ + NLOHMANN_JSON_PASTE31, \ + NLOHMANN_JSON_PASTE30, \ + NLOHMANN_JSON_PASTE29, \ + NLOHMANN_JSON_PASTE28, \ + NLOHMANN_JSON_PASTE27, \ + NLOHMANN_JSON_PASTE26, \ + NLOHMANN_JSON_PASTE25, \ + NLOHMANN_JSON_PASTE24, \ + NLOHMANN_JSON_PASTE23, \ + NLOHMANN_JSON_PASTE22, \ + NLOHMANN_JSON_PASTE21, \ + NLOHMANN_JSON_PASTE20, \ + NLOHMANN_JSON_PASTE19, \ + NLOHMANN_JSON_PASTE18, \ + NLOHMANN_JSON_PASTE17, \ + NLOHMANN_JSON_PASTE16, \ + NLOHMANN_JSON_PASTE15, \ + NLOHMANN_JSON_PASTE14, \ + NLOHMANN_JSON_PASTE13, \ + NLOHMANN_JSON_PASTE12, \ + NLOHMANN_JSON_PASTE11, \ + NLOHMANN_JSON_PASTE10, \ + NLOHMANN_JSON_PASTE9, \ + NLOHMANN_JSON_PASTE8, \ + NLOHMANN_JSON_PASTE7, \ + NLOHMANN_JSON_PASTE6, \ + NLOHMANN_JSON_PASTE5, \ + NLOHMANN_JSON_PASTE4, \ + NLOHMANN_JSON_PASTE3, \ + NLOHMANN_JSON_PASTE2, \ + NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) +#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) +#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) +#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) +#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) +#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) +#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) +#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) +#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) +#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) +#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) +#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) +#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) +#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) +#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) +#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) +#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) +#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) +#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) +#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) +#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) +#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) +#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) +#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) +#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) +#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) +#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) +#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) +#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) +#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) +#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) +#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) +#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) +#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) +#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) +#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) +#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) +#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) +#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) +#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) +#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) +#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) +#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) +#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) +#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) +#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) +#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) +#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) +#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) +#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) +#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) +#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) +#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) +#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) +#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) +#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) + +#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; +#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#ifndef JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_USE_IMPLICIT_CONVERSIONS 1 +#endif + +#if JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_EXPLICIT +#else + #define JSON_EXPLICIT explicit +#endif namespace nlohmann @@ -1915,6 +2403,7 @@ json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vect json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet). +json.exception.parse_error.115 | parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text: 1A | A UBJSON high-precision number could not be parsed. @note For an input with n bytes, 1 is the index of the first character and n+1 is the index of the terminating null byte or the end of file. This also @@ -2103,7 +2592,7 @@ json.exception.out_of_range.403 | key 'foo' not found | The provided key was not json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. -json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. | +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. (until version 3.8.0) | json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string | @@ -2178,7 +2667,6 @@ class other_error : public exception // #include -#include // not #include // size_t #include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type @@ -2243,7 +2731,6 @@ constexpr T static_const::value; // #include -#include // not #include // numeric_limits #include // false_type, is_constructible, is_integral, is_same, true_type #include // declval @@ -2260,11 +2747,11 @@ namespace nlohmann { namespace detail { -template struct make_void +template struct make_void { using type = void; }; -template using void_t = typename make_void::type; +template using void_t = typename make_void::type; } // namespace detail } // namespace nlohmann @@ -2275,10 +2762,10 @@ namespace nlohmann { namespace detail { -template +template struct iterator_types {}; -template +template struct iterator_types < It, void_t +template struct iterator_traits { }; -template +template struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> : iterator_types { }; -template +template struct iterator_traits::value>> { using iterator_category = std::random_access_iterator_tag; @@ -2328,7 +2815,7 @@ struct iterator_traits::value>> // #include -// http://en.cppreference.com/w/cpp/experimental/is_detected +// https://en.cppreference.com/w/cpp/experimental/is_detected namespace nlohmann { namespace detail @@ -2343,39 +2830,39 @@ struct nonesuch void operator=(nonesuch&&) = delete; }; -template class Op, - class... Args> +template class Op, + class... Args> struct detector { using value_t = std::false_type; using type = Default; }; -template class Op, class... Args> +template class Op, class... Args> struct detector>, Op, Args...> { using value_t = std::true_type; using type = Op; }; -template