summaryrefslogtreecommitdiffstats
path: root/src/VBox/Runtime/common/rest/rest-primary-object-types.cpp
diff options
context:
space:
mode:
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.cpp2403
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;
+}
+