#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <vector>
#include <sstream>
#include <fstream>

#ifdef _WIN32 || _WIN64
    #include <windows.h>
    #include <conio.h>
    #define mkfolder(dirname) CreateDirectoryA(dirname, NULL)
#else
    #ifdef __linux__ //untested
        #include <sys/types.h>
        #include <sys/stat.h>

        #include <termios.h>
        #include <unistd.h>

        #define mkfolder(dirname) mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)

        int getch(void)
        {
            struct termios oldt,
            newt;
            int ch;
            tcgetattr( STDIN_FILENO, &oldt );
            newt = oldt;
            newt.c_lflag &= ~( ICANON | ECHO );
            tcsetattr( STDIN_FILENO, TCSANOW, &newt );
            ch = getchar();
            tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
            return ch;
        }
    #else
        #error "THIS OS NOT SUPPORTED YET!"
    #endif
#endif

#define FourCC 0x5A4F434D
#define ItemFourCC 0x5850494D
#define MobFourCC 0x5450494D
#define IndexHeader 0x444B5045
#define IndexVersion 2
#define IndexBlockSize 0xC0
#define delta -1640531527 //-0x61C88647
#define LZO_E_OK 1
#define LZO_E_INPUT_OVERRUN (-1)
#define LZO_E_EOF_NOT_FOUND (-2)
#define LZO_E_INPUT_NOT_CONSUMED (-3)
#define IndexName ".eix"
#define DataName ".epk"
int crashi = 0;

unsigned char IndexXTEA[] = {0xB9, 0x9E, 0xB0, 0x02, 0x6F, 0x69, 0x81, 0x05, 0x63, 0x98, 0x9B, 0x28, 0x79, 0x18, 0x1A, 0x00,};

unsigned char DataXTEA[] = {0x22, 0xB8, 0xB4, 0x04, 0x64, 0xB2, 0x6E, 0x1F, 0xAE, 0xEA, 0x18, 0x00, 0xA6, 0xF6, 0xFB, 0x1C,};

int XteaEncrypt(unsigned long* output, unsigned long* input, unsigned char* XTEA, int size)
{
    int round_count = 32;
    int rounds = 0;
    if (size & 7) size = (size & 0xFFFFFFF8) + 8;
    if(size) {
        do {
            output[0] = input[0];
            output[1] = input[1];
            unsigned int sum  = 0;
            for (int i=0; i < round_count; i++) {
                output[0] += (((output[1] << 4) ^ (output[1] >> 5)) + output[1]) ^ (sum  + *(unsigned long*)(XTEA + 4 * (sum  & 3)));
                sum  += delta;
                output[1] += (((output[0] << 4)  ^ (output[0] >> 5)) + output[0]) ^ (sum  + *(unsigned long*)(XTEA + 4 * ((sum  >> 11) & 3)));
            }
            input += 2;
            output += 2;
            ++rounds;
        } while ( size/8 > rounds );
    }
    return size;
}

int XteaDecrypt(unsigned long* output, unsigned long* input, unsigned char* XTEA, int size)
{
    int round_count = 32;
    int rounds = 0;
    if (size & 7) size = (size & 0xFFFFFFF8) + 8;
    if(size) {
        do {
            output[0] = input[0];
            output[1] = input[1];
            unsigned int sum  = delta * round_count;
            for (int i=0; i < round_count; i++) {
                output[1] -= (((output[0] << 4)  ^ (output[0] >> 5)) + output[0]) ^ (sum  + *(unsigned long*)(XTEA + 4 * ((sum  >> 11) & 3)));
                sum  -= delta;
                output[0] -= (((output[1] << 4) ^ (output[1] >> 5)) + output[1]) ^ (sum  + *(unsigned long*)(XTEA + 4 * (sum  & 3)));
            }
            input += 2;
            output += 2;
            ++rounds;
        } while ( size/8 > rounds );
    }
    return size;
}

static unsigned long lzo_docompress(const unsigned char* in ,  unsigned long  in_len, unsigned char* out,  unsigned long* out_len,  unsigned long  ti,  void* wrkmem)
{
    register const unsigned char* ip;
    unsigned char* op;
    const unsigned char* const in_end = in + in_len;
    const unsigned char* const ip_end = in + in_len - 20;
    const unsigned char* ii;
    unsigned short* const dict = (unsigned short*)wrkmem;

    op = out;
    ip = in;
    ii = ip;

    ip += ti < 4 ? 4 - ti : 0;
    for (;;)
    {
        const unsigned char* m_pos;
        unsigned long m_off;
        unsigned long m_len;
        {
        int dv;
        unsigned long dindex;
literal:
        ip += 1 + ((ip - ii) >> 5);
next:
        if (ip >= ip_end)
            break;
        dv = (* (volatile const int*) (volatile const void*) (ip));
        dindex = ((unsigned long) (((((((unsigned long) ((0x1824429d) * (dv)))) >> (32-14))) & ( ((1u << 14) - 1) >> (0))) << (0)));
        m_pos = in+dict[dindex];
        dict[dindex] = ((unsigned short)  ((unsigned long) ((ip)-(in))));
        if (dv != (* (volatile const int*) (volatile const void*) (m_pos)))
            goto literal;
        }

        ii -= ti; ti = 0;
        {
        register unsigned long t = (unsigned long) ((ip)-(ii));
        if (t != 0)
        {
            if (t <= 3)
            {
                op[-2] |= (unsigned char)(t);
                ((* (volatile int*) (volatile void*) (op)) = (int) ((* (volatile const int*) (volatile const void*) (ii))));
                op += t;
            }
            else if (t <= 16)
            {
                *op++ = (unsigned char)(t - 3);
                ((* (volatile int*) (volatile void*) (op)) = (int) ((* (volatile const int*) (volatile const void*) (ii))));
                ((* (volatile int*) (volatile void*) (op+4)) = (int) ((* (volatile const int*) (volatile const void*) (ii+4))));
                ((* (volatile int*) (volatile void*) (op+8)) = (int) ((* (volatile const int*) (volatile const void*) (ii+8))));
                ((* (volatile int*) (volatile void*) (op+12)) = (int) ((* (volatile const int*) (volatile const void*) (ii+12))));
                op += t;
            }
            else
            {
                if (t <= 18)
                    *op++ = (unsigned char)(t - 3);
                else
                {
                    register unsigned long tt = t - 18;
                    *op++ = 0;
                    while (tt > 255)
                    {
                        tt -= 255;
                        * (volatile unsigned char *) op++ = 0;
                    }
                    *op++ = (unsigned char)(tt);
                }
                do {
                    ((* (volatile int*) (volatile void*) (op)) = (int) ((* (volatile const int*) (volatile const void*) (ii))));
                    ((* (volatile int*) (volatile void*) (op+4)) = (int) ((* (volatile const int*) (volatile const void*) (ii+4))));
                    ((* (volatile int*) (volatile void*) (op+8)) = (int) ((* (volatile const int*) (volatile const void*) (ii+8))));
                    ((* (volatile int*) (volatile void*) (op+12)) = (int) ((* (volatile const int*) (volatile const void*) (ii+12))));
                    op += 16; ii += 16; t -= 16;
                } while (t >= 16); if (t > 0)
                { do *op++ = *ii++; while (--t > 0); }
            }
        }
        }
        m_len = 4;
        {
        int v;
        v = (* (volatile const int*) (volatile const void*) (ip + m_len)) ^ (* (volatile const int*) (volatile const void*) (m_pos + m_len));
        if (v == 0) {
            do {
                m_len += 4;
                v = (* (volatile const int*) (volatile const void*) (ip + m_len)) ^ (* (volatile const int*) (volatile const void*) (m_pos + m_len));
                if (ip + m_len >= ip_end)
                    goto m_len_done;
            } while (v == 0);
        }
        unsigned long res;
        m_len += res / 8;
        }
m_len_done:
        m_off = (unsigned long) ((ip)-(m_pos));
        ip += m_len;
        ii = ip;
        if (m_len <= 8 && m_off <= 0x0800)
        {
            m_off -= 1;
            *op++ = (unsigned char)(((m_len - 1) << 5) | ((m_off & 7) << 2));
            *op++ = (unsigned char)(m_off >> 3);
        }
        else if (m_off <= 0x4000)
        {
            m_off -= 1;
            if (m_len <= 33)
                *op++ = (unsigned char)(32 | (m_len - 2));
            else
            {
                m_len -= 33;
                *op++ = 32 | 0;
                while (m_len > 255)
                {
                    m_len -= 255;
                    * (volatile unsigned char *) op++ = 0;
                }
                *op++ = (unsigned char)(m_len);
            }
            *op++ = (unsigned char)(m_off << 2);
            *op++ = (unsigned char)(m_off >> 6);
        }
        else
        {
            m_off -= 0x4000;
            if (m_len <= 9)
                *op++ = (unsigned char)(16 | ((m_off >> 11) & 8) | (m_len - 2));
            else
            {
                m_len -= 9;
                *op++ = (unsigned char)(16 | ((m_off >> 11) & 8));
                while (m_len > 255)
                {
                    m_len -= 255;
                    * (volatile unsigned char *) op++ = 0;
                }
                *op++ = (unsigned char)(m_len);
            }
            *op++ = (unsigned char)(m_off << 2);
            *op++ = (unsigned char)(m_off >> 6);
        }
        goto next;
    }

    *out_len = (unsigned long) ((op)-(out));
    return (unsigned long) ((in_end)-(ii-ti));
}

int lzo_compress(const unsigned char* in , unsigned long  in_len, unsigned char* out, unsigned long* out_len)
{
    const unsigned char* ip = in;
    unsigned char* op = out;
    unsigned long l = in_len;
    unsigned long t = 0;
    void* wrkmem = new void*[16384];

    while (l > 20)
    {
        unsigned long ll = l;
        size_t ll_end;
        ll = ((ll) <= (49152) ? (ll) : (49152));
        ll_end = (size_t)ip + ll;
        if ((ll_end + ((t + ll) >> 5)) <= ll_end || (const unsigned char*)(ll_end + ((t + ll) >> 5)) <= ip + ll) break;
        memset(wrkmem, 0, ((unsigned long)1 << 14) * sizeof(unsigned short));
        t = lzo_docompress(ip,ll,op,out_len,t,wrkmem);
        ip += ll;
        op += *out_len;
        l  -= ll;
    }
    t += l;

    if (t > 0)
    {
        const unsigned char* ii = in + in_len - t;

        if (op == out && t <= 238)
            *op++ = (unsigned char)(17 + t);
        else if (t <= 3)
            op[-2] |= (unsigned char)(t);
        else if (t <= 18)
            *op++ = (unsigned char)(t - 3);
        else
        {
            unsigned long tt = t - 18;

            *op++ = 0;
            while (tt > 255)
            {
                tt -= 255;

                * (volatile unsigned char *) op++ = 0;
            }
            *op++ = (unsigned char)(tt);
        }
        do *op++ = *ii++; while (--t > 0);
    }

    *op++ = 16 | 1;
    *op++ = 0;
    *op++ = 0;

    *out_len = (unsigned long) ((op)-(out));
    return LZO_E_OK;
}

