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(®,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;
}