1 #ifndef OBJECT_PACKERS_CLASS
2 #define OBJECT_PACKERS_CLASS
4 /*****************************************************************************\
6 * Name : object_packers *
7 * Author : Chris Koeritz *
9 *******************************************************************************
10 * Copyright (c) 1995-$now By Author. This program is free software; you can *
11 * redistribute it and/or modify it under the terms of the GNU General Public *
12 * License as published by the Free Software Foundation; either version 2 of *
13 * the License or (at your option) any later version. This is online at: *
14 * http://www.fsf.org/copyleft/gpl.html *
15 * Please send any updates to: fred@gruntose.com *
16 \*****************************************************************************/
18 #include <basis/byte_array.h>
19 #include <basis/definitions.h>
21 namespace structures {
23 // the sizes in bytes of common objects. if the compiler doesn't match these, there will
24 // probably be severe tire damage.
25 const int PACKED_SIZE_BYTE = 1;
26 const int PACKED_SIZE_INT16 = 2;
27 const int PACKED_SIZE_INT32 = 4;
29 // these functions pack and unpack popular data types.
31 void attach(basis::byte_array &packed_form, bool to_attach);
32 //!< Packs a bool "to_attach" into "packed_form".
33 bool detach(basis::byte_array &packed_form, bool &to_detach);
34 //!< Unpacks a bool "to_detach" from "packed_form".
36 void attach(basis::byte_array &packed_form, basis::abyte to_attach);
37 //!< Packs a byte "to_attach" into "packed_form".
38 bool detach(basis::byte_array &packed_form, basis::abyte &to_detach);
39 //!< Unpacks a byte "to_detach" from "packed_form".
41 int packed_size(const basis::byte_array &packed_form);
42 //!< Reports the size required to pack a byte array into a byte array.
43 void attach(basis::byte_array &packed_form, const basis::byte_array &to_attach);
44 //!< Packs a byte_array "to_attach" into "packed_form".
45 bool detach(basis::byte_array &packed_form, basis::byte_array &to_detach);
46 //!< Unpacks a byte_array "to_detach" from "packed_form".
48 void attach(basis::byte_array &packed_form, char to_attach);
49 //!< Packs a char "to_attach" into "packed_form".
50 bool detach(basis::byte_array &packed_form, char &to_detach);
51 //!< Unpacks a char "to_detach" from "packed_form".
53 int packed_size(double to_pack);
54 //!< Reports how large the "to_pack" will be as a stream of bytes.
55 void attach(basis::byte_array &packed_form, double to_pack);
56 //!< Packs a double precision floating point "to_attach" into "packed_form".
57 bool detach(basis::byte_array &packed_form, double &to_unpack);
58 //!< Unpacks a double precision floating point "to_attach" from "packed_form".
60 void attach(basis::byte_array &packed_form, float to_pack);
61 //!< Packs a floating point "to_attach" into "packed_form".
62 bool detach(basis::byte_array &packed_form, float &to_unpack);
63 //!< Unpacks a floating point "to_attach" from "packed_form".
65 void attach(basis::byte_array &packed_form, int to_attach);
66 //!< Packs an integer "to_attach" into "packed_form".
67 /*!< This method and the other simple numerical storage methods use a little
68 endian ordering of the bytes. They are platform independent with respect to
69 endianness and will reassemble the number properly on any platform. */
70 bool detach(basis::byte_array &packed_form, int &to_detach);
71 //!< Unpacks an integer "to_attach" from "packed_form".
73 void obscure_attach(basis::byte_array &packed_form, basis::un_int to_attach);
74 //!< like the normal attach but shifts in some recognizable sentinel data.
75 /*!< this is slightly more sure than a simple integer attachment. it can
76 be used to make sure upcoming data is probably a valid int. */
77 bool obscure_detach(basis::byte_array &packed_form, basis::un_int &to_detach);
78 //!< shifts the number back and checks validity, false returned if corrupted.
81 void attach(basis::byte_array &packed_form, long to_attach);
82 //!< Packs a long integer "to_attach" into "packed_form".
83 bool detach(basis::byte_array &packed_form, long &to_detach);
84 //!< Unpacks a long integer "to_attach" from "packed_form".
87 void attach(basis::byte_array &packed_form, short to_attach);
88 //!< Packs a short integer "to_attach" into "packed_form".
89 bool detach(basis::byte_array &packed_form, short &to_detach);
90 //!< Unpacks a short integer "to_attach" from "packed_form".
92 void attach(basis::byte_array &packed_form, basis::un_int to_attach);
93 //!< Packs an unsigned integer "to_attach" into "packed_form".
94 bool detach(basis::byte_array &packed_form, basis::un_int &to_detach);
95 //!< Unpacks an unsigned integer "to_attach" from "packed_form".
98 void attach(basis::byte_array &packed_form, basis::un_long to_attach);
99 //!< Packs an unsigned long integer "to_attach" into "packed_form".
100 bool detach(basis::byte_array &packed_form, basis::un_long &to_detach);
101 //!< Unpacks an unsigned long integer "to_attach" from "packed_form".
104 void attach(basis::byte_array &packed_form, basis::un_short to_attach);
105 //!< Packs an unsigned short integer "to_attach" into "packed_form".
106 bool detach(basis::byte_array &packed_form, basis::un_short &to_detach);
107 //!< Unpacks an unsigned short integer "to_attach" from "packed_form".
111 // helpful template functions for packing.
113 //! provides a way to pack any array that stores packable objects.
114 template <class contents>
115 void pack_array(basis::byte_array &packed_form, const basis::array<contents> &to_pack) {
116 obscure_attach(packed_form, to_pack.length());
117 for (int i = 0; i < to_pack.length(); i++) to_pack[i].pack(packed_form);
120 //! provides a way to unpack any array that stores packable objects.
121 template <class contents>
122 bool unpack_array(basis::byte_array &packed_form, basis::array<contents> &to_unpack) {
125 if (!obscure_detach(packed_form, len)) return false;
126 basis::array<contents> swappy_array(len, NULL_POINTER, to_unpack.flags());
127 // we create an array of the specified length to see if it's tenable.
128 if (!swappy_array.observe()) return false; // failed to allocate.
129 for (int i = 0; i < (int)len; i++) {
130 if (!swappy_array[i].unpack(packed_form))
133 // now that we've got exactly what we want, plunk it into the result array.
134 swappy_array.swap_contents(to_unpack);
138 //! provides space estimation for the objects to be packed.
139 template <class contents>
140 int packed_size_array(const basis::array<contents> &to_pack) {
141 int to_return = sizeof(int) * 2; // obscure version uses double int size.
142 for (int i = 0; i < to_pack.length(); i++)
143 to_return += to_pack[i].packed_size();
147 //! Packs flat objects into an array of bytes.
148 /*! Similar to pack above, but operates on arrays with simple
149 objects that do not support functional pack and unpack. */
150 template <class contents>
151 void pack_simple(basis::byte_array &packed_form, const basis::array<contents> &to_pack) {
152 obscure_attach(packed_form, to_pack.length());
153 for (int i = 0; i < to_pack.length(); i++)
154 attach(packed_form, to_pack[i]);
157 //! Unpacks flat objects from an array of bytes.
158 /*! Similar to unpack above, but operates on arrays with simple
159 objects that do not support functional pack and unpack. */
160 template <class contents>
161 bool unpack_simple(basis::byte_array &packed_form, basis::array<contents> &to_unpack) {
164 if (!obscure_detach(packed_form, len)) return false;
165 basis::array<contents> swappy_array(len, NULL_POINTER, to_unpack.flags());
166 if (!swappy_array.observe()) return false; // failed to allocate.
167 for (int i = 0; i < len; i++) {
168 if (!detach(packed_form, swappy_array[i]))
171 swappy_array.swap_contents(to_unpack);