//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / OVOPS++
//
//File: frame.cpp
//
//Version: $Revision: 1.24 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/10/05 07:09:48 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Authors:
//      Pasi Nummisalo
//      Timo Pärnänen
//      Juhana Räsänen
//	Vesa-Matti Puro
//	Sami Raatikainen
//
//Description:
//	See corresponding header file.  
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//      
//Licence:
//     
//
//History:
//
//

#include "frame.h"
#include <assert.h>
#include "bytes.h"

//
//Function: FrameContainer constructors
//
//Description:
//      Allocate container's data area and initializes container.
//      Begin and end pointers are set to the middle of the frame
//      so that there is about equal amout of free buffer for both
//      head and tail parts of the frame. The buffer is circular,
//      however, so user needs not worry about how the buffer is
//      actually utilized.
//      NOTE: reference count is initialized to 0, so it is the
//      callers responsibility to update it correctly.
//

pfFrame :: FrameContainer :: FrameContainer(pfUlong dataSize_)
    : _data(0),
      _referenceCount(0),
      _beginPointer(dataSize_ / 2),
      _endPointer(dataSize_ / 2 + 1),
      _dataSize(dataSize_)
{
    _data = allocateFrameData(dataSize_);
    return;
}

pfFrame :: FrameContainer :: FrameContainer(
    const pfByte *data_,
    pfUlong length_,
    pfUlong dataSize_)
    : _data(0),
      _referenceCount(0),
      _beginPointer(0),
      _endPointer(0),
      _dataSize(dataSize_)
{
    if (dataSize_ < length_)
    {
        _dataSize = length_;
    }
    //assert((data_ != 0) && (_dataSize > 0));
    _data = allocateFrameData(_dataSize);
    _beginPointer = _dataSize - 1;
    _endPointer = length_;
    memcpy(_data, data_, length_);
    return;
}

pfFrame :: FrameContainer :: FrameContainer(const FrameContainer &other_)
    : _data(0),
      _referenceCount(0),
      _beginPointer(other_._beginPointer),
      _endPointer(other_._endPointer),
      _dataSize(other_._dataSize)
{
    _data = allocateFrameData(other_._dataSize);
    memcpy(_data, other_._data, other_._dataSize);
    return;
}

//
//Function: FrameContainer destructor
//
//Description:
//      Frees the allocated frame data.
//

pfFrame :: FrameContainer :: ~FrameContainer(void)
{
    freeFrameData(_data, _dataSize);
    return;
}

//
//Function: length
//
//Description:
//      Returns the number of octets in the container.
//

pfUlong pfFrame :: FrameContainer :: length(void) const
{
    pfUlong value = 0;
    
    // If _endPointer has not wrapped around _dataSize (is greater than
    // _beginPointer), the number of octets in frame are the number of
    // octets between pointers.
    if (_beginPointer < _endPointer)
    {
        value = _endPointer - _beginPointer - 1;
    }
    
    // If _endPointer has wrapped, (is less than _beginPointer), the
    // number of octets in frame is _dataSize minus the number of octets
    // between and under the pointers.
    else if (_beginPointer > _endPointer)
    {
        value = _dataSize - (_beginPointer - _endPointer) - 1;
    }
    
    // Otherwise pointers are equal and the frame is full.
    else
    {
        value = _dataSize;
    }
    return value;
}

//
//Function: getDataSize
//
//Description:
//      Returns the maximum data size of the container.
//

pfUlong pfFrame :: FrameContainer :: getDataSize(void) const
{
    return _dataSize;
}

//
//Function: putFirst methods
//
//Description:
//      Insert an octet or a string to the head of the container.
//      If there is not enough space, an assertion will fail.
//      Should think of a better way to do this.
//

void pfFrame :: FrameContainer :: putFirst(pfByte byte_)
{
    if (_beginPointer == _endPointer)
    {
        expandBuffer();
    }
    
    _data[_beginPointer] = byte_;
    if (_beginPointer > 0)
    {
        _beginPointer--;
    }
    else
    {
        _beginPointer = _dataSize - 1;
    }
    return;
}

