Rev 2 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2 | Rev 5 | ||
---|---|---|---|
1 | /** |
1 | /** |
2 | * ART file unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
2 | * ART file unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018 |
3 | * Supports: |
3 | * Supports: |
4 | * - Blown Away - The Interactive Game by Imagination Pilots |
4 | * - Blown Away - The Interactive Game by Imagination Pilots |
5 | * - Panic in the Park - The Interactive Game by Imagination Pilots |
5 | * - Panic in the Park - The Interactive Game by Imagination Pilots |
6 | * - Where's Waldo? At the Circus (Waldo1) |
6 | * - Where's Waldo? At the Circus (Waldo1) |
7 | * Revision: 2018-02-15 |
7 | * Revision: 2018-02-15 |
8 | **/ |
8 | **/ |
9 | 9 | ||
10 | #include <stdio.h> |
10 | #include <stdio.h> |
11 | #include <stdlib.h> |
11 | #include <stdlib.h> |
12 | #include <assert.h> |
12 | #include <assert.h> |
13 | #include <string.h> |
13 | #include <string.h> |
14 | #include <getopt.h> |
14 | #include <getopt.h> |
15 | 15 | ||
16 | #include "ipe16_bmpexport.h" |
16 | #include "ipe16_bmpexport.h" |
17 | #include "ipe16_artfile.h" |
17 | #include "ipe16_artfile.h" |
18 | #include "ipe16_lzw_decoder.h" |
18 | #include "ipe16_lzw_decoder.h" |
19 | 19 | ||
20 | #include "utils.h" |
20 | #include "utils.h" |
21 | 21 | ||
22 | #define MAX_FILE 256 |
22 | #define MAX_FILE 256 |
23 | 23 | ||
24 | void ipe16_generate_gray_table(Ipe16ColorTable *ct) { |
24 | void ipe16_generate_gray_table(Ipe16ColorTable *ct) { |
25 | int i; |
25 | int i; |
26 | for (i=0; i<=0xFF; ++i) { |
26 | for (i=0; i<=0xFF; ++i) { |
27 | ct->colors[i].r = i; |
27 | ct->colors[i].r = i; |
28 | ct->colors[i].g = i; |
28 | ct->colors[i].g = i; |
29 | ct->colors[i].b = i; |
29 | ct->colors[i].b = i; |
30 | } |
30 | } |
31 | } |
31 | } |
32 | 32 | ||
33 | bool ipe16_extract_art_to_folder(FILE* fibArt, const char* szDestFolder, const int verbosity) { |
33 | bool ipe16_extract_art_to_folder(FILE* fibArt, const char* szDestFolder, const int verbosity) { |
34 | bool bEverythingOK = true; |
34 | bool bEverythingOK = true; |
35 | 35 | ||
36 | fseek(fibArt, 0, SEEK_SET); |
36 | fseek(fibArt, 0, SEEK_SET); |
37 | 37 | ||
38 | Ipe16FileHeader bfh; |
38 | Ipe16FileHeader bfh; |
39 | if (fread(&bfh, sizeof(bfh), 1, fibArt) != 1) { |
39 | if (fread(&bfh, sizeof(bfh), 1, fibArt) != 1) { |
40 | fprintf(stderr, "FATAL: Cannot read Ipe16FileHeader. It is probably not an art file.\n"); |
40 | fprintf(stderr, "FATAL: Cannot read Ipe16FileHeader. It is probably not an art file.\n"); |
41 | return false; |
41 | return false; |
42 | } |
42 | } |
43 | 43 | ||
44 | // The "super header" has some different meanings of the fields |
44 | // The "super header" has some different meanings of the fields |
45 | // Name and Type are hardcoded |
45 | // Name and Type are hardcoded |
46 | // startOffset is the number of header entries (including the super header) |
46 | // startOffset is the number of header entries (including the super header) |
47 | // length is the complete file size |
47 | // length is the complete file size |
48 | const size_t fileSize = file_size(fibArt); |
48 | const size_t fileSize = file_size(fibArt); |
49 | if ((strcmp(bfh.magic, IPE16_MAGIC_ART) != 0) || // better memcpy over all 23 bytes? |
49 | if ((strcmp(bfh.magic, IPE16_MAGIC_ART) != 0) || // better memcpy over all 23 bytes? |
50 | (bfh.dummy != IPE16_MAGIC_DUMMY) || |
50 | (bfh.dummy != IPE16_MAGIC_DUMMY) || |
51 | (bfh.totalFileSize != fileSize)) { |
51 | (bfh.totalFileSize != fileSize)) { |
52 | fprintf(stderr, "FATAL: Something does not seem to be correct with this art file's header. It is probably not an art file.\n"); |
52 | fprintf(stderr, "FATAL: Something does not seem to be correct with this art file's header. It is probably not an art file.\n"); |
53 | return false; |
53 | return false; |
54 | } |
54 | } |
55 | 55 | ||
56 | Ipe16LZWDecoder* lzwDecoder = NULL; |
56 | Ipe16LZWDecoder* lzwDecoder = NULL; |
57 | 57 | ||
58 | FILE* fotIndex = NULL; |
58 | FILE* fotIndex = NULL; |
59 | if (strlen(szDestFolder) > 0) { |
59 | if (strlen(szDestFolder) > 0) { |
60 | char szIndexFilename[MAX_FILE]; |
60 | char szIndexFilename[MAX_FILE]; |
61 | sprintf(szIndexFilename, "%s/index.txt", szDestFolder); |
61 | sprintf(szIndexFilename, "%s/index.txt", szDestFolder); |
62 | fotIndex = fopen(szIndexFilename, "wt"); |
62 | fotIndex = fopen(szIndexFilename, "wt"); |
63 | if (!fotIndex) { |
63 | if (!fotIndex) { |
64 | fprintf(stderr, "FATAL: Cannot open %s for writing\n", szIndexFilename); |
64 | fprintf(stderr, "FATAL: Cannot open %s for writing\n", szIndexFilename); |
65 | return false; |
65 | return false; |
66 | } |
66 | } |
67 | } |
67 | } |
68 | 68 | ||
69 | const int numPictures = bfh.numHeaderEntries - 1; |
69 | const int numPictures = bfh.numHeaderEntries - 1; |
70 | char knownNames[numPictures][IPE16_NAME_SIZE]; |
70 | char knownNames[numPictures][IPE16_NAME_SIZE]; |
71 | memset(&knownNames[0][0], 0, numPictures*IPE16_NAME_SIZE); |
71 | memset(&knownNames[0][0], 0, numPictures*IPE16_NAME_SIZE); |
72 | int iPicNo; |
72 | int iPicNo; |
73 | for (iPicNo=0; iPicNo<numPictures; ++iPicNo) { |
73 | for (iPicNo=0; iPicNo<numPictures; ++iPicNo) { |
74 | Ipe16PictureEntryHeader peh; |
74 | Ipe16PictureEntryHeader peh; |
75 | if (fread(&peh, sizeof(peh), 1, fibArt) != 1) { |
75 | if (fread(&peh, sizeof(peh), 1, fibArt) != 1) { |
76 | fprintf(stderr, "FATAL: Cannot read Ipe16PictureEntryHeader.\n"); |
76 | fprintf(stderr, "FATAL: Cannot read Ipe16PictureEntryHeader.\n"); |
77 | return false; |
77 | return false; |
78 | } |
78 | } |
79 | 79 | ||
80 | // Begin duplicate check |
80 | // Begin duplicate check |
81 | memcpy(&knownNames[iPicNo][0], peh.name, IPE16_NAME_SIZE); |
81 | memcpy(&knownNames[iPicNo][0], peh.name, IPE16_NAME_SIZE); |
82 | int iCopyNumber = 0; |
82 | int iCopyNumber = 0; |
83 | int j; |
83 | int j; |
84 | for (j=0; j<=iPicNo; ++j) { |
84 | for (j=0; j<=iPicNo; ++j) { |
85 | // TODO: should we rather use strcmp() in IPE16? |
85 | // TODO: should we rather use strcmp() in IPE16? |
86 | if (memcmp(&knownNames[j][0], peh.name, IPE16_NAME_SIZE) == 0) ++iCopyNumber; |
86 | if (memcmp(&knownNames[j][0], peh.name, IPE16_NAME_SIZE) == 0) ++iCopyNumber; |
87 | } |
87 | } |
88 | assert(iCopyNumber > 0); |
88 | assert(iCopyNumber > 0); |
89 | // End duplicate check |
89 | // End duplicate check |
90 | 90 | ||
91 | // in the English version of Blown Away (not the Special Edition), there is a header entry |
91 | // in the English version of Blown Away (not the Special Edition), there is a header entry |
92 | // with the fields seh.name='', peh.paletteType=0x00, seh.offset[end of file], seh.size=0 |
92 | // with the fields seh.name='', peh.paletteType=0x00, seh.offset[end of file], seh.size=0 |
93 | // ignore it |
93 | // ignore it |
94 | if (strlen(peh.name) == 0) continue; |
94 | if (strlen(peh.name) == 0) continue; |
95 | if (peh.size == 0) continue; |
95 | if (peh.size == 0) continue; |
96 | 96 | ||
97 | if (strlen(peh.name) > IPE16_NAME_SIZE-1) { |
97 | if (strlen(peh.name) > IPE16_NAME_SIZE-1) { |
98 | fprintf(stderr, "FATAL: szName at picture %d is breaking the boundaries. The file is probably corrupt.\n", iPicNo); |
98 | fprintf(stderr, "FATAL: szName at picture %d is breaking the boundaries. The file is probably corrupt.\n", iPicNo); |
99 | return false; |
99 | return false; |
100 | } |
100 | } |
101 | 101 | ||
102 | size_t headersPos = ftell(fibArt); |
102 | size_t headersPos = ftell(fibArt); |
103 | #define FAIL_CONTINUE { bEverythingOK = false; fseek(fibArt, headersPos, SEEK_SET); continue; } |
103 | #define FAIL_CONTINUE { bEverythingOK = false; fseek(fibArt, headersPos, SEEK_SET); continue; } |
104 | 104 | ||
105 | if (fseek(fibArt, peh.offset, SEEK_SET) != 0) { |
105 | if (fseek(fibArt, peh.offset, SEEK_SET) != 0) { |
106 | fprintf(stderr, "ERROR: Error jumping to offset defined for %s\n", peh.name); |
106 | fprintf(stderr, "ERROR: Error jumping to offset defined for %s\n", peh.name); |
107 | FAIL_CONTINUE; |
107 | FAIL_CONTINUE; |
108 | } |
108 | } |
109 | 109 | ||
110 | if (peh.offset+peh.size > fileSize) { |
110 | if (peh.offset+peh.size > fileSize) { |
111 | fprintf(stderr, "ERROR: Defined size of %s exceeds file size\n", peh.name); |
111 | fprintf(stderr, "ERROR: Defined size of %s exceeds file size\n", peh.name); |
112 | FAIL_CONTINUE; |
112 | FAIL_CONTINUE; |
113 | } |
113 | } |
114 | 114 | ||
115 | unsigned char compressionType; |
115 | unsigned char compressionType; |
116 | int bakPos = ftell(fibArt); |
116 | int bakPos = ftell(fibArt); |
117 | fread(&compressionType, sizeof(compressionType), 1, fibArt); |
117 | fread(&compressionType, sizeof(compressionType), 1, fibArt); |
118 | fseek(fibArt, bakPos, SEEK_SET); |
118 | fseek(fibArt, bakPos, SEEK_SET); |
119 | 119 | ||
120 | if ((compressionType == BA_COMPRESSIONTYPE_LZW) || (compressionType == BA_COMPRESSIONTYPE_NONE)) { |
120 | if ((compressionType == BA_COMPRESSIONTYPE_LZW) || (compressionType == BA_COMPRESSIONTYPE_NONE)) { |
121 | BAPictureHeader ph; |
121 | BAPictureHeader ph; |
122 | if (fread(&ph, sizeof(ph), 1, fibArt) != 1) { |
122 | if (fread(&ph, sizeof(ph), 1, fibArt) != 1) { |
123 | fprintf(stderr, "ERROR: Cannot read BAPictureHeader of %s\n", peh.name); |
123 | fprintf(stderr, "ERROR: Cannot read BAPictureHeader of %s\n", peh.name); |
124 | FAIL_CONTINUE; |
124 | FAIL_CONTINUE; |
125 | } |
125 | } |
126 | 126 | ||
127 | size_t imagedata_len = ph.width * ph.height; |
127 | size_t imagedata_len = ph.width * ph.height; |
128 | unsigned char* imagedata = (unsigned char*)malloc(imagedata_len); |
128 | unsigned char* imagedata = (unsigned char*)malloc(imagedata_len); |
129 | 129 | ||
130 | Ipe16ColorTable ct; |
130 | Ipe16ColorTable ct; |
131 | if (peh.paletteType == IPE16_PALETTETYPE_ATTACHED) { |
131 | if (peh.paletteType == IPE16_PALETTETYPE_ATTACHED) { |
132 | if ((fseek(fibArt, peh.offset+peh.size-sizeof(ct), SEEK_SET) != 0) || |
132 | if ((fseek(fibArt, peh.offset+peh.size-sizeof(ct), SEEK_SET) != 0) || |
133 | (fread(&ct, sizeof(ct), 1, fibArt) != 1) || |
133 | (fread(&ct, sizeof(ct), 1, fibArt) != 1) || |
134 | (fseek(fibArt, peh.offset+sizeof(ph), SEEK_SET) != 0)) { |
134 | (fseek(fibArt, peh.offset+sizeof(ph), SEEK_SET) != 0)) { |
135 | fprintf(stderr, "ERROR: Cannot read palette of %s\n", peh.name); |
135 | fprintf(stderr, "ERROR: Cannot read palette of %s\n", peh.name); |
136 | FAIL_CONTINUE; |
136 | FAIL_CONTINUE; |
137 | } |
137 | } |
138 | } else if (peh.paletteType == IPE16_PALETTETYPE_PARENT) { |
138 | } else if (peh.paletteType == IPE16_PALETTETYPE_PARENT) { |
139 | ipe16_generate_gray_table(&ct); |
139 | ipe16_generate_gray_table(&ct); |
140 | } else { |
140 | } else { |
141 | fprintf(stderr, "ERROR: Unknown palette type 0x%x at %s\n", peh.paletteType, peh.name); |
141 | fprintf(stderr, "ERROR: Unknown palette type 0x%x at %s\n", peh.paletteType, peh.name); |
142 | FAIL_CONTINUE; |
142 | FAIL_CONTINUE; |
143 | } |
143 | } |
144 | 144 | ||
145 | unsigned int bytes_written, expected_uncompressed_len; |
145 | unsigned int bytes_written, expected_uncompressed_len; |
146 | switch (ph.compressionType) { |
146 | switch (ph.compressionType) { |
147 | case BA_COMPRESSIONTYPE_LZW: |
147 | case BA_COMPRESSIONTYPE_LZW: |
148 | if (!lzwDecoder) lzwDecoder = new_ipe16lzw_decoder(); |
148 | if (!lzwDecoder) lzwDecoder = new_ipe16lzw_decoder(); |
149 | bytes_written = ipe16lzw_decode(fibArt, lzwDecoder, imagedata, imagedata_len); |
149 | bytes_written = ipe16lzw_decode(fibArt, lzwDecoder, imagedata, imagedata_len); |
150 | if (bytes_written < 0) { |
150 | if (bytes_written < 0) { |
151 | fprintf(stderr, "ERROR: LZW decompression error at %s\n", peh.name); |
151 | fprintf(stderr, "ERROR: LZW decompression error at %s\n", peh.name); |
152 | FAIL_CONTINUE; |
152 | FAIL_CONTINUE; |
153 | } |
153 | } |
154 | if (bytes_written != imagedata_len) { |
154 | if (bytes_written != imagedata_len) { |
155 | fprintf(stderr, "ERROR: Image dimensions and decompressed data size does not match for %s\n", peh.name); |
155 | fprintf(stderr, "ERROR: Image dimensions and decompressed data size does not match for %s\n", peh.name); |
156 | FAIL_CONTINUE; |
156 | FAIL_CONTINUE; |
157 | } |
157 | } |
158 | 158 | ||
159 | break; |
159 | break; |
160 | case BA_COMPRESSIONTYPE_NONE: |
160 | case BA_COMPRESSIONTYPE_NONE: |
161 | expected_uncompressed_len = imagedata_len; |
161 | expected_uncompressed_len = imagedata_len; |
162 | if (peh.paletteType == IPE16_PALETTETYPE_ATTACHED) expected_uncompressed_len += sizeof(ct); |
162 | if (peh.paletteType == IPE16_PALETTETYPE_ATTACHED) expected_uncompressed_len += sizeof(ct); |
163 | expected_uncompressed_len += sizeof(ph.compressionType)+sizeof(ph.width)+sizeof(ph.height); |
163 | expected_uncompressed_len += sizeof(ph.compressionType)+sizeof(ph.width)+sizeof(ph.height); |
164 | if (expected_uncompressed_len != peh.size) { |
164 | if (expected_uncompressed_len != peh.size) { |
165 | 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); |
165 | 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); |
166 | FAIL_CONTINUE; |
166 | FAIL_CONTINUE; |
167 | } |
167 | } |
168 | fread(imagedata, imagedata_len, 1, fibArt); // no error checking, because filesize was already checked |
168 | fread(imagedata, imagedata_len, 1, fibArt); // no error checking, because filesize was already checked |
169 | break; |
169 | break; |
170 | } |
170 | } |
171 | 171 | ||
172 | char szBitmapFilename[MAX_FILE]; |
172 | char szBitmapFilename[MAX_FILE]; |
173 | if (iCopyNumber == 1) { |
173 | if (iCopyNumber == 1) { |
174 | sprintf(szBitmapFilename, "%s.bmp", sanitize_filename(peh.name)); |
174 | sprintf(szBitmapFilename, "%s.bmp", sanitize_filename(peh.name)); |
175 | } else { |
175 | } else { |
176 | sprintf(szBitmapFilename, "%s__%d.bmp", sanitize_filename(peh.name), iCopyNumber); |
176 | sprintf(szBitmapFilename, "%s__%d.bmp", sanitize_filename(peh.name), iCopyNumber); |
177 | } |
177 | } |
178 | 178 | ||
179 | if (strlen(szDestFolder) > 0) { |
179 | if (strlen(szDestFolder) > 0) { |
180 | char szAbsoluteBitmapFilename[MAX_FILE]; |
180 | char szAbsoluteBitmapFilename[MAX_FILE+1]; |
181 | sprintf(szAbsoluteBitmapFilename, "%s/%s", szDestFolder, szBitmapFilename); |
181 | sprintf(szAbsoluteBitmapFilename, "%s/%s", szDestFolder, szBitmapFilename); |
182 | FILE* fobBitmap = fopen(szAbsoluteBitmapFilename, "wb"); |
182 | FILE* fobBitmap = fopen(szAbsoluteBitmapFilename, "wb"); |
183 | if (!fobBitmap) { |
183 | if (!fobBitmap) { |
184 | fprintf(stderr, "FATAL: Cannot open %s for writing\n", szAbsoluteBitmapFilename); |
184 | fprintf(stderr, "FATAL: Cannot open %s for writing\n", szAbsoluteBitmapFilename); |
185 | FAIL_CONTINUE; |
185 | FAIL_CONTINUE; |
186 | } |
186 | } |
187 | ipe16_write_bmp(fobBitmap, ph.width, ph.height, imagedata, imagedata_len, ct); |
187 | ipe16_write_bmp(fobBitmap, ph.width, ph.height, imagedata, imagedata_len, ct); |
188 | fclose(fobBitmap); |
188 | fclose(fobBitmap); |
189 | } |
189 | } |
190 | 190 | ||
191 | if (fotIndex) { |
191 | if (fotIndex) { |
192 | // We require this index file for 2 reasons |
192 | // We require this index file for 2 reasons |
193 | // 1. Our packer tool can then know what to pack |
193 | // 1. Our packer tool can then know what to pack |
194 | // 2. The packer tool can know which picture would have a palette appended and which one does not |
194 | // 2. The packer tool can know which picture would have a palette appended and which one does not |
195 | // The index file won't be written in simulation mode (when no output directory is defined) |
195 | // The index file won't be written in simulation mode (when no output directory is defined) |
196 | fprintf(fotIndex, "%c %c %s %s\n", peh.paletteType, ph.compressionType, peh.name, szBitmapFilename); |
196 | fprintf(fotIndex, "%c %c %s %s\n", peh.paletteType, ph.compressionType, peh.name, szBitmapFilename); |
197 | } |
197 | } |
198 | if (verbosity >= 1) { |
198 | if (verbosity >= 1) { |
199 | fprintf(stdout, "%c %c %s %s\n", peh.paletteType, ph.compressionType, peh.name, szBitmapFilename); |
199 | fprintf(stdout, "%c %c %s %s\n", peh.paletteType, ph.compressionType, peh.name, szBitmapFilename); |
200 | } |
200 | } |
201 | 201 | ||
202 | free(imagedata); |
202 | free(imagedata); |
203 | } else if ((compressionType == PIP_COMPRESSIONTYPE_LZW) || (compressionType == PIP_COMPRESSIONTYPE_NONE)) { |
203 | } else if ((compressionType == PIP_COMPRESSIONTYPE_LZW) || (compressionType == PIP_COMPRESSIONTYPE_NONE)) { |
204 | PipPictureHeader ph; |
204 | PipPictureHeader ph; |
205 | if (fread(&ph, sizeof(ph), 1, fibArt) != 1) { |
205 | if (fread(&ph, sizeof(ph), 1, fibArt) != 1) { |
206 | fprintf(stderr, "ERROR: Cannot read PipPictureHeader of %s\n", peh.name); |
206 | fprintf(stderr, "ERROR: Cannot read PipPictureHeader of %s\n", peh.name); |
207 | FAIL_CONTINUE; |
207 | FAIL_CONTINUE; |
208 | } |
208 | } |
209 | 209 | ||
210 | size_t imagedata_len = ph.width * ph.height; |
210 | size_t imagedata_len = ph.width * ph.height; |
211 | unsigned char* imagedata = (unsigned char*)malloc(imagedata_len); |
211 | unsigned char* imagedata = (unsigned char*)malloc(imagedata_len); |
212 | 212 | ||
213 | Ipe16ColorTable ct; |
213 | Ipe16ColorTable ct; |
214 | if (peh.paletteType == IPE16_PALETTETYPE_ATTACHED) { |
214 | if (peh.paletteType == IPE16_PALETTETYPE_ATTACHED) { |
215 | if ((fseek(fibArt, peh.offset+peh.size-sizeof(ct), SEEK_SET) != 0) || |
215 | if ((fseek(fibArt, peh.offset+peh.size-sizeof(ct), SEEK_SET) != 0) || |
216 | (fread(&ct, sizeof(ct), 1, fibArt) != 1) || |
216 | (fread(&ct, sizeof(ct), 1, fibArt) != 1) || |
217 | (fseek(fibArt, peh.offset+sizeof(ph), SEEK_SET) != 0)) { |
217 | (fseek(fibArt, peh.offset+sizeof(ph), SEEK_SET) != 0)) { |
218 | fprintf(stderr, "ERROR: Cannot read palette of %s\n", peh.name); |
218 | fprintf(stderr, "ERROR: Cannot read palette of %s\n", peh.name); |
219 | FAIL_CONTINUE; |
219 | FAIL_CONTINUE; |
220 | } |
220 | } |
221 | } else if (peh.paletteType == IPE16_PALETTETYPE_PARENT) { |
221 | } else if (peh.paletteType == IPE16_PALETTETYPE_PARENT) { |
222 | ipe16_generate_gray_table(&ct); |
222 | ipe16_generate_gray_table(&ct); |
223 | } else { |
223 | } else { |
224 | fprintf(stderr, "ERROR: Unknown palette type 0x%x at %s\n", peh.paletteType, peh.name); |
224 | fprintf(stderr, "ERROR: Unknown palette type 0x%x at %s\n", peh.paletteType, peh.name); |
225 | FAIL_CONTINUE; |
225 | FAIL_CONTINUE; |
226 | } |
226 | } |
227 | 227 | ||
228 | unsigned int bytes_written, expected_uncompressed_len; |
228 | unsigned int bytes_written, expected_uncompressed_len; |
229 | switch (ph.compressionType) { |
229 | switch (ph.compressionType) { |
230 | case PIP_COMPRESSIONTYPE_LZW: |
230 | case PIP_COMPRESSIONTYPE_LZW: |
231 | if (!lzwDecoder) lzwDecoder = new_ipe16lzw_decoder(); |
231 | if (!lzwDecoder) lzwDecoder = new_ipe16lzw_decoder(); |
232 | bytes_written = ipe16lzw_decode(fibArt, lzwDecoder, imagedata, imagedata_len); |
232 | bytes_written = ipe16lzw_decode(fibArt, lzwDecoder, imagedata, imagedata_len); |
233 | if (bytes_written < 0) { |
233 | if (bytes_written < 0) { |
234 | fprintf(stderr, "ERROR: LZW decompression error at %s\n", peh.name); |
234 | fprintf(stderr, "ERROR: LZW decompression error at %s\n", peh.name); |
235 | FAIL_CONTINUE; |
235 | FAIL_CONTINUE; |
236 | } |
236 | } |
237 | if (bytes_written != imagedata_len) { |
237 | if (bytes_written != imagedata_len) { |
238 | fprintf(stderr, "ERROR: Image dimensions and decompressed data size does not match for %s\n", peh.name); |
238 | fprintf(stderr, "ERROR: Image dimensions and decompressed data size does not match for %s\n", peh.name); |
239 | FAIL_CONTINUE; |
239 | FAIL_CONTINUE; |
240 | } |
240 | } |
241 | 241 | ||
242 | break; |
242 | break; |
243 | case PIP_COMPRESSIONTYPE_NONE: |
243 | case PIP_COMPRESSIONTYPE_NONE: |
244 | expected_uncompressed_len = imagedata_len; |
244 | expected_uncompressed_len = imagedata_len; |
245 | if (peh.paletteType == IPE16_PALETTETYPE_ATTACHED) expected_uncompressed_len += sizeof(ct); |
245 | if (peh.paletteType == IPE16_PALETTETYPE_ATTACHED) expected_uncompressed_len += sizeof(ct); |
246 | expected_uncompressed_len += sizeof(ph.compressionType)+sizeof(ph.offsetX)+sizeof(ph.offsetY)+sizeof(ph.width)+sizeof(ph.height); |
246 | expected_uncompressed_len += sizeof(ph.compressionType)+sizeof(ph.offsetX)+sizeof(ph.offsetY)+sizeof(ph.width)+sizeof(ph.height); |
247 | if (expected_uncompressed_len != peh.size) { |
247 | if (expected_uncompressed_len != peh.size) { |
248 | 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); |
248 | 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); |
249 | FAIL_CONTINUE; |
249 | FAIL_CONTINUE; |
250 | } |
250 | } |
251 | fread(imagedata, imagedata_len, 1, fibArt); // no error checking, because filesize was already checked |
251 | fread(imagedata, imagedata_len, 1, fibArt); // no error checking, because filesize was already checked |
252 | break; |
252 | break; |
253 | } |
253 | } |
254 | 254 | ||
255 | char szBitmapFilename[MAX_FILE]; |
255 | char szBitmapFilename[MAX_FILE]; |
256 | if (iCopyNumber == 1) { |
256 | if (iCopyNumber == 1) { |
257 | sprintf(szBitmapFilename, "%s.bmp", sanitize_filename(peh.name)); |
257 | sprintf(szBitmapFilename, "%s.bmp", sanitize_filename(peh.name)); |
258 | } else { |
258 | } else { |
259 | sprintf(szBitmapFilename, "%s__%d.bmp", sanitize_filename(peh.name), iCopyNumber); |
259 | sprintf(szBitmapFilename, "%s__%d.bmp", sanitize_filename(peh.name), iCopyNumber); |
260 | } |
260 | } |
261 | 261 | ||
262 | if (strlen(szDestFolder) > 0) { |
262 | if (strlen(szDestFolder) > 0) { |
263 | char szAbsoluteBitmapFilename[MAX_FILE]; |
263 | char szAbsoluteBitmapFilename[MAX_FILE+1]; |
264 | sprintf(szAbsoluteBitmapFilename, "%s/%s", szDestFolder, szBitmapFilename); |
264 | sprintf(szAbsoluteBitmapFilename, "%s/%s", szDestFolder, szBitmapFilename); |
265 | FILE* fobBitmap = fopen(szAbsoluteBitmapFilename, "wb"); |
265 | FILE* fobBitmap = fopen(szAbsoluteBitmapFilename, "wb"); |
266 | if (!fobBitmap) { |
266 | if (!fobBitmap) { |
267 | fprintf(stderr, "FATAL: Cannot open %s for writing\n", szAbsoluteBitmapFilename); |
267 | fprintf(stderr, "FATAL: Cannot open %s for writing\n", szAbsoluteBitmapFilename); |
268 | FAIL_CONTINUE; |
268 | FAIL_CONTINUE; |
269 | } |
269 | } |
270 | ipe16_write_bmp(fobBitmap, ph.width, ph.height, imagedata, imagedata_len, ct); |
270 | ipe16_write_bmp(fobBitmap, ph.width, ph.height, imagedata, imagedata_len, ct); |
271 | fclose(fobBitmap); |
271 | fclose(fobBitmap); |
272 | } |
272 | } |
273 | 273 | ||
274 | if (fotIndex) { |
274 | if (fotIndex) { |
275 | // We require this index file for 2 reasons |
275 | // We require this index file for 2 reasons |
276 | // 1. Our packer tool can then know what to pack |
276 | // 1. Our packer tool can then know what to pack |
277 | // 2. The packer tool can know which picture would have a palette appended and which one does not |
277 | // 2. The packer tool can know which picture would have a palette appended and which one does not |
278 | // The index file won't be written in simulation mode (when no output directory is defined) |
278 | // The index file won't be written in simulation mode (when no output directory is defined) |
279 | fprintf(fotIndex, "%c %c %s %s %d %d\n", peh.paletteType, ph.compressionType, peh.name, szBitmapFilename, ph.offsetX, ph.offsetY); |
279 | fprintf(fotIndex, "%c %c %s %s %d %d\n", peh.paletteType, ph.compressionType, peh.name, szBitmapFilename, ph.offsetX, ph.offsetY); |
280 | } |
280 | } |
281 | if (verbosity >= 1) { |
281 | if (verbosity >= 1) { |
282 | fprintf(stdout, "%c %c %s %s %d %d\n", peh.paletteType, ph.compressionType, peh.name, szBitmapFilename, ph.offsetX, ph.offsetY); |
282 | fprintf(stdout, "%c %c %s %s %d %d\n", peh.paletteType, ph.compressionType, peh.name, szBitmapFilename, ph.offsetX, ph.offsetY); |
283 | } |
283 | } |
284 | 284 | ||
285 | free(imagedata); |
285 | free(imagedata); |
286 | } else { |
286 | } else { |
287 | fprintf(stderr, "ERROR: Unknown compression type 0x%x at %s\n", compressionType, peh.name); |
287 | fprintf(stderr, "ERROR: Unknown compression type 0x%x at %s\n", compressionType, peh.name); |
288 | FAIL_CONTINUE; |
288 | FAIL_CONTINUE; |
289 | } |
289 | } |
290 | 290 | ||
291 | fseek(fibArt, headersPos, SEEK_SET); // we were already there, so we don't need to check for errors |
291 | fseek(fibArt, headersPos, SEEK_SET); // we were already there, so we don't need to check for errors |
292 | } |
292 | } |
293 | 293 | ||
294 | if (lzwDecoder) del_ipe16lzw_decoder(lzwDecoder); |
294 | if (lzwDecoder) del_ipe16lzw_decoder(lzwDecoder); |
295 | 295 | ||
296 | if (strlen(szDestFolder) > 0) fclose(fotIndex); |
296 | if (strlen(szDestFolder) > 0) fclose(fotIndex); |
297 | 297 | ||
298 | return bEverythingOK; |
298 | return bEverythingOK; |
299 | } |
299 | } |
300 | 300 |