/trunk/Makefile |
---|
0,0 → 1,33 |
all: ipe_artfile_unpacker ipe_artfile_packer |
ipe_artfile_unpacker: ipe_artfile_unpacker.c ipe_artfile_unpacker_ipe16.c ipe_artfile_unpacker_ipe32.c ipe16_lzw_decoder.c ipe32_lzw_decoder.c ipe16_bmpexport.c ipe32_bmpexport.c utils.c |
gcc -std=c99 -Wall -c ipe_artfile_unpacker.c -o ipe_artfile_unpacker.o |
gcc -std=c99 -Wall -c ipe_artfile_unpacker_ipe16.c -o ipe_artfile_unpacker_ipe16.o |
gcc -std=c99 -Wall -c ipe_artfile_unpacker_ipe32.c -o ipe_artfile_unpacker_ipe32.o |
gcc -std=c99 -Wall -c ipe16_lzw_decoder.c -o ipe16_lzw_decoder.o |
gcc -std=c99 -Wall -c ipe32_lzw_decoder.c -o ipe32_lzw_decoder.o |
gcc -std=c99 -Wall -c ipe16_bmpexport.c -o ipe16_bmpexport.o |
gcc -std=c99 -Wall -c ipe32_bmpexport.c -o ipe32_bmpexport.o |
gcc -std=c99 -Wall -c utils.c -o utils.o |
gcc -o ipe_artfile_unpacker ipe_artfile_unpacker.o ipe_artfile_unpacker_ipe16.o ipe_artfile_unpacker_ipe32.o ipe16_lzw_decoder.o ipe32_lzw_decoder.o ipe16_bmpexport.o ipe32_bmpexport.o utils.o |
rm *.o |
ipe_artfile_packer: ipe_artfile_packer.c ipe_artfile_packer_ipe16_ba.c ipe_artfile_packer_ipe16_pip.c ipe_artfile_packer_ipe32.c ipe16_lzw_encoder.c ipe32_lzw_encoder.c ipe16_bmpimport.c ipe32_bmpimport.c utils.c |
gcc -std=c99 -Wall -c ipe_artfile_packer.c -o ipe_artfile_packer.o |
gcc -std=c99 -Wall -c ipe_artfile_packer_ipe16_ba.c -o ipe_artfile_packer_ipe16_ba.o |
gcc -std=c99 -Wall -c ipe_artfile_packer_ipe16_pip.c -o ipe_artfile_packer_ipe16_pip.o |
gcc -std=c99 -Wall -c ipe_artfile_packer_ipe32.c -o ipe_artfile_packer_ipe32.o |
gcc -std=c99 -Wall -c ipe16_lzw_encoder.c -o ipe16_lzw_encoder.o |
gcc -std=c99 -Wall -c ipe32_lzw_encoder.c -o ipe32_lzw_encoder.o |
gcc -std=c99 -Wall -c ipe16_bmpimport.c -o ipe16_bmpimport.o |
gcc -std=c99 -Wall -c ipe32_bmpimport.c -o ipe32_bmpimport.o |
gcc -std=c99 -Wall -c utils.c -o utils.o |
gcc -lm -o ipe_artfile_packer ipe_artfile_packer.o ipe_artfile_packer_ipe16_ba.o ipe_artfile_packer_ipe16_pip.o ipe_artfile_packer_ipe32.o ipe16_lzw_encoder.c ipe32_lzw_encoder.o ipe16_bmpimport.o ipe32_bmpimport.o utils.o |
rm *.o |
clean: |
rm -f *.o |
# TODO: if [ -f ... ] then rm |
rm ipe_artfile_packer |
rm ipe_artfile_unpacker |
/trunk/TODO |
---|
0,0 → 1,6 |
Future: Allow several input arguments (e.g. *.ART) |
Packer: Like the unpacker, implement a simulation mode (so that no ART file is written) |
Please see also : grep -r "// TODO" |
/trunk/artfile_overview.txt |
---|
0,0 → 1,56 |
ART FILES BY IMAGINATION PILOTS |
Technical overview by Daniel Marschall 15 Feb 2018 |
VERSION 1.x (16-bit era, "IPE16") |
================================= |
Version 1.0 For game: "Blown Away" (1994) |
* File signature "Art" + 20 NUL bytes |
* Image names up to 23 characters |
(unsure if the 23th byte must be a zero terminator) |
* LZW implementation: GIF standard implementation |
- variable code length between 9 and 12 bits |
- clear code (256) |
- end code (257) |
* Pictures can only be 8-bit |
* Each picture can either be LZW compressed (code "P") |
or uncompressed (code "p", lower case) |
* Decompressed/raw data: Top-down pixel data |
* Attached: Optional palette (R,G,B), uncompressed. |
(Sprites usually do not have a palette, so the game |
will use the palette of the parent picture) |
Version 1.1 For games: "Panic in the Park" (1995) |
"Where's Waldo? At the Circus" (1995) |
* Codes for compression/raw are now "Q" and "q" instead of |
"P" and "p" |
* Each picture has now a relative X- and Y-offsets for 'fine-tuning'. |
These offsets cannot be negative, though. |
VERSION 2.x (32-bit era, "IPE32") |
================================= |
Version 2.0 For games: "Where's Waldo? Exploring Geography" (1996) |
"Eraser Turnabout" (1997) |
"Virtual K'Nex" (1998) |
* File signature "ART_DATA" |
* Image names up to 8 characters; |
no zero termination required after the 8 characters. |
* LZW implementation by Mark R. Nelson and Shawn M. Regan |
- variable code length between 9 and 13 bits |
- clear code (256) |
- end code (257) |
* Pictures are divided into chunks. Each chunk can be compressed or |
uncompressed. Limitations: |
- Each compressed chunk (except the last one) must decode into |
exactly 16382 (0x3FFE) bytes of uncompressed data. |
- The size of the compressed data of a chunk must not exceed the |
size of the original uncompressed data. |
* The size of each chunk (raw or compressed) is limited |
to max. 32767 Bytes (0x7FFF). |
* Decompressed/raw data: Windows Bitmap (without file header); |
therefore, theoretically every color depth/compression/etc. can be used. |
For 8-bit pictures, the palette is included in the Bitmap. |
* Re-using of parent palette is not possible. |
Property changes: |
Added: svn:mime-type |
+text/plain |
\ No newline at end of property |
/trunk/artfile_structure_10.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = image/png |
Property changes: |
Added: svn:mime-type |
+image/png |
\ No newline at end of property |
/trunk/artfile_structure_11.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = image/png |
Property changes: |
Added: svn:mime-type |
+image/png |
\ No newline at end of property |
/trunk/artfile_structure_20.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = image/png |
Property changes: |
Added: svn:mime-type |
+image/png |
\ No newline at end of property |
/trunk/bitmap.h |
---|
0,0 → 1,51 |
#ifndef __inc__bitmap |
#define __inc__bitmap |
#include <stdint.h> |
// "BM" |
#define BI_SIGNATURE 0x4D42 |
// see https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751%28v=vs.85%29.aspx |
#define BYTE uint8_t |
#define WORD uint16_t |
#define DWORD uint32_t |
#define LONG int32_t |
// These parts were extracted from WinGDI.h and WinDef.h |
#define BI_RGB 0 |
#pragma pack(push,2) |
typedef struct tagBITMAPFILEHEADER { |
WORD bfType; |
DWORD bfSize; |
WORD bfReserved1; |
WORD bfReserved2; |
DWORD bfOffBits; |
} BITMAPFILEHEADER,*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER; |
#pragma pack(pop) |
typedef struct tagBITMAPINFOHEADER{ |
DWORD biSize; |
LONG biWidth; |
LONG biHeight; |
WORD biPlanes; |
WORD biBitCount; |
DWORD biCompression; |
DWORD biSizeImage; |
LONG biXPelsPerMeter; |
LONG biYPelsPerMeter; |
DWORD biClrUsed; |
DWORD biClrImportant; |
} BITMAPINFOHEADER,*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER; |
typedef struct tagRGBQUAD { |
BYTE rgbBlue; |
BYTE rgbGreen; |
BYTE rgbRed; |
BYTE rgbReserved; |
} RGBQUAD,*LPRGBQUAD; |
#endif // #ifndef __inc__bitmap |
Property changes: |
Added: svn:mime-type |
+text/x-chdr |
\ No newline at end of property |
/trunk/build_stable |
---|
0,0 → 1,25 |
#!/bin/bash |
# Get the directory of this script (also works with symlinks) |
# http://stackoverflow.com/questions/59895/can-a-bash-script-tell-what-directory-its-stored-in |
SOURCE="${BASH_SOURCE[0]}" |
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink |
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" |
SOURCE="$(readlink "$SOURCE")" |
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located |
done |
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" |
cd "$DIR" |
dirname=$( basename "$( pwd )" ) |
tmpfile=$( mktemp ) |
FILENAME="stable.tar.gz" |
cd .. |
tar cvfz "$tmpfile" --exclude="$dirname"/"$FILENAME" --exclude ".svn" -- "$dirname" |
# otherwise: "the file has changed while reading" |
mv "$tmpfile" "$dirname"/"$FILENAME" |
chmod 644 "$dirname"/"$FILENAME" |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/trunk/ipe16_artfile.h |
---|
0,0 → 1,85 |
/** |
* ART files for Imagination Pilots Entertainment 16-bit games (IPE16) |
* - Blown Away - The Interactive Game by Imagination Pilots (BA) |
* - Panic in the Park - The Interactive Game by Imagination Pilots (PiP) |
* - Where's Waldo? At the Circus (Waldo1) |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Revision: 2018-02-15 |
**/ |
#ifndef __inc__ipe16_artfile |
#define __inc__ipe16_artfile |
#include <stdint.h> |
#define BA_COMPRESSIONTYPE_LZW 'P' |
#define BA_COMPRESSIONTYPE_NONE 'p' |
// PANIC.EXE offset 0x44365: Choice between "Q" and "q" |
#define PIP_COMPRESSIONTYPE_LZW 'Q' |
#define PIP_COMPRESSIONTYPE_NONE 'q' |
#define IPE16_PALETTETYPE_ATTACHED 'X' |
// Pictures with the type 'C' do not have a palette. |
// They use the palette of their parent picture where they are embedded in |
#define IPE16_PALETTETYPE_PARENT 'C' |
#define IPE16_NAME_SIZE 23 |
#define IPE16_MAGIC_ART "Art" |
#define IPE16_MAGIC_DUMMY '?' |
#pragma pack(push, 1) |
typedef struct tagIpe16FileHeader { |
char magic[IPE16_NAME_SIZE]; // always "Art\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" (ignored by the game) |
char dummy; // always '?' (ignored by the game) |
uint32_t numHeaderEntries; // number of headers including this file header (number of follow-up Ipe16PictureEntryHeader entries plus one) |
uint32_t totalFileSize; // total file size including this header (ignored by the game) |
} Ipe16FileHeader; |
typedef struct tagIpe16PictureEntryHeader { |
char name[IPE16_NAME_SIZE]; // zero terminated string. case sensitive |
char paletteType; // 'X' (0x58) = RGB palette attached |
// 'C' (0x43) = no palette attached (for embedded picture, use palette of parent picture) |
uint32_t offset; // offset to the picture (PictureHeader) |
uint32_t size; // size of the picture (PictureHeader + picture data + optional palette) |
} Ipe16PictureEntryHeader; |
typedef struct tagBAPictureHeader { |
char compressionType; // Compression type of the follow-up data (top down pixel data; the palette won't be compressed) |
// 'P' (0x50, upper case) = LZW compression, more precisely: |
// The LZW variant of the GIF specification, |
// but without splitting the output data into chunks |
// 'p' (0x70, lower case) = No compression |
uint16_t width; // width of the picture |
uint16_t height; // height of the picture |
} BAPictureHeader; |
typedef struct tagPipPictureHeader { |
char compressionType; // Compression type of the follow-up data (top down pixel data; the palette won't be compressed) |
// 'Q' (0x51, upper case) = LZW compression, more precisely: |
// The LZW variant of the GIF specification, |
// but without splitting the output data into chunks |
// 'q' (0x71, lower case) = No compression |
uint16_t offsetX; // Additional offsets for 'fine-tuning' |
uint16_t offsetY; |
uint16_t width; // width of the picture |
uint16_t height; // height of the picture |
} PipPictureHeader; |
typedef struct tagIpe16ColorTableEntry { |
uint8_t r; |
uint8_t g; |
uint8_t b; |
} Ipe16ColorTableEntry; |
typedef struct tagIpe16ColorTable { |
Ipe16ColorTableEntry colors[256]; |
} Ipe16ColorTable; |
#pragma pack(pop) |
#endif // #ifndef __inc__ipe16_artfile |
Property changes: |
Added: svn:mime-type |
+text/x-chdr |
\ No newline at end of property |
/trunk/ipe16_bmpexport.c |
---|
0,0 → 1,106 |
/** |
* Bitmap Export for Imagination Pilots Entertainment 16-bit games (IPE16) |
* - Blown Away - The Interactive Game by Imagination Pilots (BA) |
* - Panic in the Park - The Interactive Game by Imagination Pilots (PiP) |
* - Where's Waldo? At the Circus (Waldo1) |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Revision: 2018-02-15 |
**/ |
#include <stdio.h> |
#include <stdint.h> |
#include <stdlib.h> |
#include <string.h> |
#include <assert.h> |
#include "ipe16_bmpexport.h" |
#define BMP_LINE_PADDING 4 |
// Windows 98 does not support top-down bitmaps, so we need to flip everything |
#define USE_BOTTOMUP |
RGBQUAD ipe16_rgb_to_rgbquad(Ipe16ColorTableEntry cte) { |
RGBQUAD ret; |
ret.rgbRed = cte.r; |
ret.rgbGreen = cte.g; |
ret.rgbBlue = cte.b; |
ret.rgbReserved = 0; |
return ret; |
} |
void ipe16_write_bmp(FILE* output, unsigned int width, unsigned int height, unsigned char* imagedata, size_t imagedata_len, Ipe16ColorTable ct) { |
#ifdef USE_BOTTOMUP |
const size_t bmpDataSize = width*height; |
unsigned char* bmpData = (unsigned char*)malloc(bmpDataSize); |
assert(bmpData != NULL); |
int h; |
for (h=0; h<height; ++h) { |
int idx_dest = (height-1)-h; |
int idx_src = h; |
assert(idx_src*width >= 0); |
assert(idx_dest*width >= 0); |
memcpy(bmpData+idx_dest*width, imagedata+idx_src*width, width); |
} |
imagedata = bmpData; |
#endif |
// Each line must be padded to a multiple of 4 |
int pad = (BMP_LINE_PADDING - (width % BMP_LINE_PADDING)) % BMP_LINE_PADDING; |
int newwidth = width+pad; |
int newsize = newwidth * height; |
unsigned char* padded_imagedata = (unsigned char*)malloc(newsize); |
int i; |
for (i=0; i<height; ++i) { |
int offset = newwidth*i; |
memcpy(&padded_imagedata[offset], imagedata, width); |
memset(&padded_imagedata[offset+width], 0, pad); |
imagedata += width; |
} |
// Color table in a bitmap is BGR0, while Blown Away uses RGB |
const unsigned int NUM_COLORS = sizeof(ct.colors)/sizeof(ct.colors[0]); |
RGBQUAD rgba_colortable[NUM_COLORS]; |
for (i=0; i<NUM_COLORS; ++i) { |
rgba_colortable[i] = ipe16_rgb_to_rgbquad(ct.colors[i]); |
} |
BITMAPFILEHEADER bfh; |
bfh.bfType = BI_SIGNATURE; |
bfh.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(rgba_colortable)+newsize; |
bfh.bfReserved1 = 0; |
bfh.bfReserved2 = 0; |
bfh.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(rgba_colortable); |
fwrite(&bfh, sizeof(bfh), 1, output); |
BITMAPINFOHEADER bih; |
bih.biSize = sizeof(BITMAPINFOHEADER); |
bih.biWidth = width; |
#ifdef USE_BOTTOMUP |
bih.biHeight = height; // (positive = "bottom-up"-Bitmap) |
#else |
bih.biHeight = -height; // (negative = "top-down"-Bitmap) |
#endif |
bih.biPlanes = 1; |
bih.biBitCount = 8; |
bih.biCompression = BI_RGB; |
bih.biSizeImage = 0; |
bih.biXPelsPerMeter = 0; |
bih.biYPelsPerMeter = 0; |
bih.biClrUsed = 0; |
bih.biClrImportant = 0; |
fwrite(&bih, sizeof(bih), 1, output); |
// Color table |
fwrite(rgba_colortable, sizeof(rgba_colortable), 1, output); |
// Image data |
fwrite(padded_imagedata, newsize, 1, output); |
free(padded_imagedata); |
#ifdef USE_BOTTOMUP |
free(bmpData); |
#endif |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/ipe16_bmpexport.h |
---|
0,0 → 1,23 |
/** |
* Bitmap Export for Imagination Pilots Entertainment 16-bit games (IPE16) |
* - Blown Away - The Interactive Game by Imagination Pilots (BA) |
* - Panic in the Park - The Interactive Game by Imagination Pilots (PiP) |
* - Where's Waldo? At the Circus (Waldo1) |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Revision: 2018-02-15 |
**/ |
#ifndef __inc__ipe16_bmpexport |
#define __inc__ipe16_bmpexport |
#include <stdio.h> |
#include <stdint.h> |
#include <stdlib.h> |
#include "bitmap.h" |
#include "ipe16_artfile.h" |
void ipe16_write_bmp(FILE* output, unsigned int width, unsigned int height, unsigned char* imagedata, size_t imagedata_len, Ipe16ColorTable ct); |
#endif // #ifndef __inc__ipe16_bmpexport |
Property changes: |
Added: svn:mime-type |
+text/x-chdr |
\ No newline at end of property |
/trunk/ipe16_bmpimport.c |
---|
0,0 → 1,108 |
/** |
* Bitmap Import for Imagination Pilots Entertainment 16-bit games (IPE16) |
* - Blown Away - The Interactive Game by Imagination Pilots (BA) |
* - Panic in the Park - The Interactive Game by Imagination Pilots (PiP) |
* - Where's Waldo? At the Circus (Waldo1) |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Revision: 2018-02-15 |
**/ |
#include <stdio.h> |
#include <stdint.h> |
#include <stdbool.h> |
#include <stdlib.h> |
#include <string.h> |
#include <assert.h> |
#include "bitmap.h" |
#include "ipe16_bmpimport.h" |
Ipe16ColorTableEntry rgbquad_to_ipe16_rgb(RGBQUAD rq) { |
Ipe16ColorTableEntry cte; |
cte.r = rq.rgbRed; |
cte.g = rq.rgbGreen; |
cte.b = rq.rgbBlue; |
return cte; |
} |
bool ipe16_bmp_import(FILE* fibBitmap, Ipe16BmpImportData* result) { |
BITMAPFILEHEADER bitmapFileHeader; |
BITMAPINFOHEADER bitmapInfoHeader; |
#define EXIT_ERROR(msg) { sprintf(result->error, msg); return false; } |
fseek(fibBitmap, 0, SEEK_SET); |
if (!fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, fibBitmap) || |
(bitmapFileHeader.bfType != BI_SIGNATURE) || |
!fread(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, fibBitmap)) { |
EXIT_ERROR("Not a bitmap file"); |
} |
if (bitmapInfoHeader.biCompression != BI_RGB) { |
EXIT_ERROR("At the moment, only uncompressed files can be read."); |
} |
if (bitmapInfoHeader.biBitCount != 8) { |
EXIT_ERROR("The color depth has to be 8 bpp."); |
} |
Ipe16ColorTable* ct = malloc(sizeof(Ipe16ColorTable)); |
#define NUM_COLORS 256 |
RGBQUAD rgba_colortable[NUM_COLORS]; |
if (!fread(&rgba_colortable, sizeof(rgba_colortable), 1, fibBitmap)) { |
EXIT_ERROR("Error reading color table."); |
} |
int i; |
for (i=0; i<NUM_COLORS; ++i) { |
Ipe16ColorTableEntry x; |
x = rgbquad_to_ipe16_rgb(rgba_colortable[i]); |
ct->colors[i] = x; |
} |
fseek(fibBitmap, bitmapFileHeader.bfOffBits, SEEK_SET); |
const uint32_t realwidth = bitmapInfoHeader.biWidth; |
const uint32_t realheight = abs(bitmapInfoHeader.biHeight); |
const size_t bmpDataSize = realwidth*realheight; |
unsigned char* bmpData = (unsigned char*)malloc(bmpDataSize); |
assert(bmpData != NULL); |
const int padded_width = (bitmapInfoHeader.biWidth + 3) & ~0x03; // http://stackoverflow.com/a/2022194/3544341 |
unsigned char* bmpLine = (unsigned char*)malloc(padded_width); |
assert(bmpLine != NULL); |
int h; |
for (h=0; h<realheight; ++h) { |
if (fread(bmpLine, padded_width, 1, fibBitmap) != 1) { |
free(bmpLine); |
free(bmpData); |
free(ct); |
EXIT_ERROR("Error while reading pixel data."); |
} |
int idx; |
if (bitmapInfoHeader.biHeight > 0) { |
// "bottom-up" (most usual) |
// Convert to "top-down": |
idx = (realheight-1)-h; |
} else { |
// "top-down" |
idx = h; |
} |
assert(idx*realwidth >= 0); |
memcpy(bmpData+idx*realwidth, bmpLine, realwidth); |
} |
free(bmpLine); |
result->colorTable = ct; |
result->bmpData = bmpData; |
result->bmpDataSize = bmpDataSize; |
result->width = realwidth; |
result->height = realheight; |
result->error[0] = 0; |
return true; |
} |
void ipe16_free_bmpimport_result(Ipe16BmpImportData *res) { |
if (res->colorTable) free(res->colorTable); |
if (res->bmpData) free(res->bmpData); |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/ipe16_bmpimport.h |
---|
0,0 → 1,34 |
/** |
* Bitmap Import for Imagination Pilots Entertainment 16-bit games (IPE16) |
* - Blown Away - The Interactive Game by Imagination Pilots (BA) |
* - Panic in the Park - The Interactive Game by Imagination Pilots (PiP) |
* - Where's Waldo? At the Circus (Waldo1) |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Revision: 2018-02-15 |
**/ |
#ifndef __inc__ipe16_bmpimport |
#define __inc__ipe16_bmpimport |
#include <stdio.h> |
#include <stdint.h> |
#include <stdbool.h> |
#include <stdlib.h> |
#include "bitmap.h" |
#include "ipe16_artfile.h" |
typedef struct tagIpe16BmpImportData { |
Ipe16ColorTable* colorTable; |
unsigned char* bmpData; |
size_t bmpDataSize; |
unsigned int width; |
unsigned int height; |
char error[255]; |
} Ipe16BmpImportData; |
bool ipe16_bmp_import(FILE* fibBitmap, Ipe16BmpImportData* result); |
void ipe16_free_bmpimport_result(Ipe16BmpImportData *res); |
#endif // #ifndef __inc__ipe16_bmpimport |
Property changes: |
Added: svn:mime-type |
+text/x-chdr |
\ No newline at end of property |
/trunk/ipe16_lzw_decoder.c |
---|
0,0 → 1,179 |
/** |
* LZW Decoder for Imagination Pilots Entertainment 16-bit games (IPE16) |
* - Blown Away - The Interactive Game by Imagination Pilots (BA) |
* - Panic in the Park - The Interactive Game by Imagination Pilots (PiP) |
* - Where's Waldo? At the Circus (Waldo1) |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Revision: 2018-02-15 |
* |
* The code is based on "Cross platform GIF source code" (c) L. Patrick |
* http://www.cs.usyd.edu.au/~graphapp/package/src/libgif/gif.c |
* It was simplified and modified to encode IPE16-LZW instead of GIF-LZW. |
* The game uses exactly the compressed stream as defined in the GIF standard, |
* but the compressed stream is not divided into chunks. |
**/ |
#include "ipe16_lzw_decoder.h" |
#include "utils.h" |
#include <stdlib.h> |
#include <stdio.h> |
#include <stdbool.h> |
Ipe16LZWDecoder* new_ipe16lzw_decoder(void) { |
return (Ipe16LZWDecoder*)app_zero_alloc(sizeof(Ipe16LZWDecoder)); |
} |
void del_ipe16lzw_decoder(Ipe16LZWDecoder* decoder) { |
free(decoder); |
} |
void ipe16lzw_init_decoder(Ipe16LZWDecoder* decoder) { |
decoder->running_code = FIRST_CODE; |
decoder->running_bits = LZ_MIN_BITS; |
decoder->max_code_plus_one = 1 << decoder->running_bits; |
decoder->shift_state = 0; |
decoder->shift_data = 0; |
int i; |
for (i = 0; i <= LZ_MAX_CODE; i++) { |
decoder->prefix[i] = NO_SUCH_CODE; |
} |
} |
int ipe16lzw_read_code(FILE* inFile, Ipe16LZWDecoder* decoder) { |
int code; |
unsigned char next_byte; |
static int code_masks[] = { |
0x0000, 0x0001, 0x0003, 0x0007, |
0x000f, 0x001f, 0x003f, 0x007f, |
0x00ff, 0x01ff, 0x03ff, 0x07ff, |
0x0fff |
}; |
while (decoder->shift_state < decoder->running_bits) { |
next_byte = read_byte(inFile); |
decoder->shift_data |= |
((unsigned long) next_byte) << decoder->shift_state; |
decoder->shift_state += 8; |
} |
code = decoder->shift_data & code_masks[decoder->running_bits]; |
decoder->shift_data >>= decoder->running_bits; |
decoder->shift_state -= decoder->running_bits; |
if (++decoder->running_code > decoder->max_code_plus_one |
&& decoder->running_bits < LZ_MAX_BITS) { |
decoder->max_code_plus_one <<= 1; |
decoder->running_bits++; |
} |
return code; |
} |
static int ipe16lzw_trace_prefix(unsigned int* prefix, int code, int clear_code) { |
int i = 0; |
while (code > clear_code && i++ <= LZ_MAX_CODE) { |
code = prefix[code]; |
} |
return code; |
} |
// We don't do unsigned, because we want to have <0 as error result |
/*unsigned*/ int ipe16lzw_decode(FILE* inFile, Ipe16LZWDecoder* decoder, unsigned char* output, int outputLength) { |
int i = 0, j; |
int current_code; |
int current_prefix; |
int stack_ptr = 0; |
int prev_code = NO_SUCH_CODE; |
unsigned char* stack; |
unsigned int* prefix; |
unsigned int* suffix; |
unsigned int bytes_written = 0; |
ipe16lzw_init_decoder(decoder); |
prefix = decoder->prefix; |
suffix = decoder->suffix; |
stack = decoder->stack; |
/* Pop the stack */ |
while (stack_ptr != 0 && i < outputLength) { |
output[i++] = stack[--stack_ptr]; |
//if (i > bytes_written) bytes_written = i; |
++bytes_written; |
} |
while (i < outputLength) { |
current_code = ipe16lzw_read_code(inFile, decoder); |
if (current_code == END_CODE) { |
if (i != outputLength - 1) // || decoder->pixel_count != 0 |
return -1; /* unexpected eof */ |
i++; |
} else if (current_code == CLEAR_CODE) { |
for (j = 0; j <= LZ_MAX_CODE; j++) { |
prefix[j] = NO_SUCH_CODE; |
} |
decoder->running_code = FIRST_CODE; |
decoder->running_bits = LZ_MIN_BITS; |
decoder->max_code_plus_one = 1 << decoder->running_bits; |
prev_code = NO_SUCH_CODE; |
} else { |
if (current_code < CLEAR_CODE) { |
output[i++] = current_code; |
//if (i > bytes_written) bytes_written = i; |
++bytes_written; |
} else { |
if ((current_code < 0) || (current_code > LZ_MAX_CODE)) |
return -2; /* image defect */ |
if (prefix[current_code] == NO_SUCH_CODE) { |
if (current_code == decoder->running_code - 2) { |
current_prefix = prev_code; |
suffix[decoder->running_code - 2] |
= stack[stack_ptr++] |
= ipe16lzw_trace_prefix(prefix, prev_code, CLEAR_CODE); |
} else { |
return -3; /* image defect */ |
} |
} else { |
current_prefix = current_code; |
} |
j = 0; |
while (j++ <= LZ_MAX_CODE && current_prefix > CLEAR_CODE && current_prefix <= LZ_MAX_CODE) { |
stack[stack_ptr++] = suffix[current_prefix]; |
current_prefix = prefix[current_prefix]; |
} |
if (j >= LZ_MAX_CODE || current_prefix > LZ_MAX_CODE) |
return -4; /* image defect */ |
stack[stack_ptr++] = current_prefix; |
while (stack_ptr != 0 && i < outputLength) { |
output[i++] = stack[--stack_ptr]; |
//if (i > bytes_written) bytes_written = i; |
++bytes_written; |
} |
} |
if (prev_code != NO_SUCH_CODE) { |
if ((decoder->running_code < 2) || |
(decoder->running_code > LZ_MAX_CODE+2)) |
return -5; /* image defect */ |
prefix[decoder->running_code - 2] = prev_code; |
if (current_code == decoder->running_code - 2) { |
suffix[decoder->running_code - 2] |
= ipe16lzw_trace_prefix(prefix, prev_code, CLEAR_CODE); |
} else { |
suffix[decoder->running_code - 2] |
= ipe16lzw_trace_prefix(prefix, current_code, CLEAR_CODE); |
} |
} |
prev_code = current_code; |
} |
} |
return bytes_written; |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/ipe16_lzw_decoder.h |
---|
0,0 → 1,48 |
/** |
* LZW Decoder for Imagination Pilots Entertainment 16-bit games (IPE16) |
* - Blown Away - The Interactive Game by Imagination Pilots (BA) |
* - Panic in the Park - The Interactive Game by Imagination Pilots (PiP) |
* - Where's Waldo? At the Circus (Waldo1) |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Revision: 2018-02-15 |
* |
* The code is based on "Cross platform GIF source code" (c) L. Patrick |
* http://www.cs.usyd.edu.au/~graphapp/package/src/libgif/gif.c |
* It was simplified and modified to encode IPE16-LZW instead of GIF-LZW. |
* The game uses exactly the compressed stream as defined in the GIF standard, |
* but the compressed stream is not divided into chunks. |
**/ |
#ifndef __inc__ipe16_lzw_decoder |
#define __inc__ipe16_lzw_decoder |
#include <stdio.h> |
#include <stdbool.h> |
#define LZ_MIN_BITS 9 |
#define LZ_MAX_BITS 12 |
#define LZ_MAX_CODE 4095 /* Largest 12 bit code */ |
#define NO_SUCH_CODE 4098 /* Impossible code = empty */ |
#define CLEAR_CODE 256 |
#define END_CODE 257 |
#define FIRST_CODE 258 |
typedef struct tagIpe16LZWDecoder { |
int running_code; |
int running_bits; |
int max_code_plus_one; |
int shift_state; |
unsigned long shift_data; |
unsigned char stack[LZ_MAX_CODE+1]; |
unsigned int suffix[LZ_MAX_CODE+1]; |
unsigned int prefix[LZ_MAX_CODE+1]; |
} Ipe16LZWDecoder; |
Ipe16LZWDecoder* new_ipe16lzw_decoder(void); |
void del_ipe16lzw_decoder(Ipe16LZWDecoder* decoder); |
/*unsigned*/ int ipe16lzw_decode(FILE* outFile, Ipe16LZWDecoder *decoder, unsigned char *input, int inputLength); |
#endif // #ifndef __inc__ipe16_lzw_decoder |
Property changes: |
Added: svn:mime-type |
+text/x-chdr |
\ No newline at end of property |
/trunk/ipe16_lzw_encoder.c |
---|
0,0 → 1,140 |
/** |
* LZW Encoder for Imagination Pilots Entertainment 16-bit games (IPE16) |
* - Blown Away - The Interactive Game by Imagination Pilots (BA) |
* - Panic in the Park - The Interactive Game by Imagination Pilots (PiP) |
* - Where's Waldo? At the Circus (Waldo1) |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Revision: 2018-02-15 |
* |
* The code is based on "Cross platform GIF source code" (c) L. Patrick |
* http://www.cs.usyd.edu.au/~graphapp/package/src/libgif/gif.c |
* It was simplified and modified to encode IPE16-LZW instead of GIF-LZW. |
* The game uses exactly the compressed stream as defined in the GIF standard, |
* but the compressed stream is not divided into chunks. |
**/ |
#include "ipe16_lzw_encoder.h" |
#include "utils.h" |
#include <stdlib.h> |
#include <stdio.h> |
#include <stdbool.h> |
Ipe16LZWEncoder* new_ipe16lzw_encoder(void) { |
return (Ipe16LZWEncoder*)app_zero_alloc(sizeof(Ipe16LZWEncoder)); |
} |
void del_ipe16lzw_encoder(Ipe16LZWEncoder* encoder) { |
free(encoder); |
} |
void ipe16lzw_write_code(FILE* outFile, Ipe16LZWEncoder* encoder, int code) { |
if (code == FLUSH_OUTPUT) { |
/* write all remaining data */ |
while (encoder->shift_state > 0) { |
fputc(encoder->shift_data & 0xff, outFile); |
encoder->shift_data >>= 8; |
encoder->shift_state -= 8; |
} |
encoder->shift_state = 0; |
} else { |
encoder->shift_data |= ((long) code) << encoder->shift_state; |
encoder->shift_state += encoder->running_bits; |
while (encoder->shift_state >= 8) { |
/* write full bytes */ |
fputc(encoder->shift_data & 0xff, outFile); |
encoder->shift_data >>= 8; |
encoder->shift_state -= 8; |
} |
} |
if (encoder->running_code >= encoder->max_code_plus_one && code <= LZ_MAX_CODE) { |
encoder->max_code_plus_one = 1 << ++encoder->running_bits; |
} |
} |
static void ipe16lzw_clear_hash_table(unsigned long* hash_table) { |
int i; |
for (i=0; i<HT_SIZE; i++) { |
hash_table[i] = 0xFFFFFFFFL; |
} |
} |
void ipe16lzw_init_encoder(Ipe16LZWEncoder* encoder) { |
encoder->running_code = FIRST_CODE; |
encoder->running_bits = LZ_MIN_BITS; |
encoder->max_code_plus_one = 1 << encoder->running_bits; |
encoder->shift_state = 0; |
encoder->shift_data = 0; |
} |
static int ipe16lzw_hash_key(unsigned long key) { |
return ((key >> 12) ^ key) & HT_KEY_MASK; |
} |
static int ipe16lzw_lookup_hash(unsigned long* hash_table, unsigned long key) { |
int hkey = ipe16lzw_hash_key(key); |
unsigned long htkey; |
while ((htkey = HT_GET_KEY(hash_table[hkey])) != 0xFFFFFL) { |
if (key == htkey) { |
return HT_GET_CODE(hash_table[hkey]); |
} |
hkey = (hkey + 1) & HT_KEY_MASK; |
} |
return -1; |
} |
static void ipe16lzw_add_hash_entry(unsigned long* hash_table, unsigned long key, int code) { |
int hkey = ipe16lzw_hash_key(key); |
while (HT_GET_KEY(hash_table[hkey]) != 0xFFFFFL) { |
hkey = (hkey + 1) & HT_KEY_MASK; |
} |
hash_table[hkey] = HT_PUT_KEY(key) | HT_PUT_CODE(code); |
} |
void ipe16lzw_encode(FILE* outFile, Ipe16LZWEncoder* encoder, unsigned char* input, int inputLength) { |
int i = 0, current_code, new_code; |
unsigned long new_key; |
unsigned char pixval; |
/* Init stuff */ |
ipe16lzw_init_encoder(encoder); |
ipe16lzw_clear_hash_table(encoder->hash_table); |
ipe16lzw_write_code(outFile, encoder, CLEAR_CODE); |
if (inputLength == 0) return; |
current_code = input[i++]; |
while (i < inputLength) { |
pixval = input[i++]; /* Fetch next pixel from stream */ |
new_key = (((unsigned long) current_code) << 8) + pixval; |
if ((new_code = ipe16lzw_lookup_hash(encoder->hash_table, new_key)) >= 0) { |
current_code = new_code; |
} else { |
ipe16lzw_write_code(outFile, encoder, current_code); |
current_code = pixval; |
if (encoder->running_code >= LZ_MAX_CODE) { |
ipe16lzw_write_code(outFile, encoder, CLEAR_CODE); |
encoder->running_code = FIRST_CODE; |
encoder->running_bits = LZ_MIN_BITS; |
encoder->max_code_plus_one = 1 << encoder->running_bits; |
ipe16lzw_clear_hash_table(encoder->hash_table); |
} else { |
/* Put this unique key with its relative code in hash table */ |
ipe16lzw_add_hash_entry(encoder->hash_table, new_key, encoder->running_code++); |
} |
} |
} |
/* Flush */ |
ipe16lzw_write_code(outFile, encoder, current_code); |
ipe16lzw_write_code(outFile, encoder, END_CODE); |
ipe16lzw_write_code(outFile, encoder, FLUSH_OUTPUT); |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/ipe16_lzw_encoder.h |
---|
0,0 → 1,53 |
/** |
* LZW Encoder for Imagination Pilots Entertainment 16-bit games (IPE16) |
* - Blown Away - The Interactive Game by Imagination Pilots (BA) |
* - Panic in the Park - The Interactive Game by Imagination Pilots (PiP) |
* - Where's Waldo? At the Circus (Waldo1) |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Revision: 2018-02-15 |
* |
* The code is based on "Cross platform GIF source code" (c) L. Patrick |
* http://www.cs.usyd.edu.au/~graphapp/package/src/libgif/gif.c |
* It was simplified and modified to encode IPE16-LZW instead of GIF-LZW. |
* The game uses exactly the compressed stream as defined in the GIF standard, |
* but the compressed stream is not divided into chunks. |
**/ |
#ifndef __inc__ipe16_lzw_encoder |
#define __inc__ipe16_lzw_encoder |
#include <stdio.h> |
#include <stdbool.h> |
#define LZ_MIN_BITS 9 |
#define LZ_MAX_CODE 4095 /* Largest 12 bit code */ |
#define FLUSH_OUTPUT 4096 /* Impossible code = flush */ |
#define HT_SIZE 8192 /* 13 bit hash table size */ |
#define HT_KEY_MASK 0x1FFF /* 13 bit key mask */ |
#define CLEAR_CODE 256 |
#define END_CODE 257 |
#define FIRST_CODE 258 |
#define HT_GET_KEY(x) ((x) >> 12) |
#define HT_GET_CODE(x) ((x) & 0x0FFF) |
#define HT_PUT_KEY(x) ((x) << 12) |
#define HT_PUT_CODE(x) ((x) & 0x0FFF) |
typedef struct tagIpe16LZWEncoder { |
int running_code; |
int running_bits; |
int max_code_plus_one; |
int shift_state; |
unsigned long shift_data; |
unsigned long hash_table[HT_SIZE]; |
} Ipe16LZWEncoder; |
Ipe16LZWEncoder* new_ipe16lzw_encoder(void); |
void del_ipe16lzw_encoder(Ipe16LZWEncoder* encoder); |
void ipe16lzw_encode(FILE* outFile, Ipe16LZWEncoder* encoder, unsigned char* input, int inputLength); |
#endif // #ifndef __inc__ipe16_lzw_encoder |
Property changes: |
Added: svn:mime-type |
+text/x-chdr |
\ No newline at end of property |
/trunk/ipe32_artfile.h |
---|
0,0 → 1,49 |
/** |
* ART files for Imagination Pilots Entertainment 32-bit games (IPE32) |
* - Where's Waldo? Exploring Geography |
* - Eraser Turnabout by Imagination Pilots |
* - Virtual K'Nex by Imagination Pilots |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2018 |
* Revision: 2018-02-15 |
**/ |
#ifndef __inc__ipe32_artfile |
#define __inc__ipe32_artfile |
#include <stdint.h> |
#define IPE32_COMPRESSIONTYPE_LZW 0 |
#define IPE32_COMPRESSIONTYPE_NONE 1 |
#define IPE32_NAME_SIZE 8 |
#define IPE32_MAGIC_ART "ART_DATA" |
#pragma pack(push, 1) |
typedef struct tagIpe32FileHeader { |
char magic[IPE32_NAME_SIZE]; // always "ART_DATA" |
uint32_t totalHeaderSize; // size of all headers (file header and all picture headers). headerSize/16 = numberPictures |
uint32_t reserved; // always 0 |
} Ipe32FileHeader; |
typedef struct tagIpe32PictureEntryHeader { |
char name[IPE32_NAME_SIZE]; |
uint32_t offset; // offset to the picture (Ipe32PictureHeader) |
uint32_t uncompressedSize; // size of the picture (picture data + palette) |
} Ipe32PictureEntryHeader; |
/* |
typedef struct tagIpe32PictureChunk { |
unsigned compressionType : 1; // Compression type of the follow-up data |
// 0 = LZW-like compression (special implementation) |
// 1 = None |
unsigned chunkDataSize : 15; // size of the chunk data |
//char data[]; |
} Ipe32PictureChunk; |
*/ |
#pragma pack(pop) |
#endif // #ifndef __inc__ipe32_artfile |
Property changes: |
Added: svn:mime-type |
+text/x-chdr |
\ No newline at end of property |
/trunk/ipe32_bmpexport.c |
---|
0,0 → 1,29 |
/** |
* Bitmap Export for Imagination Pilots Entertainment 32-bit games (IPE32) |
* - Where's Waldo? Exploring Geography |
* - Eraser Turnabout by Imagination Pilots |
* - Virtual K'Nex by Imagination Pilots |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Revision: 2018-02-15 |
**/ |
#include <stdio.h> |
#include <stdint.h> |
#include <stdlib.h> |
#include <string.h> |
#include "bitmap.h" |
#include "ipe32_bmpexport.h" |
void ipe32_write_bmp(FILE* output, unsigned char* imagedata, size_t imagedata_len) { |
BITMAPFILEHEADER bh={0}; |
bh.bfType = BI_SIGNATURE; |
bh.bfSize = sizeof(bh) + imagedata_len; |
bh.bfReserved1 = 0; |
bh.bfReserved2 = 0; |
bh.bfOffBits = 0x436; |
fwrite(&bh, 1, sizeof(bh), output); |
fwrite(imagedata, 1, imagedata_len, output); |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/ipe32_bmpexport.h |
---|
0,0 → 1,20 |
/** |
* Bitmap Export for Imagination Pilots Entertainment 32-bit games (IPE32) |
* - Where's Waldo? Exploring Geography |
* - Eraser Turnabout by Imagination Pilots |
* - Virtual K'Nex by Imagination Pilots |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Revision: 2018-02-15 |
**/ |
#ifndef __inc__ipe32_bmpexport |
#define __inc__ipe32_bmpexport |
#include <stdio.h> |
#include <stdint.h> |
#include <stdlib.h> |
void ipe32_write_bmp(FILE* output, unsigned char* imagedata, size_t imagedata_len); |
#endif // #ifndef __inc__ipe32_bmpexport |
Property changes: |
Added: svn:mime-type |
+text/x-chdr |
\ No newline at end of property |
/trunk/ipe32_bmpimport.c |
---|
0,0 → 1,83 |
/** |
* Bitmap Import for Imagination Pilots Entertainment 32-bit games (IPE32) |
* - Where's Waldo? Exploring Geography |
* - Eraser Turnabout by Imagination Pilots |
* - Virtual K'Nex by Imagination Pilots |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Revision: 2018-02-15 |
**/ |
#include <stdio.h> |
#include <stdint.h> |
#include <stdlib.h> |
#include <string.h> |
#include <math.h> |
#include "bitmap.h" |
#include "utils.h" |
#include "ipe32_bmpimport.h" |
#define BI_BITFIELDS 3 |
bool bmp_has_gap1(BITMAPFILEHEADER bitmapFileHeader, BITMAPINFOHEADER bitmapInfoHeader) { |
int expected = 0; |
expected = sizeof(bitmapFileHeader) + bitmapInfoHeader.biSize; |
if (bitmapInfoHeader.biCompression == BI_BITFIELDS) { |
expected += 3*sizeof(DWORD); |
} |
int numColorEntries; |
if (bitmapInfoHeader.biClrUsed == 0) { |
if ((bitmapInfoHeader.biBitCount == 1) || (bitmapInfoHeader.biBitCount == 4) || (bitmapInfoHeader.biBitCount == 8)) { |
numColorEntries = pow(2, bitmapInfoHeader.biBitCount); |
} else { |
numColorEntries = 0; |
} |
} else { |
numColorEntries = bitmapInfoHeader.biClrUsed; |
} |
expected += sizeof(RGBQUAD)*numColorEntries; |
return bitmapFileHeader.bfOffBits != expected; |
} |
bool ipe32_bmp_import(FILE* fibBitmap, Ipe32BmpImportData* result) { |
BITMAPFILEHEADER bitmapFileHeader; |
BITMAPINFOHEADER bitmapInfoHeader; |
#define EXIT_ERROR(msg) { sprintf(result->error, msg); return false; } |
fseek(fibBitmap, 0, SEEK_SET); |
if (!fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, fibBitmap) || |
(bitmapFileHeader.bfType != BI_SIGNATURE) || |
!fread(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, fibBitmap)) { |
EXIT_ERROR("Not a bitmap file"); |
} |
if (bmp_has_gap1(bitmapFileHeader, bitmapInfoHeader)) { |
EXIT_ERROR("Picture may not have a gap between header and bitmap data"); |
} |
// TODO: Find out if the game has limitations in regards to compression, top-down/bottom-up, Bitmap version etc. |
/* |
if (bitmapInfoHeader.biCompression != BI_RGB) { |
EXIT_ERROR("At the moment, only uncompressed files can be read."); |
} |
if (bitmapInfoHeader.biBitCount != 8) { |
EXIT_ERROR("The color depth has to be 8 bpp."); |
} |
*/ |
fseek(fibBitmap, sizeof(bitmapFileHeader), SEEK_SET); |
result->error[0] = 0; |
result->dataSize = file_size(fibBitmap)-sizeof(bitmapFileHeader); |
return true; |
} |
void ipe32_free_bmpimport_result(Ipe32BmpImportData *res) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/ipe32_bmpimport.h |
---|
0,0 → 1,27 |
/** |
* Bitmap Import for Imagination Pilots Entertainment 32-bit games (IPE32) |
* - Where's Waldo? Exploring Geography |
* - Eraser Turnabout by Imagination Pilots |
* - Virtual K'Nex by Imagination Pilots |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Revision: 2018-02-15 |
**/ |
#ifndef __inc__ipe32_bmpimport |
#define __inc__ipe32_bmpimport |
#include <stdio.h> |
#include <stdint.h> |
#include <stdbool.h> |
#include <stdlib.h> |
typedef struct tagIpe32BmpImportData { |
size_t dataSize; |
char error[255]; |
} Ipe32BmpImportData; |
bool ipe32_bmp_import(FILE* fibBitmap, Ipe32BmpImportData* result); |
void ipe32_free_bmpimport_result(Ipe32BmpImportData *res); |
#endif // #ifndef __inc__ipe32_bmpimport |
Property changes: |
Added: svn:mime-type |
+text/x-chdr |
\ No newline at end of property |
/trunk/ipe32_lzw_decoder.c |
---|
0,0 → 1,159 |
/** |
* LZW Decoder for Imagination Pilots Entertainment 32-bit games (IPE32) |
* - Where's Waldo? Exploring Geography |
* - Eraser Turnabout by Imagination Pilots |
* - Virtual K'Nex by Imagination Pilots |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2018 |
* Revision: 2018-02-15 |
* |
* Based on : Basic LZW Data Compression program published in DDJ October 1989 issue. |
* by Mark R. Nelson |
* http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/DDJ/1989/8910/8910b/8910b.htm |
* Updated by: Shawn M. Regan, January 1990 |
* http://mirror.bagelwood.com/textfiles/computers/regan.lst |
* Updated by: Daniel Marschall, 11 February 2018 |
* https://misc.daniel-marschall.de/code/c/lzw.c |
* Changed for IPE32: - Simplified |
* - Thread safe |
* - MAX_BITS = 13 |
**/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdint.h> |
#include "utils.h" |
#include "ipe32_lzw_decoder.h" |
#define INIT_BITS 9 |
#define MAX_BITS 13 /* Do not exceed 14 with this program */ |
#if MAX_BITS == 14 /* Set the table size. Must be a prime */ |
#define TABLE_SIZE 18041 /* number somewhat larger than 2^MAX_BITS.*/ |
#elif MAX_BITS == 13 |
#define TABLE_SIZE 9029 |
#else |
#define TABLE_SIZE 5021 |
#endif |
#define CLEAR_TABLE 256 /* Code to flush the string table */ |
#define TERMINATOR 257 /* To mark EOF Condition, instead of MAX_VALUE */ |
#define FIRST_CODE 258 /* First available code for code_value table */ |
#define MAXVAL(n) (( 1 <<( n )) -1) /* max_value formula macro */ |
unsigned char* decode_string(Ipe32LZWDecoder *decoder, unsigned char *buffer, unsigned int code) { |
int i=0; |
while (code > 255) { |
*buffer++ = decoder->append_character[code]; |
code = decoder->prefix_code[code]; |
if (i++ >= 4000) { |
// printf("Error during code expansion\n"); |
return NULL; |
} |
} |
*buffer=code; |
return(buffer); |
} |
unsigned input_code(Ipe32LZWDecoder *decoder, unsigned char* lzwInputBuffer, int* inputBufferPos) { |
unsigned int return_value; |
while (decoder->input_bit_count <= 24) { |
decoder->input_bit_buffer |= lzwInputBuffer[(*inputBufferPos)] << (24 - decoder->input_bit_count); |
(*inputBufferPos)++; |
decoder->input_bit_count += 8; |
} |
return_value=decoder->input_bit_buffer >> (32-decoder->num_bits); |
decoder->input_bit_buffer <<= decoder->num_bits; |
decoder->input_bit_count -= decoder->num_bits; |
return(return_value); |
} |
void reset_input_buffer(Ipe32LZWDecoder *decoder) { |
decoder->input_bit_count = 0; |
decoder->input_bit_buffer = 0; |
} |
void ipe32lzw_reset_decoder(Ipe32LZWDecoder *decoder) { |
decoder->num_bits = INIT_BITS; |
decoder->max_code = MAXVAL(decoder->num_bits); /* Initialize max_value & max_code */ |
// Make sure the input buffer is correctly flushed |
reset_input_buffer(decoder); |
} |
void ipe32lzw_init_decoder(Ipe32LZWDecoder *decoder) { |
decoder->prefix_code = malloc(TABLE_SIZE*sizeof(unsigned int)); |
decoder->append_character = malloc(TABLE_SIZE*sizeof(unsigned char)); |
ipe32lzw_reset_decoder(decoder); |
} |
// Returns: Bytes written or -1 when an error occurs |
int ipe32lzw_decode(Ipe32LZWDecoder *decoder, unsigned char* outputBuffer, const size_t outpufBufferSize, unsigned char* lzwInputBuffer, const size_t maxReadBytes) { |
unsigned int next_code=FIRST_CODE; |
unsigned int new_code; |
unsigned int old_code; |
int character; |
int clear_flag=1; /* Need to clear the code value array */ |
unsigned char *string; |
int inputBufferPos = 0; |
int outputBufferPos = 0; |
#define OUTPUT(code) { if (outputBufferPos == outpufBufferSize) return -1; outputBuffer[outputBufferPos++] = code; } |
ipe32lzw_reset_decoder(decoder); |
while (1) { |
if (inputBufferPos == maxReadBytes) return -1; |
if ((new_code=input_code(decoder, lzwInputBuffer, &inputBufferPos)) == TERMINATOR) break; |
if (clear_flag) { /* Initialize or Re-Initialize */ |
clear_flag=0; |
old_code=new_code; /* The next three lines have been moved */ |
character=old_code; /* from the original */ |
OUTPUT(old_code); |
continue; |
} |
if (new_code == CLEAR_TABLE) { /* Clear string table */ |
clear_flag=1; |
decoder->num_bits=INIT_BITS; |
next_code=FIRST_CODE; |
decoder->max_code = MAXVAL(decoder->num_bits); |
continue; |
} |
if (new_code >= next_code) { /* Check for string+char+string */ |
*decoder->decode_stack=character; |
string = decode_string(decoder, decoder->decode_stack+1,old_code); |
} else { |
string = decode_string(decoder, decoder->decode_stack,new_code); |
} |
if (string == NULL) return -1; |
character = *string; /* Output decoded string in reverse */ |
while (string >= decoder->decode_stack) { |
OUTPUT(*string--); |
} |
if (next_code <= decoder->max_code) { /* Add to string table if not full */ |
decoder->prefix_code[next_code]=old_code; |
decoder->append_character[next_code++]=character; |
if (next_code == decoder->max_code && decoder->num_bits < MAX_BITS) { |
decoder->max_code = MAXVAL(++decoder->num_bits); |
} |
} |
old_code=new_code; |
} |
return outputBufferPos; |
} |
void ipe32lzw_free_decoder(Ipe32LZWDecoder *decoder) { |
free(decoder->prefix_code); |
free(decoder->append_character); |
} |
Ipe32LZWDecoder* new_ipe32lzw_decoder(void) { |
return (Ipe32LZWDecoder*)app_zero_alloc(sizeof(Ipe32LZWDecoder)); |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/ipe32_lzw_decoder.h |
---|
0,0 → 1,38 |
/** |
* LZW Decoder for Imagination Pilots Entertainment 32-bit games (IPE32) |
* - Where's Waldo? Exploring Geography |
* - Eraser Turnabout by Imagination Pilots |
* - Virtual K'Nex by Imagination Pilots |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2018 |
* Revision: 2018-02-15 |
**/ |
#ifndef __inc__ipe32_lzw_decoder |
#define __inc__ipe32_lzw_decoder |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdint.h> |
#include <stdbool.h> |
typedef struct tagIpe32LZWDecoder { |
unsigned int *prefix_code; /* This array holds the prefix codes */ |
unsigned char *append_character; /* This array holds the appended chars */ |
unsigned char decode_stack[4000]; /* This array holds the decoded string */ |
int num_bits; /* Starting with 9 bit codes */ |
int max_code; /* old MAX_CODE */ |
int input_bit_count; |
uint32_t input_bit_buffer; |
} Ipe32LZWDecoder; |
// Returns: Bytes written or -1 when an error occurs |
int ipe32lzw_decode(Ipe32LZWDecoder *decoder, unsigned char* outputBuffer, const size_t outpufBufferSize, unsigned char* lzwInputBuffer, const size_t maxReadBytes); |
Ipe32LZWDecoder* new_ipe32lzw_decoder(void); |
void ipe32lzw_init_decoder(Ipe32LZWDecoder *decoder); |
void ipe32lzw_free_decoder(Ipe32LZWDecoder *decoder); |
#endif // #ifndef __inc__ipe32_lzw_decoder |
Property changes: |
Added: svn:mime-type |
+text/x-chdr |
\ No newline at end of property |
/trunk/ipe32_lzw_decoder.old |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/x-trash |
Property changes: |
Added: svn:mime-type |
+application/x-trash |
\ No newline at end of property |
/trunk/ipe32_lzw_encoder.c |
---|
0,0 → 1,192 |
/** |
* LZW Encoder for Imagination Pilots Entertainment 32-bit games (IPE32) |
* - Where's Waldo? Exploring Geography |
* - Eraser Turnabout by Imagination Pilots |
* - Virtual K'Nex by Imagination Pilots |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2018 |
* Revision: 2018-02-15 |
* |
* Based on : Basic LZW Data Compression program published in DDJ October 1989 issue. |
* by Mark R. Nelson |
* http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/DDJ/1989/8910/8910b/8910b.htm |
* Updated by: Shawn M. Regan, January 1990 |
* http://mirror.bagelwood.com/textfiles/computers/regan.lst |
* Updated by: Daniel Marschall, 11 February 2018 |
* https://misc.daniel-marschall.de/code/c/lzw.c |
* Changed for IPE32: - Simplified |
* - Thread safe |
* - MAX_BITS = 13 |
**/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdint.h> |
#include "utils.h" |
#include "ipe32_lzw_encoder.h" |
#define INIT_BITS 9 |
#define MAX_BITS 13 /* Do not exceed 14 with this program */ |
#define HASHING_SHIFT (MAX_BITS - 8) |
#if MAX_BITS == 14 /* Set the table size. Must be a prime */ |
#define TABLE_SIZE 18041 /* number somewhat larger than 2^MAX_BITS.*/ |
#elif MAX_BITS == 13 |
#define TABLE_SIZE 9029 |
#else |
#define TABLE_SIZE 5021 |
#endif |
#define CLEAR_TABLE 256 /* Code to flush the string table */ |
#define TERMINATOR 257 /* To mark EOF Condition, instead of MAX_VALUE */ |
#define FIRST_CODE 258 /* First available code for code_value table */ |
#define CHECK_TIME 100 /* Check comp ratio every CHECK_TIME chars input */ |
#define MAXVAL(n) (( 1 <<( n )) -1) /* max_value formula macro */ |
unsigned int find_match(Ipe32LZWEncoder *encoder, int hash_prefix, unsigned int hash_character) { |
int index, offset; |
index = (hash_character << HASHING_SHIFT) ^ hash_prefix; |
offset = (index == 0) ? 1 : TABLE_SIZE - index; |
while (1) { |
if (encoder->code_value[index] == -1) { |
return(index); |
} |
if (encoder->prefix_code[index] == hash_prefix && encoder->append_character[index] == hash_character) { |
return(index); |
} |
index -= offset; |
if (index < 0) { |
index += TABLE_SIZE; |
} |
} |
} |
void output_code(Ipe32LZWEncoder *encoder, unsigned int code, unsigned char* outBuf, size_t* compressedPos) { |
encoder->output_bit_buffer |= (uint32_t) code << (32 - encoder->num_bits - encoder->output_bit_count); |
encoder->output_bit_count += encoder->num_bits; |
while (encoder->output_bit_count >= 8) { |
outBuf[(*compressedPos)] = encoder->output_bit_buffer >> 24; // putc(output_bit_buffer >> 24, output); |
(*compressedPos)++; |
encoder->output_bit_buffer <<= 8; |
encoder->output_bit_count -= 8; |
encoder->bytes_out++; |
} |
} |
void reset_output_buffer(Ipe32LZWEncoder *encoder) { |
encoder->output_bit_count = 0; |
encoder->output_bit_buffer = 0; |
} |
void ipe32lzw_reset_encoder(Ipe32LZWEncoder *encoder) { |
encoder->num_bits = INIT_BITS; |
encoder->max_code = MAXVAL(encoder->num_bits); /* Initialize max_value & max_code */ |
encoder->bytes_in = 0; |
encoder->bytes_out = 0; |
encoder->checkpoint = CHECK_TIME; |
// For some reason, the output buffer doesn't get correctly flushed when |
// a new compression is started. So I made the static symbols global |
// and clear them here. |
reset_output_buffer(encoder); |
} |
// Returns: Bytes written, or -1 if compression failed |
int ipe32lzw_encode(Ipe32LZWEncoder *encoder, unsigned char* compressedData, const size_t compressedBufLen, unsigned char* uncompressedData, const size_t uncompressedSize) { |
unsigned int next_code=FIRST_CODE; |
unsigned int index; |
int i, /* All purpose integer */ |
ratio_new, /* New compression ratio as a percentage */ |
ratio_old=100; /* Original ratio at 100% */ |
ipe32lzw_reset_encoder(encoder); |
for (i=0; i<TABLE_SIZE; ++i) { /* Initialize the string table first */ |
encoder->code_value[i]=-1; |
} |
/* Get the first code */ |
if (compressedBufLen == 0) return -1; |
unsigned int string_code = uncompressedData[0]; //string_code=getc(input); |
size_t uncompressedPos = 1; |
size_t compressedPos = 0; |
#define OUTPUT(code) { if (compressedPos == compressedBufLen) return -1; output_code(encoder,code,compressedData,&compressedPos); } |
/* This is the main compression loop. Notice when the table is full we try |
* to increment the code size. Only when num_bits == MAX_BITS and the code |
* value table is full do we start to monitor the compression ratio. |
*/ |
while (uncompressedPos < uncompressedSize) { // while((character=getc(input)) != (unsigned)EOF) { |
unsigned int character = uncompressedData[uncompressedPos++]; |
++encoder->bytes_in; |
index=find_match(encoder,string_code,character); |
if (encoder->code_value[index] != -1) { |
string_code=encoder->code_value[index]; |
} else { |
if (next_code <= encoder->max_code) { |
encoder->code_value[index]=next_code++; |
encoder->prefix_code[index]=string_code; |
encoder->append_character[index]=character; |
} |
OUTPUT(string_code); /* Send out current code */ |
string_code=character; |
if (next_code > encoder->max_code) { /* Is table Full? */ |
if (encoder->num_bits < MAX_BITS) { /* Any more bits? */ |
encoder->max_code = MAXVAL(++encoder->num_bits); /* Increment code size then */ |
} else if (encoder->bytes_in > encoder->checkpoint) { /* At checkpoint? */ |
if (encoder->num_bits == MAX_BITS) { |
ratio_new = encoder->bytes_out*100/encoder->bytes_in; /* New compression ratio */ |
if (ratio_new > ratio_old) { /* Has ratio degraded? */ |
OUTPUT(CLEAR_TABLE); /* YES,flush string table */ |
encoder->num_bits=INIT_BITS; |
next_code=FIRST_CODE; /* Reset to FIRST_CODE */ |
encoder->max_code = MAXVAL(encoder->num_bits); /* Re-Initialize this stuff */ |
encoder->bytes_in = encoder->bytes_out = 0; |
ratio_old = 100; /* Reset compression ratio */ |
for (i=0; i<TABLE_SIZE; ++i) { /* Reset code value array */ |
encoder->code_value[i]=-1; |
} |
} else { /* NO, then save new */ |
ratio_old = ratio_new; /* compression ratio */ |
} |
} |
encoder->checkpoint = encoder->bytes_in + CHECK_TIME; /* Set new checkpoint */ |
} |
} |
} |
} |
OUTPUT(string_code); /* Output the last code */ |
if (next_code == encoder->max_code) { /* Handles special case for bit */ |
++encoder->num_bits; /* increment on EOF */ |
} |
OUTPUT(TERMINATOR); /* Output the end of buffer code */ |
OUTPUT(0); /* Flush the output buffer */ |
OUTPUT(0); |
OUTPUT(0); |
return compressedPos; |
} |
void ipe32lzw_init_encoder(Ipe32LZWEncoder *encoder) { |
/* The three buffers for the compression phase. */ |
encoder->code_value=malloc(TABLE_SIZE*sizeof(unsigned int)); |
encoder->prefix_code=malloc(TABLE_SIZE*sizeof(unsigned int)); |
encoder->append_character=malloc(TABLE_SIZE*sizeof(unsigned char)); |
ipe32lzw_reset_encoder(encoder); |
} |
void ipe32lzw_free_encoder(Ipe32LZWEncoder *encoder) { |
free(encoder->code_value); /* Needed only for compression */ |
free(encoder->prefix_code); |
free(encoder->append_character); |
} |
Ipe32LZWEncoder* new_ipe32lzw_encoder(void) { |
return (Ipe32LZWEncoder*)app_zero_alloc(sizeof(Ipe32LZWEncoder)); |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/ipe32_lzw_encoder.h |
---|
0,0 → 1,39 |
/** |
* LZW Encoder for Imagination Pilots Entertainment 32-bit games (IPE32) |
* - Where's Waldo? Exploring Geography |
* - Eraser Turnabout by Imagination Pilots |
* - Virtual K'Nex by Imagination Pilots |
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2018 |
* Revision: 2018-02-15 |
**/ |
#ifndef __inc__ipe32_lzw_encoder |
#define __inc__ipe32_lzw_encoder |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdint.h> |
#include <stdbool.h> |
typedef struct tagIpe32LZWEncoder { |
int *code_value; /* This is the code value array */ |
unsigned int *prefix_code; /* This array holds the prefix codes */ |
unsigned char *append_character; /* This array holds the appended chars */ |
int num_bits; /* Starting with 9 bit codes */ |
uint32_t bytes_in,bytes_out; /* Used to monitor compression ratio */ |
int max_code; /* old MAX_CODE */ |
uint32_t checkpoint; /* For compression ratio monitoring */ |
int output_bit_count; |
uint32_t output_bit_buffer; |
} Ipe32LZWEncoder; |
// Returns: Bytes written, or -1 if compression failed |
int ipe32lzw_encode(Ipe32LZWEncoder *encoder, unsigned char* compressedData, const size_t compressedBufLen, unsigned char* uncompressedData, const size_t uncompressedSize); |
Ipe32LZWEncoder* new_ipe32lzw_encoder(void); |
void ipe32lzw_init_encoder(Ipe32LZWEncoder *encoder); |
void ipe32lzw_free_encoder(Ipe32LZWEncoder *encoder); |
#endif // #ifndef __inc__ipe32_lzw_encoder |
Property changes: |
Added: svn:mime-type |
+text/x-chdr |
\ No newline at end of property |
/trunk/ipe_artfile_packer |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/trunk/ipe_artfile_packer.c |
---|
0,0 → 1,107 |
/** |
* ART file packer by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Supports: |
* - Blown Away - The Interactive Game by Imagination Pilots |
* - Panic in the Park - The Interactive Game by Imagination Pilots |
* - Where's Waldo? At the Circus |
* - Where's Waldo? Exploring Geography |
* - Eraser Turnabout by Imagination Pilots |
* - Virtual K'Nex by Imagination Pilots |
* Revision: 2018-02-21 |
**/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdbool.h> |
#include <string.h> |
#include <math.h> |
#include <getopt.h> |
#include "ipe_artfile_packer_ipe16_ba.h" |
#include "ipe_artfile_packer_ipe16_pip.h" |
#include "ipe_artfile_packer_ipe32.h" |
#define VERSION "2018-02-21" |
void print_syntax() { |
fprintf(stderr, "Syntax: [-v] -t <type> -i <input dir> -o <output artfile>\n"); |
fprintf(stderr, " -t : ba (Blown Away)\n"); |
fprintf(stderr, " pip (Panic in the Park)\n"); |
fprintf(stderr, " waldo (Where's Waldo? At the Circus)\n"); |
fprintf(stderr, " waldo2 (Where's Waldo? Exploring Geography)\n"); |
fprintf(stderr, " eraser (Eraser Turnabout)\n"); |
fprintf(stderr, " knex (Virtual K'Nex)\n"); |
fprintf(stderr, " -v : verbose output\n"); |
} |
#define GAME_UNKNOWN 0 |
#define GAME_BA 1 |
#define GAME_PIP 2 |
#define GAME_WALDO_CIRCUS 3 |
#define GAME_WALDO_GEOGRAPHY 4 |
#define GAME_ERASER 5 |
#define GAME_KNEX 6 |
int main(int argc, char *argv[]) { |
int verbosity = 0; |
char* szSrcFolder = ""; |
char* szArtFile = ""; |
int c; |
#define PRINT_SYNTAX { print_syntax(); return 0; } |
int game = GAME_UNKNOWN; |
while ((c = getopt(argc, argv, "Vvi:o:t:")) != -1) { |
switch (c) { |
case 't': |
if (strcmp(optarg, "ba") == 0) game = GAME_BA; |
if (strcmp(optarg, "pip") == 0) game = GAME_PIP; |
if (strcmp(optarg, "waldo") == 0) game = GAME_WALDO_CIRCUS; |
if (strcmp(optarg, "waldo2") == 0) game = GAME_WALDO_GEOGRAPHY; |
if (strcmp(optarg, "eraser") == 0) game = GAME_ERASER; |
if (strcmp(optarg, "knex") == 0) game = GAME_KNEX; |
break; |
case 'v': |
verbosity++; |
break; |
case 'V': |
fprintf(stdout, "IPE artfile packer, revision %s\n", VERSION); |
return 0; |
case 'i': |
szSrcFolder = optarg; |
break; |
case 'o': |
szArtFile = optarg; |
break; |
case '?': |
PRINT_SYNTAX; |
break; |
} |
} |
if (optind < argc) PRINT_SYNTAX; |
if (game == GAME_UNKNOWN) { |
fprintf(stderr, "Please specify the game\n"); |
PRINT_SYNTAX; |
} |
if (strlen(szArtFile) == 0) PRINT_SYNTAX; |
if (strlen(szSrcFolder) == 0) PRINT_SYNTAX; |
FILE* fobArt = fopen(szArtFile, "wb"); |
switch (game) { |
case GAME_BA: |
return ba_pack_art(szSrcFolder, fobArt, verbosity) ? 0 : 1; |
break; |
case GAME_PIP: |
case GAME_WALDO_CIRCUS: |
return pip_pack_art(szSrcFolder, fobArt, verbosity) ? 0 : 1; |
break; |
case GAME_WALDO_GEOGRAPHY: |
case GAME_ERASER: |
case GAME_KNEX: |
return ipe32_pack_art(szSrcFolder, fobArt, verbosity) ? 0 : 1; |
break; |
} |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/ipe_artfile_packer.dev |
---|
0,0 → 1,182 |
[Project] |
FileName=ipe_artfile_packer.dev |
Name=Artfile Packer |
UnitCount=12 |
Type=1 |
Ver=2 |
ObjFiles= |
Includes= |
Libs= |
PrivateResource= |
ResourceIncludes= |
MakeIncludes= |
Compiler= |
CppCompiler= |
Linker= |
IsCpp=0 |
Icon= |
ExeOutput= |
ObjectOutput= |
OverrideOutput=0 |
OverrideOutputName=ipe_artfile_packer.exe |
HostApplication= |
Folders= |
CommandLine= |
UseCustomMakefile=0 |
CustomMakefile= |
IncludeVersionInfo=0 |
SupportXPThemes=0 |
CompilerSet=0 |
CompilerSettings=0000000000000000000000000 |
LogOutput= |
LogOutputEnabled=0 |
[VersionInfo] |
Major=0 |
Minor=1 |
Release=1 |
Build=1 |
LanguageID=1033 |
CharsetID=1252 |
CompanyName= |
FileVersion=0.1.1.1 |
FileDescription=Developed using the Dev-C++ IDE |
InternalName= |
LegalCopyright= |
LegalTrademarks= |
OriginalFilename= |
ProductName= |
ProductVersion= |
AutoIncBuildNr=0 |
SyncProduct=0 |
[Unit1] |
FileName=ipe_artfile_packer.c |
CompileCpp=0 |
Folder=BA Artfile Packer |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit2] |
FileName=ipe16_artfile.h |
CompileCpp=0 |
Folder= |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit3] |
FileName=ipe32_artfile.h |
CompileCpp=0 |
Folder= |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit4] |
FileName=bitmap.h |
CompileCpp=0 |
Folder= |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit5] |
FileName=ipe32_lzw_encoder.c |
CompileCpp=0 |
Folder= |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit7] |
FileName=ipe16_bmpimport.c |
CompileCpp=0 |
Folder= |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit8] |
FileName=utils.c |
CompileCpp=0 |
Folder= |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit9] |
FileName=ipe32_bmpimport.c |
CompileCpp=0 |
Folder= |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit9] |
FileName=ipe_artfile_packer_ipe16_ba.c |
CompileCpp=0 |
Folder=BA Artfile Packer |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit10] |
FileName=ipe_artfile_packer_ipe16_pip.c |
CompileCpp=0 |
Folder=BA Artfile Packer |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit11] |
FileName=ipe_artfile_packer_ipe32.c |
CompileCpp=0 |
Folder=BA Artfile Packer |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit12] |
FileName=ipe32_bmpimport.c |
CompileCpp=0 |
Folder= |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit6] |
FileName=ipe16_lzw_encoder.c |
CompileCpp=0 |
Folder= |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
/trunk/ipe_artfile_packer.exe |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/x-msdos-program |
Property changes: |
Added: svn:mime-type |
+application/x-msdos-program |
\ No newline at end of property |
/trunk/ipe_artfile_packer.layout |
---|
0,0 → 1,48 |
[Editor_0] |
CursorCol=13 |
CursorRow=3 |
TopLine=1 |
LeftChar=1 |
[Editor_2] |
CursorCol=1 |
CursorRow=47 |
TopLine=16 |
LeftChar=1 |
[Editor_1] |
CursorCol=20 |
CursorRow=69 |
TopLine=1 |
LeftChar=1 |
[Editor_6] |
CursorCol=39 |
CursorRow=83 |
TopLine=64 |
LeftChar=1 |
[Editor_7] |
CursorCol=7 |
CursorRow=17 |
TopLine=1 |
LeftChar=1 |
[Editor_3] |
CursorCol=21 |
CursorRow=19 |
TopLine=1 |
LeftChar=1 |
[Editors] |
Order=0 |
Focused=0 |
[Editor_5] |
CursorCol=1 |
CursorRow=8 |
TopLine=83 |
LeftChar=1 |
[Editor_8] |
CursorCol=42 |
CursorRow=97 |
TopLine=120 |
LeftChar=1 |
[Editor_4] |
CursorCol=13 |
CursorRow=144 |
TopLine=120 |
LeftChar=1 |
/trunk/ipe_artfile_packer_ipe16_ba.c |
---|
0,0 → 1,167 |
/** |
* ART file packer by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Supports: |
* - Blown Away - The Interactive Game by Imagination Pilots |
* Revision: 2018-02-15 |
**/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdbool.h> |
#include <string.h> |
#include <math.h> |
#include "ipe_artfile_packer_ipe16_ba.h" |
#include "ipe16_artfile.h" |
#include "ipe16_bmpimport.h" |
#include "ipe16_lzw_encoder.h" |
#define MAX_FILE 256 |
bool ba_pack_art(const char* szSrcFolder, FILE* fobArt, const int verbosity) { |
bool bEverythingOK = true; |
char szIndexFilename[MAX_FILE]; |
sprintf(szIndexFilename, "%s/index.txt", szSrcFolder); |
FILE* fitIndex = fopen(szIndexFilename, "rt"); |
if (!fitIndex) { |
fprintf(stderr, "Cannot open %s\n", szIndexFilename); |
return false; |
} |
#define MAX_LINE 1024 |
char line[MAX_LINE]; |
int cItems = 0; |
while (fgets(line, sizeof(line), fitIndex)) { |
if (strlen(line) == 0) continue; |
++cItems; |
} |
if (verbosity >= 1) printf("%s contains %d entries\n", szIndexFilename, cItems); // TODO: don't print double / |
Ipe16FileHeader bfh; |
memset(&bfh, 0x00, sizeof(bfh)); |
strcpy(bfh.magic, IPE16_MAGIC_ART); |
bfh.dummy = IPE16_MAGIC_DUMMY; |
bfh.numHeaderEntries = cItems+1; |
Ipe16PictureEntryHeader peh[cItems]; |
memset(&peh, 0x00, sizeof(peh)); |
BAPictureHeader ph[cItems]; |
memset(&ph, 0x00, sizeof(ph)); |
// We need to write the (still empty) headers, so we can use ftell() to determine the offsets correctly |
// These headers are currently just dummies. They will be rewritten after all pictures are processed |
fwrite(&bfh, sizeof(bfh), 1, fobArt); |
fwrite(&peh, sizeof(peh), 1, fobArt); |
fseek(fitIndex, 0, SEEK_SET); |
int curItem = 0; |
Ipe16LZWEncoder* lzwEncoder = NULL; |
while (fgets(line, sizeof(line), fitIndex)) { |
// If something fails, we discard the item, but continue in building the file! |
#define FAIL_CONTINUE { memset(&peh[curItem], 0x00, sizeof(peh[curItem])); bEverythingOK=false; continue; } |
const char* szDelimiters = " \t\r\n"; |
char* szPaletteType = strtok(&line[0], szDelimiters); |
char* szCompressionType = strtok(NULL, szDelimiters); |
char* szName = strtok(NULL, szDelimiters); |
char* szFilename = strtok(NULL, szDelimiters); |
if (strlen(szPaletteType) != 1) { |
fprintf(stderr, "ERROR: Palette type (argument 1) at line %d is not valid (must be 1 char)\n", curItem+1); |
FAIL_CONTINUE; |
} |
const char chPaletteType = *szPaletteType; |
if ((chPaletteType != IPE16_PALETTETYPE_ATTACHED) && (chPaletteType != IPE16_PALETTETYPE_PARENT)) { |
fprintf(stderr, "ERROR: Unknown palette type '%c' at line %d\n", chPaletteType, curItem+1); |
FAIL_CONTINUE; |
} |
if (strlen(szCompressionType) != 1) { |
fprintf(stderr, "ERROR: Compression type (argument 2) at line %d is not valid (must be 1 char)\n", curItem+1); |
FAIL_CONTINUE; |
} |
const char chCompressionType = *szCompressionType; |
if (strlen(szName) > IPE16_NAME_SIZE) { |
fprintf(stderr, "ERROR: Name %s is too long (max %d chars allowed)\n", szName, IPE16_NAME_SIZE); |
FAIL_CONTINUE; |
} |
strcpy(peh[curItem].name, szName); |
peh[curItem].paletteType = chPaletteType; |
peh[curItem].offset = ftell(fobArt); |
peh[curItem].size = 0; // will be increased later |
if (verbosity >= 1) printf("Process %s at offset %x\n", szName, peh[curItem].offset); |
// Read bitmap |
const bool colorTableExisting = (chPaletteType == IPE16_PALETTETYPE_ATTACHED); |
char szBitmapFilename[MAX_FILE]; |
sprintf(szBitmapFilename, "%s/%s", szSrcFolder, szFilename); |
FILE* fibBitmap = fopen(szBitmapFilename, "rb"); |
if (!fibBitmap) { |
fprintf(stderr, "ERROR: cannot open '%s'\n", szFilename); |
FAIL_CONTINUE; |
} |
Ipe16BmpImportData result={0}; |
if (!ipe16_bmp_import(fibBitmap, &result)) { |
fprintf(stderr, "Error at %s: %s\n", szFilename, result.error); |
fclose(fibBitmap); |
ipe16_free_bmpimport_result(&result); |
FAIL_CONTINUE; |
} |
ph[curItem].compressionType = chCompressionType; |
ph[curItem].width = result.width; |
ph[curItem].height = result.height; |
fwrite(&ph[curItem], sizeof(ph[curItem]), 1, fobArt); |
peh[curItem].size += sizeof(ph[curItem]); |
// Write picture data |
size_t tmpBefore = ftell(fobArt); |
if (chCompressionType == BA_COMPRESSIONTYPE_LZW) { |
if (!lzwEncoder) lzwEncoder = new_ipe16lzw_encoder(); |
ipe16lzw_encode(fobArt, lzwEncoder, result.bmpData, result.bmpDataSize); |
} else if (chCompressionType == BA_COMPRESSIONTYPE_NONE) { |
fwrite(result.bmpData, result.bmpDataSize, 1, fobArt); |
} else { |
fprintf(stderr, "Unknown compression type '%c' at line %d\n", chCompressionType, curItem+1); |
fclose(fibBitmap); |
ipe16_free_bmpimport_result(&result); |
FAIL_CONTINUE; |
} |
peh[curItem].size += ftell(fobArt)-tmpBefore; |
if (colorTableExisting) { |
fwrite(result.colorTable, sizeof(*result.colorTable), 1, fobArt); |
peh[curItem].size += sizeof(*result.colorTable); |
} |
// Free and continue |
fclose(fibBitmap); |
ipe16_free_bmpimport_result(&result); |
++curItem; |
} |
if (lzwEncoder) del_ipe16lzw_encoder(lzwEncoder); |
fclose(fitIndex); |
bfh.totalFileSize = ftell(fobArt); |
fseek(fobArt, 0, SEEK_SET); |
fwrite(&bfh, sizeof(bfh), 1, fobArt); |
fwrite(&peh, sizeof(peh), 1, fobArt); |
fclose(fobArt); |
return bEverythingOK; |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/ipe_artfile_packer_ipe16_ba.h |
---|
0,0 → 1,16 |
/** |
* ART file packer by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Supports: |
* - Blown Away - The Interactive Game by Imagination Pilots |
* Revision: 2018-02-15 |
**/ |
#ifndef __inc__ipe_artfile_packer_ipe16_ba |
#define __inc__ipe_artfile_packer_ipe16_ba |
#include <stdio.h> |
#include <stdbool.h> |
bool ba_pack_art(const char* szSrcFolder, FILE* fobArt, const int verbosity); |
#endif // #ifndef __inc__ipe_artfile_packer_ipe16_ba |
Property changes: |
Added: svn:mime-type |
+text/x-chdr |
\ No newline at end of property |
/trunk/ipe_artfile_packer_ipe16_pip.c |
---|
0,0 → 1,173 |
/** |
* ART file packer by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Supports: |
* - Panic in the Park - The Interactive Game by Imagination Pilots |
* - Where's Waldo? At the Circus (Waldo1) |
* Revision: 2018-02-15 |
**/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdbool.h> |
#include <string.h> |
#include <math.h> |
#include "ipe_artfile_packer_ipe16_pip.h" |
#include "ipe16_artfile.h" |
#include "ipe16_bmpimport.h" |
#include "ipe16_lzw_encoder.h" |
#define MAX_FILE 256 |
bool pip_pack_art(const char* szSrcFolder, FILE* fobArt, const int verbosity) { |
bool bEverythingOK = true; |
char szIndexFilename[MAX_FILE]; |
sprintf(szIndexFilename, "%s/index.txt", szSrcFolder); |
FILE* fitIndex = fopen(szIndexFilename, "rt"); |
if (!fitIndex) { |
fprintf(stderr, "Cannot open %s\n", szIndexFilename); |
return false; |
} |
#define MAX_LINE 1024 |
char line[MAX_LINE]; |
int cItems = 0; |
while (fgets(line, sizeof(line), fitIndex)) { |
if (strlen(line) == 0) continue; |
++cItems; |
} |
if (verbosity >= 1) printf("%s contains %d entries\n", szIndexFilename, cItems); // TODO: don't print double / |
Ipe16FileHeader bfh; |
memset(&bfh, 0x00, sizeof(bfh)); |
strcpy(bfh.magic, IPE16_MAGIC_ART); |
bfh.dummy = IPE16_MAGIC_DUMMY; |
bfh.numHeaderEntries = cItems+1; |
Ipe16PictureEntryHeader peh[cItems]; |
memset(&peh, 0x00, sizeof(peh)); |
PipPictureHeader ph[cItems]; |
memset(&ph, 0x00, sizeof(ph)); |
// We need to write the (still empty) headers, so we can use ftell() to determine the offsets correctly |
// These headers are currently just dummies. They will be rewritten after all pictures are processed |
fwrite(&bfh, sizeof(bfh), 1, fobArt); |
fwrite(&peh, sizeof(peh), 1, fobArt); |
fseek(fitIndex, 0, SEEK_SET); |
int curItem = 0; |
Ipe16LZWEncoder* lzwEncoder = NULL; |
while (fgets(line, sizeof(line), fitIndex)) { |
// If something fails, we discard the item, but continue in building the file! |
#define FAIL_CONTINUE { memset(&peh[curItem], 0x00, sizeof(peh[curItem])); bEverythingOK=false; continue; } |
const char* szDelimiters = " \t\r\n"; |
char* szPaletteType = strtok(&line[0], szDelimiters); |
char* szCompressionType = strtok(NULL, szDelimiters); |
char* szName = strtok(NULL, szDelimiters); |
char* szFilename = strtok(NULL, szDelimiters); |
char* szOffsetX = strtok(NULL, szDelimiters); |
int iOffsetX = (szOffsetX != NULL) ? atoi(szOffsetX) : 0; |
char* szOffsetY = strtok(NULL, szDelimiters); |
int iOffsetY = (szOffsetY != NULL) ? atoi(szOffsetY) : 0; |
if (strlen(szPaletteType) != 1) { |
fprintf(stderr, "ERROR: Palette type (argument 1) at line %d is not valid (must be 1 char)\n", curItem+1); |
FAIL_CONTINUE; |
} |
const char chPaletteType = *szPaletteType; |
if ((chPaletteType != IPE16_PALETTETYPE_ATTACHED) && (chPaletteType != IPE16_PALETTETYPE_PARENT)) { |
fprintf(stderr, "ERROR: Unknown palette type '%c' at line %d\n", chPaletteType, curItem+1); |
FAIL_CONTINUE; |
} |
if (strlen(szCompressionType) != 1) { |
fprintf(stderr, "ERROR: Compression type (argument 2) at line %d is not valid (must be 1 char)\n", curItem+1); |
FAIL_CONTINUE; |
} |
const char chCompressionType = *szCompressionType; |
if (strlen(szName) > IPE16_NAME_SIZE) { |
fprintf(stderr, "ERROR: Name %s is too long (max %d chars allowed)\n", szName, IPE16_NAME_SIZE); |
FAIL_CONTINUE; |
} |
strcpy(peh[curItem].name, szName); |
peh[curItem].paletteType = chPaletteType; |
peh[curItem].offset = ftell(fobArt); |
peh[curItem].size = 0; // will be increased later |
if (verbosity >= 1) printf("Process %s at offset %x\n", szName, peh[curItem].offset); |
// Read bitmap |
const bool colorTableExisting = (chPaletteType == IPE16_PALETTETYPE_ATTACHED); |
char szBitmapFilename[MAX_FILE]; |
sprintf(szBitmapFilename, "%s/%s", szSrcFolder, szFilename); |
FILE* fibBitmap = fopen(szBitmapFilename, "rb"); |
if (!fibBitmap) { |
fprintf(stderr, "ERROR: cannot open '%s'\n", szFilename); |
FAIL_CONTINUE; |
} |
Ipe16BmpImportData result={0}; |
if (!ipe16_bmp_import(fibBitmap, &result)) { |
fprintf(stderr, "Error at %s: %s\n", szFilename, result.error); |
fclose(fibBitmap); |
ipe16_free_bmpimport_result(&result); |
FAIL_CONTINUE; |
} |
ph[curItem].compressionType = chCompressionType; |
ph[curItem].offsetX = iOffsetX; |
ph[curItem].offsetY = iOffsetY; |
ph[curItem].width = result.width; |
ph[curItem].height = result.height; |
fwrite(&ph[curItem], sizeof(ph[curItem]), 1, fobArt); |
peh[curItem].size += sizeof(ph[curItem]); |
// Write picture data |
size_t tmpBefore = ftell(fobArt); |
if (chCompressionType == PIP_COMPRESSIONTYPE_LZW) { |
if (!lzwEncoder) lzwEncoder = new_ipe16lzw_encoder(); |
ipe16lzw_encode(fobArt, lzwEncoder, result.bmpData, result.bmpDataSize); |
} else if (chCompressionType == PIP_COMPRESSIONTYPE_NONE) { |
fwrite(result.bmpData, result.bmpDataSize, 1, fobArt); |
} else { |
fprintf(stderr, "Unknown compression type '%c' at line %d\n", chCompressionType, curItem+1); |
fclose(fibBitmap); |
ipe16_free_bmpimport_result(&result); |
FAIL_CONTINUE; |
} |
peh[curItem].size += ftell(fobArt)-tmpBefore; |
if (colorTableExisting) { |
fwrite(result.colorTable, sizeof(*result.colorTable), 1, fobArt); |
peh[curItem].size += sizeof(*result.colorTable); |
} |
// Free and continue |
fclose(fibBitmap); |
ipe16_free_bmpimport_result(&result); |
++curItem; |
} |
if (lzwEncoder) del_ipe16lzw_encoder(lzwEncoder); |
fclose(fitIndex); |
bfh.totalFileSize = ftell(fobArt); |
fseek(fobArt, 0, SEEK_SET); |
fwrite(&bfh, sizeof(bfh), 1, fobArt); |
fwrite(&peh, sizeof(peh), 1, fobArt); |
fclose(fobArt); |
return bEverythingOK; |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/ipe_artfile_packer_ipe16_pip.h |
---|
0,0 → 1,17 |
/** |
* ART file packer by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Supports: |
* - Panic in the Park - The Interactive Game by Imagination Pilots |
* - Where's Waldo? At the Circus (Waldo1) |
* Revision: 2018-02-15 |
**/ |
#ifndef __inc__ipe_artfile_packer_ipe16_pip |
#define __inc__ipe_artfile_packer_ipe16_pip |
#include <stdio.h> |
#include <stdbool.h> |
bool pip_pack_art(const char* szSrcFolder, FILE* fobArt, const int verbosity); |
#endif // #ifndef __inc__ipe_artfile_packer_ipe16_pip |
Property changes: |
Added: svn:mime-type |
+text/x-chdr |
\ No newline at end of property |
/trunk/ipe_artfile_packer_ipe32.c |
---|
0,0 → 1,143 |
/** |
* ART file packer by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Supports: |
* - Where's Waldo? Exploring Geography |
* - Eraser Turnabout by Imagination Pilots |
* - Virtual K'Nex by Imagination Pilots |
* Revision: 2018-02-15 |
**/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdbool.h> |
#include <string.h> |
#include <math.h> |
#include "ipe_artfile_packer_ipe32.h" |
#include "ipe32_artfile.h" |
#include "ipe32_bmpimport.h" |
#include "ipe32_lzw_encoder.h" |
#define MAX_FILE 256 |
bool ipe32_pack_art(const char* szSrcFolder, FILE* fobArt, const int verbosity) { |
bool bEverythingOK = true; |
char szIndexFilename[MAX_FILE]; |
sprintf(szIndexFilename, "%s/index.txt", szSrcFolder); |
FILE* fitIndex = fopen(szIndexFilename, "rt"); |
if (!fitIndex) { |
fprintf(stderr, "Cannot open %s\n", szIndexFilename); |
return false; |
} |
#define MAX_LINE 1024 |
char line[MAX_LINE]; |
int cItems = 0; |
while (fgets(line, sizeof(line), fitIndex)) { |
if (strlen(line) == 0) continue; |
++cItems; |
} |
if (verbosity >= 1) printf("%s contains %d entries\n", szIndexFilename, cItems); // TODO: don't print double / |
Ipe32FileHeader efh; |
memset(&efh, 0x00, sizeof(efh)); |
strcpy(efh.magic, IPE32_MAGIC_ART); |
efh.reserved = 0; |
efh.totalHeaderSize = (cItems+1)*sizeof(efh); |
Ipe32PictureEntryHeader peh[cItems]; |
memset(&peh, 0x00, sizeof(peh)); |
// These headers are currently just dummies. They will be rewritten after all pictures are processed |
fwrite(&efh, sizeof(efh), 1, fobArt); |
fwrite(&peh, sizeof(peh), 1, fobArt); |
Ipe32LZWEncoder *encoder = new_ipe32lzw_encoder(); |
ipe32lzw_init_encoder(encoder); |
fseek(fitIndex, 0, SEEK_SET); |
int curItem = 0; |
while (fgets(line, sizeof(line), fitIndex)) { |
// If something fails, we discard the item, but continue in building the file! |
#define FAIL_CONTINUE { memset(&peh[curItem], 0x00, sizeof(peh[curItem])); bEverythingOK=false; continue; } |
const char* szDelimiters = " \t\r\n"; |
char* szName = strtok(&line[0], szDelimiters); |
/* char* szNumCompressedChunks = */ strtok(NULL, szDelimiters); |
/* char* szNumRawChunks = */ strtok(NULL, szDelimiters); |
char* szFilename = strtok(NULL, szDelimiters); |
if (strlen(szName) > IPE32_NAME_SIZE) { |
fprintf(stderr, "ERROR: Name %s is too long (max %d chars allowed)\n", szName, IPE32_NAME_SIZE); |
FAIL_CONTINUE; |
} |
char szBitmapFilename[MAX_FILE]; |
sprintf(szBitmapFilename, "%s/%s", szSrcFolder, szFilename); |
FILE* fibBitmap = fopen(szBitmapFilename, "rb"); |
if (!fibBitmap) { |
fprintf(stderr, "ERROR: cannot open '%s'\n", szFilename); |
FAIL_CONTINUE; |
} |
Ipe32BmpImportData result={0}; |
if (!ipe32_bmp_import(fibBitmap, &result)) { // This function moves the file pointer to the bitmap info header |
fprintf(stderr, "Error at %s: %s\n", szFilename, result.error); |
fclose(fibBitmap); |
ipe32_free_bmpimport_result(&result); |
FAIL_CONTINUE; |
} |
strcpy(peh[curItem].name, szName); |
peh[curItem].offset = ftell(fobArt); |
peh[curItem].uncompressedSize = result.dataSize; |
if (verbosity >= 1) printf("Process %s at offset %x\n", szName, peh[curItem].offset); |
// Now write the chunks |
int chunkNo = 0; |
unsigned char uncompressedChunk[0x3FFE]; |
unsigned char compressedChunk[0x3FFE]; |
while (1) { |
if (verbosity >= 2) fprintf(stdout, "Bitmap %s: Write chunk %d.\n", szFilename, chunkNo); |
int uncompressedSize = fread(uncompressedChunk, 1, sizeof(uncompressedChunk), fibBitmap); |
if (uncompressedSize == 0) break; // done |
int compressedSize = ipe32lzw_encode(encoder, compressedChunk, sizeof(compressedChunk), uncompressedChunk, uncompressedSize); |
uint16_t len; |
if ((compressedSize == -1) || (compressedSize >= uncompressedSize)) { |
// Choose uncompressed chunk |
len = 0x8000 | uncompressedSize; |
fwrite(&len, sizeof(len), 1, fobArt); |
fwrite(uncompressedChunk, uncompressedSize, 1, fobArt); |
} else { |
// Choose compressed chunk |
len = compressedSize; |
fwrite(&len, sizeof(len), 1, fobArt); |
fwrite(compressedChunk, compressedSize, 1, fobArt); |
} |
chunkNo++; |
} |
// Free and continue |
fclose(fibBitmap); |
ipe32_free_bmpimport_result(&result); |
++curItem; |
} |
fclose(fitIndex); |
ipe32lzw_free_encoder(encoder); |
fseek(fobArt, 0, SEEK_SET); |
fwrite(&efh, sizeof(efh), 1, fobArt); |
fwrite(&peh, sizeof(peh), 1, fobArt); |
fclose(fobArt); |
return bEverythingOK; |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/ipe_artfile_packer_ipe32.h |
---|
0,0 → 1,19 |
/** |
* ART file packer by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Supports: |
* - Where's Waldo? Exploring Geography |
* - Eraser Turnabout by Imagination Pilots |
* - Virtual K'Nex by Imagination Pilots |
* Revision: 2018-02-15 |
**/ |
#ifndef __inc__ipe_artfile_packer_ipe32 |
#define __inc__ipe_artfile_packer_ipe32 |
#include <stdio.h> |
#include <stdbool.h> |
bool ipe32_pack_art(const char* szSrcFolder, FILE* fobArt, const int verbosity); |
#endif // #ifndef __inc__ipe_artfile_packer_ipe32 |
Property changes: |
Added: svn:mime-type |
+text/x-chdr |
\ No newline at end of property |
/trunk/ipe_artfile_unpacker |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/trunk/ipe_artfile_unpacker.c |
---|
0,0 → 1,87 |
/** |
* ART file unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Supports: |
* - Blown Away - The Interactive Game by Imagination Pilots |
* - Panic in the Park - The Interactive Game by Imagination Pilots |
* - Where's Waldo? At the Circus (Waldo1) |
* - Where's Waldo? Exploring Geography |
* - Eraser Turnabout by Imagination Pilots |
* - Virtual K'Nex by Imagination Pilots |
* Revision: 2018-02-15 |
**/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <assert.h> |
#include <string.h> |
#include <getopt.h> |
#include "ipe16_artfile.h" |
#include "ipe32_artfile.h" |
#include "ipe_artfile_unpacker_ipe16.h" |
#include "ipe_artfile_unpacker_ipe32.h" |
#define VERSION "2018-02-15" |
void print_syntax() { |
fprintf(stderr, "Syntax: -v [-o <outputdir>] -i <artfile>\n"); |
fprintf(stderr, " -v : verbose output\n"); |
fprintf(stderr, "Runs in simulation mode if no output directory is defined.\n"); |
} |
int main(int argc, char *argv[]) { |
int verbosity = 0; |
char* szOutputDir = ""; |
char* szArtFile = ""; |
int c; |
#define PRINT_SYNTAX { print_syntax(); return 0; } |
while ((c = getopt(argc, argv, "Vvi:o:")) != -1) { |
switch (c) { |
case 'v': |
verbosity++; |
break; |
case 'V': |
fprintf(stdout, "IPE Artfile unpacker, revision %s\n", VERSION); |
return 0; |
case 'i': |
szArtFile = optarg; |
break; |
case 'o': |
szOutputDir = optarg; |
break; |
case '?': |
PRINT_SYNTAX; |
break; |
} |
} |
if (optind < argc) PRINT_SYNTAX; |
if (strlen(szArtFile) == 0) PRINT_SYNTAX; |
FILE* fibArt = fopen(szArtFile, "rb"); |
if (!fibArt) { |
fprintf(stderr, "FATAL: Cannot open %s\n", szArtFile); |
return 1; |
} |
char signature[9]={0}; |
if (fread(&signature, 8, 1, fibArt) != 1) { |
fprintf(stderr, "FATAL: Cannot read signature of %s\n", szArtFile); |
return 1; |
} |
if (strcmp(signature, IPE32_MAGIC_ART) == 0) { |
if (verbosity >= 1) fprintf(stdout, "%s: Detected file as IPE32 (Waldo2/Eraser/K'Nex) art file\n", szArtFile); |
return ipe32_extract_art_to_folder(fibArt, szOutputDir, verbosity) ? 0 : 1; |
} else if (strcmp(signature, IPE16_MAGIC_ART) == 0) { |
if (verbosity >= 1) fprintf(stdout, "%s: Detected file as IPE16 (BA/PiP/Waldo1) art file\n", szArtFile); |
return ipe16_extract_art_to_folder(fibArt, szOutputDir, verbosity) ? 0 : 1; |
} else { |
fprintf(stderr, "FATAL: %s is not a valid ART file of Imagination Pilots!\n", szArtFile); |
return 1; |
} |
fclose(fibArt); |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/ipe_artfile_unpacker.dev |
---|
0,0 → 1,182 |
[Project] |
FileName=ipe_artfile_unpacker.dev |
Name=Artfile Unpacker |
UnitCount=11 |
Type=1 |
Ver=2 |
ObjFiles= |
Includes= |
Libs= |
PrivateResource= |
ResourceIncludes= |
MakeIncludes= |
Compiler= |
CppCompiler= |
Linker= |
IsCpp=0 |
Icon= |
ExeOutput= |
ObjectOutput= |
OverrideOutput=0 |
OverrideOutputName=ipe_artfile_unpacker.exe |
HostApplication= |
Folders= |
CommandLine= |
UseCustomMakefile=0 |
CustomMakefile= |
IncludeVersionInfo=0 |
SupportXPThemes=0 |
CompilerSet=0 |
CompilerSettings=0000000000000000000000000 |
LogOutput= |
LogOutputEnabled=0 |
[VersionInfo] |
Major=0 |
Minor=1 |
Release=1 |
Build=1 |
LanguageID=1033 |
CharsetID=1252 |
CompanyName= |
FileVersion=0.1.1.1 |
FileDescription=Developed using the Dev-C++ IDE |
InternalName= |
LegalCopyright= |
LegalTrademarks= |
OriginalFilename= |
ProductName= |
ProductVersion= |
AutoIncBuildNr=0 |
SyncProduct=0 |
[Unit1] |
FileName=ipe_artfile_unpacker.c |
CompileCpp=0 |
Folder=BA Artfile Unpacker |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit2] |
FileName=ipe16_artfile.h |
CompileCpp=0 |
Folder=BA Artfile Unpacker |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit3] |
FileName=ipe16_bmpexport.c |
CompileCpp=0 |
Folder=BA Artfile Unpacker |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit6] |
FileName=ipe32_lzw_decoder.c |
CompileCpp=0 |
Folder= |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit8] |
FileName=utils.c |
CompileCpp=0 |
Folder= |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit9] |
FileName=ipe_artfile_unpacker_ipe16.c |
CompileCpp=0 |
Folder=BA Artfile Unpacker |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit10] |
FileName=ipe_artfile_unpacker_ipe32.c |
CompileCpp=0 |
Folder=BA Artfile Unpacker |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit11] |
FileName=ipe32_bmpexport.c |
CompileCpp=0 |
Folder= |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit12] |
FileName=ipe_artfile_unpacker_ipe16.c |
CompileCpp=0 |
Folder=BA Artfile Unpacker |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit13] |
FileName=ipe_artfile_unpacker_ipe32.c |
CompileCpp=0 |
Folder=BA Artfile Unpacker |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit4] |
FileName=ipe16_lzw_decoder.c |
CompileCpp=0 |
Folder=BA Artfile Unpacker |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit5] |
FileName=ipe32_artfile.h |
CompileCpp=0 |
Folder= |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
[Unit7] |
FileName=bitmap.h |
CompileCpp=0 |
Folder= |
Compile=1 |
Link=1 |
Priority=1000 |
OverrideBuildCmd=0 |
BuildCmd= |
/trunk/ipe_artfile_unpacker.exe |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/x-msdos-program |
Property changes: |
Added: svn:mime-type |
+application/x-msdos-program |
\ No newline at end of property |
/trunk/ipe_artfile_unpacker.layout |
---|
0,0 → 1,53 |
[Editor_6] |
CursorCol=29 |
CursorRow=8 |
TopLine=1 |
LeftChar=1 |
[Editor_7] |
CursorCol=19 |
CursorRow=8 |
TopLine=1 |
LeftChar=1 |
[Editor_4] |
CursorCol=35 |
CursorRow=9 |
TopLine=1 |
LeftChar=1 |
[Editor_5] |
CursorCol=35 |
CursorRow=54 |
TopLine=44 |
LeftChar=1 |
[Editor_3] |
CursorCol=1 |
CursorRow=9 |
TopLine=1 |
LeftChar=1 |
[Editor_2] |
CursorCol=5 |
CursorRow=51 |
TopLine=50 |
LeftChar=1 |
[Editor_1] |
CursorCol=20 |
CursorRow=13 |
TopLine=1 |
LeftChar=1 |
[Editor_0] |
CursorCol=1 |
CursorRow=1 |
TopLine=1 |
LeftChar=1 |
[Editor_8] |
CursorCol=1 |
CursorRow=8 |
TopLine=1 |
LeftChar=1 |
[Editor_9] |
CursorCol=17 |
CursorRow=4 |
TopLine=1 |
LeftChar=1 |
[Editors] |
Order=1 |
Focused=1 |
/trunk/ipe_artfile_unpacker_ipe16.c |
---|
0,0 → 1,299 |
/** |
* ART file unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Supports: |
* - Blown Away - The Interactive Game by Imagination Pilots |
* - Panic in the Park - The Interactive Game by Imagination Pilots |
* - Where's Waldo? At the Circus (Waldo1) |
* Revision: 2018-02-15 |
**/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <assert.h> |
#include <string.h> |
#include <getopt.h> |
#include "ipe16_bmpexport.h" |
#include "ipe16_artfile.h" |
#include "ipe16_lzw_decoder.h" |
#include "utils.h" |
#define MAX_FILE 256 |
void ipe16_generate_gray_table(Ipe16ColorTable *ct) { |
int i; |
for (i=0; i<=0xFF; ++i) { |
ct->colors[i].r = i; |
ct->colors[i].g = i; |
ct->colors[i].b = i; |
} |
} |
bool ipe16_extract_art_to_folder(FILE* fibArt, const char* szDestFolder, const int verbosity) { |
bool bEverythingOK = true; |
fseek(fibArt, 0, SEEK_SET); |
Ipe16FileHeader bfh; |
if (fread(&bfh, sizeof(bfh), 1, fibArt) != 1) { |
fprintf(stderr, "FATAL: Cannot read Ipe16FileHeader. It is probably not an art file.\n"); |
return false; |
} |
// The "super header" has some different meanings of the fields |
// Name and Type are hardcoded |
// startOffset is the number of header entries (including the super header) |
// length is the complete file size |
const size_t fileSize = file_size(fibArt); |
if ((strcmp(bfh.magic, IPE16_MAGIC_ART) != 0) || // better memcpy over all 23 bytes? |
(bfh.dummy != IPE16_MAGIC_DUMMY) || |
(bfh.totalFileSize != fileSize)) { |
fprintf(stderr, "FATAL: Something does not seem to be correct with this art file's header. It is probably not an art file.\n"); |
return false; |
} |
Ipe16LZWDecoder* lzwDecoder = NULL; |
FILE* fotIndex = NULL; |
if (strlen(szDestFolder) > 0) { |
char szIndexFilename[MAX_FILE]; |
sprintf(szIndexFilename, "%s/index.txt", szDestFolder); |
fotIndex = fopen(szIndexFilename, "wt"); |
if (!fotIndex) { |
fprintf(stderr, "FATAL: Cannot open %s for writing\n", szIndexFilename); |
return false; |
} |
} |
const int numPictures = bfh.numHeaderEntries - 1; |
char knownNames[numPictures][IPE16_NAME_SIZE]; |
memset(&knownNames[0][0], 0, numPictures*IPE16_NAME_SIZE); |
int iPicNo; |
for (iPicNo=0; iPicNo<numPictures; ++iPicNo) { |
Ipe16PictureEntryHeader peh; |
if (fread(&peh, sizeof(peh), 1, fibArt) != 1) { |
fprintf(stderr, "FATAL: Cannot read Ipe16PictureEntryHeader.\n"); |
return false; |
} |
// Begin duplicate check |
memcpy(&knownNames[iPicNo][0], peh.name, IPE16_NAME_SIZE); |
int iCopyNumber = 0; |
int j; |
for (j=0; j<=iPicNo; ++j) { |
// TODO: should we rather use strcmp() in IPE16? |
if (memcmp(&knownNames[j][0], peh.name, IPE16_NAME_SIZE) == 0) ++iCopyNumber; |
} |
assert(iCopyNumber > 0); |
// End duplicate check |
// in the English version of Blown Away (not the Special Edition), there is a header entry |
// with the fields seh.name='', peh.paletteType=0x00, seh.offset[end of file], seh.size=0 |
// ignore it |
if (strlen(peh.name) == 0) continue; |
if (peh.size == 0) continue; |
if (strlen(peh.name) > IPE16_NAME_SIZE-1) { |
fprintf(stderr, "FATAL: szName at picture %d is breaking the boundaries. The file is probably corrupt.\n", iPicNo); |
return false; |
} |
size_t headersPos = ftell(fibArt); |
#define FAIL_CONTINUE { bEverythingOK = false; fseek(fibArt, headersPos, SEEK_SET); continue; } |
if (fseek(fibArt, peh.offset, SEEK_SET) != 0) { |
fprintf(stderr, "ERROR: Error jumping to offset defined for %s\n", peh.name); |
FAIL_CONTINUE; |
} |
if (peh.offset+peh.size > fileSize) { |
fprintf(stderr, "ERROR: Defined size of %s exceeds file size\n", peh.name); |
FAIL_CONTINUE; |
} |
unsigned char compressionType; |
int bakPos = ftell(fibArt); |
fread(&compressionType, sizeof(compressionType), 1, fibArt); |
fseek(fibArt, bakPos, SEEK_SET); |
if ((compressionType == BA_COMPRESSIONTYPE_LZW) || (compressionType == BA_COMPRESSIONTYPE_NONE)) { |
BAPictureHeader ph; |
if (fread(&ph, sizeof(ph), 1, fibArt) != 1) { |
fprintf(stderr, "ERROR: Cannot read BAPictureHeader of %s\n", peh.name); |
FAIL_CONTINUE; |
} |
size_t imagedata_len = ph.width * ph.height; |
unsigned char* imagedata = (unsigned char*)malloc(imagedata_len); |
Ipe16ColorTable ct; |
if (peh.paletteType == IPE16_PALETTETYPE_ATTACHED) { |
if ((fseek(fibArt, peh.offset+peh.size-sizeof(ct), SEEK_SET) != 0) || |
(fread(&ct, sizeof(ct), 1, fibArt) != 1) || |
(fseek(fibArt, peh.offset+sizeof(ph), SEEK_SET) != 0)) { |
fprintf(stderr, "ERROR: Cannot read palette of %s\n", peh.name); |
FAIL_CONTINUE; |
} |
} else if (peh.paletteType == IPE16_PALETTETYPE_PARENT) { |
ipe16_generate_gray_table(&ct); |
} else { |
fprintf(stderr, "ERROR: Unknown palette type 0x%x at %s\n", peh.paletteType, peh.name); |
FAIL_CONTINUE; |
} |
unsigned int bytes_written, expected_uncompressed_len; |
switch (ph.compressionType) { |
case BA_COMPRESSIONTYPE_LZW: |
if (!lzwDecoder) lzwDecoder = new_ipe16lzw_decoder(); |
bytes_written = ipe16lzw_decode(fibArt, lzwDecoder, imagedata, imagedata_len); |
if (bytes_written < 0) { |
fprintf(stderr, "ERROR: LZW decompression error at %s\n", peh.name); |
FAIL_CONTINUE; |
} |
if (bytes_written != imagedata_len) { |
fprintf(stderr, "ERROR: Image dimensions and decompressed data size does not match for %s\n", peh.name); |
FAIL_CONTINUE; |
} |
break; |
case BA_COMPRESSIONTYPE_NONE: |
expected_uncompressed_len = imagedata_len; |
if (peh.paletteType == IPE16_PALETTETYPE_ATTACHED) expected_uncompressed_len += sizeof(ct); |
expected_uncompressed_len += sizeof(ph.compressionType)+sizeof(ph.width)+sizeof(ph.height); |
if (expected_uncompressed_len != peh.size) { |
fprintf(stderr, "ERROR: Image dimensions/palette (%d) and defined memory size (%d) does not match for %s\n", expected_uncompressed_len, peh.size, peh.name); |
FAIL_CONTINUE; |
} |
fread(imagedata, imagedata_len, 1, fibArt); // no error checking, because filesize was already checked |
break; |
} |
char szBitmapFilename[MAX_FILE]; |
if (iCopyNumber == 1) { |
sprintf(szBitmapFilename, "%s.bmp", sanitize_filename(peh.name)); |
} else { |
sprintf(szBitmapFilename, "%s__%d.bmp", sanitize_filename(peh.name), iCopyNumber); |
} |
if (strlen(szDestFolder) > 0) { |
char szAbsoluteBitmapFilename[MAX_FILE]; |
sprintf(szAbsoluteBitmapFilename, "%s/%s", szDestFolder, szBitmapFilename); |
FILE* fobBitmap = fopen(szAbsoluteBitmapFilename, "wb"); |
if (!fobBitmap) { |
fprintf(stderr, "FATAL: Cannot open %s for writing\n", szAbsoluteBitmapFilename); |
FAIL_CONTINUE; |
} |
ipe16_write_bmp(fobBitmap, ph.width, ph.height, imagedata, imagedata_len, ct); |
fclose(fobBitmap); |
} |
if (fotIndex) { |
// We require this index file for 2 reasons |
// 1. Our packer tool can then know what to pack |
// 2. The packer tool can know which picture would have a palette appended and which one does not |
// The index file won't be written in simulation mode (when no output directory is defined) |
fprintf(fotIndex, "%c %c %s %s\n", peh.paletteType, ph.compressionType, peh.name, szBitmapFilename); |
} |
if (verbosity >= 1) { |
fprintf(stdout, "%c %c %s %s\n", peh.paletteType, ph.compressionType, peh.name, szBitmapFilename); |
} |
free(imagedata); |
} else if ((compressionType == PIP_COMPRESSIONTYPE_LZW) || (compressionType == PIP_COMPRESSIONTYPE_NONE)) { |
PipPictureHeader ph; |
if (fread(&ph, sizeof(ph), 1, fibArt) != 1) { |
fprintf(stderr, "ERROR: Cannot read PipPictureHeader of %s\n", peh.name); |
FAIL_CONTINUE; |
} |
size_t imagedata_len = ph.width * ph.height; |
unsigned char* imagedata = (unsigned char*)malloc(imagedata_len); |
Ipe16ColorTable ct; |
if (peh.paletteType == IPE16_PALETTETYPE_ATTACHED) { |
if ((fseek(fibArt, peh.offset+peh.size-sizeof(ct), SEEK_SET) != 0) || |
(fread(&ct, sizeof(ct), 1, fibArt) != 1) || |
(fseek(fibArt, peh.offset+sizeof(ph), SEEK_SET) != 0)) { |
fprintf(stderr, "ERROR: Cannot read palette of %s\n", peh.name); |
FAIL_CONTINUE; |
} |
} else if (peh.paletteType == IPE16_PALETTETYPE_PARENT) { |
ipe16_generate_gray_table(&ct); |
} else { |
fprintf(stderr, "ERROR: Unknown palette type 0x%x at %s\n", peh.paletteType, peh.name); |
FAIL_CONTINUE; |
} |
unsigned int bytes_written, expected_uncompressed_len; |
switch (ph.compressionType) { |
case PIP_COMPRESSIONTYPE_LZW: |
if (!lzwDecoder) lzwDecoder = new_ipe16lzw_decoder(); |
bytes_written = ipe16lzw_decode(fibArt, lzwDecoder, imagedata, imagedata_len); |
if (bytes_written < 0) { |
fprintf(stderr, "ERROR: LZW decompression error at %s\n", peh.name); |
FAIL_CONTINUE; |
} |
if (bytes_written != imagedata_len) { |
fprintf(stderr, "ERROR: Image dimensions and decompressed data size does not match for %s\n", peh.name); |
FAIL_CONTINUE; |
} |
break; |
case PIP_COMPRESSIONTYPE_NONE: |
expected_uncompressed_len = imagedata_len; |
if (peh.paletteType == IPE16_PALETTETYPE_ATTACHED) expected_uncompressed_len += sizeof(ct); |
expected_uncompressed_len += sizeof(ph.compressionType)+sizeof(ph.offsetX)+sizeof(ph.offsetY)+sizeof(ph.width)+sizeof(ph.height); |
if (expected_uncompressed_len != peh.size) { |
fprintf(stderr, "ERROR: Image dimensions/palette (%d) and defined memory size (%d) does not match for %s\n", expected_uncompressed_len, peh.size, peh.name); |
FAIL_CONTINUE; |
} |
fread(imagedata, imagedata_len, 1, fibArt); // no error checking, because filesize was already checked |
break; |
} |
char szBitmapFilename[MAX_FILE]; |
if (iCopyNumber == 1) { |
sprintf(szBitmapFilename, "%s.bmp", sanitize_filename(peh.name)); |
} else { |
sprintf(szBitmapFilename, "%s__%d.bmp", sanitize_filename(peh.name), iCopyNumber); |
} |
if (strlen(szDestFolder) > 0) { |
char szAbsoluteBitmapFilename[MAX_FILE]; |
sprintf(szAbsoluteBitmapFilename, "%s/%s", szDestFolder, szBitmapFilename); |
FILE* fobBitmap = fopen(szAbsoluteBitmapFilename, "wb"); |
if (!fobBitmap) { |
fprintf(stderr, "FATAL: Cannot open %s for writing\n", szAbsoluteBitmapFilename); |
FAIL_CONTINUE; |
} |
ipe16_write_bmp(fobBitmap, ph.width, ph.height, imagedata, imagedata_len, ct); |
fclose(fobBitmap); |
} |
if (fotIndex) { |
// We require this index file for 2 reasons |
// 1. Our packer tool can then know what to pack |
// 2. The packer tool can know which picture would have a palette appended and which one does not |
// The index file won't be written in simulation mode (when no output directory is defined) |
fprintf(fotIndex, "%c %c %s %s %d %d\n", peh.paletteType, ph.compressionType, peh.name, szBitmapFilename, ph.offsetX, ph.offsetY); |
} |
if (verbosity >= 1) { |
fprintf(stdout, "%c %c %s %s %d %d\n", peh.paletteType, ph.compressionType, peh.name, szBitmapFilename, ph.offsetX, ph.offsetY); |
} |
free(imagedata); |
} else { |
fprintf(stderr, "ERROR: Unknown compression type 0x%x at %s\n", compressionType, peh.name); |
FAIL_CONTINUE; |
} |
fseek(fibArt, headersPos, SEEK_SET); // we were already there, so we don't need to check for errors |
} |
if (lzwDecoder) del_ipe16lzw_decoder(lzwDecoder); |
if (strlen(szDestFolder) > 0) fclose(fotIndex); |
return bEverythingOK; |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/ipe_artfile_unpacker_ipe16.h |
---|
0,0 → 1,18 |
/** |
* ART file unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Supports: |
* - Blown Away - The Interactive Game by Imagination Pilots |
* - Panic in the Park - The Interactive Game by Imagination Pilots |
* - Where's Waldo? At the Circus (Waldo1) |
* Revision: 2018-02-15 |
**/ |
#ifndef __inc__ipe_artfile_packer_ipe16 |
#define __inc__ipe_artfile_packer_ipe16 |
#include <stdio.h> |
#include <stdbool.h> |
bool ipe16_extract_art_to_folder(FILE* fibArt, const char* szDestFolder, const int verbosity); |
#endif // #ifndef __inc__ipe_artfile_packer_ipe16 |
Property changes: |
Added: svn:mime-type |
+text/x-chdr |
\ No newline at end of property |
/trunk/ipe_artfile_unpacker_ipe32.c |
---|
0,0 → 1,197 |
/** |
* ART file unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Supports: |
* - Where's Waldo? Exploring Geography |
* - Eraser Turnabout by Imagination Pilots |
* - Virtual K'Nex by Imagination Pilots |
* Revision: 2018-02-15 |
**/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <assert.h> |
#include <string.h> |
#include <getopt.h> |
#include "ipe32_bmpexport.h" |
#include "ipe32_artfile.h" |
#include "ipe32_lzw_decoder.h" |
#include "utils.h" |
#define MAX_FILE 256 |
typedef struct tagIpe32ReadPictureResult { |
uint32_t writtenBytes; |
uint32_t numCompressedChunks; |
uint32_t numRawChunks; |
} Ipe32ReadPictureResult; |
Ipe32ReadPictureResult ipe32_read_picture(FILE* hFile, unsigned char* outbuf, const int outputBufLength, bool bVerbose) { |
unsigned char* lzwbuf = (unsigned char*)malloc(0x8000); |
int availableOutputBytes = outputBufLength; |
Ipe32ReadPictureResult res; |
res.numCompressedChunks = 0; |
res.numRawChunks = 0; |
res.writtenBytes = 0; |
Ipe32LZWDecoder *decoder = new_ipe32lzw_decoder(); |
ipe32lzw_init_decoder(decoder); |
if (outputBufLength != 0) { |
int chunkNo = 0; |
do { |
uint16_t len; |
fread(&len, 1, 2, hFile); |
uint16_t writtenBytes; |
if (len < 0x8000) { |
fread(lzwbuf, 1, len, hFile); |
res.numCompressedChunks++; |
if (bVerbose) fprintf(stdout, "Chunk %d (compressed, length: %d) ...\n", chunkNo, len); |
// Requirement 1: Each chunk (except the last one) MUST have 0x3FFE of uncompressed data |
uint16_t expectedOutputSize = availableOutputBytes > 0x3FFE ? 0x3FFE : availableOutputBytes; |
// Requirement 2: The size of the uncompressed data must not exceed the size of the compressed data |
size_t maxReadBytes = expectedOutputSize; |
writtenBytes = ipe32lzw_decode(decoder, outbuf, outputBufLength, lzwbuf, maxReadBytes); // returns bytes written, or -1 |
if (writtenBytes == -1) { |
fprintf(stderr, "ERROR: Fatal error during decompression of chunk %d!\n", chunkNo); |
break; |
} |
if (writtenBytes != expectedOutputSize) { |
fprintf(stderr, "ERROR: Chunk %d decompressed %d bytes, but %d bytes are expected!\n", chunkNo, writtenBytes, expectedOutputSize); |
break; |
} |
} else { |
len &= 0x7FFF; |
res.numRawChunks++; |
if (bVerbose) fprintf(stdout, "Chunk %d (raw, length: %d) ...\n", chunkNo, len); |
fread(outbuf, 1, len, hFile); |
writtenBytes = len; |
} |
outbuf += writtenBytes; |
availableOutputBytes -= writtenBytes; |
chunkNo++; |
} while (availableOutputBytes != 0); |
} |
ipe32lzw_free_decoder(decoder); |
free(lzwbuf); |
res.writtenBytes = outputBufLength-availableOutputBytes; |
return res; |
} |
bool ipe32_extract_art_to_folder(FILE* fibArt, const char* szDestFolder, const int verbosity) { |
bool bEverythingOK = true; |
fseek(fibArt, 0, SEEK_SET); |
Ipe32FileHeader efh; |
if (fread(&efh, sizeof(efh), 1, fibArt) != 1) { |
fprintf(stderr, "FATAL: Cannot read Ipe32FileHeader. It is probably not an art file.\n"); |
return false; |
} |
// Check if the super header is correct |
if ((memcmp(efh.magic, IPE32_MAGIC_ART, 8) != 0) || (efh.reserved != 0)) { |
fprintf(stderr, "FATAL: Something does not seem to be correct with this art file's header. It is probably not an art file.\n"); |
return false; |
} |
FILE* fotIndex = NULL; |
if (strlen(szDestFolder) > 0) { |
char szIndexFilename[MAX_FILE]; |
sprintf(szIndexFilename, "%s/index.txt", szDestFolder); |
fotIndex = fopen(szIndexFilename, "wt"); |
if (!fotIndex) { |
fprintf(stderr, "FATAL: Cannot open %s for writing\n", szIndexFilename); |
return false; |
} |
} |
const int numPictures = efh.totalHeaderSize/sizeof(efh) - 1; |
char knownNames[numPictures][IPE32_NAME_SIZE]; |
memset(knownNames, 0, numPictures*IPE32_NAME_SIZE); |
int iPicNo; |
for (iPicNo=0; iPicNo<numPictures; ++iPicNo) { |
Ipe32PictureEntryHeader peh; |
if (fread(&peh, sizeof(peh), 1, fibArt) != 1) { |
fprintf(stderr, "FATAL: Cannot read Ipe32PictureEntryHeader.\n"); |
return false; |
} |
char szName[IPE32_NAME_SIZE+1]={0}; |
memcpy(szName, peh.name, IPE32_NAME_SIZE); |
// Begin duplicate check |
// In ERASER, there are a few pictures which have the same identifier, in the same ART file! |
memcpy(&knownNames[iPicNo][0], peh.name, IPE32_NAME_SIZE); |
int iCopyNumber = 0; |
int j; |
for (j=0; j<=iPicNo; ++j) { |
if (memcmp(&knownNames[j][0], peh.name, IPE32_NAME_SIZE) == 0) ++iCopyNumber; |
} |
assert(iCopyNumber > 0); |
// End duplicate check |
if (verbosity >= 2) fprintf(stdout, "Extracting %s (expected file size: %d bytes) ...\n", szName, peh.uncompressedSize); |
size_t headersPos = ftell(fibArt); |
#define FAIL_CONTINUE { bEverythingOK = false; fseek(fibArt, headersPos, SEEK_SET); continue; } |
if (fseek(fibArt, peh.offset, SEEK_SET) != 0) { |
fprintf(stderr, "ERROR: Error jumping to offset defined for %s\n", szName); |
FAIL_CONTINUE; |
} |
int outputBufLen = peh.uncompressedSize; |
unsigned char* outputBuf = (unsigned char*)malloc(outputBufLen); |
char szBitmapFilename[MAX_FILE]; |
if (iCopyNumber == 1) { |
sprintf(szBitmapFilename, "%s.bmp", sanitize_filename(szName)); |
} else { |
sprintf(szBitmapFilename, "%s__%d.bmp", sanitize_filename(szName), iCopyNumber); |
} |
Ipe32ReadPictureResult res = ipe32_read_picture(fibArt, outputBuf, outputBufLen, verbosity >= 2); |
if (res.writtenBytes != outputBufLen) { |
fprintf(stderr, "FATAL: Error reading picture %s (compression failure?)\n", szName); |
FAIL_CONTINUE; |
} |
if (strlen(szDestFolder) > 0) { |
char szAbsoluteBitmapFilename[MAX_FILE]; |
sprintf(szAbsoluteBitmapFilename, "%s/%s", szDestFolder, szBitmapFilename); |
FILE* fobBitmap = fopen(szAbsoluteBitmapFilename, "wb"); |
if (!fobBitmap) { |
fprintf(stderr, "FATAL: Cannot open %s for writing\n", szAbsoluteBitmapFilename); |
FAIL_CONTINUE; |
} |
ipe32_write_bmp(fobBitmap, outputBuf, outputBufLen); |
fclose(fobBitmap); |
} |
free(outputBuf); |
if (fotIndex) { |
// We require this index file so that our packer tool can know what to pack |
// The index file won't be written in simulation mode (when no output directory is defined) |
fprintf(fotIndex, "%s %d(C) %d(R) %s\n", szName, res.numCompressedChunks, res.numRawChunks, szBitmapFilename); |
} |
if (verbosity >= 1) { |
fprintf(stdout, "%s %d(C) %d(R) %s\n", szName, res.numCompressedChunks, res.numRawChunks, szBitmapFilename); |
} |
fseek(fibArt, headersPos, SEEK_SET); // we were already there, so we don't need to check for errors |
} |
if (strlen(szDestFolder) > 0) fclose(fotIndex); |
return bEverythingOK; |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/ipe_artfile_unpacker_ipe32.h |
---|
0,0 → 1,18 |
/** |
* ART file unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
* Supports: |
* - Where's Waldo? Exploring Geography |
* - Eraser Turnabout by Imagination Pilots |
* - Virtual K'Nex by Imagination Pilots |
* Revision: 2018-02-15 |
**/ |
#ifndef __inc__ipe_artfile_unpacker_ipe32 |
#define __inc__ipe_artfile_unpacker_ipe32 |
#include <stdio.h> |
#include <stdbool.h> |
bool ipe32_extract_art_to_folder(FILE* fibArt, const char* szDestFolder, const int verbosity); |
#endif // #ifndef __inc__ipe_artfile_packer_ipe32 |
Property changes: |
Added: svn:mime-type |
+text/x-chdr |
\ No newline at end of property |
/trunk/stable.tar.gz |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/gzip |
Property changes: |
Added: svn:mime-type |
+application/gzip |
\ No newline at end of property |
/trunk/test/ba_test/MENU.bmp |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = image/x-ms-bmp |
Property changes: |
Added: svn:mime-type |
+image/x-ms-bmp |
\ No newline at end of property |
/trunk/test/ba_test/index.txt |
---|
0,0 → 1,0 |
X P MENU MENU.bmp |
Property changes: |
Added: svn:mime-type |
+text/plain |
\ No newline at end of property |
/trunk/test/eraser_test/CHRBDOSS.bmp |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = image/x-ms-bmp |
Property changes: |
Added: svn:mime-type |
+image/x-ms-bmp |
\ No newline at end of property |
/trunk/test/eraser_test/index.txt |
---|
0,0 → 1,0 |
CHRBDOSS 19(C) 0(R) CHRBDOSS.bmp |
Property changes: |
Added: svn:mime-type |
+text/plain |
\ No newline at end of property |
/trunk/test/pip_test/CCES2S.bmp |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = image/x-ms-bmp |
Property changes: |
Added: svn:mime-type |
+image/x-ms-bmp |
\ No newline at end of property |
/trunk/test/pip_test/index.txt |
---|
0,0 → 1,0 |
X Q CCES2S CCES2S.bmp 0 0 |
Property changes: |
Added: svn:mime-type |
+text/plain |
\ No newline at end of property |
/trunk/test/test.sh |
---|
0,0 → 1,72 |
#!/bin/bash |
DIR=$( dirname "$0" ) |
cd "$DIR" |
if [ -d out_test ]; then |
rm -Rf out_test |
fi |
if [ -f eraser_test.art ]; then |
rm -f eraser_test.art |
fi |
# --- |
if [ -f ba_test.art ]; then |
rm -f ba_test.art |
fi |
../ipe_artfile_packer -v -i ba_test -o ba_test.art -t ba |
if [ -f ba_test.art ]; then |
mkdir out_test |
../ipe_artfile_unpacker -v -i ba_test.art -o out_test |
fi |
diff ba_test/MENU.bmp out_test/MENU.bmp |
RES=$? |
#if [ $RES -ne 0 ]; then |
# exit 1 |
#fi |
echo "DIFF Result (BA): $RES" |
if [ -d out_test ]; then |
rm -Rf out_test |
fi |
if [ -f ba_test.art ]; then |
rm -f ba_test.art |
fi |
echo "------------------------" |
../ipe_artfile_packer -v -i pip_test -o pip_test.art -t pip |
if [ -f pip_test.art ]; then |
mkdir out_test |
../ipe_artfile_unpacker -v -i pip_test.art -o out_test |
fi |
diff pip_test/CCES2S.bmp out_test/CCES2S.bmp |
RES=$? |
#if [ $RES -ne 0 ]; then |
# exit |
#fi |
echo "DIFF Result (PiP): $RES" |
if [ -d out_test ]; then |
rm -Rf out_test |
fi |
if [ -f pip_test.art ]; then |
rm -f pip_test.art |
fi |
echo "------------------------" |
../ipe_artfile_packer -v -i eraser_test -o eraser_test.art -t eraser |
if [ -f eraser_test.art ]; then |
mkdir out_test |
../ipe_artfile_unpacker -v -i eraser_test.art -o out_test |
fi |
diff eraser_test/CHRBDOSS.bmp out_test/CHRBDOSS.bmp |
RES=$? |
#if [ $RES -ne 0 ]; then |
# exit |
#fi |
echo "DIFF Result (Eraser): $RES" |
if [ -d out_test ]; then |
rm -Rf out_test |
fi |
if [ -f eraser_test.art ]; then |
rm -f eraser_test.art |
fi |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
Added: svn:mime-type |
+text/x-sh |
\ No newline at end of property |
/trunk/test_h/INFO |
---|
0,0 → 1,2 |
These tests test if the header files can be compiled standalone |
/trunk/test_h/test.sh |
---|
0,0 → 1,25 |
#!/bin/bash |
DIR=$( dirname "$0" ) |
cd "$DIR" |
gcc --std=c99 test_bitmap.c |
gcc --std=c99 test_utils.c |
gcc --std=c99 test_ipe16_artfile.c |
gcc --std=c99 test_ipe16_bmpexport.c |
gcc --std=c99 test_ipe16_bmpimport.c |
gcc --std=c99 test_ipe16_lzw_encoder.c |
gcc --std=c99 test_ipe16_lzw_decoder.c |
gcc --std=c99 test_ipe32_artfile.c |
gcc --std=c99 test_ipe32_bmpexport.c |
gcc --std=c99 test_ipe32_bmpimport.c |
gcc --std=c99 test_ipe32_lzw_encoder.c |
gcc --std=c99 test_ipe32_lzw_decoder.c |
gcc --std=c99 test_ipe_artfile_packer_ipe16_ba.c |
gcc --std=c99 test_ipe_artfile_packer_ipe16_pip.c |
gcc --std=c99 test_ipe_artfile_packer_ipe32.c |
gcc --std=c99 test_ipe_artfile_unpacker_ipe16.c |
gcc --std=c99 test_ipe_artfile_unpacker_ipe32.c |
rm a.out |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
Added: svn:mime-type |
+text/x-sh |
\ No newline at end of property |
/trunk/test_h/test_bitmap.c |
---|
0,0 → 1,5 |
#include "../bitmap.h" |
int main(int argc, char *argv[]) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/test_h/test_ipe16_artfile.c |
---|
0,0 → 1,5 |
#include "../ipe16_artfile.h" |
int main(int argc, char *argv[]) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/test_h/test_ipe16_bmpexport.c |
---|
0,0 → 1,5 |
#include "../ipe16_bmpexport.h" |
int main(int argc, char *argv[]) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/test_h/test_ipe16_bmpimport.c |
---|
0,0 → 1,5 |
#include "../ipe16_bmpimport.h" |
int main(int argc, char *argv[]) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/test_h/test_ipe16_lzw_decoder.c |
---|
0,0 → 1,5 |
#include "../ipe16_lzw_decoder.h" |
int main(int argc, char *argv[]) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/test_h/test_ipe16_lzw_encoder.c |
---|
0,0 → 1,5 |
#include "../ipe16_lzw_encoder.h" |
int main(int argc, char *argv[]) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/test_h/test_ipe32_artfile.c |
---|
0,0 → 1,5 |
#include "../ipe32_artfile.h" |
int main(int argc, char *argv[]) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/test_h/test_ipe32_bmpexport.c |
---|
0,0 → 1,5 |
#include "../ipe32_bmpexport.h" |
int main(int argc, char *argv[]) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/test_h/test_ipe32_bmpimport.c |
---|
0,0 → 1,5 |
#include "../ipe32_bmpimport.h" |
int main(int argc, char *argv[]) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/test_h/test_ipe32_lzw_decoder.c |
---|
0,0 → 1,5 |
#include "../ipe32_lzw_decoder.h" |
int main(int argc, char *argv[]) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/test_h/test_ipe32_lzw_encoder.c |
---|
0,0 → 1,5 |
#include "../ipe32_lzw_encoder.h" |
int main(int argc, char *argv[]) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/test_h/test_ipe_artfile_packer_ipe16_ba.c |
---|
0,0 → 1,5 |
#include "../ipe_artfile_packer_ipe16_ba.h" |
int main(int argc, char *argv[]) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/test_h/test_ipe_artfile_packer_ipe16_pip.c |
---|
0,0 → 1,5 |
#include "../ipe_artfile_packer_ipe16_pip.h" |
int main(int argc, char *argv[]) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/test_h/test_ipe_artfile_packer_ipe32.c |
---|
0,0 → 1,5 |
#include "../ipe_artfile_packer_ipe32.h" |
int main(int argc, char *argv[]) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/test_h/test_ipe_artfile_unpacker_ipe16.c |
---|
0,0 → 1,5 |
#include "../ipe_artfile_unpacker_ipe16.h" |
int main(int argc, char *argv[]) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/test_h/test_ipe_artfile_unpacker_ipe32.c |
---|
0,0 → 1,5 |
#include "../ipe_artfile_unpacker_ipe32.h" |
int main(int argc, char *argv[]) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/test_h/test_utils.c |
---|
0,0 → 1,5 |
#include "../utils.h" |
int main(int argc, char *argv[]) { |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/utils.c |
---|
0,0 → 1,33 |
#include <stdlib.h> |
#include <stdio.h> |
#include "utils.h" |
size_t file_size(FILE* fp) { |
size_t pos = ftell(fp); |
fseek(fp, 0, SEEK_END); |
size_t len = ftell(fp); |
fseek(fp, pos, SEEK_SET); |
return len; |
} |
char* sanitize_filename(char* picname) { |
// Remove invalid windows characters |
// TODO: not yet implemented. not necessary for the regular ART files, though |
return picname; |
} |
void* app_zero_alloc(long bytes) { |
char* ptr = (char*)malloc(bytes); |
int i; |
for (i=0; i<bytes; ++i) ptr[i] = 0; |
return (void*)ptr; |
} |
unsigned char read_byte(FILE *file) { |
int ch = getc(file); |
if (ch == EOF) |
ch = 0; |
return ch; |
} |
Property changes: |
Added: svn:mime-type |
+text/x-csrc |
\ No newline at end of property |
/trunk/utils.h |
---|
0,0 → 1,12 |
#ifndef __inc__utils |
#define __inc__utils |
#include <stdio.h> |
size_t file_size(FILE* fp); |
char* sanitize_filename(char* picname); |
void* app_zero_alloc(long bytes); |
unsigned char read_byte(FILE *file); |
#endif // #ifndef __inc__utils |
Property changes: |
Added: svn:mime-type |
+text/x-chdr |
\ No newline at end of property |
/trunk/variable_prefixes.txt |
---|
0,0 → 1,7 |
My variable prefixes: |
fit = text file input handle ("rt") |
fib = binary file input handle ("rb") |
fot = text file output handle ("ot") |
fob = binary file output handle ("ob") |
Property changes: |
Added: svn:mime-type |
+text/plain |
\ No newline at end of property |