// ReadNpk.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//




static void ReadColor(BYTE* Tab, int Type, BYTE* SaveByte, int Offset)
{
    BYTE a = 0;
    BYTE r = 0;
    BYTE g = 0;
    BYTE b = 0;
    switch (Type)
    {
    case 0x0e:
        a = (byte)(Tab[1] >> 7);
        r = (byte)((Tab[1] >> 2) & 0x1f);
        g = (byte)((Tab[0] >> 5) | ((Tab[1] & 3) << 3));
        b = (byte)(Tab[0] & 0x1f);
        a = (byte)(a * 0xff);
        r = (byte)((r << 3) | (r >> 2));
        g = (byte)((g << 3) | (g >> 2));
        b = (byte)((b << 3) | (b >> 2));
        break;
    case 0x0f:
        a = (byte)(Tab[1] & 0xf0);
        r = (byte)((Tab[1] & 0xf) << 4);
        g = (byte)(Tab[0] & 0xf0);
        b = (byte)((Tab[0] & 0xf) << 4);
        break;
    }
    SaveByte[Offset + 0] = b;
    SaveByte[Offset + 1] = g;
    SaveByte[Offset + 2] = r;
    SaveByte[Offset + 3] = a;
}



class ReadNpk :public std::ifstream
{
    const BYTE Key[256] = { 112,117,99,104,105,107,111,110,64,110,101,111,112,108,101,32,100,117,110,103,101,111,110,32,97,110,100,32,102,105,103,104,116,101,114,32,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,68,78,70,0 };

public:
    //char* 转整数
    int CharToInt(char* Str)
    {
        return *(int*)Str;
    }

    //char* 转Long
    long long CharToLong(char* Str)
    {
        return *(long long*)Str;
    }


    //DNFTOOL::ReadInt
    int ReadInt()
    {
        char* CountBuffer = new char[4];
        for (int i = 0; i < 4; i++)
        {
            this->get(CountBuffer[i]);
        }
        int Count = CharToInt(CountBuffer);
        delete[]CountBuffer;
        return Count;
    }

    //读字符串
    std::string ReadString()
    {
        char* CharBuffer = new char[1024];
        this->get(CharBuffer, 1024, '\0');
        std::string Str = CharBuffer;
        delete[]CharBuffer;
        this->seekg(1, std::ios::cur);
        return Str;
    }

    //读取信息
    std::string ReadInfo()
    {
        char* CharBuffer = new char[256];
        char var;
        int i = 0;
        while (i < 256)
        {
            this->get(var);
            CharBuffer[i] = var ^ Key[i];
            ++i;
        }
        std::string Str = CharBuffer;
        delete[] CharBuffer;
        return Str;
    }

    //读LONG
    long long ReadLong()
    {
        char* CountBuffer = new char[8];
        for (int i = 0; i < 8; i++)
        {
            this->get(CountBuffer[i]);
        }
        long long Count = CharToLong(CountBuffer);
        delete[]CountBuffer;
        return Count;
    }

    //读指定长度数据
    BYTE* ReadCustomSize(int Size)
    {
        BYTE* CharBuffer = new BYTE[Size];
        for (int j = 0; j < Size; j++)
        {
            char var;
            this->get(var);
            CharBuffer[j] = var;
        }
        return CharBuffer;
    }
};



struct NpkInfo
{
    int Offset;
    int Length;
    std::string Path;
};

struct ImgInfo
{
    //图片格式
    int Type;
    //压缩类型
    int CmpType;
    //宽度
    int Width;
    //高度
    int Height;
    //大小
    int Size;
    //Xpos
    int Xpos;
    //Ypos
    int Ypos;
    //帧域X
    int FrameXpos;
    //帧域Y
    int FrameYpos;
    //偏移
    int Offset;
    
};

// xxxx.img 5

