diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Runtime/common/rest/rest-primary-object-types.cpp | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Runtime/common/rest/rest-primary-object-types.cpp')
-rw-r--r-- | src/VBox/Runtime/common/rest/rest-primary-object-types.cpp | 2403 |
1 files changed, 2403 insertions, 0 deletions
diff --git a/src/VBox/Runtime/common/rest/rest-primary-object-types.cpp b/src/VBox/Runtime/common/rest/rest-primary-object-types.cpp new file mode 100644 index 00000000..9657a018 --- /dev/null +++ b/src/VBox/Runtime/common/rest/rest-primary-object-types.cpp @@ -0,0 +1,2403 @@ +/* $Id: rest-primary-object-types.cpp $ */ +/** @file + * IPRT - C++ REST, RTCRestObjectBase implementation. + */ + +/* + * Copyright (C) 2018-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP RTLOGGROUP_REST +#include <iprt/cpp/restbase.h> + +#include <iprt/ctype.h> +#include <iprt/err.h> +#include <iprt/string.h> +#include <iprt/cpp/restoutput.h> + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + + + +/********************************************************************************************************************************* +* RTCRestObjectBase implementation * +*********************************************************************************************************************************/ + +/** Default constructor. */ +RTCRestObjectBase::RTCRestObjectBase() RT_NOEXCEPT + : m_fNullIndicator(false) +{ +} + + +/** Copy constructor. */ +RTCRestObjectBase::RTCRestObjectBase(RTCRestObjectBase const &a_rThat) RT_NOEXCEPT + : m_fNullIndicator(a_rThat.m_fNullIndicator) +{ +} + + +/** Destructor. */ +RTCRestObjectBase::~RTCRestObjectBase() +{ + /* nothing to do */ +} + + +/** Copy assignment operator. */ +RTCRestObjectBase &RTCRestObjectBase::operator=(RTCRestObjectBase const &a_rThat) RT_NOEXCEPT +{ + m_fNullIndicator = a_rThat.m_fNullIndicator; + return *this; +} + + +int RTCRestObjectBase::setNull() RT_NOEXCEPT +{ + int rc = resetToDefault(); + m_fNullIndicator = true; + return rc; +} + + +void RTCRestObjectBase::setNotNull() RT_NOEXCEPT +{ + m_fNullIndicator = false; +} + + +int RTCRestObjectBase::toString(RTCString *a_pDst, uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) const RT_NOEXCEPT +{ + /* + * Just wrap the JSON serialization method. + */ + RTCRestOutputToString Tmp(a_pDst, RT_BOOL(a_fFlags & kToString_Append)); + serializeAsJson(Tmp); + return Tmp.finalize() ? VINF_SUCCESS : VERR_NO_MEMORY; +} + + +RTCString RTCRestObjectBase::toString() const +{ + RTCString strRet; + toString(&strRet, 0); + return strRet; +} + + +int RTCRestObjectBase::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo /*= NULL*/, + uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) RT_NOEXCEPT +{ + RT_NOREF(a_fFlags); + + /* + * Just wrap the JSON serialization method. + */ + RTJSONVAL hValue = NIL_RTJSONVAL; + int rc = RTJsonParseFromString(&hValue, a_rValue.c_str(), a_pErrInfo); + if (RT_SUCCESS(rc)) + { + RTCRestJsonPrimaryCursor PrimaryCursor(hValue, a_pszName, a_pErrInfo); + rc = deserializeFromJson(PrimaryCursor.m_Cursor); + } + return rc; +} + + + +/********************************************************************************************************************************* +* RTCRestBool implementation * +*********************************************************************************************************************************/ + +/** Factory method. */ +/*static*/ DECLCALLBACK(RTCRestObjectBase *) RTCRestBool::createInstance(void) RT_NOEXCEPT +{ + return new (std::nothrow) RTCRestBool(); +} + + +/** + * @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON + */ +/*static*/ DECLCALLBACK(int) +RTCRestBool::deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT +{ + RTCRestObjectBase *pObj = createInstance(); + *a_ppInstance = pObj; + if (pObj) + return pObj->deserializeFromJson(a_rCursor); + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_NO_MEMORY, "Out of memory"); +} + + +/** Default constructor. */ +RTCRestBool::RTCRestBool() RT_NOEXCEPT + : RTCRestObjectBase() + , m_fValue(false) +{ +} + + +/** Copy constructor. */ +RTCRestBool::RTCRestBool(RTCRestBool const &a_rThat) RT_NOEXCEPT + : RTCRestObjectBase(a_rThat) + , m_fValue(a_rThat.m_fValue) +{ +} + + +/** From value constructor. */ +RTCRestBool::RTCRestBool(bool fValue) RT_NOEXCEPT + : m_fValue(fValue) +{ +} + + +/** Destructor. */ +RTCRestBool::~RTCRestBool() +{ + /* nothing to do */ +} + + +/** Copy assignment operator. */ +RTCRestBool &RTCRestBool::operator=(RTCRestBool const &a_rThat) RT_NOEXCEPT +{ + m_fNullIndicator = a_rThat.m_fNullIndicator; + m_fValue = a_rThat.m_fValue; + return *this; +} + + +int RTCRestBool::assignCopy(RTCRestBool const &a_rThat) RT_NOEXCEPT +{ + m_fNullIndicator = a_rThat.m_fNullIndicator; + m_fValue = a_rThat.m_fValue; + return VINF_SUCCESS; +} + + +void RTCRestBool::assignValue(bool a_fValue) RT_NOEXCEPT +{ + m_fValue = a_fValue; + m_fNullIndicator = false; +} + + +RTCRestObjectBase *RTCRestBool::baseClone() const RT_NOEXCEPT +{ + return new (std::nothrow) RTCRestBool(*this); +} + + +int RTCRestBool::resetToDefault() RT_NOEXCEPT +{ + m_fValue = false; + m_fNullIndicator = false; + return VINF_SUCCESS; +} + + +RTCRestOutputBase &RTCRestBool::serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT +{ + a_rDst.printf(!m_fNullIndicator ? m_fValue ? "true" : "false" : "null"); + return a_rDst; +} + + +int RTCRestBool::deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT +{ + m_fValue = false; + m_fNullIndicator = false; + + RTJSONVALTYPE enmType = RTJsonValueGetType(a_rCursor.m_hValue); + + if (enmType == RTJSONVALTYPE_TRUE) + { + m_fValue = true; + return VINF_SUCCESS; + } + + if (enmType == RTJSONVALTYPE_FALSE) + return VINF_SUCCESS; + + if (enmType == RTJSONVALTYPE_NULL) + { + m_fNullIndicator = true; + return VINF_SUCCESS; + } + + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_REST_WRONG_JSON_TYPE_FOR_BOOL, "wrong JSON type %s for boolean", + RTJsonValueTypeName(RTJsonValueGetType(a_rCursor.m_hValue))); +} + + +int RTCRestBool::toString(RTCString *a_pDst, uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) const RT_NOEXCEPT +{ + if (!(a_fFlags & kToString_Append)) + { + if (!m_fNullIndicator) + { + if (m_fValue) + return a_pDst->assignNoThrow(RT_STR_TUPLE("true")); + return a_pDst->assignNoThrow(RT_STR_TUPLE("false")); + } + return a_pDst->assignNoThrow(RT_STR_TUPLE("null")); + } + + if (!m_fNullIndicator) + { + if (m_fValue) + return a_pDst->appendNoThrow(RT_STR_TUPLE("true")); + return a_pDst->appendNoThrow(RT_STR_TUPLE("false")); + } + return a_pDst->appendNoThrow(RT_STR_TUPLE("null")); +} + + +int RTCRestBool::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo /*= NULL*/, + uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) RT_NOEXCEPT +{ + RT_NOREF(a_fFlags); + + if (a_rValue.startsWithWord("true", RTCString::CaseInsensitive)) + { + m_fValue = true; + m_fNullIndicator = false; + } + else if (a_rValue.startsWithWord("false", RTCString::CaseInsensitive)) + { + m_fValue = false; + m_fNullIndicator = false; + } + else if (a_rValue.startsWithWord("null", RTCString::CaseInsensitive)) + { + m_fValue = false; + m_fNullIndicator = true; + } + else + return RTErrInfoSetF(a_pErrInfo, VERR_REST_UNABLE_TO_PARSE_STRING_AS_BOOL, + "%s: unable to parse '%s' as bool", a_pszName, a_rValue.c_str()); + return VINF_SUCCESS; +} + + +RTCRestObjectBase::kTypeClass RTCRestBool::typeClass() const RT_NOEXCEPT +{ + return kTypeClass_Bool; +} + + +const char *RTCRestBool::typeName() const RT_NOEXCEPT +{ + return "bool"; +} + + + +/********************************************************************************************************************************* +* RTCRestInt64 implementation * +*********************************************************************************************************************************/ + +/** Factory method. */ +/*static*/ DECLCALLBACK(RTCRestObjectBase *) RTCRestInt64::createInstance(void) RT_NOEXCEPT +{ + return new (std::nothrow) RTCRestInt64(); +} + + +/** + * @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON + */ +/*static*/ DECLCALLBACK(int) +RTCRestInt64::deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT +{ + RTCRestObjectBase *pObj = createInstance(); + *a_ppInstance = pObj; + if (pObj) + return pObj->deserializeFromJson(a_rCursor); + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_NO_MEMORY, "Out of memory"); +} + + +/** Default constructor. */ +RTCRestInt64::RTCRestInt64() RT_NOEXCEPT + : RTCRestObjectBase() + , m_iValue(0) +{ +} + + +/** Copy constructor. */ +RTCRestInt64::RTCRestInt64(RTCRestInt64 const &a_rThat) RT_NOEXCEPT + : RTCRestObjectBase(a_rThat) + , m_iValue(a_rThat.m_iValue) +{ +} + + +/** From value constructor. */ +RTCRestInt64::RTCRestInt64(int64_t iValue) RT_NOEXCEPT + : RTCRestObjectBase() + , m_iValue(iValue) +{ +} + + +/** Destructor. */ +RTCRestInt64::~RTCRestInt64() +{ + /* nothing to do */ +} + + +/** Copy assignment operator. */ +RTCRestInt64 &RTCRestInt64::operator=(RTCRestInt64 const &a_rThat) RT_NOEXCEPT +{ + m_fNullIndicator = a_rThat.m_fNullIndicator; + m_iValue = a_rThat.m_iValue; + return *this; +} + + +int RTCRestInt64::assignCopy(RTCRestInt64 const &a_rThat) RT_NOEXCEPT +{ + m_fNullIndicator = a_rThat.m_fNullIndicator; + m_iValue = a_rThat.m_iValue; + return VINF_SUCCESS; +} + + +void RTCRestInt64::assignValue(int64_t a_iValue) RT_NOEXCEPT +{ + m_iValue = a_iValue; + m_fNullIndicator = false; +} + + +RTCRestObjectBase *RTCRestInt64::baseClone() const RT_NOEXCEPT +{ + return new (std::nothrow) RTCRestInt64(*this); +} + + +int RTCRestInt64::resetToDefault() RT_NOEXCEPT +{ + m_iValue = 0; + m_fNullIndicator = false; + return VINF_SUCCESS; +} + + +RTCRestOutputBase &RTCRestInt64::serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT +{ + if (!m_fNullIndicator) + a_rDst.printf("%RI64", m_iValue); + else + a_rDst.nullValue(); + return a_rDst; +} + + +int RTCRestInt64::deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT +{ + m_iValue = 0; + m_fNullIndicator = false; + + RTJSONVALTYPE enmType = RTJsonValueGetType(a_rCursor.m_hValue); + if (enmType == RTJSONVALTYPE_INTEGER) + { + int rc = RTJsonValueQueryInteger(a_rCursor.m_hValue, &m_iValue); + if (RT_SUCCESS(rc)) + return rc; + return a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonValueQueryInteger failed with %Rrc", rc); + } + + if (enmType == RTJSONVALTYPE_NULL) + { + m_fNullIndicator = true; + return VINF_SUCCESS; + } + + /* This is probably non-sense... */ + if (enmType == RTJSONVALTYPE_TRUE) + m_iValue = 1; + + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_REST_WRONG_JSON_TYPE_FOR_INTEGER, "wrong JSON type %s for 64-bit integer", + RTJsonValueTypeName(RTJsonValueGetType(a_rCursor.m_hValue))); +} + + +int RTCRestInt64::toString(RTCString *a_pDst, uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) const RT_NOEXCEPT +{ + if (!(a_fFlags & kToString_Append)) + { + if (!m_fNullIndicator) + return a_pDst->printfNoThrow("%RI64", m_iValue); + return a_pDst->assignNoThrow(RT_STR_TUPLE("null")); + } + if (!m_fNullIndicator) + return a_pDst->appendPrintfNoThrow("%RI64", m_iValue); + return a_pDst->appendNoThrow(RT_STR_TUPLE("null")); +} + + +int RTCRestInt64::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo /*= NULL*/, + uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) RT_NOEXCEPT +{ + RT_NOREF(a_fFlags); + + m_iValue = 0; + m_fNullIndicator = false; + +/** @todo RTStrStripL and RTStrToInt64Full has a different idea what consitutes spaces... */ + int rc = RTStrToInt64Full(RTStrStripL(a_rValue.c_str()), 0, &m_iValue); + if (rc == VINF_SUCCESS || rc == VERR_TRAILING_SPACES) + return VINF_SUCCESS; + + if (a_rValue.startsWithWord("null", RTCString::CaseInsensitive)) + { + m_iValue = 0; + m_fNullIndicator = true; + return VINF_SUCCESS; + } + + return RTErrInfoSetF(a_pErrInfo, rc, "%s: error %Rrc parsing '%s' as int64_t", a_pszName, rc, a_rValue.c_str()); +} + + +RTCRestObjectBase::kTypeClass RTCRestInt64::typeClass() const RT_NOEXCEPT +{ + return kTypeClass_Int64; +} + + +const char *RTCRestInt64::typeName() const RT_NOEXCEPT +{ + return "int64_t"; +} + + + +/********************************************************************************************************************************* +* RTCRestInt32 implementation * +*********************************************************************************************************************************/ + +/** Factory method. */ +/*static*/ DECLCALLBACK(RTCRestObjectBase *) RTCRestInt32::createInstance(void) RT_NOEXCEPT +{ + return new (std::nothrow) RTCRestInt32(); +} + + +/** + * @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON + */ +/*static*/ DECLCALLBACK(int) +RTCRestInt32::deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT +{ + RTCRestObjectBase *pObj = createInstance(); + *a_ppInstance = pObj; + if (pObj) + return pObj->deserializeFromJson(a_rCursor); + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_NO_MEMORY, "Out of memory"); +} + + +/** Default constructor. */ +RTCRestInt32::RTCRestInt32() RT_NOEXCEPT + : RTCRestObjectBase() + , m_iValue(0) +{ +} + + +/** Copy constructor. */ +RTCRestInt32::RTCRestInt32(RTCRestInt32 const &a_rThat) RT_NOEXCEPT + : RTCRestObjectBase(a_rThat) + , m_iValue(a_rThat.m_iValue) +{ +} + + +/** From value constructor. */ +RTCRestInt32::RTCRestInt32(int32_t iValue) RT_NOEXCEPT + : RTCRestObjectBase() + , m_iValue(iValue) +{ +} + + +/** Destructor. */ +RTCRestInt32::~RTCRestInt32() RT_NOEXCEPT +{ + /* nothing to do */ +} + + +/** Copy assignment operator. */ +RTCRestInt32 &RTCRestInt32::operator=(RTCRestInt32 const &a_rThat) RT_NOEXCEPT +{ + m_fNullIndicator = a_rThat.m_fNullIndicator; + m_iValue = a_rThat.m_iValue; + return *this; +} + + +int RTCRestInt32::assignCopy(RTCRestInt32 const &a_rThat) RT_NOEXCEPT +{ + m_fNullIndicator = a_rThat.m_fNullIndicator; + m_iValue = a_rThat.m_iValue; + return VINF_SUCCESS; +} + + +RTCRestObjectBase *RTCRestInt32::baseClone() const RT_NOEXCEPT +{ + return new (std::nothrow) RTCRestInt32(*this); +} + + +int RTCRestInt32::resetToDefault() RT_NOEXCEPT +{ + m_iValue = 0; + m_fNullIndicator = false; + return VINF_SUCCESS; +} + + +void RTCRestInt32::assignValue(int32_t a_iValue) RT_NOEXCEPT +{ + m_iValue = a_iValue; + m_fNullIndicator = false; +} + + +RTCRestOutputBase &RTCRestInt32::serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT +{ + if (!m_fNullIndicator) + a_rDst.printf("%RI32", m_iValue); + else + a_rDst.nullValue(); + return a_rDst; +} + + +int RTCRestInt32::deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT +{ + m_iValue = 0; + m_fNullIndicator = false; + + RTJSONVALTYPE enmType = RTJsonValueGetType(a_rCursor.m_hValue); + if (enmType == RTJSONVALTYPE_INTEGER) + { + int64_t iTmp = m_iValue; + int rc = RTJsonValueQueryInteger(a_rCursor.m_hValue, &iTmp); + if (RT_SUCCESS(rc)) + { + m_iValue = (int32_t)iTmp; + if (m_iValue == iTmp) + return rc; + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_OUT_OF_RANGE, "value %RI64 does not fit in 32 bits", iTmp); + } + return a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonValueQueryInteger failed with %Rrc", rc); + } + + if (enmType == RTJSONVALTYPE_NULL) + { + m_fNullIndicator = true; + return VINF_SUCCESS; + } + + /* This is probably non-sense... */ + if (enmType == RTJSONVALTYPE_TRUE) + m_iValue = 1; + + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_REST_WRONG_JSON_TYPE_FOR_INTEGER, "wrong JSON type %s for 32-bit integer", + RTJsonValueTypeName(RTJsonValueGetType(a_rCursor.m_hValue))); +} + + +int RTCRestInt32::toString(RTCString *a_pDst, uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) const RT_NOEXCEPT +{ + if (!(a_fFlags & kToString_Append)) + { + if (!m_fNullIndicator) + return a_pDst->printfNoThrow("%RI32", m_iValue); + return a_pDst->assignNoThrow(RT_STR_TUPLE("null")); + } + if (!m_fNullIndicator) + return a_pDst->appendPrintfNoThrow("%RI32", m_iValue); + return a_pDst->appendNoThrow(RT_STR_TUPLE("null")); +} + + +int RTCRestInt32::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo /*= NULL*/, + uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) RT_NOEXCEPT +{ + RT_NOREF(a_fFlags); + + m_iValue = 0; + m_fNullIndicator = false; + +/** @todo RTStrStripL and RTStrToInt32Full has a different idea what consitutes spaces... */ + int rc = RTStrToInt32Full(RTStrStripL(a_rValue.c_str()), 0, &m_iValue); + if (rc == VINF_SUCCESS || rc == VERR_TRAILING_SPACES) + return VINF_SUCCESS; + + if (a_rValue.startsWithWord("null", RTCString::CaseInsensitive)) + { + m_iValue = 0; + m_fNullIndicator = true; + return VINF_SUCCESS; + } + + return RTErrInfoSetF(a_pErrInfo, rc, "%s: error %Rrc parsing '%s' as int32_t", a_pszName, rc, a_rValue.c_str()); +} + + +RTCRestObjectBase::kTypeClass RTCRestInt32::typeClass() const RT_NOEXCEPT +{ + return kTypeClass_Int32; +} + + +const char *RTCRestInt32::typeName() const RT_NOEXCEPT +{ + return "int32_t"; +} + + + +/********************************************************************************************************************************* +* RTCRestInt16 implementation * +*********************************************************************************************************************************/ + +/** Factory method. */ +/*static*/ DECLCALLBACK(RTCRestObjectBase *) RTCRestInt16::createInstance(void) RT_NOEXCEPT +{ + return new (std::nothrow) RTCRestInt16(); +} + + +/** + * @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON + */ +/*static*/ DECLCALLBACK(int) +RTCRestInt16::deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT +{ + RTCRestObjectBase *pObj = createInstance(); + *a_ppInstance = pObj; + if (pObj) + return pObj->deserializeFromJson(a_rCursor); + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_NO_MEMORY, "Out of memory"); +} + + +/** Default constructor. */ +RTCRestInt16::RTCRestInt16() RT_NOEXCEPT + : RTCRestObjectBase() + , m_iValue(0) +{ +} + + +/** Copy constructor. */ +RTCRestInt16::RTCRestInt16(RTCRestInt16 const &a_rThat) RT_NOEXCEPT + : RTCRestObjectBase(a_rThat) + , m_iValue(a_rThat.m_iValue) +{ +} + + +/** From value constructor. */ +RTCRestInt16::RTCRestInt16(int16_t iValue) RT_NOEXCEPT + : RTCRestObjectBase() + , m_iValue(iValue) +{ +} + + +/** Destructor. */ +RTCRestInt16::~RTCRestInt16() +{ + /* nothing to do */ +} + + +/** Copy assignment operator. */ +RTCRestInt16 &RTCRestInt16::operator=(RTCRestInt16 const &a_rThat) RT_NOEXCEPT +{ + m_fNullIndicator = a_rThat.m_fNullIndicator; + m_iValue = a_rThat.m_iValue; + return *this; +} + + +int RTCRestInt16::assignCopy(RTCRestInt16 const &a_rThat) RT_NOEXCEPT +{ + m_fNullIndicator = a_rThat.m_fNullIndicator; + m_iValue = a_rThat.m_iValue; + return VINF_SUCCESS; +} + + +void RTCRestInt16::assignValue(int16_t a_iValue) RT_NOEXCEPT +{ + m_iValue = a_iValue; + m_fNullIndicator = false; +} + + +RTCRestObjectBase *RTCRestInt16::baseClone() const RT_NOEXCEPT +{ + return new (std::nothrow) RTCRestInt16(*this); +} + + +int RTCRestInt16::resetToDefault() RT_NOEXCEPT +{ + m_iValue = 0; + m_fNullIndicator = false; + return VINF_SUCCESS; +} + + +RTCRestOutputBase &RTCRestInt16::serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT +{ + if (!m_fNullIndicator) + a_rDst.printf("%RI16", m_iValue); + else + a_rDst.nullValue(); + return a_rDst; +} + + +int RTCRestInt16::deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT +{ + m_iValue = 0; + m_fNullIndicator = false; + + RTJSONVALTYPE enmType = RTJsonValueGetType(a_rCursor.m_hValue); + if (enmType == RTJSONVALTYPE_INTEGER) + { + int64_t iTmp = m_iValue; + int rc = RTJsonValueQueryInteger(a_rCursor.m_hValue, &iTmp); + if (RT_SUCCESS(rc)) + { + m_iValue = (int16_t)iTmp; + if (m_iValue == iTmp) + return rc; + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_OUT_OF_RANGE, "value %RI64 does not fit in 16 bits", iTmp); + } + return a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonValueQueryInteger failed with %Rrc", rc); + } + + if (enmType == RTJSONVALTYPE_NULL) + { + m_fNullIndicator = true; + return VINF_SUCCESS; + } + + /* This is probably non-sense... */ + if (enmType == RTJSONVALTYPE_TRUE) + m_iValue = 1; + + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_REST_WRONG_JSON_TYPE_FOR_INTEGER, "wrong JSON type %s for 16-bit integer", + RTJsonValueTypeName(RTJsonValueGetType(a_rCursor.m_hValue))); +} + + +int RTCRestInt16::toString(RTCString *a_pDst, uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) const RT_NOEXCEPT +{ + if (!(a_fFlags & kToString_Append)) + { + if (!m_fNullIndicator) + return a_pDst->printfNoThrow("%RI16", m_iValue); + return a_pDst->assignNoThrow(RT_STR_TUPLE("null")); + } + if (!m_fNullIndicator) + return a_pDst->appendPrintfNoThrow("%RI16", m_iValue); + return a_pDst->appendNoThrow(RT_STR_TUPLE("null")); +} + + +int RTCRestInt16::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo /*= NULL*/, + uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) RT_NOEXCEPT +{ + RT_NOREF(a_fFlags); + + m_iValue = 0; + m_fNullIndicator = false; + +/** @todo RTStrStripL and RTStrToInt16Full has a different idea what consitutes spaces... */ + int rc = RTStrToInt16Full(RTStrStripL(a_rValue.c_str()), 0, &m_iValue); + if (rc == VINF_SUCCESS || rc == VERR_TRAILING_SPACES) + return VINF_SUCCESS; + + if (a_rValue.startsWithWord("null", RTCString::CaseInsensitive)) + { + m_iValue = 0; + m_fNullIndicator = true; + return VINF_SUCCESS; + } + + return RTErrInfoSetF(a_pErrInfo, rc, "%s: error %Rrc parsing '%s' as int16_t", a_pszName, rc, a_rValue.c_str()); +} + + +RTCRestObjectBase::kTypeClass RTCRestInt16::typeClass() const RT_NOEXCEPT +{ + return kTypeClass_Int16; +} + + +const char *RTCRestInt16::typeName() const RT_NOEXCEPT +{ + return "int16_t"; +} + + + +/********************************************************************************************************************************* +* RTCRestDouble implementation * +*********************************************************************************************************************************/ + +/** Factory method. */ +/*static*/ DECLCALLBACK(RTCRestObjectBase *) RTCRestDouble::createInstance(void) RT_NOEXCEPT +{ + return new (std::nothrow) RTCRestDouble(); +} + + +/** + * @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON + */ +/*static*/ DECLCALLBACK(int) +RTCRestDouble::deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT +{ + RTCRestObjectBase *pObj = createInstance(); + *a_ppInstance = pObj; + if (pObj) + return pObj->deserializeFromJson(a_rCursor); + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_NO_MEMORY, "Out of memory"); +} + + +/** Default constructor. */ +RTCRestDouble::RTCRestDouble() RT_NOEXCEPT + : RTCRestObjectBase() + , m_rdValue(0.0) +{ +} + + +/** Copy constructor. */ +RTCRestDouble::RTCRestDouble(RTCRestDouble const &a_rThat) RT_NOEXCEPT + : RTCRestObjectBase(a_rThat) + , m_rdValue(a_rThat.m_rdValue) +{ +} + + +/** From value constructor. */ +RTCRestDouble::RTCRestDouble(double rdValue) RT_NOEXCEPT + : RTCRestObjectBase() + , m_rdValue(rdValue) +{ +} + + +/** Destructor. */ +RTCRestDouble::~RTCRestDouble() +{ + /* nothing to do */ +} + + +/** Copy assignment operator. */ +RTCRestDouble &RTCRestDouble::operator=(RTCRestDouble const &a_rThat) RT_NOEXCEPT +{ + m_fNullIndicator = a_rThat.m_fNullIndicator; + m_rdValue = a_rThat.m_rdValue; + return *this; +} + + +int RTCRestDouble::assignCopy(RTCRestDouble const &a_rThat) RT_NOEXCEPT +{ + m_fNullIndicator = a_rThat.m_fNullIndicator; + m_rdValue = a_rThat.m_rdValue; + return VINF_SUCCESS; +} + + +void RTCRestDouble::assignValue(double a_rdValue) RT_NOEXCEPT +{ + m_rdValue = a_rdValue; + m_fNullIndicator = false; +} + + +RTCRestObjectBase *RTCRestDouble::baseClone() const RT_NOEXCEPT +{ + return new (std::nothrow) RTCRestDouble(*this); +} + + +int RTCRestDouble::resetToDefault() RT_NOEXCEPT +{ + m_rdValue = 0.0; + m_fNullIndicator = false; + return VINF_SUCCESS; +} + + +RTCRestOutputBase &RTCRestDouble::serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT +{ + if (!m_fNullIndicator) + { + + /* Just a simple approximation here. */ + /** @todo Not 100% sure printf %g produces the right result for JSON floating point, but it'll have to do for now... */ + char szValue[128]; +#ifdef _MSC_VER + _snprintf(szValue, sizeof(szValue), "%.18g", m_rdValue); +#else + snprintf(szValue, sizeof(szValue), "%.18g", m_rdValue); +#endif + size_t cchValue = strlen(szValue); + while (cchValue > 0 && szValue[cchValue - 1] == '0') + cchValue--; + szValue[cchValue] = '\0'; + + a_rDst.printf("%s", szValue); + } + else + a_rDst.nullValue(); + return a_rDst; +} + + +int RTCRestDouble::deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT +{ + m_rdValue = 0.0; + m_fNullIndicator = false; + + RTJSONVALTYPE enmType = RTJsonValueGetType(a_rCursor.m_hValue); + if (enmType == RTJSONVALTYPE_NUMBER) + { + int rc = RTJsonValueQueryNumber(a_rCursor.m_hValue, &m_rdValue); + if (RT_SUCCESS(rc)) + return rc; + return a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonValueQueryNumber failed with %Rrc", rc); + } + + if (enmType == RTJSONVALTYPE_INTEGER) + { + int64_t iTmp = 0; + int rc = RTJsonValueQueryInteger(a_rCursor.m_hValue, &iTmp); + if (RT_SUCCESS(rc)) + { + m_rdValue = iTmp; + if ((int64_t)m_rdValue == iTmp) + return rc; + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_OUT_OF_RANGE, "value %RI64 does not fit in a double", iTmp); + } + return a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonValueQueryInteger failed with %Rrc", rc); + } + + if (enmType == RTJSONVALTYPE_NULL) + { + m_fNullIndicator = true; + return VINF_SUCCESS; + } + + /* This is probably non-sense... */ + if (enmType == RTJSONVALTYPE_TRUE) + m_rdValue = 1.0; + + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_REST_WRONG_JSON_TYPE_FOR_DOUBLE, "wrong JSON type %s for a double", + RTJsonValueTypeName(RTJsonValueGetType(a_rCursor.m_hValue))); +} + + +int RTCRestDouble::toString(RTCString *a_pDst, uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) const RT_NOEXCEPT +{ + if (!m_fNullIndicator) + { + /* Just a simple approximation here. */ + /** @todo Not 100% sure printf %g produces the right result for JSON floating point, but it'll have to do for now... */ + char szValue[128]; +#ifdef _MSC_VER + _snprintf(szValue, sizeof(szValue), "%.18g", m_rdValue); +#else + snprintf(szValue, sizeof(szValue), "%.18g", m_rdValue); +#endif + size_t cchValue = strlen(szValue); + while (cchValue > 0 && szValue[cchValue - 1] == '0') + cchValue--; + szValue[cchValue] = '\0'; + + if (!(a_fFlags & kToString_Append)) + return a_pDst->assignNoThrow(szValue, cchValue); + return a_pDst->appendNoThrow(szValue, cchValue); + } + + if (!(a_fFlags & kToString_Append)) + return a_pDst->assignNoThrow(RT_STR_TUPLE("null")); + return a_pDst->appendNoThrow(RT_STR_TUPLE("null")); +} + + +int RTCRestDouble::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo /*= NULL*/, + uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) RT_NOEXCEPT +{ + RT_NOREF(a_fFlags); + + if (a_rValue.startsWithWord("null", RTCString::CaseInsensitive)) + { + m_rdValue = 0.0; + m_fNullIndicator = true; + return VINF_SUCCESS; + } + + m_fNullIndicator = false; + + const char *pszValue = RTStrStripL(a_rValue.c_str()); + errno = 0; + char *pszNext = NULL; + m_rdValue = strtod(pszValue, &pszNext); + if (errno == 0 && pszNext != pszValue) + { + if (!pszNext || *pszNext == '\0') + return VINF_SUCCESS; + + while (RT_C_IS_SPACE(*pszNext)) + pszNext++; + if (*pszNext == '\0') + return VINF_SUCCESS; + + return RTErrInfoSetF(a_pErrInfo, VERR_TRAILING_CHARS, "%s: error VERR_TRAILING_CHARS parsing '%s' as double", + a_pszName, a_rValue.c_str()); + } + + if (!RT_C_IS_DIGIT(*pszValue) && *pszValue != '.') + return RTErrInfoSetF(a_pErrInfo, VERR_NO_DIGITS, "%s: error VERR_NO_DIGITS parsing '%s' as double", + a_pszName, a_rValue.c_str()); + int rc = RTErrConvertFromErrno(errno); + return RTErrInfoSetF(a_pErrInfo, rc, "%s: error %Rrc parsing '%s' as double", a_pszName, rc, a_rValue.c_str()); +} + + +RTCRestObjectBase::kTypeClass RTCRestDouble::typeClass() const RT_NOEXCEPT +{ + return kTypeClass_Double; +} + + +const char *RTCRestDouble::typeName() const RT_NOEXCEPT +{ + return "double"; +} + + + +/********************************************************************************************************************************* +* RTCRestString implementation * +*********************************************************************************************************************************/ + +/** Factory method. */ +/*static*/ DECLCALLBACK(RTCRestObjectBase *) RTCRestString::createInstance(void) RT_NOEXCEPT +{ + return new (std::nothrow) RTCRestString(); +} + + +/** + * @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON + */ +/*static*/ DECLCALLBACK(int) +RTCRestString::deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT +{ + RTCRestObjectBase *pObj = createInstance(); + *a_ppInstance = pObj; + if (pObj) + return pObj->deserializeFromJson(a_rCursor); + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_NO_MEMORY, "Out of memory"); +} + + +/** Default constructor. */ +RTCRestString::RTCRestString() RT_NOEXCEPT + : RTCRestObjectBase() + , RTCString() +{ +} + + +/** Copy constructor. */ +RTCRestString::RTCRestString(RTCRestString const &a_rThat) + : RTCRestObjectBase(a_rThat) + , RTCString(a_rThat) +{ +} + + +/** From value constructor. */ +RTCRestString::RTCRestString(RTCString const &a_rThat) + : RTCString(a_rThat) +{ +} + + +/** From value constructor. */ +RTCRestString::RTCRestString(const char *a_pszSrc) + : RTCRestObjectBase() + , RTCString(a_pszSrc) +{ +} + + +/** Destructor. */ +RTCRestString::~RTCRestString() +{ + /* nothing to do */ +} + + +int RTCRestString::assignCopy(RTCRestString const &a_rThat) RT_NOEXCEPT +{ + int rc = assignNoThrow(a_rThat); + m_fNullIndicator = a_rThat.m_fNullIndicator; + return rc; +} + + +int RTCRestString::assignCopy(RTCString const &a_rThat) RT_NOEXCEPT +{ + m_fNullIndicator = false; + return assignNoThrow(a_rThat); +} + + +int RTCRestString::assignCopy(const char *a_pszThat) RT_NOEXCEPT +{ + m_fNullIndicator = false; + return assignNoThrow(a_pszThat); +} + + +int RTCRestString::setNull() RT_NOEXCEPT +{ + RTCString::setNull(); + m_fNullIndicator = true; + return VINF_SUCCESS; +} + + +RTCRestObjectBase *RTCRestString::baseClone() const RT_NOEXCEPT +{ + RTCRestString *pClone = new (std::nothrow) RTCRestString(); + if (pClone) + { + int rc = pClone->assignCopy(*this); + if (RT_SUCCESS(rc)) + return pClone; + delete pClone; + } + return NULL; +} + + +int RTCRestString::resetToDefault() RT_NOEXCEPT +{ + RTCString::setNull(); + m_fNullIndicator = false; + return VINF_SUCCESS; +} + + +RTCRestOutputBase &RTCRestString::serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT +{ + if (!m_fNullIndicator) + a_rDst.printf("%RMjs", m_psz ? m_psz : ""); + else + a_rDst.nullValue(); + return a_rDst; +} + + +int RTCRestString::deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT +{ + m_fNullIndicator = false; + + RTJSONVALTYPE enmType = RTJsonValueGetType(a_rCursor.m_hValue); + if (enmType == RTJSONVALTYPE_STRING) + { + const char *pszValue = RTJsonValueGetString(a_rCursor.m_hValue); + const size_t cchValue = strlen(pszValue); + int rc = assignNoThrow(pszValue, cchValue); + if (RT_SUCCESS(rc)) + return VINF_SUCCESS; + return a_rCursor.m_pPrimary->addError(a_rCursor, rc, "no memory for %zu char long string", cchValue); + } + + RTCString::setNull(); + + if (enmType == RTJSONVALTYPE_NULL) + { + m_fNullIndicator = true; + return VINF_SUCCESS; + } + + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_REST_WRONG_JSON_TYPE_FOR_STRING, "wrong JSON type %s for string", + RTJsonValueTypeName(RTJsonValueGetType(a_rCursor.m_hValue))); +} + + +int RTCRestString::toString(RTCString *a_pDst, uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) const RT_NOEXCEPT +{ + /* Note! m_fNullIndicator == true: empty string. */ + if (!(a_fFlags & kToString_Append)) + return a_pDst->assignNoThrow(*this); + return a_pDst->appendNoThrow(*this); +} + + +int RTCRestString::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo /*= NULL*/, + uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) RT_NOEXCEPT +{ + RT_NOREF(a_fFlags); RT_NOREF(a_pszName); RT_NOREF(a_pErrInfo); + + /* Note! Unable to set m_fNullIndicator = true here. */ + m_fNullIndicator = false; + return assignNoThrow(a_rValue); +} + + +RTCRestObjectBase::kTypeClass RTCRestString::typeClass() const RT_NOEXCEPT +{ + return kTypeClass_String; +} + + +const char *RTCRestString::typeName() const RT_NOEXCEPT +{ + return "RTCString"; +} + + +int RTCRestString::assignNoThrow(const RTCString &a_rSrc) RT_NOEXCEPT +{ + m_fNullIndicator = false; + return RTCString::assignNoThrow(a_rSrc); +} + + +int RTCRestString::assignNoThrow(const char *a_pszSrc) RT_NOEXCEPT +{ + m_fNullIndicator = false; + return RTCString::assignNoThrow(a_pszSrc); +} + + +int RTCRestString::assignNoThrow(const RTCString &a_rSrc, size_t a_offSrc, size_t a_cchSrc /*= npos*/) RT_NOEXCEPT +{ + m_fNullIndicator = false; + return RTCString::assignNoThrow(a_rSrc, a_offSrc, a_cchSrc); +} + + +int RTCRestString::assignNoThrow(const char *a_pszSrc, size_t a_cchSrc) RT_NOEXCEPT +{ + m_fNullIndicator = false; + return RTCString::assignNoThrow(a_pszSrc, a_cchSrc); +} + + +int RTCRestString::assignNoThrow(size_t a_cTimes, char a_ch) RT_NOEXCEPT +{ + m_fNullIndicator = false; + return RTCString::assignNoThrow(a_cTimes, a_ch); +} + + +int RTCRestString::printfNoThrow(const char *pszFormat, ...) RT_NOEXCEPT +{ + m_fNullIndicator = false; + va_list va; + va_start(va, pszFormat); + int rc = RTCString::printfVNoThrow(pszFormat, va); + va_end(va); + return rc; +} + + +int RTCRestString::printfVNoThrow(const char *pszFormat, va_list va) RT_NOEXCEPT +{ + m_fNullIndicator = false; + return RTCString::printfVNoThrow(pszFormat, va); +} + + +RTCRestString &RTCRestString::operator=(const char *a_pcsz) +{ + m_fNullIndicator = false; + RTCString::operator=(a_pcsz); + return *this; +} + + +RTCRestString &RTCRestString::operator=(const RTCString &a_rThat) +{ + m_fNullIndicator = false; + RTCString::operator=(a_rThat); + return *this; +} + + +RTCRestString &RTCRestString::operator=(const RTCRestString &a_rThat) +{ + m_fNullIndicator = a_rThat.m_fNullIndicator; + RTCString::operator=(a_rThat); + return *this; +} + + +RTCRestString &RTCRestString::assign(const RTCString &a_rSrc) +{ + m_fNullIndicator = false; + RTCString::assign(a_rSrc); + return *this; +} + + +RTCRestString &RTCRestString::assign(const char *a_pszSrc) +{ + m_fNullIndicator = false; + RTCString::assign(a_pszSrc); + return *this; +} + + +RTCRestString &RTCRestString::assign(const RTCString &a_rSrc, size_t a_offSrc, size_t a_cchSrc /*= npos*/) +{ + m_fNullIndicator = false; + RTCString::assign(a_rSrc, a_offSrc, a_cchSrc); + return *this; +} + + +RTCRestString &RTCRestString::assign(const char *a_pszSrc, size_t a_cchSrc) +{ + m_fNullIndicator = false; + RTCString::assign(a_pszSrc, a_cchSrc); + return *this; +} + + +RTCRestString &RTCRestString::assign(size_t a_cTimes, char a_ch) +{ + m_fNullIndicator = false; + RTCString::assign(a_cTimes, a_ch); + return *this; +} + + +RTCRestString &RTCRestString::printf(const char *pszFormat, ...) +{ + m_fNullIndicator = false; + va_list va; + va_start(va, pszFormat); + RTCString::printfV(pszFormat, va); + va_end(va); + return *this; +} + + +RTCRestString &RTCRestString::printfV(const char *pszFormat, va_list va) +{ + m_fNullIndicator = false; + RTCString::printfV(pszFormat, va); + return *this; +} + + + +/********************************************************************************************************************************* +* RTCRestDate implementation * +*********************************************************************************************************************************/ +/*static*/ DECLCALLBACK(RTCRestObjectBase *) RTCRestDate::createInstance(void) RT_NOEXCEPT +{ + return new (std::nothrow) RTCRestDate(); +} + + +/** + * @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON + */ +/*static*/ DECLCALLBACK(int) +RTCRestDate::deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT +{ + RTCRestObjectBase *pObj = createInstance(); + *a_ppInstance = pObj; + if (pObj) + return pObj->deserializeFromJson(a_rCursor); + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_NO_MEMORY, "Out of memory"); +} + + +RTCRestDate::RTCRestDate() RT_NOEXCEPT + : RTCRestObjectBase() + , m_fTimeSpecOkay(false) + , m_enmFormat(kFormat_Invalid) + , m_strFormatted() +{ + RTTimeSpecSetNano(&m_TimeSpec, 0); + RT_ZERO(m_Exploded); + + /* Since we need to know the format, all date-time values default to 'null'. */ + m_fNullIndicator = true; +} + + +RTCRestDate::RTCRestDate(RTCRestDate const &a_rThat) + : RTCRestObjectBase(a_rThat) + , m_fTimeSpecOkay(a_rThat.m_fTimeSpecOkay) + , m_enmFormat(a_rThat.m_enmFormat) + , m_strFormatted(a_rThat.m_strFormatted) +{ + m_TimeSpec = a_rThat.m_TimeSpec; + m_Exploded = a_rThat.m_Exploded; +} + + +RTCRestDate::~RTCRestDate() +{ + /* nothing to do */ +} + + +RTCRestDate &RTCRestDate::operator=(RTCRestDate const &a_rThat) +{ + RTCRestObjectBase::operator=(a_rThat); + m_TimeSpec = a_rThat.m_TimeSpec; + m_Exploded = a_rThat.m_Exploded; + m_fTimeSpecOkay = a_rThat.m_fTimeSpecOkay; + m_enmFormat = a_rThat.m_enmFormat; + m_strFormatted = a_rThat.m_strFormatted; + return *this; +} + + +int RTCRestDate::assignCopy(RTCRestDate const &a_rThat) RT_NOEXCEPT +{ + m_fNullIndicator = a_rThat.m_fNullIndicator; + m_TimeSpec = a_rThat.m_TimeSpec; + m_Exploded = a_rThat.m_Exploded; + m_fTimeSpecOkay = a_rThat.m_fTimeSpecOkay; + m_enmFormat = a_rThat.m_enmFormat; + return m_strFormatted.assignNoThrow(a_rThat.m_strFormatted); +} + + +RTCRestObjectBase *RTCRestDate::baseClone() const RT_NOEXCEPT +{ + RTCRestDate *pClone = new (std::nothrow) RTCRestDate(); + if (pClone) + { + int rc = pClone->assignCopy(*this); + if (RT_SUCCESS(rc)) + return pClone; + delete pClone; + } + return NULL; +} + + +int RTCRestDate::resetToDefault() RT_NOEXCEPT +{ + m_fNullIndicator = true; + RTTimeSpecSetNano(&m_TimeSpec, 0); + RT_ZERO(m_Exploded); + m_fTimeSpecOkay = false; + m_strFormatted.setNull(); + /*m_enmFormat - leave as hint. */ + return VINF_SUCCESS; +} + + +RTCRestOutputBase &RTCRestDate::serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT +{ + if (m_fNullIndicator) + a_rDst.nullValue(); + else + a_rDst.printf("%RMjs", m_strFormatted.c_str()); + return a_rDst; +} + + +int RTCRestDate::deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT +{ + setNull(); + + RTJSONVALTYPE enmType = RTJsonValueGetType(a_rCursor.m_hValue); + if (enmType == RTJSONVALTYPE_STRING) + { + int rc = m_strFormatted.assignNoThrow(RTJsonValueGetString(a_rCursor.m_hValue)); + AssertRCReturn(rc, rc); + + m_fNullIndicator = false; + rc = decodeFormattedString(m_enmFormat); + if (RT_SUCCESS(rc)) + return rc; + if (m_enmFormat != kFormat_Invalid) + { + rc = decodeFormattedString(); + if (RT_SUCCESS(rc)) + return rc; + } + return a_rCursor.m_pPrimary->addError(a_rCursor, VWRN_REST_UNABLE_TO_DECODE_DATE, + "Unable to decode date value: %s", m_strFormatted.c_str()); + } + + if (enmType == RTJSONVALTYPE_NULL) + return VINF_SUCCESS; + + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_REST_WRONG_JSON_TYPE_FOR_DATE, "wrong JSON type for date: %s", + RTJsonValueTypeName(RTJsonValueGetType(a_rCursor.m_hValue))); +} + + +int RTCRestDate::toString(RTCString *a_pDst, uint32_t a_fFlags /*= 0*/) const RT_NOEXCEPT +{ + if (m_fNullIndicator) + { + if (a_fFlags & kToString_Append) + return a_pDst->appendNoThrow(RT_STR_TUPLE("null")); + return a_pDst->assignNoThrow(RT_STR_TUPLE("null")); + } + if (a_fFlags & kToString_Append) + return a_pDst->appendNoThrow(m_strFormatted); + return a_pDst->assignNoThrow(m_strFormatted); +} + + +int RTCRestDate::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo /*= NULL*/, + uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) RT_NOEXCEPT +{ + setNull(); + if (a_rValue.startsWithWord("null", RTCString::CaseInsensitive)) + return VINF_SUCCESS; + + int rc = m_strFormatted.assignNoThrow(a_rValue); + AssertRCReturn(rc, rc); + + m_fNullIndicator = false; + rc = decodeFormattedString(m_enmFormat); + if (RT_SUCCESS(rc)) + return rc; + if (m_enmFormat != kFormat_Invalid) + { + rc = decodeFormattedString(); + if (RT_SUCCESS(rc)) + return rc; + } + RT_NOREF(a_fFlags); + return RTErrInfoSetF(a_pErrInfo, VERR_REST_UNABLE_TO_DECODE_DATE, + "Unable to decode date value (%s): %s", a_pszName, m_strFormatted.c_str()); +} + + +RTCRestObjectBase::kTypeClass RTCRestDate::typeClass(void) const RT_NOEXCEPT +{ + return kTypeClass_Date; +} + + +const char *RTCRestDate::typeName(void) const RT_NOEXCEPT +{ + return "RTCRestDate"; +} + + +int RTCRestDate::assignValue(PCRTTIMESPEC a_pTimeSpec, kFormat a_enmFormat) RT_NOEXCEPT +{ + AssertPtrReturn(a_pTimeSpec, VERR_INVALID_PARAMETER); + AssertReturn(a_enmFormat > kFormat_Invalid && a_enmFormat < kFormat_End, VERR_INVALID_PARAMETER); + + m_TimeSpec = *a_pTimeSpec; + return explodeAndFormat(a_enmFormat); +} + + +int RTCRestDate::assignValueRfc2822(PCRTTIMESPEC a_pTimeSpec) RT_NOEXCEPT +{ + AssertPtrReturn(a_pTimeSpec, VERR_INVALID_PARAMETER); + m_TimeSpec = *a_pTimeSpec; + return explodeAndFormat(kFormat_Rfc2822); +} + + +int RTCRestDate::assignValueRfc7131(PCRTTIMESPEC a_pTimeSpec) RT_NOEXCEPT +{ + AssertPtrReturn(a_pTimeSpec, VERR_INVALID_PARAMETER); + m_TimeSpec = *a_pTimeSpec; + return explodeAndFormat(kFormat_Rfc7131); +} + + +int RTCRestDate::assignValueRfc3339(PCRTTIMESPEC a_pTimeSpec) RT_NOEXCEPT +{ + AssertPtrReturn(a_pTimeSpec, VERR_INVALID_PARAMETER); + m_TimeSpec = *a_pTimeSpec; + return explodeAndFormat(kFormat_Rfc3339); +} + + +int RTCRestDate::assignNow(kFormat a_enmFormat) RT_NOEXCEPT +{ + RTTIMESPEC Now; + return assignValue(RTTimeNow(&Now), a_enmFormat); +} + + +int RTCRestDate::assignNowRfc2822() RT_NOEXCEPT +{ + RTTIMESPEC Now; + return assignValueRfc2822(RTTimeNow(&Now)); +} + + +int RTCRestDate::assignNowRfc7131() RT_NOEXCEPT +{ + RTTIMESPEC Now; + return assignValueRfc7131(RTTimeNow(&Now)); +} + + +int RTCRestDate::assignNowRfc3339() RT_NOEXCEPT +{ + RTTIMESPEC Now; + return assignValueRfc3339(RTTimeNow(&Now)); +} + + +int RTCRestDate::setFormat(kFormat a_enmFormat) RT_NOEXCEPT +{ + /* + * If this is a null object, just set the format as a hint for upcoming deserialization. + */ + if (m_fNullIndicator) + { + AssertReturn(a_enmFormat >= kFormat_Invalid && a_enmFormat < kFormat_End, VERR_INVALID_PARAMETER); + m_enmFormat = a_enmFormat; + return VINF_SUCCESS; + } + + /* + * If the tiem spec is okay, just reformat the string value accordingly. + */ + if (m_fTimeSpecOkay) + { + AssertReturn(a_enmFormat > kFormat_Invalid && a_enmFormat < kFormat_End, VERR_INVALID_PARAMETER); + if (a_enmFormat == m_enmFormat) + return VINF_SUCCESS; + return format(a_enmFormat); + } + + /* + * Try decode + */ + AssertReturn(a_enmFormat > kFormat_Invalid && a_enmFormat < kFormat_End, VERR_INVALID_PARAMETER); + return decodeFormattedString(a_enmFormat); +} + + +int RTCRestDate::explodeAndFormat(kFormat a_enmFormat) RT_NOEXCEPT +{ + RTTimeExplode(&m_Exploded, &m_TimeSpec); + return format(a_enmFormat); +} + + +/** + * Formats the m_Exploded value. + * + * Sets m_strFormatted, m_fTimeSpecOkay, and m_enmFormat, clears m_fNullIndicator. + * + * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY. + * @param a_enmFormat The format to use. + */ +int RTCRestDate::format(kFormat a_enmFormat) RT_NOEXCEPT +{ + m_fNullIndicator = false; + m_fTimeSpecOkay = true; + m_enmFormat = a_enmFormat; + int rc; + switch (a_enmFormat) + { + case kFormat_Rfc2822: + case kFormat_Rfc7131: + rc = m_strFormatted.reserveNoThrow(RTTIME_RFC2822_LEN); + AssertRCReturn(rc, rc); + RTTimeToRfc2822(&m_Exploded, m_strFormatted.mutableRaw(), m_strFormatted.capacity(), + a_enmFormat == kFormat_Rfc7131 ? RTTIME_RFC2822_F_GMT : 0); + m_strFormatted.jolt(); + return VINF_SUCCESS; + + case kFormat_Rfc3339: + case kFormat_Rfc3339_Fraction_2: + case kFormat_Rfc3339_Fraction_3: + case kFormat_Rfc3339_Fraction_6: + case kFormat_Rfc3339_Fraction_9: + rc = m_strFormatted.reserveNoThrow(RTTIME_STR_LEN); + AssertRCReturn(rc, rc); + RTTimeToStringEx(&m_Exploded, m_strFormatted.mutableRaw(), m_strFormatted.capacity(), + a_enmFormat == kFormat_Rfc3339 ? 0 + : a_enmFormat == kFormat_Rfc3339_Fraction_2 ? 2 + : a_enmFormat == kFormat_Rfc3339_Fraction_3 ? 3 + : a_enmFormat == kFormat_Rfc3339_Fraction_6 ? 6 : 9); + m_strFormatted.jolt(); + return VINF_SUCCESS; + + /* no default */ + case kFormat_Invalid: + case kFormat_End: + break; + } + AssertFailedReturn(VERR_REST_INTERNAL_ERROR_7); +} + + +/** + * Internal worker that attempts to decode m_strFormatted. + * + * Sets m_fTimeSpecOkay. + * + * @returns IPRT status code. + * @param enmFormat Specific format to try, kFormat_Invalid (default) to try guess it. + */ +int RTCRestDate::decodeFormattedString(kFormat enmFormat /*= kFormat_Invalid*/) RT_NOEXCEPT +{ + /* + * Take empty string to mean null. + */ + const char *pszTmp = RTStrStripL(m_strFormatted.c_str()); + if (*pszTmp == '\0') + { + setNull(); + return VINF_SUCCESS; + } + + switch (enmFormat) + { + case kFormat_Invalid: + { + size_t cch = strlen(pszTmp); + if (cch >= 6) + { + if ( !RT_C_IS_DIGIT(pszTmp[0]) + || RT_C_IS_SPACE(pszTmp[5]) + || RT_C_IS_SPACE(pszTmp[2]) + || RT_C_IS_SPACE(pszTmp[1]) + || RT_C_IS_SPACE(pszTmp[3]) + || RT_C_IS_SPACE(pszTmp[4])) + return decodeFormattedString(kFormat_Rfc2822); + return decodeFormattedString(kFormat_Rfc3339); + } + return VERR_REST_UNABLE_TO_DECODE_DATE; + } + + /* + * Examples: + * Fri, 31 Aug 2018 00:00:00 +0200 + * Mon, 3 Sep 2018 00:00:00 GMT + * Mon, 3 Sep 2018 00:00:00 -0000 + * 3 Sep 2018 00:00:00 -0000 (?) + * 3 Sep 2018 00:00:00 GMT (?) + */ + case kFormat_Rfc2822: + case kFormat_Rfc7131: + if (RTTimeFromRfc2822(&m_Exploded, pszTmp)) + { + RTTimeImplode(&m_TimeSpec, &m_Exploded); + + pszTmp = strchr(pszTmp, '\0'); + if (pszTmp[-1] == 'T' || pszTmp[-1] == 't') + m_enmFormat = kFormat_Rfc7131; + else + m_enmFormat = kFormat_Rfc2822; + m_fTimeSpecOkay = true; + return VINF_SUCCESS; + } + return VERR_REST_UNABLE_TO_DECODE_DATE; + + /* + * Examples: + * 2018-08-31T00:00:00+0200 + * 2018-09-03T00:00:00Z + * 2018-09-03T00:00:00+0000 + * 2018-09-03T00:00:00.123456789Z + */ + case kFormat_Rfc3339: + case kFormat_Rfc3339_Fraction_2: + case kFormat_Rfc3339_Fraction_3: + case kFormat_Rfc3339_Fraction_6: + case kFormat_Rfc3339_Fraction_9: + if (RTTimeFromString(&m_Exploded, pszTmp)) + { + RTTimeImplode(&m_TimeSpec, &m_Exploded); + + pszTmp = strchr(pszTmp, '.'); + if (!pszTmp) + m_enmFormat = kFormat_Rfc3339; + else + { + size_t cchFraction = 0; + pszTmp++; + while (RT_C_IS_DIGIT(pszTmp[cchFraction])) + cchFraction++; + if (cchFraction == 0) + m_enmFormat = kFormat_Rfc3339; + else if (cchFraction <= 2) + m_enmFormat = kFormat_Rfc3339_Fraction_2; + else if (cchFraction <= 3) + m_enmFormat = kFormat_Rfc3339_Fraction_3; + else if (cchFraction <= 6) + m_enmFormat = kFormat_Rfc3339_Fraction_6; + else + m_enmFormat = kFormat_Rfc3339_Fraction_9; + } + m_fTimeSpecOkay = true; + return VINF_SUCCESS; + } + return VERR_REST_UNABLE_TO_DECODE_DATE; + + /* no default */ + case kFormat_End: + break; + } + AssertFailedReturn(VERR_INVALID_PARAMETER); +} + + +/********************************************************************************************************************************* +* RTCRestStringEnumBase implementation * +*********************************************************************************************************************************/ + +/** Default constructor. */ +RTCRestStringEnumBase::RTCRestStringEnumBase() RT_NOEXCEPT + : RTCRestObjectBase() + , m_iEnumValue(0 /*invalid*/) + , m_strValue() +{ +} + + +/** Destructor. */ +RTCRestStringEnumBase::~RTCRestStringEnumBase() +{ + /* nothing to do */ +} + + +/** Copy constructor. */ +RTCRestStringEnumBase::RTCRestStringEnumBase(RTCRestStringEnumBase const &a_rThat) + : RTCRestObjectBase(a_rThat) + , m_iEnumValue(a_rThat.m_iEnumValue) + , m_strValue(a_rThat.m_strValue) +{ +} + + +/** Copy assignment operator. */ +RTCRestStringEnumBase &RTCRestStringEnumBase::operator=(RTCRestStringEnumBase const &a_rThat) +{ + RTCRestObjectBase::operator=(a_rThat); + m_iEnumValue = a_rThat.m_iEnumValue; + m_strValue = a_rThat.m_strValue; + return *this; +} + + +int RTCRestStringEnumBase::assignCopy(RTCRestStringEnumBase const &a_rThat) RT_NOEXCEPT +{ + m_fNullIndicator = a_rThat.m_fNullIndicator; + m_iEnumValue = a_rThat.m_iEnumValue; + return m_strValue.assignNoThrow(a_rThat.m_strValue); +} + + +int RTCRestStringEnumBase::resetToDefault() RT_NOEXCEPT +{ + m_iEnumValue = 0; /*invalid*/ + m_strValue.setNull(); + return VINF_SUCCESS; +} + + +RTCRestOutputBase &RTCRestStringEnumBase::serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT +{ + if (!m_fNullIndicator) + a_rDst.printf("%RMjs", getString()); + else + a_rDst.nullValue(); + return a_rDst; +} + + +int RTCRestStringEnumBase::deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT +{ + m_fNullIndicator = false; + m_iEnumValue = 0; + + RTJSONVALTYPE enmType = RTJsonValueGetType(a_rCursor.m_hValue); + if (enmType == RTJSONVALTYPE_STRING) + { + const char *pszValue = RTJsonValueGetString(a_rCursor.m_hValue); + const size_t cchValue = strlen(pszValue); + int rc = setByString(pszValue, cchValue); + if (RT_SUCCESS(rc)) + return rc; + return a_rCursor.m_pPrimary->addError(a_rCursor, rc, "no memory for %zu char long string", cchValue); + } + + m_strValue.setNull(); + if (enmType == RTJSONVALTYPE_NULL) + { + m_fNullIndicator = true; + return VINF_SUCCESS; + } + + return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_REST_WRONG_JSON_TYPE_FOR_STRING, "wrong JSON type %s for string/enum", + RTJsonValueTypeName(RTJsonValueGetType(a_rCursor.m_hValue))); +} + + +int RTCRestStringEnumBase::toString(RTCString *a_pDst, uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) const RT_NOEXCEPT +{ + if (!m_fNullIndicator) + { + if (m_iEnumValue > 0) + { + size_t cEntries = 0; + ENUMMAPENTRY const *paEntries = getMappingTable(&cEntries); + AssertReturn((unsigned)(m_iEnumValue - 1) < cEntries, VERR_REST_INTERNAL_ERROR_3); + Assert(paEntries[m_iEnumValue - 1].iValue == m_iEnumValue); + + if (a_fFlags & kToString_Append) + return a_pDst->appendNoThrow(paEntries[m_iEnumValue - 1].pszName, paEntries[m_iEnumValue - 1].cchName); + return a_pDst->assignNoThrow(paEntries[m_iEnumValue - 1].pszName, paEntries[m_iEnumValue - 1].cchName); + } + if (a_fFlags & kToString_Append) + return a_pDst->appendNoThrow(m_strValue); + return a_pDst->assignNoThrow(m_strValue); + } + if (a_fFlags & kToString_Append) + return a_pDst->appendNoThrow(RT_STR_TUPLE("null")); + return a_pDst->assignNoThrow(RT_STR_TUPLE("null")); +} + + +int RTCRestStringEnumBase::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo /*= NULL*/, + uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) RT_NOEXCEPT +{ + int iEnumValue = stringToEnum(a_rValue); + if (iEnumValue > 0) + { + m_iEnumValue = iEnumValue; + m_strValue.setNull(); + return VINF_SUCCESS; + } + + /* No translation. Check for null... */ + m_iEnumValue = 0; + if (a_rValue.startsWithWord("null", RTCString::CaseInsensitive)) + { + m_strValue.setNull(); + setNull(); + return VINF_SUCCESS; + } + + /* Try copy the string. */ + int rc = m_strValue.assignNoThrow(a_rValue); + if (RT_SUCCESS(rc)) + return VWRN_NOT_FOUND; + + RT_NOREF(a_pszName, a_pErrInfo, a_fFlags); + return rc; +} + + +RTCRestObjectBase::kTypeClass RTCRestStringEnumBase::typeClass(void) const RT_NOEXCEPT +{ + return kTypeClass_StringEnum; +} + + +int RTCRestStringEnumBase::setByString(const char *a_pszValue, size_t a_cchValue /*= RTSTR_MAX*/) RT_NOEXCEPT +{ + if (a_cchValue == RTSTR_MAX) + a_cchValue = strlen(a_pszValue); + int iEnumValue = stringToEnum(a_pszValue, a_cchValue); + if (iEnumValue > 0) + { + m_iEnumValue = iEnumValue; + m_strValue.setNull(); + return VINF_SUCCESS; + } + + /* No translation. */ + m_iEnumValue = 0; + int rc = m_strValue.assignNoThrow(a_pszValue, a_cchValue); + if (RT_SUCCESS(rc)) + return VWRN_NOT_FOUND; + return rc; +} + + +int RTCRestStringEnumBase::setByString(RTCString const &a_rValue) RT_NOEXCEPT +{ + return setByString(a_rValue.c_str(), a_rValue.length()); +} + + +const char *RTCRestStringEnumBase::getString() const RT_NOEXCEPT +{ + /* We ASSUME a certain mapping table layout here. */ + if (m_iEnumValue > 0) + { + size_t cEntries = 0; + ENUMMAPENTRY const *paEntries = getMappingTable(&cEntries); + AssertReturn((unsigned)(m_iEnumValue - 1) < cEntries, "<internal-error-#1>"); + Assert(paEntries[m_iEnumValue - 1].iValue == m_iEnumValue); + return paEntries[m_iEnumValue - 1].pszName; + } + + AssertReturn(m_iEnumValue == 0, "<internal-error-#2>"); + if (m_strValue.isEmpty()) + return "invalid"; + + return m_strValue.c_str(); +} + + +int RTCRestStringEnumBase::stringToEnum(const char *a_pszValue, size_t a_cchValue) RT_NOEXCEPT +{ + if (a_cchValue == RTSTR_MAX) + a_cchValue = strlen(a_pszValue); + + size_t cEntries = 0; + ENUMMAPENTRY const *paEntries = getMappingTable(&cEntries); + for (size_t i = 0; i < cEntries; i++) + if ( paEntries[i].cchName == a_cchValue + && memcmp(paEntries[i].pszName, a_pszValue, a_cchValue) == 0) + return paEntries[i].iValue; + return 0; +} + + +int RTCRestStringEnumBase::stringToEnum(RTCString const &a_rStrValue) RT_NOEXCEPT +{ + return stringToEnum(a_rStrValue.c_str(), a_rStrValue.length()); +} + + +const char *RTCRestStringEnumBase::enumToString(int a_iEnumValue, size_t *a_pcchString) RT_NOEXCEPT +{ + /* We ASSUME a certain mapping table layout here. */ + if (a_iEnumValue > 0) + { + size_t cEntries = 0; + ENUMMAPENTRY const *paEntries = getMappingTable(&cEntries); + if ((unsigned)(a_iEnumValue - 1) < cEntries) + { + Assert(paEntries[a_iEnumValue - 1].iValue == a_iEnumValue); + if (a_pcchString) + *a_pcchString = paEntries[a_iEnumValue - 1].cchName; + return paEntries[a_iEnumValue - 1].pszName; + } + } + /* Zero is the special invalid value. */ + else if (a_iEnumValue == 0) + { + if (a_pcchString) + *a_pcchString = 7; + return "invalid"; + } + return NULL; +} + + +bool RTCRestStringEnumBase::setWorker(int a_iEnumValue) RT_NOEXCEPT +{ + /* We ASSUME a certain mapping table layout here. */ + if (a_iEnumValue > 0) + { + size_t cEntries = 0; + ENUMMAPENTRY const *paEntries = getMappingTable(&cEntries); + AssertReturn((unsigned)(a_iEnumValue - 1) < cEntries, false); + Assert(paEntries[a_iEnumValue - 1].iValue == a_iEnumValue); + RT_NOREF(paEntries); + } + /* Zero is the special invalid value. */ + else if (a_iEnumValue != 0) + AssertFailedReturn(false); + + m_iEnumValue = a_iEnumValue; + m_strValue.setNull(); + return true; +} + + +RTCRestObjectBase *RTCRestStringEnumBase::cloneWorker(RTCRestStringEnumBase *a_pDst) const RT_NOEXCEPT +{ + if (a_pDst) + { + int rc = a_pDst->assignCopy(*this); + if (RT_SUCCESS(rc)) + return a_pDst; + delete a_pDst; + } + return NULL; +} + + + +/********************************************************************************************************************************* +* RTCRestDataObject * +*********************************************************************************************************************************/ + +RTCRestDataObject::RTCRestDataObject() RT_NOEXCEPT + : RTCRestObjectBase() + , m_fIsSet(0) +{ +} + + +RTCRestDataObject::~RTCRestDataObject() +{ +} + + +RTCRestDataObject::RTCRestDataObject(RTCRestDataObject const &a_rThat) RT_NOEXCEPT + : RTCRestObjectBase(a_rThat) + , m_fIsSet(a_rThat.m_fIsSet) +{ +} + + +RTCRestDataObject &RTCRestDataObject::operator=(RTCRestDataObject const &a_rThat) RT_NOEXCEPT +{ + m_fNullIndicator = a_rThat.m_fNullIndicator; + m_fIsSet = a_rThat.m_fIsSet; + return *this; +} + + +int RTCRestDataObject::assignCopy(RTCRestDataObject const &a_rThat) RT_NOEXCEPT +{ + m_fNullIndicator = a_rThat.m_fNullIndicator; + m_fIsSet = a_rThat.m_fIsSet; + return VINF_SUCCESS; +} + + +int RTCRestDataObject::resetToDefault() RT_NOEXCEPT +{ + m_fNullIndicator = false; + m_fIsSet = 0; + return VINF_SUCCESS; +} + + +RTCRestOutputBase &RTCRestDataObject::serializeMembersAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT +{ + RT_NOREF(a_rDst); + return a_rDst; +} + + +RTCRestOutputBase &RTCRestDataObject::serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT +{ + if (!m_fNullIndicator) + { + uint32_t const uOldState = a_rDst.beginObject(); + serializeMembersAsJson(a_rDst); + a_rDst.endObject(uOldState); + } + else + a_rDst.nullValue(); + return a_rDst; +} + + +int RTCRestDataObject::deserializeMemberFromJson(RTCRestJsonCursor const &a_rCursor, size_t a_cchName) RT_NOEXCEPT +{ + RT_NOREF(a_rCursor, a_cchName); + return VERR_NOT_FOUND; +} + + +int RTCRestDataObject::deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT +{ + if (RTJsonValueGetType(a_rCursor.m_hValue) == RTJSONVALTYPE_NULL) + { + setNull(); + return VINF_SUCCESS; + } + + /* + * Make sure the object starts out with default values. + */ + if (m_fIsSet == 0) + m_fNullIndicator = false; + else + resetToDefault(); + + /* + * Iterate the object values. + */ + RTJSONIT hIterator; + int rcRet = RTJsonIteratorBeginObject(a_rCursor.m_hValue, &hIterator); + if (RT_SUCCESS(rcRet)) + { + for (;;) + { + RTCRestJsonCursor SubCursor(a_rCursor); + int rc = RTJsonIteratorQueryValue(hIterator, &SubCursor.m_hValue, &SubCursor.m_pszName); + if (RT_SUCCESS(rc)) + { + size_t const cchName = strlen(SubCursor.m_pszName); + + rc = deserializeMemberFromJson(SubCursor, cchName); + if (rc == VINF_SUCCESS) + { /* likely */ } + else if (rc == VERR_NOT_FOUND) + { + rc = SubCursor.m_pPrimary->unknownField(SubCursor); + if (rcRet == VINF_SUCCESS) + rcRet = rc; + } + else if (RT_SUCCESS(rc)) + { + if (rcRet == VINF_SUCCESS) + rcRet = rc; + } + else if (RT_SUCCESS(rcRet)) + rcRet = rc; + } + else + rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonIteratorQueryValue failed: %Rrc", rc); + + /* + * Advance. + */ + rc = RTJsonIteratorNext(hIterator); + if (RT_SUCCESS(rc)) + { /* likely */ } + else if (rc == VERR_JSON_ITERATOR_END) + break; + else + { + rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonIteratorNext failed: %Rrc", rc); + break; + } + } + + RTJsonIteratorFree(hIterator); + } + else if ( rcRet == VERR_JSON_VALUE_INVALID_TYPE + && RTJsonValueGetType(a_rCursor.m_hValue) == RTJSONVALTYPE_NULL) + { + m_fNullIndicator = true; + rcRet = VINF_SUCCESS; + } + else + rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rcRet, "RTJsonIteratorBeginObject failed: %Rrc (type %s)", + rcRet, RTJsonValueTypeName(RTJsonValueGetType(a_rCursor.m_hValue))); + return rcRet; +} + + +RTCRestObjectBase::kTypeClass RTCRestDataObject::typeClass(void) const RT_NOEXCEPT +{ + return kTypeClass_DataObject; +} + + + +/********************************************************************************************************************************* +* RTCRestPolyDataObject * +*********************************************************************************************************************************/ + +RTCRestPolyDataObject::RTCRestPolyDataObject() RT_NOEXCEPT + : RTCRestDataObject() +{ +} + + +RTCRestPolyDataObject::RTCRestPolyDataObject(RTCRestPolyDataObject const &a_rThat) RT_NOEXCEPT + : RTCRestDataObject(a_rThat) +{ +} + + +RTCRestPolyDataObject::~RTCRestPolyDataObject() +{ +} + + +int RTCRestPolyDataObject::resetToDefault() RT_NOEXCEPT +{ + return RTCRestDataObject::resetToDefault(); +} + + +bool RTCRestPolyDataObject::isChild() const RT_NOEXCEPT +{ + return false; +} + + +RTCRestPolyDataObject &RTCRestPolyDataObject::operator=(RTCRestPolyDataObject const &a_rThat) RT_NOEXCEPT +{ + RTCRestDataObject::operator=(a_rThat); + return *this; +} + |