void pfFrame :: FrameContainer :: putFirst(const pfByte *byte_, pfUlong length_)
{
    // First check that there is enough room in the data buffer,
    // if not, expand the data area
    if (length_ > (getDataSize() - length()))
    {
        expandBuffer(length_ - (getDataSize() - length()));
    }
    
    // If all of new data would fit in the beginning part of the
    // frame, it can be copied in one chunk, even if _endPointer
    // is smaller than _beginPointer - think about it.
    if (_beginPointer >= (length_ - 1))
    {
        memcpy(&(_data[_beginPointer - length_ + 1]), byte_, length_);
        
        // It might just happen, that the data length is exactly the
        // length of the beginning part, in which case _beginPointer
        // must point to the first free octet before data - ie the
        // LAST octet of the data buffer.
        if (length_ > _beginPointer)
        {
            _beginPointer = _dataSize - 1;
        }
        else
        {
            _beginPointer -= length_;
        }
    }
    
    // This branch copies the data in two chunks. Head part contains
    // octets _data[0.._beginPointer] and the tail part the rest.
    else
    {
        pfUlong headLength = _beginPointer + 1;
        pfUlong tailLength = length_ - headLength;
        memcpy(_data, &(byte_[tailLength]), headLength);
        memcpy(&(_data[_dataSize - tailLength]), byte_, tailLength);
        _beginPointer = _dataSize - tailLength - 1;
    }
    return;
}

//
//Function: getFirst
//
//Description:
//      Returns and removes the first octet in the container, 0
//      if the container is empty.
//

pfByte pfFrame :: FrameContainer :: getFirst(void)
{
    pfByte octet = 0;
    if (length() > 0)
    {
        _beginPointer = (_beginPointer + 1) % _dataSize;
        octet = _data[_beginPointer];
    }
    return octet;
}

//
//Function: putLast methods
//
//Description:
//      Append an octet or a string to the end of the container.
//      If there is not enough space, an assertion will fail.
//      Should think of a better way to do this.
//

void pfFrame :: FrameContainer :: putLast(pfByte byte_)
{
    if (_beginPointer == _endPointer)
    {
        expandBuffer();
    }
    
    _data[_endPointer] = byte_;
    _endPointer = (_endPointer + 1) % _dataSize;
    return;
}

void pfFrame :: FrameContainer :: putLast(const pfByte *byte_, pfUlong length_)
{
    // First check that there is enough room in the data buffer,
    // if not, expand the data area
    if (length_ > (getDataSize() - length()))
    {
        expandBuffer(length_ - (getDataSize() - length()));
    }
    
    // If all of new data would fit in the end part of the frame,
    // it can be copied in one chunk, even if _beginPointer is
    // greater than _beginPointer - think about it.
    if ((getDataSize() - _endPointer) >= length_)
    {
        memcpy(&(_data[_endPointer]), byte_, length_);
        _endPointer = (_endPointer + length_) % _dataSize;
    }
    
    // This branch copies the data in two chunks. Tail part contains
    // octets _data[_endPointer.._dataSize-1] and the head part the rest.
    else
    {
        pfUlong tailLength = getDataSize() - _endPointer;
        pfUlong headLength = length_ - tailLength;
        memcpy(&(_data[_endPointer]), byte_, tailLength);
        memcpy(_data, &(byte_[tailLength]), headLength);
        _endPointer = headLength;
    }
    return;
}

//
//Function: getLast
//
//Description:
//      Returns and removes the last octet in the container, 0
//      if the container is empty.
//

pfByte pfFrame :: FrameContainer :: getLast(void)
{
    pfByte octet = 0;
    if (length() > 0)
    {
        if (_endPointer > 0)
        {
            _endPointer--;
        }
        else
        {
            _endPointer = _dataSize - 1;
        }
        octet = _data[_endPointer];
    }
    return octet;
}

//
//Function: read
//
//Description:
//      Returns the octet at the given index in the container but
//      doesn't remove it. If offset is outside boundaries of the
//      container, 0 is returned. The offset 0 indicates first octet.
//      Question: why beginPointer + 1
//

pfByte pfFrame :: FrameContainer :: read(pfUlong offset_) const
{
    pfByte octet = 0;
    if (offset_ < length())
    {
        octet = _data[(_beginPointer + 1 + offset_) % _dataSize];
    }
    return octet;
}

//
//Function: write
//
//Description:
//    Replace the octet at the given index with given byte.
//    If offset is outside boundaries nothing is done, so
//    frame cannot be expanded with write method.
//

void pfFrame :: FrameContainer :: write(pfByte value_, pfUlong offset_)
{
    if (offset_ < length())
    {
        _data[(_beginPointer + 1 + offset_)] = value_;
    }
    return;
}

