tripwire-open-source/src/twcrypto/bytequeue.cpp

346 lines
8.4 KiB
C++

//
// The developer of the original code and/or files is Tripwire, Inc.
// Portions created by Tripwire, Inc. are copyright (C) 2000-2019 Tripwire,
// Inc. Tripwire is a registered trademark of Tripwire, Inc. All rights
// reserved.
//
// This program is free software. The contents of this file are subject
// to the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version. You may redistribute it and/or modify it
// only in compliance with the GNU General Public License.
//
// This program is distributed in the hope that it will be useful.
// However, this program is distributed AS-IS WITHOUT ANY
// WARRANTY; INCLUDING THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS
// FOR A PARTICULAR PURPOSE. Please see the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//
// Nothing in the GNU General Public License or any other license to use
// the code or files shall permit you to use Tripwire's trademarks,
// service marks, or other intellectual property without Tripwire's
// prior written consent.
//
// If you have any questions, please contact Tripwire, Inc. at either
// info@tripwire.org or www.tripwire.org.
//
///////////////////////////////////////////////////////////////////////////////
// bytequeue.cpp - written and placed in the public domain by Wei Dai
// - modified 29 Oct 1998 mdb
#include "stdtwcrypto.h"
#include "bytequeue.h"
#include "cryptlib/queue.h"
#include "cryptlib/misc.h"
//-----------------------------------------------------------------------------
// cByteQueueNode
// this class for use by cByteQueue only
//-----------------------------------------------------------------------------
class cByteQueueNode
{
public:
explicit cByteQueueNode(unsigned int maxSize);
unsigned int CurrentSize() const
{
return tail - head;
}
unsigned int UsedUp() const
{
return (head == MaxSize());
}
unsigned int Put(uint8_t inByte);
unsigned int Put(const uint8_t* inString, unsigned int length);
unsigned int Get(uint8_t& outByte);
unsigned int Get(uint8_t* outString, unsigned int getMax);
unsigned int Peek(uint8_t& outByte) const;
void CopyTo(BufferedTransformation& target) const
{
target.Put(buf + head, tail - head);
}
void CopyTo(uint8_t* target) const
{
memcpy(target, buf + head, tail - head);
}
uint8_t operator[](unsigned int i) const
{
return buf[i - head];
}
cByteQueueNode* next;
private:
unsigned int MaxSize() const
{
return buf.size;
}
SecByteBlock buf;
unsigned int head, tail;
};
cByteQueueNode::cByteQueueNode(unsigned int maxSize) : buf(maxSize)
{
head = tail = 0;
next = 0;
}
unsigned int cByteQueueNode::Put(uint8_t inByte)
{
if (MaxSize() == tail)
return 0;
buf[tail++] = inByte;
return 1;
}
unsigned int cByteQueueNode::Put(const uint8_t* inString, unsigned int length)
{
unsigned int l = STDMIN(length, MaxSize() - tail);
memcpy(buf + tail, inString, l);
tail += l;
return l;
}
unsigned int cByteQueueNode::Get(uint8_t& outByte)
{
if (tail == head)
return 0;
outByte = buf[head++];
return 1;
}
unsigned int cByteQueueNode::Get(uint8_t* outString, unsigned int getMax)
{
unsigned int l = STDMIN(getMax, tail - head);
memcpy(outString, buf + head, l);
head += l;
return l;
}
unsigned int cByteQueueNode::Peek(uint8_t& outByte) const
{
if (tail == head)
return 0;
outByte = buf[head];
return 1;
}
//-----------------------------------------------------------------------------
// cByteQueue
//-----------------------------------------------------------------------------
cByteQueue::cByteQueue(int nodeSize) : BufferedTransformation(), mNodeSize(nodeSize), mCurrentSize(0)
{
head = tail = new cByteQueueNode(mNodeSize);
}
cByteQueue::cByteQueue(const cByteQueue& copy) : BufferedTransformation()
{
CopyFrom(copy);
}
void cByteQueue::CopyFrom(const cByteQueue& copy)
{
mNodeSize = copy.mNodeSize;
mCurrentSize = copy.mCurrentSize;
head = tail = new cByteQueueNode(*copy.head);
for (cByteQueueNode* current = copy.head->next; current; current = current->next)
{
tail->next = new cByteQueueNode(*current);
tail = tail->next;
}
tail->next = NULL;
}
cByteQueue::~cByteQueue()
{
Destroy();
}
void cByteQueue::Destroy()
{
cByteQueueNode* next;
for (cByteQueueNode* current = head; current; current = next)
{
next = current->next;
delete current;
}
mCurrentSize = 0;
}
///////////////////////////////////////////////////////////////////////////////
// CopyTo -- note that this does not remove anything from the queue
///////////////////////////////////////////////////////////////////////////////
void cByteQueue::CopyTo(BufferedTransformation& target) const
{
for (cByteQueueNode* current = head; current; current = current->next)
current->CopyTo(target);
}
void cByteQueue::CopyTo(uint8_t* target) const
{
for (cByteQueueNode* current = head; current; current = current->next)
{
current->CopyTo(target);
target += current->CurrentSize();
}
}
unsigned long cByteQueue::CurrentSize() const
{
return mCurrentSize;
/*
unsigned long size=0;
for (cByteQueueNode *current=head; current; current=current->next)
size += current->CurrentSize();
return size;
*/
}
void cByteQueue::Put(uint8_t inByte)
{
if (!tail->Put(inByte))
{
tail->next = new cByteQueueNode(mNodeSize);
tail = tail->next;
tail->Put(inByte);
}
// put increases the size of the queue by one
mCurrentSize++;
}
void cByteQueue::Put(const uint8_t* inString, unsigned int length)
{
unsigned int l;
// put increases the size of the queue by length
mCurrentSize += length;
while ((l = tail->Put(inString, length)) < length)
{
tail->next = new cByteQueueNode(mNodeSize);
tail = tail->next;
inString += l;
length -= l;
}
}
unsigned int cByteQueue::Get(uint8_t& outByte)
{
int l = head->Get(outByte);
if (head->UsedUp())
{
cByteQueueNode* temp = head;
head = head->next;
delete temp;
if (!head) // just deleted the last node
head = tail = new cByteQueueNode(mNodeSize);
}
// put decreases the size of the queue by one
mCurrentSize--;
return l;
}
unsigned int cByteQueue::Get(uint8_t* outString, unsigned int getMax)
{
unsigned int getMaxSave = getMax;
cByteQueueNode* current = head;
while (getMax && current)
{
int l = current->Get(outString, getMax);
outString += l;
getMax -= l;
current = current->next;
}
// delete all used up nodes except the last one, to avoid the final new
// that used to be below....
while (head && head->UsedUp() && (head != tail))
{
current = head;
head = head->next;
delete current;
}
/*
if (!head) // every single node has been used up and deleted
head = tail = new cByteQueueNode(mNodeSize);
*/
int rtn = getMaxSave - getMax;
mCurrentSize -= rtn;
return (rtn);
}
unsigned int cByteQueue::Peek(uint8_t& outByte) const
{
return head->Peek(outByte);
}
cByteQueue& cByteQueue::operator=(const cByteQueue& rhs)
{
if (this != &rhs)
{
Destroy();
CopyFrom(rhs);
}
return *this;
}
bool cByteQueue::operator==(const cByteQueue& rhs) const
{
const unsigned long currentSize = CurrentSize();
if (currentSize != rhs.CurrentSize())
return false;
for (unsigned long i = 0; i < currentSize; i++)
if ((*this)[i] != rhs[i])
return false;
return true;
}
uint8_t cByteQueue::operator[](unsigned long i) const
{
for (cByteQueueNode* current = head; current; current = current->next)
{
if (i < current->CurrentSize())
return (*current)[i];
i -= current->CurrentSize();
}
// i should be less than CurrentSize(), therefore we should not be here
assert(false);
return 0;
}