// // Copyright (c) ANSCENTER. All rights reserved. // #include "precomp.h" #include #include #ifdef _WIN32 #include #endif #include "bitstream.h" using namespace std; BitStream::BitStream(int bitSize) { Create(bitSize); } BitStream::BitStream(vector& buf, int bufBits) { Attach(buf, bufBits); } bool BitStream::Create(int bitCount) { m_bufBits = bitCount; m_currentBitIndex = 0; if (!bitCount) { m_buf.clear(); return true; } m_buf.resize((bitCount + 7) >> 3); Clear(); return true; } void BitStream::Attach(vector& buf, int bufBits) { m_buf = std::move(buf); m_bufBits = bufBits; m_currentBitIndex = 0; } int BitStream::Read(void *bitPtr, int bitCount) { if(bitCount + m_currentBitIndex > m_bufBits) { bitCount = m_bufBits - m_currentBitIndex; } if(!bitCount) { return 0; } int readBitCount = bitCount; unsigned char lastByteMask = (unsigned char)((1 << (readBitCount & 7)) - 1); unsigned char * sourcePtr = m_buf.data() + (m_currentBitIndex >> 3); int byteCount = (bitCount + 7) >> 3; unsigned char * destPtr = (unsigned char *)bitPtr; int downShift = m_currentBitIndex & 0x7; int upShift = 8 - downShift; if (!downShift) { while(byteCount--) *destPtr++ = *sourcePtr++; m_currentBitIndex += bitCount; if (lastByteMask > 0) ((unsigned char *)bitPtr)[readBitCount >> 3] &= lastByteMask; return readBitCount; } unsigned char sourceByte = *sourcePtr >> downShift; m_currentBitIndex += bitCount; for (; bitCount > 8; bitCount -= 8) { unsigned char nextByte = *++sourcePtr; *destPtr++ = sourceByte | (nextByte << upShift); sourceByte = nextByte >> downShift; } if (bitCount) { if (bitCount <= upShift) { *destPtr = sourceByte; return readBitCount; } *destPtr = sourceByte | ( (*++sourcePtr) << upShift); } if (lastByteMask > 0) ((unsigned char *)bitPtr)[readBitCount >> 3] &= lastByteMask; return readBitCount; } int BitStream::Write(const void * bitPtr, int bitCount) { int maxBits = ((m_bufBits + 7) >> 3) << 3; if (bitCount + m_currentBitIndex > maxBits) { bitCount = maxBits - m_currentBitIndex; } if(!bitCount) return 0; int writeBitCount = bitCount; int upShift = m_currentBitIndex & 0x7; int downShift = 8 - upShift; const unsigned char * sourcePtr = (unsigned char *)bitPtr; unsigned char * destPtr = m_buf.data() + (m_currentBitIndex >> 3); // if this write is for <= 1 byte, and it will all fit in the // first dest byte, then do some special masking. if (downShift >= bitCount) { unsigned char mask = (unsigned char)(((1 << bitCount) - 1) << upShift); *destPtr = (*destPtr & ~mask) | ((*sourcePtr << upShift) & mask); m_currentBitIndex += bitCount; return writeBitCount; } // check for byte aligned writes -- this will be // much faster than the shifting writes. if(!upShift) { m_currentBitIndex += bitCount; for(; bitCount >= 8; bitCount -= 8) *destPtr++ = *sourcePtr++; if(bitCount) { unsigned char mask = (unsigned char)((1 << bitCount) - 1); *destPtr = (*sourcePtr & mask) | (*destPtr & ~mask); } return writeBitCount; } // the write destination is not byte aligned. unsigned char sourceByte; unsigned char destByte = *destPtr & (0xFF >> downShift); unsigned char lastMask = (unsigned char)(0xFF >> (7 - ((m_currentBitIndex + bitCount - 1) & 0x7))); m_currentBitIndex += bitCount; for(;bitCount >= 8; bitCount -= 8) { sourceByte = *sourcePtr++; *destPtr++ = destByte | (sourceByte << upShift); destByte = sourceByte >> downShift; } if(bitCount == 0) { *destPtr = (*destPtr & ~lastMask) | (destByte & lastMask); return writeBitCount; } if(bitCount <= downShift) { *destPtr = (*destPtr & ~lastMask) | ((destByte | (*sourcePtr << upShift)) & lastMask); return writeBitCount; } sourceByte = *sourcePtr; *destPtr++ = destByte | (sourceByte << upShift); *destPtr = (*destPtr & ~lastMask) | ((sourceByte >> downShift) & lastMask); return writeBitCount; } void BitStream::ZeroPadToNextByte() { unsigned char zero = 0; if(m_currentBitIndex & 0x7) Write(&zero, 8 - (m_currentBitIndex & 0x7)); } int BitStream::Seek(int offset, bool relative) { unsigned oldIndex = m_currentBitIndex; m_currentBitIndex = (relative) ? m_currentBitIndex + offset : offset; return oldIndex; } int BitStream::GetSize() { return m_bufBits; } void * BitStream::GetBuffer(int * sizeInBits) { if (sizeInBits != NULL) *sizeInBits = m_bufBits; return m_buf.data(); } void BitStream::ReleaseBuffer(int bitCount) { m_currentBitIndex = bitCount; } void BitStream::Clear() { memset(m_buf.data(), 0, m_buf.size()); }