Skip to content

Commit

Permalink
Change: Support decoding NewGRFs with out-of-order v2 container.
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterN committed Dec 12, 2023
1 parent 13c2e81 commit ef78232
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 12 deletions.
33 changes: 29 additions & 4 deletions src/grfcodec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <sys/stat.h>
#include <getopt.h>
#include <algorithm>
#include <map>

#ifdef __MINGW32__
#include <io.h>
Expand Down Expand Up @@ -651,6 +652,31 @@ static int encode(const char *file, const char *dir, int compress, int *colourma
return 0;
}

std::map<uint, off_t> _sprite_offsets{};

static void read_grf_sprite_offsets(FILE *grf)
{
_sprite_offsets.clear();

const char action[] = "Reading sprite offsets";
uint32_t offset = readdword(action, grf);
off_t pos = ftell(grf);
fseek(grf, offset, SEEK_CUR);

uint id = 0, count = 0;
while ((id = readdword(action, grf)) != 0) {
if (_sprite_offsets.count(id) == 0)
_sprite_offsets[id] = ftell(grf) - 4;

fseek(grf, readdword(action, grf), SEEK_CUR);
count++;
}

printf("Found %zu / %u container chunks\n", _sprite_offsets.size(), count);

fseek(grf, pos, SEEK_SET);
}

static int decode(const char *file, const char *dir, const U8 *palette, int box, int width, int height, int *colourmap, int useplaintext)
{
int count, result, lastpct = -1;
Expand Down Expand Up @@ -694,14 +720,13 @@ static int decode(const char *file, const char *dir, const U8 *palette, int box,
cfread(action, buffer, 1, sizeof(buffer), grf);
int grfcontversion = memcmp(buffer, header, sizeof(header)) == 0 ? 2 : 1;

U32 dataoffset = 0;
printf("Found grf container version %d\n", grfcontversion);
if (grfcontversion == 1) {
fseek(grf, 0, SEEK_SET);
} else {
dataoffset = sizeof(header) + 4 + readdword(action, grf); // GRF data offset
read_grf_sprite_offsets(grf);
fgetc(grf); // Compression
}
printf("Found grf container version %d\n", grfcontversion);

// We do the 'file' and 'writer' seperate to make
// this a little bit less messy
Expand Down Expand Up @@ -764,7 +789,7 @@ static int decode(const char *file, const char *dir, const U8 *palette, int box,
pcx->newsprite();
if (pcx32 != NULL) pcx32->newsprite();

result = decodesprite(grf, pcx, pcx32, &writer, count, &dataoffset, grfcontversion);
result = decodesprite(grf, pcx, pcx32, &writer, count, grfcontversion);
writer.flush();
count++;
} while (result);
Expand Down
14 changes: 7 additions & 7 deletions src/sprites.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
\*****************************************/

#include <stdlib.h>
#include <map>

#include "sprites.h"
#include "grfcomm.h"
Expand Down Expand Up @@ -241,7 +242,9 @@ static void writesprite(bool first, spritestorage *image_writer, spriteinfowrite
image_writer->spritedone(info.xdim, info.ydim);
}

int decodesprite(FILE *grf, spritestorage *imgpal, spritestorage *imgrgba, spriteinfowriter *writer, int spriteno, U32 *dataoffset, int grfcontversion)
extern std::map<uint, off_t> _sprite_offsets;

int decodesprite(FILE *grf, spritestorage *imgpal, spritestorage *imgrgba, spriteinfowriter *writer, int spriteno, int grfcontversion)
{
static const char *action = "decoding sprite";
unsigned long size, datasize, inbufsize, outbufsize, startpos, returnpos = 0;
Expand All @@ -268,7 +271,8 @@ int decodesprite(FILE *grf, spritestorage *imgpal, spritestorage *imgrgba, sprit
id = readdword(action, grf);
returnpos = ftell(grf);

fseek(grf, *dataoffset, SEEK_SET);
uint32_t dataoffset = _sprite_offsets[id];
fseek(grf, dataoffset, SEEK_SET);
}

long result;
Expand Down Expand Up @@ -302,7 +306,6 @@ int decodesprite(FILE *grf, spritestorage *imgpal, spritestorage *imgrgba, sprit
result = 1;

if (returnpos == 0) return result;
*dataoffset = startpos + size + 1;
break;
}

Expand Down Expand Up @@ -422,10 +425,7 @@ int decodesprite(FILE *grf, spritestorage *imgpal, spritestorage *imgrgba, sprit
free(outbuffer);
free(imgbuffer);

if (returnpos != 0) {
*dataoffset = startpos + inbufsize;
if (grfcontversion == 2 && HASTRANSPARENCY(info.info)) *dataoffset += 4;
} else {
if (returnpos == 0) {
returnpos = startpos + inbufsize;
break;
}
Expand Down
2 changes: 1 addition & 1 deletion src/sprites.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class spritestorage {

extern int maxx, maxy, maxs;

int decodesprite(FILE *grf, spritestorage *imgpal, spritestorage *imgrgba, spriteinfowriter *writer, int spriteno, U32 *dataoffset, int grfcontversion);
int decodesprite(FILE *grf, spritestorage *imgpal, spritestorage *imgrgba, spriteinfowriter *writer, int spriteno, int grfcontversion);

long getlasttilesize();
long encodetile(U8 **compressed_data, long *uncompressed_size, const CommonPixel *image, long imgsize, int sx, int sy, SpriteInfo inf, int docompress, int spriteno, bool has_mask, bool rgba, int grfcontversion);
Expand Down

0 comments on commit ef78232

Please sign in to comment.