예제 #1
0
        IDictionary <string, string> ReadNameMap(ArcFile file, Arc3Entry entry)
        {
            byte[] table = new byte[entry.UnpackedSize];
            using (var input = OpenEntry(file, entry))
            {
                input.Read(table, 0, table.Length);
            }
            int count = LittleEndian.ToInt32(table, 0);

            if (!IsSaneCount(count))
            {
                throw new InvalidFormatException("Invalid longinfo map format");
            }
            var map       = new Dictionary <string, string> (count);
            int index_pos = 4;
            int names_pos = index_pos + count * 8;

            for (int i = 0; i < count; ++i)
            {
                int key_pos   = names_pos + LittleEndian.ToInt32(table, index_pos);
                int value_pos = names_pos + LittleEndian.ToInt32(table, index_pos + 4);
                index_pos += 8;
                string key = Binary.GetCString(table, key_pos, table.Length - key_pos);
                map[key] = Binary.GetCString(table, value_pos, table.Length - value_pos);
            }
            return(map);
        }
예제 #2
0
        public override ArcFile TryOpen(ArcView file)
        {
            int  version      = Binary.BigEndian(file.View.ReadInt32(4));
            uint cluster_size = Binary.BigEndian(file.View.ReadUInt32(0x08));
            uint base_offset  = Binary.BigEndian(file.View.ReadUInt32(0x0C));
            uint index_offset = Binary.BigEndian(file.View.ReadUInt32(0x18));
            uint index_size   = Binary.BigEndian(file.View.ReadUInt32(0x1C));

            if (0 == index_size)
            {
                return(null);
            }

            bool new_name       = false;
            var  dir            = new List <Entry>();
            var  name_buffer    = new byte[0x10];
            long current_offset = (long)index_offset * cluster_size;
            long index_end      = current_offset + index_size;

            if (index_end > file.MaxOffset)
            {
                return(null);
            }

            // --- read index ---

            uint      last_entry_offset   = 0x7FFFFFFF;
            int       current_name_length = 0;
            Arc3Entry prev_entry          = null;
            Arc3Entry long_info           = null;

            while (current_offset < index_end)
            {
                byte name_length = file.View.ReadByte(current_offset++);
                int  name_offset = name_length >> 4;
                name_length &= 0xF;
                if (name_offset != 0xF)
                {
                    file.View.Read(current_offset, name_buffer, name_offset, name_length);
                    current_offset     += name_length;
                    current_name_length = name_offset + name_length;
                }
                else if (0xF == name_length)
                {
                    name_buffer[current_name_length - 1]++;
                }
                else if (name_length != 0)
                {
                    file.View.Read(current_offset, name_buffer, 0, name_length);
                    current_offset     += name_length;
                    current_name_length = name_length;
                    new_name            = true;
                }
                else
                {
                    uint offset = BigEndian24(file.View.ReadUInt32(current_offset));
                    offset = (uint)Math.Abs((int)(offset - index_offset));
                    if (offset < last_entry_offset)
                    {
                        last_entry_offset = offset;
                    }

                    if (prev_entry != null)
                    {
                        prev_entry.Offset = (long)(last_entry_offset + base_offset) * cluster_size;
                    }
                }
                last_entry_offset = BigEndian24(file.View.ReadUInt32(current_offset));
                current_offset   += 3;
                if (new_name)
                {
                    current_offset += 3;
                    new_name        = false;
                }
                string name;
                if (current_name_length > 3)
                {
                    name = Encodings.cp932.GetString(name_buffer, 3, current_name_length - 3);
                    string ext = Encodings.cp932.GetString(name_buffer, 0, 3);
                    name = name + '.' + ext;
                }
                else
                {
                    name = Encodings.cp932.GetString(name_buffer, 0, current_name_length);
                }

                var entry = new Arc3Entry {
                    Name = name
                };
                entry.Offset = (long)(last_entry_offset + base_offset) * cluster_size;
                if (entry.Offset >= file.MaxOffset)
                {
                    return(null);
                }
                dir.Add(entry);
                prev_entry = entry;
                if (null == long_info && "longinfo.$$$" == name)
                {
                    long_info = entry;
                }
            }

            // --- read attributes ---

            foreach (Arc3Entry entry in dir)
            {
                entry.Size         = Binary.BigEndian(file.View.ReadUInt32(entry.Offset + 8));
                entry.Flags        = Binary.BigEndian(file.View.ReadUInt32(entry.Offset + 0x14));
                entry.UnpackedSize = entry.Size;
                entry.IsEncrypted  = 2 == entry.Flags;
                entry.Offset      += 0x20;
                uint signature = file.View.ReadUInt32(entry.Offset);
                if (entry.IsEncrypted)
                {
                    signature = ~signature;
                }
                entry.IsPacked = (signature & 0xFFFF) == 0x7A6C; // 'lz'
                if (entry.IsPacked)
                {
                    entry.UnpackedSize = Binary.BigEndian(file.View.ReadUInt32(entry.Offset + 2));
                    if (entry.IsEncrypted)
                    {
                        entry.UnpackedSize ^= 0xFFFFFFFF;
                    }
                    entry.Offset += 6;
                    entry.Size   -= 6;
                }
                else
                {
                    var res = AutoEntry.DetectFileType(signature);
                    if (res != null)
                    {
                        entry.Type = res.Type;
                    }
                }
            }
            var arc = new ArcFile(file, this, dir);

            try // read long filenames stored within 'longinfo.$$$', if available
            {
                if (version > 1 && long_info != null)
                {
                    var name_map = ReadNameMap(arc, long_info);
                    foreach (var entry in dir)
                    {
                        string orig_name;
                        if (name_map.TryGetValue(entry.Name, out orig_name))
                        {
                            entry.Name = orig_name;
                        }
                    }
                }
            }
            catch { /* ignore 'longinfo.$$$' read errors */ }

            foreach (var entry in dir.Where(e => e.Name.Contains('*')))
            {
                entry.Name = entry.Name.Replace('*', '*');
            }
            return(arc);
        }