/***************************************************************************** * tendian.c * * DESCRIPTION * This file contains some functions to solve endian'ness related issues. * * HISTORY * 9/2002 Arthur Taylor (MDL / RSIS): Created. * 12/2002 Rici Yu, Fangyu Chi, Mark Armstrong, & Tim Boyer * (RY,FC,MA,&TB): Code Review 2. * 2/2007 AAT (MDL): Commented * * NOTES ****************************************************************************/ #include #include #include "libaat.h" #ifndef TENDIAN_BITMASK #define TENDIAN_BITMASK static const uChar BitMask[] = { 0, 1, 3, 7, 15, 31, 63, 127, 255 }; #endif /***************************************************************************** * memswp() -- Arthur Taylor / MDL * * PURPOSE * To swap memory in the Data array based on the knownledge that there are * "num" elements, each of size "size". * * ARGUMENTS * Data = A pointer to the data to be swapped. (Input/Output) * size = The size of an individual element. (Input) * num = The number of elements to swap. (Input) * * RETURNS: void * * HISTORY * 9/2002 Arthur Taylor (MDL/RSIS): Created. * 12/2002 (RY,FC,MA,&TB): Code Review. * 2/2007 AAT (MDL): Commented * * NOTES * Could try this with exclusive or? ****************************************************************************/ void memswp(void *Data, size_t size, size_t num) { size_t i; /* Element count */ char *data; /* Allows us to treat Data as an array of char. */ char temp; /* A temporary holder of a byte when swapping. */ char *ptr, *ptr2; /* Pointers to the two bytes to swap. */ if (size == 1) { return; } data = (char *)Data; for (i = 0; i < size * num; i += size) { ptr = data + i; ptr2 = ptr + size - 1; while (ptr2 > ptr) { temp = *ptr; *(ptr++) = *ptr2; *(ptr2--) = temp; } } } /***************************************************************************** * MEMCPY_BIG (sometimes macro for revmemcpy()) -- Arthur Taylor / MDL * MEMCPY_LIT (sometimes macro for revmemcpy()) -- Arthur Taylor / MDL * * PURPOSE * Copies and reverses memory (similar to memcpy). In order to have the * same arguments as memcpy, this can not handle arrays. For arrays use * revmemcpyRay(). Returns the same thing that memcpy does. * This assumes that Dst is allocated to a size of "len". If Dst is larger * then "len", the data will be in the first "len" bytes. * * ARGUMENTS * Dst = The destination for the data. (Output) * Src = The source of the data. (Input) * len = The length of Src in bytes. (Input) * * RETURNS: void * * A pointer to Dst. * * HISTORY * 9/2002 Arthur Taylor (MDL/RSIS): Created. * 12/2002 (RY,FC,MA,&TB): Code Review. * 2/2007 AAT (MDL): Commented * * NOTES * 1) This came about as I was trying to improve on the use of memcpy. I * figured that revmemcpy would be faster than memcpy followed by memswp. ****************************************************************************/ void *revmemcpy(void *Dst, const void *Src, size_t len) { size_t i; /* Byte count */ char *src = (char *)Src; /* Allows us to treat Src as an array of char. */ char *dst = (char *)Dst; /* Allows us to treat Dst as an array of char. */ src += len - 1; for (i = 0; i < len; ++i) { *(dst++) = *(src--); } return Dst; } /***************************************************************************** * revmemcpyRay() -- Arthur Taylor / MDL * * PURPOSE * Copies and reverses memory (similar to memcpy). This handles the case * when we need to reverse memcpy an array of data. * This assumes that Dst is allocated to a size of "len" * "num". If Dst * is larger then "len" * "num", the data will be in the first "len" * "num" * bytes. * * ARGUMENTS * Dst = The destination for the data. (Output) * Src = The source of the data. (Input) * len = The size of a single element. (Input) * num = The number of elements in Src. (Input) * * RETURNS: void * * A pointer to Dst. * * HISTORY * 9/2002 Arthur Taylor (MDL/RSIS): Created. * 12/2002 (RY,FC,MA,&TB): Code Review. * 2/2007 AAT (MDL): Commented * * NOTES ****************************************************************************/ void *revmemcpyRay(void *Dst, const void *Src, size_t len, size_t num) { size_t i; /* Element count. */ size_t j; /* Byte count. */ char *src = (char *)Src; /* Allows us to treat Src as an array of char. */ char *dst = (char *)Dst; /* Allows us to treat Dst as an array of char. */ if (len == 1) { return memcpy(Dst, Src, num); } src -= (len + 1); for (i = 0; i < num; ++i) { src += 2 * len; for (j = 0; j < len; ++j) { *(dst++) = *(src--); } } return Dst; } /***************************************************************************** * memBitRead() -- Arthur Taylor / MDL * * PURPOSE * To read bits from an uChar buffer array of memory. Assumes BufLoc is * valid before first call. Typically this means do a "bufLoc = 8;" before * the first call. * * ARGUMENTS * Dst = Where to put the results. (Output) * dstLen = Length in bytes of Dst. (Input) * Src = The data to read the bits from. (Input) * numBits = How many bits to read. (Input) * BufLoc = In Src, which bit to start reading from. * Starts at 8 goes to 1. (Input/Output) * numUsed = How many bytes from Src were used while reading (Output) * * RETURNS: int * 1 on error, 0 if ok. * * HISTORY * 4/2003 Arthur Taylor (MDL/RSIS): Created * 5/2004 AAT: Bug in call to MEMCPY_BIG when numBytes != dstLen. * On big endian machines we need to right justify the number. * 3/2007 AAT (MDL): Commented * * NOTES * 1) Assumes binary bit stream is "big endian". Resulting in no byte * boundaries ie 00100110101101 => 001001 | 10101101 ****************************************************************************/ int memBitRead(void *Dst, size_t dstLen, const void *Src, size_t numBits, uChar *bufLoc, size_t *numUsed) { uChar *src = (uChar *)Src; /* Allows us to treat Src as array of char. */ uChar *dst = (uChar *)Dst; /* Allows us to treat Dst as array of char. */ size_t numBytes; /* How many bytes are needed in dst. */ uChar dstLoc; /* Where we are writing to in dst. */ uChar *ptr; /* Current byte we are writing to in dst. */ /* uses: static const uChar BitMask[] */ if (numBits == 0) { memset(Dst, 0, dstLen); (*numUsed) = 0; return 0; } /* Since numBits is always used with -1, may as well do --numBits here. */ numBytes = ((--numBits) / 8) + 1; /* Check if dst has enough room. */ if (dstLen < numBytes) { myWarn_Err1Arg("Dst doesn't have enough space\n"); return 1; } memset(Dst, 0, dstLen); dstLoc = (uChar)((numBits % 8) + 1); if ((*bufLoc == 8) && (dstLoc == 8)) { #ifndef WORDS_BIGENDIAN MEMCPY_BIG(Dst, Src, numBytes); #else /* If numBytes != dstLen, then we need to right justify the ans */ MEMCPY_BIG(dst + (dstLen - numBytes), Src, numBytes); #endif (*numUsed) = numBytes; return 0; } #ifndef WORDS_BIGENDIAN ptr = dst + (numBytes - 1); #else ptr = dst + (dstLen - numBytes); #endif *numUsed = 0; /* Deal with most significant byte in dst. */ if (*bufLoc >= dstLoc) { #ifndef WORDS_BIGENDIAN (*ptr--) |= ((*src & BitMask[*bufLoc]) >> (*bufLoc - dstLoc)); #else (*ptr++) |= ((*src & BitMask[*bufLoc]) >> (*bufLoc - dstLoc)); #endif (*bufLoc) -= dstLoc; } else { if (*bufLoc != 0) { *ptr |= ((*src & BitMask[*bufLoc]) << (dstLoc - *bufLoc)); dstLoc -= *bufLoc; /* Assert: bufLoc should now be 0 */ } src++; (*numUsed)++; /* Assert: bufLoc should now be 8 */ /* Assert: We want to >> by bufLoc - dstLoc = 8 - dstLoc */ /* 1) We can get fancy by moving "bufLoc = 8 - dstLoc" here, and then * shifting by bufLoc. */ /* 2) Since dstLoc is no longer used, we can get fancy by not updating * dstLoc in earlier part. So instead of: */ /* A) dstLoc = dstLoc - bufLoc; bufLoc = 8 - dstLoc; we have */ /* B) bufloc = 8 - (dstLoc - bufLoc) = bufLoc + 8 - dstLoc; */ #ifndef WORDS_BIGENDIAN *(ptr--) |= (*src >> (8 - dstLoc)); #else *(ptr++) |= (*src >> (8 - dstLoc)); #endif (*bufLoc) = 8 - dstLoc; } /* Assert: dstLoc should now be 8, but we don't use again in procedure. */ /* Note bufLoc < dstLoc from here on. Either it is 0 or < 8. */ /* Also dstLoc is always 8 from here out. */ #ifndef WORDS_BIGENDIAN while (ptr >= dst) { #else while (ptr < dst + dstLen) { #endif if (*bufLoc != 0) { *ptr |= ((*src & BitMask[*bufLoc]) << (8 - *bufLoc)); /* Assert: dstLoc should now be initDstLoc (8) - initBufLoc */ /* Assert: bufLoc should now be 0 */ } src++; (*numUsed)++; /* Assert: bufLoc should now be 8 */ /* Assert: dstLoc should now be initDstLoc (8) - initBufLoc */ /* Assert: We want to >> by bufLoc - dstLoc = (8 - (8 - initbufLoc)). */ #ifndef WORDS_BIGENDIAN *(ptr--) |= (*src >> *bufLoc); #else *(ptr++) |= (*src >> *bufLoc); #endif } if (*bufLoc == 0) { (*numUsed)++; *bufLoc = 8; } return 0; } /***************************************************************************** * memBitWrite() -- Arthur Taylor / MDL * * PURPOSE * To write bits from a data structure to an array of uChar. Assumes that * the part of Dst we don't write to have been correctly initialized. * Typically this means do a "memset (dst, 0, sizeof (dst));" before the first * call. Also assumes BufLoc is valid before first call. Typically this * means do a "bufLoc = 8;" before the first call. * * ARGUMENTS * Src = The data to read from. (Input) * srcLen = Length in bytes of Src. (Input) * Dst = The char buffer to write the bits to. (Output) * numBits = How many bits to write. (Input) * BufLoc = Which bit in Dst to start writing to. * Starts at 8 goes to 1. (Input/Output) * numUsed = How many bytes were written to Dst. (Output) * * RETURNS: int * 1 on error, 0 if ok. * * HISTORY * 4/2003 Arthur Taylor (MDL/RSIS): Created * 3/2007 AAT (MDL): Commented * * NOTES * 1) Assumes binary bit stream should be "big endian". Resulting in no byte * boundaries ie 00100110101101 => 001001 | 1010110 * 2) Assumes that Dst is already zero'ed out. ****************************************************************************/ int memBitWrite(const void *Src, size_t srcLen, void *Dst, size_t numBits, uChar *bufLoc, size_t *numUsed) { uChar *src = (uChar *)Src; /* Allows us to treat Src as array of char. */ uChar *dst = (uChar *)Dst; /* Allows us to treat Dst as array of char. */ size_t numBytes; /* How many bytes are needed from src. */ uChar srcLoc; /* Which bit we are reading from in src. */ uChar *ptr; /* Current byte we are reading from in src. */ /* uses: static const uChar BitMask[] */ if (numBits == 0) { return 0; } /* Since numBits is always used with -1, may as well do --numBits here. */ numBytes = ((--numBits) / 8) + 1; if (srcLen < numBytes) { myWarn_Err1Arg("Src doesn't have enough space\n"); return 1; } srcLoc = (numBits % 8) + 1; if ((*bufLoc == 8) && (srcLoc == 8)) { MEMCPY_BIG(Dst, Src, numBytes); (*numUsed) = numBytes; return 0; } #ifndef WORDS_BIGENDIAN ptr = src + (numBytes - 1); #else ptr = src + (srcLen - numBytes); #endif *numUsed = 0; /* Deal with most significant byte in src. */ if (*bufLoc >= srcLoc) { #ifndef WORDS_BIGENDIAN (*dst) |= ((*(ptr--) & BitMask[srcLoc]) << (*bufLoc - srcLoc)); #else (*dst) |= ((*(ptr++) & BitMask[srcLoc]) << (*bufLoc - srcLoc)); #endif (*bufLoc) -= srcLoc; } else { if (*bufLoc != 0) { (*dst) |= ((*ptr & BitMask[srcLoc]) >> (srcLoc - *bufLoc)); /* Assert: srcLoc should now be srcLoc - InitBufLoc */ srcLoc -= *bufLoc; /* Assert: bufLoc should now be 0 */ } dst++; (*dst) = 0; (*numUsed)++; /* Assert: bufLoc should now be 8 */ /* Assert: We want to >> by bufLoc - srcLoc = 8 - srcLoc */ /* 1) We can get fancy by moving "bufLoc = 8 - srcLoc" here, and then * shifting by bufLoc. */ /* 2) Since srcLoc is no longer used, we can get fancy by not updating * dstLoc in earlier part. So instead of: */ /* A) dstLoc = dstLoc - bufLoc; bufLoc = 8 - dstLoc; we have */ /* B) bufloc = 8 - (dstLoc - bufLoc) = bufLoc + 8 - dstLoc; */ #ifndef WORDS_BIGENDIAN (*dst) |= (*(ptr--) << (8 - srcLoc)); #else (*dst) |= (*(ptr++) << (8 - srcLoc)); #endif (*bufLoc) = 8 - srcLoc; } /* Assert: srcLoc should now be 8, but we don't use again in procedure. */ #ifndef WORDS_BIGENDIAN while (ptr >= src) { #else while (ptr < src + srcLen) { #endif if (*bufLoc == 0) { dst++; (*numUsed)++; #ifndef WORDS_BIGENDIAN (*dst) = *(ptr--); #else (*dst) = *(ptr++); #endif } else { (*dst) |= ((*ptr) >> (8 - *bufLoc)); dst++; (*numUsed)++; (*dst) = 0; #ifndef WORDS_BIGENDIAN (*dst) |= (*(ptr--) << *bufLoc); #else (*dst) |= (*(ptr++) << *bufLoc); #endif } } if (*bufLoc == 0) { dst++; (*numUsed)++; (*bufLoc) = 8; (*dst) = 0; } return 0; } /***************************************************************************** * FREAD_BIG (sometimes macro for revfread()) -- Arthur Taylor / MDL * FREAD_LIT (sometimes macro for revfread()) -- Arthur Taylor / MDL * * PURPOSE * To do an "fread", but in a reverse manner. It is assumed that file is * already opened and in the correct place. * * ARGUMENTS * Dst = The destination for the data. (Output) * size = The size of a single element. (Input) * num = The number of elements in Src. (Input) * fp = The file to read from. (Input) * * RETURNS: size_t * Number of elements read, or short count (possibly 0) on EOF or error. * * HISTORY * 9/2002 Arthur Taylor (MDL/RSIS): Created. * 12/2002 (RY,FC,MA,&TB): Code Review. * 3/2007 AAT (MDL): Commented * * NOTES * Decided to read it in and then swap. The thought is that it is faster * than doing several fgetc. This is the exact opposite method as used in * revfwrite(). ****************************************************************************/ size_t revfread(void *Dst, size_t size, size_t num, FILE *fp) { size_t ans; /* The answer from fread. */ size_t i; /* Byte count. */ char *dst; /* Allows us to treat Dst as an array of char. */ char temp; /* A temporary holder of a byte when swapping. */ char *ptr, *ptr2; /* Pointers to the two bytes to swap. */ ans = fread(Dst, size, num, fp); if (size == 1) { return ans; } if (ans == num) { dst = (char *)Dst; for (i = 0; i < size * num; i += size) { ptr = dst + i; ptr2 = ptr + size - 1; while (ptr2 > ptr) { temp = *ptr; *(ptr++) = *ptr2; *(ptr2--) = temp; } } } return ans; } /***************************************************************************** * FWRITE_BIG (sometimes macro for revfwrite()) -- Arthur Taylor / MDL * FWRITE_LIT (sometimes macro for revfwrite()) -- Arthur Taylor / MDL * * PURPOSE * To do an "fwrite", but in a reverse manner. It is assumed that file is * already opened and in the correct place. * * ARGUMENTS * Src = The source of the data. (Input) * size = The size of a single element. (Input) * num = The number of elements in Src. (Input) * fp = The file to write to. (Output) * * RETURNS: size_t * Number of elements written, or short count (possibly 0) on EOF or error. * * HISTORY * 9/2002 Arthur Taylor (MDL/RSIS): Created. * 11/2002 Arthur Taylor (MDL/RSIS): Updated. * 12/2002 (RY,FC,MA,&TB): Code Review. * 3/2007 AAT (MDL): Commented * * NOTES * Decided to write using a bunch of fputc, since this is buffered. The * thought here, is that it is faster than swapping memory and then writing. * This is the exact opposite method as revfread(). ****************************************************************************/ size_t revfwrite(const void *Src, size_t size, size_t num, FILE *fp) { char *ptr; /* Current byte to put to file. */ size_t i; /* Byte count */ size_t j; /* Element count */ char *src; /* Allows us to treat Src as an array of char. */ if (size == 1) { return fwrite(Src, size, num, fp); } else { src = (char *)Src; ptr = src - size - 1; for (j = 0; j < num; ++j) { ptr += 2 * size; for (i = 0; i < size; ++i) { if (fputc((int)*(ptr--), fp) == EOF) { return j; } } } return num; } } /***************************************************************************** * FREAD_ODDINT_BIG() -- Arthur Taylor / MDL * * PURPOSE * To do an "fread" into a sInt4, but in a reverse manner with not * necessarily all 4 bytes. It reads big endian data from disk. It is * assumed that the file is already opened and in the correct place. * * ARGUMENTS * dst = Where to store the data. (Output) * len = The number of bytes to read. (<= 4) (Input) * fp = The file to read from. (Input) * * RETURNS: size_t * Number of elements read, or short count (possibly 0) on EOF or error. * * HISTORY * 12/2004 Arthur Taylor (MDL): Created. * 3/2007 AAT (MDL): Commented * * NOTES ****************************************************************************/ size_t FREAD_ODDINT_BIG(sInt4 *dst, uChar len, FILE *fp) { *dst = 0; if (len > 4) { len = 4; } #ifndef WORDS_BIGENDIAN return revfread(dst, len, 1, fp); #else return fread((((char *)dst) + (4 - len)), len, 1, fp); #endif } /***************************************************************************** * FREAD_ODDINT_LIT() -- Arthur Taylor / MDL * * PURPOSE * To do an "fread" into a sInt4, but in a reverse manner with not * necessarily all 4 bytes. It reads little endian data from disk. It is * assumed that the file is already opened and in the correct place. * * ARGUMENTS * dst = Where to store the data. (Output) * len = The number of bytes to read. (<= 4) (Input) * fp = The file to read from. (Input) * * RETURNS: size_t * Number of elements read, or short count (possibly 0) on EOF or error. * * HISTORY * 12/2004 Arthur Taylor (MDL): Created. * 3/2007 AAT (MDL): Commented * * NOTES ****************************************************************************/ size_t FREAD_ODDINT_LIT(sInt4 *dst, uChar len, FILE *fp) { *dst = 0; if (len > 4) { len = 4; } #ifndef WORDS_BIGENDIAN return fread(dst, len, 1, fp); #else return revfread((((char *)dst) + (4 - len)), len, 1, fp); #endif } /***************************************************************************** * FWRITE_ODDINT_BIG() -- Arthur Taylor / MDL * * PURPOSE * To do an "fwrite" from a sInt4, but in a reverse manner with not * necessarily all 4 bytes. It writes big endian data to disk. It is * assumed that the file is already opened and in the correct place. * * ARGUMENTS * src = Where to read the data from. (Input) * len = The number of bytes to read. (<= 4) (Input) * fp = The file to write the data to. (Input) * * RETURNS: size_t * Number of elements written, or short count (possibly 0) on EOF or error. * * HISTORY * 12/2004 Arthur Taylor (MDL): Created. * 3/2007 AAT (MDL): Commented * * NOTES ****************************************************************************/ size_t FWRITE_ODDINT_BIG(const sInt4 *src, uChar len, FILE *fp) { if (len > 4) { len = 4; } #ifndef WORDS_BIGENDIAN return revfwrite(src, len, 1, fp); #else return fwrite((((char *)src) + (4 - len)), len, 1, fp); #endif } /***************************************************************************** * FWRITE_ODDINT_LIT() -- Arthur Taylor / MDL * * PURPOSE * To do an "fwrite" from a sInt4, but in a reverse manner with not * necessarily all 4 bytes. It writes little endian data to disk. It is * assumed that the file is already opened and in the correct place. * * ARGUMENTS * src = Where to read the data from. (Input) * len = The number of bytes to read. (<= 4) (Input) * fp = The file to write the data to. (Input) * * RETURNS: size_t * Number of elements written, or short count (possibly 0) on EOF or error. * * HISTORY * 12/2004 Arthur Taylor (MDL): Created. * 3/2007 AAT (MDL): Commented * * NOTES ****************************************************************************/ size_t FWRITE_ODDINT_LIT(const sInt4 *src, uChar len, FILE *fp) { if (len > 4) { len = 4; } #ifndef WORDS_BIGENDIAN return fwrite(src, len, 1, fp); #else return revfwrite((((char *)src) + (4 - len)), len, 1, fp); #endif } /***************************************************************************** * fileBitRead() -- Arthur Taylor / MDL * * PURPOSE * To read bits from a file. Stores the current byte, and passes the bits * that were requested to the user. Leftover bits, are stored in "gbuf", * which should be passed in for future reads. * If numBits == 0, then flush the gbuf. * * ARGUMENTS * Dst = The storage place for the data read from file. (Output) * dstLen = The size of dst (in bytes) (Input) * fp = The open file to read from. (Input) * numBits = The number of bits to read from the file. (Input) * gbuf = The current bit buffer (Input/Output) * gbufLoc = Where we are in the current bit buffer. (Input/Output) * * RETURNS: int * EOF if EOF, 1 if error, 0 if ok. * * HISTORY * 3/2007 AAT (MDL): Commented * * NOTES ****************************************************************************/ int fileBitRead(void *Dst, size_t dstLen, FILE *fp, size_t numBits, uChar *gbuf, sChar *gbufLoc) { uChar *dst = (uChar *)Dst; /* Allows us to treat Dst as array of char. */ size_t numBytes; /* How many bytes are needed in dst. */ uChar dstLoc; /* Where we are writing to in dst. */ uChar *ptr; /* Current byte we are writing to in dst. */ /* uses: static const uChar BitMask[] */ int c; /* The current byte from file. */ uChar buf; /* The current buffer of extra bits. */ uChar bufLoc; /* Where we are reading from in buffer */ if (numBits == 0) { memset(Dst, 0, dstLen); *gbuf = 0; *gbufLoc = 0; return 0; } /* Since numBits is always used with -1, may as well do --numBits here. */ numBytes = ((--numBits) / 8) + 1; /* Check if dst has enough room. */ if (dstLen < numBytes) { myWarn_Err1Arg("Dst doesn't have enough space\n"); return 1; } memset(Dst, 0, dstLen); dstLoc = (uChar)((numBits % 8) + 1); bufLoc = *gbufLoc; buf = *gbuf; #ifndef WORDS_BIGENDIAN ptr = dst + (numBytes - 1); #else ptr = dst + (dstLen - numBytes); #endif /* Deal with initial "remainder" part (most significant byte) in dst. */ if (bufLoc >= dstLoc) { /* can now deal with entire "remainder". */ #ifndef WORDS_BIGENDIAN *(ptr--) |= ((buf & BitMask[bufLoc]) >> (bufLoc - dstLoc)); #else *(ptr++) |= ((buf & BitMask[bufLoc]) >> (bufLoc - dstLoc)); #endif bufLoc -= dstLoc; } else { /* need to do 2 calls to deal with entire "remainder". */ if (bufLoc != 0) { *ptr |= ((buf & BitMask[bufLoc]) << (dstLoc - bufLoc)); dstLoc -= bufLoc; /* Assert: bufLoc should now be 0 */ } if ((c = fgetc(fp)) == EOF) { *gbufLoc = bufLoc; *gbuf = buf; return EOF; } buf = (uChar)c; /* Assert: bufLoc should now be 8 */ /* Assert: We want to >> by bufLoc - dstLoc = 8 - dstLoc */ /* 1) We can get fancy by moving "bufLoc = 8 - dstLoc" here, and then * shifting by bufLoc. */ /* 2) Since dstLoc is no longer used, we can get fancy by not updating * dstLoc in earlier part. So instead of: */ /* A) dstLoc = dstLoc - bufLoc; bufLoc = 8 - dstLoc; we have */ /* B) bufloc = 8 - (dstLoc - bufLoc) = bufLoc + 8 - dstLoc; */ #ifndef WORDS_BIGENDIAN *(ptr--) |= (buf >> (8 - dstLoc)); #else *(ptr++) |= (buf >> (8 - dstLoc)); #endif bufLoc = 8 - dstLoc; } /* Assert: dstLoc should now be 8, but we don't use again in procedure. */ /* Note bufLoc < dstLoc from here on. Either it is 0 or < 8. */ /* Also dstLoc is always 8 from here out. */ #ifndef WORDS_BIGENDIAN while (ptr >= dst) { #else while (ptr < dst + dstLen) { #endif if (bufLoc != 0) { *ptr |= (uChar)((buf & BitMask[bufLoc]) << (8 - bufLoc)); /* Assert: dstLoc should now be initDstLoc (8) - initBufLoc */ /* Assert: bufLoc should now be 0 */ } if ((c = fgetc(fp)) == EOF) { *gbufLoc = bufLoc; *gbuf = buf; return EOF; } buf = (uChar)c; /* Assert: bufLoc should now be 8 */ /* Assert: dstLoc should now be initDstLoc (8) - initBufLoc */ /* Assert: We want to >> by bufLoc - dstLoc = (8 - (8 - initbufLoc)). */ #ifndef WORDS_BIGENDIAN *(ptr--) |= (buf >> bufLoc); #else *(ptr++) |= (buf >> bufLoc); #endif } *gbufLoc = bufLoc; *gbuf = buf; return 0; } /***************************************************************************** * fileBitWrite() -- Arthur Taylor / MDL * * PURPOSE * To write bits from src out to file. First writes out any leftover bits * in pbuf, then bits from src. Any leftover bits that aren't on a full byte * boundary, are stored in pbuf. * If numBits == 0, then flush the pbuf. * * ARGUMENTS * Src = The data to put out to file. (Input) * srcLen = Length in bytes of src. (Input) * numBits = The number of bits to write to file. (Input) * fp = The opened file ptr to write to. (Input) * pbuf = The extra bit buffer (Input/Output) * pBufLoc = The location in the bit buffer. * * RETURNS: int * 1 on error, 0 if ok. * * HISTORY * 8/2004 Arthur Taylor (MDL): Created * 3/2007 AAT (MDL): Commented * * NOTES ****************************************************************************/ int fileBitWrite(const void *Src, size_t srcLen, FILE *fp, size_t numBits, uChar *pbuf, sChar *pbufLoc) { uChar *src = (uChar *)Src; /* Allows us to treat Src as array of char. */ size_t numBytes; /* How many bytes are needed from src. */ uChar srcLoc; /* Which bit we are reading from in src. */ uChar *ptr; /* Current byte we are reading from in src. */ uChar buf; /* The current buffer of extra bits. */ uChar bufLoc; /* Where we are reading from in buffer */ if (numBits == 0) { if (*pbufLoc != 8) { fputc((int)*pbuf, fp); *pbuf = 0; *pbufLoc = 8; /* return 8; */ myWarn_Note1Arg("Changed return value from 8 to 0 (is this an " "introduced bug?\n"); return 0; } else { /* Assert: *pbufLoc == 8 */ *pbuf = 0; return 0; } } /* Since numBits is always used with -1, may as well do --numBits here. */ numBytes = ((--numBits) / 8) + 1; if (srcLen < numBytes) { myWarn_Err1Arg("Src doesn't have enough space\n"); return 1; } srcLoc = (numBits % 8) + 1; bufLoc = *pbufLoc; buf = *pbuf; #ifndef WORDS_BIGENDIAN ptr = src + (numBytes - 1); #else ptr = src + (srcLen - numBytes); #endif /* Deal with most significant byte in src. */ if (bufLoc >= srcLoc) { #ifndef WORDS_BIGENDIAN buf |= ((*(ptr--) & BitMask[srcLoc]) << (bufLoc - srcLoc)); #else buf |= ((*(ptr++) & BitMask[srcLoc]) << (bufLoc - srcLoc)); #endif bufLoc -= srcLoc; } else { if (bufLoc != 0) { buf |= ((*ptr & BitMask[srcLoc]) >> (srcLoc - bufLoc)); /* Assert: srcLoc should now be srcLoc - InitBufLoc */ srcLoc -= bufLoc; /* Assert: bufLoc should now be 0 */ } if (fputc((int)buf, fp) == EOF) { *pbufLoc = bufLoc; *pbuf = buf; myWarn_Err1Arg("Problems writing to file\n"); return 1; } buf = 0; /* Assert: bufLoc should now be 8 */ /* Assert: We want to >> by bufLoc - srcLoc = 8 - srcLoc */ /* 1) We can get fancy by moving "bufLoc = 8 - srcLoc" here, and then * shifting by bufLoc. */ /* 2) Since srcLoc is no longer used, we can get fancy by not updating * dstLoc in earlier part. So instead of: */ /* A) dstLoc = dstLoc - bufLoc; bufLoc = 8 - dstLoc; we have */ /* B) bufloc = 8 - (dstLoc - bufLoc) = bufLoc + 8 - dstLoc; */ #ifndef WORDS_BIGENDIAN buf |= (*(ptr--) << (8 - srcLoc)); #else buf |= (*(ptr++) << (8 - srcLoc)); #endif bufLoc = 8 - srcLoc; } /* Assert: srcLoc should now be 8, but we don't use again in procedure. */ #ifndef WORDS_BIGENDIAN while (ptr >= src) { #else while (ptr < src + srcLen) { #endif if (bufLoc == 0) { if (fputc((int)buf, fp) == EOF) { *pbufLoc = bufLoc; *pbuf = buf; myWarn_Err1Arg("Problems writing to file\n"); return 1; } #ifndef WORDS_BIGENDIAN buf = *(ptr--); #else buf = *(ptr++); #endif } else { buf |= ((*ptr) >> (8 - bufLoc)); if (fputc((int)buf, fp) == EOF) { *pbufLoc = bufLoc; *pbuf = buf; myWarn_Err1Arg("Problems writing to file\n"); return 1; } buf = 0; #ifndef WORDS_BIGENDIAN buf |= (*(ptr--) << bufLoc); #else buf |= (*(ptr++) << bufLoc); #endif } } if (bufLoc == 0) { if (fputc((int)buf, fp) == EOF) { *pbufLoc = bufLoc; *pbuf = buf; myWarn_Err1Arg("Problems writing to file\n"); return 1; } bufLoc = 8; buf = 0; } *pbufLoc = bufLoc; *pbuf = buf; return 0; } /***************************************************************************** * main() (Private) -- Arthur Taylor / MDL * * PURPOSE * To test the memBitRead, and memBitWrite routines, to make sure that they * function correctly on some sample data.. * * ARGUMENTS * argc = The number of arguments on the command line. (Input) * argv = The arguments on the command line. (Input) * * RETURNS: int * * HISTORY * 4/2003 Arthur Taylor (MDL/RSIS): Created. * 3/2007 AAT (MDL): Commented * * NOTES ****************************************************************************/ #ifdef DEBUG_TENDIAN int main(int argc, char **argv) { uChar buff[5], buff2[5]; uChar bufLoc = 8; uChar *ptr, *ptr2; int numUsed; buff[0] = 0x8f; buff[1] = 0x8f; buff[2] = 0x8f; buff[3] = 0x8f; buff[4] = 0x8f; bufLoc = 7; memBitRead(buff2, sizeof(buff2), buff, 39, &bufLoc, &numUsed); printf("%d %d %d %d %d ", buff2[0], buff2[1], buff2[2], buff2[3], buff2[4]); printf("-------should be----- "); printf("143 143 143 143 15\n"); memset(buff, 0, sizeof(buff)); bufLoc = 8; ptr = buff; ptr2 = buff2; memBitWrite(ptr2, sizeof(buff2), ptr, 9, &bufLoc, &numUsed); ptr += numUsed; ptr2++; memBitWrite(ptr2, sizeof(buff2), ptr, 7, &bufLoc, &numUsed); ptr += numUsed; ptr2++; memBitWrite(ptr2, sizeof(buff2), ptr, 7, &bufLoc, &numUsed); ptr += numUsed; ptr2++; memBitWrite(ptr2, sizeof(buff2), ptr, 9, &bufLoc, &numUsed); ptr += numUsed; ptr2++; memBitWrite(ptr2, sizeof(buff2), ptr, 8, &bufLoc, &numUsed); ptr += numUsed; printf("%d %d %d %d %d ", buff[0], buff[1], buff[2], buff[3], buff[4]); printf("-------should be----- "); printf("199 143 31 143 15\n"); return 0; } #endif