Files
ANSCORE/anslicensing/bitstream.cpp

233 lines
4.7 KiB
C++

//
// Copyright (c) ANSCENTER. All rights reserved.
//
#include "precomp.h"
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <tchar.h>
#endif
#include "bitstream.h"
using namespace std;
BitStream::BitStream(int bitSize)
{
Create(bitSize);
}
BitStream::BitStream(vector<unsigned char>& 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<unsigned char>& 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());
}