static BYTE* GetNPK()
{
    typedef  int (*__Decompress)(BYTE* dest, ULONG* destLen, BYTE* source, ULONG sourceLen);
    HMODULE hDll = LoadLibrary(L"zlib1.dll");

    __Decompress Decompress = (__Decompress)GetProcAddress(hDll, "uncompress");


    ReadNpk Fs;
    Fs.open("!HUD_阿拉德猜数字.NPK", std::ios::in | std::ios::binary);

    if (Fs)
    {

        std::string Header = Fs.ReadString();
        //如果是NPK
        if (Header._Equal("NeoplePack_Bill"))
        {
            int Count = Fs.ReadInt();
            std::cout << "img数量:" << Count << std::endl;

            //new出 img数量的 结构体
            NpkInfo* ImgList = new NpkInfo[Count];
            //读取 img列表数据
            for (int i = 0; i < Count; i++)
            {
                ImgList[i].Offset = Fs.ReadInt();
                ImgList[i].Length = Fs.ReadInt();
                ImgList[i].Path = Fs.ReadInfo();
            }

            for (int z = 0; z < Count; z++)
            {
                Fs.seekg(ImgList[z].Offset);
                std::string Flag = Fs.ReadString();
                if (Flag._Equal("Neople Img File"))
                {
                    //索引表大小
                    long long TableLength = Fs.ReadLong();
                    //img 版本 4字节
                    int ver = Fs.ReadInt();
                    //img 帧数
                    int IndexCount = Fs.ReadInt();

                    //new出 Png数量的 结构体
                    ImgInfo* PngList = new ImgInfo[IndexCount];
                    for (int i = 0; i < IndexCount; i++)
                    {
                        PngList[i].Type = Fs.ReadInt();
                        if (PngList[i].Type == 17)
                        {
                            //引用贴图
                            std::cout << Fs.ReadInt() << std::endl;
                            continue;
                        }
                        //压缩类型
                        PngList[i].CmpType = Fs.ReadInt();
                        //宽度
                        PngList[i].Width = Fs.ReadInt();
                        //高度
                        PngList[i].Height = Fs.ReadInt();
                        //大小
                        PngList[i].Size = Fs.ReadInt();
                        //Xpos
                        PngList[i].Xpos = Fs.ReadInt();
                        //Ypos
                        PngList[i].Ypos = Fs.ReadInt();
                        //帧域X
                        PngList[i].FrameXpos = Fs.ReadInt();
                        //帧域Y
                        PngList[i].FrameYpos = Fs.ReadInt();
                        //计算偏移
                        if (i == 0)PngList[i].Offset = 0 + ImgList[z].Offset + TableLength + 32;
                        else PngList[i].Offset = PngList[i - 1].Offset + PngList[i - 1].Size;
                    }



                    Fs.seekg(PngList[0].Offset);
                    std::cout << PngList[0].Size << std::endl;
                    BYTE* PngData = Fs.ReadCustomSize(PngList[0].Size);

                    int DeSize = PngList[0].Width * PngList[0].Height * 4;
                    BYTE* bByte = new BYTE[DeSize];
                    ULONG RealSize;
                    int a = Decompress(bByte, &RealSize, PngData, (ULONG)PngList[0].Size);
                    delete[]PngData;

                    if (PngList[0].Type != 16)
                    {
                        int PngByteSize = DeSize * 2;
                        BYTE* PngByte = new BYTE[PngByteSize];


                        for (int e = 0; e < PngByteSize; e += 4)
                        {
                            BYTE NeedData[4];
                            memset(NeedData, 0, sizeof(NeedData));
                            memcpy(NeedData, bByte + e, sizeof(NeedData));
                            ReadColor(NeedData, PngList[0].Type, PngByte, e);
                        }
                        delete[]bByte;

                        for (int o = 0; o < PngByteSize; o++)
                        {
                            //std::cout << (int)PngByte[o] << ",";
                        }
                        delete[]PngByte;
                    }


                    return bByte;

                    delete[] bByte;
                    delete[]PngList;
                }
            }

            //销毁img列表数据
            delete[]ImgList;
            //销毁Png列表数据
        }
    }
    else
    {
        std::cout << "打开失败" << std::endl;
    }
    Fs.close();
    return 0;
}

