VirtualBox

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

Last change on this file since 73977 was 73977, checked in by vboxsync, 7 years ago

IPRT/rest: More request array and map setter methods. Fixed string defaults. Safer copying and resetToDefaults. bugref:9167

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

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