310 lines
7.7 KiB
C++
310 lines
7.7 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* Additional copyright for this file:
|
|
* Copyright (C) 1999-2000 Revolution Software Ltd.
|
|
* This code is based on source code created by Revolution Software,
|
|
* used with permission.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "engines/icb/common/datapacker.h"
|
|
|
|
#include "common/stream.h"
|
|
#include "common/textconsole.h"
|
|
|
|
namespace ICB {
|
|
|
|
// Just initialise the buffer position and the min, max values
|
|
// used for packing and error detection
|
|
DataPacker::DataPacker() {
|
|
readMode = false;
|
|
iMode = NO_MODE;
|
|
iPackMode = NO_PACKMODE;
|
|
pos = 0;
|
|
packMin = -(1 << (PACK_BIT_SIZE - 1));
|
|
packMax = +((1 << PACK_BIT_SIZE) - 1);
|
|
|
|
// clear out the data buffer
|
|
ClearBuffer();
|
|
}
|
|
|
|
// Could do something here - but not sure what !
|
|
// Could error check on pos = 0 : but might lead to trouble
|
|
DataPacker::~DataPacker() {}
|
|
|
|
// Start the bit-packing process : say if we are in READ or WRITE mode
|
|
DataPacker::ReturnCodes DataPacker::open(const ModeEnum mode, const PackModeEnum packMode) {
|
|
if (pos != 0) {
|
|
return BAD_POS;
|
|
}
|
|
|
|
if ((mode != READ) && (mode != WRITE)) {
|
|
return BAD_MODE;
|
|
}
|
|
|
|
if ((packMode != PACK) && (packMode != DONT_PACK)) {
|
|
return BAD_PACKMODE;
|
|
}
|
|
|
|
if (mode == READ) {
|
|
readMode = true;
|
|
pos = PACK_CHUNK_SIZE;
|
|
}
|
|
|
|
if (mode == WRITE) {
|
|
readMode = false;
|
|
pos = 0;
|
|
}
|
|
|
|
// clear out the data buffer
|
|
ClearBuffer();
|
|
|
|
iMode = mode;
|
|
iPackMode = packMode;
|
|
|
|
return OK;
|
|
}
|
|
|
|
// Put a value into the bit-stream
|
|
DataPacker::ReturnCodes DataPacker::put(const int32 value, Common::WriteStream *stream) {
|
|
if (iMode != WRITE) {
|
|
return BAD_MODE;
|
|
}
|
|
|
|
if ((iPackMode != PACK) && (iPackMode != DONT_PACK)) {
|
|
return BAD_PACKMODE;
|
|
}
|
|
|
|
if ((pos < 0) || (pos >= PACK_CHUNK_SIZE)) {
|
|
return BAD_POS;
|
|
}
|
|
|
|
// For DONT_PACK mode just write the data straight out
|
|
if (iPackMode == DONT_PACK) {
|
|
// Check it is a legal value : 16-bits
|
|
int32 lvarMin = -(1 << 15);
|
|
int32 lvarMax = +((1 << 15) - 1);
|
|
if ((value < lvarMin) || (value > lvarMax)) {
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
int32 nItems = 2;
|
|
int16 v16 = (int16)value;
|
|
int32 ret = stream->write((const void *)&v16, nItems);
|
|
|
|
if (ret != nItems) {
|
|
return WRITE_ERROR;
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
// Convert the value to be within limits
|
|
int32 v = value - packMin;
|
|
|
|
// Check the value is within range
|
|
if ((v < 0) || (v > packMax)) {
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
// Add the value in
|
|
if (pos == 0) {
|
|
buffer[0] = (uint8)((v >> 6) & 0xFF); // v's top 8-bits
|
|
buffer[1] = (uint8)((v & 0x3F) << 2); // v's bottom 6-bits into top 6-bits
|
|
} else if (pos == 1) {
|
|
buffer[1] |= ((v >> 12) & 0x03); // v's top 2-bits into bottom 2
|
|
buffer[2] = (uint8)((v >> 4) & 0xFF); // v's middle 8-bits
|
|
buffer[3] = (uint8)((v & 0x0F) << 4); // v's bottom 4-bits into top 4
|
|
} else if (pos == 2) {
|
|
buffer[3] |= ((v >> 10) & 0x0F); // v's top 4-bits into bottom 4
|
|
buffer[4] = (uint8)((v >> 2) & 0xFF); // v's middle 8-bits
|
|
buffer[5] = (uint8)((v & 0x03) << 6); // v's bottom 2-bits into top 2
|
|
} else if (pos == 3) {
|
|
buffer[5] |= ((v >> 8) & 0x3F); // v's top 6-bits into bottom 6
|
|
buffer[6] = (uint8)(v & 0xFF); // v's bottom 8-bits
|
|
}
|
|
// Put data into the next position !
|
|
pos++;
|
|
|
|
// Do we need to output the current buffer ?
|
|
if (pos == PACK_CHUNK_SIZE) {
|
|
#if 0
|
|
printf("WRITE %X %X %X %X %X %X %X",
|
|
buffer[0], buffer[1], buffer[2], buffer[3],
|
|
buffer[4], buffer[5], buffer[6]);
|
|
#endif // #if 0
|
|
// Write out the buffer
|
|
int32 nItems = BUFFER_BYTE_SIZE;
|
|
int32 ret = stream->write((const void *)buffer, nItems);
|
|
|
|
if (ret != nItems) {
|
|
return WRITE_ERROR;
|
|
}
|
|
|
|
pos = 0;
|
|
ClearBuffer();
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
// Get a value from the bit-stream
|
|
DataPacker::ReturnCodes DataPacker::Get(int32 &value, Common::SeekableReadStream *stream) {
|
|
if (iMode != READ) {
|
|
return BAD_MODE;
|
|
}
|
|
|
|
if ((iPackMode != PACK) && (iPackMode != DONT_PACK)) {
|
|
return BAD_PACKMODE;
|
|
}
|
|
|
|
if ((pos < 0) || (pos > PACK_CHUNK_SIZE)) {
|
|
return BAD_POS;
|
|
}
|
|
|
|
// For DONT_PACK mode just read the data straight in
|
|
if (iPackMode == DONT_PACK) {
|
|
int32 nItems = 2;
|
|
int16 v16;
|
|
int32 ret = stream->read((void *)&v16, nItems);
|
|
value = v16;
|
|
|
|
if (ret != nItems) {
|
|
return READ_ERROR;
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
// Do we need to fill up the current buffer ?
|
|
if (pos == PACK_CHUNK_SIZE) {
|
|
// Read into the buffer
|
|
int32 nItems = BUFFER_BYTE_SIZE;
|
|
int32 ret = stream->read((void *)buffer, nItems);
|
|
|
|
if (ret != nItems) {
|
|
return READ_ERROR;
|
|
}
|
|
|
|
#if 0
|
|
printf("READ %X %X %X %X %X %X %X",
|
|
buffer[0], buffer[1], buffer[2], buffer[3],
|
|
buffer[4], buffer[5], buffer[6]);
|
|
#endif
|
|
pos = 0;
|
|
}
|
|
|
|
int32 v = 0;
|
|
// Get the value out of the buffer
|
|
if (pos == 0) {
|
|
v = (buffer[0] << 6); // v's top 8-bits
|
|
v |= (buffer[1] >> 2); // v's bottom 6-bits into top 6-bits
|
|
} else if (pos == 1) {
|
|
v = ((buffer[1] & 0x03) << 12); // v's top 2-bits into bottom 2
|
|
v |= (buffer[2] << 4); // v's middle 8-bits
|
|
v |= (buffer[3] >> 4); // v's bottom 4-bits into top 4
|
|
} else if (pos == 2) {
|
|
v = ((buffer[3] & 0x0F) << 10); // v's top 4-bits into bottom 4
|
|
v |= (buffer[4] << 2); // v's middle 8-bits
|
|
v |= (buffer[5] >> 6); // v's bottom 2-bits into top 2
|
|
} else if (pos == 3) {
|
|
v = (buffer[5] & 0x3F) << 8; // v's top 6-bits into bottom 6
|
|
v |= buffer[6]; // v's bottom 8-bits
|
|
}
|
|
// Get data from the next position !
|
|
pos++;
|
|
|
|
// Check the value is within range
|
|
// This should just not be possible !
|
|
if ((v < 0) || (v > packMax)) {
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
// Convert the extracted value to be in normal signed/unsigned limits
|
|
value = v + packMin;
|
|
|
|
return OK;
|
|
}
|
|
|
|
// Stop the bit-packing process : will output any remaining data
|
|
DataPacker::ReturnCodes DataPacker::close(Common::WriteStream *stream) {
|
|
if ((iMode == WRITE) && (pos != 0)) {
|
|
// Write out the remaining data items
|
|
int32 nItems = BUFFER_BYTE_SIZE;
|
|
int32 ret = stream->write((const void *)buffer, nItems);
|
|
|
|
if (ret != nItems) {
|
|
return WRITE_ERROR;
|
|
}
|
|
} else {
|
|
error("Wrong close-function called, passed WriteStream without being in WRITE-mode");
|
|
}
|
|
|
|
iMode = NO_MODE;
|
|
iPackMode = NO_PACKMODE;
|
|
|
|
pos = 0;
|
|
|
|
ClearBuffer();
|
|
|
|
return OK;
|
|
}
|
|
|
|
DataPacker::ReturnCodes DataPacker::close(Common::SeekableReadStream *stream) {
|
|
// TODO: If write mode.
|
|
if ((iMode == WRITE) && (pos != 0)) {
|
|
error("Wrong close-function called, passed ReadStream in WRITE-mode");
|
|
}
|
|
iMode = NO_MODE;
|
|
iPackMode = NO_PACKMODE;
|
|
|
|
pos = 0;
|
|
|
|
ClearBuffer();
|
|
|
|
return OK;
|
|
}
|
|
|
|
// Copy constructor
|
|
DataPacker::DataPacker(DataPacker &src) { *this = src; }
|
|
|
|
// Assignment operator
|
|
DataPacker &DataPacker::operator=(DataPacker &b) {
|
|
readMode = b.readMode;
|
|
|
|
iMode = b.iMode;
|
|
iPackMode = b.iPackMode;
|
|
pos = b.pos;
|
|
packMin = b.packMin;
|
|
packMax = b.packMax;
|
|
|
|
for (int32 i = 0; i < BUFFER_BYTE_SIZE; i++) {
|
|
buffer[i] = b.buffer[i];
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
// Clear out the data buffer
|
|
void DataPacker::ClearBuffer() {
|
|
for (int32 i = 0; i < BUFFER_BYTE_SIZE; i++) {
|
|
buffer[i] = 0x00;
|
|
}
|
|
}
|
|
|
|
} // End of namespace ICB
|