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 #include "strings.h"
27
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 mike 1.1 r |= (r >> 2);
44 r |= (r >> 4);
45 r |= (r >> 8);
46 r |= (r >> 16);
47 return r + 1;
48 }
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 mike 1.1 /* Adjust capacity if too small */
65 if (capacity < _MIN_CAPACITY)
66 capacity = _MIN_CAPACITY;
67
68 /* Allocate data buffer */
69 page = (Page*)malloc(sizeof(Page) + capacity);
70
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 memset(self->data,0xAA,self->capacity);
85 mike 1.1 #endif
86
87 return MI_RESULT_OK;
88 }
89
90 void Buf_Destroy(
91 Buf* self)
92 {
93 if (self->data)
94 free((Page*)self->data - 1);
95 }
96
97 MI_Result Buf_Reserve(
98 Buf* self,
99 MI_Uint32 capacity)
100 {
101 /* Expand allocation if we need more space */
102 if (capacity > self->capacity)
103 {
104 Page* page;
105
106 mike 1.1 capacity = _RoundPow2(capacity);
107
108 if (self->data)
109 {
110 page = (Page*)self->data - 1;
111 page = (Page*)realloc(page, sizeof(Page) + capacity);
112 #ifdef CONFIG_ENABLE_DEBUG
113 memset(((char*)(page+1)) + self->capacity,0xAA,capacity - self->capacity);
114 #endif
115 }
116 else
117 {
118 page = (Page*)malloc(sizeof(Page) + capacity);
119 #ifdef CONFIG_ENABLE_DEBUG
120 memset(page,0xAA,sizeof(Page) + capacity);
121 #endif
122 }
123
124 if (!page)
125 return MI_RESULT_FAILED;
126
127 mike 1.1 page->u.s.size = capacity;
128 self->data = page + 1;
129 self->capacity = capacity;
130 }
131
132 return MI_RESULT_OK;
133 }
134
135 MI_Result Buf_App(
136 Buf* self,
137 const void* data,
138 MI_Uint32 size)
139 {
140 /* Calculate the new size */
141 MI_Uint32 newSize = self->size + size;
142
143 /* Expand allocation if we need more space */
144 if (newSize > self->capacity)
145 {
146 MI_Result r = Buf_Reserve(self, newSize);
147
148 mike 1.1 if (r != MI_RESULT_OK)
149 return MI_RESULT_FAILED;
150 }
151
152 /* Copy in the new data */
153 memcpy((char*)self->data + self->size, data, size);
154 self->size += size;
155
156 return MI_RESULT_OK;
157 }
158
159 MI_Result Buf_PackStr(
160 Buf* self,
161 const MI_Char* x)
162 {
163 MI_Uint32 size;
164
165 /* Pack null strings as 0 */
166 if (!x)
167 return Buf_PackU32(self, 0);
168
169 mike 1.1 /* Pack the size of the string (size including null terminator) */
170 size = (MI_Uint32)Zlen(x) + 1;
171 MI_RETURN_ERR(Buf_PackU32(self, size));
172
173 /* Pack the characters (including the null terminator) */
174 MI_RETURN_ERR(Buf_App(self, x, size * sizeof(MI_Char)));
175
176 return MI_RESULT_OK;
177 }
178
179 MI_Result Buf_UnpackU8A(
180 Buf* self,
181 const MI_Uint8** data,
182 MI_Uint32* size)
183 {
184 /* Unpack size */
185 MI_RETURN_ERR(Buf_UnpackU32(self, size));
186
187 if (*size == 0)
188 {
189 *data = NULL;
190 mike 1.1 return MI_RESULT_OK;
191 }
192
193 /* Check whether there are enough bytes left */
194 if (self->offset + *size * sizeof(MI_Uint8) > self->size)
195 return MI_RESULT_FAILED;
196
197 /* Store pointer to array */
198 *data = (const MI_Uint8*)((char*)self->data + self->offset);
199 self->offset += *size * sizeof(MI_Uint8);
200
201 return MI_RESULT_OK;
202 }
203
204 MI_Result Buf_UnpackU16A(
205 Buf* self,
206 const MI_Uint16** data,
207 MI_Uint32* size)
208 {
209 /* Unpack size */
210 MI_RETURN_ERR(Buf_UnpackU32(self, size));
211 mike 1.1
212 if (*size == 0)
213 {
214 *data = NULL;
215 return MI_RESULT_OK;
216 }
217
218 /* Check whether there are enough bytes left */
219 if (self->offset + *size * sizeof(MI_Uint16) > self->size)
220 return MI_RESULT_FAILED;
221
222 /* Store pointer to array */
223 *data = (const MI_Uint16*)((char*)self->data + self->offset);
224 self->offset += *size * sizeof(MI_Uint16);
225
226 return MI_RESULT_OK;
227 }
228
229 MI_Result Buf_UnpackU32A(
230 Buf* self,
231 const MI_Uint32** data,
232 mike 1.1 MI_Uint32* size)
233 {
234 /* Unpack size */
235 MI_RETURN_ERR(Buf_UnpackU32(self, size));
236
237 if (*size == 0)
238 {
239 *data = NULL;
240 return MI_RESULT_OK;
241 }
242
243 /* Check whether there are enough bytes left */
244 if (self->offset + *size * sizeof(MI_Uint32) > self->size)
245 return MI_RESULT_FAILED;
246
247 /* Store pointer to array */
248 *data = (const MI_Uint32*)((char*)self->data + self->offset);
249 self->offset += *size * sizeof(MI_Uint32);
250
251 return MI_RESULT_OK;
252 }
253 mike 1.1
254 MI_Result Buf_UnpackU64A(
255 Buf* self,
256 const MI_Uint64** data,
257 MI_Uint32* size)
258 {
259 /* Unpack size */
260 MI_RETURN_ERR(Buf_UnpackU32(self, size));
261
262 if (*size == 0)
263 {
264 *data = NULL;
265 return MI_RESULT_OK;
266 }
267
268 /* Align buffer on 8 byte boundary */
269 MI_RETURN_ERR(Buf_Align64(self));
270
271 /* Check whether there are enough bytes left */
272 if (self->offset + *size * sizeof(MI_Uint64) > self->size)
273 return MI_RESULT_FAILED;
274 mike 1.1
275 /* Store pointer to array */
276 *data = (const MI_Uint64*)((char*)self->data + self->offset);
277 self->offset += *size * sizeof(MI_Uint64);
278
279 return MI_RESULT_OK;
280 }
281
282 MI_Result Buf_UnpackStr(
283 Buf* self,
284 const MI_Char** x)
285 {
286 MI_Uint32 size;
287
288 /* Unpack size */
289 MI_RETURN_ERR(Buf_UnpackU32(self, &size));
290
291 if (size == 0)
292 {
293 *x = NULL;
294 return MI_RESULT_OK;
295 mike 1.1 }
296
297 /* Check whether there are enough bytes left */
298 if (self->offset + size * sizeof(MI_Char) > self->size)
299 return MI_RESULT_FAILED;
300
301 /* Store pointer to array */
302 *x = (const MI_Char*)((char*)self->data + self->offset);
303 self->offset += size * sizeof(MI_Char);
304
305 return MI_RESULT_OK;
306 }
307
308 MI_Result Buf_PackStrA(
309 Buf* self,
310 const MI_Char** data,
311 MI_Uint32 size)
312 {
313 MI_Uint32 i;
314
315 /* Pack the array size (the number of strings) */
316 mike 1.1 MI_RETURN_ERR(Buf_PackU32(self, size));
317
318 if (size)
319 {
320 MI_Uint32 sizes[64];
321
322 if (!data)
323 return MI_RESULT_FAILED;
324
325 /* Put sizes of all strings first. Each size is encoded as a 64-bit
326 * integer. The unpack function replaces this integer with a pointer
327 * to the corresponding string. This avoids having to allocate memory
328 * for the pointer array while unpacking.
329 */
330 for (i = 0; i < size; i++)
331 {
332 MI_Uint32 n;
333
334 if (!data[i])
335 return MI_RESULT_FAILED;
336
337 mike 1.1 n = (MI_Uint32)Zlen(data[i]) + 1;
338
339 /* Save size so that it will not have to be recalculated by the
340 * next loop using strlen.
341 */
342 if (i < MI_COUNT(sizes))
343 sizes[i] = n;
344
345 MI_RETURN_ERR(Buf_PackU64(self, (MI_Uint64)n));
346 }
347
348 /* Pack strings one after the other. */
349 for (i = 0; i < size; i++)
350 {
351 MI_Uint32 n;
352
353 if (i < MI_COUNT(sizes))
354 n = sizes[i];
355 else
356 n = (MI_Uint32)Zlen(data[i]) + 1;
357
358 mike 1.1 MI_RETURN_ERR(Buf_App(self, data[i], n * sizeof(MI_Char)));
359 }
360 }
361
362 return MI_RESULT_OK;
363 }
364
365 MI_Result Buf_UnpackStrA(
366 Buf* self,
367 const MI_Char*** dataOut,
368 MI_Uint32* sizeOut)
369 {
370 const MI_Char** data;
371 MI_Uint32 size;
372 MI_Uint32 i;
373 MI_Uint32 offset;
374
375 /* Unpack the size of the array */
376 MI_RETURN_ERR(Buf_UnpackU32(self, &size));
377
378 /* Handle zero-size array case */
379 mike 1.1 if (size == 0)
380 {
381 *dataOut = NULL;
382 *sizeOut = 0;
383 return MI_RESULT_OK;
384 }
385
386 /* Align to read uint64 sizes */
387 MI_RETURN_ERR(Buf_Align64(self));
388
389 /* Set pointer data array */
390 data = (const MI_Char**)((char*)self->data + self->offset);
391
392 /* Calculate offset to first string in array (data[0]) */
393 offset = self->offset + (size * sizeof(MI_Uint64));
394
395 /* Fail if offset is beyond end of buffer */
396 if (offset > self->size)
397 return MI_RESULT_FAILED;
398
399 /* Unpack the string sizes and covert to string pointers */
400 mike 1.1 for (i = 0; i < size; i++)
401 {
402 MI_Uint64 tmp;
403 MI_Uint32 n;
404
405 /* Unpack size of next string in array */
406 MI_RETURN_ERR(Buf_UnpackU64(self, &tmp));
407 n = (MI_Uint32)tmp;
408
409 /* Fail if not enough room left in buffer for string */
410 if (offset + n * sizeof(MI_Char) > self->size)
411 return MI_RESULT_FAILED;
412
413 /* Add string to array */
414 data[i] = (MI_Char*)((char*)self->data + offset);
415 offset += n * sizeof(MI_Char);
416 }
417
418 /* Update the offset */
419 self->offset = offset;
420
421 mike 1.1 /* Set the output parameters */
422 *dataOut = data;
423 *sizeOut = size;
424
425 return MI_RESULT_OK;
426 }
427
428 MI_Result Buf_PackDT(
429 Buf* self,
430 const MI_Datetime* x)
431 {
432 MI_RETURN_ERR(Buf_Pad32(self));
433 MI_RETURN_ERR(Buf_App(self, x, sizeof(MI_Datetime)));
434 return MI_RESULT_OK;
435 }
436
437 MI_Result Buf_UnpackDT(
438 Buf* self,
439 MI_Datetime* x)
440 {
441 MI_Uint32 offset;
442 mike 1.1
443 MI_RETURN_ERR(Buf_Align32(self));
444
445 /* Find ending offset of datetime structure */
446 offset = self->offset + sizeof(MI_Datetime);
447
448 if (offset > self->size)
449 return MI_RESULT_FAILED;
450
451 memcpy(x, (char*)self->data + self->offset, sizeof(MI_Datetime));
452 self->offset = offset;
453
454 return MI_RESULT_OK;
455 }
456
457 MI_Result Buf_PackDTA(
458 Buf* self,
459 const MI_Datetime* data,
460 MI_Uint32 size)
461 {
462 MI_RETURN_ERR(Buf_PackU32(self, size));
463 mike 1.1 MI_RETURN_ERR(Buf_App(self, data, size * sizeof(MI_Datetime)));
464 return MI_RESULT_OK;
465 }
466
467 MI_Result Buf_UnpackDTA(
468 Buf* self,
469 const MI_Datetime** dataPtr,
470 MI_Uint32* sizePtr)
471 {
472 MI_Uint32 offset;
473
474 /* Unpack the size */
475 MI_RETURN_ERR(Buf_UnpackU32(self, sizePtr));
476
477 /* Handle zero-sized array (null data pointer) */
478 if (*sizePtr == 0)
479 {
480 *dataPtr = NULL;
481 return MI_RESULT_OK;
482 }
483
484 mike 1.1 /* Find ending offset of datetime array */
485 offset = self->offset + *sizePtr * sizeof(MI_Datetime);
486
487 /* Set pointer to data array */
488 *dataPtr = (const MI_Datetime*)((char*)self->data + self->offset);
489
490 /* Advance offset beyond array */
491 self->offset = offset;
492
493 return MI_RESULT_OK;
494 }
495
496 Page* Buf_StealPage(
497 Buf* self)
498 {
499 if (self->data)
500 {
501 Page* page = (Page*)self->data - 1;
502 self->data = NULL;
503 return page;
504 }
505 mike 1.1
506 return NULL;
507 }
|