//
//Function: clear
//
//Description:
//      Empties the frame by setting begin and end pointers to
//      their initial values.
//

void pfFrame :: FrameContainer :: clear(void)
{
    _beginPointer = _dataSize / 2;
    _endPointer = _dataSize / 2 + 1;
    return;
}

//
//Function: FrameContainer reference count methods
//
//Description:
//      Increase, decrease and return reference count on the container.
//

void pfFrame :: FrameContainer :: incRefCount(void)
{
    _referenceCount++;
    return;
}

void pfFrame :: FrameContainer :: decRefCount(void)
{
    _referenceCount--;
    return;
}

int pfFrame :: FrameContainer :: getRefCount(void) const
{
    return _referenceCount;
}

//
//Function: copyData
//
//Description:
//      Copies the contents of the container to the given pointer.
//      Caller must ensure that the pointer is valid and the data
//      area behind it is large enough.
//

void pfFrame :: FrameContainer :: copyData(pfByte *destination_) const
{
    // Simple case: data is in one piece, so one memcpy is enough.
    if (_beginPointer < _endPointer)
    {
        memcpy(destination_, &(_data[_beginPointer + 1]), length());
    }
    
    // Otherwise first part of the data is in the end of the buffer and
    // (possible) second part in the beginning.
    else
    {
        pfUlong tailSize = getDataSize() - _beginPointer - 1;
        memcpy(destination_, &(_data[_beginPointer + 1]), tailSize);
        
        // If _endPointer is 0, there is no data in the beginning of the
        // data buffer (_endPointer points to the FREE index in the end)
        if (_endPointer > 0)
        {
            memcpy(&(destination_[tailSize]), _data, _endPointer);
        }
        
        // Special case: buffer is full, and the very last octet must be
        // copied separately
        if (_endPointer == _beginPointer)
        {
            destination_[length() - 1] = _data[_endPointer];
        }
    }
    return;
}

//
//Function: expandBuffer
//
//Description:
//      Expand data area. Size of the expansion is minimumGrowth_ plus
//      current buffer size times two, not more than minimumGrowth_ plus
//      MAX_GROWTH, however. Data is copied to the new area and the old
//      data area is discarded.
//

void pfFrame :: FrameContainer :: expandBuffer(pfUlong minimumGrowth_)
{
    pfUlong saveLength = length();
    pfUlong delta = _dataSize;
    if (delta > MAX_GROWTH)
    {
        delta = MAX_GROWTH;
    }
    delta += minimumGrowth_;
    pfByte *newData = allocateFrameData(_dataSize + delta);
    copyData(newData);
    freeFrameData(_data, _dataSize);
    _data = newData;
    _dataSize += delta;
    _beginPointer = _dataSize - 1;
    _endPointer = saveLength;
    return;
}

//
//Function: FrameContainer memory management routines
//
//Description:
//      These methods implement a private memory management scheme
//      for containers. Currently they just allocate and free data
//      every time they are called, but a more intelligent scheme
//      will hopefully be implemented some day.
//

pfByte * pfFrame :: FrameContainer :: allocateFrameData(pfUlong dataSize_)
{
    pfByte *data = new pfByte[dataSize_];
    return data;
}

void pfFrame :: FrameContainer :: freeFrameData(pfByte *data_, pfUlong dataSize_)
{
    if (dataSize_ > 0)
    {
        delete [] data_;
    }
    return;
}

//
//Function: pfFrame constructors
//
//Description:
//      Create new instances of pfFrames and allocate FrameFrameContainers
//      for those. Copy constructor does not create a new container
//      but copies the pointer to the other container instead. The
//      reference count must be updated in every constructor, as the
//      container class constructors don't do that.
//

pfFrame :: pfFrame(pfUlong dataSize_)
    : _container(0),
      _useBinary(0)
{
    _container = new FrameContainer(dataSize_);
    _container->incRefCount();
    return;
}

pfFrame :: pfFrame(pfByte *data_, pfUlong length_, pfUlong dataSize_)
    : _container(0),
      _useBinary(0)
{
    _container = new FrameContainer(data_, length_, dataSize_);
    _container->incRefCount();
    return;
}

pfFrame :: pfFrame(const pfFrame &other_)
    : _container(other_._container),
      _useBinary(other_._useBinary)
{
    _container->incRefCount();
    return;
}

