VirtualBox

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

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

IPRT/rest: Added RTJsonIteratorBeginArray and RTJsonIteratorBeginObject for more accurate JSON decoding. Early RTCRestArray implementation. bugref:9167

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.8 KB
Line 
1/* $Id: RTCRestStringMapBase.cpp 73956 2018-08-29 15:09:34Z 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#include <iprt/cpp/restbase.h>
32
33#include <iprt/err.h>
34#include <iprt/string.h>
35
36
37/**
38 * Default destructor.
39 */
40RTCRestStringMapBase::RTCRestStringMapBase()
41 : m_Map(NULL)
42 , m_cEntries(0)
43{
44 RTListInit(&m_ListHead);
45}
46
47
48#if 0 /* trigger link error for now. */
49/** Copy constructor. */
50RTCRestStringMapBase::RTCRestStringMapBase(RTCRestStringMapBase const &a_rThat);
51#endif
52
53
54/**
55 * Destructor.
56 */
57RTCRestStringMapBase::~RTCRestStringMapBase()
58{
59 clear();
60}
61
62
63
64#if 0 /* trigger link error for now. */
65/** Copy assignment operator. */
66RTCRestStringMapBase &RTCRestStringMapBase::operator=(RTCRestStringMapBase const &a_rThat);
67#endif
68
69
70/*********************************************************************************************************************************
71* Overridden base object methods *
72*********************************************************************************************************************************/
73
74void RTCRestStringMapBase::resetToDefault()
75{
76 /* Default is an empty map. */
77 clear();
78}
79
80
81RTCRestOutputBase &RTCRestStringMapBase::serializeAsJson(RTCRestOutputBase &a_rDst) const
82{
83 a_rDst.printf("{\n");
84 unsigned const uOldIndent = a_rDst.incrementIndent();
85
86 MapEntry const * const pLast = RTListGetLastCpp(&m_ListHead, MapEntry, ListEntry);
87 MapEntry const * pCur;
88 RTListForEachCpp(&m_ListHead, pCur, MapEntry, ListEntry)
89 {
90 a_rDst.printf("%RJs: ", pCur->strKey.c_str());
91 pCur->pValue->serializeAsJson(a_rDst);
92
93 if (pCur != pLast)
94 a_rDst.printf(",\n");
95 else
96 a_rDst.printf("\n");
97 }
98
99 a_rDst.setIndent(uOldIndent);
100 a_rDst.printf("}");
101 return a_rDst;
102}
103
104
105int RTCRestStringMapBase::deserializeFromJson(RTCRestJsonCursor const &a_rCursor)
106{
107 /*
108 * Make sure the object starts out with an empty map.
109 */
110 if (m_cEntries > 0)
111 clear();
112
113 /*
114 * Iterate the object values.
115 */
116 RTJSONIT hIterator;
117 int rcRet = RTJsonIteratorBeginObject(a_rCursor.m_hValue, &hIterator);
118 if (RT_SUCCESS(rcRet))
119 {
120 for (;;)
121 {
122 RTCRestJsonCursor SubCursor(a_rCursor);
123 int rc = RTJsonIteratorQueryValue(hIterator, &SubCursor.m_hValue, &SubCursor.m_pszName);
124 if (RT_SUCCESS(rc))
125 {
126 RTCRestObjectBase *pObj = createValue();
127 if (pObj)
128 {
129 rc = pObj->deserializeFromJson(SubCursor);
130 if (RT_SUCCESS(rc))
131 { /* likely */ }
132 else if (RT_SUCCESS(rcRet))
133 rcRet = rc;
134
135 rc = putWorker(SubCursor.m_pszName, pObj, true /*a_fReplace*/);
136 if (rc == VINF_SUCCESS)
137 { /* likely */ }
138 else if (RT_SUCCESS(rc))
139 {
140 a_rCursor.m_pPrimary->addError(a_rCursor, rc, "warning %Rrc inserting '%s' into map",
141 rc, SubCursor.m_pszName);
142 if (rcRet == VINF_SUCCESS)
143 rcRet = rc;
144 }
145 else
146 {
147 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "Failed to insert '%s' into map: %Rrc",
148 SubCursor.m_pszName, rc);
149 delete pObj;
150 }
151 }
152 else
153 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "Failed to create new value object");
154 }
155 else
156 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonIteratorQueryValue failed: %Rrc", rc);
157
158 /*
159 * Advance.
160 */
161 rc = RTJsonIteratorNext(hIterator);
162 if (RT_SUCCESS(rc))
163 { /* likely */ }
164 else if (rc == VERR_JSON_ITERATOR_END)
165 break;
166 else
167 {
168 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonIteratorNext failed: %Rrc", rc);
169 break;
170 }
171 }
172
173 RTJsonIteratorFree(hIterator);
174 }
175 else
176 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rcRet, "RTJsonIteratorBegin failed: %Rrc", rcRet);
177 return rcRet;
178}
179
180// later?
181// virtual int RTCRestStringMapBase::toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const ;
182// virtual int RTCRestStringMapBase::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL,
183// uint32_t a_fFlags = kCollectionFormat_Unspecified) ;
184//
185
186
187/*********************************************************************************************************************************
188* Generic map methods *
189*********************************************************************************************************************************/
190
191/**
192 * @callback_method_impl{FNRTSTRSPACECALLBACK}
193 */
194/*static*/ DECLCALLBACK(int) RTCRestStringMapBase::stringSpaceDestructorCallback(PRTSTRSPACECORE pStr, void *pvUser)
195{
196 MapEntry *pNode = (MapEntry *)pStr;
197 if (pNode->pValue)
198 {
199 delete pNode->pValue;
200 pNode->pValue = NULL;
201 }
202 pNode->strKey.setNull();
203 delete pNode;
204
205 RT_NOREF(pvUser);
206 return VINF_SUCCESS;
207}
208
209
210void RTCRestStringMapBase::clear()
211{
212 RTStrSpaceDestroy(&m_Map, stringSpaceDestructorCallback, NULL);
213 RTListInit(&m_ListHead);
214 m_cEntries = 0;
215}
216
217
218size_t RTCRestStringMapBase::size() const
219{
220 return m_cEntries;
221}
222
223
224bool RTCRestStringMapBase::constainsKey(const char *a_pszKey) const
225{
226 return RTStrSpaceGet((PRTSTRSPACE)&m_Map, a_pszKey) != NULL;
227}
228
229
230bool RTCRestStringMapBase::constainsKey(RTCString const &a_rStrKey) const
231{
232 return constainsKey(a_rStrKey.c_str());
233}
234
235
236bool RTCRestStringMapBase::remove(const char *a_pszKey)
237{
238 PRTSTRSPACECORE pRemoved = RTStrSpaceRemove(&m_Map, a_pszKey);
239 if (pRemoved)
240 {
241 stringSpaceDestructorCallback(pRemoved, NULL);
242 return true;
243 }
244 return false;
245}
246
247
248bool RTCRestStringMapBase::remove(RTCString const &a_rStrKey)
249{
250 return remove(a_rStrKey.c_str());
251}
252
253
254/*********************************************************************************************************************************
255* Protected methods *
256*********************************************************************************************************************************/
257
258int RTCRestStringMapBase::copyMapWorker(RTCRestStringMapBase const &a_rThat, bool fThrow)
259{
260 Assert(this != &a_rThat);
261 clear();
262
263 MapEntry const *pCur;
264 RTListForEachCpp(&a_rThat.m_ListHead, pCur, MapEntry, ListEntry)
265 {
266 int rc = putCopyWorker(pCur->strKey.c_str(), *pCur->pValue, true /*a_fReplace*/);
267 if (RT_SUCCESS(rc))
268 { /* likely */ }
269 else if (fThrow)
270 throw std::bad_alloc();
271 else
272 return rc;
273 }
274
275 return VINF_SUCCESS;
276}
277
278
279int RTCRestStringMapBase::putWorker(const char *a_pszKey, RTCRestObjectBase *a_pValue, bool a_fReplace)
280{
281 int rc;
282 MapEntry *pEntry = new (std::nothrow) MapEntry;
283 if (pEntry)
284 {
285 rc = pEntry->strKey.assignNoThrow(a_pszKey);
286 if (RT_SUCCESS(rc))
287 {
288 pEntry->Core.pszString = pEntry->strKey.c_str();
289 pEntry->Core.cchString = pEntry->strKey.length();
290 pEntry->pValue = a_pValue;
291 if (RTStrSpaceInsert(&m_Map, &pEntry->Core))
292 {
293 m_cEntries++;
294 return VINF_SUCCESS;
295 }
296
297 if (!a_fReplace)
298 rc = VERR_ALREADY_EXISTS;
299 else
300 {
301 /* Just replace the pValue in the existing entry. */
302 MapEntry *pCollision = (MapEntry *)RTStrSpaceGet(&m_Map, a_pszKey);
303 if (pCollision)
304 {
305 if (pCollision->pValue)
306 delete pCollision->pValue;
307 pCollision->pValue = a_pValue;
308 pEntry->pValue = NULL; /* paranoia */
309 rc = VWRN_ALREADY_EXISTS;
310 }
311 else
312 rc = VERR_INTERNAL_ERROR;
313 }
314 }
315 delete pEntry;
316 }
317 else
318 rc = VERR_NO_MEMORY;
319 return rc;
320}
321
322
323int RTCRestStringMapBase::putCopyWorker(const char *a_pszKey, RTCRestObjectBase const &a_rValue, bool a_fReplace)
324{
325 int rc;
326 RTCRestObjectBase *pValueCopy = createValueCopy(&a_rValue);
327 if (pValueCopy)
328 {
329 rc = putWorker(a_pszKey, pValueCopy, a_fReplace);
330 if (RT_SUCCESS(rc))
331 { /* likely */ }
332 else
333 delete pValueCopy;
334 }
335 else
336 rc = VERR_NO_MEMORY;
337 return rc;
338}
339
340
341RTCRestObjectBase *RTCRestStringMapBase::getWorker(const char *a_pszKey)
342{
343 MapEntry *pHit = (MapEntry *)RTStrSpaceGet(&m_Map, a_pszKey);
344 if (pHit)
345 return pHit->pValue;
346 return NULL;
347}
348
349
350RTCRestObjectBase const *RTCRestStringMapBase::getWorker(const char *a_pszKey) const
351{
352 MapEntry const *pHit = (MapEntry const *)RTStrSpaceGet((PRTSTRSPACE)&m_Map, a_pszKey);
353 if (pHit)
354 return pHit->pValue;
355 return NULL;
356}
357
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