Subversion Repositories ipe_artfile_utils

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
/**
2
 * ART file packer by Daniel Marschall, ViaThinkSoft (C) 2014-2018
3
 * Supports:
4
 * - Panic in the Park - The Interactive Game by Imagination Pilots
5
 * - Where's Waldo? At the Circus (Waldo1)
6
 * Revision: 2018-02-15
7
 **/
8
 
9
#include <stdio.h>
10
#include <stdlib.h>
11
#include <stdbool.h>
12
#include <string.h>
13
#include <math.h>
14
 
15
#include "ipe_artfile_packer_ipe16_pip.h"
16
#include "ipe16_artfile.h"
17
#include "ipe16_bmpimport.h"
18
#include "ipe16_lzw_encoder.h"
19
 
20
#define MAX_FILE 256
21
 
22
bool pip_pack_art(const char* szSrcFolder, FILE* fobArt, const int verbosity) {
23
        bool bEverythingOK = true;
24
 
25
        char szIndexFilename[MAX_FILE];
26
        sprintf(szIndexFilename, "%s/index.txt", szSrcFolder);
27
        FILE* fitIndex = fopen(szIndexFilename, "rt");
28
        if (!fitIndex) {
29
                fprintf(stderr, "Cannot open %s\n", szIndexFilename);
30
                return false;
31
        }
32
 
33
        #define MAX_LINE 1024
34
        char line[MAX_LINE];
35
        int cItems = 0;
36
        while (fgets(line, sizeof(line), fitIndex)) {
37
                if (strlen(line) == 0) continue;
38
                ++cItems;
39
        }
40
        if (verbosity >= 1) printf("%s contains %d entries\n", szIndexFilename, cItems); // TODO: don't print double /
41
 
42
        Ipe16FileHeader bfh;
43
        memset(&bfh, 0x00, sizeof(bfh));
44
        strcpy(bfh.magic, IPE16_MAGIC_ART);
45
        bfh.dummy = IPE16_MAGIC_DUMMY;
46
        bfh.numHeaderEntries = cItems+1;
47
 
48
        Ipe16PictureEntryHeader peh[cItems];
49
        memset(&peh, 0x00, sizeof(peh));
50
 
51
        PipPictureHeader ph[cItems];
52
        memset(&ph,  0x00, sizeof(ph));
53
 
54
        // We need to write the (still empty) headers, so we can use ftell() to determine the offsets correctly
55
        // These headers are currently just dummies. They will be rewritten after all pictures are processed
56
        fwrite(&bfh, sizeof(bfh), 1, fobArt);
57
        fwrite(&peh, sizeof(peh), 1, fobArt);
58
 
59
        fseek(fitIndex, 0, SEEK_SET);
60
        int curItem = 0;
61
        Ipe16LZWEncoder* lzwEncoder = NULL;
62
        while (fgets(line, sizeof(line), fitIndex)) {
63
                // If something fails, we discard the item, but continue in building the file!
64
                #define FAIL_CONTINUE { memset(&peh[curItem], 0x00, sizeof(peh[curItem])); bEverythingOK=false; continue; }
65
 
66
                const char* szDelimiters = " \t\r\n";
67
                char* szPaletteType     = strtok(&line[0], szDelimiters);
68
                char* szCompressionType = strtok(NULL, szDelimiters);
69
                char* szName            = strtok(NULL, szDelimiters);
70
                char* szFilename        = strtok(NULL, szDelimiters);
71
                char* szOffsetX         = strtok(NULL, szDelimiters);
72
                int iOffsetX            = (szOffsetX != NULL) ? atoi(szOffsetX) : 0;
73
                char* szOffsetY         = strtok(NULL, szDelimiters);
74
                int iOffsetY            = (szOffsetY != NULL) ? atoi(szOffsetY) : 0;
75
 
76
                if (strlen(szPaletteType) != 1) {
77
                        fprintf(stderr, "ERROR: Palette type (argument 1) at line %d is not valid (must be 1 char)\n", curItem+1);
78
                        FAIL_CONTINUE;
79
                }
80
                const char chPaletteType = *szPaletteType;
81
 
82
                if ((chPaletteType != IPE16_PALETTETYPE_ATTACHED) && (chPaletteType != IPE16_PALETTETYPE_PARENT)) {
83
                        fprintf(stderr, "ERROR: Unknown palette type '%c' at line %d\n", chPaletteType, curItem+1);
84
                        FAIL_CONTINUE;
85
                }
86
 
87
                if (strlen(szCompressionType) != 1) {
88
                        fprintf(stderr, "ERROR: Compression type (argument 2) at line %d is not valid (must be 1 char)\n", curItem+1);
89
                        FAIL_CONTINUE;
90
                }
91
                const char chCompressionType = *szCompressionType;
92
 
93
                if (strlen(szName) > IPE16_NAME_SIZE) {
94
                        fprintf(stderr, "ERROR: Name %s is too long (max %d chars allowed)\n", szName, IPE16_NAME_SIZE);
95
                        FAIL_CONTINUE;
96
                }
97
 
98
                strcpy(peh[curItem].name, szName);
99
                peh[curItem].paletteType = chPaletteType;
100
                peh[curItem].offset = ftell(fobArt);
101
                peh[curItem].size = 0; // will be increased later
102
 
103
                if (verbosity >= 1) printf("Process %s at offset %x\n", szName, peh[curItem].offset);
104
 
105
                // Read bitmap
106
 
107
                const bool colorTableExisting = (chPaletteType == IPE16_PALETTETYPE_ATTACHED);
108
 
109
                char szBitmapFilename[MAX_FILE];
110
                sprintf(szBitmapFilename, "%s/%s", szSrcFolder, szFilename);
111
                FILE* fibBitmap = fopen(szBitmapFilename, "rb");
112
                if (!fibBitmap) {
113
                        fprintf(stderr, "ERROR: cannot open '%s'\n", szFilename);
114
                        FAIL_CONTINUE;
115
                }
116
 
117
                Ipe16BmpImportData result={0};
118
                if (!ipe16_bmp_import(fibBitmap, &result)) {
119
                        fprintf(stderr, "Error at %s: %s\n", szFilename, result.error);
120
                        fclose(fibBitmap);
121
                        ipe16_free_bmpimport_result(&result);
122
                        FAIL_CONTINUE;
123
                }
124
 
125
                ph[curItem].compressionType = chCompressionType;
126
                ph[curItem].offsetX = iOffsetX;
127
                ph[curItem].offsetY = iOffsetY;
128
                ph[curItem].width = result.width;
129
                ph[curItem].height = result.height;
130
                fwrite(&ph[curItem], sizeof(ph[curItem]), 1, fobArt);
131
                peh[curItem].size += sizeof(ph[curItem]);
132
 
133
                // Write picture data
134
 
135
                size_t tmpBefore = ftell(fobArt);
136
                if (chCompressionType == PIP_COMPRESSIONTYPE_LZW) {
137
                        if (!lzwEncoder) lzwEncoder = new_ipe16lzw_encoder();
138
                        ipe16lzw_encode(fobArt, lzwEncoder, result.bmpData, result.bmpDataSize);
139
                } else if (chCompressionType == PIP_COMPRESSIONTYPE_NONE) {
140
                        fwrite(result.bmpData, result.bmpDataSize, 1, fobArt);
141
                } else {
142
                        fprintf(stderr, "Unknown compression type '%c' at line %d\n", chCompressionType, curItem+1);
143
                        fclose(fibBitmap);
144
                        ipe16_free_bmpimport_result(&result);
145
                        FAIL_CONTINUE;
146
                }
147
                peh[curItem].size += ftell(fobArt)-tmpBefore;
148
 
149
                if (colorTableExisting) {
150
                        fwrite(result.colorTable, sizeof(*result.colorTable), 1, fobArt);
151
                        peh[curItem].size += sizeof(*result.colorTable);
152
                }
153
 
154
                // Free and continue
155
 
156
                fclose(fibBitmap);
157
                ipe16_free_bmpimport_result(&result);
158
 
159
                ++curItem;
160
        }
161
        if (lzwEncoder) del_ipe16lzw_encoder(lzwEncoder);
162
        fclose(fitIndex);
163
 
164
        bfh.totalFileSize = ftell(fobArt);
165
 
166
        fseek(fobArt, 0, SEEK_SET);
167
        fwrite(&bfh, sizeof(bfh), 1, fobArt);
168
        fwrite(&peh, sizeof(peh), 1, fobArt);
169
 
170
        fclose(fobArt);
171
 
172
        return bEverythingOK;
173
}