Skip to content

Commit

Permalink
Common: check (de)compression result in SpriteFile, + tidy deflate func
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-mogilko committed Aug 30, 2023
1 parent 72e0d00 commit efa54fb
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 57 deletions.
35 changes: 22 additions & 13 deletions Common/ac/spritefile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ HError SpriteFile::LoadSprite(sprkey_t index, Common::Bitmap *&sprite)
ReadSprHeader(hdr, _stream.get(), _version, _compress);
if (hdr.BPP == 0) return HError::None(); // empty slot, this is normal
int bpp = hdr.BPP, w = hdr.Width, h = hdr.Height;
Bitmap *image = BitmapHelper::CreateBitmap(w, h, bpp * 8);
std::unique_ptr<Bitmap> image(BitmapHelper::CreateBitmap(w, h, bpp * 8));
if (image == nullptr)
{
return new Error(String::FromFormat("LoadSprite: failed to allocate bitmap %d (%dx%d%d).",
Expand Down Expand Up @@ -434,22 +434,28 @@ HError SpriteFile::LoadSprite(sprkey_t index, Common::Bitmap *&sprite)
(uint32_t)_stream->ReadInt32() : (w * h * bpp);
if (hdr.Compress != kSprCompress_None)
{
// TODO: rewrite this to only make a choice once the SpriteFile is initialized
// and use either function ptr or a decompressing stream class object
if (in_data_size == 0)
{
delete image;
return new Error(String::FromFormat("LoadSprite: bad compressed data for sprite %d.", index));
}
bool result;
switch (hdr.Compress)
{
case kSprCompress_RLE: rle_decompress(im_data.Buf, im_data.Size, im_data.BPP, _stream.get());
case kSprCompress_RLE: result = rle_decompress(im_data.Buf, im_data.Size, im_data.BPP, _stream.get());
break;
case kSprCompress_LZW: lzw_decompress(im_data.Buf, im_data.Size, im_data.BPP, _stream.get(), in_data_size);
case kSprCompress_LZW: result = lzw_decompress(im_data.Buf, im_data.Size, im_data.BPP, _stream.get(), in_data_size);
break;
case kSprCompress_Deflate: inflate_decompress(im_data.Buf, im_data.Size, im_data.BPP, _stream.get(), in_data_size);
case kSprCompress_Deflate: result = inflate_decompress(im_data.Buf, im_data.Size, im_data.BPP, _stream.get(), in_data_size);
break;
default: assert(!"Unsupported compression type!"); break;
default: assert(!"Unsupported compression type!"); result = false; break;
}
// TODO: test that not more than data_size was read!
if (!result)
{
return new Error(String::FromFormat("LoadSprite: failed to decompress pixel array for sprite %d.", index));
}
}
// Otherwise (no compression) read directly
else
Expand All @@ -470,10 +476,10 @@ HError SpriteFile::LoadSprite(sprkey_t index, Common::Bitmap *&sprite)
// Finally revert storage options
if (pal_bpp > 0)
{
UnpackIndexedBitmap(image, im_data.Buf, im_data.Size, palette, hdr.PalCount);
UnpackIndexedBitmap(image.get(), im_data.Buf, im_data.Size, palette, hdr.PalCount);
}

sprite = image;
sprite = image.release(); // FIXME: pass unique_ptr in this function
_curPos = index + 1; // mark correct pos
return HError::None();
}
Expand Down Expand Up @@ -693,20 +699,23 @@ void SpriteFileWriter::WriteBitmap(Bitmap *image)
SpriteCompression compress = kSprCompress_None;
if (_compress != kSprCompress_None)
{
// TODO: rewrite this to only make a choice once the SpriteFile is initialized
// and use either function ptr or a decompressing stream class object
compress = _compress;
VectorStream mems(_membuf, kStream_Write);
bool result;
switch (compress)
{
case kSprCompress_RLE: rle_compress(im_data.Buf, im_data.Size, im_data.BPP, &mems);
case kSprCompress_RLE: result = rle_compress(im_data.Buf, im_data.Size, im_data.BPP, &mems);
break;
case kSprCompress_LZW: lzw_compress(im_data.Buf, im_data.Size, im_data.BPP, &mems);
case kSprCompress_LZW: result = lzw_compress(im_data.Buf, im_data.Size, im_data.BPP, &mems);
break;
case kSprCompress_Deflate: deflate_compress(im_data.Buf, im_data.Size, im_data.BPP, &mems);
case kSprCompress_Deflate: result = deflate_compress(im_data.Buf, im_data.Size, im_data.BPP, &mems);
break;
default: assert(!"Unsupported compression type!"); break;
default: assert(!"Unsupported compression type!"); result = false; break;
}
// mark to write as a plain byte array
im_data = ImBufferCPtr(&_membuf[0], _membuf.size(), 1);
im_data = result ? ImBufferCPtr(&_membuf[0], _membuf.size(), 1) : ImBufferCPtr();
}

// Write the final data
Expand Down
59 changes: 21 additions & 38 deletions Common/util/compress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,18 @@
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================

#include "util/compress.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <vector>
#include <miniz.h>
#include "ac/common.h" // quit, update_polled_stuff
#include "gfx/bitmap.h"
#include "util/lzw.h"
#include "util/memorystream.h"
#if AGS_PLATFORM_ENDIAN_BIG
#include "util/bbop.h"
#endif
#include <miniz.h>

using namespace AGS::Common;

Expand Down Expand Up @@ -149,8 +147,6 @@ static int cunpackbitl(uint8_t *line, size_t size, Stream *in)

while (n < size) {
int ix = in->ReadByte(); // get index byte
if (in->HasErrors())
break;

signed char cx = ix;
if (cx == -128)
Expand Down Expand Up @@ -178,7 +174,7 @@ static int cunpackbitl(uint8_t *line, size_t size, Stream *in)
}
}

return in->HasErrors() ? -1 : 0;
return 0;
}

