他人の空似自作物置場

touhouSE_old.zip/touhouSE_src/th11.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include "lib.h"
#include "png.h"
#include "main.h"
#include "th11.h"

typedef struct region{
	int id;
	float left;
	float top;
	float right;
	float bottom;
}REGION;

typedef struct attr{
	unsigned short type;
	unsigned short len;
	int addr;
}ATTR;

struct dat_data th11dat;

int getnbit(unsigned char *s,int *a,int len){
	unsigned char map[40],*b;
	int i,l,t,max;

	max = ((*a%8)+len)/8 + 1;

	i = *a;
	*a += len;
	s += i/8;
	i = i%8;
	t = i;

	l = 0;
	while(l < max){
		while(i < 8){
			map[l*8+i-t] = (s[l]&(1<<(7-i)))>>(7-i);
			i++;
		}
		i = 0;
		l++;
	}

	i = len;
	t = 0;
	while(i > 0){
		i--;
		t += map[len-i-1]<<i;
	}

	return t;
}
#define getbit(x,y)	getnbit(x,y,1)

#define DICT_SIZE 0x2000
void decomp(unsigned char *in,int in_size,unsigned char *out,int out_size){
	unsigned char dict[DICT_SIZE],*o;
	unsigned int dictop = 1;
	int b = 0,c,i;
	int patofs,patlen;

	o = out;
	memset(dict, 0, DICT_SIZE);
	while(1){
		if(getnbit(in,&b,1)) {
			c = getnbit(in,&b,8);
			if(o-out >= out_size){return;}
			*o = c;
			o++;
			dict[dictop % DICT_SIZE] = c;
			dictop++;
		} else {
			patofs = getnbit(in,&b,13);
			if(!patofs)return;
			patlen = getnbit(in,&b,4) + 3;
			for(i = 0; i < patlen; ++i){
				c = dict[(patofs + i) % DICT_SIZE];
				if(o-out >= out_size){return;}
				*o = c;
				o++;
				dict[dictop % DICT_SIZE] = c;
				dictop++;
			}
		}
	}
}
/*
void thcrypter(unsigned char *data,int size,unsigned char key,unsigned char step,int block,int limit){
	unsigned char *map,*in,*out;
	int addup;
	int i,j;

	//printf("%d\t%x\t%x\t%x\t%x\n",size,key,step,block,limit);

	addup = size % block;
	if(addup >= block / 4) addup = 0;
	addup += size % 2;
	size -= addup;

	map = malloc(block);
	while(size > 0 && limit > 0) {
		if(size < block)block = size;
		memcpy(map,data,block);
		in = map;
		j = 1;
		while(j < 3){
			out = data+block-j;
			i = 0;
			while(i < block / 2){
				*out = *in ^ key;
				in++;
				out -= 2;
				key += step;
				i++;
			}
			j++;
		}
		data += block;
		limit -= block;
		size -= block;
	}
	free(map);
}*/

void thcrypter(unsigned char* in,int size,unsigned char key,unsigned char step,int block,int limit){
	const unsigned char* iend;
	const unsigned char* ilimit;
	unsigned char* ip;
	const unsigned char* irealend = in + size;
	unsigned int rest;
	unsigned char *out,*_in,*_out;

	_in = in;
	_out = out = malloc(size);
	rest = size % block;
	if (rest >= block / 4)
		rest = 0;
	rest += size % 2;
	size -= rest;

	for(iend = out + size, ilimit = out + limit; out < iend && out < ilimit; out += block){
		int increment;
		if (iend - out < block)
			block = iend - out;
		increment = block / 2;
		if (block % 2)
			increment++;

		for (ip = out + block - 1; ip > out; ip -= 2) {
			*ip = *in ^ key;
			*(ip - 1) = *(in + increment) ^ ((key + step * increment));
			in++;
			key += step;
		}

		if (block % 2) {
			*ip = *in ^ key;
			key += step;
		}

		/* Increment key by step * (block / 2). */
		key += step * increment;
		/* Increment out by (block / 2). */
		in += increment;
	}

	if (in != irealend)
		memcpy(out, in, irealend - in);

	memcpy(_in,_out,size+rest);
	free(_out);
}


