Jump to content

Recommended Posts

I've been working on a tool for extracting and patching LiveMaker/LiveNovel games and figured I should post it here. It started out as a fork of tinfoil's irl which I guess was kickstarted and then abandoned a while back?

Current status is:

  • LiveMaker assets can be extracted from .exe or .dat files
  • LiveMaker's binary .lsb format for their "chart" scripting can be dumped as text or xml
  • LiveNovel scripts can be extracted from LiveMaker's binary .lsb format
  • (Translated) LiveNovel scripts can be compiled and inserted back into a .lsb file
  • Modified .lsb's can be patched back into a livemaker game and run with (cp932 encoded) english text, but currently the application will lock up when you try to exit.

My current code is here: https://github.com/pmrowla/pylivemaker/tree/wip (you have to use the wip branch link since I'm not pushing anything into master until I figure out the crash on exit thing)

The code itself is mostly fully commented but I haven't published any of the actual docs yet, so there's a github issue w/a summary of what works right now and what doesn't: https://github.com/pmrowla/pylivemaker/issues/1

 

Honestly idk if there's even any livemaker games worth patching but I was bored and felt like reversing something so I picked an obscure engine that afaik hasn't been dug into very much before. I think GARbro supports viewing .gal CG's from LiveMaker archives, but that doesn't cover the text extraction and patching side of things.

Share this post


Link to post
Share on other sites

I'm trying to extract the scenario files from the md scr.med file from saiminjutsu4. I tried garbro but i can only extract the contents from the root file. I can't extract any of the scenario files so I can change coding such as translation and sprite image generation.  Anyone have anything useful to help out?

https://imgur.com/a/nx3j75p

 

 

Edited by Haiyami

Share this post


Link to post
Share on other sites
On 3/29/2019 at 10:31 AM, pmrowla said:

I've been working on a tool for extracting and patching LiveMaker/LiveNovel games and figured I should post it here. It started out as a fork of tinfoil's irl which I guess was kickstarted and then abandoned a while back?

This thing is mostly done now, everything at https://github.com/pmrowla/pylivemaker works and there's some actual documentation now. It's still more of a proof-of-concept thing than an actual tool someone could use to make a full translation patch, but I probably won't get around to making it particularly user friendly until/unless someone actually wants to make a full patch for something.

If you are interested in RE I wrote up a short post about it here: https://pmrowla.com/blog/reverse-engineering-livemaker/

Share this post


Link to post
Share on other sites

Thought somebody might be interested in this; me and a friend of mine are currently working on an all-purpose archive unpacker (mostly for visual novel archives)

The link can be found at https://github.com/Azukee/Macaron currently in development is the Criware unpacker (unpacker works, conversion to custom files atm not) and Kirikiri unpacker (Header reading works atm; can be found in the Kirkiri branch)

You can find the currently supported archives in the readme file of the repo, and if you have any archive requests you can request them in the issues page with the "archive request" tag

Share this post


Link to post
Share on other sites

It's possible this exists somewhere else but I couldn't find it: something that can convert the BGI / Ethornell engine's sysgrp UI images to something you can work with. (target: senmomo). My searches brought me to xupefei's BGIKit, which had no binary releases, so I had to compile it myself (ok visual studio makes this easy actually). I'm not sure exactly what platforms these binaries will work on bar windows 64-bit, but at least you don't have to compile them yourself: https://drive.google.com/file/d/1cy1SnLSQZ_rCW8H6AsD9SZDxZrUd7qtZ/view?usp=sharing

Only the sysgrp tool is tested and only from game format to .bmp, have fun. To use that, call the program from the command line (cmd.exe or powershell) with the path to the file to be converted  to bmp / from bmp as the sole argument, or more concretely:

SysgrpConverter.exe filenamehere

 

Share this post


Link to post
Share on other sites

So i've able to extract the scenario files from saiminjustu 4. But of course those files don't have any file type extension on them. When i try to open any of the scenario files in notepad++ I get a garbled mess.zofcK7p.png

 

any help I'm trying to change the picture references for uncenosred pictures as well as translating. Thank you.

Share this post


Link to post
Share on other sites
22 hours ago, Haiyami said:

So i've able to extract the scenario files from saiminjustu 4. But of course those files don't have any file type extension on them. When i try to open any of the scenario files in notepad++ I get a garbled mess.zofcK7p.png

 

any help I'm trying to change the picture references for uncenosred pictures as well as translating. Thank you.

Change the unicode from ansi to any japanese lang like JIS. . .If does not work maybe the extraction failed

 

Share this post


Link to post
Share on other sites

iwi7spL.png

Looks like the extraction failed. It still shows weird characters. it's super hard to determine the file organization tree when the text is illegible. I also tried extracting an older game, Bakyunyuu Kissa and I got better results as seen below. But I still see garbled messes. I at least can see evt images an dialogue text with Bakyunyuu kissa but I can't see sprite CG references. I wonder if it has something to do with the language notepad++ is set at. Maybe change it to python, C++ or something. Anyways the image below for Bakyunyuu Kissa shows other problems. Also ignore how the file isn't saved. I was tampering some other settings but it did nothing to change anything .This looks the same as when the file was saved.

yy4oGRD.png

Share this post


Link to post
Share on other sites
On 5/17/2019 at 5:08 AM, Haiyami said:

iwi7spL.png

Looks like the extraction failed. It still shows weird characters. it's super hard to determine the file organization tree when the text is illegible. I also tried extracting an older game, Bakyunyuu Kissa and I got better results as seen below. But I still see garbled messes. I at least can see evt images an dialogue text with Bakyunyuu kissa but I can't see sprite CG references. I wonder if it has something to do with the language notepad++ is set at. Maybe change it to python, C++ or something. Anyways the image below for Bakyunyuu Kissa shows other problems. Also ignore how the file isn't saved. I was tampering some other settings but it did nothing to change anything .This looks the same as when the file was saved.

yy4oGRD.png

It has nothing to do with language. . .

Use other method of extracting that script. . .I encountered that also. . .Then I realized to change program for extracting the scenarios. . .

Share this post


Link to post
Share on other sites

Sorry for bothering, but can anyone know about files with CZ2 in the header? I tried to findinformation, but could not find anything useful ... Are these files compressed or something? These files are used for font in Planetarian HD on Switch. Please help with this. Link to files

Share this post


Link to post
Share on other sites

Hiya everyone, was wondering if anybody knows tools for repacking .PAK files. crass unpacks them fine, but I've no way of putting them back together.

