scummvm/scumm/smush/chunk.cpp

289 lines
6.7 KiB
C++
Raw Normal View History

2002-08-30 07:24:45 +00:00
/* ScummVM - Scumm int32erpreter
2002-08-24 15:31:37 +00:00
* Copyright (C) 2001/2002 The ScummVM project
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#include <stdafx.h>
2002-08-25 17:36:34 +00:00
#include "chunk.h"
2002-08-24 15:31:37 +00:00
#include <stdio.h> // for FILE, fopen, fclose, fseek and ftell
#include <string.h> // for memcpy
/*! @brief very small and fast wrapper for a ifstream.
implements reference counting, so that ::file_Chunk does not leak memory !
2002-08-24 15:31:37 +00:00
*/
class FilePtr {
char * _filename;
FILE * _ifs;
2002-08-30 07:24:45 +00:00
int32 _refcount;
int32 _curPos;
2002-08-24 15:31:37 +00:00
public:
FilePtr(const char * fname) : _refcount(1), _curPos(0) {
debug(9, "FilePtr created for %s", fname);
_filename = strdup(fname);
_ifs = fopen(fname, "rb");
if(_ifs == NULL) error("FilePtr unable to read file \"%s\"", fname);
}
~FilePtr() {
debug(9, "FilePtr destroyed for %s", _filename);
free(_filename);
fclose(_ifs);
}
2002-08-30 07:24:45 +00:00
int32 tell() {
2002-08-24 15:31:37 +00:00
return _curPos;
}
2002-08-30 07:24:45 +00:00
bool seek(int32 pos) {
2002-08-24 15:31:37 +00:00
if(pos != _curPos) {
fseek(_ifs, pos, SEEK_SET);
_curPos = pos;
}
return true;
}
2002-08-30 07:24:45 +00:00
bool read(void * ptr, int32 size) {
2002-08-24 15:31:37 +00:00
fread(ptr, size, 1, _ifs);
_curPos += size;
return true;
}
void incRef() {
_refcount++;
}
void decRef() {
if(--_refcount == 0)
delete this;
}
};
const char * Chunk::ChunkString(Chunk::type t) {
2002-08-24 15:31:37 +00:00
static char data[5];
data[0] = (char)((t >> 24) & 0xFF);
data[1] = (char)((t >> 16) & 0xFF);
data[2] = (char)((t >> 8) & 0xFF);
data[3] = (char)((t >> 0) & 0xFF);
data[4] = 0;
return data;
}
FileChunk::FileChunk() : _data(0), _type(0), _size(0), _curPos(0) {
2002-08-24 15:31:37 +00:00
}
FileChunk::~FileChunk() {
2002-08-24 15:31:37 +00:00
if(_data) _data->decRef();
}
FileChunk::FileChunk(const char * fname) {
2002-08-24 15:31:37 +00:00
_data = new FilePtr(fname);
_data->read(&_type, 4);
_type = TO_BE_32(_type);
_data->read(&_size, 4);
_size = TO_BE_32(_size);
_offset = _data->tell();
_curPos = 0;
}
Chunk::type FileChunk::getType() const {
2002-08-24 15:31:37 +00:00
return _type;
}
2002-08-30 07:24:45 +00:00
uint32 FileChunk::getSize() const {
2002-08-24 15:31:37 +00:00
return _size;
}
Chunk * FileChunk::subBlock() {
FileChunk * ptr = new FileChunk;
2002-08-24 15:31:37 +00:00
ptr->_data = _data;
_data->incRef();
_data->seek(_offset + _curPos);
2002-08-30 07:24:45 +00:00
uint32 temp;
2002-08-24 15:31:37 +00:00
_data->read(&temp, 4);
ptr->_type = TO_BE_32(temp);
_data->read(&temp, 4);
ptr->_size = TO_BE_32(temp);
ptr->_offset = _offset + _curPos + 8;
ptr->_curPos = 0;
seek(8 + ptr->getSize());
return ptr;
}
bool FileChunk::eof() const {
2002-08-24 15:31:37 +00:00
return _curPos >= _size;
}
2002-08-30 07:24:45 +00:00
uint32 FileChunk::tell() const {
2002-08-24 15:31:37 +00:00
return _curPos;
}
2002-08-30 07:24:45 +00:00
bool FileChunk::seek(int32 delta, seek_type dir) {
2002-08-24 15:31:37 +00:00
switch(dir) {
case seek_cur:
_curPos += delta;
break;
case seek_start:
if(delta < 0) error("invalid seek request");
2002-08-30 07:24:45 +00:00
_curPos = (uint32)delta;
2002-08-24 15:31:37 +00:00
break;
case seek_end:
if(delta > 0 || (_size + delta) < 0) error("invalid seek request");
2002-08-30 07:24:45 +00:00
_curPos = (uint32)(_size + delta);
2002-08-24 15:31:37 +00:00
break;
}
if(_curPos > _size) {
error("invalid seek request : %d > %d (delta == %d)", _curPos, _size, delta);
}
return true;
}
2002-08-30 07:24:45 +00:00
bool FileChunk::read(void * buffer, uint32 size) {
2002-08-24 15:31:37 +00:00
if(size <= 0 || (_curPos + size) > _size) error("invalid buffer read request");
_data->seek(_offset + _curPos);
_data->read(buffer, size);
_curPos += size;
return true;
}
int8 FileChunk::getChar() {
2002-08-24 15:31:37 +00:00
if(_curPos >= _size) error("invalid char read request");
_data->seek(_offset + _curPos);
int8 buffer;
2002-08-24 15:31:37 +00:00
_data->read(&buffer, sizeof(buffer));
_curPos+= sizeof(buffer);
return buffer;
}
2002-08-30 07:24:45 +00:00
byte FileChunk::getByte() {
2002-08-24 15:31:37 +00:00
if(_curPos >= _size) error("invalid byte read request");
_data->seek(_offset + _curPos);
2002-08-30 07:24:45 +00:00
byte buffer;
2002-08-24 15:31:37 +00:00
_data->read(&buffer, sizeof(buffer));
_curPos+= sizeof(buffer);
return buffer;
}
2002-08-30 07:24:45 +00:00
int16 FileChunk::getShort() {
int16 buffer = getWord();
return *((int16*)&buffer);
2002-08-24 15:31:37 +00:00
}
2002-08-30 07:24:45 +00:00
uint16 FileChunk::getWord() {
2002-08-24 15:31:37 +00:00
if(_curPos >= _size - 1) error("invalid word read request");
_data->seek(_offset + _curPos);
2002-08-30 07:24:45 +00:00
uint16 buffer;
2002-08-24 15:31:37 +00:00
_data->read(&buffer, sizeof(buffer));
_curPos+= sizeof(buffer);
return TO_LE_16(buffer);
}
2002-08-30 07:24:45 +00:00
uint32 FileChunk::getDword() {
2002-08-24 15:31:37 +00:00
if(_curPos >= _size - 3) error("invalid dword read request");
_data->seek(_offset + _curPos);
2002-08-30 07:24:45 +00:00
uint32 buffer;
2002-08-24 15:31:37 +00:00
_data->read(&buffer, sizeof(buffer));
_curPos+= sizeof(buffer);
return TO_LE_32(buffer);
}
2002-08-30 07:24:45 +00:00
ContChunk::ContChunk(byte * data) {
if(data == 0) error("Chunk() called with NULL point32er");
_type = (Chunk::type)READ_BE_UINT32(data);
2002-08-30 07:24:45 +00:00
_size = READ_BE_UINT32(data + 4);
_data = data + sizeof(Chunk::type) + sizeof(uint32);
2002-08-24 15:31:37 +00:00
_curPos = 0;
}
Chunk::type ContChunk::getType() const {
2002-08-24 15:31:37 +00:00
return _type;
}
2002-08-30 07:24:45 +00:00
uint32 ContChunk::getSize() const {
2002-08-24 15:31:37 +00:00
return _size;
}
Chunk * ContChunk::subBlock() {
ContChunk * ptr = new ContChunk(_data + _curPos);
2002-08-30 07:24:45 +00:00
seek(sizeof(Chunk::type) + sizeof(uint32) + ptr->getSize());
2002-08-24 15:31:37 +00:00
return ptr;
}
bool ContChunk::eof() const {
2002-08-24 15:31:37 +00:00
return _curPos >= _size;
}
2002-08-30 07:24:45 +00:00
uint32 ContChunk::tell() const {
2002-08-24 15:31:37 +00:00
return _curPos;
}
2002-08-30 07:24:45 +00:00
bool ContChunk::seek(int32 delta, seek_type dir) {
2002-08-24 15:31:37 +00:00
switch(dir) {
case seek_cur:
_curPos += delta;
break;
case seek_start:
if(delta < 0) error("invalid seek request");
2002-08-30 07:24:45 +00:00
_curPos = (uint32)delta;
2002-08-24 15:31:37 +00:00
break;
case seek_end:
if(delta > 0 || (_size + delta) < 0) error("invalid seek request");
2002-08-30 07:24:45 +00:00
_curPos = (uint32)(_size + delta);
2002-08-24 15:31:37 +00:00
break;
}
if(_curPos > _size) {
error("invalid seek request : %d > %d (delta == %d)", _curPos, _size, delta);
}
return true;
}
2002-08-30 07:24:45 +00:00
bool ContChunk::read(void * buffer, uint32 size) {
2002-08-24 15:31:37 +00:00
if(size <= 0 || (_curPos + size) > _size) error("invalid buffer read request");
memcpy(buffer, _data + _curPos, size);
_curPos += size;
return true;
}
int8 ContChunk::getChar() {
2002-08-24 15:31:37 +00:00
if(_curPos >= _size) error("invalid char read request");
return _data[_curPos++];
}
2002-08-30 07:24:45 +00:00
byte ContChunk::getByte() {
2002-08-24 15:31:37 +00:00
if(_curPos >= _size) error("invalid byte read request");
2002-08-30 07:24:45 +00:00
byte * ptr = (byte *)(_data + _curPos);
2002-08-24 15:31:37 +00:00
_curPos += 1;
return *ptr;
}
2002-08-30 07:24:45 +00:00
int16 ContChunk::getShort() {
if(_curPos >= _size - 1) error("invalid int16 read request");
int16 buffer = getWord();
return *((int16*)&buffer);
2002-08-24 15:31:37 +00:00
}
2002-08-30 07:24:45 +00:00
uint16 ContChunk::getWord() {
2002-08-24 15:31:37 +00:00
if(_curPos >= _size - 1) error("invalid word read request");
2002-08-30 07:24:45 +00:00
uint16 * ptr = (uint16 *)(_data + _curPos);
2002-08-24 15:31:37 +00:00
_curPos += 2;
return READ_LE_UINT16(ptr);
}
2002-08-30 07:24:45 +00:00
uint32 ContChunk::getDword() {
2002-08-24 15:31:37 +00:00
if(_curPos >= _size - 3) error("invalid dword read request");
2002-08-30 07:24:45 +00:00
uint32 * ptr = (uint32 *)(_data + _curPos);
2002-08-24 15:31:37 +00:00
_curPos += 4;
return READ_LE_UINT32(ptr);
}