Example #1
0
        public override ArcFile TryOpen(ArcView file)
        {
            int          version     = '2' == file.View.ReadByte(3) ? 2 : 1;
            long         base_offset = 0;
            List <Entry> dir         = null;

            byte[] names = null;
            using (var stream = file.CreateStream())
            {
                Func <IBinaryStream, long> read_long;
                if (2 == version)
                {
                    read_long = s => s.ReadInt64();
                }
                else
                {
                    read_long = s => s.ReadUInt32();
                }

                stream.Position = 4;
                if (file.MaxOffset != read_long(stream))
                {
                    return(null);
                }
                for (;;)
                {
                    long section_start = stream.Position;
                    var  id_bytes      = stream.ReadBytes(4);
                    if (0 == id_bytes.Length)
                    {
                        break;
                    }
                    var id           = new AsciiString(id_bytes);
                    var section_size = read_long(stream);
                    var header_size  = read_long(stream);
                    if (section_size < 4 || header_size > section_size)
                    {
                        return(null);
                    }
                    var content_pos = section_start + header_size;
                    if ("cLST" == id)
                    {
                        stream.ReadUInt32();
                        int count = stream.ReadInt32();
                        if (!IsSaneCount(count))
                        {
                            return(null);
                        }
                        uint key = stream.ReadUInt32();
                        stream.Position = content_pos;
                        var clst = stream.ReadBytes((int)(section_size - header_size));
                        Decrypt(clst, key);
                        dir = new List <Entry> (count);
                        using (var index = new BinMemoryStream(clst))
                        {
                            for (int i = 0; i < count; ++i)
                            {
                                var entry = new PkEntry {
                                    NameOffset = (int)read_long(index),
                                    Offset     = (long)read_long(index),
                                    Size       = (uint)read_long(index),
                                };
                                dir.Add(entry);
                            }
                        }
                    }
                    else if ("cNAM" == id)
                    {
                        if (null == dir)
                        {
                            return(null);
                        }
                        stream.ReadUInt32();
                        uint key = stream.ReadUInt32();
                        stream.Position = content_pos;
                        names           = stream.ReadBytes((int)(section_size - header_size));
                        Decrypt(names, key);
                    }
                    else if ("cDAT" == id)
                    {
                        base_offset = content_pos;
                    }
                    stream.Position = section_start + section_size;
                }
            }
            if (null == dir || null == names || 0 == base_offset)
            {
                return(null);
            }

            foreach (PkEntry entry in dir)
            {
                entry.Offset += base_offset;
                if (!entry.CheckPlacement(file.MaxOffset))
                {
                    return(null);
                }
                var name = Binary.GetCString(names, entry.NameOffset);
                entry.Name = name;
                if (name.HasExtension(".px"))
                {
                    entry.Type = "audio";
                }
                else
                {
                    entry.Type = FormatCatalog.Instance.GetTypeFromName(name);
                }
            }
            return(new ArcFile(file, this, dir));
        }
Example #2
0
        public override ArcFile TryOpen(ArcView file)
        {
            if (file.MaxOffset != file.View.ReadUInt32(4))
            {
                return(null);
            }

            long         base_offset = 0;
            List <Entry> dir         = null;
            bool         got_names   = false;
            long         offset      = 8;

            while (offset < file.MaxOffset)
            {
                var  id           = new AsciiString(file.View.ReadBytes(offset, 4));
                uint section_size = file.View.ReadUInt32(offset + 4);
                if (0 == section_size)
                {
                    return(null);
                }
                uint header_size = file.View.ReadUInt32(offset + 8);
                if ("cLST" == id)
                {
                    int count = file.View.ReadInt32(offset + 0x10);
                    if (!IsSaneCount(count))
                    {
                        return(null);
                    }
                    uint key  = file.View.ReadUInt32(offset + 0x14);
                    var  clst = file.View.ReadBytes(offset + header_size, section_size - header_size);
                    Decrypt(clst, key);
                    dir = new List <Entry> (count);
                    int index_offset = 0;
                    for (int i = 0; i < count; ++i)
                    {
                        var entry = new PkEntry {
                            NameOffset = LittleEndian.ToInt32(clst, index_offset),
                            Offset     = LittleEndian.ToUInt32(clst, index_offset + 4),
                            Size       = LittleEndian.ToUInt32(clst, index_offset + 8),
                        };
                        dir.Add(entry);
                        index_offset += 12;
                    }
                }
                else if ("cNAM" == id)
                {
                    if (null == dir)
                    {
                        return(null);
                    }
                    uint key  = file.View.ReadUInt32(offset + 0x10);
                    var  cnam = file.View.ReadBytes(offset + header_size, section_size - header_size);
                    Decrypt(cnam, key);
                    foreach (PkEntry entry in dir)
                    {
                        var name = Binary.GetCString(cnam, entry.NameOffset);
                        entry.Name = name;
                        if (name.HasExtension(".px"))
                        {
                            entry.Type = "audio";
                        }
                        else
                        {
                            entry.Type = FormatCatalog.Instance.GetTypeFromName(name);
                        }
                    }
                    got_names = true;
                }
                else if ("cDAT" == id)
                {
                    base_offset = offset + header_size;
                }
                offset += section_size;
            }
            if (null == dir || !got_names || 0 == base_offset)
            {
                return(null);
            }

            foreach (var entry in dir)
            {
                entry.Offset += base_offset;
                if (!entry.CheckPlacement(file.MaxOffset))
                {
                    return(null);
                }
            }
            return(new ArcFile(file, this, dir));
        }