*tried createSRPak, doesn't work.       Btw the game is Dain~kutsujoku no coming out 

Share this post


Link to post
Share on other sites
2 hours ago, Mutank said:

Hiya everyone, was wondering if anybody knows tools for repacking .PAK files. crass unpacks them fine, but I've no way of putting them back together.

*tried createSRPak, doesn't work.       Btw the game is Dain~kutsujoku no coming out 

I don't think you will find anything already pre-made...

This is Heat-soft & other sister brands, I guess the format is https://github.com/morkt/GARbro/blob/master/ArcFormats/Ipac/ArcIPAC.cs 

A header, 4-field entries... Fairly vanilla, unlike their games, if you ask me :wahaha:

Code from crass

#include <windows.h>
#include <tchar.h>
#include <crass_types.h>
#include <acui.h>
#include <cui.h>
#include <package.h>
#include <resource.h>
#include <cui_error.h>
#include <utility.h>
#include <stdio.h>

/* 接口数据结构: 表示cui插件的一般信息 */
struct acui_information IPAC_cui_information = {
	NULL,					/* copyright */
	NULL,					/* system */
	_T(".PAK .WST"),		/* package */
	_T("1.0.3"),			/* revision */
	_T("痴汉公贼"),			/* author */
	_T("2009-3-29 23:09"),	/* date */
	NULL,					/* notion */
	ACUI_ATTRIBUTE_LEVEL_UNSTABLE
};

/* 所有的封包特定的数据结构都要放在这个#pragma段里 */

#pragma pack (1)
typedef struct {
	s8 magic[4];		/* "IPAC" */
	u16 index_entries;
	u16 unknown;
} PAK_header_t;

typedef struct {
	s8 name[32];
	u32 unknown;
	u32 offset;
	u32 length;
} PAK_entry_t;

typedef struct {
	s8 magic[4];		/* "IEL1" */
	u32 length;
} iel1_header_t;

/*
20 bytes header
1024 bytes palette
width * height * 3 dib data
width * height alpha
*/
typedef struct {
	s8 magic[4];		/* "IES2" */
	u32 unknown;		/* "IES2" */
	u32 width;
	u32 height;
	u32 bits_count;
	u32 reserved[3];
} ies2_header_t;

struct key {
	s32 low;
	s32 high;
};

typedef struct {
	s8 magic[4];		/* "WST2" */
	u32 reserved[2];
	u16 adpcm_fmt_parameter[14];
} wst_header_t;
#pragma pack ()

static void *my_malloc(DWORD len)
{
	return malloc(len);
}

static inline unsigned char getbit_le(unsigned char byte, unsigned int pos)
{
	return !!(byte & (1 << pos));
}

static DWORD lzss_decompress(unsigned char *uncompr, DWORD uncomprlen, 
							unsigned char *compr, DWORD comprlen)
{
	unsigned int act_uncomprlen = 0;
	/* compr中的当前字节中的下一个扫描位的位置 */
	unsigned int curbit = 0;
	/* compr中的当前扫描字节 */
	unsigned int curbyte = 0;
	unsigned int nCurWindowByte = 0xfee;
	unsigned int win_size = 4096;
	BYTE win[4096];
	
	memset(win, ' ', nCurWindowByte);
	while (1) {
		/* 如果为0, 表示接下来的1个字节原样输出 */
		BYTE flag;

		if (curbyte >= comprlen)
			break;

		flag = compr[curbyte++];
		for (curbit = 0; curbit < 8; curbit++) {
			if (getbit_le(flag, curbit)) {
				unsigned char data;
	
				if (curbyte >= comprlen)
					goto out;

				if (act_uncomprlen >= uncomprlen)
					goto out;

				data = compr[curbyte++];
				uncompr[act_uncomprlen++] = data;
				/* 输出的1字节放入滑动窗口 */
				win[nCurWindowByte++] = data;
				nCurWindowByte &= win_size - 1;
			} else {
				unsigned int copy_bytes, win_offset;
				unsigned int i;

				if (curbyte >= comprlen)
					goto out;

				win_offset = compr[curbyte++];

				if (curbyte >= comprlen)
					goto out;
				copy_bytes = compr[curbyte++];
				win_offset |= (copy_bytes >> 4) << 8;
				copy_bytes &= 0x0f;
				copy_bytes += 3;

				for (i = 0; i < copy_bytes; i++) {	
					unsigned char data;

					if (act_uncomprlen >= uncomprlen)
						goto out;

					data = win[(win_offset + i) & (win_size - 1)];
					uncompr[act_uncomprlen++] = data;		
					/* 输出的1字节放入滑动窗口 */
					win[nCurWindowByte++] = data;
					nCurWindowByte &= win_size - 1;	
				}
			}
		}
	}
out:
	return act_uncomprlen;
}

static int ipac_decompress_iel1(iel1_header_t *iel1, DWORD iel1_len, 
						BYTE **ret_buf, DWORD *ret_len)
{
	BYTE *uncompr, *compr;
	DWORD uncomprLen, comprLen, actlen;

	uncomprLen = iel1->length;
	uncompr = (BYTE *)malloc(uncomprLen);
	if (!uncompr)
		return -1;

	compr = (BYTE *)(iel1 + 1);
	comprLen = iel1_len - sizeof(*iel1);
	actlen = lzss_decompress(uncompr, uncomprLen, compr, comprLen);
	if (actlen != uncomprLen) {
		free(uncompr);
		return -1;
	}
	*ret_buf = uncompr;
	*ret_len = actlen;

	return 0;
}

/********************* WST *********************/

/* 封包匹配回调函数 */
static int IPAC_WST_match(struct package *pkg)
{
	s8 magic[4];

	if (pkg->pio->open(pkg, IO_READONLY))
		return -CUI_EOPEN;

	if (pkg->pio->read(pkg, magic, sizeof(magic))) {
		pkg->pio->close(pkg);
		return -CUI_EREAD;
	}

	if (memcmp(magic, "WST2", 4)) {
		pkg->pio->close(pkg);
		return -CUI_EMATCH;	
	}

	return 0;	
}

/* 封包资源提取函数 */
static int IPAC_WST_extract_resource(struct package *pkg,
									 struct package_resource *pkg_res)
{
	BYTE *wst_buf;
	u32 wst_buf_len;

	if (pkg->pio->seek(pkg, 0, IO_SEEK_SET))
		return -CUI_ESEEK;

	if (pkg->pio->length_of(pkg, &wst_buf_len))
		return -CUI_ELEN;

