1 : /*****************************************************************************
2 : * memendian.c
3 : *
4 : * DESCRIPTION
5 : * This file contains all the utility functions that the Driver uses to
6 : * solve endian'ness related issues.
7 : *
8 : * HISTORY
9 : * 9/2002 Arthur Taylor (MDL / RSIS): Created.
10 : * 12/2002 Rici Yu, Fangyu Chi, Mark Armstrong, & Tim Boyer
11 : * (RY,FC,MA,&TB): Code Review 2.
12 : *
13 : * NOTES
14 : *****************************************************************************
15 : */
16 : #include <stdio.h>
17 : #include <string.h>
18 : #include "memendian.h"
19 :
20 : /*****************************************************************************
21 : * memswp() -- Review 12/2002
22 : *
23 : * Arthur Taylor / MDL
24 : *
25 : * PURPOSE
26 : * To swap memory in the Data array based on the knownledge that there are
27 : * "num_elem" elements, each of size "elem_size".
28 : *
29 : * ARGUMENTS
30 : * Data = A pointer to the data to be swapped. (Input/Output)
31 : * elem_size = The size of an individual element. (Input)
32 : * num_elem = The number of elements to swap. (Input)
33 : *
34 : * FILES/DATABASES: None
35 : *
36 : * RETURNS: void
37 : *
38 : * HISTORY
39 : * 9/2002 Arthur Taylor (MDL/RSIS): Created.
40 : * 12/2002 (RY,FC,MA,&TB): Code Review.
41 : *
42 : * NOTES
43 : * 1) A similar routine was provided with the GRIB2 library. It was called:
44 : * "unpk_swap". Since it had the restriction that it only dealt with long
45 : * ints, I felt that I needed more flexibility. In addition this procedure
46 : * may be more efficient. I did an operation count for swapping an array
47 : * that consisted of 1 4 byte int.
48 : * "unpk_swap" = 46 operations, "memswp" = 33.
49 : * 2) Could try this with exclusive or?
50 : *****************************************************************************
51 : */
52 6 : void memswp (void *Data, const size_t elem_size, const size_t num_elem)
53 : {
54 : size_t j; /* Element count */
55 : char *data; /* Allows us to treat Data as an array of char. */
56 : char temp; /* A temporary holder of a byte when swapping. */
57 : char *ptr, *ptr2; /* Pointers to the two bytes to swap. */
58 :
59 6 : if (elem_size == 1) {
60 0 : return;
61 : }
62 6 : data = (char *) Data;
63 137004 : for (j = 0; j < elem_size * num_elem; j += elem_size) {
64 136998 : ptr = data + j;
65 136998 : ptr2 = ptr + elem_size - 1;
66 547992 : while (ptr2 > ptr) {
67 273996 : temp = *ptr;
68 273996 : *(ptr++) = *ptr2;
69 273996 : *(ptr2--) = temp;
70 : }
71 : }
72 : }
73 :
74 : /*****************************************************************************
75 : * revmemcpy() -- Review 12/2002
76 : *
77 : * Arthur Taylor / MDL
78 : *
79 : * PURPOSE
80 : * To copy memory similar to memcpy, but in a reverse manner. In order to
81 : * have the same arguments as memcpy, this can not handle arrays... For
82 : * arrays use revmemcpyRay(). Returns the same thing that memcpy does.
83 : *
84 : * ARGUMENTS
85 : * Dst = The destination for the data. (Output)
86 : * Src = The source of the data. (Input)
87 : * len = The length of Src in bytes. (Input)
88 : *
89 : * FILES/DATABASES: None
90 : *
91 : * RETURNS: void *
92 : *
93 : * HISTORY
94 : * 9/2002 Arthur Taylor (MDL/RSIS): Created.
95 : * 12/2002 (RY,FC,MA,&TB): Code Review.
96 : *
97 : * NOTES
98 : * 1) This came about as I was trying to improve on the use of memcpy. I
99 : * figured that revmemcpy would be faster than memcpy followed by memswp.
100 : * 2) Assumes that Dst is allocated to a size of Src.
101 : * 3) Problems with MEMCPY if len != sizeof (dst)... Is it left or right
102 : * justified?
103 : *****************************************************************************
104 : */
105 63 : void *revmemcpy (void *Dst, void *Src, const size_t len)
106 : {
107 : size_t j; /* Byte count */
108 63 : char *src = (char *) Src; /* Allows us to treat Src as an array of char. */
109 63 : char *dst = (char *) Dst; /* Allows us to treat Dst as an array of char. */
110 :
111 63 : src = src + len - 1;
112 291 : for (j = 0; j < len; ++j) {
113 228 : *(dst++) = *(src--);
114 : }
115 63 : return Dst;
116 : }
117 :
118 : /*****************************************************************************
119 : * revmemcpyRay() -- Review 12/2002
120 : *
121 : * Arthur Taylor / MDL
122 : *
123 : * PURPOSE
124 : * To copy memory similar to memcpy, but in a reverse manner. This handles
125 : * the case when we need to reverse memcpy an array of data.
126 : *
127 : * ARGUMENTS
128 : * Dst = The destination for the data. (Output)
129 : * Src = The source of the data. (Input)
130 : * elem_size = The size of a single element. (Input)
131 : * num_elem = The number of elements in Src. (Input)
132 : *
133 : * FILES/DATABASES: None
134 : *
135 : * RETURNS: void *
136 : *
137 : * HISTORY
138 : * 9/2002 Arthur Taylor (MDL/RSIS): Created.
139 : * 12/2002 (RY,FC,MA,&TB): Code Review.
140 : *
141 : * NOTES
142 : * 1) Assumes that Dst is allocated to a size of Src.
143 : *****************************************************************************
144 : */
145 0 : void *revmemcpyRay (void *Dst, void *Src, const size_t elem_size,
146 : const size_t num_elem)
147 : {
148 : size_t i; /* Element count. */
149 : size_t j; /* Byte count. */
150 0 : char *src = (char *) Src; /* Allows us to treat Src as an array of char. */
151 0 : char *dst = (char *) Dst; /* Allows us to treat Dst as an array of char. */
152 :
153 0 : if (elem_size == 1) {
154 0 : return memcpy (Dst, Src, num_elem);
155 : }
156 0 : src -= (elem_size + 1);
157 0 : for (i = 0; i < num_elem; ++i) {
158 0 : src += 2 * elem_size;
159 0 : for (j = 0; j < elem_size; ++j) {
160 0 : *(dst++) = *(src--);
161 : }
162 : }
163 0 : return Dst;
164 : }
165 :
166 : /*****************************************************************************
167 : * memBitRead() --
168 : *
169 : * Arthur Taylor / MDL
170 : *
171 : * PURPOSE
172 : * To read bits from an uChar buffer array of memory. Assumes BufLoc is
173 : * valid before first call. Typically this means do a "bufLoc = 8;" before
174 : * the first call.
175 : *
176 : * ARGUMENTS
177 : * Dst = Where to put the results. (Output)
178 : * dstLen = Length in bytes of Dst. (Input)
179 : * Src = The data to read the bits from. (Input)
180 : * numBits = How many bits to read. (Input)
181 : * BufLoc = Which bit to start reading from in Src.
182 : * Starts at 8 goes to 1. (Input/Output)
183 : * numUsed = How many bytes from Src were used while reading (Output)
184 : *
185 : * FILES/DATABASES: None
186 : *
187 : * RETURNS:
188 : * Returns 1 on error, 0 if ok.
189 : *
190 : * HISTORY
191 : * 4/2003 Arthur Taylor (MDL/RSIS): Created
192 : * 5/2004 AAT: Bug in call to MEMCPY_BIG when numBytes != dstLen.
193 : * On big endian machines we need to right justify the number.
194 : *
195 : * NOTES
196 : * 1) Assumes binary bit stream is "big endian". Resulting in no byte
197 : * boundaries ie 00100110101101 => 001001 | 10101101
198 : *****************************************************************************
199 : */
200 10848 : char memBitRead (void *Dst, size_t dstLen, void *Src, size_t numBits,
201 : uChar * bufLoc, size_t * numUsed)
202 : {
203 10848 : uChar *src = (uChar *) Src; /* Allows us to treat Src as an array of
204 : * char. */
205 10848 : uChar *dst = (uChar *) Dst; /* Allows us to treat Dst as an array of
206 : * char. */
207 : size_t numBytes; /* How many bytes are needed in dst. */
208 : uChar dstLoc; /* Where we are writing to in dst. */
209 : uChar *ptr; /* Current byte we are writing to in dst. */
210 : static uChar BitMask[] = {
211 : 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
212 : };
213 :
214 10848 : if (numBits == 0) {
215 0 : memset (Dst, 0, dstLen);
216 0 : (*numUsed) = 0;
217 0 : return 0;
218 : }
219 10848 : numBytes = ((numBits - 1) / 8) + 1;
220 10848 : if (dstLen < numBytes) {
221 0 : return 1;
222 : }
223 10848 : memset (Dst, 0, dstLen);
224 10848 : dstLoc = ((numBits - 1) % 8) + 1;
225 10848 : if ((*bufLoc == 8) && (dstLoc == 8)) {
226 : #ifdef LITTLE_ENDIAN
227 0 : MEMCPY_BIG (Dst, Src, numBytes);
228 : #else
229 : /* If numBytes != dstLen, then we need to right justify the ans */
230 : MEMCPY_BIG (dst + (dstLen - numBytes), Src, numBytes);
231 : #endif
232 0 : (*numUsed) = numBytes;
233 0 : return 0;
234 : }
235 : #ifdef LITTLE_ENDIAN
236 10848 : ptr = dst + (numBytes - 1);
237 : #else
238 : ptr = dst + (dstLen - numBytes);
239 : #endif
240 :
241 10848 : *numUsed = 0;
242 : /* Deal with most significant byte in dst. */
243 10848 : if (*bufLoc >= dstLoc) {
244 : #ifdef LITTLE_ENDIAN
245 8106 : (*ptr--) |= ((*src & BitMask[*bufLoc]) >> (*bufLoc - dstLoc));
246 : #else
247 : (*ptr++) |= ((*src & BitMask[*bufLoc]) >> (*bufLoc - dstLoc));
248 : #endif
249 8106 : (*bufLoc) -= dstLoc;
250 : } else {
251 2742 : if (*bufLoc != 0) {
252 2742 : *ptr |= ((*src & BitMask[*bufLoc]) << (dstLoc - *bufLoc));
253 : /* Assert: dstLoc should now be dstLoc - InitBufLoc */
254 2742 : dstLoc = dstLoc - *bufLoc;
255 : /* Assert: bufLoc should now be 0 */
256 : }
257 2742 : src++;
258 2742 : (*numUsed)++;
259 : /* Assert: bufLoc should now be 8 */
260 : /* Assert: We want to >> by bufLoc - dstLoc = 8 - dstLoc */
261 : #ifdef LITTLE_ENDIAN
262 2742 : *(ptr--) |= (*src >> (8 - dstLoc));
263 : #else
264 : *(ptr++) |= (*src >> (8 - dstLoc));
265 : #endif
266 2742 : (*bufLoc) = 8 - dstLoc;
267 : }
268 : /* Assert: dstLoc should now be 8, but we don't use again in procedure. */
269 :
270 : /* We have now reached the state which we want after each iteration of
271 : * the loop. That is initDstLoc == 8, initBufLoc = bufLoc < dstLoc. */
272 : #ifdef LITTLE_ENDIAN
273 32544 : while (ptr >= dst) {
274 : #else
275 : while (ptr < dst + dstLen) {
276 : #endif
277 10848 : if (*bufLoc != 0) {
278 9219 : *ptr |= ((*src & BitMask[*bufLoc]) << (8 - *bufLoc));
279 : /* Assert: dstLoc should now be initDstLoc (8) - initBufLoc */
280 : /* Assert: bufLoc should now be 0 */
281 : }
282 10848 : src++;
283 10848 : (*numUsed)++;
284 : /* Assert: bufLoc should now be 8 */
285 : /* Assert: dstLoc should now be initDstLoc (8) - initBufLoc */
286 : /* Assert: We want to >> by bufLoc - dstLoc = (8 - (8 - initbufLoc)). */
287 : #ifdef LITTLE_ENDIAN
288 10848 : *(ptr--) |= (*src >> *bufLoc);
289 : #else
290 : *(ptr++) |= (*src >> *bufLoc);
291 : #endif
292 : }
293 10848 : if (*bufLoc == 0) {
294 1629 : (*numUsed)++;
295 1629 : *bufLoc = 8;
296 : }
297 10848 : return 0;
298 : }
299 :
300 : /*****************************************************************************
301 : * memBitWrite() --
302 : *
303 : * Arthur Taylor / MDL
304 : *
305 : * PURPOSE
306 : * To write bits from a data structure to an array of uChar.
307 : * Assumes that the part of Dst we don't write to have been correctly
308 : * initialized. Typically this means do a "memset (dst, 0, sizeof (dst));"
309 : * before the first call.
310 : * Also assumes BufLoc is valid before first call. Typically this means do
311 : * a "bufLoc = 8;" before the first call.
312 : *
313 : * ARGUMENTS
314 : * Src = The data to read from. (Input)
315 : * srcLen = Length in bytes of Src. (Input)
316 : * Dst = The char buffer to write the bits to. (Output)
317 : * numBits = How many bits to write. (Input)
318 : * BufLoc = Which bit in Dst to start writing to.
319 : * Starts at 8 goes to 1. (Input/Output)
320 : * numUsed = How many bytes were written to Dst. (Output)
321 : *
322 : * FILES/DATABASES: None
323 : *
324 : * RETURNS:
325 : * Returns 1 on error, 0 if ok.
326 : *
327 : * HISTORY
328 : * 4/2003 Arthur Taylor (MDL/RSIS): Created
329 : *
330 : * NOTES
331 : * 1) Assumes binary bit stream should be "big endian". Resulting in no byte
332 : * boundaries ie 00100110101101 => 001001 | 1010110
333 : * 2) Assumes that Dst is already zero'ed out.
334 : *****************************************************************************
335 : */
336 0 : char memBitWrite (void *Src, size_t srcLen, void *Dst, size_t numBits,
337 : uChar * bufLoc, size_t * numUsed)
338 : {
339 0 : uChar *src = (uChar *) Src; /* Allows us to treat Src as an array of
340 : * char. */
341 0 : uChar *dst = (uChar *) Dst; /* Allows us to treat Dst as an array of
342 : * char. */
343 : size_t numBytes; /* How many bytes are needed from src. */
344 : uChar srcLoc; /* Which bit we are reading from in src. */
345 : uChar *ptr; /* Current byte we are reading from in src. */
346 : static uChar BitMask[] = {
347 : 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
348 : };
349 :
350 0 : if (numBits == 0) {
351 0 : return 0;
352 : }
353 0 : numBytes = ((numBits - 1) / 8) + 1;
354 0 : if (srcLen < numBytes) {
355 0 : return 1;
356 : }
357 0 : srcLoc = ((numBits - 1) % 8) + 1;
358 :
359 0 : if ((*bufLoc == 8) && (srcLoc == 8)) {
360 0 : MEMCPY_BIG (Dst, Src, numBytes);
361 0 : (*numUsed) = numBytes;
362 0 : return 0;
363 : }
364 : #ifdef LITTLE_ENDIAN
365 0 : ptr = src + (numBytes - 1);
366 : #else
367 : ptr = src + (srcLen - numBytes);
368 : #endif
369 :
370 0 : *numUsed = 0;
371 : /* Deal with most significant byte in src. */
372 0 : if (*bufLoc >= srcLoc) {
373 : #ifdef LITTLE_ENDIAN
374 0 : (*dst) |= ((*(ptr--) & BitMask[srcLoc]) << (*bufLoc - srcLoc));
375 : #else
376 : (*dst) |= ((*(ptr++) & BitMask[srcLoc]) << (*bufLoc - srcLoc));
377 : #endif
378 0 : (*bufLoc) -= srcLoc;
379 : } else {
380 0 : if (*bufLoc != 0) {
381 0 : (*dst) |= ((*ptr & BitMask[srcLoc]) >> (srcLoc - *bufLoc));
382 : /* Assert: srcLoc should now be srcLoc - InitBufLoc */
383 0 : srcLoc = srcLoc - *bufLoc;
384 : /* Assert: bufLoc should now be 0 */
385 : }
386 0 : dst++;
387 0 : (*dst) = 0;
388 0 : (*numUsed)++;
389 : /* Assert: bufLoc should now be 8 */
390 : /* Assert: We want to >> by bufLoc - srcLoc = 8 - srcLoc */
391 : #ifdef LITTLE_ENDIAN
392 0 : (*dst) |= (*(ptr--) << (8 - srcLoc));
393 : #else
394 : (*dst) |= (*(ptr++) << (8 - srcLoc));
395 : #endif
396 0 : (*bufLoc) = 8 - srcLoc;
397 : }
398 : /* Assert: dstLoc should now be 8, but we don't use again in procedure. */
399 :
400 : /* We have now reached the state which we want after each iteration of
401 : * the loop. That is initSrcLoc == 8, initBufLoc = bufLoc < srcLoc. */
402 : #ifdef LITTLE_ENDIAN
403 0 : while (ptr >= src) {
404 : #else
405 : while (ptr < src + srcLen) {
406 : #endif
407 0 : if (*bufLoc == 0) {
408 0 : dst++;
409 0 : (*numUsed)++;
410 : #ifdef LITTLE_ENDIAN
411 0 : (*dst) = *(ptr--);
412 : #else
413 : (*dst) = *(ptr++);
414 : #endif
415 : } else {
416 0 : (*dst) |= ((*ptr) >> (8 - *bufLoc));
417 0 : dst++;
418 0 : (*numUsed)++;
419 0 : (*dst) = 0;
420 : #ifdef LITTLE_ENDIAN
421 0 : (*dst) |= (*(ptr--) << *bufLoc);
422 : #else
423 : (*dst) |= (*(ptr++) << *bufLoc);
424 : #endif
425 : }
426 : }
427 0 : if (*bufLoc == 0) {
428 0 : dst++;
429 0 : (*numUsed)++;
430 0 : (*bufLoc) = 8;
431 0 : (*dst) = 0;
432 : }
433 0 : return 0;
434 : }
435 :
436 : /*****************************************************************************
437 : * main() --
438 : *
439 : * Arthur Taylor / MDL
440 : *
441 : * PURPOSE
442 : * To test the memBitRead, and memBitWrite routines, to make sure that they
443 : * function correctly on some sample data..
444 : *
445 : * ARGUMENTS
446 : * argc = The number of arguments on the command line. (Input)
447 : * argv = The arguments on the command line. (Input)
448 : *
449 : * FILES/DATABASES: None
450 : *
451 : * RETURNS: void
452 : *
453 : * HISTORY
454 : * 4/2003 Arthur Taylor (MDL/RSIS): Created.
455 : *
456 : * NOTES
457 : *****************************************************************************
458 : */
459 : #ifdef DEBUG_ENDIAN
460 : int main (int argc, char **argv)
461 : {
462 : uChar buff[5], buff2[5];
463 : uChar bufLoc = 8;
464 : uChar *ptr, *ptr2;
465 : int numUsed;
466 :
467 : buff[0] = 0x8f;
468 : buff[1] = 0x8f;
469 : buff[2] = 0x8f;
470 : buff[3] = 0x8f;
471 : buff[4] = 0x8f;
472 :
473 : bufLoc = 7;
474 : memBitRead (buff2, sizeof (buff2), buff, 39, &bufLoc, &numUsed);
475 : printf ("%d %d %d %d %d ", buff2[0], buff2[1], buff2[2], buff2[3],
476 : buff2[4]);
477 : printf ("-------should be----- ");
478 : printf ("143 143 143 143 15\n");
479 :
480 : memset (buff, 0, sizeof (buff));
481 : bufLoc = 8;
482 : ptr = buff;
483 : ptr2 = buff2;
484 : memBitWrite (ptr2, sizeof (buff2), ptr, 9, &bufLoc, &numUsed);
485 : ptr += numUsed;
486 : ptr2++;
487 : memBitWrite (ptr2, sizeof (buff2), ptr, 7, &bufLoc, &numUsed);
488 : ptr += numUsed;
489 : ptr2++;
490 : memBitWrite (ptr2, sizeof (buff2), ptr, 7, &bufLoc, &numUsed);
491 : ptr += numUsed;
492 : ptr2++;
493 : memBitWrite (ptr2, sizeof (buff2), ptr, 9, &bufLoc, &numUsed);
494 : ptr += numUsed;
495 : ptr2++;
496 : memBitWrite (ptr2, sizeof (buff2), ptr, 8, &bufLoc, &numUsed);
497 : ptr += numUsed;
498 : printf ("%d %d %d %d %d ", buff[0], buff[1], buff[2], buff[3], buff[4]);
499 : printf ("-------should be----- ");
500 : printf ("199 143 31 143 15\n");
501 : return 0;
502 : }
503 : #endif
|