1 mike 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
8 ** Licensed under the Apache License, Version 2.0 (the "License"); you may not
9 ** use this file except in compliance with the License. You may obtain a copy
10 ** of the License at
11 **
12 ** http://www.apache.org/licenses/LICENSE-2.0
13 **
14 ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 ** MERCHANTABLITY OR NON-INFRINGEMENT.
18 **
19 ** See the Apache 2 License for the specific language governing permissions
20 ** and limitations under the License.
21 **
22 mike 1.1 **==============================================================================
23 */
24
25 #include "buf.h"
|
26 krisbash 1.3 #include <pal/strings.h>
|
27 mike 1.1
28 #define _MIN_CAPACITY 256
29
30 /*
31 **==============================================================================
32 **
33 ** Local definitions
34 **
35 **==============================================================================
36 */
37
38 /* Round x up to the nearest power of 2 */
39 static MI_Uint32 _RoundPow2(MI_Uint32 x)
40 {
41 MI_Uint32 r = x - 1;
42 r |= (r >> 1);
43 r |= (r >> 2);
44 r |= (r >> 4);
45 r |= (r >> 8);
46 r |= (r >> 16);
47 return r + 1;
48 mike 1.1 }
49
50 /*
51 **==============================================================================
52 **
53 ** Public definitions
54 **
55 **==============================================================================
56 */
57
58 MI_Result Buf_Init(
59 Buf* self,
60 MI_Uint32 capacity)
61 {
62 Page* page;
63
64 /* Adjust capacity if too small */
65 if (capacity < _MIN_CAPACITY)
66 capacity = _MIN_CAPACITY;
67
68 /* Allocate data buffer */
|
69 krisbash 1.3 page = (Page*)PAL_Malloc(sizeof(Page) + capacity);
|
70 mike 1.1
71 if (!page)
72 return MI_RESULT_FAILED;
73
74 page->u.s.size = capacity;
75 page->u.s.next = 0;
76
77 /* Set fields */
78 self->data = page + 1;
79 self->size = 0;
80 self->capacity = capacity;
81 self->offset = 0;
82
83 #ifdef CONFIG_ENABLE_DEBUG
|
84 krisbash 1.3 #ifdef _PREFAST_
85 #pragma prefast(push)
86 #pragma prefast(disable:22107)
87 #endif
|
88 mike 1.1 memset(self->data,0xAA,self->capacity);
|
89 krisbash 1.3 #ifdef _PREFAST_
90 #pragma prefast(pop)
91 #endif
|
92 mike 1.1 #endif
93
94 return MI_RESULT_OK;
95 }
96
97 void Buf_Destroy(
98 Buf* self)
99 {
100 if (self->data)
|
101 krisbash 1.3 PAL_Free((Page*)self->data - 1);
|
102 mike 1.1 }
103
104 MI_Result Buf_Reserve(
105 Buf* self,
106 MI_Uint32 capacity)
107 {
108 /* Expand allocation if we need more space */
109 if (capacity > self->capacity)
110 {
111 Page* page;
112
113 capacity = _RoundPow2(capacity);
114
115 if (self->data)
116 {
117 page = (Page*)self->data - 1;
|
118 krisbash 1.3 page = (Page*)PAL_Realloc(page, sizeof(Page) + capacity);
|
119 mike 1.1 #ifdef CONFIG_ENABLE_DEBUG
|
120 krisbash 1.3 if (page)
121 memset(((char*)(page+1)) + self->capacity,0xAA,capacity - self->capacity);
|
122 mike 1.1 #endif
123 }
124 else
125 {
|
126 krisbash 1.3 page = (Page*)PAL_Malloc(sizeof(Page) + capacity);
|
127 mike 1.1 #ifdef CONFIG_ENABLE_DEBUG
|
128 krisbash 1.3 if(page)
129 memset(page,0xAA,sizeof(Page) + capacity);
|
130 mike 1.1 #endif
131 }
132
133 if (!page)
134 return MI_RESULT_FAILED;
135
136 page->u.s.size = capacity;
137 self->data = page + 1;
138 self->capacity = capacity;
139 }
140
141 return MI_RESULT_OK;
142 }
143
|
144 krisbash 1.3 MI_Result __Buf_App(
|
145 mike 1.1 Buf* self,
146 const void* data,
147 MI_Uint32 size)
148 {
|
149 krisbash 1.3 MI_Result r = Buf_Reserve(self, self->size + size);
|
150 mike 1.1
|
151 krisbash 1.3 if (r != MI_RESULT_OK)
152 return MI_RESULT_FAILED;
|
153 mike 1.1
154 memcpy((char*)self->data + self->size, data, size);
155 self->size += size;
156
157 return MI_RESULT_OK;
158 }
159
160 MI_Result Buf_PackStr(
161 Buf* self,
|
162 krisbash 1.3 const ZChar* x)
|
163 mike 1.1 {
164 MI_Uint32 size;
165
166 /* Pack null strings as 0 */
167 if (!x)
168 return Buf_PackU32(self, 0);
169
170 /* Pack the size of the string (size including null terminator) */
|
171 krisbash 1.3 size = (MI_Uint32)Tcslen(x) + 1;
|
172 mike 1.1 MI_RETURN_ERR(Buf_PackU32(self, size));
173
174 /* Pack the characters (including the null terminator) */
|
175 krisbash 1.3 MI_RETURN_ERR(Buf_App(self, x, size * sizeof(ZChar)));
176
177 return MI_RESULT_OK;
178 }
179
180 MI_Result Buf_PackStrLen(
181 Buf* self,
182 const ZChar* x,
183 MI_Uint32 size)
184 {
185 /* Pack null strings as 0 */
186 if (!x)
187 return Buf_PackU32(self, 0);
188
189 /* Pack the size of the string (size including null terminator) */
190 MI_RETURN_ERR(Buf_PackU32(self, size + 1));
191
192 /* Pack the characters (including the null terminator) */
193 MI_RETURN_ERR(Buf_App(self, x, (size + 1) * sizeof(ZChar)));
|
194 mike 1.1
195 return MI_RESULT_OK;
196 }
197
198 MI_Result Buf_UnpackU8A(
199 Buf* self,
200 const MI_Uint8** data,
201 MI_Uint32* size)
202 {
203 /* Unpack size */
204 MI_RETURN_ERR(Buf_UnpackU32(self, size));
205
206 if (*size == 0)
207 {
208 *data = NULL;
209 return MI_RESULT_OK;
210 }
211
212 /* Check whether there are enough bytes left */
213 if (self->offset + *size * sizeof(MI_Uint8) > self->size)
214 return MI_RESULT_FAILED;
215 mike 1.1
216 /* Store pointer to array */
217 *data = (const MI_Uint8*)((char*)self->data + self->offset);
218 self->offset += *size * sizeof(MI_Uint8);
219
220 return MI_RESULT_OK;
221 }
222
223 MI_Result Buf_UnpackU16A(
224 Buf* self,
225 const MI_Uint16** data,
226 MI_Uint32* size)
227 {
228 /* Unpack size */
229 MI_RETURN_ERR(Buf_UnpackU32(self, size));
230
231 if (*size == 0)
232 {
233 *data = NULL;
234 return MI_RESULT_OK;
235 }
236 mike 1.1
237 /* Check whether there are enough bytes left */
238 if (self->offset + *size * sizeof(MI_Uint16) > self->size)
239 return MI_RESULT_FAILED;
240
241 /* Store pointer to array */
242 *data = (const MI_Uint16*)((char*)self->data + self->offset);
243 self->offset += *size * sizeof(MI_Uint16);
244
245 return MI_RESULT_OK;
246 }
247
248 MI_Result Buf_UnpackU32A(
249 Buf* self,
250 const MI_Uint32** data,
251 MI_Uint32* size)
252 {
253 /* Unpack size */
254 MI_RETURN_ERR(Buf_UnpackU32(self, size));
255
256 if (*size == 0)
257 mike 1.1 {
258 *data = NULL;
259 return MI_RESULT_OK;
260 }
261
262 /* Check whether there are enough bytes left */
263 if (self->offset + *size * sizeof(MI_Uint32) > self->size)
264 return MI_RESULT_FAILED;
265
266 /* Store pointer to array */
267 *data = (const MI_Uint32*)((char*)self->data + self->offset);
268 self->offset += *size * sizeof(MI_Uint32);
269
270 return MI_RESULT_OK;
271 }
272
273 MI_Result Buf_UnpackU64A(
274 Buf* self,
275 const MI_Uint64** data,
276 MI_Uint32* size)
277 {
278 mike 1.1 /* Unpack size */
279 MI_RETURN_ERR(Buf_UnpackU32(self, size));
280
281 if (*size == 0)
282 {
283 *data = NULL;
284 return MI_RESULT_OK;
285 }
286
287 /* Align buffer on 8 byte boundary */
288 MI_RETURN_ERR(Buf_Align64(self));
289
290 /* Check whether there are enough bytes left */
291 if (self->offset + *size * sizeof(MI_Uint64) > self->size)
292 return MI_RESULT_FAILED;
293
294 /* Store pointer to array */
295 *data = (const MI_Uint64*)((char*)self->data + self->offset);
296 self->offset += *size * sizeof(MI_Uint64);
297
298 return MI_RESULT_OK;
299 mike 1.1 }
300
301 MI_Result Buf_UnpackStr(
302 Buf* self,
|
303 krisbash 1.3 const ZChar** x)
|
304 mike 1.1 {
305 MI_Uint32 size;
306
307 /* Unpack size */
308 MI_RETURN_ERR(Buf_UnpackU32(self, &size));
309
310 if (size == 0)
311 {
312 *x = NULL;
313 return MI_RESULT_OK;
314 }
315
316 /* Check whether there are enough bytes left */
|
317 krisbash 1.3 if (self->offset + size * sizeof(ZChar) > self->size)
|
318 mike 1.1 return MI_RESULT_FAILED;
319
320 /* Store pointer to array */
|
321 krisbash 1.3 *x = (const ZChar*)((char*)self->data + self->offset);
322 self->offset += size * sizeof(ZChar);
|
323 mike 1.1
324 return MI_RESULT_OK;
325 }
326
|
327 krisbash 1.3 MI_Result Buf_PackPtrdiff_t (
328 Buf* self,
329 ptrdiff_t data)
330 {
331 #if defined(PAL_64BIT)
332 MI_RETURN_ERR(Buf_PackU64(self, (MI_Uint64)data));
333 #elif defined(PAL_32BIT)
334 MI_RETURN_ERR(Buf_PackU32(self, (MI_Uint32)data));
335 #else
336 return MI_RESULT_NOT_SUPPORTED;
337 #endif
338 return MI_RESULT_OK;
339 }
340
341 MI_Result Buf_UnpackPtrdiff_t (
342 Buf* self,
343 ptrdiff_t* x)
344 {
345 #if defined(PAL_64BIT)
346 MI_RETURN_ERR(Buf_UnpackU64(self, (MI_Uint64*)x));
347 #elif defined(PAL_32BIT)
348 krisbash 1.3 MI_RETURN_ERR(Buf_UnpackU32(self, (MI_Uint32*)x));
349 #else
350 return MI_RESULT_NOT_SUPPORTED;
351 #endif
352 return MI_RESULT_OK;
353 }
354
|
355 mike 1.1 MI_Result Buf_PackStrA(
356 Buf* self,
|
357 krisbash 1.3 const ZChar** data,
|
358 mike 1.1 MI_Uint32 size)
359 {
360 MI_Uint32 i;
361
362 /* Pack the array size (the number of strings) */
363 MI_RETURN_ERR(Buf_PackU32(self, size));
364
365 if (size)
366 {
|
367 krisbash 1.3 ptrdiff_t sizes[64];
368 ptrdiff_t offset;
|
369 mike 1.1
370 if (!data)
371 return MI_RESULT_FAILED;
372
|
373 krisbash 1.3 MI_RETURN_ERR(Buf_Pad64(self));
374
375 /* Let "size(string) times size(ZChar)" be denoted by ZCharSize(string).
376 * Put ZCharSize offsets of all strings first.
377 *
378 * For example: consider the string "RED\0GREEN\0BLUE\0"
379 * We put four ZCharSize offsets in the buffer:
380 * 0*sizeof(ZChar) | (4)*sizeof(ZChar) | (4+6)*sizeof(ZChar) | (4+6+5)*sizeof(ZChar)
381 *
382 * Each ZCharSize offset is encoded as a 64-bit
383 * integer. The unpack function replaces this integer with a pointer
384 * to the corresponding string. This avoids having to allocate memory
385 * for the pointer array while unpacking.
386 */
387
388 /* Pack the ZCharSize offsets */
389 offset = 0;
|
390 mike 1.1 for (i = 0; i < size; i++)
391 {
|
392 krisbash 1.3 ptrdiff_t n;
|
393 mike 1.1
394 if (!data[i])
|
395 krisbash 1.3 return MI_RESULT_FAILED;
|
396 mike 1.1
|
397 krisbash 1.3 n = ((ptrdiff_t)Tcslen(data[i]) + 1) * sizeof(ZChar);
|
398 mike 1.1
399 /* Save size so that it will not have to be recalculated by the
|
400 krisbash 1.3 * next loop using strlen.
401 */
|
402 mike 1.1 if (i < MI_COUNT(sizes))
|
403 krisbash 1.3 sizes[i] = n;
404
405 /* Pack according to the platform */
406 MI_RETURN_ERR(Buf_PackPtrdiff_t (self, offset));
|
407 mike 1.1
|
408 krisbash 1.3 /* Accumulate the ZCharSizes */
409 offset += n;
|
410 mike 1.1 }
411
|
412 krisbash 1.3 /* Pack the total size */
413 MI_RETURN_ERR(Buf_PackPtrdiff_t(self, offset));
414
|
415 mike 1.1 /* Pack strings one after the other. */
416 for (i = 0; i < size; i++)
417 {
418 MI_Uint32 n;
419
420 if (i < MI_COUNT(sizes))
|
421 krisbash 1.3 n = (MI_Uint32)sizes[i];
|
422 mike 1.1 else
|
423 krisbash 1.3 n = ((MI_Uint32)Tcslen(data[i]) + 1) * sizeof(ZChar);
|
424 mike 1.1
|
425 krisbash 1.3 MI_RETURN_ERR(Buf_App(self, data[i], n));
|
426 mike 1.1 }
427 }
428
429 return MI_RESULT_OK;
430 }
431
432 MI_Result Buf_UnpackStrA(
433 Buf* self,
|
434 krisbash 1.3 const ZChar*** dataOut,
|
435 mike 1.1 MI_Uint32* sizeOut)
436 {
|
437 krisbash 1.3 const ZChar** data;
|
438 mike 1.1 MI_Uint32 size;
439 MI_Uint32 i;
440 MI_Uint32 offset;
|
441 krisbash 1.3 ptrdiff_t start;
442
|
443 mike 1.1 /* Unpack the size of the array */
444 MI_RETURN_ERR(Buf_UnpackU32(self, &size));
445
446 /* Handle zero-size array case */
447 if (size == 0)
448 {
449 *dataOut = NULL;
450 *sizeOut = 0;
451 return MI_RESULT_OK;
452 }
453
454 /* Align to read uint64 sizes */
455 MI_RETURN_ERR(Buf_Align64(self));
456
457 /* Set pointer data array */
|
458 krisbash 1.3 data = (const ZChar**)((char*)self->data + self->offset);
|
459 mike 1.1
460 /* Calculate offset to first string in array (data[0]) */
|
461 krisbash 1.3 offset = self->offset + ((size+1) * sizeof(ptrdiff_t));
|
462 mike 1.1
463 /* Fail if offset is beyond end of buffer */
464 if (offset > self->size)
465 return MI_RESULT_FAILED;
466
|
467 krisbash 1.3 /* Unpack the string ZCharSizes/pointers and convert to string pointers
468 * We intentionally iterate (size + 1) times.
469 */
470 start = 0;
471 for (i = 0; i <= size; i++)
|
472 mike 1.1 {
|
473 krisbash 1.3 ptrdiff_t n;
|
474 mike 1.1
475 /* Unpack size of next string in array */
|
476 krisbash 1.3 MI_RETURN_ERR(Buf_UnpackPtrdiff_t (self, &n));
477
478 /* Remember the first element - this will be the base */
479 if (i == 0)
480 start = n;
|
481 mike 1.1
482 /* Fail if not enough room left in buffer for string */
|
483 krisbash 1.3 if (offset + (n-start) > self->size)
|
484 mike 1.1 return MI_RESULT_FAILED;
|
485 krisbash 1.3
486 /* Add string pointer to array */
487 data[i] = (ZChar*)((char*)self->data + offset + (n-start));
|
488 mike 1.1 }
|
489 krisbash 1.3
|
490 mike 1.1 /* Update the offset */
|
491 krisbash 1.3 self->offset = offset + (MI_Uint32)(((ptrdiff_t)data[size]) - ((ptrdiff_t)data[0]));
|
492 mike 1.1
493 /* Set the output parameters */
494 *dataOut = data;
495 *sizeOut = size;
496
497 return MI_RESULT_OK;
498 }
499
500 MI_Result Buf_PackDT(
501 Buf* self,
502 const MI_Datetime* x)
503 {
504 MI_RETURN_ERR(Buf_Pad32(self));
505 MI_RETURN_ERR(Buf_App(self, x, sizeof(MI_Datetime)));
506 return MI_RESULT_OK;
507 }
508
509 MI_Result Buf_UnpackDT(
510 Buf* self,
511 MI_Datetime* x)
512 {
513 mike 1.1 MI_Uint32 offset;
514
515 MI_RETURN_ERR(Buf_Align32(self));
516
517 /* Find ending offset of datetime structure */
518 offset = self->offset + sizeof(MI_Datetime);
519
520 if (offset > self->size)
521 return MI_RESULT_FAILED;
522
523 memcpy(x, (char*)self->data + self->offset, sizeof(MI_Datetime));
524 self->offset = offset;
525
526 return MI_RESULT_OK;
527 }
528
529 MI_Result Buf_PackDTA(
530 Buf* self,
531 const MI_Datetime* data,
532 MI_Uint32 size)
533 {
534 mike 1.1 MI_RETURN_ERR(Buf_PackU32(self, size));
535 MI_RETURN_ERR(Buf_App(self, data, size * sizeof(MI_Datetime)));
536 return MI_RESULT_OK;
537 }
538
539 MI_Result Buf_UnpackDTA(
540 Buf* self,
541 const MI_Datetime** dataPtr,
542 MI_Uint32* sizePtr)
543 {
544 MI_Uint32 offset;
545
546 /* Unpack the size */
547 MI_RETURN_ERR(Buf_UnpackU32(self, sizePtr));
548
549 /* Handle zero-sized array (null data pointer) */
550 if (*sizePtr == 0)
551 {
552 *dataPtr = NULL;
553 return MI_RESULT_OK;
554 }
555 mike 1.1
556 /* Find ending offset of datetime array */
557 offset = self->offset + *sizePtr * sizeof(MI_Datetime);
558
559 /* Set pointer to data array */
560 *dataPtr = (const MI_Datetime*)((char*)self->data + self->offset);
561
562 /* Advance offset beyond array */
563 self->offset = offset;
564
565 return MI_RESULT_OK;
566 }
567
568 Page* Buf_StealPage(
569 Buf* self)
570 {
571 if (self->data)
572 {
573 Page* page = (Page*)self->data - 1;
574 self->data = NULL;
575 return page;
576 mike 1.1 }
577
578 return NULL;
579 }
|
580 krisbash 1.3
581 MI_Result Buf_AppStr(
582 Buf* self,
583 const ZChar* str)
584 {
585 return Buf_App(self, str, (MI_Uint32)Tcslen(str) * sizeof(ZChar));
586 }
587
588 MI_Result Buf_AppStrN(
589 Buf* self,
590 const ZChar* str,
591 size_t size)
592 {
593 return Buf_App(self, str, (MI_Uint32)size * sizeof(ZChar));
594 }
595
|