le_pack.h

1 /**
2  * @page c_pack Low-level Pack/Unpack API
3  *
4  * @ref le_pack.h "API Reference"
5  *
6  * <HR>
7  *
8  * This low-level pack/unpack API is intended to support the higher level
9  * IPC messaging system, specifically code generated by ifgen. But it
10  * can also be used to hand-pack messages if using the @ref c_messaging
11  * API directly.
12  *
13  * This low-level pack/unpack API supports:
14  * - Packing basic types supported by the IPC system.
15  * - Packing reference types
16  * - Packing arrays of the above types
17  * - Packing strings.
18  * It also supports unpacking any of the above.
19  */
20 
21 #ifndef LE_PACK_H_INCLUDE_GUARD
22 #define LE_PACK_H_INCLUDE_GUARD
23 
24 //--------------------------------------------------------------------------------------------------
25 // Pack functions
26 //--------------------------------------------------------------------------------------------------
27 
28 // Packing a simple value is basically the same regardless of type. But don't use this macro
29 // directly to get better verification that we're only packing the types we expect
30 #define LE_PACK_PACK_SIMPLE_VALUE(value) \
31  if (*sizePtr < sizeof(value)) \
32  { \
33  return false; \
34  } \
35  \
36  memcpy(*bufferPtr, &(value), sizeof(value)); \
37  \
38  *bufferPtr = *bufferPtr + sizeof(value); \
39  *sizePtr -= sizeof(value); \
40  \
41  return true
42 
43 
44 //--------------------------------------------------------------------------------------------------
45 /**
46  * Pack a uint8_t into a buffer, incrementing the buffer pointer and decrementing the
47  * available size, as appropriate.
48  *
49  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
50  * size is known at compile time.
51  */
52 //--------------------------------------------------------------------------------------------------
53 static inline bool le_pack_PackUint8
54 (
55  uint8_t** bufferPtr,
56  size_t* sizePtr,
57  uint8_t value
58 )
59 {
60  LE_PACK_PACK_SIMPLE_VALUE(value);
61 }
62 
63 //--------------------------------------------------------------------------------------------------
64 /**
65  * Pack a uint16_t into a buffer, incrementing the buffer pointer and decrementing the
66  * available size, as appropriate.
67  *
68  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
69  * size is known at compile time.
70  */
71 //--------------------------------------------------------------------------------------------------
72 static inline bool le_pack_PackUint16
73 (
74  uint8_t** bufferPtr,
75  size_t* sizePtr,
76  uint16_t value
77 )
78 {
79  LE_PACK_PACK_SIMPLE_VALUE(value);
80 }
81 
82 //--------------------------------------------------------------------------------------------------
83 /**
84  * Pack a uint32_t into a buffer, incrementing the buffer pointer and decrementing the
85  * available size, as appropriate.
86  *
87  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
88  * size is known at compile time.
89  */
90 //--------------------------------------------------------------------------------------------------
91 static inline bool le_pack_PackUint32
92 (
93  uint8_t** bufferPtr,
94  size_t* sizePtr,
95  uint32_t value
96 )
97 {
98  LE_PACK_PACK_SIMPLE_VALUE(value);
99 }
100 
101 //--------------------------------------------------------------------------------------------------
102 /**
103  * Pack a uint64_t into a buffer, incrementing the buffer pointer and decrementing the
104  * available size, as appropriate.
105  *
106  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
107  * size is known at compile time.
108  */
109 //--------------------------------------------------------------------------------------------------
110 static inline bool le_pack_PackUint64
111 (
112  uint8_t** bufferPtr,
113  size_t* sizePtr,
114  uint64_t value
115 )
116 {
117  LE_PACK_PACK_SIMPLE_VALUE(value);
118 }
119 
120 //--------------------------------------------------------------------------------------------------
121 /**
122  * Pack a int8_t into a buffer, incrementing the buffer pointer and decrementing the
123  * available size, as appropriate.
124  *
125  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
126  * size is known at compile time.
127  */
128 //--------------------------------------------------------------------------------------------------
129 static inline bool le_pack_PackInt8
130 (
131  uint8_t** bufferPtr,
132  size_t* sizePtr,
133  int8_t value
134 )
135 {
136  LE_PACK_PACK_SIMPLE_VALUE(value);
137 }
138 
139 //--------------------------------------------------------------------------------------------------
140 /**
141  * Pack a int16_t into a buffer, incrementing the buffer pointer and decrementing the
142  * available size, as appropriate.
143  *
144  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
145  * size is known at compile time.
146  */
147 //--------------------------------------------------------------------------------------------------
148 static inline bool le_pack_PackInt16
149 (
150  uint8_t** bufferPtr,
151  size_t* sizePtr,
152  int16_t value
153 )
154 {
155  LE_PACK_PACK_SIMPLE_VALUE(value);
156 }
157 
158 //--------------------------------------------------------------------------------------------------
159 /**
160  * Pack a int32_t into a buffer, incrementing the buffer pointer and decrementing the
161  * available size, as appropriate.
162  *
163  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
164  * size is known at compile time.
165  */
166 //--------------------------------------------------------------------------------------------------
167 static inline bool le_pack_PackInt32
168 (
169  uint8_t** bufferPtr,
170  size_t* sizePtr,
171  int32_t value
172 )
173 {
174  LE_PACK_PACK_SIMPLE_VALUE(value);
175 }
176 
177 //--------------------------------------------------------------------------------------------------
178 /**
179  * Pack a int64_t into a buffer, incrementing the buffer pointer and decrementing the
180  * available size, as appropriate.
181  *
182  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
183  * size is known at compile time.
184  */
185 //--------------------------------------------------------------------------------------------------
186 static inline bool le_pack_PackInt64
187 (
188  uint8_t** bufferPtr,
189  size_t* sizePtr,
190  int64_t value
191 )
192 {
193  LE_PACK_PACK_SIMPLE_VALUE(value);
194 }
195 
196 //--------------------------------------------------------------------------------------------------
197 /**
198  * Pack a size_t into a buffer, incrementing the buffer pointer and decrementing the
199  * available size, as appropriate.
200  *
201  * @note Packed sizes are limited to 2^32-1, regardless of platform
202  */
203 //--------------------------------------------------------------------------------------------------
204 static inline bool le_pack_PackSize
205 (
206  uint8_t **bufferPtr,
207  size_t *sizePtr,
208  size_t value
209 )
210 {
211  if (value > UINT32_MAX)
212  {
213  return false;
214  }
215 
216  return le_pack_PackUint32(bufferPtr, sizePtr, value);
217 }
218 
219 //--------------------------------------------------------------------------------------------------
220 /**
221  * Pack a bool into a buffer, incrementing the buffer pointer and decrementing the
222  * available size, as appropriate.
223  *
224  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
225  * size is known at compile time.
226  */
227 //--------------------------------------------------------------------------------------------------
228 static inline bool le_pack_PackBool
229 (
230  uint8_t** bufferPtr,
231  size_t* sizePtr,
232  bool value
233 )
234 {
235  // Force boolean to uint8_t 0 or 1 for packing, regarldess of underlying OS type.
236  // Underlying type has been int on some platforms in the past.
237  uint8_t simpleValue = ((value)?1:0);
238  LE_PACK_PACK_SIMPLE_VALUE(simpleValue);
239 }
240 
241 //--------------------------------------------------------------------------------------------------
242 /**
243  * Pack a char into a buffer, incrementing the buffer pointer and decrementing the
244  * available size, as appropriate.
245  *
246  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
247  * size is known at compile time.
248  */
249 //--------------------------------------------------------------------------------------------------
250 static inline bool le_pack_PackChar
251 (
252  uint8_t** bufferPtr,
253  size_t* sizePtr,
254  char value
255 )
256 {
257  LE_PACK_PACK_SIMPLE_VALUE(value);
258 }
259 
260 //--------------------------------------------------------------------------------------------------
261 /**
262  * Pack a double into a buffer, incrementing the buffer pointer and decrementing the
263  * available size, as appropriate.
264  *
265  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
266  * size is known at compile time.
267  */
268 //--------------------------------------------------------------------------------------------------
269 static inline bool le_pack_PackDouble
270 (
271  uint8_t** bufferPtr,
272  size_t* sizePtr,
273  double value
274 )
275 {
276  LE_PACK_PACK_SIMPLE_VALUE(value);
277 }
278 
279 //--------------------------------------------------------------------------------------------------
280 /**
281  * Pack a le_result_t into a buffer, incrementing the buffer pointer and decrementing the
282  * available size, as appropriate.
283  *
284  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
285  * size is known at compile time.
286  */
287 //--------------------------------------------------------------------------------------------------
288 static inline bool le_pack_PackResult
289 (
290  uint8_t** bufferPtr,
291  size_t* sizePtr,
292  le_result_t value
293 )
294 {
295  LE_PACK_PACK_SIMPLE_VALUE(value);
296 }
297 
298 //--------------------------------------------------------------------------------------------------
299 /**
300  * Pack le_onoff_t into a buffer, incrementing the buffer pointer and decrementing the
301  * available size, as appropriate.
302  *
303  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
304  * size is known at compile time.
305  */
306 //--------------------------------------------------------------------------------------------------
307 static inline bool le_pack_PackOnOff
308 (
309  uint8_t** bufferPtr,
310  size_t* sizePtr,
311  le_onoff_t value
312 )
313 {
314  LE_PACK_PACK_SIMPLE_VALUE(value);
315 }
316 
317 #undef LE_PACK_PACK_SIMPLE_VALUE
318 
319 //--------------------------------------------------------------------------------------------------
320 /**
321  * Pack a reference into a buffer, incrementing the buffer pointer and decrementing the available
322  * size.
323  */
324 //--------------------------------------------------------------------------------------------------
325 static inline bool le_pack_PackReference
326 (
327  uint8_t** bufferPtr,
328  size_t* sizePtr,
329  const void* ref
330 )
331 {
332  size_t refAsInt = (size_t)ref;
333 
334  // All references passed through an API must be safe references (or NULL), so
335  // 0-bit will be set and reference will be <= UINT32_MAX. Size check
336  // is performed in pack function.
337  if ((refAsInt <= UINT32_MAX) &&
338  ((refAsInt & 0x01) ||
339  !refAsInt))
340  {
341  return le_pack_PackUint32(bufferPtr, sizePtr, (uint32_t)refAsInt);
342  }
343  else
344  {
345  return false;
346  }
347 }
348 
349 //--------------------------------------------------------------------------------------------------
350 /**
351  * Pack a string into a buffer, incrementing the buffer pointer and decrementing the available
352  * size.
353  *
354  * @note Always decrements available size according to the max possible size used, not actual size
355  * used. Will assert if provided string is larger than maximum allowable string.
356  */
357 //--------------------------------------------------------------------------------------------------
358 static inline bool le_pack_PackString
359 (
360  uint8_t** bufferPtr,
361  size_t* sizePtr,
362  const char *stringPtr,
363  uint32_t maxStringCount
364 )
365 {
366  size_t bytesCopied;
367 
368  if (*sizePtr < (maxStringCount + sizeof(uint32_t)))
369  {
370  return false;
371  }
372 
373  if (!stringPtr)
374  {
375  return false;
376  }
377 
378 #if defined(__KLOCWORK__)
379  // Just like strncpy & strnlen, this function doesn't know the size of the source string,
380  // which can potentially result in a read overflow on the input buffer.
381  // Static code analyzer can report this issue, which is deliberatly ignored since this
382  // function expects NULL-terminated strings.
383  maxStringCount = strnlen(stringPtr, maxStringCount);
384 #endif
385 
386  // First copy in the string -- up to maxStringCount bytes, allowing enough
387  // space at the begining for a uint32.
388  for (bytesCopied = 0;
389  (bytesCopied < maxStringCount) && (stringPtr[bytesCopied] != '\0');
390  ++bytesCopied)
391  {
392  (*bufferPtr)[bytesCopied + sizeof(uint32_t)] = stringPtr[bytesCopied];
393  }
394 
395  // String was too long to fit in the buffer -- return false.
396  if (stringPtr[bytesCopied] != '\0')
397  {
398  return false;
399  }
400 
401  // Then go back and copy string size. No loss of precision packing into a uint32
402  // because maxStringCount is a uint32 or less.
403  bool packResult = le_pack_PackUint32(bufferPtr, sizePtr, bytesCopied);
404  LE_ASSERT(packResult); // Should not fail -- have checked there's enough space above.
405 
406  // Now increment buffer by size of string actually copied, and decrement available
407  // space by max which could have been copied. This ensures out of space errors will
408  // be caught as soon as possible.
409  *bufferPtr = *bufferPtr + bytesCopied;
410  *sizePtr -= maxStringCount;
411 
412  return true;
413 }
414 
415 //--------------------------------------------------------------------------------------------------
416 /**
417  * Pack the size information for an array into a buffer, incrementing the buffer pointer and
418  * decrementing the available size.
419  *
420  * @note Users of this API should generally use LE_PACK_PACKARRAY macro instead which also
421  * packs the array data.
422  */
423 //--------------------------------------------------------------------------------------------------
424 static inline bool le_pack_PackArrayHeader
425 (
426  uint8_t **bufferPtr,
427  size_t *sizePtr,
428  const void *arrayPtr,
429  size_t elementSize,
430  size_t arrayCount,
431  size_t arrayMaxCount
432 )
433 {
434  if ((*sizePtr < arrayMaxCount*elementSize + sizeof(uint32_t)) ||
435  (arrayCount > arrayMaxCount))
436  {
437  return false;
438  }
439 
440  LE_ASSERT(le_pack_PackSize(bufferPtr, sizePtr, arrayCount));
441 
442  return true;
443 }
444 
445 //--------------------------------------------------------------------------------------------------
446 /**
447  * Pack an array into a buffer, incrementing the buffer pointer and decrementing the available
448  * size.
449  *
450  * @note Always decrements available size according to the max possible size used, not actual size
451  * used. Will assert if provided string is larger than maximum allowable string.
452  */
453 //--------------------------------------------------------------------------------------------------
454 #define LE_PACK_PACKARRAY(bufferPtr, \
455  sizePtr, \
456  arrayPtr, \
457  arrayCount, \
458  arrayMaxCount, \
459  packFunc, \
460  resultPtr) \
461  do { \
462  *(resultPtr) = le_pack_PackArrayHeader((bufferPtr), (sizePtr), \
463  (arrayPtr), sizeof((arrayPtr)[0]), \
464  (arrayCount), (arrayMaxCount)); \
465  if (*(resultPtr)) \
466  { \
467  uint32_t i; \
468  size_t newSizePtr = *(sizePtr) - sizeof((arrayPtr)[0])*(arrayMaxCount); \
469  for (i = 0; i < (arrayCount); ++i) \
470  { \
471  LE_ASSERT(packFunc((bufferPtr), (sizePtr), (arrayPtr)[i])); \
472  } \
473  LE_ASSERT(*(sizePtr) >= newSizePtr); \
474  *(sizePtr) = newSizePtr; \
475  *(resultPtr) = true; \
476  } \
477  } while (0)
478 
479 //--------------------------------------------------------------------------------------------------
480 // Unpack functions
481 //--------------------------------------------------------------------------------------------------
482 
483 #define LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr) \
484  if (*sizePtr < sizeof(*(valuePtr))) \
485  { \
486  return false; \
487  } \
488  \
489  memcpy((valuePtr), *bufferPtr, sizeof(*(valuePtr))); \
490  \
491  *bufferPtr = (*bufferPtr) + sizeof(*(valuePtr)); \
492  *sizePtr -= sizeof(*(valuePtr)); \
493  \
494  return true
495 
496 //--------------------------------------------------------------------------------------------------
497 /**
498  * Unpack a uint8_t from a buffer, incrementing the buffer pointer and decrementing the
499  * available size, as appropriate.
500  *
501  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
502  * size is known at compile time.
503  */
504 //--------------------------------------------------------------------------------------------------
505 static inline bool le_pack_UnpackUint8
506 (
507  uint8_t** bufferPtr,
508  size_t* sizePtr,
509  uint8_t* valuePtr
510 )
511 {
512  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
513 }
514 
515 //--------------------------------------------------------------------------------------------------
516 /**
517  * Unpack a uint16_t from a buffer, incrementing the buffer pointer and decrementing the
518  * available size, as appropriate.
519  *
520  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
521  * size is known at compile time.
522  */
523 //--------------------------------------------------------------------------------------------------
524 static inline bool le_pack_UnpackUint16
525 (
526  uint8_t** bufferPtr,
527  size_t* sizePtr,
528  uint16_t* valuePtr
529 )
530 {
531  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
532 }
533 
534 //--------------------------------------------------------------------------------------------------
535 /**
536  * Unpack a uint32_t from a buffer, incrementing the buffer pointer and decrementing the
537  * available size, as appropriate.
538  *
539  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
540  * size is known at compile time.
541  */
542 //--------------------------------------------------------------------------------------------------
543 static inline bool le_pack_UnpackUint32
544 (
545  uint8_t** bufferPtr,
546  size_t* sizePtr,
547  uint32_t* valuePtr
548 )
549 {
550  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
551 }
552 
553 //--------------------------------------------------------------------------------------------------
554 /**
555  * Unpack a uint64_t from a buffer, incrementing the buffer pointer and decrementing the
556  * available size, as appropriate.
557  *
558  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
559  * size is known at compile time.
560  */
561 //--------------------------------------------------------------------------------------------------
562 static inline bool le_pack_UnpackUint64
563 (
564  uint8_t** bufferPtr,
565  size_t* sizePtr,
566  uint64_t* valuePtr
567 )
568 {
569  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
570 }
571 
572 //--------------------------------------------------------------------------------------------------
573 /**
574  * Unpack a int8_t from a buffer, incrementing the buffer pointer and decrementing the
575  * available size, as appropriate.
576  *
577  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
578  * size is known at compile time.
579  */
580 //--------------------------------------------------------------------------------------------------
581 static inline bool le_pack_UnpackInt8
582 (
583  uint8_t** bufferPtr,
584  size_t* sizePtr,
585  int8_t* valuePtr
586 )
587 {
588  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
589 }
590 
591 //--------------------------------------------------------------------------------------------------
592 /**
593  * Unpack a int16_t from a buffer, incrementing the buffer pointer and decrementing the
594  * available size, as appropriate.
595  *
596  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
597  * size is known at compile time.
598  */
599 //--------------------------------------------------------------------------------------------------
600 static inline bool le_pack_UnpackInt16
601 (
602  uint8_t** bufferPtr,
603  size_t* sizePtr,
604  int16_t* valuePtr
605 )
606 {
607  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
608 }
609 
610 //--------------------------------------------------------------------------------------------------
611 /**
612  * Unpack a int32_t from a buffer, incrementing the buffer pointer and decrementing the
613  * available size, as appropriate.
614  *
615  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
616  * size is known at compile time.
617  */
618 //--------------------------------------------------------------------------------------------------
619 static inline bool le_pack_UnpackInt32
620 (
621  uint8_t** bufferPtr,
622  size_t* sizePtr,
623  int32_t* valuePtr
624 )
625 {
626  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
627 }
628 
629 //--------------------------------------------------------------------------------------------------
630 /**
631  * Unpack a int64_t from a buffer, incrementing the buffer pointer and decrementing the
632  * available size, as appropriate.
633  *
634  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
635  * size is known at compile time.
636  */
637 //--------------------------------------------------------------------------------------------------
638 static inline bool le_pack_UnpackInt64
639 (
640  uint8_t** bufferPtr,
641  size_t* sizePtr,
642  int64_t* valuePtr
643 )
644 {
645  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
646 }
647 
648 /**
649  * Pack a size_t into a buffer, incrementing the buffer pointer and decrementing the
650  * available size, as appropriate.
651  *
652  * @note Packed sizes are limited to 2^32-1, regardless of platform
653  */
654 //--------------------------------------------------------------------------------------------------
655 static inline bool le_pack_UnpackSize
656 (
657  uint8_t **bufferPtr,
658  size_t *sizePtr,
659  size_t *valuePtr
660 )
661 {
662  uint32_t rawValue;
663 
664  if (!le_pack_UnpackUint32(bufferPtr, sizePtr, &rawValue))
665  {
666  return false;
667  }
668 
669  *valuePtr = rawValue;
670 
671  return true;
672 }
673 
674 //--------------------------------------------------------------------------------------------------
675 /**
676  * Unpack a bool from a buffer, incrementing the buffer pointer and decrementing the
677  * available size, as appropriate.
678  *
679  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
680  * size is known at compile time.
681  */
682 //--------------------------------------------------------------------------------------------------
683 static inline bool le_pack_UnpackBool
684 (
685  uint8_t** bufferPtr,
686  size_t* sizePtr,
687  bool* valuePtr
688 )
689 {
690  // Treat boolean as uint8_t for packing, regarldess of underlying OS type.
691  // Underlying type has been int on some platforms in the past.
692  uint8_t simpleValue;
693  if (*sizePtr < sizeof(simpleValue))
694  {
695  return false;
696  }
697 
698  memcpy(&simpleValue, *bufferPtr, sizeof(simpleValue));
699 
700  *bufferPtr = ((uint8_t* )*bufferPtr) + sizeof(simpleValue);
701  *sizePtr -= sizeof(simpleValue);
702 
703  // force to true or false
704  *valuePtr = !!simpleValue;
705 
706  return true;
707 }
708 
709 //--------------------------------------------------------------------------------------------------
710 /**
711  * Unpack a char from a buffer, incrementing the buffer pointer and decrementing the
712  * available size, as appropriate.
713  *
714  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
715  * size is known at compile time.
716  */
717 //--------------------------------------------------------------------------------------------------
718 static inline bool le_pack_UnpackChar
719 (
720  uint8_t** bufferPtr,
721  size_t* sizePtr,
722  char* valuePtr
723 )
724 {
725  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
726 }
727 
728 //--------------------------------------------------------------------------------------------------
729 /**
730  * Unpack a double from a buffer, incrementing the buffer pointer and decrementing the
731  * available size, as appropriate.
732  *
733  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
734  * size is known at compile time.
735  */
736 //--------------------------------------------------------------------------------------------------
737 static inline bool le_pack_UnpackDouble
738 (
739  uint8_t** bufferPtr,
740  size_t* sizePtr,
741  double* valuePtr
742 )
743 {
744  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
745 }
746 
747 //--------------------------------------------------------------------------------------------------
748 /**
749  * Unpack a le_result_t from a buffer, incrementing the buffer pointer and decrementing the
750  * available size, as appropriate.
751  *
752  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
753  * size is known at compile time.
754  */
755 //--------------------------------------------------------------------------------------------------
756 static inline bool le_pack_UnpackResult
757 (
758  uint8_t** bufferPtr,
759  size_t* sizePtr,
760  le_result_t* valuePtr
761 )
762 {
763  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
764 }
765 
766 //--------------------------------------------------------------------------------------------------
767 /**
768  * Pack le_onoff_t into a buffer, incrementing the buffer pointer and decrementing the
769  * available size, as appropriate.
770  *
771  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
772  * size is known at compile time.
773  */
774 //--------------------------------------------------------------------------------------------------
775 static inline bool le_pack_UnpackOnOff
776 (
777  uint8_t** bufferPtr,
778  size_t* sizePtr,
779  le_onoff_t* valuePtr
780 )
781 {
782  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
783 }
784 
785 #undef LE_PACK_UNPACK_SIMPLE_VALUE
786 
787 //--------------------------------------------------------------------------------------------------
788 /**
789  * Unpack a reference from a buffer, incrementing the buffer pointer and decrementing the available
790  * size.
791  */
792 //--------------------------------------------------------------------------------------------------
793 static inline bool le_pack_UnpackReference
794 (
795  uint8_t** bufferPtr,
796  size_t* sizePtr,
797  void* refPtr ///< Pointer to the reference. Declared as void * to allow implicit
798  ///< conversion from pointer to reference types.
799 )
800 {
801  uint32_t refAsInt;
802 
803  if (!le_pack_UnpackUint32(bufferPtr, sizePtr, &refAsInt))
804  {
805  return false;
806  }
807 
808  // All references passed through an API must be safe references, so
809  // 0-bit will be set. Check that here to be safe.
810  if ((refAsInt & 0x01) ||
811  (!refAsInt))
812  {
813  // Double cast to avoid warnings.
814  *(void **)refPtr = (void *)(size_t)refAsInt;
815  return true;
816  }
817  else
818  {
819  return false;
820  }
821 }
822 
823 //--------------------------------------------------------------------------------------------------
824 /**
825  * Unpack a string from a buffer, incrementing the buffer pointer and decrementing the available
826  * size.
827  *
828  * @note Always decrements available size according to the max possible size used, not actual size
829  * used. Will assert if provided string is larger than maximum allowable string.
830  */
831 //--------------------------------------------------------------------------------------------------
832 static inline bool le_pack_UnpackString
833 (
834  uint8_t** bufferPtr,
835  size_t* sizePtr,
836  char *stringPtr,
837  uint32_t bufferSize,
838  uint32_t maxStringCount
839 )
840 {
841  uint32_t stringSize;
842 
843  if (*sizePtr < (maxStringCount + sizeof(uint32_t)))
844  {
845  return false;
846  }
847 
848  // First get string size
849  if (!le_pack_UnpackUint32(bufferPtr, sizePtr, &stringSize))
850  {
851  return false;
852  }
853 
854  if ((stringSize > maxStringCount) ||
855  (stringSize > bufferSize))
856  {
857  return false;
858  }
859 
860  if (!stringPtr)
861  {
862  // Only allow unpacking into no output buffer if the string is zero sized.
863  // Otherwise an output buffer is required.
864  if (stringSize)
865  {
866  return false;
867  }
868  else
869  {
870  return true;
871  }
872  }
873 
874  memcpy(stringPtr, *bufferPtr, stringSize);
875  stringPtr[stringSize] = '\0';
876 
877  *bufferPtr = *bufferPtr + stringSize;
878  *sizePtr -= maxStringCount;
879 
880  return true;
881 }
882 
883 //--------------------------------------------------------------------------------------------------
884 /**
885  * Pack the size information for an array into a buffer, incrementing the buffer pointer and
886  * decrementing the available size.
887  *
888  * @note Users of this API should generally use LE_PACK_PACKARRAY macro instead which also
889  * packs the array data.
890  */
891 //--------------------------------------------------------------------------------------------------
892 static inline bool le_pack_UnpackArrayHeader
893 (
894  uint8_t **bufferPtr,
895  size_t *sizePtr,
896  const void *arrayPtr,
897  size_t elementSize,
898  size_t *arrayCountPtr,
899  size_t arrayMaxCount
900 )
901 {
902  if (*sizePtr < (arrayMaxCount*elementSize + sizeof(uint32_t)))
903  {
904  return false;
905  }
906 
907  LE_ASSERT(le_pack_UnpackSize(bufferPtr, sizePtr, arrayCountPtr));
908  if (*arrayCountPtr > arrayMaxCount)
909  {
910  return false;
911  }
912  else if (!arrayPtr)
913  {
914  // Missing array pointer must match zero sized array.
915  return (*arrayCountPtr == 0);
916  }
917 
918  return true;
919 }
920 
921 //--------------------------------------------------------------------------------------------------
922 /**
923  * Unpack an array into from buffer, incrementing the buffer pointer and decrementing the available
924  * size.
925  *
926  * @note Always decrements available size according to the max possible size used, not actual size
927  * used. Will assert if provided string is larger than maximum allowable string.
928  */
929 //--------------------------------------------------------------------------------------------------
930 #define LE_PACK_UNPACKARRAY(bufferPtr, \
931  sizePtr, \
932  arrayPtr, \
933  arrayCountPtr, \
934  arrayMaxCount, \
935  unpackFunc, \
936  resultPtr) \
937  do { \
938  if (!le_pack_UnpackArrayHeader((bufferPtr), (sizePtr), \
939  (arrayPtr), sizeof((arrayPtr)[0]), \
940  (arrayCountPtr), (arrayMaxCount))) \
941  { \
942  *(resultPtr) = false; \
943  } \
944  else \
945  { \
946  uint32_t i; \
947  size_t newSizePtr = *(sizePtr) - sizeof((arrayPtr)[0])*(arrayMaxCount); \
948  for (i = 0; i < *(arrayCountPtr); ++i) \
949  { \
950  LE_ASSERT(unpackFunc((bufferPtr), (sizePtr), &(arrayPtr)[i])); \
951  } \
952  LE_ASSERT(*(sizePtr) >= newSizePtr); \
953  *(sizePtr) = newSizePtr; \
954  *(resultPtr) = true; \
955  } \
956  } while (0)
957 
958 #endif /* LE_PACK_H_INCLUDE_GUARD */
le_result_t
Definition: le_basics.h:35
#define LE_ASSERT(condition)
Definition: le_log.h:560
le_onoff_t
Definition: le_basics.h:70