netmsgs  1.2.2
RoadNarrows Robotics Network Messaging Package
nmLibPack.c
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: netmsgs
4 //
5 // Library: libnetmsgs
6 //
7 // File: nmLibPack.c
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2011-11-18 13:32:30 -0700 (Fri, 18 Nov 2011) $
12  * $Rev: 1578 $
13  *
14  * \brief Field value packing/unpacking definitions.
15  *
16  * The host may be either a big-endian or little-endian architecture. Currenly,
17  * any exotic architectures are not supported. It is assumed that 1, 2, and 4
18  * byte (unsigned) integers and 4 byte floats are supported. For systems that
19  * do not support 8 byte (unsigned) integers or 8 byte doubles, promotion
20  * will be done in software. However, on unpacking, rounding or truncation will
21  * occur if the unpacked element exceeds the 4 byte limits.
22  *
23  * Floats are expected to be in IEEE 754 format.
24  *
25  * \author Robin Knight (robin.knight@roadnarrows.com)
26  *
27  * \copyright
28  * \h_copy 2009-2017. RoadNarrows LLC.\n
29  * http://www.roadnarrows.com\n
30  * All Rights Reserved
31  */
32 // Permission is hereby granted, without written agreement and without
33 // license or royalty fees, to use, copy, modify, and distribute this
34 // software and its documentation for any purpose, provided that
35 // (1) The above copyright notice and the following two paragraphs
36 // appear in all copies of the source code and (2) redistributions
37 // including binaries reproduces these notices in the supporting
38 // documentation. Substantial modifications to this software may be
39 // copyrighted by their authors and need not follow the licensing terms
40 // described here, provided that the new terms are clearly indicated in
41 // all files where they apply.
42 //
43 // IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY MEMBERS/EMPLOYEES
44 // OF ROADNARROW LLC OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
45 // PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
46 // DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
47 // EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
48 // THE POSSIBILITY OF SUCH DAMAGE.
49 //
50 // THE AUTHOR AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
51 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
52 // FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
53 // "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
54 // PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
55 //
56 ////////////////////////////////////////////////////////////////////////////////
57 
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <limits.h>
61 #include <libgen.h>
62 #include <string.h>
63 #include <ctype.h>
64 #include <endian.h>
65 
66 #ifdef ARCH_cygwin
67 #include "cyg-ieee754.h"
68 #else
69 #include <ieee754.h>
70 #endif
71 
72 #include "rnr/rnrconfig.h"
73 #include "rnr/log.h"
74 
75 #include "rnr/netmsgs.h"
76 
77 #include "nmLibInternal.h"
78 
79 
80 // ---------------------------------------------------------------------------
81 // Private Interface
82 // ---------------------------------------------------------------------------
83 
84 //
85 // Host Architecture Prerequisites.
86 //
87 // Adjust the checks out as more architectures are supported.
88 //
89 // For example, if an embedded MCU only supports 16-bit integers, then the U32
90 // and S32 packing and unpacking routines, amoung others, must change to
91 // pack/unpack 2 16-bit integers.
92 //
93 #if UCHAR_MAX != 0xff
94 #error "The netmsgs package requires 8-bit bytes."
95 #endif
96 
97 #if USHRT_MAX != 0xffff
98 #error "The netmsgs package requires 16-bit shorts."
99 #endif
100 
101 #if UINT_MAX != 0xffffffff
102 #error "The netmsgs package requires 32-bit integers."
103 #endif
104 
105 //
106 // This Host Byte Order
107 //
108 #if __BYTE_ORDER == __BIG_ENDIAN
109 #define HOST_BIG_ENDIAN ///< big-endian byte order
110 #else
111 #define HOST_LITTLE_ENDIAN ///< little-endian byte order
112 #endif
113 
114 #if __WORDSIZE == 64
115 #define HOST_WORD_SIZE 64 ///< 64-bit architecture
116 #else
117 #define HOST_WORD_SIZE 32 ///< 32-bit architecture
118 #endif
119 
120 
121 //.............................................................................
122 // Big-Endian Host Core Packing and Unpacking Operations
123 //.............................................................................
124 #ifdef HOST_BIG_ENDIAN
125 
126 /*!
127  * \brief Pack an element into the message buffer in big-endian byte order.
128  *
129  * Big-Endian Host Version
130  *
131  * \param [in] p Byte pointer to typecasted element to be packed.
132  * \param size Byte size of element to pack.
133  * \param [out] buf Output message buffer.
134  */
135 static inline void packbig(byte_t *p, size_t size, byte_t buf[])
136 {
137  size_t n = 0;
138 
139  // forward copy
140  while( n < size )
141  {
142  buf[n++] = *p++;
143  }
144 }
145 
146 /*!
147  * \brief Unpack an element from the message buffer in big-endian byte order.
148  *
149  * Big-Endian Host Version
150  *
151  * \param [in] buf Output message buffer.
152  * \param [out] p Byte pointer to typecasted element to be unpacked (set).
153  * \param size Byte size of element to unpack.
154  */
155 static inline void unpackbig(byte_t buf[], byte_t *p, size_t size)
156 {
157  size_t n = 0;
158 
159  // forward copy
160  while( n < size )
161  {
162  *p++ = buf[n++];
163  }
164 }
165 
166 /*!
167  * \brief Pack an element into the message buffer in little-endian byte order.
168  *
169  * Big-Endian Host Version
170  *
171  * \param [in] p Byte pointer to typecasted element to be packed.
172  * \param size Byte size of element to pack.
173  * \param [out] buf Output message buffer.
174  */
175 static inline void packlittle(byte_t *p, size_t size, byte_t buf[])
176 {
177  size_t n = 0;
178  size_t k = size - 1;
179 
180  // reverse copy
181  while( n < size )
182  {
183  buf[n++] = p[k--];
184  }
185 }
186 
187 /*!
188  * \brief Unpack an element from the message buffer in little-endian byte order.
189  *
190  * Big-Endian Host Version
191  *
192  * \param [in] buf Output message buffer.
193  * \param [out] p Byte pointer to typecasted element to be unpacked (set).
194  * \param size Byte size of element to unpack.
195  */
196 static inline void unpacklittle(byte_t buf[], byte_t *p, size_t size)
197 {
198  size_t n = 0;
199  size_t k = size - 1;
200 
201  // reverse copy
202  while( n < size )
203  {
204  p[k--] = buf[n++];
205  }
206 }
207 
208 /*!
209  * \brief Pack an element into the message buffer in native byte order.
210  *
211  * Big-Endian Host Version
212  *
213  * \param [in] val Type T element to be packed.
214  * \param [out] buf Output message buffer.
215  */
216 #define PACKNATIVE(val, buf) packbig((byte_t *)&(val), sizeof(val), buf)
217 
218 /*!
219  * \brief Unpack an element from the message buffer in native byte order.
220  *
221  * Big-Endian Host Version
222  *
223  * \param [in] buf Output message buffer.
224  * \param [out] pval Type T* element to be unpacked (set).
225  */
226 #define UNPACKNATIVE(buf, pval) unpackbig(buf, (byte_t *)pval, sizeof(*pval))
227 
228 /*!
229  * \brief Pack two 4-btye unsigned integers into the message buffer in native
230  * byte order.
231  *
232  * Big-Endian Host Version
233  *
234  * \param [in] uMSB Most Significant Bytes.
235  * \param [in] uLSB Least Significant Bytes.
236  * \param [out] buf Output message buffer.
237  */
238 #define PACK64NATIVE(uMSB, uLSB, buf) PACK64BIG(uMSB, uLSB, buf)
239 
240 /*!
241  * \brief Unpack two 4-byte unsigned integers from the message buffer in native
242  * byte order.
243  *
244  * Big-Endian Host Version
245  *
246  * \param [in] buf Output message buffer.
247  * \param [out] puMSB Most Significant Bytes.
248  * \param [out] puLSB Least Significant Bytes.
249  */
250 #define UNPACK64NATIVE(buf, puMSB, puLSB) UNPACK64BIG(buf, puMSB, puLSB)
251 
252 
253 //.............................................................................
254 // Little-Endian Host Core Packing and Unpacking Operations
255 //.............................................................................
256 #else // HOST_LITTLE_ENDIAN
257 
258 /*!
259  * \brief Pack an element into the message buffer in big-endian byte order.
260  *
261  * Little-Endian Host Version
262  *
263  * \param [in] p Byte pointer to typecasted element to be packed.
264  * \param size Byte size of element to pack.
265  * \param [out] buf Output message buffer.
266  */
267 static inline void packbig(byte_t *p, size_t size, byte_t buf[])
268 {
269  size_t n = 0;
270  size_t k = size - 1;
271 
272  // reverse copy
273  while( n < size )
274  {
275  buf[n++] = p[k--];
276  }
277 }
278 
279 /*!
280  * \brief Unpack an element from the message buffer in big-endian byte order.
281  *
282  * Little-Endian Host Version
283  *
284  * \param [in] buf Output message buffer.
285  * \param [out] p Byte pointer to typecasted element to be unpacked (set).
286  * \param size Byte size of element to unpack.
287  */
288 static inline void unpackbig(byte_t buf[], byte_t *p, size_t size)
289 {
290  size_t n = 0;
291  size_t k = size - 1;
292 
293  // reverse copy
294  while( n < size )
295  {
296  p[k--] = buf[n++];
297  }
298 }
299 
300 /*!
301  * \brief Pack an element into the message buffer in little-endian byte order.
302  *
303  * Little-Endian Host Version
304  *
305  * \param [in] p Byte pointer to typecasted element to be packed.
306  * \param size Byte size of element to pack.
307  * \param [out] buf Output message buffer.
308  */
309 static inline void packlittle(byte_t *p, size_t size, byte_t buf[])
310 {
311  size_t n = 0;
312 
313  // forward copy
314  while( n < size )
315  {
316  buf[n++] = *p++;
317  }
318 }
319 
320 /*!
321  * \brief Unpack an element from the message buffer in little-endian byte order.
322  *
323  * Little-Endian Host Version
324  *
325  * \param [in] buf Output message buffer.
326  * \param [out] p Byte pointer to typecasted element to be unpacked (set).
327  * \param size Byte size of element to unpack.
328  */
329 static inline void unpacklittle(byte_t buf[], byte_t *p, size_t size)
330 {
331  size_t n = 0;
332 
333  // forward copy
334  while( n < size )
335  {
336  *p++ = buf[n++];
337  }
338 }
339 
340 /*!
341  * \brief Pack an element into the message buffer in native byte order.
342  *
343  * Little-Endian Host Version
344  *
345  * \param [in] val Type T element to be packed.
346  * \param [out] buf Output message buffer.
347  */
348 #define PACKNATIVE(val, buf) packlittle((byte_t *)&(val), sizeof(val), buf)
349 
350 /*!
351  * \brief Unpack an element from the message buffer in native byte order.
352  *
353  * Little-Endian Host Version
354  *
355  * \param [in] buf Output message buffer.
356  * \param [out] pval Type T* element to be unpacked (set).
357  */
358 #define UNPACKNATIVE(buf, pval) unpacklittle(buf, (byte_t *)pval, sizeof(*pval))
359 
360 /*!
361  * \brief Pack two 4-btye unsigned integers into the message buffer in native
362  * byte order.
363  *
364  * Little-Endian Host Version
365  *
366  * \param [in] uMSB Most Significant Bytes.
367  * \param [in] uLSB Least Significant Bytes.
368  * \param [out] buf Output message buffer.
369  */
370 #define PACK64NATIVE(uMSB, uLSB, buf) PACK64LITTLE(uMSB, uLSB, buf)
371 
372 /*!
373  * \brief Unpack two 4-byte unsigned integers from the message buffer in native
374  * byte order.
375  *
376  * Little-Endian Host Version
377  *
378  * \param [in] buf Output message buffer.
379  * \param [out] puMSB Pointer to Most Significant Bytes.
380  * \param [out] puLSB Pointer to Least Significant Bytes.
381  */
382 #define UNPACK64NATIVE(buf, puMSB, puLSB) UNPACK64LITTLE(buf, puMSB, puLSB)
383 
384 #endif // HOST_BIG_ENDIAN
385 
386 
387 //.............................................................................
388 // Auto-Endian Host Core Packing and Unpacking Operations
389 //.............................................................................
390 
391 /*!
392  * \brief Pack an element into the message buffer in big-endian byte order.
393  *
394  * \param [in] val Type T element to be packed.
395  * \param [out] buf Output message buffer.
396  */
397 #define PACKBIG(val, buf) packbig((byte_t *)&(val), sizeof(val), buf)
398 
399 /*!
400  * \brief Unpack an element from the message buffer in big-endian byte order.
401  *
402  * \param [in] buf Output message buffer.
403  * \param [out] pval Type T* element to be unpacked (set).
404  */
405 #define UNPACKBIG(buf, pval) unpackbig(buf, (byte_t *)pval, sizeof(*pval));
406 
407 /*!
408  * \brief Pack an element into the message buffer in little-endian byte order.
409  *
410  * \param [in] val Type T element to be packed.
411  * \param [out] buf Output message buffer.
412  */
413 #define PACKLITTLE(val, buf) packlittle((byte_t *)&(val), sizeof(val), buf)
414 
415 /*!
416  * \brief Unpack an element from the message buffer in little-endian byte order.
417  *
418  * \param [in] buf Output message buffer.
419  * \param [out] pval Type T* element to be unpacked (set).
420  */
421 #define UNPACKLITTLE(buf, pval) unpacklittle(buf, (byte_t *)pval, sizeof(*pval))
422 
423 /*!
424  * \brief Pack two 4-btye unsigned integers into the message buffer in
425  * big-endian byte order.
426  *
427  * Safe 8-byte packing.
428  *
429  * \note The netmsgs package requires the host to have 4-byte integers
430  * available, but not 8-byte versions.
431  *
432  * \param [in] uMSB Most Significant Bytes.
433  * \param [in] uLSB Least Significant Bytes.
434  * \param [out] buf Output message buffer.
435  */
436 #define PACK64BIG(uMSB, uLSB, buf) \
437  do \
438  { \
439  PACKBIG(uMSB, buf); \
440  PACKBIG(uLSB, &(buf)[4]); \
441  } while(0)
442 
443 /*!
444  * \brief Unpack two 4-byte unsigned integers from the message buffer in
445  * big-endian byte order.
446  *
447  * Safe 8-byte packing.
448  *
449  * \note The netmsgs package requires the host to have 4-byte integers
450  * available, but not 8-byte versions.
451  *
452  *
453  * \param [in] buf Output message buffer.
454  * \param [out] puMSB Pointer to Most Significant Bytes.
455  * \param [out] puLSB Pointer to Least Significant Bytes.
456  */
457 #define UNPACK64BIG(buf, puMSB, puLSB) \
458  do \
459  { \
460  UNPACKBIG(buf, puMSB); \
461  UNPACKBIG(&(buf)[4], puLSB); \
462  } while(0)
463 
464 /*!
465  * \brief Pack two 4-btye unsigned integers into the message buffer in
466  * little-endian byte order.
467  *
468  * Safe 8-byte packing.
469  *
470  * \note The netmsgs package requires the host to have 4-byte integers
471  * available, but not 8-byte versions.
472  *
473  * \param [in] uMSB Most Significant Bytes.
474  * \param [in] uLSB Least Significant Bytes.
475  * \param [out] buf Output message buffer.
476  */
477 #define PACK64LITTLE(uMSB, uLSB, buf) \
478  do \
479  { \
480  PACKLITTLE(uLSB, buf); \
481  PACKLITTLE(uMSB, &(buf)[4]); \
482  } while(0)
483 
484 /*!
485  * \brief Unpack two 4-byte unsigned integers from the message buffer in
486  * little-endian byte order.
487  *
488  * Safe 8-byte packing.
489  *
490  * \note The netmsgs package requires the host to have 4-byte integers
491  * available, but not 8-byte versions.
492  *
493  *
494  * \param [in] buf Output message buffer.
495  * \param [out] puMSB Pointer to Most Significant Bytes.
496  * \param [out] puLSB Pointer to Least Significant Bytes.
497  */
498 #define UNPACK64LITTLE(buf, puMSB, puLSB) \
499  do \
500  { \
501  UNPACKLITTLE(buf, puLSB); \
502  UNPACKLITTLE(&(buf)[4], puMSB); \
503  } while(0)
504 
505 
506 //.............................................................................
507 // IEEE754 Floating-Pointer Numbers Constants, Macros, and Functions
508 //.............................................................................
509 
510 //
511 // Single Precision 32-Bit Floating Point Numbers
512 //
513 // Shifts are relative to packing into a 4-byte unsigned integer.
514 // Masks are right-justified (pre-shifted) values.
515 //
516 #define IEEE754_F32_SIGN_SHIFT 31 ///< f32 sign shift
517 #define IEEE754_F32_SIGN_MASK 0x00000001 ///< f32 sign mask
518 #define IEEE754_F32_EXPONENT_SHIFT 23 ///< f32 exponent shift
519 #define IEEE754_F32_EXPONENT_MASK 0x000000ff ///< f32 exponent mask
520 #define IEEE754_F32_MANTISSA_SHIFT 0 ///< f32 mantissa shift
521 #define IEEE754_F32_MANTISSA_MASK 0x007fffff ///< f32 mantissa mask
522 
523 
524 //
525 // Double Precision 64-Bit Floating Point Numbers
526 //
527 // Shifts are relative to packing into a 4-byte unsigned integer. Two unsigned
528 // integers are required to fully represent the bit-pattern.
529 // Masks are right-justified (pre-shifted) values.
530 //
531 #define IEEE754_F64_SIGN_SHIFT 31 ///< f64 sign shift
532 #define IEEE754_F64_SIGN_MASK 0x00000001 ///< f64 sign mask
533 #define IEEE754_F64_EXPONENT_SHIFT 20 ///< f64 exponent shift
534 #define IEEE754_F64_EXPONENT_MASK 0x000007ff ///< f64 exponent mask
535 #define IEEE754_F64_MANTISSA0_SHIFT 0 ///< f64 msb mantissa shift
536 #define IEEE754_F64_MANTISSA0_MASK 0x000fffff ///< f64 msb mantissa mask
537 #define IEEE754_F64_MANTISSA1_SHIFT 0 ///< f64 lsb mantissa shift
538 #define IEEE754_F64_MANTISSA1_MASK 0xffffffff ///< f64 lsb mantissa mask
539 
540 //
541 // Conversions between 32-bit and 64-bit Floating-Point Numbers Shifts and Masks
542 //
543 #define IEEE754_F32_F64_MANTISSA0_SHIFT 3 ///< msb mantissa shift
544 #define IEEE754_F32_F64_MANTISSA1_SHIFT 29 ///< lsb mantissa shift
545 #define IEEE754_F32_F64_MANTISSA1_MASK 0x00000007 ///< lsb mantissa mask
546 
547 //
548 // Floating-Point Numbers Limits
549 //
550 #define IEEE754_F32_EXP_MAX 127 ///< maximum power of 2 exponent
551 #define IEEE754_F32_EXP_MIN (-126) ///< minimum power of 2 exponent
552 #define IEEE754_F64_EXP_MAX 1023 ///< maximum power of 2 exponent
553 #define IEEE754_F64_EXP_MIN (-1022) ///< minimum power of 2 exponent
554 
555 //
556 // Floating-Point Number Infinities
557 //
558 #define IEEE754_F32_POS_INF HUGE_VALF ///< f32 positive infinity
559 #define IEEE754_F32_NEG_INF (-HUGE_VALF) ///< f32 negative infinity
560 #define IEEE754_F64_POS_INF HUGE_VAL ///< f64 positive infinity
561 #define IEEE754_F64_NEG_INF (-HUGE_VAL) ///< f64 negative infinity
562 
563 /*!
564  * Not-a-Number bit pattern for 32-bit floating-point numbers.
565  */
566 static const union ieee754_float IEEE754_F32_NaN =
567 {
568  .ieee.negative = 0,
569  .ieee.exponent = IEEE754_F32_EXPONENT_MASK, // 0xff,
570  .ieee.mantissa = 0x400000,
571 };
572 
573 /*!
574  * Not-a-Number bit pattern for 64-bit floating-point numbers.
575  */
576 static const union ieee754_double IEEE754_F64_NaN =
577 {
578  .ieee.negative = 0,
579  .ieee.exponent = IEEE754_F64_EXPONENT_MASK, //0x7ff,
580  .ieee.mantissa0 = 0x80000,
581  .ieee.mantissa1 = 0
582 };
583 
584 /*!
585  * \h_plusmn Infinity bit pattern for 32-bit floating-point numbers.
586  */
587 static const union ieee754_float IEEE754_F32_Inf =
588 {
589  .ieee.negative = 0,
590  .ieee.exponent = IEEE754_F32_EXPONENT_MASK, // 0xff,
591  .ieee.mantissa = 0
592 };
593 
594 /*!
595  * \h_plusmn Infinity bit pattern for 64-bit floating-point numbers.
596  */
597 static const union ieee754_double IEEE754_F64_Inf =
598 {
599  .ieee.negative = 0,
600  .ieee.exponent = IEEE754_F64_EXPONENT_MASK, //0x7ff,
601  .ieee.mantissa0 = 0,
602  .ieee.mantissa1 = 0
603 };
604 
605 /*!
606  * \h_plusmn 0 bit pattern for 32-bit floating-point numbers.
607  */
608 static const union ieee754_float IEEE754_F32_Zero =
609 {
610  .ieee.negative = 0,
611  .ieee.exponent = 0,
612  .ieee.mantissa = 0
613 };
614 
615 /*!
616  * \h_plusmn 0 bit pattern for 64-bit floating-point numbers.
617  */
618 static const union ieee754_double IEEE754_F64_Zero =
619 {
620  .ieee.negative = 0,
621  .ieee.exponent = 0,
622  .ieee.mantissa0 = 0,
623  .ieee.mantissa1 = 0
624 };
625 
626 /*!
627  * \brief Test if 32-bit floating-point number is a NaN.
628  * \param f 32-bit float with bit overlay.
629  * \return Returns true or false.
630  */
631 static inline bool_t ieee754_f32_is_nan(union ieee754_float f)
632 {
633  return (f.ieee.exponent == IEEE754_F32_NaN.ieee.exponent)
634  && (f.ieee.mantissa != 0)? true: false;
635 }
636 
637 /*!
638  * \brief Test if 64-bit floating-point number is a NaN.
639  * \param d 64-bit float with bit overlay.
640  * \return Returns true or false.
641  */
642 static inline bool_t ieee754_f64_is_nan(union ieee754_double d)
643 {
644  return (d.ieee.exponent == IEEE754_F64_NaN.ieee.exponent)
645  && ((d.ieee.mantissa0 != 0) || (d.ieee.mantissa1 != 0))? true: false;
646 }
647 
648 /*!
649  * \brief Test if 32-bit floating-point number is \h_plusmn infinity.
650  * \param f 32-bit float with bit overlay.
651  * \return Returns true or false.
652  */
653 static inline bool_t ieee754_f32_is_inf(union ieee754_float f)
654 {
655  return (f.ieee.exponent == IEEE754_F32_Inf.ieee.exponent)
656  && (f.ieee.mantissa == 0)? true: false;
657 }
658 
659 /*!
660  * \brief Test if 64-bit floating-point number is \h_plusmn infinity.
661  * \param d 64-bit float with bit overlay.
662  * \return Returns true or false.
663  */
664 static inline bool_t ieee754_f64_is_inf(union ieee754_double d)
665 {
666  return (d.ieee.exponent == IEEE754_F64_Inf.ieee.exponent)
667  && ((d.ieee.mantissa0 == 0) || (d.ieee.mantissa1 == 0))? true: false;
668 }
669 
670 /*!
671  * \brief Test if 32-bit floating-point number is \h_plusmn 0.0.
672  * \param f 32-bit float with bit overlay.
673  * \return Returns true or false.
674  */
675 static inline bool_t ieee754_f32_is_zero(union ieee754_float f)
676 {
677  return (f.ieee.exponent == IEEE754_F32_Zero.ieee.exponent)
678  && (f.ieee.mantissa == 0)? true: false;
679 }
680 
681 /*!
682  * \brief Test if 64-bit floating-point number is \h_plusmn 0.0.
683  * \param d 64-bit float with bit overlay.
684  * \return Returns true or false.
685  */
686 static inline bool_t ieee754_f64_is_zero(union ieee754_double d)
687 {
688  return (d.ieee.exponent == IEEE754_F64_Zero.ieee.exponent)
689  && ((d.ieee.mantissa0 == 0) || (d.ieee.mantissa1 == 0))? true: false;
690 }
691 
692 
693 //.............................................................................
694 // Helper Checks
695 //.............................................................................
696 
697 /*!
698  * \brief Check if memory is available.
699  *
700  * On check failure, returns from calling function with \ref NM_ECODE_NOMEM.
701  *
702  * \param size Available memory in bytes.
703  * \param count Required memory.
704  */
705 #define _NM_CHK_MEM(size, count) \
706  do \
707  { \
708  if( (size) < (count) ) \
709  { \
710  return -NM_ECODE_NOMEM; \
711  } \
712  } \
713  while(0)
714 
715 /*!
716  * \brief Check if host architecture supports basic element sizes.
717  *
718  * On check failure, returns from calling function with
719  * \ref NM_ECODE_ARCH_NOTSUP.
720  *
721  * \param val Element to check
722  * \param size Required byte size.
723  */
724 #define _NM_CHK_ARCH(val, size) \
725  do \
726  { \
727  if( sizeof(val) != (size) ) \
728  { \
729  return -NM_ECODE_ARCH_NOTSUP; \
730  } \
731  } \
732  while(0)
733 
734 
735 // ---------------------------------------------------------------------------
736 // Base Packing Public Interface
737 // ---------------------------------------------------------------------------
738 
739 /*!
740  * \brief Pack an unsigned 8-bit byte into the message buffer.
741  *
742  * \copydoc doc_params_pack_std
743  * \copydoc doc_return_pack_std
744  */
745 int nmPackU8(byte_t val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
746 {
747  static size_t fvalLen = NMFVAL_LEN_U8; // message field value length
748 
749  _NM_CHK_MEM(bufSize, fvalLen);
750 
751  buf[0] = val & 0xff;
752 
753  return (int)fvalLen;
754 }
755 
756 /*!
757  * \brief Pack an unsigned 16-bit integer into the message buffer.
758  *
759  * \copydoc doc_params_pack_std
760  * \copydoc doc_return_pack_std
761  */
762 int nmPackU16(ushort_t val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
763 {
764  static size_t fvalLen = NMFVAL_LEN_U16; // message field value length
765 
766  _NM_CHK_MEM(bufSize, fvalLen);
767 
768  switch( eEndian )
769  {
770  case NMEndianLittle:
771  PACKLITTLE(val, buf);
772  break;
773  case NMEndianNative:
774  PACKNATIVE(val, buf);
775  break;
776  case NMEndianBig:
777  default:
778  PACKBIG(val, buf);
779  break;
780  }
781 
782  return (int)fvalLen;
783 }
784 
785 /*!
786  * \brief Pack an unsigned 32-bit integer into the message buffer.
787  *
788  * \copydoc doc_params_pack_std
789  * \copydoc doc_return_pack_std
790  */
791 int nmPackU32(uint_t val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
792 {
793  static size_t fvalLen = NMFVAL_LEN_U32; // message field value length
794 
795  _NM_CHK_MEM(bufSize, fvalLen);
796 
797  switch( eEndian )
798  {
799  case NMEndianLittle:
800  PACKLITTLE(val, buf);
801  break;
802  case NMEndianNative:
803  PACKNATIVE(val, buf);
804  break;
805  case NMEndianBig:
806  default:
807  PACKBIG(val, buf);
808  break;
809  }
810 
811  return (int)fvalLen;
812 }
813 
814 /*!
815  * \brief Pack an unsigned 64-bit integer into the message buffer.
816  *
817  * If the machine architecture only supports 32-bit long longs, then
818  * the 4 MSBs are padded with zero's.
819  *
820  * \copydoc doc_params_pack_std
821  * \copydoc doc_return_pack_std
822  */
823 int nmPackU64(ulonglong_t val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
824 {
825  static size_t fvalLen = NMFVAL_LEN_U64; // message field value length
826 
827  uint_t uMSB; // most significant bytes
828  uint_t uLSB; // least signifcant bytes
829 
830  _NM_CHK_MEM(bufSize, fvalLen);
831 
832  // 8-byte unsigned long long
833  if( sizeof(ulonglong_t) == fvalLen )
834  {
835  switch( eEndian )
836  {
837  case NMEndianLittle:
838  PACKLITTLE(val, buf);
839  break;
840  case NMEndianNative:
841  PACKNATIVE(val, buf);
842  break;
843  case NMEndianBig:
844  default:
845  PACKBIG(val, buf);
846  break;
847  }
848  }
849 
850  // 4-byte unsigned long long
851  else
852  {
853  _NM_CHK_ARCH(val, (size_t)NMFVAL_LEN_U32);
854 
855  uMSB = 0;
856  uLSB = (uint_t)val;
857 
858  switch( eEndian )
859  {
860  case NMEndianLittle:
861  PACK64LITTLE(uMSB, uLSB, buf);
862  break;
863  case NMEndianNative:
864  PACK64NATIVE(uMSB, uLSB, buf);
865  break;
866  case NMEndianBig:
867  default:
868  PACK64BIG(uMSB, uLSB, buf);
869  break;
870  }
871  }
872 
873  return (int)fvalLen;
874 }
875 
876 /*!
877  * \brief Pack an signed 64-bit integer into the message buffer.
878  *
879  * If the machine architecture only supports 32-bit long longs, then
880  * the 4 MSBs are signed extended.
881  *
882  * \copydoc doc_params_pack_std
883  * \copydoc doc_return_pack_std
884  */
885 int nmPackS64(long long val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
886 {
887  static size_t fvalLen = NMFVAL_LEN_S64; // message field value length
888 
889  uint_t uMSB; // most significant bytes
890  uint_t uLSB; // least signifcant bytes
891 
892  _NM_CHK_MEM(bufSize, fvalLen);
893 
894  // 8-byte signed long long
895  if( sizeof(long long) == fvalLen )
896  {
897  switch( eEndian )
898  {
899  case NMEndianLittle:
900  PACKLITTLE(val, buf);
901  break;
902  case NMEndianNative:
903  PACKNATIVE(val, buf);
904  break;
905  case NMEndianBig:
906  default:
907  PACKBIG(val, buf);
908  break;
909  }
910  }
911 
912  // 4-byte signed long long
913  else
914  {
915  _NM_CHK_ARCH(val, (size_t)NMFVAL_LEN_S32);
916 
917  uMSB = val & 0x80000000? 0xffffffff: 0x00000000; // extend sign
918  uLSB = (uint_t)val;
919 
920  switch( eEndian )
921  {
922  case NMEndianLittle:
923  PACK64LITTLE(uMSB, uLSB, buf);
924  break;
925  case NMEndianNative:
926  PACK64NATIVE(uMSB, uLSB, buf);
927  break;
928  case NMEndianBig:
929  default:
930  PACK64BIG(uMSB, uLSB, buf);
931  break;
932  }
933  }
934 
935  return (int)fvalLen;
936 }
937 
938 /*!
939  * \brief Pack a 32-bit float into the message buffer.
940  *
941  * The IEEE 754 32-bit format is used with both the big and little endian byte
942  * orders.
943  *
944  * \note
945  * <em>On some machines, while integers were represented in little-endian form,
946  * floating point numbers were represented in big-endian form. Because there
947  * are many floating point formats, and a lack of a standard <b>network</b>
948  * representation, no standard for transferring floating point values has been
949  * made</em> - Wikipedia.
950  *
951  * \todo
952  * Detect non-IEEE 754 formats and convert to IEEE 754 prior to packing.
953  *
954  * \copydoc doc_params_pack_std
955  * \copydoc doc_return_pack_std
956  */
957 int nmPackF32(float val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
958 {
959  static size_t fvalLen = NMFVAL_LEN_F32; // message field value length
960 
961  union ieee754_float f; // 4 byte floating-point number
962  uint_t uBits; // bits
963 
964  _NM_CHK_MEM(bufSize, fvalLen);
965  _NM_CHK_ARCH(val, fvalLen);
966 
967  f.f = val;
968 
969  uBits = (uint_t)((f.ieee.negative & IEEE754_F32_SIGN_MASK)
971  uBits |= (uint_t)((f.ieee.exponent & IEEE754_F32_EXPONENT_MASK)
973  uBits |= (uint_t)((f.ieee.mantissa & IEEE754_F32_MANTISSA_MASK)
975 
976  switch( eEndian )
977  {
978  case NMEndianLittle:
979  PACKLITTLE(uBits, buf);
980  break;
981  case NMEndianNative:
982  PACKNATIVE(f.f, buf);
983  break;
984  case NMEndianBig:
985  default:
986  PACKBIG(uBits, buf);
987  break;
988  }
989 
990  return (int)fvalLen;
991 }
992 
993 /*!
994  * \brief Pack a 64-bit float into the message buffer.
995  *
996  * The IEEE 754 64-bit format is used with both the big and little endian byte
997  * orders. If the machine architecture only supports 32-bit doubles, then a
998  * conversion to 64-bit representation is performed first.
999  *
1000  * \note
1001  * <em>On some machines, while integers were represented in little-endian form,
1002  * floating point numbers were represented in big-endian form. Because there
1003  * are many floating point formats, and a lack of a standard <b>network</b>
1004  * representation, no standard for transferring floating point values has been
1005  * made</em> - Wikipedia.
1006  *
1007  * \todo
1008  * Detect non-IEEE 754 formats and convert to IEEE 754 prior to packing.
1009  *
1010  * \copydoc doc_params_pack_std
1011  * \copydoc doc_return_pack_std
1012  */
1013 int nmPackF64(double val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
1014 {
1015  static size_t fvalLen = NMFVAL_LEN_F64; // message field value length
1016 
1017  union ieee754_float f; // 4-byte floating-point number
1018  union ieee754_double d; // 8-byte floating-point number
1019  uint_t uMSB; // Most Signifcant Bytes
1020  uint_t uLSB; // Least Signifcant Bytes
1021 
1022  _NM_CHK_MEM(bufSize, fvalLen);
1023 
1024  // 8-byte double
1025  if( sizeof(double) == fvalLen )
1026  {
1027  d.d = val;
1028  }
1029 
1030  // 4-byte double
1031  else
1032  {
1033  _NM_CHK_ARCH(val, (size_t)NMFVAL_LEN_F32);
1034 
1035  f.f = (float)val;
1036 
1037  // special infinity cases
1038  if( ieee754_f32_is_inf(f) )
1039  {
1040  d = IEEE754_F64_Inf;
1041  }
1042 
1043  // special zero cases
1044  else if( ieee754_f32_is_zero(f) )
1045  {
1046  d = IEEE754_F64_Zero;
1047  }
1048 
1049  // special Not-a-Number case
1050  else if( ieee754_f32_is_nan(f) )
1051  {
1052  d = IEEE754_F64_NaN;
1053  }
1054 
1055  // "normal" floating-point numbers
1056  else
1057  {
1058  d.ieee.exponent = (f.ieee.exponent + (uint_t)IEEE754_DOUBLE_BIAS
1059  - (uint_t)IEEE754_FLOAT_BIAS)
1061  d.ieee.mantissa0 = ((uint_t)(f.ieee.mantissa
1062  >> (uint_t)IEEE754_F32_F64_MANTISSA0_SHIFT))
1064  d.ieee.mantissa1 = (((uint_t)(f.ieee.mantissa))
1067  }
1068 
1069  // preserve the sign
1070  d.ieee.negative = f.ieee.negative;
1071  }
1072 
1073  //
1074  // Stuff the bits into two 4-byte unsigned integers.
1075  //
1076  uMSB = (uint_t)((d.ieee.negative & IEEE754_F64_SIGN_MASK)
1078  uMSB |= (uint_t)((d.ieee.exponent & IEEE754_F64_EXPONENT_MASK)
1080  uMSB |= (uint_t)((d.ieee.mantissa0 & IEEE754_F64_MANTISSA0_MASK)
1082  uLSB = (uint_t)((d.ieee.mantissa1 & IEEE754_F64_MANTISSA1_MASK)
1084 
1085  switch( eEndian )
1086  {
1087  case NMEndianLittle:
1088  PACK64LITTLE(uMSB, uLSB, buf);
1089  break;
1090  case NMEndianNative:
1091  PACK64NATIVE(uMSB, uLSB, buf);
1092  break;
1093  case NMEndianBig:
1094  default:
1095  PACK64BIG(uMSB, uLSB, buf);
1096  break;
1097  }
1098 
1099  return (int)fvalLen;
1100 }
1101 
1102 /*!
1103  * \brief Pack a 32-bit pointer into the message buffer.
1104  *
1105  * If the machine architecture has 64-bit pointers, then only the
1106  * LSB 4 bytes are packed.
1107  *
1108  * \note Pointer is always packed in native byte order.
1109  *
1110  * \copydoc doc_params_pack_std
1111  * \copydoc doc_return_pack_std
1112  */
1113 int nmPackP32(void *val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
1114 {
1115  static size_t fvalLen = NMFVAL_LEN_P32; // message field value length
1116  ulong_t luVal;
1117  uint_t uVal;
1118 
1119  _NM_CHK_MEM(bufSize, fvalLen);
1120 
1121  // long's are same size as void *'s. exceptions?
1122  luVal = *((ulong_t *)val);
1123 
1124  // 4-byte natvie pointer
1125  if( sizeof(void *) == fvalLen )
1126  {
1127  PACKNATIVE(luVal, buf);
1128  }
1129 
1130  // 8-byte native pointer - "convert"
1131  if( sizeof(void *) == NMFVAL_LEN_P64 )
1132  {
1133 #if HOST_WORD_SIZE == 64
1134  //if( luVal & 0xffffffff00000000 )
1135  if( (luVal) & 0xffffffff00000000 )
1136  {
1137  NMLIB_WARNING("%p: Packing 64-bit pointer in 32 bits lost non-zero "
1138  "significance.", (void *)luVal);
1139  }
1140 #endif // HOST_WORD_SIZE
1141  uVal = (uint_t)(luVal & 0xffffffff);
1142  PACKNATIVE(uVal, buf);
1143  }
1144 
1145 
1146  return (int)fvalLen;
1147 }
1148 
1149 /*!
1150  * \brief Pack a 64-bit pointer into the message buffer.
1151  *
1152  * If the machine architecture only supports 32-bit pointers, then
1153  * the 4 MSBs are padded with 0's.
1154  *
1155  * \note Pointer is always packed in native byte order.
1156  *
1157  * \copydoc doc_params_pack_std
1158  * \copydoc doc_return_pack_std
1159  */
1160 int nmPackP64(void *val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
1161 {
1162  static size_t fvalLen = NMFVAL_LEN_P64; // message field value length
1163 
1164  ulong_t luVal;
1165  uint_t uMSB; // Most Signifcant Bytes
1166  uint_t uLSB; // Least Signifcant Bytes
1167 
1168  _NM_CHK_MEM(bufSize, fvalLen);
1169 
1170  // long's are same size as void *'s. exceptions?
1171  luVal = *((ulong_t *)val);
1172 
1173  // 8-byte pointer
1174  if( sizeof(void *) == fvalLen )
1175  {
1176 #if HOST_WORD_SIZE == 64
1177  uMSB = (uint_t)(luVal >> 32);
1178  uLSB = (uint_t)(luVal & 0xffffffff);
1179 #else
1180  uMSB = 0;
1181  uLSB = (uint_t)luVal;
1182 #endif // HOST_WORD_SIZE
1183  }
1184 
1185  // 4-byte pointer
1186  else
1187  {
1188  _NM_CHK_ARCH(val, (size_t)NMFVAL_LEN_P32);
1189 
1190  uMSB = 0;
1191  uLSB = (uint_t)luVal;
1192  }
1193 
1194  PACK64NATIVE(uMSB, uLSB, buf);
1195 
1196  return (int)fvalLen;
1197 }
1198 
1199 /*!
1200  * \brief Pack a byte buffer into the message buffer.
1201  *
1202  * The source and message buffer memory areas can overlap.
1203  *
1204  * \note The buffer is always packed in sequential order ignoring the byte
1205  * order parameter.
1206  *
1207  * \param [in] bufSrc Source buffer.
1208  * \param uCount Number of bytes to copy.
1209  * \param [out] buf Output message buffer.
1210  * \param bufSize Size of output buffer.
1211  * \param eEndian Packing order. See \ref NMEndian_T.
1212  *
1213  * \copydoc doc_return_pack_std
1214  */
1215 int nmPackBuf(byte_t bufSrc[],
1216  size_t uCount,
1217  byte_t buf[],
1218  size_t bufSize,
1219  NMEndian_T eEndian)
1220 {
1221  _NM_CHK_MEM(bufSize, uCount);
1222 
1223  // safe copy
1224  memmove(buf, bufSrc, uCount);
1225 
1226  return (int)uCount;
1227 }
1228 
1229 // ---------------------------------------------------------------------------
1230 // Base Unpacking Public Interface
1231 // ---------------------------------------------------------------------------
1232 
1233 /*!
1234  * \brief Unpack an unsigned 8-bit byte from the message buffer.
1235  *
1236  * \copydoc doc_params_unpack_std
1237  * \copydoc doc_return_unpack_std
1238  */
1239 int nmUnpackU8(byte_t buf[], size_t bufSize, byte_t *pVal, NMEndian_T eEndian)
1240 {
1241  static size_t fvalLen = NMFVAL_LEN_U8; // message field value length
1242 
1243  _NM_CHK_MEM(bufSize, fvalLen);
1244 
1245  *pVal = buf[0];
1246 
1247  return (int)fvalLen;
1248 }
1249 
1250 /*!
1251  * \brief Unpack an unsigned 16-bit integer from the message buffer.
1252  *
1253  * \copydoc doc_params_unpack_std
1254  * \copydoc doc_return_unpack_std
1255  */
1256 int nmUnpackU16(byte_t buf[],
1257  size_t bufSize,
1258  ushort_t *pVal,
1259  NMEndian_T eEndian)
1260 {
1261  static size_t fvalLen = NMFVAL_LEN_U16; // message field value length
1262 
1263  _NM_CHK_MEM(bufSize, fvalLen);
1264 
1265  switch( eEndian )
1266  {
1267  case NMEndianLittle:
1268  UNPACKLITTLE(buf, pVal);
1269  break;
1270  case NMEndianNative:
1271  UNPACKNATIVE(buf, pVal);
1272  break;
1273  case NMEndianBig:
1274  default:
1275  UNPACKBIG(buf, pVal);
1276  break;
1277  }
1278 
1279  return (int)fvalLen;
1280 }
1281 
1282 /*!
1283  * \brief Unpack an unsigned 32-bit integer from the message buffer.
1284  *
1285  * \copydoc doc_params_unpack_std
1286  * \copydoc doc_return_unpack_std
1287  */
1288 int nmUnpackU32(byte_t buf[], size_t bufSize, uint_t *pVal, NMEndian_T eEndian)
1289 {
1290  static size_t fvalLen = NMFVAL_LEN_U32; // message field value length
1291 
1292  _NM_CHK_MEM(bufSize, fvalLen);
1293 
1294  switch( eEndian )
1295  {
1296  case NMEndianLittle:
1297  UNPACKLITTLE(buf, pVal);
1298  break;
1299  case NMEndianNative:
1300  UNPACKNATIVE(buf, pVal);
1301  break;
1302  case NMEndianBig:
1303  default:
1304  UNPACKBIG(buf, pVal);
1305  break;
1306  }
1307 
1308  return (int)fvalLen;
1309 }
1310 
1311 /*!
1312  * \brief Unpack an unsigned 64-bit integer from the message buffer.
1313  *
1314  * If the machine architecture only supports 32-bit unsigned long longs, then
1315  * the 4 MSBs are truncated.
1316  *
1317  * \copydoc doc_params_unpack_std
1318  * \copydoc doc_return_unpack_std
1319  */
1320 int nmUnpackU64(byte_t buf[],
1321  size_t bufSize,
1322  ulonglong_t *pVal,
1323  NMEndian_T eEndian)
1324 {
1325  static size_t fvalLen = NMFVAL_LEN_U64; // message field value length
1326 
1327  uint_t uMSB; // most significant bytes
1328  uint_t uLSB; // least signifcant bytes
1329 
1330  _NM_CHK_MEM(bufSize, fvalLen);
1331 
1332  // 8-byte unsigned long long
1333  if( sizeof(ulonglong_t) == fvalLen )
1334  {
1335  switch( eEndian )
1336  {
1337  case NMEndianLittle:
1338  UNPACKLITTLE(buf, pVal);
1339  break;
1340  case NMEndianNative:
1341  UNPACKNATIVE(buf, pVal);
1342  break;
1343  case NMEndianBig:
1344  default:
1345  UNPACKBIG(buf, pVal);
1346  break;
1347  }
1348  }
1349 
1350  // 4-byte unsigned long long
1351  else
1352  {
1353  _NM_CHK_ARCH(*pVal, (size_t)NMFVAL_LEN_U32);
1354 
1355  switch( eEndian )
1356  {
1357  case NMEndianLittle:
1358  UNPACK64LITTLE(buf, &uMSB, &uLSB);
1359  break;
1360  case NMEndianNative:
1361  UNPACK64NATIVE(buf, &uMSB, &uLSB);
1362  break;
1363  case NMEndianBig:
1364  default:
1365  UNPACK64BIG(buf, &uMSB, &uLSB);
1366  break;
1367  }
1368 
1369  if( uMSB != 0 )
1370  {
1371  NMLIB_WARNING("0x%08x%08x: Unpacking unsigned 64-bit integer into "
1372  "32 bits lost non-zero significance.",
1373  uMSB, uLSB);
1374  }
1375 
1376  *pVal = (ulonglong_t)uLSB;
1377  }
1378 
1379  return (int)fvalLen;
1380 }
1381 
1382 /*!
1383  * \brief Unpack an signed 64-bit integer from the message buffer.
1384  *
1385  * If the machine architecture only supports 32-bit long longs, then
1386  * the 4 MSBs are truncated.
1387  *
1388  * \copydoc doc_params_unpack_std
1389  * \copydoc doc_return_unpack_std
1390  */
1391 int nmUnpackS64(byte_t buf[],
1392  size_t bufSize,
1393  long long *pVal,
1394  NMEndian_T eEndian)
1395 {
1396  static size_t fvalLen = NMFVAL_LEN_S64; // message field value length
1397 
1398  uint_t uMSB; // most significant bytes
1399  uint_t uLSB; // least signifcant bytes
1400 
1401  _NM_CHK_MEM(bufSize, fvalLen);
1402 
1403  // 8-byte unsigned long long
1404  if( sizeof(ulonglong_t) == fvalLen )
1405  {
1406  switch( eEndian )
1407  {
1408  case NMEndianLittle:
1409  UNPACKLITTLE(buf, pVal);
1410  break;
1411  case NMEndianNative:
1412  UNPACKNATIVE(buf, pVal);
1413  break;
1414  case NMEndianBig:
1415  default:
1416  UNPACKBIG(buf, pVal);
1417  break;
1418  }
1419  }
1420 
1421  // 4-byte unsigned long long
1422  else
1423  {
1424  _NM_CHK_ARCH(*pVal, (size_t)NMFVAL_LEN_S32);
1425 
1426  switch( eEndian )
1427  {
1428  case NMEndianLittle:
1429  UNPACK64LITTLE(buf, &uMSB, &uLSB);
1430  break;
1431  case NMEndianNative:
1432  UNPACK64NATIVE(buf, &uMSB, &uLSB);
1433  break;
1434  case NMEndianBig:
1435  default:
1436  UNPACK64BIG(buf, &uMSB, &uLSB);
1437  break;
1438  }
1439 
1440  if( (uMSB != 0) && (uMSB != 0xffffffff) )
1441  {
1442  NMLIB_WARNING("0x%08x%08x: Unpacking signed 64-bit integer into "
1443  "32 bits lost non-zero significance.",
1444  uMSB, uLSB);
1445  }
1446 
1447  *pVal = (long long)uLSB;
1448  }
1449 
1450  return (int)fvalLen;
1451 }
1452 
1453 /*!
1454  * \brief Unpack a 32-bit float from the message buffer.
1455  *
1456  * The IEEE 754 32-bit format is used with both the big and little endian byte
1457  * orders.
1458  *
1459  * \note
1460  * <em>On some machines, while integers were represented in little-endian form,
1461  * floating point numbers were represented in big-endian form. Because there
1462  * are many floating point formats, and a lack of a standard <b>network</b>
1463  * representation, no standard for transferring floating point values has been
1464  * made</em> - Wikipedia.
1465  *
1466  * \todo
1467  * Detect non-IEEE 754 formats and convert to IEEE 754 prior to packing.
1468  *
1469  * \copydoc doc_params_unpack_std
1470  * \copydoc doc_return_unpack_std
1471  */
1472 int nmUnpackF32(byte_t buf[], size_t bufSize, float *pVal, NMEndian_T eEndian)
1473 {
1474  static size_t fvalLen = NMFVAL_LEN_F32; // message field value length
1475 
1476  _NM_CHK_MEM(bufSize, fvalLen);
1477  _NM_CHK_ARCH(*pVal, fvalLen);
1478 
1479  switch( eEndian )
1480  {
1481  case NMEndianLittle:
1482  UNPACKLITTLE(buf, pVal);
1483  break;
1484  case NMEndianNative:
1485  UNPACKNATIVE(buf, pVal);
1486  break;
1487  case NMEndianBig:
1488  default:
1489  UNPACKBIG(buf, pVal);
1490  break;
1491  }
1492 
1493 
1494  return (int)fvalLen;
1495 }
1496 
1497 /*!
1498  * \brief Unpack a 64-bit float from the message buffer.
1499  *
1500  * The IEEE 754 64-bit format is used with both the big and little endian byte
1501  * orders. If the machine architecture only supports 32-bit doubles, then
1502  * mantissa truncation will occur.
1503  *
1504  * \note
1505  * <em>On some machines, while integers were represented in little-endian form,
1506  * floating point numbers were represented in big-endian form. Because there
1507  * are many floating point formats, and a lack of a standard <b>network</b>
1508  * representation, no standard for transferring floating point values has been
1509  * made</em> - Wikipedia.
1510  *
1511  * \todo
1512  * Detect non-IEEE 754 formats and convert to IEEE 754 prior to packing.
1513  *
1514  * \copydoc doc_params_unpack_std
1515  * \copydoc doc_return_unpack_std
1516  */
1517 int nmUnpackF64(byte_t buf[], size_t bufSize, double *pVal, NMEndian_T eEndian)
1518 {
1519  static size_t fvalLen = NMFVAL_LEN_F64; // message field value length
1520 
1521  uint_t uMSB; // Most Signifcant Bytes
1522  uint_t uLSB; // Least Signifcant Bytes
1523  int exponent; // ieee754 unbiased exponent
1524  union ieee754_float f; // 4-byte floating-point number
1525  union ieee754_double d; // 8-byte floating-point number
1526 
1527  _NM_CHK_MEM(bufSize, fvalLen);
1528 
1529  // 8-byte doubles
1530  if( sizeof(double) == (size_t)NMFVAL_LEN_F64 )
1531  {
1532  switch( eEndian )
1533  {
1534  case NMEndianLittle:
1535  UNPACKLITTLE(buf, &d.d);
1536  break;
1537  case NMEndianNative:
1538  UNPACKNATIVE(buf, &d.d);
1539  break;
1540  case NMEndianBig:
1541  default:
1542  UNPACKBIG(buf, &d.d);
1543  break;
1544  }
1545 
1546  *pVal = d.d;
1547  }
1548 
1549  else // 4-byte doubles
1550  {
1551  _NM_CHK_ARCH(*pVal, (size_t)NMFVAL_LEN_F32);
1552 
1553  switch( eEndian )
1554  {
1555  case NMEndianLittle:
1556  UNPACK64LITTLE(buf, &uMSB, &uLSB);
1557  break;
1558  case NMEndianNative:
1559  UNPACK64NATIVE(buf, &uMSB, &uLSB);
1560  break;
1561  case NMEndianBig:
1562  default:
1563  UNPACK64BIG(buf, &uMSB, &uLSB);
1564  break;
1565  }
1566 
1567  d.ieee.negative = ((uMSB >> IEEE754_F64_SIGN_SHIFT)
1568  & IEEE754_F64_SIGN_MASK)? 1: 0;
1569  d.ieee.exponent = (uMSB >> IEEE754_F64_EXPONENT_SHIFT)
1571  d.ieee.mantissa0 = (uMSB >> IEEE754_F64_MANTISSA0_SHIFT)
1573  d.ieee.mantissa1 = (uLSB >> IEEE754_F64_MANTISSA1_SHIFT)
1575 
1576  // unbias the exponent
1577  exponent = (int)d.ieee.exponent - IEEE754_DOUBLE_BIAS;
1578 
1579  // special Not-a-Number case
1580  if( ieee754_f64_is_nan(d) )
1581  {
1582  f = IEEE754_F32_NaN;
1583  }
1584 
1585  // special infinity cases
1586  else if( ieee754_f64_is_inf(d) )
1587  {
1588  f = IEEE754_F32_Inf;
1589  }
1590 
1591  // exponent overflow
1592  else if( exponent > IEEE754_F32_EXP_MAX )
1593  {
1594  f = IEEE754_F32_Inf;
1595  NMLIB_WARNING("floating-point number overflow.");
1596  }
1597 
1598  // exponent overflow
1599  else if( exponent < IEEE754_F32_EXP_MIN )
1600  {
1601  f = IEEE754_F32_Zero;
1602  NMLIB_WARNING("floating-point number underflow.");
1603  }
1604 
1605  // special zero cases
1606  else if( ieee754_f64_is_zero(d) )
1607  {
1608  f = IEEE754_F32_Zero;
1609  }
1610 
1611  // "normal" floating-point numbers
1612  else
1613  {
1614  f.ieee.exponent = (byte_t)(exponent + IEEE754_FLOAT_BIAS);
1615  f.ieee.mantissa = ( (uint_t)((d.ieee.mantissa0
1618  | (uint_t)((d.ieee.mantissa1
1622  if( (d.ieee.mantissa1 & (uint_t)~IEEE754_F32_F64_MANTISSA1_MASK) != 0 )
1623  {
1624  NMLIB_WARNING("floating-point number mantissa truncation.");
1625  }
1626  }
1627 
1628  // preserve the sign
1629  f.ieee.negative = d.ieee.negative;
1630 
1631  *pVal = (double)f.f;
1632  }
1633 
1634  return (int)fvalLen;
1635 }
1636 
1637 /*!
1638  * \brief Unpack a 32-bit pointer from the message buffer.
1639  *
1640  * If the machine architecture has 64-bit pointers, then only the
1641  * LSB 4 bytes are packed.
1642  *
1643  * \note Pointer is always unpacked in native byte order.
1644  *
1645  * \copydoc doc_params_unpack_std
1646  * \copydoc doc_return_unpack_std
1647  */
1648 int nmUnpackP32(byte_t buf[], size_t bufSize, void *pVal, NMEndian_T eEndian)
1649 {
1650  static size_t fvalLen = NMFVAL_LEN_P32; // message field value length
1651 
1652  ulong_t *pluVal; // longs are same size as pointers on 32/64 bit machines
1653  uint_t uP32;
1654 
1655  _NM_CHK_MEM(bufSize, fvalLen);
1656 
1657  pluVal = (ulong_t *)pVal;
1658 
1659  UNPACKNATIVE(buf, &uP32);
1660 
1661  *pluVal = (ulong_t)uP32;
1662 
1663  return (int)fvalLen;
1664 
1665 }
1666 
1667 /*!
1668  * \brief Unpack a 64-bit pointer from the message buffer.
1669  *
1670  * If the machine architecture only supports 32-bit pointers, then
1671  * the 4 MSBs are padded with 0's.
1672  *
1673  * \note Pointer is always unpacked in native byte order.
1674  *
1675  * \copydoc doc_params_unpack_std
1676  * \copydoc doc_return_unpack_std
1677  */
1678 int nmUnpackP64(byte_t buf[], size_t bufSize, void *pVal, NMEndian_T eEndian)
1679 {
1680  static size_t fvalLen = NMFVAL_LEN_P64; // message field value length
1681 
1682  uint_t uMSB; // Most Signifcant Bytes
1683  uint_t uLSB; // Least Signifcant Bytes
1684  ulong_t *pluVal; // longs are same size as pointers on 32/64 bit machines
1685 
1686  _NM_CHK_MEM(bufSize, fvalLen);
1687 
1688  pluVal = (ulong_t *)pVal;
1689 
1690  UNPACK64NATIVE(buf, &uMSB, &uLSB);
1691 
1692  // 8-byte pointer
1693  if( sizeof(void *) == fvalLen )
1694  {
1695 #if HOST_WORD_SIZE == 64
1696  *pluVal = (ulong_t)(((ulong_t)uMSB << 32) | (uLSB & 0xffffffff));
1697 #else
1698  *pluVal = (ulong_t)uLSB;
1699 #endif // HOST_WORD_SIZE
1700  }
1701 
1702  // 4-byte pointer
1703  else
1704  {
1705  _NM_CHK_ARCH(pVal, (size_t)NMFVAL_LEN_P32);
1706 
1707  if( uMSB != 0 )
1708  {
1709  NMLIB_WARNING("0x%08x%08x: Unpacking 64-bit pointer into 32 bits "
1710  "lost non-zero significance.\n",
1711  uMSB, uLSB);
1712  }
1713  *pluVal = (ulong_t)uLSB;
1714  }
1715 
1716  return (int)fvalLen;
1717 }
1718 
1719 /*!
1720  * \brief Unpack a byte buffer from the message buffer.
1721  *
1722  * The source and message buffer memory areas can overlap.
1723  *
1724  * \note The buffer is always packed in sequential order ignoring the byte
1725  * order parameter.
1726  *
1727  * \param [in] buf Input message buffer.
1728  * \param bufSize Size of input buffer.
1729  * \param [out] bufDst Destination output buffer.
1730  * \param uCount Number of bytes to copy.
1731  * \param eEndian Unpacking order. See \ref NMEndian_T.
1732  *
1733  * \copydoc doc_return_unpack_std
1734  */
1735 int nmUnpackBuf(byte_t buf[],
1736  size_t bufSize,
1737  byte_t bufDst[],
1738  size_t uCount,
1739  NMEndian_T eEndian)
1740 {
1741  _NM_CHK_MEM(bufSize, uCount);
1742 
1743  // safe copy
1744  memmove(bufDst, buf, uCount);
1745 
1746  return (int)uCount;
1747 }
int nmUnpackU64(byte_t buf[], size_t bufSize, ulonglong_t *pVal, NMEndian_T eEndian)
Unpack an unsigned 64-bit integer from the message buffer.
Definition: nmLibPack.c:1320
int nmUnpackU8(byte_t buf[], size_t bufSize, byte_t *pVal, NMEndian_T eEndian)
Unpack an unsigned 8-bit byte from the message buffer.
Definition: nmLibPack.c:1239
int nmUnpackF32(byte_t buf[], size_t bufSize, float *pVal, NMEndian_T eEndian)
Unpack a 32-bit float from the message buffer.
Definition: nmLibPack.c:1472
#define NMFVAL_LEN_U64
unsigned 64-bit field value length
Definition: netmsgs.h:179
static bool_t ieee754_f32_is_zero(union ieee754_float f)
Test if 32-bit floating-point number is &plusmn; 0.0.
Definition: nmLibPack.c:675
#define UNPACKNATIVE(buf, pval)
Unpack an element from the message buffer in native byte order.
Definition: nmLibPack.c:226
#define IEEE754_F32_F64_MANTISSA1_SHIFT
lsb mantissa shift
Definition: nmLibPack.c:544
int nmUnpackU32(byte_t buf[], size_t bufSize, uint_t *pVal, NMEndian_T eEndian)
Unpack an unsigned 32-bit integer from the message buffer.
Definition: nmLibPack.c:1288
#define IEEE754_F64_MANTISSA0_SHIFT
f64 msb mantissa shift
Definition: nmLibPack.c:535
#define NMFVAL_LEN_S32
signed 32-bit field value length
Definition: netmsgs.h:178
static const union ieee754_double IEEE754_F64_NaN
Definition: nmLibPack.c:576
#define IEEE754_F64_SIGN_SHIFT
f64 sign shift
Definition: nmLibPack.c:531
int nmPackU8(byte_t val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
Pack an unsigned 8-bit byte into the message buffer.
Definition: nmLibPack.c:745
#define IEEE754_F32_EXP_MAX
maximum power of 2 exponent
Definition: nmLibPack.c:550
#define IEEE754_F64_MANTISSA1_MASK
f64 lsb mantissa mask
Definition: nmLibPack.c:538
static const union ieee754_double IEEE754_F64_Inf
Definition: nmLibPack.c:597
#define _NM_CHK_ARCH(val, size)
Check if host architecture supports basic element sizes.
Definition: nmLibPack.c:724
#define IEEE754_F32_EXPONENT_SHIFT
f32 exponent shift
Definition: nmLibPack.c:518
Most Significant Byte first.
Definition: netmsgs.h:102
#define NMFVAL_LEN_F64
64-bit floating-point number field val len
Definition: netmsgs.h:182
#define PACK64BIG(uMSB, uLSB, buf)
Pack two 4-btye unsigned integers into the message buffer in big-endian byte order.
Definition: nmLibPack.c:436
#define IEEE754_F64_MANTISSA0_MASK
f64 msb mantissa mask
Definition: nmLibPack.c:536
int nmPackU32(uint_t val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
Pack an unsigned 32-bit integer into the message buffer.
Definition: nmLibPack.c:791
native processor order
Definition: netmsgs.h:104
#define UNPACK64NATIVE(buf, puMSB, puLSB)
Unpack two 4-byte unsigned integers from the message buffer in native byte order. ...
Definition: nmLibPack.c:250
#define PACKBIG(val, buf)
Pack an element into the message buffer in big-endian byte order.
Definition: nmLibPack.c:397
static void unpackbig(byte_t buf[], byte_t *p, size_t size)
Unpack an element from the message buffer in big-endian byte order.
Definition: nmLibPack.c:155
#define PACKLITTLE(val, buf)
Pack an element into the message buffer in little-endian byte order.
Definition: nmLibPack.c:413
#define IEEE754_F64_EXPONENT_MASK
f64 exponent mask
Definition: nmLibPack.c:534
#define NMLIB_WARNING(fmt,...)
Log libnetmsgs warning.
Definition: nmLibInternal.h:80
int nmUnpackP32(byte_t buf[], size_t bufSize, void *pVal, NMEndian_T eEndian)
Unpack a 32-bit pointer from the message buffer.
Definition: nmLibPack.c:1648
static void unpacklittle(byte_t buf[], byte_t *p, size_t size)
Unpack an element from the message buffer in little-endian byte order.
Definition: nmLibPack.c:196
int nmUnpackP64(byte_t buf[], size_t bufSize, void *pVal, NMEndian_T eEndian)
Unpack a 64-bit pointer from the message buffer.
Definition: nmLibPack.c:1678
#define NMFVAL_LEN_F32
32-bit floating-point number field val len
Definition: netmsgs.h:181
#define IEEE754_F32_SIGN_MASK
f32 sign mask
Definition: nmLibPack.c:517
#define PACKNATIVE(val, buf)
Pack an element into the message buffer in native byte order.
Definition: nmLibPack.c:216
#define IEEE754_F64_EXPONENT_SHIFT
f64 exponent shift
Definition: nmLibPack.c:533
#define PACK64LITTLE(uMSB, uLSB, buf)
Pack two 4-btye unsigned integers into the message buffer in little-endian byte order.
Definition: nmLibPack.c:477
static void packlittle(byte_t *p, size_t size, byte_t buf[])
Pack an element into the message buffer in little-endian byte order.
Definition: nmLibPack.c:175
static bool_t ieee754_f64_is_inf(union ieee754_double d)
Test if 64-bit floating-point number is &plusmn; infinity.
Definition: nmLibPack.c:664
#define IEEE754_F32_EXPONENT_MASK
f32 exponent mask
Definition: nmLibPack.c:519
static bool_t ieee754_f32_is_nan(union ieee754_float f)
Test if 32-bit floating-point number is a NaN.
Definition: nmLibPack.c:631
static const union ieee754_float IEEE754_F32_NaN
Definition: nmLibPack.c:566
int nmPackF32(float val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
Pack a 32-bit float into the message buffer.
Definition: nmLibPack.c:957
int nmPackP64(void *val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
Pack a 64-bit pointer into the message buffer.
Definition: nmLibPack.c:1160
#define IEEE754_F32_F64_MANTISSA1_MASK
lsb mantissa mask
Definition: nmLibPack.c:545
int nmPackS64(long long val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
Pack an signed 64-bit integer into the message buffer.
Definition: nmLibPack.c:885
#define NMFVAL_LEN_P32
32-bit pointer field value length
Definition: netmsgs.h:183
#define UNPACK64BIG(buf, puMSB, puLSB)
Unpack two 4-byte unsigned integers from the message buffer in big-endian byte order.
Definition: nmLibPack.c:457
#define IEEE754_F32_SIGN_SHIFT
f32 sign shift
Definition: nmLibPack.c:516
int nmPackP32(void *val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
Pack a 32-bit pointer into the message buffer.
Definition: nmLibPack.c:1113
#define NMFVAL_LEN_U16
unsigned 16-bit field value length
Definition: netmsgs.h:175
NMEndian_T
Definition: netmsgs.h:100
#define UNPACK64LITTLE(buf, puMSB, puLSB)
Unpack two 4-byte unsigned integers from the message buffer in little-endian byte order...
Definition: nmLibPack.c:498
int nmPackBuf(byte_t bufSrc[], size_t uCount, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
Pack a byte buffer into the message buffer.
Definition: nmLibPack.c:1215
static const union ieee754_double IEEE754_F64_Zero
Definition: nmLibPack.c:618
#define PACK64NATIVE(uMSB, uLSB, buf)
Pack two 4-btye unsigned integers into the message buffer in native byte order.
Definition: nmLibPack.c:238
#define NMFVAL_LEN_U32
unsigned 32-bit field value length
Definition: netmsgs.h:177
static bool_t ieee754_f32_is_inf(union ieee754_float f)
Test if 32-bit floating-point number is &plusmn; infinity.
Definition: nmLibPack.c:653
#define UNPACKBIG(buf, pval)
Unpack an element from the message buffer in big-endian byte order.
Definition: nmLibPack.c:405
#define IEEE754_F32_MANTISSA_MASK
f32 mantissa mask
Definition: nmLibPack.c:521
#define UNPACKLITTLE(buf, pval)
Unpack an element from the message buffer in little-endian byte order.
Definition: nmLibPack.c:421
Least Significant Byte first.
Definition: netmsgs.h:103
#define NMFVAL_LEN_P64
64-bit pointer field value length
Definition: netmsgs.h:184
int nmUnpackBuf(byte_t buf[], size_t bufSize, byte_t bufDst[], size_t uCount, NMEndian_T eEndian)
Unpack a byte buffer from the message buffer.
Definition: nmLibPack.c:1735
int nmUnpackU16(byte_t buf[], size_t bufSize, ushort_t *pVal, NMEndian_T eEndian)
Unpack an unsigned 16-bit integer from the message buffer.
Definition: nmLibPack.c:1256
#define IEEE754_F32_MANTISSA_SHIFT
f32 mantissa shift
Definition: nmLibPack.c:520
Internal intra-library declarations.
int nmUnpackF64(byte_t buf[], size_t bufSize, double *pVal, NMEndian_T eEndian)
Unpack a 64-bit float from the message buffer.
Definition: nmLibPack.c:1517
int nmUnpackS64(byte_t buf[], size_t bufSize, long long *pVal, NMEndian_T eEndian)
Unpack an signed 64-bit integer from the message buffer.
Definition: nmLibPack.c:1391
static bool_t ieee754_f64_is_zero(union ieee754_double d)
Test if 64-bit floating-point number is &plusmn; 0.0.
Definition: nmLibPack.c:686
#define IEEE754_F64_MANTISSA1_SHIFT
f64 lsb mantissa shift
Definition: nmLibPack.c:537
#define NMFVAL_LEN_U8
unsigned 8-bit field value length
Definition: netmsgs.h:172
#define _NM_CHK_MEM(size, count)
Check if memory is available.
Definition: nmLibPack.c:705
int nmPackU64(ulonglong_t val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
Pack an unsigned 64-bit integer into the message buffer.
Definition: nmLibPack.c:823
Network Messaging declarations.
#define NMFVAL_LEN_S64
signed 64-bit field value length
Definition: netmsgs.h:180
int nmPackU16(ushort_t val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
Pack an unsigned 16-bit integer into the message buffer.
Definition: nmLibPack.c:762
#define IEEE754_F64_SIGN_MASK
f64 sign mask
Definition: nmLibPack.c:532
static const union ieee754_float IEEE754_F32_Inf
Definition: nmLibPack.c:587
int nmPackF64(double val, byte_t buf[], size_t bufSize, NMEndian_T eEndian)
Pack a 64-bit float into the message buffer.
Definition: nmLibPack.c:1013
static bool_t ieee754_f64_is_nan(union ieee754_double d)
Test if 64-bit floating-point number is a NaN.
Definition: nmLibPack.c:642
static const union ieee754_float IEEE754_F32_Zero
Definition: nmLibPack.c:608
static void packbig(byte_t *p, size_t size, byte_t buf[])
Pack an element into the message buffer in big-endian byte order.
Definition: nmLibPack.c:135
#define IEEE754_F32_F64_MANTISSA0_SHIFT
msb mantissa shift
Definition: nmLibPack.c:543
#define IEEE754_F32_EXP_MIN
minimum power of 2 exponent
Definition: nmLibPack.c:551