	wst_buf = (BYTE *)malloc(wst_buf_len);
	if (!wst_buf)
		return -CUI_EMEM;

	if (pkg->pio->read(pkg, wst_buf, wst_buf_len)) {
		free(wst_buf);
		return -CUI_EREAD;
	}

	pkg_res->raw_data = wst_buf;
	pkg_res->raw_data_length = wst_buf_len;

	return 0;
}

/* 资源保存函数 */
static int IPAC_WST_save_resource(struct resource *res, 
								  struct package_resource *pkg_res)
{
	WAVEFORMATEX wav_header;
	DWORD riff_chunk_len, fmt_chunk_len, data_chunk_len;
	char *riff = "RIFF";
	char *id = "WAVE"; 
	char *fmt_chunk_id = "fmt ";
	char *data_chunk_id = "data";
	char *hack_info = "Hacked By 痴汉公贼";
	WORD adpcm_para[16];
	BYTE *data_chunk; 
	wst_header_t *wst2;
	BYTE *wst_buf = (BYTE *)pkg_res->raw_data;
	DWORD wst_buf_len = pkg_res->raw_data_length;
	
	if (res->rio->create(res))
		return -CUI_ECREATE;

	wst2 = (wst_header_t *)wst_buf;
	/* 这个应该是还原为ADCM以后的结果 */
	/* 00441E00  01 00 02 00 44 AC 00 00 10 B1 02 00 04 00 10 00  ....D?..?..... */
	wav_header.wFormatTag = 2;	/* ADPCM */
	wav_header.nChannels = 2;
	wav_header.nSamplesPerSec = 0xac44;	
	wav_header.nAvgBytesPerSec = 0xac44;	/* ADPCM是4:1压缩,因此ac44的4倍就是0x2b110了 */
	wav_header.nBlockAlign = 0x800;
	wav_header.wBitsPerSample = 4;
	wav_header.cbSize = 32;

	adpcm_para[0] = 0x07f4;
	adpcm_para[1] = 0x0007;

	memcpy(&adpcm_para[2], wst2->adpcm_fmt_parameter, 
		sizeof(wst2->adpcm_fmt_parameter));
	data_chunk = (BYTE *)(wst2 + 1);

	data_chunk_len = wst_buf_len - sizeof(*wst2);
	data_chunk_len &= ~(wav_header.nBlockAlign - 1);
	fmt_chunk_len = 16 + 2 + wav_header.cbSize;
	riff_chunk_len = 4 + (8 + fmt_chunk_len) + (8 + data_chunk_len);

	if (res->rio->write(res, (char *)riff, 4)) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}

	if (res->rio->write(res, &riff_chunk_len, 4)) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}
			
	if (res->rio->write(res, id, 4)) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}		
			
	if (res->rio->write(res, fmt_chunk_id, 4)) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}

	if (res->rio->write(res, &fmt_chunk_len, 4)) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}
			
	if (res->rio->write(res, &wav_header, sizeof(wav_header))) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}			

	if (res->rio->write(res, adpcm_para, sizeof(adpcm_para))) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}	

	if (res->rio->write(res, data_chunk_id, 4)) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}
				
	if (res->rio->write(res, &data_chunk_len, 4)) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}

	if (res->rio->write(res, data_chunk, data_chunk_len)) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}
			
	if (res->rio->write(res, hack_info, strlen(hack_info))) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}

	res->rio->close(res);
	
	return 0;
}

/* 封包资源释放函数 */
static void IPAC_WST_release_resource(struct package *pkg, 
									  struct package_resource *pkg_res)
{
	if (pkg_res->raw_data) {
		free(pkg_res->raw_data);
		pkg_res->raw_data = NULL;
	}
}

/* 封包卸载函数 */
static void IPAC_WST_release(struct package *pkg, 
							 struct package_directory *pkg_dir)
{
	pkg->pio->close(pkg);
}

/* 封包处理回调函数集合 */
static cui_ext_operation IPAC_WST_operation = {
	IPAC_WST_match,				/* match */
	NULL,						/* extract_directory */
	NULL,						/* parse_resource_info */
	IPAC_WST_extract_resource,	/* extract_resource */
	IPAC_WST_save_resource,		/* save_resource */
	IPAC_WST_release_resource,	/* release_resource */
	IPAC_WST_release			/* release */
};

/********************* PAK *********************/

/* 封包匹配回调函数 */
static int IPAC_PAK_match(struct package *pkg)
{
	s8 magic[4];

	if (pkg->pio->open(pkg, IO_READONLY))
		return -CUI_EOPEN;

	if (pkg->pio->read(pkg, magic, sizeof(magic))) {
		pkg->pio->close(pkg);
		return -CUI_EREAD;
	}

	if (memcmp(magic, "IPAC", 4)) {
		pkg->pio->close(pkg);
		return -CUI_EMATCH;	
	}

	return 0;	
}

/* 封包索引目录提取函数 */
static int IPAC_PAK_extract_directory(struct package *pkg,
									  struct package_directory *pkg_dir)
{
	PAK_header_t PAK_header;
	PAK_entry_t *index_buffer;
	unsigned int index_buffer_length;	

	if (pkg->pio->seek(pkg, 0, IO_SEEK_SET))
		return -CUI_ESEEK;

	if (pkg->pio->read(pkg, &PAK_header, sizeof(PAK_header)))
		return -CUI_EREAD;

	pkg_dir->index_entries = PAK_header.index_entries;
	index_buffer_length = pkg_dir->index_entries * sizeof(PAK_entry_t);
	index_buffer = (PAK_entry_t *)malloc(index_buffer_length);
	if (!index_buffer)
		return -CUI_EMEM;

	if (pkg->pio->read(pkg, index_buffer, index_buffer_length)) {
		free(index_buffer);
		return -CUI_EREAD;
	}

	pkg_dir->directory = index_buffer;
	pkg_dir->directory_length = index_buffer_length;
	pkg_dir->index_entry_length = sizeof(PAK_entry_t);

	return 0;
}

/* 封包索引项解析函数 */
static int IPAC_PAK_parse_resource_info(struct package *pkg,
										struct package_resource *pkg_res)
{
	PAK_entry_t *PAK_entry;

	PAK_entry = (PAK_entry_t *)pkg_res->actual_index_entry;
	strcpy(pkg_res->name, PAK_entry->name);
	pkg_res->name_length = -1;			/* -1表示名称以NULL结尾 */
	pkg_res->raw_data_length = PAK_entry->length;
	pkg_res->actual_data_length = 0;	/* 数据都是明文 */
	pkg_res->offset = PAK_entry->offset;

