(file) Return to buf.c CVS log (file) (dir) Up to [OMI] / omi / base

  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              

ViewCVS 0.9.2