VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/rest/RTCRestStringMapBase.cpp@ 74525

Last change on this file since 74525 was 74525, checked in by vboxsync, 6 years ago

IPRT/rest: RTCRestStringMapBase::deserializeFromJson - fix edito,
deserialize from subcursor that points into the object, not from the
original cursor that still points to the whole object.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.5 KB
Line 
1/* $Id: RTCRestStringMapBase.cpp 74525 2018-09-28 14:46:09Z vboxsync $ */
2/** @file
3 * IPRT - C++ REST, RTCRestStringMapBase implementation.
4 */
5
6/*
7 * Copyright (C) 2018 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_REST
32#include <iprt/cpp/reststringmap.h>
33
34#include <iprt/err.h>
35#include <iprt/string.h>
36#include <iprt/cpp/restoutput.h>
37
38
39/**
40 * Default destructor.
41 */
42RTCRestStringMapBase::RTCRestStringMapBase() RT_NOEXCEPT
43 : RTCRestObjectBase()
44 , m_Map(NULL)
45 , m_cEntries(0)
46{
47 RTListInit(&m_ListHead);
48}
49
50
51#if 0 /* trigger link error for now. */
52/** Copy constructor. */
53RTCRestStringMapBase::RTCRestStringMapBase(RTCRestStringMapBase const &a_rThat);
54#endif
55
56
57/**
58 * Destructor.
59 */
60RTCRestStringMapBase::~RTCRestStringMapBase()
61{
62 clear();
63}
64
65
66
67#if 0 /* trigger link error for now. */
68/** Copy assignment operator. */
69RTCRestStringMapBase &RTCRestStringMapBase::operator=(RTCRestStringMapBase const &a_rThat);
70#endif
71
72
73/*********************************************************************************************************************************
74* Overridden base object methods *
75*********************************************************************************************************************************/
76
77RTCRestObjectBase *RTCRestStringMapBase::baseClone() const RT_NOEXCEPT
78{
79 RTCRestStringMapBase *pClone = createClone();
80 if (pClone)
81 {
82 int rc = pClone->copyMapWorkerNoThrow(*this);
83 if (RT_SUCCESS(rc))
84 return pClone;
85 delete pClone;
86 }
87 return NULL;
88}
89
90
91int RTCRestStringMapBase::resetToDefault() RT_NOEXCEPT
92{
93 /* Default is an empty map. */
94 clear();
95 m_fNullIndicator = false;
96 return VINF_SUCCESS;
97}
98
99
100RTCRestOutputBase &RTCRestStringMapBase::serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT
101{
102 if (!m_fNullIndicator)
103 {
104 uint32_t const uOldState = a_rDst.beginObject();
105 MapEntry const *pCur;
106 RTListForEachCpp(&m_ListHead, pCur, MapEntry, ListEntry)
107 {
108 a_rDst.valueSeparatorAndName(pCur->strKey.c_str(), pCur->strKey.length());
109 pCur->pValue->serializeAsJson(a_rDst);
110 }
111 a_rDst.endArray(uOldState);
112 }
113 else
114 a_rDst.nullValue();
115 return a_rDst;
116}
117
118
119int RTCRestStringMapBase::deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT
120{
121 /*
122 * Make sure the object starts out with an empty map.
123 */
124 if (m_cEntries > 0)
125 clear();
126 m_fNullIndicator = false;
127
128 /*
129 * Iterate the object values.
130 */
131 RTJSONIT hIterator;
132 int rcRet = RTJsonIteratorBeginObject(a_rCursor.m_hValue, &hIterator);
133 if (RT_SUCCESS(rcRet))
134 {
135 for (;;)
136 {
137 /* Set up the sub-cursor. */
138 RTCRestJsonCursor SubCursor(a_rCursor);
139 int rc = RTJsonIteratorQueryValue(hIterator, &SubCursor.m_hValue, &SubCursor.m_pszName);
140 if (RT_SUCCESS(rc))
141 {
142 /* Call the static deserializeInstanceFromJson method of the value class. */
143 RTCRestObjectBase *pObj = NULL;
144 rc = deserializeValueInstanceFromJson(SubCursor, &pObj);
145 if (RT_SUCCESS(rc))
146 Assert(pObj);
147 else if (RT_SUCCESS(rcRet))
148 rcRet = rc;
149 if (pObj)
150 {
151 /* Insert the value. */
152 rc = putWorker(SubCursor.m_pszName, pObj, true /*a_fReplace*/);
153 if (rc == VINF_SUCCESS)
154 { /* likely */ }
155 else if (RT_SUCCESS(rc))
156 {
157 a_rCursor.m_pPrimary->addError(a_rCursor, rc, "warning %Rrc inserting '%s' into map",
158 rc, SubCursor.m_pszName);
159 if (rcRet == VINF_SUCCESS)
160 rcRet = rc;
161 }
162 else
163 {
164 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "Failed to insert '%s' into map: %Rrc",
165 SubCursor.m_pszName, rc);
166 delete pObj;
167 }
168 }
169 }
170 else
171 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonIteratorQueryValue failed: %Rrc", rc);
172
173 /*
174 * Advance.
175 */
176 rc = RTJsonIteratorNext(hIterator);
177 if (RT_SUCCESS(rc))
178 { /* likely */ }
179 else if (rc == VERR_JSON_ITERATOR_END)
180 break;
181 else
182 {
183 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonIteratorNext failed: %Rrc", rc);
184 break;
185 }
186 }
187
188 RTJsonIteratorFree(hIterator);
189 }
190 else if (rcRet == VERR_JSON_IS_EMPTY)
191 rcRet = VINF_SUCCESS;
192 else if ( rcRet == VERR_JSON_VALUE_INVALID_TYPE
193 && RTJsonValueGetType(a_rCursor.m_hValue) == RTJSONVALTYPE_NULL)
194 {
195 m_fNullIndicator = true;
196 rcRet = VINF_SUCCESS;
197 }
198 else
199 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rcRet, "RTJsonIteratorBegin failed: %Rrc (type %s)",
200 rcRet, RTJsonValueTypeName(RTJsonValueGetType(a_rCursor.m_hValue)));
201 return rcRet;
202}
203
204// later?
205// virtual int RTCRestStringMapBase::toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const ;
206// virtual int RTCRestStringMapBase::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL,
207// uint32_t a_fFlags = kCollectionFormat_Unspecified) ;
208//
209
210
211RTCRestObjectBase::kTypeClass RTCRestStringMapBase::typeClass(void) const RT_NOEXCEPT
212{
213 return kTypeClass_StringMap;
214}
215
216
217const char *RTCRestStringMapBase::typeName(void) const RT_NOEXCEPT
218{
219 return "RTCRestStringMap<ValueType>";
220}
221
222
223/*********************************************************************************************************************************
224* Generic map methods *
225*********************************************************************************************************************************/
226
227/**
228 * @callback_method_impl{FNRTSTRSPACECALLBACK}
229 */
230/*static*/ DECLCALLBACK(int) RTCRestStringMapBase::stringSpaceDestructorCallback(PRTSTRSPACECORE pStr, void *pvUser) RT_NOEXCEPT
231{
232 MapEntry *pNode = (MapEntry *)pStr;
233 if (pNode->pValue)
234 {
235 delete pNode->pValue;
236 pNode->pValue = NULL;
237 }
238 pNode->strKey.setNull();
239 delete pNode;
240
241 RT_NOREF(pvUser);
242 return VINF_SUCCESS;
243}
244
245
246void RTCRestStringMapBase::clear() RT_NOEXCEPT
247{
248 RTStrSpaceDestroy(&m_Map, stringSpaceDestructorCallback, NULL);
249 RTListInit(&m_ListHead);
250 m_cEntries = 0;
251 m_fNullIndicator = false;
252}
253
254
255size_t RTCRestStringMapBase::size() const RT_NOEXCEPT
256{
257 return m_cEntries;
258}
259
260
261bool RTCRestStringMapBase::containsKey(const char *a_pszKey) const RT_NOEXCEPT
262{
263 return RTStrSpaceGet((PRTSTRSPACE)&m_Map, a_pszKey) != NULL;
264}
265
266
267bool RTCRestStringMapBase::containsKey(RTCString const &a_rStrKey) const RT_NOEXCEPT
268{
269 return containsKey(a_rStrKey.c_str());
270}
271
272
273bool RTCRestStringMapBase::remove(const char *a_pszKey) RT_NOEXCEPT
274{
275 MapEntry *pRemoved = (MapEntry *)RTStrSpaceRemove(&m_Map, a_pszKey);
276 if (pRemoved)
277 {
278 m_cEntries--;
279 RTListNodeRemove(&pRemoved->ListEntry);
280 stringSpaceDestructorCallback(&pRemoved->Core, NULL);
281 return true;
282 }
283 return false;
284}
285
286
287bool RTCRestStringMapBase::remove(RTCString const &a_rStrKey) RT_NOEXCEPT
288{
289 return remove(a_rStrKey.c_str());
290}
291
292
293int RTCRestStringMapBase::putNewValue(RTCRestObjectBase **a_ppValue, const char *a_pszKey, size_t a_cchKey /*= RTSTR_MAX*/,
294 bool a_fReplace /*= false*/) RT_NOEXCEPT
295{
296 RTCRestObjectBase *pValue = createValue();
297 if (pValue)
298 {
299 int rc = putWorker(a_pszKey, pValue, a_fReplace, a_cchKey);
300 if (RT_SUCCESS(rc))
301 *a_ppValue = pValue;
302 else
303 {
304 delete pValue;
305 *a_ppValue = NULL;
306 }
307 return rc;
308 }
309 *a_ppValue = NULL;
310 return VERR_NO_MEMORY;
311}
312
313
314int RTCRestStringMapBase::putNewValue(RTCRestObjectBase **a_ppValue, RTCString const &a_rStrKey, bool a_fReplace /*= false*/) RT_NOEXCEPT
315{
316 return putNewValue(a_ppValue, a_rStrKey.c_str(), a_rStrKey.length(), a_fReplace);
317}
318
319
320/*********************************************************************************************************************************
321* Protected methods *
322*********************************************************************************************************************************/
323
324int RTCRestStringMapBase::copyMapWorkerNoThrow(RTCRestStringMapBase const &a_rThat) RT_NOEXCEPT
325{
326 Assert(this != &a_rThat);
327 clear();
328 m_fNullIndicator = a_rThat.m_fNullIndicator;
329
330 if (!a_rThat.m_fNullIndicator)
331 {
332 MapEntry const *pCur;
333 RTListForEachCpp(&a_rThat.m_ListHead, pCur, MapEntry, ListEntry)
334 {
335 int rc = putCopyWorker(pCur->strKey.c_str(), *pCur->pValue, true /*a_fReplace*/);
336 if (RT_SUCCESS(rc))
337 { /* likely */ }
338 else
339 return rc;
340 }
341 }
342
343 return VINF_SUCCESS;
344}
345
346
347void RTCRestStringMapBase::copyMapWorkerMayThrow(RTCRestStringMapBase const &a_rThat)
348{
349 int rc = copyMapWorkerNoThrow(a_rThat);
350 if (RT_SUCCESS(rc))
351 return;
352 throw std::bad_alloc();
353}
354
355
356int RTCRestStringMapBase::putWorker(const char *a_pszKey, RTCRestObjectBase *a_pValue, bool a_fReplace,
357 size_t a_cchKey /*= RTSTR_MAX*/) RT_NOEXCEPT
358{
359 int rc;
360 MapEntry *pEntry = new (std::nothrow) MapEntry;
361 if (pEntry)
362 {
363 rc = pEntry->strKey.assignNoThrow(a_pszKey, a_cchKey);
364 if (RT_SUCCESS(rc))
365 {
366 pEntry->Core.pszString = pEntry->strKey.c_str();
367 pEntry->Core.cchString = pEntry->strKey.length();
368 pEntry->pValue = a_pValue;
369 if (RTStrSpaceInsert(&m_Map, &pEntry->Core))
370 {
371 RTListAppend(&m_ListHead, &pEntry->ListEntry);
372 m_cEntries++;
373 m_fNullIndicator = false;
374 return VINF_SUCCESS;
375 }
376
377 Assert(!m_fNullIndicator);
378 if (!a_fReplace)
379 rc = VERR_ALREADY_EXISTS;
380 else
381 {
382 /* Just replace the pValue in the existing entry. */
383 MapEntry *pCollision = (MapEntry *)RTStrSpaceGet(&m_Map, a_pszKey);
384 if (pCollision)
385 {
386 if (pCollision->pValue)
387 delete pCollision->pValue;
388 pCollision->pValue = a_pValue;
389 pEntry->pValue = NULL; /* paranoia */
390 rc = VWRN_ALREADY_EXISTS;
391 }
392 else
393 rc = VERR_INTERNAL_ERROR;
394 }
395 }
396 delete pEntry;
397 }
398 else
399 rc = VERR_NO_MEMORY;
400 return rc;
401}
402
403
404int RTCRestStringMapBase::putCopyWorker(const char *a_pszKey, RTCRestObjectBase const &a_rValue, bool a_fReplace,
405 size_t a_cchKey /*= RTSTR_MAX*/) RT_NOEXCEPT
406{
407 int rc;
408 RTCRestObjectBase *pValueCopy = a_rValue.baseClone();
409 if (pValueCopy)
410 {
411 rc = putWorker(a_pszKey, pValueCopy, a_fReplace, a_cchKey);
412 if (RT_SUCCESS(rc))
413 { /* likely */ }
414 else
415 delete pValueCopy;
416 }
417 else
418 rc = VERR_NO_MEMORY;
419 return rc;
420}
421
422
423RTCRestObjectBase *RTCRestStringMapBase::getWorker(const char *a_pszKey) RT_NOEXCEPT
424{
425 MapEntry *pHit = (MapEntry *)RTStrSpaceGet(&m_Map, a_pszKey);
426 if (pHit)
427 return pHit->pValue;
428 return NULL;
429}
430
431
432RTCRestObjectBase const *RTCRestStringMapBase::getWorker(const char *a_pszKey) const RT_NOEXCEPT
433{
434 MapEntry const *pHit = (MapEntry const *)RTStrSpaceGet((PRTSTRSPACE)&m_Map, a_pszKey);
435 if (pHit)
436 return pHit->pValue;
437 return NULL;
438}
439
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette