新FF14は海外だとARRの略称なんですなあ、という事でだらだらと海外サイトを見ていたら、新FF14のデータ解析についてのスレッドがあって中々興味深く(0x08と0x02がヘッダとか)、もっと探せば解析完了したのがありそうだと更に探すと、

FFXIV 2.0 Dat Mining.

というForumを発見。

ついでにC言語のソースもあったので、ちょっと試すとバグはあるものの動作したので、ソースを見ながらsqpackのフォーマットを大体理解してBugFix。

試した所、どうやら内部データを見る所まではできる模様。解析した人すごいな。indexファイル側で制御してるっぽい感じだけど。

ff14parse01ff14parse02

修正版ソースは以下の通り。コピペしてフリーのコンパイラとライブラリで動作する筈。日本語はUTF-8なので、文字コードさえ間違わなければ内容が大体読める感じ。

以下 parse.cpp

    #include <stdio.h>
    #include <string.h>

    #include "zlib.h"

    int decompress(char* outBuf, int buffSize, char * pInBuf, int size) {
            int result;
            int inRes;

            z_stream c_stream;

            c_stream.zalloc = Z_NULL;
            c_stream.zfree = Z_NULL;
            c_stream.opaque = Z_NULL;

            c_stream.next_out = (Bytef *)outBuf;
            c_stream.avail_out = (uInt)buffSize;

            c_stream.next_in = (Bytef *)pInBuf;
            c_stream.avail_in = (uInt)size;

            result = inflateInit(&c_stream);
            if (!result) {
                    inRes = inflate(&c_stream, Z_FINISH);
                    if (inRes == 1) {
                            result = inflateEnd(&c_stream);
                    } else {
                            inflateEnd(&c_stream);
                            if(inRes != 2 && (inRes != -5 || size)) {
                                    result = inRes;
                            } else {
                                    result = -3;
                            }
                    }
            }

            return result;
    }

    int Adler32(char* bytes, int size)
    {
        const int a32mod = 65521;
        int s1 = 1, s2 = 0;

        for(int i = 0; i < size; i++)
        {
            int b = bytes[i];

            s1 = (s1 + b) % a32mod;
            s2 = (s2 + s1) % a32mod;
        }
        return (int)((s2 << 16) + s1);
    }

    int main(int argc, char* argv[])
    {
    //FILE* fp = fopen(argv[1], "rb");
            FILE* fp = fopen("030000.win32.dat0", "rb");
            char * data;
            int fname;
            fseek(fp, 0, SEEK_END);
            int size = ftell(fp);
            rewind(fp);
            data = new char[size];
            fread(data, sizeof(char), size, fp);
            fclose(fp);

            const int find = 0x80;
            const int find2 = 0x02;

            for(int i = 0; i < size; i++)
             {
                     if((*(int*)(data + i) == find) && *(int*)(data + i + 4) == find2)
                     {
                             int found = i + 0x88;
                             int headerPos = i;
                             fname = i;
                             int totalUncompressedSize = *(int*)(data + i + 0x08);
                             int totalFrames = *(int*)(data + i + 0x14);
                             char * tmpBuffer = new char[totalUncompressedSize];
                             memset(tmpBuffer, 0, totalUncompressedSize);
                             int eSize = *(int*)(data + i + 0x88);
                             int oSize = *(int*)(data + i + 0x8C);
                             char * entry = new char[eSize + 6];
                             entry[0x00] = 0x58;
                             entry[0x01] = 0x85;
                             memcpy(entry + 2, data + i + 0x90, eSize);
                             int adler = Adler32(entry + 2, eSize);
                             memcpy(entry + 2 + eSize, &adler, 4);
                             unsigned int result = decompress(tmpBuffer, oSize, entry, eSize + 6);
                             i += eSize + 0x90;
                            
                            if(totalFrames > 1)
                            {
                                    int currentFrame = 2;
                                    int lastSize = oSize;
//                                    i += eSize + 0x90;

                                    for(; currentFrame <= totalFrames; i++)
                                    {

                                            if(data[i] == 0x10)
                                            {

                                                    int eSize = *(int*)(data + i + 0x08);
                                                    int oSize = *(int*)(data + i + 0x0C);

                                                    char * entry = new char[eSize + 6];
                                                    entry[0x00] = 0x58;
                                                    entry[0x01] = 0x85;
                                                    memcpy(entry + 2, data + i + 0x10, eSize);
                                                    int adler = Adler32(entry + 2, eSize);
                                                    memcpy(entry + 2 + eSize, &adler, 4);

               unsigned int result2 = decompress(tmpBuffer + lastSize, oSize, entry, eSize + 6);

                                                    i += eSize + 0x0F;
                                                    currentFrame++;
                                                    lastSize += oSize;
                                                    delete[] entry;

                                            }
                                    }
                            }

                            char filename[255];
                            sprintf(filename, "dc_030000_%08x.dat", fname);
                            fp = fopen(filename, "wb");
                            fwrite(tmpBuffer, totalUncompressedSize, 1, fp);
                            fclose(fp);
                            if(entry != NULL)
                                    delete[] entry;
                            delete[] tmpBuffer;

                    }

            }
            return 0;
    }
コメントする