char *th11_extract(int num){
	static int conv_map[8][4] = {	{0x1b,	0x37,	0x40,	0x2800},
					{0x51,	0xe9,	0x40,	0x3000},
					{0xc1,	0x51,	0x80,	0x3200},
					{0x03,	0x19,	0x400,	0x7800},
					{0xab,	0xcd,	0x200,	0x2800},
					{0x12,	0x34,	0x80,	0x3200},
					{0x35,	0x97,	0x80,	0x2800},
					{0x99,	0x37,	0x400,	0x2000}};
	int i,size,comp;
	char *data,*fn,*ret;


	size = list[num].size;
	comp = list[num].comp_size;
	data = malloc(comp);
	fseek(fp,list[num].addr,SEEK_SET);
	fread(data,1,comp,fp);
	fn = list[num].fn;

	i = 0;
	while(*fn){i += *fn;fn++;}
	i = i&0x07;
	thcrypter(data,comp,conv_map[i][0],conv_map[i][1],conv_map[i][2],conv_map[i][3]);

	if(size != comp){
		ret = malloc(size);
		decomp(data,comp,ret,size);
		free(data);
	} else {
		ret = data;
	}

	return ret;
}

void read_region(char *head,int num,char *p,char *filename,int x,int y,int add){
	REGION reg;
	int addr,i;
	char fn[256];
	FILE *fp;

	strcpy(fn,filename);
	strcpy(&fn[strlen(fn)-4],".txt");
	if(add){
		fp = fopen2(fn,"a");
	} else {
		fp = fopen2(fn,"w");
		fprintf(fp,"//id\tleft\ttop\tright\tbottom\n");
	}
	i = 0;
	while(i < num){
		addr = *(int *)&head[i*4];
		memcpy(&reg,p+addr,sizeof(REGION));
		fprintf(fp,"%d\t%.0f\t%.0f\t%.0f\t%.0f\n",reg.id,reg.left+x,reg.top+y,reg.right,reg.bottom);
		i++;
	}
	fclose(fp);
}

void read_attr(ATTR *attr,int num,char *base,char *filename){
	int i;
	char fn[256];
	FILE *fp;

	strcpy(fn,filename);
	strcpy(&fn[strlen(fn)-4],".attr");
	fp = fopen2(fn,"w");
	i = 0;
	while(i < num){
		fprintf(fp,"%d\t%d\t0x%08x\n",attr[i].type,attr[i].len,attr[i].addr);
		i++;
	}
	fclose(fp);
}

