1 // -----------------------------------------------------------------------
2
3 // Do a more-portable Endian check
IsBigEndian()4 bool IsBigEndian()
5 {
6 short word = 0x4321;
7 if((*(char *)& word) != 0x21 )
8 return true;
9 else
10 return false;
11 }
12
13 int g_isBigEndian = IsBigEndian();
14
15 // -----------------------------------------------------------------------
16
17 /* file.cc : KANON の圧縮ファイル・PDT ファイル(画像ファイル)の展開の
18 * ためのメソッド
19 * class ARCINFO : 書庫ファイルの中の1つのファイルを扱うクラス
20 * class PDTCONV : PDT ファイルの展開を行う。
21 *
22 */
23
24 /*
25 *
26 * Copyright (C) 2000, 2007- Kazunori Ueno(JAGARL) <jagarl@creator.club.ne.jp>
27 *
28 * This program is free software; you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation; either version 2 of the License, or
31 * (at your option) any later version.
32 *
33 * This program is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 * GNU General Public License for more details.
37 *
38 * You should have received a copy of the GNU General Public License
39 * along with this program; if not, write to the Free Software
40 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
41 *
42 */
43
44 #ifdef HAVE_CONFIG_H
45 # include "config.h"
46 #endif
47
48 #ifdef HAVE_MMAP
49 # ifdef MACOSX
50 # undef HAVE_MMAP
51 # endif /* MACOSX */
52 #endif /* HAVE_MMAP */
53
54 #include <ctype.h>
55 #include <fcntl.h>
56 #ifdef WIN32
57 # include <io.h>
58 #else
59 # include <unistd.h>
60 #endif
61 #include <stdlib.h>
62 #include <stdio.h>
63 #include <sys/types.h>
64 #include <sys/stat.h>
65 #include <vector>
66 #include <algorithm>
67 #if HAVE_MMAP
68 #include<sys/mman.h>
69 #endif /* HAVE_MMAP */
70
71 #ifdef WIN32
72 # include <direct.h>
73 # include "dirent_impl.h"
74 # ifdef MAX_PATH
75 # define PATH_MAX MAX_PATH
76 # else
77 # define PATH_MAX 260
78 # endif
79 #else
80 # include <dirent.h>
81 # ifndef PATH_MAX
82 # define PATH_MAX 1024
83 # endif
84 #endif
85
86 # define NAMLEN(dirent) strlen((dirent)->d_name)
87
88 #include "file.h"
89 #include "endian.hpp"
90
91 #include <set>
92 #include <tuple>
93
94 using namespace std;
95
96 // -----------------------------------------------------------------------
97
operator <(const REGION & rhs) const98 bool GRPCONV::REGION::operator<(const REGION& rhs) const {
99 return
100 std::tie(x1, y1, x2, y2, origin_x, origin_y) <
101 std::tie(rhs.x1, rhs.y1, rhs.x2, rhs.y2, rhs.origin_x, rhs.origin_y);
102 }
103
104 /**********************************************
105 **
106 ** 画像展開系クラスの定義、実装
107 **
108 ***********************************************
109 */
GRPCONV(void)110 GRPCONV::GRPCONV(void) {
111 filename = 0;
112 data = 0;
113 }
~GRPCONV()114 GRPCONV::~GRPCONV() {
115 if (filename) delete[] filename;
116 }
Init(const char * f,const char * d,int dlen,int w,int h,bool is_m)117 void GRPCONV::Init(const char* f, const char* d, int dlen, int w, int h, bool is_m) {
118 if (filename) delete[] filename;
119 if (f == 0) {
120 char* fn = new char[1];
121 fn[0] = 0;
122 filename = fn;
123 } else {
124 char* fn = new char[strlen(f)+1];
125 strcpy(fn,f);
126 filename = fn;
127 }
128
129 data = d;
130 datalen = dlen;
131 width = w;
132 height = h;
133 is_mask = is_m;
134 }
135 class PDTCONV : public GRPCONV {
136 bool Read_PDT10(char* image);
137 bool Read_PDT11(char* image);
138 public:
139 PDTCONV(const char* _inbuf, int inlen, const char* fname);
~PDTCONV()140 ~PDTCONV() {}
141 bool Read(char* image);
142 };
143 class G00CONV : public GRPCONV {
144 void Copy_16bpp(char* image, int x, int y, const char* src, int bpl, int h);
145 void Copy_32bpp(char* image, int x, int y, const char* src, int bpl, int h);
146 bool Read_Type0(char* image);
147 bool Read_Type1(char* image);
148 bool Read_Type2(char* image);
149 public:
150 G00CONV(const char* _inbuf, int _inlen, const char* fname);
~G00CONV()151 ~G00CONV() { }
152 bool Read(char* image);
153 };
154
155 class BMPCONV : public GRPCONV {
156 public:
157 BMPCONV(const char* _inbuf, int _inlen, const char* fname);
~BMPCONV()158 ~BMPCONV() {};
159 bool Read(char* image);
160 };
161
AssignConverter(const char * inbuf,int inlen,const char * fname)162 GRPCONV* GRPCONV::AssignConverter(const char* inbuf, int inlen, const char* fname) {
163 /* ファイルの内容に応じたコンバーターを割り当てる */
164 GRPCONV* conv = 0;
165 if (inlen < 10) return 0; /* invalid file */
166 if (strncmp(inbuf, "PDT10", 5) == 0 || strncmp(inbuf, "PDT11", 5) == 0) { /* PDT10 or PDT11 */
167 conv = new PDTCONV(inbuf, inlen, fname);
168 if (conv->data == 0) { delete conv; conv = 0;}
169 }
170 if (conv == 0 && inbuf[0]=='B' && inbuf[1]=='M' && read_little_endian_int(inbuf+10)==0x36 && read_little_endian_int(inbuf+14) == 0x28) { // Windows BMP
171 conv = new BMPCONV(inbuf, inlen, fname);
172 if (conv->data == 0) { delete conv; conv = 0;}
173 }
174 if (conv == 0 && (inbuf[0] == 0 || inbuf[0] == 1 || inbuf[0] == 2)) { /* G00 */
175 conv = new G00CONV(inbuf, inlen, fname);
176 if (conv->data == 0) { delete conv; conv = 0;}
177 }
178 return conv;
179 }
180
PDTCONV(const char * _inbuf,int _inlen,const char * filename)181 PDTCONV::PDTCONV(const char* _inbuf, int _inlen,const char* filename) {
182 // PDT FILE のヘッダ
183 // +00 'PDT10' (PDT11 は未対応)
184 // +08 ファイルサイズ (無視)
185 // +0C width (ほぼすべて、640)
186 // +10 height(ほぼすべて、480)
187 // +14 (mask の) x 座標 (実際は無視・・・全ファイルで 0 )
188 // +1c (mask の) y座標 (実際は無視 ・・・全ファイルで 0 )
189 // +20 mask が存在すれば、mask へのポインタ
190
191 /* ヘッダチェック */
192 if (_inlen < 0x20) {
193 fprintf(stderr, "Invalid PDT file %s : size is too small\n",filename);
194 return;
195 }
196 if (strncmp(_inbuf, "PDT10", 5) != 0 && strncmp(_inbuf, "PDT11", 5) != 0) {
197 fprintf(stderr, "Invalid PDT file %s : not 'PDT10 / PDT11' file.\n", filename);
198 return;
199 }
200 if (size_t(_inlen) != size_t(read_little_endian_int(_inbuf+0x08))) {
201 fprintf(stderr, "Invalid archive file %s : invalid header.(size)\n",
202 filename);
203 return;
204 }
205
206 int w = read_little_endian_int(_inbuf+0x0c);
207 int h = read_little_endian_int(_inbuf+0x10);
208 int mask_pt = read_little_endian_int(_inbuf + 0x1c);
209 Init(filename, _inbuf, _inlen, w, h, mask_pt ? true : false);
210
211 return;
212 }
213
214
G00CONV(const char * _inbuf,int _inlen,const char * filename)215 G00CONV::G00CONV(const char* _inbuf, int _inlen, const char* filename) {
216 // G00 FILE のヘッダ
217 // +00 type (1, 2)
218 // +01: width(word)
219 // +03: height(word)
220 // type 1: (color table 付き LZ 圧縮 ; PDT11 に対応)
221 // +05: 圧縮サイズ(dword) ; +5 するとデータ全体のサイズ
222 // +09: 展開後サイズ(dword)
223 // type 2: (マスク可、画像を矩形領域に分割してそれぞれ圧縮)
224 // +05: index size
225 // +09: index table(each size is 0x18)
226 // +00
227 //
228 // +09+0x18*size+00: data size
229 // +09+0x18*size+04: out size
230 // +09+0x18*size+08: (data top)
231 //
232
233 /* データから情報読み込み */
234 int type = *_inbuf;
235
236 int w = read_little_endian_short(_inbuf+1);
237 int h = read_little_endian_short(_inbuf+3);
238 if (w < 0 || h < 0) return;
239
240 if (type == 0 || type == 1) { // color table 付き圧縮
241 if (_inlen < 13) {
242 fprintf(stderr, "Invalid G00 file %s : size is too small\n",filename);
243 return;
244 }
245 int data_sz = read_little_endian_int(_inbuf+5);
246
247 if (_inlen != data_sz+5) {
248 fprintf(stderr, "Invalid archive file %s : invalid header.(size)\n",
249 filename);
250 return;
251 }
252 Init(filename, _inbuf, _inlen, w, h, false);
253 } else if (type == 2) { // color table なし、マスク付き可の圧縮
254
255 int head_size = read_little_endian_short(_inbuf+5);
256 if (head_size < 0 || head_size*24 > _inlen) return;
257
258 region_table = vector<REGION>(head_size);
259
260 int real_region_count = 0;
261 std::set<REGION> unique_regions;
262 const char* head = _inbuf + 9;
263 bool overlaid_image = head_size > 1;
264 for (int i = 0; i < head_size; i++) {
265 region_table[i].x1 = read_little_endian_int(head+0);
266 region_table[i].y1 = read_little_endian_int(head+4);
267 region_table[i].x2 = read_little_endian_int(head+8);
268 region_table[i].y2 = read_little_endian_int(head+12);
269 region_table[i].origin_x = read_little_endian_int(head+16);
270 region_table[i].origin_y = read_little_endian_int(head+20);
271 region_table[i].Fix(w, h);
272 if (region_table[i].Width() &&
273 region_table[i].Height()) {
274 unique_regions.insert(region_table[i]);
275 real_region_count++;
276 }
277
278 head += 24;
279 }
280
281 if (real_region_count > 1 && unique_regions.size() == 1) {
282 // This is one of those newer images where each region is the size of
283 // width/height and is stacked on top of each other. We therefore have to
284 // munge the height and the region table so each region gets its own
285 // space on the canvas.
286 for (int i = 0; i < head_size; ++i) {
287 region_table[i].y1 += i * h;
288 region_table[i].y2 += i * h;
289 }
290 h = h * head_size;
291 }
292
293 const char* data_top = _inbuf + 9 + head_size*24;
294 int data_sz = read_little_endian_int(data_top);
295 if (_inbuf + _inlen != data_top + data_sz) {
296 fprintf(stderr, "Invalid archive file %s : invalid header.(size)\n",
297 filename);
298 return;
299 }
300 Init(filename, _inbuf, _inlen, w, h, true);
301 }
302 return;
303 }
304
Read(char * image)305 bool G00CONV::Read(char* image) {
306 if (data == 0) return false;
307 /* header 識別 */
308 int type = *data;
309 if (type == 0) return Read_Type0(image);
310 else if (type == 1) return Read_Type1(image);
311 else if (type == 2) return Read_Type2(image);
312 return false;
313 }
314
315 /* 一般的な LZ 圧縮の展開ルーチン */
316 /* datasize はデータの大きさ、char / short / int を想定 */
317 /* datatype は Copy1Pixel (1データのコピー)及び ExtractData(LZ 圧縮の情報を得る
318 ** というメソッドを実装したクラス */
319 static int bitrev_table[256] = {
320 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
321 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
322 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
323 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
324 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
325 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
326 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
327 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
328 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
329 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
330 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
331 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
332 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
333 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
334 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
335 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff};
lzExtract(DataType & datatype,const char * & src,char * & dest,const char * srcend,char * destend)336 template<class DataType, class DataSize> inline int lzExtract(DataType& datatype,const char*& src, char*& dest, const char* srcend, char* destend) {
337 int count = 0;
338 const char* lsrcend = srcend; char* ldestend = destend;
339 const char* lsrc = src; char* ldest = dest;
340
341 if (lsrc+50 < lsrcend && ldest+1024 < ldestend) {
342 /* まず、範囲チェックを緩くして高速なルーチンを使う */
343 lsrcend -= 50;
344 ldestend += 1024;
345 while (ldest < ldestend && lsrc < lsrcend) {
346 count += 8;
347 int flag = int(*(unsigned char*)lsrc++);
348 if (datatype.IsRev()) flag = bitrev_table[flag];
349 int i; for (i=0; i<8; i++) {
350 if (flag & 0x80) {
351 datatype.Copy1Pixel(lsrc, ldest);
352 } else {
353 int data, size;
354 datatype.ExtractData(lsrc, data, size);
355 DataSize* p_dest = ((DataSize*)ldest) - data;
356 int k; for (k=0; k<size; k++) {
357 p_dest[data] = *p_dest;
358 p_dest++;
359 }
360 ldest += size*sizeof(DataSize);
361 }
362 flag <<= 1;
363 }
364 }
365 lsrcend += 50;
366 ldestend += 1024;
367 }
368 /* 残りを変換 */
369 while (ldest < ldestend && lsrc < lsrcend) {
370 count += 8;
371 int flag = int(*(unsigned char*)lsrc++);
372 if (datatype.IsRev()) flag = bitrev_table[flag];
373 int i; for (i=0; i<8 && ldest < ldestend && lsrc < lsrcend; i++) {
374 if (flag & 0x80) {
375 datatype.Copy1Pixel(lsrc, ldest);
376 } else {
377 int data, size;
378 datatype.ExtractData(lsrc, data, size);
379 DataSize* p_dest = ((DataSize*)ldest) - data;
380 int k; for (k=0; k<size; k++) {
381 p_dest[data] = *p_dest;
382 p_dest++;
383 }
384 ldest += size*sizeof(DataSize);
385 }
386 flag <<= 1;
387 }
388 }
389 dest=ldest; src=lsrc;
390 return 0;
391 }
392 /* 引数を減らすためのwrapper */
lzExtract(DataType datatype,DataSize datasize,const char * & src,char * & dest,const char * srcend,char * destend)393 template<class DataType, class DataSize> inline int lzExtract(DataType datatype, DataSize datasize ,const char*& src, char*& dest, const char* srcend, char* destend) {
394 return lzExtract<DataType, DataSize>(datatype,src,dest,srcend,destend);
395 }
396
397 /* 普通の PDT */
398 class Extract_DataType {
399 public:
ExtractData(const char * & lsrc,int & data,int & size)400 static void ExtractData(const char*& lsrc, int& data, int& size) {
401 data = read_little_endian_short(lsrc) & 0xffff;
402 size = (data & 0x0f) + 1;
403 data = (data>>4)+1;
404 lsrc += 2;
405 }
Copy1Pixel(const char * & lsrc,char * & ldest)406 static void Copy1Pixel(const char*& lsrc, char*& ldest) {
407 if(g_isBigEndian)
408 {
409 ldest[3] = lsrc[0];
410 ldest[2] = lsrc[1];
411 ldest[1] = lsrc[2];
412 ldest[0] = 0;
413 }
414 else
415 {
416 *(int*)ldest = read_little_endian_int(lsrc); ldest[3]=0;
417 }
418
419 lsrc += 3; ldest += 4;
420 }
IsRev(void)421 static int IsRev(void) { return 0; }
422 };
423
424 /* PDT11 の第一段階変換 */
425 class Extract_DataType_PDT11 {
426 int* index_table;
427 public:
Extract_DataType_PDT11(int * it)428 Extract_DataType_PDT11(int* it) { index_table = it; }
ExtractData(const char * & lsrc,int & data,int & size)429 void ExtractData(const char*& lsrc, int& data, int& size) {
430 data = int(*(const unsigned char*)lsrc);
431 size = (data>>4) + 2;
432 data = index_table[data&0x0f];
433 lsrc++;
434 }
Copy1Pixel(const char * & lsrc,char * & ldest)435 static void Copy1Pixel(const char*& lsrc, char*& ldest) {
436 *ldest = *lsrc;
437 ldest++; lsrc++;
438 }
IsRev(void)439 static int IsRev(void) { return 0; }
440 };
441 /* マスク用 */
442 class Extract_DataType_Mask {
443 public:
ExtractData(const char * & lsrc,int & data,int & size)444 void ExtractData(const char*& lsrc, int& data, int& size) {
445 int d = read_little_endian_short(lsrc) & 0xffff;
446 size = (d & 0xff) + 2;
447 data = (d>>8)+1;
448 lsrc += 2;
449 }
Copy1Pixel(const char * & lsrc,char * & ldest)450 static void Copy1Pixel(const char*& lsrc, char*& ldest) {
451 *ldest = *lsrc;
452 ldest++; lsrc++;
453 }
IsRev(void)454 static int IsRev(void) { return 0; }
455 };
456 /* avg2000 のシナリオ用 */
457 class Extract_DataType_SCN2k {
458 public:
ExtractData(const char * & lsrc,int & data,int & size)459 void ExtractData(const char*& lsrc, int& data, int& size) {
460 data = read_little_endian_short(lsrc) & 0xffff;
461 size = (data&0x0f) + 2;
462 data = (data>>4);
463 lsrc+= 2;
464 }
Copy1Pixel(const char * & lsrc,char * & ldest)465 static void Copy1Pixel(const char*& lsrc, char*& ldest) {
466 *ldest = *lsrc;
467 ldest++; lsrc++;
468 }
IsRev(void)469 static int IsRev(void) { return 1; }
470 };
471 /* ReadLive の type0 */
472 class Extract_DataType_G00Type0 {
473 public:
ExtractData(const char * & lsrc,int & data,int & size)474 static void ExtractData(const char*& lsrc, int& data, int& size) {
475 data = read_little_endian_short(lsrc) & 0xffff;
476 size = ((data & 0x0f)+ 1) * 3;
477 data = (data>>4) * 3;
478 lsrc += 2;
479 }
Copy1Pixel(const char * & lsrc,char * & ldest)480 static void Copy1Pixel(const char*& lsrc, char*& ldest) {
481 if(g_isBigEndian)
482 {
483 ldest[0] = lsrc[0];
484 ldest[1] = lsrc[1];
485 ldest[2] = lsrc[2];
486 }
487 else
488 {
489 *(int*)ldest = *(int*)lsrc;
490 }
491
492 lsrc += 3; ldest += 3;
493 }
IsRev(void)494 static int IsRev(void) { return 1; }
495 };
496
Read(char * image)497 bool PDTCONV::Read(char* image) {
498 if (data == 0) return false;
499
500 if (strncmp(data, "PDT10", 5) == 0) {
501 if (! Read_PDT10(image)) return false;
502 } else if (strncmp(data, "PDT11", 5) == 0) {
503 if (! Read_PDT11(image)) return false;
504 }
505 if (! is_mask) return true;
506 // マスク読み込み
507 int mask_pt = read_little_endian_int(data + 0x1c);
508 char* buf = new char[width*height+1024];
509 const char* src = data + mask_pt;
510 const char* srcend = data + datalen;
511 char* dest = buf;
512 char* destend = buf + width*height;
513 while(lzExtract(Extract_DataType_Mask(), char(), src, dest, srcend, destend)) ;
514 int i; int len = width*height;
515 src = buf; dest = image;
516 for (i=0; i<len; i++) {
517 *(int*)dest |= int(*(unsigned char*)src) << 24;
518 src++;
519 dest += 4;
520 }
521 delete[] buf;
522 return true;
523 }
524
Read_PDT10(char * image)525 bool PDTCONV::Read_PDT10(char* image) {
526 int mask_pt = read_little_endian_int(data + 0x1c);
527
528 const char* src = data + 0x20;
529 const char* srcend;
530 if (mask_pt == 0) srcend = data + datalen;
531 else srcend = data + mask_pt;
532
533 char* dest = image;
534 char* destend;
535
536 destend = image + width*height*4;
537 while(lzExtract(Extract_DataType(), int(), src, dest, srcend, destend)) ;
538 return true;
539 }
540
Read_PDT11(char * image)541 bool PDTCONV::Read_PDT11(char* image) {
542 int index_table[16];
543 int color_table[256];
544 int i;
545 for (i=0; i<16; i++)
546 index_table[i] = read_little_endian_int(data + 0x420 + i*4);
547
548 int mask_pt = read_little_endian_int(data + 0x1c);
549
550 const char* src = data + 0x460;
551 const char* srcend;
552 if (mask_pt == 0) srcend = data + datalen;
553 else srcend = data + mask_pt;
554
555 char* dest = image;
556 char* destend = image + width*height;
557
558 while(lzExtract(Extract_DataType_PDT11(index_table), char(), src, dest, srcend, destend)) ;
559
560 const char* cur = data + 0x20;
561 for (i=0; i<256; i++) {
562 color_table[i] = read_little_endian_int(cur);
563 cur += 4;
564 }
565 src = image + width*height;
566 int* desti = (int*)(image + width*height*4);
567 while(desti != (int*)image)
568 *--desti = color_table[*(unsigned char*)--src];
569 return true;
570 }
571
572 /* dest は dest_end よりも 256 byte 以上先まで
573 ** 書き込み可能であること。
574 */
Extract2k(char * & dest_start,char * & src_start,char * dest_end,char * src_end)575 void ARCINFO::Extract2k(char*& dest_start, char*& src_start, char* dest_end, char* src_end) {
576 const char* src = src_start;
577 while (lzExtract(Extract_DataType_SCN2k(), char(), src, dest_start, src_end, dest_end)) ;
578 src_start = (char*)src;
579 return;
580 }
581
Read_Type0(char * image)582 bool G00CONV::Read_Type0(char* image) {
583 int uncompress_size = read_little_endian_int(data+9);
584 char* uncompress_data = new char[uncompress_size+1024];
585
586 // まず展開
587 const char* src = data + 13;
588 const char* srcend = data + datalen;
589 char* dest = uncompress_data;
590 char* dstend = uncompress_data + uncompress_size;
591 while(lzExtract(Extract_DataType_G00Type0(), char(), src, dest, srcend, dstend));
592 // image にコピー
593 CopyRGB(image, uncompress_data);
594 delete[] uncompress_data;
595 return true;
596 }
597
Read_Type1(char * image)598 bool G00CONV::Read_Type1(char* image) {
599 int i;
600 int uncompress_size = read_little_endian_int(data+9) + 1;
601 char* uncompress_data = new char[uncompress_size + 1024];
602
603 // まず、展開
604 const char* src = data + 13;
605 const char* srcend = data + datalen;
606 char* dest = uncompress_data;
607 char* destend = uncompress_data + uncompress_size;
608
609 while(lzExtract(Extract_DataType_SCN2k(), char(), src, dest, srcend, destend));
610
611 int colortable[256];
612 memset(colortable, 0, sizeof(int)*256);
613 int colortable_len = read_little_endian_short(uncompress_data);
614 if (colortable_len > 256) colortable_len = 256;
615 if (colortable_len < 0) colortable_len = 0;
616 for (i=0; i<colortable_len; i++) {
617 colortable[i] = read_little_endian_int(uncompress_data+2+i*4);
618 }
619 src = uncompress_data + 2 + read_little_endian_short(uncompress_data)*4;
620 srcend = uncompress_data + uncompress_size;
621 dest = image; destend = image + width*height*4;
622 while(dest < destend && src < srcend) {
623 *(int*)dest = colortable[*(unsigned char*)src];
624 dest += 4; src ++;
625 }
626 delete[] uncompress_data;
627 return true;
628 }
629
Read_Type2(char * image)630 bool G00CONV::Read_Type2(char* image) {
631 memset(image, 0, width*height*4);
632
633 int region_deal = read_little_endian_int(data+5);
634 const char* head = data + 9 + (region_deal * 24);
635
636 // 展開
637 int uncompress_size = read_little_endian_int(head+4);
638 char* uncompress_data = new char[uncompress_size + 1024];
639
640 const char* src = head + 8;
641 const char* srcend = data + datalen;
642 char* dest = uncompress_data;
643 char* destend = uncompress_data + uncompress_size;
644 while(lzExtract(Extract_DataType_SCN2k(), char(), src, dest, srcend, destend));
645
646 /* region_deal2 == region_deal のはず……*/
647 int region_deal2 = read_little_endian_int(uncompress_data);
648 if (region_deal > region_deal2) region_deal = region_deal2;
649
650 for (int i = 0; i < region_deal; i++) {
651 int offset = read_little_endian_int(uncompress_data + i*8 + 4);
652 int length = read_little_endian_int(uncompress_data + i*8 + 8);
653 src = (const char*)(uncompress_data + offset + 0x74);
654 srcend = (const char*)(uncompress_data + offset + length);
655 while(src < srcend) {
656 int x, y, w, h;
657 /* コピーする領域を得る */
658 x = read_little_endian_short(src);
659 y = read_little_endian_short(src+2);
660 w = read_little_endian_short(src+6);
661 h = read_little_endian_short(src+8);
662 src += 0x5c;
663
664 x += region_table[i].x1;
665 y += region_table[i].y1;
666
667 Copy_32bpp(image, x, y, src, w*4, h);
668
669 src += w*h*4;
670 }
671 }
672 delete[] uncompress_data;
673 return true;
674 }
675
Copy_32bpp(char * image,int x,int y,const char * src,int bpl,int h)676 void G00CONV::Copy_32bpp(char* image, int x, int y, const char* src, int bpl, int h) {
677 int i;
678 int* dest = (int*)(image + x*4 + y*4*width);
679 int w = bpl / 4;
680 for (i=0; i<h; i++) {
681 const char* s = src;
682 int* d = dest;
683 int j; for (j=0; j<w; j++) {
684 *d++ = read_little_endian_int(s);
685 s += 4;
686 }
687 src += bpl; dest += width;
688 }
689 }
690
CopyRGBA_rev(char * image,const char * buf)691 void GRPCONV::CopyRGBA_rev(char* image, const char* buf) {
692 int mask = is_mask ? 0 : 0xff000000;
693 /* 色変換を行う */
694 int len = width * height;
695 int i;
696 unsigned char* s = (unsigned char*)buf;
697 int* d = (int*)image;
698 for(i=0; i<len; i++) {
699 *d = (int(s[2])) | (int(s[1])<<8) | (int(s[0])<<16) | (int(s[3])<<24) | mask;
700 d++; s += 4;
701 }
702 return;
703 }
704
CopyRGBA(char * image,const char * buf)705 void GRPCONV::CopyRGBA(char* image, const char* buf) {
706 if (!is_mask) {
707 CopyRGB(image, buf);
708 return;
709 }
710 /* 色変換を行う */
711 int len = width * height;
712 int i;
713 int* outbuf = (int*)image;
714 for(i=0; i<len; i++) {
715 *outbuf++ = read_little_endian_int(buf);
716 buf += 4;
717 }
718 return;
719 }
720
CopyRGB(char * image,const char * buf)721 void GRPCONV::CopyRGB(char* image, const char* buf) {
722 /* 色変換を行う */
723 int len = width * height;
724 int i;
725 unsigned char* s = (unsigned char*)buf;
726 int* d = (int*)image;
727 for(i=0; i<len; i++) {
728 *d = (int(s[0])) | (int(s[1])<<8) | (int(s[2])<<16) | 0xff000000;
729 d++; s+=3;
730 }
731 return;
732 }
733
BMPCONV(const char * _inbuf,int _inlen,const char * _filename)734 BMPCONV::BMPCONV(const char* _inbuf, int _inlen, const char* _filename) {
735 /* データから情報読み込み */
736 int w = read_little_endian_int(_inbuf + 0x12);
737 int h = read_little_endian_int(_inbuf + 0x16);
738 if (h < 0) h = -h;
739 int bpp = read_little_endian_short(_inbuf + 0x1c);
740 // int comp = read_little_endian_int(_inbuf + 0x1e);
741 Init(filename, _inbuf, _inlen, w, h, bpp==32 ? true : false);
742 return;
743 }
744
Read(char * image)745 bool BMPCONV::Read(char* image) {
746 if (data == 0) return false;
747
748 /* マスクのチェック */
749 int bpp = read_little_endian_short(data+0x1c);
750 int h = read_little_endian_int(data + 0x16);
751 int dsz = read_little_endian_int(data + 0x22);
752 bpp /= 8;
753
754 int bpl = dsz / height;
755 if (bpl == 0) bpl = bpp*width;
756 bpl = bpp * width;
757 bpl = (bpl+3) & (~3);
758
759
760 int i;
761 char* buf = new char[width*height*bpp+1024];
762 const char* src = data + 0x36;
763 char* dest = buf;
764 if (h < 0) {
765 for (i=0; i<height; i++) {
766 memcpy(dest+i*width*bpp, src+i*bpl, width*bpp);
767 }
768 } else {
769 for (i=0; i<height; i++) {
770 memcpy(dest+i*width*bpp, src+(height-i-1)*bpl, width*bpp);
771 }
772 }
773 if (bpp == 3) CopyRGB(image, buf);
774 else /* bpp == 4 */ CopyRGBA(image, buf);
775 delete[] buf;
776 return true;
777 }
778
779