blob: 0374e947afac0501495c41ed4a257ea231a189a6 [file] [log] [blame]
/**********
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
more details.
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
**********/
// "liveMedia"
// Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved.
// Bit Vector data structure
// Implementation
#include "BitVector.hh"
BitVector::BitVector(unsigned char* baseBytePtr,
unsigned baseBitOffset,
unsigned totNumBits) {
setup(baseBytePtr, baseBitOffset, totNumBits);
}
void BitVector::setup(unsigned char* baseBytePtr,
unsigned baseBitOffset,
unsigned totNumBits) {
fBaseBytePtr = baseBytePtr;
fBaseBitOffset = baseBitOffset;
fTotNumBits = totNumBits;
fCurBitIndex = 0;
}
static unsigned char const singleBitMask[8]
= {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
#define MAX_LENGTH 32
void BitVector::putBits(unsigned from, unsigned numBits) {
if (numBits == 0) return;
unsigned char tmpBuf[4];
unsigned overflowingBits = 0;
if (numBits > MAX_LENGTH) {
numBits = MAX_LENGTH;
}
if (numBits > fTotNumBits - fCurBitIndex) {
overflowingBits = numBits - (fTotNumBits - fCurBitIndex);
}
tmpBuf[0] = (unsigned char)(from>>24);
tmpBuf[1] = (unsigned char)(from>>16);
tmpBuf[2] = (unsigned char)(from>>8);
tmpBuf[3] = (unsigned char)from;
shiftBits(fBaseBytePtr, fBaseBitOffset + fCurBitIndex, /* to */
tmpBuf, MAX_LENGTH - numBits, /* from */
numBits - overflowingBits /* num bits */);
fCurBitIndex += numBits - overflowingBits;
}
void BitVector::put1Bit(unsigned bit) {
// The following is equivalent to "putBits(..., 1)", except faster:
if (fCurBitIndex >= fTotNumBits) { /* overflow */
return;
} else {
unsigned totBitOffset = fBaseBitOffset + fCurBitIndex++;
unsigned char mask = singleBitMask[totBitOffset%8];
if (bit) {
fBaseBytePtr[totBitOffset/8] |= mask;
} else {
fBaseBytePtr[totBitOffset/8] &=~ mask;
}
}
}
unsigned BitVector::getBits(unsigned numBits) {
if (numBits == 0) return 0;
unsigned char tmpBuf[4];
unsigned overflowingBits = 0;
if (numBits > MAX_LENGTH) {
numBits = MAX_LENGTH;
}
if (numBits > fTotNumBits - fCurBitIndex) {
overflowingBits = numBits - (fTotNumBits - fCurBitIndex);
}
shiftBits(tmpBuf, 0, /* to */
fBaseBytePtr, fBaseBitOffset + fCurBitIndex, /* from */
numBits - overflowingBits /* num bits */);
fCurBitIndex += numBits - overflowingBits;
unsigned result
= (tmpBuf[0]<<24) | (tmpBuf[1]<<16) | (tmpBuf[2]<<8) | tmpBuf[3];
result >>= (MAX_LENGTH - numBits); // move into low-order part of word
result &= (0xFFFFFFFF << overflowingBits); // so any overflow bits are 0
return result;
}
unsigned BitVector::get1Bit() {
// The following is equivalent to "getBits(1)", except faster:
if (fCurBitIndex >= fTotNumBits) { /* overflow */
return 0;
} else {
unsigned totBitOffset = fBaseBitOffset + fCurBitIndex++;
unsigned char curFromByte = fBaseBytePtr[totBitOffset/8];
unsigned result = (curFromByte >> (7-(totBitOffset%8))) & 0x01;
return result;
}
}
void BitVector::skipBits(unsigned numBits) {
if (numBits > fTotNumBits - fCurBitIndex) { /* overflow */
fCurBitIndex = fTotNumBits;
} else {
fCurBitIndex += numBits;
}
}
unsigned BitVector::get_expGolomb() {
unsigned numLeadingZeroBits = 0;
unsigned codeStart = 1;
while (get1Bit() == 0 && fCurBitIndex < fTotNumBits) {
++numLeadingZeroBits;
codeStart *= 2;
}
return codeStart - 1 + getBits(numLeadingZeroBits);
}
int BitVector::get_expGolombSigned() {
unsigned codeNum = get_expGolomb();
if ((codeNum&1) == 0) { // even
return -(int)(codeNum/2);
} else { // odd
return (codeNum+1)/2;
}
}
void shiftBits(unsigned char* toBasePtr, unsigned toBitOffset,
unsigned char const* fromBasePtr, unsigned fromBitOffset,
unsigned numBits) {
if (numBits == 0) return;
/* Note that from and to may overlap, if from>to */
unsigned char const* fromBytePtr = fromBasePtr + fromBitOffset/8;
unsigned fromBitRem = fromBitOffset%8;
unsigned char* toBytePtr = toBasePtr + toBitOffset/8;
unsigned toBitRem = toBitOffset%8;
while (numBits-- > 0) {
unsigned char fromBitMask = singleBitMask[fromBitRem];
unsigned char fromBit = (*fromBytePtr)&fromBitMask;
unsigned char toBitMask = singleBitMask[toBitRem];
if (fromBit != 0) {
*toBytePtr |= toBitMask;
} else {
*toBytePtr &=~ toBitMask;
}
if (++fromBitRem == 8) {
++fromBytePtr;
fromBitRem = 0;
}
if (++toBitRem == 8) {
++toBytePtr;
toBitRem = 0;
}
}
}