static int cunpackbitl16(uint16_t *line, size_t size, Stream *in)
Expand All @@ -187,8 +183,6 @@ static int cunpackbitl16(uint16_t *line, size_t size, Stream *in)

while (n < size) {
int ix = in->ReadByte(); // get index byte
if (in->HasErrors())
break;

signed char cx = ix;
if (cx == -128)
Expand Down Expand Up @@ -216,7 +210,7 @@ static int cunpackbitl16(uint16_t *line, size_t size, Stream *in)
}
}

return in->HasErrors() ? -1 : 0;
return 0;
}

static int cunpackbitl32(uint32_t *line, size_t size, Stream *in)
Expand All @@ -225,8 +219,6 @@ static int cunpackbitl32(uint32_t *line, size_t size, Stream *in)

while (n < size) {
int ix = in->ReadByte(); // get index byte
if (in->HasErrors())
break;

signed char cx = ix;
if (cx == -128)
Expand Down Expand Up @@ -254,10 +246,10 @@ static int cunpackbitl32(uint32_t *line, size_t size, Stream *in)
}
}

return in->HasErrors() ? -1 : 0;
return 0;
}

void rle_compress(const uint8_t *data, size_t data_sz, int image_bpp, Stream *out)
bool rle_compress(const uint8_t *data, size_t data_sz, int image_bpp, Stream *out)
{
switch (image_bpp)
{
Expand All @@ -266,9 +258,10 @@ void rle_compress(const uint8_t *data, size_t data_sz, int image_bpp, Stream *ou
case 4: cpackbitl32(reinterpret_cast<const uint32_t*>(data), data_sz / sizeof(uint32_t), out); break;
default: assert(0); break;
}
return true;
}

void rle_decompress(uint8_t *data, size_t data_sz, int image_bpp, Stream *in)
bool rle_decompress(uint8_t *data, size_t data_sz, int image_bpp, Stream *in)
{
switch (image_bpp)
{
Expand All @@ -277,6 +270,7 @@ void rle_decompress(uint8_t *data, size_t data_sz, int image_bpp, Stream *in)
case 4: cunpackbitl32(reinterpret_cast<uint32_t*>(data), data_sz / sizeof(uint32_t), in); break;
default: assert(0); break;
}
return true;
}

void save_rle_bitmap8(Stream *out, const Bitmap *bmp, const RGB (*pal)[256])
Expand Down Expand Up @@ -342,29 +336,29 @@ void skip_rle_bitmap8(Stream *in)
// LZW
//-----------------------------------------------------------------------------

void lzw_compress(const uint8_t *data, size_t data_sz, int /*image_bpp*/, Stream *out)
bool lzw_compress(const uint8_t *data, size_t data_sz, int /*image_bpp*/, Stream *out)
{
// LZW algorithm that we use fails on sequence less than 16 bytes.
if (data_sz < 16)
{
out->Write(data, data_sz);
return;
return true;
}
MemoryStream mem_in(data, data_sz);
lzwcompress(&mem_in, out);
return lzwcompress(&mem_in, out);
}

void lzw_decompress(uint8_t *data, size_t data_sz, int /*image_bpp*/, Stream *in, size_t in_sz)
bool lzw_decompress(uint8_t *data, size_t data_sz, int /*image_bpp*/, Stream *in, size_t in_sz)
{
// LZW algorithm that we use fails on sequence less than 16 bytes.
if (data_sz < 16)
{
in->Read(data, data_sz);
return;
return true;
}
std::vector<uint8_t> in_buf(in_sz);
in->Read(in_buf.data(), in_sz);
lzwexpand(in_buf.data(), in_sz, data, data_sz);
return lzwexpand(in_buf.data(), in_sz, data, data_sz);
}

void save_lzw(Stream *out, const Bitmap *bmpp, const RGB (*pal)[256])
Expand Down Expand Up @@ -458,14 +452,11 @@ bool z_deflate(Stream* input, Stream* output) {

int ret = deflateInit(&stream, Z_DEFAULT_COMPRESSION);
if (ret != Z_OK) {
std::cerr << "Error initializing compression" << std::endl;
return false;
}

stream.data_type = 0;

char inbuf[1024];
char outbuf[1024];
uint8_t inbuf[1024];
uint8_t outbuf[1024];

stream.avail_in = input->Read(inbuf, sizeof(inbuf));
while (stream.avail_in > 0) {
Expand All @@ -485,21 +476,15 @@ bool z_deflate(Stream* input, Stream* output) {
}

(void)deflateEnd(&stream);

return true;
}

bool z_inflate(const uint8_t* src, size_t src_sz, uint8_t* dst, size_t dst_sz) {
z_stream stream;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
stream.avail_in = 0;
stream.next_in = Z_NULL;
memset(&stream, 0, sizeof(stream));

int ret = inflateInit(&stream);
if (ret != Z_OK) {
std::cerr << "Error initializing decompression" << std::endl;
return false;
}

Expand All @@ -515,7 +500,6 @@ bool z_inflate(const uint8_t* src, size_t src_sz, uint8_t* dst, size_t dst_sz) {
case Z_DATA_ERROR:
case Z_MEM_ERROR:
case Z_BUF_ERROR:
std::cerr << "Error decompressing data" << std::endl;
(void)inflateEnd(&stream);
return false;
default:
Expand All @@ -525,19 +509,18 @@ bool z_inflate(const uint8_t* src, size_t src_sz, uint8_t* dst, size_t dst_sz) {
} while (stream.avail_out > 0);

(void)inflateEnd(&stream);

return true;
}

void deflate_compress(const uint8_t* data, size_t data_sz, int /*image_bpp*/, Stream* out)
bool deflate_compress(const uint8_t* data, size_t data_sz, int /*image_bpp*/, Stream* out)
{
MemoryStream mem_in(data, data_sz);
z_deflate(&mem_in, out);
return z_deflate(&mem_in, out);
}

void inflate_decompress(uint8_t* data, size_t data_sz, int /*image_bpp*/, Stream* in, size_t in_sz)
bool inflate_decompress(uint8_t* data, size_t data_sz, int /*image_bpp*/, Stream* in, size_t in_sz)
{
std::vector<uint8_t> in_buf(in_sz);
in->Read(in_buf.data(), in_sz);
z_inflate(in_buf.data(), in_sz, data, data_sz);
return z_inflate(in_buf.data(), in_sz, data, data_sz);
}
12 changes: 6 additions & 6 deletions Common/util/compress.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ namespace AGS { namespace Common { class Stream; class Bitmap; } }
using namespace AGS; // FIXME later

// RLE compression
void rle_compress(const uint8_t *data, size_t data_sz, int image_bpp, Common::Stream *out);
void rle_decompress(uint8_t *data, size_t data_sz, int image_bpp, Common::Stream *in);
bool rle_compress(const uint8_t *data, size_t data_sz, int image_bpp, Common::Stream *out);
bool rle_decompress(uint8_t *data, size_t data_sz, int image_bpp, Common::Stream *in);
// Packs a 8-bit bitmap using RLE compression, and writes into stream along with the palette
void save_rle_bitmap8(Common::Stream *out, const Common::Bitmap *bmp, const RGB (*pal)[256] = nullptr);
// Reads a 8-bit bitmap with palette from the stream and unpacks from RLE
Expand All @@ -34,15 +34,15 @@ std::unique_ptr<Common::Bitmap> load_rle_bitmap8(Common::Stream *in, RGB (*pal)[
void skip_rle_bitmap8(Common::Stream *in);

// LZW compression
void lzw_compress(const uint8_t *data, size_t data_sz, int image_bpp, Common::Stream *out);
void lzw_decompress(uint8_t *data, size_t data_sz, int image_bpp, Common::Stream *in, size_t in_sz);
bool lzw_compress(const uint8_t *data, size_t data_sz, int image_bpp, Common::Stream *out);
bool lzw_decompress(uint8_t *data, size_t data_sz, int image_bpp, Common::Stream *in, size_t in_sz);
// Saves bitmap with an optional palette compressed by LZW
void save_lzw(Common::Stream *out, const Common::Bitmap *bmpp, const RGB (*pal)[256] = nullptr);
// Loads bitmap decompressing
std::unique_ptr<Common::Bitmap> load_lzw(Common::Stream *in, int dst_bpp, RGB (*pal)[256] = nullptr);

// Deflate compression
void deflate_compress(const uint8_t* data, size_t data_sz, int image_bpp, Common::Stream* out);
void inflate_decompress(uint8_t* data, size_t data_sz, int image_bpp, Common::Stream* in, size_t in_sz);
bool deflate_compress(const uint8_t* data, size_t data_sz, int image_bpp, Common::Stream* out);
bool inflate_decompress(uint8_t* data, size_t data_sz, int image_bpp, Common::Stream* in, size_t in_sz);

#endif // __AC_COMPRESS_H

0 comments on commit efa54fb

Please sign in to comment.