	return 0;
}

/* 封包资源提取函数 */
static int IPAC_PAK_extract_resource(struct package *pkg,
									 struct package_resource *pkg_res)
{
	BYTE *compr, *uncompr, *actbuf;
	DWORD uncomprlen, comprlen, actlen;

	comprlen = pkg_res->raw_data_length;
	compr = (BYTE *)malloc(comprlen);
	if (!compr)
		return -CUI_EMEM;

	if (pkg->pio->readvec(pkg, compr, comprlen,	pkg_res->offset, IO_SEEK_SET)) {
		free(compr);
		return -CUI_EREADVEC;
	}

	if (pkg_res->flags & PKG_RES_FLAG_RAW) {
		pkg_res->raw_data = compr;
		return 0;
	}

	if (!memcmp(compr, "IEL1", 4)) {
		if (ipac_decompress_iel1((iel1_header_t *)compr, comprlen, &uncompr, &uncomprlen)) {
			free(compr);
			return -CUI_EUNCOMPR;
		}
		free(compr);
		compr = NULL;
		actbuf = uncompr;
		actlen = uncomprlen;
	} else {
		uncompr = NULL;
		uncomprlen = 0;
		actbuf = compr;
		actlen = comprlen;
	}

	if (!memcmp(actbuf, "IES2", 4)) {
		ies2_header_t *ies2 = (ies2_header_t *)actbuf;
		BYTE *save_buf;
		DWORD save_len;

		if (ies2->bits_count == 24) {
			BYTE *rgba;

			actlen = ies2->width * ies2->height * 4;
			rgba = (BYTE *)malloc(actlen);
			if (!rgba) {
				free(actbuf);
				free(compr);
				return -CUI_EMEM;
			}

			BYTE *rgb = actbuf + 0x420;
			BYTE *p_alpha = rgb + ies2->width * ies2->height * 3;
			BYTE *p_rgba = rgba;
			for (unsigned int y = 0; y < ies2->height; y++) {
				for (unsigned int x = 0; x < ies2->width; x++) {
					BYTE alpha = *p_alpha++;					
					p_rgba[0] = (rgb[0] * alpha + 0xff * ~alpha) / 255;
					p_rgba[1] = (rgb[1] * alpha + 0xff * ~alpha) / 255;
					p_rgba[2] = (rgb[2] * alpha + 0xff * ~alpha) / 255;	
					p_rgba[3] = alpha;	
					rgb += 3;
					p_rgba += 4;
				}
			}

			if (MyBuildBMPFile(rgba, actlen, NULL, 0, ies2->width,
					0 - ies2->height, 32, &save_buf, &save_len, my_malloc)) {
				free(rgba);
				free(actbuf);
				free(compr);
				return -CUI_EMEM;				
			}
			free(rgba);
		} else {
			if (MyBuildBMPFile(actbuf + 0x420, actlen - 0x420, (BYTE *)(ies2 + 1), 0x400, ies2->width,
					0 - ies2->height, ies2->bits_count, &save_buf, &save_len, my_malloc)) {
				free(actbuf);
				free(compr);
				return -CUI_EMEM;				
			}
		}
		free(actbuf);
		uncompr = save_buf;
		uncomprlen = save_len;
		pkg_res->replace_extension = _T(".IES2.bmp");
		pkg_res->flags |= PKG_RES_FLAG_REEXT;
//	} else if (!lstrcmpi(pkg->extension, _T(".IES"))) {
	} else if (strstr(pkg_res->name, ".IES")) {
		BYTE *save_buf;
		DWORD save_len;

#if 0
//		if (MyBuildBMPFile(actbuf + 0x420, actlen - 0x420, actbuf + 0x20, 0x400, *(DWORD *)actbuf,
		if (MyBuildBMPFile(actbuf + 0x414, actlen - 0x414, NULL, 0, *(DWORD *)actbuf,
				0 - *(DWORD *)(actbuf + 4), *(DWORD *)(actbuf + 8), &save_buf, &save_len, my_malloc)) {
			free(actbuf);
			return -CUI_EMEM;			
		}
#else
		if (!memcmp(actbuf, "BM", 2)) {
			pkg_res->raw_data = compr;
			pkg_res->raw_data_length = comprlen;
			pkg_res->actual_data = actbuf;
			pkg_res->actual_data_length = actlen;
			return 0;
		} else if (*(DWORD *)(actbuf + 8) == 24) {
			DWORD width = *(DWORD *)actbuf;
			DWORD height = *(DWORD *)(actbuf + 4);
			BYTE *rgba;

			actlen = width * height * 4;
			rgba = (BYTE *)malloc(actlen);
			if (!rgba) {
				free(actbuf);
				free(compr);
				return -CUI_EMEM;
			}

			BYTE *rgb = actbuf + 0x414;
			BYTE *p_alpha = rgb + width * height * 3;
			BYTE *p_rgba = rgba;
			for (unsigned int y = 0; y < height; y++) {
				for (unsigned int x = 0; x < width; x++) {
					BYTE alpha = *p_alpha++;					
					p_rgba[0] = (rgb[0] * alpha + 0xff * ~alpha) / 255;
					p_rgba[1] = (rgb[1] * alpha + 0xff * ~alpha) / 255;
					p_rgba[2] = (rgb[2] * alpha + 0xff * ~alpha) / 255;	
					p_rgba[3] = alpha;	
					rgb += 3;
					p_rgba += 4;
				}
			}

			if (MyBuildBMPFile(rgba, actlen, NULL, 0, width,
					0 - height, 32, &save_buf, &save_len, my_malloc)) {
				free(rgba);
				free(actbuf);
				free(compr);
				return -CUI_EMEM;				
			}
			free(rgba);
		} else {
			if (MyBuildBMPFile(actbuf + 0x414, actlen - 0x414, NULL, 0, *(DWORD *)actbuf,
					0 - *(DWORD *)(actbuf + 4), *(DWORD *)(actbuf + 8), &save_buf, &save_len, my_malloc)) {
				free(actbuf);
				free(compr);
				return -CUI_EMEM;			
			}
		}
#endif
		free(actbuf);
		uncompr = save_buf;
		uncomprlen = save_len;
		pkg_res->replace_extension = _T(".IES.bmp");
		pkg_res->flags |= PKG_RES_FLAG_REEXT;
	}

