/********** 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 .) 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; } } }