le_pack.h

1 /**
2  * @page c_pack Low-level Pack/Unpack API
3  *
4  * @subpage 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 /**
26  * Pack Definitions and Types
27  */
28 //--------------------------------------------------------------------------------------------------
29 #ifdef LE_CONFIG_RPC
30 typedef uint8_t TagID_t;
31 
32 #define LE_PACK_UINT8 1
33 #define LE_PACK_UINT16 2
34 #define LE_PACK_UINT32 3
35 #define LE_PACK_UINT64 4
36 #define LE_PACK_INT8 5
37 #define LE_PACK_INT16 6
38 #define LE_PACK_INT32 7
39 #define LE_PACK_INT64 8
40 #define LE_PACK_SIZE 9
41 #define LE_PACK_BOOL 10
42 #define LE_PACK_CHAR 11
43 #define LE_PACK_DOUBLE 12
44 #define LE_PACK_RESULT 13
45 #define LE_PACK_ONOFF 14
46 #define LE_PACK_REFERENCE 15
47 #define LE_PACK_STRING 16
48 #define LE_PACK_ARRAYHEADER 17
49 #define LE_PACK_IN_STRING_POINTER 18
50 #define LE_PACK_OUT_STRING_POINTER 19
51 #define LE_PACK_IN_ARRAY_POINTER 20
52 #define LE_PACK_OUT_ARRAY_POINTER 21
53 
54 #define LE_PACK_SIZEOF_TAG_ID sizeof(TagID_t)
55 #define LE_PACK_SIZEOF_BOOL sizeof(bool)
56 #define LE_PACK_SIZEOF_CHAR sizeof(char)
57 #define LE_PACK_SIZEOF_UINT8 sizeof(uint8_t)
58 #define LE_PACK_SIZEOF_UINT16 sizeof(uint16_t)
59 #define LE_PACK_SIZEOF_UINT32 sizeof(uint32_t)
60 #define LE_PACK_SIZEOF_UINT64 sizeof(uint64_t)
61 #define LE_PACK_SIZEOF_INT8 sizeof(int8_t)
62 #define LE_PACK_SIZEOF_INT16 sizeof(int16_t)
63 #define LE_PACK_SIZEOF_INT32 sizeof(int32_t)
64 #define LE_PACK_SIZEOF_INT64 sizeof(int64_t)
65 #define LE_PACK_SIZEOF_DOUBLE sizeof(double)
66 #define LE_PACK_SIZEOF_RESULT LE_PACK_SIZEOF_UINT32
67 #define LE_PACK_SIZEOF_ONOFF LE_PACK_SIZEOF_UINT32
68 #define LE_PACK_SIZEOF_SIZE LE_PACK_SIZEOF_UINT32
69 #define LE_PACK_SIZEOF_REFERENCE LE_PACK_SIZEOF_UINT32
70 #endif
71 
72 //--------------------------------------------------------------------------------------------------
73 // Pack functions
74 //--------------------------------------------------------------------------------------------------
75 
76 // Packing a simple value is basically the same regardless of type. But don't use this macro
77 // directly to get better verification that we're only packing the types we expect
78 #define LE_PACK_PACK_SIMPLE_VALUE(value) \
79  do { \
80  memcpy(*bufferPtr, &(value), sizeof(value)); \
81  *bufferPtr = *bufferPtr + sizeof(value); \
82  } while (0)
83 
84 
85 #ifdef LE_CONFIG_RPC
86 //--------------------------------------------------------------------------------------------------
87 /**
88  * Pack a TagID into a buffer, incrementing the buffer pointer and decrementing the
89  * available size, as appropriate.
90  *
91  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
92  * size is known at compile time.
93  */
94 //--------------------------------------------------------------------------------------------------
95 LE_DECLARE_INLINE bool le_pack_PackTagID
96 (
97  uint8_t** bufferPtr,
98  TagID_t value
99 )
100 {
101  LE_PACK_PACK_SIMPLE_VALUE(value);
102  return true;
103 }
104 #endif
105 
106 //--------------------------------------------------------------------------------------------------
107 /**
108  * Pack a uint8_t into a buffer, incrementing the buffer pointer as appropriate.
109  *
110  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
111  * size is known at compile time.
112  */
113 //--------------------------------------------------------------------------------------------------
114 LE_DECLARE_INLINE bool le_pack_PackUint8
115 (
116  uint8_t** bufferPtr,
117  uint8_t value
118 )
119 {
120 #ifdef LE_CONFIG_RPC
121  le_pack_PackTagID(bufferPtr, LE_PACK_UINT8);
122 #endif
123  LE_PACK_PACK_SIMPLE_VALUE(value);
124  return true;
125 }
126 
127 #ifdef LE_CONFIG_RPC
128 //--------------------------------------------------------------------------------------------------
129 /**
130  * Pack a uint8_t into a buffer using the specified TagID, incrementing the buffer pointer
131  * and decrementing the available size, as appropriate.
132  *
133  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
134  * size is known at compile time.
135  */
136 //--------------------------------------------------------------------------------------------------
137 LE_DECLARE_INLINE bool le_pack_PackTaggedUint8
138 (
139  uint8_t** bufferPtr,
140  uint8_t value,
141  TagID_t tagId
142 )
143 {
144  le_pack_PackTagID(bufferPtr, tagId);
145  LE_PACK_PACK_SIMPLE_VALUE(value);
146  return true;
147 }
148 #endif
149 
150 //--------------------------------------------------------------------------------------------------
151 /**
152  * Pack a uint16_t into a buffer, incrementing the buffer pointer as appropriate.
153  */
154 //--------------------------------------------------------------------------------------------------
155 LE_DECLARE_INLINE bool le_pack_PackUint16
156 (
157  uint8_t** bufferPtr,
158  uint16_t value
159 )
160 {
161 #ifdef LE_CONFIG_RPC
162  uint16_t newValue = htobe16(value);
163  le_pack_PackTagID(bufferPtr, LE_PACK_UINT16);
164  LE_PACK_PACK_SIMPLE_VALUE(newValue);
165 #else
166  LE_PACK_PACK_SIMPLE_VALUE(value);
167 #endif
168  return true;
169 }
170 
171 
172 #ifdef LE_CONFIG_RPC
173 //--------------------------------------------------------------------------------------------------
174 /**
175  * Pack a uint16_t into a buffer using the specified TagID, incrementing the buffer pointer
176  * and decrementing the available size, as appropriate.
177  *
178  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
179  * size is known at compile time.
180  */
181 //--------------------------------------------------------------------------------------------------
182 LE_DECLARE_INLINE bool le_pack_PackTaggedUint16
183 (
184  uint8_t** bufferPtr,
185  uint16_t value,
186  TagID_t tagId
187 )
188 {
189  uint16_t newValue = htobe16(value);
190  le_pack_PackTagID(bufferPtr, tagId);
191  LE_PACK_PACK_SIMPLE_VALUE(newValue);
192  return true;
193 }
194 #endif
195 
196 //--------------------------------------------------------------------------------------------------
197 /**
198  * Pack a uint32_t into a buffer, incrementing the buffer pointer as appropriate.
199  */
200 //--------------------------------------------------------------------------------------------------
201 LE_DECLARE_INLINE bool le_pack_PackUint32
202 (
203  uint8_t** bufferPtr,
204  uint32_t value
205 )
206 {
207 #ifdef LE_CONFIG_RPC
208  uint32_t newValue = htobe32(value);
209  le_pack_PackTagID(bufferPtr, LE_PACK_UINT32);
210  LE_PACK_PACK_SIMPLE_VALUE(newValue);
211 #else
212  LE_PACK_PACK_SIMPLE_VALUE(value);
213 #endif
214  return true;
215 }
216 
217 
218 #ifdef LE_CONFIG_RPC
219 //--------------------------------------------------------------------------------------------------
220 /**
221  * Pack a uint32_t into a buffer using the specified TagID, incrementing the buffer pointer
222  * and decrementing the 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 LE_DECLARE_INLINE bool le_pack_PackTaggedUint32
229 (
230  uint8_t** bufferPtr,
231  uint32_t value,
232  TagID_t tagId
233 )
234 {
235  uint32_t newValue = htobe32(value);
236  le_pack_PackTagID(bufferPtr, tagId);
237  LE_PACK_PACK_SIMPLE_VALUE(newValue);
238  return true;
239 }
240 #endif
241 
242 //--------------------------------------------------------------------------------------------------
243 /**
244  * Pack a uint64_t into a buffer, incrementing the buffer pointer as appropriate.
245  */
246 //--------------------------------------------------------------------------------------------------
247 LE_DECLARE_INLINE bool le_pack_PackUint64
248 (
249  uint8_t** bufferPtr,
250  uint64_t value
251 )
252 {
253 #ifdef LE_CONFIG_RPC
254  uint64_t newValue = htobe64(value);
255  le_pack_PackTagID(bufferPtr, LE_PACK_UINT64);
256  LE_PACK_PACK_SIMPLE_VALUE(newValue);
257 #else
258  LE_PACK_PACK_SIMPLE_VALUE(value);
259 #endif
260  return true;
261 }
262 
263 #ifdef LE_CONFIG_RPC
264 //--------------------------------------------------------------------------------------------------
265 /**
266  * Pack a uint64_t into a buffer using the specified TagID, incrementing the buffer pointer
267  * and decrementing the available size, as appropriate.
268  *
269  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
270  * size is known at compile time.
271  */
272 //--------------------------------------------------------------------------------------------------
273 LE_DECLARE_INLINE bool le_pack_PackTaggedUint64
274 (
275  uint8_t** bufferPtr,
276  uint64_t value,
277  TagID_t tagId
278 )
279 {
280  uint64_t newValue = htobe64(value);
281  le_pack_PackTagID(bufferPtr, tagId);
282  LE_PACK_PACK_SIMPLE_VALUE(newValue);
283  return true;
284 }
285 #endif
286 
287 //--------------------------------------------------------------------------------------------------
288 /**
289  * Pack a int8_t into a buffer, incrementing the buffer pointer as appropriate.
290  */
291 //--------------------------------------------------------------------------------------------------
292 LE_DECLARE_INLINE bool le_pack_PackInt8
293 (
294  uint8_t** bufferPtr,
295  int8_t value
296 )
297 {
298 #ifdef LE_CONFIG_RPC
299  le_pack_PackTagID(bufferPtr, LE_PACK_INT8);
300 #endif
301  LE_PACK_PACK_SIMPLE_VALUE(value);
302  return true;
303 }
304 
305 #ifdef LE_CONFIG_RPC
306 //--------------------------------------------------------------------------------------------------
307 /**
308  * Pack a int8_t into a buffer using the specified TagID, incrementing the buffer pointer
309  * and decrementing the available size, as appropriate.
310  *
311  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
312  * size is known at compile time.
313  */
314 //--------------------------------------------------------------------------------------------------
315 LE_DECLARE_INLINE bool le_pack_PackTaggedInt8
316 (
317  uint8_t** bufferPtr,
318  int8_t value,
319  TagID_t tagId
320 )
321 {
322  le_pack_PackTagID(bufferPtr, tagId);
323  LE_PACK_PACK_SIMPLE_VALUE(value);
324  return true;
325 }
326 #endif
327 
328 //--------------------------------------------------------------------------------------------------
329 /**
330  * Pack a int16_t into a buffer, incrementing the buffer pointer as appropriate.
331  */
332 //--------------------------------------------------------------------------------------------------
333 LE_DECLARE_INLINE bool le_pack_PackInt16
334 (
335  uint8_t** bufferPtr,
336  int16_t value
337 )
338 {
339 #ifdef LE_CONFIG_RPC
340  int16_t newValue = htobe16(value);
341  le_pack_PackTagID(bufferPtr, LE_PACK_INT16);
342  LE_PACK_PACK_SIMPLE_VALUE(newValue);
343 #else
344  LE_PACK_PACK_SIMPLE_VALUE(value);
345 #endif
346  return true;
347 }
348 
349 #ifdef LE_CONFIG_RPC
350 //--------------------------------------------------------------------------------------------------
351 /**
352  * Pack a int16_t into a buffer using the specified TagID, incrementing the buffer pointer
353  * and decrementing the available size, as appropriate.
354  *
355  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
356  * size is known at compile time.
357  */
358 //--------------------------------------------------------------------------------------------------
359 LE_DECLARE_INLINE bool le_pack_PackTaggedInt16
360 (
361  uint8_t** bufferPtr,
362  int16_t value,
363  TagID_t tagId
364 )
365 {
366  int16_t newValue = htobe16(value);
367  le_pack_PackTagID(bufferPtr, tagId);
368  LE_PACK_PACK_SIMPLE_VALUE(newValue);
369  return true;
370 }
371 #endif
372 
373 //--------------------------------------------------------------------------------------------------
374 /**
375  * Pack a int32_t into a buffer, incrementing the buffer pointer as appropriate.
376  */
377 //--------------------------------------------------------------------------------------------------
378 LE_DECLARE_INLINE bool le_pack_PackInt32
379 (
380  uint8_t** bufferPtr,
381  int32_t value
382 )
383 {
384 #ifdef LE_CONFIG_RPC
385  int32_t newValue = htobe32(value);
386  le_pack_PackTagID(bufferPtr, LE_PACK_INT32);
387  LE_PACK_PACK_SIMPLE_VALUE(newValue);
388 #else
389  LE_PACK_PACK_SIMPLE_VALUE(value);
390 #endif
391  return true;
392 }
393 
394 #ifdef LE_CONFIG_RPC
395 //--------------------------------------------------------------------------------------------------
396 /**
397  * Pack a int32_t into a buffer using the specified TagID, incrementing the buffer pointer
398  * and decrementing the available size, as appropriate.
399  *
400  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
401  * size is known at compile time.
402  */
403 //--------------------------------------------------------------------------------------------------
404 LE_DECLARE_INLINE bool le_pack_PackTaggedInt32
405 (
406  uint8_t** bufferPtr,
407  int32_t value,
408  TagID_t tagId
409 )
410 {
411  int32_t newValue = htobe32(value);
412  le_pack_PackTagID(bufferPtr, tagId);
413  LE_PACK_PACK_SIMPLE_VALUE(newValue);
414  return true;
415 }
416 #endif
417 
418 //--------------------------------------------------------------------------------------------------
419 /**
420  * Pack a int64_t into a buffer, incrementing the buffer pointer as appropriate.
421  */
422 //--------------------------------------------------------------------------------------------------
423 LE_DECLARE_INLINE bool le_pack_PackInt64
424 (
425  uint8_t** bufferPtr,
426  int64_t value
427 )
428 {
429 #ifdef LE_CONFIG_RPC
430  int64_t newValue = htobe64(value);
431  le_pack_PackTagID(bufferPtr, LE_PACK_INT64);
432  LE_PACK_PACK_SIMPLE_VALUE(newValue);
433 #else
434  LE_PACK_PACK_SIMPLE_VALUE(value);
435 #endif
436  return true;
437 }
438 
439 #ifdef LE_CONFIG_RPC
440 //--------------------------------------------------------------------------------------------------
441 /**
442  * Pack a int64_t into a buffer using the specified TagID, incrementing the buffer pointer
443  * and decrementing the available size, as appropriate.
444  *
445  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
446  * size is known at compile time.
447  */
448 //--------------------------------------------------------------------------------------------------
449 LE_DECLARE_INLINE bool le_pack_PackTaggedInt64
450 (
451  uint8_t** bufferPtr,
452  int64_t value,
453  TagID_t tagId
454 )
455 {
456  int64_t newValue = htobe64(value);
457  le_pack_PackTagID(bufferPtr, tagId);
458  LE_PACK_PACK_SIMPLE_VALUE(newValue);
459  return true;
460 }
461 #endif
462 
463 #ifdef LE_CONFIG_RPC
464 //--------------------------------------------------------------------------------------------------
465 /**
466  * Pack size_t and 32-bit integer tuple into a buffer using the specified TagID,
467  * incrementing the buffer pointer
468  * and decrementing the available size, as appropriate.
469  *
470  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
471  * size is known at compile time.
472  */
473 //--------------------------------------------------------------------------------------------------
474 LE_DECLARE_INLINE bool le_pack_PackTaggedUint32Tuple
475 (
476  uint8_t** bufferPtr,
477  size_t size,
478  uint32_t value,
479  TagID_t tagId
480 )
481 {
482  le_pack_PackTagID(bufferPtr, tagId);
483  if (size > UINT32_MAX)
484  {
485  return false;
486  }
487  uint32_t newSize = htobe32(size);
488  LE_PACK_PACK_SIMPLE_VALUE(newSize);
489 
490  uint32_t newValue = htobe32(value);
491  LE_PACK_PACK_SIMPLE_VALUE(newValue);
492  return true;
493 }
494 
495 
496 //--------------------------------------------------------------------------------------------------
497 /**
498  * Pack size_t and 64-bit integer tuple into a buffer using the specified TagID,
499  * incrementing the buffer pointer
500  * and decrementing the available size, as appropriate.
501  *
502  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
503  * size is known at compile time.
504  */
505 //--------------------------------------------------------------------------------------------------
506 LE_DECLARE_INLINE bool le_pack_PackTaggedUint64Tuple
507 (
508  uint8_t** bufferPtr,
509  size_t size,
510  uint64_t value,
511  TagID_t tagId
512 )
513 {
514  le_pack_PackTagID(bufferPtr, tagId);
515  if (size > UINT32_MAX)
516  {
517  return false;
518  }
519  uint32_t newSize = htobe32(size);
520  LE_PACK_PACK_SIMPLE_VALUE(newSize);
521 
522  uint64_t newValue = htobe64(value);
523  LE_PACK_PACK_SIMPLE_VALUE(newValue);
524  return true;
525 }
526 #endif
527 
528 //--------------------------------------------------------------------------------------------------
529 /**
530  * Pack a size_t into a buffer, incrementing the buffer pointer as appropriate.
531  *
532  * @note Packed sizes are limited to 2^32-1, regardless of platform
533  */
534 //--------------------------------------------------------------------------------------------------
535 LE_DECLARE_INLINE bool le_pack_PackSize
536 (
537  uint8_t **bufferPtr,
538  size_t value
539 )
540 {
541  if (value > UINT32_MAX)
542  {
543  return false;
544  }
545 
546 #ifdef LE_CONFIG_RPC
547  return le_pack_PackTaggedUint32(bufferPtr, value, LE_PACK_SIZE);
548 #else
549  return le_pack_PackUint32(bufferPtr, value);
550 #endif
551 }
552 
553 #ifdef LE_CONFIG_RPC
554 //--------------------------------------------------------------------------------------------------
555 /**
556  * Pack a size_t into a buffer using the specified TagID, incrementing the buffer pointer
557  * and decrementing the available size, as appropriate.
558  *
559  * @note Packed sizes are limited to 2^32-1, regardless of platform
560  */
561 //--------------------------------------------------------------------------------------------------
562 LE_DECLARE_INLINE bool le_pack_PackTaggedSize
563 (
564  uint8_t **bufferPtr,
565  size_t value,
566  TagID_t tagId
567 )
568 {
569  if (value > UINT32_MAX)
570  {
571  return false;
572  }
573 
574  return le_pack_PackTaggedUint32(bufferPtr, value, tagId);
575 }
576 #endif
577 
578 //--------------------------------------------------------------------------------------------------
579 /**
580  * Pack a bool into a buffer, incrementing the buffer pointer as appropriate.
581  */
582 //--------------------------------------------------------------------------------------------------
583 LE_DECLARE_INLINE bool le_pack_PackBool
584 (
585  uint8_t** bufferPtr,
586  bool value
587 )
588 {
589 #ifdef LE_CONFIG_RPC
590  le_pack_PackTagID(bufferPtr, LE_PACK_BOOL);
591 #endif
592 
593  // Force boolean to uint8_t 0 or 1 for packing, regarldess of underlying OS type.
594  // Underlying type has been int on some platforms in the past.
595  uint8_t simpleValue = ((value)?1:0);
596  LE_PACK_PACK_SIMPLE_VALUE(simpleValue);
597  return true;
598 }
599 
600 #ifdef LE_CONFIG_RPC
601 //--------------------------------------------------------------------------------------------------
602 /**
603  * Pack a bool into a buffer using the specified TagID, incrementing the buffer pointer
604  * and decrementing the available size, as appropriate.
605  *
606  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
607  * size is known at compile time.
608  */
609 //--------------------------------------------------------------------------------------------------
610 LE_DECLARE_INLINE bool le_pack_PackTaggedBool
611 (
612  uint8_t** bufferPtr,
613  bool value,
614  TagID_t tagId
615 )
616 {
617  le_pack_PackTagID(bufferPtr, tagId);
618 
619  // Force boolean to uint8_t 0 or 1 for packing, regarldess of underlying OS type.
620  // Underlying type has been int on some platforms in the past.
621  uint8_t simpleValue = ((value)?1:0);
622  LE_PACK_PACK_SIMPLE_VALUE(simpleValue);
623  return true;
624 }
625 #endif
626 
627 //--------------------------------------------------------------------------------------------------
628 /**
629  * Pack a char into a buffer, incrementing the buffer pointer as appropriate.
630  */
631 //--------------------------------------------------------------------------------------------------
632 LE_DECLARE_INLINE bool le_pack_PackChar
633 (
634  uint8_t** bufferPtr,
635  char value
636 )
637 {
638 #ifdef LE_CONFIG_RPC
639  le_pack_PackTagID(bufferPtr, LE_PACK_CHAR);
640 #endif
641  LE_PACK_PACK_SIMPLE_VALUE(value);
642  return true;
643 }
644 
645 #ifdef LE_CONFIG_RPC
646 //--------------------------------------------------------------------------------------------------
647 /**
648  * Pack a char into a buffer using the specified TagID, incrementing the buffer pointer
649  * and decrementing the available size, as appropriate.
650  *
651  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
652  * size is known at compile time.
653  */
654 //--------------------------------------------------------------------------------------------------
655 LE_DECLARE_INLINE bool le_pack_PackTaggedChar
656 (
657  uint8_t** bufferPtr,
658  char value,
659  TagID_t tagId
660 )
661 {
662  le_pack_PackTagID(bufferPtr, tagId);
663  LE_PACK_PACK_SIMPLE_VALUE(value);
664  return true;
665 }
666 #endif
667 
668 //--------------------------------------------------------------------------------------------------
669 /**
670  * Pack a double into a buffer, incrementing the buffer pointer as appropriate.
671  */
672 //--------------------------------------------------------------------------------------------------
673 LE_DECLARE_INLINE bool le_pack_PackDouble
674 (
675  uint8_t** bufferPtr,
676  double value
677 )
678 {
679 #ifdef LE_CONFIG_RPC
680  double newValue = htobe64(value);
681  le_pack_PackTagID(bufferPtr, LE_PACK_DOUBLE);
682  LE_PACK_PACK_SIMPLE_VALUE(newValue);
683 #else
684  LE_PACK_PACK_SIMPLE_VALUE(value);
685 #endif
686  return true;
687 }
688 
689 #ifdef LE_CONFIG_RPC
690 //--------------------------------------------------------------------------------------------------
691 /**
692  * Pack a double into a buffer using the specified TagID, incrementing the buffer pointer
693  * and decrementing the available size, as appropriate.
694  *
695  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
696  * size is known at compile time.
697  */
698 //--------------------------------------------------------------------------------------------------
699 LE_DECLARE_INLINE bool le_pack_PackTaggedDouble
700 (
701  uint8_t** bufferPtr,
702  double value,
703  TagID_t tagId
704 )
705 {
706  double newValue = htobe64(value);
707  le_pack_PackTagID(bufferPtr, tagId);
708  LE_PACK_PACK_SIMPLE_VALUE(newValue);
709  return true;
710 }
711 #endif
712 
713 //--------------------------------------------------------------------------------------------------
714 /**
715  * Pack a le_result_t into a buffer, incrementing the buffer pointer as appropriate.
716  */
717 //--------------------------------------------------------------------------------------------------
718 LE_DECLARE_INLINE bool le_pack_PackResult
719 (
720  uint8_t** bufferPtr,
721  le_result_t value
722 )
723 {
724 #ifdef LE_CONFIG_RPC
725  int32_t newValue = htobe32((int32_t) value);
726  le_pack_PackTagID(bufferPtr, LE_PACK_RESULT);
727  LE_PACK_PACK_SIMPLE_VALUE(newValue);
728 #else
729  LE_PACK_PACK_SIMPLE_VALUE(value);
730 #endif
731  return true;
732 }
733 
734 #ifdef LE_CONFIG_RPC
735 //--------------------------------------------------------------------------------------------------
736 /**
737  * Pack a le_result_t into a buffer using the specified TagID, incrementing the buffer pointer
738  * and decrementing the available size, as appropriate.
739  *
740  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
741  * size is known at compile time.
742  */
743 //--------------------------------------------------------------------------------------------------
744 LE_DECLARE_INLINE bool le_pack_PackTaggedResult
745 (
746  uint8_t** bufferPtr,
747  le_result_t value,
748  TagID_t tagId
749 )
750 {
751  int32_t newValue = htobe32((int32_t) value);
752  le_pack_PackTagID(bufferPtr, tagId);
753  LE_PACK_PACK_SIMPLE_VALUE(newValue);
754  return true;
755 }
756 #endif
757 
758 //--------------------------------------------------------------------------------------------------
759 /**
760  * Pack le_onoff_t into a buffer, incrementing the buffer pointer as appropriate.
761  */
762 //--------------------------------------------------------------------------------------------------
763 LE_DECLARE_INLINE bool le_pack_PackOnOff
764 (
765  uint8_t** bufferPtr,
766  le_onoff_t value
767 )
768 {
769 #ifdef LE_CONFIG_RPC
770  int32_t newValue = htobe32((int32_t) value);
771  le_pack_PackTagID(bufferPtr, LE_PACK_ONOFF);
772  LE_PACK_PACK_SIMPLE_VALUE(newValue);
773 #else
774  LE_PACK_PACK_SIMPLE_VALUE(value);
775 #endif
776  return true;
777 }
778 
779 #ifdef LE_CONFIG_RPC
780 //--------------------------------------------------------------------------------------------------
781 /**
782  * Pack le_onoff_t into a buffer using the specified TagID, incrementing the buffer pointer
783  * and decrementing the available size, as appropriate.
784  *
785  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
786  * size is known at compile time.
787  */
788 //--------------------------------------------------------------------------------------------------
789 LE_DECLARE_INLINE bool le_pack_PackTaggedOnOff
790 (
791  uint8_t** bufferPtr,
792  le_onoff_t value,
793  TagID_t tagId
794 )
795 {
796  int32_t newValue = htobe32((int32_t) value);
797  le_pack_PackTagID(bufferPtr, tagId);
798  LE_PACK_PACK_SIMPLE_VALUE(newValue);
799  return true;
800 }
801 #endif
802 
803 #undef LE_PACK_PACK_SIMPLE_VALUE
804 
805 //--------------------------------------------------------------------------------------------------
806 /**
807  * Pack a reference into a buffer, incrementing the buffer pointer.
808  */
809 //--------------------------------------------------------------------------------------------------
810 LE_DECLARE_INLINE bool le_pack_PackReference
811 (
812  uint8_t** bufferPtr,
813  const void* ref
814 )
815 {
816  size_t refAsInt = (size_t)ref;
817 
818  // All references passed through an API must be safe references (or NULL), so
819  // 0-bit will be set and reference will be <= UINT32_MAX. Size check
820  // is performed in pack function.
821  if ((refAsInt <= UINT32_MAX) &&
822  ((refAsInt & 0x01) ||
823  !refAsInt))
824  {
825 #ifdef LE_CONFIG_RPC
826  return le_pack_PackTaggedUint32(bufferPtr, (uint32_t)refAsInt, LE_PACK_REFERENCE);
827 #else
828  return le_pack_PackUint32(bufferPtr, (uint32_t)refAsInt);
829 #endif
830  }
831  else
832  {
833  return false;
834  }
835 }
836 
837 #ifdef LE_CONFIG_RPC
838 //--------------------------------------------------------------------------------------------------
839 /**
840  * Pack a reference into a buffer using the specified TagID, incrementing the buffer pointer
841  * and decrementing the available size.
842  */
843 //--------------------------------------------------------------------------------------------------
844 LE_DECLARE_INLINE bool le_pack_PackTaggedReference
845 (
846  uint8_t** bufferPtr,
847  const void* ref,
848  TagID_t tagId
849 )
850 {
851  size_t refAsInt = (size_t)ref;
852 
853  // All references passed through an API must be safe references (or NULL), so
854  // 0-bit will be set and reference will be <= UINT32_MAX. Size check
855  // is performed in pack function.
856  if ((refAsInt <= UINT32_MAX) &&
857  ((refAsInt & 0x01) ||
858  !refAsInt))
859  {
860  return le_pack_PackTaggedUint32(bufferPtr, (uint32_t)refAsInt, tagId);
861  }
862  else
863  {
864  return false;
865  }
866 }
867 #endif
868 
869 //--------------------------------------------------------------------------------------------------
870 /**
871  * Pack a string into a buffer, incrementing the buffer pointer.
872  *
873  * @note Will assert if provided string is larger than maximum allowable string.
874  */
875 //--------------------------------------------------------------------------------------------------
876 LE_DECLARE_INLINE bool le_pack_PackString
877 (
878  uint8_t** bufferPtr,
879  const char *stringPtr,
880  uint32_t maxStringCount
881 )
882 {
883  size_t bytesCopied;
884 
885  if (!stringPtr)
886  {
887  return false;
888  }
889 
890 #if defined(__KLOCWORK__)
891  // Just like strncpy & strnlen, this function doesn't know the size of the source string,
892  // which can potentially result in a read overflow on the input buffer.
893  // Static code analyzer can report this issue, which is deliberatly ignored since this
894  // function expects NULL-terminated strings.
895  maxStringCount = strnlen(stringPtr, maxStringCount);
896 #endif
897 
898  // First copy in the string -- up to maxStringCount bytes, allowing enough
899  // space at the begining for a uint32 + TagID_t.
900  for (bytesCopied = 0;
901  (bytesCopied < maxStringCount) && (stringPtr[bytesCopied] != '\0');
902  ++bytesCopied)
903  {
904 #ifdef LE_CONFIG_RPC
905  (*bufferPtr)[bytesCopied + sizeof(uint32_t) + sizeof(TagID_t)] = stringPtr[bytesCopied];
906 #else
907  (*bufferPtr)[bytesCopied + sizeof(uint32_t)] = stringPtr[bytesCopied];
908 #endif
909  }
910 
911  // String was too long to fit in the buffer -- return false.
912  if (stringPtr[bytesCopied] != '\0')
913  {
914  return false;
915  }
916 
917  // Then go back and copy string size. No loss of precision packing into a uint32
918  // because maxStringCount is a uint32 or less.
919 #ifdef LE_CONFIG_RPC
920  bool packResult = le_pack_PackTaggedUint32(bufferPtr, bytesCopied, LE_PACK_STRING);
921 #else
922  bool packResult = le_pack_PackUint32(bufferPtr, bytesCopied);
923 #endif
924  LE_ASSERT(packResult); // Should not fail -- have checked there's enough space above.
925 
926  // Now increment buffer by size of string actually copied, and decrement available
927  // space by max which could have been copied. This ensures out of space errors will
928  // be caught as soon as possible.
929  *bufferPtr = *bufferPtr + bytesCopied;
930 
931  return true;
932 }
933 
934 #ifdef LE_CONFIG_RPC
935 //--------------------------------------------------------------------------------------------------
936 /**
937  * Pack a string into a buffer using the specified TagID, incrementing the buffer pointer
938  * and decrementing the available size.
939  *
940  * @note Always decrements available size according to the max possible size used, not actual size
941  * used. Will assert if provided string is larger than maximum allowable string.
942  */
943 //--------------------------------------------------------------------------------------------------
944 LE_DECLARE_INLINE bool le_pack_PackTaggedString
945 (
946  uint8_t** bufferPtr,
947  const char *stringPtr,
948  uint32_t maxStringCount,
949  TagID_t tagId
950 )
951 {
952  size_t bytesCopied;
953 
954  if (!stringPtr)
955  {
956  return false;
957  }
958 
959 #if defined(__KLOCWORK__)
960  // Just like strncpy & strnlen, this function doesn't know the size of the source string,
961  // which can potentially result in a read overflow on the input buffer.
962  // Static code analyzer can report this issue, which is deliberatly ignored since this
963  // function expects NULL-terminated strings.
964  maxStringCount = strnlen(stringPtr, maxStringCount);
965 #endif
966 
967  // First copy in the string -- up to maxStringCount bytes, allowing enough
968  // space at the begining for a uint32 + TagID_t.
969  for (bytesCopied = 0;
970  (bytesCopied < maxStringCount) && (stringPtr[bytesCopied] != '\0');
971  ++bytesCopied)
972  {
973  (*bufferPtr)[bytesCopied + sizeof(uint32_t) + sizeof(TagID_t)] = stringPtr[bytesCopied];
974  }
975 
976  // String was too long to fit in the buffer -- return false.
977  if (stringPtr[bytesCopied] != '\0')
978  {
979  return false;
980  }
981 
982  // Then go back and copy string size. No loss of precision packing into a uint32
983  // because maxStringCount is a uint32 or less.
984  bool packResult = le_pack_PackTaggedUint32(bufferPtr, bytesCopied, tagId);
985  LE_ASSERT(packResult); // Should not fail -- have checked there's enough space above.
986 
987  // Now increment buffer by size of string actually copied, and decrement available
988  // space by max which could have been copied. This ensures out of space errors will
989  // be caught as soon as possible.
990  *bufferPtr = *bufferPtr + bytesCopied;
991 
992  return true;
993 }
994 #endif
995 
996 //--------------------------------------------------------------------------------------------------
997 /**
998  * Pack the size information for an array into a buffer, incrementing the buffer pointer.
999  *
1000  * @note Users of this API should generally use LE_PACK_PACKARRAY macro instead which also
1001  * packs the array data.
1002  */
1003 //--------------------------------------------------------------------------------------------------
1004 LE_DECLARE_INLINE bool le_pack_PackArrayHeader
1005 (
1006  uint8_t **bufferPtr,
1007  const void *arrayPtr,
1008  size_t elementSize,
1009  size_t arrayCount,
1010  size_t arrayMaxCount
1011 )
1012 {
1013  if (arrayCount > arrayMaxCount)
1014  {
1015  return false;
1016  }
1017 
1018 #ifdef LE_CONFIG_RPC
1019  LE_ASSERT(le_pack_PackTaggedSize(bufferPtr, arrayCount, LE_PACK_ARRAYHEADER));
1020 #else
1021  LE_ASSERT(le_pack_PackSize(bufferPtr, arrayCount));
1022 #endif
1023  return true;
1024 }
1025 
1026 #ifdef LE_CONFIG_RPC
1027 //--------------------------------------------------------------------------------------------------
1028 /**
1029  * Pack the size information for an array into a buffer using the specified TagID,
1030  * incrementing the buffer pointer and decrementing the available size.
1031  *
1032  * @note Users of this API should generally use LE_PACK_PACKARRAY macro instead which also
1033  * packs the array data.
1034  */
1035 //--------------------------------------------------------------------------------------------------
1036 LE_DECLARE_INLINE bool le_pack_PackTaggedArrayHeader
1037 (
1038  uint8_t **bufferPtr,
1039  const void *arrayPtr,
1040  size_t elementSize,
1041  size_t arrayCount,
1042  size_t arrayMaxCount,
1043  TagID_t tagId
1044 )
1045 {
1046  if (arrayCount > arrayMaxCount)
1047  {
1048  return false;
1049  }
1050 
1051  LE_ASSERT(le_pack_PackTaggedSize(bufferPtr, arrayCount, tagId));
1052  return true;
1053 }
1054 #endif
1055 
1056 //--------------------------------------------------------------------------------------------------
1057 /**
1058  * Pack an array into a buffer, incrementing the buffer pointer.
1059  *
1060  * @note Will assert if the resulted array exceeds the maximum size allowed.
1061  */
1062 //--------------------------------------------------------------------------------------------------
1063 #define LE_PACK_PACKARRAY(bufferPtr, \
1064  arrayPtr, \
1065  arrayCount, \
1066  arrayMaxCount, \
1067  packFunc, \
1068  resultPtr) \
1069  do { \
1070  *(resultPtr) = le_pack_PackArrayHeader((bufferPtr), \
1071  (arrayPtr), sizeof((arrayPtr)[0]), \
1072  (arrayCount), (arrayMaxCount)); \
1073  if (*(resultPtr)) \
1074  { \
1075  uint32_t i; \
1076  for (i = 0; i < (arrayCount); ++i) \
1077  { \
1078  LE_ASSERT(packFunc((bufferPtr), (arrayPtr)[i])); \
1079  } \
1080  *(resultPtr) = true; \
1081  } \
1082  } while (0)
1083 
1084 //--------------------------------------------------------------------------------------------------
1085 /**
1086  * Pack an array of struct into a buffer, incrementing the buffer pointer.
1087  *
1088  * @note Will assert if the resulted array of struct exceeds the maximum size allowed.
1089  */
1090 //--------------------------------------------------------------------------------------------------
1091 #define LE_PACK_PACKSTRUCTARRAY(bufferPtr, \
1092  arrayPtr, \
1093  arrayCount, \
1094  arrayMaxCount, \
1095  packFunc, \
1096  resultPtr) \
1097  do { \
1098  *(resultPtr) = le_pack_PackArrayHeader((bufferPtr), \
1099  (arrayPtr), sizeof((arrayPtr)[0]), \
1100  (arrayCount), (arrayMaxCount)); \
1101  if (*(resultPtr)) \
1102  { \
1103  uint32_t i; \
1104  for (i = 0; i < (arrayCount); ++i) \
1105  { \
1106  LE_ASSERT(packFunc((bufferPtr), &((arrayPtr)[i]))); \
1107  } \
1108  *(resultPtr) = true; \
1109  } \
1110  } while (0)
1111 
1112 //--------------------------------------------------------------------------------------------------
1113 // Unpack functions
1114 //--------------------------------------------------------------------------------------------------
1115 
1116 #define LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr) \
1117  do { \
1118  memcpy((valuePtr), *bufferPtr, sizeof(*(valuePtr))); \
1119  *bufferPtr = (*bufferPtr) + sizeof(*(valuePtr)); \
1120  } while (0)
1121 
1122 
1123 
1124 #ifdef LE_CONFIG_RPC
1125 //--------------------------------------------------------------------------------------------------
1126 /**
1127  * Unpack a TagID from a buffer, incrementing the buffer pointer and decrementing the
1128  * available size, as appropriate.
1129  *
1130  * @note By making this an inline function, gcc can often optimize out the size check if the buffer
1131  * size is known at compile time.
1132  */
1133 //--------------------------------------------------------------------------------------------------
1134 LE_DECLARE_INLINE bool le_pack_UnpackTagID
1135 (
1136  uint8_t** bufferPtr,
1137  TagID_t* tagIdPtr
1138 )
1139 {
1140  LE_PACK_UNPACK_SIMPLE_VALUE(tagIdPtr);
1141  return true;
1142 }
1143 #endif
1144 
1145 //--------------------------------------------------------------------------------------------------
1146 /**
1147  * Unpack a uint8_t from a buffer, incrementing the buffer pointer as appropriate.
1148  */
1149 //--------------------------------------------------------------------------------------------------
1150 LE_DECLARE_INLINE bool le_pack_UnpackUint8
1151 (
1152  uint8_t** bufferPtr,
1153  uint8_t* valuePtr
1154 )
1155 {
1156 #ifdef LE_CONFIG_RPC
1157  TagID_t tag;
1158  le_pack_UnpackTagID(bufferPtr, &tag);
1159 #endif
1160  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1161  return true;
1162 }
1163 
1164 //--------------------------------------------------------------------------------------------------
1165 /**
1166  * Unpack a uint16_t from a buffer, incrementing the buffer pointer as appropriate.
1167  */
1168 //--------------------------------------------------------------------------------------------------
1169 LE_DECLARE_INLINE bool le_pack_UnpackUint16
1170 (
1171  uint8_t** bufferPtr,
1172  uint16_t* valuePtr
1173 )
1174 {
1175 #ifdef LE_CONFIG_RPC
1176  TagID_t tag;
1177  le_pack_UnpackTagID(bufferPtr, &tag);
1178  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1179  *valuePtr = be16toh(*valuePtr);
1180 #else
1181  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1182 #endif
1183  return true;
1184 }
1185 
1186 //--------------------------------------------------------------------------------------------------
1187 /**
1188  * Unpack a uint32_t from a buffer, incrementing the buffer pointer as appropriate.
1189  */
1190 //--------------------------------------------------------------------------------------------------
1191 LE_DECLARE_INLINE bool le_pack_UnpackUint32
1192 (
1193  uint8_t** bufferPtr,
1194  uint32_t* valuePtr
1195 )
1196 {
1197 #ifdef LE_CONFIG_RPC
1198  TagID_t tag;
1199  le_pack_UnpackTagID(bufferPtr, &tag);
1200  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1201  *valuePtr = be32toh(*valuePtr);
1202 #else
1203  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1204 #endif
1205  return true;
1206 }
1207 
1208 //--------------------------------------------------------------------------------------------------
1209 /**
1210  * Unpack a uint64_t from a buffer, incrementing the buffer pointer as appropriate.
1211  */
1212 //--------------------------------------------------------------------------------------------------
1213 LE_DECLARE_INLINE bool le_pack_UnpackUint64
1214 (
1215  uint8_t** bufferPtr,
1216  uint64_t* valuePtr
1217 )
1218 {
1219 #ifdef LE_CONFIG_RPC
1220  TagID_t tag;
1221  le_pack_UnpackTagID(bufferPtr, &tag);
1222  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1223  *valuePtr = be64toh(*valuePtr);
1224 #else
1225  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1226 #endif
1227  return true;
1228 }
1229 
1230 //--------------------------------------------------------------------------------------------------
1231 /**
1232  * Unpack a int8_t from a buffer, incrementing the buffer pointer as appropriate.
1233  */
1234 //--------------------------------------------------------------------------------------------------
1235 LE_DECLARE_INLINE bool le_pack_UnpackInt8
1236 (
1237  uint8_t** bufferPtr,
1238  int8_t* valuePtr
1239 )
1240 {
1241 #ifdef LE_CONFIG_RPC
1242  TagID_t tag;
1243  le_pack_UnpackTagID(bufferPtr, &tag);
1244 #endif
1245  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1246  return true;
1247 }
1248 
1249 //--------------------------------------------------------------------------------------------------
1250 /**
1251  * Unpack a int16_t from a buffer, incrementing the buffer pointer as appropriate.
1252  */
1253 //--------------------------------------------------------------------------------------------------
1254 LE_DECLARE_INLINE bool le_pack_UnpackInt16
1255 (
1256  uint8_t** bufferPtr,
1257  int16_t* valuePtr
1258 )
1259 {
1260 #ifdef LE_CONFIG_RPC
1261  TagID_t tag;
1262  le_pack_UnpackTagID(bufferPtr, &tag);
1263  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1264  *valuePtr = be16toh(*valuePtr);
1265 #else
1266  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1267 #endif
1268  return true;
1269 }
1270 
1271 //--------------------------------------------------------------------------------------------------
1272 /**
1273  * Unpack a int32_t from a buffer, incrementing the buffer pointer as appropriate.
1274  */
1275 //--------------------------------------------------------------------------------------------------
1276 LE_DECLARE_INLINE bool le_pack_UnpackInt32
1277 (
1278  uint8_t** bufferPtr,
1279  int32_t* valuePtr
1280 )
1281 {
1282 #ifdef LE_CONFIG_RPC
1283  TagID_t tag;
1284  le_pack_UnpackTagID(bufferPtr, &tag);
1285  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1286  *valuePtr = be32toh(*valuePtr);
1287 #else
1288  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1289 #endif
1290  return true;
1291 }
1292 
1293 //--------------------------------------------------------------------------------------------------
1294 /**
1295  * Unpack a int64_t from a buffer, incrementing the buffer pointer as appropriate.
1296  */
1297 //--------------------------------------------------------------------------------------------------
1298 LE_DECLARE_INLINE bool le_pack_UnpackInt64
1299 (
1300  uint8_t** bufferPtr,
1301  int64_t* valuePtr
1302 )
1303 {
1304 #ifdef LE_CONFIG_RPC
1305  TagID_t tag;
1306  le_pack_UnpackTagID(bufferPtr, &tag);
1307  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1308  *valuePtr = be64toh(*valuePtr);
1309 #else
1310  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1311 #endif
1312  return true;
1313 }
1314 
1315 #ifdef LE_CONFIG_RPC
1316 //--------------------------------------------------------------------------------------------------
1317 /**
1318  * Unpack a size_t and 32-bit integer tuple from the buffer,
1319  * incrementing the buffer pointer as appropriate.
1320  */
1321 //--------------------------------------------------------------------------------------------------
1322 LE_DECLARE_INLINE bool le_pack_UnpackUint32Tuple
1323 (
1324  uint8_t** bufferPtr,
1325  size_t* sizePtr,
1326  uint32_t* valuePtr
1327 )
1328 {
1329  uint32_t rawSize;
1330  TagID_t tag;
1331 
1332  le_pack_UnpackTagID(bufferPtr, &tag);
1333  LE_PACK_UNPACK_SIMPLE_VALUE(&rawSize);
1334  *sizePtr = be32toh(rawSize);
1335 
1336  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1337  *valuePtr = be32toh(*valuePtr);
1338  return true;
1339 }
1340 
1341 
1342 //--------------------------------------------------------------------------------------------------
1343 /**
1344  * Unpack a size_t and 64-bit integer tuple from the buffer,
1345  * incrementing the buffer pointer as appropriate.
1346  */
1347 //--------------------------------------------------------------------------------------------------
1348 LE_DECLARE_INLINE bool le_pack_UnpackUint64Tuple
1349 (
1350  uint8_t** bufferPtr,
1351  size_t* sizePtr,
1352  uint64_t* valuePtr
1353 )
1354 {
1355  uint32_t rawSize;
1356  TagID_t tag;
1357 
1358  le_pack_UnpackTagID(bufferPtr, &tag);
1359  LE_PACK_UNPACK_SIMPLE_VALUE(&rawSize);
1360  *sizePtr = be32toh(rawSize);
1361 
1362  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1363  *valuePtr = be64toh(*valuePtr);
1364  return true;
1365 }
1366 #endif
1367 
1368 
1369 //--------------------------------------------------------------------------------------------------
1370 /**
1371  * Pack a size_t into a buffer, incrementing the buffer pointer as appropriate.
1372  *
1373  * @note Packed sizes are limited to 2^32-1, regardless of platform
1374  */
1375 //--------------------------------------------------------------------------------------------------
1376 LE_DECLARE_INLINE bool le_pack_UnpackSize
1377 (
1378  uint8_t **bufferPtr,
1379  size_t *valuePtr
1380 )
1381 {
1382  uint32_t rawValue;
1383 
1384  if (!le_pack_UnpackUint32(bufferPtr, &rawValue))
1385  {
1386  return false;
1387  }
1388 
1389  *valuePtr = rawValue;
1390 
1391  return true;
1392 }
1393 
1394 //--------------------------------------------------------------------------------------------------
1395 /**
1396  * Unpack a bool from a buffer, incrementing the buffer pointer as appropriate.
1397  */
1398 //--------------------------------------------------------------------------------------------------
1399 LE_DECLARE_INLINE bool le_pack_UnpackBool
1400 (
1401  uint8_t** bufferPtr,
1402  bool* valuePtr
1403 )
1404 {
1405  // Treat boolean as uint8_t for packing, regardless of underlying OS type.
1406  // Underlying type has been int on some platforms in the past.
1407  uint8_t simpleValue;
1408 
1409 #ifdef LE_CONFIG_RPC
1410  TagID_t tag;
1411  le_pack_UnpackTagID(bufferPtr, &tag);
1412 #endif
1413  memcpy(&simpleValue, *bufferPtr, sizeof(simpleValue));
1414 
1415  *bufferPtr = ((uint8_t* )*bufferPtr) + sizeof(simpleValue);
1416 
1417  // force to true or false
1418  *valuePtr = !!simpleValue;
1419 
1420  return true;
1421 }
1422 
1423 //--------------------------------------------------------------------------------------------------
1424 /**
1425  * Unpack a char from a buffer, incrementing the buffer pointer as appropriate.
1426  */
1427 //--------------------------------------------------------------------------------------------------
1428 LE_DECLARE_INLINE bool le_pack_UnpackChar
1429 (
1430  uint8_t** bufferPtr,
1431  char* valuePtr
1432 )
1433 {
1434 #ifdef LE_CONFIG_RPC
1435  TagID_t tag;
1436  le_pack_UnpackTagID(bufferPtr, &tag);
1437 #endif
1438  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1439  return true;
1440 }
1441 
1442 //--------------------------------------------------------------------------------------------------
1443 /**
1444  * Unpack a double from a buffer, incrementing the buffer pointer as appropriate.
1445  */
1446 //--------------------------------------------------------------------------------------------------
1447 LE_DECLARE_INLINE bool le_pack_UnpackDouble
1448 (
1449  uint8_t** bufferPtr,
1450  double* valuePtr
1451 )
1452 {
1453 #ifdef LE_CONFIG_RPC
1454  TagID_t tag;
1455  le_pack_UnpackTagID(bufferPtr, &tag);
1456  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1457  *valuePtr = be64toh(*valuePtr);
1458 #else
1459  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1460 #endif
1461  return true;
1462 }
1463 
1464 //--------------------------------------------------------------------------------------------------
1465 /**
1466  * Unpack a le_result_t from a buffer, incrementing the buffer pointer as appropriate.
1467  */
1468 //--------------------------------------------------------------------------------------------------
1469 LE_DECLARE_INLINE bool le_pack_UnpackResult
1470 (
1471  uint8_t** bufferPtr,
1472  le_result_t* valuePtr
1473 )
1474 {
1475 #ifdef LE_CONFIG_RPC
1476  int32_t value;
1477  TagID_t tag;
1478  le_pack_UnpackTagID(bufferPtr, &tag);
1479  LE_PACK_UNPACK_SIMPLE_VALUE(&value);
1480  *valuePtr = (le_result_t) be32toh(value);
1481 #else
1482  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1483 #endif
1484  return true;
1485 }
1486 
1487 //--------------------------------------------------------------------------------------------------
1488 /**
1489  * Pack le_onoff_t into a buffer, incrementing the buffer pointer as appropriate.
1490  */
1491 //--------------------------------------------------------------------------------------------------
1492 LE_DECLARE_INLINE bool le_pack_UnpackOnOff
1493 (
1494  uint8_t** bufferPtr,
1495  le_onoff_t* valuePtr
1496 )
1497 {
1498 #ifdef LE_CONFIG_RPC
1499  int32_t value;
1500  TagID_t tag;
1501  le_pack_UnpackTagID(bufferPtr, &tag);
1502  LE_PACK_UNPACK_SIMPLE_VALUE(&value);
1503  *valuePtr = (le_onoff_t) be32toh(value);
1504 #else
1505  LE_PACK_UNPACK_SIMPLE_VALUE(valuePtr);
1506 #endif
1507  return true;
1508 }
1509 
1510 #undef LE_PACK_UNPACK_SIMPLE_VALUE
1511 
1512 //--------------------------------------------------------------------------------------------------
1513 /**
1514  * Unpack a reference from a buffer, incrementing the buffer pointer.
1515  */
1516 //--------------------------------------------------------------------------------------------------
1517 LE_DECLARE_INLINE bool le_pack_UnpackReference
1518 (
1519  uint8_t** bufferPtr,
1520  void* refPtr ///< Pointer to the reference. Declared as void * to allow implicit
1521  ///< conversion from pointer to reference types.
1522 )
1523 {
1524  uint32_t refAsInt;
1525 
1526  if (!le_pack_UnpackUint32(bufferPtr, &refAsInt))
1527  {
1528  return false;
1529  }
1530 
1531  // All references passed through an API must be safe references, so
1532  // 0-bit will be set. Check that here to be safe.
1533  if ((refAsInt & 0x01) ||
1534  (!refAsInt))
1535  {
1536  // Double cast to avoid warnings.
1537  *(void **)refPtr = (void *)(size_t)refAsInt;
1538  return true;
1539  }
1540  else
1541  {
1542  return false;
1543  }
1544 }
1545 
1546 //--------------------------------------------------------------------------------------------------
1547 /**
1548  * Unpack a string from a buffer, incrementing the buffer pointer.
1549  */
1550 //--------------------------------------------------------------------------------------------------
1551 LE_DECLARE_INLINE bool le_pack_UnpackString
1552 (
1553  uint8_t** bufferPtr,
1554  char *stringPtr,
1555  uint32_t bufferSize,
1556  uint32_t maxStringCount
1557 )
1558 {
1559  uint32_t stringSize;
1560 
1561  // First get string size
1562  if (!le_pack_UnpackUint32(bufferPtr, &stringSize))
1563  {
1564  return false;
1565  }
1566 
1567  if ((stringSize > maxStringCount) ||
1568  (stringSize > bufferSize))
1569  {
1570  return false;
1571  }
1572 
1573  if (!stringPtr)
1574  {
1575  // Only allow unpacking into no output buffer if the string is zero sized.
1576  // Otherwise an output buffer is required.
1577  if (stringSize)
1578  {
1579  return false;
1580  }
1581  else
1582  {
1583  return true;
1584  }
1585  }
1586 
1587  memcpy(stringPtr, *bufferPtr, stringSize);
1588  stringPtr[stringSize] = '\0';
1589 
1590  *bufferPtr = *bufferPtr + stringSize;
1591 
1592  return true;
1593 }
1594 
1595 //--------------------------------------------------------------------------------------------------
1596 /**
1597  * Pack the size information for an array into a buffer, incrementing the buffer pointer.
1598  *
1599  * @note Users of this API should generally use LE_PACK_PACKARRAY macro instead which also
1600  * packs the array data.
1601  */
1602 //--------------------------------------------------------------------------------------------------
1603 LE_DECLARE_INLINE bool le_pack_UnpackArrayHeader
1604 (
1605  uint8_t **bufferPtr,
1606  const void *arrayPtr,
1607  size_t elementSize,
1608  size_t *arrayCountPtr,
1609  size_t arrayMaxCount
1610 )
1611 {
1612  LE_ASSERT(le_pack_UnpackSize(bufferPtr, arrayCountPtr));
1613  if (*arrayCountPtr > arrayMaxCount)
1614  {
1615  return false;
1616  }
1617  else if (!arrayPtr)
1618  {
1619  // Missing array pointer must match zero sized array.
1620  return (*arrayCountPtr == 0);
1621  }
1622 
1623  return true;
1624 }
1625 
1626 //--------------------------------------------------------------------------------------------------
1627 /**
1628  * Unpack an array into from buffer, incrementing the buffer pointer and decrementing the available
1629  * size.
1630  *
1631  * @note Always decrements available size according to the max possible size used, not actual size
1632  * used. Will assert if the resulted array exceeds the maximum size allowed.
1633  */
1634 //--------------------------------------------------------------------------------------------------
1635 #define LE_PACK_UNPACKARRAY(bufferPtr, \
1636  arrayPtr, \
1637  arrayCountPtr, \
1638  arrayMaxCount, \
1639  unpackFunc, \
1640  resultPtr) \
1641  do { \
1642  if (!le_pack_UnpackArrayHeader((bufferPtr), \
1643  (arrayPtr), sizeof((arrayPtr)[0]), \
1644  (arrayCountPtr), (arrayMaxCount))) \
1645  { \
1646  *(resultPtr) = false; \
1647  } \
1648  else \
1649  { \
1650  uint32_t i; \
1651  for (i = 0; i < *(arrayCountPtr); ++i) \
1652  { \
1653  LE_ASSERT(unpackFunc((bufferPtr), &(arrayPtr)[i])); \
1654  } \
1655  *(resultPtr) = true; \
1656  } \
1657  } while (0)
1658 
1659 
1660 //--------------------------------------------------------------------------------------------------
1661 /**
1662  * Unpack an array of struct from buffer. Since its logic is the same as that for unpacking an
1663  * array, here it calls LE_PACK_UNPACKSTRUCTARRAY() to do the work.
1664  */
1665 //--------------------------------------------------------------------------------------------------
1666 #define LE_PACK_UNPACKSTRUCTARRAY(bufferPtr, \
1667  arrayPtr, \
1668  arrayCountPtr, \
1669  arrayMaxCount, \
1670  unpackFunc, \
1671  resultPtr) \
1672  LE_PACK_UNPACKARRAY((bufferPtr), (arrayPtr), (arrayCountPtr), \
1673  (arrayMaxCount), (unpackFunc), (resultPtr))
1674 
1675 #endif /* LE_PACK_H_INCLUDE_GUARD */
le_result_t
Definition: le_basics.h:35
#define LE_ASSERT(condition)
Definition: le_log.h:878
#define LE_DECLARE_INLINE
Definition: le_basics.h:274
le_onoff_t
Definition: le_basics.h:71