他人の空似自作物置場

touhouSE.zip/touhouSE_src/npa.cpp

#include "stdafx.h"

namespace NPA {

using namespace ::Utility;

namespace {

void UnCrypt(unsigned char *data, unsigned int size) {
	const unsigned char map[] = {0xBD, 0xAA, 0xBC, 0xB4, 0xAB, 0xB6, 0xBC, 0xB4};
	for(unsigned int i = 0; i < size; i++) {
		data[i] ^= map[i % (sizeof(map) / sizeof(*map))];
	}
}

} // anonymous

bool Extract(std::vector<unsigned char> &data, std::shared_ptr<const LIST> file_data, std::shared_ptr<FILE> fp) {
	BOOST_ASSERT(file_data->comp_size == file_data->size);
	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);
	if(data.size() != ::fread(&data.front(), 1, data.size(), fp.get())) {
		return false;
	}
	UnCrypt(&data.front(), data.size());
	return true;
}

bool PutFile(std::shared_ptr<const LIST> file_data, const std::vector<unsigned char> &data, const std::vector<std::shared_ptr<LIST> > &, std::shared_ptr<FILE>) {
	const char * const file_ext = ::PathFindExtensionA(file_data->fn);
	std::shared_ptr<FILE> fp = MyFOpen(file_data->fn, "wb");
	if(file_data->size == 0) {
		return true;
	}
	if(data.size() != ::fwrite(&data.front(), 1, data.size(), fp.get())) {
		return false;
	}
	return true;
}


bool GetList(std::vector<std::shared_ptr<LIST> > &list, std::shared_ptr<FILE> fp) {
	if(!fp) {
		return false;
	}
	::fseek(fp.get(), 0, SEEK_END);
	const unsigned int file_size = static_cast<unsigned int>(::ftell(fp.get()));
	if(file_size < 4){
		return false;
	}
	::fseek(fp.get(), 0, SEEK_SET);
	unsigned int head_size;
	if(1 != fread(&head_size, 4, 1, fp.get())) {
		return false;
	}
	unsigned int read_size = 4;
	if(head_size < 4 || file_size < read_size + head_size) {
		return false;
	}
	std::vector<unsigned char> head_data(head_size);
	if(head_size != ::fread(&head_data.front(), 1, head_size, fp.get())) {
		return false;
	}
	read_size += head_size;
	UnCrypt(&head_data.front(), head_data.size());
	const unsigned char *p = &head_data.front();
	const unsigned int file_count = *reinterpret_cast<const unsigned int *>(p);
	p += 4;
	if (file_size < read_size + static_cast<unsigned long long int>(file_count) * (4 + 1 + 4 + 4 + 4)) {
		return false;
	}

	list.resize(file_count);
	unsigned int last_addr = 0;
	const unsigned char * const end = &head_data.back();
	for(unsigned int i = 0; i < file_count; i++) {
		list[i].reset(new LIST());
		if(end - p + 1 < 4) {
			return false;
		}
		const unsigned int filename_length = *reinterpret_cast<const unsigned int *>(p);
		p += 4;
		if(filename_length > 99 || static_cast<unsigned int>(std::distance(p, end + 1)) < filename_length + 12) {
			return false;
		}
		if(0 != ::memcpy_s(list[i]->fn, sizeof(list[i]->fn), p, filename_length)) {
			return false;
		}
		p += filename_length;
		list[i]->fn[filename_length] = '\0';
		list[i]->comp_size = list[i]->size = *reinterpret_cast<const unsigned int *>(p);
		p += 4;
		list[i]->addr = *reinterpret_cast<const unsigned int *>(p);
		p += 4;
		p += 4; // unknown
		if(last_addr < list[i]->addr + list[i]->comp_size) {
			last_addr = list[i]->addr + list[i]->comp_size;
		}
	}
	if(last_addr > file_size) {
		return false;
	}
	return true;
}

} // NPA