	pkg_res->raw_data = compr;
	pkg_res->raw_data_length = comprlen;
	pkg_res->actual_data = uncompr;
	pkg_res->actual_data_length = uncomprlen;

	return 0;
}

/* 资源保存函数 */
static int IPAC_PAK_save_resource(struct resource *res, 
								  struct package_resource *pkg_res)
{
	if (res->rio->create(res))
		return -CUI_ECREATE;

	if (pkg_res->actual_data && pkg_res->actual_data_length) {
		if (res->rio->write(res, pkg_res->actual_data, pkg_res->actual_data_length)) {
			res->rio->close(res);
			return -CUI_EWRITE;
		}
	} else if (pkg_res->raw_data && pkg_res->raw_data_length) {
		if (res->rio->write(res, pkg_res->raw_data, pkg_res->raw_data_length)) {
			res->rio->close(res);
			return -CUI_EWRITE;
		}
	}

	res->rio->close(res);

	return 0;
}

/* 封包资源释放函数 */
static void IPAC_PAK_release_resource(struct package *pkg, 
									  struct package_resource *pkg_res)
{
	if (pkg_res->actual_data) {
		free(pkg_res->actual_data);
		pkg_res->actual_data = NULL;
	}
	if (pkg_res->raw_data) {
		free(pkg_res->raw_data);
		pkg_res->raw_data = NULL;
	}
}

/* 封包卸载函数 */
static void IPAC_PAK_release(struct package *pkg, 
							 struct package_directory *pkg_dir)
{
	if (pkg_dir->directory) {
		free(pkg_dir->directory);
		pkg_dir->directory = NULL;
	}

	pkg->pio->close(pkg);
}

/* 封包处理回调函数集合 */
static cui_ext_operation IPAC_PAK_operation = {
	IPAC_PAK_match,					/* match */
	IPAC_PAK_extract_directory,		/* extract_directory */
	IPAC_PAK_parse_resource_info,	/* parse_resource_info */
	IPAC_PAK_extract_resource,		/* extract_resource */
	IPAC_PAK_save_resource,			/* save_resource */
	IPAC_PAK_release_resource,		/* release_resource */
	IPAC_PAK_release				/* release */
};

/* 接口函数: 向cui_core注册支持的封包类型 */
int CALLBACK IPAC_register_cui(struct cui_register_callback *callback)
{
	/* 注册cui插件支持的扩展名、资源放入扩展名、处理回调函数和封包属性 */
	if (callback->add_extension(callback->cui, _T(".PAK"), NULL, 
		NULL, &IPAC_PAK_operation, CUI_EXT_FLAG_PKG | CUI_EXT_FLAG_DIR))
			return -1;

	if (callback->add_extension(callback->cui, _T(".WST"), _T(".wav"), 
		NULL, &IPAC_WST_operation, CUI_EXT_FLAG_PKG))
			return -1;	

	return 0;
}

 

Share this post


Link to post
Share on other sites
On 6/3/2019 at 11:26 PM, wwwklopar said:

Sorry for bothering, but can anyone know about files with CZ2 in the header? I tried to findinformation, but could not find anything useful ... Are these files compressed or something? These files are used for font in Planetarian HD on Switch. Please help with this. Link to files

Google fu gives this: https://sourceforge.net/projects/rlpaktool/

See also https://github.com/marcussacana/LucaSystem by @marcus-beta

Edit: and in garbro https://github.com/morkt/GARbro/issues/325

 

 

Edited by Nanashi3

Share this post


Link to post
Share on other sites
On 6/10/2019 at 10:14 PM, Nanashi3 said:

I don't think you will find anything already pre-made...

This is Heat-soft & other sister brands, I guess the format is https://github.com/morkt/GARbro/blob/master/ArcFormats/Ipac/ArcIPAC.cs 

A header, 4-field entries... Fairly vanilla, unlike their games, if you ask me :wahaha:

Code from crass


#include <windows.h>
#include <tchar.h>
#include <crass_types.h>
#include <acui.h>
#include <cui.h>
#include <package.h>
#include <resource.h>
#include <cui_error.h>
#include <utility.h>
#include <stdio.h>

/* 接口数据结构: 表示cui插件的一般信息 */
struct acui_information IPAC_cui_information = {
	NULL,					/* copyright */
	NULL,					/* system */
	_T(".PAK .WST"),		/* package */
	_T("1.0.3"),			/* revision */
	_T("痴汉公贼"),			/* author */
	_T("2009-3-29 23:09"),	/* date */
	NULL,					/* notion */
	ACUI_ATTRIBUTE_LEVEL_UNSTABLE
};

/* 所有的封包特定的数据结构都要放在这个#pragma段里 */

#pragma pack (1)
typedef struct {
	s8 magic[4];		/* "IPAC" */
	u16 index_entries;
	u16 unknown;
} PAK_header_t;

typedef struct {
	s8 name[32];
	u32 unknown;
	u32 offset;
	u32 length;
} PAK_entry_t;

typedef struct {
	s8 magic[4];		/* "IEL1" */
	u32 length;
} iel1_header_t;

/*
20 bytes header
1024 bytes palette
width * height * 3 dib data
width * height alpha
*/
typedef struct {
	s8 magic[4];		/* "IES2" */
	u32 unknown;		/* "IES2" */
	u32 width;
	u32 height;
	u32 bits_count;
	u32 reserved[3];
} ies2_header_t;

struct key {
	s32 low;
	s32 high;
};

typedef struct {
	s8 magic[4];		/* "WST2" */
	u32 reserved[2];
	u16 adpcm_fmt_parameter[14];
} wst_header_t;
#pragma pack ()

static void *my_malloc(DWORD len)
{
	return malloc(len);
}

static inline unsigned char getbit_le(unsigned char byte, unsigned int pos)
{
	return !!(byte & (1 << pos));
}