//
//Function: pfFrame destructor
//
//Description:
//      Does not delete FrameFrameContainer instance if it is still
//      referenced by another frame, just decreases refcount instead.
//

pfFrame :: ~pfFrame(void)
{
    giveUpFrameContainer();
    return;
}

//
//Function: pfFrame assignment operator
//
//Description:
//      Copies only the pointer of the container of the other frame.
//      The refcount of the old container must be decreased and if
//      no other frames reference to it, it must be deleted.
//

const pfFrame &pfFrame :: operator = (const pfFrame &other_)
{
    if (this != &other_)
    {
        giveUpFrameContainer();
        _container = other_._container;
        _container->incRefCount();
    }
    return *this;
}

//
//Function: length
//
//Description:
//      Returns the number of octets in the frame.
//

pfUlong  pfFrame :: length(void) const
{
    pfUlong frameLength = _container->length();
    return frameLength;
}

//
//Function: getDataSize
//
//Description:
//      Returns maximum data size of the frame.
//

pfUlong pfFrame :: getDataSize(void) const
{
    pfUlong dataSize = _container->getDataSize();
    return dataSize;
}

pfUlong pfFrame :: toInteger(void) const
    throw (pfBadValue)
{
    pfUlong result;
    pfFrame frame(*this);
    switch (frame.length())
    {
        case 1:
            result = frame.getFirst();
            break;
        case 2:
            result = frame.getFirst16bit();
            break;
        case 3:
            result = frame.getFirst24bit();
            break;
        case 4:
            result = frame.getFirst32bit();
            break;
        default:
            throw pfBadValue(0, 0, 4294967295, PF_EX_INFO);
            break;
    }
    return result;
}

void pfFrame :: fromInteger(const pfUlong value_)
{
    clear();
    if (value_ < 256)
    {
        putFirst(value_);
    }
    else if (value_ < 65536)
    {
        putFirst16bit(value_);
    }
    else if (value_ < 16777216)
    {
        putFirst24bit(value_);
    }
    else
    {
        putFirst32bit(value_);
    }
    return;
}

string pfFrame :: toString(void) const
{
    string result;
    if (_useBinary == 0)
    {
        result = toHex();
    }
    else
    {
        result = toBit();
    }
    return result;
}

void pfFrame :: fromString(const string &octetstring_)
{
    if (_useBinary == 0)
    {
        fromHex(octetstring_);
    }
    else
    {
        fromBit(octetstring_);
    }
    return;
}

void pfFrame :: useBinary(void)
{
    _useBinary = 1;
    return;
}

void pfFrame :: useHex(void)
{
    _useBinary = 0;
    return;
}

//
//Function: putFirst methods
//
//Description:
//      Insert an octet or a string to the head of the frame.
//      If the container of this frame is shared by other frames,
//      a copy must be made before inserting. 16/24/32-bit versions
//      insert a 16/24/32 bit integer respectively, MSB first.
//

void pfFrame :: putFirst(pfByte byte_)
{
    copyIfNecessary();
    _container->putFirst(byte_);
    return;
}

void pfFrame :: putFirst16bit(pfUlong value_)
{
    copyIfNecessary();
    _container->putFirst((value_ & B1111_1111));
    _container->putFirst(((value_ >> 8) & B1111_1111));
    return;
}

void pfFrame :: putFirst24bit(pfUlong value_)
{
    copyIfNecessary();
    _container->putFirst((value_ & B1111_1111));
    _container->putFirst(((value_ >> 8) & B1111_1111));
    _container->putFirst(((value_ >> 16) & B1111_1111));
    return;
}

void pfFrame :: putFirst32bit(pfUlong value_)
{
    copyIfNecessary();
    _container->putFirst((value_ & B1111_1111));
    _container->putFirst(((value_ >> 8) & B1111_1111));
    _container->putFirst(((value_ >> 16) & B1111_1111));
    _container->putFirst(((value_ >> 24) & B1111_1111));
    return;
}

void pfFrame :: putFirst(const pfByte *byte_, pfUlong length_)
{
    copyIfNecessary();
    _container->putFirst(byte_, length_);
    return;
}

//
//Function: getFirst methods
//
//Description:
//      Removes and returns the first octet in the frame. As the
//      frame is modified, we must check if other frames reference
//      to the same container and make a copy if necessary. 16/24/32-
//      bit versions return and remove a 16/24/32 bit integer.
//