int lzo_decompress( const unsigned char* in , unsigned long in_len, unsigned char* out, unsigned long* out_len)
{
    register unsigned char* op;
    register const unsigned char* ip;
    register unsigned long t;
    register const unsigned char* m_pos;

    const unsigned char* const ip_end = in + in_len;
    unsigned char* const op_end = out + *out_len;

    *out_len = 0;

    op = out;
    ip = in;

    if (*ip > 17)
    {
        t = *ip++ - 17;
        if (t < 4) goto match_next;
        do *op++ = *ip++; while (--t > 0);
        goto first_literal_run;
    }

    while (ip < ip_end)
    {
        t = *ip++;
        if (t >= 16)
            goto match;
        if (t == 0)
        {
            while (*ip == 0)
            {
                t += 255;
                ip++;
            }
            t += 15 + *ip++;
        }
        ((* (volatile unsigned int*) (volatile void*) (op)) = (unsigned long) (* (volatile const unsigned int*) (volatile const void*) (ip)));
        op += 4; ip += 4;
        if (--t > 0)
        {
            if (t >= 4)
            {
                do {
                    ((* (volatile unsigned int*) (volatile void*) (op)) = (unsigned long) (* (volatile const unsigned int*) (volatile const void*) (ip)));
                    op += 4; ip += 4; t -= 4;
                } while (t >= 4);
                if (t > 0) do *op++ = *ip++; while (--t > 0);
            }
            else
                do *op++ = *ip++; while (--t > 0);
        }

first_literal_run:

        t = *ip++;
        if (t >= 16) goto match;
        m_pos = op - (1 + 0x0800);
        m_pos -= t >> 2;
        m_pos -= *ip++ << 2;
        *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;
        goto match_done;

        do {
match:
            if (t >= 64)
            {
                m_pos = op - 1;
                m_pos -= (t >> 2) & 7;
                m_pos -= *ip++ << 3;
                t = (t >> 5) - 1;
                goto copy_match;
            }
            else if (t >= 32)
            {
                t &= 31;
                if (t == 0)
                {
                    while (*ip == 0)
                    {
                        t += 255;
                        ip++;
                    }
                    t += 31 + *ip++;
                }
                m_pos = op - 1;
                m_pos -= (* (volatile const unsigned short*) (volatile const void*) (ip)) >> 2;
                ip += 2;
            }
            else if (t >= 16)
            {
                m_pos = op;
                m_pos -= (t & 8) << 11;
                t &= 7;
                if (t == 0)
                {
                    while (*ip == 0)
                    {
                        t += 255;
                        ip++;
                    }
                    t += 7 + *ip++;
                }
                m_pos -= (* (volatile const unsigned short*) (volatile const void*) (ip)) >> 2;
                ip += 2;
                if (m_pos == op)
                    goto eof_found;
                m_pos -= 0x4000;
            }
            else
            {
                m_pos = op - 1;
                m_pos -= t >> 2;
                m_pos -= *ip++ << 2;
                *op++ = *m_pos++; *op++ = *m_pos;
                goto match_done;
            }

            if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
            {
                ((* (volatile unsigned int*) (volatile void*) (op)) = (unsigned long) (* (volatile const unsigned int*) (volatile const void*) (m_pos)));
                op += 4; m_pos += 4; t -= 4 - (3 - 1);
                do {
                    ((* (volatile unsigned int*) (volatile void*) (op)) = (unsigned long) (* (volatile const unsigned int*) (volatile const void*) (m_pos)));
                    op += 4; m_pos += 4; t -= 4;
                } while (t >= 4);
                if (t > 0) do *op++ = *m_pos++; while (--t > 0);
            }
            else
            {
copy_match:
                *op++ = *m_pos++; *op++ = *m_pos++;
                do *op++ = *m_pos++; while (--t > 0);
            }


match_done:
            t = ip[-2] & 3;
            if (t == 0)
                break;

match_next:
            *op++ = *ip++;
            if (t > 1) {
                *op++ = *ip++;
                if (t > 2) 
                {
                    *op++ = *ip++;
                }
            }
            t = *ip++;
        } while (ip < ip_end);
    }
    *out_len = ((unsigned long) ((op)-(out)));
    return LZO_E_EOF_NOT_FOUND;

eof_found:
    *out_len = ((unsigned long) ((op)-(out)));
    return (ip == ip_end ? LZO_E_OK :
           (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
}

static const int crctable[] = {
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
    0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
    0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
    0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
    0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
    0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
    0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
    0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
    0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
    0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
    0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
    0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
    0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
    0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
    0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
    0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
    0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
    0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
    0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
    0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
    0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
    0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
    0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
    0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
    0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
    0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
    0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
    0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
    0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
    0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
    0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
    0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
    0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
    0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
    0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
    0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
    0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
    0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};

unsigned long CRC32(unsigned char* buffer, int size) {
    unsigned long crc = 0xffffffff;
    for (int i = 0; i < size; i++) crc = (crc >> 8) ^ crctable[buffer[i] ^ crc & 0x000000FF];
    return ~crc;
}

void pause()
{
    printf("Press a key to continue...\n");
    getch();
}

int main(int argc, char * argv[])
{
    printf("Metin2 File Tool By balika011\nVersion: 1.1\n\nThanks to:\n  Memory leak fix, r26+ type2 --> tim66613\n  Used sources --> pushedx, wikipedia, Markus F.X.J. Oberhumer\n\n");
    
    if(argc != 2)
    {
        std::string exename = argv[0];
        exename = exename.substr(exename.find_last_of("\\") + 1, exename.find_last_of(".") - exename.find_last_of("\\") - 1);
        printf("Usage: %s <.dat file>\n\nunpack:\n  unpack|pack_name|out_folder|out_dat_name\npack:\n  pack|pack_name\n\tfile_name|file_path|file_type\ncomment:\n  start line whit \"--\"\n", exename.c_str());
        pause();
        return -1;
    }

    std::ifstream myfile(argv[1]);
    if (myfile.is_open())
    {
        while(1)
        {
            std::string line;
            std::getline(myfile,line);
LAB1:
            if(strlen(line.c_str()) == 0 || line.substr(0, 2) == "--") if(!myfile.good()) break; else continue;
            if(line.substr(0, 4) == "pack")
            {
                if(strlen(line.c_str())-5 < 1) continue;
                std::string outfile = line.substr(5, strlen(line.c_str())-5);
                bool agin = 0;
                std::string file[9999];
                std::string path[9999];
                int type[9999];
                int filecount = 0;
                while(1)
                {
                    std::getline(myfile,line);
                    if(strlen(line.c_str()) == 0 || line.substr(0, 2) == "--") if(!myfile.good()) break; else continue;
                    if(line.substr(0, 1) != "\t") 
                    {
                        agin = 1;
                        break;
                    }
                    if(strlen(line.c_str())-1 < 1 || line.substr(2, 3) == "--") if(!myfile.good()) break; else continue;
                    std::string filename = line.substr(1, strlen(line.c_str())-1);
                    file[filecount] = strtok((char*)(filename.c_str()),"|");
                    path[filecount] = strtok(NULL, "|");
                    type[filecount] = atoi(strtok(NULL, "|"));
                    ++filecount;
                    if(!myfile.good()) break;
                }
                unsigned char* eixdecompressedBuffer = new unsigned char[0x0C + filecount * IndexBlockSize];
                memset(eixdecompressedBuffer, 0, 0x0C + filecount * IndexBlockSize);

                eixdecompressedBuffer += 0x0C;

                unsigned char* epkBuffer = new unsigned char[536870911]; //512MB

                int lastoffset = 0;
                int donefiles = 0;
                for(int i=0; i < filecount; ++i) {
                    unsigned char* Buffer;
                    unsigned long Size;
                    
                    FILE* File = fopen(path[i].c_str() , "rb" );
                    if (File == NULL) {
                        printf("Could not open %s file.\n", path[i].c_str());
                        if(agin) goto LAB1; else return 0;
                    }
                    fseek(File , 0 , SEEK_END);
                    Size = ftell(File);
                    rewind(File);
                    Buffer = new unsigned char[Size];
                    if (Buffer == NULL) {
                        printf("Memory error when make buffer for %s file.\n", path[i].c_str());
                        if(agin) goto LAB1; else return 0;
                    }
                    if (fread(Buffer,1,Size,File) != Size) {
                        printf("Could not read %s file.\n", path[i].c_str());
                        if(agin) goto LAB1; else return 0;
                    }
                    fclose(File);

                    *(unsigned long*)eixdecompressedBuffer = i;
                    memcpy(eixdecompressedBuffer + 4, file[i].c_str(), strlen(file[i].c_str()));
                    *(unsigned long*)(eixdecompressedBuffer + 168) = CRC32((unsigned char*)file[i].c_str(),strlen(file[i].c_str()));
                    *(unsigned long*)(eixdecompressedBuffer + 184) = lastoffset;
                    *(unsigned char*)(eixdecompressedBuffer + 188) = type[i];

                    if(type[i] == 0){
                        *(unsigned long*)(eixdecompressedBuffer + 172) = Size;
                        *(unsigned long*)(eixdecompressedBuffer + 176) = Size;
                        *(unsigned long*)(eixdecompressedBuffer + 180) = CRC32(Buffer, Size);
                        memset(epkBuffer + lastoffset, 0, Size);
                        memcpy(epkBuffer + lastoffset, Buffer, Size);
                        lastoffset += Size;
                    }
                    else if(type[i] == 1){
                        unsigned char* compressedBuffer = new unsigned char[Size + (Size / 16) + 64 + 3 + 20];
                        memset(compressedBuffer, 0, Size + (Size / 16) + 64 + 3 + 20);
    
                        unsigned long compSize = 0;
                        if(lzo_compress(Buffer, Size, compressedBuffer + 20, &compSize) != LZO_E_OK)
                        {
                            printf("Error when compressing %s.\n", file[i].c_str());
                            delete [] compressedBuffer;
                            pause();
                            if(agin) goto LAB1; else return 0;
                        }
                        
                        *(unsigned long*)compressedBuffer = FourCC;
                        *(unsigned long*)(compressedBuffer + 8) = compSize;
                        *(unsigned long*)(compressedBuffer + 12) = Size;
                        *(unsigned long*)(compressedBuffer + 16) = FourCC;

                        memset(epkBuffer + lastoffset, 0, compSize + 20);
                        memcpy(epkBuffer + lastoffset, compressedBuffer, compSize + 20);

                        *(unsigned long*)(eixdecompressedBuffer + 172) = Size;
                        *(unsigned long*)(eixdecompressedBuffer + 176) = compSize + 4;
                        *(unsigned long*)(eixdecompressedBuffer + 180) = CRC32(Buffer, Size);
                        lastoffset += compSize + 20;
                        delete[] compressedBuffer;
                    }
                    else if(type[i] == 2)
                    {
                        unsigned char* compressedBuffer = new unsigned char[Size + (Size / 16) + 64 + 3 + 4];
                        memset(compressedBuffer, 0, Size + (Size / 16) + 64 + 3 + 4);
    
                        unsigned long compSize = 0;
                        if(lzo_compress(Buffer, Size, compressedBuffer + 4, &compSize) != LZO_E_OK)
                        {
                            printf("Error when compressing %s.\n", file[i].c_str());
                            delete [] compressedBuffer;
                            pause();
                            if(agin) goto LAB1; else return 0;
                        }
                        *(unsigned long*)compressedBuffer = FourCC;

                        unsigned char* encryptedBuffer = new unsigned char[compSize + 4 + 7];
                        memset(encryptedBuffer, 0, compSize + 4 + 7);
    
                        unsigned long cryptSize = XteaEncrypt((unsigned long*)encryptedBuffer, (unsigned long*)compressedBuffer, DataXTEA, compSize + 4);

                        memset(epkBuffer + lastoffset, 0, cryptSize + 16);
                        *(unsigned long*)(epkBuffer + lastoffset) = FourCC;
                        *(unsigned long*)(epkBuffer + lastoffset + 4)  = cryptSize;
                        *(unsigned long*)(epkBuffer + lastoffset + 8)  = compSize;
                        *(unsigned long*)(epkBuffer + lastoffset + 12)  = Size;
                        memcpy(epkBuffer + lastoffset + 16, encryptedBuffer, cryptSize);

                        
                        *(unsigned long*)(eixdecompressedBuffer + 172) = 512 + (512 / (cryptSize + 16));
                        *(unsigned long*)(eixdecompressedBuffer + 176) = cryptSize;
                        *(unsigned long*)(eixdecompressedBuffer + 180) = CRC32(epkBuffer + lastoffset, cryptSize);
                        lastoffset += cryptSize + 16;
                        delete[] compressedBuffer;
                        delete[] encryptedBuffer;
                    }
                    else
                    {
                        printf("type %i is unsupported\n", type[i]);
                        delete [] Buffer;
                        continue;
                    }
                    eixdecompressedBuffer += IndexBlockSize;
                    ++donefiles;
                    delete [] Buffer;
                }

                unsigned long eixdecompressedSize = 0x0C + donefiles * IndexBlockSize;
                eixdecompressedBuffer -= eixdecompressedSize;

                *(unsigned long*)eixdecompressedBuffer = IndexHeader;
                *(unsigned long*)(eixdecompressedBuffer + 4) = IndexVersion;
                *(unsigned long*)(eixdecompressedBuffer + 8) = donefiles;

                unsigned char* compressedBuffer = new unsigned char[eixdecompressedSize + (eixdecompressedSize / 16) + 64 + 3 + 4];
                memset(compressedBuffer, 0, eixdecompressedSize + (eixdecompressedSize / 16) + 64 + 3 + 4);
    
                unsigned long compSize = 0;
                if(lzo_compress(eixdecompressedBuffer, eixdecompressedSize, compressedBuffer + 4, &compSize) != LZO_E_OK)
                {
                    printf("Error when compressing index.\n");
                    delete [] compressedBuffer;
                    pause();
                    if(agin) goto LAB1; else return 0;
                }
                *(unsigned long*)compressedBuffer = FourCC;

                unsigned char* encryptedBuffer = new unsigned char[compSize + 4];
                memset(encryptedBuffer, 0, compSize + 4);
    
                unsigned long cryptSize = XteaEncrypt((unsigned long*)encryptedBuffer, (unsigned long*)compressedBuffer, IndexXTEA, compSize + 4);

                unsigned char* DoneBuffer = new unsigned char[cryptSize + 16];
                memset(DoneBuffer, 0, cryptSize + 16);
                *(unsigned long*)DoneBuffer = FourCC;
                *(unsigned long*)(DoneBuffer + 4)  = cryptSize;
                *(unsigned long*)(DoneBuffer + 8)  = compSize;
                *(unsigned long*)(DoneBuffer + 12)  = eixdecompressedSize;
                memcpy(DoneBuffer + 16, encryptedBuffer, cryptSize);

                FILE * indexof = fopen((outfile + IndexName).c_str(), "wb");
                if(indexof)
                {
                    fwrite(DoneBuffer, 1, cryptSize + 16, indexof);
                    fclose(indexof);
                }
                
                FILE * dataof = fopen((outfile + DataName).c_str(), "wb");
                if(dataof)
                {
                    fwrite(epkBuffer, 1, lastoffset + 16, dataof);
                    fclose(dataof);
                }
                
                printf("Done!\n");
                if(agin) goto LAB1;
            }
            else if(line.substr(0, 6) == "unpack")
            {
                if(strlen(line.c_str())-7 < 1) continue;
                std::string in = line.substr(7, strlen(line.c_str())-7);
                char* infile = strtok((char*)(in.c_str()),"|");
                std::string outfolder = strtok(NULL, "|");
                char* outfile = strtok(NULL, "|");

                std::string eixName_ = (std::string)infile + IndexName;
                std::string epkName_ = (std::string)infile + DataName;
                const char * eixName = eixName_.c_str();
                const char * epkName = epkName_.c_str();
    
                unsigned char* eixBuffer;
                unsigned long eixSize;
                
                FILE* eixFile = fopen(eixName , "rb" );
                if (eixFile == NULL) {
                    printf("Could not open %s file.\n", eixName);
                    if(!myfile.good()) {pause(); return 0;} else goto LAB1;
                }
                fseek(eixFile , 0 , SEEK_END);
                eixSize = ftell(eixFile);
                rewind(eixFile);
                eixBuffer = new unsigned char[eixSize];
                if (eixBuffer == NULL) {
                    printf("Memory error when make buffer for %s file.\n", eixName);
                    if(!myfile.good()) {pause(); return 0;} else goto LAB1;
                }
                if (fread(eixBuffer,1,eixSize,eixFile) != eixSize) {
                    printf("Could not read %s file.\n", eixName);
                    if(!myfile.good()) {pause(); return 0;} else goto LAB1;
                }
                fclose(eixFile);
                
                unsigned char* epkBuffer;
                unsigned long epkSize;
                
                FILE* epkFile = fopen(epkName , "rb" );
                if (epkFile == NULL) {
                    printf("Could not open %s file.\n", epkName);
                    if(!myfile.good()) {pause(); return 0;} else goto LAB1;
                }
                fseek(epkFile , 0 , SEEK_END);
                epkSize = ftell(epkFile);
                rewind(epkFile);
                epkBuffer = new unsigned char[epkSize];
                if (epkBuffer == NULL) {
                    printf("Memory error when make buffer for %s file.\n", epkName);
                    if(!myfile.good()) {pause(); return 0;} else goto LAB1;
                }
                if (fread(epkBuffer,1,epkSize,epkFile) != epkSize) {
                    printf("Could not read %s file.\n", epkName);
                    if(!myfile.good()) {pause(); return 0;} else goto LAB1;
                }
                fclose(epkFile);

                if(eixSize < 0x0C)
                {
                    printf("The file size for the %s file is too small. The program will now exit.\n", eixName);
                    pause();
                    if(!myfile.good()) {pause(); return 0;} else goto LAB1;
                }

                unsigned char* eixdecompressedBuffer;
                unsigned long eixdecompressedSize;

                if (*(unsigned long*)eixBuffer != IndexHeader)
                {
                    unsigned long eixheader = *(unsigned long*)eixBuffer;
                    unsigned long eixcryptedSize = *(unsigned long*)(eixBuffer + 4);
                    unsigned long eixcompressedSize = *(unsigned long*)(eixBuffer + 8);
                    eixdecompressedSize = *(unsigned long*)(eixBuffer + 12);

                    if (eixheader != FourCC)
                    {
                        printf("The FourCC of %s is incorrect.\n", eixName);
                        pause();
                        if(!myfile.good()) return 0; else goto LAB1;
                    }
        
                    if(eixcryptedSize == 0)
                    {
                        printf("[TODO] -- Index of %s is not encrypted!\n", eixName);
                        pause();
                        if(!myfile.good()) return 0; else goto LAB1;
                    }

                    unsigned char* eixcompressedBuffer = new unsigned char[eixcryptedSize];
                    memset(eixcompressedBuffer, 0, eixcryptedSize);

                    XteaDecrypt((unsigned long*)eixcompressedBuffer, (unsigned long*)(eixBuffer + 0x10), IndexXTEA, eixcryptedSize);
                    if(*(unsigned long*)eixcompressedBuffer != FourCC)
                    {
                        delete [] eixcompressedBuffer;
                        printf("The XTEA Key of %s is incorrect.\n", eixName);
                        pause();
                        if(!myfile.good()) return 0; else goto LAB1;
                    }

                    eixdecompressedBuffer = new unsigned char[eixdecompressedSize];
                    memset(eixdecompressedBuffer, 0, eixdecompressedSize);

                    unsigned long finalSize = 0;
                    if(lzo_decompress(eixcompressedBuffer + 4, eixcompressedSize, eixdecompressedBuffer, &finalSize) != LZO_E_OK || finalSize != eixdecompressedSize)
                    {
                        delete [] eixdecompressedBuffer;
                        delete [] eixcompressedBuffer;
                        printf("There was an error when decompressing %s.\n", eixName);
                        if(!myfile.good()) return 0; else goto LAB1;
                    }
                    delete [] eixcompressedBuffer;
                }
                else
                {
                    eixdecompressedBuffer = eixBuffer + 4;
                    eixdecompressedSize = eixSize - 4;
                }

                unsigned long eixheader2 = *(unsigned long*)eixdecompressedBuffer;
                unsigned long eixversion = *(unsigned long*)(eixdecompressedBuffer + 4);
                unsigned long eixfileCount = *(unsigned long*)(eixdecompressedBuffer + 8);

                if(eixversion != IndexVersion)
                {
                    delete [] eixdecompressedBuffer;
                    printf("The version of %s file is incorrect. Found: %i Supported: %i).\n", eixName, eixversion, IndexVersion);
                    pause();
                    if(!myfile.good()) return 0; else goto LAB1;
                }

                std::string filename = ((std::string)infile).substr(1 + ((std::string)infile).find_last_of("\\/"));

                eixdecompressedBuffer += 0x0C;

                FILE * of = fopen(outfile, "w");
                if(!of)
                {
                    printf("There was an error creating %s file.\n", "name");
                    pause();
                    if(!myfile.good()) return 0; else goto LAB1;
                }
                if(of) fprintf(of, "pack|%s\n", infile);

                for(unsigned long x = 0; x < eixfileCount; ++x)
                {
                    unsigned long index = *(unsigned long*)eixdecompressedBuffer;
                    char filename[160];
                    memcpy(filename,eixdecompressedBuffer + 4,160);
                    unsigned long filenameCRC = *(unsigned long*)(eixdecompressedBuffer + 168);
                    unsigned long dw3 = *(unsigned long*)(eixdecompressedBuffer + 172);
                    unsigned long dwSrcSize = *(unsigned long*)(eixdecompressedBuffer + 176);
                    unsigned long unpackedCRC = *(unsigned long*)(eixdecompressedBuffer + 180);
                    unsigned long dwFileOffset = *(unsigned long*)(eixdecompressedBuffer + 184);
                    unsigned char packedType = *(unsigned char*)(eixdecompressedBuffer + 188);
                    eixdecompressedBuffer += IndexBlockSize;
                    std::string outfilename;
                    if(packedType == 0)
                    {
                        std::stringstream dirPath;
                        std::vector<std::string> pathTokens;
                        size_t p0 = 0, p1 = std::string::npos;
                        while(p0 != std::string::npos)
                        {
                            p1 = ((const std::string&)filename).find_first_of("\\/", p0);
                            if(p1 != p0)
                            {
                                std::string token = ((const std::string&)filename).substr(p0, p1 - p0);
                                pathTokens.push_back(token);
                            }
                            p0 = ((const std::string&)filename).find_first_not_of("\\/", p1);
                        }
                        dirPath << outfolder;
                        mkfolder(dirPath.str().c_str());
                        dirPath << "\\";
                        size_t index = 0;
                        for(index = 0; index < pathTokens.size() - 1; ++index)
                        {
                            if(pathTokens[index].find_first_of(":") != std::string::npos)
                                continue;
                            dirPath << pathTokens[index];
                            mkfolder(dirPath.str().c_str());
                            dirPath << "\\";
                        }
                        dirPath << pathTokens[index];
                        outfilename = dirPath.str();
                        FILE * of = fopen(outfilename.c_str(), "wb");
                        if(!of)
                        {
                            std::string buff = outfolder + "\\crashfile" + (char)crashi;
                            ++crashi;
                            of = fopen(buff.c_str(), "wb");
                            printf("Crash file %s saved as: %s\n", outfilename.c_str(), buff.c_str());
                            outfilename = buff;
                        }
                        if(of)
                        {
                            fwrite(epkBuffer + dwFileOffset, 1, dwSrcSize, of);
                            fclose(of);
                        }
                        else
                        {
                            printf("Could not save the file %s\n", outfilename.c_str());
                        }
                    }
                    else if(packedType == 1)
                    {
                        unsigned long dataheader = *(unsigned long*)(epkBuffer + dwFileOffset);
                        unsigned long datacryptedSize = *(unsigned long*)(epkBuffer + dwFileOffset + 4);
                        unsigned long datacompressedSize = *(unsigned long*)(epkBuffer + dwFileOffset + 8);
                        unsigned long datadecompressedSize = *(unsigned long*)(epkBuffer + dwFileOffset + 12);

                        if(dataheader != FourCC)
                        {
                            printf("The FourCC is incorrect of %s.\n", filename);
                            continue;
                        }

                        unsigned char* datauncompressedBuffer = new unsigned char[datadecompressedSize];
                        memset(datauncompressedBuffer, 0, datadecompressedSize);

                        unsigned long finalSize = 0;
                        if(lzo_decompress(epkBuffer + dwFileOffset + 16 + 4, datacompressedSize, datauncompressedBuffer, &finalSize) == LZO_E_OK && finalSize == datadecompressedSize)
                        {
                            std::stringstream dirPath;
                            std::vector<std::string> pathTokens;
                            size_t p0 = 0, p1 = std::string::npos;
                            while(p0 != std::string::npos)
                            {
                                p1 = ((const std::string&)filename).find_first_of("\\/", p0);
                                if(p1 != p0)
                                {
                                    std::string token = ((const std::string&)filename).substr(p0, p1 - p0);
                                    pathTokens.push_back(token);
                                }
                                p0 = ((const std::string&)filename).find_first_not_of("\\/", p1);
                            }
                            dirPath << outfolder;
                            mkfolder(dirPath.str().c_str());
                            dirPath << "\\";
                            size_t index = 0;
                            for(index = 0; index < pathTokens.size() - 1; ++index)
                            {
                                if(pathTokens[index].find_first_of(":") != std::string::npos)
                                    continue;
                                dirPath << pathTokens[index];
                                mkfolder(dirPath.str().c_str());
                                dirPath << "\\";
                            }
                            dirPath << pathTokens[index];
                            outfilename = dirPath.str();
                            FILE * of = fopen(outfilename.c_str(), "wb");
                            if(!of)
                            {
                                std::string buff = outfolder + "\\crashfile" + (char)crashi;
                                ++crashi;
                                of = fopen(buff.c_str(), "wb");
                                printf("Crash file %s saved as: %s\n", outfilename.c_str(), buff.c_str());
                                outfilename = buff;
                            }
                            if(of)
                            {
                                fwrite(datauncompressedBuffer, 1, datadecompressedSize, of);
                                fclose(of);
                            }
                            else
                            {
                                printf("Could not save the file %s\n", outfilename.c_str());
                            }
                        }
                        else
                        {
                            printf("There was an error when decompressing %s file.\n", filename);
                        }

                        delete [] datauncompressedBuffer;
                    }
                    else if(packedType == 2)
                    {
                        unsigned long dataheader = *(unsigned long*)(epkBuffer + dwFileOffset);
                        unsigned long datacryptedSize = *(unsigned long*)(epkBuffer + dwFileOffset + 4);
                        unsigned long datacompressedSize = *(unsigned long*)(epkBuffer + dwFileOffset + 8);
                        unsigned long datadecompressedSize = *(unsigned long*)(epkBuffer + dwFileOffset + 12);

                        if(dataheader != FourCC)
                        {
                            printf("The FourCC is incorrect of %s.\n", filename);
                            continue;
                        }

                        unsigned char* datadecryptedBuffer = new unsigned char[datacryptedSize];
                        memset(datadecryptedBuffer, 0, datacryptedSize);
            
                        XteaDecrypt((unsigned long*)datadecryptedBuffer, (unsigned long*)(epkBuffer + dwFileOffset + 16), DataXTEA, datacryptedSize);
                        if(*(unsigned long*)datadecryptedBuffer != FourCC)
                        {
                            printf("There was an error decrypting the data for the %s file. It will be skipped.\n", filename);
                            delete [] datadecryptedBuffer;
                            continue;
                        }

                        unsigned char* datauncompressedBuffer = new unsigned char[datadecompressedSize];
                        memset(datauncompressedBuffer, 0, datadecompressedSize);

                        unsigned long finalSize = 0;
                        if(lzo_decompress(datadecryptedBuffer + 4, datacompressedSize, datauncompressedBuffer, &finalSize) == LZO_E_OK && finalSize == datadecompressedSize)
                        {
                            std::stringstream dirPath;
                            std::vector<std::string> pathTokens;
                            size_t p0 = 0, p1 = std::string::npos;
                            while(p0 != std::string::npos)
                            {
                                p1 = ((const std::string&)filename).find_first_of("\\/", p0);
                                if(p1 != p0)
                                {
                                    std::string token = ((const std::string&)filename).substr(p0, p1 - p0);
                                    pathTokens.push_back(token);
                                }
                                p0 = ((const std::string&)filename).find_first_not_of("\\/", p1);
                            }
                            dirPath << outfolder;
                            mkfolder(dirPath.str().c_str());
                            dirPath << "\\";
                            size_t index = 0;
                            for(index = 0; index < pathTokens.size() - 1; ++index)
                            {
                                if(pathTokens[index].find_first_of(":") != std::string::npos)
                                    continue;
                                dirPath << pathTokens[index];
                                mkfolder(dirPath.str().c_str());
                                dirPath << "\\";
                            }
                            dirPath << pathTokens[index];
                            outfilename = dirPath.str();
                            FILE * of = fopen(outfilename.c_str(), "wb");
                            if(!of)
                            {
                                std::string buff = outfolder + "\\crashfile" + (char)crashi;
                                ++crashi;
                                of = fopen(buff.c_str(), "wb");
                                printf("Crash file %s saved as: %s\n", outfilename.c_str(), buff.c_str());
                                outfilename = buff;
                            }
                            if(of)
                            {
                                fwrite(datauncompressedBuffer, 1, datadecompressedSize, of);
                                fclose(of);
                            }
                            else
                            {
                                printf("Could not save the file %s\n", outfilename.c_str());
                            }
                        }
                        else
                        {
                            printf("There was an error when decompressing %s file.\n", filename);
                        }

                        delete [] datadecryptedBuffer;
                        delete [] datauncompressedBuffer;
                    }
                    else
                    {
                        printf("Unsupported type: %i (%s).\n", packedType, filename);
                        continue;
                    }
                    fprintf(of, "\t%s|%s|%i\n", filename, outfilename.c_str(), packedType);
                }
                fclose(of);
                printf("Done!\n");
            }
            else printf("dat file error!\n");
            if(!myfile.good()) break;
        }
        printf("All done!\n");
        myfile.close();
    }
    else printf("%s file not found!\n", argv[1]);

    pause();
    return 0;
}  