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