From 6fdb39c69c2d5e526aa880dc5b3b9989fd4458dd Mon Sep 17 00:00:00 2001 From: toyobayashi <lifenglin314@outlook.com> Date: Thu, 19 Sep 2019 20:43:40 +0800 Subject: [PATCH] 2.0.1 --- CGSSAssetsDownloader.vcxproj | 7 +- CGSSAssetsDownloader.vcxproj.filters | 21 +- lib/ACBExtractor/ACBExtractor.cpp | 111 --- lib/ACBExtractor/AFSArchive.cpp | 67 -- lib/ACBExtractor/Reader.cpp | 163 ----- lib/ACBExtractor/TrackList.cpp | 81 --- lib/ACBExtractor/UTFTable.cpp | 313 -------- lib/ACBExtractor/include/ACBExtractor.h | 23 - lib/ACBExtractor/include/AFSArchive.h | 33 - lib/ACBExtractor/include/Reader.h | 61 -- lib/ACBExtractor/include/TrackList.h | 29 - lib/ACBExtractor/include/UTFTable.h | 72 -- lib/acb/acb.c | 915 ++++++++++++++++++++++++ lib/acb/acb.h | 93 +++ src/ApiClient.cpp | 2 +- src/CGSSAssetsDownloader.cpp | 13 +- src/download.cpp | 2 +- 17 files changed, 1027 insertions(+), 979 deletions(-) delete mode 100644 lib/ACBExtractor/ACBExtractor.cpp delete mode 100644 lib/ACBExtractor/AFSArchive.cpp delete mode 100644 lib/ACBExtractor/Reader.cpp delete mode 100644 lib/ACBExtractor/TrackList.cpp delete mode 100644 lib/ACBExtractor/UTFTable.cpp delete mode 100644 lib/ACBExtractor/include/ACBExtractor.h delete mode 100644 lib/ACBExtractor/include/AFSArchive.h delete mode 100644 lib/ACBExtractor/include/Reader.h delete mode 100644 lib/ACBExtractor/include/TrackList.h delete mode 100644 lib/ACBExtractor/include/UTFTable.h create mode 100644 lib/acb/acb.c create mode 100644 lib/acb/acb.h diff --git a/CGSSAssetsDownloader.vcxproj b/CGSSAssetsDownloader.vcxproj index 6686132..1ba1579 100644 --- a/CGSSAssetsDownloader.vcxproj +++ b/CGSSAssetsDownloader.vcxproj @@ -147,11 +147,7 @@ </Link> </ItemDefinitionGroup> <ItemGroup> - <ClCompile Include="lib\ACBExtractor\ACBExtractor.cpp" /> - <ClCompile Include="lib\ACBExtractor\AFSArchive.cpp" /> - <ClCompile Include="lib\ACBExtractor\Reader.cpp" /> - <ClCompile Include="lib\ACBExtractor\TrackList.cpp" /> - <ClCompile Include="lib\ACBExtractor\UTFTable.cpp" /> + <ClCompile Include="lib\acb\acb.c" /> <ClCompile Include="lib\aes\aes.c" /> <ClCompile Include="lib\jstype\base64\decode.c" /> <ClCompile Include="lib\jstype\base64\encode.c" /> @@ -175,6 +171,7 @@ <ClCompile Include="src\lz4.cpp" /> </ItemGroup> <ItemGroup> + <ClInclude Include="lib\acb\acb.h" /> <ClInclude Include="lib\aes\aes.h" /> <ClInclude Include="lib\aes\aes.hpp" /> <ClInclude Include="lib\curl\curl.h" /> diff --git a/CGSSAssetsDownloader.vcxproj.filters b/CGSSAssetsDownloader.vcxproj.filters index 5c53559..caab509 100644 --- a/CGSSAssetsDownloader.vcxproj.filters +++ b/CGSSAssetsDownloader.vcxproj.filters @@ -39,21 +39,6 @@ <ClCompile Include="src\lz4.cpp"> <Filter>源文件</Filter> </ClCompile> - <ClCompile Include="lib\ACBExtractor\ACBExtractor.cpp"> - <Filter>源文件</Filter> - </ClCompile> - <ClCompile Include="lib\ACBExtractor\AFSArchive.cpp"> - <Filter>源文件</Filter> - </ClCompile> - <ClCompile Include="lib\ACBExtractor\Reader.cpp"> - <Filter>源文件</Filter> - </ClCompile> - <ClCompile Include="lib\ACBExtractor\TrackList.cpp"> - <Filter>源文件</Filter> - </ClCompile> - <ClCompile Include="lib\ACBExtractor\UTFTable.cpp"> - <Filter>源文件</Filter> - </ClCompile> <ClCompile Include="lib\sqlite3\sqlite3.c"> <Filter>源文件</Filter> </ClCompile> @@ -93,6 +78,9 @@ <ClCompile Include="lib\jstype\Uuid.cpp"> <Filter>源文件</Filter> </ClCompile> + <ClCompile Include="lib\acb\acb.c"> + <Filter>源文件</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="lib\sha1\sha1.h"> @@ -200,5 +188,8 @@ <ClInclude Include="lib\jstype\Uuid.h"> <Filter>头文件</Filter> </ClInclude> + <ClInclude Include="lib\acb\acb.h"> + <Filter>头文件</Filter> + </ClInclude> </ItemGroup> </Project> \ No newline at end of file diff --git a/lib/ACBExtractor/ACBExtractor.cpp b/lib/ACBExtractor/ACBExtractor.cpp deleted file mode 100644 index d6a761e..0000000 --- a/lib/ACBExtractor/ACBExtractor.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "./include/ACBExtractor.h" -#include <regex> - -ACBExtractor::ACBExtractor(std::string acbFile) { - std::regex re("/|\\\\"); -#ifdef _WIN32 - acbFile = std::regex_replace(acbFile, re, "\\"); -#else - std::regex_replace(acbFile, re, "/"); -#endif - path = acbFile; - headerTable = new UTFTable(acbFile); - tracklist = new TrackList(headerTable); - - acbData* awbData = headerTable->get(0, "AwbFile"); - unsigned char* awbbuf = new unsigned char[awbData->length]; - headerTable->readBinary(awbbuf, static_cast<unsigned int*>(awbData->data)[0], static_cast<unsigned int*>(awbData->data)[1]); - awbFile = new AFSArchive(awbbuf, awbData->length); - delete[] awbbuf; -} - -bool ACBExtractor::extract(void (*callback)(std::string filename, unsigned int length)) { - std::string dirname, targetDir, filename; - -#ifdef _WIN32 - auto posw = path.find_last_of('\\'); - if (posw == std::string::npos) { - dirname = "."; - filename = path; - } else { - dirname = path.substr(0, posw); - filename = path.substr(posw + 1); - } - targetDir = dirname + "\\_acb_" + filename; - std::string cmd = "mkdir " + targetDir; -#else - auto posl = path.find_last_of('/'); - if (posl == std::string::npos) { - dirname = "."; - filename = path; - } else { - dirname = path.substr(0, posl); - filename = path.substr(posl + 1); - } - targetDir = dirname + "/_acb_" + filename; - std::string cmd = "mkdir -p " + targetDir; -#endif - - system(cmd.c_str()); - std::ofstream fs; - for (unsigned int i = 0; i < tracklist->length; i++) { - int inFiles = -1; - for (unsigned int j = 0; j < awbFile->header->fileCount; j++) { - if (tracklist->tracks[i].wavId == awbFile->files[j].id) { - inFiles = j; - break; - } - } - if (inFiles != -1) { - std::string cueName = tracklist->tracks[i].cueName; - std::string encodeType = ""; - switch (tracklist->tracks[i].encodeType) { - case 0: { - encodeType = ".adx"; - break; - } - case 2: { - encodeType = ".hca"; - break; - } - case 7: { - encodeType = ".at3"; - break; - } - case 8: { - encodeType = ".vag"; - break; - } - case 9: { - encodeType = ".bcwav"; - break; - } - case 13: { - encodeType = ".dsp"; - break; - } - default: - break; - } -#ifdef _WIN32 - std::string acbFilename = targetDir + "\\" + cueName + encodeType; -#else - std::string acbFilename = targetDir + "/" + cueName + encodeType; -#endif - fs.open(acbFilename, std::ios::binary); - fs.write((const char*)awbFile->files[inFiles].buf, awbFile->files[inFiles].length); - if (callback) callback(cueName + encodeType, awbFile->files[inFiles].length); - fs.close(); - } - else { - return false; - } - } - return true; -} - -ACBExtractor::~ACBExtractor() { - delete headerTable; - delete tracklist; - delete awbFile; -} diff --git a/lib/ACBExtractor/AFSArchive.cpp b/lib/ACBExtractor/AFSArchive.cpp deleted file mode 100644 index ff6fce0..0000000 --- a/lib/ACBExtractor/AFSArchive.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "./include/AFSArchive.h" - -void AFSArchive::readHeader() { - std::streampos back = r->tell(); - r->seek(5); - header = new awbHeader; - - header->offsetSize = r->readUInt8(); - r->seek(8); - header->fileCount = r->readUInt32LE(); - header->alignment = r->readUInt32LE(); - header->ids = new unsigned short[header->fileCount]; - header->fileEndPoints = new unsigned int[header->fileCount + 1]; - - for (unsigned int i = 0; i < header->fileCount; i++) { - header->ids[i] = r->readUInt16LE(); - } - - for (unsigned int i = 0; i < header->fileCount + 1; i++) { - header->fileEndPoints[i] = r->readUIntLE(header->offsetSize); - } - - r->seek(back); -} - -AFSArchive::AFSArchive(unsigned char * awb, unsigned int l) { - r = new Reader(awb, l); - r->seek(0); - unsigned int t = r->readUInt32BE(); - if (t != 0x41465332) { - r->close(); - delete r; - throw "Not AWB file."; - } - - length = l; - readHeader(); - - files = new entryFile[header->fileCount]; - for (unsigned int i = 0; i < header->fileCount; i++) { - unsigned int tmp = header->fileEndPoints[i] % header->alignment; - - unsigned int start = (tmp == 0 ? header->fileEndPoints[i] / header->alignment : header->fileEndPoints[i] / header->alignment + 1) * header->alignment; - unsigned int length = header->fileEndPoints[i + 1] - start; - files[header->ids[i]].buf = new unsigned char[length]; - files[header->ids[i]].length = length; - files[header->ids[i]].id = header->ids[i]; - - std::streampos back = r->tell(); - r->seek(start); - r->read((char*)files[header->ids[i]].buf, length); - r->seek(back); - } - r->close(); -} - -AFSArchive::~AFSArchive() { - delete r; - for (unsigned int i = 0; i < header->fileCount; i++) { - delete[] files[i].buf; - } - delete[] files; - delete[] header->fileEndPoints; - delete[] header->ids; - delete header; - -} diff --git a/lib/ACBExtractor/Reader.cpp b/lib/ACBExtractor/Reader.cpp deleted file mode 100644 index b3f6aef..0000000 --- a/lib/ACBExtractor/Reader.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#include "./include/Reader.h" -#include <math.h> - -int Reader::isLittleEndian = -1; - -void Reader::checkEndian() { - if (isLittleEndian == -1) { - int x = 0x12; - isLittleEndian = *(char*)&x == 0x12 ? 1 : 0; - } -} - -// template<typename T> -// T Reader::readByte(bool isLE) { -// unsigned char buf[sizeof(T)]; -// unsigned int size = sizeof(T); -// read((char*)buf, size); -// if ((isLittleEndian && !isLE) || (!isLittleEndian && isLE)) { -// unsigned char temp; -// for (unsigned int i = 0; i < size / 2; i++) { -// temp = buf[i]; -// buf[i] = buf[size - 1 - i]; -// buf[size - 1 - i] = temp; -// } -// } - -// T* result = (T*)buf; - -// return *result; -// } - -Reader::Reader(unsigned char* buf, unsigned int length) { - checkEndian(); - std::string tmpname = std::tmpnam(nullptr); - tmpfile = tmpname; - - std::ofstream fs(tmpname, std::ios::binary); - fs.write((const char*)buf, length); - fs.close(); - length = length; - open(tmpfile, std::ios::binary); -} - -Reader::Reader() { - checkEndian(); - std::ifstream(); -} - -Reader::~Reader() { - if (tmpfile != "") remove(tmpfile.c_str()); -} - -Reader::Reader(std::string filename, ios_base::openmode mode) { - checkEndian(); - open(filename.c_str(), mode); -} - -void Reader::open(std::string filename, ios_base::openmode mode) { - std::ifstream::open(filename.c_str(), mode); - std::streampos current = tellg(); - seekg(0, std::ios::end); - length = (unsigned int)tellg(); - seekg(current, std::ios::beg); -} - -std::streampos Reader::tell() { - return tellg(); -} - -Reader& Reader::seek(std::streampos at, std::streampos offset) { - seekg(at + offset, std::ios::beg); - return *this; -} - -unsigned int Reader::readUInt32BE() { - return readByte<unsigned int>(); -} - -unsigned int Reader::readUInt32LE() { - return readByte<unsigned int>(true); -} - -unsigned long long Reader::readUInt64BE() { - return readByte<unsigned long long>(); -} - -unsigned long long Reader::readUInt64LE() { - return readByte<unsigned long long>(true); -} - -unsigned short Reader::readUInt16BE() { - return readByte<unsigned short>(); -} - -unsigned short Reader::readUInt16LE() { - return readByte<unsigned short>(true); -} - -unsigned char Reader::readUInt8() { - return readByte<unsigned char>(); -} - -char Reader::readInt8() { - return readByte<char>(); -} - -short Reader::readInt16BE() { - return readByte<short>(); -} - -short Reader::readInt16LE() { - return readByte<short>(true); -} - -int Reader::readInt32BE() { - return readByte<int>(); -} - -int Reader::readInt32LE() { - return readByte<int>(true); -} - -long long Reader::readInt64BE() { - return readByte<int>(); -} - -long long Reader::readInt64LE() { - return readByte<long long>(true); -} - -double Reader::readDoubleBE() { - return readByte<double>(); -} - -double Reader::readDoubleLE() { - return readByte<double>(true); -} - -float Reader::readFloatBE() { - return readByte<float>(); -} - -float Reader::readFloatLE() { - return readByte<float>(true); -} - -unsigned int Reader::readUIntLE(unsigned int size) { - unsigned char* buf = new unsigned char[size]; - - read((char*)buf, size); - - unsigned int result = 0; - for (unsigned int i = 0; i < size; i++) { - int high, low, power; - high = buf[i] / 16; - low = buf[i] % 16; - power = 2 * i; // 2 * size - 1 - 2 * i; - result += (high * (unsigned int)pow(16, power + 1) + low * (unsigned int)pow(16, power)); - } - - delete[] buf; - return result; -} diff --git a/lib/ACBExtractor/TrackList.cpp b/lib/ACBExtractor/TrackList.cpp deleted file mode 100644 index e24aded..0000000 --- a/lib/ACBExtractor/TrackList.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "./include/TrackList.h" - -TrackList::TrackList(UTFTable* utf) { - acbData* cueTableData = utf->get(0, "CueTable"); - unsigned char* buf1 = new unsigned char[cueTableData->length]; - utf->readBinary(buf1, static_cast<unsigned int*>(cueTableData->data)[0], static_cast<unsigned int*>(cueTableData->data)[1]); - cueTable = new UTFTable(buf1, cueTableData->length); - delete[] buf1; - - acbData* cueNameTableData = utf->get(0, "CueNameTable"); - unsigned char* buf2 = new unsigned char[cueNameTableData->length]; - utf->readBinary(buf2, static_cast<unsigned int*>(cueNameTableData->data)[0], static_cast<unsigned int*>(cueNameTableData->data)[1]); - cueNameTable = new UTFTable(buf2, cueNameTableData->length); - delete[] buf2; - - acbData* waveformTableData = utf->get(0, "WaveformTable"); - unsigned char* buf3 = new unsigned char[waveformTableData->length]; - utf->readBinary(buf3, static_cast<unsigned int*>(waveformTableData->data)[0], static_cast<unsigned int*>(waveformTableData->data)[1]); - waveformTable = new UTFTable(buf3, waveformTableData->length); - delete[] buf3; - - acbData* synthTableData = utf->get(0, "SynthTable"); - unsigned char* buf4 = new unsigned char[synthTableData->length]; - utf->readBinary(buf4, static_cast<unsigned int*>(synthTableData->data)[0], static_cast<unsigned int*>(synthTableData->data)[1]); - synthTable = new UTFTable(buf4, synthTableData->length); - delete[] buf4; - - std::string* nameMap = new std::string[cueNameTable->header->rowLength]; - - for (unsigned int i = 0; i < cueNameTable->header->rowLength; i++) { - acbData* str = cueNameTable->get(i, "CueName"); - nameMap[*(static_cast<unsigned short*>(cueNameTable->get(i, "CueIndex")->data))] = str ? - std::string(static_cast<char*>(str->data)) : "UNKNOWN"; - } - - tracks = new track[cueTable->header->rowLength]; - length = cueTable->header->rowLength; - for (unsigned int i = 0; i < cueTable->header->rowLength; i++) { - unsigned char referenceType = *(static_cast<unsigned char*>(cueTable->get(i, "ReferenceType")->data)); - if (referenceType != static_cast<unsigned char>(3) && referenceType != static_cast<unsigned char>(8)) { - delete cueTable; - delete cueNameTable; - delete waveformTable; - delete synthTable; - delete[] tracks; - throw "ReferenceType not implemented."; - } - - unsigned short referenceIndex = *(static_cast<unsigned short*>(cueTable->get(i, "ReferenceIndex")->data)); - - acbData* refitm = synthTable->get(referenceIndex, "ReferenceItems"); - unsigned char* referenceItems = new unsigned char[refitm->length]; - synthTable->readBinary(referenceItems, static_cast<unsigned int*>(refitm->data)[0], static_cast<unsigned int*>(refitm->data)[1]); - unsigned short b = (referenceItems[2] / 16) * 4096 + (referenceItems[2] % 16) * 256 + (referenceItems[3] / 16) * 16 + (referenceItems[3] % 16); - delete[] referenceItems; - - unsigned short wavId; - acbData* hasId = waveformTable->get(b, "Id"); - if (hasId) { - wavId = *(static_cast<unsigned short*>(hasId->data)); - } else { - wavId = *(static_cast<unsigned short*>(waveformTable->get(b, "MemoryAwbId")->data)); - } - - tracks[i].cueId = *(static_cast<unsigned int*>(cueTable->get(i, "CueId")->data)); - tracks[i].cueName = nameMap[i]; - tracks[i].wavId = wavId; - tracks[i].encodeType = *(static_cast<unsigned char*>(waveformTable->get(b, "EncodeType")->data)); - tracks[i].streaming = *(static_cast<unsigned char*>(waveformTable->get(b, "Streaming")->data)); - } - - delete[] nameMap; -} - -TrackList::~TrackList() { - delete cueTable; - delete cueNameTable; - delete waveformTable; - delete synthTable; - delete[] tracks; -} diff --git a/lib/ACBExtractor/UTFTable.cpp b/lib/ACBExtractor/UTFTable.cpp deleted file mode 100644 index 98f45d5..0000000 --- a/lib/ACBExtractor/UTFTable.cpp +++ /dev/null @@ -1,313 +0,0 @@ -#include "./include/UTFTable.h" - -unsigned int UTFTable::dataLength[12] = { - 1, 1, 2, 2, 4, 4, 8, 8, 4, 8, 4, 8 -}; - -UTFTable::acbColumnType UTFTable::columnType = { - 0x10, 0x30, 0x50, 0x70 -}; - -//std::string UTFTable::dataType[12] = { -// "UInt8", // 00 -// "Int8", // 01 -// "UInt16", // 02 -// "Int16", // 03 -// "UInt32", // 04 -// "Int32", // 05 -// "UInt64", // 06 -// "Int64", // 07 -// "Float", // 08 -// "Double", // 09 -// "String", // 0a -// "Binary" // 0b -//}; - -UTFTable::UTFTable(std::string acb) { - r = new Reader; - r->open(acb, std::ios::binary); - if (!r->is_open()) { - r->close(); - delete r; - throw "Open file failed."; - } - unsigned int magic = r->readUInt32BE(); - - if (magic != 0x40555446) { - r->close(); - delete r; - throw "Not acb file."; - } - length = r->readUInt32BE(); - if (length != r->length - 8) { - r->close(); - delete r; - throw "UTFTable Error length."; - } - - readHeader(); - name = readString(header->tableNameStringOffset, nullptr); - readColumns(); - readRows(); - -} - -UTFTable::UTFTable(unsigned char* acb, unsigned int l) { - r = new Reader(acb, l); - unsigned int magic = r->readUInt32BE(); - - if (magic != 0x40555446) { - r->close(); - delete r; - throw "Not acb file."; - } - length = r->readUInt32BE(); - if (length != r->length - 8) { - r->close(); - delete r; - throw "UTFTable Error length."; - } - - readHeader(); - name = readString(header->tableNameStringOffset, nullptr); - readColumns(); - readRows(); - -} - -UTFTable::~UTFTable() { - r->close(); - delete r; - delete name; - for (unsigned int i = 0; i < header->columnLength; i++) { - delete[] columns[i].columnName; - if (columns[i].columnType == UTFTable::columnType.CONSTANT || columns[i].columnType == UTFTable::columnType.CONSTANT2) { - deleteVoid(columns[i]); - } - } - - for (unsigned int i = 0; i < header->rowLength; i++) { - for (unsigned int j = 0; j < header->columnLength; j++) { - deleteVoid(rows[i][j]); - } - delete[] rows[i]; - } - delete header; - delete[] columns; - delete[] rows; -} - -acbData* UTFTable::get(unsigned int lineNumber, std::string columnName) { - if (lineNumber >= header->rowLength) return nullptr; - for (unsigned int i = 0; i < header->columnLength; i++) { - if (rows[lineNumber][i].columnName == columnName) { - return &(rows[lineNumber][i]); - } - } - return nullptr; -} - -void UTFTable::readHeader() { - std::streampos back = r->tell(); - r->seek(8 + 0); - header = new acbHeader; - - header->u1 = r->readUInt16BE(); - header->tableDataOffset = r->readUInt16BE(); - header->stringDataOffset = r->readUInt32BE(); - header->binaryDataOffset = r->readUInt32BE(); - header->tableNameStringOffset = r->readUInt32BE(); - header->columnLength = r->readUInt16BE(); - header->rowTotalByte = r->readUInt16BE(); - header->rowLength = r->readUInt32BE(); - r->seek(back); -} - -char* UTFTable::readString(std::streampos offset, unsigned int* outlength) { - std::streampos back = r->tell(); - r->seek(header->stringDataOffset + 8, offset); - unsigned int length = 0; - while (true) { - length++; - if (r->readUInt8() == 0) break; - } - r->seek(header->stringDataOffset + 8, offset); - if (outlength) *outlength = length - 1; - char* outstr = new char[length]; - r->read(outstr, length); - r->seek(back); - - return outstr; -} - -void UTFTable::readBinary(unsigned char* outbuf, std::streampos offset, std::streampos length) { - std::streampos back = r->tell(); - r->seek(header->binaryDataOffset + 8, offset); - r->read((char*)outbuf, length); - r->seek(back); -} - -void UTFTable::readColumns() { - std::streampos back = r->tell(); - r->seek(24 + 8); - columns = new acbColumn[header->columnLength]; - - for (unsigned int i = 0; i < header->columnLength; i++) { - unsigned char columnTypeAndDataType = r->readUInt8(); - unsigned int nameOffset = r->readUInt32BE(); - unsigned char columnType = columnTypeAndDataType & 0xf0; - unsigned char dataType = columnTypeAndDataType & 0x0f; - - char* columnName = readString(nameOffset, nullptr); - - columns[i].columnName = columnName; - columns[i].dataType = dataType; - columns[i].columnType = columnType; - - if (columnType == UTFTable::columnType.CONSTANT || columnType == UTFTable::columnType.CONSTANT2) { - readData(dataType, columns[i]); - } - } - r->seek(back); -} - -void UTFTable::readRows() { - - rows = new acbRow[header->rowLength]; - - for (unsigned int ri = 0; ri < header->rowLength; ri++) { - rows[ri] = new acbData[header->columnLength]; - unsigned int dataPos = ri * header->rowTotalByte; - - for (unsigned int i = 0; i < header->columnLength; i++) { - rows[ri][i].columnName = columns[i].columnName; - rows[ri][i].dataType = columns[i].dataType; - if (columns[i].columnType == UTFTable::columnType.CONSTANT || columns[i].columnType == UTFTable::columnType.CONSTANT2) { - unsigned char* data = new unsigned char[columns[i].length]; - for (unsigned int j = 0; j < columns[i].length; j++) { - data[j] = static_cast<unsigned char*>(columns[i].data)[j]; - } - rows[ri][i].data = static_cast<void*>(data); - rows[ri][i].length = columns[i].length; - } else { - - std::streampos back = r->tell(); - r->seek(header->tableDataOffset + 8, dataPos); - - readData(rows[ri][i].dataType, rows[ri][i]); - r->seek(back); - dataPos += UTFTable::dataLength[columns[i].dataType]; - } - } - } -} - -template<typename T, typename Arg> -void UTFTable::readDataTemplate(Arg& columnOrData) { - T* data = new T; - *data = r->readByte<T>(); - columnOrData.data = static_cast<void*>(data); - columnOrData.length = sizeof(T); -} - -template<typename Arg> -void UTFTable::deleteVoid(Arg& columnOrData) { - if (columnOrData.dataType == static_cast<unsigned char>(0x0b)) - delete[] static_cast<unsigned int*>(columnOrData.data); - else if (columnOrData.dataType == static_cast<unsigned char>(0x0a)) - delete[] static_cast<char*>(columnOrData.data); - else if (columnOrData.dataType == static_cast<unsigned char>(0x00)) - delete static_cast<unsigned char*>(columnOrData.data); - else if (columnOrData.dataType == static_cast<unsigned char>(0x01)) - delete static_cast<char*>(columnOrData.data); - else if (columnOrData.dataType == static_cast<unsigned char>(0x02)) - delete static_cast<unsigned short*>(columnOrData.data); - else if (columnOrData.dataType == static_cast<unsigned char>(0x03)) - delete static_cast<short*>(columnOrData.data); - else if (columnOrData.dataType == static_cast<unsigned char>(0x04)) - delete static_cast<unsigned int*>(columnOrData.data); - else if (columnOrData.dataType == static_cast<unsigned char>(0x05)) - delete static_cast<int*>(columnOrData.data); - else if (columnOrData.dataType == static_cast<unsigned char>(0x06)) - delete static_cast<unsigned long long*>(columnOrData.data); - else if (columnOrData.dataType == static_cast<unsigned char>(0x07)) - delete static_cast<long long*>(columnOrData.data); - else if (columnOrData.dataType == static_cast<unsigned char>(0x08)) - delete static_cast<float*>(columnOrData.data); - else if (columnOrData.dataType == static_cast<unsigned char>(0x09)) - delete static_cast<double*>(columnOrData.data); -} - -template<typename Arg> -void UTFTable::readData(unsigned char type, Arg& columnOrData) { - switch (type) { - case 0x00: { - readDataTemplate<unsigned char, Arg>(columnOrData); - break; - } - - case 0x01: { - readDataTemplate<char, Arg>(columnOrData); - break; - } - - case 0x02: { - readDataTemplate<unsigned short, Arg>(columnOrData); - break; - } - - case 0x03: { - readDataTemplate<short, Arg>(columnOrData); - break; - } - - case 0x04: { - readDataTemplate<unsigned int, Arg>(columnOrData); - break; - } - - case 0x05: { - readDataTemplate<int, Arg>(columnOrData); - break; - } - - case 0x06: { - readDataTemplate<unsigned long long, Arg>(columnOrData); - break; - } - - case 0x07: { - readDataTemplate<long long, Arg>(columnOrData); - break; - } - - case 0x08: { - readDataTemplate<float, Arg>(columnOrData); - break; - } - - case 0x09: { - readDataTemplate<double, Arg>(columnOrData); - break; - } - - case 0x0a: { - unsigned int l = 0; - char* data = readString(r->readUInt32BE(), &l); - columnOrData.length = l; - columnOrData.data = static_cast<void*>(data); - break; - } - case 0x0b: { - unsigned int* data = new unsigned int[2]; - data[0] = r->readUInt32BE(); // offset - data[1] = r->readUInt32BE(); // length - // readBinary(data, offset, length); - columnOrData.length = data[1]; - columnOrData.data = static_cast<void*>(data); - break; - } - - default: break; - } -} diff --git a/lib/ACBExtractor/include/ACBExtractor.h b/lib/ACBExtractor/include/ACBExtractor.h deleted file mode 100644 index ee3ad2d..0000000 --- a/lib/ACBExtractor/include/ACBExtractor.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _ACB_ACBEXTRACTOR_H_ -#define _ACB_ACBEXTRACTOR_H_ - -#include "./UTFTable.h" -#include "./AFSArchive.h" -#include "./TrackList.h" - -class ACBExtractor { -private: - -public: - std::string path; - UTFTable* headerTable; - TrackList* tracklist; - AFSArchive* awbFile; - - ACBExtractor(std::string acbFile); - - bool extract(void (*callback)(std::string filename, unsigned int length)); - - ~ACBExtractor(); -}; -#endif // !_ACB_ACBEXTRACTOR_H_ diff --git a/lib/ACBExtractor/include/AFSArchive.h b/lib/ACBExtractor/include/AFSArchive.h deleted file mode 100644 index 5ed9570..0000000 --- a/lib/ACBExtractor/include/AFSArchive.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef _ACB_AFSARCHIVE_H_ -#define _ACB_AFSARCHIVE_H_ - -#include "./Reader.h" - -typedef struct { - unsigned char offsetSize; - unsigned int fileCount; - unsigned int alignment; - unsigned short* ids; - unsigned int* fileEndPoints; -} awbHeader; - -typedef struct { - unsigned char* buf; - unsigned int length; - unsigned short id; -} entryFile; - -class AFSArchive { -private: - Reader* r; - void readHeader(); -public: - - unsigned int length; - awbHeader* header; - entryFile* files; - - AFSArchive(unsigned char* awb, unsigned int l); - ~AFSArchive(); -}; -#endif // !_ACB_AFSARCHIVE_H_ diff --git a/lib/ACBExtractor/include/Reader.h b/lib/ACBExtractor/include/Reader.h deleted file mode 100644 index 4abbff6..0000000 --- a/lib/ACBExtractor/include/Reader.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef _ACB_READER_H_ -#define _ACB_READER_H_ - -#include <fstream> - -class Reader : public std::ifstream { -private: - - static int isLittleEndian; - void checkEndian(); - std::string tmpfile = ""; - -public: - unsigned int length; - Reader(unsigned char* buf, unsigned int length); - Reader(); - ~Reader(); - Reader(std::string filename, ios_base::openmode mode); - void open(std::string filename, ios_base::openmode mode); - std::streampos tell(); - Reader& seek(std::streampos at, std::streampos offset = 0); - unsigned int readUInt32BE(); - unsigned int readUInt32LE(); - unsigned long long readUInt64BE(); - unsigned long long readUInt64LE(); - unsigned short readUInt16BE(); - unsigned short readUInt16LE(); - unsigned char readUInt8(); - char readInt8(); - short readInt16BE(); - short readInt16LE(); - int readInt32BE(); - int readInt32LE(); - long long readInt64BE(); - long long readInt64LE(); - double readDoubleBE(); - double readDoubleLE(); - float readFloatBE(); - float readFloatLE(); - unsigned int readUIntLE(unsigned int size); - - template<typename T> - T readByte(bool isLE = false) { - unsigned char buf[sizeof(T)]; - unsigned int size = sizeof(T); - read((char*)buf, size); - if ((isLittleEndian && !isLE) || (!isLittleEndian && isLE)) { - unsigned char temp; - for (unsigned int i = 0; i < size / 2; i++) { - temp = buf[i]; - buf[i] = buf[size - 1 - i]; - buf[size - 1 - i] = temp; - } - } - - T* result = (T*)buf; - - return *result; - } -}; -#endif // !_ACB_READER_H_ diff --git a/lib/ACBExtractor/include/TrackList.h b/lib/ACBExtractor/include/TrackList.h deleted file mode 100644 index 3ba4f3d..0000000 --- a/lib/ACBExtractor/include/TrackList.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _ACB_TRACKLIST_H_ -#define _ACB_TRACKLIST_H_ - -#include "./Reader.h" -#include "./UTFTable.h" - -typedef struct { - unsigned int cueId; - std::string cueName; - unsigned short wavId; - unsigned char encodeType; - unsigned char streaming; -} track; - -class TrackList { -private: - -public: - UTFTable* cueTable; - UTFTable* cueNameTable; - UTFTable* waveformTable; - UTFTable* synthTable; - track* tracks; - unsigned int length; - - TrackList(UTFTable* utf); - ~TrackList(); -}; -#endif // !_ACB_TRACKLIST_H_ diff --git a/lib/ACBExtractor/include/UTFTable.h b/lib/ACBExtractor/include/UTFTable.h deleted file mode 100644 index b692860..0000000 --- a/lib/ACBExtractor/include/UTFTable.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef _ACB_UTFTABLE_H_ -#define _ACB_UTFTABLE_H_ - -#include "./Reader.h" - -typedef struct { - char* columnName; - void* data; - unsigned char dataType; - unsigned int length; -} acbData; - -typedef struct { - unsigned char columnType; - char* columnName; - void* data; - unsigned char dataType; - unsigned int length; -} acbColumn; - -typedef acbData* acbRow; - -typedef struct { - unsigned short u1; - unsigned short tableDataOffset; - unsigned int stringDataOffset; - unsigned int binaryDataOffset; - unsigned int tableNameStringOffset; - unsigned short columnLength; - unsigned short rowTotalByte; - unsigned int rowLength; -} acbHeader; - -class UTFTable { -private: - typedef struct { - const unsigned char ZERO; - const unsigned char CONSTANT; - const unsigned char PERROW; - const unsigned char CONSTANT2; - } acbColumnType; - - static unsigned int dataLength[12]; - static acbColumnType columnType; - Reader* r; - void readHeader(); - char* readString(std::streampos offset, unsigned int* outlength); - void readBinary(unsigned char* outbuf, std::streampos offset, std::streampos length); - void readColumns(); - void readRows(); - template<typename Arg> - void readData(unsigned char type, Arg& columnOrData); - template<typename T, typename Arg> - void readDataTemplate(Arg& columnOrData); - template<typename Arg> - void deleteVoid(Arg& columnOrData); -public: - friend class TrackList; - friend class ACBExtractor; - - unsigned int length; - acbHeader* header; - acbColumn* columns; - acbRow* rows; - - char* name; - UTFTable(std::string acb); - UTFTable(unsigned char* acb, unsigned int l); - ~UTFTable(); - acbData* get(unsigned int lineNumber, std::string columnName); -}; -#endif // !_ACB_UTFTABLE_H_ diff --git a/lib/acb/acb.c b/lib/acb/acb.c new file mode 100644 index 0000000..ed905a5 --- /dev/null +++ b/lib/acb/acb.c @@ -0,0 +1,915 @@ +#ifdef _WIN32 +#include <Windows.h> +#include <wchar.h> +#include <direct.h> +#else +#include <sys/stat.h> +#endif // _WIN32 + +#include "acb.h" +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#define ACB_ENDIAN_BIG (1) +#define ACB_ENDIAN_LITTLE (0) +#define BUF_SIZE_MAX (128 * 1024) + +static int get_data_type_size(int data_type); + +static bool check_memory_endian() { + uint32_t n = 1; + uint8_t b = (uint8_t)n; + if (b) { + return ACB_ENDIAN_LITTLE; + } else { + return ACB_ENDIAN_BIG; + } +} + +static uint8_t read_uint_8(uint8_t* buf) { + return *buf; +} + +static int8_t read_int_8(uint8_t* buf) { + return *((int8_t*)buf); +} + +static uint16_t read_uint_16(uint8_t* buf, bool endian) { + if (endian == check_memory_endian()) { + return *((uint16_t*)buf); + } else { + uint8_t tmp[2] = { buf[1], buf[0] }; + return *((uint16_t*)tmp); + } +} + +static int16_t read_int_16(uint8_t* buf, bool endian) { + if (endian == check_memory_endian()) { + return *((int16_t*)buf); + } else { + uint8_t tmp[2] = { buf[1], buf[0] }; + return *((int16_t*)tmp); + } +} + +static uint32_t read_uint_32(uint8_t* buf, bool endian) { + if (endian == check_memory_endian()) { + return *((uint32_t*)buf); + } else { + uint8_t tmp[4] = { buf[3], buf[2], buf[1], buf[0] }; + return *((uint32_t*)tmp); + } +} + +static int32_t read_int_32(uint8_t* buf, bool endian) { + if (endian == check_memory_endian()) { + return *((int32_t*)buf); + } else { + uint8_t tmp[4] = { buf[3], buf[2], buf[1], buf[0] }; + return *((int32_t*)tmp); + } +} + +static int64_t read_int_64(uint8_t* buf, bool endian) { + if (endian == check_memory_endian()) { + return *((int64_t*)buf); + } else { + uint8_t tmp[8] = { buf[7], buf[6], buf[5], buf[4], buf[3], buf[2], buf[1], buf[0] }; + return *((int64_t*)tmp); + } +} + +static uint64_t read_uint_64(uint8_t* buf, bool endian) { + if (endian == check_memory_endian()) { + return *((uint64_t*)buf); + } else { + uint8_t tmp[8] = { buf[7], buf[6], buf[5], buf[4], buf[3], buf[2], buf[1], buf[0] }; + return *((uint64_t*)tmp); + } +} + +static float read_float(uint8_t* buf, bool endian) { + if (endian == check_memory_endian()) { + return *((float*)buf); + } else { + uint8_t tmp[8] = { buf[3], buf[2], buf[1], buf[0] }; + return *((float*)tmp); + } +} + +static double read_double(uint8_t* buf, bool endian) { + if (endian == check_memory_endian()) { + return *((double*)buf); + } else { + uint8_t tmp[8] = { buf[7], buf[6], buf[5], buf[4], buf[3], buf[2], buf[1], buf[0] }; + return *((double*)tmp); + } +} + +static int acb_fseek(acb* acbp, long pos) { + if (pos > acbp->size) { + return 1; + } + long origin = ftell(acbp->f); + int res = fseek(acbp->f, acbp->start + pos, SEEK_SET); + if (!res) { + acbp->pos = pos; + fseek(acbp->f, origin, SEEK_SET); + return 0; + } + return res; +} + +static long acb_ftell(acb* acbp) { + return acbp->pos; +} + +static size_t acb_fread(void* dest, size_t size, size_t count, acb* acbp) { + if (acbp->pos + (size * count) > (size_t)acbp->size) { + return 0; + } + long origin = ftell(acbp->f); + fseek(acbp->f, acbp->start + acbp->pos, SEEK_SET); + int read = fread(dest, size, count, acbp->f); + if (read != 0) { + acbp->pos = acbp->pos + read; + fseek(acbp->f, origin, SEEK_SET); + return read; + } + fseek(acbp->f, origin, SEEK_SET); + return 0; +} + +static int acb_fclose(acb* acbp) { + if (acbp->f && acbp->start == 0) { + return fclose(acbp->f); + acbp->f = NULL; + } + + acbp->start = 0; + acbp->size = 0; + acbp->pos = 0; + return 0; +} + +static void get_encode_type_suffix(uint8_t type, char* out) { + switch (type) { + case 0: + { + strcpy(out, ".adx"); + return; + } + case 2: + { + strcpy(out, ".hca"); + return; + } + case 7: + { + strcpy(out, ".at3"); + return; + } + case 8: + { + strcpy(out, ".vag"); + return; + } + case 9: + { + strcpy(out, ".bcwav"); + return; + } + case 13: + { + strcpy(out, ".dsp"); + return; + } + default: + return; + } +} + +acb* acb_open(const char* path) { +#ifdef _WIN32 + int len = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0); + wchar_t* wpath = (wchar_t*)malloc(len * sizeof(wchar_t)); + if (!wpath) return NULL; + MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, len); + FILE* f = _wfopen(wpath, L"rb"); + free(wpath); +#else + FILE* f = fopen(path, "rb"); +#endif // _WIN32 + + if (f) { + acb* _acb = (acb*)malloc(sizeof(acb)); + if (!_acb) return NULL; + memset(_acb, 0, sizeof(acb)); + + _acb->f = f; + memset(_acb->path, 0, MAX_PATH_LENGTH); + strcpy(_acb->path, path); + + _acb->start = 0; + fseek(f, 0L, SEEK_END); + _acb->size = ftell(f); + fseek(f, 0L, SEEK_SET); + _acb->pos = 0; + + acb_read_file_header(_acb, &(_acb->file_header)); + acb_read_utf_header(_acb, &(_acb->utf_header)); + _acb->name = acb_read_string(_acb, _acb->utf_header.table_name_string_offset); + + _acb->columns = (acb_utf_column*)malloc(_acb->utf_header.column_length * sizeof(acb_utf_column)); + acb_read_column(_acb, _acb->columns, _acb->utf_header.column_length); + + return _acb; + } else { + return NULL; + } +} + +acb* acb_memopen(acb* parent, long start, long size) { + acb* _acb = (acb*)malloc(sizeof(acb)); + if (!_acb) return NULL; + memset(_acb, 0, sizeof(acb)); + + _acb->f = parent->f; + memset(_acb->path, 0, MAX_PATH_LENGTH); + + _acb->start = start; + _acb->size = size; + _acb->pos = 0; + + acb_read_file_header(_acb, &(_acb->file_header)); + acb_read_utf_header(_acb, &(_acb->utf_header)); + _acb->name = acb_read_string(_acb, _acb->utf_header.table_name_string_offset); + + _acb->columns = (acb_utf_column*)malloc(_acb->utf_header.column_length * sizeof(acb_utf_column)); + acb_read_column(_acb, _acb->columns, _acb->utf_header.column_length); + + return _acb; +} + +acb* acb_memopen_awb(acb* parent, long start, long size) { + acb* _acb = (acb*)malloc(sizeof(acb)); + if (!_acb) return NULL; + memset(_acb, 0, sizeof(acb)); + + _acb->f = parent->f; + memset(_acb->path, 0, MAX_PATH_LENGTH); + + _acb->start = start; + _acb->size = size; + _acb->pos = 0; + + return _acb; +} + +void acb_close(acb* acbp) { + acb_fclose(acbp); + acbp->f = NULL; + acbp->start = 0; + acbp->size = 0; + acbp->pos = 0; + + if (acbp->name != NULL) { + free(acbp->name); + acbp->name = NULL; + } + + if (acbp->columns != NULL) { + for (int i = 0; i < acbp->utf_header.column_length; i++) { + if (acbp->columns[i].name) { free(acbp->columns[i].name); acbp->columns[i].name = NULL; } + if (acbp->columns[i].const_value) { free(acbp->columns[i].const_value); acbp->columns[i].const_value = NULL; } + } + free(acbp->columns); + acbp->columns = NULL; + } + + free(acbp); +} + +void acb_read_file_header(acb* acbp, acb_file_header* header) { + if (!acbp) return; + long original_pos = acb_ftell(acbp); + acb_fseek(acbp, 0); + uint8_t magic[4]; + uint8_t size[4]; + acb_fread(magic, 1, 4, acbp); + acb_fread(size, 1, 4, acbp); + + header->magic = read_uint_32(magic, ACB_ENDIAN_BIG); + header->size = read_uint_32(size, ACB_ENDIAN_BIG); + acb_fseek(acbp, original_pos); +} + +uint32_t acb_get_size(acb* acbp) { + if (!acbp) return 0; + return acbp->file_header.size; +} + +void acb_read_utf_header(acb* acbp, acb_utf_header* header) { + if (!acbp) return; + long original_pos = acb_ftell(acbp); + acb_fseek(acbp, 8); + + uint8_t unknown1[2]; + uint8_t table_data_offset[2]; + uint8_t string_data_offset[4]; + uint8_t binary_data_offset[4]; + uint8_t table_name_string_offset[4]; + uint8_t column_length[2]; + uint8_t row_total_byte[2]; + uint8_t row_length[4]; + + acb_fread(unknown1, 1, 2, acbp); + acb_fread(table_data_offset, 1, 2, acbp); + acb_fread(string_data_offset, 1, 4, acbp); + acb_fread(binary_data_offset, 1, 4, acbp); + acb_fread(table_name_string_offset, 1, 4, acbp); + acb_fread(column_length, 1, 2, acbp); + acb_fread(row_total_byte, 1, 2, acbp); + acb_fread(row_length, 1, 4, acbp); + + header->unknown1 = read_uint_16(unknown1, ACB_ENDIAN_BIG); + header->table_data_offset = read_uint_16(table_data_offset, ACB_ENDIAN_BIG); + header->string_data_offset = read_uint_32(string_data_offset, ACB_ENDIAN_BIG); + header->binary_data_offset = read_uint_32(binary_data_offset, ACB_ENDIAN_BIG); + header->table_name_string_offset = read_uint_32(table_name_string_offset, ACB_ENDIAN_BIG); + header->column_length = read_uint_16(column_length, ACB_ENDIAN_BIG); + header->row_total_byte = read_uint_16(row_total_byte, ACB_ENDIAN_BIG); + header->row_length = read_uint_32(row_length, ACB_ENDIAN_BIG); + + acb_fseek(acbp, original_pos); +} + +char* acb_read_string(acb* acbp, uint32_t offset) { + if (!acbp) return NULL; + long original_pos = acb_ftell(acbp); + acb_fseek(acbp, 8 + acbp->utf_header.string_data_offset + offset); + + char c; + uint32_t len = 0; + + while (true) { + acb_fread(&c, 1, 1, acbp); + len++; + if (c == '\0') { + break; + } + } + + char* res = (char*)malloc(len * sizeof(char)); + acb_fseek(acbp, 8 + acbp->utf_header.string_data_offset + offset); + acb_fread(res, 1, len, acbp); + + acb_fseek(acbp, original_pos); + return res; +} + +void acb_read_column(acb* acbp, acb_utf_column* columns, int column_length) { + if (!acbp) return; + long original_pos = acb_ftell(acbp); + + acb_fseek(acbp, 8 + 24); + + for (int i = 0; i < column_length; i++) { + uint8_t type[1]; + uint8_t name_offset[4]; + acb_fread(type, 1, 1, acbp); + acb_fread(name_offset, 1, 4, acbp); + + columns[i].type = type[0]; + columns[i].index = i; + columns[i].name = acb_read_string(acbp, read_uint_32(name_offset, ACB_ENDIAN_BIG)); + columns[i].const_value = NULL; + + int column_type = columns[i].type & 0xf0; + int data_type = columns[i].type & 0x0f; + + if (column_type == 0x30 || column_type == 0x70) { + switch (data_type) { + case 0x00: + { + uint8_t* data = (uint8_t*)malloc(1); + acb_fread(data, 1, 1, acbp); + columns[i].const_value = data; + break; + } + case 0x01: + { + int8_t* data = (int8_t*)malloc(1); + acb_fread(data, 1, 1, acbp); + columns[i].const_value = data; + break; + } + case 0x02: + { + uint8_t data[2]; + acb_fread(data, 1, 2, acbp); + uint16_t* res = (uint16_t*)malloc(2); + if (!res) break; + *res = read_uint_16(data, ACB_ENDIAN_BIG); + columns[i].const_value = res; + break; + } + case 0x03: + { + uint8_t data[2]; + acb_fread(data, 1, 2, acbp); + int16_t* res = (int16_t*)malloc(2); + if (!res) break; + *res = read_int_16(data, ACB_ENDIAN_BIG); + columns[i].const_value = res; + break; + } + case 0x04: + { + uint8_t data[4]; + acb_fread(data, 1, 4, acbp); + uint32_t* res = (uint32_t*)malloc(4); + if (!res) break; + *res = read_uint_32(data, ACB_ENDIAN_BIG); + columns[i].const_value = res; + break; + } + case 0x05: + { + uint8_t data[4]; + acb_fread(data, 1, 4, acbp); + int32_t* res = (int32_t*)malloc(4); + if (!res) break; + *res = read_int_32(data, ACB_ENDIAN_BIG); + columns[i].const_value = res; + break; + } + case 0x08: + { + uint8_t data[4]; + acb_fread(data, 1, 4, acbp); + float* res = (float*)malloc(4); + if (!res) break; + *res = read_float(data, ACB_ENDIAN_BIG); + columns[i].const_value = res; + break; + } + case 0x06: + { + uint8_t data[8]; + acb_fread(data, 1, 8, acbp); + uint64_t* res = (uint64_t*)malloc(8); + if (!res) break; + *res = read_uint_64(data, ACB_ENDIAN_BIG); + columns[i].const_value = res; + break; + } + case 0x07: + { + uint8_t data[8]; + acb_fread(data, 1, 8, acbp); + int64_t* res = (int64_t*)malloc(8); + if (!res) break; + *res = read_int_64(data, ACB_ENDIAN_BIG); + columns[i].const_value = res; + break; + } + case 0x09: + { + uint8_t data[8]; + acb_fread(data, 1, 8, acbp); + double* res = (double*)malloc(8); + if (!res) break; + *res = read_double(data, ACB_ENDIAN_BIG); + columns[i].const_value = res; + break; + } + case 0x0A: + { + uint8_t data[4]; + acb_fread(data, 1, 4, acbp); + columns[i].const_value = acb_read_string(acbp, read_uint_32(data, ACB_ENDIAN_BIG)); + break; + } + case 0x0B: + { + uint8_t offset[4]; + uint8_t length[4]; + + acb_fread(offset, 1, 4, acbp); + acb_fread(length, 1, 4, acbp); + + acb_utf_binary_desc* desc = (acb_utf_binary_desc*)malloc(sizeof(acb_utf_binary_desc)); + if (!desc) break; + desc->offset = read_uint_32(offset, ACB_ENDIAN_BIG); + desc->length = read_uint_32(length, ACB_ENDIAN_BIG); + columns[i].const_value = desc; + break; + } + default: + break; + } + } + } + + acb_fseek(acbp, original_pos); +} + +int get_data_type_size(int data_type) { + switch (data_type) { + case 0x00: { return 1; } + case 0x01: { return 1; } + case 0x02: { return 2; } + case 0x03: { return 2; } + case 0x04: { return 4; } + case 0x05: { return 4; } + case 0x06: { return 8; } + case 0x07: { return 8; } + case 0x08: { return 4; } + case 0x09: { return 8; } + case 0x0A: { return 4; } + case 0x0B: { return 8; } + default: { return 0; } + } +} + +int acb_get_row_data(acb* acbp, uint32_t row_index, const char* column_name, void* res, uint32_t buf_size) { + if (!acbp) return 0; + + int column_index = -1; + int i = 0; + for (i = 0; i < acbp->utf_header.column_length; i++) { + if (strcmp(acbp->columns[i].name, column_name) == 0) { + column_index = i; + break; + } + } + + if (column_index == -1) return 0; + + int data_type = acbp->columns[column_index].type & 0x0f; + + if (res == NULL) { + return data_type; + } + + int column_type = acbp->columns[column_index].type & 0xf0; + + if ((column_type == 0x30 || column_type == 0x70) && acbp->columns[column_index].const_value != NULL) { + switch (data_type) { + case 0x00: { *((uint8_t*)res) = *((uint8_t*)(acbp->columns[column_index].const_value)); return data_type; } + case 0x01: { *((int8_t*)res) = *((int8_t*)(acbp->columns[column_index].const_value)); return data_type; } + case 0x02: { *((uint16_t*)res) = *((uint16_t*)(acbp->columns[column_index].const_value)); return data_type; } + case 0x03: { *((int16_t*)res) = *((int16_t*)(acbp->columns[column_index].const_value)); return data_type; } + case 0x04: { *((uint32_t*)res) = *((uint32_t*)(acbp->columns[column_index].const_value)); return data_type; } + case 0x05: { *((int32_t*)res) = *((int32_t*)(acbp->columns[column_index].const_value)); return data_type; } + case 0x06: { *((uint64_t*)res) = *((uint64_t*)(acbp->columns[column_index].const_value)); return data_type; } + case 0x07: { *((int64_t*)res) = *((int64_t*)(acbp->columns[column_index].const_value)); return data_type; } + case 0x08: { *((float*)res) = *((float*)(acbp->columns[column_index].const_value)); return data_type; } + case 0x09: { *((double*)res) = *((double*)(acbp->columns[column_index].const_value)); return data_type; } + case 0x0A: + { + if (strlen((char*)(acbp->columns[column_index].const_value)) > buf_size - 1) { + strncpy((char*)res, (char*)(acbp->columns[column_index].const_value), buf_size - 1); + } else { + strcpy((char*)res, (char*)(acbp->columns[column_index].const_value)); + } + return data_type; + } + case 0x0B: + { + ((acb_utf_binary_desc*)res)->offset = ((acb_utf_binary_desc*)acbp->columns[column_index].const_value)->offset; + ((acb_utf_binary_desc*)res)->length = ((acb_utf_binary_desc*)acbp->columns[column_index].const_value)->length; + return data_type; + } + default: { return 0; } + } + } + + long original_pos = acb_ftell(acbp); + + uint32_t pos = 8 + acbp->utf_header.table_data_offset + row_index * acbp->utf_header.row_total_byte; + + for (i = 0; i < column_index; i++) { + int column_type = acbp->columns[i].type & 0xf0; + if (column_type == 0x30 || column_type == 0x70) { + continue; + } + int data_type = acbp->columns[i].type & 0x0f; + pos += get_data_type_size(data_type); + } + + acb_fseek(acbp, pos); + + switch (data_type) { + case 0x00: { uint8_t tmp[1]; acb_fread(tmp, 1, 1, acbp); *((uint8_t*)res) = read_uint_8(tmp); break; } + case 0x01: { uint8_t tmp[1]; acb_fread(tmp, 1, 1, acbp); *((int8_t*)res) = read_int_8(tmp); break; } + case 0x02: { uint8_t tmp[2]; acb_fread(tmp, 1, 2, acbp); *((uint16_t*)res) = read_uint_16(tmp, ACB_ENDIAN_BIG); break; } + case 0x03: { uint8_t tmp[2]; acb_fread(tmp, 1, 2, acbp); *((int16_t*)res) = read_int_16(tmp, ACB_ENDIAN_BIG); break; } + case 0x04: { uint8_t tmp[4]; acb_fread(tmp, 1, 4, acbp); *((uint32_t*)res) = read_uint_32(tmp, ACB_ENDIAN_BIG); break; } + case 0x05: { uint8_t tmp[4]; acb_fread(tmp, 1, 4, acbp); *((int32_t*)res) = read_int_32(tmp, ACB_ENDIAN_BIG); break; } + case 0x06: { uint8_t tmp[8]; acb_fread(tmp, 1, 8, acbp); *((uint64_t*)res) = read_uint_64(tmp, ACB_ENDIAN_BIG); break; } + case 0x07: { uint8_t tmp[8]; acb_fread(tmp, 1, 8, acbp); *((int64_t*)res) = read_int_64(tmp, ACB_ENDIAN_BIG); break; } + case 0x08: { uint8_t tmp[4]; acb_fread(tmp, 1, 4, acbp); *((float*)res) = read_float(tmp, ACB_ENDIAN_BIG); break; } + case 0x09: { uint8_t tmp[8]; acb_fread(tmp, 1, 8, acbp); *((double*)res) = read_double(tmp, ACB_ENDIAN_BIG); break; } + case 0x0A: + { + uint8_t tmp[4]; + acb_fread(tmp, 1, 4, acbp); + char* tmpstr = acb_read_string(acbp, read_uint_32(tmp, ACB_ENDIAN_BIG)); + if (strlen(tmpstr) > buf_size - 1) { + strncpy((char*)res, tmpstr, buf_size - 1); + } else { + strcpy((char*)res, tmpstr); + } + free(tmpstr); + break; + } + case 0x0B: + { + uint8_t offset[4]; + uint8_t length[4]; + + acb_fread(offset, 1, 4, acbp); + acb_fread(length, 1, 4, acbp); + ((acb_utf_binary_desc*)res)->offset = read_uint_32(offset, ACB_ENDIAN_BIG); + ((acb_utf_binary_desc*)res)->length = read_uint_32(length, ACB_ENDIAN_BIG); + break; + } + default: { break; } + } + + acb_fseek(acbp, original_pos); + return data_type; +} + +acb_track* acb_get_track_list(acb* acbp, uint32_t* len) { + if (!acbp) return NULL; + if (acbp->start != 0) return NULL; + + acb_utf_binary_desc desc_cue_table; + acb_utf_binary_desc desc_cue_name_table; + acb_utf_binary_desc desc_wave_form_table; + acb_utf_binary_desc desc_synth_table; + + acb_get_row_data(acbp, 0, "CueTable", &desc_cue_table, 0); + acb_get_row_data(acbp, 0, "CueNameTable", &desc_cue_name_table, 0); + acb_get_row_data(acbp, 0, "WaveformTable", &desc_wave_form_table, 0); + acb_get_row_data(acbp, 0, "SynthTable", &desc_synth_table, 0); + + acb* cue_table = acb_memopen(acbp, 8 + acbp->utf_header.binary_data_offset + desc_cue_table.offset, desc_cue_table.length); + acb* name_table = acb_memopen(acbp, 8 + acbp->utf_header.binary_data_offset + desc_cue_name_table.offset, desc_cue_name_table.length); + acb* wave_form_table = acb_memopen(acbp, 8 + acbp->utf_header.binary_data_offset + desc_wave_form_table.offset, desc_wave_form_table.length); + acb* synth_table = acb_memopen(acbp, 8 + acbp->utf_header.binary_data_offset + desc_synth_table.offset, desc_synth_table.length); + + acb_track* track_list = (acb_track*)malloc(cue_table->utf_header.row_length * sizeof(acb_track)); + if (track_list) { + memset(track_list, 0, cue_table->utf_header.row_length * sizeof(acb_track)); + for (uint16_t i = 0; i < cue_table->utf_header.row_length; i++) { + int found = 0; + for (uint16_t j = 0; j < name_table->utf_header.row_length; j++) { + uint16_t cue_index = 0; + acb_get_row_data(name_table, j, "CueIndex", &cue_index, 0); + if (cue_index == i) { + acb_get_row_data(name_table, j, "CueName", (track_list + i)->cue_name, 64); + found = 1; + } + } + + if (!found) { + strcpy((track_list + i)->cue_name, "UNKNOWN"); + } + + uint32_t cue_id = 0; + acb_get_row_data(cue_table, i, "CueId", &cue_id, 0); + + (track_list + i)->cue_id = cue_id; + + uint8_t reference_type = 0; + acb_get_row_data(cue_table, i, "ReferenceType", &reference_type, 0); + if (reference_type != 3 && reference_type != 8) { + printf("ReferenceType %d not implemented.\n", reference_type); + break; + } + + uint16_t reference_index = 0; + acb_get_row_data(cue_table, i, "ReferenceIndex", &reference_index, 0); + + acb_utf_binary_desc desc_ref_item; + acb_get_row_data(synth_table, reference_index, "ReferenceItems", &desc_ref_item, 0); + + + uint8_t _b[2]; + long origin = acb_ftell(synth_table); + acb_fseek(synth_table, 8 + synth_table->utf_header.binary_data_offset + desc_ref_item.offset + 2); + acb_fread(_b, 1, 2, synth_table); + acb_fseek(synth_table, origin); + uint16_t b = read_uint_16(_b, ACB_ENDIAN_BIG); + + uint16_t wav_id = 0; + // if (b >= wave_form_table->utf_header.row_length) { + if (b < wave_form_table->utf_header.row_length) { + int res = acb_get_row_data(wave_form_table, b, "Id", &wav_id, 0); + if (res == 0) { + acb_get_row_data(wave_form_table, b, "MemoryAwbId", &wav_id, 0); + } + } else { + acb_get_row_data(wave_form_table, b, "MemoryAwbId", &wav_id, 0); + } + + (track_list + i)->wav_id = wav_id; + + uint8_t encode_type = 0; + uint8_t streaming = 0; + acb_get_row_data(wave_form_table, b, "EncodeType", &encode_type, 0); + acb_get_row_data(wave_form_table, b, "Streaming", &streaming, 0); + + (track_list + i)->encode_type = encode_type; + (track_list + i)->streaming = streaming; + } + } + + *len = cue_table->utf_header.row_length; + + acb_close(cue_table); + acb_close(name_table); + acb_close(wave_form_table); + acb_close(synth_table); + + return track_list; +} + + +int acb_extract(acb* acbp, const char* target_dir, acb_extract_callback callback) { + if (!acbp) return 1; + if (acbp->start != 0) return 2; + + uint32_t track_list_length = 0; + acb_track* track_list = acb_get_track_list(acbp, &track_list_length); + + acb_utf_binary_desc desc_awb; + acb_get_row_data(acbp, 0, "AwbFile", &desc_awb, 0); + + acb* awb = acb_memopen_awb(acbp, 8 + acbp->utf_header.binary_data_offset + desc_awb.offset, desc_awb.length); + + uint8_t magic[4]; + acb_fread(magic, 1, 4, awb); + if (read_uint_32(magic, ACB_ENDIAN_BIG) != 0x41465332) { + acb_close(awb); + free(track_list); + return 3; + } + + uint8_t offset_size = 0; + acb_fseek(awb, 5); + acb_fread(&offset_size, 1, 1, awb); + acb_fseek(awb, 8); + uint8_t file_count_buf[4]; + uint8_t alignment_buf[4]; + acb_fread(file_count_buf, 1, 4, awb); + acb_fread(alignment_buf, 1, 4, awb); + uint32_t file_count = read_uint_32(file_count_buf, ACB_ENDIAN_LITTLE); + uint32_t alignment = read_uint_32(alignment_buf, ACB_ENDIAN_LITTLE); + + uint16_t* id_arr = (uint16_t*)malloc(file_count * sizeof(uint16_t)); + if (!id_arr) { + acb_close(awb); + free(track_list); + return 4; + } + + uint8_t id_buf[2]; + for (uint32_t i = 0; i < file_count; i++) { + acb_fread(id_buf, 1, 2, awb); + *(id_arr + i) = read_uint_16(id_buf, ACB_ENDIAN_LITTLE); + } + + uint64_t* file_end_points = (uint64_t*)malloc((file_count + 1) * sizeof(uint64_t)); + if (!file_end_points) { + free(id_arr); + acb_close(awb); + free(track_list); + return 4; + } + + uint8_t ep_8[8] = { 0 }; + for (uint32_t i = 0; i < file_count + 1; i++) { + acb_fread(ep_8, 1, offset_size, awb); + *(file_end_points + i) = read_uint_64(ep_8, ACB_ENDIAN_LITTLE); + } + + acb_awb_wav_file* files = (acb_awb_wav_file*)malloc(file_count * sizeof(acb_awb_wav_file)); + if (!files) { + free(file_end_points); + free(id_arr); + acb_close(awb); + free(track_list); + return 5; + } + + for (uint32_t i = 0; i < file_count; i++) { + (files + i)->id = *(id_arr + i); + (files + i)->start = (uint32_t)ceil((double)(file_end_points[i]) / (double)(alignment)) * alignment; + (files + i)->length = (uint32_t)(*(file_end_points + i + 1)) - (files + i)->start; + } + + char name[MAX_PATH_LENGTH] = { 0 }; + uint8_t* buffer = (uint8_t*)malloc(BUF_SIZE_MAX * sizeof(uint8_t)); + if (!buffer) { + free(files); + free(file_end_points); + free(id_arr); + acb_close(awb); + free(track_list); + return 6; + } + +#ifdef _WIN32 + wchar_t* target_dir_w = NULL; + if (target_dir) { + int len = MultiByteToWideChar(CP_UTF8, 0, target_dir, -1, NULL, 0); + target_dir_w = (wchar_t*)malloc(len * sizeof(wchar_t)); + if (target_dir_w) { + MultiByteToWideChar(CP_UTF8, 0, target_dir, -1, target_dir_w, len); + _wmkdir(target_dir_w); + free(target_dir_w); + } + } +#else + mkdir(target_dir, 0777); +#endif + + for (uint32_t i = 0; i < track_list_length; i++) { + acb_track* track = (track_list + i); + bool result = false; + for (uint32_t j = 0; j < file_count; j++) { + if ((files + j)->id == track->wav_id) { + acb_awb_wav_file* file = (files + track->wav_id); + uint32_t total = 0; + uint32_t read = 0; + acb_fseek(awb, file->start); + memset(name, 0, MAX_PATH_LENGTH); + if (target_dir) { + strcat(name, target_dir); +#ifdef _WIN32 + strcat(name, "\\"); +#else + strcat(name, "/"); +#endif + } + strcat(name, track->cue_name); + char suffix[16] = { 0 }; + get_encode_type_suffix(track->encode_type, suffix); + strcat(name, suffix); +#ifdef _WIN32 + int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0); + wchar_t* wpath = (wchar_t*)malloc(len * sizeof(wchar_t)); + if (!wpath) break; + MultiByteToWideChar(CP_UTF8, 0, name, -1, wpath, len); + FILE* wp = _wfopen(wpath, L"wb+"); + free(wpath); +#else + FILE* wp = fopen(name, "wb+"); +#endif + if (!wp) { + free(files); + free(file_end_points); + free(id_arr); + acb_close(awb); + free(track_list); + return 7; + } + while (1) { + if (total + BUF_SIZE_MAX <= file->length) { + read = acb_fread(buffer, 1, BUF_SIZE_MAX, awb); + total += read; + fwrite(buffer, 1, read, wp); + } else { + read = acb_fread(buffer, 1, file->length - total, awb); + total += read; + fwrite(buffer, 1, read, wp); + break; + } + } + + fclose(wp); + result = true; + break; + } + } + + if (callback) { + callback(i + 1, track_list_length, name, result); + } + } + + free(buffer); + free(files); + free(file_end_points); + free(id_arr); + acb_close(awb); + free(track_list); + + return 0; +} diff --git a/lib/acb/acb.h b/lib/acb/acb.h new file mode 100644 index 0000000..b05e79e --- /dev/null +++ b/lib/acb/acb.h @@ -0,0 +1,93 @@ +#ifndef __ACB_H__ +#define __ACB_H__ + +#ifdef _WIN32 +#define MAX_PATH_LENGTH 260 +#else +#define MAX_PATH_LENGTH 1024 +#endif + +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct acb_file_header { + uint32_t size; + uint32_t magic; + } acb_file_header; + + typedef struct acb_utf_header { + uint16_t unknown1; + uint16_t table_data_offset; + uint32_t string_data_offset; + uint32_t binary_data_offset; + uint32_t table_name_string_offset; + uint16_t column_length; + uint16_t row_total_byte; + uint32_t row_length; + } acb_utf_header; + + typedef struct acb_utf_column { + char* name; + uint32_t index; + uint8_t type; + void* const_value; + } acb_utf_column; + + typedef struct acb_track { + int32_t cue_id; + char cue_name[64]; + uint16_t wav_id; + uint8_t encode_type; + uint8_t streaming; + } acb_track; + + typedef struct acb_awb_wav_file { + uint16_t id; + uint32_t start; + uint32_t length; + } acb_awb_wav_file; + + typedef struct acb { + char path[MAX_PATH_LENGTH]; + + FILE* f; + long start; + long size; + long pos; + + acb_file_header file_header; + acb_utf_header utf_header; + char* name; + acb_utf_column* columns; + } acb; + + typedef struct acb_utf_binary_desc { + uint32_t offset; + uint32_t length; + } acb_utf_binary_desc; + + typedef void (*acb_extract_callback)(uint32_t completed, uint32_t total, const char* file, bool status); + + acb* acb_open(const char* path); + acb* acb_memopen(acb* parent, long start, long size); + acb* acb_memopen_awb(acb* parent, long start, long size); + void acb_close(acb* acbp); + void acb_read_file_header(acb* acbp, acb_file_header* header); + void acb_read_utf_header(acb* acbp, acb_utf_header* header); + char* acb_read_string(acb* acbp, uint32_t offset); + void acb_read_column(acb* acbp, acb_utf_column* columns, int column_length); + int acb_get_row_data(acb* acbp, uint32_t row_index, const char* column_name, void* out, uint32_t buf_size); + uint32_t acb_get_size(acb* acbp); + acb_track* acb_get_track_list(acb* acbp, uint32_t* len); + int acb_extract(acb* acbp, const char* target_dir, acb_extract_callback callback); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/ApiClient.cpp b/src/ApiClient.cpp index e642d1e..f049541 100644 --- a/src/ApiClient.cpp +++ b/src/ApiClient.cpp @@ -54,7 +54,7 @@ nlohmann::json ApiClient::post(const String& path, nlohmann::json& args) { headers = curl_slist_append(headers, "KEYCHAIN: "); headers = curl_slist_append(headers, "PLATFORM-OS-VERSION: Android OS 13.3.7 / API-42 (XYZZ1Y/74726f6c6c)"); headers = curl_slist_append(headers, (String("PARAM: ") + sha1Encrypt(_udid + _viewer + path + plain)).toCString()); - headers = curl_slist_append(headers, "X-Unity-Version': '2017.4.2f2"); + headers = curl_slist_append(headers, "X-Unity-Version': '2018.3.8f1"); headers = curl_slist_append(headers, "CARRIER: google"); headers = curl_slist_append(headers, (String("RES-VER: ") + _resVer).toCString()); headers = curl_slist_append(headers, (String("UDID: ") + encode(_udid)).toCString()); diff --git a/src/CGSSAssetsDownloader.cpp b/src/CGSSAssetsDownloader.cpp index 15dbdc6..c710bfc 100644 --- a/src/CGSSAssetsDownloader.cpp +++ b/src/CGSSAssetsDownloader.cpp @@ -6,7 +6,8 @@ #include "./lz4.h" #include "./clHCA.h" #include "./CGSSAssetsDownloader.h" -#include "../lib/ACBExtractor/include/ACBExtractor.h" +// #include "../lib/ACBExtractor/include/ACBExtractor.h" +#include "../lib/acb/acb.h" #include "../lib/lame/lame.h" #include "ApiClient.h" #include "../lib/jstype/fs.h" @@ -214,7 +215,7 @@ void Downloader::download_single(string file) { } void show_introduction() { - printf("CGSSAssetsDownloader VERSION 2.0.0\n\n"); + printf("CGSSAssetsDownloader VERSION 2.0.1\n\n"); printf("Usage: \n"); printf("CGSSAssetsDownloader [-v resource_version] [-a] [-u] [-mp3]\n"); @@ -262,14 +263,18 @@ void show_introduction() { } bool extract_acb (string acbFile) { - try { + acb* acbp = acb_open(acbFile.c_str()); + int res = acb_extract(acbp, path::join(path::dirname(acbFile), String("_acb_") + path::basename(acbFile)).toCString(), nullptr); + acb_close(acbp); + return res == 0; + /*try { ACBExtractor extractor(acbFile); bool result = extractor.extract(nullptr); return result; } catch (const char* err) { printf("ACBExtractor Error: %s\n", err); return false; - } + }*/ } int string_index_of (char* arr[], const char* str, int length) { diff --git a/src/download.cpp b/src/download.cpp index b1955a5..eeaea3a 100644 --- a/src/download.cpp +++ b/src/download.cpp @@ -131,7 +131,7 @@ bool download (string url, string path) { CURL* curl = curl_easy_init(); struct curl_slist* headers = NULL; - headers = curl_slist_append(headers, "X-Unity-Version: 2017.4.2f2"); + headers = curl_slist_append(headers, "X-Unity-Version: 2018.3.8f1"); headers = curl_slist_append(headers, "Connection: Keep-Alive"); headers = curl_slist_append(headers, "Accept-Encoding: gzip"); headers = curl_slist_append(headers, "Accept: */*");