PNG *col_sum(char *fn,COLOR *col,int w,int h,int w2,int h2){
	PNG *png;
	COLOR *c,*p,*a;
	int x,y,i,l;

	png = load_png(fn);
	if(png == NULL){
		png = malloc(sizeof(PNG));
		png->col = NULL;
		png->w = 0;
		png->h = 0;
		png->cn = 32;
		png->pal = NULL;
	}
	x = w2+w;
	y = h2+h;
	if(png->w > x)x = png->w;
	if(png->h > y)y = png->h;

	c = malloc(x*y*sizeof(COLOR));
	memset(c,0,x*y*sizeof(COLOR));
	if(png->col != NULL){
		i = 0;
		p = c;
		a = png->col;
		while(i < png->h){
			memcpy(p,a,png->w*sizeof(COLOR));
			p += x;
			a += png->w;
			i++;
		}
	}
	i = 0;
	p = c+w2+h2*x;
	a = col;
	while(i < h){
		memcpy(p,a,w*sizeof(COLOR));
		p += x;
		a += w;
		i++;
	}

	if(png->col != NULL)free(png->col);
	png->col = c;
	png->w = x;
	png->h = y;
	return png;
}
void th11img_convert(char *data,int size,char *filename){
	int w2,h2,w,h,i,l,len,cn,type;
	unsigned char *str,*str2,*s,*base,fn[256] = "data/";
	COLOR *col,*c;
	FILE *fp;
	PNG *png,*t;

	//printf("%s\n",filename);
	s = data;
	while(s-data < size){
		//w2 = *(short *)&s[0x0A];
		//h2 = *(short *)&s[0x0C];
		strcpy(&fn[5],s + *(int *)&s[0x10]);
		if(strcmp(&fn[strlen(fn)-4],".png") == 0){
			base = s;
			w2 = *(short *)&s[0x14];
			h2 = *(short *)&s[0x16];
			//printf("\t%s\t%d\t%d\t%d\t%d\n",fn,w2,h2,*(short *)&s[0x14],*(short *)&s[0x16]);
			//read_attr((ATTR*)&s[0x40+*(short *)&s[0x04]*4],*(short *)&s[0x06],s,fn);

			str = s + *(int *)&s[0x1C];

			if(strncmp(str,"THTX",4) != 0)return;
			type = *(short *)&str[6];
			w = *(short *)&str[8];
			h = *(short *)&str[10];
			len = *(int*)&str[12];
			str += 16;
			col = malloc(sizeof(col)*w*h);

			l = 0;
			if(type == 1){
				while(l < w*h){
					col[l].b = str[0];
					col[l].g = str[1];
					col[l].r = str[2];
					col[l].alpha = str[3];
					str+=4;
					l++;
				}
			} else if(type == 5){
				while(l < w*h){
					col[l].b = (str[0]&0x0F) << 4;
					col[l].g = str[0]&0xF0;
					col[l].r = (str[1]&0x0F) << 4;
					col[l].alpha = str[1]&0xF0;
					str+=2;
					l++;
				}
			} else if(type == 3){
				while(l < w*h){
					col[l].b = (str[0]&0x1F) << 3;
					col[l].g = ((str[0]&0xE0) >> 3) + ((str[1]&0x07) << 5);
					col[l].r = str[1]&0xF8;
					col[l].alpha = 0xFF;
					str+=2;
					l++;
				}
			} else {
				//printf("%s:unknown format(%d)\n",fn,type);
				while(l < w*h){
					col[l].b = str[0];
					col[l].g = str[1];
					col[l].r = 0;
					col[l].alpha = 0xFF;
					str+=2;
					l++;
				}
			}
			if(w2+h2 > 0 && NULL != (png = col_sum(fn,col,w,h,w2,h2)) ){
				//read_region(&base[0x40],*(short *)&base[0x04],base,fn,w2,h2,1);
				pngout(png->w,png->h,png->w,(char *)png->col,fn,png->cn);
				free(png->col);
				free(png);
			} else {
				//read_region(&base[0x40],*(short *)&base[0x04],base,fn,w2,h2,0);
				/*fp = fopen(fn,"rb");
				while(fp != NULL){
					strcpy(&fn[strlen(fn)-4],"_.png");
					fclose(fp);
					fp = fopen(fn,"rb");
				}*/
				pngout(w,h,w,(char *)col,fn,32);
			}
			free(col);
		}
		if(*(int *)&s[0x24]==0)break;
		s += *(int *)&s[0x24];
	}
}

