VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/rest/RTCRestArrayBase.cpp@ 74008

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

IPRT/rest: Deal (more) properly with 'null'. bugref:9167

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.1 KB
Line 
1/* $Id: RTCRestArrayBase.cpp 74008 2018-08-31 19:08:02Z vboxsync $ */
2/** @file
3 * IPRT - C++ REST, RTCRestArrayBase 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/**
40 * Default destructor.
41 */
42RTCRestArrayBase::RTCRestArrayBase()
43 : RTCRestObjectBase()
44 , m_papElements(NULL)
45 , m_cElements(0)
46 , m_cCapacity(0)
47{
48}
49
50
51#if 0 /* should not be used */
52/**
53 * Copy constructor.
54 */
55RTCRestArrayBase::RTCRestArrayBase(RTCRestArrayBase const &a_rThat);
56#endif
57
58/**
59 * Destructor.
60 */
61RTCRestArrayBase::~RTCRestArrayBase()
62{
63 clear();
64
65 if (m_papElements)
66 {
67 RTMemFree(m_papElements);
68 m_papElements = NULL;
69 m_cCapacity = 0;
70 }
71}
72
73
74#if 0 /* should not be used */
75/**
76 * Copy assignment operator.
77 */
78RTCRestArrayBase &RTCRestArrayBase::operator=(RTCRestArrayBase const &a_rThat);
79#endif
80
81
82/*********************************************************************************************************************************
83* Overridden methods *
84*********************************************************************************************************************************/
85
86int RTCRestArrayBase::resetToDefault()
87{
88 /* The default state of an array is empty. At least for now. */
89 clear();
90 m_fNullIndicator = false;
91 return VINF_SUCCESS;
92}
93
94
95RTCRestOutputBase &RTCRestArrayBase::serializeAsJson(RTCRestOutputBase &a_rDst) const
96{
97 if (!m_fNullIndicator)
98 {
99 a_rDst.printf("[\n");
100 unsigned const uOldIndent = a_rDst.incrementIndent();
101
102 for (size_t i = 0; i < m_cElements; i++)
103 {
104 m_papElements[i]->serializeAsJson(a_rDst);
105 if (i < m_cElements)
106 a_rDst.printf(",\n");
107 else
108 a_rDst.printf("\n");
109 }
110
111 a_rDst.setIndent(uOldIndent);
112 a_rDst.printf("]");
113 }
114 else
115 a_rDst.printf("null");
116 return a_rDst;
117}
118
119
120int RTCRestArrayBase::deserializeFromJson(RTCRestJsonCursor const &a_rCursor)
121{
122 /*
123 * Make sure the object starts out with an empty map.
124 */
125 if (m_cElements > 0)
126 clear();
127 m_fNullIndicator = false;
128
129 /*
130 * Iterate the array values.
131 */
132 RTJSONIT hIterator;
133 int rcRet = RTJsonIteratorBeginArray(a_rCursor.m_hValue, &hIterator);
134 if (RT_SUCCESS(rcRet))
135 {
136 for (size_t idxName = 0;; idxName++)
137 {
138 RTCRestJsonCursor SubCursor(a_rCursor);
139 int rc = RTJsonIteratorQueryValue(hIterator, &SubCursor.m_hValue, &SubCursor.m_pszName);
140 if (RT_SUCCESS(rc))
141 {
142 RTCRestObjectBase *pObj = createValue();
143 if (pObj)
144 {
145 char szName[32];
146 RTStrPrintf(szName, sizeof(szName), "[%u]", idxName);
147 SubCursor.m_pszName = szName;
148
149 rc = pObj->deserializeFromJson(SubCursor);
150 if (RT_SUCCESS(rc))
151 { /* likely */ }
152 else if (RT_SUCCESS(rcRet))
153 rcRet = rc;
154
155 rc = insertWorker(~(size_t)0, pObj, false /*a_fReplace*/);
156 if (RT_SUCCESS(rc))
157 { /* likely */ }
158 else
159 {
160 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "Array insert failed (index %zu): %Rrc",
161 idxName, rc);
162 delete pObj;
163 }
164 }
165 else
166 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "Failed to create new value object");
167 }
168 else
169 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonIteratorQueryValue failed: %Rrc", rc);
170
171 /*
172 * Advance.
173 */
174 rc = RTJsonIteratorNext(hIterator);
175 if (RT_SUCCESS(rc))
176 { /* likely */ }
177 else if (rc == VERR_JSON_ITERATOR_END)
178 break;
179 else
180 {
181 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonIteratorNext failed: %Rrc", rc);
182 break;
183 }
184 }
185
186 RTJsonIteratorFree(hIterator);
187 }
188 else if (rcRet == VERR_JSON_IS_EMPTY)
189 rcRet = VINF_SUCCESS;
190 else if ( rcRet == VERR_JSON_VALUE_INVALID_TYPE
191 && RTJsonValueGetType(a_rCursor.m_hValue) == RTJSONVALTYPE_NULL)
192 {
193 m_fNullIndicator = true;
194 rcRet = VINF_SUCCESS;
195 }
196 else
197 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rcRet,
198 "RTJsonIteratorBeginrray failed: %Rrc (type %s)",
199 rcRet, RTJsonValueTypeName(RTJsonValueGetType(a_rCursor.m_hValue)));
200 return rcRet;
201
202}
203
204
205int RTCRestArrayBase::toString(RTCString *a_pDst, uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) const
206{
207 int rc;
208 if (!m_fNullIndicator)
209 {
210 if (m_cElements)
211 {
212 static char const s_szSep[kCollectionFormat_Mask + 1] = ",, \t|,,";
213 char const chSep = s_szSep[a_fFlags & kCollectionFormat_Mask];
214
215 rc = m_papElements[0]->toString(a_pDst, a_fFlags);
216 for (size_t i = 1; RT_SUCCESS(rc) && i < m_cElements; i++)
217 {
218 rc = a_pDst->appendNoThrow(chSep);
219 if (RT_SUCCESS(rc))
220 rc = m_papElements[i]->toString(a_pDst, a_fFlags | kToString_Append);
221 }
222 }
223 else
224 {
225 if (!(a_fFlags & kToString_Append))
226 a_pDst->setNull();
227 rc = VINF_SUCCESS;
228 }
229 }
230 else if (a_fFlags & kToString_Append)
231 rc = a_pDst->appendNoThrow(RT_STR_TUPLE("null"));
232 else
233 rc = a_pDst->appendNoThrow(RT_STR_TUPLE("null"));
234
235 return rc;
236}
237
238
239int RTCRestArrayBase::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo /*= NULL*/,
240 uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/)
241{
242 /** @todo proper fromString implementation for arrays. */
243 return RTCRestObjectBase::fromString(a_rValue, a_pszName, a_pErrInfo, a_fFlags);
244}
245
246
247
248/*********************************************************************************************************************************
249* Array methods *
250*********************************************************************************************************************************/
251
252void RTCRestArrayBase::clear()
253{
254 size_t i = m_cElements;
255 while (i-- > 0)
256 {
257 delete m_papElements[i];
258 m_papElements[i] = NULL;
259 }
260 m_cElements = 0;
261 m_fNullIndicator = false;
262}
263
264
265bool RTCRestArrayBase::removeAt(size_t a_idx)
266{
267 if (a_idx == ~(size_t)0)
268 a_idx = m_cElements - 1;
269 if (a_idx < m_cElements)
270 {
271 delete m_papElements[a_idx];
272 m_papElements[a_idx] = NULL;
273
274 m_cElements--;
275 if (a_idx < m_cElements)
276 memmove(&m_papElements[a_idx], &m_papElements[a_idx + 1], (m_cElements - a_idx) * sizeof(m_papElements[0]));
277
278 m_cElements--;
279 }
280 return false;
281}
282
283
284int RTCRestArrayBase::ensureCapacity(size_t a_cEnsureCapacity)
285{
286 if (m_cCapacity < a_cEnsureCapacity)
287 {
288 if (a_cEnsureCapacity < 512)
289 a_cEnsureCapacity = RT_ALIGN_Z(a_cEnsureCapacity, 16);
290 else if (a_cEnsureCapacity < 16384)
291 a_cEnsureCapacity = RT_ALIGN_Z(a_cEnsureCapacity, 128);
292 else
293 a_cEnsureCapacity = RT_ALIGN_Z(a_cEnsureCapacity, 512);
294
295 void *pvNew = RTMemRealloc(m_papElements, sizeof(m_papElements[0]) * a_cEnsureCapacity);
296 if (pvNew)
297 {
298 m_papElements = (RTCRestObjectBase **)pvNew;
299 memset(&m_papElements[m_cCapacity], 0, (a_cEnsureCapacity - m_cCapacity) * sizeof(sizeof(m_papElements[0])));
300 m_cCapacity = a_cEnsureCapacity;
301 }
302 else
303 return VERR_NO_MEMORY;
304 }
305 return VINF_SUCCESS;
306}
307
308
309int RTCRestArrayBase::copyArrayWorker(RTCRestArrayBase const &a_rThat, bool a_fThrow)
310{
311 int rc;
312 clear();
313 if (a_rThat.m_cElements == 0)
314 {
315 m_fNullIndicator = a_rThat.m_fNullIndicator;
316 rc = VINF_SUCCESS;
317 }
318 else
319 {
320 Assert(!a_rThat.m_fNullIndicator);
321 rc = ensureCapacity(a_rThat.m_cElements);
322 if (RT_SUCCESS(rc))
323 {
324 for (size_t i = 0; i < a_rThat.m_cElements; i++)
325 {
326 AssertPtr(a_rThat.m_papElements[i]);
327 rc = insertCopyWorker(i, *a_rThat.m_papElements[i], false);
328 if (RT_SUCCESS(rc))
329 { /* likely */ }
330 else if (a_fThrow)
331 throw std::bad_alloc();
332 else
333 return rc;
334 }
335 }
336 }
337 return rc;
338}
339
340
341int RTCRestArrayBase::insertWorker(size_t a_idx, RTCRestObjectBase *a_pValue, bool a_fReplace)
342{
343 AssertPtrReturn(a_pValue, VERR_INVALID_POINTER);
344
345 if (a_idx == ~(size_t)0)
346 a_idx = m_cElements;
347
348 if (a_idx <= m_cElements)
349 {
350 if (a_idx == m_cElements || !a_fReplace)
351 {
352 /* Make sure we've got array space. */
353 if (m_cElements + 1 < m_cCapacity)
354 { /* kind of likely */ }
355 else
356 {
357 int rc = ensureCapacity(m_cElements + 1);
358 if (RT_SUCCESS(rc))
359 { /* likely */ }
360 else
361 return rc;
362 }
363
364 /* Shift following elements before inserting. */
365 if (a_idx < m_cElements)
366 memmove(&m_papElements[a_idx + 1], &m_papElements[a_idx], (m_cElements - a_idx) * sizeof(m_papElements[0]));
367 m_papElements[a_idx] = a_pValue;
368 m_cElements++;
369#ifdef RT_STRICT
370 for (size_t i = 0; i < m_cElements; i++)
371 AssertPtr(m_papElements[i]);
372#endif
373 m_fNullIndicator = false;
374 return VINF_SUCCESS;
375 }
376
377 /* Replace element. */
378 delete m_papElements[a_idx];
379 m_papElements[a_idx] = a_pValue;
380 m_fNullIndicator = false;
381 return VWRN_ALREADY_EXISTS;
382 }
383 return VERR_OUT_OF_RANGE;
384}
385
386
387int RTCRestArrayBase::insertCopyWorker(size_t a_idx, RTCRestObjectBase const &a_rValue, bool a_fReplace)
388{
389 int rc;
390 RTCRestObjectBase *pValueCopy = createValueCopy(&a_rValue);
391 if (pValueCopy)
392 {
393 rc = insertWorker(a_idx, pValueCopy, a_fReplace);
394 if (RT_SUCCESS(rc))
395 { /* likely */ }
396 else
397 delete pValueCopy;
398 }
399 else
400 rc = VERR_NO_MEMORY;
401 return rc;
402}
403
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