Last active
June 23, 2022 15:01
-
-
Save krofna/10605563 to your computer and use it in GitHub Desktop.
bl unpacker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Copyright © 2014 Mislav Blažević <krofnica996@gmail.com> | |
This work is free. You can redistribute it and/or modify it under the | |
terms of the Do What The Fuck You Want To Public License, Version 2, | |
as published by Sam Hocevar. See the COPYING file for more details. | |
*/ | |
#include <fstream> | |
#include <cstdint> | |
#include <cstring> | |
#include <iostream> | |
#include <vector> | |
#include <boost/filesystem.hpp> | |
using namespace boost::filesystem; | |
using namespace std; | |
string StripDir(string Filename) | |
{ | |
#ifdef _WIN32 | |
size_t Index = Filename.find_last_of("\\"); | |
#else | |
size_t Index = Filename.find_last_of("/"); | |
#endif | |
if (Index != string::npos) | |
Filename = Filename.substr(Index + 1); | |
return Filename; | |
} | |
class File | |
{ | |
public: | |
File() | |
{ | |
} | |
File(const char* Filename, uint32_t Size) : Size(Size) | |
{ | |
memset(Name, 0, 9); | |
strcpy(Name, Filename); | |
} | |
void ReadHeader(ifstream& in) | |
{ | |
in.read(Name, 9); | |
in.read((char*)&Size, 4); | |
in.read((char*)&Offset, 4); | |
} | |
char* ReadData(ifstream& in) | |
{ | |
char* pData = new char[Size]; | |
in.seekg(Offset); | |
in.read(pData, Size); | |
return pData; | |
} | |
void WritePack(ofstream& out) | |
{ | |
uint32_t NullOffset = 0; | |
out.write(Name, 9); | |
out.write((char*)&Size, 4); | |
Offset = out.tellp(); | |
out.write((char*)&NullOffset, 4); | |
} | |
void WritePackData(ofstream& out, const char* Dir, const char* Ext) | |
{ | |
uint32_t Tmp = out.tellp(); | |
out.seekp(Offset); | |
out.write((char*)&Tmp, 4); | |
out.seekp(Tmp); | |
Offset = 0; | |
string Filename = string(Dir) + string(Name) + string(".") + string(Ext); | |
ifstream in(Filename, ios::binary); | |
char* pData = ReadData(in); | |
if (strcmp(Ext, "WSC") == 0) | |
{ | |
for (uint32_t i = 0; i < Size; ++i) | |
{ | |
unsigned char al = pData[i]; | |
unsigned char cl = 2; | |
pData[i] = (al << cl) | (al >> (8 - cl)); | |
} | |
} | |
out.write(pData, Size); | |
delete[] pData; | |
Offset = Tmp; | |
} | |
const char* GetName() const | |
{ | |
return Name; | |
} | |
uint32_t GetSize() const | |
{ | |
return Size; | |
} | |
private: | |
char Name[9]; | |
uint32_t Size; | |
uint32_t Offset; | |
}; | |
class Type | |
{ | |
public: | |
Type(const char* Ext) : NumFiles(0) | |
{ | |
memcpy(this->Ext, Ext, 4); | |
} | |
Type() | |
{ | |
} | |
void ReadHeader(ifstream& in) | |
{ | |
in.read(Ext, 4); | |
in.read((char*)&NumFiles, 4); | |
in.read((char*)&Offset, 4); | |
Files.resize(NumFiles); | |
} | |
void ReadFileHeader(ifstream& in) | |
{ | |
in.seekg(Offset); | |
for (int i = 0; i < NumFiles; ++i) | |
Files[i].ReadHeader(in); | |
} | |
void WriteUnpack(ifstream& in, const char* Directory) | |
{ | |
for (int i = 0; i < NumFiles; ++i) | |
{ | |
File* pFile = &Files[i]; | |
string Filename = string(Directory) + string("/") + string(pFile->GetName()) + string(".") + string(Ext); | |
ofstream out(Filename); | |
char* pData = pFile->ReadData(in); | |
if (strcmp(Ext, "WSC") == 0) | |
{ | |
for (uint32_t i = 0; i < pFile->GetSize(); ++i) | |
{ | |
unsigned char al = pData[i]; | |
unsigned char cl = 2; | |
pData[i] = (al >> cl) | (al << (8 - cl)); | |
} | |
} | |
out.write(pData, pFile->GetSize()); | |
delete[] pData; | |
} | |
} | |
void WritePack(ofstream& out) | |
{ | |
uint32_t NullOffset = 0; | |
out.write(Ext, 4); | |
out.write((char*)&NumFiles, 4); | |
Offset = out.tellp(); | |
out.write((char*)&NullOffset, 4); | |
} | |
void WritePackFile(ofstream& out) | |
{ | |
uint32_t Tmp = out.tellp(); | |
out.seekp(Offset); | |
Offset = Tmp; | |
out.write((char*)&Offset, 4); | |
out.seekp(Offset); | |
for (uint32_t i = 0; i < NumFiles; ++i) | |
Files[i].WritePack(out); | |
} | |
void WritePackFileData(const char* Dir, ofstream& out) | |
{ | |
for (uint32_t i = 0; i < NumFiles; ++i) | |
Files[i].WritePackData(out, Dir, Ext); | |
} | |
void AppendFile(string Filename) | |
{ | |
ifstream in(Filename, ios::binary); | |
in.seekg(0, ios::end); | |
uint32_t Size = in.tellg(); | |
in.seekg(0, ios::beg); | |
Filename = StripDir(Filename); | |
Files.push_back(File(Filename.substr(0, Filename.size() - 4).c_str(), Size)); | |
++NumFiles; | |
} | |
const char* GetExt() const | |
{ | |
return Ext; | |
} | |
private: | |
char Ext[4]; | |
uint32_t NumFiles; | |
uint32_t Offset; | |
vector<File> Files; | |
}; | |
class Archive | |
{ | |
public: | |
Archive(const char* Filename) | |
{ | |
in.open(Filename, ios::binary); | |
in.read((char*)&NumTypes, 4); | |
Types.resize(NumTypes); | |
for (uint32_t i = 0; i < NumTypes; ++i) | |
Types[i].ReadHeader(in); | |
for (uint32_t i = 0; i < NumTypes; ++i) | |
Types[i].ReadFileHeader(in); | |
} | |
Archive() : NumTypes(0) | |
{ | |
} | |
void AppendDirectory(const char* Directory) | |
{ | |
path dir(Directory); | |
if (!exists(dir) || !is_directory(dir)) | |
return; | |
directory_iterator end; | |
for (directory_iterator i(dir); i != end; ++i) | |
if (!is_directory(i->path())) | |
AppendFile(i->path().string()); | |
} | |
void WriteUnpack(const char* Directory) | |
{ | |
create_directory(Directory); | |
for (uint32_t i = 0; i < NumTypes; ++i) | |
Types[i].WriteUnpack(in, Directory); | |
} | |
void WritePack(string Filename) | |
{ | |
ofstream out(Filename + string(".arc"), ios::binary); | |
out.write((char*)&NumTypes, 4); | |
for (uint32_t i = 0; i < NumTypes; ++i) | |
Types[i].WritePack(out); | |
for (uint32_t i = 0; i < NumTypes; ++i) | |
Types[i].WritePackFile(out); | |
for (uint32_t i = 0; i < NumTypes; ++i) | |
Types[i].WritePackFileData(string(Filename + "/").c_str(), out); | |
} | |
private: | |
void AppendFile(string Filename) | |
{ | |
string Full = Filename; | |
Filename = StripDir(Filename); | |
string Ext = Filename.substr(Filename.size() - 3); | |
Type* pType = nullptr; | |
for (int i = 0; i < Types.size(); ++i) | |
if (string(Types[i].GetExt()) == Ext) | |
pType = &Types[i]; | |
if (!pType) | |
{ | |
Types.push_back(Type(Ext.c_str())); | |
pType = &Types.back(); | |
++NumTypes; | |
} | |
pType->AppendFile(Full); | |
} | |
ifstream in; | |
uint32_t NumTypes; | |
vector<Type> Types; | |
}; | |
void main_unpack(int argc, char** argv) | |
{ | |
if (string(argv[1]) != "x") | |
{ | |
cout << "usage: " << argv[0] << " x file.arc" << endl; | |
return; | |
} | |
string Directory = StripDir(string(argv[2])); | |
Directory.resize(Directory.size() - 4); | |
Archive* pArchive = new Archive(argv[2]); | |
pArchive->WriteUnpack(Directory.c_str()); | |
delete pArchive; | |
} | |
void main_pack(int argc, char** argv) | |
{ | |
if (argc != 2) | |
{ | |
cout << "usage: " << argv[0] << " folder" << endl; | |
return; | |
} | |
Archive* pArchive = new Archive; | |
pArchive->AppendDirectory(argv[1]); | |
pArchive->WritePack(string(argv[1])); | |
delete pArchive; | |
} | |
int main(int argc, char** argv) | |
{ | |
if (argc == 3) | |
main_unpack(argc, argv); | |
else | |
main_pack(argc, argv); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment