某データ展開用Susieプラグイン [投げっぱなしツール]
某ゲームで使われていたアーカイブデータを展開するSusieプラグインです。
同様のプラグインが存在していたはずなのですが、配布サイトが閉鎖していたため、自分で作ってみました。
といっても、圧縮も暗号化も全くしていないデータなので、アーカイブ型のSusieプラグインの練習も兼ねての習作です。
大した理由はないけれど、公開はソースコードのみ。
使いたい人は、各自、コンパイルしてください。
「コンパイルの方法を詳しく説明しろ」とか「コンパイル済みのバイナリデータを寄越せ」といった要望には、一切お答えしません。
ちなみに、Visual C++ 7.1 (Visual Studio .NET 2003)ではコンパイル出来たのを確認。
「某ゲームって、なんじゃー」という質問にも答えませんので、親切な人が「○○では?」とコメント欄で指摘してくれるのを期待しましょう。
ところで、GetFile API にメモリ上のイメージを渡した時の処理って、おかしくないかな?っていうか、おかしいよね?#include <windows.h> #include <time.h> #include <memory> #pragma pack(push,1) // Susieプラグインが扱うファイル情報 typedef struct { unsigned char method[8]; // 圧縮法の種類 unsigned long position; // ファイル上での位置 unsigned long compsize; // 圧縮されたサイズ unsigned long filesize; // 元のファイルサイズ time_t timestamp; // ファイルの更新日時 char path[200]; // 相対パス char filename[200]; // ファイルネーム unsigned long crc; // CRC } fileInfo; // データファイルのヘッダ部分にあるファイル情報 struct PackFileInfo { char path[0x20]; // ファイル名 unsigned long offset; // ファイル先頭からの位置 unsigned long unknown; // 不明(ファイルの種類…?) unsigned long size; // ファイルサイズ unsigned long size0; // ファイルサイズ }; // sizeとsize0の、どっちかがオリジナルサイズで、もう一方が圧縮サイズ? #pragma pack(pop) // データファイルヘッダ部のサイズ static const int PACKDAT_HEADER_SIZE = 0x10; // =================================================================== // ファイル出力クラス class FileWriter { private: HANDLE handle; public: FileWriter(const char* path) { handle = ::CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); } ~FileWriter() { if (handle != INVALID_HANDLE_VALUE) ::CloseHandle(handle); } bool write(const void* buff, unsigned long size) { if (handle == INVALID_HANDLE_VALUE) return false; DWORD write_byte; if (!::WriteFile(handle, buff, size, &write_byte, NULL)) return false; return write_byte == size; } }; // ファイル入力クラス class FileReader { private: HANDLE handle; public: FileReader(const char* path) { handle = ::CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } ~FileReader() { close(); } void close() { if (handle != INVALID_HANDLE_VALUE) ::CloseHandle(handle); } bool seek(long pos) { if (handle == INVALID_HANDLE_VALUE) return false; return ::SetFilePointer(handle, pos, NULL, FILE_BEGIN) != (DWORD)-1; } bool read(void* buff, unsigned long size) { if (handle == INVALID_HANDLE_VALUE) return false; DWORD read_byte; if (!::ReadFile(handle, buff, size, &read_byte, NULL)) return false; return read_byte == size; } }; // データファイルのファイル情報を読むクラス class FileInfoReader { public: virtual ~FileInfoReader() {} virtual const PackFileInfo* next(void*) = 0; virtual bool toMemory(unsigned long, unsigned long, void*) = 0; virtual bool toFile(unsigned long, unsigned long, const char*) = 0; }; // ファイルからデータファイルのファイル情報を読むクラス class FIRFile : public FileInfoReader { private: FileReader in; public: FIRFile(LPSTR fname, long offset) : in(fname) { if (!in.seek(offset + PACKDAT_HEADER_SIZE)) close(); } const PackFileInfo* next(void* buff) { if (in.read(buff, sizeof(PackFileInfo))) return reinterpret_cast<PackFileInfo*>(buff); else return NULL; } bool toMemory(unsigned long offset, unsigned long size, void* buff) { if (!in.seek(offset)) return false; return in.read(buff, size); } bool toFile(unsigned long offset, unsigned long size, const char* path) { if (!in.seek(offset)) return false; char buff[1024]; DWORD read_byte; FileWriter out(path); while (size != 0) { unsigned long s = min(size, 1024); if (!in.read(buff, s)) return false; if (!out.write(buff, s)) return false; size -= s; } return true; } }; // メモリ上のデータイメージからデータファイルのファイル情報を読むクラス class FIRMem : public FileInfoReader { private: const char* data; unsigned long current; unsigned long end; public: FIRMem(LPSTR buff, long len) : data(buff), current(PACKDAT_HEADER_SIZE), end(len) { } const PackFileInfo* next(void*) { const void* p = data + current; current += sizeof(PackFileInfo); return reinterpret_cast<const PackFileInfo*>(current <= end ? p : NULL); } bool toMemory(unsigned long offset, unsigned long size, void* buff) { if (offset + size > end) return false; ::CopyMemory(buff, data + offset, size); return true; } bool toFile(unsigned long offset, unsigned long size, const char* path) { if (offset + size > end) return false; FileWriter out(path); return out.write(data + offset, size); } }; // データファイルのファイル情報からSusie用ファイル情報に変換 void copyPackFileInfo2fileInfo(fileInfo* dest, const PackFileInfo* src) { ::ZeroMemory(dest, sizeof(fileInfo)); memcpy(dest->method, "PACKDAT", 8); dest->position = src->offset; dest->compsize = src->size; dest->filesize = src->size; // dest->timestamp = 0; // strcpy(dest->path, ""); strncpy(dest->filename, src->path, 0x20); // dest->crc = 0;; } // =================================================================== BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } // =================================================================== // =================================================================== // Plug-inに関する情報を得る extern "C" int WINAPI GetPluginInfo(int infono, LPSTR buf, int buflen) { const char* DATA[] = { "00AM", "PACKDAT extract plug-in programmed by 依積晶紀", "*.dat", "PACKDAT archive", }; const int num = sizeof(DATA)/sizeof(DATA[0]); if (infono < 0 || infono >= num) return 0; const int output_len = min(buflen, strlen(DATA[infono]) + 1); memcpy(buf, DATA[infono], output_len); return output_len; } // 展開可能な(対応している)ファイル形式か調べる。 extern "C" int WINAPI IsSupported(LPSTR filename, DWORD dw) { char buff[100]; DWORD size; const char* DATA; if (HIWORD(dw) == 0) { // ファイルハンドル指定 if (!::ReadFile((HANDLE)dw, buff, sizeof(buff), &size, NULL)) { return 0; // 読み込みエラーは、「非対応」と言う事で… } if (size <= PACKDAT_HEADER_SIZE + sizeof(PackFileInfo)) { return 0; } DATA = buff; } else { // バッファ指定 DATA = reinterpret_cast<const char*>(dw); size = 1024*2; } return memcmp(DATA, "PACKDAT", 7) == 0 ? 1 : 0; } // アーカイブ内のすべてのファイルの情報を取得する extern "C" int WINAPI GetArchiveInfo(LPSTR buf, long len, unsigned int flag, HLOCAL* lphInf) { char buff[0x30]; std::auto_ptr<FileInfoReader> in; switch (flag & 0x07) { case 0: in.reset(new FIRFile(buf, len)); break; case 1: in.reset(new FIRMem(buf, len)); break; default: return -1; } const PackFileInfo* info = in->next(buff); if (info == NULL) return 2; if ((info->offset - PACKDAT_HEADER_SIZE) % sizeof(PackFileInfo) != 0) return 2; const int num = (info->offset - PACKDAT_HEADER_SIZE) / sizeof(PackFileInfo); HLOCAL hInf = ::LocalAlloc(LHND, (num + 1)*sizeof(fileInfo)); if (hInf == NULL) return 4; fileInfo* pInf = reinterpret_cast<fileInfo*>(::LocalLock(hInf)); if (pInf == NULL) { ::LocalFree(hInf); return 5; } copyPackFileInfo2fileInfo(pInf, info); pInf++; for (int i = 1; i < num; i++, pInf++) { info = in->next(buff); if (info == NULL) { ::LocalUnlock(hInf); ::LocalFree(hInf); return 3; } copyPackFileInfo2fileInfo(pInf, info); } ::ZeroMemory(pInf, sizeof(fileInfo)); ::LocalUnlock(hInf); *lphInf = hInf; return 0; } // アーカイブ内の指定したファイルの情報を取得する extern "C" int WINAPI GetFileInfo(LPSTR buf, long len, LPSTR filename, unsigned int flag, fileInfo *lpInfo) { int (*CompareFunction)(const char*,const char*); CompareFunction = (flag & 0x0080) == 0 ? strcmp : stricmp; HANDLE hInf; int ret = GetArchiveInfo(buf, len, flag, &hInf); if (ret != 0) return ret; ret = 8; const fileInfo* pInf = reinterpret_cast<fileInfo*>(::LocalLock(hInf)); while (pInf->method[0] != '\0') { if (CompareFunction(pInf->filename, filename) == 0) { memcpy(lpInfo, pInf, sizeof(fileInfo)); ret = 0; break; } pInf++; } ::LocalUnlock(hInf); ::LocalFree(hInf); return ret; } // アーカイブ内のファイルを取得する extern "C" int WINAPI GetFile(LPSTR src, long len, LPSTR dest, unsigned int flag, FARPROC prgressCallback, long lData) { char buff[0x30]; std::auto_ptr<FileInfoReader> in; switch (flag & 0x07) { case 0: in.reset(new FIRFile(src, 0)); break; case 1: in.reset(new FIRMem(src, len)); break; default: return -1; } const PackFileInfo* info = in->next(buff); if (info == NULL) return 2; if ((info->offset - PACKDAT_HEADER_SIZE) % sizeof(PackFileInfo) != 0) return 2; const int num = (info->offset - PACKDAT_HEADER_SIZE) / sizeof(PackFileInfo); unsigned long offset = 0; unsigned long size = 0; const char* fname = NULL; if (info->offset == len) { offset = info->offset; size = info->size; fname = info->path; } else { for (int i = 1; i < num; i++) { info = in->next(buff); if (info == NULL) return -1; if (info->offset == len) { offset = info->offset; size = info->size; fname = info->path; break; } } } if (fname == NULL) return -1; if ((flag & 0x0700) == 0) { // ファイルに出力 char path[MAX_PATH]; sprintf(path, "%s\\%s", dest, fname); if (!in->toFile(offset, size, path)) { return 6; } return 0; } else if ((flag & 0x0700) == 0x0100) { // メモリに出力 HANDLE hBuf = ::LocalAlloc(LHND, size); if (hBuf == NULL) return 4; void* pBuf = ::LocalLock(hBuf); if (pBuf == NULL) { ::LocalFree(hBuf); return 5; } if (!in->toMemory(offset, size, pBuf)) { ::LocalUnlock(hBuf); ::LocalFree(hBuf); return 6; } ::LocalUnlock(hBuf); *((HANDLE*)dest) = hBuf; return 0; } else { return -1; } }
今日の一冊 | |
|
タグ:VisualC++
2007-06-16 08:59
nice!(0)
コメント(0)
トラックバック(0)
コメント 0