Ticket #8988: iff001.patch

File iff001.patch, 25.0 KB (added by peres, 12 years ago)

New IFF parser and related classes.

  • common/iff_container.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11 *
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16 *
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 */
     24
     25
     26#include "common/iff_container.h"
     27
     28namespace Common {
     29
     30
     31char *ID2string(Common::IFF_ID id) {
     32        static char str[] = "abcd";
     33
     34        str[0] = (char)(id >> 24 & 0xff);
     35        str[1] = (char)(id >> 16 & 0xff);
     36        str[2] = (char)(id >>  8 & 0xff);
     37        str[3] = (char)(id >>  0 & 0xff);
     38
     39        return str;
     40}
     41
     42
     43void IFFParser::setInputStream(SeekableReadStream *stream) {
     44        destroy();
     45
     46        assert(stream);
     47        _stream = stream;
     48        _startOffset = 0;
     49        _endOffset = _stream->size();
     50
     51        _formType = 0;
     52        _formSize = (uint32)-1;
     53
     54        if (_stream->size() < 12) {
     55                // this file is too small to be a valid IFF container
     56                return;
     57        }
     58
     59        if (_stream->readUint32BE() != ID_FORM) {
     60                // no FORM header was found
     61                return;
     62        }
     63
     64        _formSize = _stream->readUint32BE();
     65        _formType = _stream->readUint32BE();
     66}
     67
     68void IFFParser::destroy() {
     69        _stream = 0;
     70        _startOffset = _endOffset = 0;
     71}
     72
     73uint32 IFFParser::getFORMSize() const {
     74        return _formSize;
     75}
     76
     77IFF_ID IFFParser::getFORMType() const {
     78        return _formType;
     79}
     80
     81uint32 IFFParser::moveToIFFBlock(IFF_ID chunkName) {
     82        uint32 size = (uint32)-1;
     83
     84        _stream->seek(_startOffset + 0x0C);
     85
     86        while ((uint)_stream->pos() < _endOffset) {
     87                uint32 chunk = _stream->readUint32BE();
     88                uint32 size_temp = _stream->readUint32BE();
     89
     90                if (chunk != chunkName) {
     91                        _stream->seek((size_temp + 1) & (~1), SEEK_CUR);
     92                        assert((uint)_stream->pos() <= _endOffset);
     93                } else {
     94                        size = size_temp;
     95                        break;
     96                }
     97        }
     98
     99        return size;
     100}
     101
     102uint32 IFFParser::getIFFBlockSize(IFF_ID chunkName) {
     103        uint32 size = moveToIFFBlock(chunkName);
     104        return size;
     105}
     106
     107bool IFFParser::loadIFFBlock(IFF_ID chunkName, void *loadTo, uint32 ptrSize) {
     108        uint32 chunkSize = moveToIFFBlock(chunkName);
     109
     110        if (chunkSize == (uint32)-1) {
     111                return false;
     112        }
     113
     114        uint32 loadSize = 0;
     115        loadSize = MIN(ptrSize, chunkSize);
     116        _stream->read(loadTo, loadSize);
     117        return true;
     118}
     119
     120SeekableReadStream *IFFParser::getIFFBlockStream(IFF_ID chunkName) {
     121        uint32 chunkSize = moveToIFFBlock(chunkName);
     122
     123        if (chunkSize == (uint32)-1) {
     124                return 0;
     125        }
     126
     127        uint32 pos = _stream->pos();
     128        return new SeekableSubReadStream(_stream, pos, pos + chunkSize, false);
     129}
     130
     131} // namespace Common
  • common/iff_container.h

    Property changes on: common\iff_container.cpp
    ___________________________________________________________________
    Added: svn:mime-type
       + text/plain
    Added: svn:keywords
       + Date Rev Author URL Id
    Added: svn:eol-style
       + native
    
     
    142142/* 8SVX Voice8Header */
    143143
    144144
    145 char * ID2string(Common::IFF_ID id);
     145char * ID2string(IFF_ID id);
    146146
    147147
    148 class IFFChunk : public Common::ReadStream {
    149 
    150 protected:
    151         Common::ReadStream *_input;
    152         uint32 bytesRead;
    153 
     148class IFFParser {
    154149public:
    155         IFF_ID id;
    156         uint32 size;
    157 
    158         IFFChunk(Common::ReadStream *input): _input(input) {
    159                 size = bytesRead = 0;
     150        IFFParser() : _stream(0), _startOffset(0), _endOffset(0) {}
     151        IFFParser(SeekableReadStream *stream) : _stream(0), _startOffset(0), _endOffset(0) {
     152                setInputStream(stream);
    160153        }
     154        ~IFFParser() { destroy(); }
    161155
    162         void incBytesRead(uint32 inc) {
    163                 bytesRead += inc;
    164                 if (bytesRead > size) {
    165                         error("Chunk overread");
    166                 }
    167         }
     156        /**
     157         *  Sets up the parser to work on the stream. It is the caller duty to
     158         *  destroy any previously assigned stream.
     159         */
     160        void setInputStream(SeekableReadStream *stream);
    168161
    169         void readHeader() {
    170                 id = _input->readUint32BE();
    171                 size = _input->readUint32BE();
    172                 bytesRead = 0;
    173         }
     162        operator bool() const { return (_startOffset != _endOffset) && _stream; }
    174163
    175         bool hasReadAll() const {
    176                 return (size - bytesRead) == 0;
    177         }
     164        /**
     165         *  Returns the size from the IFF FORM header, or -1 if not found.
     166         */
     167        uint32 getFORMSize() const;
    178168
    179         void feed() {
    180                 if (size % 2) {
    181                         size++;
    182                 }
    183                 while (!hasReadAll()) {
    184                         readByte();
    185                 }
    186         }
     169        /**
     170         *  Returns the type from the IFF FORM header, or 0 if not found.
     171         */
     172        IFF_ID getFORMType() const;
    187173
    188         // Common::ReadStream implementation
    189         bool eos() const { return _input->eos(); }
    190         bool err() const { return _input->err(); }
    191         void clearErr() { _input->clearErr(); }
     174        /**
     175         *  Returns the size (in bytes) of a chunk, or -1 if not found.
     176         */
     177        uint32 getIFFBlockSize(IFF_ID chunk);
    192178
    193         uint32 read(void *dataPtr, uint32 dataSize) {
    194                 incBytesRead(dataSize);
    195                 return _input->read(dataPtr, dataSize);
    196         }
     179        /**
     180         *  Loads at most ptrSize bytes from the beginning of the selected chunk
     181         *  to the buffer. The caller must allocate the buffer.
     182         *
     183         *  Returns false if the chunk is not found in the file.
     184         */
     185        bool loadIFFBlock(IFF_ID chunk, void *loadTo, uint32 ptrSize);
    197186
    198 };
     187        /**
     188         *  Returns a stream pointing to the beginning of the raw data in the
     189         *  specified IFF block if it exists, or 0 otherwise.
     190         */
     191        SeekableReadStream *getIFFBlockStream(IFF_ID chunkName);
    199192
    200 class IFFParser {
    201 public:
    202         IFFParser(Common::ReadStream &input) : _formChunk(&input), _chunk(&input) {
    203                 _formChunk.readHeader();
    204                 if (_formChunk.id != ID_FORM) {
    205                         error("IFFDecoder input is not a FORM type IFF file");
    206                 }
    207                 _typeId = _formChunk.readUint32BE();
    208         }
     193protected:
     194        uint32 moveToIFFBlock(IFF_ID chunkName);
    209195
    210         virtual ~IFFParser() {}
     196private:
     197        void destroy();
    211198
    212         IFFChunk *nextChunk() {
    213                 _chunk.feed();
    214                 _formChunk.incBytesRead(_chunk.size);
     199        SeekableReadStream *_stream;
     200        uint32 _startOffset;
     201        uint32 _endOffset;
    215202
    216                 if (_formChunk.hasReadAll())
    217                         return 0;
    218 
    219                 _formChunk.incBytesRead(8);
    220                 _chunk.readHeader();
    221 
    222                 return &_chunk;
    223         }
    224 
    225         IFF_ID  _typeId;
    226 
    227 protected:
    228         IFFChunk        _formChunk;
    229         IFFChunk        _chunk;
     203        uint32 _formSize;
     204        IFF_ID _formType;
    230205};
    231206
    232207} // namespace Common
  • engines/parallaction/sound_br.cpp

     
    453453        if (!stream)
    454454                return false;
    455455
    456         Audio::A8SVXDecoder decoder(*stream, ch->header, ch->data, ch->dataSize);
    457         decoder.decode();
     456        Audio::A8SVXDecoder decoder(stream);
     457        decoder.fillHeader(&ch->header);
     458        ch->data = decoder.getData();
     459        assert(ch->data);
     460        ch->dataSize = decoder.getDataSize();
    458461        ch->dispose = true;
    459462        delete stream;
    460463
  • engines/parallaction/sound_ns.cpp

     
    380380        }
    381381
    382382        Common::SeekableReadStream *stream = _vm->_disk->loadSound(filename);
    383         Audio::A8SVXDecoder decoder(*stream, ch->header, ch->data, ch->dataSize);
    384         decoder.decode();
     383        Audio::A8SVXDecoder decoder(stream);
     384        decoder.fillHeader(&ch->header);
     385        ch->data = decoder.getData();
     386        assert(ch->data);
     387        ch->dataSize = decoder.getDataSize();
    385388        ch->dispose = true;
    386389        delete stream;
    387390}
  • engines/saga/scene.cpp

     
    506506                                                cPal[j].green = *pal++;
    507507                                                cPal[j].blue = *pal++;
    508508                                        }
    509                                         free(colors);
     509                                        delete []colors;
    510510                                        _vm->_gfx->setPalette(cPal);
    511511
    512512                                }
  • graphics/iff.cpp

     
    2828#include "common/util.h"
    2929
    3030
    31 namespace Common {
    32 
    33 // this really belongs to iff_container.cpp, but we don't want
    34 // to put only this in a source file
    35 char *ID2string(Common::IFF_ID id) {
    36         static char str[] = "abcd";
    37 
    38         str[0] = (char)(id >> 24 & 0xff);
    39         str[1] = (char)(id >> 16 & 0xff);
    40         str[2] = (char)(id >>  8 & 0xff);
    41         str[3] = (char)(id >>  0 & 0xff);
    42 
    43         return str;
    44 }
    45 
    46 }
    47 
    48 
    4931namespace Graphics {
    5032
     33// ILBM decoder implementation
    5134
    52 void fillBMHD(BMHD &bitmapHeader, Common::ReadStream &stream) {
     35ILBMDecoder::ILBMDecoder(Common::SeekableReadStream *in, bool disposeStream) : _in(in), _hasHeader(false), _bodySize((uint32)-1), _paletteSize((uint32)-1) {
     36        assert(in);
     37        _parser.setInputStream(in);
    5338
    54         bitmapHeader.width = stream.readUint16BE();
    55         bitmapHeader.height = stream.readUint16BE();
    56         bitmapHeader.x = stream.readUint16BE();
    57         bitmapHeader.y = stream.readUint16BE();
    58         bitmapHeader.depth = stream.readByte();
    59         bitmapHeader.masking = stream.readByte();
    60         bitmapHeader.pack = stream.readByte();
    61         bitmapHeader.flags = stream.readByte();
    62         bitmapHeader.transparentColor = stream.readUint16BE();
    63         bitmapHeader.xAspect = stream.readByte();
    64         bitmapHeader.yAspect = stream.readByte();
    65         bitmapHeader.pageWidth = stream.readUint16BE();
    66         bitmapHeader.pageHeight = stream.readUint16BE();
     39        _hasHeader = _parser.loadIFFBlock(ID_BMHD, &_header, sizeof(_header));
     40        if (!_hasHeader) {
     41                return;
     42        }
    6743
    68 }
     44        _header.width = TO_BE_16(_header.width);
     45        _header.height = TO_BE_16(_header.height);
    6946
    70 
    71 ILBMDecoder::ILBMDecoder(Common::ReadStream &input, Surface &surface, byte *&colors) : IFFParser(input), _surface(&surface), _colors(&colors) {
    72         if (_typeId != ID_ILBM)
    73                 error("unsupported IFF subtype '%s'", Common::ID2string(_typeId));
     47        _paletteSize = _parser.getIFFBlockSize(ID_CMAP);
     48        _bodySize = _parser.getIFFBlockSize(ID_BODY);
    7449}
    7550
    76 void ILBMDecoder::decode() {
    7751
    78         Common::IFFChunk *chunk;
    79         while ((chunk = nextChunk()) != 0) {
    80                 switch (chunk->id) {
    81                 case ID_BMHD:
    82                         readBMHD(*chunk);
    83                         break;
    84 
    85                 case ID_CMAP:
    86                         readCMAP(*chunk);
    87                         break;
    88 
    89                 case ID_BODY:
    90                         readBODY(*chunk);
    91                         break;
    92                 }
     52ILBMDecoder::~ILBMDecoder() {
     53        if (_disposeStream) {
     54                delete _in;
    9355        }
     56}
    9457
    95         return;
     58uint32 ILBMDecoder::getWidth() {
     59        assert(_hasHeader);
     60        return _header.width;
    9661}
    9762
    98 void ILBMDecoder::readBMHD(Common::IFFChunk &chunk) {
     63uint32 ILBMDecoder::getHeight() {
     64        assert(_hasHeader);
     65        return _header.height;
     66}
    9967
    100         fillBMHD(_bitmapHeader, chunk);
     68uint32 ILBMDecoder::getNumColors() {
     69        assert(_hasHeader);
     70        return (1 << _header.depth);
     71}
    10172
    102         _colorCount = 1 << _bitmapHeader.depth;
    103         *_colors = (byte*)malloc(sizeof(**_colors) * _colorCount * 3);
    104         _surface->create(_bitmapHeader.width, _bitmapHeader.height, 1);
    105 
     73byte *ILBMDecoder::getPalette() {
     74        assert(_paletteSize != (uint32)-1);
     75        byte *palette = new byte[_paletteSize];
     76        assert(palette);
     77        _parser.loadIFFBlock(ID_CMAP, palette, _paletteSize);
     78        return palette;
    10679}
    10780
    108 void ILBMDecoder::readCMAP(Common::IFFChunk &chunk) {
    109         if (*_colors == NULL) {
    110                 error("wrong input chunk sequence");
     81byte *ILBMDecoder::getBitmap(uint32 numPlanes, bool packPixels) {
     82        assert(_bodySize != (uint32)-1);
     83        assert(numPlanes == 1 || numPlanes == 2 || numPlanes == 4 || numPlanes == 5 || numPlanes == 8);
     84
     85        _packPixels = packPixels;
     86        _outPlanes = MIN(numPlanes, (uint32)_header.depth);
     87        if (_outPlanes > 4) {
     88                _packPixels = false;
    11189        }
    112         for (uint32 i = 0; i < _colorCount; i++) {
    113                 (*_colors)[i * 3 + 0] = chunk.readByte();
    114                 (*_colors)[i * 3 + 1] = chunk.readByte();
    115                 (*_colors)[i * 3 + 2] = chunk.readByte();
     90
     91        uint32 bitmapSize = _header.width * _header.height;
     92        uint32 bitmapWidth = _header.width;
     93        if (packPixels) {
     94                bitmapSize /= (8 / _outPlanes);
     95                bitmapWidth /= (8 / _outPlanes);
    11696        }
    117 }
    11897
    119 void ILBMDecoder::readBODY(Common::IFFChunk& chunk) {
     98        Common::SeekableReadStream *bodyStream = _parser.getIFFBlockStream(ID_BODY);
     99        assert(bodyStream);
    120100
    121         switch (_bitmapHeader.pack) {
    122         case 0:
    123                 error("unpacked ILBM files are not supported");
    124                 break;
     101        byte *bitmap = new byte[bitmapSize];
     102        assert(bitmap);
     103        memset(bitmap, 0, bitmapSize);
    125104
    126         case 1: {
    127                 uint32 scanWidth = (_bitmapHeader.width + 7) >> 3;
    128                 byte *scan = (byte*)malloc(scanWidth);
    129                 byte *out = (byte*)_surface->pixels;
     105        switch (_header.pack) {
     106        case 1: {       // PackBits compressed bitmap
     107                Graphics::PackBitsReadStream stream(*bodyStream);
    130108
    131                 PackBitsReadStream stream(chunk);
     109                byte *out = bitmap;
    132110
    133                 for (uint32 i = 0; i < _bitmapHeader.height; i++) {
    134                         for (uint32 j = 0; j < _bitmapHeader.depth; j++) {
    135                                 stream.read(scan, scanWidth);
    136                                 fillPlane(out, scan, scanWidth, j);
     111                // setup a buffer to hold enough data to build a line in the output
     112                uint32 scanWidth = (_header.width + 7) >> 3;
     113                byte *scanBuffer = new byte[scanWidth * _header.depth];
     114
     115                for (uint i = 0; i < _header.height; ++i) {
     116                        byte *s = scanBuffer;
     117                        for (uint32 j = 0; j < _header.depth; ++j) {
     118                                stream.read(s, scanWidth);
     119                                s += scanWidth;
    137120                        }
    138121
    139                         out += _bitmapHeader.width;
     122                        planarToChunky(out, bitmapWidth, scanBuffer, scanWidth);
     123                        out += bitmapWidth;
    140124                }
    141                 free(scan);
     125
     126                delete []scanBuffer;
    142127                break;
    143128        }
    144 
     129        default:
     130                error("only RLE compressed ILBM files are supported");
     131                break;
    145132        }
    146 }
    147133
    148 void ILBMDecoder::fillPlane(byte *out, byte* buf, uint32 width, uint32 plane) {
     134        delete bodyStream;
    149135
    150         byte src, idx, set;
    151         byte mask = 1 << plane;
    152 
    153         for (uint32 j = 0; j < _bitmapHeader.width; j++) {
    154                 src = buf[j >> 3];
    155                 idx = 7 - (j & 7);
    156                 set = src & (1 << idx);
    157 
    158                 if (set)
    159                         out[j] |= mask;
    160         }
    161 
     136        return bitmap;
    162137}
    163138
    164139
     140void ILBMDecoder::planarToChunky(byte *out, uint32 width, byte *in, uint32 planeWidth) {
     141        byte pix, ofs, bit;
     142        byte *s;
    165143
     144        uint32 pixels = width;
     145        if (_packPixels) {
     146                pixels *= (8 / _outPlanes);
     147        }
    166148
    167 PBMDecoder::PBMDecoder(Common::ReadStream &input, Surface &surface, byte *&colors) : IFFParser(input), _surface(&surface), _colors(&colors) {
    168         if (_typeId != ID_PBM)
    169                 error("unsupported IFF subtype '%s'", Common::ID2string(_typeId));
    170 }
     149        for (uint32 x = 0; x < pixels; ++x) {
    171150
    172 void PBMDecoder::decode() {
     151                pix = 0;
     152                ofs = x >> 3;
     153                bit = 0x80 >> (x & 7);
    173154
    174         Common::IFFChunk *chunk;
    175         while ((chunk = nextChunk()) != 0) {
    176                 switch (chunk->id) {
    177                 case ID_BMHD:
    178                         readBMHD(*chunk);
    179                         break;
     155                // first build a pixel by scanning all the usable planes in the input
     156                s = in;
     157                for (uint32 plane = 0; plane < _outPlanes; ++plane) {
     158                        if (s[ofs] & bit) {
     159                                pix |= (1 << plane);
     160                        }
     161                        s += planeWidth;
     162                }
    180163
    181                 case ID_CMAP:
    182                         readCMAP(*chunk);
    183                         break;
    184164
    185                 case ID_BODY:
    186                         readBODY(*chunk);
    187                         break;
     165                // then output the pixel according to the requested packing
     166                if (!_packPixels) {
     167                        out[x] = pix;
     168                } else
     169                if (_outPlanes == 1) {
     170                        out[x/8] |= (pix << (x & 7));
     171                } else
     172                if (_outPlanes == 2) {
     173                        out[x/4] |= (pix << ((x & 3) << 1));
     174                } else
     175                if (_outPlanes == 4) {
     176                        out[x/2] |= (pix << ((x & 1) << 2));
    188177                }
    189178        }
    190179
    191         return;
    192180}
    193181
    194 void PBMDecoder::readBMHD(Common::IFFChunk &chunk) {
    195182
    196         fillBMHD(_bitmapHeader, chunk);
    197183
    198         _colorCount = 1 << _bitmapHeader.depth;
    199         *_colors = (byte*)malloc(sizeof(**_colors) * _colorCount * 3);
    200         _surface->create(_bitmapHeader.width, _bitmapHeader.height, 1);
    201184
    202 }
    203185
    204 void PBMDecoder::readCMAP(Common::IFFChunk &chunk) {
    205         if (*_colors == NULL) {
    206                 error("wrong input chunk sequence");
     186PBMDecoder::PBMDecoder(Common::SeekableReadStream *input) : _hasHeader(false), _paletteSize((uint32)-1), _bodySize((uint32)-1) {
     187        assert(input);
     188        _parser.setInputStream(input);
     189
     190        Common::IFF_ID typeId = _parser.getFORMType();
     191        if (typeId != ID_PBM) {
     192                error("unsupported IFF subtype '%s'", Common::ID2string(typeId));
    207193        }
    208         for (uint32 i = 0; i < _colorCount; i++) {
    209                 (*_colors)[i * 3 + 0] = chunk.readByte();
    210                 (*_colors)[i * 3 + 1] = chunk.readByte();
    211                 (*_colors)[i * 3 + 2] = chunk.readByte();
     194
     195        _hasHeader = _parser.loadIFFBlock(ID_BMHD, &_header, sizeof(_header));
     196        if (!_hasHeader) {
     197                return;
    212198        }
     199
     200        _header.width = TO_BE_16(_header.width);
     201        _header.height = TO_BE_16(_header.height);
     202
     203        _paletteSize = _parser.getIFFBlockSize(ID_CMAP);
     204        _bodySize = _parser.getIFFBlockSize(ID_BODY);
    213205}
    214206
    215 void PBMDecoder::readBODY(Common::IFFChunk& chunk) {
     207byte *PBMDecoder::getPalette() {
     208        assert(_paletteSize != (uint32)-1);
     209        byte *palette = new byte[_paletteSize];
     210        assert(palette);
     211        _parser.loadIFFBlock(ID_CMAP, palette, _paletteSize);
     212        return palette;
     213}
    216214
    217         uint si = 0;
     215byte *PBMDecoder::getBitmap() {
     216        byte *bitmap = new byte[_bodySize];
     217        assert(bitmap);
    218218
    219         switch (_bitmapHeader.pack) {
     219        switch (_header.pack) {
    220220        case 0:
    221                 while (!chunk.hasReadAll()) {
    222                         ((byte*)_surface->pixels)[si++] = chunk.readByte();
    223                 }
     221                _parser.loadIFFBlock(ID_BODY, bitmap, _bodySize);
    224222                break;
    225223
    226224        case 1: {
    227                 PackBitsReadStream stream(chunk);
    228                 stream.read((byte*)_surface->pixels, _surface->w * _surface->h);
     225                Common::SeekableReadStream *packed = _parser.getIFFBlockStream(ID_BODY);
     226                assert(packed);
     227                PackBitsReadStream stream(*packed);
     228                stream.read(bitmap, _bodySize);
     229                delete packed;
    229230                break;
    230231        }
    231232
    232233        }
     234
     235        return bitmap;
    233236}
    234237
     238uint32 PBMDecoder::getWidth() {
     239        assert(_hasHeader);
     240        return _header.width;
     241}
    235242
     243uint32 PBMDecoder::getHeight() {
     244        assert(_hasHeader);
     245        return _header.height;
     246}
    236247
     248uint32 PBMDecoder::getNumColors() {
     249        assert(_hasHeader);
     250        return (1 << _header.depth);
     251}
    237252
     253void decodePBM(Common::SeekableReadStream &input, Surface &surface, byte *&colors) {
     254        PBMDecoder decoder(&input);
    238255
     256        colors = decoder.getPalette();
     257
     258        surface.w = decoder.getWidth();
     259        surface.h = decoder.getHeight();
     260        surface.pitch = surface.w;
     261        surface.bytesPerPixel = 1;
     262        surface.pixels = decoder.getBitmap();
     263}
     264
     265
     266
     267
     268
     269
     270
     271
    239272PackBitsReadStream::PackBitsReadStream(Common::ReadStream &input) : _input(&input) {
    240273}
    241274
     
    281314        return dataSize - left;
    282315}
    283316
    284 
    285 void decodePBM(Common::ReadStream &input, Surface &surface, byte *&colors) {
    286         PBMDecoder decoder(input, surface, colors);
    287         decoder.decode();
    288317}
    289 
    290 }
  • graphics/iff.h

     
    5555};
    5656
    5757
    58 //      handles ILBM subtype of IFF FORM files
    59 //
    60 class ILBMDecoder : public Common::IFFParser {
     58/**
     59 *  Loads and decodes ILBM pictures.
     60 *  The decoder handles 1,2,4,5 and 8 bit deep pictures.
     61 */
     62class ILBMDecoder {
     63        Common::SeekableReadStream *_in;
     64        bool _disposeStream;
    6165
     66        void planarToChunky(byte *out, uint32 width, byte *in, uint32 planeWidth);
     67
     68        uint32 _outPlanes;
     69        bool _packPixels;
     70
    6271protected:
    63         void readBMHD(Common::IFFChunk &chunk);
    64         void readCMAP(Common::IFFChunk &chunk);
    65         void readBODY(Common::IFFChunk &chunk);
     72        Common::IFFParser       _parser;
     73        BMHD    _header;
     74        bool    _hasHeader;
     75        uint32  _bodySize;
     76        uint32  _paletteSize;
    6677
    67         BMHD    _bitmapHeader;
    68         uint32  _colorCount;
     78public:
     79        ILBMDecoder(Common::SeekableReadStream *input, bool disposeStream = false);
    6980
    70         Surface *_surface;
    71         byte    **_colors;
     81        virtual ~ILBMDecoder();
    7282
    73         void fillPlane(byte *out, byte* buf, uint32 width, uint32 plane);
     83        uint32 getWidth();
     84        uint32 getHeight();
    7485
    75 public:
    76         ILBMDecoder(Common::ReadStream &input, Surface &surface, byte *&colors);
    77         virtual ~ILBMDecoder() { }
    78         void decode();
     86        /**
     87     *  Returns the number of colors in the palette.
     88     */
     89        uint32 getNumColors();
     90
     91        /**
     92     *  Returns the palette.
     93     *  The caller must delete the returned buffer.
     94     */
     95        byte *getPalette();
     96
     97        /**
     98         *  Extract and decompress the pixels in the image. Caller can specify the
     99         *  number of color planes needed (higher order planes are discarded).
     100         *
     101         *  packPixels controls how the pixels are stored in the output bitmap. E.g.:
     102         *  an unpacked picture stores 1 pixel per byte, while in case of 2 or 4 bit
     103         *  deep pictures, multiple pixels can be stored into 1 byte.
     104     *
     105     *  The caller must delete the returned buffer.
     106         */
     107        byte *getBitmap(uint32 numPlanes, bool packPixels);
     108
     109        /**
     110         *  Default call using physical color depth and producing an unpacked bitmap.
     111         */
     112        byte *getBitmap() {
     113                assert(_hasHeader);
     114                return getBitmap(_header.depth, false);
     115        }
    79116};
    80117
    81118
    82 //      handles PBM subtype of IFF FORM files
    83 //
     119/**
     120 *  Loads and decodes ILBM pictures.
     121 *  The decoder handles 8 bit deep pictures.
     122 */
    84123class PBMDecoder : public Common::IFFParser {
    85124
    86125protected:
    87         void readBMHD(Common::IFFChunk &chunk);
    88         void readCMAP(Common::IFFChunk &chunk);
    89         void readBODY(Common::IFFChunk &chunk);
     126        Common::IFFParser _parser;
     127        BMHD _header;
    90128
    91         BMHD    _bitmapHeader;
    92         uint32  _colorCount;
     129        bool _hasHeader;
     130        uint32 _paletteSize;
     131        uint32 _bodySize;
    93132
    94         Surface *_surface;
    95         byte    **_colors;
     133public:
     134        PBMDecoder(Common::SeekableReadStream *input);
    96135
    97 public:
    98         PBMDecoder(Common::ReadStream &input, Surface &surface, byte *&colors);
    99         virtual ~PBMDecoder() { }
    100         void decode();
     136        uint32 getWidth();
     137        uint32 getHeight();
     138
     139        /**
     140     *  Returns the number of colors in the palette.
     141     */
     142        uint32 getNumColors();
     143
     144        /**
     145     *  Returns the palette.
     146     *  The caller must delete the returned buffer.
     147         */
     148        byte *getPalette();
     149
     150        /**
     151     *  Returns the picture.
     152     *  The caller must delete the returned buffer.
     153         */
     154        byte *getBitmap();
    101155};
    102156
    103 void decodePBM(Common::ReadStream &input, Surface &surface, byte *&colors);
     157void decodePBM(Common::SeekableReadStream &input, Surface &surface, byte *&colors);
    104158
    105 
    106159/*
    107160        PackBits is a RLE compression algorithm introduced
    108161        by Apple. It is also used to encode ILBM and PBM
  • sound/iff.cpp

     
    3030namespace Audio {
    3131
    3232
    33 void A8SVXDecoder::readVHDR(Common::IFFChunk &chunk) {
    34         _header.oneShotHiSamples = chunk.readUint32BE();
    35         _header.repeatHiSamples = chunk.readUint32BE();
    36         _header.samplesPerHiCycle = chunk.readUint32BE();
    37         _header.samplesPerSec = chunk.readUint16BE();
    38         _header.octaves = chunk.readByte();
    39         _header.compression = chunk.readByte();
    40         _header.volume = chunk.readUint32BE();
    41 }
     33bool A8SVXDecoder::fillHeader(Voice8Header *header) {
     34        assert(header);
    4235
    43 void A8SVXDecoder::readBODY(Common::IFFChunk &chunk) {
     36        if (!_parser.loadIFFBlock(ID_VHDR, header, sizeof(Voice8Header))) {
     37                return false;
     38        }
    4439
    45         switch (_header.compression) {
    46         case 0:
    47                 _dataSize = chunk.size;
    48                 _data = (int8*)malloc(_dataSize);
    49                 chunk.read(_data, _dataSize);
    50                 break;
     40        header->oneShotHiSamples = TO_BE_32(header->oneShotHiSamples);
     41        header->repeatHiSamples = TO_BE_32(header->repeatHiSamples);
     42        header->samplesPerHiCycle = TO_BE_32(header->samplesPerHiCycle);
     43        header->samplesPerSec = TO_BE_16(header->samplesPerSec);
     44        header->volume = TO_BE_32(header->volume);
     45        return true;
     46}
    5147
    52         case 1:
    53                 warning("compressed IFF audio is not supported");
    54                 break;
     48int8 *A8SVXDecoder::getData() {
     49        uint32 size = getDataSize();
     50        if (size == (uint32)-1) {
     51                return 0;
    5552        }
     53        int8 *data = new int8[size];
     54        assert(data);
     55        _parser.loadIFFBlock(ID_BODY, data, size);
     56        return data;
     57}
    5658
     59uint32 A8SVXDecoder::getDataSize() {
     60        return _parser.getIFFBlockSize(ID_BODY);
    5761}
    5862
    5963
    60 A8SVXDecoder::A8SVXDecoder(Common::ReadStream &input, Voice8Header &header, int8 *&data, uint32 &dataSize) :
    61         IFFParser(input), _header(header), _data(data), _dataSize(dataSize) {
    62         if (_typeId != ID_8SVX)
     64A8SVXDecoder::A8SVXDecoder(Common::SeekableReadStream *input) : _parser(input) {
     65        if (_parser.getFORMType() != ID_8SVX) {
    6366                error("unknown audio format");
     67        }
    6468}
    6569
    66 void A8SVXDecoder::decode() {
    6770
    68         Common::IFFChunk *chunk;
    69 
    70         while ((chunk = nextChunk()) != 0) {
    71                 switch (chunk->id) {
    72                 case ID_VHDR:
    73                         readVHDR(*chunk);
    74                         break;
    75 
    76                 case ID_BODY:
    77                         readBODY(*chunk);
    78                         break;
    79                 }
    80         }
    8171}
    82 
    83 }
  • sound/iff.h

     
    5555
    5656        TODO: make a factory function for this kind of stream?
    5757 */
    58 class A8SVXDecoder : public Common::IFFParser {
     58class A8SVXDecoder  {
     59        Common::IFFParser _parser;
    5960
    6061protected:
    61         Voice8Header    &_header;
    62         int8*                   &_data;
    63         uint32                  &_dataSize;
     62        Voice8Header    *_header;
    6463
    65 protected:
    66         void readVHDR(Common::IFFChunk &chunk);
    67         void readBODY(Common::IFFChunk &chunk);
    68 
    6964public:
    70         A8SVXDecoder(Common::ReadStream &input, Voice8Header &header, int8 *&data, uint32 &dataSize);
    71         void decode();
     65        A8SVXDecoder(Common::SeekableReadStream *input);
     66
     67        bool fillHeader(Voice8Header *header);
     68        int8 *getData();
     69        uint32 getDataSize();
    7270};
    7371
    7472