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