VirtualBox

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

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

IPRT/rest: fixes. bugref:9167

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