int th11text_convert(unsigned char *data,unsigned int size){
	unsigned char a,b;
	unsigned int i;

	a = 0x77;
	b = 0x07;
	i = 0;
	do{
		data[i] ^= a;
		a += b;
		b += 0x10;
		i++;
		if(i >= size)return 1;
	}while(data[i-1] != '\0');
	return 0;
}
void th11msg_convert(char *in,int size,char *filename){
	int i,l,num,prev,flag,p;
	unsigned char data[256],fn[256],head[8];
	FILE *wfp;
	unsigned short id;
	unsigned char proc,len;
	char boolean[2][6] = {{"FALSE"},{"TRUE"}};

	num = *(int*)&in[0];//msg個数の取得
	sprintf(fn,"data/%s",filename);
	strcpy(&fn[strlen(fn)-4],".txt");
	wfp = fopen(fn,"w");

	if(fn[strlen(fn)-7] == 'e' || strncmp(&fn[strlen(fn)-9],"staff",5) == 0){
		flag = 0;
	} else {
		flag = 1;
	}

	i = 0;
	while(i < num){
		fprintf(wfp,"function proc%d{\n",i);
		p = *(int*)&in[4+8*i];
		prev = 0;
		do{
			id = *(short*)&in[p];
			proc = in[p+2];
			len = in[p+3];
			memcpy(data,&in[p+4],len);
			p += len+4;
			fprintf(wfp,"\t");
			if(prev < id){
				fprintf(wfp,"sleep(%d);\n\n\t",id-prev);
			}
			if(flag == 0){	//ED
				switch(proc){
					case 0x00:
						break;
					case 0x03:
						th11text_convert(data,len);
						fprintf(wfp,"print(\"%s\")\n",data);
						break;
					case 0x07:
						fprintf(wfp,"load_anm(%d,\"%s\");\n",*(int *)data,&data[4]);
						break;
					case 0x0A:
						fprintf(wfp,"play(\"%s\");\n",data);
						break;
					default:
						fprintf(wfp,"%d\t%d\t",proc,len);
						l = 0;
						while(l < len){
							fprintf(wfp,"%02x ",data[l]);
							l++;
						}
						fprintf(wfp,"\n");
						break;
				}
			} else {	//STG
				switch(proc){
					case 0x00:
						break;
					case 0x01:
						fprintf(wfp,"enable_img(player,%d);\n",*(int *)data);
						break;
					case 0x02:
						fprintf(wfp,"enable_img(enemy,%d);\n",*(int *)data);
						break;
					case 0x03:
						fprintf(wfp,"enable_textarea();\n");
						break;
					case 0x04:
						fprintf(wfp,"disable_img(player);\n");
						break;
					case 0x05:
						fprintf(wfp,"disable_img(enemy);\n");
						break;
					case 0x06:
						fprintf(wfp,"disable_textarea();\n");
						break;
					case 0x07:
						fprintf(wfp,"mode(player);\n");
						break;
					case 0x08:
						fprintf(wfp,"mode(enemy);\n");
						break;
					case 0x09:
						fprintf(wfp,"mode(other);\n");
						break;
					case 0x0A:
						fprintf(wfp,"skip(%s);\n",boolean[*(int *)data]);
						break;
					case 0x0B:
						fprintf(wfp,"enter_sleep(%d);\n",*(int *)data);
						break;
					case 0x0C:
						fprintf(wfp,"call_boss();\n");
						break;
					case 0x0D:
						fprintf(wfp,"image_change(player,%d);\n",*(int *)data);
						break;
					case 0x0E:
						fprintf(wfp,"image_change(enemy,%d);\n",*(int *)data);
						break;
					case 0x11:
						th11text_convert(data,len);
						fprintf(wfp,"print(\"%s\");\n",data);
						break;
					case 0x13:
						fprintf(wfp,"play_bgm();\n");
						break;
					case 0x14:
						fprintf(wfp,"name_img();\n");
						break;
					case 0x15:
						fprintf(wfp,"next_stage();\n");
						break;
					case 0x16:
						fprintf(wfp,"end_bgm();\n");
						break;
					case 0x19:
						fprintf(wfp,"print_position(%d);\n",*(int *)data);
						break;
					case 0x1b:
						fprintf(wfp,"bgm_fadeout(%f);\n",*(float *)data);
						break;
					default:
						fprintf(wfp,"%d\t%d\t%d\t",id,proc,len);
						l = 0;
						while(l < len){
							fprintf(wfp,"%02x ",data[l]);
							l++;
						}
						fprintf(wfp,"\n");
						break;
				}
			}
			prev = id;
		}while(proc != 0x00);
		fseek(wfp,-1,SEEK_CUR);
		fprintf(wfp,"}\n",i);
		i++;
	}
	fclose(wfp);
}
void th11_putfile(char *data,int size,char *fn){
	FILE *fp;
	char str[256] = "data/",s[256];

	if(strcmp(&fn[strlen(fn)-4],".anm") == 0){
		th11img_convert(data,size,fn);
	} else if(strcmp(&fn[strlen(fn)-4],".msg") == 0){
		th11msg_convert(data,size,fn);
	} else {
		strcpy(&str[5],fn);
		fp = fopen2(str,"wb");
		fwrite(data,1,size,fp);
		fclose(fp);/*
		if(strcmp(&fn[strlen(fn)-4],".msg") == 0){
			sprintf(s,"msg2txt %s",str);
			system(s);
			remove(str);
		}*/
	}
}


