Example #1
0
        static async Task Decompress(byte[] bts, string dir, NItem item)
        {
            if (item.IsCompressed == 0 || (item.Unk4 == item.Unk5 && item.OriginalLength == item.CompressedLength))
            {
                //Console.WriteLine($"Unpack {item.Id:X8}");
                var header   = bts.Take(32).ToArray();
                var fileName = InferExtension(header, item, out var category);
                Console.WriteLine($"Unpack: {fileName}");
                var path = Path.Combine(dir, category);
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }

                using (var fs = File.Create(Path.Combine(path, fileName)))
                {
                    await fs.WriteAsync(bts, 0, bts.Length);
                }
            }
            else
            {
                //Console.WriteLine($"Decompress: {item.Id:X8}");
                using (var output = new MemoryStream((int)item.OriginalLength))
                {
                    try
                    {
                        using (var ms = new MemoryStream(bts, 2, bts.Length - 2))
                            using (var zs = new DeflateStream(ms, CompressionMode.Decompress, false))
                            {
                                await zs.CopyToAsync(output);

                                output.Position = 0;
                            }
                    }
                    catch (InvalidDataException e)
                    {
                        Console.WriteLine($"Decompress {item.Id:X8}({item.Offset}) failed.");
                    }

                    var header = new byte[32];
                    await output.ReadAsync(header, 0, header.Length);

                    var fileName = InferExtension(header, item, out var category);
                    Console.WriteLine($"Decompress: {fileName}");
                    var path = Path.Combine(dir, category);
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }

                    output.Position = 0;
                    using (var fs = File.Create(Path.Combine(path, fileName)))
                    {
                        await output.CopyToAsync(fs);
                    }
                }
            }
        }
Example #2
0
        static void Unpack(string npk, string dir)
        {
            if (!File.Exists(npk))
            {
                Console.WriteLine("Can not find npk file.");
                return;
            }
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }

            var fs = File.OpenRead(npk);
            var br = new BinaryReader(fs);

            var len = fs.Length;

            fs.Seek(20, SeekOrigin.Begin);
            var mapOffset = br.ReadUInt32(); //begin: res bytes, end: map

            List <NItem> items = new List <NItem>();

            fs.Seek(mapOffset, SeekOrigin.Begin);
            while (fs.Position + 4 * 7 <= len)
            {
                var item = new NItem
                {
                    Id               = br.ReadUInt32(),
                    Offset           = br.ReadUInt32(),
                    CompressedLength = br.ReadUInt32(),
                    OriginalLength   = br.ReadUInt32(),
                    Unk4             = br.ReadUInt32(),
                    Unk5             = br.ReadUInt32(),
                    IsCompressed     = br.ReadUInt32(),
                };
                //if (item.Id == 0x694FDF33 || item.Unk4 == 0x694FDF33 || item.Unk5 == 0x694FDF33)
                //{
                //    Console.WriteLine("maybe have name");
                //}
                items.Add(item);
            }

            items.Sort((o1, o2) => (int)((long)o1.Offset - (long)o2.Offset));
            List <Task> tasks = new List <Task>(items.Count);

            foreach (var it in items)
            {
                fs.Seek(it.Offset, SeekOrigin.Begin);
                var bts = br.ReadBytes((int)it.CompressedLength);
                tasks.Add(Decompress(bts, dir, it));
            }

            Task.WaitAll(tasks.ToArray());
            Console.WriteLine("Done.");
            br.Dispose();
        }
Example #3
0
        static string InferExtension(byte[] header, NItem item, out string category)
        {
            var result = _sniffer.Match(header);

            if (result.Count == 0)
            {
                var headerStr = Encoding.ASCII.GetString(header);
                if (headerStr.StartsWith("KTX") ||
                    headerStr.StartsWith("«KTX"))
                {
                    category = "texture";
                    return($"{item.Id:X8}.ktx");
                }
                if (headerStr.StartsWith("PKM"))
                {
                    category = "texture";
                    return($"{item.Id:X8}.pkm");
                }
                if (headerStr.StartsWith("RGIS"))
                {
                    category = "rgis";
                    return($"{item.Id:X8}.rgis");
                }
                if (headerStr.StartsWith("<NeoX") ||
                    headerStr.StartsWith("<Neox"))
                {
                    category = "NeoXml";
                    return($"{item.Id:X8}.NeoX.xml");
                }
                if (headerStr.StartsWith("<FxGroup"))
                {
                    category = "NeoXml";
                    return($"{item.Id:X8}.FxGroup.xml");
                }
                if (headerStr.StartsWith("<SceneMusic"))
                {
                    category = "NeoXml";
                    return($"{item.Id:X8}.SceneMusic.xml");
                }
                if (headerStr.StartsWith("<MusicTriggers"))
                {
                    category = "NeoXml";
                    return($"{item.Id:X8}.MusicTriggers.xml");
                }
                if (headerStr.StartsWith("<cinematic"))
                {
                    category = "NeoXml";
                    return($"{item.Id:X8}.cinematic.xml");
                }
                if (headerStr.StartsWith("<EquipList"))
                {
                    category = "NeoXml";
                    return($"{item.Id:X8}.EquipList.xml");
                }
                if (headerStr.StartsWith("<SceneConfig"))
                {
                    category = "NeoXml";
                    return($"{item.Id:X8}.SceneConfig.xml");
                }
                if (headerStr.StartsWith("<SceneRoad"))
                {
                    category = "NeoXml";
                    return($"{item.Id:X8}.SceneRoad.xml");
                }

                if (headerStr.StartsWith("v ") ||
                    headerStr.StartsWith("vt ") ||
                    headerStr.StartsWith("f ")
                    )
                {
                    category = "model";
                    return($"{item.Id:X8}.obj");
                }
                if (headerStr.StartsWith("CocosStudio-UI"))
                {
                    category = "ui";
                    return($"{item.Id:X8}.csb");
                }
                if (headerStr.StartsWith("vec4") ||
                    headerStr.StartsWith("vec2") ||
                    headerStr.StartsWith("tex2D") ||
                    headerStr.StartsWith("tex3D") ||
                    headerStr.StartsWith("float") ||
                    headerStr.StartsWith("define") ||
                    headerStr.StartsWith("incloud") ||
                    headerStr.StartsWith("#if") ||
                    headerStr.StartsWith("#define") ||
                    headerStr.StartsWith("int ") ||
                    headerStr.StartsWith("precision ")
                    )
                {
                    category = "shader";
                    return($"{item.Id:X8}.glsl");
                }
                if (headerStr.StartsWith("{"))
                {
                    category = "json";
                    return($"{item.Id:X8}.json");
                }

                if (header.Length >= 32 && header[0] != 0 && header.Skip(16).Take(16).All(b => b == 0))
                {
                    category = "unknown";
                    return($"{item.Id:X8}.unkAnim");
                }
                category = "";
                return(item.Id.ToString("X8"));
            }

            var ext = result[0];

            switch (ext)
            {
            case "jpg":
            case "jpeg":
            case "png":
            case "gif":
            case "ico":
            case "bmp":
            case "psd":
                category = "image";
                break;

            case "xml":
                category = "xml";
                break;

            case "ktx":
                category = "texture";
                break;

            case "unkModel":
                category = "unknown";
                break;

            default:
                category = "";
                break;
            }

            return($"{item.Id:X8}.{ext}");
        }