VirtualBox

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

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

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

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