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