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