mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
Merge branch 'dev' of https://github.com/emsesp/EMS-ESP32 into dev
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
- Added scripts for OTA (scripts/upload.py and upload_cli.py) [#1738](https://github.com/emsesp/EMS-ESP32/issues/1738)
|
||||
- timeout for remote thermostat emulation [#1680](https://github.com/emsesp/EMS-ESP32/discussions/1680), [#1774](https://github.com/emsesp/EMS-ESP32/issues/1774)
|
||||
- seltemp/mode for CR120 [#1779](https://github.com/emsesp/EMS-ESP32/discussions/1779)
|
||||
- Modules - external linkable module library [#1778](https://github.com/emsesp/EMS-ESP32/issues/1778)
|
||||
|
||||
## Fixed
|
||||
|
||||
|
||||
5
Makefile
5
Makefile
@@ -29,8 +29,7 @@ CHECKFLAGS = -q --force --std=c++11
|
||||
# Languages Standard
|
||||
#----------------------------------------------------------------------
|
||||
C_STANDARD := -std=c17
|
||||
# CXX_STANDARD := -std=c++17
|
||||
CXX_STANDARD := -std=gnu++11
|
||||
CXX_STANDARD := -std=gnu++14
|
||||
|
||||
# C_STANDARD := -std=c11
|
||||
# CXX_STANDARD := -std=c++11
|
||||
@@ -38,7 +37,7 @@ CXX_STANDARD := -std=gnu++11
|
||||
#----------------------------------------------------------------------
|
||||
# Defined Symbols
|
||||
#----------------------------------------------------------------------
|
||||
DEFINES += -DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_PROGMEM=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0
|
||||
DEFINES += -DARDUINOJSON_ENABLE -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0
|
||||
DEFINES += -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_TEST -D__linux__ -DEMC_RX_BUFFER_SIZE=1500
|
||||
DEFINES += $(ARGS)
|
||||
|
||||
|
||||
@@ -23,18 +23,18 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@alova/adapter-xhr": "^1.0.6",
|
||||
"@alova/scene-react": "^1.5.0",
|
||||
"@alova/scene-react": "^1.6.1",
|
||||
"@emotion/react": "^11.11.4",
|
||||
"@emotion/styled": "^11.11.5",
|
||||
"@mui/icons-material": "^5.15.18",
|
||||
"@mui/material": "^5.15.18",
|
||||
"@mui/icons-material": "^5.15.20",
|
||||
"@mui/material": "^5.15.20",
|
||||
"@table-library/react-table-library": "4.1.7",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^20.12.12",
|
||||
"@types/react": "^18.3.2",
|
||||
"@types/node": "^20.14.2",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"alova": "^2.20.5",
|
||||
"alova": "^2.21.3",
|
||||
"async-validator": "^4.2.5",
|
||||
"history": "^5.3.0",
|
||||
"jwt-decode": "^4.0.0",
|
||||
@@ -50,21 +50,21 @@
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.5",
|
||||
"@eslint/js": "^9.3.0",
|
||||
"@babel/core": "^7.24.7",
|
||||
"@eslint/js": "^9.5.0",
|
||||
"@preact/compat": "^17.1.2",
|
||||
"@preact/preset-vite": "^2.8.2",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||
"@types/babel__core": "^7",
|
||||
"concurrently": "^8.2.2",
|
||||
"eslint": "^9.3.0",
|
||||
"eslint": "^9.5.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"preact": "^10.22.0",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier": "^3.3.2",
|
||||
"rollup-plugin-visualizer": "^5.12.0",
|
||||
"terser": "^5.31.0",
|
||||
"typescript-eslint": "^7.9.0",
|
||||
"vite": "^5.2.11",
|
||||
"terser": "^5.31.1",
|
||||
"typescript-eslint": "^7.13.0",
|
||||
"vite": "^5.3.1",
|
||||
"vite-plugin-imagemin": "^0.6.1",
|
||||
"vite-tsconfig-paths": "^4.3.2"
|
||||
},
|
||||
|
||||
@@ -16,6 +16,7 @@ import ApplicationSettings from 'project/ApplicationSettings';
|
||||
import CustomEntities from 'project/CustomEntities';
|
||||
import Customization from 'project/Customization';
|
||||
import Devices from 'project/Devices';
|
||||
import Modules from 'project/Modules';
|
||||
import Scheduler from 'project/Scheduler';
|
||||
import Sensors from 'project/Sensors';
|
||||
|
||||
@@ -43,6 +44,7 @@ const AuthenticatedRouting: FC = () => {
|
||||
<Route path="/settings/ntp/*" element={<NetworkTime />} />
|
||||
<Route path="/settings/mqtt/*" element={<Mqtt />} />
|
||||
<Route path="/settings/security/*" element={<Security />} />
|
||||
<Route path="/settings/modules/*" element={<Modules />} />
|
||||
<Route path="/system/espsystemstatus/*" element={<ESPSystemStatus />} />
|
||||
<Route path="/settings/upload/*" element={<UploadDownload />} />
|
||||
</>
|
||||
|
||||
@@ -9,6 +9,7 @@ import SettingsBackupRestoreIcon from '@mui/icons-material/SettingsBackupRestore
|
||||
import SettingsEthernetIcon from '@mui/icons-material/SettingsEthernet';
|
||||
import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna';
|
||||
import TuneIcon from '@mui/icons-material/Tune';
|
||||
import ViewModuleIcon from '@mui/icons-material/ViewModule';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@@ -122,6 +123,14 @@ const Settings: FC = () => {
|
||||
to="security"
|
||||
/>
|
||||
|
||||
<ListMenuItem
|
||||
icon={ViewModuleIcon}
|
||||
bgcolor="#efc34b"
|
||||
label="Modules"
|
||||
text="Activate or deactivate external modules"
|
||||
to="modules"
|
||||
/>
|
||||
|
||||
<Divider />
|
||||
|
||||
<ListMenuItem
|
||||
|
||||
@@ -10,8 +10,10 @@ import MemoryIcon from '@mui/icons-material/Memory';
|
||||
import PermScanWifiIcon from '@mui/icons-material/PermScanWifi';
|
||||
import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew';
|
||||
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||
import RouterIcon from '@mui/icons-material/Router';
|
||||
import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna';
|
||||
import TimerIcon from '@mui/icons-material/Timer';
|
||||
import WifiIcon from '@mui/icons-material/Wifi';
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
@@ -38,7 +40,7 @@ import ListMenuItem from 'components/layout/ListMenuItem';
|
||||
import { AuthenticatedContext } from 'contexts/authentication';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import { busConnectionStatus } from 'project/types';
|
||||
import { NTPSyncStatus } from 'types';
|
||||
import { NTPSyncStatus, NetworkConnectionStatus } from 'types';
|
||||
|
||||
import RestartMonitor from './RestartMonitor';
|
||||
|
||||
@@ -151,6 +153,46 @@ const SystemStatus: FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const networkStatusHighlight = () => {
|
||||
switch (data.network_status) {
|
||||
case NetworkConnectionStatus.WIFI_STATUS_IDLE:
|
||||
case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED:
|
||||
case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD:
|
||||
return theme.palette.info.main;
|
||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECTED:
|
||||
case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED:
|
||||
return theme.palette.success.main;
|
||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED:
|
||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST:
|
||||
return theme.palette.error.main;
|
||||
default:
|
||||
return theme.palette.warning.main;
|
||||
}
|
||||
};
|
||||
|
||||
const networkStatus = () => {
|
||||
switch (data.network_status) {
|
||||
case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD:
|
||||
return LL.INACTIVE(1);
|
||||
case NetworkConnectionStatus.WIFI_STATUS_IDLE:
|
||||
return LL.IDLE();
|
||||
case NetworkConnectionStatus.WIFI_STATUS_NO_SSID_AVAIL:
|
||||
return 'No SSID Available';
|
||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECTED:
|
||||
return LL.CONNECTED(0) + ' (WiFi, ' + data.wifi_rssi + ' dBm)';
|
||||
case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED:
|
||||
return LL.CONNECTED(0) + ' (Ethernet)';
|
||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED:
|
||||
return LL.CONNECTED(1) + ' ' + LL.FAILED(0);
|
||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST:
|
||||
return LL.CONNECTED(1) + ' ' + LL.LOST();
|
||||
case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED:
|
||||
return LL.DISCONNECTED();
|
||||
default:
|
||||
return LL.UNKNOWN();
|
||||
}
|
||||
};
|
||||
|
||||
const activeHighlight = (value: boolean) =>
|
||||
value ? theme.palette.success.main : theme.palette.info.main;
|
||||
|
||||
@@ -247,7 +289,7 @@ const SystemStatus: FC = () => {
|
||||
variant="outlined"
|
||||
onClick={restart}
|
||||
disabled={processing}
|
||||
color="primary"
|
||||
color="error"
|
||||
>
|
||||
{LL.RESTART()}
|
||||
</Button>
|
||||
@@ -256,7 +298,7 @@ const SystemStatus: FC = () => {
|
||||
variant="outlined"
|
||||
onClick={partition}
|
||||
disabled={processing}
|
||||
color="primary"
|
||||
color="warning"
|
||||
>
|
||||
EMS-ESP Loader
|
||||
</Button>
|
||||
@@ -296,7 +338,7 @@ const SystemStatus: FC = () => {
|
||||
<Button
|
||||
startIcon={<PowerSettingsNewIcon />}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
color="error"
|
||||
onClick={() => setConfirmRestart(true)}
|
||||
>
|
||||
{LL.RESTART()}
|
||||
@@ -355,6 +397,20 @@ const SystemStatus: FC = () => {
|
||||
/>
|
||||
<Divider variant="inset" component="li" />
|
||||
|
||||
<ListMenuItem
|
||||
disabled={!me.admin}
|
||||
icon={
|
||||
data.network_status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED
|
||||
? WifiIcon
|
||||
: RouterIcon
|
||||
}
|
||||
bgcolor={networkStatusHighlight()}
|
||||
label={LL.STATUS_OF(LL.NETWORK(1))}
|
||||
text={networkStatus()}
|
||||
to="/settings/network/status"
|
||||
/>
|
||||
<Divider variant="inset" component="li" />
|
||||
|
||||
<ListMenuItem
|
||||
disabled={!me.admin}
|
||||
icon={DeviceHubIcon}
|
||||
|
||||
@@ -145,7 +145,7 @@ const UploadDownload: FC = () => {
|
||||
onGetAPI((event) => {
|
||||
saveFile(
|
||||
event.data,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
|
||||
event.sendArgs[0].device + '_' + event.sendArgs[0].entity + '.txt'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -325,7 +325,10 @@ const de: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||
SECURITY_1: 'Add or remove users', // TODO translate
|
||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // TODO translate
|
||||
MODULES: 'Module'
|
||||
MODULES: 'Module', // TODO translate
|
||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
||||
MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate
|
||||
MODULES_NONE: 'No external modules detected' // TODO translate
|
||||
};
|
||||
|
||||
export default de;
|
||||
|
||||
@@ -325,7 +325,10 @@ const en: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings',
|
||||
SECURITY_1: 'Add or remove users',
|
||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware',
|
||||
MODULES: 'Modules'
|
||||
MODULES: 'Modules',
|
||||
MODULES_UPDATED: 'Modules updated',
|
||||
MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules',
|
||||
MODULES_NONE: 'No external modules detected'
|
||||
};
|
||||
|
||||
export default en;
|
||||
|
||||
@@ -325,7 +325,10 @@ const fr: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||
SECURITY_1: 'Add or remove users', // TODO translate
|
||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // TODO translate
|
||||
MODULES: 'Modules' // TODO translate
|
||||
MODULES: 'Module', // TODO translate
|
||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
||||
MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate
|
||||
MODULES_NONE: 'No external modules detected' // TODO translate
|
||||
};
|
||||
|
||||
export default fr;
|
||||
|
||||
@@ -325,7 +325,10 @@ const it: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||
SECURITY_1: 'Add or remove users', // TODO translate
|
||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // TODO translate
|
||||
MODULES: 'Modules' // TODO translate
|
||||
MODULES: 'Module', // TODO translate
|
||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
||||
MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate
|
||||
MODULES_NONE: 'No external modules detected' // TODO translate
|
||||
};
|
||||
|
||||
export default it;
|
||||
|
||||
@@ -325,7 +325,10 @@ const nl: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Applicatie-instellingen wijzigen',
|
||||
SECURITY_1: 'Gebruikers toevoegen of verwijderen',
|
||||
UPLOAD_DOWNLOAD_1: 'Upload-/downloadinstellingen en firmware',
|
||||
MODULES: 'Modules'
|
||||
MODULES: 'Module',
|
||||
MODULES_UPDATED: 'Modules geüpdatet',
|
||||
MODULES_DESCRIPTION: 'Klik op de module om EMS-ESP library modules te activeren of te deactiveren',
|
||||
MODULES_NONE: 'Geen externe modules gedetecteerd'
|
||||
};
|
||||
|
||||
export default nl;
|
||||
|
||||
@@ -325,7 +325,10 @@ const no: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||
SECURITY_1: 'Add or remove users', // TODO translate
|
||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // TODO translate
|
||||
MODULES: 'Modules' // TODO translate
|
||||
MODULES: 'Module', // TODO translate
|
||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
||||
MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate
|
||||
MODULES_NONE: 'No external modules detected' // TODO translate
|
||||
};
|
||||
|
||||
export default no;
|
||||
|
||||
@@ -325,7 +325,10 @@ const pl: BaseTranslation = {
|
||||
APPLICATION_SETTINGS_1: 'Modyfikacja ustawień aplikacji EMS-ESP',
|
||||
SECURITY_1: 'Dodawanie i usuwanie użytkowników',
|
||||
UPLOAD_DOWNLOAD_1: 'Wysyłanie/pobieranie ustawień i firmware',
|
||||
MODULES: 'Moduły'
|
||||
MODULES: 'Module', // TODO translate
|
||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
||||
MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate
|
||||
MODULES_NONE: 'No external modules detected' // TODO translate
|
||||
};
|
||||
|
||||
export default pl;
|
||||
|
||||
@@ -325,7 +325,10 @@ const sk: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||
SECURITY_1: 'Add or remove users', // TODO translate
|
||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // TODO translate
|
||||
MODULES: 'Modules' // TODO translate
|
||||
MODULES: 'Module', // TODO translate
|
||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
||||
MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate
|
||||
MODULES_NONE: 'No external modules detected' // TODO translate
|
||||
};
|
||||
|
||||
export default sk;
|
||||
|
||||
@@ -325,7 +325,10 @@ const sv: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||
SECURITY_1: 'Add or remove users', // TODO translate
|
||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // TODO translate
|
||||
MODULES: 'Modules' // TODO translate
|
||||
MODULES: 'Module', // TODO translate
|
||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
||||
MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate
|
||||
MODULES_NONE: 'No external modules detected' // TODO translate
|
||||
};
|
||||
|
||||
export default sv;
|
||||
|
||||
@@ -325,7 +325,10 @@ const tr: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||
SECURITY_1: 'Add or remove users', // TODO translate
|
||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // TODO translate
|
||||
MODULES: 'Modules' // TODO translate
|
||||
MODULES: 'Module', // TODO translate
|
||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
||||
MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate
|
||||
MODULES_NONE: 'No external modules detected' // TODO translate
|
||||
};
|
||||
|
||||
export default tr;
|
||||
|
||||
@@ -270,7 +270,7 @@ const Devices: FC = () => {
|
||||
async function onSelectChange(action: Action, state: State) {
|
||||
setSelectedDevice(state.id as number);
|
||||
if (action.type === 'ADD_BY_ID_EXCLUSIVELY') {
|
||||
await readDeviceData(state.id);
|
||||
await readDeviceData(state.id as number);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,7 +417,7 @@ const Devices: FC = () => {
|
||||
|
||||
const deviceValueDialogSave = async (devicevalue: DeviceValue) => {
|
||||
const id = Number(device_select.state.id);
|
||||
await writeDeviceValue({ id, c: devicevalue.c, v: devicevalue.v })
|
||||
await writeDeviceValue({ id, c: devicevalue.c ?? '', v: devicevalue.v })
|
||||
.then(() => {
|
||||
toast.success(LL.WRITE_CMD_SENT());
|
||||
})
|
||||
|
||||
@@ -45,7 +45,6 @@ const Help: FC = () => {
|
||||
);
|
||||
|
||||
anchor.download =
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
'emsesp_' + event.sendArgs[0].device + '_' + event.sendArgs[0].entity + '.txt';
|
||||
anchor.click();
|
||||
URL.revokeObjectURL(anchor.href);
|
||||
|
||||
274
interface/src/project/Modules.tsx
Normal file
274
interface/src/project/Modules.tsx
Normal file
@@ -0,0 +1,274 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import type { FC } from 'react';
|
||||
import { useBlocker } from 'react-router-dom';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import CircleIcon from '@mui/icons-material/Circle';
|
||||
import WarningIcon from '@mui/icons-material/Warning';
|
||||
import { Box, Button, Typography } from '@mui/material';
|
||||
|
||||
import {
|
||||
Body,
|
||||
Cell,
|
||||
Header,
|
||||
HeaderCell,
|
||||
HeaderRow,
|
||||
Row,
|
||||
Table
|
||||
} from '@table-library/react-table-library/table';
|
||||
import { useTheme } from '@table-library/react-table-library/theme';
|
||||
import { updateState, useRequest } from 'alova';
|
||||
import {
|
||||
BlockNavigation,
|
||||
ButtonRow,
|
||||
FormLoader,
|
||||
SectionContent,
|
||||
useLayoutTitle
|
||||
} from 'components';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
|
||||
import * as EMSESP from './api';
|
||||
import ModulesDialog from './ModulesDialog';
|
||||
import type { ModuleItem, Modules } from './types';
|
||||
|
||||
const Modules: FC = () => {
|
||||
const { LL } = useI18nContext();
|
||||
const [numChanges, setNumChanges] = useState<number>(0);
|
||||
const blocker = useBlocker(numChanges !== 0);
|
||||
|
||||
const [selectedModuleItem, setSelectedModuleItem] = useState<ModuleItem>();
|
||||
const [dialogOpen, setDialogOpen] = useState<boolean>(false);
|
||||
|
||||
const {
|
||||
data: modules,
|
||||
send: fetchModules,
|
||||
error
|
||||
} = useRequest(EMSESP.readModules, {
|
||||
initialData: []
|
||||
});
|
||||
|
||||
const { send: writeModules } = useRequest(
|
||||
(data: { key: string; enabled: boolean; license: string }) =>
|
||||
EMSESP.writeModules(data),
|
||||
{
|
||||
immediate: false
|
||||
}
|
||||
);
|
||||
|
||||
const modules_theme = useTheme({
|
||||
Table: `
|
||||
--data-table-library_grid-template-columns: 48px 180px 120px 100px repeat(1, minmax(160px, 1fr)) 180px;
|
||||
`,
|
||||
BaseRow: `
|
||||
font-size: 14px;
|
||||
.td {
|
||||
height: 32px;
|
||||
}
|
||||
`,
|
||||
BaseCell: `
|
||||
&:nth-of-type(1) {
|
||||
text-align: center;
|
||||
}
|
||||
`,
|
||||
HeaderRow: `
|
||||
text-transform: uppercase;
|
||||
background-color: black;
|
||||
color: #90CAF9;
|
||||
.th {
|
||||
border-bottom: 1px solid #565656;
|
||||
height: 36px;
|
||||
}
|
||||
`,
|
||||
Row: `
|
||||
background-color: #1e1e1e;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
.td {
|
||||
border-top: 1px solid #565656;
|
||||
border-bottom: 1px solid #565656;
|
||||
}
|
||||
&:hover .td {
|
||||
border-top: 1px solid #177ac9;
|
||||
border-bottom: 1px solid #177ac9;
|
||||
}
|
||||
&:nth-of-type(odd) .td {
|
||||
background-color: #303030;
|
||||
}
|
||||
`
|
||||
});
|
||||
|
||||
const onDialogClose = () => {
|
||||
setDialogOpen(false);
|
||||
};
|
||||
|
||||
const onDialogSave = (updatedItem: ModuleItem) => {
|
||||
setDialogOpen(false);
|
||||
updateModuleItem(updatedItem);
|
||||
};
|
||||
|
||||
const editModuleItem = useCallback((mi: ModuleItem) => {
|
||||
setSelectedModuleItem(mi);
|
||||
setDialogOpen(true);
|
||||
}, []);
|
||||
|
||||
const onCancel = async () => {
|
||||
await fetchModules().then(() => {
|
||||
setNumChanges(0);
|
||||
});
|
||||
};
|
||||
|
||||
function hasModulesChanged(mi: ModuleItem) {
|
||||
return mi.enabled !== mi.o_enabled || mi.license !== mi.o_license;
|
||||
}
|
||||
|
||||
const updateModuleItem = (updatedItem: ModuleItem) => {
|
||||
updateState('modules', (data: ModuleItem[]) => {
|
||||
const new_data = data.map((mi) =>
|
||||
mi.id === updatedItem.id ? { ...mi, ...updatedItem } : mi
|
||||
);
|
||||
setNumChanges(new_data.filter((mi) => hasModulesChanged(mi)).length);
|
||||
return new_data;
|
||||
});
|
||||
};
|
||||
|
||||
const saveModules = async () => {
|
||||
await writeModules({
|
||||
modules: modules.map((condensed_mi) => ({
|
||||
key: condensed_mi.key,
|
||||
enabled: condensed_mi.enabled,
|
||||
license: condensed_mi.license
|
||||
}))
|
||||
})
|
||||
.then(() => {
|
||||
toast.success(LL.MODULES_UPDATED());
|
||||
})
|
||||
.catch((error: Error) => {
|
||||
toast.error(error.message);
|
||||
})
|
||||
.finally(async () => {
|
||||
await fetchModules();
|
||||
setNumChanges(0);
|
||||
});
|
||||
};
|
||||
|
||||
const renderContent = () => {
|
||||
if (!modules) {
|
||||
return <FormLoader onRetry={fetchModules} errorMessage={error?.message} />;
|
||||
}
|
||||
|
||||
useLayoutTitle(LL.MODULES());
|
||||
|
||||
if (modules.length === 0) {
|
||||
return (
|
||||
<Typography variant="body2" color="error">
|
||||
{LL.MODULES_NONE()}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
const colorStatus = (status: number) => {
|
||||
if (status === 1) {
|
||||
// TODO translate
|
||||
return <div style={{ color: 'red' }}>Pending Activation</div>;
|
||||
}
|
||||
return <div style={{ color: '#00FF7F' }}>Activated</div>;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box mb={2} color="warning.main">
|
||||
<Typography variant="body2">{LL.MODULES_DESCRIPTION()}</Typography>
|
||||
</Box>
|
||||
<Table
|
||||
data={{ nodes: modules }}
|
||||
theme={modules_theme}
|
||||
layout={{ custom: true }}
|
||||
>
|
||||
{(tableList: ModuleItem[]) => (
|
||||
<>
|
||||
<Header>
|
||||
<HeaderRow>
|
||||
<HeaderCell />
|
||||
<HeaderCell>{LL.NAME(0)}</HeaderCell>
|
||||
{/* TODO translate */}
|
||||
<HeaderCell>Author</HeaderCell>
|
||||
<HeaderCell>{LL.VERSION()}</HeaderCell>
|
||||
{/* TODO translate */}
|
||||
<HeaderCell>Message</HeaderCell>
|
||||
<HeaderCell>{LL.STATUS_OF('')}</HeaderCell>
|
||||
</HeaderRow>
|
||||
</Header>
|
||||
<Body>
|
||||
{tableList.map((mi: ModuleItem) => (
|
||||
<Row key={mi.id} item={mi} onClick={() => editModuleItem(mi)}>
|
||||
<Cell stiff>
|
||||
{mi.enabled ? (
|
||||
<CircleIcon
|
||||
color="success"
|
||||
sx={{ fontSize: 16, verticalAlign: 'middle' }}
|
||||
/>
|
||||
) : (
|
||||
<CircleIcon
|
||||
color="error"
|
||||
sx={{ fontSize: 16, verticalAlign: 'middle' }}
|
||||
/>
|
||||
)}
|
||||
</Cell>
|
||||
<Cell>{mi.name}</Cell>
|
||||
<Cell>{mi.author}</Cell>
|
||||
<Cell>{mi.version}</Cell>
|
||||
<Cell>{mi.message}</Cell>
|
||||
<Cell>{colorStatus(mi.status)}</Cell>
|
||||
</Row>
|
||||
))}
|
||||
</Body>
|
||||
</>
|
||||
)}
|
||||
</Table>
|
||||
|
||||
<Box mt={1} display="flex" flexWrap="wrap">
|
||||
<Box flexGrow={1}>
|
||||
{numChanges !== 0 && (
|
||||
<ButtonRow>
|
||||
<Button
|
||||
startIcon={<CancelIcon />}
|
||||
variant="outlined"
|
||||
onClick={onCancel}
|
||||
color="secondary"
|
||||
>
|
||||
{LL.CANCEL()}
|
||||
</Button>
|
||||
<Button
|
||||
startIcon={<WarningIcon color="warning" />}
|
||||
variant="contained"
|
||||
color="info"
|
||||
onClick={saveModules}
|
||||
>
|
||||
{LL.APPLY_CHANGES(numChanges)}
|
||||
</Button>
|
||||
</ButtonRow>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<SectionContent>
|
||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||
{renderContent()}
|
||||
{selectedModuleItem && (
|
||||
<ModulesDialog
|
||||
open={dialogOpen}
|
||||
onClose={onDialogClose}
|
||||
onSave={onDialogSave}
|
||||
selectedItem={selectedModuleItem}
|
||||
/>
|
||||
)}
|
||||
</SectionContent>
|
||||
);
|
||||
};
|
||||
|
||||
export default Modules;
|
||||
108
interface/src/project/ModulesDialog.tsx
Normal file
108
interface/src/project/ModulesDialog.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import DoneIcon from '@mui/icons-material/Done';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Checkbox,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
Grid,
|
||||
TextField
|
||||
} from '@mui/material';
|
||||
|
||||
import { dialogStyle } from 'CustomTheme';
|
||||
import { BlockFormControlLabel } from 'components';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import { updateValue } from 'utils';
|
||||
|
||||
import type { ModuleItem } from './types';
|
||||
|
||||
interface ModulesDialogProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
onSave: (mi: ModuleItem) => void;
|
||||
selectedItem: ModuleItem;
|
||||
}
|
||||
|
||||
const ModulesDialog = ({
|
||||
open,
|
||||
onClose,
|
||||
onSave,
|
||||
selectedItem
|
||||
}: ModulesDialogProps) => {
|
||||
const { LL } = useI18nContext();
|
||||
const [editItem, setEditItem] = useState<ModuleItem>(selectedItem);
|
||||
|
||||
const updateFormValue = updateValue(setEditItem);
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
setEditItem(selectedItem);
|
||||
}
|
||||
}, [open, selectedItem]);
|
||||
|
||||
const close = () => {
|
||||
onClose();
|
||||
};
|
||||
|
||||
const save = () => {
|
||||
onSave(editItem);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog sx={dialogStyle} fullWidth maxWidth="xs" open={open} onClose={onClose}>
|
||||
<DialogTitle>{LL.EDIT() + ' ' + editItem.key}</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Grid container>
|
||||
<BlockFormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={editItem.enabled}
|
||||
onChange={updateFormValue}
|
||||
name="enabled"
|
||||
/>
|
||||
}
|
||||
// TODO translate
|
||||
label="Enabled"
|
||||
/>
|
||||
</Grid>
|
||||
<Box mt={2} mb={1}>
|
||||
<TextField
|
||||
name="license"
|
||||
label="License Key"
|
||||
multiline
|
||||
rows={6}
|
||||
columns={40}
|
||||
fullWidth
|
||||
value={editItem.license}
|
||||
onChange={updateFormValue}
|
||||
/>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
startIcon={<CancelIcon />}
|
||||
variant="outlined"
|
||||
onClick={close}
|
||||
color="secondary"
|
||||
>
|
||||
{LL.CANCEL()}
|
||||
</Button>
|
||||
<Button
|
||||
startIcon={<DoneIcon />}
|
||||
variant="outlined"
|
||||
onClick={save}
|
||||
color="primary"
|
||||
>
|
||||
{LL.UPDATE()}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModulesDialog;
|
||||
@@ -9,6 +9,8 @@ import type {
|
||||
Devices,
|
||||
Entities,
|
||||
EntityItem,
|
||||
ModuleItem,
|
||||
Modules,
|
||||
Schedule,
|
||||
ScheduleItem,
|
||||
SensorData,
|
||||
@@ -48,6 +50,7 @@ export const writeAnalogSensor = (as: WriteAnalogSensor) =>
|
||||
// Activity
|
||||
export const readActivity = () => alovaInstance.Get<Activity>('/rest/activity');
|
||||
|
||||
// Scan devices
|
||||
export const scanDevices = () => alovaInstance.Post('/rest/scanDevices');
|
||||
|
||||
// API, used in HelpInformation
|
||||
@@ -104,6 +107,24 @@ export const readSchedule = () =>
|
||||
export const writeSchedule = (data: Schedule) =>
|
||||
alovaInstance.Post('/rest/schedule', data);
|
||||
|
||||
// Modules
|
||||
export const readModules = () =>
|
||||
alovaInstance.Get<ModuleItem[]>('/rest/modules', {
|
||||
name: 'modules',
|
||||
transformData(data) {
|
||||
return (data as Modules).modules.map((mi: ModuleItem) => ({
|
||||
...mi,
|
||||
o_enabled: mi.enabled,
|
||||
o_license: mi.license
|
||||
}));
|
||||
}
|
||||
});
|
||||
export const writeModules = (data: {
|
||||
key: string;
|
||||
enabled: boolean;
|
||||
license: string;
|
||||
}) => alovaInstance.Post('/rest/modules', data);
|
||||
|
||||
// SettingsEntities
|
||||
export const readCustomEntities = () =>
|
||||
alovaInstance.Get<EntityItem[]>('/rest/customEntities', {
|
||||
|
||||
@@ -308,6 +308,24 @@ export interface Schedule {
|
||||
schedule: ScheduleItem[];
|
||||
}
|
||||
|
||||
export interface ModuleItem {
|
||||
id: number; // unique index
|
||||
key: string;
|
||||
name: string;
|
||||
author: string;
|
||||
version: string;
|
||||
status: number;
|
||||
message: string;
|
||||
enabled: boolean;
|
||||
license: string;
|
||||
o_enabled?: boolean;
|
||||
o_license?: string;
|
||||
}
|
||||
|
||||
export interface Modules {
|
||||
modules: ModuleItem[];
|
||||
}
|
||||
|
||||
export enum ScheduleFlag {
|
||||
SCHEDULE_SUN = 1,
|
||||
SCHEDULE_MON = 2,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { busConnectionStatus } from 'project/types';
|
||||
|
||||
import type { NetworkConnectionStatus } from './network';
|
||||
|
||||
export interface ESPSystemStatus {
|
||||
emsesp_version: string;
|
||||
esp_platform: string;
|
||||
@@ -37,6 +39,8 @@ export interface SystemStatus {
|
||||
ntp_status: number;
|
||||
mqtt_status: boolean;
|
||||
ap_status: boolean;
|
||||
network_status: NetworkConnectionStatus;
|
||||
wifi_rssi: number;
|
||||
}
|
||||
|
||||
export enum LogLevel {
|
||||
|
||||
@@ -65,7 +65,7 @@ export const useRest = <D>({ read, update }: RestRequestOptions<D>) => {
|
||||
setErrorMessage(undefined);
|
||||
setDirtyFlags([]);
|
||||
setOrigData(data as D);
|
||||
await writeData(data).catch((error: Error) => {
|
||||
await writeData(data as D).catch((error: Error) => {
|
||||
if (error.message === 'Reboot required') {
|
||||
setRestartNeeded(true);
|
||||
} else {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include "src/ArduinoJson.h"
|
||||
@@ -1,130 +0,0 @@
|
||||
ArduinoJson: change log
|
||||
=======================
|
||||
|
||||
v7.0.3 (2024-02-05)
|
||||
------
|
||||
|
||||
* Improve error messages when using `char` or `char*` (issue #2043)
|
||||
* Reduce stack consumption (issue #2046)
|
||||
* Fix compatibility with GCC 4.8 (issue #2045)
|
||||
|
||||
v7.0.2 (2024-01-19)
|
||||
------
|
||||
|
||||
* Fix assertion `poolIndex < count_` after `JsonDocument::clear()` (issue #2034)
|
||||
|
||||
v7.0.1 (2024-01-10)
|
||||
------
|
||||
|
||||
* Fix "no matching function" with `JsonObjectConst::operator[]` (issue #2019)
|
||||
* Remove unused files in the PlatformIO package
|
||||
* Fix `volatile bool` serialized as `1` or `0` instead of `true` or `false` (issue #2029)
|
||||
|
||||
v7.0.0 (2024-01-03)
|
||||
------
|
||||
|
||||
* Remove `BasicJsonDocument`
|
||||
* Remove `StaticJsonDocument`
|
||||
* Add abstract `Allocator` class
|
||||
* Merge `DynamicJsonDocument` with `JsonDocument`
|
||||
* Remove `JSON_ARRAY_SIZE()`, `JSON_OBJECT_SIZE()`, and `JSON_STRING_SIZE()`
|
||||
* Remove `ARDUINOJSON_ENABLE_STRING_DEDUPLICATION` (string deduplication cannot be disabled anymore)
|
||||
* Remove `JsonDocument::capacity()`
|
||||
* Store the strings in the heap
|
||||
* Reference-count shared strings
|
||||
* Always store `serialized("string")` by copy (#1915)
|
||||
* Remove the zero-copy mode of `deserializeJson()` and `deserializeMsgPack()`
|
||||
* Fix double lookup in `to<JsonVariant>()`
|
||||
* Fix double call to `size()` in `serializeMsgPack()`
|
||||
* Include `ARDUINOJSON_SLOT_OFFSET_SIZE` in the namespace name
|
||||
* Remove `JsonVariant::shallowCopy()`
|
||||
* `JsonDocument`'s capacity grows as needed, no need to pass it to the constructor anymore
|
||||
* `JsonDocument`'s allocator is not monotonic anymore, removed values get recycled
|
||||
* Show a link to the documentation when user passes an unsupported input type
|
||||
* Remove `JsonDocument::memoryUsage()`
|
||||
* Remove `JsonDocument::garbageCollect()`
|
||||
* Add `deserializeJson(JsonVariant, ...)` and `deserializeMsgPack(JsonVariant, ...)` (#1226)
|
||||
* Call `shrinkToFit()` in `deserializeJson()` and `deserializeMsgPack()`
|
||||
* `serializeJson()` and `serializeMsgPack()` replace the content of `std::string` and `String` instead of appending to it
|
||||
* Replace `add()` with `add<T>()` (`add(T)` is still supported)
|
||||
* Remove `createNestedArray()` and `createNestedObject()` (use `to<JsonArray>()` and `to<JsonObject>()` instead)
|
||||
|
||||
> ### BREAKING CHANGES
|
||||
>
|
||||
> As every major release, ArduinoJson 7 introduces several breaking changes.
|
||||
> I added some stubs so that most existing programs should compile, but I highty recommend you upgrade your code.
|
||||
>
|
||||
> #### `JsonDocument`
|
||||
>
|
||||
> In ArduinoJson 6, you could allocate the memory pool on the stack (with `StaticJsonDocument`) or in the heap (with `DynamicJsonDocument`).
|
||||
> In ArduinoJson 7, the memory pool is always allocated in the heap, so `StaticJsonDocument` and `DynamicJsonDocument` have been merged into `JsonDocument`.
|
||||
>
|
||||
> In ArduinoJson 6, `JsonDocument` had a fixed capacity; in ArduinoJson 7, it has an elastic capacity that grows as needed.
|
||||
> Therefore, you don't need to specify the capacity anymore, so the macros `JSON_ARRAY_SIZE()`, `JSON_OBJECT_SIZE()`, and `JSON_STRING_SIZE()` have been removed.
|
||||
>
|
||||
> ```c++
|
||||
> // ArduinoJson 6
|
||||
> StaticJsonDocument<256> doc;
|
||||
> // or
|
||||
> DynamicJsonDocument doc(256);
|
||||
>
|
||||
> // ArduinoJson 7
|
||||
> JsonDocument doc;
|
||||
> ```
|
||||
>
|
||||
> In ArduinoJson 7, `JsonDocument` reuses released memory, so `garbageCollect()` has been removed.
|
||||
> `shrinkToFit()` is still available and releases the over-allocated memory.
|
||||
>
|
||||
> Due to a change in the implementation, it's not possible to store a pointer to a variant from another `JsonDocument`, so `shallowCopy()` has been removed.
|
||||
>
|
||||
> In ArduinoJson 6, the meaning of `memoryUsage()` was clear: it returned the number of bytes used in the memory pool.
|
||||
> In ArduinoJson 7, the meaning of `memoryUsage()` would be ambiguous, so it has been removed.
|
||||
>
|
||||
> #### Custom allocators
|
||||
>
|
||||
> In ArduinoJson 6, you could specify a custom allocator class as a template parameter of `BasicJsonDocument`.
|
||||
> In ArduinoJson 7, you must inherit from `ArduinoJson::Allocator` and pass a pointer to an instance of your class to the constructor of `JsonDocument`.
|
||||
>
|
||||
> ```c++
|
||||
> // ArduinoJson 6
|
||||
> class MyAllocator {
|
||||
> // ...
|
||||
> };
|
||||
> BasicJsonDocument<MyAllocator> doc(256);
|
||||
>
|
||||
> // ArduinoJson 7
|
||||
> class MyAllocator : public ArduinoJson::Allocator {
|
||||
> // ...
|
||||
> };
|
||||
> MyAllocator myAllocator;
|
||||
> JsonDocument doc(&myAllocator);
|
||||
> ```
|
||||
>
|
||||
> #### `createNestedArray()` and `createNestedObject()`
|
||||
>
|
||||
> In ArduinoJson 6, you could create a nested array or object with `createNestedArray()` and `createNestedObject()`.
|
||||
> In ArduinoJson 7, you must use `add<T>()` or `to<T>()` instead.
|
||||
>
|
||||
> For example, to create `[[],{}]`, you would write:
|
||||
>
|
||||
> ```c++
|
||||
> // ArduinoJson 6
|
||||
> arr.createNestedArray();
|
||||
> arr.createNestedObject();
|
||||
>
|
||||
> // ArduinoJson 7
|
||||
> arr.add<JsonArray>();
|
||||
> arr.add<JsonObject>();
|
||||
> ```
|
||||
>
|
||||
> And to create `{"array":[],"object":{}}`, you would write:
|
||||
>
|
||||
> ```c++
|
||||
> // ArduinoJson 6
|
||||
> obj.createNestedArray("array");
|
||||
> obj.createNestedObject("object");
|
||||
>
|
||||
> // ArduinoJson 7
|
||||
> obj["array"].to<JsonArray>();
|
||||
> obj["object"].to<JsonObject>();
|
||||
> ```
|
||||
@@ -1,10 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
---------------------
|
||||
|
||||
Copyright © 2014-2024, Benoit BLANCHON
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,155 +0,0 @@
|
||||
<p align="center">
|
||||
<a href="https://arduinojson.org/"><img alt="ArduinoJson" src="https://arduinojson.org/images/logo.svg" width="200" /></a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
[](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A7.x)
|
||||
[](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/7.x)
|
||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
|
||||
[](https://coveralls.io/github/bblanchon/ArduinoJson?branch=7.x)
|
||||
[](https://github.com/bblanchon/ArduinoJson/stargazers)
|
||||
[](https://github.com/sponsors/bblanchon)
|
||||
|
||||
ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
|
||||
|
||||
## Features
|
||||
|
||||
* [JSON deserialization](https://arduinojson.org/v7/api/json/deserializejson/)
|
||||
* [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v7/api/config/decode_unicode/)
|
||||
* [Optionally supports comments in the input](https://arduinojson.org/v7/api/config/enable_comments/)
|
||||
* [Optionally filters the input to keep only desired values](https://arduinojson.org/v7/api/json/deserializejson/#filtering)
|
||||
* Supports single quotes as a string delimiter
|
||||
* Compatible with [NDJSON](http://ndjson.org/) and [JSON Lines](https://jsonlines.org/)
|
||||
* [JSON serialization](https://arduinojson.org/v7/api/json/serializejson/)
|
||||
* [Can write to a buffer or a stream](https://arduinojson.org/v7/api/json/serializejson/)
|
||||
* [Optionally indents the document (prettified JSON)](https://arduinojson.org/v7/api/json/serializejsonpretty/)
|
||||
* [MessagePack serialization](https://arduinojson.org/v7/api/msgpack/serializemsgpack/)
|
||||
* [MessagePack deserialization](https://arduinojson.org/v7/api/msgpack/deserializemsgpack/)
|
||||
* Efficient
|
||||
* [Twice smaller than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
|
||||
* [Almost 10% faster than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
|
||||
* [Consumes roughly 10% less RAM than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
|
||||
* [Deduplicates strings](https://arduinojson.org/news/2020/08/01/version-6-16-0/)
|
||||
* Versatile
|
||||
* Supports [custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v7/how-to/use-external-ram-on-esp32/)
|
||||
* Supports [`String`](https://arduinojson.org/v7/api/config/enable_arduino_string/), [`std::string`](https://arduinojson.org/v7/api/config/enable_std_string/), and [`std::string_view`](https://arduinojson.org/v7/api/config/enable_string_view/)
|
||||
* Supports [`Stream`](https://arduinojson.org/v7/api/config/enable_arduino_stream/) and [`std::istream`/`std::ostream`](https://arduinojson.org/v7/api/config/enable_std_stream/)
|
||||
* Supports [Flash strings](https://arduinojson.org/v7/api/config/enable_progmem/)
|
||||
* Supports [custom readers](https://arduinojson.org/v7/api/json/deserializejson/#custom-reader) and [custom writers](https://arduinojson.org/v7/api/json/serializejson/#custom-writer)
|
||||
* Supports [custom converters](https://arduinojson.org/news/2021/05/04/version-6-18-0/)
|
||||
* Portable
|
||||
* Usable on any C++ project (not limited to Arduino)
|
||||
* Compatible with C++11, C++14 and C++17
|
||||
* Support for C++98/C++03 available on [ArduinoJson 6.20.x](https://github.com/bblanchon/ArduinoJson/tree/6.20.x)
|
||||
* Zero warnings with `-Wall -Wextra -pedantic` and `/W4`
|
||||
* [Header-only library](https://en.wikipedia.org/wiki/Header-only)
|
||||
* Works with virtually any board
|
||||
* Arduino boards: [Uno](https://amzn.to/38aL2ik), [Due](https://amzn.to/36YkWi2), [Micro](https://amzn.to/35WkdwG), [Nano](https://amzn.to/2QTvwRX), [Mega](https://amzn.to/36XWhuf), [Yun](https://amzn.to/30odURc), [Leonardo](https://amzn.to/36XWjlR)...
|
||||
* Espressif chips: [ESP8266](https://amzn.to/36YluV8), [ESP32](https://amzn.to/2G4pRCB)
|
||||
* Lolin (WeMos) boards: [D1 mini](https://amzn.to/2QUpz7q), [D1 Mini Pro](https://amzn.to/36UsGSs)...
|
||||
* Teensy boards: [4.0](https://amzn.to/30ljXGq), [3.2](https://amzn.to/2FT0EuC), [2.0](https://amzn.to/2QXUMXj)
|
||||
* Particle boards: [Argon](https://amzn.to/2FQHa9X), [Boron](https://amzn.to/36WgLUd), [Electron](https://amzn.to/30vEc4k), [Photon](https://amzn.to/387F9Cd)...
|
||||
* Texas Instruments boards: [MSP430](https://amzn.to/30nJWgg)...
|
||||
* Soft cores: [Nios II](https://en.wikipedia.org/wiki/Nios_II)...
|
||||
* Tested on all major development environments
|
||||
* [Arduino IDE](https://www.arduino.cc/en/Main/Software)
|
||||
* [Atmel Studio](http://www.atmel.com/microsite/atmel-studio/)
|
||||
* [Atollic TrueSTUDIO](https://atollic.com/truestudio/)
|
||||
* [Energia](http://energia.nu/)
|
||||
* [IAR Embedded Workbench](https://www.iar.com/iar-embedded-workbench/)
|
||||
* [Keil uVision](http://www.keil.com/)
|
||||
* [MPLAB X IDE](http://www.microchip.com/mplab/mplab-x-ide)
|
||||
* [Particle](https://www.particle.io/)
|
||||
* [PlatformIO](http://platformio.org/)
|
||||
* [Sloeber plugin for Eclipse](https://eclipse.baeyens.it/)
|
||||
* [Visual Micro](http://www.visualmicro.com/)
|
||||
* [Visual Studio](https://www.visualstudio.com/)
|
||||
* [Even works with online compilers like wandbox.org](https://wandbox.org/permlink/RlZSKy17DjJ6HcdN)
|
||||
* [CMake friendly](https://arduinojson.org/v7/how-to/use-arduinojson-with-cmake/)
|
||||
* Well designed
|
||||
* [Elegant API](http://arduinojson.org/v7/example/)
|
||||
* [Thread-safe](https://en.wikipedia.org/wiki/Thread_safety)
|
||||
* Self-contained (no external dependency)
|
||||
* `const` friendly
|
||||
* [`for` friendly](https://arduinojson.org/v7/api/jsonobject/begin_end/)
|
||||
* [TMP friendly](https://en.wikipedia.org/wiki/Template_metaprogramming)
|
||||
* Handles [integer overflows](https://arduinojson.org/v7/api/jsonvariant/as/#integer-overflows)
|
||||
* Well tested
|
||||
* [Unit test coverage close to 100%](https://coveralls.io/github/bblanchon/ArduinoJson?branch=7.x)
|
||||
* Continuously tested on
|
||||
* [Visual Studio 2017, 2019, 2022](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/7.x)
|
||||
* [GCC 4.8, 5, 6, 7, 8, 9, 10, 11, 12](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
|
||||
* [Clang 3.9, 4.0, 5.0, 6.0, 7, 8, 9, 10, 11, 12, 13, 14, 15](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
|
||||
* [Continuously fuzzed with Google OSS Fuzz](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
|
||||
* Passes all default checks of [clang-tidy](https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/)
|
||||
* Well documented
|
||||
* [Tutorials](https://arduinojson.org/v7/doc/deserialization/)
|
||||
* [Examples](https://arduinojson.org/v7/example/)
|
||||
* [How-tos](https://arduinojson.org/v7/example/)
|
||||
* [FAQ](https://arduinojson.org/v7/faq/)
|
||||
* [Troubleshooter](https://arduinojson.org/v7/troubleshooter/)
|
||||
* [Book](https://arduinojson.org/book/)
|
||||
* [Changelog](CHANGELOG.md)
|
||||
* Vibrant user community
|
||||
* Most popular of all Arduino libraries on [GitHub](https://github.com/search?o=desc&q=arduino+library&s=stars&type=Repositories)
|
||||
* [Used in hundreds of projects](https://www.hackster.io/search?i=projects&q=arduinojson)
|
||||
* [Responsive support](https://github.com/bblanchon/ArduinoJson/issues?q=is%3Aissue+is%3Aclosed)
|
||||
|
||||
## Quickstart
|
||||
|
||||
### Deserialization
|
||||
|
||||
Here is a program that parses a JSON document with ArduinoJson.
|
||||
|
||||
```c++
|
||||
const char* json = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
|
||||
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, json);
|
||||
|
||||
const char* sensor = doc["sensor"];
|
||||
long time = doc["time"];
|
||||
double latitude = doc["data"][0];
|
||||
double longitude = doc["data"][1];
|
||||
```
|
||||
|
||||
See the [tutorial on arduinojson.org](https://arduinojson.org/v7/doc/deserialization/)
|
||||
|
||||
### Serialization
|
||||
|
||||
Here is a program that generates a JSON document with ArduinoJson:
|
||||
|
||||
```c++
|
||||
JsonDocument doc;
|
||||
|
||||
doc["sensor"] = "gps";
|
||||
doc["time"] = 1351824120;
|
||||
doc["data"][0] = 48.756080;
|
||||
doc["data"][1] = 2.302038;
|
||||
|
||||
serializeJson(doc, Serial);
|
||||
// This prints:
|
||||
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
|
||||
```
|
||||
|
||||
See the [tutorial on arduinojson.org](https://arduinojson.org/v7/doc/serialization/)
|
||||
|
||||
## Sponsors
|
||||
|
||||
ArduinoJson is thankful to its sponsors. Please give them a visit; they deserve it!
|
||||
|
||||
<p>
|
||||
<a href="https://www.programmingelectronics.com/" rel="sponsored">
|
||||
<img src="https://arduinojson.org/images/2021/10/programmingeleactronicsacademy.png" alt="Programming Electronics Academy" width="200">
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://github.com/1technophile" rel="sponsored">
|
||||
<img alt="1technophile" src="https://avatars.githubusercontent.com/u/12672732?s=40&v=4">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
If you run a commercial project that embeds ArduinoJson, think about [sponsoring the library's development](https://github.com/sponsors/bblanchon): it ensures the code that your products rely on stays actively maintained. It can also give your project some exposure to the makers' community.
|
||||
|
||||
If you are an individual user and want to support the development (or give a sign of appreciation), consider purchasing the book [Mastering ArduinoJson](https://arduinojson.org/book/) ❤, or simply [cast a star](https://github.com/bblanchon/ArduinoJson/stargazers) ⭐.
|
||||
@@ -1,27 +0,0 @@
|
||||
# ArduinoJson Support
|
||||
|
||||
First off, thank you very much for using ArduinoJson.
|
||||
|
||||
We'll be very happy to help you, but first please read the following.
|
||||
|
||||
## Before asking for help
|
||||
|
||||
1. Read the [FAQ](https://arduinojson.org/faq/?utm_source=github&utm_medium=support)
|
||||
2. Search in the [API Reference](https://arduinojson.org/api/?utm_source=github&utm_medium=support)
|
||||
|
||||
If you did not find the answer, please create a [new issue on GitHub](https://github.com/bblanchon/ArduinoJson/issues/new).
|
||||
|
||||
It is OK to add a comment to a currently opened issue, but please avoid adding comments to a closed issue.
|
||||
|
||||
## Before hitting the Submit button
|
||||
|
||||
Please provide all the relevant information:
|
||||
|
||||
* Good title
|
||||
* Short description of the problem
|
||||
* Target platform
|
||||
* Compiler model and version
|
||||
* [MVCE](https://stackoverflow.com/help/mcve)
|
||||
* Compiler output
|
||||
|
||||
Good questions get fast answers!
|
||||
@@ -1,17 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
# include "ArduinoJson.hpp"
|
||||
|
||||
using namespace ArduinoJson;
|
||||
|
||||
#else
|
||||
|
||||
#error ArduinoJson requires a C++ compiler, please change file extension to .cc or .cpp
|
||||
|
||||
#endif
|
||||
@@ -1,53 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_VER < 1910)
|
||||
# error ArduinoJson requires C++11 or newer. Configure your compiler for C++11 or downgrade ArduinoJson to 6.20.
|
||||
#endif
|
||||
|
||||
#include "ArduinoJson/Configuration.hpp"
|
||||
|
||||
// Include Arduino.h before stdlib.h to avoid conflict with atexit()
|
||||
// https://github.com/bblanchon/ArduinoJson/pull/1693#issuecomment-1001060240
|
||||
#if ARDUINOJSON_ENABLE_ARDUINO_STRING || ARDUINOJSON_ENABLE_ARDUINO_STREAM || \
|
||||
ARDUINOJSON_ENABLE_ARDUINO_PRINT || \
|
||||
(ARDUINOJSON_ENABLE_PROGMEM && defined(ARDUINO))
|
||||
# include <Arduino.h>
|
||||
#endif
|
||||
|
||||
#if !ARDUINOJSON_DEBUG
|
||||
# ifdef __clang__
|
||||
# pragma clang system_header
|
||||
# elif defined __GNUC__
|
||||
# pragma GCC system_header
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "ArduinoJson/Array/JsonArray.hpp"
|
||||
#include "ArduinoJson/Object/JsonObject.hpp"
|
||||
#include "ArduinoJson/Variant/JsonVariantConst.hpp"
|
||||
|
||||
#include "ArduinoJson/Document/JsonDocument.hpp"
|
||||
|
||||
#include "ArduinoJson/Array/ArrayImpl.hpp"
|
||||
#include "ArduinoJson/Array/ElementProxy.hpp"
|
||||
#include "ArduinoJson/Array/Utilities.hpp"
|
||||
#include "ArduinoJson/Collection/CollectionImpl.hpp"
|
||||
#include "ArduinoJson/Memory/VariantPoolImpl.hpp"
|
||||
#include "ArduinoJson/Object/MemberProxy.hpp"
|
||||
#include "ArduinoJson/Object/ObjectImpl.hpp"
|
||||
#include "ArduinoJson/Variant/ConverterImpl.hpp"
|
||||
#include "ArduinoJson/Variant/JsonVariantCopier.hpp"
|
||||
#include "ArduinoJson/Variant/VariantCompare.hpp"
|
||||
#include "ArduinoJson/Variant/VariantRefBaseImpl.hpp"
|
||||
|
||||
#include "ArduinoJson/Json/JsonDeserializer.hpp"
|
||||
#include "ArduinoJson/Json/JsonSerializer.hpp"
|
||||
#include "ArduinoJson/Json/PrettyJsonSerializer.hpp"
|
||||
#include "ArduinoJson/MsgPack/MsgPackDeserializer.hpp"
|
||||
#include "ArduinoJson/MsgPack/MsgPackSerializer.hpp"
|
||||
|
||||
#include "ArduinoJson/compatibility.hpp"
|
||||
@@ -1,57 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Collection/CollectionData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class ArrayData : public CollectionData {
|
||||
public:
|
||||
VariantData* addElement(ResourceManager* resources) {
|
||||
return addSlot(resources).data();
|
||||
}
|
||||
|
||||
static VariantData* addElement(ArrayData* array, ResourceManager* resources) {
|
||||
if (!array)
|
||||
return nullptr;
|
||||
return array->addElement(resources);
|
||||
}
|
||||
|
||||
VariantData* getOrAddElement(size_t index, ResourceManager* resources);
|
||||
|
||||
VariantData* getElement(size_t index, const ResourceManager* resources) const;
|
||||
|
||||
static VariantData* getElement(const ArrayData* array, size_t index,
|
||||
const ResourceManager* resources) {
|
||||
if (!array)
|
||||
return nullptr;
|
||||
return array->getElement(index, resources);
|
||||
}
|
||||
|
||||
void removeElement(size_t index, ResourceManager* resources);
|
||||
|
||||
static void removeElement(ArrayData* array, size_t index,
|
||||
ResourceManager* resources) {
|
||||
if (!array)
|
||||
return;
|
||||
array->removeElement(index, resources);
|
||||
}
|
||||
|
||||
bool copyFrom(const ArrayData& src, ResourceManager* resources);
|
||||
|
||||
static bool copy(ArrayData* dst, const ArrayData* src,
|
||||
ResourceManager* resources) {
|
||||
if (!dst || !src)
|
||||
return false;
|
||||
|
||||
return dst->copyFrom(*src, resources);
|
||||
}
|
||||
|
||||
private:
|
||||
iterator at(size_t index, const ResourceManager* resources) const;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,50 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Array/ArrayData.hpp>
|
||||
#include <ArduinoJson/Variant/VariantCompare.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
inline ArrayData::iterator ArrayData::at(
|
||||
size_t index, const ResourceManager* resources) const {
|
||||
auto it = createIterator(resources);
|
||||
while (!it.done() && index) {
|
||||
it.next(resources);
|
||||
--index;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
inline VariantData* ArrayData::getOrAddElement(size_t index,
|
||||
ResourceManager* resources) {
|
||||
auto it = createIterator(resources);
|
||||
while (!it.done() && index > 0) {
|
||||
it.next(resources);
|
||||
index--;
|
||||
}
|
||||
if (it.done())
|
||||
index++;
|
||||
VariantData* element = it.data();
|
||||
while (index > 0) {
|
||||
element = addElement(resources);
|
||||
if (!element)
|
||||
return nullptr;
|
||||
index--;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
inline VariantData* ArrayData::getElement(
|
||||
size_t index, const ResourceManager* resources) const {
|
||||
return at(index, resources).data();
|
||||
}
|
||||
|
||||
inline void ArrayData::removeElement(size_t index, ResourceManager* resources) {
|
||||
remove(at(index, resources), resources);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,65 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Variant/VariantRefBase.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
// A proxy class to get or set an element of an array.
|
||||
// https://arduinojson.org/v7/api/jsonarray/subscript/
|
||||
template <typename TUpstream>
|
||||
class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
|
||||
public VariantOperators<ElementProxy<TUpstream>> {
|
||||
friend class VariantAttorney;
|
||||
|
||||
public:
|
||||
ElementProxy(TUpstream upstream, size_t index)
|
||||
: upstream_(upstream), index_(index) {}
|
||||
|
||||
ElementProxy(const ElementProxy& src)
|
||||
: upstream_(src.upstream_), index_(src.index_) {}
|
||||
|
||||
ElementProxy& operator=(const ElementProxy& src) {
|
||||
this->set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ElementProxy& operator=(const T& src) {
|
||||
this->set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ElementProxy& operator=(T* src) {
|
||||
this->set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
ResourceManager* getResourceManager() const {
|
||||
return VariantAttorney::getResourceManager(upstream_);
|
||||
}
|
||||
|
||||
FORCE_INLINE VariantData* getData() const {
|
||||
return VariantData::getElement(
|
||||
VariantAttorney::getData(upstream_), index_,
|
||||
VariantAttorney::getResourceManager(upstream_));
|
||||
}
|
||||
|
||||
VariantData* getOrCreateData() const {
|
||||
auto data = VariantAttorney::getOrCreateData(upstream_);
|
||||
if (!data)
|
||||
return nullptr;
|
||||
return data->getOrAddElement(
|
||||
index_, VariantAttorney::getResourceManager(upstream_));
|
||||
}
|
||||
|
||||
TUpstream upstream_;
|
||||
size_t index_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,196 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Array/ElementProxy.hpp>
|
||||
#include <ArduinoJson/Array/JsonArrayConst.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
class JsonObject;
|
||||
|
||||
// A reference to an array in a JsonDocument
|
||||
// https://arduinojson.org/v7/api/jsonarray/
|
||||
class JsonArray : public detail::VariantOperators<JsonArray> {
|
||||
friend class detail::VariantAttorney;
|
||||
|
||||
public:
|
||||
typedef JsonArrayIterator iterator;
|
||||
|
||||
// Constructs an unbound reference.
|
||||
JsonArray() : data_(0), resources_(0) {}
|
||||
|
||||
// INTERNAL USE ONLY
|
||||
JsonArray(detail::ArrayData* data, detail::ResourceManager* resources)
|
||||
: data_(data), resources_(resources) {}
|
||||
|
||||
// Returns a JsonVariant pointing to the array.
|
||||
// https://arduinojson.org/v7/api/jsonvariant/
|
||||
operator JsonVariant() {
|
||||
void* data = data_; // prevent warning cast-align
|
||||
return JsonVariant(reinterpret_cast<detail::VariantData*>(data),
|
||||
resources_);
|
||||
}
|
||||
|
||||
// Returns a read-only reference to the array.
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/
|
||||
operator JsonArrayConst() const {
|
||||
return JsonArrayConst(data_, resources_);
|
||||
}
|
||||
|
||||
// Appends a new (empty) element to the array.
|
||||
// Returns a reference to the new element.
|
||||
// https://arduinojson.org/v7/api/jsonarray/add/
|
||||
template <typename T>
|
||||
typename detail::enable_if<!detail::is_same<T, JsonVariant>::value, T>::type
|
||||
add() const {
|
||||
return add<JsonVariant>().to<T>();
|
||||
}
|
||||
|
||||
// Appends a new (null) element to the array.
|
||||
// Returns a reference to the new element.
|
||||
// https://arduinojson.org/v7/api/jsonarray/add/
|
||||
template <typename T>
|
||||
typename detail::enable_if<detail::is_same<T, JsonVariant>::value, T>::type
|
||||
add() const {
|
||||
return JsonVariant(detail::ArrayData::addElement(data_, resources_),
|
||||
resources_);
|
||||
}
|
||||
|
||||
// Appends a value to the array.
|
||||
// https://arduinojson.org/v7/api/jsonarray/add/
|
||||
template <typename T>
|
||||
bool add(const T& value) const {
|
||||
return add<JsonVariant>().set(value);
|
||||
}
|
||||
|
||||
// Appends a value to the array.
|
||||
// https://arduinojson.org/v7/api/jsonarray/add/
|
||||
template <typename T>
|
||||
bool add(T* value) const {
|
||||
return add<JsonVariant>().set(value);
|
||||
}
|
||||
|
||||
// Returns an iterator to the first element of the array.
|
||||
// https://arduinojson.org/v7/api/jsonarray/begin/
|
||||
iterator begin() const {
|
||||
if (!data_)
|
||||
return iterator();
|
||||
return iterator(data_->createIterator(resources_), resources_);
|
||||
}
|
||||
|
||||
// Returns an iterator following the last element of the array.
|
||||
// https://arduinojson.org/v7/api/jsonarray/end/
|
||||
iterator end() const {
|
||||
return iterator();
|
||||
}
|
||||
|
||||
// Copies an array.
|
||||
// https://arduinojson.org/v7/api/jsonarray/set/
|
||||
bool set(JsonArrayConst src) const {
|
||||
if (!data_)
|
||||
return false;
|
||||
|
||||
clear();
|
||||
for (auto element : src) {
|
||||
if (!add(element))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Removes the element at the specified iterator.
|
||||
// https://arduinojson.org/v7/api/jsonarray/remove/
|
||||
void remove(iterator it) const {
|
||||
detail::ArrayData::remove(data_, it.iterator_, resources_);
|
||||
}
|
||||
|
||||
// Removes the element at the specified index.
|
||||
// https://arduinojson.org/v7/api/jsonarray/remove/
|
||||
void remove(size_t index) const {
|
||||
detail::ArrayData::removeElement(data_, index, resources_);
|
||||
}
|
||||
|
||||
// Removes all the elements of the array.
|
||||
// https://arduinojson.org/v7/api/jsonarray/clear/
|
||||
void clear() const {
|
||||
detail::ArrayData::clear(data_, resources_);
|
||||
}
|
||||
|
||||
// Gets or sets the element at the specified index.
|
||||
// https://arduinojson.org/v7/api/jsonarray/subscript/
|
||||
detail::ElementProxy<JsonArray> operator[](size_t index) const {
|
||||
return {*this, index};
|
||||
}
|
||||
|
||||
operator JsonVariantConst() const {
|
||||
return JsonVariantConst(collectionToVariant(data_), resources_);
|
||||
}
|
||||
|
||||
// Returns true if the reference is unbound.
|
||||
// https://arduinojson.org/v7/api/jsonarray/isnull/
|
||||
bool isNull() const {
|
||||
return data_ == 0;
|
||||
}
|
||||
|
||||
// Returns true if the reference is bound.
|
||||
// https://arduinojson.org/v7/api/jsonarray/isnull/
|
||||
operator bool() const {
|
||||
return data_ != 0;
|
||||
}
|
||||
|
||||
// Returns the depth (nesting level) of the array.
|
||||
// https://arduinojson.org/v7/api/jsonarray/nesting/
|
||||
size_t nesting() const {
|
||||
return detail::VariantData::nesting(collectionToVariant(data_), resources_);
|
||||
}
|
||||
|
||||
// Returns the number of elements in the array.
|
||||
// https://arduinojson.org/v7/api/jsonarray/size/
|
||||
size_t size() const {
|
||||
return data_ ? data_->size(resources_) : 0;
|
||||
}
|
||||
|
||||
// DEPRECATED: use add<JsonVariant>() instead
|
||||
ARDUINOJSON_DEPRECATED("use add<JsonVariant>() instead")
|
||||
JsonVariant add() const {
|
||||
return add<JsonVariant>();
|
||||
}
|
||||
|
||||
// DEPRECATED: use add<JsonArray>() instead
|
||||
ARDUINOJSON_DEPRECATED("use add<JsonArray>() instead")
|
||||
JsonArray createNestedArray() const {
|
||||
return add<JsonArray>();
|
||||
}
|
||||
|
||||
// DEPRECATED: use add<JsonObject>() instead
|
||||
ARDUINOJSON_DEPRECATED("use add<JsonObject>() instead")
|
||||
JsonObject createNestedObject() const;
|
||||
|
||||
// DEPRECATED: always returns zero
|
||||
ARDUINOJSON_DEPRECATED("always returns zero")
|
||||
size_t memoryUsage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
detail::ResourceManager* getResourceManager() const {
|
||||
return resources_;
|
||||
}
|
||||
|
||||
detail::VariantData* getData() const {
|
||||
return collectionToVariant(data_);
|
||||
}
|
||||
|
||||
detail::VariantData* getOrCreateData() const {
|
||||
return collectionToVariant(data_);
|
||||
}
|
||||
|
||||
detail::ArrayData* data_;
|
||||
detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,119 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Array/JsonArrayIterator.hpp>
|
||||
#include <ArduinoJson/Variant/VariantAttorney.hpp>
|
||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
class JsonObject;
|
||||
|
||||
// A read-only reference to an array in a JsonDocument
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/
|
||||
class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
|
||||
friend class JsonArray;
|
||||
friend class detail::VariantAttorney;
|
||||
|
||||
public:
|
||||
typedef JsonArrayConstIterator iterator;
|
||||
|
||||
// Returns an iterator to the first element of the array.
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/begin/
|
||||
iterator begin() const {
|
||||
if (!data_)
|
||||
return iterator();
|
||||
return iterator(data_->createIterator(resources_), resources_);
|
||||
}
|
||||
|
||||
// Returns an iterator to the element following the last element of the array.
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/end/
|
||||
iterator end() const {
|
||||
return iterator();
|
||||
}
|
||||
|
||||
// Creates an unbound reference.
|
||||
JsonArrayConst() : data_(0) {}
|
||||
|
||||
// INTERNAL USE ONLY
|
||||
JsonArrayConst(const detail::ArrayData* data,
|
||||
const detail::ResourceManager* resources)
|
||||
: data_(data), resources_(resources) {}
|
||||
|
||||
// Returns the element at the specified index.
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/subscript/
|
||||
JsonVariantConst operator[](size_t index) const {
|
||||
return JsonVariantConst(
|
||||
detail::ArrayData::getElement(data_, index, resources_), resources_);
|
||||
}
|
||||
|
||||
operator JsonVariantConst() const {
|
||||
return JsonVariantConst(getData(), resources_);
|
||||
}
|
||||
|
||||
// Returns true if the reference is unbound.
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/isnull/
|
||||
bool isNull() const {
|
||||
return data_ == 0;
|
||||
}
|
||||
|
||||
// Returns true if the reference is bound.
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/isnull/
|
||||
operator bool() const {
|
||||
return data_ != 0;
|
||||
}
|
||||
|
||||
// Returns the depth (nesting level) of the array.
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/nesting/
|
||||
size_t nesting() const {
|
||||
return detail::VariantData::nesting(getData(), resources_);
|
||||
}
|
||||
|
||||
// Returns the number of elements in the array.
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/size/
|
||||
size_t size() const {
|
||||
return data_ ? data_->size(resources_) : 0;
|
||||
}
|
||||
|
||||
// DEPRECATED: always returns zero
|
||||
ARDUINOJSON_DEPRECATED("always returns zero")
|
||||
size_t memoryUsage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
const detail::VariantData* getData() const {
|
||||
return collectionToVariant(data_);
|
||||
}
|
||||
|
||||
const detail::ArrayData* data_;
|
||||
const detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
// Compares the content of two arrays.
|
||||
// Returns true if the two arrays are equal.
|
||||
inline bool operator==(JsonArrayConst lhs, JsonArrayConst rhs) {
|
||||
if (!lhs && !rhs)
|
||||
return true;
|
||||
if (!lhs || !rhs)
|
||||
return false;
|
||||
|
||||
auto a = lhs.begin();
|
||||
auto b = rhs.begin();
|
||||
|
||||
for (;;) {
|
||||
if (a == b) // same pointer or both null
|
||||
return true;
|
||||
if (a == lhs.end() || b == rhs.end())
|
||||
return false;
|
||||
if (*a != *b)
|
||||
return false;
|
||||
++a;
|
||||
++b;
|
||||
}
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,96 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Variant/JsonVariant.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
template <typename T>
|
||||
class Ptr {
|
||||
public:
|
||||
Ptr(T value) : value_(value) {}
|
||||
|
||||
T* operator->() {
|
||||
return &value_;
|
||||
}
|
||||
|
||||
T& operator*() {
|
||||
return value_;
|
||||
}
|
||||
|
||||
private:
|
||||
T value_;
|
||||
};
|
||||
|
||||
class JsonArrayIterator {
|
||||
friend class JsonArray;
|
||||
|
||||
public:
|
||||
JsonArrayIterator() {}
|
||||
explicit JsonArrayIterator(detail::ArrayData::iterator iterator,
|
||||
detail::ResourceManager* resources)
|
||||
: iterator_(iterator), resources_(resources) {}
|
||||
|
||||
JsonVariant operator*() {
|
||||
return JsonVariant(iterator_.data(), resources_);
|
||||
}
|
||||
Ptr<JsonVariant> operator->() {
|
||||
return operator*();
|
||||
}
|
||||
|
||||
bool operator==(const JsonArrayIterator& other) const {
|
||||
return iterator_ == other.iterator_;
|
||||
}
|
||||
|
||||
bool operator!=(const JsonArrayIterator& other) const {
|
||||
return iterator_ != other.iterator_;
|
||||
}
|
||||
|
||||
JsonArrayIterator& operator++() {
|
||||
iterator_.next(resources_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
detail::ArrayData::iterator iterator_;
|
||||
detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
class JsonArrayConstIterator {
|
||||
friend class JsonArray;
|
||||
|
||||
public:
|
||||
JsonArrayConstIterator() {}
|
||||
explicit JsonArrayConstIterator(detail::ArrayData::iterator iterator,
|
||||
const detail::ResourceManager* resources)
|
||||
: iterator_(iterator), resources_(resources) {}
|
||||
|
||||
JsonVariantConst operator*() const {
|
||||
return JsonVariantConst(iterator_.data(), resources_);
|
||||
}
|
||||
Ptr<JsonVariantConst> operator->() {
|
||||
return operator*();
|
||||
}
|
||||
|
||||
bool operator==(const JsonArrayConstIterator& other) const {
|
||||
return iterator_ == other.iterator_;
|
||||
}
|
||||
|
||||
bool operator!=(const JsonArrayConstIterator& other) const {
|
||||
return iterator_ != other.iterator_;
|
||||
}
|
||||
|
||||
JsonArrayConstIterator& operator++() {
|
||||
iterator_.next(resources_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
detail::ArrayData::iterator iterator_;
|
||||
const detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,114 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Array/JsonArray.hpp>
|
||||
#include <ArduinoJson/Document/JsonDocument.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Copies a value to a JsonVariant.
|
||||
// This is a degenerated form of copyArray() to stop the recursion.
|
||||
template <typename T>
|
||||
inline typename detail::enable_if<!detail::is_array<T>::value, bool>::type
|
||||
copyArray(const T& src, JsonVariant dst) {
|
||||
return dst.set(src);
|
||||
}
|
||||
|
||||
// Copies values from an array to a JsonArray or a JsonVariant.
|
||||
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||
template <typename T, size_t N, typename TDestination>
|
||||
inline typename detail::enable_if<
|
||||
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
|
||||
copyArray(T (&src)[N], const TDestination& dst) {
|
||||
return copyArray(src, N, dst);
|
||||
}
|
||||
|
||||
// Copies values from an array to a JsonArray or a JsonVariant.
|
||||
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||
template <typename T, typename TDestination>
|
||||
inline typename detail::enable_if<
|
||||
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
|
||||
copyArray(const T* src, size_t len, const TDestination& dst) {
|
||||
bool ok = true;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
ok &= copyArray(src[i], dst.template add<JsonVariant>());
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Copies a string to a JsonVariant.
|
||||
// This is a degenerated form of copyArray() to handle strings.
|
||||
template <typename TDestination>
|
||||
inline bool copyArray(const char* src, size_t, const TDestination& dst) {
|
||||
return dst.set(src);
|
||||
}
|
||||
|
||||
// Copies values from an array to a JsonDocument.
|
||||
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||
template <typename T>
|
||||
inline bool copyArray(const T& src, JsonDocument& dst) {
|
||||
return copyArray(src, dst.to<JsonArray>());
|
||||
}
|
||||
|
||||
// Copies an array to a JsonDocument.
|
||||
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||
template <typename T>
|
||||
inline bool copyArray(const T* src, size_t len, JsonDocument& dst) {
|
||||
return copyArray(src, len, dst.to<JsonArray>());
|
||||
}
|
||||
|
||||
// Copies a value from a JsonVariant.
|
||||
// This is a degenerated form of copyArray() to stop the recursion.
|
||||
template <typename T>
|
||||
inline typename detail::enable_if<!detail::is_array<T>::value, size_t>::type
|
||||
copyArray(JsonVariantConst src, T& dst) {
|
||||
dst = src.as<T>();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Copies values from a JsonArray or JsonVariant to an array.
|
||||
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||
template <typename T, size_t N>
|
||||
inline size_t copyArray(JsonArrayConst src, T (&dst)[N]) {
|
||||
return copyArray(src, dst, N);
|
||||
}
|
||||
|
||||
// Copies values from a JsonArray or JsonVariant to an array.
|
||||
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||
template <typename T>
|
||||
inline size_t copyArray(JsonArrayConst src, T* dst, size_t len) {
|
||||
size_t i = 0;
|
||||
for (JsonArrayConst::iterator it = src.begin(); it != src.end() && i < len;
|
||||
++it)
|
||||
copyArray(*it, dst[i++]);
|
||||
return i;
|
||||
}
|
||||
|
||||
// Copies a string from a JsonVariant.
|
||||
// This is a degenerated form of copyArray() to handle strings.
|
||||
template <size_t N>
|
||||
inline size_t copyArray(JsonVariantConst src, char (&dst)[N]) {
|
||||
JsonString s = src;
|
||||
size_t len = N - 1;
|
||||
if (len > s.size())
|
||||
len = s.size();
|
||||
memcpy(dst, s.c_str(), len);
|
||||
dst[len] = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Copies values from a JsonDocument to an array.
|
||||
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||
template <typename TSource, typename T>
|
||||
inline typename detail::enable_if<
|
||||
detail::is_array<T>::value &&
|
||||
detail::is_base_of<JsonDocument, TSource>::value,
|
||||
size_t>::type
|
||||
copyArray(const TSource& src, T& dst) {
|
||||
return copyArray(src.template as<JsonArrayConst>(), dst);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,133 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class VariantData;
|
||||
class VariantSlot;
|
||||
|
||||
class CollectionIterator {
|
||||
friend class CollectionData;
|
||||
|
||||
public:
|
||||
CollectionIterator() : slot_(nullptr), currentId_(NULL_SLOT) {}
|
||||
|
||||
void next(const ResourceManager* resources);
|
||||
|
||||
bool done() const {
|
||||
return slot_ == nullptr;
|
||||
}
|
||||
|
||||
bool operator==(const CollectionIterator& other) const {
|
||||
return slot_ == other.slot_;
|
||||
}
|
||||
|
||||
bool operator!=(const CollectionIterator& other) const {
|
||||
return slot_ != other.slot_;
|
||||
}
|
||||
|
||||
VariantData* operator->() {
|
||||
ARDUINOJSON_ASSERT(slot_ != nullptr);
|
||||
return data();
|
||||
}
|
||||
|
||||
VariantData& operator*() {
|
||||
ARDUINOJSON_ASSERT(slot_ != nullptr);
|
||||
return *data();
|
||||
}
|
||||
|
||||
const VariantData& operator*() const {
|
||||
ARDUINOJSON_ASSERT(slot_ != nullptr);
|
||||
return *data();
|
||||
}
|
||||
|
||||
const char* key() const;
|
||||
bool ownsKey() const;
|
||||
|
||||
void setKey(StringNode*);
|
||||
void setKey(const char*);
|
||||
|
||||
VariantData* data() {
|
||||
return reinterpret_cast<VariantData*>(slot_);
|
||||
}
|
||||
|
||||
const VariantData* data() const {
|
||||
return reinterpret_cast<const VariantData*>(slot_);
|
||||
}
|
||||
|
||||
private:
|
||||
CollectionIterator(VariantSlot* slot, SlotId slotId);
|
||||
|
||||
VariantSlot* slot_;
|
||||
SlotId currentId_, nextId_;
|
||||
};
|
||||
|
||||
class CollectionData {
|
||||
SlotId head_ = NULL_SLOT;
|
||||
SlotId tail_ = NULL_SLOT;
|
||||
|
||||
public:
|
||||
// Placement new
|
||||
static void* operator new(size_t, void* p) noexcept {
|
||||
return p;
|
||||
}
|
||||
|
||||
static void operator delete(void*, void*) noexcept {}
|
||||
|
||||
using iterator = CollectionIterator;
|
||||
|
||||
iterator createIterator(const ResourceManager* resources) const {
|
||||
return iterator(resources->getSlot(head_), head_);
|
||||
}
|
||||
|
||||
size_t size(const ResourceManager*) const;
|
||||
size_t nesting(const ResourceManager*) const;
|
||||
|
||||
void clear(ResourceManager* resources);
|
||||
|
||||
static void clear(CollectionData* collection, ResourceManager* resources) {
|
||||
if (!collection)
|
||||
return;
|
||||
collection->clear(resources);
|
||||
}
|
||||
|
||||
void remove(iterator it, ResourceManager* resources);
|
||||
|
||||
static void remove(CollectionData* collection, iterator it,
|
||||
ResourceManager* resources) {
|
||||
if (collection)
|
||||
return collection->remove(it, resources);
|
||||
}
|
||||
|
||||
SlotId head() const {
|
||||
return head_;
|
||||
}
|
||||
|
||||
protected:
|
||||
iterator addSlot(ResourceManager*);
|
||||
|
||||
private:
|
||||
SlotWithId getPreviousSlot(VariantSlot*, const ResourceManager*) const;
|
||||
void releaseSlot(SlotWithId, ResourceManager*);
|
||||
};
|
||||
|
||||
inline const VariantData* collectionToVariant(
|
||||
const CollectionData* collection) {
|
||||
const void* data = collection; // prevent warning cast-align
|
||||
return reinterpret_cast<const VariantData*>(data);
|
||||
}
|
||||
|
||||
inline VariantData* collectionToVariant(CollectionData* collection) {
|
||||
void* data = collection; // prevent warning cast-align
|
||||
return reinterpret_cast<VariantData*>(data);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,133 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Collection/CollectionData.hpp>
|
||||
#include <ArduinoJson/Memory/Alignment.hpp>
|
||||
#include <ArduinoJson/Strings/StringAdapters.hpp>
|
||||
#include <ArduinoJson/Variant/VariantCompare.hpp>
|
||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
inline CollectionIterator::CollectionIterator(VariantSlot* slot, SlotId slotId)
|
||||
: slot_(slot), currentId_(slotId) {
|
||||
nextId_ = slot_ ? slot_->next() : NULL_SLOT;
|
||||
}
|
||||
|
||||
inline const char* CollectionIterator::key() const {
|
||||
ARDUINOJSON_ASSERT(slot_ != nullptr);
|
||||
return slot_->key();
|
||||
}
|
||||
|
||||
inline void CollectionIterator::setKey(const char* s) {
|
||||
ARDUINOJSON_ASSERT(slot_ != nullptr);
|
||||
ARDUINOJSON_ASSERT(s != nullptr);
|
||||
return slot_->setKey(s);
|
||||
}
|
||||
|
||||
inline void CollectionIterator::setKey(StringNode* s) {
|
||||
ARDUINOJSON_ASSERT(slot_ != nullptr);
|
||||
ARDUINOJSON_ASSERT(s != nullptr);
|
||||
return slot_->setKey(s);
|
||||
}
|
||||
|
||||
inline bool CollectionIterator::ownsKey() const {
|
||||
ARDUINOJSON_ASSERT(slot_ != nullptr);
|
||||
return slot_->ownsKey();
|
||||
}
|
||||
|
||||
inline void CollectionIterator::next(const ResourceManager* resources) {
|
||||
ARDUINOJSON_ASSERT(currentId_ != NULL_SLOT);
|
||||
slot_ = resources->getSlot(nextId_);
|
||||
currentId_ = nextId_;
|
||||
if (slot_)
|
||||
nextId_ = slot_->next();
|
||||
}
|
||||
|
||||
inline CollectionData::iterator CollectionData::addSlot(
|
||||
ResourceManager* resources) {
|
||||
auto slot = resources->allocSlot();
|
||||
if (!slot)
|
||||
return {};
|
||||
if (tail_ != NULL_SLOT) {
|
||||
auto tail = resources->getSlot(tail_);
|
||||
tail->setNext(slot.id());
|
||||
tail_ = slot.id();
|
||||
} else {
|
||||
head_ = slot.id();
|
||||
tail_ = slot.id();
|
||||
}
|
||||
return iterator(slot, slot.id());
|
||||
}
|
||||
|
||||
inline void CollectionData::clear(ResourceManager* resources) {
|
||||
auto next = head_;
|
||||
while (next != NULL_SLOT) {
|
||||
auto currId = next;
|
||||
auto slot = resources->getSlot(next);
|
||||
next = slot->next();
|
||||
releaseSlot(SlotWithId(slot, currId), resources);
|
||||
}
|
||||
|
||||
head_ = NULL_SLOT;
|
||||
tail_ = NULL_SLOT;
|
||||
}
|
||||
|
||||
inline SlotWithId CollectionData::getPreviousSlot(
|
||||
VariantSlot* target, const ResourceManager* resources) const {
|
||||
auto prev = SlotWithId();
|
||||
auto currentId = head_;
|
||||
while (currentId != NULL_SLOT) {
|
||||
auto currentSlot = resources->getSlot(currentId);
|
||||
if (currentSlot == target)
|
||||
return prev;
|
||||
prev = SlotWithId(currentSlot, currentId);
|
||||
currentId = currentSlot->next();
|
||||
}
|
||||
return SlotWithId();
|
||||
}
|
||||
|
||||
inline void CollectionData::remove(iterator it, ResourceManager* resources) {
|
||||
if (it.done())
|
||||
return;
|
||||
auto curr = it.slot_;
|
||||
auto prev = getPreviousSlot(curr, resources);
|
||||
auto next = curr->next();
|
||||
if (prev)
|
||||
prev->setNext(next);
|
||||
else
|
||||
head_ = next;
|
||||
if (next == NULL_SLOT)
|
||||
tail_ = prev.id();
|
||||
releaseSlot({it.slot_, it.currentId_}, resources);
|
||||
}
|
||||
|
||||
inline size_t CollectionData::nesting(const ResourceManager* resources) const {
|
||||
size_t maxChildNesting = 0;
|
||||
for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
|
||||
size_t childNesting = it->nesting(resources);
|
||||
if (childNesting > maxChildNesting)
|
||||
maxChildNesting = childNesting;
|
||||
}
|
||||
return maxChildNesting + 1;
|
||||
}
|
||||
|
||||
inline size_t CollectionData::size(const ResourceManager* resources) const {
|
||||
size_t count = 0;
|
||||
for (auto it = createIterator(resources); !it.done(); it.next(resources))
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
inline void CollectionData::releaseSlot(SlotWithId slot,
|
||||
ResourceManager* resources) {
|
||||
if (slot->ownsKey())
|
||||
resources->dereferenceString(slot->key());
|
||||
slot->data()->setNull(resources);
|
||||
resources->freeSlot(slot);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,253 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
// Support std::istream and std::ostream
|
||||
#ifndef ARDUINOJSON_ENABLE_STD_STREAM
|
||||
# ifdef __has_include
|
||||
# if __has_include(<istream>) && \
|
||||
__has_include(<ostream>) && \
|
||||
!defined(min) && \
|
||||
!defined(max)
|
||||
# define ARDUINOJSON_ENABLE_STD_STREAM 1
|
||||
# else
|
||||
# define ARDUINOJSON_ENABLE_STD_STREAM 0
|
||||
# endif
|
||||
# else
|
||||
# ifdef ARDUINO
|
||||
# define ARDUINOJSON_ENABLE_STD_STREAM 0
|
||||
# else
|
||||
# define ARDUINOJSON_ENABLE_STD_STREAM 1
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Support std::string
|
||||
#ifndef ARDUINOJSON_ENABLE_STD_STRING
|
||||
# ifdef __has_include
|
||||
# if __has_include(<string>) && !defined(min) && !defined(max)
|
||||
# define ARDUINOJSON_ENABLE_STD_STRING 1
|
||||
# else
|
||||
# define ARDUINOJSON_ENABLE_STD_STRING 0
|
||||
# endif
|
||||
# else
|
||||
# ifdef ARDUINO
|
||||
# define ARDUINOJSON_ENABLE_STD_STRING 0
|
||||
# else
|
||||
# define ARDUINOJSON_ENABLE_STD_STRING 1
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Support for std::string_view
|
||||
#ifndef ARDUINOJSON_ENABLE_STRING_VIEW
|
||||
# ifdef __has_include
|
||||
# if __has_include(<string_view>) && __cplusplus >= 201703L
|
||||
# define ARDUINOJSON_ENABLE_STRING_VIEW 1
|
||||
# else
|
||||
# define ARDUINOJSON_ENABLE_STRING_VIEW 0
|
||||
# endif
|
||||
# else
|
||||
# define ARDUINOJSON_ENABLE_STRING_VIEW 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Store floating-point values with float (0) or double (1)
|
||||
#ifndef ARDUINOJSON_USE_DOUBLE
|
||||
# define ARDUINOJSON_USE_DOUBLE 1
|
||||
#endif
|
||||
|
||||
// Pointer size: a heuristic to set sensible defaults
|
||||
#ifndef ARDUINOJSON_SIZEOF_POINTER
|
||||
# if defined(__SIZEOF_POINTER__)
|
||||
# define ARDUINOJSON_SIZEOF_POINTER __SIZEOF_POINTER__
|
||||
# elif defined(_WIN64) && _WIN64
|
||||
# define ARDUINOJSON_SIZEOF_POINTER 8 // 64 bits
|
||||
# else
|
||||
# define ARDUINOJSON_SIZEOF_POINTER 4 // assume 32 bits otherwise
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Store integral values with long (0) or long long (1)
|
||||
#ifndef ARDUINOJSON_USE_LONG_LONG
|
||||
# if ARDUINOJSON_SIZEOF_POINTER >= 4 // 32 & 64 bits systems
|
||||
# define ARDUINOJSON_USE_LONG_LONG 1
|
||||
# else
|
||||
# define ARDUINOJSON_USE_LONG_LONG 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Limit nesting as the stack is likely to be small
|
||||
#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
|
||||
# define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
|
||||
#endif
|
||||
|
||||
// Number of bytes to store the variant identifier
|
||||
#ifndef ARDUINOJSON_SLOT_ID_SIZE
|
||||
# if ARDUINOJSON_SIZEOF_POINTER <= 2
|
||||
# define ARDUINOJSON_SLOT_ID_SIZE 1 // up to 255 slots
|
||||
# elif ARDUINOJSON_SIZEOF_POINTER == 4
|
||||
# define ARDUINOJSON_SLOT_ID_SIZE 2 // up to 65535 slots
|
||||
# else
|
||||
# define ARDUINOJSON_SLOT_ID_SIZE 4 // up to 4294967295 slots
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Capacity of each variant pool (in slots)
|
||||
#ifndef ARDUINOJSON_POOL_CAPACITY
|
||||
# if ARDUINOJSON_SIZEOF_POINTER <= 2
|
||||
# define ARDUINOJSON_POOL_CAPACITY 16 // 128 bytes
|
||||
# elif ARDUINOJSON_SIZEOF_POINTER == 4
|
||||
# define ARDUINOJSON_POOL_CAPACITY 64 // 1024 bytes
|
||||
# else
|
||||
# define ARDUINOJSON_POOL_CAPACITY 128 // 3072 bytes
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Initial capacity of the pool list
|
||||
#ifndef ARDUINOJSON_INITIAL_POOL_COUNT
|
||||
# define ARDUINOJSON_INITIAL_POOL_COUNT 4
|
||||
#endif
|
||||
|
||||
// Automatically call shrinkToFit() from deserializeXxx()
|
||||
// Disabled by default on 8-bit platforms because it's not worth the increase in
|
||||
// code size
|
||||
#ifndef ARDUINOJSON_AUTO_SHRINK
|
||||
# if ARDUINOJSON_SIZEOF_POINTER <= 2
|
||||
# define ARDUINOJSON_AUTO_SHRINK 0
|
||||
# else
|
||||
# define ARDUINOJSON_AUTO_SHRINK 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Number of bytes to store the length of a string
|
||||
#ifndef ARDUINOJSON_STRING_LENGTH_SIZE
|
||||
# if ARDUINOJSON_SIZEOF_POINTER <= 2
|
||||
# define ARDUINOJSON_STRING_LENGTH_SIZE 1 // up to 255 characters
|
||||
# else
|
||||
# define ARDUINOJSON_STRING_LENGTH_SIZE 2 // up to 65535 characters
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO
|
||||
|
||||
// Enable support for Arduino's String class
|
||||
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||
# define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
|
||||
# endif
|
||||
|
||||
// Enable support for Arduino's Stream class
|
||||
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
||||
# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
|
||||
# endif
|
||||
|
||||
// Enable support for Arduino's Print class
|
||||
# ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT
|
||||
# define ARDUINOJSON_ENABLE_ARDUINO_PRINT 1
|
||||
# endif
|
||||
|
||||
// Enable support for PROGMEM
|
||||
# ifndef ARDUINOJSON_ENABLE_PROGMEM
|
||||
# define ARDUINOJSON_ENABLE_PROGMEM 1
|
||||
# endif
|
||||
|
||||
#else // ARDUINO
|
||||
|
||||
// Disable support for Arduino's String class
|
||||
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||
# define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
|
||||
# endif
|
||||
|
||||
// Disable support for Arduino's Stream class
|
||||
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
||||
# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0
|
||||
# endif
|
||||
|
||||
// Disable support for Arduino's Print class
|
||||
# ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT
|
||||
# define ARDUINOJSON_ENABLE_ARDUINO_PRINT 0
|
||||
# endif
|
||||
|
||||
// Enable PROGMEM support on AVR only
|
||||
# ifndef ARDUINOJSON_ENABLE_PROGMEM
|
||||
# ifdef __AVR__
|
||||
# define ARDUINOJSON_ENABLE_PROGMEM 1
|
||||
# else
|
||||
# define ARDUINOJSON_ENABLE_PROGMEM 0
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#endif // ARDUINO
|
||||
|
||||
// Convert unicode escape sequence (\u0123) to UTF-8
|
||||
#ifndef ARDUINOJSON_DECODE_UNICODE
|
||||
# define ARDUINOJSON_DECODE_UNICODE 1
|
||||
#endif
|
||||
|
||||
// Ignore comments in input
|
||||
#ifndef ARDUINOJSON_ENABLE_COMMENTS
|
||||
# define ARDUINOJSON_ENABLE_COMMENTS 0
|
||||
#endif
|
||||
|
||||
// Support NaN in JSON
|
||||
#ifndef ARDUINOJSON_ENABLE_NAN
|
||||
# define ARDUINOJSON_ENABLE_NAN 0
|
||||
#endif
|
||||
|
||||
// Support Infinity in JSON
|
||||
#ifndef ARDUINOJSON_ENABLE_INFINITY
|
||||
# define ARDUINOJSON_ENABLE_INFINITY 0
|
||||
#endif
|
||||
|
||||
// Control the exponentiation threshold for big numbers
|
||||
// CAUTION: cannot be more that 1e9 !!!!
|
||||
#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD
|
||||
# define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7
|
||||
#endif
|
||||
|
||||
// Control the exponentiation threshold for small numbers
|
||||
#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD
|
||||
# define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5
|
||||
#endif
|
||||
|
||||
#ifndef ARDUINOJSON_LITTLE_ENDIAN
|
||||
# if defined(_MSC_VER) || \
|
||||
(defined(__BYTE_ORDER__) && \
|
||||
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
|
||||
defined(__LITTLE_ENDIAN__) || defined(__i386) || defined(__x86_64)
|
||||
# define ARDUINOJSON_LITTLE_ENDIAN 1
|
||||
# else
|
||||
# define ARDUINOJSON_LITTLE_ENDIAN 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef ARDUINOJSON_ENABLE_ALIGNMENT
|
||||
# if defined(__AVR)
|
||||
# define ARDUINOJSON_ENABLE_ALIGNMENT 0
|
||||
# else
|
||||
# define ARDUINOJSON_ENABLE_ALIGNMENT 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef ARDUINOJSON_TAB
|
||||
# define ARDUINOJSON_TAB " "
|
||||
#endif
|
||||
|
||||
#ifndef ARDUINOJSON_STRING_BUFFER_SIZE
|
||||
# define ARDUINOJSON_STRING_BUFFER_SIZE 32
|
||||
#endif
|
||||
|
||||
#ifndef ARDUINOJSON_DEBUG
|
||||
# ifdef __PLATFORMIO_BUILD_DEBUG__
|
||||
# define ARDUINOJSON_DEBUG 1
|
||||
# else
|
||||
# define ARDUINOJSON_DEBUG 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(nullptr)
|
||||
# error nullptr is defined as a macro. Remove the faulty #define or #undef nullptr
|
||||
// See https://github.com/bblanchon/ArduinoJson/issues/1355
|
||||
#endif
|
||||
@@ -1,106 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
#include <ArduinoJson/Polyfills/pgmspace_generic.hpp>
|
||||
#include <ArduinoJson/Polyfills/preprocessor.hpp>
|
||||
|
||||
#if ARDUINOJSON_ENABLE_STD_STREAM
|
||||
# include <ostream>
|
||||
#endif
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
class DeserializationError {
|
||||
public:
|
||||
enum Code {
|
||||
Ok,
|
||||
EmptyInput,
|
||||
IncompleteInput,
|
||||
InvalidInput,
|
||||
NoMemory,
|
||||
TooDeep
|
||||
};
|
||||
|
||||
DeserializationError() {}
|
||||
DeserializationError(Code c) : code_(c) {}
|
||||
|
||||
// Compare with DeserializationError
|
||||
friend bool operator==(const DeserializationError& lhs,
|
||||
const DeserializationError& rhs) {
|
||||
return lhs.code_ == rhs.code_;
|
||||
}
|
||||
friend bool operator!=(const DeserializationError& lhs,
|
||||
const DeserializationError& rhs) {
|
||||
return lhs.code_ != rhs.code_;
|
||||
}
|
||||
|
||||
// Compare with Code
|
||||
friend bool operator==(const DeserializationError& lhs, Code rhs) {
|
||||
return lhs.code_ == rhs;
|
||||
}
|
||||
friend bool operator==(Code lhs, const DeserializationError& rhs) {
|
||||
return lhs == rhs.code_;
|
||||
}
|
||||
friend bool operator!=(const DeserializationError& lhs, Code rhs) {
|
||||
return lhs.code_ != rhs;
|
||||
}
|
||||
friend bool operator!=(Code lhs, const DeserializationError& rhs) {
|
||||
return lhs != rhs.code_;
|
||||
}
|
||||
|
||||
// Returns true if there is an error
|
||||
explicit operator bool() const {
|
||||
return code_ != Ok;
|
||||
}
|
||||
|
||||
// Returns internal enum, useful for switch statement
|
||||
Code code() const {
|
||||
return code_;
|
||||
}
|
||||
|
||||
const char* c_str() const {
|
||||
static const char* messages[] = {
|
||||
"Ok", "EmptyInput", "IncompleteInput",
|
||||
"InvalidInput", "NoMemory", "TooDeep"};
|
||||
ARDUINOJSON_ASSERT(static_cast<size_t>(code_) <
|
||||
sizeof(messages) / sizeof(messages[0]));
|
||||
return messages[code_];
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_ENABLE_PROGMEM
|
||||
const __FlashStringHelper* f_str() const {
|
||||
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s0, "Ok");
|
||||
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s1, "EmptyInput");
|
||||
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s2, "IncompleteInput");
|
||||
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s3, "InvalidInput");
|
||||
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s4, "NoMemory");
|
||||
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s5, "TooDeep");
|
||||
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(const char*, messages,
|
||||
{s0, s1, s2, s3, s4, s5});
|
||||
return reinterpret_cast<const __FlashStringHelper*>(
|
||||
detail::pgm_read(messages + code_));
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
Code code_;
|
||||
};
|
||||
|
||||
#if ARDUINOJSON_ENABLE_STD_STREAM
|
||||
inline std::ostream& operator<<(std::ostream& s,
|
||||
const DeserializationError& e) {
|
||||
s << e.c_str();
|
||||
return s;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& s, DeserializationError::Code c) {
|
||||
s << DeserializationError(c).c_str();
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,35 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Deserialization/Filter.hpp>
|
||||
#include <ArduinoJson/Deserialization/NestingLimit.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TFilter>
|
||||
struct DeserializationOptions {
|
||||
TFilter filter;
|
||||
DeserializationOption::NestingLimit nestingLimit;
|
||||
};
|
||||
|
||||
template <typename TFilter>
|
||||
inline DeserializationOptions<TFilter> makeDeserializationOptions(
|
||||
TFilter filter, DeserializationOption::NestingLimit nestingLimit = {}) {
|
||||
return {filter, nestingLimit};
|
||||
}
|
||||
|
||||
template <typename TFilter>
|
||||
inline DeserializationOptions<TFilter> makeDeserializationOptions(
|
||||
DeserializationOption::NestingLimit nestingLimit, TFilter filter) {
|
||||
return {filter, nestingLimit};
|
||||
}
|
||||
|
||||
inline DeserializationOptions<AllowAllFilter> makeDeserializationOptions(
|
||||
DeserializationOption::NestingLimit nestingLimit = {}) {
|
||||
return {{}, nestingLimit};
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,77 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Variant/JsonVariant.hpp>
|
||||
#include <ArduinoJson/Variant/VariantAttorney.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
namespace DeserializationOption {
|
||||
class Filter {
|
||||
public:
|
||||
#if ARDUINOJSON_AUTO_SHRINK
|
||||
explicit Filter(JsonDocument& doc) : variant_(doc) {
|
||||
doc.shrinkToFit();
|
||||
}
|
||||
#endif
|
||||
|
||||
explicit Filter(JsonVariantConst variant) : variant_(variant) {}
|
||||
|
||||
bool allow() const {
|
||||
return variant_;
|
||||
}
|
||||
|
||||
bool allowArray() const {
|
||||
return variant_ == true || variant_.is<JsonArrayConst>();
|
||||
}
|
||||
|
||||
bool allowObject() const {
|
||||
return variant_ == true || variant_.is<JsonObjectConst>();
|
||||
}
|
||||
|
||||
bool allowValue() const {
|
||||
return variant_ == true;
|
||||
}
|
||||
|
||||
template <typename TKey>
|
||||
Filter operator[](const TKey& key) const {
|
||||
if (variant_ == true) // "true" means "allow recursively"
|
||||
return *this;
|
||||
JsonVariantConst member = variant_[key];
|
||||
return Filter(member.isNull() ? variant_["*"] : member);
|
||||
}
|
||||
|
||||
private:
|
||||
JsonVariantConst variant_;
|
||||
};
|
||||
} // namespace DeserializationOption
|
||||
|
||||
namespace detail {
|
||||
struct AllowAllFilter {
|
||||
bool allow() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool allowArray() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool allowObject() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool allowValue() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TKey>
|
||||
AllowAllFilter operator[](const TKey&) const {
|
||||
return AllowAllFilter();
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,32 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
namespace DeserializationOption {
|
||||
class NestingLimit {
|
||||
public:
|
||||
NestingLimit() : value_(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {}
|
||||
explicit NestingLimit(uint8_t n) : value_(n) {}
|
||||
|
||||
NestingLimit decrement() const {
|
||||
ARDUINOJSON_ASSERT(value_ > 0);
|
||||
return NestingLimit(static_cast<uint8_t>(value_ - 1));
|
||||
}
|
||||
|
||||
bool reached() const {
|
||||
return value_ == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t value_;
|
||||
};
|
||||
} // namespace DeserializationOption
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,75 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||
|
||||
#include <stdlib.h> // for size_t
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
// The default reader is a simple wrapper for Readers that are not copiable
|
||||
template <typename TSource, typename Enable = void>
|
||||
struct Reader {
|
||||
public:
|
||||
Reader(TSource& source) : source_(&source) {}
|
||||
|
||||
int read() {
|
||||
// clang-format off
|
||||
return source_->read(); // Error here? See https://arduinojson.org/v7/invalid-input/
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
size_t readBytes(char* buffer, size_t length) {
|
||||
return source_->readBytes(buffer, length);
|
||||
}
|
||||
|
||||
private:
|
||||
TSource* source_;
|
||||
};
|
||||
|
||||
template <typename TSource, typename Enable = void>
|
||||
struct BoundedReader {
|
||||
// no default implementation because we need to pass the size to the
|
||||
// constructor
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
#include <ArduinoJson/Deserialization/Readers/IteratorReader.hpp>
|
||||
#include <ArduinoJson/Deserialization/Readers/RamReader.hpp>
|
||||
#include <ArduinoJson/Deserialization/Readers/VariantReader.hpp>
|
||||
|
||||
#if ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
||||
# include <ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp>
|
||||
#endif
|
||||
|
||||
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||
# include <ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp>
|
||||
#endif
|
||||
|
||||
#if ARDUINOJSON_ENABLE_PROGMEM
|
||||
# include <ArduinoJson/Deserialization/Readers/FlashReader.hpp>
|
||||
#endif
|
||||
|
||||
#if ARDUINOJSON_ENABLE_STD_STREAM
|
||||
# include <ArduinoJson/Deserialization/Readers/StdStreamReader.hpp>
|
||||
#endif
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TInput>
|
||||
Reader<typename remove_reference<TInput>::type> makeReader(TInput&& input) {
|
||||
return Reader<typename remove_reference<TInput>::type>{
|
||||
detail::forward<TInput>(input)};
|
||||
}
|
||||
|
||||
template <typename TChar>
|
||||
BoundedReader<TChar*> makeReader(TChar* input, size_t inputSize) {
|
||||
return BoundedReader<TChar*>{input, inputSize};
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,31 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TSource>
|
||||
struct Reader<TSource,
|
||||
typename enable_if<is_base_of<Stream, TSource>::value>::type> {
|
||||
public:
|
||||
explicit Reader(Stream& stream) : stream_(&stream) {}
|
||||
|
||||
int read() {
|
||||
// don't use stream_->read() as it ignores the timeout
|
||||
char c;
|
||||
return stream_->readBytes(&c, 1) ? static_cast<unsigned char>(c) : -1;
|
||||
}
|
||||
|
||||
size_t readBytes(char* buffer, size_t length) {
|
||||
return stream_->readBytes(buffer, length);
|
||||
}
|
||||
|
||||
private:
|
||||
Stream* stream_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,19 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TSource>
|
||||
struct Reader<TSource,
|
||||
typename enable_if<is_base_of<::String, TSource>::value>::type>
|
||||
: BoundedReader<const char*> {
|
||||
explicit Reader(const ::String& s)
|
||||
: BoundedReader<const char*>(s.c_str(), s.length()) {}
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,56 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Polyfills/pgmspace.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <>
|
||||
struct Reader<const __FlashStringHelper*, void> {
|
||||
const char* ptr_;
|
||||
|
||||
public:
|
||||
explicit Reader(const __FlashStringHelper* ptr)
|
||||
: ptr_(reinterpret_cast<const char*>(ptr)) {}
|
||||
|
||||
int read() {
|
||||
return pgm_read_byte(ptr_++);
|
||||
}
|
||||
|
||||
size_t readBytes(char* buffer, size_t length) {
|
||||
memcpy_P(buffer, ptr_, length);
|
||||
ptr_ += length;
|
||||
return length;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct BoundedReader<const __FlashStringHelper*, void> {
|
||||
const char* ptr_;
|
||||
const char* end_;
|
||||
|
||||
public:
|
||||
explicit BoundedReader(const __FlashStringHelper* ptr, size_t size)
|
||||
: ptr_(reinterpret_cast<const char*>(ptr)), end_(ptr_ + size) {}
|
||||
|
||||
int read() {
|
||||
if (ptr_ < end_)
|
||||
return pgm_read_byte(ptr_++);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t readBytes(char* buffer, size_t length) {
|
||||
size_t available = static_cast<size_t>(end_ - ptr_);
|
||||
if (available < length)
|
||||
length = available;
|
||||
memcpy_P(buffer, ptr_, length);
|
||||
ptr_ += length;
|
||||
return length;
|
||||
}
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,45 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TIterator>
|
||||
class IteratorReader {
|
||||
TIterator ptr_, end_;
|
||||
|
||||
public:
|
||||
explicit IteratorReader(TIterator begin, TIterator end)
|
||||
: ptr_(begin), end_(end) {}
|
||||
|
||||
int read() {
|
||||
if (ptr_ < end_)
|
||||
return static_cast<unsigned char>(*ptr_++);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t readBytes(char* buffer, size_t length) {
|
||||
size_t i = 0;
|
||||
while (i < length && ptr_ < end_)
|
||||
buffer[i++] = *ptr_++;
|
||||
return i;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct void_ {
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
template <typename TSource>
|
||||
struct Reader<TSource, typename void_<typename TSource::const_iterator>::type>
|
||||
: IteratorReader<typename TSource::const_iterator> {
|
||||
explicit Reader(const TSource& source)
|
||||
: IteratorReader<typename TSource::const_iterator>(source.begin(),
|
||||
source.end()) {}
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,51 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename T>
|
||||
struct IsCharOrVoid {
|
||||
static const bool value =
|
||||
is_same<T, void>::value || is_same<T, char>::value ||
|
||||
is_same<T, unsigned char>::value || is_same<T, signed char>::value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct IsCharOrVoid<const T> : IsCharOrVoid<T> {};
|
||||
|
||||
template <typename TSource>
|
||||
struct Reader<TSource*,
|
||||
typename enable_if<IsCharOrVoid<TSource>::value>::type> {
|
||||
const char* ptr_;
|
||||
|
||||
public:
|
||||
explicit Reader(const void* ptr)
|
||||
: ptr_(ptr ? reinterpret_cast<const char*>(ptr) : "") {}
|
||||
|
||||
int read() {
|
||||
return static_cast<unsigned char>(*ptr_++);
|
||||
}
|
||||
|
||||
size_t readBytes(char* buffer, size_t length) {
|
||||
for (size_t i = 0; i < length; i++)
|
||||
buffer[i] = *ptr_++;
|
||||
return length;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TSource>
|
||||
struct BoundedReader<TSource*,
|
||||
typename enable_if<IsCharOrVoid<TSource>::value>::type>
|
||||
: public IteratorReader<const char*> {
|
||||
public:
|
||||
explicit BoundedReader(const void* ptr, size_t len)
|
||||
: IteratorReader<const char*>(reinterpret_cast<const char*>(ptr),
|
||||
reinterpret_cast<const char*>(ptr) + len) {}
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,30 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <istream>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TSource>
|
||||
struct Reader<TSource, typename enable_if<
|
||||
is_base_of<std::istream, TSource>::value>::type> {
|
||||
public:
|
||||
explicit Reader(std::istream& stream) : stream_(&stream) {}
|
||||
|
||||
int read() {
|
||||
return stream_->get();
|
||||
}
|
||||
|
||||
size_t readBytes(char* buffer, size_t length) {
|
||||
stream_->read(buffer, static_cast<std::streamsize>(length));
|
||||
return static_cast<size_t>(stream_->gcount());
|
||||
}
|
||||
|
||||
private:
|
||||
std::istream* stream_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,19 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Object/MemberProxy.hpp>
|
||||
#include <ArduinoJson/Variant/JsonVariantConst.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TVariant>
|
||||
struct Reader<TVariant, typename enable_if<IsVariant<TVariant>::value>::type>
|
||||
: Reader<char*, void> {
|
||||
explicit Reader(const TVariant& x)
|
||||
: Reader<char*, void>(x.template as<const char*>()) {}
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,83 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Deserialization/DeserializationError.hpp>
|
||||
#include <ArduinoJson/Deserialization/DeserializationOptions.hpp>
|
||||
#include <ArduinoJson/Deserialization/Reader.hpp>
|
||||
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
// A meta-function that returns the first type of the parameter pack
|
||||
// or void if empty
|
||||
template <typename...>
|
||||
struct first_or_void {
|
||||
using type = void;
|
||||
};
|
||||
template <typename T, typename... Rest>
|
||||
struct first_or_void<T, Rest...> {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
// A meta-function that returns true if T is a valid destination type for
|
||||
// deserialize()
|
||||
template <class T, class = void>
|
||||
struct is_deserialize_destination : false_type {};
|
||||
|
||||
template <class T>
|
||||
struct is_deserialize_destination<
|
||||
T, typename enable_if<is_same<decltype(VariantAttorney::getResourceManager(
|
||||
detail::declval<T&>())),
|
||||
ResourceManager*>::value>::type> : true_type {
|
||||
};
|
||||
|
||||
template <typename TDestination>
|
||||
inline void shrinkJsonDocument(TDestination&) {
|
||||
// no-op by default
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_AUTO_SHRINK
|
||||
inline void shrinkJsonDocument(JsonDocument& doc) {
|
||||
doc.shrinkToFit();
|
||||
}
|
||||
#endif
|
||||
|
||||
template <template <typename> class TDeserializer, typename TDestination,
|
||||
typename TReader, typename TOptions>
|
||||
DeserializationError doDeserialize(TDestination&& dst, TReader reader,
|
||||
TOptions options) {
|
||||
auto data = VariantAttorney::getOrCreateData(dst);
|
||||
if (!data)
|
||||
return DeserializationError::NoMemory;
|
||||
auto resources = VariantAttorney::getResourceManager(dst);
|
||||
dst.clear();
|
||||
auto err = TDeserializer<TReader>(resources, reader)
|
||||
.parse(*data, options.filter, options.nestingLimit);
|
||||
shrinkJsonDocument(dst);
|
||||
return err;
|
||||
}
|
||||
|
||||
template <template <typename> class TDeserializer, typename TDestination,
|
||||
typename TStream, typename... Args,
|
||||
typename = typename enable_if< // issue #1897
|
||||
!is_integral<typename first_or_void<Args...>::type>::value>::type>
|
||||
DeserializationError deserialize(TDestination&& dst, TStream&& input,
|
||||
Args... args) {
|
||||
return doDeserialize<TDeserializer>(
|
||||
dst, makeReader(detail::forward<TStream>(input)),
|
||||
makeDeserializationOptions(args...));
|
||||
}
|
||||
|
||||
template <template <typename> class TDeserializer, typename TDestination,
|
||||
typename TChar, typename Size, typename... Args,
|
||||
typename = typename enable_if<is_integral<Size>::value>::type>
|
||||
DeserializationError deserialize(TDestination&& dst, TChar* input,
|
||||
Size inputSize, Args... args) {
|
||||
return doDeserialize<TDeserializer>(dst, makeReader(input, size_t(inputSize)),
|
||||
makeDeserializationOptions(args...));
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,375 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Array/ElementProxy.hpp>
|
||||
#include <ArduinoJson/Memory/Allocator.hpp>
|
||||
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||
#include <ArduinoJson/Object/JsonObject.hpp>
|
||||
#include <ArduinoJson/Object/MemberProxy.hpp>
|
||||
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||
#include <ArduinoJson/Variant/JsonVariantConst.hpp>
|
||||
#include <ArduinoJson/Variant/VariantTo.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// A JSON document.
|
||||
// https://arduinojson.org/v7/api/jsondocument/
|
||||
class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
friend class detail::VariantAttorney;
|
||||
|
||||
public:
|
||||
explicit JsonDocument(Allocator* alloc = detail::DefaultAllocator::instance())
|
||||
: resources_(alloc) {}
|
||||
|
||||
// Copy-constructor
|
||||
JsonDocument(const JsonDocument& src) : JsonDocument(src.allocator()) {
|
||||
set(src);
|
||||
}
|
||||
|
||||
// Move-constructor
|
||||
JsonDocument(JsonDocument&& src)
|
||||
: JsonDocument(detail::DefaultAllocator::instance()) {
|
||||
swap(*this, src);
|
||||
}
|
||||
|
||||
// Construct from variant, array, or object
|
||||
template <typename T>
|
||||
JsonDocument(const T& src,
|
||||
Allocator* alloc = detail::DefaultAllocator::instance(),
|
||||
typename detail::enable_if<
|
||||
detail::is_same<T, JsonVariant>::value ||
|
||||
detail::is_same<T, JsonVariantConst>::value ||
|
||||
detail::is_same<T, JsonArray>::value ||
|
||||
detail::is_same<T, JsonArrayConst>::value ||
|
||||
detail::is_same<T, JsonObject>::value ||
|
||||
detail::is_same<T, JsonObjectConst>::value>::type* = 0)
|
||||
: JsonDocument(alloc) {
|
||||
set(src);
|
||||
}
|
||||
|
||||
JsonDocument& operator=(JsonDocument src) {
|
||||
swap(*this, src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
JsonDocument& operator=(const T& src) {
|
||||
set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Allocator* allocator() const {
|
||||
return resources_.allocator();
|
||||
}
|
||||
|
||||
// Reduces the capacity of the memory pool to match the current usage.
|
||||
// https://arduinojson.org/v7/api/jsondocument/shrinktofit/
|
||||
void shrinkToFit() {
|
||||
resources_.shrinkToFit();
|
||||
}
|
||||
|
||||
// Casts the root to the specified type.
|
||||
// https://arduinojson.org/v7/api/jsondocument/as/
|
||||
template <typename T>
|
||||
T as() {
|
||||
return getVariant().template as<T>();
|
||||
}
|
||||
|
||||
// Casts the root to the specified type.
|
||||
// https://arduinojson.org/v7/api/jsondocument/as/
|
||||
template <typename T>
|
||||
T as() const {
|
||||
return getVariant().template as<T>();
|
||||
}
|
||||
|
||||
// Empties the document and resets the memory pool
|
||||
// https://arduinojson.org/v7/api/jsondocument/clear/
|
||||
void clear() {
|
||||
resources_.clear();
|
||||
data_.reset();
|
||||
}
|
||||
|
||||
// Returns true if the root is of the specified type.
|
||||
// https://arduinojson.org/v7/api/jsondocument/is/
|
||||
template <typename T>
|
||||
bool is() {
|
||||
return getVariant().template is<T>();
|
||||
}
|
||||
|
||||
// Returns true if the root is of the specified type.
|
||||
// https://arduinojson.org/v7/api/jsondocument/is/
|
||||
template <typename T>
|
||||
bool is() const {
|
||||
return getVariant().template is<T>();
|
||||
}
|
||||
|
||||
// Returns true if the root is null.
|
||||
// https://arduinojson.org/v7/api/jsondocument/isnull/
|
||||
bool isNull() const {
|
||||
return getVariant().isNull();
|
||||
}
|
||||
|
||||
// Returns trues if the memory pool was too small.
|
||||
// https://arduinojson.org/v7/api/jsondocument/overflowed/
|
||||
bool overflowed() const {
|
||||
return resources_.overflowed();
|
||||
}
|
||||
|
||||
// Returns the depth (nesting level) of the array.
|
||||
// https://arduinojson.org/v7/api/jsondocument/nesting/
|
||||
size_t nesting() const {
|
||||
return data_.nesting(&resources_);
|
||||
}
|
||||
|
||||
// Returns the number of elements in the root array or object.
|
||||
// https://arduinojson.org/v7/api/jsondocument/size/
|
||||
size_t size() const {
|
||||
return data_.size(&resources_);
|
||||
}
|
||||
|
||||
// Copies the specified document.
|
||||
// https://arduinojson.org/v7/api/jsondocument/set/
|
||||
bool set(const JsonDocument& src) {
|
||||
return to<JsonVariant>().set(src.as<JsonVariantConst>());
|
||||
}
|
||||
|
||||
// Replaces the root with the specified value.
|
||||
// https://arduinojson.org/v7/api/jsondocument/set/
|
||||
template <typename T>
|
||||
typename detail::enable_if<!detail::is_base_of<JsonDocument, T>::value,
|
||||
bool>::type
|
||||
set(const T& src) {
|
||||
return to<JsonVariant>().set(src);
|
||||
}
|
||||
|
||||
// Clears the document and converts it to the specified type.
|
||||
// https://arduinojson.org/v7/api/jsondocument/to/
|
||||
template <typename T>
|
||||
typename detail::VariantTo<T>::type to() {
|
||||
clear();
|
||||
return getVariant().template to<T>();
|
||||
}
|
||||
|
||||
// Returns true if the root object contains the specified key.
|
||||
// https://arduinojson.org/v7/api/jsondocument/containskey/
|
||||
template <typename TChar>
|
||||
bool containsKey(TChar* key) const {
|
||||
return data_.getMember(detail::adaptString(key), &resources_) != 0;
|
||||
}
|
||||
|
||||
// Returns true if the root object contains the specified key.
|
||||
// https://arduinojson.org/v7/api/jsondocument/containskey/
|
||||
template <typename TString>
|
||||
bool containsKey(const TString& key) const {
|
||||
return data_.getMember(detail::adaptString(key), &resources_) != 0;
|
||||
}
|
||||
|
||||
// Gets or sets a root object's member.
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
template <typename TString>
|
||||
typename detail::enable_if<detail::IsString<TString>::value,
|
||||
detail::MemberProxy<JsonDocument&, TString>>::type
|
||||
operator[](const TString& key) {
|
||||
return {*this, key};
|
||||
}
|
||||
|
||||
// Gets or sets a root object's member.
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
template <typename TChar>
|
||||
typename detail::enable_if<detail::IsString<TChar*>::value,
|
||||
detail::MemberProxy<JsonDocument&, TChar*>>::type
|
||||
operator[](TChar* key) {
|
||||
return {*this, key};
|
||||
}
|
||||
|
||||
// Gets a root object's member.
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
template <typename TString>
|
||||
typename detail::enable_if<detail::IsString<TString>::value,
|
||||
JsonVariantConst>::type
|
||||
operator[](const TString& key) const {
|
||||
return JsonVariantConst(
|
||||
data_.getMember(detail::adaptString(key), &resources_), &resources_);
|
||||
}
|
||||
|
||||
// Gets a root object's member.
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
template <typename TChar>
|
||||
typename detail::enable_if<detail::IsString<TChar*>::value,
|
||||
JsonVariantConst>::type
|
||||
operator[](TChar* key) const {
|
||||
return JsonVariantConst(
|
||||
data_.getMember(detail::adaptString(key), &resources_), &resources_);
|
||||
}
|
||||
|
||||
// Gets or sets a root array's element.
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
detail::ElementProxy<JsonDocument&> operator[](size_t index) {
|
||||
return {*this, index};
|
||||
}
|
||||
|
||||
// Gets a root array's member.
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
JsonVariantConst operator[](size_t index) const {
|
||||
return JsonVariantConst(data_.getElement(index, &resources_), &resources_);
|
||||
}
|
||||
|
||||
// Appends a new (empty) element to the root array.
|
||||
// Returns a reference to the new element.
|
||||
// https://arduinojson.org/v7/api/jsondocument/add/
|
||||
template <typename T>
|
||||
typename detail::enable_if<!detail::is_same<T, JsonVariant>::value, T>::type
|
||||
add() {
|
||||
return add<JsonVariant>().to<T>();
|
||||
}
|
||||
|
||||
// Appends a new (null) element to the root array.
|
||||
// Returns a reference to the new element.
|
||||
// https://arduinojson.org/v7/api/jsondocument/add/
|
||||
template <typename T>
|
||||
typename detail::enable_if<detail::is_same<T, JsonVariant>::value, T>::type
|
||||
add() {
|
||||
return JsonVariant(data_.addElement(&resources_), &resources_);
|
||||
}
|
||||
|
||||
// Appends a value to the root array.
|
||||
// https://arduinojson.org/v7/api/jsondocument/add/
|
||||
template <typename TValue>
|
||||
bool add(const TValue& value) {
|
||||
return add<JsonVariant>().set(value);
|
||||
}
|
||||
|
||||
// Appends a value to the root array.
|
||||
// https://arduinojson.org/v7/api/jsondocument/add/
|
||||
template <typename TChar>
|
||||
bool add(TChar* value) {
|
||||
return add<JsonVariant>().set(value);
|
||||
}
|
||||
|
||||
// Removes an element of the root array.
|
||||
// https://arduinojson.org/v7/api/jsondocument/remove/
|
||||
void remove(size_t index) {
|
||||
detail::VariantData::removeElement(getData(), index, getResourceManager());
|
||||
}
|
||||
|
||||
// Removes a member of the root object.
|
||||
// https://arduinojson.org/v7/api/jsondocument/remove/
|
||||
template <typename TChar>
|
||||
typename detail::enable_if<detail::IsString<TChar*>::value>::type remove(
|
||||
TChar* key) {
|
||||
detail::VariantData::removeMember(getData(), detail::adaptString(key),
|
||||
getResourceManager());
|
||||
}
|
||||
|
||||
// Removes a member of the root object.
|
||||
// https://arduinojson.org/v7/api/jsondocument/remove/
|
||||
template <typename TString>
|
||||
|
||||
typename detail::enable_if<detail::IsString<TString>::value>::type remove(
|
||||
const TString& key) {
|
||||
detail::VariantData::removeMember(getData(), detail::adaptString(key),
|
||||
getResourceManager());
|
||||
}
|
||||
|
||||
operator JsonVariant() {
|
||||
return getVariant();
|
||||
}
|
||||
|
||||
operator JsonVariantConst() const {
|
||||
return getVariant();
|
||||
}
|
||||
|
||||
friend void swap(JsonDocument& a, JsonDocument& b) {
|
||||
swap(a.resources_, b.resources_);
|
||||
swap_(a.data_, b.data_);
|
||||
}
|
||||
|
||||
// DEPRECATED: use add<JsonVariant>() instead
|
||||
ARDUINOJSON_DEPRECATED("use add<JsonVariant>() instead")
|
||||
JsonVariant add() {
|
||||
return add<JsonVariant>();
|
||||
}
|
||||
|
||||
// DEPRECATED: use add<JsonArray>() instead
|
||||
ARDUINOJSON_DEPRECATED("use add<JsonArray>() instead")
|
||||
JsonArray createNestedArray() {
|
||||
return add<JsonArray>();
|
||||
}
|
||||
|
||||
// DEPRECATED: use doc[key].to<JsonArray>() instead
|
||||
template <typename TChar>
|
||||
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonArray>() instead")
|
||||
JsonArray createNestedArray(TChar* key) {
|
||||
return operator[](key).template to<JsonArray>();
|
||||
}
|
||||
|
||||
// DEPRECATED: use doc[key].to<JsonArray>() instead
|
||||
template <typename TString>
|
||||
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonArray>() instead")
|
||||
JsonArray createNestedArray(const TString& key) {
|
||||
return operator[](key).template to<JsonArray>();
|
||||
}
|
||||
|
||||
// DEPRECATED: use add<JsonObject>() instead
|
||||
ARDUINOJSON_DEPRECATED("use add<JsonObject>() instead")
|
||||
JsonObject createNestedObject() {
|
||||
return add<JsonObject>();
|
||||
}
|
||||
|
||||
// DEPRECATED: use doc[key].to<JsonObject>() instead
|
||||
template <typename TChar>
|
||||
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonObject>() instead")
|
||||
JsonObject createNestedObject(TChar* key) {
|
||||
return operator[](key).template to<JsonObject>();
|
||||
}
|
||||
|
||||
// DEPRECATED: use doc[key].to<JsonObject>() instead
|
||||
template <typename TString>
|
||||
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonObject>() instead")
|
||||
JsonObject createNestedObject(const TString& key) {
|
||||
return operator[](key).template to<JsonObject>();
|
||||
}
|
||||
|
||||
// DEPRECATED: always returns zero
|
||||
ARDUINOJSON_DEPRECATED("always returns zero")
|
||||
size_t memoryUsage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
JsonVariant getVariant() {
|
||||
return JsonVariant(&data_, &resources_);
|
||||
}
|
||||
|
||||
JsonVariantConst getVariant() const {
|
||||
return JsonVariantConst(&data_, &resources_);
|
||||
}
|
||||
|
||||
detail::ResourceManager* getResourceManager() {
|
||||
return &resources_;
|
||||
}
|
||||
|
||||
detail::VariantData* getData() {
|
||||
return &data_;
|
||||
}
|
||||
|
||||
const detail::VariantData* getData() const {
|
||||
return &data_;
|
||||
}
|
||||
|
||||
detail::VariantData* getOrCreateData() {
|
||||
return &data_;
|
||||
}
|
||||
|
||||
detail::ResourceManager resources_;
|
||||
detail::VariantData data_;
|
||||
};
|
||||
|
||||
inline void convertToJson(const JsonDocument& src, JsonVariant dst) {
|
||||
dst.set(src.as<JsonVariantConst>());
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,40 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class EscapeSequence {
|
||||
public:
|
||||
// Optimized for code size on a 8-bit AVR
|
||||
static char escapeChar(char c) {
|
||||
const char* p = escapeTable(true);
|
||||
while (p[0] && p[1] != c) {
|
||||
p += 2;
|
||||
}
|
||||
return p[0];
|
||||
}
|
||||
|
||||
// Optimized for code size on a 8-bit AVR
|
||||
static char unescapeChar(char c) {
|
||||
const char* p = escapeTable(false);
|
||||
for (;;) {
|
||||
if (p[0] == '\0')
|
||||
return 0;
|
||||
if (p[0] == c)
|
||||
return p[1];
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static const char* escapeTable(bool excludeSolidus) {
|
||||
return &"//\"\"\\\\b\bf\fn\nr\rt\t"[excludeSolidus ? 2 : 0];
|
||||
}
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,695 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Deserialization/deserialize.hpp>
|
||||
#include <ArduinoJson/Json/EscapeSequence.hpp>
|
||||
#include <ArduinoJson/Json/Latch.hpp>
|
||||
#include <ArduinoJson/Json/Utf16.hpp>
|
||||
#include <ArduinoJson/Json/Utf8.hpp>
|
||||
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||
#include <ArduinoJson/Numbers/parseNumber.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TReader>
|
||||
class JsonDeserializer {
|
||||
public:
|
||||
JsonDeserializer(ResourceManager* resources, TReader reader)
|
||||
: stringBuilder_(resources),
|
||||
foundSomething_(false),
|
||||
latch_(reader),
|
||||
resources_(resources) {}
|
||||
|
||||
template <typename TFilter>
|
||||
DeserializationError parse(VariantData& variant, TFilter filter,
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
err = parseVariant(variant, filter, nestingLimit);
|
||||
|
||||
if (!err && latch_.last() != 0 && variant.isFloat()) {
|
||||
// We don't detect trailing characters earlier, so we need to check now
|
||||
return DeserializationError::InvalidInput;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
private:
|
||||
char current() {
|
||||
return latch_.current();
|
||||
}
|
||||
|
||||
void move() {
|
||||
latch_.clear();
|
||||
}
|
||||
|
||||
bool eat(char charToSkip) {
|
||||
if (current() != charToSkip)
|
||||
return false;
|
||||
move();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TFilter>
|
||||
DeserializationError::Code parseVariant(
|
||||
VariantData& variant, TFilter filter,
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
err = skipSpacesAndComments();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (current()) {
|
||||
case '[':
|
||||
if (filter.allowArray())
|
||||
return parseArray(variant.toArray(), filter, nestingLimit);
|
||||
else
|
||||
return skipArray(nestingLimit);
|
||||
|
||||
case '{':
|
||||
if (filter.allowObject())
|
||||
return parseObject(variant.toObject(), filter, nestingLimit);
|
||||
else
|
||||
return skipObject(nestingLimit);
|
||||
|
||||
case '\"':
|
||||
case '\'':
|
||||
if (filter.allowValue())
|
||||
return parseStringValue(variant);
|
||||
else
|
||||
return skipQuotedString();
|
||||
|
||||
case 't':
|
||||
if (filter.allowValue())
|
||||
variant.setBoolean(true);
|
||||
return skipKeyword("true");
|
||||
|
||||
case 'f':
|
||||
if (filter.allowValue())
|
||||
variant.setBoolean(false);
|
||||
return skipKeyword("false");
|
||||
|
||||
case 'n':
|
||||
// the variant should already by null, except if the same object key was
|
||||
// used twice, as in {"a":1,"a":null}
|
||||
return skipKeyword("null");
|
||||
|
||||
default:
|
||||
if (filter.allowValue())
|
||||
return parseNumericValue(variant);
|
||||
else
|
||||
return skipNumericValue();
|
||||
}
|
||||
}
|
||||
|
||||
DeserializationError::Code skipVariant(
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
err = skipSpacesAndComments();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (current()) {
|
||||
case '[':
|
||||
return skipArray(nestingLimit);
|
||||
|
||||
case '{':
|
||||
return skipObject(nestingLimit);
|
||||
|
||||
case '\"':
|
||||
case '\'':
|
||||
return skipQuotedString();
|
||||
|
||||
case 't':
|
||||
return skipKeyword("true");
|
||||
|
||||
case 'f':
|
||||
return skipKeyword("false");
|
||||
|
||||
case 'n':
|
||||
return skipKeyword("null");
|
||||
|
||||
default:
|
||||
return skipNumericValue();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TFilter>
|
||||
DeserializationError::Code parseArray(
|
||||
ArrayData& array, TFilter filter,
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
if (nestingLimit.reached())
|
||||
return DeserializationError::TooDeep;
|
||||
|
||||
// Skip opening braket
|
||||
ARDUINOJSON_ASSERT(current() == '[');
|
||||
move();
|
||||
|
||||
// Skip spaces
|
||||
err = skipSpacesAndComments();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
// Empty array?
|
||||
if (eat(']'))
|
||||
return DeserializationError::Ok;
|
||||
|
||||
TFilter elementFilter = filter[0UL];
|
||||
|
||||
// Read each value
|
||||
for (;;) {
|
||||
if (elementFilter.allow()) {
|
||||
// Allocate slot in array
|
||||
VariantData* value = array.addElement(resources_);
|
||||
if (!value)
|
||||
return DeserializationError::NoMemory;
|
||||
|
||||
// 1 - Parse value
|
||||
err = parseVariant(*value, elementFilter, nestingLimit.decrement());
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
err = skipVariant(nestingLimit.decrement());
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
// 2 - Skip spaces
|
||||
err = skipSpacesAndComments();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
// 3 - More values?
|
||||
if (eat(']'))
|
||||
return DeserializationError::Ok;
|
||||
if (!eat(','))
|
||||
return DeserializationError::InvalidInput;
|
||||
}
|
||||
}
|
||||
|
||||
DeserializationError::Code skipArray(
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
if (nestingLimit.reached())
|
||||
return DeserializationError::TooDeep;
|
||||
|
||||
// Skip opening braket
|
||||
ARDUINOJSON_ASSERT(current() == '[');
|
||||
move();
|
||||
|
||||
// Read each value
|
||||
for (;;) {
|
||||
// 1 - Skip value
|
||||
err = skipVariant(nestingLimit.decrement());
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
// 2 - Skip spaces
|
||||
err = skipSpacesAndComments();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
// 3 - More values?
|
||||
if (eat(']'))
|
||||
return DeserializationError::Ok;
|
||||
if (!eat(','))
|
||||
return DeserializationError::InvalidInput;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TFilter>
|
||||
DeserializationError::Code parseObject(
|
||||
ObjectData& object, TFilter filter,
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
if (nestingLimit.reached())
|
||||
return DeserializationError::TooDeep;
|
||||
|
||||
// Skip opening brace
|
||||
ARDUINOJSON_ASSERT(current() == '{');
|
||||
move();
|
||||
|
||||
// Skip spaces
|
||||
err = skipSpacesAndComments();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
// Empty object?
|
||||
if (eat('}'))
|
||||
return DeserializationError::Ok;
|
||||
|
||||
// Read each key value pair
|
||||
for (;;) {
|
||||
// Parse key
|
||||
err = parseKey();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
// Skip spaces
|
||||
err = skipSpacesAndComments();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
// Colon
|
||||
if (!eat(':'))
|
||||
return DeserializationError::InvalidInput;
|
||||
|
||||
JsonString key = stringBuilder_.str();
|
||||
|
||||
TFilter memberFilter = filter[key.c_str()];
|
||||
|
||||
if (memberFilter.allow()) {
|
||||
auto member = object.getMember(adaptString(key.c_str()), resources_);
|
||||
if (!member) {
|
||||
// Save key in memory pool.
|
||||
auto savedKey = stringBuilder_.save();
|
||||
|
||||
// Allocate slot in object
|
||||
member = object.addMember(savedKey, resources_);
|
||||
if (!member)
|
||||
return DeserializationError::NoMemory;
|
||||
} else {
|
||||
member->setNull(resources_);
|
||||
}
|
||||
|
||||
// Parse value
|
||||
err = parseVariant(*member, memberFilter, nestingLimit.decrement());
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
err = skipVariant(nestingLimit.decrement());
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
// Skip spaces
|
||||
err = skipSpacesAndComments();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
// More keys/values?
|
||||
if (eat('}'))
|
||||
return DeserializationError::Ok;
|
||||
if (!eat(','))
|
||||
return DeserializationError::InvalidInput;
|
||||
|
||||
// Skip spaces
|
||||
err = skipSpacesAndComments();
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
DeserializationError::Code skipObject(
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
if (nestingLimit.reached())
|
||||
return DeserializationError::TooDeep;
|
||||
|
||||
// Skip opening brace
|
||||
ARDUINOJSON_ASSERT(current() == '{');
|
||||
move();
|
||||
|
||||
// Skip spaces
|
||||
err = skipSpacesAndComments();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
// Empty object?
|
||||
if (eat('}'))
|
||||
return DeserializationError::Ok;
|
||||
|
||||
// Read each key value pair
|
||||
for (;;) {
|
||||
// Skip key
|
||||
err = skipKey();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
// Skip spaces
|
||||
err = skipSpacesAndComments();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
// Colon
|
||||
if (!eat(':'))
|
||||
return DeserializationError::InvalidInput;
|
||||
|
||||
// Skip value
|
||||
err = skipVariant(nestingLimit.decrement());
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
// Skip spaces
|
||||
err = skipSpacesAndComments();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
// More keys/values?
|
||||
if (eat('}'))
|
||||
return DeserializationError::Ok;
|
||||
if (!eat(','))
|
||||
return DeserializationError::InvalidInput;
|
||||
|
||||
err = skipSpacesAndComments();
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
DeserializationError::Code parseKey() {
|
||||
stringBuilder_.startString();
|
||||
if (isQuote(current())) {
|
||||
return parseQuotedString();
|
||||
} else {
|
||||
return parseNonQuotedString();
|
||||
}
|
||||
}
|
||||
|
||||
DeserializationError::Code parseStringValue(VariantData& variant) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
stringBuilder_.startString();
|
||||
|
||||
err = parseQuotedString();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
variant.setOwnedString(stringBuilder_.save());
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
DeserializationError::Code parseQuotedString() {
|
||||
#if ARDUINOJSON_DECODE_UNICODE
|
||||
Utf16::Codepoint codepoint;
|
||||
DeserializationError::Code err;
|
||||
#endif
|
||||
const char stopChar = current();
|
||||
|
||||
move();
|
||||
for (;;) {
|
||||
char c = current();
|
||||
move();
|
||||
if (c == stopChar)
|
||||
break;
|
||||
|
||||
if (c == '\0')
|
||||
return DeserializationError::IncompleteInput;
|
||||
|
||||
if (c == '\\') {
|
||||
c = current();
|
||||
|
||||
if (c == '\0')
|
||||
return DeserializationError::IncompleteInput;
|
||||
|
||||
if (c == 'u') {
|
||||
#if ARDUINOJSON_DECODE_UNICODE
|
||||
move();
|
||||
uint16_t codeunit;
|
||||
err = parseHex4(codeunit);
|
||||
if (err)
|
||||
return err;
|
||||
if (codepoint.append(codeunit))
|
||||
Utf8::encodeCodepoint(codepoint.value(), stringBuilder_);
|
||||
#else
|
||||
stringBuilder_.append('\\');
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
// replace char
|
||||
c = EscapeSequence::unescapeChar(c);
|
||||
if (c == '\0')
|
||||
return DeserializationError::InvalidInput;
|
||||
move();
|
||||
}
|
||||
|
||||
stringBuilder_.append(c);
|
||||
}
|
||||
|
||||
if (!stringBuilder_.isValid())
|
||||
return DeserializationError::NoMemory;
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
DeserializationError::Code parseNonQuotedString() {
|
||||
char c = current();
|
||||
ARDUINOJSON_ASSERT(c);
|
||||
|
||||
if (canBeInNonQuotedString(c)) { // no quotes
|
||||
do {
|
||||
move();
|
||||
stringBuilder_.append(c);
|
||||
c = current();
|
||||
} while (canBeInNonQuotedString(c));
|
||||
} else {
|
||||
return DeserializationError::InvalidInput;
|
||||
}
|
||||
|
||||
if (!stringBuilder_.isValid())
|
||||
return DeserializationError::NoMemory;
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
DeserializationError::Code skipKey() {
|
||||
if (isQuote(current())) {
|
||||
return skipQuotedString();
|
||||
} else {
|
||||
return skipNonQuotedString();
|
||||
}
|
||||
}
|
||||
|
||||
DeserializationError::Code skipQuotedString() {
|
||||
const char stopChar = current();
|
||||
|
||||
move();
|
||||
for (;;) {
|
||||
char c = current();
|
||||
move();
|
||||
if (c == stopChar)
|
||||
break;
|
||||
if (c == '\0')
|
||||
return DeserializationError::IncompleteInput;
|
||||
if (c == '\\') {
|
||||
if (current() != '\0')
|
||||
move();
|
||||
}
|
||||
}
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
DeserializationError::Code skipNonQuotedString() {
|
||||
char c = current();
|
||||
while (canBeInNonQuotedString(c)) {
|
||||
move();
|
||||
c = current();
|
||||
}
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
DeserializationError::Code parseNumericValue(VariantData& result) {
|
||||
uint8_t n = 0;
|
||||
|
||||
char c = current();
|
||||
while (canBeInNumber(c) && n < 63) {
|
||||
move();
|
||||
buffer_[n++] = c;
|
||||
c = current();
|
||||
}
|
||||
buffer_[n] = 0;
|
||||
|
||||
if (!parseNumber(buffer_, result))
|
||||
return DeserializationError::InvalidInput;
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
DeserializationError::Code skipNumericValue() {
|
||||
char c = current();
|
||||
while (canBeInNumber(c)) {
|
||||
move();
|
||||
c = current();
|
||||
}
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
DeserializationError::Code parseHex4(uint16_t& result) {
|
||||
result = 0;
|
||||
for (uint8_t i = 0; i < 4; ++i) {
|
||||
char digit = current();
|
||||
if (!digit)
|
||||
return DeserializationError::IncompleteInput;
|
||||
uint8_t value = decodeHex(digit);
|
||||
if (value > 0x0F)
|
||||
return DeserializationError::InvalidInput;
|
||||
result = uint16_t((result << 4) | value);
|
||||
move();
|
||||
}
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
static inline bool isBetween(char c, char min, char max) {
|
||||
return min <= c && c <= max;
|
||||
}
|
||||
|
||||
static inline bool canBeInNumber(char c) {
|
||||
return isBetween(c, '0', '9') || c == '+' || c == '-' || c == '.' ||
|
||||
#if ARDUINOJSON_ENABLE_NAN || ARDUINOJSON_ENABLE_INFINITY
|
||||
isBetween(c, 'A', 'Z') || isBetween(c, 'a', 'z');
|
||||
#else
|
||||
c == 'e' || c == 'E';
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool canBeInNonQuotedString(char c) {
|
||||
return isBetween(c, '0', '9') || isBetween(c, '_', 'z') ||
|
||||
isBetween(c, 'A', 'Z');
|
||||
}
|
||||
|
||||
static inline bool isQuote(char c) {
|
||||
return c == '\'' || c == '\"';
|
||||
}
|
||||
|
||||
static inline uint8_t decodeHex(char c) {
|
||||
if (c < 'A')
|
||||
return uint8_t(c - '0');
|
||||
c = char(c & ~0x20); // uppercase
|
||||
return uint8_t(c - 'A' + 10);
|
||||
}
|
||||
|
||||
DeserializationError::Code skipSpacesAndComments() {
|
||||
for (;;) {
|
||||
switch (current()) {
|
||||
// end of string
|
||||
case '\0':
|
||||
return foundSomething_ ? DeserializationError::IncompleteInput
|
||||
: DeserializationError::EmptyInput;
|
||||
|
||||
// spaces
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
move();
|
||||
continue;
|
||||
|
||||
#if ARDUINOJSON_ENABLE_COMMENTS
|
||||
// comments
|
||||
case '/':
|
||||
move(); // skip '/'
|
||||
switch (current()) {
|
||||
// block comment
|
||||
case '*': {
|
||||
move(); // skip '*'
|
||||
bool wasStar = false;
|
||||
for (;;) {
|
||||
char c = current();
|
||||
if (c == '\0')
|
||||
return DeserializationError::IncompleteInput;
|
||||
if (c == '/' && wasStar) {
|
||||
move();
|
||||
break;
|
||||
}
|
||||
wasStar = c == '*';
|
||||
move();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// trailing comment
|
||||
case '/':
|
||||
// no need to skip "//"
|
||||
for (;;) {
|
||||
move();
|
||||
char c = current();
|
||||
if (c == '\0')
|
||||
return DeserializationError::IncompleteInput;
|
||||
if (c == '\n')
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// not a comment, just a '/'
|
||||
default:
|
||||
return DeserializationError::InvalidInput;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
foundSomething_ = true;
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeserializationError::Code skipKeyword(const char* s) {
|
||||
while (*s) {
|
||||
char c = current();
|
||||
if (c == '\0')
|
||||
return DeserializationError::IncompleteInput;
|
||||
if (*s != c)
|
||||
return DeserializationError::InvalidInput;
|
||||
++s;
|
||||
move();
|
||||
}
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
StringBuilder stringBuilder_;
|
||||
bool foundSomething_;
|
||||
Latch<TReader> latch_;
|
||||
ResourceManager* resources_;
|
||||
char buffer_[64]; // using a member instead of a local variable because it
|
||||
// ended in the recursive path after compiler inlined the
|
||||
// code
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Parses a JSON input, filters, and puts the result in a JsonDocument.
|
||||
// https://arduinojson.org/v7/api/json/deserializejson/
|
||||
template <typename TDestination, typename... Args>
|
||||
typename detail::enable_if<
|
||||
detail::is_deserialize_destination<TDestination>::value,
|
||||
DeserializationError>::type
|
||||
deserializeJson(TDestination&& dst, Args&&... args) {
|
||||
using namespace detail;
|
||||
return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
|
||||
detail::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Parses a JSON input, filters, and puts the result in a JsonDocument.
|
||||
// https://arduinojson.org/v7/api/json/deserializejson/
|
||||
template <typename TDestination, typename TChar, typename... Args>
|
||||
typename detail::enable_if<
|
||||
detail::is_deserialize_destination<TDestination>::value,
|
||||
DeserializationError>::type
|
||||
deserializeJson(TDestination&& dst, TChar* input, Args&&... args) {
|
||||
using namespace detail;
|
||||
return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
|
||||
input, detail::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,161 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Json/TextFormatter.hpp>
|
||||
#include <ArduinoJson/Serialization/measure.hpp>
|
||||
#include <ArduinoJson/Serialization/serialize.hpp>
|
||||
#include <ArduinoJson/Variant/VariantDataVisitor.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TWriter>
|
||||
class JsonSerializer : public VariantDataVisitor<size_t> {
|
||||
public:
|
||||
static const bool producesText = true;
|
||||
|
||||
JsonSerializer(TWriter writer, const ResourceManager* resources)
|
||||
: formatter_(writer), resources_(resources) {}
|
||||
|
||||
size_t visit(const ArrayData& array) {
|
||||
write('[');
|
||||
|
||||
auto slotId = array.head();
|
||||
|
||||
while (slotId != NULL_SLOT) {
|
||||
auto slot = resources_->getSlot(slotId);
|
||||
|
||||
slot->data()->accept(*this);
|
||||
|
||||
slotId = slot->next();
|
||||
|
||||
if (slotId != NULL_SLOT)
|
||||
write(',');
|
||||
}
|
||||
|
||||
write(']');
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(const ObjectData& object) {
|
||||
write('{');
|
||||
|
||||
auto slotId = object.head();
|
||||
|
||||
while (slotId != NULL_SLOT) {
|
||||
auto slot = resources_->getSlot(slotId);
|
||||
|
||||
formatter_.writeString(slot->key());
|
||||
write(':');
|
||||
slot->data()->accept(*this);
|
||||
|
||||
slotId = slot->next();
|
||||
|
||||
if (slotId != NULL_SLOT)
|
||||
write(',');
|
||||
}
|
||||
|
||||
write('}');
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(JsonFloat value) {
|
||||
formatter_.writeFloat(value);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(const char* value) {
|
||||
formatter_.writeString(value);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(JsonString value) {
|
||||
formatter_.writeString(value.c_str(), value.size());
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(RawString value) {
|
||||
formatter_.writeRaw(value.data(), value.size());
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(JsonInteger value) {
|
||||
formatter_.writeInteger(value);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(JsonUInt value) {
|
||||
formatter_.writeInteger(value);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(bool value) {
|
||||
formatter_.writeBoolean(value);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(nullptr_t) {
|
||||
formatter_.writeRaw("null");
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
protected:
|
||||
size_t bytesWritten() const {
|
||||
return formatter_.bytesWritten();
|
||||
}
|
||||
|
||||
void write(char c) {
|
||||
formatter_.writeRaw(c);
|
||||
}
|
||||
|
||||
void write(const char* s) {
|
||||
formatter_.writeRaw(s);
|
||||
}
|
||||
|
||||
private:
|
||||
TextFormatter<TWriter> formatter_;
|
||||
|
||||
protected:
|
||||
const ResourceManager* resources_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Produces a minified JSON document.
|
||||
// https://arduinojson.org/v7/api/json/serializejson/
|
||||
template <typename TDestination>
|
||||
size_t serializeJson(JsonVariantConst source, TDestination& destination) {
|
||||
using namespace detail;
|
||||
return serialize<JsonSerializer>(source, destination);
|
||||
}
|
||||
|
||||
// Produces a minified JSON document.
|
||||
// https://arduinojson.org/v7/api/json/serializejson/
|
||||
inline size_t serializeJson(JsonVariantConst source, void* buffer,
|
||||
size_t bufferSize) {
|
||||
using namespace detail;
|
||||
return serialize<JsonSerializer>(source, buffer, bufferSize);
|
||||
}
|
||||
|
||||
// Computes the length of the document that serializeJson() produces.
|
||||
// https://arduinojson.org/v7/api/json/measurejson/
|
||||
inline size_t measureJson(JsonVariantConst source) {
|
||||
using namespace detail;
|
||||
return measure<JsonSerializer>(source);
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_ENABLE_STD_STREAM
|
||||
template <typename T>
|
||||
inline typename detail::enable_if<
|
||||
detail::is_convertible<T, JsonVariantConst>::value, std::ostream&>::type
|
||||
operator<<(std::ostream& os, const T& source) {
|
||||
serializeJson(source, os);
|
||||
return os;
|
||||
}
|
||||
#endif
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,56 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TReader>
|
||||
class Latch {
|
||||
public:
|
||||
Latch(TReader reader) : reader_(reader), loaded_(false) {
|
||||
#if ARDUINOJSON_DEBUG
|
||||
ended_ = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void clear() {
|
||||
loaded_ = false;
|
||||
}
|
||||
|
||||
int last() const {
|
||||
return current_;
|
||||
}
|
||||
|
||||
FORCE_INLINE char current() {
|
||||
if (!loaded_) {
|
||||
load();
|
||||
}
|
||||
return current_;
|
||||
}
|
||||
|
||||
private:
|
||||
void load() {
|
||||
ARDUINOJSON_ASSERT(!ended_);
|
||||
int c = reader_.read();
|
||||
#if ARDUINOJSON_DEBUG
|
||||
if (c <= 0)
|
||||
ended_ = true;
|
||||
#endif
|
||||
current_ = static_cast<char>(c > 0 ? c : 0);
|
||||
loaded_ = true;
|
||||
}
|
||||
|
||||
TReader reader_;
|
||||
char current_; // NOLINT(clang-analyzer-optin.cplusplus.UninitializedObject)
|
||||
// Not initialized in constructor (+10 bytes on AVR)
|
||||
bool loaded_;
|
||||
#if ARDUINOJSON_DEBUG
|
||||
bool ended_;
|
||||
#endif
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,104 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Configuration.hpp>
|
||||
#include <ArduinoJson/Json/JsonSerializer.hpp>
|
||||
#include <ArduinoJson/Serialization/measure.hpp>
|
||||
#include <ArduinoJson/Serialization/serialize.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TWriter>
|
||||
class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
||||
typedef JsonSerializer<TWriter> base;
|
||||
|
||||
public:
|
||||
PrettyJsonSerializer(TWriter writer, const ResourceManager* resources)
|
||||
: base(writer, resources), nesting_(0) {}
|
||||
|
||||
size_t visit(const ArrayData& array) {
|
||||
auto it = array.createIterator(base::resources_);
|
||||
if (!it.done()) {
|
||||
base::write("[\r\n");
|
||||
nesting_++;
|
||||
while (!it.done()) {
|
||||
indent();
|
||||
it->accept(*this);
|
||||
|
||||
it.next(base::resources_);
|
||||
base::write(it.done() ? "\r\n" : ",\r\n");
|
||||
}
|
||||
nesting_--;
|
||||
indent();
|
||||
base::write("]");
|
||||
} else {
|
||||
base::write("[]");
|
||||
}
|
||||
return this->bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(const ObjectData& object) {
|
||||
auto it = object.createIterator(base::resources_);
|
||||
if (!it.done()) {
|
||||
base::write("{\r\n");
|
||||
nesting_++;
|
||||
while (!it.done()) {
|
||||
indent();
|
||||
base::visit(it.key());
|
||||
base::write(": ");
|
||||
it->accept(*this);
|
||||
|
||||
it.next(base::resources_);
|
||||
base::write(it.done() ? "\r\n" : ",\r\n");
|
||||
}
|
||||
nesting_--;
|
||||
indent();
|
||||
base::write("}");
|
||||
} else {
|
||||
base::write("{}");
|
||||
}
|
||||
return this->bytesWritten();
|
||||
}
|
||||
|
||||
using base::visit;
|
||||
|
||||
private:
|
||||
void indent() {
|
||||
for (uint8_t i = 0; i < nesting_; i++)
|
||||
base::write(ARDUINOJSON_TAB);
|
||||
}
|
||||
|
||||
uint8_t nesting_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Produces JsonDocument to create a prettified JSON document.
|
||||
// https://arduinojson.org/v7/api/json/serializejsonpretty/
|
||||
template <typename TDestination>
|
||||
size_t serializeJsonPretty(JsonVariantConst source, TDestination& destination) {
|
||||
using namespace ArduinoJson::detail;
|
||||
return serialize<PrettyJsonSerializer>(source, destination);
|
||||
}
|
||||
|
||||
// Produces JsonDocument to create a prettified JSON document.
|
||||
// https://arduinojson.org/v7/api/json/serializejsonpretty/
|
||||
inline size_t serializeJsonPretty(JsonVariantConst source, void* buffer,
|
||||
size_t bufferSize) {
|
||||
using namespace ArduinoJson::detail;
|
||||
return serialize<PrettyJsonSerializer>(source, buffer, bufferSize);
|
||||
}
|
||||
|
||||
// Computes the length of the document that serializeJsonPretty() produces.
|
||||
// https://arduinojson.org/v7/api/json/measurejsonpretty/
|
||||
inline size_t measureJsonPretty(JsonVariantConst source) {
|
||||
using namespace ArduinoJson::detail;
|
||||
return measure<PrettyJsonSerializer>(source);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,173 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h> // for strlen
|
||||
|
||||
#include <ArduinoJson/Json/EscapeSequence.hpp>
|
||||
#include <ArduinoJson/Numbers/FloatParts.hpp>
|
||||
#include <ArduinoJson/Numbers/JsonInteger.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/attributes.hpp>
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
#include <ArduinoJson/Serialization/CountingDecorator.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TWriter>
|
||||
class TextFormatter {
|
||||
public:
|
||||
explicit TextFormatter(TWriter writer) : writer_(writer) {}
|
||||
|
||||
TextFormatter& operator=(const TextFormatter&) = delete;
|
||||
|
||||
// Returns the number of bytes sent to the TWriter implementation.
|
||||
size_t bytesWritten() const {
|
||||
return writer_.count();
|
||||
}
|
||||
|
||||
void writeBoolean(bool value) {
|
||||
if (value)
|
||||
writeRaw("true");
|
||||
else
|
||||
writeRaw("false");
|
||||
}
|
||||
|
||||
void writeString(const char* value) {
|
||||
ARDUINOJSON_ASSERT(value != NULL);
|
||||
writeRaw('\"');
|
||||
while (*value)
|
||||
writeChar(*value++);
|
||||
writeRaw('\"');
|
||||
}
|
||||
|
||||
void writeString(const char* value, size_t n) {
|
||||
ARDUINOJSON_ASSERT(value != NULL);
|
||||
writeRaw('\"');
|
||||
while (n--)
|
||||
writeChar(*value++);
|
||||
writeRaw('\"');
|
||||
}
|
||||
|
||||
void writeChar(char c) {
|
||||
char specialChar = EscapeSequence::escapeChar(c);
|
||||
if (specialChar) {
|
||||
writeRaw('\\');
|
||||
writeRaw(specialChar);
|
||||
} else if (c) {
|
||||
writeRaw(c);
|
||||
} else {
|
||||
writeRaw("\\u0000");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void writeFloat(T value) {
|
||||
if (isnan(value))
|
||||
return writeRaw(ARDUINOJSON_ENABLE_NAN ? "NaN" : "null");
|
||||
|
||||
#if ARDUINOJSON_ENABLE_INFINITY
|
||||
if (value < 0.0) {
|
||||
writeRaw('-');
|
||||
value = -value;
|
||||
}
|
||||
|
||||
if (isinf(value))
|
||||
return writeRaw("Infinity");
|
||||
#else
|
||||
if (isinf(value))
|
||||
return writeRaw("null");
|
||||
|
||||
if (value < 0.0) {
|
||||
writeRaw('-');
|
||||
value = -value;
|
||||
}
|
||||
#endif
|
||||
|
||||
FloatParts<T> parts(value);
|
||||
|
||||
writeInteger(parts.integral);
|
||||
if (parts.decimalPlaces)
|
||||
writeDecimals(parts.decimal, parts.decimalPlaces);
|
||||
|
||||
if (parts.exponent) {
|
||||
writeRaw('e');
|
||||
writeInteger(parts.exponent);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<is_signed<T>::value>::type writeInteger(T value) {
|
||||
typedef typename make_unsigned<T>::type unsigned_type;
|
||||
unsigned_type unsigned_value;
|
||||
if (value < 0) {
|
||||
writeRaw('-');
|
||||
unsigned_value = unsigned_type(unsigned_type(~value) + 1);
|
||||
} else {
|
||||
unsigned_value = unsigned_type(value);
|
||||
}
|
||||
writeInteger(unsigned_value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<is_unsigned<T>::value>::type writeInteger(T value) {
|
||||
char buffer[22];
|
||||
char* end = buffer + sizeof(buffer);
|
||||
char* begin = end;
|
||||
|
||||
// write the string in reverse order
|
||||
do {
|
||||
*--begin = char(value % 10 + '0');
|
||||
value = T(value / 10);
|
||||
} while (value);
|
||||
|
||||
// and dump it in the right order
|
||||
writeRaw(begin, end);
|
||||
}
|
||||
|
||||
void writeDecimals(uint32_t value, int8_t width) {
|
||||
// buffer should be big enough for all digits and the dot
|
||||
char buffer[16];
|
||||
char* end = buffer + sizeof(buffer);
|
||||
char* begin = end;
|
||||
|
||||
// write the string in reverse order
|
||||
while (width--) {
|
||||
*--begin = char(value % 10 + '0');
|
||||
value /= 10;
|
||||
}
|
||||
*--begin = '.';
|
||||
|
||||
// and dump it in the right order
|
||||
writeRaw(begin, end);
|
||||
}
|
||||
|
||||
void writeRaw(const char* s) {
|
||||
writer_.write(reinterpret_cast<const uint8_t*>(s), strlen(s));
|
||||
}
|
||||
|
||||
void writeRaw(const char* s, size_t n) {
|
||||
writer_.write(reinterpret_cast<const uint8_t*>(s), n);
|
||||
}
|
||||
|
||||
void writeRaw(const char* begin, const char* end) {
|
||||
writer_.write(reinterpret_cast<const uint8_t*>(begin),
|
||||
static_cast<size_t>(end - begin));
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
void writeRaw(const char (&s)[N]) {
|
||||
writer_.write(reinterpret_cast<const uint8_t*>(s), N - 1);
|
||||
}
|
||||
void writeRaw(char c) {
|
||||
writer_.write(static_cast<uint8_t>(c));
|
||||
}
|
||||
|
||||
protected:
|
||||
CountingDecorator<TWriter> writer_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,67 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
|
||||
#include <stdint.h> // uint16_t, uint32_t
|
||||
|
||||
// The high surrogate may be uninitialized if the pair is invalid,
|
||||
// we choose to ignore the problem to reduce the size of the code
|
||||
// Garbage in => Garbage out
|
||||
#if defined(__GNUC__)
|
||||
# if __GNUC__ >= 7
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
namespace Utf16 {
|
||||
inline bool isHighSurrogate(uint16_t codeunit) {
|
||||
return codeunit >= 0xD800 && codeunit < 0xDC00;
|
||||
}
|
||||
|
||||
inline bool isLowSurrogate(uint16_t codeunit) {
|
||||
return codeunit >= 0xDC00 && codeunit < 0xE000;
|
||||
}
|
||||
|
||||
class Codepoint {
|
||||
public:
|
||||
Codepoint() : highSurrogate_(0), codepoint_(0) {}
|
||||
|
||||
bool append(uint16_t codeunit) {
|
||||
if (isHighSurrogate(codeunit)) {
|
||||
highSurrogate_ = codeunit & 0x3FF;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isLowSurrogate(codeunit)) {
|
||||
codepoint_ =
|
||||
uint32_t(0x10000 + ((highSurrogate_ << 10) | (codeunit & 0x3FF)));
|
||||
return true;
|
||||
}
|
||||
|
||||
codepoint_ = codeunit;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t value() const {
|
||||
return codepoint_;
|
||||
}
|
||||
|
||||
private:
|
||||
uint16_t highSurrogate_;
|
||||
uint32_t codepoint_;
|
||||
};
|
||||
} // namespace Utf16
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# if __GNUC__ >= 8
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
#endif
|
||||
@@ -1,46 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
namespace Utf8 {
|
||||
template <typename TStringBuilder>
|
||||
inline void encodeCodepoint(uint32_t codepoint32, TStringBuilder& str) {
|
||||
// this function was optimize for code size on AVR
|
||||
|
||||
if (codepoint32 < 0x80) {
|
||||
str.append(char(codepoint32));
|
||||
} else {
|
||||
// a buffer to store the string in reverse
|
||||
char buf[5];
|
||||
char* p = buf;
|
||||
|
||||
*(p++) = 0;
|
||||
*(p++) = char((codepoint32 | 0x80) & 0xBF);
|
||||
uint16_t codepoint16 = uint16_t(codepoint32 >> 6);
|
||||
if (codepoint16 < 0x20) { // 0x800
|
||||
*(p++) = char(codepoint16 | 0xC0);
|
||||
} else {
|
||||
*(p++) = char((codepoint16 | 0x80) & 0xBF);
|
||||
codepoint16 = uint16_t(codepoint16 >> 6);
|
||||
if (codepoint16 < 0x10) { // 0x10000
|
||||
*(p++) = char(codepoint16 | 0xE0);
|
||||
} else {
|
||||
*(p++) = char((codepoint16 | 0x80) & 0xBF);
|
||||
codepoint16 = uint16_t(codepoint16 >> 6);
|
||||
*(p++) = char(codepoint16 | 0xF0);
|
||||
}
|
||||
}
|
||||
|
||||
while (*(--p)) {
|
||||
str.append(*p);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Utf8
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,60 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
#if ARDUINOJSON_ENABLE_ALIGNMENT
|
||||
|
||||
inline bool isAligned(size_t value) {
|
||||
const size_t mask = sizeof(void*) - 1;
|
||||
size_t addr = value;
|
||||
return (addr & mask) == 0;
|
||||
}
|
||||
|
||||
inline size_t addPadding(size_t bytes) {
|
||||
const size_t mask = sizeof(void*) - 1;
|
||||
return (bytes + mask) & ~mask;
|
||||
}
|
||||
|
||||
template <size_t bytes>
|
||||
struct AddPadding {
|
||||
static const size_t mask = sizeof(void*) - 1;
|
||||
static const size_t value = (bytes + mask) & ~mask;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
inline bool isAligned(size_t) {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline size_t addPadding(size_t bytes) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
template <size_t bytes>
|
||||
struct AddPadding {
|
||||
static const size_t value = bytes;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
inline bool isAligned(T* ptr) {
|
||||
return isAligned(reinterpret_cast<size_t>(ptr));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T* addPadding(T* p) {
|
||||
size_t address = addPadding(reinterpret_cast<size_t>(p));
|
||||
return reinterpret_cast<T*>(address);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,49 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
|
||||
#include <stdlib.h> // malloc, free
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
class Allocator {
|
||||
public:
|
||||
virtual void* allocate(size_t size) = 0;
|
||||
virtual void deallocate(void* ptr) = 0;
|
||||
virtual void* reallocate(void* ptr, size_t new_size) = 0;
|
||||
|
||||
protected:
|
||||
~Allocator() = default;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
class DefaultAllocator : public Allocator {
|
||||
public:
|
||||
void* allocate(size_t size) override {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void deallocate(void* ptr) override {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void* reallocate(void* ptr, size_t new_size) override {
|
||||
return realloc(ptr, new_size);
|
||||
}
|
||||
|
||||
static Allocator* instance() {
|
||||
static DefaultAllocator allocator;
|
||||
return &allocator;
|
||||
}
|
||||
|
||||
private:
|
||||
DefaultAllocator() = default;
|
||||
~DefaultAllocator() = default;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,127 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/Allocator.hpp>
|
||||
#include <ArduinoJson/Memory/StringPool.hpp>
|
||||
#include <ArduinoJson/Memory/VariantPoolList.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||
#include <ArduinoJson/Strings/StringAdapters.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class VariantSlot;
|
||||
class VariantPool;
|
||||
|
||||
class ResourceManager {
|
||||
public:
|
||||
ResourceManager(Allocator* allocator = DefaultAllocator::instance())
|
||||
: allocator_(allocator), overflowed_(false) {}
|
||||
|
||||
~ResourceManager() {
|
||||
stringPool_.clear(allocator_);
|
||||
variantPools_.clear(allocator_);
|
||||
}
|
||||
|
||||
ResourceManager(const ResourceManager&) = delete;
|
||||
ResourceManager& operator=(const ResourceManager& src) = delete;
|
||||
|
||||
friend void swap(ResourceManager& a, ResourceManager& b) {
|
||||
swap(a.stringPool_, b.stringPool_);
|
||||
swap(a.variantPools_, b.variantPools_);
|
||||
swap_(a.allocator_, b.allocator_);
|
||||
swap_(a.overflowed_, b.overflowed_);
|
||||
}
|
||||
|
||||
Allocator* allocator() const {
|
||||
return allocator_;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return VariantPool::slotsToBytes(variantPools_.usage()) +
|
||||
stringPool_.size();
|
||||
}
|
||||
|
||||
bool overflowed() const {
|
||||
return overflowed_;
|
||||
}
|
||||
|
||||
SlotWithId allocSlot() {
|
||||
auto p = variantPools_.allocSlot(allocator_);
|
||||
if (!p)
|
||||
overflowed_ = true;
|
||||
return p;
|
||||
}
|
||||
|
||||
void freeSlot(SlotWithId id) {
|
||||
variantPools_.freeSlot(id);
|
||||
}
|
||||
|
||||
VariantSlot* getSlot(SlotId id) const {
|
||||
return variantPools_.getSlot(id);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
StringNode* saveString(TAdaptedString str) {
|
||||
if (str.isNull())
|
||||
return 0;
|
||||
|
||||
auto node = stringPool_.add(str, allocator_);
|
||||
if (!node)
|
||||
overflowed_ = true;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void saveString(StringNode* node) {
|
||||
stringPool_.add(node);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
StringNode* getString(const TAdaptedString& str) const {
|
||||
return stringPool_.get(str);
|
||||
}
|
||||
|
||||
StringNode* createString(size_t length) {
|
||||
auto node = StringNode::create(length, allocator_);
|
||||
if (!node)
|
||||
overflowed_ = true;
|
||||
return node;
|
||||
}
|
||||
|
||||
StringNode* resizeString(StringNode* node, size_t length) {
|
||||
node = StringNode::resize(node, length, allocator_);
|
||||
if (!node)
|
||||
overflowed_ = true;
|
||||
return node;
|
||||
}
|
||||
|
||||
void destroyString(StringNode* node) {
|
||||
StringNode::destroy(node, allocator_);
|
||||
}
|
||||
|
||||
void dereferenceString(const char* s) {
|
||||
stringPool_.dereference(s, allocator_);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
variantPools_.clear(allocator_);
|
||||
overflowed_ = false;
|
||||
stringPool_.clear(allocator_);
|
||||
}
|
||||
|
||||
void shrinkToFit() {
|
||||
variantPools_.shrinkToFit(allocator_);
|
||||
}
|
||||
|
||||
private:
|
||||
Allocator* allocator_;
|
||||
bool overflowed_;
|
||||
StringPool stringPool_;
|
||||
VariantPoolList variantPools_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,80 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class StringBuilder {
|
||||
public:
|
||||
static const size_t initialCapacity = 31;
|
||||
|
||||
StringBuilder(ResourceManager* resources) : resources_(resources) {}
|
||||
|
||||
~StringBuilder() {
|
||||
if (node_)
|
||||
resources_->destroyString(node_);
|
||||
}
|
||||
|
||||
void startString() {
|
||||
size_ = 0;
|
||||
if (!node_)
|
||||
node_ = resources_->createString(initialCapacity);
|
||||
}
|
||||
|
||||
StringNode* save() {
|
||||
ARDUINOJSON_ASSERT(node_ != nullptr);
|
||||
node_->data[size_] = 0;
|
||||
StringNode* node = resources_->getString(adaptString(node_->data, size_));
|
||||
if (!node) {
|
||||
node = resources_->resizeString(node_, size_);
|
||||
ARDUINOJSON_ASSERT(node != nullptr); // realloc to smaller can't fail
|
||||
resources_->saveString(node);
|
||||
node_ = nullptr; // next time we need a new string
|
||||
} else {
|
||||
node->references++;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
void append(const char* s) {
|
||||
while (*s)
|
||||
append(*s++);
|
||||
}
|
||||
|
||||
void append(const char* s, size_t n) {
|
||||
while (n-- > 0) // TODO: memcpy
|
||||
append(*s++);
|
||||
}
|
||||
|
||||
void append(char c) {
|
||||
if (node_ && size_ == node_->length)
|
||||
node_ = resources_->resizeString(node_, size_ * 2U + 1);
|
||||
if (node_)
|
||||
node_->data[size_++] = c;
|
||||
}
|
||||
|
||||
bool isValid() const {
|
||||
return node_ != nullptr;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return size_;
|
||||
}
|
||||
|
||||
JsonString str() const {
|
||||
ARDUINOJSON_ASSERT(node_ != nullptr);
|
||||
node_->data[size_] = 0;
|
||||
return JsonString(node_->data, size_, JsonString::Copied);
|
||||
}
|
||||
|
||||
private:
|
||||
ResourceManager* resources_;
|
||||
StringNode* node_ = nullptr;
|
||||
size_t size_ = 0;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,73 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/Allocator.hpp>
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/integer.hpp>
|
||||
#include <ArduinoJson/Polyfills/limits.hpp>
|
||||
|
||||
#include <stddef.h> // offsetof
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
struct StringNode {
|
||||
// Use the same type as SlotId to store the reference count
|
||||
// (there can never be more references than slots)
|
||||
using references_type = uint_t<ARDUINOJSON_SLOT_ID_SIZE * 8>::type;
|
||||
|
||||
using length_type = uint_t<ARDUINOJSON_STRING_LENGTH_SIZE * 8>::type;
|
||||
|
||||
struct StringNode* next;
|
||||
references_type references;
|
||||
length_type length;
|
||||
char data[1];
|
||||
|
||||
static constexpr size_t maxLength = numeric_limits<length_type>::highest();
|
||||
|
||||
static constexpr size_t sizeForLength(size_t n) {
|
||||
return n + 1 + offsetof(StringNode, data);
|
||||
}
|
||||
|
||||
static StringNode* create(size_t length, Allocator* allocator) {
|
||||
if (length > maxLength)
|
||||
return nullptr;
|
||||
auto node = reinterpret_cast<StringNode*>(
|
||||
allocator->allocate(sizeForLength(length)));
|
||||
if (node) {
|
||||
node->length = length_type(length);
|
||||
node->references = 1;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static StringNode* resize(StringNode* node, size_t length,
|
||||
Allocator* allocator) {
|
||||
ARDUINOJSON_ASSERT(node != nullptr);
|
||||
StringNode* newNode;
|
||||
if (length <= maxLength)
|
||||
newNode = reinterpret_cast<StringNode*>(
|
||||
allocator->reallocate(node, sizeForLength(length)));
|
||||
else
|
||||
newNode = nullptr;
|
||||
if (newNode)
|
||||
newNode->length = length_type(length);
|
||||
else
|
||||
allocator->deallocate(node);
|
||||
return newNode;
|
||||
}
|
||||
|
||||
static void destroy(StringNode* node, Allocator* allocator) {
|
||||
allocator->deallocate(node);
|
||||
}
|
||||
};
|
||||
|
||||
// Returns the size (in bytes) of an string with n characters.
|
||||
constexpr size_t sizeofString(size_t n) {
|
||||
return StringNode::sizeForLength(n);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,105 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/Allocator.hpp>
|
||||
#include <ArduinoJson/Memory/StringNode.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||
#include <ArduinoJson/Strings/StringAdapters.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class VariantSlot;
|
||||
class VariantPool;
|
||||
|
||||
class StringPool {
|
||||
public:
|
||||
StringPool() = default;
|
||||
StringPool(const StringPool&) = delete;
|
||||
void operator=(StringPool&& src) = delete;
|
||||
|
||||
~StringPool() {
|
||||
ARDUINOJSON_ASSERT(strings_ == nullptr);
|
||||
}
|
||||
|
||||
friend void swap(StringPool& a, StringPool& b) {
|
||||
swap_(a.strings_, b.strings_);
|
||||
}
|
||||
|
||||
void clear(Allocator* allocator) {
|
||||
while (strings_) {
|
||||
auto node = strings_;
|
||||
strings_ = node->next;
|
||||
StringNode::destroy(node, allocator);
|
||||
}
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
size_t total = 0;
|
||||
for (auto node = strings_; node; node = node->next)
|
||||
total += sizeofString(node->length);
|
||||
return total;
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
StringNode* add(TAdaptedString str, Allocator* allocator) {
|
||||
ARDUINOJSON_ASSERT(str.isNull() == false);
|
||||
|
||||
auto node = get(str);
|
||||
if (node) {
|
||||
node->references++;
|
||||
return node;
|
||||
}
|
||||
|
||||
size_t n = str.size();
|
||||
|
||||
node = StringNode::create(n, allocator);
|
||||
if (!node)
|
||||
return nullptr;
|
||||
|
||||
stringGetChars(str, node->data, n);
|
||||
node->data[n] = 0; // force NUL terminator
|
||||
add(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
void add(StringNode* node) {
|
||||
ARDUINOJSON_ASSERT(node != nullptr);
|
||||
node->next = strings_;
|
||||
strings_ = node;
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
StringNode* get(const TAdaptedString& str) const {
|
||||
for (auto node = strings_; node; node = node->next) {
|
||||
if (stringEquals(str, adaptString(node->data, node->length)))
|
||||
return node;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void dereference(const char* s, Allocator* allocator) {
|
||||
StringNode* prev = nullptr;
|
||||
for (auto node = strings_; node; node = node->next) {
|
||||
if (node->data == s) {
|
||||
if (--node->references == 0) {
|
||||
if (prev)
|
||||
prev->next = node->next;
|
||||
else
|
||||
strings_ = node->next;
|
||||
StringNode::destroy(node, allocator);
|
||||
}
|
||||
return;
|
||||
}
|
||||
prev = node;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
StringNode* strings_ = nullptr;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,63 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/integer.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class VariantSlot;
|
||||
using SlotId = uint_t<ARDUINOJSON_SLOT_ID_SIZE * 8>::type;
|
||||
using SlotCount = SlotId;
|
||||
const SlotId NULL_SLOT = SlotId(-1);
|
||||
|
||||
class SlotWithId {
|
||||
public:
|
||||
SlotWithId() : slot_(nullptr), id_(NULL_SLOT) {}
|
||||
SlotWithId(VariantSlot* slot, SlotId id) : slot_(slot), id_(id) {
|
||||
ARDUINOJSON_ASSERT((slot == nullptr) == (id == NULL_SLOT));
|
||||
}
|
||||
|
||||
SlotId id() const {
|
||||
return id_;
|
||||
}
|
||||
|
||||
operator VariantSlot*() {
|
||||
return slot_;
|
||||
}
|
||||
|
||||
VariantSlot* operator->() {
|
||||
ARDUINOJSON_ASSERT(slot_ != nullptr);
|
||||
return slot_;
|
||||
}
|
||||
|
||||
private:
|
||||
VariantSlot* slot_;
|
||||
SlotId id_;
|
||||
};
|
||||
|
||||
class VariantPool {
|
||||
public:
|
||||
void create(SlotCount cap, Allocator* allocator);
|
||||
void destroy(Allocator* allocator);
|
||||
|
||||
SlotWithId allocSlot();
|
||||
VariantSlot* getSlot(SlotId id) const;
|
||||
void clear();
|
||||
void shrinkToFit(Allocator*);
|
||||
SlotCount usage() const;
|
||||
|
||||
static SlotCount bytesToSlots(size_t);
|
||||
static size_t slotsToBytes(SlotCount);
|
||||
|
||||
private:
|
||||
SlotCount capacity_;
|
||||
SlotCount usage_;
|
||||
VariantSlot* slots_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,81 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/VariantPool.hpp>
|
||||
#include <ArduinoJson/Variant/VariantSlot.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
inline void VariantPool::create(SlotCount cap, Allocator* allocator) {
|
||||
ARDUINOJSON_ASSERT(cap > 0);
|
||||
slots_ =
|
||||
reinterpret_cast<VariantSlot*>(allocator->allocate(slotsToBytes(cap)));
|
||||
capacity_ = slots_ ? cap : 0;
|
||||
usage_ = 0;
|
||||
}
|
||||
|
||||
inline void VariantPool::destroy(Allocator* allocator) {
|
||||
if (slots_)
|
||||
allocator->deallocate(slots_);
|
||||
slots_ = nullptr;
|
||||
capacity_ = 0;
|
||||
usage_ = 0;
|
||||
}
|
||||
|
||||
inline void VariantPool::shrinkToFit(Allocator* allocator) {
|
||||
auto newSlots = reinterpret_cast<VariantSlot*>(
|
||||
allocator->reallocate(slots_, slotsToBytes(usage_)));
|
||||
if (newSlots) {
|
||||
slots_ = newSlots;
|
||||
capacity_ = usage_;
|
||||
}
|
||||
}
|
||||
|
||||
inline SlotWithId VariantPool::allocSlot() {
|
||||
if (!slots_)
|
||||
return {};
|
||||
if (usage_ >= capacity_)
|
||||
return {};
|
||||
auto index = usage_++;
|
||||
auto slot = &slots_[index];
|
||||
return {new (slot) VariantSlot, SlotId(index)};
|
||||
}
|
||||
|
||||
inline VariantSlot* VariantPool::getSlot(SlotId id) const {
|
||||
ARDUINOJSON_ASSERT(id < usage_);
|
||||
return &slots_[id];
|
||||
}
|
||||
|
||||
inline SlotCount VariantPool::usage() const {
|
||||
return usage_;
|
||||
}
|
||||
|
||||
inline void VariantPool::clear() {
|
||||
usage_ = 0;
|
||||
}
|
||||
|
||||
inline SlotCount VariantPool::bytesToSlots(size_t n) {
|
||||
return static_cast<SlotCount>(n / sizeof(VariantSlot));
|
||||
}
|
||||
|
||||
inline size_t VariantPool::slotsToBytes(SlotCount n) {
|
||||
return n * sizeof(VariantSlot);
|
||||
}
|
||||
|
||||
inline SlotWithId VariantPoolList::allocFromFreeList() {
|
||||
ARDUINOJSON_ASSERT(freeList_ != NULL_SLOT);
|
||||
auto id = freeList_;
|
||||
auto slot = getSlot(freeList_);
|
||||
freeList_ = slot->next();
|
||||
return {new (slot) VariantSlot, id};
|
||||
}
|
||||
|
||||
inline void VariantPoolList::freeSlot(SlotWithId slot) {
|
||||
slot->setNext(freeList_);
|
||||
freeList_ = slot.id();
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,189 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/VariantPool.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
using PoolCount = SlotId;
|
||||
|
||||
class VariantPoolList {
|
||||
public:
|
||||
VariantPoolList() = default;
|
||||
|
||||
~VariantPoolList() {
|
||||
ARDUINOJSON_ASSERT(count_ == 0);
|
||||
}
|
||||
|
||||
friend void swap(VariantPoolList& a, VariantPoolList& b) {
|
||||
bool aUsedPreallocated = a.pools_ == a.preallocatedPools_;
|
||||
bool bUsedPreallocated = b.pools_ == b.preallocatedPools_;
|
||||
|
||||
// Who is using preallocated pools?
|
||||
if (aUsedPreallocated && bUsedPreallocated) {
|
||||
// both of us => swap preallocated pools
|
||||
for (PoolCount i = 0; i < ARDUINOJSON_INITIAL_POOL_COUNT; i++)
|
||||
swap_(a.preallocatedPools_[i], b.preallocatedPools_[i]);
|
||||
} else if (bUsedPreallocated) {
|
||||
// only b => copy b's preallocated pools and give him a's pointer
|
||||
for (PoolCount i = 0; i < b.count_; i++)
|
||||
a.preallocatedPools_[i] = b.preallocatedPools_[i];
|
||||
b.pools_ = a.pools_;
|
||||
a.pools_ = a.preallocatedPools_;
|
||||
} else if (aUsedPreallocated) {
|
||||
// only a => copy a's preallocated pools and give him b's pointer
|
||||
for (PoolCount i = 0; i < a.count_; i++)
|
||||
b.preallocatedPools_[i] = a.preallocatedPools_[i];
|
||||
a.pools_ = b.pools_;
|
||||
b.pools_ = b.preallocatedPools_;
|
||||
} else {
|
||||
// neither => swap pointers
|
||||
swap_(a.pools_, b.pools_);
|
||||
}
|
||||
|
||||
swap_(a.count_, b.count_);
|
||||
swap_(a.capacity_, b.capacity_);
|
||||
swap_(a.freeList_, b.freeList_);
|
||||
}
|
||||
|
||||
VariantPoolList& operator=(VariantPoolList&& src) {
|
||||
ARDUINOJSON_ASSERT(count_ == 0);
|
||||
if (src.pools_ == src.preallocatedPools_) {
|
||||
memcpy(preallocatedPools_, src.preallocatedPools_,
|
||||
sizeof(preallocatedPools_));
|
||||
pools_ = preallocatedPools_;
|
||||
} else {
|
||||
pools_ = src.pools_;
|
||||
src.pools_ = nullptr;
|
||||
}
|
||||
count_ = src.count_;
|
||||
capacity_ = src.capacity_;
|
||||
src.count_ = 0;
|
||||
src.capacity_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SlotWithId allocSlot(Allocator* allocator) {
|
||||
// try to allocate from free list
|
||||
if (freeList_ != NULL_SLOT) {
|
||||
return allocFromFreeList();
|
||||
}
|
||||
|
||||
// try to allocate from last pool (other pools are full)
|
||||
if (count_) {
|
||||
auto slot = allocFromLastPool();
|
||||
if (slot)
|
||||
return slot;
|
||||
}
|
||||
|
||||
// create a new pool and try again
|
||||
auto pool = addPool(allocator);
|
||||
if (!pool)
|
||||
return {};
|
||||
|
||||
return allocFromLastPool();
|
||||
}
|
||||
|
||||
void freeSlot(SlotWithId slot);
|
||||
|
||||
VariantSlot* getSlot(SlotId id) const {
|
||||
if (id == NULL_SLOT)
|
||||
return nullptr;
|
||||
auto poolIndex = SlotId(id / ARDUINOJSON_POOL_CAPACITY);
|
||||
auto indexInPool = SlotId(id % ARDUINOJSON_POOL_CAPACITY);
|
||||
ARDUINOJSON_ASSERT(poolIndex < count_);
|
||||
return pools_[poolIndex].getSlot(indexInPool);
|
||||
}
|
||||
|
||||
void clear(Allocator* allocator) {
|
||||
for (PoolCount i = 0; i < count_; i++)
|
||||
pools_[i].destroy(allocator);
|
||||
count_ = 0;
|
||||
freeList_ = NULL_SLOT;
|
||||
if (pools_ != preallocatedPools_) {
|
||||
allocator->deallocate(pools_);
|
||||
pools_ = preallocatedPools_;
|
||||
capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
SlotCount usage() const {
|
||||
SlotCount total = 0;
|
||||
for (PoolCount i = 0; i < count_; i++)
|
||||
total = SlotCount(total + pools_[i].usage());
|
||||
return total;
|
||||
}
|
||||
|
||||
void shrinkToFit(Allocator* allocator) {
|
||||
if (count_ > 0)
|
||||
pools_[count_ - 1].shrinkToFit(allocator);
|
||||
if (pools_ != preallocatedPools_ && count_ != capacity_) {
|
||||
pools_ = static_cast<VariantPool*>(
|
||||
allocator->reallocate(pools_, count_ * sizeof(VariantPool)));
|
||||
ARDUINOJSON_ASSERT(pools_ != nullptr); // realloc to smaller can't fail
|
||||
capacity_ = count_;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SlotWithId allocFromFreeList();
|
||||
|
||||
SlotWithId allocFromLastPool() {
|
||||
ARDUINOJSON_ASSERT(count_ > 0);
|
||||
auto poolIndex = SlotId(count_ - 1);
|
||||
auto slot = pools_[poolIndex].allocSlot();
|
||||
if (!slot)
|
||||
return {};
|
||||
return {slot, SlotId(poolIndex * ARDUINOJSON_POOL_CAPACITY + slot.id())};
|
||||
}
|
||||
|
||||
VariantPool* addPool(Allocator* allocator) {
|
||||
if (count_ == capacity_ && !increaseCapacity(allocator))
|
||||
return nullptr;
|
||||
auto pool = &pools_[count_++];
|
||||
SlotCount poolCapacity = ARDUINOJSON_POOL_CAPACITY;
|
||||
if (count_ == maxPools) // last pool is smaller because of NULL_SLOT
|
||||
poolCapacity--;
|
||||
pool->create(poolCapacity, allocator);
|
||||
return pool;
|
||||
}
|
||||
|
||||
bool increaseCapacity(Allocator* allocator) {
|
||||
if (capacity_ == maxPools)
|
||||
return false;
|
||||
void* newPools;
|
||||
auto newCapacity = PoolCount(capacity_ * 2);
|
||||
|
||||
if (pools_ == preallocatedPools_) {
|
||||
newPools = allocator->allocate(newCapacity * sizeof(VariantPool));
|
||||
if (!newPools)
|
||||
return false;
|
||||
memcpy(newPools, preallocatedPools_, sizeof(preallocatedPools_));
|
||||
} else {
|
||||
newPools =
|
||||
allocator->reallocate(pools_, newCapacity * sizeof(VariantPool));
|
||||
if (!newPools)
|
||||
return false;
|
||||
}
|
||||
|
||||
pools_ = static_cast<VariantPool*>(newPools);
|
||||
capacity_ = newCapacity;
|
||||
return true;
|
||||
}
|
||||
|
||||
VariantPool preallocatedPools_[ARDUINOJSON_INITIAL_POOL_COUNT];
|
||||
VariantPool* pools_ = preallocatedPools_;
|
||||
PoolCount count_ = 0;
|
||||
PoolCount capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT;
|
||||
SlotId freeList_ = NULL_SLOT;
|
||||
|
||||
public:
|
||||
static const PoolCount maxPools =
|
||||
PoolCount(NULL_SLOT / ARDUINOJSON_POOL_CAPACITY + 1);
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,71 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Strings/StringAdapters.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// A special type of data that can be used to insert pregenerated JSON portions.
|
||||
template <typename T>
|
||||
class SerializedValue {
|
||||
public:
|
||||
explicit SerializedValue(T str) : str_(str) {}
|
||||
operator T() const {
|
||||
return str_;
|
||||
}
|
||||
|
||||
const char* data() const {
|
||||
return str_.c_str();
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
// CAUTION: the old Arduino String doesn't have size()
|
||||
return str_.length();
|
||||
}
|
||||
|
||||
private:
|
||||
T str_;
|
||||
};
|
||||
|
||||
template <typename TChar>
|
||||
class SerializedValue<TChar*> {
|
||||
public:
|
||||
explicit SerializedValue(TChar* p, size_t n) : data_(p), size_(n) {}
|
||||
operator TChar*() const {
|
||||
return data_;
|
||||
}
|
||||
|
||||
TChar* data() const {
|
||||
return data_;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return size_;
|
||||
}
|
||||
|
||||
private:
|
||||
TChar* data_;
|
||||
size_t size_;
|
||||
};
|
||||
|
||||
using RawString = SerializedValue<const char*>;
|
||||
|
||||
template <typename T>
|
||||
inline SerializedValue<T> serialized(T str) {
|
||||
return SerializedValue<T>(str);
|
||||
}
|
||||
|
||||
template <typename TChar>
|
||||
inline SerializedValue<TChar*> serialized(TChar* p) {
|
||||
return SerializedValue<TChar*>(p, detail::adaptString(p).size());
|
||||
}
|
||||
|
||||
template <typename TChar>
|
||||
inline SerializedValue<TChar*> serialized(TChar* p, size_t n) {
|
||||
return SerializedValue<TChar*>(p, n);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,586 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Deserialization/deserialize.hpp>
|
||||
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||
#include <ArduinoJson/MsgPack/endianess.hpp>
|
||||
#include <ArduinoJson/MsgPack/ieee754.hpp>
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TReader>
|
||||
class MsgPackDeserializer {
|
||||
public:
|
||||
MsgPackDeserializer(ResourceManager* resources, TReader reader)
|
||||
: resources_(resources),
|
||||
reader_(reader),
|
||||
stringBuilder_(resources),
|
||||
foundSomething_(false) {}
|
||||
|
||||
template <typename TFilter>
|
||||
DeserializationError parse(VariantData& variant, TFilter filter,
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
err = parseVariant(&variant, filter, nestingLimit);
|
||||
return foundSomething_ ? err : DeserializationError::EmptyInput;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename TFilter>
|
||||
DeserializationError::Code parseVariant(
|
||||
VariantData* variant, TFilter filter,
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
uint8_t code = 0; // TODO: why do we need to initialize this variable?
|
||||
err = readByte(code);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
foundSomething_ = true;
|
||||
|
||||
bool allowValue = filter.allowValue();
|
||||
|
||||
if (allowValue) {
|
||||
// callers pass a null pointer only when value must be ignored
|
||||
ARDUINOJSON_ASSERT(variant != 0);
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
case 0xc0:
|
||||
// already null
|
||||
return DeserializationError::Ok;
|
||||
|
||||
case 0xc1:
|
||||
return DeserializationError::InvalidInput;
|
||||
|
||||
case 0xc2:
|
||||
if (allowValue)
|
||||
variant->setBoolean(false);
|
||||
return DeserializationError::Ok;
|
||||
|
||||
case 0xc3:
|
||||
if (allowValue)
|
||||
variant->setBoolean(true);
|
||||
return DeserializationError::Ok;
|
||||
|
||||
case 0xc4: // bin 8 (not supported)
|
||||
return skipString<uint8_t>();
|
||||
|
||||
case 0xc5: // bin 16 (not supported)
|
||||
return skipString<uint16_t>();
|
||||
|
||||
case 0xc6: // bin 32 (not supported)
|
||||
return skipString<uint32_t>();
|
||||
|
||||
case 0xc7: // ext 8 (not supported)
|
||||
return skipExt<uint8_t>();
|
||||
|
||||
case 0xc8: // ext 16 (not supported)
|
||||
return skipExt<uint16_t>();
|
||||
|
||||
case 0xc9: // ext 32 (not supported)
|
||||
return skipExt<uint32_t>();
|
||||
|
||||
case 0xca:
|
||||
if (allowValue)
|
||||
return readFloat<float>(variant);
|
||||
else
|
||||
return skipBytes(4);
|
||||
|
||||
case 0xcb:
|
||||
if (allowValue)
|
||||
return readDouble<double>(variant);
|
||||
else
|
||||
return skipBytes(8);
|
||||
|
||||
case 0xcc:
|
||||
if (allowValue)
|
||||
return readInteger<uint8_t>(variant);
|
||||
else
|
||||
return skipBytes(1);
|
||||
|
||||
case 0xcd:
|
||||
if (allowValue)
|
||||
return readInteger<uint16_t>(variant);
|
||||
else
|
||||
return skipBytes(2);
|
||||
|
||||
case 0xce:
|
||||
if (allowValue)
|
||||
return readInteger<uint32_t>(variant);
|
||||
else
|
||||
return skipBytes(4);
|
||||
|
||||
case 0xcf:
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
if (allowValue)
|
||||
return readInteger<uint64_t>(variant);
|
||||
else
|
||||
return skipBytes(8);
|
||||
#else
|
||||
return skipBytes(8); // not supported
|
||||
#endif
|
||||
|
||||
case 0xd0:
|
||||
if (allowValue)
|
||||
return readInteger<int8_t>(variant);
|
||||
else
|
||||
return skipBytes(1);
|
||||
|
||||
case 0xd1:
|
||||
if (allowValue)
|
||||
return readInteger<int16_t>(variant);
|
||||
else
|
||||
return skipBytes(2);
|
||||
|
||||
case 0xd2:
|
||||
if (allowValue)
|
||||
return readInteger<int32_t>(variant);
|
||||
else
|
||||
return skipBytes(4);
|
||||
|
||||
case 0xd3:
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
if (allowValue)
|
||||
return readInteger<int64_t>(variant);
|
||||
else
|
||||
return skipBytes(8); // not supported
|
||||
#else
|
||||
return skipBytes(8);
|
||||
#endif
|
||||
|
||||
case 0xd4: // fixext 1 (not supported)
|
||||
return skipBytes(2);
|
||||
|
||||
case 0xd5: // fixext 2 (not supported)
|
||||
return skipBytes(3);
|
||||
|
||||
case 0xd6: // fixext 4 (not supported)
|
||||
return skipBytes(5);
|
||||
|
||||
case 0xd7: // fixext 8 (not supported)
|
||||
return skipBytes(9);
|
||||
|
||||
case 0xd8: // fixext 16 (not supported)
|
||||
return skipBytes(17);
|
||||
|
||||
case 0xd9:
|
||||
if (allowValue)
|
||||
return readString<uint8_t>(variant);
|
||||
else
|
||||
return skipString<uint8_t>();
|
||||
|
||||
case 0xda:
|
||||
if (allowValue)
|
||||
return readString<uint16_t>(variant);
|
||||
else
|
||||
return skipString<uint16_t>();
|
||||
|
||||
case 0xdb:
|
||||
if (allowValue)
|
||||
return readString<uint32_t>(variant);
|
||||
else
|
||||
return skipString<uint32_t>();
|
||||
|
||||
case 0xdc:
|
||||
return readArray<uint16_t>(variant, filter, nestingLimit);
|
||||
|
||||
case 0xdd:
|
||||
return readArray<uint32_t>(variant, filter, nestingLimit);
|
||||
|
||||
case 0xde:
|
||||
return readObject<uint16_t>(variant, filter, nestingLimit);
|
||||
|
||||
case 0xdf:
|
||||
return readObject<uint32_t>(variant, filter, nestingLimit);
|
||||
}
|
||||
|
||||
switch (code & 0xf0) {
|
||||
case 0x80:
|
||||
return readObject(variant, code & 0x0F, filter, nestingLimit);
|
||||
|
||||
case 0x90:
|
||||
return readArray(variant, code & 0x0F, filter, nestingLimit);
|
||||
}
|
||||
|
||||
if ((code & 0xe0) == 0xa0) {
|
||||
if (allowValue)
|
||||
return readString(variant, code & 0x1f);
|
||||
else
|
||||
return skipBytes(code & 0x1f);
|
||||
}
|
||||
|
||||
if (allowValue)
|
||||
variant->setInteger(static_cast<int8_t>(code));
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
DeserializationError::Code readByte(uint8_t& value) {
|
||||
int c = reader_.read();
|
||||
if (c < 0)
|
||||
return DeserializationError::IncompleteInput;
|
||||
value = static_cast<uint8_t>(c);
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
DeserializationError::Code readBytes(uint8_t* p, size_t n) {
|
||||
if (reader_.readBytes(reinterpret_cast<char*>(p), n) == n)
|
||||
return DeserializationError::Ok;
|
||||
return DeserializationError::IncompleteInput;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DeserializationError::Code readBytes(T& value) {
|
||||
return readBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
|
||||
}
|
||||
|
||||
DeserializationError::Code skipBytes(size_t n) {
|
||||
for (; n; --n) {
|
||||
if (reader_.read() < 0)
|
||||
return DeserializationError::IncompleteInput;
|
||||
}
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DeserializationError::Code readInteger(T& value) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
err = readBytes(value);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
fixEndianess(value);
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DeserializationError::Code readInteger(VariantData* variant) {
|
||||
DeserializationError::Code err;
|
||||
T value;
|
||||
|
||||
err = readInteger(value);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
variant->setInteger(value);
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 4, DeserializationError::Code>::type
|
||||
readFloat(VariantData* variant) {
|
||||
DeserializationError::Code err;
|
||||
T value;
|
||||
|
||||
err = readBytes(value);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
fixEndianess(value);
|
||||
variant->setFloat(value);
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 8, DeserializationError::Code>::type
|
||||
readDouble(VariantData* variant) {
|
||||
DeserializationError::Code err;
|
||||
T value;
|
||||
|
||||
err = readBytes(value);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
fixEndianess(value);
|
||||
variant->setFloat(value);
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 4, DeserializationError::Code>::type
|
||||
readDouble(VariantData* variant) {
|
||||
DeserializationError::Code err;
|
||||
uint8_t i[8]; // input is 8 bytes
|
||||
T value; // output is 4 bytes
|
||||
uint8_t* o = reinterpret_cast<uint8_t*>(&value);
|
||||
|
||||
err = readBytes(i, 8);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
doubleToFloat(i, o);
|
||||
fixEndianess(value);
|
||||
variant->setFloat(value);
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DeserializationError::Code readString(VariantData* variant) {
|
||||
DeserializationError::Code err;
|
||||
T size;
|
||||
|
||||
err = readInteger(size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return readString(variant, size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DeserializationError::Code readString() {
|
||||
DeserializationError::Code err;
|
||||
T size;
|
||||
|
||||
err = readInteger(size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return readString(size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DeserializationError::Code skipString() {
|
||||
DeserializationError::Code err;
|
||||
T size;
|
||||
|
||||
err = readInteger(size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return skipBytes(size);
|
||||
}
|
||||
|
||||
DeserializationError::Code readString(VariantData* variant, size_t n) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
err = readString(n);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
variant->setOwnedString(stringBuilder_.save());
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
DeserializationError::Code readString(size_t n) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
stringBuilder_.startString();
|
||||
for (; n; --n) {
|
||||
uint8_t c;
|
||||
|
||||
err = readBytes(c);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
stringBuilder_.append(static_cast<char>(c));
|
||||
}
|
||||
|
||||
if (!stringBuilder_.isValid())
|
||||
return DeserializationError::NoMemory;
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename TSize, typename TFilter>
|
||||
DeserializationError::Code readArray(
|
||||
VariantData* variant, TFilter filter,
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
TSize size;
|
||||
|
||||
err = readInteger(size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return readArray(variant, size, filter, nestingLimit);
|
||||
}
|
||||
|
||||
template <typename TFilter>
|
||||
DeserializationError::Code readArray(
|
||||
VariantData* variant, size_t n, TFilter filter,
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
if (nestingLimit.reached())
|
||||
return DeserializationError::TooDeep;
|
||||
|
||||
bool allowArray = filter.allowArray();
|
||||
|
||||
ArrayData* array;
|
||||
if (allowArray) {
|
||||
ARDUINOJSON_ASSERT(variant != 0);
|
||||
array = &variant->toArray();
|
||||
} else {
|
||||
array = 0;
|
||||
}
|
||||
|
||||
TFilter elementFilter = filter[0U];
|
||||
|
||||
for (; n; --n) {
|
||||
VariantData* value;
|
||||
|
||||
if (elementFilter.allow()) {
|
||||
ARDUINOJSON_ASSERT(array != 0);
|
||||
value = array->addElement(resources_);
|
||||
if (!value)
|
||||
return DeserializationError::NoMemory;
|
||||
} else {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
err = parseVariant(value, elementFilter, nestingLimit.decrement());
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename TSize, typename TFilter>
|
||||
DeserializationError::Code readObject(
|
||||
VariantData* variant, TFilter filter,
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
TSize size;
|
||||
|
||||
err = readInteger(size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return readObject(variant, size, filter, nestingLimit);
|
||||
}
|
||||
|
||||
template <typename TFilter>
|
||||
DeserializationError::Code readObject(
|
||||
VariantData* variant, size_t n, TFilter filter,
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
if (nestingLimit.reached())
|
||||
return DeserializationError::TooDeep;
|
||||
|
||||
ObjectData* object;
|
||||
if (filter.allowObject()) {
|
||||
ARDUINOJSON_ASSERT(variant != 0);
|
||||
object = &variant->toObject();
|
||||
} else {
|
||||
object = 0;
|
||||
}
|
||||
|
||||
for (; n; --n) {
|
||||
err = readKey();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
JsonString key = stringBuilder_.str();
|
||||
TFilter memberFilter = filter[key.c_str()];
|
||||
VariantData* member;
|
||||
|
||||
if (memberFilter.allow()) {
|
||||
ARDUINOJSON_ASSERT(object != 0);
|
||||
|
||||
// Save key in memory pool.
|
||||
auto savedKey = stringBuilder_.save();
|
||||
|
||||
member = object->addMember(savedKey, resources_);
|
||||
if (!member)
|
||||
return DeserializationError::NoMemory;
|
||||
} else {
|
||||
member = 0;
|
||||
}
|
||||
|
||||
err = parseVariant(member, memberFilter, nestingLimit.decrement());
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
DeserializationError::Code readKey() {
|
||||
DeserializationError::Code err;
|
||||
uint8_t code;
|
||||
|
||||
err = readByte(code);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((code & 0xe0) == 0xa0)
|
||||
return readString(code & 0x1f);
|
||||
|
||||
switch (code) {
|
||||
case 0xd9:
|
||||
return readString<uint8_t>();
|
||||
|
||||
case 0xda:
|
||||
return readString<uint16_t>();
|
||||
|
||||
case 0xdb:
|
||||
return readString<uint32_t>();
|
||||
|
||||
default:
|
||||
return DeserializationError::InvalidInput;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DeserializationError::Code skipExt() {
|
||||
DeserializationError::Code err;
|
||||
T size;
|
||||
|
||||
err = readInteger(size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return skipBytes(size + 1U);
|
||||
}
|
||||
|
||||
ResourceManager* resources_;
|
||||
TReader reader_;
|
||||
StringBuilder stringBuilder_;
|
||||
bool foundSomething_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Parses a MessagePack input and puts the result in a JsonDocument.
|
||||
// https://arduinojson.org/v7/api/msgpack/deserializemsgpack/
|
||||
template <typename TDestination, typename... Args>
|
||||
typename detail::enable_if<
|
||||
detail::is_deserialize_destination<TDestination>::value,
|
||||
DeserializationError>::type
|
||||
deserializeMsgPack(TDestination&& dst, Args&&... args) {
|
||||
using namespace detail;
|
||||
return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
|
||||
detail::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Parses a MessagePack input and puts the result in a JsonDocument.
|
||||
// https://arduinojson.org/v7/api/msgpack/deserializemsgpack/
|
||||
template <typename TDestination, typename TChar, typename... Args>
|
||||
typename detail::enable_if<
|
||||
detail::is_deserialize_destination<TDestination>::value,
|
||||
DeserializationError>::type
|
||||
deserializeMsgPack(TDestination&& dst, TChar* input, Args&&... args) {
|
||||
using namespace detail;
|
||||
return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
|
||||
input,
|
||||
detail::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,244 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/MsgPack/endianess.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
#include <ArduinoJson/Serialization/CountingDecorator.hpp>
|
||||
#include <ArduinoJson/Serialization/measure.hpp>
|
||||
#include <ArduinoJson/Serialization/serialize.hpp>
|
||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TWriter>
|
||||
class MsgPackSerializer : public VariantDataVisitor<size_t> {
|
||||
public:
|
||||
static const bool producesText = false;
|
||||
|
||||
MsgPackSerializer(TWriter writer, const ResourceManager* resources)
|
||||
: writer_(writer), resources_(resources) {}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<is_floating_point<T>::value && sizeof(T) == 4,
|
||||
size_t>::type
|
||||
visit(T value32) {
|
||||
if (canConvertNumber<JsonInteger>(value32)) {
|
||||
JsonInteger truncatedValue = JsonInteger(value32);
|
||||
if (value32 == T(truncatedValue))
|
||||
return visit(truncatedValue);
|
||||
}
|
||||
writeByte(0xCA);
|
||||
writeInteger(value32);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ARDUINOJSON_NO_SANITIZE("float-cast-overflow")
|
||||
typename enable_if<is_floating_point<T>::value && sizeof(T) == 8,
|
||||
size_t>::type visit(T value64) {
|
||||
float value32 = float(value64);
|
||||
if (value32 == value64)
|
||||
return visit(value32);
|
||||
writeByte(0xCB);
|
||||
writeInteger(value64);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(const ArrayData& array) {
|
||||
size_t n = array.size(resources_);
|
||||
if (n < 0x10) {
|
||||
writeByte(uint8_t(0x90 + n));
|
||||
} else if (n < 0x10000) {
|
||||
writeByte(0xDC);
|
||||
writeInteger(uint16_t(n));
|
||||
} else {
|
||||
writeByte(0xDD);
|
||||
writeInteger(uint32_t(n));
|
||||
}
|
||||
|
||||
auto slotId = array.head();
|
||||
while (slotId != NULL_SLOT) {
|
||||
auto slot = resources_->getSlot(slotId);
|
||||
slot->data()->accept(*this);
|
||||
slotId = slot->next();
|
||||
}
|
||||
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(const ObjectData& object) {
|
||||
size_t n = object.size(resources_);
|
||||
if (n < 0x10) {
|
||||
writeByte(uint8_t(0x80 + n));
|
||||
} else if (n < 0x10000) {
|
||||
writeByte(0xDE);
|
||||
writeInteger(uint16_t(n));
|
||||
} else {
|
||||
writeByte(0xDF);
|
||||
writeInteger(uint32_t(n));
|
||||
}
|
||||
|
||||
auto slotId = object.head();
|
||||
while (slotId != NULL_SLOT) {
|
||||
auto slot = resources_->getSlot(slotId);
|
||||
visit(slot->key());
|
||||
slot->data()->accept(*this);
|
||||
slotId = slot->next();
|
||||
}
|
||||
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(const char* value) {
|
||||
return visit(JsonString(value));
|
||||
}
|
||||
|
||||
size_t visit(JsonString value) {
|
||||
ARDUINOJSON_ASSERT(value != NULL);
|
||||
|
||||
auto n = value.size();
|
||||
|
||||
if (n < 0x20) {
|
||||
writeByte(uint8_t(0xA0 + n));
|
||||
} else if (n < 0x100) {
|
||||
writeByte(0xD9);
|
||||
writeInteger(uint8_t(n));
|
||||
} else if (n < 0x10000) {
|
||||
writeByte(0xDA);
|
||||
writeInteger(uint16_t(n));
|
||||
} else {
|
||||
writeByte(0xDB);
|
||||
writeInteger(uint32_t(n));
|
||||
}
|
||||
writeBytes(reinterpret_cast<const uint8_t*>(value.c_str()), n);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(RawString value) {
|
||||
writeBytes(reinterpret_cast<const uint8_t*>(value.data()), value.size());
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(JsonInteger value) {
|
||||
if (value > 0) {
|
||||
visit(static_cast<JsonUInt>(value));
|
||||
} else if (value >= -0x20) {
|
||||
writeInteger(int8_t(value));
|
||||
} else if (value >= -0x80) {
|
||||
writeByte(0xD0);
|
||||
writeInteger(int8_t(value));
|
||||
} else if (value >= -0x8000) {
|
||||
writeByte(0xD1);
|
||||
writeInteger(int16_t(value));
|
||||
}
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
else if (value >= -0x80000000LL)
|
||||
#else
|
||||
else
|
||||
#endif
|
||||
{
|
||||
writeByte(0xD2);
|
||||
writeInteger(int32_t(value));
|
||||
}
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
else {
|
||||
writeByte(0xD3);
|
||||
writeInteger(int64_t(value));
|
||||
}
|
||||
#endif
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(JsonUInt value) {
|
||||
if (value <= 0x7F) {
|
||||
writeInteger(uint8_t(value));
|
||||
} else if (value <= 0xFF) {
|
||||
writeByte(0xCC);
|
||||
writeInteger(uint8_t(value));
|
||||
} else if (value <= 0xFFFF) {
|
||||
writeByte(0xCD);
|
||||
writeInteger(uint16_t(value));
|
||||
}
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
else if (value <= 0xFFFFFFFF)
|
||||
#else
|
||||
else
|
||||
#endif
|
||||
{
|
||||
writeByte(0xCE);
|
||||
writeInteger(uint32_t(value));
|
||||
}
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
else {
|
||||
writeByte(0xCF);
|
||||
writeInteger(uint64_t(value));
|
||||
}
|
||||
#endif
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(bool value) {
|
||||
writeByte(value ? 0xC3 : 0xC2);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(nullptr_t) {
|
||||
writeByte(0xC0);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
private:
|
||||
size_t bytesWritten() const {
|
||||
return writer_.count();
|
||||
}
|
||||
|
||||
void writeByte(uint8_t c) {
|
||||
writer_.write(c);
|
||||
}
|
||||
|
||||
void writeBytes(const uint8_t* p, size_t n) {
|
||||
writer_.write(p, n);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void writeInteger(T value) {
|
||||
fixEndianess(value);
|
||||
writeBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
|
||||
}
|
||||
|
||||
CountingDecorator<TWriter> writer_;
|
||||
const ResourceManager* resources_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Produces a MessagePack document.
|
||||
// https://arduinojson.org/v7/api/msgpack/serializemsgpack/
|
||||
template <typename TDestination>
|
||||
inline size_t serializeMsgPack(JsonVariantConst source, TDestination& output) {
|
||||
using namespace ArduinoJson::detail;
|
||||
return serialize<MsgPackSerializer>(source, output);
|
||||
}
|
||||
|
||||
// Produces a MessagePack document.
|
||||
// https://arduinojson.org/v7/api/msgpack/serializemsgpack/
|
||||
inline size_t serializeMsgPack(JsonVariantConst source, void* output,
|
||||
size_t size) {
|
||||
using namespace ArduinoJson::detail;
|
||||
return serialize<MsgPackSerializer>(source, output, size);
|
||||
}
|
||||
|
||||
// Computes the length of the document that serializeMsgPack() produces.
|
||||
// https://arduinojson.org/v7/api/msgpack/measuremsgpack/
|
||||
inline size_t measureMsgPack(JsonVariantConst source) {
|
||||
using namespace ArduinoJson::detail;
|
||||
return measure<MsgPackSerializer>(source);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,46 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
#if ARDUINOJSON_LITTLE_ENDIAN
|
||||
inline void swapBytes(uint8_t& a, uint8_t& b) {
|
||||
uint8_t t(a);
|
||||
a = b;
|
||||
b = t;
|
||||
}
|
||||
|
||||
inline void fixEndianess(uint8_t* p, integral_constant<size_t, 8>) {
|
||||
swapBytes(p[0], p[7]);
|
||||
swapBytes(p[1], p[6]);
|
||||
swapBytes(p[2], p[5]);
|
||||
swapBytes(p[3], p[4]);
|
||||
}
|
||||
|
||||
inline void fixEndianess(uint8_t* p, integral_constant<size_t, 4>) {
|
||||
swapBytes(p[0], p[3]);
|
||||
swapBytes(p[1], p[2]);
|
||||
}
|
||||
|
||||
inline void fixEndianess(uint8_t* p, integral_constant<size_t, 2>) {
|
||||
swapBytes(p[0], p[1]);
|
||||
}
|
||||
|
||||
inline void fixEndianess(uint8_t*, integral_constant<size_t, 1>) {}
|
||||
|
||||
template <typename T>
|
||||
inline void fixEndianess(T& value) {
|
||||
fixEndianess(reinterpret_cast<uint8_t*>(&value),
|
||||
integral_constant<size_t, sizeof(T)>());
|
||||
}
|
||||
#else
|
||||
template <typename T>
|
||||
inline void fixEndianess(T&) {}
|
||||
#endif
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,18 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
inline void doubleToFloat(const uint8_t d[8], uint8_t f[4]) {
|
||||
f[0] = uint8_t((d[0] & 0xC0) | (d[0] << 3 & 0x3f) | (d[1] >> 5));
|
||||
f[1] = uint8_t((d[1] << 3) | (d[2] >> 5));
|
||||
f[2] = uint8_t((d[2] << 3) | (d[3] >> 5));
|
||||
f[3] = uint8_t((d[3] << 3) | (d[4] >> 5));
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,42 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Configuration.hpp>
|
||||
#include <ArduinoJson/Polyfills/preprocessor.hpp>
|
||||
#include <ArduinoJson/version.hpp>
|
||||
|
||||
#ifndef ARDUINOJSON_VERSION_NAMESPACE
|
||||
|
||||
# define ARDUINOJSON_VERSION_NAMESPACE \
|
||||
ARDUINOJSON_CONCAT4(ARDUINOJSON_VERSION_MACRO, \
|
||||
ARDUINOJSON_BIN2ALPHA(ARDUINOJSON_ENABLE_PROGMEM, \
|
||||
ARDUINOJSON_USE_LONG_LONG, \
|
||||
ARDUINOJSON_USE_DOUBLE, 1), \
|
||||
ARDUINOJSON_BIN2ALPHA(ARDUINOJSON_ENABLE_NAN, \
|
||||
ARDUINOJSON_ENABLE_INFINITY, \
|
||||
ARDUINOJSON_ENABLE_COMMENTS, \
|
||||
ARDUINOJSON_DECODE_UNICODE), \
|
||||
ARDUINOJSON_SLOT_ID_SIZE)
|
||||
|
||||
#endif
|
||||
|
||||
#define ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE \
|
||||
namespace ArduinoJson { \
|
||||
inline namespace ARDUINOJSON_VERSION_NAMESPACE {
|
||||
|
||||
#define ARDUINOJSON_END_PUBLIC_NAMESPACE \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE \
|
||||
namespace ArduinoJson { \
|
||||
inline namespace ARDUINOJSON_VERSION_NAMESPACE { \
|
||||
namespace detail {
|
||||
|
||||
#define ARDUINOJSON_END_PRIVATE_NAMESPACE \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Configuration.hpp>
|
||||
#include <ArduinoJson/Numbers/FloatTraits.hpp>
|
||||
#include <ArduinoJson/Polyfills/math.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TFloat>
|
||||
struct FloatParts {
|
||||
uint32_t integral;
|
||||
uint32_t decimal;
|
||||
int16_t exponent;
|
||||
int8_t decimalPlaces;
|
||||
|
||||
FloatParts(TFloat value) {
|
||||
uint32_t maxDecimalPart = sizeof(TFloat) >= 8 ? 1000000000 : 1000000;
|
||||
decimalPlaces = sizeof(TFloat) >= 8 ? 9 : 6;
|
||||
|
||||
exponent = normalize(value);
|
||||
|
||||
integral = uint32_t(value);
|
||||
// reduce number of decimal places by the number of integral places
|
||||
for (uint32_t tmp = integral; tmp >= 10; tmp /= 10) {
|
||||
maxDecimalPart /= 10;
|
||||
decimalPlaces--;
|
||||
}
|
||||
|
||||
TFloat remainder = (value - TFloat(integral)) * TFloat(maxDecimalPart);
|
||||
|
||||
decimal = uint32_t(remainder);
|
||||
remainder = remainder - TFloat(decimal);
|
||||
|
||||
// rounding:
|
||||
// increment by 1 if remainder >= 0.5
|
||||
decimal += uint32_t(remainder * 2);
|
||||
if (decimal >= maxDecimalPart) {
|
||||
decimal = 0;
|
||||
integral++;
|
||||
if (exponent && integral >= 10) {
|
||||
exponent++;
|
||||
integral = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// remove trailing zeros
|
||||
while (decimal % 10 == 0 && decimalPlaces > 0) {
|
||||
decimal /= 10;
|
||||
decimalPlaces--;
|
||||
}
|
||||
}
|
||||
|
||||
static int16_t normalize(TFloat& value) {
|
||||
typedef FloatTraits<TFloat> traits;
|
||||
int16_t powersOf10 = 0;
|
||||
|
||||
int8_t index = sizeof(TFloat) == 8 ? 8 : 5;
|
||||
int bit = 1 << index;
|
||||
|
||||
if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) {
|
||||
for (; index >= 0; index--) {
|
||||
if (value >= traits::positiveBinaryPowersOfTen()[index]) {
|
||||
value *= traits::negativeBinaryPowersOfTen()[index];
|
||||
powersOf10 = int16_t(powersOf10 + bit);
|
||||
}
|
||||
bit >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) {
|
||||
for (; index >= 0; index--) {
|
||||
if (value < traits::negativeBinaryPowersOfTen()[index] * 10) {
|
||||
value *= traits::positiveBinaryPowersOfTen()[index];
|
||||
powersOf10 = int16_t(powersOf10 - bit);
|
||||
}
|
||||
bit >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return powersOf10;
|
||||
}
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,212 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h> // for size_t
|
||||
#include <stdint.h>
|
||||
|
||||
#include <ArduinoJson/Configuration.hpp>
|
||||
#include <ArduinoJson/Polyfills/alias_cast.hpp>
|
||||
#include <ArduinoJson/Polyfills/math.hpp>
|
||||
#include <ArduinoJson/Polyfills/pgmspace_generic.hpp>
|
||||
#include <ArduinoJson/Polyfills/preprocessor.hpp>
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename T, size_t = sizeof(T)>
|
||||
struct FloatTraits {};
|
||||
|
||||
template <typename T>
|
||||
struct FloatTraits<T, 8 /*64bits*/> {
|
||||
typedef uint64_t mantissa_type;
|
||||
static const short mantissa_bits = 52;
|
||||
static const mantissa_type mantissa_max =
|
||||
(mantissa_type(1) << mantissa_bits) - 1;
|
||||
|
||||
typedef int16_t exponent_type;
|
||||
static const exponent_type exponent_max = 308;
|
||||
|
||||
static pgm_ptr<T> positiveBinaryPowersOfTen() {
|
||||
ARDUINOJSON_DEFINE_PROGMEM_ARRAY( //
|
||||
uint64_t, factors,
|
||||
{
|
||||
0x4024000000000000, // 1e1
|
||||
0x4059000000000000, // 1e2
|
||||
0x40C3880000000000, // 1e4
|
||||
0x4197D78400000000, // 1e8
|
||||
0x4341C37937E08000, // 1e16
|
||||
0x4693B8B5B5056E17, // 1e32
|
||||
0x4D384F03E93FF9F5, // 1e64
|
||||
0x5A827748F9301D32, // 1e128
|
||||
0x75154FDD7F73BF3C, // 1e256
|
||||
});
|
||||
return pgm_ptr<T>(reinterpret_cast<const T*>(factors));
|
||||
}
|
||||
|
||||
static pgm_ptr<T> negativeBinaryPowersOfTen() {
|
||||
ARDUINOJSON_DEFINE_PROGMEM_ARRAY( //
|
||||
uint64_t, factors,
|
||||
{
|
||||
0x3FB999999999999A, // 1e-1
|
||||
0x3F847AE147AE147B, // 1e-2
|
||||
0x3F1A36E2EB1C432D, // 1e-4
|
||||
0x3E45798EE2308C3A, // 1e-8
|
||||
0x3C9CD2B297D889BC, // 1e-16
|
||||
0x3949F623D5A8A733, // 1e-32
|
||||
0x32A50FFD44F4A73D, // 1e-64
|
||||
0x255BBA08CF8C979D, // 1e-128
|
||||
0x0AC8062864AC6F43 // 1e-256
|
||||
});
|
||||
return pgm_ptr<T>(reinterpret_cast<const T*>(factors));
|
||||
}
|
||||
|
||||
static T nan() {
|
||||
return forge(0x7ff8000000000000);
|
||||
}
|
||||
|
||||
static T inf() {
|
||||
return forge(0x7ff0000000000000);
|
||||
}
|
||||
|
||||
static T highest() {
|
||||
return forge(0x7FEFFFFFFFFFFFFF);
|
||||
}
|
||||
|
||||
template <typename TOut> // int64_t
|
||||
static T highest_for(
|
||||
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||
sizeof(TOut) == 8,
|
||||
signed>::type* = 0) {
|
||||
return forge(0x43DFFFFFFFFFFFFF); // 9.2233720368547748e+18
|
||||
}
|
||||
|
||||
template <typename TOut> // uint64_t
|
||||
static T highest_for(
|
||||
typename enable_if<is_integral<TOut>::value && is_unsigned<TOut>::value &&
|
||||
sizeof(TOut) == 8,
|
||||
unsigned>::type* = 0) {
|
||||
return forge(0x43EFFFFFFFFFFFFF); // 1.8446744073709549568e+19
|
||||
}
|
||||
|
||||
static T lowest() {
|
||||
return forge(0xFFEFFFFFFFFFFFFF);
|
||||
}
|
||||
|
||||
// constructs a double floating point values from its binary representation
|
||||
// we use this function to workaround platforms with single precision literals
|
||||
// (for example, when -fsingle-precision-constant is passed to GCC)
|
||||
static T forge(uint64_t bits) {
|
||||
return alias_cast<T>(bits);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct FloatTraits<T, 4 /*32bits*/> {
|
||||
typedef uint32_t mantissa_type;
|
||||
static const short mantissa_bits = 23;
|
||||
static const mantissa_type mantissa_max =
|
||||
(mantissa_type(1) << mantissa_bits) - 1;
|
||||
|
||||
typedef int8_t exponent_type;
|
||||
static const exponent_type exponent_max = 38;
|
||||
|
||||
static pgm_ptr<T> positiveBinaryPowersOfTen() {
|
||||
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(uint32_t, factors,
|
||||
{
|
||||
0x41200000, // 1e1f
|
||||
0x42c80000, // 1e2f
|
||||
0x461c4000, // 1e4f
|
||||
0x4cbebc20, // 1e8f
|
||||
0x5a0e1bca, // 1e16f
|
||||
0x749dc5ae // 1e32f
|
||||
});
|
||||
return pgm_ptr<T>(reinterpret_cast<const T*>(factors));
|
||||
}
|
||||
|
||||
static pgm_ptr<T> negativeBinaryPowersOfTen() {
|
||||
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(uint32_t, factors,
|
||||
{
|
||||
0x3dcccccd, // 1e-1f
|
||||
0x3c23d70a, // 1e-2f
|
||||
0x38d1b717, // 1e-4f
|
||||
0x322bcc77, // 1e-8f
|
||||
0x24e69595, // 1e-16f
|
||||
0x0a4fb11f // 1e-32f
|
||||
});
|
||||
return pgm_ptr<T>(reinterpret_cast<const T*>(factors));
|
||||
}
|
||||
|
||||
static T forge(uint32_t bits) {
|
||||
return alias_cast<T>(bits);
|
||||
}
|
||||
|
||||
static T nan() {
|
||||
return forge(0x7fc00000);
|
||||
}
|
||||
|
||||
static T inf() {
|
||||
return forge(0x7f800000);
|
||||
}
|
||||
|
||||
static T highest() {
|
||||
return forge(0x7f7fffff);
|
||||
}
|
||||
|
||||
template <typename TOut> // int32_t
|
||||
static T highest_for(
|
||||
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||
sizeof(TOut) == 4,
|
||||
signed>::type* = 0) {
|
||||
return forge(0x4EFFFFFF); // 2.14748352E9
|
||||
}
|
||||
|
||||
template <typename TOut> // uint32_t
|
||||
static T highest_for(
|
||||
typename enable_if<is_integral<TOut>::value && is_unsigned<TOut>::value &&
|
||||
sizeof(TOut) == 4,
|
||||
unsigned>::type* = 0) {
|
||||
return forge(0x4F7FFFFF); // 4.29496704E9
|
||||
}
|
||||
|
||||
template <typename TOut> // int64_t
|
||||
static T highest_for(
|
||||
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||
sizeof(TOut) == 8,
|
||||
signed>::type* = 0) {
|
||||
return forge(0x5EFFFFFF); // 9.22337148709896192E18
|
||||
}
|
||||
|
||||
template <typename TOut> // uint64_t
|
||||
static T highest_for(
|
||||
typename enable_if<is_integral<TOut>::value && is_unsigned<TOut>::value &&
|
||||
sizeof(TOut) == 8,
|
||||
unsigned>::type* = 0) {
|
||||
return forge(0x5F7FFFFF); // 1.844674297419792384E19
|
||||
}
|
||||
|
||||
static T lowest() {
|
||||
return forge(0xFf7fffff);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TFloat, typename TExponent>
|
||||
inline TFloat make_float(TFloat m, TExponent e) {
|
||||
using traits = FloatTraits<TFloat>;
|
||||
|
||||
auto powersOfTen = e > 0 ? traits::positiveBinaryPowersOfTen()
|
||||
: traits::negativeBinaryPowersOfTen();
|
||||
if (e <= 0)
|
||||
e = TExponent(-e);
|
||||
|
||||
for (uint8_t index = 0; e != 0; index++) {
|
||||
if (e & 1)
|
||||
m *= powersOfTen[index];
|
||||
e >>= 1;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,18 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Configuration.hpp>
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
#if ARDUINOJSON_USE_DOUBLE
|
||||
typedef double JsonFloat;
|
||||
#else
|
||||
typedef float JsonFloat;
|
||||
#endif
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,28 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Configuration.hpp>
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
|
||||
#include <stdint.h> // int64_t
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
typedef int64_t JsonInteger;
|
||||
typedef uint64_t JsonUInt;
|
||||
#else
|
||||
typedef long JsonInteger;
|
||||
typedef unsigned long JsonUInt;
|
||||
#endif
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
||||
#define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \
|
||||
static_assert(sizeof(T) <= sizeof(ArduinoJson::JsonInteger), \
|
||||
"To use 64-bit integers with ArduinoJson, you must set " \
|
||||
"ARDUINOJSON_USE_LONG_LONG to 1. See " \
|
||||
"https://arduinojson.org/v7/api/config/use_long_long/");
|
||||
@@ -1,120 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Numbers/JsonInteger.hpp>
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
enum CompareResult {
|
||||
COMPARE_RESULT_DIFFER = 0,
|
||||
COMPARE_RESULT_EQUAL = 1,
|
||||
COMPARE_RESULT_GREATER = 2,
|
||||
COMPARE_RESULT_LESS = 4,
|
||||
|
||||
COMPARE_RESULT_GREATER_OR_EQUAL = 3,
|
||||
COMPARE_RESULT_LESS_OR_EQUAL = 5
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
CompareResult arithmeticCompare(const T& lhs, const T& rhs) {
|
||||
if (lhs < rhs)
|
||||
return COMPARE_RESULT_LESS;
|
||||
else if (lhs > rhs)
|
||||
return COMPARE_RESULT_GREATER;
|
||||
else
|
||||
return COMPARE_RESULT_EQUAL;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
CompareResult arithmeticCompare(
|
||||
const T1& lhs, const T2& rhs,
|
||||
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||
sizeof(T1) < sizeof(T2)>::type* = 0) {
|
||||
return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
CompareResult arithmeticCompare(
|
||||
const T1& lhs, const T2& rhs,
|
||||
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||
sizeof(T2) < sizeof(T1)>::type* = 0) {
|
||||
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
CompareResult arithmeticCompare(
|
||||
const T1& lhs, const T2& rhs,
|
||||
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||
is_signed<T1>::value == is_signed<T2>::value &&
|
||||
sizeof(T2) == sizeof(T1)>::type* = 0) {
|
||||
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
CompareResult arithmeticCompare(
|
||||
const T1& lhs, const T2& rhs,
|
||||
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||
is_unsigned<T1>::value && is_signed<T2>::value &&
|
||||
sizeof(T2) == sizeof(T1)>::type* = 0) {
|
||||
if (rhs < 0)
|
||||
return COMPARE_RESULT_GREATER;
|
||||
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
CompareResult arithmeticCompare(
|
||||
const T1& lhs, const T2& rhs,
|
||||
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||
is_signed<T1>::value && is_unsigned<T2>::value &&
|
||||
sizeof(T2) == sizeof(T1)>::type* = 0) {
|
||||
if (lhs < 0)
|
||||
return COMPARE_RESULT_LESS;
|
||||
return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
CompareResult arithmeticCompare(
|
||||
const T1& lhs, const T2& rhs,
|
||||
typename enable_if<is_floating_point<T1>::value ||
|
||||
is_floating_point<T2>::value>::type* = 0) {
|
||||
return arithmeticCompare<double>(static_cast<double>(lhs),
|
||||
static_cast<double>(rhs));
|
||||
}
|
||||
|
||||
template <typename T2>
|
||||
CompareResult arithmeticCompareNegateLeft(
|
||||
JsonUInt, const T2&,
|
||||
typename enable_if<is_unsigned<T2>::value>::type* = 0) {
|
||||
return COMPARE_RESULT_LESS;
|
||||
}
|
||||
|
||||
template <typename T2>
|
||||
CompareResult arithmeticCompareNegateLeft(
|
||||
JsonUInt lhs, const T2& rhs,
|
||||
typename enable_if<is_signed<T2>::value>::type* = 0) {
|
||||
if (rhs > 0)
|
||||
return COMPARE_RESULT_LESS;
|
||||
return arithmeticCompare(-rhs, static_cast<T2>(lhs));
|
||||
}
|
||||
|
||||
template <typename T1>
|
||||
CompareResult arithmeticCompareNegateRight(
|
||||
const T1&, JsonUInt,
|
||||
typename enable_if<is_unsigned<T1>::value>::type* = 0) {
|
||||
return COMPARE_RESULT_GREATER;
|
||||
}
|
||||
|
||||
template <typename T1>
|
||||
CompareResult arithmeticCompareNegateRight(
|
||||
const T1& lhs, JsonUInt rhs,
|
||||
typename enable_if<is_signed<T1>::value>::type* = 0) {
|
||||
if (lhs > 0)
|
||||
return COMPARE_RESULT_GREATER;
|
||||
return arithmeticCompare(static_cast<T1>(rhs), -lhs);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,135 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wconversion"
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wconversion"
|
||||
#endif
|
||||
|
||||
#include <ArduinoJson/Numbers/FloatTraits.hpp>
|
||||
#include <ArduinoJson/Numbers/JsonFloat.hpp>
|
||||
#include <ArduinoJson/Polyfills/limits.hpp>
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
// uint32 -> int32
|
||||
// uint64 -> int32
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TIn>::value && is_unsigned<TIn>::value &&
|
||||
is_integral<TOut>::value && sizeof(TOut) <= sizeof(TIn),
|
||||
bool>::type
|
||||
canConvertNumber(TIn value) {
|
||||
return value <= TIn(numeric_limits<TOut>::highest());
|
||||
}
|
||||
|
||||
// uint32 -> int64
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TIn>::value && is_unsigned<TIn>::value &&
|
||||
is_integral<TOut>::value && sizeof(TIn) < sizeof(TOut),
|
||||
bool>::type
|
||||
canConvertNumber(TIn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// uint32 -> float
|
||||
// int32 -> float
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TIn>::value && is_floating_point<TOut>::value,
|
||||
bool>::type
|
||||
canConvertNumber(TIn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// int64 -> int32
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||
is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||
sizeof(TOut) < sizeof(TIn),
|
||||
bool>::type
|
||||
canConvertNumber(TIn value) {
|
||||
return value >= TIn(numeric_limits<TOut>::lowest()) &&
|
||||
value <= TIn(numeric_limits<TOut>::highest());
|
||||
}
|
||||
|
||||
// int32 -> int32
|
||||
// int32 -> int64
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||
is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||
sizeof(TIn) <= sizeof(TOut),
|
||||
bool>::type
|
||||
canConvertNumber(TIn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// int32 -> uint32
|
||||
// int32 -> uint64
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||
is_integral<TOut>::value && is_unsigned<TOut>::value &&
|
||||
sizeof(TOut) >= sizeof(TIn),
|
||||
bool>::type
|
||||
canConvertNumber(TIn value) {
|
||||
if (value < 0)
|
||||
return false;
|
||||
return TOut(value) <= numeric_limits<TOut>::highest();
|
||||
}
|
||||
|
||||
// int32 -> uint16
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||
is_integral<TOut>::value && is_unsigned<TOut>::value &&
|
||||
sizeof(TOut) < sizeof(TIn),
|
||||
bool>::type
|
||||
canConvertNumber(TIn value) {
|
||||
if (value < 0)
|
||||
return false;
|
||||
return value <= TIn(numeric_limits<TOut>::highest());
|
||||
}
|
||||
|
||||
// float32 -> int16
|
||||
// float64 -> int32
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_floating_point<TIn>::value && is_integral<TOut>::value &&
|
||||
sizeof(TOut) < sizeof(TIn),
|
||||
bool>::type
|
||||
canConvertNumber(TIn value) {
|
||||
return value >= numeric_limits<TOut>::lowest() &&
|
||||
value <= numeric_limits<TOut>::highest();
|
||||
}
|
||||
|
||||
// float32 -> int32
|
||||
// float32 -> uint32
|
||||
// float32 -> int64
|
||||
// float32 -> uint64
|
||||
// float64 -> int64
|
||||
// float64 -> uint64
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_floating_point<TIn>::value && is_integral<TOut>::value &&
|
||||
sizeof(TOut) >= sizeof(TIn),
|
||||
bool>::type
|
||||
canConvertNumber(TIn value) {
|
||||
// Avoid error "9.22337e+18 is outside the range of representable values of
|
||||
// type 'long'"
|
||||
return value >= numeric_limits<TOut>::lowest() &&
|
||||
value <= FloatTraits<TIn>::template highest_for<TOut>();
|
||||
}
|
||||
|
||||
template <typename TOut, typename TIn>
|
||||
TOut convertNumber(TIn value) {
|
||||
return canConvertNumber<TOut>(value) ? TOut(value) : 0;
|
||||
}
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
@@ -1,152 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Numbers/FloatTraits.hpp>
|
||||
#include <ArduinoJson/Numbers/convertNumber.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/ctype.hpp>
|
||||
#include <ArduinoJson/Polyfills/math.hpp>
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
#include <ArduinoJson/Variant/Converter.hpp>
|
||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename A, typename B>
|
||||
struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {};
|
||||
|
||||
inline bool parseNumber(const char* s, VariantData& result) {
|
||||
typedef FloatTraits<JsonFloat> traits;
|
||||
typedef choose_largest<traits::mantissa_type, JsonUInt>::type mantissa_t;
|
||||
typedef traits::exponent_type exponent_t;
|
||||
|
||||
ARDUINOJSON_ASSERT(s != 0);
|
||||
|
||||
bool is_negative = false;
|
||||
switch (*s) {
|
||||
case '-':
|
||||
is_negative = true;
|
||||
s++;
|
||||
break;
|
||||
case '+':
|
||||
s++;
|
||||
break;
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_ENABLE_NAN
|
||||
if (*s == 'n' || *s == 'N') {
|
||||
result.setFloat(traits::nan());
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ARDUINOJSON_ENABLE_INFINITY
|
||||
if (*s == 'i' || *s == 'I') {
|
||||
result.setFloat(is_negative ? -traits::inf() : traits::inf());
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!isdigit(*s) && *s != '.')
|
||||
return false;
|
||||
|
||||
mantissa_t mantissa = 0;
|
||||
exponent_t exponent_offset = 0;
|
||||
const mantissa_t maxUint = JsonUInt(-1);
|
||||
|
||||
while (isdigit(*s)) {
|
||||
uint8_t digit = uint8_t(*s - '0');
|
||||
if (mantissa > maxUint / 10)
|
||||
break;
|
||||
mantissa *= 10;
|
||||
if (mantissa > maxUint - digit)
|
||||
break;
|
||||
mantissa += digit;
|
||||
s++;
|
||||
}
|
||||
|
||||
if (*s == '\0') {
|
||||
if (is_negative) {
|
||||
const mantissa_t sintMantissaMax = mantissa_t(1)
|
||||
<< (sizeof(JsonInteger) * 8 - 1);
|
||||
if (mantissa <= sintMantissaMax) {
|
||||
result.setInteger(JsonInteger(~mantissa + 1));
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
result.setInteger(JsonUInt(mantissa));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// avoid mantissa overflow
|
||||
while (mantissa > traits::mantissa_max) {
|
||||
mantissa /= 10;
|
||||
exponent_offset++;
|
||||
}
|
||||
|
||||
// remaing digits can't fit in the mantissa
|
||||
while (isdigit(*s)) {
|
||||
exponent_offset++;
|
||||
s++;
|
||||
}
|
||||
|
||||
if (*s == '.') {
|
||||
s++;
|
||||
while (isdigit(*s)) {
|
||||
if (mantissa < traits::mantissa_max / 10) {
|
||||
mantissa = mantissa * 10 + uint8_t(*s - '0');
|
||||
exponent_offset--;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
int exponent = 0;
|
||||
if (*s == 'e' || *s == 'E') {
|
||||
s++;
|
||||
bool negative_exponent = false;
|
||||
if (*s == '-') {
|
||||
negative_exponent = true;
|
||||
s++;
|
||||
} else if (*s == '+') {
|
||||
s++;
|
||||
}
|
||||
|
||||
while (isdigit(*s)) {
|
||||
exponent = exponent * 10 + (*s - '0');
|
||||
if (exponent + exponent_offset > traits::exponent_max) {
|
||||
if (negative_exponent)
|
||||
result.setFloat(is_negative ? -0.0f : 0.0f);
|
||||
else
|
||||
result.setFloat(is_negative ? -traits::inf() : traits::inf());
|
||||
return true;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
if (negative_exponent)
|
||||
exponent = -exponent;
|
||||
}
|
||||
exponent += exponent_offset;
|
||||
|
||||
// we should be at the end of the string, otherwise it's an error
|
||||
if (*s != '\0')
|
||||
return false;
|
||||
|
||||
JsonFloat final_result =
|
||||
make_float(static_cast<JsonFloat>(mantissa), exponent);
|
||||
|
||||
result.setFloat(is_negative ? -final_result : final_result);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T parseNumber(const char* s) {
|
||||
VariantData value;
|
||||
parseNumber(s, value);
|
||||
return Converter<T>::fromJson(JsonVariantConst(&value, nullptr));
|
||||
}
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,215 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Object/JsonObjectConst.hpp>
|
||||
#include <ArduinoJson/Object/MemberProxy.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
class JsonArray;
|
||||
|
||||
// A reference to an object in a JsonDocument.
|
||||
// https://arduinojson.org/v7/api/jsonobject/
|
||||
class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||
friend class detail::VariantAttorney;
|
||||
|
||||
public:
|
||||
typedef JsonObjectIterator iterator;
|
||||
|
||||
// Creates an unbound reference.
|
||||
JsonObject() : data_(0), resources_(0) {}
|
||||
|
||||
// INTERNAL USE ONLY
|
||||
JsonObject(detail::ObjectData* data, detail::ResourceManager* resource)
|
||||
: data_(data), resources_(resource) {}
|
||||
|
||||
operator JsonVariant() const {
|
||||
void* data = data_; // prevent warning cast-align
|
||||
return JsonVariant(reinterpret_cast<detail::VariantData*>(data),
|
||||
resources_);
|
||||
}
|
||||
|
||||
operator JsonObjectConst() const {
|
||||
return JsonObjectConst(data_, resources_);
|
||||
}
|
||||
|
||||
operator JsonVariantConst() const {
|
||||
return JsonVariantConst(collectionToVariant(data_), resources_);
|
||||
}
|
||||
|
||||
// Returns true if the reference is unbound.
|
||||
// https://arduinojson.org/v7/api/jsonobject/isnull/
|
||||
bool isNull() const {
|
||||
return data_ == 0;
|
||||
}
|
||||
|
||||
// Returns true if the reference is bound.
|
||||
// https://arduinojson.org/v7/api/jsonobject/isnull/
|
||||
operator bool() const {
|
||||
return data_ != 0;
|
||||
}
|
||||
|
||||
// Returns the depth (nesting level) of the object.
|
||||
// https://arduinojson.org/v7/api/jsonobject/nesting/
|
||||
size_t nesting() const {
|
||||
return detail::VariantData::nesting(collectionToVariant(data_), resources_);
|
||||
}
|
||||
|
||||
// Returns the number of members in the object.
|
||||
// https://arduinojson.org/v7/api/jsonobject/size/
|
||||
size_t size() const {
|
||||
return data_ ? data_->size(resources_) : 0;
|
||||
}
|
||||
|
||||
// Returns an iterator to the first key-value pair of the object.
|
||||
// https://arduinojson.org/v7/api/jsonobject/begin/
|
||||
iterator begin() const {
|
||||
if (!data_)
|
||||
return iterator();
|
||||
return iterator(data_->createIterator(resources_), resources_);
|
||||
}
|
||||
|
||||
// Returns an iterator following the last key-value pair of the object.
|
||||
// https://arduinojson.org/v7/api/jsonobject/end/
|
||||
iterator end() const {
|
||||
return iterator();
|
||||
}
|
||||
|
||||
// Removes all the members of the object.
|
||||
// https://arduinojson.org/v7/api/jsonobject/clear/
|
||||
void clear() const {
|
||||
detail::ObjectData::clear(data_, resources_);
|
||||
}
|
||||
|
||||
// Copies an object.
|
||||
// https://arduinojson.org/v7/api/jsonobject/set/
|
||||
bool set(JsonObjectConst src) {
|
||||
if (!data_ || !src.data_)
|
||||
return false;
|
||||
|
||||
clear();
|
||||
for (auto kvp : src) {
|
||||
if (!operator[](kvp.key()).set(kvp.value()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Gets or sets the member with specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobject/subscript/
|
||||
template <typename TString>
|
||||
|
||||
typename detail::enable_if<detail::IsString<TString>::value,
|
||||
detail::MemberProxy<JsonObject, TString>>::type
|
||||
operator[](const TString& key) const {
|
||||
return {*this, key};
|
||||
}
|
||||
|
||||
// Gets or sets the member with specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobject/subscript/
|
||||
template <typename TChar>
|
||||
|
||||
typename detail::enable_if<detail::IsString<TChar*>::value,
|
||||
detail::MemberProxy<JsonObject, TChar*>>::type
|
||||
operator[](TChar* key) const {
|
||||
return {*this, key};
|
||||
}
|
||||
|
||||
// Removes the member at the specified iterator.
|
||||
// https://arduinojson.org/v7/api/jsonobject/remove/
|
||||
FORCE_INLINE void remove(iterator it) const {
|
||||
detail::ObjectData::remove(data_, it.iterator_, resources_);
|
||||
}
|
||||
|
||||
// Removes the member with the specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobject/remove/
|
||||
template <typename TString>
|
||||
FORCE_INLINE void remove(const TString& key) const {
|
||||
detail::ObjectData::removeMember(data_, detail::adaptString(key),
|
||||
resources_);
|
||||
}
|
||||
|
||||
// Removes the member with the specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobject/remove/
|
||||
template <typename TChar>
|
||||
FORCE_INLINE void remove(TChar* key) const {
|
||||
detail::ObjectData::removeMember(data_, detail::adaptString(key),
|
||||
resources_);
|
||||
}
|
||||
|
||||
// Returns true if the object contains the specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobject/containskey/
|
||||
template <typename TString>
|
||||
|
||||
typename detail::enable_if<detail::IsString<TString>::value, bool>::type
|
||||
containsKey(const TString& key) const {
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
// Returns true if the object contains the specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobject/containskey/
|
||||
template <typename TChar>
|
||||
|
||||
typename detail::enable_if<detail::IsString<TChar*>::value, bool>::type
|
||||
containsKey(TChar* key) const {
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
// DEPRECATED: use obj[key].to<JsonArray>() instead
|
||||
template <typename TChar>
|
||||
ARDUINOJSON_DEPRECATED("use obj[key].to<JsonArray>() instead")
|
||||
JsonArray createNestedArray(TChar* key) const {
|
||||
return operator[](key).template to<JsonArray>();
|
||||
}
|
||||
|
||||
// DEPRECATED: use obj[key].to<JsonArray>() instead
|
||||
template <typename TString>
|
||||
ARDUINOJSON_DEPRECATED("use obj[key].to<JsonArray>() instead")
|
||||
JsonArray createNestedArray(const TString& key) const {
|
||||
return operator[](key).template to<JsonArray>();
|
||||
}
|
||||
|
||||
// DEPRECATED: use obj[key].to<JsonObject>() instead
|
||||
template <typename TChar>
|
||||
ARDUINOJSON_DEPRECATED("use obj[key].to<JsonObject>() instead")
|
||||
JsonObject createNestedObject(TChar* key) {
|
||||
return operator[](key).template to<JsonObject>();
|
||||
}
|
||||
|
||||
// DEPRECATED: use obj[key].to<JsonObject>() instead
|
||||
template <typename TString>
|
||||
ARDUINOJSON_DEPRECATED("use obj[key].to<JsonObject>() instead")
|
||||
JsonObject createNestedObject(const TString& key) {
|
||||
return operator[](key).template to<JsonObject>();
|
||||
}
|
||||
|
||||
// DEPRECATED: always returns zero
|
||||
ARDUINOJSON_DEPRECATED("always returns zero")
|
||||
size_t memoryUsage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
detail::ResourceManager* getResourceManager() const {
|
||||
return resources_;
|
||||
}
|
||||
|
||||
detail::VariantData* getData() const {
|
||||
return detail::collectionToVariant(data_);
|
||||
}
|
||||
|
||||
detail::VariantData* getOrCreateData() const {
|
||||
return detail::collectionToVariant(data_);
|
||||
}
|
||||
|
||||
detail::ObjectData* data_;
|
||||
detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,143 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Object/JsonObjectIterator.hpp>
|
||||
#include <ArduinoJson/Variant/VariantOperators.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// A read-only reference to an object in a JsonDocument.
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/
|
||||
class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
|
||||
friend class JsonObject;
|
||||
friend class detail::VariantAttorney;
|
||||
|
||||
public:
|
||||
typedef JsonObjectConstIterator iterator;
|
||||
|
||||
// Creates an unbound reference.
|
||||
JsonObjectConst() : data_(0) {}
|
||||
|
||||
// INTERNAL USE ONLY
|
||||
JsonObjectConst(const detail::ObjectData* data,
|
||||
const detail::ResourceManager* resources)
|
||||
: data_(data), resources_(resources) {}
|
||||
|
||||
operator JsonVariantConst() const {
|
||||
return JsonVariantConst(getData(), resources_);
|
||||
}
|
||||
|
||||
// Returns true if the reference is unbound.
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/isnull/
|
||||
bool isNull() const {
|
||||
return data_ == 0;
|
||||
}
|
||||
|
||||
// Returns true if the reference is bound.
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/isnull/
|
||||
operator bool() const {
|
||||
return data_ != 0;
|
||||
}
|
||||
|
||||
// Returns the depth (nesting level) of the object.
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/nesting/
|
||||
size_t nesting() const {
|
||||
return detail::VariantData::nesting(getData(), resources_);
|
||||
}
|
||||
|
||||
// Returns the number of members in the object.
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/size/
|
||||
size_t size() const {
|
||||
return data_ ? data_->size(resources_) : 0;
|
||||
}
|
||||
|
||||
// Returns an iterator to the first key-value pair of the object.
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/begin/
|
||||
iterator begin() const {
|
||||
if (!data_)
|
||||
return iterator();
|
||||
return iterator(data_->createIterator(resources_), resources_);
|
||||
}
|
||||
|
||||
// Returns an iterator following the last key-value pair of the object.
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/end/
|
||||
iterator end() const {
|
||||
return iterator();
|
||||
}
|
||||
|
||||
// Returns true if the object contains the specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/containskey/
|
||||
template <typename TString>
|
||||
bool containsKey(const TString& key) const {
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
// Returns true if the object contains the specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/containskey/
|
||||
template <typename TChar>
|
||||
bool containsKey(TChar* key) const {
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
// Gets the member with specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/subscript/
|
||||
template <typename TString>
|
||||
typename detail::enable_if<detail::IsString<TString>::value,
|
||||
JsonVariantConst>::type
|
||||
operator[](const TString& key) const {
|
||||
return JsonVariantConst(detail::ObjectData::getMember(
|
||||
data_, detail::adaptString(key), resources_),
|
||||
resources_);
|
||||
}
|
||||
|
||||
// Gets the member with specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/subscript/
|
||||
template <typename TChar>
|
||||
typename detail::enable_if<detail::IsString<TChar*>::value,
|
||||
JsonVariantConst>::type
|
||||
operator[](TChar* key) const {
|
||||
return JsonVariantConst(detail::ObjectData::getMember(
|
||||
data_, detail::adaptString(key), resources_),
|
||||
resources_);
|
||||
}
|
||||
|
||||
// DEPRECATED: always returns zero
|
||||
ARDUINOJSON_DEPRECATED("always returns zero")
|
||||
size_t memoryUsage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
const detail::VariantData* getData() const {
|
||||
return collectionToVariant(data_);
|
||||
}
|
||||
|
||||
const detail::ObjectData* data_;
|
||||
const detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
inline bool operator==(JsonObjectConst lhs, JsonObjectConst rhs) {
|
||||
if (!lhs && !rhs) // both are null
|
||||
return true;
|
||||
|
||||
if (!lhs || !rhs) // only one is null
|
||||
return false;
|
||||
|
||||
size_t count = 0;
|
||||
for (auto kvp : lhs) {
|
||||
auto rhsValue = rhs[kvp.key()];
|
||||
if (rhsValue.isUnbound())
|
||||
return false;
|
||||
if (kvp.value() != rhsValue)
|
||||
return false;
|
||||
count++;
|
||||
}
|
||||
return count == rhs.size();
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,81 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Object/JsonPair.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
class JsonObjectIterator {
|
||||
friend class JsonObject;
|
||||
|
||||
public:
|
||||
JsonObjectIterator() {}
|
||||
|
||||
explicit JsonObjectIterator(detail::ObjectData::iterator iterator,
|
||||
detail::ResourceManager* resources)
|
||||
: iterator_(iterator), resources_(resources) {}
|
||||
|
||||
JsonPair operator*() const {
|
||||
return JsonPair(iterator_, resources_);
|
||||
}
|
||||
Ptr<JsonPair> operator->() {
|
||||
return operator*();
|
||||
}
|
||||
|
||||
bool operator==(const JsonObjectIterator& other) const {
|
||||
return iterator_ == other.iterator_;
|
||||
}
|
||||
|
||||
bool operator!=(const JsonObjectIterator& other) const {
|
||||
return iterator_ != other.iterator_;
|
||||
}
|
||||
|
||||
JsonObjectIterator& operator++() {
|
||||
iterator_.next(resources_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
detail::ObjectData::iterator iterator_;
|
||||
detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
class JsonObjectConstIterator {
|
||||
friend class JsonObject;
|
||||
|
||||
public:
|
||||
JsonObjectConstIterator() {}
|
||||
|
||||
explicit JsonObjectConstIterator(detail::ObjectData::iterator iterator,
|
||||
const detail::ResourceManager* resources)
|
||||
: iterator_(iterator), resources_(resources) {}
|
||||
|
||||
JsonPairConst operator*() const {
|
||||
return JsonPairConst(iterator_, resources_);
|
||||
}
|
||||
Ptr<JsonPairConst> operator->() {
|
||||
return operator*();
|
||||
}
|
||||
|
||||
bool operator==(const JsonObjectConstIterator& other) const {
|
||||
return iterator_ == other.iterator_;
|
||||
}
|
||||
|
||||
bool operator!=(const JsonObjectConstIterator& other) const {
|
||||
return iterator_ != other.iterator_;
|
||||
}
|
||||
|
||||
JsonObjectConstIterator& operator++() {
|
||||
iterator_.next(resources_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
detail::ObjectData::iterator iterator_;
|
||||
const detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,70 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Strings/JsonString.hpp>
|
||||
#include <ArduinoJson/Variant/JsonVariant.hpp>
|
||||
#include <ArduinoJson/Variant/JsonVariantConst.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// A key-value pair.
|
||||
// https://arduinojson.org/v7/api/jsonobject/begin_end/
|
||||
class JsonPair {
|
||||
public:
|
||||
// INTERNAL USE ONLY
|
||||
JsonPair(detail::ObjectData::iterator iterator,
|
||||
detail::ResourceManager* resources)
|
||||
: iterator_(iterator), resources_(resources) {}
|
||||
|
||||
// Returns the key.
|
||||
JsonString key() const {
|
||||
if (!iterator_.done())
|
||||
return JsonString(iterator_.key(), iterator_.ownsKey()
|
||||
? JsonString::Copied
|
||||
: JsonString::Linked);
|
||||
else
|
||||
return JsonString();
|
||||
}
|
||||
|
||||
// Returns the value.
|
||||
JsonVariant value() {
|
||||
return JsonVariant(iterator_.data(), resources_);
|
||||
}
|
||||
|
||||
private:
|
||||
detail::ObjectData::iterator iterator_;
|
||||
detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
// A read-only key-value pair.
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/begin_end/
|
||||
class JsonPairConst {
|
||||
public:
|
||||
JsonPairConst(detail::ObjectData::iterator iterator,
|
||||
const detail::ResourceManager* resources)
|
||||
: iterator_(iterator), resources_(resources) {}
|
||||
|
||||
// Returns the key.
|
||||
JsonString key() const {
|
||||
if (!iterator_.done())
|
||||
return JsonString(iterator_.key(), iterator_.ownsKey()
|
||||
? JsonString::Copied
|
||||
: JsonString::Linked);
|
||||
else
|
||||
return JsonString();
|
||||
}
|
||||
|
||||
// Returns the value.
|
||||
JsonVariantConst value() const {
|
||||
return JsonVariantConst(iterator_.data(), resources_);
|
||||
}
|
||||
|
||||
private:
|
||||
detail::ObjectData::iterator iterator_;
|
||||
const detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@@ -1,67 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Variant/VariantRefBase.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
// A proxy class to get or set a member of an object.
|
||||
// https://arduinojson.org/v7/api/jsonobject/subscript/
|
||||
template <typename TUpstream, typename TStringRef>
|
||||
class MemberProxy
|
||||
: public VariantRefBase<MemberProxy<TUpstream, TStringRef>>,
|
||||
public VariantOperators<MemberProxy<TUpstream, TStringRef>> {
|
||||
friend class VariantAttorney;
|
||||
|
||||
public:
|
||||
MemberProxy(TUpstream upstream, TStringRef key)
|
||||
: upstream_(upstream), key_(key) {}
|
||||
|
||||
MemberProxy(const MemberProxy& src)
|
||||
: upstream_(src.upstream_), key_(src.key_) {}
|
||||
|
||||
MemberProxy& operator=(const MemberProxy& src) {
|
||||
this->set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MemberProxy& operator=(const T& src) {
|
||||
this->set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MemberProxy& operator=(T* src) {
|
||||
this->set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
ResourceManager* getResourceManager() const {
|
||||
return VariantAttorney::getResourceManager(upstream_);
|
||||
}
|
||||
|
||||
VariantData* getData() const {
|
||||
return VariantData::getMember(
|
||||
VariantAttorney::getData(upstream_), adaptString(key_),
|
||||
VariantAttorney::getResourceManager(upstream_));
|
||||
}
|
||||
|
||||
VariantData* getOrCreateData() const {
|
||||
auto data = VariantAttorney::getOrCreateData(upstream_);
|
||||
if (!data)
|
||||
return nullptr;
|
||||
return data->getOrAddMember(adaptString(key_),
|
||||
VariantAttorney::getResourceManager(upstream_));
|
||||
}
|
||||
|
||||
private:
|
||||
TUpstream upstream_;
|
||||
TStringRef key_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,73 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Collection/CollectionData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class ObjectData : public CollectionData {
|
||||
public:
|
||||
VariantData* addMember(StringNode* key, ResourceManager* resources) {
|
||||
ARDUINOJSON_ASSERT(key != nullptr);
|
||||
auto it = addSlot(resources);
|
||||
if (it.done())
|
||||
return nullptr;
|
||||
|
||||
it.setKey(key);
|
||||
return it.data();
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* addMember(TAdaptedString key, ResourceManager* resources) {
|
||||
ARDUINOJSON_ASSERT(!key.isNull());
|
||||
if (key.isLinked()) {
|
||||
auto it = addSlot(resources);
|
||||
if (!it.done())
|
||||
it.setKey(key.data());
|
||||
return it.data();
|
||||
} else {
|
||||
auto storedKey = resources->saveString(key);
|
||||
if (!storedKey)
|
||||
return nullptr;
|
||||
auto it = addSlot(resources);
|
||||
if (!it.done())
|
||||
it.setKey(storedKey);
|
||||
return it.data();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources);
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* getMember(TAdaptedString key,
|
||||
const ResourceManager* resources) const;
|
||||
|
||||
template <typename TAdaptedString>
|
||||
static VariantData* getMember(const ObjectData* object, TAdaptedString key,
|
||||
const ResourceManager* resources) {
|
||||
if (!object)
|
||||
return nullptr;
|
||||
return object->getMember(key, resources);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
void removeMember(TAdaptedString key, ResourceManager* resources);
|
||||
|
||||
template <typename TAdaptedString>
|
||||
static void removeMember(ObjectData* obj, TAdaptedString key,
|
||||
ResourceManager* resources) {
|
||||
if (!obj)
|
||||
return;
|
||||
obj->removeMember(key, resources);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename TAdaptedString>
|
||||
iterator findKey(TAdaptedString key, const ResourceManager* resources) const;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,45 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Object/ObjectData.hpp>
|
||||
#include <ArduinoJson/Variant/VariantCompare.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline VariantData* ObjectData::getMember(
|
||||
TAdaptedString key, const ResourceManager* resources) const {
|
||||
return findKey(key, resources).data();
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* ObjectData::getOrAddMember(TAdaptedString key,
|
||||
ResourceManager* resources) {
|
||||
auto it = findKey(key, resources);
|
||||
if (!it.done())
|
||||
return it.data();
|
||||
return addMember(key, resources);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline ObjectData::iterator ObjectData::findKey(
|
||||
TAdaptedString key, const ResourceManager* resources) const {
|
||||
if (key.isNull())
|
||||
return iterator();
|
||||
for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
|
||||
if (stringEquals(key, adaptString(it.key())))
|
||||
return it;
|
||||
}
|
||||
return iterator();
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline void ObjectData::removeMember(TAdaptedString key,
|
||||
ResourceManager* resources) {
|
||||
remove(findKey(key, resources), resources);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,30 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h> // for size_t
|
||||
|
||||
#include <ArduinoJson/Configuration.hpp>
|
||||
#include "math.hpp"
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename T, typename F>
|
||||
struct alias_cast_t {
|
||||
union {
|
||||
F raw;
|
||||
T data;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T, typename F>
|
||||
T alias_cast(F raw_data) {
|
||||
alias_cast_t<T, F> ac;
|
||||
ac.raw = raw_data;
|
||||
return ac.data;
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,14 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Configuration.hpp>
|
||||
|
||||
#if ARDUINOJSON_DEBUG
|
||||
# include <assert.h>
|
||||
# define ARDUINOJSON_ASSERT(X) assert(X)
|
||||
#else
|
||||
# define ARDUINOJSON_ASSERT(X) ((void)0)
|
||||
#endif
|
||||
@@ -1,45 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER // Visual Studio
|
||||
|
||||
# define FORCE_INLINE // __forceinline causes C4714 when returning std::string
|
||||
|
||||
# ifndef ARDUINOJSON_DEPRECATED
|
||||
# define ARDUINOJSON_DEPRECATED(msg) __declspec(deprecated(msg))
|
||||
# endif
|
||||
|
||||
#elif defined(__GNUC__) // GCC or Clang
|
||||
|
||||
# define FORCE_INLINE __attribute__((always_inline))
|
||||
|
||||
# ifndef ARDUINOJSON_DEPRECATED
|
||||
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
|
||||
# define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated(msg)))
|
||||
# else
|
||||
# define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated))
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#else // Other compilers
|
||||
|
||||
# define FORCE_INLINE
|
||||
|
||||
# ifndef ARDUINOJSON_DEPRECATED
|
||||
# define ARDUINOJSON_DEPRECATED(msg)
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__has_attribute)
|
||||
# if __has_attribute(no_sanitize)
|
||||
# define ARDUINOJSON_NO_SANITIZE(check) __attribute__((no_sanitize(check)))
|
||||
# else
|
||||
# define ARDUINOJSON_NO_SANITIZE(check)
|
||||
# endif
|
||||
#else
|
||||
# define ARDUINOJSON_NO_SANITIZE(check)
|
||||
#endif
|
||||
@@ -1,21 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
#ifndef isdigit
|
||||
inline bool isdigit(char c) {
|
||||
return '0' <= c && c <= '9';
|
||||
}
|
||||
#endif
|
||||
|
||||
inline bool issign(char c) {
|
||||
return '-' == c || c == '+';
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,31 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h> // int8_t, int16_t
|
||||
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <int Bits>
|
||||
struct uint_t;
|
||||
|
||||
template <>
|
||||
struct uint_t<8> {
|
||||
typedef uint8_t type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct uint_t<16> {
|
||||
typedef uint16_t type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct uint_t<32> {
|
||||
typedef uint32_t type;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@@ -1,45 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "type_traits.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4310)
|
||||
#endif
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
// Differs from standard because we can't use the symbols "min" and "max"
|
||||
template <typename T, typename Enable = void>
|
||||
struct numeric_limits;
|
||||
|
||||
template <typename T>
|
||||
struct numeric_limits<T, typename enable_if<is_unsigned<T>::value>::type> {
|
||||
static constexpr T lowest() {
|
||||
return 0;
|
||||
}
|
||||
static constexpr T highest() {
|
||||
return T(-1);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct numeric_limits<
|
||||
T, typename enable_if<is_integral<T>::value && is_signed<T>::value>::type> {
|
||||
static constexpr T lowest() {
|
||||
return T(T(1) << (sizeof(T) * 8 - 1));
|
||||
}
|
||||
static constexpr T highest() {
|
||||
return T(~lowest());
|
||||
}
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user