feisty meow concerns codebase 2.140
object_packers.cpp
Go to the documentation of this file.
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
19using namespace basis;
20
21namespace structures {
22
23// rotate_in and snag_out do most of the real "work", if any.
24
25void 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
34void 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
45
46int packed_size(const byte_array &packed_form)
47{ return 2 * sizeof(int) + packed_form.length(); }
48
49void 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
55bool 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
66
67// these are the only "real" attach/detach functions on number types. the
68// others are all faking it by calling these.
69
70void attach(byte_array &packed_form, basis::un_int to_attach)
71{ rotate_in(packed_form, to_attach, 4); }
72
73bool 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
82void attach(byte_array &packed_form, basis::un_short to_attach)
83{ rotate_in(packed_form, to_attach, 2); }
84
85bool 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
94void attach(byte_array &packed_form, abyte to_attach)
95{ packed_form += to_attach; }
96
97bool 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
106
107void attach(byte_array &packed_form, int to_attach)
108{ attach(packed_form, basis::un_int(to_attach)); }
109
110bool detach(byte_array &packed_form, int &to_detach)
111{ return detach(packed_form, (basis::un_int &)to_detach); }
112
113void attach(byte_array &packed_form, signed_long to_attach)
114{ attach(packed_form, basis::signed_long(to_attach)); }
115
116bool detach(byte_array &packed_form, signed_long &to_detach)
117{ return detach(packed_form, (basis::signed_long &)to_detach); }
118
119//void attach(byte_array &packed_form, basis::un_long to_attach)
120//{ attach(packed_form, basis::un_int(to_attach)); }
121
122//bool detach(byte_array &packed_form, basis::un_long &to_detach)
123//{ return detach(packed_form, (basis::un_int &)to_detach); }
124
125//void attach(byte_array &packed_form, long to_attach)
126//{ attach(packed_form, basis::un_int(to_attach)); }
127
128//bool detach(byte_array &packed_form, long &to_detach)
129//{ return detach(packed_form, (basis::un_int &)to_detach); }
130
131void attach(byte_array &packed_form, short to_attach)
132{ attach(packed_form, basis::un_short(to_attach)); }
133
134bool detach(byte_array &packed_form, short &to_detach)
135{ return detach(packed_form, (basis::un_short &)to_detach); }
136
137void attach(byte_array &packed_form, char to_attach)
138{ attach(packed_form, abyte(to_attach)); }
139
140bool detach(byte_array &packed_form, char &to_detach)
141{ return detach(packed_form, (abyte &)to_detach); }
142
143void attach(byte_array &packed_form, bool to_attach)
144{ attach(packed_form, abyte(to_attach)); }
145
147
148// can't assume that bool is same size as byte, although it should fit
149// into a byte just fine.
150bool detach(byte_array &packed_form, bool &to_detach)
151{
152 abyte chomp;
153 if (!detach(packed_form, chomp)) return false;
154 to_detach = !!chomp;
155 return true;
156}
157
158// operates on a number less than 1.0 that we need to snag the next digit
159// to the right of the decimal point from.
160double break_off_digit(double &input) {
161//printf(astring(astring::SPRINTF, "break input=%f\n", input).s());
162 input *= 10.0;
163//printf(astring(astring::SPRINTF, "after mult=%f\n", input).s());
164 double mod_part = fmod(input, 1.0);
165//printf(astring(astring::SPRINTF, "modded=%f\n", mod_part).s());
166 double to_return = input - mod_part;
167//printf(astring(astring::SPRINTF, "to ret=%f\n", to_return).s());
168 input -= to_return;
169 return to_return;
170}
171
172//hmmm: not very efficient! it's just packing and wasting bytes doing it...
173int packed_size(double to_pack)
174{
175 byte_array packed;
176 attach(packed, to_pack);
177 return packed.length();
178}
179
180void attach(byte_array &packed_form, double to_pack)
181{
182 int exponent = 0;
183 double mantissa = frexp(to_pack, &exponent);
184 abyte pos = mantissa < 0.0? false : true;
185 mantissa = fabs(mantissa);
186//printf("mant=%10.10f pos=%d expon=%d\n", mantissa, int(pos), exponent);
187 packed_form += pos;
188 attach(packed_form, exponent);
189 byte_array mantis;
190 // even if the double has 52 bits for mantissa (where ms docs say 44),
191 // a 16 digit bcd encoded number should handle the size (based on size of
192 // 2^52 in digits).
193 for (int i = 0; i < 9; i++) {
194 double dig1 = break_off_digit(mantissa);
195//printf(astring(astring::SPRINTF, "break digit=%d\n", int(dig1)).s());
196 double dig2 = break_off_digit(mantissa);
197//printf(astring(astring::SPRINTF, "break digit=%d\n", int(dig2)).s());
198 mantis += abyte(dig1 * 16 + dig2);
199 }
200 attach(packed_form, mantis);
201//printf("attach exit\n");
202}
203
204bool detach(byte_array &packed_form, double &to_unpack)
205{
206//printf("detach entry\n");
207 if (packed_form.length() < 1) return false; // no sign byte.
208 abyte pos = packed_form[0];
209//printf(astring(astring::SPRINTF, "pos=%d\n", int(pos)).s());
210 packed_form.zap(0, 0);
211 int exponent;
212 if (!detach(packed_form, exponent)) return false;
213//printf(astring(astring::SPRINTF, "expon=%d\n", exponent).s());
214 byte_array mantis;
215 if (!detach(packed_form, mantis)) return false;
216 double mantissa = 0;
217 for (int i = mantis.last(); i >= 0; i--) {
218 abyte chop = mantis[i];
219 double dig1 = chop / 16;
220//printf(astring(astring::SPRINTF, "break digit=%d\n", int(dig1)).s());
221 double dig2 = chop % 16;
222//printf(astring(astring::SPRINTF, "break digit=%d\n", int(dig2)).s());
223 mantissa += dig2;
224 mantissa /= 10;
225 mantissa += dig1;
226 mantissa /= 10;
227 }
228//printf(astring(astring::SPRINTF, "mant=%10.10f\n", mantissa).s());
229 to_unpack = ldexp(mantissa, exponent);
230 if (!pos) to_unpack = -1.0 * to_unpack;
231//printf("pos=%d\n", int(pos));
232//printf(astring(astring::SPRINTF, "to_unpack=%f\n", to_unpack).s());
233//printf("detach exit\n");
234 return true;
235}
236
237void attach(byte_array &packed_form, float to_pack)
238{ attach(packed_form, double(to_pack)); }
239
240bool detach(byte_array &packed_form, float &to_unpack)
241{
242 double real_unpack;
243 bool to_return = detach(packed_form, real_unpack);
244 to_unpack = (float)real_unpack;
245 return to_return;
246}
247
249
250void obscure_attach(byte_array &packed_form, un_int to_attach)
251{
252//printf("initial value=%x\n", to_attach);
253 basis::un_int first_part = 0xfade0000;
254//printf("first part curr=%x\n", first_part);
255 basis::un_int second_part = 0x0000ce0f;
256//printf("second part curr=%x\n", second_part);
257 first_part = first_part | (to_attach & 0x0000ffff);
258//printf("first part now=%x\n", first_part);
259 second_part = second_part | (to_attach & 0xffff0000);
260//printf("second part now=%x\n", second_part);
261 attach(packed_form, first_part);
262 attach(packed_form, second_part);
263}
264
265bool obscure_detach(byte_array &packed_form, un_int &to_detach)
266{
267 basis::un_int first_part;
268 basis::un_int second_part;
269 if (!detach(packed_form, first_part)) return false;
270 if (!detach(packed_form, second_part)) return false;
271//printf("first part after unpack=%x\n", first_part);
272//printf("second part after unpack=%x\n", second_part);
273 if (basis::un_int(first_part & 0xffff0000) != basis::un_int(0xfade0000)) return false;
274//printf("first part with and=%x\n", first_part & 0xffff0000);
275 if (basis::un_int(second_part & 0x0000ffff) != basis::un_int(0x0000ce0f)) return false;
276//printf("second part with and=%x\n", second_part & 0x0000ffff);
277 to_detach = int( (second_part & 0xffff0000) + (first_part & 0x0000ffff) );
278//printf("final result=%x\n", to_detach);
279 return true;
280}
281
283
284} // namespace
285
array subarray(int start, int end) const
Returns the array segment between the indices "start" and "end".
Definition array.h:443
int length() const
Returns the current reported length of the allocated C array.
Definition array.h:115
outcome zap(int start, int end)
Deletes from "this" the objects inclusively between "start" and "end".
Definition array.h:769
int last() const
Returns the last valid element in the array.
Definition array.h:118
A very common template for a dynamic array of bytes.
Definition byte_array.h:36
The guards collection helps in testing preconditions and reporting errors.
Definition array.h:30
unsigned char abyte
A fairly important unit which is seldom defined...
Definition definitions.h:51
long int signed_long
Abbreviated name for signed long integers.
Definition definitions.h:68
unsigned int un_int
Abbreviated name for unsigned integers.
Definition definitions.h:62
unsigned short un_short
Abbreviated name for unsigned short integers.
Definition definitions.h:64
A dynamic container class that holds any kind of object via pointers.
Definition amorph.h:55
void snag_out(byte_array &eat_from, basis::un_int &accumulator, int size_in_bytes)
bool obscure_detach(byte_array &packed_form, un_int &to_detach)
shifts the number back and checks validity, false returned if corrupted.
void obscure_attach(byte_array &packed_form, un_int to_attach)
like the normal attach but shifts in some recognizable sentinel data.
void attach(byte_array &packed_form, const byte_array &to_attach)
Packs a byte_array "to_attach" into "packed_form".
bool detach(byte_array &packed_form, byte_array &to_detach)
Unpacks a byte_array "to_detach" from "packed_form".
double break_off_digit(double &input)
int packed_size(const byte_array &packed_form)
Reports the size required to pack a byte array into a byte array.
void rotate_in(byte_array &attach_into, int to_attach, int size_in_bytes)