static DWORD lzss_decompress(unsigned char *uncompr, DWORD uncomprlen, 
							unsigned char *compr, DWORD comprlen)
{
	unsigned int act_uncomprlen = 0;
	/* compr中的当前字节中的下一个扫描位的位置 */
	unsigned int curbit = 0;
	/* compr中的当前扫描字节 */
	unsigned int curbyte = 0;
	unsigned int nCurWindowByte = 0xfee;
	unsigned int win_size = 4096;
	BYTE win[4096];
	
	memset(win, ' ', nCurWindowByte);
	while (1) {
		/* 如果为0, 表示接下来的1个字节原样输出 */
		BYTE flag;

		if (curbyte >= comprlen)
			break;

		flag = compr[curbyte++];
		for (curbit = 0; curbit < 8; curbit++) {
			if (getbit_le(flag, curbit)) {
				unsigned char data;
	
				if (curbyte >= comprlen)
					goto out;

				if (act_uncomprlen >= uncomprlen)
					goto out;

				data = compr[curbyte++];
				uncompr[act_uncomprlen++] = data;
				/* 输出的1字节放入滑动窗口 */
				win[nCurWindowByte++] = data;
				nCurWindowByte &= win_size - 1;
			} else {
				unsigned int copy_bytes, win_offset;
				unsigned int i;

				if (curbyte >= comprlen)
					goto out;

				win_offset = compr[curbyte++];

				if (curbyte >= comprlen)
					goto out;
				copy_bytes = compr[curbyte++];
				win_offset |= (copy_bytes >> 4) << 8;
				copy_bytes &= 0x0f;
				copy_bytes += 3;

				for (i = 0; i < copy_bytes; i++) {	
					unsigned char data;

					if (act_uncomprlen >= uncomprlen)
						goto out;

					data = win[(win_offset + i) & (win_size - 1)];
					uncompr[act_uncomprlen++] = data;		
					/* 输出的1字节放入滑动窗口 */
					win[nCurWindowByte++] = data;
					nCurWindowByte &= win_size - 1;	
				}
			}
		}
	}
out:
	return act_uncomprlen;
}

static int ipac_decompress_iel1(iel1_header_t *iel1, DWORD iel1_len, 
						BYTE **ret_buf, DWORD *ret_len)
{
	BYTE *uncompr, *compr;
	DWORD uncomprLen, comprLen, actlen;

	uncomprLen = iel1->length;
	uncompr = (BYTE *)malloc(uncomprLen);
	if (!uncompr)
		return -1;

	compr = (BYTE *)(iel1 + 1);
	comprLen = iel1_len - sizeof(*iel1);
	actlen = lzss_decompress(uncompr, uncomprLen, compr, comprLen);
	if (actlen != uncomprLen) {
		free(uncompr);
		return -1;
	}
	*ret_buf = uncompr;
	*ret_len = actlen;

	return 0;
}

/********************* WST *********************/

/* 封包匹配回调函数 */
static int IPAC_WST_match(struct package *pkg)
{
	s8 magic[4];

	if (pkg->pio->open(pkg, IO_READONLY))
		return -CUI_EOPEN;

	if (pkg->pio->read(pkg, magic, sizeof(magic))) {
		pkg->pio->close(pkg);
		return -CUI_EREAD;
	}

	if (memcmp(magic, "WST2", 4)) {
		pkg->pio->close(pkg);
		return -CUI_EMATCH;	
	}

	return 0;	
}

/* 封包资源提取函数 */
static int IPAC_WST_extract_resource(struct package *pkg,
									 struct package_resource *pkg_res)
{
	BYTE *wst_buf;
	u32 wst_buf_len;

	if (pkg->pio->seek(pkg, 0, IO_SEEK_SET))
		return -CUI_ESEEK;

	if (pkg->pio->length_of(pkg, &wst_buf_len))
		return -CUI_ELEN;

	wst_buf = (BYTE *)malloc(wst_buf_len);
	if (!wst_buf)
		return -CUI_EMEM;

	if (pkg->pio->read(pkg, wst_buf, wst_buf_len)) {
		free(wst_buf);
		return -CUI_EREAD;
	}

	pkg_res->raw_data = wst_buf;
	pkg_res->raw_data_length = wst_buf_len;

	return 0;
}

/* 资源保存函数 */
static int IPAC_WST_save_resource(struct resource *res, 
								  struct package_resource *pkg_res)
{
	WAVEFORMATEX wav_header;
	DWORD riff_chunk_len, fmt_chunk_len, data_chunk_len;
	char *riff = "RIFF";
	char *id = "WAVE"; 
	char *fmt_chunk_id = "fmt ";
	char *data_chunk_id = "data";
	char *hack_info = "Hacked By 痴汉公贼";
	WORD adpcm_para[16];
	BYTE *data_chunk; 
	wst_header_t *wst2;
	BYTE *wst_buf = (BYTE *)pkg_res->raw_data;
	DWORD wst_buf_len = pkg_res->raw_data_length;
	
	if (res->rio->create(res))
		return -CUI_ECREATE;

	wst2 = (wst_header_t *)wst_buf;
	/* 这个应该是还原为ADCM以后的结果 */
	/* 00441E00  01 00 02 00 44 AC 00 00 10 B1 02 00 04 00 10 00  ....D?..?..... */
	wav_header.wFormatTag = 2;	/* ADPCM */
	wav_header.nChannels = 2;
	wav_header.nSamplesPerSec = 0xac44;	
	wav_header.nAvgBytesPerSec = 0xac44;	/* ADPCM是4:1压缩,因此ac44的4倍就是0x2b110了 */
	wav_header.nBlockAlign = 0x800;
	wav_header.wBitsPerSample = 4;
	wav_header.cbSize = 32;

	adpcm_para[0] = 0x07f4;
	adpcm_para[1] = 0x0007;

	memcpy(&adpcm_para[2], wst2->adpcm_fmt_parameter, 
		sizeof(wst2->adpcm_fmt_parameter));
	data_chunk = (BYTE *)(wst2 + 1);

	data_chunk_len = wst_buf_len - sizeof(*wst2);
	data_chunk_len &= ~(wav_header.nBlockAlign - 1);
	fmt_chunk_len = 16 + 2 + wav_header.cbSize;
	riff_chunk_len = 4 + (8 + fmt_chunk_len) + (8 + data_chunk_len);

	if (res->rio->write(res, (char *)riff, 4)) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}

	if (res->rio->write(res, &riff_chunk_len, 4)) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}
			
	if (res->rio->write(res, id, 4)) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}		
			
	if (res->rio->write(res, fmt_chunk_id, 4)) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}

	if (res->rio->write(res, &fmt_chunk_len, 4)) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}
			
	if (res->rio->write(res, &wav_header, sizeof(wav_header))) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}			

	if (res->rio->write(res, adpcm_para, sizeof(adpcm_para))) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}	

	if (res->rio->write(res, data_chunk_id, 4)) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}
				
	if (res->rio->write(res, &data_chunk_len, 4)) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}

	if (res->rio->write(res, data_chunk, data_chunk_len)) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}
			
	if (res->rio->write(res, hack_info, strlen(hack_info))) {
		res->rio->close(res);
		return -CUI_EWRITE;
	}

	res->rio->close(res);
	
	return 0;
}

