他人の空似自作物置場

touhouSE_th145BGMOnly.zip/touhouSE_src/thmj.cpp

#include "stdafx.h"

namespace THMJ {

using namespace Utility;

bool thmj_convert(const unsigned char *in, unsigned int in_size, unsigned char *out, unsigned int out_size) {
	unsigned char dic[0x1000];
	unsigned int addr = 0xFF0;

	memset(dic, 0, 0x1000);
	const unsigned char *in_ptr = in;
	const unsigned char * const in_end = &in[in_size];
	unsigned char *out_ptr = out;
	const unsigned char * const out_end = &out[out_size];
	while(out_ptr < out_end && in_ptr < in_end){
		unsigned int flags = static_cast<unsigned int>(*in_ptr + 0x100);
		in_ptr++;
		while(flags > 1) {
			if((flags&0x01) == 1){
				if(in_ptr >= in_end || out_ptr >= out_end) {
					return false;
				}
				*out_ptr = *in_ptr;
				dic[addr] = *in_ptr;
				out_ptr++;
				in_ptr++;
				addr = (addr + 1) % sizeof(dic);
			} else {
				if(&in_ptr[2] > in_end) {
					return false;
				}
				unsigned int dic_ptr = static_cast<unsigned int>(in_ptr[0] + ((in_ptr[1]&0xF0) << 4));
				const unsigned int len = static_cast<unsigned int>((in_ptr[1]&0x0F) + 3);
				if(&out_ptr[len] > out_end) {
					return false;
				}
				in_ptr += 2;
				for(unsigned int i = 0; i < len; i++) {
					*out_ptr = dic[dic_ptr];
					out_ptr++;
					dic[addr] = dic[dic_ptr];
					addr = (addr + 1) % sizeof(dic);
					dic_ptr = (dic_ptr + 1) % sizeof(dic);
				}
			}
			if(in_ptr == in_end) {
				break;
			}
			flags >>= 1;
		}
	}
	return true;
}

bool Extract(std::vector<unsigned char> &data, boost::shared_ptr<const LIST> file_data, boost::shared_ptr<FILE> fp) {
	if(file_data->size == 0) {
		data.clear();
		return true;
	}
	data.resize(file_data->size);
	::fseek(fp.get(), static_cast<int>(file_data->addr), SEEK_SET);
	::fread(&data.front(), 1, data.size(), fp.get());
	if(data.size() < 4) {
		return true;
	}
	if(::memcmp(&data[0], "LZSS", 4) == 0) {
		const unsigned int out_size = *reinterpret_cast<unsigned int*>(&data[4]);
		std::vector<unsigned char> out(out_size);
		if(!thmj_convert(&data[8], data.size() - 8, &out[0], out_size)) {
			return false;
		}
		data.swap(out);
	}

	return true;
}

bool PutFile(boost::shared_ptr<const LIST> file_data, const std::vector<unsigned char> &data, const std::vector<boost::shared_ptr<LIST> > &, boost::shared_ptr<FILE>) {
	char dir[MAX_PATH];
	::GetCurrentDirectoryA(MAX_PATH, dir);
	boost::shared_ptr<FILE> fp = MyFOpen(file_data->fn, "wb");
	if(!fp) {
		return false;
	}
	if(data.empty()) {
		return true;
	}
	if(data.size() != ::fwrite(&data.front(), 1, data.size(), fp.get())) {
		return false;
	}
	return true;
}

bool GetList(std::vector<boost::shared_ptr<LIST> > &list, boost::shared_ptr<FILE> fp) {
	if(!fp) {
		return false;
	}
	::fseek(fp.get(), 0, SEEK_END);
	const unsigned int dat_size = static_cast<unsigned int>(::ftell(fp.get()));
	if(dat_size < 16) {
		return false;
	}
	::fseek(fp.get(), 0, SEEK_SET);
	unsigned char head[8];
	if(sizeof(head) != ::fread(head, 1, sizeof(head), fp.get())) {
		return false;
	}
	if(*reinterpret_cast<const unsigned int *>(head) != 0x4B434150) {//識別子PACK
		return false;
	}
	const unsigned int file_count = *reinterpret_cast<unsigned int*>(&head[4]);
	if(dat_size <= file_count * 80) {
		return false;
	}

	list.resize(file_count);
	for(unsigned int i = 0; i < file_count; i++) {
		list[i].reset(new LIST());
		if(64 != ::fread(list[i]->fn, 1, 64, fp.get())) {
			return false;
		}
		if(STRLEN(list[i]->fn) >= 64){
			return false;
		}
		::fseek(fp.get(), 8, SEEK_CUR);
		if(1 != ::fread(&list[i]->addr, 4, 1, fp.get())) {
			return false;
		}
		if(1 != ::fread(&list[i]->comp_size, 4, 1, fp.get())) {
			return false;
		}
		list[i]->size = list[i]->comp_size;
	}
	return true;
}

} // THMJ