diff system/visarc.cc @ 0:223b71206888

Initial import
author thib
date Fri, 01 Aug 2008 16:32:45 +0000
parents
children 3a6aaeab7b4e
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/system/visarc.cc
@@ -0,0 +1,296 @@
+#define CMDNAME "visarc"
+#define VERSION "1.00"
+
+/*****************************************
+**	Visual Arts の圧縮書庫ファイルを
+**	展開する
+**
+**	usage : visarc x <arcfile> <file> [<file> ...]
+**		visarc l <arcfile>
+**		visarc g <arcfile> <graphic file>
+**		visarc m <arcfile> <mask file>
+**
+******************************************
+*/
+/*
+ *
+ *  Copyright (C) 2000-   Kazunori Ueno(JAGARL) <jagarl@creator.club.ne.jp>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+// use only file subsystem
+#include "file.h"
+#include "file_impl.h"
+// #include "file.cc"
+
+#ifdef HAVE_LIBPNG
+#include <png.h>
+#endif
+
+void usage(void) {
+	fprintf(stderr, "usage : visarc <cmd> <arcfile> [<file1> [<file2> [...] ]]\n");
+	fprintf(stderr, "           cmd :   x : extract\n");
+	fprintf(stderr, "                   l : list all files\n");
+	fprintf(stderr, "\n");
+#ifdef HAVE_LIBPNG
+	fprintf(stderr, "usage2: visarc <cmd> <pdt-file> [<output-file>]\n");
+	fprintf(stderr, "           cmd     p : unpack pdt file and save as png file\n");
+#endif /* HAVE_LIBPNG */ 
+	fprintf(stderr, "\n");
+}
+
+void List(char* path) {
+	ARCFILE* file;
+	FILE* f = fopen(path, "rb");
+	if (f == 0) return;
+	char header[32];
+	fread(header, 32, 1, f);
+	fclose(f);
+	char magic_raf[8] = {'C','A','P','F',1,0,0,0};
+	if (strncmp(header, "PACL", 4) == 0) file = new ARCFILE(path);
+	else file = new SCN2kFILE(path);
+	file->Init();
+	file->ListFiles(stdout);
+	delete file;
+	return;
+}
+
+void ExtractOne(ARCFILE* arc, char* file) {
+	ARCINFO* info = arc->Find(file,"");
+	if (info == 0) {
+		fprintf(stderr, "Cannot find file %s in archive\n",file);
+		return;
+	}
+	FILE* out = fopen(file, "w");
+	if (out == 0) {
+		delete info;
+		fprintf(stderr, "Cannot open output file %s\n",file);
+		return;
+	}
+	
+	fprintf(stdout, "Extracting %s ... ",file);
+	int size = info->Size();
+	const char* data = info->Read();
+	fwrite(data, size, 1, out);
+	fclose(out);
+	fprintf(stdout, "done\n");
+	delete info;
+	return;
+}
+
+void Extract(char* path, char** files, int fnum) {
+	ARCFILE* file;
+	FILE* f = fopen(path, "rb");
+	if (f == 0) return;
+	char header[32];
+	fread(header, 32, 1, f);
+	fclose(f);
+	char magic_raf[8] = {'C','A','P','F',1,0,0,0};
+	if (strncmp(header, "PACL", 4) == 0) file = new ARCFILE(path);
+	else file = new SCN2kFILE(path);
+	file->Init();
+	if (files != 0 && fnum != 0) {
+		int i; for (i=0; i<fnum; i++) {
+			ExtractOne(file, files[i]);
+		}
+	} else {
+		file->InitList();
+		char* path; while( (path=file->ListItem()) != 0) {
+			ExtractOne(file, path);
+		}
+	}
+	delete file;
+	return;
+}
+
+void ChangeExt(char* path, char* new_ext, char* buf) {
+	char* name = strrchr(path, DIR_SPLIT);
+	if (name == 0) name = path;
+	else name++;
+	int path_len = name - path;
+
+	char* ext = strrchr(name, '.');
+	int ext_len;
+	if (ext) ext_len = ext - name;
+	else ext_len = strlen(name);
+
+	strncpy(buf, path, path_len+ext_len);
+	strcpy(buf+path_len+ext_len, new_ext);
+}
+
+char* ReadFile(char* fname, int* len) {
+	FILE* in = fopen(fname, "rb");
+	if (in == 0) return 0;
+	fseek(in,0,2); size_t s = ftell(in); fseek(in,0,0);
+	char* buf = new char[s];
+	fread(buf,s,1,in);
+	fclose(in);
+	if (len) *len = s;
+	return buf;
+}
+
+
+#ifdef HAVE_LIBPNG
+void create_png(FILE* stream, char* path, char* desc, int width, int height, char* data) {
+	png_structp png_ptr;
+	png_infop info_ptr;
+
+	/* create struct */
+	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+	if (png_ptr == NULL) return;
+
+	/* initialize information */
+	info_ptr = png_create_info_struct(png_ptr);
+	if (info_ptr == NULL) {
+		png_destroy_write_struct(&png_ptr, (png_infop*)NULL);
+		return;
+	}
+
+	if (setjmp(png_jmpbuf(png_ptr))) {
+		/* error occured !! */
+		png_destroy_write_struct(&png_ptr,&info_ptr);
+		fprintf(stderr, "Get error while processing PNG from file %s\n",path);
+		return;
+	}
+
+	/* initialize I/O (for stream) */
+	png_init_io(png_ptr, stream);
+
+	/* initialize headers */
+	png_set_IHDR(png_ptr, info_ptr,
+		width, height, 8 /* bit_dept */,
+		PNG_COLOR_TYPE_RGB_ALPHA,
+		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+	/* create text information */
+	png_text info_text[3];
+	info_text[0].key = "Title";
+	info_text[0].text= path;
+	info_text[0].compression = PNG_TEXT_COMPRESSION_NONE;
+	info_text[1].key = "Author";
+	info_text[1].text= CMDNAME " version " VERSION;
+	info_text[1].compression = PNG_TEXT_COMPRESSION_NONE;
+	info_text[2].key = "Description";
+	info_text[2].text= desc;
+	info_text[2].compression = PNG_TEXT_COMPRESSION_NONE;
+	png_set_text(png_ptr, info_ptr, info_text, 3);
+
+	/* write information */
+	png_write_info(png_ptr, info_ptr);
+
+	/* write body */
+	/* rgba image ; input/output is 32bpp.*/
+	char* row = new char[width*4];
+	int i; for (i=0; i<height; i++) {
+		char* row_ptr = row;
+		int j; for (j=0; j<width; j++) {
+			row_ptr[0] = data[2];
+			row_ptr[1] = data[1];
+			row_ptr[2] = data[0];
+			row_ptr[3] = data[3];
+			row_ptr += 4; data += 4;
+		}
+		png_write_rows(png_ptr, (png_byte**)&row, 1);
+	}
+	png_write_end(png_ptr, info_ptr);
+	png_destroy_write_struct(&png_ptr, &info_ptr);
+	return;
+}
+
+void ExtractPngRgbaGraphic(char* path,char* outpath = 0) {
+	char buf[1024]; char* fname = buf;
+	int len;
+	char* dat = ReadFile(path, &len);
+	if (dat == 0) {
+		fprintf(stderr, "Cannot open PDT file : %s\n",path);
+		return;
+	}
+	GRPCONV* conv = GRPCONV::AssignConverter(dat, len, path);
+	if (conv == 0) {
+		fprintf(stderr, "Invalid format\n");
+		return;
+	}
+	bool masked = conv->IsMask();
+	char* data = new char[conv->Width() * conv->Height() * 4 + 1024];
+	if (! conv->Read(data)) {
+		fprintf(stderr, "Insufficient memory\n");
+		delete conv;
+		return;
+	}
+	if (! masked) {
+		for (int i = 0; i < conv->Width() * conv->Height(); i++) {
+			data[4*i+3] = 0xff;	// 不透明度を最大にする
+		}
+	}
+	if (outpath == 0) ChangeExt(path,".png", buf); // path をつくる
+	else fname = outpath;
+	FILE* out = fopen(fname, "wb"); // ファイルを開く
+	if (out == 0) {
+		fprintf(stderr, "Cannot open raw file : %s\n",buf);
+		delete conv;
+		return;
+	}
+	create_png(out, path, "", conv->Width(), conv->Height(), data);
+  	fclose(out);
+  	
+	delete conv;
+}
+#endif /* HAVE_LIBPNG */
+
+int main(int argc, char* argv[]) {
+	int i; 
+	fprintf(stderr, "%s version %s\n", CMDNAME, VERSION);
+	if (argc < 3) { 
+		usage(); return -1;
+	}
+	if (strlen(argv[1]) != 1) {
+		usage(); return -1;
+	}
+	for (i=2; i<argc; i++) {
+		/* option を削る */
+		argc--;
+		int j; for (j=i; j<argc; j++) argv[j] = argv[j+1];
+	}
+	switch(argv[1][0]) {
+		case 'x': case 'X':
+			if (argc < 4) Extract(argv[2], 0, -1);
+			else Extract(argv[2], argv+3, argc-3);
+			break;
+		case 'l': case 'L':
+			List(argv[2]);
+			break;
+#ifdef HAVE_LIBPNG
+		case 'p': case 'P':
+		case 'a': case 'A':
+			if (argc < 4)
+				ExtractPngRgbaGraphic(argv[2]);
+			else
+				ExtractPngRgbaGraphic(argv[2],argv[3]);
+			break;
+#endif /* HAVE_LIBPNG */
+		default:
+			usage(); return -1;
+	}
+	return 0;
+}