pfByte pfFrame :: getFirst(void)
{
    copyIfNecessary();
    pfByte value = _container->getFirst();
    return value;
}

pfUlong pfFrame :: getFirst16bit(void)
{
    copyIfNecessary();
    pfUlong value = _container->getFirst() << 8;
    value += _container->getFirst();
    value &= 0xFFFF; // 64-bit safe
    return value;
}

pfUlong pfFrame :: getFirst24bit(void)
{
    copyIfNecessary();
    pfUlong value = _container->getFirst() << 16;
    value += _container->getFirst() << 8;
    value += _container->getFirst();
    value &= 0xFFFFFF; // 64-bit safe
    return value;
}

pfUlong pfFrame :: getFirst32bit(void)
{
    copyIfNecessary();
    pfUlong value = _container->getFirst() << 24;
    value += _container->getFirst() << 16;
    value += _container->getFirst() << 8;
    value += _container->getFirst();
    value &= 0xFFFFFFFF; // 64-bit safe
    return value;
}

//
//Function: putLast methods
//
//Description:
//      Append an octet or a string to the end of the frame.
//      If the container of this frame is shared by other frames,
//      a copy must be made before inserting. 16/24/32-bit versions
//      append a 16/24/32 bit integer respectively, MSB first.
//

void pfFrame :: putLast(pfByte byte_)
{
    copyIfNecessary();
    _container->putLast(byte_);
    return;
}

void pfFrame :: putLast16bit(pfUlong value_)
{
    copyIfNecessary();
    _container->putLast(((value_ >> 8) & B1111_1111));
    _container->putLast((value_ & B1111_1111));
    return;
}

void pfFrame :: putLast24bit(pfUlong value_)
{
    copyIfNecessary();
    _container->putLast(((value_ >> 16) & B1111_1111));
    _container->putLast(((value_ >> 8) & B1111_1111));
    _container->putLast((value_ & B1111_1111));
    return;
}

void pfFrame :: putLast32bit(pfUlong value_)
{
    copyIfNecessary();
    _container->putLast(((value_ >> 24) & B1111_1111));
    _container->putLast(((value_ >> 16) & B1111_1111));
    _container->putLast(((value_ >> 8) & B1111_1111));
    _container->putLast((value_ & B1111_1111));
    return;
}

void pfFrame :: putLast(const pfByte *byte_, pfUlong length_)
{
    copyIfNecessary();
    _container->putLast(byte_, length_);
    return;
}

//
//Function: getLast methods
//
//Description:
//      Removes and returns the last octet in the frame. As the
//      frame is modified, we must check if other frames reference
//      to the same container and make a copy if necessary. 16/24/32-
//      bit versions return and remove a 16/24/32 bit integer.
//

pfByte pfFrame :: getLast(void)
{
    copyIfNecessary();
    pfByte value = _container->getLast();
    return value;
}

pfUlong pfFrame :: getLast16bit(void)
{
    copyIfNecessary();
    pfUlong value = _container->getLast();
    value += _container->getLast() << 8;
    value &= 0xFFFF; // 64-bit safe
    return value;
}

pfUlong pfFrame :: getLast24bit(void)
{
    copyIfNecessary();
    pfUlong value = _container->getLast();
    value += _container->getLast() << 8;
    value += _container->getLast() << 16;
    value &= 0xFFFFFF; // 64-bit safe
    return value;
}

pfUlong pfFrame :: getLast32bit(void)
{
    copyIfNecessary();
    pfUlong value = _container->getLast();
    value += _container->getLast() << 8;
    value += _container->getLast() << 16;
    value += _container->getLast() << 24;
    value &= 0xFFFFFFFF; // 64-bit safe
    return value;
}

//
//Function: read methods
//
//Description:
//      Returns the octet at the given index. Frame is not modified,
//      so it is not necessary to check reference count. 16/24/32-bit
//      versions read a 16/24/32 bit integer.
//

pfByte pfFrame :: read(pfUlong offset_) const
{
    pfByte value = _container->read(offset_);
    return value;
}

pfUlong pfFrame :: read16bit(pfUlong offset_) const
{
    pfUlong value = _container->read(offset_) << 8;
    value += _container->read(offset_ + 1);
    value &= 0xFFFF; // 64-bit safe
    return value;
}

