Skip to content

Instantly share code, notes, and snippets.

@krofna
Last active Jun 23, 2022
Embed
What would you like to do?
bl unpacker
/*
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