scummvm/common/iff_container.h
2009-10-08 21:28:57 +00:00

305 lines
7.9 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.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
*/
#ifndef COMMON_IFF_CONTAINER_H
#define COMMON_IFF_CONTAINER_H
#include "common/scummsys.h"
#include "common/endian.h"
#include "common/func.h"
#include "common/stream.h"
#include "common/util.h"
namespace Common {
typedef uint32 IFF_ID;
#define ID_FORM MKID_BE('FORM')
/* EA IFF 85 group identifier */
#define ID_CAT MKID_BE('CAT ')
/* EA IFF 85 group identifier */
#define ID_LIST MKID_BE('LIST')
/* EA IFF 85 group identifier */
#define ID_PROP MKID_BE('PROP')
/* EA IFF 85 group identifier */
#define ID_END MKID_BE('END ')
/* unofficial END-of-FORM identifier (see Amiga RKM Devices Ed.3
page 376) */
#define ID_ILBM MKID_BE('ILBM')
/* EA IFF 85 raster bitmap form */
#define ID_DEEP MKID_BE('DEEP')
/* Chunky pixel image files (Used in TV Paint) */
#define ID_RGB8 MKID_BE('RGB8')
/* RGB image forms, Turbo Silver (Impulse) */
#define ID_RGBN MKID_BE('RGBN')
/* RGB image forms, Turbo Silver (Impulse) */
#define ID_PBM MKID_BE('PBM ')
/* 256-color chunky format (DPaint 2 ?) */
#define ID_ACBM MKID_BE('ACBM')
/* Amiga Contiguous Bitmap (AmigaBasic) */
#define ID_8SVX MKID_BE('8SVX')
/* Amiga 8 bits voice */
/* generic */
#define ID_FVER MKID_BE('FVER')
/* AmigaOS version string */
#define ID_JUNK MKID_BE('JUNK')
/* always ignore this chunk */
#define ID_ANNO MKID_BE('ANNO')
/* EA IFF 85 Generic Annotation chunk */
#define ID_AUTH MKID_BE('AUTH')
/* EA IFF 85 Generic Author chunk */
#define ID_CHRS MKID_BE('CHRS')
/* EA IFF 85 Generic character string chunk */
#define ID_NAME MKID_BE('NAME')
/* EA IFF 85 Generic Name of art, music, etc. chunk */
#define ID_TEXT MKID_BE('TEXT')
/* EA IFF 85 Generic unformatted ASCII text chunk */
#define ID_copy MKID_BE('(c) ')
/* EA IFF 85 Generic Copyright text chunk */
/* ILBM chunks */
#define ID_BMHD MKID_BE('BMHD')
/* ILBM BitmapHeader */
#define ID_CMAP MKID_BE('CMAP')
/* ILBM 8bit RGB colormap */
#define ID_GRAB MKID_BE('GRAB')
/* ILBM "hotspot" coordiantes */
#define ID_DEST MKID_BE('DEST')
/* ILBM destination image info */
#define ID_SPRT MKID_BE('SPRT')
/* ILBM sprite identifier */
#define ID_CAMG MKID_BE('CAMG')
/* Amiga viewportmodes */
#define ID_BODY MKID_BE('BODY')
/* ILBM image data */
#define ID_CRNG MKID_BE('CRNG')
/* color cycling */
#define ID_CCRT MKID_BE('CCRT')
/* color cycling */
#define ID_CLUT MKID_BE('CLUT')
/* Color Lookup Table chunk */
#define ID_DPI MKID_BE('DPI ')
/* Dots per inch chunk */
#define ID_DPPV MKID_BE('DPPV')
/* DPaint perspective chunk (EA) */
#define ID_DRNG MKID_BE('DRNG')
/* DPaint IV enhanced color cycle chunk (EA) */
#define ID_EPSF MKID_BE('EPSF')
/* Encapsulated Postscript chunk */
#define ID_CMYK MKID_BE('CMYK')
/* Cyan, Magenta, Yellow, & Black color map (Soft-Logik) */
#define ID_CNAM MKID_BE('CNAM')
/* Color naming chunk (Soft-Logik) */
#define ID_PCHG MKID_BE('PCHG')
/* Line by line palette control information (Sebastiano Vigna) */
#define ID_PRVW MKID_BE('PRVW')
/* A mini duplicate ILBM used for preview (Gary Bonham) */
#define ID_XBMI MKID_BE('XBMI')
/* eXtended BitMap Information (Soft-Logik) */
#define ID_CTBL MKID_BE('CTBL')
/* Newtek Dynamic Ham color chunk */
#define ID_DYCP MKID_BE('DYCP')
/* Newtek Dynamic Ham chunk */
#define ID_SHAM MKID_BE('SHAM')
/* Sliced HAM color chunk */
#define ID_ABIT MKID_BE('ABIT')
/* ACBM body chunk */
#define ID_DCOL MKID_BE('DCOL')
/* unofficial direct color */
#define ID_DPPS MKID_BE('DPPS')
/* ? */
#define ID_TINY MKID_BE('TINY')
/* ? */
#define ID_DPPV MKID_BE('DPPV')
/* ? */
/* 8SVX chunks */
#define ID_VHDR MKID_BE('VHDR')
/* 8SVX Voice8Header */
char * ID2string(Common::IFF_ID id);
/**
* Represents a IFF chunk available to client code.
*
* Client code must *not* deallocate _stream when done.
*/
struct IFFChunk {
Common::IFF_ID _type;
uint32 _size;
Common::ReadStream *_stream;
IFFChunk(Common::IFF_ID type, uint32 size, Common::ReadStream *stream) : _type(type), _size(size), _stream(stream) {
assert(_stream);
}
};
/**
* Parser for IFF containers.
*/
class IFFParser {
/**
* This private class implements IFF chunk navigation.
*/
class IFFChunkNav : public Common::ReadStream {
protected:
Common::ReadStream *_input;
uint32 _bytesRead;
public:
Common::IFF_ID id;
uint32 size;
IFFChunkNav() : _input(0) {
}
void setInputStream(Common::ReadStream *input) {
_input = input;
size = _bytesRead = 0;
}
void incBytesRead(uint32 inc) {
_bytesRead += inc;
if (_bytesRead > size) {
error("Chunk overread");
}
}
void readHeader() {
id = _input->readUint32BE();
size = _input->readUint32BE();
_bytesRead = 0;
}
bool hasReadAll() const {
return (size - _bytesRead) == 0;
}
void feed() {
if (size % 2) {
size++;
}
while (!hasReadAll()) {
readByte();
}
}
// Common::ReadStream implementation
bool eos() const { return _input->eos(); }
bool err() const { return _input->err(); }
void clearErr() { _input->clearErr(); }
uint32 read(void *dataPtr, uint32 dataSize) {
incBytesRead(dataSize);
return _input->read(dataPtr, dataSize);
}
};
protected:
IFFChunkNav _formChunk; ///< The root chunk of the file.
IFFChunkNav _chunk; ///< The current chunk.
uint32 _formSize;
Common::IFF_ID _formType;
Common::ReadStream *_stream;
bool _disposeStream;
void setInputStream(Common::ReadStream *stream) {
assert(stream);
_formChunk.setInputStream(stream);
_chunk.setInputStream(stream);
_formChunk.readHeader();
if (_formChunk.id != ID_FORM) {
error("IFFParser input is not a FORM type IFF file");
}
_formSize = _formChunk.size;
_formType = _formChunk.readUint32BE();
}
public:
IFFParser(Common::ReadStream *stream, bool disposeStream = false) : _stream(stream), _disposeStream(disposeStream) {
setInputStream(stream);
}
~IFFParser() {
if (_disposeStream) {
delete _stream;
}
_stream = 0;
}
/**
* Returns the IFF FORM type.
* @return the IFF FORM type of the stream, or 0 if FORM header is not found.
*/
Common::IFF_ID getFORMType() const;
/**
* Returns the size of the data.
* @return the size of the data in file, or -1 if FORM header is not found.
*/
uint32 getFORMSize() const;
/**
* Callback type for the parser.
*/
typedef Common::Functor1< IFFChunk&, bool > IFFCallback;
/**
* Parse the IFF container, invoking the callback on each chunk encountered.
* The callback can interrupt the parsing by returning 'true'.
*/
void parse(IFFCallback &callback) {
bool stop;
do {
_chunk.feed();
_formChunk.incBytesRead(_chunk.size);
if (_formChunk.hasReadAll()) {
break;
}
_formChunk.incBytesRead(8);
_chunk.readHeader();
// invoke the callback
Common::SubReadStream stream(&_chunk, _chunk.size);
IFFChunk chunk(_chunk.id, _chunk.size, &stream);
stop = callback(chunk);
// eats up all the remaining data in the chunk
while (!stream.eos()) {
stream.readByte();
}
} while (!stop);
}
};
} // namespace Common
#endif