VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/rest/RTCRestArrayBase.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.7 KB
Line 
1/* $Id: RTCRestArrayBase.cpp 73977 2018-08-30 12:13: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 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
182 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rcRet, "RTJsonIteratorBeginArray failed: %Rrc", rcRet);
183 return rcRet;
184
185}
186
187
188int RTCRestArrayBase::toString(RTCString *a_pDst, uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) const
189{
190 int rc;
191 if (m_cElements)
192 {
193 static char const s_szSep[kCollectionFormat_Mask + 1] = ",, \t|,,";
194 char const chSep = s_szSep[a_fFlags & kCollectionFormat_Mask];
195
196 rc = m_papElements[0]->toString(a_pDst, a_fFlags);
197 for (size_t i = 1; RT_SUCCESS(rc) && i < m_cElements; i++)
198 {
199 rc = a_pDst->appendNoThrow(chSep);
200 if (RT_SUCCESS(rc))
201 rc = m_papElements[i]->toString(a_pDst, a_fFlags | kToString_Append);
202 }
203 }
204 else
205 {
206 a_pDst->setNull();
207 rc = VINF_SUCCESS;
208 }
209 return rc;
210}
211
212
213int RTCRestArrayBase::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo /*= NULL*/,
214 uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/)
215{
216 /** @todo proper fromString implementation for arrays. */
217 return RTCRestObjectBase::fromString(a_rValue, a_pszName, a_pErrInfo, a_fFlags);
218}
219
220
221
222/*********************************************************************************************************************************
223* Array methods *
224*********************************************************************************************************************************/
225
226void RTCRestArrayBase::clear()
227{
228 size_t i = m_cElements;
229 while (i-- > 0)
230 {
231 delete m_papElements[i];
232 m_papElements[i] = NULL;
233 }
234 m_cElements = 0;
235}
236
237
238bool RTCRestArrayBase::removeAt(size_t a_idx)
239{
240 if (a_idx == ~(size_t)0)
241 a_idx = m_cElements - 1;
242 if (a_idx < m_cElements)
243 {
244 delete m_papElements[a_idx];
245 m_papElements[a_idx] = NULL;
246
247 m_cElements--;
248 if (a_idx < m_cElements)
249 memmove(&m_papElements[a_idx], &m_papElements[a_idx + 1], (m_cElements - a_idx) * sizeof(m_papElements[0]));
250
251 m_cElements--;
252 }
253 return false;
254}
255
256
257int RTCRestArrayBase::ensureCapacity(size_t a_cEnsureCapacity)
258{
259 if (m_cCapacity < a_cEnsureCapacity)
260 {
261 if (a_cEnsureCapacity < 512)
262 a_cEnsureCapacity = RT_ALIGN_Z(a_cEnsureCapacity, 16);
263 else if (a_cEnsureCapacity < 16384)
264 a_cEnsureCapacity = RT_ALIGN_Z(a_cEnsureCapacity, 128);
265 else
266 a_cEnsureCapacity = RT_ALIGN_Z(a_cEnsureCapacity, 512);
267
268 void *pvNew = RTMemRealloc(m_papElements, sizeof(m_papElements[0]) * a_cEnsureCapacity);
269 if (pvNew)
270 {
271 m_papElements = (RTCRestObjectBase **)pvNew;
272 memset(m_papElements, 0, (a_cEnsureCapacity - m_cCapacity) * sizeof(sizeof(m_papElements[0])));
273 m_cCapacity = a_cEnsureCapacity;
274 }
275 else
276 return VERR_NO_MEMORY;
277 }
278 return VINF_SUCCESS;
279}
280
281
282int RTCRestArrayBase::copyArrayWorker(RTCRestArrayBase const &a_rThat, bool a_fThrow)
283{
284 int rc;
285 clear();
286 if (a_rThat.m_cElements == 0)
287 rc = VINF_SUCCESS;
288 else
289 {
290 rc = ensureCapacity(a_rThat.m_cElements);
291 if (RT_SUCCESS(rc))
292 {
293 for (size_t i = 0; i < a_rThat.m_cElements; i++)
294 {
295 rc = insertCopyWorker(i, *a_rThat.m_papElements[i], false);
296 if (RT_SUCCESS(rc))
297 { /* likely */ }
298 else if (a_fThrow)
299 throw std::bad_alloc();
300 else
301 return rc;
302 }
303 }
304 }
305 return rc;
306}
307
308
309int RTCRestArrayBase::insertWorker(size_t a_idx, RTCRestObjectBase *a_pValue, bool a_fReplace)
310{
311 AssertPtrReturn(a_pValue, VERR_INVALID_POINTER);
312
313 if (a_idx == ~(size_t)0)
314 a_idx = m_cElements;
315
316 if (a_idx <= m_cElements)
317 {
318 if (a_idx == m_cElements || !a_fReplace)
319 {
320 /* Make sure we've got array space. */
321 if (m_cElements + 1 < m_cCapacity)
322 { /* kind of likely */ }
323 else
324 {
325 int rc = ensureCapacity(m_cElements + 1);
326 if (RT_SUCCESS(rc))
327 { /* likely */ }
328 else
329 return rc;
330 }
331
332 /* Shift following elements before inserting. */
333 if (a_idx < m_cElements)
334 memmove(&m_papElements[a_idx + 1], &m_papElements[a_idx], (m_cElements - a_idx) * sizeof(m_papElements[0]));
335 m_papElements[a_idx] = a_pValue;
336 m_cElements++;
337 return VINF_SUCCESS;
338 }
339
340 /* Replace element. */
341 delete m_papElements[a_idx];
342 m_papElements[a_idx] = a_pValue;
343 return VWRN_ALREADY_EXISTS;
344 }
345 return VERR_OUT_OF_RANGE;
346}
347
348
349int RTCRestArrayBase::insertCopyWorker(size_t a_idx, RTCRestObjectBase const &a_rValue, bool a_fReplace)
350{
351 int rc;
352 RTCRestObjectBase *pValueCopy = createValueCopy(&a_rValue);
353 if (pValueCopy)
354 {
355 rc = insertWorker(a_idx, pValueCopy, a_fReplace);
356 if (RT_SUCCESS(rc))
357 { /* likely */ }
358 else
359 delete pValueCopy;
360 }
361 else
362 rc = VERR_NO_MEMORY;
363 return rc;
364}
365
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