233ee8add41097e19f2e20f899a50d140bc895fa
[feisty_meow.git] / nucleus / library / structures / object_packers.cpp
1 /*****************************************************************************\
2 *                                                                             *
3 *  Name   : object_packers                                                    *
4 *  Author : Chris Koeritz                                                     *
5 *                                                                             *
6 *******************************************************************************
7 * Copyright (c) 1995-$now By Author.  This program is free software; you can  *
8 * redistribute it and/or modify it under the terms of the GNU General Public  *
9 * License as published by the Free Software Foundation; either version 2 of   *
10 * the License or (at your option) any later version.  This is online at:      *
11 *     http://www.fsf.org/copyleft/gpl.html                                    *
12 * Please send any updates to: fred@gruntose.com                               *
13 \*****************************************************************************/
14
15 #include "object_packers.h"
16
17 #include <math.h>
18
19 using namespace basis;
20
21 namespace structures {
22
23 // rotate_in and snag_out do most of the real "work", if any.
24
25 void rotate_in(byte_array &attach_into, int to_attach, int size_in_bytes)
26 {
27   basis::un_int temp = basis::un_int(to_attach);
28   for (int i = 0; i < size_in_bytes; i++) {
29     attach_into += abyte(temp % 0x100);
30     temp >>= 8;
31   }
32 }
33
34 void snag_out(byte_array &eat_from, basis::un_int &accumulator, int size_in_bytes)
35 {
36   accumulator = 0;
37   for (int i = 0; i < size_in_bytes; i++) {
38     accumulator <<= 8;
39     accumulator += eat_from[size_in_bytes - i - 1];
40   }
41   eat_from.zap(0, size_in_bytes - 1);
42 }
43
44 //////////////
45
46 int packed_size(const byte_array &packed_form)
47 { return 2 * sizeof(int) + packed_form.length(); }
48
49 void attach(byte_array &packed_form, const byte_array &to_attach)
50 {
51   obscure_attach(packed_form, to_attach.length());
52   packed_form += to_attach;
53 }
54
55 bool detach(byte_array &packed_form, byte_array &to_detach)
56 {
57   un_int len = 0;
58   if (!obscure_detach(packed_form, len)) return false;
59   if (packed_form.length() < (int)len) return false;
60   to_detach = packed_form.subarray(0, len - 1);
61   packed_form.zap(0, len - 1);
62   return true;
63 }
64
65 //////////////
66
67 // these are the only "real" attach/detach functions on number types.  the
68 // others are all faking it by calling these.
69
70 void attach(byte_array &packed_form, basis::un_int to_attach)
71 { rotate_in(packed_form, to_attach, 4); }
72
73 bool detach(byte_array &packed_form, basis::un_int &to_detach)
74 {
75   if (packed_form.length() < 4) return false;
76   basis::un_int temp;
77   snag_out(packed_form, temp, 4);
78   to_detach = basis::un_int(temp);
79   return true;
80 }
81
82 void attach(byte_array &packed_form, basis::un_short to_attach)
83 { rotate_in(packed_form, to_attach, 2); }
84
85 bool detach(byte_array &packed_form, basis::un_short &to_detach)
86 {
87   if (packed_form.length() < 2) return false;
88   basis::un_int temp;
89   snag_out(packed_form, temp, 2);
90   to_detach = basis::un_short(temp);
91   return true;
92 }
93
94 void attach(byte_array &packed_form, abyte to_attach)
95 { packed_form += to_attach; }
96
97 bool detach(byte_array &packed_form, abyte &to_detach)
98 {
99   if (packed_form.length() < 1) return false;
100   to_detach = packed_form[0];
101   packed_form.zap(0, 0);
102   return true;
103 }
104
105 //////////////
106
107 void attach(byte_array &packed_form, int to_attach)
108 { attach(packed_form, basis::un_int(to_attach)); }
109
110 bool detach(byte_array &packed_form, int &to_detach)
111 { return detach(packed_form, (basis::un_int &)to_detach); }
112
113 //void attach(byte_array &packed_form, basis::un_long to_attach)
114 //{ attach(packed_form, basis::un_int(to_attach)); }
115
116 //bool detach(byte_array &packed_form, basis::un_long &to_detach)
117 //{ return detach(packed_form, (basis::un_int &)to_detach); }
118
119 //void attach(byte_array &packed_form, long to_attach)
120 //{ attach(packed_form, basis::un_int(to_attach)); }
121
122 //bool detach(byte_array &packed_form, long &to_detach)
123 //{ return detach(packed_form, (basis::un_int &)to_detach); }
124
125 void attach(byte_array &packed_form, short to_attach)
126 { attach(packed_form, basis::un_short(to_attach)); }
127
128 bool detach(byte_array &packed_form, short &to_detach)
129 { return detach(packed_form, (basis::un_short &)to_detach); }
130
131 void attach(byte_array &packed_form, char to_attach)
132 { attach(packed_form, abyte(to_attach)); }
133
134 bool detach(byte_array &packed_form, char &to_detach)
135 { return detach(packed_form, (abyte &)to_detach); }
136
137 void attach(byte_array &packed_form, bool to_attach)
138 { attach(packed_form, abyte(to_attach)); }
139
140 //////////////
141
142 // can't assume that bool is same size as byte, although it should fit
143 // into a byte just fine.
144 bool detach(byte_array &packed_form, bool &to_detach)
145 {
146   abyte chomp;
147   if (!detach(packed_form, chomp)) return false;
148   to_detach = !!chomp;
149   return true;
150 }
151
152 // operates on a number less than 1.0 that we need to snag the next digit
153 // to the right of the decimal point from.
154 double break_off_digit(double &input) {
155 //printf(astring(astring::SPRINTF, "break input=%f\n", input).s());
156   input *= 10.0;
157 //printf(astring(astring::SPRINTF, "after mult=%f\n", input).s());
158   double mod_part = fmod(input, 1.0);
159 //printf(astring(astring::SPRINTF, "modded=%f\n", mod_part).s());
160   double to_return = input - mod_part;
161 //printf(astring(astring::SPRINTF, "to ret=%f\n", to_return).s());
162   input -= to_return;
163   return to_return;
164 }
165
166 //hmmm: not very efficient!  it's just packing and wasting bytes doing it...
167 int packed_size(double to_pack)
168 {
169   byte_array packed;
170   attach(packed, to_pack);
171   return packed.length();
172 }
173
174 void attach(byte_array &packed_form, double to_pack)
175 {
176   int exponent = 0;
177   double mantissa = frexp(to_pack, &exponent);
178   abyte pos = mantissa < 0.0? false : true;
179   mantissa = fabs(mantissa);
180 //printf("mant=%10.10f pos=%d expon=%d\n", mantissa, int(pos), exponent);
181   packed_form += pos;
182   attach(packed_form, exponent);
183   byte_array mantis;
184   // even if the double has 52 bits for mantissa (where ms docs say 44),
185   // a 16 digit bcd encoded number should handle the size (based on size of
186   // 2^52 in digits).
187   for (int i = 0; i < 9; i++) {
188     double dig1 = break_off_digit(mantissa);
189 //printf(astring(astring::SPRINTF, "break digit=%d\n", int(dig1)).s());
190     double dig2 = break_off_digit(mantissa);
191 //printf(astring(astring::SPRINTF, "break digit=%d\n", int(dig2)).s());
192     mantis += abyte(dig1 * 16 + dig2);
193   }
194   attach(packed_form, mantis);
195 //printf("attach exit\n");
196 }
197
198 bool detach(byte_array &packed_form, double &to_unpack)
199 {
200 //printf("detach entry\n");
201   if (packed_form.length() < 1) return false;  // no sign byte.
202   abyte pos = packed_form[0];
203 //printf(astring(astring::SPRINTF, "pos=%d\n", int(pos)).s());
204   packed_form.zap(0, 0);
205   int exponent;
206   if (!detach(packed_form, exponent)) return false;
207 //printf(astring(astring::SPRINTF, "expon=%d\n", exponent).s());
208   byte_array mantis;
209   if (!detach(packed_form, mantis)) return false;
210   double mantissa = 0;
211   for (int i = mantis.last(); i >= 0; i--) {
212     abyte chop = mantis[i];
213     double dig1 = chop / 16;
214 //printf(astring(astring::SPRINTF, "break digit=%d\n", int(dig1)).s());
215     double dig2 = chop % 16;
216 //printf(astring(astring::SPRINTF, "break digit=%d\n", int(dig2)).s());
217     mantissa += dig2;
218     mantissa /= 10;
219     mantissa += dig1;
220     mantissa /= 10;
221   }
222 //printf(astring(astring::SPRINTF, "mant=%10.10f\n", mantissa).s());
223   to_unpack = ldexp(mantissa, exponent);
224   if (!pos) to_unpack = -1.0 * to_unpack;
225 //printf("pos=%d\n", int(pos));
226 //printf(astring(astring::SPRINTF, "to_unpack=%f\n", to_unpack).s());
227 //printf("detach exit\n");
228   return true;
229 }
230
231 void attach(byte_array &packed_form, float to_pack)
232 { attach(packed_form, double(to_pack)); }
233
234 bool detach(byte_array &packed_form, float &to_unpack)
235 {
236   double real_unpack;
237   bool to_return = detach(packed_form, real_unpack);
238   to_unpack = (float)real_unpack;
239   return to_return;
240 }
241
242 //////////////
243
244 void obscure_attach(byte_array &packed_form, un_int to_attach)
245 {
246 //printf("initial value=%x\n", to_attach);
247   basis::un_int first_part = 0xfade0000;
248 //printf("first part curr=%x\n", first_part);
249   basis::un_int second_part = 0x0000ce0f;
250 //printf("second part curr=%x\n", second_part);
251   first_part = first_part | (to_attach & 0x0000ffff);
252 //printf("first part now=%x\n", first_part);
253   second_part = second_part | (to_attach & 0xffff0000);
254 //printf("second part now=%x\n", second_part);
255   attach(packed_form, first_part);
256   attach(packed_form, second_part);
257 }
258
259 bool obscure_detach(byte_array &packed_form, un_int &to_detach)
260 {
261   basis::un_int first_part;
262   basis::un_int second_part;
263   if (!detach(packed_form, first_part)) return false;
264   if (!detach(packed_form, second_part)) return false;
265 //printf("first part after unpack=%x\n", first_part);
266 //printf("second part after unpack=%x\n", second_part);
267   if (basis::un_int(first_part & 0xffff0000) != basis::un_int(0xfade0000)) return false;
268 //printf("first part with and=%x\n", first_part & 0xffff0000);
269   if (basis::un_int(second_part & 0x0000ffff) != basis::un_int(0x0000ce0f)) return false;
270 //printf("second part with and=%x\n", second_part & 0x0000ffff);
271   to_detach = int( (second_part & 0xffff0000) + (first_part & 0x0000ffff) );
272 //printf("final result=%x\n", to_detach);
273   return true;
274 }
275
276 //////////////
277
278 } // namespace
279