/* 封包资源释放函数 */
static void IPAC_WST_release_resource(struct package *pkg, 
									  struct package_resource *pkg_res)
{
	if (pkg_res->raw_data) {
		free(pkg_res->raw_data);
		pkg_res->raw_data = NULL;
	}
}

/* 封包卸载函数 */
static void IPAC_WST_release(struct package *pkg, 
							 struct package_directory *pkg_dir)
{
	pkg->pio->close(pkg);
}

/* 封包处理回调函数集合 */
static cui_ext_operation IPAC_WST_operation = {
	IPAC_WST_match,				/* match */
	NULL,						/* extract_directory */
	NULL,						/* parse_resource_info */
	IPAC_WST_extract_resource,	/* extract_resource */
	IPAC_WST_save_resource,		/* save_resource */
	IPAC_WST_release_resource,	/* release_resource */
	IPAC_WST_release			/* release */
};

/********************* PAK *********************/

/* 封包匹配回调函数 */
static int IPAC_PAK_match(struct package *pkg)
{
	s8 magic[4];

	if (pkg->pio->open(pkg, IO_READONLY))
		return -CUI_EOPEN;

	if (pkg->pio->read(pkg, magic, sizeof(magic))) {
		pkg->pio->close(pkg);
		return -CUI_EREAD;
	}

	if (memcmp(magic, "IPAC", 4)) {
		pkg->pio->close(pkg);
		return -CUI_EMATCH;	
	}

	return 0;	
}

/* 封包索引目录提取函数 */
static int IPAC_PAK_extract_directory(struct package *pkg,
									  struct package_directory *pkg_dir)
{
	PAK_header_t PAK_header;
	PAK_entry_t *index_buffer;
	unsigned int index_buffer_length;	

	if (pkg->pio->seek(pkg, 0, IO_SEEK_SET))
		return -CUI_ESEEK;

	if (pkg->pio->read(pkg, &PAK_header, sizeof(PAK_header)))
		return -CUI_EREAD;

	pkg_dir->index_entries = PAK_header.index_entries;
	index_buffer_length = pkg_dir->index_entries * sizeof(PAK_entry_t);
	index_buffer = (PAK_entry_t *)malloc(index_buffer_length);
	if (!index_buffer)
		return -CUI_EMEM;

	if (pkg->pio->read(pkg, index_buffer, index_buffer_length)) {
		free(index_buffer);
		return -CUI_EREAD;
	}

	pkg_dir->directory = index_buffer;
	pkg_dir->directory_length = index_buffer_length;
	pkg_dir->index_entry_length = sizeof(PAK_entry_t);

	return 0;
}

/* 封包索引项解析函数 */
static int IPAC_PAK_parse_resource_info(struct package *pkg,
										struct package_resource *pkg_res)
{
	PAK_entry_t *PAK_entry;

	PAK_entry = (PAK_entry_t *)pkg_res->actual_index_entry;
	strcpy(pkg_res->name, PAK_entry->name);
	pkg_res->name_length = -1;			/* -1表示名称以NULL结尾 */
	pkg_res->raw_data_length = PAK_entry->length;
	pkg_res->actual_data_length = 0;	/* 数据都是明文 */
	pkg_res->offset = PAK_entry->offset;

	return 0;
}

/* 封包资源提取函数 */
static int IPAC_PAK_extract_resource(struct package *pkg,
									 struct package_resource *pkg_res)
{
	BYTE *compr, *uncompr, *actbuf;
	DWORD uncomprlen, comprlen, actlen;

	comprlen = pkg_res->raw_data_length;
	compr = (BYTE *)malloc(comprlen);
	if (!compr)
		return -CUI_EMEM;

	if (pkg->pio->readvec(pkg, compr, comprlen,	pkg_res->offset, IO_SEEK_SET)) {
		free(compr);
		return -CUI_EREADVEC;
	}

	if (pkg_res->flags & PKG_RES_FLAG_RAW) {
		pkg_res->raw_data = compr;
		return 0;
	}

	if (!memcmp(compr, "IEL1", 4)) {
		if (ipac_decompress_iel1((iel1_header_t *)compr, comprlen, &uncompr, &uncomprlen)) {
			free(compr);
			return -CUI_EUNCOMPR;
		}
		free(compr);
		compr = NULL;
		actbuf = uncompr;
		actlen = uncomprlen;
	} else {
		uncompr = NULL;
		uncomprlen = 0;
		actbuf = compr;
		actlen = comprlen;
	}