pfUlong pfFrame :: read24bit(pfUlong offset_) const
{
    pfUlong value = _container->read(offset_) << 16;
    value += _container->read(offset_ + 1) << 8;
    value += _container->read(offset_ + 2);
    value &= 0xFFFFFF; // 64-bit safe
    return value;
}

pfUlong pfFrame :: read32bit(pfUlong offset_) const
{
    pfUlong value = _container->read(offset_) << 24;
    value += _container->read(offset_ + 1) << 16;
    value += _container->read(offset_ + 2) << 8;
    value += _container->read(offset_ + 3);
    value &= 0xFFFFFFFF; // 64-bit safe
    return value;
}

//
//Function: write methods
//
//Description:
//    Replace the octet at the given index with given byte.
//

void pfFrame :: write(pfByte value_, pfUlong offset_)
{
    copyIfNecessary();
    _container->write(value_, offset_);
    return;
}

//
//Function: getSubFrame
//
//Description:
//    Get a sub frame of given length starting at given offset.
//    Offset zero (start_ = 0) indicates first octet (begin of frame).
//

pfFrame pfFrame :: getSubFrame(pfUlong start_, pfUlong length_) const
{
    pfFrame frame;
    pfUlong size = length();
    length_ += start_;
    while ((start_ < length_) && (start_ < size))
    {
        frame.putLast(read(start_));
        start_++;
    }
    return frame;
}

//
//Function: clear
//
//Description:
//      If the container of this frame is shared with other frames,
//      a new (empty) instance of a FrameFrameContainer is created, otherwise
//      the container is just cleared.
//

void pfFrame :: clear(void)
{
    if (_container->getRefCount() > 1)
    {
        _container->decRefCount();
        _container = new FrameContainer(_container->getDataSize());
        _container->incRefCount();
    }
    else
    {
        _container->clear();
    }
    return;
}

//
//Function: destroy
//
//Description:
//      Just call pfFrame::clear (backwards compatibility, in this
//      implementation there is no difference between these two methods).
//

void pfFrame :: destroy(void)
{
    clear();
    return;
}

//
//Function: setData
//
//Description:
//      Copies the given string to the frame. This is done by creating
//      a new instance of FrameFrameContainer, so reference count must be
//      checked.
//

void pfFrame :: setData(const pfByte *data_, pfUlong length_)
{
    // Check that the given string is not longer than the existing
    // container's datasize, if so, we must allocate a big enough
    // container.
    pfUlong datasize = _container->getDataSize();
    if (length_ > datasize)
    {
        datasize = length_;
    }
    
    giveUpFrameContainer();
    _container = new FrameContainer(data_, length_, datasize);
    _container->incRefCount();
    return;
}

//
//Function: copyData
//
//Description:
//      Copies the data of the frame to the given memory location.
//      Caller must be sure that the pointer is valid and enough
//      space has been allocated to hold all of data.
//

void pfFrame :: copyData(pfByte *destination_) const
{
    _container->copyData(destination_);
    return;
}

//
//Function: copyIfNecessary
//
//Description:
//      If the container attached to this frame is referenced by other
//      frames, make a new copy of the container that is not shared with
//      any other frame. This is used only by other pfFrame methods
//      (eg put/get methods).
//

void pfFrame :: copyIfNecessary(void)
{
    if (_container->getRefCount() > 1)
    {
        _container->decRefCount();
        _container = new FrameContainer(*_container);
        _container->incRefCount();
    }
    return;
}

//
//Function: giveUpFrameContainer
//
//Description:
//      Gives up the current container. If it is referenced by other
//      frames, just decrease the reference count, otherwise delete
//      the container instance.
//

void pfFrame :: giveUpFrameContainer(void)
{
    if (_container->getRefCount() > 1)
    {
        _container->decRefCount();
    }
    else
    {
        delete _container;
    }
    _container = 0;
    return;
}

void pfFrame :: fromBit(const string &bitstring_)
{
    pfUlong value = 0;
    pfUlong bitsLength = bitstring_.size(); 
    pfUlong bitsIndex = 0; 
    pfUlong bitsCoded = 0;

    clear();
    if ((bitsLength % 8) != 0)
    {
        bitsCoded += (8 - (bitsLength % 8));
        bitsLength += (8 - (bitsLength % 8));
    }
    while (bitsCoded < bitsLength)
    {
        value <<= 1;
        char bit = bitstring_.at (bitsIndex);
        switch (bit)
        {
            case '0':
	        value |= 0x00;
                break;
	    case '1':
	        value |= 0x01;
	        break;
	    default:
	        assert (0);
	        break;
        }
        ++bitsCoded;
        ++bitsIndex;
        if ((bitsCoded % 8) == 0)
        {
            putLast(value);
            value = 0;
        }
    }
    return;
}