int head_print(char *data,int size,int num){
	int i,a,comp;
	LIST *p;

	list = malloc(sizeof(LIST)*num);
	if(list == NULL)return 1;

	i = 0;
	a = 0;
	while(i < size && a < num){
		p = &list[a];
		strcpy(p->fn,&data[i]);
		i += strlen(p->fn)/4*4+4;
		p->addr = *(int *)&data[i];
		if(a>0){(p-1)->comp_size = p->addr - (p-1)->addr;}
		p->size = *(int *)&data[i+4];
		if(*(int *)&data[i+8] != 0){
			free(list);
			list = NULL;
			return 2;
		}
		i+=12;
		a++;
	}
	if(a != num){
		free(list);
		list = NULL;
		return 3;
	}

	p = &list[a-1];
	p->comp_size = th11dat.size - th11dat.comp_lsize - p->addr;
/*
	i = 0;
	while(i < num){
		printf("%20s\t%10d\t%10d\t%10d\n",list[i].fn,list[i].addr,list[i].comp_size,list[i].size);
		i++;
	}
*/
	return 0;
}
int th11_getlist(char *filename){
	int flist,size,last;
	char head[16],*data,*str,*s;
	int i,k,t,ret;
	unsigned char len;

	list_free();
	ret = 0;
	fp = fopen(filename,"rb");
	if(fp == NULL){
		//printf("指定されたファイルが存在しません\n");
		ret = 1;
		goto end;
	}
	fseek(fp,0,SEEK_END);
	th11dat.size = ftell(fp);
	dat_size = th11dat.size;
	fseek(fp,0,SEEK_SET);
	if(th11dat.size < 16){
		//printf("dat構成情報を読み取れません\nファイルサイズが小さすぎます\n");
		ret = 2;
		goto end;
	}
	fread(head,1,16,fp);
	thcrypter(head,0x10,0x1B,0x37,0x10,0x10);
	if(*(int *)head != 0x31414854){
		//printf("dat形式がth11形式ではありません\n");
		ret = 3;
		goto end;
	}
	th11dat.list_size = *(int *)&head[4] - 0x075BCD15;
	th11dat.comp_lsize = *(int *)&head[8] - 0x3ADE68B1;
	th11dat.list_num = *(int *)&head[12] + 0xF7E7F8AC;
	fcount = th11dat.list_num;

	fseek(fp,-(th11dat.comp_lsize),SEEK_END);
	data = malloc(th11dat.comp_lsize);
	if(data == NULL){
		//printf("メモリー確保に失敗しました\n格納されたファイル数が多すぎます\n");
		ret = 4;
		goto end;
	}
	fread(data,1,th11dat.comp_lsize,fp);
	thcrypter(data,th11dat.comp_lsize,0x3E,0x9B,0x80,th11dat.comp_lsize);
	if(th11dat.comp_lsize != th11dat.list_size){
		str = malloc(th11dat.list_size);
		decomp(data,th11dat.comp_lsize,str,th11dat.list_size);
		free(data);
		data = str;
	}
	t = head_print(data,th11dat.list_size,fcount);
	free(data);
	if(t != 0){
		//printf("ファイルリストが異常です(%d)\n",t);
		return 5;
	}

	printf("%d個のファイルを検出しました。\n",fcount);
	strcpy(dat_name,filename);

end:
	return ret;
}