	if (!memcmp(actbuf, "IES2", 4)) {
		ies2_header_t *ies2 = (ies2_header_t *)actbuf;
		BYTE *save_buf;
		DWORD save_len;

		if (ies2->bits_count == 24) {
			BYTE *rgba;

			actlen = ies2->width * ies2->height * 4;
			rgba = (BYTE *)malloc(actlen);
			if (!rgba) {
				free(actbuf);
				free(compr);
				return -CUI_EMEM;
			}

			BYTE *rgb = actbuf + 0x420;
			BYTE *p_alpha = rgb + ies2->width * ies2->height * 3;
			BYTE *p_rgba = rgba;
			for (unsigned int y = 0; y < ies2->height; y++) {
				for (unsigned int x = 0; x < ies2->width; x++) {
					BYTE alpha = *p_alpha++;					
					p_rgba[0] = (rgb[0] * alpha + 0xff * ~alpha) / 255;
					p_rgba[1] = (rgb[1] * alpha + 0xff * ~alpha) / 255;
					p_rgba[2] = (rgb[2] * alpha + 0xff * ~alpha) / 255;	
					p_rgba[3] = alpha;	
					rgb += 3;
					p_rgba += 4;
				}
			}

			if (MyBuildBMPFile(rgba, actlen, NULL, 0, ies2->width,
					0 - ies2->height, 32, &save_buf, &save_len, my_malloc)) {
				free(rgba);
				free(actbuf);
				free(compr);
				return -CUI_EMEM;				
			}
			free(rgba);
		} else {
			if (MyBuildBMPFile(actbuf + 0x420, actlen - 0x420, (BYTE *)(ies2 + 1), 0x400, ies2->width,
					0 - ies2->height, ies2->bits_count, &save_buf, &save_len, my_malloc)) {
				free(actbuf);
				free(compr);
				return -CUI_EMEM;				
			}
		}
		free(actbuf);
		uncompr = save_buf;
		uncomprlen = save_len;
		pkg_res->replace_extension = _T(".IES2.bmp");
		pkg_res->flags |= PKG_RES_FLAG_REEXT;
//	} else if (!lstrcmpi(pkg->extension, _T(".IES"))) {
	} else if (strstr(pkg_res->name, ".IES")) {
		BYTE *save_buf;
		DWORD save_len;

#if 0
//		if (MyBuildBMPFile(actbuf + 0x420, actlen - 0x420, actbuf + 0x20, 0x400, *(DWORD *)actbuf,
		if (MyBuildBMPFile(actbuf + 0x414, actlen - 0x414, NULL, 0, *(DWORD *)actbuf,
				0 - *(DWORD *)(actbuf + 4), *(DWORD *)(actbuf + 8), &save_buf, &save_len, my_malloc)) {
			free(actbuf);
			return -CUI_EMEM;			
		}
#else
		if (!memcmp(actbuf, "BM", 2)) {
			pkg_res->raw_data = compr;
			pkg_res->raw_data_length = comprlen;
			pkg_res->actual_data = actbuf;
			pkg_res->actual_data_length = actlen;
			return 0;
		} else if (*(DWORD *)(actbuf + 8) == 24) {
			DWORD width = *(DWORD *)actbuf;
			DWORD height = *(DWORD *)(actbuf + 4);
			BYTE *rgba;

			actlen = width * height * 4;
			rgba = (BYTE *)malloc(actlen);
			if (!rgba) {
				free(actbuf);
				free(compr);
				return -CUI_EMEM;
			}

			BYTE *rgb = actbuf + 0x414;
			BYTE *p_alpha = rgb + width * height * 3;
			BYTE *p_rgba = rgba;
			for (unsigned int y = 0; y < height; y++) {
				for (unsigned int x = 0; x < width; x++) {
					BYTE alpha = *p_alpha++;					
					p_rgba[0] = (rgb[0] * alpha + 0xff * ~alpha) / 255;
					p_rgba[1] = (rgb[1] * alpha + 0xff * ~alpha) / 255;
					p_rgba[2] = (rgb[2] * alpha + 0xff * ~alpha) / 255;	
					p_rgba[3] = alpha;	
					rgb += 3;
					p_rgba += 4;
				}
			}

			if (MyBuildBMPFile(rgba, actlen, NULL, 0, width,
					0 - height, 32, &save_buf, &save_len, my_malloc)) {
				free(rgba);
				free(actbuf);
				free(compr);
				return -CUI_EMEM;				
			}
			free(rgba);
		} else {
			if (MyBuildBMPFile(actbuf + 0x414, actlen - 0x414, NULL, 0, *(DWORD *)actbuf,
					0 - *(DWORD *)(actbuf + 4), *(DWORD *)(actbuf + 8), &save_buf, &save_len, my_malloc)) {
				free(actbuf);
				free(compr);
				return -CUI_EMEM;			
			}
		}
#endif
		free(actbuf);
		uncompr = save_buf;
		uncomprlen = save_len;
		pkg_res->replace_extension = _T(".IES.bmp");
		pkg_res->flags |= PKG_RES_FLAG_REEXT;
	}

	pkg_res->raw_data = compr;
	pkg_res->raw_data_length = comprlen;
	pkg_res->actual_data = uncompr;
	pkg_res->actual_data_length = uncomprlen;

	return 0;
}

/* 资源保存函数 */
static int IPAC_PAK_save_resource(struct resource *res, 
								  struct package_resource *pkg_res)
{
	if (res->rio->create(res))
		return -CUI_ECREATE;

	if (pkg_res->actual_data && pkg_res->actual_data_length) {
		if (res->rio->write(res, pkg_res->actual_data, pkg_res->actual_data_length)) {
			res->rio->close(res);
			return -CUI_EWRITE;
		}
	} else if (pkg_res->raw_data && pkg_res->raw_data_length) {
		if (res->rio->write(res, pkg_res->raw_data, pkg_res->raw_data_length)) {
			res->rio->close(res);
			return -CUI_EWRITE;
		}
	}

	res->rio->close(res);

	return 0;
}

/* 封包资源释放函数 */
static void IPAC_PAK_release_resource(struct package *pkg, 
									  struct package_resource *pkg_res)
{
	if (pkg_res->actual_data) {
		free(pkg_res->actual_data);
		pkg_res->actual_data = NULL;
	}
	if (pkg_res->raw_data) {
		free(pkg_res->raw_data);
		pkg_res->raw_data = NULL;
	}
}

/* 封包卸载函数 */
static void IPAC_PAK_release(struct package *pkg, 
							 struct package_directory *pkg_dir)
{
	if (pkg_dir->directory) {
		free(pkg_dir->directory);
		pkg_dir->directory = NULL;
	}

	pkg->pio->close(pkg);
}

/* 封包处理回调函数集合 */
static cui_ext_operation IPAC_PAK_operation = {
	IPAC_PAK_match,					/* match */
	IPAC_PAK_extract_directory,		/* extract_directory */
	IPAC_PAK_parse_resource_info,	/* parse_resource_info */
	IPAC_PAK_extract_resource,		/* extract_resource */
	IPAC_PAK_save_resource,			/* save_resource */
	IPAC_PAK_release_resource,		/* release_resource */
	IPAC_PAK_release				/* release */
};

/* 接口函数: 向cui_core注册支持的封包类型 */
int CALLBACK IPAC_register_cui(struct cui_register_callback *callback)
{
	/* 注册cui插件支持的扩展名、资源放入扩展名、处理回调函数和封包属性 */
	if (callback->add_extension(callback->cui, _T(".PAK"), NULL, 
		NULL, &IPAC_PAK_operation, CUI_EXT_FLAG_PKG | CUI_EXT_FLAG_DIR))
			return -1;

	if (callback->add_extension(callback->cui, _T(".WST"), _T(".wav"), 
		NULL, &IPAC_WST_operation, CUI_EXT_FLAG_PKG))
			return -1;	

	return 0;
}

 

Ah. It is a rather minor brand so I was afraid that might be the case. 

anyhow, thanks for the help :sachi:   I'll try to figure something out with the info you got me

Share this post


Link to post
Share on other sites
On 5/28/2019 at 6:32 AM, ichigop3p said:

It has nothing to do with language. . .

Use other method of extracting that script. . .I encountered that also. . .Then I realized to change program for extracting the scenarios. . .

Do you know what programs to use for MSD scenario files and MED files? I need an extractor and compiler.

Edited by Haiyami

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.

×