string pfFrame :: toBit(void) const
{
    string bitstring;
    pfUlong value = 0;
    pfUlong bitsLength = 8 * length();
    pfUlong frameIndex = length() - 1;
    pfUlong bitsCoded = 0;

    while (bitsCoded < bitsLength)
    {
        if ((bitsCoded % 8) == 0)
        {
            value = read (frameIndex);
            --frameIndex;
        }
        if (value & 0x01)
        {
            bitstring.insert (0, "1");
        }
        else
        {
            bitstring.insert (0, "0");
        }
        value >>= 1;
        ++bitsCoded;
    }
    return bitstring;
}

string pfFrame :: toHex (void) const
{
    string hexstring;
    pfUlong value = 0;
    pfUlong digitsLength = 2 * length();
    pfUlong frameIndex = length() - 1;
    pfUlong digitsCoded = 0;

    while (digitsCoded < digitsLength)
    {
        if ((digitsCoded % 2) == 0)
        {
            value = read (frameIndex);
            --frameIndex;
        }
        switch (value & 0x0f)
        {
            case 0:
                hexstring.insert (0, "0");
                break;
            case 1:
                hexstring.insert (0, "1");
                break;
            case 2:
                hexstring.insert (0, "2");
                break;
            case 3:
                hexstring.insert (0, "3");
                break;
            case 4:
                hexstring.insert (0, "4");
                break;
            case 5:
                hexstring.insert (0, "5");
                break;
            case 6:
                hexstring.insert (0, "6");
                break;
            case 7:
                hexstring.insert (0, "7");
                break;
            case 8:
                hexstring.insert (0, "8");
                break;
            case 9:
                hexstring.insert (0, "9");
                break;
            case 10:
                hexstring.insert (0, "A");
                break;
            case 11:
                hexstring.insert (0, "B");
                break;
            case 12:
                hexstring.insert (0, "C");
                break;
            case 13:
                hexstring.insert (0, "D");
                break;
            case 14:
                hexstring.insert (0, "E");
                break;
            case 15:
                hexstring.insert (0, "F");
                break;
	    default:
	        assert (0);
	        break;
        }

        value >>= 4;
        ++digitsCoded;
    }
    return hexstring;
}


void pfFrame :: fromHex (const string &hexstring_)
    {
    pfUlong value = 0;
    pfUlong digitsLength = hexstring_.size(); 
    pfUlong digitsIndex = 0; 
    pfUlong digitsCoded = 0;

    clear();
    if ((digitsLength % 2) != 0)
    {
        ++digitsCoded;
        ++digitsLength;
    }
    while (digitsCoded < digitsLength) 
        {
        char hexchar = hexstring_.at (digitsIndex);
        value <<= 4;
        switch (hexchar)
            {
            case '0':
	        value |= 0x00;
                break;
	    case '1':
	        value |= 0x01;
	        break;
	    case '2':
	        value |= 0x02;
	        break;
	    case '3':
	        value |= 0x03;
	        break;
	    case '4':
	        value |= 0x04;
	        break;
	    case '5':
	        value |= 0x05;
	        break;
	    case '6':
	        value |= 0x06;
	        break;
	    case '7':
	        value |= 0x07;
	        break;
	    case '8':
	        value |= 0x08;
	        break;
	    case '9':
	        value |= 0x09;
	        break;
	    case 'A':
	        value |= 0x0A;
	        break;
	    case 'B':
	        value |= 0x0B;
	        break;
	    case 'C':
	        value |= 0x0C;
	        break;
	    case 'D':
	        value |= 0x0D;
	        break;
	    case 'E':
	        value |= 0x0E;
	        break;
	    case 'F':
	        value |= 0x0F;
	        break;
	    default:
	        assert (0);
	        break;
            }
        ++digitsCoded;
        ++digitsIndex;
        if ((digitsCoded % 2) == 0)
        {
            putLast(value);
            value = 0;
        }
    }
    return;
}

