comparison system/file.cc @ 0:223b71206888

Initial import
author thib
date Fri, 01 Aug 2008 16:32:45 +0000
parents
children fa8511a21d05
comparison
equal deleted inserted replaced
-1:000000000000 0:223b71206888
1 bool init_end=false;
2 /* file.cc : KANON の圧縮ファイル・PDT ファイル(画像ファイル)の展開の
3 * ためのメソッド
4 * class ARCFILE : 書庫ファイル全体を扱うクラス
5 * class ARCINFO : 書庫ファイルの中の1つのファイルを扱うクラス
6 * class PDTCONV : PDT ファイルの展開を行う。
7 *
8 */
9
10 /*
11 *
12 * Copyright (C) 2000- Kazunori Ueno(JAGARL) <jagarl@creator.club.ne.jp>
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28 */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #ifdef HAVE_MMAP
35 # ifdef MACOSX
36 # undef HAVE_MMAP
37 # endif /* MACOSX */
38 #endif /* HAVE_MMAP */
39
40 #include <ctype.h>
41 #include <fcntl.h>
42 #include <unistd.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <vector>
48 #include <algorithm>
49 #if HAVE_MMAP
50 #include<sys/mman.h>
51 #endif /* HAVE_MMAP */
52 #if HAVE_DIRENT_H
53 # include <dirent.h>
54 # define NAMLEN(dirent) strlen((dirent)->d_name)
55 #else
56 # define dirent direct
57 # define NAMLEN(dirent) (dirent)->d_namlen
58 # if HAVE_SYS_NDIR_H
59 # include <sys/ndir.h>
60 # endif
61 # if HAVE_SYS_DIR_H
62 # include <sys/dir.h>
63 # endif
64 # if HAVE_NDIR_H
65 # include <ndir.h>
66 # endif
67 #endif
68
69 #if HAVE_LIBZ
70 #include<zlib.h>
71 #endif
72 #if HAVE_LIBPNG
73 #include<png.h>
74 #endif
75 #if HAVE_LIBJPEG
76 extern "C" {
77 #include<jpeglib.h>
78 }
79 #endif
80
81 #include "file.h"
82 #include "file_impl.h"
83
84 using namespace std;
85
86 FILESEARCH file_searcher;
87 // #define delete fprintf(stderr,"file.cc: %d.",__LINE__), delete
88
89 /* FILESEARCH class の default の振る舞い */
90 FILESEARCH::ARCTYPE FILESEARCH::default_is_archived[TYPEMAX] = {
91 ATYPE_DIR, ATYPE_DIR, ATYPE_DIR, ATYPE_DIR,
92 ATYPE_ARC, ATYPE_ARC, ATYPE_ARC, ATYPE_ARC,
93 ATYPE_DIR, ATYPE_DIR, ATYPE_DIR, ATYPE_DIR,
94 ATYPE_DIR, ATYPE_DIR
95 };
96 char* FILESEARCH::default_dirnames[TYPEMAX] = {
97 0, 0, "", "pdt",
98 "seen.txt", "allanm.anl", "allard.ard", "allcur.cur",
99 0, 0, "koe", "bgm", "mov", "gan"};
100
101 /*********************************************
102 ** ARCFILE / DIRFILE:
103 ** 書庫ファイル、あるいはディレクトリの
104 ** 全体を管理するクラス
105 **
106 ** 書庫ファイルからファイルの抜き出しはFind()
107 ** Find したものをReadすると内容が得られる。
108 */
109
110 ARCFILE::ARCFILE(char* aname) {
111 struct stat sb;
112 /* 変数初期化 */
113 arcname = 0;
114 list_point = 0;
115 filenames_orig = 0;
116 next = 0;
117 if (aname[0] == '\0') {arcname=new char[1]; arcname[0]='\0';return;} // NULFILE
118 /* ディレクトリか否かのチェック */
119 if (stat(aname,&sb) == -1) { /* error */
120 perror("stat");
121 }
122 if ( (sb.st_mode&S_IFMT) == S_IFDIR) {
123 int l = strlen(aname);
124 arcname = new char[l+2]; strcpy(arcname, aname);
125 if (arcname[l-1] != DIR_SPLIT) {
126 arcname[l] = DIR_SPLIT;
127 arcname[l+1] = 0;
128 }
129 } else if ( (sb.st_mode&S_IFMT) == S_IFREG) {
130 arcname = new char[strlen(aname)+1];
131 strcpy(arcname,aname);
132 if (arcname[strlen(arcname)-1] == DIR_SPLIT)
133 arcname[strlen(arcname)-1] = '\0';
134 }
135 return;
136 }
137
138 void ARCFILE::Init(void) {
139 int i;
140 if (! arc_atom.empty()) return;
141 if (arcname == 0) return;
142 /* ファイル数を得る */
143 int slen = CheckFileDeal();
144 /* ファイル名のセット */
145 ListupFiles(slen);
146 if ( (!arc_atom.empty()) && arc_atom[0].filename) filenames_orig = arc_atom[0].filename;
147 sort(arc_atom.begin(), arc_atom.end());
148 }
149 ARCFILE::~ARCFILE() {
150 if (filenames_orig) delete[] filenames_orig;
151 delete[] arcname;
152 }
153
154 ARCFILE::iterator ARCFILE::SearchName(const char* f, const char* ext) {
155 char buf[1024]; char buf_ext[1024];
156 iterator it;
157 Init();
158 if (f == 0) return arc_atom.end();
159 if (arc_atom.empty()) return arc_atom.end();
160 /* エラーチェック */
161 if (strlen(f)>500) return arc_atom.end();
162 if (ext && strlen(ext)>500) return arc_atom.end();
163
164 /* 検索 */
165 strncpy(buf, f, 1000);
166 buf[1000]=0;
167 it = lower_bound(arc_atom.begin(), arc_atom.end(), (char*)buf);
168 if (it != arc_atom.end() && strcmp(it->filename_lower, buf) == 0) return it;
169 // 拡張子をつけて検索
170 if (ext) {
171 strcpy(buf_ext, buf);
172 char* ext_pt = strrchr(buf_ext, '.');
173 if (ext_pt == 0 || ext_pt == buf_ext) ext_pt = buf_ext + strlen(buf_ext);
174 *ext_pt++ = '.';
175 while(*ext=='.') ext++;
176 strcat(buf_ext, ext);
177 it = lower_bound(arc_atom.begin(), arc_atom.end(), (char*)buf_ext);
178 if (it != arc_atom.end() && strcmp(it->filename_lower, buf_ext) == 0) return it;
179 }
180
181 /* 小文字にして 検索 */
182 int i; int l = strlen(f);
183 if (l > 500) l = 500;
184 for (i=0; i<l; i++)
185 buf[i] = tolower(f[i]);
186 buf[i++] = 0;
187 it = lower_bound(arc_atom.begin(), arc_atom.end(), (char*)buf);
188 if (it != arc_atom.end() && strcmp(it->filename_lower, buf) == 0) return it;
189
190 // 拡張子をつけて検索
191 if (ext == 0) return arc_atom.end();
192 strcpy(buf_ext, buf);
193 char* ext_pt = strrchr(buf_ext, '.');
194 if (ext_pt == 0 || ext_pt == buf_ext) ext_pt = buf_ext + strlen(buf_ext);
195 *ext_pt++ = '.';
196 /* 拡張子の長さを得る */
197 l = strlen(ext);
198 for (i=0; i<l; i++)
199 ext_pt[i] = tolower(*ext++);
200 ext_pt[i] = 0;
201 it = lower_bound(arc_atom.begin(), arc_atom.end(), (char*)buf_ext);
202 if (it != arc_atom.end() && strcmp(it->filename_lower, buf_ext) == 0) return it;
203 return arc_atom.end();
204 }
205
206 ARCINFO* ARCFILE::Find(const char* fname, const char* ext) {
207 Init();
208 iterator atom = SearchName(fname,ext);
209 if (atom == arc_atom.end()) {
210 if (next) return next->Find(fname, ext);
211 else return 0;
212 }
213 return MakeARCINFO(*atom);
214 }
215 ARCINFO* ARCFILE::MakeARCINFO(ARCFILE_ATOM& atom) {
216 if (atom.arcsize == atom.filesize)
217 return new ARCINFO(arcname, atom);
218 else // 圧縮付
219 return new ARCINFO_AVG32(arcname, atom);
220 }
221 ARCINFO* NULFILE::MakeARCINFO(ARCFILE_ATOM& atom) {
222 fprintf(stderr,"NULFILE::MakeARCINFO is invalid call!\n");
223 return 0;
224 }
225 ARCINFO* SCN2kFILE::MakeARCINFO(ARCFILE_ATOM& atom) {
226 return new ARCINFO2k(arcname, atom);
227 }
228 ARCINFO* DIRFILE::MakeARCINFO(ARCFILE_ATOM& atom) {
229 char* name = atom.filename;
230 char* new_path = new char[strlen(arcname)+strlen(name)+1];
231 strcpy(new_path,arcname); strcat(new_path, name);
232 ARCINFO* ret = new ARCINFO(new_path, atom);
233 delete[] new_path;
234 return ret;
235 }
236
237 FILE* DIRFILE::Open(const char* fname) {
238 iterator atom = SearchName(fname);
239 if (atom == arc_atom.end()) return 0;
240 char* name = atom->filename;
241 // make FILE*
242 char* new_path = new char[strlen(arcname)+strlen(name)+1];
243 strcpy(new_path,arcname); strcat(new_path, name);
244 FILE* ret = fopen(new_path, "rb+");
245 fseek(ret, 0, 0);
246 delete[] new_path;
247 return ret;
248 }
249
250 char* DIRFILE::SearchFile(const char* fname) {
251 iterator atom = SearchName(fname);
252 if (atom == arc_atom.end()) return 0;
253 char* name = atom->filename;
254 char* new_path = new char[strlen(arcname)+strlen(name)+1];
255 strcpy(new_path,arcname); strcat(new_path, name);
256 struct stat sb;
257 if (stat(new_path, &sb) == 0 &&
258 ( (sb.st_mode&S_IFMT) == S_IFREG ||
259 (sb.st_mode&S_IFMT) == S_IFDIR)) {
260 return new_path;
261 }
262 delete[] new_path;
263 return 0;
264 }
265
266 void ARCFILE::ListFiles(FILE* out) {
267 int i;
268 Init();
269 if (arc_atom.empty()) return;
270 // list file name...
271 fprintf(out,"%16s %10s %10s %10s\n", "Filename",
272 "pointer","arcsize", "filesize");
273 vector<ARCFILE_ATOM>::iterator it;
274 for (it=arc_atom.begin(); it!=arc_atom.end(); it++) {
275 fprintf(out,"%16s %10d %10d %10d\n",
276 it->filename,it->offset,it->arcsize,it->filesize);
277 }
278 return;
279 }
280
281 void ARCFILE::InitList(void) {
282 Init();
283 list_point = 0;
284 }
285 char* ARCFILE::ListItem(void) {
286 if (list_point < 0) return 0;
287 if (list_point >= arc_atom.size()) return 0;
288 char* fname = arc_atom[list_point].filename;
289 if (fname == 0) return 0;
290 char* ret = new char[strlen(fname)+1];
291 strcpy(ret, fname);
292 list_point++;
293 return ret;
294 }
295
296 int ARCFILE::CheckFileDeal(void) {
297 char buf[0x20];
298 /* ヘッダのチェック */
299 FILE* stream = fopen(arcname, "rb");
300 if (stream == 0) {
301 fprintf(stderr, "Cannot open archive file : %s\n",arcname);
302 return 0;
303 }
304 fseek(stream, 0, 2); size_t arc_size = ftell(stream);
305 fseek(stream, 0, 0);
306 if (arc_size < 0x20) {
307 fclose(stream);
308 return 0;
309 }
310 fread(buf, 0x20, 1, stream);
311 if (strncmp(buf, "PACL", 4) != 0) {
312 fclose(stream);
313 return 0;
314 }
315 int len = read_little_endian_int(buf+0x10);
316 if (arc_size < size_t(0x20 + len*0x20)) {
317 fclose(stream);
318 return 0;
319 }
320 int i; int slen = 0;
321 for (i=0; i<len; i++) {
322 fread(buf, 0x20, 1, stream);
323 slen += strlen(buf)+1;
324 }
325 fclose(stream);
326 return slen;
327 }
328 void ARCFILE::ListupFiles(int fname_len) {
329 int i; char fbuf[0x20];
330 fname_len *= 2;
331 char* buf = new char[fname_len];
332 FILE* stream = fopen(arcname, "rb");
333 if (stream == 0) {
334 fprintf(stderr, "Cannot open archive file : %s\n",arcname);
335 return;
336 }
337 fread(fbuf,0x20,1,stream);
338 int len = read_little_endian_int(fbuf+0x10);
339 ARCFILE_ATOM atom;
340 for (i=0; i<len; i++) {
341 fread(fbuf, 0x20, 1, stream);
342 int l = strlen(fbuf);
343 if (l*2+2 > fname_len) {
344 break;
345 }
346 atom.offset = read_little_endian_int(fbuf+0x10);
347 atom.arcsize = read_little_endian_int(fbuf+0x14);
348 atom.filesize = read_little_endian_int(fbuf+0x18);
349 int j; for (j=0; j<l; j++) {
350 buf[j] = fbuf[j];
351 buf[j+l+1] = tolower(fbuf[j]);
352 }
353 buf[j] = buf[j+l+1] = 0;
354 atom.filename = buf;
355 atom.filename_lower = buf+l+1;
356 arc_atom.push_back(atom);
357 buf += l*2+2; fname_len -= l*2+2;
358 }
359 fclose(stream);
360 return;
361 }
362 int DIRFILE::CheckFileDeal(void) {
363 DIR* dir; struct dirent* ent;
364 int flen = 0;
365 dir = opendir(arcname);
366 if (dir == 0) {
367 fprintf(stderr, "Cannot open dir file : %s\n",arcname);
368 return 0;
369 }
370 int count = 0;
371 while( (ent = readdir(dir)) != NULL) {
372 count++;
373 flen += strlen(ent->d_name)+1;
374 }
375 closedir(dir);
376 return flen;
377 }
378 void DIRFILE::ListupFiles(int fname_len) {
379 DIR* dir; int i;
380 fname_len *= 2;
381 dir = opendir(arcname);
382 if (dir == 0) {
383 fprintf(stderr, "Cannot open dir file : %s\n",arcname);
384 return;
385 }
386 /* 一時的に arcname のディレクトリに移動する */
387 int old_dir_fd = open(".",O_RDONLY);
388 if (old_dir_fd < 0) {
389 closedir(dir);
390 return;
391 }
392 if (chdir(arcname) != 0) {
393 fprintf(stderr, "Cannot open dir file : %s\n",arcname);
394 closedir(dir);
395 close(old_dir_fd);
396 return;
397 };
398
399 char* buf = new char[fname_len];
400 ARCFILE_ATOM atom;
401 struct stat sb;
402 struct dirent* ent;
403 while( (ent = readdir(dir)) != NULL) {
404 if (stat(ent->d_name, &sb) == -1) continue;
405 if ( (sb.st_mode & S_IFMT) == S_IFREG) {
406 atom.offset = 0;
407 atom.arcsize = sb.st_size;
408 atom.filesize = sb.st_size;
409 } else if ( (sb.st_mode & S_IFMT) == S_IFDIR) {
410 atom.offset = 0;
411 atom.arcsize = atom.filesize = 0;
412 } else {
413 continue;
414 }
415 int l = strlen(ent->d_name);
416 if (l*2+2 > fname_len) {
417 break;
418 }
419 int j; for (j=0; j<l+1; j++) {
420 buf[j] = ent->d_name[j];
421 buf[j+l+1] = tolower(ent->d_name[j]);
422 }
423 atom.filename = buf; atom.filename_lower = buf+l+1;
424 arc_atom.push_back(atom);
425 buf += l*2+2; fname_len -= l*2+2;
426 }
427 /* chdir() したのを元に戻る */
428 closedir(dir);
429 fchdir(old_dir_fd); close(old_dir_fd);
430 return;
431 }
432 int NULFILE::CheckFileDeal(void) {
433 return 20;
434 }
435 void NULFILE::ListupFiles(int fname_len) {
436 char* s = new char[40];
437 ARCFILE_ATOM atom;
438 atom.offset = 0; atom.arcsize = 0; atom.filesize = 0;
439 strcpy(s, "** null dummy **");
440 atom.filename = s;
441 atom.filename_lower = s;
442 arc_atom.push_back(atom);
443 }
444 int SCN2kFILE::CheckFileDeal(void) {
445 /* ヘッダのチェック */
446 FILE* stream = fopen(arcname, "rb");
447 if (stream == 0) {
448 fprintf(stderr, "Cannot open archive file : %s\n",arcname);
449 return 0;
450 }
451 fseek(stream, 0, 2); size_t arc_size = ftell(stream);
452 fseek(stream, 0, 0);
453 if (arc_size < 10000*8) {
454 fclose(stream);
455 return 0;
456 }
457 char* buf = new char[10000*8];
458 fread(buf, 10000, 8, stream);
459 /* size == 0 のデータは存在しない */
460 int count = 0;
461 int i; for (i=0; i<10000; i++) {
462 int tmp_offset = read_little_endian_int(buf+i*8);
463 int tmp_size = read_little_endian_int(buf+i*8+4);
464 if (tmp_size <= 0 || tmp_offset < 0 || tmp_offset+tmp_size > int(arc_size) ) continue;
465 count++;
466 }
467 fclose(stream);
468 delete[] buf;
469 return count*13; /* ファイル名は seenXXXX.txt だから、一つ12文字+null */
470 }
471 void SCN2kFILE::ListupFiles(int fname_len) {
472 FILE* stream = fopen(arcname, "rb");
473 if (stream == 0) {
474 fprintf(stderr, "Cannot open archive file : %s\n",arcname);
475 return;
476 }
477 char* sbuf = new char[fname_len];
478 char* buf = new char[10000*8];
479 fread(buf, 10000, 8, stream);
480 fseek(stream, 0, 2); size_t arc_size = ftell(stream);
481 ARCFILE_ATOM atom;
482 int i; for (i=0; i<10000; i++) {
483 char header[0x200];
484 int tmp_offset = read_little_endian_int(buf+i*8);
485 int tmp_size = read_little_endian_int(buf+i*8+4);
486 if (tmp_size <= 0 || tmp_offset < 0 || tmp_offset+tmp_size > int(arc_size) ) continue;
487 /* header を得て圧縮形式などを調べる */
488 fseek(stream, tmp_offset, 0);
489 fread(header, 0x200, 1, stream);
490 int header_top = read_little_endian_int(header+0);
491 int file_version = read_little_endian_int(header+4);
492
493 if (file_version == 0x1adb2) ; // Little Busters!
494 else if (file_version != 0x2712) continue; /* system version が違う */
495
496 if (header_top == 0x1cc) { /* 古い形式 : avg2000 */
497 int header_size = read_little_endian_int(header+0)+read_little_endian_int(header+0x20)*4;
498 int data_size = read_little_endian_int(header+0x24);
499 atom.arcsize = data_size + header_size;
500 atom.filesize = data_size + header_size;
501 atom.private_data = header_size;
502
503 } else if (header_top == 0x1b8) { /* 初夜献上 */
504 int header_size = read_little_endian_int(header+0)+read_little_endian_int(header+0x08)*4;
505 int data_size = read_little_endian_int(header+0x0c);
506 int compdata_size = read_little_endian_int(header+0x10);
507 atom.arcsize = compdata_size + header_size;
508 atom.filesize = data_size + header_size;
509 atom.private_data = header_size;
510
511 } else if (header_top == 0x1d0) { /* 新しい形式: reallive */
512 int header_size = read_little_endian_int(header+0x20);
513 int data_size = read_little_endian_int(header+0x24);
514 int compdata_size = read_little_endian_int(header+0x28);
515 atom.arcsize = compdata_size + header_size;
516 atom.filesize = data_size + header_size;
517 atom.private_data = header_size;
518 } else {
519 fprintf(stderr,"invalid header top; %x : not supported\n",header_top);
520 continue; /* サポートしない形式 */
521 }
522
523 atom.offset = tmp_offset;
524 atom.filename = sbuf;
525 atom.filename_lower = sbuf;
526 arc_atom.push_back(atom);
527 sprintf(sbuf, "seen%04d.txt",i); sbuf += 13;
528 }
529 fclose(stream);
530 return;
531 }
532
533 /********************************************************
534 ** FILESEARCH クラスの実装
535 */
536
537 FILESEARCH::FILESEARCH(void) {
538 int i;
539 root_dir = 0; dat_dir = 0;
540 for (i=0; i<TYPEMAX; i++) {
541 searcher[i] = 0;
542 filenames[i] = default_dirnames[i];
543 is_archived[i] = default_is_archived[i];
544 }
545 }
546 FILESEARCH::~FILESEARCH(void) {
547 int i;
548 for (i=0; i<TYPEMAX; i++) {
549 if (filenames[i] != 0 && filenames[i] != default_dirnames[i]) delete[] filenames[i];
550 if (searcher[i] && searcher[i] != dat_dir && searcher[i] != root_dir) {
551 delete searcher[i];
552 }
553 }
554 if (dat_dir && dat_dir != root_dir) delete dat_dir;
555 if (root_dir) delete root_dir;
556 }
557
558 int FILESEARCH::InitRoot(char* root) {
559 /* 必要に応じて ~/ を展開 */
560 if (root[0] == '~' && root[1] == '/') {
561 char* home = getenv("HOME");
562 if (home != 0) {
563 char* new_root = new char[strlen(home)+strlen(root)];
564 strcpy(new_root, home);
565 strcat(new_root, root+1);
566 root = new_root;
567 }
568 }
569 /* 古いデータを消す */
570 int i;
571 for (i=0; i<TYPEMAX; i++) {
572 if (searcher[i] != 0 &&
573 searcher[i] != root_dir &&
574 searcher[i] != dat_dir) {
575 delete searcher[i];
576 }
577 searcher[i] = 0;
578 }
579 if (dat_dir && root_dir != dat_dir) delete dat_dir;
580 if (root_dir) delete root_dir;
581 dat_dir = 0;
582
583 /* 新しいディレクトリのもとで初期化 */
584 root_dir = new DIRFILE(root);
585 root_dir->Init();
586 /* dat/ を検索 */
587 char* dat_path = root_dir->SearchFile("dat");
588 if (dat_path == 0) {
589 /* 見つからなかったら root を dat の代わりにつかう */
590 dat_dir = root_dir;
591 } else {
592 dat_dir = new DIRFILE(dat_path);
593 dat_dir->Init();
594 }
595 searcher[ALL] = dat_dir;
596 searcher[ROOT] = root_dir;
597 return 0;
598 }
599
600 void FILESEARCH::SetFileInformation(FILETYPE tp, ARCTYPE is_arc, char* filename) {
601 int type = tp;
602 if (type < 0 || type >= TYPEMAX) return;
603 ARCFILE* next_arc = 0;
604 /* すでに searcher が存在すれば解放 */
605 if (searcher[type] != 0 &&
606 searcher[type] != root_dir &&
607 searcher[type] != dat_dir) {
608 next_arc = searcher[type]->Next();
609 delete searcher[type];
610 }
611 searcher[type] = 0;
612 /* 適当に初期化 */
613 if (filenames[type] != 0 &&
614 filenames[type] != default_dirnames[type]) delete[] filenames[type];
615 filenames[type] = new char[strlen(filename)+1];
616 strcpy(filenames[type], filename);
617 is_archived[type] = is_arc;
618 searcher[type] = MakeARCFILE(is_arc, filename);
619 if (searcher[type] && next_arc)
620 searcher[type]->SetNext(next_arc);
621 return;
622 }
623 void FILESEARCH::AppendFileInformation(FILETYPE tp, ARCTYPE is_arc, char* filename) {
624 int type = tp;
625 if (type < 0 || type >= TYPEMAX) return;
626 /* searcher がまだ割り当てられてない場合 */
627 if (searcher[type] == 0 ||
628 searcher[type] == root_dir ||
629 searcher[type] == dat_dir) {
630 searcher[type] = MakeARCFILE(is_archived[type], filenames[type]);
631 if (searcher[type] == 0) { /* 作成できなかった場合 */
632 /* この型情報を FileInformation とする */
633 SetFileInformation(tp, is_arc, filename);
634 return;
635 }
636 }
637 /* 初期化 */
638 ARCFILE* arc = MakeARCFILE(is_arc, filename);
639 /* append */
640 ARCFILE* cur;
641 for (cur=searcher[type]; cur->Next() != 0; cur = cur->Next()) ;
642 cur->SetNext(arc);
643 return;
644 }
645
646 ARCFILE* FILESEARCH::MakeARCFILE(ARCTYPE tp, char* filename) {
647 ARCFILE* arc = 0;
648 char* file;
649 if (filename == 0) goto err;
650 if (tp == ATYPE_DIR) {
651 file = root_dir->SearchFile(filename);
652 } else {
653 file = dat_dir->SearchFile(filename);
654 if (file == 0)
655 file = root_dir->SearchFile(filename);
656 }
657 if (file == 0) goto err;
658 switch(tp) {
659 case ATYPE_DIR: arc = new DIRFILE(file); break;
660 case ATYPE_SCN2k:
661 case ATYPE_ARC: {
662 FILE* f = fopen(file, "rb");
663 if (f == 0) goto err;
664 char header[32];
665 memset(header, 0, 32);
666 fread(header, 32, 1, f);
667 fclose(f);
668 char magic_raf[8] = {'C','A','P','F',1,0,0,0};
669 if (strncmp(header, "PACL", 4) == 0) arc = new ARCFILE(file);
670 else arc = new SCN2kFILE(file);
671 }
672 break;
673 default: fprintf(stderr,"FILESEARCH::MAKEARCFILE : invalid archive type; type %d name %s\n",tp,filename);
674 delete[] file;
675 goto err;
676 }
677 delete[] file;
678 return arc;
679 err:
680 arc = new NULFILE;
681 return arc;
682
683 }
684
685 ARCINFO* FILESEARCH::Find(FILETYPE type, const char* fname, const char* ext) {
686 if (searcher[type] == 0) {
687 /* searcher 作成 */
688 if (filenames[type] == 0) {
689 searcher[type] = dat_dir;
690 } else {
691 searcher[type] = MakeARCFILE(is_archived[type], filenames[type]);
692 if (searcher[type] == 0) {
693 fprintf(stderr,"FILESEARCH::Find : invalid archive type; type %d name %s\n",type,fname);
694 return 0;
695 }
696 }
697 }
698 return searcher[type]->Find(fname,ext);
699 }
700
701 char** FILESEARCH::ListAll(FILETYPE type) {
702 int i;
703 /* とりあえず searcher を初期化 */
704 Find(type, "THIS FILENAME MAY NOT EXIST IN THE FILE SYSTEM !!!");
705 if (searcher[type] == 0) return 0;
706 /* 全ファイルのリストアップ */
707 int deal = 0;
708 ARCFILE* file;
709 for (file = searcher[type]; file != 0; file = file->Next())
710 deal += file->Deal();
711 if (deal <= 0) return 0;
712 char** ret_list = new char*[deal+1];
713 int count = 0;
714 for (file = searcher[type]; file != 0; file = file->Next()) {
715 file->InitList();
716 char* f;
717 while( (f = file->ListItem() ) != 0) {
718 ret_list[count] = new char[strlen(f)+1];
719 strcpy(ret_list[count], f);
720 count++;
721 }
722 }
723 ret_list[count] = 0;
724 return ret_list;
725 }
726
727 ARCINFO::ARCINFO(const char* __arcname, ARCFILE_ATOM& atom) : info(atom) {
728 arcfile = new char[strlen(__arcname)+1];
729 strcpy(arcfile, __arcname);
730 use_mmap = false;
731 mmapped_memory = 0;
732 data = 0;
733 fd = -1;
734 }
735
736 ARCINFO::~ARCINFO() {
737 #ifdef HAVE_MMAP
738 if (mmapped_memory) munmap(mmapped_memory, info.arcsize);
739 #endif /* HAVE_MMAP */
740 if (fd != -1) close(fd);
741 if (data != mmapped_memory) delete[] data;
742 delete[] arcfile;
743 }
744
745 int ARCINFO::Size(void) const {
746 return info.filesize;
747 }
748
749 /* コピーを返す */
750 char* ARCINFO::CopyRead(void) {
751 const char* d = Read();
752 if (d == 0) return 0;
753 int s = Size();
754 if (s <= 0) return 0;
755 char* ret = new char[s]; memcpy(ret, d, s);
756 return ret;
757 }
758
759 const char* ARCINFO::Path(void) const {
760 if (info.offset != 0) return 0; /* archive file なのでパスを帰せない */
761 char* ret = new char[strlen(arcfile)+1];
762 strcpy(ret, arcfile);
763 return ret;
764 }
765 /* 互換性専用 */
766 FILE* ARCINFO::OpenFile(int* length) const {
767 FILE* f = fopen(arcfile, "rb");
768 if (info.offset) lseek(fileno(f), info.offset, SEEK_SET);
769 if (length) *length = info.arcsize;
770 return f;
771 }
772
773 // 展開処理はなし
774 bool ARCINFO::ExecExtract(void) {
775 return true;
776 }
777 /* 読み込みを開始する */
778 const char* ARCINFO::Read(void) {
779 // すでにデータを読み込み済みなら何もしない
780 if (data) return data;
781
782 if (info.offset < 0 || info.arcsize <= 0) {
783 return 0;
784 }
785 /* ファイルを開く */
786 fd = open(arcfile, O_RDONLY);
787 if (fd < 0) {
788 return 0;
789 }
790 if (lseek(fd, info.offset, 0) != info.offset) {
791 close(fd); fd = -1; return 0;
792 }
793 /* mmap を試みる */
794 #ifdef HAVE_MMAP
795 mmapped_memory = (char*)mmap(0, info.arcsize, PROT_READ, MAP_SHARED, fd, info.offset);
796 if (mmapped_memory != MAP_FAILED) {
797 use_mmap = true;
798 data = (const char*)mmapped_memory;
799 } else
800 #endif /* HAVE_MMAP */
801 {
802 /* 失敗:普通にファイルを読み込み */
803 char* d = new char[info.arcsize];
804 read(fd, d, info.arcsize);
805 close(fd);
806 fd = -1;
807 use_mmap = false;
808 data = d;
809 }
810 /* 展開する */
811 if (! ExecExtract()) {
812 // 失敗
813 #ifdef HAVE_MMAP
814 if (use_mmap) {
815 munmap(mmapped_memory, info.arcsize);
816 if (data == (const char*)mmapped_memory) data = 0;
817 }
818 #endif /* HAVE_MMAP */
819 delete[] (char*)data;
820 close(fd);
821 fd = -1; data = 0;
822 return 0;
823 }
824 #ifdef HAVE_MMAP
825 if (use_mmap && data != (const char*)mmapped_memory) {
826 // すでに mmap は必要ない
827 munmap(mmapped_memory, info.arcsize);
828 close(fd);
829 fd = -1;
830 use_mmap = false;
831 }
832 #endif /* HAVE_MMAP */
833 return data;
834 }
835
836 /**********************************************
837 **
838 ** 画像展開系クラスの定義、実装
839 **
840 ***********************************************
841 */
842 GRPCONV::GRPCONV(void) {
843 filename = 0;
844 data = 0;
845 }
846 GRPCONV::~GRPCONV() {
847 if (filename) delete[] filename;
848 }
849 void GRPCONV::Init(const char* f, const char* d, int dlen, int w, int h, bool is_m) {
850 if (filename) delete[] filename;
851 if (f == 0) {
852 char* fn = new char[1];
853 fn[0] = 0;
854 filename = fn;
855 } else {
856 char* fn = new char[strlen(f)+1];
857 strcpy(fn,f);
858 filename = fn;
859 }
860
861 data = d;
862 datalen = dlen;
863 width = w;
864 height = h;
865 is_mask = is_m;
866 }
867 class PDTCONV : public GRPCONV {
868 bool Read_PDT10(char* image);
869 bool Read_PDT11(char* image);
870 public:
871 PDTCONV(const char* _inbuf, int inlen, const char* fname);
872 ~PDTCONV() {}
873 bool Read(char* image);
874 };
875 class G00CONV : public GRPCONV {
876 struct REGION {
877 int x1, y1, x2, y2;
878 int Width() { return x2-x1+1;}
879 int Height() { return y2-y1+1;}
880 void FixVar(int& v, int& w) {
881 if (v < 0) v = 0;
882 if (v >= w) v = w-1;
883 }
884 void Fix(int w, int h) {
885 FixVar(x1,w);
886 FixVar(x2,w);
887 FixVar(y1,h);
888 FixVar(y2,h);
889 if (x1 > x2) x2 = x1;
890 if (y1 > y2) y2 = y1;
891 }
892 };
893
894 void Copy_16bpp(char* image, int x, int y, const char* src, int bpl, int h);
895 void Copy_32bpp(char* image, int x, int y, const char* src, int bpl, int h);
896 bool Read_Type0(char* image);
897 bool Read_Type1(char* image);
898 bool Read_Type2(char* image);
899 public:
900 G00CONV(const char* _inbuf, int _inlen, const char* fname);
901 ~G00CONV() { }
902 bool Read(char* image);
903 };
904
905 class BMPCONV : public GRPCONV {
906 public:
907 BMPCONV(const char* _inbuf, int _inlen, const char* fname);
908 ~BMPCONV() {};
909 bool Read(char* image);
910 };
911 #if HAVE_LIBPNG
912 class PNGCONV : public GRPCONV {
913 const char* png_data;
914 static void png_read(png_structp, png_bytep, png_size_t);
915
916 public:
917 PNGCONV(const char* _inbuf, int _inlen, const char* fname);
918 ~PNGCONV() {};
919 bool Read(char* image);
920 };
921 #endif
922
923 #if HAVE_LIBJPEG
924 class JPEGCONV : public GRPCONV {
925
926 public:
927 JPEGCONV(const char* _inbuf, int _inlen, const char* fname);
928 ~JPEGCONV() {};
929 bool Read(char* image);
930 void SetupSrc(struct jpeg_decompress_struct* cinfo, const char* data, int size);
931 static void init_source(j_decompress_ptr cinfo);
932 static boolean fill_input_buffer(j_decompress_ptr cinfo);
933 static void skip_input_data(j_decompress_ptr cinfo, long num_bytes);
934 static boolean resync_to_restart(j_decompress_ptr cinfo, int desired);
935 static void term_source(j_decompress_ptr cinf);
936 };
937 #endif
938
939 GRPCONV* GRPCONV::AssignConverter(const char* inbuf, int inlen, const char* fname) {
940 /* ファイルの内容に応じたコンバーターを割り当てる */
941 GRPCONV* conv = 0;
942 if (inlen < 10) return 0; /* invalid file */
943 if (conv == 0 && strncmp(inbuf, "PDT10", 5) == 0 || strncmp(inbuf, "PDT11", 5) == 0) { /* PDT10 or PDT11 */
944 conv = new PDTCONV(inbuf, inlen, fname);
945 if (conv->data == 0) { delete conv; conv = 0;}
946 }
947 #if HAVE_LIBPNG
948 unsigned char png_magic[4] = {0x89, 'P', 'N', 'G'};
949 if (conv == 0 && memcmp(inbuf, png_magic,4) == 0) {
950 conv = new PNGCONV(inbuf, inlen, fname);
951 if (conv->data == 0) { delete conv; conv = 0;}
952 }
953 #endif
954 #if HAVE_LIBJPEG
955 if ( conv == 0 && *(unsigned char*)inbuf == 0xff && *(unsigned char*)(inbuf+1) == 0xd8 &&
956 (strncmp(inbuf+6, "JFIF",4) == 0 || strncmp(inbuf+6,"Exif",4) == 0)) {
957 conv = new JPEGCONV(inbuf, inlen, fname);
958 if (conv->data == 0) { delete conv; conv = 0;}
959 }
960 #endif
961 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
962 conv = new BMPCONV(inbuf, inlen, fname);
963 if (conv->data == 0) { delete conv; conv = 0;}
964 }
965 if (conv == 0 && (inbuf[0] == 0 || inbuf[0] == 1 || inbuf[0] == 2)) { /* G00 */
966 conv = new G00CONV(inbuf, inlen, fname);
967 if (conv->data == 0) { delete conv; conv = 0;}
968 }
969 return conv;
970 }
971
972 PDTCONV::PDTCONV(const char* _inbuf, int _inlen,const char* filename) {
973 // PDT FILE のヘッダ
974 // +00 'PDT10' (PDT11 は未対応)
975 // +08 ファイルサイズ (無視)
976 // +0C width (ほぼすべて、640)
977 // +10 height(ほぼすべて、480)
978 // +14 (mask の) x 座標 (実際は無視・・・全ファイルで 0 )
979 // +1c (mask の) y座標 (実際は無視 ・・・全ファイルで 0 )
980 // +20 mask が存在すれば、mask へのポインタ
981
982 /* ヘッダチェック */
983 if (_inlen < 0x20) {
984 fprintf(stderr, "Invalid PDT file %s : size is too small\n",filename);
985 return;
986 }
987 if (strncmp(_inbuf, "PDT10", 5) != 0 && strncmp(_inbuf, "PDT11", 5) != 0) {
988 fprintf(stderr, "Invalid PDT file %s : not 'PDT10 / PDT11' file.\n", filename);
989 return;
990 }
991 if (size_t(_inlen) != size_t(read_little_endian_int(_inbuf+0x08))) {
992 fprintf(stderr, "Invalid archive file %s : invalid header.(size)\n",
993 filename);
994 return;
995 }
996
997 int w = read_little_endian_int(_inbuf+0x0c);
998 int h = read_little_endian_int(_inbuf+0x10);
999 int mask_pt = read_little_endian_int(_inbuf + 0x1c);
1000 Init(filename, _inbuf, _inlen, w, h, mask_pt ? true : false);
1001
1002 return;
1003 }
1004
1005
1006 G00CONV::G00CONV(const char* _inbuf, int _inlen, const char* filename) {
1007 // G00 FILE のヘッダ
1008 // +00 type (1, 2)
1009 // +01: width(word)
1010 // +03: height(word)
1011 // type 1: (color table 付き LZ 圧縮 ; PDT11 に対応)
1012 // +05: 圧縮サイズ(dword) ; +5 するとデータ全体のサイズ
1013 // +09: 展開後サイズ(dword)
1014 // type 2: (マスク可、画像を矩形領域に分割してそれぞれ圧縮)
1015 // +05: index size
1016 // +09: index table(each size is 0x18)
1017 // +00
1018 //
1019 // +09+0x18*size+00: data size
1020 // +09+0x18*size+04: out size
1021 // +09+0x18*size+08: (data top)
1022 //
1023
1024 /* データから情報読み込み */
1025 int type = *_inbuf;
1026
1027 int w = read_little_endian_short(_inbuf+1);
1028 int h = read_little_endian_short(_inbuf+3);
1029 if (w < 0 || h < 0) return;
1030
1031 if (type == 0 || type == 1) { // color table 付き圧縮
1032 if (_inlen < 13) {
1033 fprintf(stderr, "Invalid G00 file %s : size is too small\n",filename);
1034 return;
1035 }
1036 int data_sz = read_little_endian_int(_inbuf+5);
1037
1038 if (_inlen != data_sz+5) {
1039 fprintf(stderr, "Invalid archive file %s : invalid header.(size)\n",
1040 filename);
1041 return;
1042 }
1043 Init(filename, _inbuf, _inlen, w, h, false);
1044 } else if (type == 2) { // color table なし、マスク付き可の圧縮
1045
1046 int head_size = read_little_endian_short(_inbuf+5);
1047 if (head_size < 0 || head_size*24 > _inlen) return;
1048
1049 const char* data_top = _inbuf + 9 + head_size*24;
1050 int data_sz = read_little_endian_int(data_top);
1051 if (_inbuf + _inlen != data_top + data_sz) {
1052 fprintf(stderr, "Invalid archive file %s : invalid header.(size)\n",
1053 filename);
1054 return;
1055 }
1056 Init(filename, _inbuf, _inlen, w, h, true);
1057 }
1058 return;
1059 }
1060
1061 bool G00CONV::Read(char* image) {
1062 if (data == 0) return false;
1063 /* header 識別 */
1064 int type = *data;
1065 if (type == 0) return Read_Type0(image);
1066 else if (type == 1) return Read_Type1(image);
1067 else if (type == 2) return Read_Type2(image);
1068 }
1069
1070 /* 一般的な LZ 圧縮の展開ルーチン */
1071 /* datasize はデータの大きさ、char / short / int を想定 */
1072 /* datatype は Copy1Pixel (1データのコピー)及び ExtractData(LZ 圧縮の情報を得る
1073 ** というメソッドを実装したクラス */
1074 static int bitrev_table[256] = {
1075 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
1076 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
1077 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
1078 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
1079 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
1080 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
1081 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
1082 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
1083 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
1084 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
1085 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
1086 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
1087 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
1088 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
1089 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
1090 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff};
1091 template<class DataType, class DataSize> inline int lzExtract(DataType& datatype,const char*& src, char*& dest, const char* srcend, char* destend) {
1092 int count = 0;
1093 const char* lsrcend = srcend; char* ldestend = destend;
1094 const char* lsrc = src; char* ldest = dest;
1095
1096 if (lsrc+50 < lsrcend && ldest+1024 < ldestend) {
1097 /* まず、範囲チェックを緩くして高速なルーチンを使う */
1098 lsrcend -= 50;
1099 ldestend += 1024;
1100 while (ldest < ldestend && lsrc < lsrcend) {
1101 count += 8;
1102 int flag = int(*(unsigned char*)lsrc++);
1103 if (datatype.IsRev()) flag = bitrev_table[flag];
1104 int i; for (i=0; i<8; i++) {
1105 if (flag & 0x80) {
1106 datatype.Copy1Pixel(lsrc, ldest);
1107 } else {
1108 int data, size;
1109 datatype.ExtractData(lsrc, data, size);
1110 DataSize* p_dest = ((DataSize*)ldest) - data;
1111 int k; for (k=0; k<size; k++) {
1112 p_dest[data] = *p_dest;
1113 p_dest++;
1114 }
1115 ldest += size*sizeof(DataSize);
1116 }
1117 flag <<= 1;
1118 }
1119 }
1120 lsrcend += 50;
1121 ldestend += 1024;
1122 }
1123 /* 残りを変換 */
1124 while (ldest < ldestend && lsrc < lsrcend) {
1125 count += 8;
1126 int flag = int(*(unsigned char*)lsrc++);
1127 if (datatype.IsRev()) flag = bitrev_table[flag];
1128 int i; for (i=0; i<8 && ldest < ldestend && lsrc < lsrcend; i++) {
1129 if (flag & 0x80) {
1130 datatype.Copy1Pixel(lsrc, ldest);
1131 } else {
1132 int data, size;
1133 datatype.ExtractData(lsrc, data, size);
1134 DataSize* p_dest = ((DataSize*)ldest) - data;
1135 int k; for (k=0; k<size; k++) {
1136 p_dest[data] = *p_dest;
1137 p_dest++;
1138 }
1139 ldest += size*sizeof(DataSize);
1140 }
1141 flag <<= 1;
1142 }
1143 }
1144 dest=ldest; src=lsrc;
1145 return 0;
1146 }
1147 /* 引数を減らすためのwrapper */
1148 template<class DataType, class DataSize> inline int lzExtract(DataType datatype, DataSize datasize ,const char*& src, char*& dest, const char* srcend, char* destend) {
1149 return lzExtract<DataType, DataSize>(datatype,src,dest,srcend,destend);
1150 }
1151
1152 /* 普通の PDT */
1153 class Extract_DataType {
1154 public:
1155 static void ExtractData(const char*& lsrc, int& data, int& size) {
1156 data = read_little_endian_short(lsrc) & 0xffff;
1157 size = (data & 0x0f) + 1;
1158 data = (data>>4)+1;
1159 lsrc += 2;
1160 }
1161 static void Copy1Pixel(const char*& lsrc, char*& ldest) {
1162 #ifdef WORDS_BIGENDIAN
1163 ldest[3] = lsrc[0];
1164 ldest[2] = lsrc[1];
1165 ldest[1] = lsrc[2];
1166 ldest[0] = 0;
1167 #else
1168 *(int*)ldest = read_little_endian_int(lsrc); ldest[3]=0;
1169 #endif
1170 lsrc += 3; ldest += 4;
1171 }
1172 static int IsRev(void) { return 0; }
1173 };
1174
1175 /* PDT11 の第一段階変換 */
1176 class Extract_DataType_PDT11 {
1177 int* index_table;
1178 public:
1179 Extract_DataType_PDT11(int* it) { index_table = it; }
1180 void ExtractData(const char*& lsrc, int& data, int& size) {
1181 data = int(*(const unsigned char*)lsrc);
1182 size = (data>>4) + 2;
1183 data = index_table[data&0x0f];
1184 lsrc++;
1185 }
1186 static void Copy1Pixel(const char*& lsrc, char*& ldest) {
1187 *ldest = *lsrc;
1188 ldest++; lsrc++;
1189 }
1190 static int IsRev(void) { return 0; }
1191 };
1192 /* マスク用 */
1193 class Extract_DataType_Mask {
1194 public:
1195 void ExtractData(const char*& lsrc, int& data, int& size) {
1196 int d = read_little_endian_short(lsrc) & 0xffff;
1197 size = (d & 0xff) + 2;
1198 data = (d>>8)+1;
1199 lsrc += 2;
1200 }
1201 static void Copy1Pixel(const char*& lsrc, char*& ldest) {
1202 *ldest = *lsrc;
1203 ldest++; lsrc++;
1204 }
1205 static int IsRev(void) { return 0; }
1206 };
1207 /* 書庫用 */
1208 class Extract_DataType_ARC {
1209 public:
1210 void ExtractData(const char*& lsrc, int& data, int& size) {
1211 data = read_little_endian_short(lsrc) & 0xffff;
1212 size = (data&0x0f) + 2;
1213 data = (data>>4) + 1;
1214 lsrc+= 2;
1215 }
1216 static void Copy1Pixel(const char*& lsrc, char*& ldest) {
1217 *ldest = *lsrc;
1218 ldest++; lsrc++;
1219 }
1220 static int IsRev(void) { return 0; }
1221 };
1222 /* avg2000 のシナリオ用 */
1223 class Extract_DataType_SCN2k {
1224 public:
1225 void ExtractData(const char*& lsrc, int& data, int& size) {
1226 data = read_little_endian_short(lsrc) & 0xffff;
1227 size = (data&0x0f) + 2;
1228 data = (data>>4);
1229 lsrc+= 2;
1230 }
1231 static void Copy1Pixel(const char*& lsrc, char*& ldest) {
1232 *ldest = *lsrc;
1233 ldest++; lsrc++;
1234 }
1235 static int IsRev(void) { return 1; }
1236 };
1237 /* ReadLive の type0 */
1238 class Extract_DataType_G00Type0 {
1239 public:
1240 static void ExtractData(const char*& lsrc, int& data, int& size) {
1241 data = read_little_endian_short(lsrc) & 0xffff;
1242 size = ((data & 0x0f)+ 1) * 3;
1243 data = (data>>4) * 3;
1244 lsrc += 2;
1245 }
1246 static void Copy1Pixel(const char*& lsrc, char*& ldest) {
1247 #ifdef WORDS_BIGENDIAN
1248 ldest[0] = lsrc[0];
1249 ldest[1] = lsrc[1];
1250 ldest[2] = lsrc[2];
1251 #else /* LITTLE ENDIAN / intel architecture */
1252 *(int*)ldest = *(int*)lsrc;
1253 #endif
1254 lsrc += 3; ldest += 3;
1255 }
1256 static int IsRev(void) { return 1; }
1257 };
1258
1259
1260 bool PDTCONV::Read(char* image) {
1261 if (data == 0) return false;
1262
1263 if (strncmp(data, "PDT10", 5) == 0) {
1264 if (! Read_PDT10(image)) return false;
1265 } else if (strncmp(data, "PDT11", 5) == 0) {
1266 if (! Read_PDT11(image)) return false;
1267 }
1268 if (! is_mask) return true;
1269 // マスク読み込み
1270 int mask_pt = read_little_endian_int(data + 0x1c);
1271 char* buf = new char[width*height+1024];
1272 const char* src = data + mask_pt;
1273 const char* srcend = data + datalen;
1274 char* dest = buf;
1275 char* destend = buf + width*height;
1276 while(lzExtract(Extract_DataType_Mask(), char(), src, dest, srcend, destend)) ;
1277 int i; int len = width*height;
1278 src = buf; dest = image;
1279 for (i=0; i<len; i++) {
1280 *(int*)dest |= int(*(unsigned char*)src) << 24;
1281 src++;
1282 dest += 4;
1283 }
1284 delete[] buf;
1285 return true;
1286 }
1287
1288
1289 bool PDTCONV::Read_PDT10(char* image) {
1290 int mask_pt = read_little_endian_int(data + 0x1c);
1291
1292 const char* src = data + 0x20;
1293 const char* srcend;
1294 if (mask_pt == 0) srcend = data + datalen;
1295 else srcend = data + mask_pt;
1296
1297 char* dest = image;
1298 char* destend;
1299
1300 destend = image + width*height*4;
1301 while(lzExtract(Extract_DataType(), int(), src, dest, srcend, destend)) ;
1302 return true;
1303 }
1304 bool PDTCONV::Read_PDT11(char* image) {
1305 int index_table[16];
1306 int color_table[256];
1307 int i;
1308 for (i=0; i<16; i++)
1309 index_table[i] = read_little_endian_int(data + 0x420 + i*4);
1310
1311 int mask_pt = read_little_endian_int(data + 0x1c);
1312
1313 const char* src = data + 0x460;
1314 const char* srcend;
1315 if (mask_pt == 0) srcend = data + datalen;
1316 else srcend = data + mask_pt;
1317
1318 char* dest = image;
1319 char* destend = image + width*height;
1320
1321 while(lzExtract(Extract_DataType_PDT11(index_table), char(), src, dest, srcend, destend)) ;
1322
1323 const char* cur = data + 0x20;
1324 for (i=0; i<256; i++) {
1325 color_table[i] = read_little_endian_int(cur);
1326 cur += 4;
1327 }
1328 src = image + width*height;
1329 int* desti = (int*)(image + width*height*4);
1330 while(desti != (int*)image)
1331 *--desti = color_table[*(unsigned char*)--src];
1332 return true;
1333 }
1334
1335 /* dest は dest_end よりも 256 byte 以上先まで
1336 ** 書き込み可能であること。
1337 */
1338 void ARCINFO::Extract(char*& dest_start, char*& src_start, char* dest_end, char* src_end) {
1339 const char* src = src_start;
1340 while (lzExtract(Extract_DataType_ARC(), char(), src, dest_start, src_end, dest_end)) ;
1341 src_start = (char*)src;
1342 return;
1343 }
1344 void ARCINFO::Extract2k(char*& dest_start, char*& src_start, char* dest_end, char* src_end) {
1345 const char* src = src_start;
1346 while (lzExtract(Extract_DataType_SCN2k(), char(), src, dest_start, src_end, dest_end)) ;
1347 src_start = (char*)src;
1348 return;
1349 }
1350
1351 bool ARCINFO_AVG32::ExecExtract(void) {
1352 // ヘッダのチェック
1353 if (strncmp(data, "PACK", 4) != 0) return false;
1354 if (read_little_endian_int(data+8) != info.filesize) return false;
1355 if (read_little_endian_int(data+12) != info.arcsize) return false;
1356
1357 // ファイルを展開する
1358 char* ret_data = new char[info.filesize+1024];
1359
1360 const char* s = data + 0x10;
1361 const char* send = data + info.arcsize;
1362 char* d = ret_data;
1363 char* dend = ret_data + info.filesize;
1364 while(lzExtract(Extract_DataType_ARC(), char(), s, d, send, dend)) ;
1365 if (! use_mmap) delete[] data;
1366 data = ret_data;
1367 return true;
1368 }
1369
1370 char ARCINFO2k::decode_seed[256] ={
1371 0x8b ,0xe5 ,0x5d ,0xc3 ,0xa1 ,0xe0 ,0x30 ,0x44 ,0x00 ,0x85 ,0xc0 ,0x74 ,0x09 ,0x5f ,0x5e ,0x33
1372 ,0xc0 ,0x5b ,0x8b ,0xe5 ,0x5d ,0xc3 ,0x8b ,0x45 ,0x0c ,0x85 ,0xc0 ,0x75 ,0x14 ,0x8b ,0x55 ,0xec
1373 ,0x83 ,0xc2 ,0x20 ,0x52 ,0x6a ,0x00 ,0xe8 ,0xf5 ,0x28 ,0x01 ,0x00 ,0x83 ,0xc4 ,0x08 ,0x89 ,0x45
1374 ,0x0c ,0x8b ,0x45 ,0xe4 ,0x6a ,0x00 ,0x6a ,0x00 ,0x50 ,0x53 ,0xff ,0x15 ,0x34 ,0xb1 ,0x43 ,0x00
1375 ,0x8b ,0x45 ,0x10 ,0x85 ,0xc0 ,0x74 ,0x05 ,0x8b ,0x4d ,0xec ,0x89 ,0x08 ,0x8a ,0x45 ,0xf0 ,0x84
1376 ,0xc0 ,0x75 ,0x78 ,0xa1 ,0xe0 ,0x30 ,0x44 ,0x00 ,0x8b ,0x7d ,0xe8 ,0x8b ,0x75 ,0x0c ,0x85 ,0xc0
1377 ,0x75 ,0x44 ,0x8b ,0x1d ,0xd0 ,0xb0 ,0x43 ,0x00 ,0x85 ,0xff ,0x76 ,0x37 ,0x81 ,0xff ,0x00 ,0x00
1378 ,0x04 ,0x00 ,0x6a ,0x00 ,0x76 ,0x43 ,0x8b ,0x45 ,0xf8 ,0x8d ,0x55 ,0xfc ,0x52 ,0x68 ,0x00 ,0x00
1379 ,0x04 ,0x00 ,0x56 ,0x50 ,0xff ,0x15 ,0x2c ,0xb1 ,0x43 ,0x00 ,0x6a ,0x05 ,0xff ,0xd3 ,0xa1 ,0xe0
1380 ,0x30 ,0x44 ,0x00 ,0x81 ,0xef ,0x00 ,0x00 ,0x04 ,0x00 ,0x81 ,0xc6 ,0x00 ,0x00 ,0x04 ,0x00 ,0x85
1381 ,0xc0 ,0x74 ,0xc5 ,0x8b ,0x5d ,0xf8 ,0x53 ,0xe8 ,0xf4 ,0xfb ,0xff ,0xff ,0x8b ,0x45 ,0x0c ,0x83
1382 ,0xc4 ,0x04 ,0x5f ,0x5e ,0x5b ,0x8b ,0xe5 ,0x5d ,0xc3 ,0x8b ,0x55 ,0xf8 ,0x8d ,0x4d ,0xfc ,0x51
1383 ,0x57 ,0x56 ,0x52 ,0xff ,0x15 ,0x2c ,0xb1 ,0x43 ,0x00 ,0xeb ,0xd8 ,0x8b ,0x45 ,0xe8 ,0x83 ,0xc0
1384 ,0x20 ,0x50 ,0x6a ,0x00 ,0xe8 ,0x47 ,0x28 ,0x01 ,0x00 ,0x8b ,0x7d ,0xe8 ,0x89 ,0x45 ,0xf4 ,0x8b
1385 ,0xf0 ,0xa1 ,0xe0 ,0x30 ,0x44 ,0x00 ,0x83 ,0xc4 ,0x08 ,0x85 ,0xc0 ,0x75 ,0x56 ,0x8b ,0x1d ,0xd0
1386 ,0xb0 ,0x43 ,0x00 ,0x85 ,0xff ,0x76 ,0x49 ,0x81 ,0xff ,0x00 ,0x00 ,0x04 ,0x00 ,0x6a ,0x00 ,0x76};
1387 char ARCINFO2k::decode_seed2[16] = {
1388 0xa8, 0x28, 0xfd, 0x66,
1389 0xa0, 0x23, 0x77, 0x69,
1390 0xf9, 0x45, 0xf8, 0x2c,
1391 0x7c, 0x00, 0xad, 0xf4
1392 };
1393
1394 bool ARCINFO2k::ExecExtract(void) {
1395 int i;
1396 char* ret_data = new char[info.filesize + 1024];
1397 char* decoded_data = new char[info.arcsize + 1024];
1398
1399 /* header のコピー */
1400 memcpy(ret_data, data, info.private_data);
1401
1402 /* まず、xor の暗号化を解く */
1403 const char* s; const char* send;
1404 char* d; char* dend;
1405
1406 s = data + info.private_data;
1407 send = data + info.arcsize;
1408 d = decoded_data + info.private_data;
1409 dend = decoded_data + info.arcsize;
1410 i = 0;
1411 while(s != send)
1412 *d++ = *s++ ^ decode_seed[(i++)&0xff];
1413
1414 if (info.filesize == info.arcsize) {
1415 memcpy(ret_data+info.private_data, decoded_data + info.private_data + 8, info.arcsize - info.private_data - 8);
1416 } else {
1417 /* 圧縮されているなら、それを展開 */
1418 s = (const char*)(decoded_data + info.private_data + 8);
1419 send = (const char*)(decoded_data + info.arcsize);
1420 d = ret_data + info.private_data;
1421 dend = ret_data + info.filesize;
1422 while(lzExtract(Extract_DataType_SCN2k(), char(), s, d, send, dend)) ;
1423 }
1424 if (read_little_endian_int(data+4) == 0x1adb2) { // Little Busters!
1425 int header_size = info.private_data;
1426 for (i=0x100; i<=0x200 && header_size+i < info.filesize; i++) {
1427 ret_data[header_size+i] ^= decode_seed2[i&0x0f];
1428 }
1429 }
1430 delete[] decoded_data;
1431 if (! use_mmap) delete[] data;
1432 data = ret_data;
1433 return true;
1434 }
1435
1436 bool G00CONV::Read_Type0(char* image) {
1437 int uncompress_size = read_little_endian_int(data+9);
1438 char* uncompress_data = new char[uncompress_size+1024];
1439
1440 // まず展開
1441 const char* src = data + 13;
1442 const char* srcend = data + datalen;
1443 char* dest = uncompress_data;
1444 char* dstend = uncompress_data + uncompress_size;
1445 while(lzExtract(Extract_DataType_G00Type0(), char(), src, dest, srcend, dstend));
1446 // image にコピー
1447 CopyRGB(image, uncompress_data);
1448 delete[] uncompress_data;
1449 return true;
1450 }
1451 bool G00CONV::Read_Type1(char* image) {
1452 int i;
1453 int uncompress_size = read_little_endian_int(data+9) + 1;
1454 char* uncompress_data = new char[uncompress_size + 1024];
1455
1456 // まず、展開
1457 const char* src = data + 13;
1458 const char* srcend = data + datalen;
1459 char* dest = uncompress_data;
1460 char* destend = uncompress_data + uncompress_size;
1461
1462 while(lzExtract(Extract_DataType_SCN2k(), char(), src, dest, srcend, destend));
1463
1464 int colortable[256];
1465 memset(colortable, 0, sizeof(int)*256);
1466 int colortable_len = read_little_endian_short(uncompress_data);
1467 if (colortable_len > 256) colortable_len = 256;
1468 if (colortable_len < 0) colortable_len = 0;
1469 for (i=0; i<colortable_len; i++) {
1470 colortable[i] = read_little_endian_int(uncompress_data+2+i*4);
1471 }
1472 src = uncompress_data + 2 + read_little_endian_short(uncompress_data)*4;
1473 srcend = uncompress_data + uncompress_size;
1474 dest = image; destend = image + width*height*4;
1475 while(dest < destend && src < srcend) {
1476 *(int*)dest = colortable[*(unsigned char*)src];
1477 dest += 4; src ++;
1478 }
1479 delete[] uncompress_data;
1480 return true;
1481 }
1482
1483 bool G00CONV::Read_Type2(char* image) {
1484 memset(image, 0, width*height*4);
1485 /* 分割領域を得る */
1486 int region_deal = read_little_endian_int(data+5);
1487 REGION* region_table = new REGION[region_deal];
1488
1489 const char* head = data + 9;
1490 int i; for (i=0; i<region_deal; i++) {
1491 region_table[i].x1 = read_little_endian_int(head+0);
1492 region_table[i].y1 = read_little_endian_int(head+4);
1493 region_table[i].x2 = read_little_endian_int(head+8);
1494 region_table[i].y2 = read_little_endian_int(head+12);
1495 region_table[i].Fix(width, height);
1496 head += 24;
1497 }
1498
1499 // 展開
1500 int uncompress_size = read_little_endian_int(head+4);
1501 char* uncompress_data = new char[uncompress_size + 1024];
1502
1503 const char* src = head + 8;
1504 const char* srcend = data + datalen;
1505 char* dest = uncompress_data;
1506 char* destend = uncompress_data + uncompress_size;
1507 while(lzExtract(Extract_DataType_SCN2k(), char(), src, dest, srcend, destend));
1508
1509 /* region_deal2 == region_deal のはず……*/
1510 int region_deal2 = read_little_endian_int(uncompress_data);
1511 if (region_deal > region_deal2) region_deal = region_deal2;
1512
1513 for (i=0; i < region_deal; i++) {
1514 int offset = read_little_endian_int(uncompress_data + i*8 + 4);
1515 int length = read_little_endian_int(uncompress_data + i*8 + 8);
1516 src = (const char*)(uncompress_data + offset + 0x74);
1517 srcend = (const char*)(uncompress_data + offset + length);
1518 while(src < srcend) {
1519 int x, y, w, h;
1520 /* コピーする領域を得る */
1521 x = read_little_endian_short(src);
1522 y = read_little_endian_short(src+2);
1523 w = read_little_endian_short(src+6);
1524 h = read_little_endian_short(src+8);
1525 src += 0x5c;
1526
1527 x += region_table[i].x1;
1528 y += region_table[i].y1;
1529
1530 Copy_32bpp(image, x, y, src, w*4, h);
1531
1532 src += w*h*4;
1533 }
1534 }
1535 delete[] uncompress_data;
1536 return true;
1537 }
1538
1539 void G00CONV::Copy_32bpp(char* image, int x, int y, const char* src, int bpl, int h) {
1540 int i;
1541 int* dest = (int*)(image + x*4 + y*4*width);
1542 int w = bpl / 4;
1543 for (i=0; i<h; i++) {
1544 const char* s = src;
1545 int* d = dest;
1546 int j; for (j=0; j<w; j++) {
1547 *d++ = read_little_endian_int(s);
1548 s += 4;
1549 }
1550 src += bpl; dest += width;
1551 }
1552 }
1553
1554 void GRPCONV::CopyRGBA_rev(char* image, const char* buf) {
1555 int mask = is_mask ? 0 : 0xff000000;
1556 /* 色変換を行う */
1557 int len = width * height;
1558 int i;
1559 unsigned char* s = (unsigned char*)buf;
1560 int* d = (int*)image;
1561 for(i=0; i<len; i++) {
1562 *d = (int(s[2])) | (int(s[1])<<8) | (int(s[0])<<16) | (int(s[3])<<24) | mask;
1563 d++; s += 4;
1564 }
1565 return;
1566 }
1567
1568 void GRPCONV::CopyRGBA(char* image, const char* buf) {
1569 if (!is_mask) {
1570 CopyRGB(image, buf);
1571 return;
1572 }
1573 /* 色変換を行う */
1574 int len = width * height;
1575 int i;
1576 int* outbuf = (int*)image;
1577 for(i=0; i<len; i++) {
1578 *outbuf++ = read_little_endian_int(buf);
1579 buf += 4;
1580 }
1581 return;
1582 }
1583 void GRPCONV::CopyRGB(char* image, const char* buf) {
1584 /* 色変換を行う */
1585 int len = width * height;
1586 int i;
1587 unsigned char* s = (unsigned char*)buf;
1588 int* d = (int*)image;
1589 for(i=0; i<len; i++) {
1590 *d = (int(s[0])) | (int(s[1])<<8) | (int(s[2])<<16) | 0xff000000;
1591 d++; s+=3;
1592 }
1593 return;
1594 }
1595
1596 #if HAVE_LIBPNG
1597 PNGCONV::PNGCONV(const char* _inbuf, int _inlen, const char* _filename) {
1598 int w,h,type;
1599 png_structp png_ptr = 0;
1600 png_infop info_ptr = 0;
1601 png_infop end_info = 0;
1602
1603 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
1604 if (!png_ptr) return;
1605
1606 info_ptr = png_create_info_struct(png_ptr);
1607 if (!info_ptr) goto err;
1608
1609 end_info = png_create_info_struct(png_ptr);
1610 if (!end_info) goto err;
1611
1612 if (setjmp(png_jmpbuf(png_ptr))) {
1613 /* error occured !! */
1614 goto err;
1615 }
1616
1617 /* initialize I/O */
1618 png_data = _inbuf;
1619 png_set_read_fn(png_ptr, (png_voidp)this, &png_read);
1620
1621 png_read_info(png_ptr, info_ptr);
1622
1623 w = png_get_image_width(png_ptr, info_ptr);
1624 h = png_get_image_height(png_ptr, info_ptr);
1625 type = png_get_color_type(png_ptr, info_ptr);
1626
1627 if (type == PNG_COLOR_TYPE_GRAY || type == PNG_COLOR_TYPE_GRAY_ALPHA) goto err; // not supported
1628
1629 Init(filename, _inbuf, _inlen, w, h, type == PNG_COLOR_TYPE_RGB_ALPHA ? true : false);
1630
1631 err:
1632 if (png_ptr) {
1633 if (end_info)
1634 png_destroy_read_struct(&png_ptr, &info_ptr,&end_info);
1635 else if (info_ptr)
1636 png_destroy_read_struct(&png_ptr, &info_ptr,(png_infopp)0);
1637 else
1638 png_destroy_read_struct(&png_ptr, (png_infopp) 0,(png_infopp)0);
1639 }
1640 return;
1641 }
1642
1643 bool PNGCONV::Read(char* image) {
1644 if (data == 0) return false;
1645 bool retcode = false;
1646 int bpp = is_mask ? 4 : 3;
1647 int i;
1648 char* buf;
1649 png_bytepp row_pointers = 0;
1650
1651 png_structp png_ptr = 0;
1652 png_infop info_ptr = 0;
1653 png_infop end_info = 0;
1654
1655 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
1656 if (!png_ptr) goto err;
1657 info_ptr = png_create_info_struct(png_ptr);
1658 if (!info_ptr) goto err;
1659 end_info = png_create_info_struct(png_ptr);
1660 if (!end_info) goto err;
1661
1662 if (setjmp(png_jmpbuf(png_ptr))) {
1663 /* error occured !! */
1664 goto err;
1665 }
1666
1667 buf= new char[width*height*4];
1668 /* initialize I/O */
1669 png_data = data;
1670 png_set_read_fn(png_ptr, (png_voidp)this, &png_read);
1671
1672 row_pointers = (png_bytepp)png_malloc(png_ptr, height*sizeof(png_bytep));
1673 for (i=0; i<height; i++) row_pointers[i] = (png_bytep)(buf + width*bpp*i);
1674 png_set_rows(png_ptr, info_ptr, row_pointers);
1675
1676 png_read_png(png_ptr, info_ptr,
1677 PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_BGR,0);
1678
1679 if (buf != image) {
1680 CopyRGBA(image, buf);
1681 delete[] buf;
1682 }
1683 png_free(png_ptr, (png_voidp)row_pointers);
1684
1685 retcode = true;
1686 err:
1687 if (png_ptr) {
1688 if (end_info)
1689 png_destroy_read_struct(&png_ptr, &info_ptr,&end_info);
1690 else if (info_ptr)
1691 png_destroy_read_struct(&png_ptr, &info_ptr,(png_infopp)0);
1692 else
1693 png_destroy_read_struct(&png_ptr, (png_infopp) 0,(png_infopp)0);
1694 }
1695 return retcode;
1696 }
1697
1698 void PNGCONV::png_read(png_structp png_ptr, png_bytep d, png_size_t sz) {
1699 PNGCONV* orig = (PNGCONV*)png_get_io_ptr(png_ptr);
1700 memcpy(d, orig->png_data, sz);
1701 orig->png_data += sz;
1702 return;
1703 }
1704 #endif /* HAVE_LIBPNG */
1705
1706 #if HAVE_LIBJPEG
1707 JPEGCONV::JPEGCONV(const char* _inbuf, int _inlen, const char* _filename) {
1708 int w,h,type;
1709 JSAMPARRAY rows, rows_orig; int i;
1710 char* buf = 0;
1711
1712 struct jpeg_decompress_struct cinfo;
1713 struct jpeg_error_mgr jerr;
1714 cinfo.err = jpeg_std_error(&jerr);
1715 jpeg_create_decompress(&cinfo);
1716 cinfo.src = new jpeg_source_mgr;
1717 SetupSrc(&cinfo, _inbuf, _inlen);
1718
1719 if (jpeg_read_header(&cinfo, TRUE) == JPEG_HEADER_OK) {
1720 Init(filename, _inbuf, _inlen, cinfo.image_width, cinfo.image_height, false);
1721 }
1722 delete cinfo.src;
1723 cinfo.src = 0;
1724 jpeg_destroy_decompress(&cinfo);
1725 return;
1726 }
1727
1728 bool JPEGCONV::Read(char* image) {
1729 if (data == 0) return false;
1730 bool retcode = false;
1731 JSAMPARRAY rows, rows_orig; int i;
1732 char* buf = 0;
1733
1734 struct jpeg_decompress_struct cinfo;
1735 struct jpeg_error_mgr jerr;
1736 cinfo.err = jpeg_std_error(&jerr);
1737 jpeg_create_decompress(&cinfo);
1738 cinfo.src = new jpeg_source_mgr;
1739 SetupSrc(&cinfo, data, datalen);
1740
1741 if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK) goto err;
1742
1743 cinfo.out_color_space = JCS_RGB;
1744
1745 jpeg_start_decompress(&cinfo);
1746
1747 rows = new JSAMPROW[height];
1748 rows_orig = rows;
1749 buf = new char[width*height*3];
1750 for (i=0; i<height; i++) rows[i] = (JSAMPROW)(buf+width*3*i);
1751
1752 for (i=0; i<height; ) {
1753 int cnt = jpeg_read_scanlines(&cinfo, rows, height-i);
1754 rows += cnt;
1755 i += cnt;
1756 }
1757 delete[] rows_orig;
1758 CopyRGBA_rev(image, buf);
1759 delete[] buf;
1760
1761 jpeg_finish_decompress(&cinfo);
1762 retcode = true;
1763 err:
1764 delete cinfo.src;
1765 cinfo.src = 0;
1766 jpeg_destroy_decompress(&cinfo);
1767 return retcode;
1768 }
1769
1770 void JPEGCONV::init_source(j_decompress_ptr cinfo) {
1771 }
1772 boolean JPEGCONV::fill_input_buffer(j_decompress_ptr cinfo) {
1773 static char dummy[1024];
1774 memset(dummy, 0, 1024);
1775 cinfo->src->next_input_byte = (const JOCTET*)dummy;
1776 cinfo->src->bytes_in_buffer = 1024;
1777 fprintf(stderr,"JPEGCONV::fill_input_buffer: warning corrupted jpeg stream\n");
1778 return TRUE;
1779 }
1780 void JPEGCONV::skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
1781 if (cinfo->src->bytes_in_buffer > num_bytes) {
1782 cinfo->src->next_input_byte += num_bytes;
1783 cinfo->src->bytes_in_buffer -= num_bytes;
1784 }
1785 }
1786 boolean JPEGCONV::resync_to_restart(j_decompress_ptr cinfo, int desired) {
1787 return jpeg_resync_to_restart(cinfo, desired);
1788 }
1789 void JPEGCONV::term_source(j_decompress_ptr cinf) {
1790 }
1791
1792 void JPEGCONV::SetupSrc(struct jpeg_decompress_struct* cinfo, const char* data, int size) {
1793 cinfo->src->next_input_byte = (const JOCTET*) data;
1794 cinfo->src->bytes_in_buffer = size;
1795 cinfo->src->init_source = init_source;
1796 cinfo->src->fill_input_buffer = fill_input_buffer;
1797 cinfo->src->skip_input_data = skip_input_data;
1798 cinfo->src->resync_to_restart = resync_to_restart;
1799 cinfo->src->term_source = term_source;
1800 }
1801 #endif /* HAVE_LIBJPEG */
1802 BMPCONV::BMPCONV(const char* _inbuf, int _inlen, const char* _filename) {
1803 /* データから情報読み込み */
1804 int w = read_little_endian_int(_inbuf + 0x12);
1805 int h = read_little_endian_int(_inbuf + 0x16);
1806 if (h < 0) h = -h;
1807 int bpp = read_little_endian_short(_inbuf + 0x1c);
1808 int comp = read_little_endian_int(_inbuf + 0x1e);
1809 Init(filename, _inbuf, _inlen, w, h, bpp==32 ? true : false);
1810 return;
1811 }
1812
1813 bool BMPCONV::Read(char* image) {
1814 if (data == 0) return false;
1815
1816 /* マスクのチェック */
1817 int bpp = read_little_endian_short(data+0x1c);
1818 int h = read_little_endian_int(data + 0x16);
1819 int dsz = read_little_endian_int(data + 0x22);
1820 bpp /= 8;
1821
1822 int bpl = dsz / height;
1823 if (bpl == 0) bpl = bpp*width;
1824 bpl = bpp * width;
1825 bpl = (bpl+3) & (~3);
1826
1827
1828 int i;
1829 char* buf = new char[width*height*bpp+1024];
1830 const char* src = data + 0x36;
1831 char* dest = buf;
1832 if (h < 0) {
1833 for (i=0; i<height; i++) {
1834 memcpy(dest+i*width*bpp, src+i*bpl, width*bpp);
1835 }
1836 } else {
1837 for (i=0; i<height; i++) {
1838 memcpy(dest+i*width*bpp, src+(height-i-1)*bpl, width*bpp);
1839 }
1840 }
1841 if (bpp == 3) CopyRGB(image, buf);
1842 else /* bpp == 4 */ CopyRGBA(image, buf);
1843 delete[] buf;
1844 return true;
1845 }
1846