BitstreamReader.h

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2005 Palmsource, Inc.
00003  * 
00004  * This software is licensed as described in the file LICENSE, which
00005  * you should have received as part of this distribution. The terms
00006  * are also available at http://www.openbinder.org/license.html.
00007  * 
00008  * This software consists of voluntary contributions made by many
00009  * individuals. For the exact contribution history, see the revision
00010  * history and logs, available at http://www.openbinder.org
00011  */
00012 
00013 #ifndef _SUPPORT_BITSTREAM_READER_H_
00014 #define _SUPPORT_BITSTREAM_READER_H_
00015 
00016 #include <support/Buffer.h>
00017 #include <support/ByteOrder.h>
00018 #include <support/StdIO.h>
00019 #include <assert.h>
00020 
00021 #if _SUPPORTS_NAMESPACE
00022 namespace palmos {
00023 namespace support {
00024 #endif
00025 
00026 #if BYTE_ORDER == LITTLE_ENDIAN
00027 #define SWAP_INT32(uarg)                                    \
00028 {                                                           \
00029     uint32_t swapped = uarg ^ ((uarg<<16)|(uarg>>16));      \
00030     swapped &= 0xFF00FFFF;                                  \
00031     uarg = (uarg>>8)|(uarg<<24);                            \
00032     uarg = (swapped >> 8) ^ uarg;                           \
00033 }
00034 #else
00035 #define SWAP_INT32(uarg)
00036 #endif
00037 
00038 
00039 class SBitstreamReader
00040 {
00041     public:
00042                                 SBitstreamReader();
00043                                 SBitstreamReader(const SBuffer& sourceBuffer);
00044                                 SBitstreamReader(const void * data, size_t size);
00045                                 ~SBitstreamReader();
00046 
00047         inline  status_t        SetSource(const SBuffer& sourceBuffer);
00048         inline  status_t        SetSource(const void * data, size_t size);
00049 
00050         inline  bool            IsInRange() const;
00051 
00052         inline  uint32_t        PeekBits(size_t bits) const;
00053         inline  uint32_t        GetBits(size_t bits);
00054 
00055         inline  void            SkipBit();
00056         inline  void            SkipByte();
00057         inline  void            SkipBits(size_t bits);
00058         inline  void            SkipToByteBoundary();
00059 
00060         inline  void            RewindBits(size_t bits);
00061 
00062         inline  bool            Find(uint32_t pattern, size_t bits);
00063         inline  bool            FindByteAligned(uint32_t pattern, size_t bits);
00064         inline  bool            FindReverse(uint32_t pattern, size_t bits);
00065         inline  bool            FindByteAlignedReverse(uint32_t pattern, size_t bits);
00066 
00067         inline  size_t          BytePosition() const;
00068         inline  size_t          BitPosition() const;
00069 
00070         // note that this will only return meaningful values <= 32, as it only
00071         // reports the amount of data in the cache.  use BytesAvailable() to get
00072         // the distance from the end of the source (this is considerably slower.)
00073         inline  size_t          BitsAvailable() const
00074         {
00075             if (m_cacheOffset > m_cacheSize) return 0;
00076             return m_cacheSize - m_cacheOffset;
00077         }
00078 
00079         inline  size_t          BytesAvailable() const;
00080 
00081         inline  status_t        SetBytePosition(size_t pos);
00082         inline  status_t        SetBitPosition(size_t pos);
00083 
00084         inline  size_t          ByteLength() const;
00085 
00086     private:
00087         struct  SFragment
00088         {
00089             const uint8_t *     data;
00090             size_t              size;
00091             size_t              offset;
00092         };
00093         
00094                 uint32_t        m_cache[2];
00095                 size_t          m_cacheOffset;          // bits
00096                 const uint8_t * m_fragmentPointer;
00097                 size_t          m_fragmentRemaining;    // bytes
00098 
00099                 size_t          m_cacheSize;        // bits cached; usually 64 unless out of data
00100 
00101                 SFragment *     m_fragments;
00102                 size_t          m_fragmentCount;
00103                 size_t          m_fragmentIndex;
00104 
00105         inline  size_t          fill_forward(size_t fillOffset)
00106         {
00107             assert (fillOffset == 0 || fillOffset == 4);
00108             size_t n;
00109 
00110             m_cache[fillOffset >> 2] = 0;
00111             uint8_t * cacheByte = (uint8_t*)m_cache + fillOffset;
00112             size_t toCache = 4;
00113 
00114             assert (m_fragmentPointer >= m_fragments[m_fragmentIndex].data);
00115             
00116             // handle source(s) with fewer than 4 bytes of data
00117             while (true)
00118             {
00119                 while (m_fragmentRemaining == 0)
00120                 {
00121                     if (m_fragmentIndex + 1 < m_fragmentCount)
00122                     {
00123                         m_fragmentIndex++;
00124                         m_fragmentPointer = m_fragments[m_fragmentIndex].data;
00125                         m_fragmentRemaining = m_fragments[m_fragmentIndex].size;
00126                     }
00127                     else
00128                     {
00129                         toCache = 0;
00130                         break;
00131                     }
00132                 }
00133 
00134                 if (m_fragmentRemaining >= toCache) break;
00135             
00136                 *cacheByte = *m_fragmentPointer;
00137                 m_fragmentPointer++;
00138                 cacheByte++;
00139                 toCache--;
00140                 m_fragmentRemaining--;
00141             }
00142             
00143             size_t shift = 0;
00144             while (toCache > 0)
00145             {
00146                 assert (m_fragmentPointer >= m_fragments[m_fragmentIndex].data);
00147                 assert (m_fragmentRemaining >= toCache); // this precondition is handled by the first loop
00148 
00149                 // read the next cache word; we want to read on 32-bit
00150                 // boundaries after this point, so pad accordingly if
00151                 // there's room.
00152                 size_t align = 4 - (uint32_t(m_fragmentPointer) & 0x3);
00153                     
00154                 if (align == 4 && toCache == 4)
00155                 {
00156                     // easy case: aligned word
00157                     m_cache[fillOffset >> 2] = *(uint32_t*)m_fragmentPointer;
00158                     m_fragmentPointer += 4;
00159                     m_fragmentRemaining -= toCache;
00160                     cacheByte += 4;
00161                     break;
00162                 }
00163                 else
00164                 {
00165                     size_t toRead;
00166                     if (align != 4 && align < toCache)
00167                     {
00168                         toRead = align;
00169                         
00170                         // we have room to pad.  shift current data so that the following
00171                         // read can be a whole word.  this is rather hairy because, depending
00172                         // on where we started filling the cache, the first word may or
00173                         // may not be byteswapped.
00174                         shift = toCache - align;
00175                         if (shift > 4) shift -= 4;
00176 
00177                         toCache -= shift;
00178                         
00179                         shift <<= 3;
00180 
00181                         m_cacheOffset += shift;
00182                     }
00183                     else
00184                     {
00185                         toRead = toCache;
00186                     }
00187                         
00188                     for (n = 0; n < toRead; n++)
00189                     {
00190                         *cacheByte = *m_fragmentPointer;
00191                         m_fragmentPointer++;
00192                         m_fragmentRemaining--;
00193                         cacheByte++;
00194                     }
00195                     toCache -= toRead;
00196                 }
00197             }
00198 
00199             if (fillOffset == 0)
00200             {
00201                 SWAP_INT32(m_cache[0]);
00202             }
00203             SWAP_INT32(m_cache[1]);
00204 
00205             if (shift > 0)
00206             {
00207                 uint32_t v = m_cache[0];
00208                 m_cache[0] >>= shift;
00209                 m_cache[1] >>= shift;
00210                 m_cache[1] |= (v << (32-shift));
00211                 cacheByte += (shift >> 3);
00212             }
00213 
00214             size_t writeOffset = (cacheByte - (uint8_t*)m_cache);
00215             return (writeOffset - fillOffset) << 3;
00216         }
00217 
00218         inline  void            fill_reverse()
00219         {
00220             // read one word before current cache position
00221             size_t cachedBytes = (m_cacheSize >> 3);
00222 
00223             m_cache[0] = 0;
00224             uint8_t * cacheByte = ((uint8_t*)&m_cache[0]) + 3;
00225             size_t toRead = 4;
00226 
00227             // rewind fragment pointer to first byte we want to read
00228             const uint8_t * fptr = m_fragmentPointer;
00229             size_t findex = m_fragmentIndex;
00230             int32_t toRewind = cachedBytes;
00231             int32_t dataLeft = m_fragmentPointer - m_fragments[m_fragmentIndex].data;
00232             while (toRewind > 0)
00233             {
00234                 if (toRewind >= dataLeft)
00235                 {
00236                     toRewind -= dataLeft;
00237                     assert (findex > 0);
00238                     --findex;
00239                     dataLeft = m_fragments[findex].size;
00240                     fptr = m_fragments[findex].data + dataLeft;
00241                 }
00242                 else
00243                 {
00244                     fptr -= toRewind;
00245                     dataLeft -= toRewind;
00246                     break;
00247                 }
00248             }
00249             
00250             // read
00251             while (toRead > 0)
00252             {
00253                 fptr--;
00254                 dataLeft--;
00255                 if (dataLeft < 0)
00256                 {
00257                     if (findex == 0)
00258                     {
00259                         // out of data
00260                         fptr++;
00261                         break;
00262                     }
00263                     --findex;
00264                     dataLeft = m_fragments[findex].size - 1;
00265                     fptr = m_fragments[findex].data + dataLeft;
00266                 }
00267                 
00268                 *cacheByte = *fptr;
00269                 cacheByte--;
00270                 toRead--;
00271             }
00272 
00273             if (m_cacheSize < 32)
00274             {
00275                 m_cacheSize += 32;
00276             }
00277             else
00278             {
00279                 m_cacheSize = 64;
00280             }
00281 
00282             cachedBytes = (m_cacheSize >> 3) - toRead;
00283 
00284             SWAP_INT32(m_cache[0]);
00285 
00286             // advance fragment pointer past cached data
00287             size_t toAdvance = cachedBytes;
00288             size_t foffset = fptr - m_fragments[findex].data;
00289             size_t fremaining = m_fragments[findex].size - foffset;
00290             while (toAdvance > 0)
00291             {
00292                 if (toAdvance > fremaining)
00293                 {
00294                     toAdvance -= fremaining;
00295                     assert (findex + 1 < m_fragmentCount);
00296                     ++findex;
00297                     fremaining = m_fragments[findex].size;
00298                     fptr = m_fragments[findex].data;
00299                 }
00300                 else
00301                 {
00302                     fptr += toAdvance;
00303                     fremaining -= toAdvance;
00304                     break;
00305                 }
00306             }
00307             m_fragmentPointer = fptr;
00308             m_fragmentIndex = findex;
00309             m_fragmentRemaining = fremaining;
00310         }
00311         
00312         inline  void            next_word()
00313         {
00314 //berr << ">> next_word : frag remaining " << m_fragmentRemaining << " ptr align " << ((uint32_t)m_fragmentPointer & 0x3) << " << \n";
00315             assert (m_cacheOffset >= 32);
00316             
00317             // cache[0] is empty
00318             m_cache[0] = m_cache[1];
00319             m_cacheOffset -= 32;
00320 
00321             if (m_fragmentRemaining >= 4 &&
00322                 ((uint32_t)m_fragmentPointer & 0x3) == 0)
00323             {
00324                 // aligned read
00325                 m_cache[1] = *(uint32_t*)m_fragmentPointer;
00326                 m_fragmentPointer += 4;
00327                 m_fragmentRemaining -= 4;
00328                 SWAP_INT32(m_cache[1]);
00329             }
00330             else
00331             {
00332                 // unaligned read
00333                 if (m_cacheSize == 64)
00334                 {
00335                     // the cache is full, so there may be more data to read.
00336                     size_t readCount = fill_forward(4);
00337                     m_cacheSize = 32 + readCount;
00338                 }
00339                 else
00340                 if (m_cacheSize > 32)
00341                 {
00342                     m_cacheSize -= 32;
00343                 }
00344                 else
00345                 {
00346                     m_cacheSize = 0;
00347                 }
00348             }
00349         }
00350 };
00351 
00352 // ------------------------------------------------------------------------- //
00353 
00354 inline 
00355 SBitstreamReader::SBitstreamReader()
00356     : m_cacheOffset(0),
00357       m_fragmentRemaining(0),
00358       m_cacheSize(0),
00359       m_fragments(0),
00360       m_fragmentCount(0),
00361       m_fragmentIndex(0)
00362 {
00363 }
00364 
00365 inline 
00366 SBitstreamReader::SBitstreamReader(const SBuffer& sourceBuffer)
00367     : m_fragments(0)
00368 {
00369     SetSource(sourceBuffer);
00370 }
00371 
00372 inline 
00373 SBitstreamReader::SBitstreamReader(const void * data, size_t size)
00374     : m_fragments(0)
00375 {
00376     SetSource(data, size);
00377 }
00378 
00379 inline
00380 SBitstreamReader::~SBitstreamReader()
00381 {
00382     if (m_fragments != 0)
00383     {
00384         delete [] m_fragments;
00385     }
00386 }
00387 
00388 inline status_t
00389 SBitstreamReader::SetSource(const SBuffer& sourceBuffer)
00390 {
00391     if (m_fragments != 0)
00392     {
00393         delete [] m_fragments;
00394     }
00395 
00396     // count fragments
00397     m_fragmentCount = 0;
00398     const SBuffer * i;
00399     for (i = &sourceBuffer; i; i = i->next)
00400     {
00401         ++m_fragmentCount;
00402     }
00403     m_fragments = new SFragment[m_fragmentCount];
00404     if (m_fragments == 0)
00405     {
00406         assert (!"SBitstreamReader: no memory for fragment list");
00407         return B_NO_MEMORY;
00408     }
00409     size_t n;
00410     size_t offset = 0;
00411     for (n = 0, i = &sourceBuffer; i; i = i->next, n++)
00412     {
00413         m_fragments[n].data = (const uint8_t*)i->Data();
00414         m_fragments[n].size = i->Size();
00415         m_fragments[n].offset = offset;
00416         offset += m_fragments[n].size;
00417     }
00418     
00419     m_cacheOffset = 0;
00420     m_fragmentIndex = 0;
00421     m_fragmentPointer = m_fragments[0].data;
00422     m_fragmentRemaining = m_fragments[0].size;
00423 
00424     m_cacheSize = fill_forward(0);
00425     m_cacheSize += fill_forward(4);
00426 
00427     return B_OK;
00428 }   
00429 
00430 inline status_t
00431 SBitstreamReader::SetSource(const void * data, size_t size)
00432 {
00433     if (m_fragments != 0)
00434     {
00435         delete [] m_fragments;
00436     }
00437     m_fragmentCount = 1;
00438     m_fragments = new SFragment[1];
00439     if (m_fragments == 0)
00440     {
00441         assert (!"SBitstreamReader: no memory for fragment list");
00442         return B_NO_MEMORY;
00443     }
00444     m_fragments[0].data = (const uint8_t*)data;
00445     m_fragments[0].size = size;
00446     m_fragments[0].offset = 0;
00447     
00448     m_cacheOffset = 0;
00449     m_fragmentIndex = 0;
00450     m_fragmentPointer = (const uint8_t*)data;
00451     m_fragmentRemaining = size;
00452 
00453     m_cacheSize = fill_forward(0);
00454     m_cacheSize += fill_forward(4);
00455 
00456     return B_OK;
00457 }
00458 
00459 inline bool
00460 SBitstreamReader::IsInRange() const
00461 {
00462     return (m_cacheSize > 0);
00463 }
00464 
00465 inline uint32_t
00466 SBitstreamReader::PeekBits(size_t bits) const
00467 {
00468     assert (m_cacheOffset + bits <= m_cacheSize);
00469 
00470     uint32_t result = m_cache[0] << m_cacheOffset;
00471     if (bits > (32-m_cacheOffset))
00472     {
00473         uint32_t v = m_cache[1] >> (32-m_cacheOffset);
00474         result |= v;
00475     }
00476     return result >> (32-bits);
00477 }
00478 
00479 inline uint32_t
00480 SBitstreamReader::GetBits(size_t bits)
00481 {
00482     assert (m_cacheOffset + bits <= m_cacheSize);
00483     
00484     uint32_t result = m_cache[0] << m_cacheOffset;
00485     if (bits > (32-m_cacheOffset))
00486     {
00487         uint32_t v = m_cache[1] >> (32-m_cacheOffset);
00488         result |= v;
00489     }
00490     m_cacheOffset += bits;
00491     if (m_cacheOffset >= 32)
00492     {
00493         next_word();
00494     }
00495     return result >> (32-bits);
00496 }
00497 
00498 inline void
00499 SBitstreamReader::SkipBit()
00500 {
00501     m_cacheOffset++;
00502     if (m_cacheOffset >= 32)
00503     {
00504         next_word();
00505     }
00506 }
00507 
00508 inline void
00509 SBitstreamReader::SkipByte()
00510 {
00511     m_cacheOffset += 8;
00512     if (m_cacheOffset >= 32)
00513     {
00514         next_word();
00515     }
00516 }
00517 
00518 inline void
00519 SBitstreamReader::SkipBits(size_t bits)
00520 {
00521     m_cacheOffset += bits;
00522     while (m_cacheOffset >= 32)
00523     {
00524         next_word();
00525     }
00526 }
00527 
00528 inline void
00529 SBitstreamReader::SkipToByteBoundary()
00530 {
00531     m_cacheOffset = (m_cacheOffset + 7) & ~7;
00532     if (m_cacheOffset >= 32)
00533     {
00534         next_word();
00535     }
00536 }
00537 
00538 inline void
00539 SBitstreamReader::RewindBits(size_t bits)
00540 {
00541     assert (bits > 0);
00542     assert (bits <= 32);
00543 //berr << SPrintf("RewindBits in (%ld): cache 0x%08lx 0x%08lx offset %ld\n", bits, m_cache[0], m_cache[1], m_cacheOffset );
00544     
00545     if (m_cacheOffset >= bits)
00546     {
00547         m_cacheOffset -= bits;
00548 //berr << SPrintf("RewindBits (simple): cache 0x%08lx 0x%08lx offset %ld\n", m_cache[0], m_cache[1], m_cacheOffset );
00549         return;
00550     }
00551     m_cache[1] = m_cache[0];
00552     fill_reverse();
00553     m_cacheOffset += (32 - bits);
00554 
00555 // berr << SPrintf("RewindBits: cache 0x%08lx 0x%08lx cacheOffset %ld cacheSize %ld frag %ld offset %ld\n",
00556         // m_cache[0], m_cache[1], m_cacheOffset, m_cacheSize, m_fragmentIndex,
00557         // m_fragmentPointer - m_fragments[m_fragmentIndex].data);
00558 }
00559 
00560 inline bool
00561 SBitstreamReader::Find(uint32_t pattern, size_t bits)
00562 {
00563     while (BitsAvailable() >= bits)
00564     {
00565         uint32_t v = PeekBits(bits);
00566         if (v == pattern) return true;
00567 
00568         SkipBit();
00569     }
00570     return false; // +++ should rewind to previous position
00571 }
00572 
00573 inline bool
00574 SBitstreamReader::FindByteAligned(uint32_t pattern, size_t bits)
00575 {
00576     SkipToByteBoundary();
00577     while (BitsAvailable() >= bits)
00578     {
00579         uint32_t v = PeekBits(bits);
00580         if (v == pattern) return true;
00581 
00582         SkipByte();
00583     }
00584 
00585     return false; // +++ should rewind to previous position
00586 }
00587 
00588 inline bool
00589 SBitstreamReader::FindReverse(uint32_t pattern, size_t bits)
00590 {
00591     // start search at (current position) - bits
00592     if (BitPosition() < bits)
00593     {
00594         return false;
00595     }
00596     RewindBits(bits);
00597     while (true)
00598     {
00599         uint32_t v = PeekBits(bits);
00600         if (v == pattern) return true;
00601 
00602         if (BitPosition() == 0)
00603         {
00604             break;
00605         }
00606         RewindBits(1);
00607     }
00608     return false; // +++ should rewind to previous position
00609 }
00610 
00611 inline bool
00612 SBitstreamReader::FindByteAlignedReverse(uint32_t pattern, size_t bits)
00613 {
00614     int32_t pos = (int32_t)BitPosition();
00615     pos -= (bits + 7);
00616     pos = (pos + 0x7) & ~0x7;
00617     if (pos < 0)
00618     {
00619         return false;
00620     }
00621     SetBytePosition(pos >> 3);
00622     while (true)
00623     {
00624         uint32_t v = PeekBits(bits);
00625         if (v == pattern) return true;
00626 
00627         if (BitPosition() == 0)
00628         {
00629             break;
00630         }
00631         RewindBits(8);
00632     }
00633 
00634     return false; // +++ should rewind to previous position
00635 }
00636 
00637 inline size_t
00638 SBitstreamReader::BytesAvailable() const
00639 {
00640     return ByteLength() - BytePosition();
00641 }
00642 
00643 inline size_t
00644 SBitstreamReader::BytePosition() const
00645 {
00646     const SFragment& f = m_fragments[m_fragmentIndex];
00647     size_t pos = f.offset + (f.size - m_fragmentRemaining);
00648     pos -= ((m_cacheSize - m_cacheOffset) >> 3);
00649     return pos;
00650 }
00651 
00652 inline size_t
00653 SBitstreamReader::BitPosition() const
00654 {
00655     const SFragment& f = m_fragments[m_fragmentIndex];
00656     size_t pos = f.offset + (f.size - m_fragmentRemaining);
00657     pos <<= 3;
00658     pos -= (m_cacheSize - m_cacheOffset);
00659     return pos;
00660 }
00661 
00662 inline status_t
00663 SBitstreamReader::SetBytePosition(size_t pos)
00664 {
00665     // find fragment corresponding to pos
00666     size_t findex;
00667     for (findex = 0; findex < m_fragmentCount; findex++)
00668     {
00669         const SFragment & f = m_fragments[findex];
00670         size_t offset = f.offset;
00671         size_t end = offset + f.size;
00672         if (offset <= pos && end >= pos)
00673         {
00674             // cache
00675             m_fragmentIndex = findex;
00676             m_fragmentPointer = m_fragments[findex].data + (pos - offset);
00677             m_fragmentRemaining = end - pos;
00678             m_cacheOffset = 0;
00679             m_cacheSize = fill_forward(0);
00680             m_cacheSize += fill_forward(4);
00681             return B_OK;
00682         }
00683     }
00684     return B_OUT_OF_RANGE;
00685 }
00686 
00687 inline status_t
00688 SBitstreamReader::SetBitPosition(size_t pos)
00689 {
00690     status_t result = SetBytePosition(pos >> 3);
00691     if (result < B_OK)
00692     {
00693         return result;
00694     }
00695     size_t bit = pos & 0x7;
00696     if (BitsAvailable() < bit)
00697     {
00698         return B_OUT_OF_RANGE;
00699     }
00700     SkipBits(bit);
00701     return B_OK;
00702 }
00703 
00704 inline size_t
00705 SBitstreamReader::ByteLength() const
00706 {
00707     if (m_fragmentCount == 0)
00708     {
00709         return 0;
00710     }
00711     const SFragment& f = m_fragments[m_fragmentCount-1];
00712     return f.offset + f.size;
00713 }
00714 
00715 #if _SUPPORTS_NAMESPACE
00716 } } // palmos::support
00717 #endif
00718 
00719 #endif // _SUPPORT_BITSTREAM_READER_H_