VirtualBox

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

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