VirtualBox

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

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

IPRT/rest: Fixed empty array & map handling by making the begin iteration functions return VERR_JSON_IS_EMPTY rather than letter the query method do that. Made query parameter processing table driven and made it use the right escapeing. bugref:9167

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.0 KB
Line 
1/* $Id: RTCRestStringMapBase.cpp 73978 2018-08-30 13:19:36Z 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 if (rcRet == VERR_JSON_IS_EMPTY)
178 rcRet = VINF_SUCCESS;
179 else
180 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rcRet, "RTJsonIteratorBegin failed: %Rrc", rcRet);
181 return rcRet;
182}
183
184// later?
185// virtual int RTCRestStringMapBase::toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const ;
186// virtual int RTCRestStringMapBase::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL,
187// uint32_t a_fFlags = kCollectionFormat_Unspecified) ;
188//
189
190
191/*********************************************************************************************************************************
192* Generic map methods *
193*********************************************************************************************************************************/
194
195/**
196 * @callback_method_impl{FNRTSTRSPACECALLBACK}
197 */
198/*static*/ DECLCALLBACK(int) RTCRestStringMapBase::stringSpaceDestructorCallback(PRTSTRSPACECORE pStr, void *pvUser)
199{
200 MapEntry *pNode = (MapEntry *)pStr;
201 if (pNode->pValue)
202 {
203 delete pNode->pValue;
204 pNode->pValue = NULL;
205 }
206 pNode->strKey.setNull();
207 delete pNode;
208
209 RT_NOREF(pvUser);
210 return VINF_SUCCESS;
211}
212
213
214void RTCRestStringMapBase::clear()
215{
216 RTStrSpaceDestroy(&m_Map, stringSpaceDestructorCallback, NULL);
217 RTListInit(&m_ListHead);
218 m_cEntries = 0;
219}
220
221
222size_t RTCRestStringMapBase::size() const
223{
224 return m_cEntries;
225}
226
227
228bool RTCRestStringMapBase::constainsKey(const char *a_pszKey) const
229{
230 return RTStrSpaceGet((PRTSTRSPACE)&m_Map, a_pszKey) != NULL;
231}
232
233
234bool RTCRestStringMapBase::constainsKey(RTCString const &a_rStrKey) const
235{
236 return constainsKey(a_rStrKey.c_str());
237}
238
239
240bool RTCRestStringMapBase::remove(const char *a_pszKey)
241{
242 PRTSTRSPACECORE pRemoved = RTStrSpaceRemove(&m_Map, a_pszKey);
243 if (pRemoved)
244 {
245 stringSpaceDestructorCallback(pRemoved, NULL);
246 return true;
247 }
248 return false;
249}
250
251
252bool RTCRestStringMapBase::remove(RTCString const &a_rStrKey)
253{
254 return remove(a_rStrKey.c_str());
255}
256
257
258/*********************************************************************************************************************************
259* Protected methods *
260*********************************************************************************************************************************/
261
262int RTCRestStringMapBase::copyMapWorker(RTCRestStringMapBase const &a_rThat, bool a_fThrow)
263{
264 Assert(this != &a_rThat);
265 clear();
266
267 MapEntry const *pCur;
268 RTListForEachCpp(&a_rThat.m_ListHead, pCur, MapEntry, ListEntry)
269 {
270 int rc = putCopyWorker(pCur->strKey.c_str(), *pCur->pValue, true /*a_fReplace*/);
271 if (RT_SUCCESS(rc))
272 { /* likely */ }
273 else if (a_fThrow)
274 throw std::bad_alloc();
275 else
276 return rc;
277 }
278
279 return VINF_SUCCESS;
280}
281
282
283int RTCRestStringMapBase::putWorker(const char *a_pszKey, RTCRestObjectBase *a_pValue, bool a_fReplace)
284{
285 int rc;
286 MapEntry *pEntry = new (std::nothrow) MapEntry;
287 if (pEntry)
288 {
289 rc = pEntry->strKey.assignNoThrow(a_pszKey);
290 if (RT_SUCCESS(rc))
291 {
292 pEntry->Core.pszString = pEntry->strKey.c_str();
293 pEntry->Core.cchString = pEntry->strKey.length();
294 pEntry->pValue = a_pValue;
295 if (RTStrSpaceInsert(&m_Map, &pEntry->Core))
296 {
297 m_cEntries++;
298 return VINF_SUCCESS;
299 }
300
301 if (!a_fReplace)
302 rc = VERR_ALREADY_EXISTS;
303 else
304 {
305 /* Just replace the pValue in the existing entry. */
306 MapEntry *pCollision = (MapEntry *)RTStrSpaceGet(&m_Map, a_pszKey);
307 if (pCollision)
308 {
309 if (pCollision->pValue)
310 delete pCollision->pValue;
311 pCollision->pValue = a_pValue;
312 pEntry->pValue = NULL; /* paranoia */
313 rc = VWRN_ALREADY_EXISTS;
314 }
315 else
316 rc = VERR_INTERNAL_ERROR;
317 }
318 }
319 delete pEntry;
320 }
321 else
322 rc = VERR_NO_MEMORY;
323 return rc;
324}
325
326
327int RTCRestStringMapBase::putCopyWorker(const char *a_pszKey, RTCRestObjectBase const &a_rValue, bool a_fReplace)
328{
329 int rc;
330 RTCRestObjectBase *pValueCopy = createValueCopy(&a_rValue);
331 if (pValueCopy)
332 {
333 rc = putWorker(a_pszKey, pValueCopy, a_fReplace);
334 if (RT_SUCCESS(rc))
335 { /* likely */ }
336 else
337 delete pValueCopy;
338 }
339 else
340 rc = VERR_NO_MEMORY;
341 return rc;
342}
343
344
345RTCRestObjectBase *RTCRestStringMapBase::getWorker(const char *a_pszKey)
346{
347 MapEntry *pHit = (MapEntry *)RTStrSpaceGet(&m_Map, a_pszKey);
348 if (pHit)
349 return pHit->pValue;
350 return NULL;
351}
352
353
354RTCRestObjectBase const *RTCRestStringMapBase::getWorker(const char *a_pszKey) const
355{
356 MapEntry const *pHit = (MapEntry const *)RTStrSpaceGet((PRTSTRSPACE)&m_Map, a_pszKey);
357 if (pHit)
358 return pHit->pValue;
359 return NULL;
360}
361
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