Example #1
0
        public override ArcFile TryOpen(ArcView file)
        {
            int index_size = file.View.ReadInt32(0);

            if (index_size < 0x14 || index_size >= file.MaxOffset || index_size > 0xffffff)
            {
                return(null);
            }

            var stream = new SteinsGateEncryptedStream(file, 4, (uint)index_size);

            using (var header = new BinaryReader(stream))
            {
                int entry_count = header.ReadInt32();
                if (!IsSaneCount(entry_count))
                {
                    return(null);
                }
                index_size -= 4;
                int average_entry_size = index_size / entry_count;
                if (average_entry_size < 0x11)
                {
                    return(null);
                }

                var dir = new List <Entry> (entry_count);
                for (int i = 0; i < entry_count; ++i)
                {
                    int name_length = header.ReadInt32();
                    if (name_length + 0x10 > index_size)
                    {
                        return(null);
                    }
                    byte[]   name_raw = header.ReadBytes(name_length);
                    Encoding enc      = GuessEncoding(name_raw);
                    string   filename = enc.GetString(name_raw);

                    var entry = FormatCatalog.Instance.Create <Entry> (filename);
                    entry.Size   = header.ReadUInt32();
                    entry.Offset = header.ReadInt64();
                    if (!entry.CheckPlacement(file.MaxOffset))
                    {
                        return(null);
                    }
                    dir.Add(entry);

                    index_size -= name_length + 0x10;
                }
                return(new ArcFile(file, this, dir));
            }
        }
Example #2
0
        public override void Create(Stream output, IEnumerable <Entry> list, ResourceOptions options,
                                    EntryCallback callback)
        {
            var      sg_options     = GetOptions <SteinsGateOptions> (options);
            Encoding encoding       = sg_options.FileNameEncoding.WithFatalFallback();
            long     start_pos      = output.Position;
            int      callback_count = 0;

            uint index_size      = 4;
            var  real_entry_list = new List <RawEntry> (list.Count());
            var  used_names      = new HashSet <string>();

            foreach (var entry in list)
            {
                string name = entry.Name.Replace(@"\", "/");
                if (!used_names.Add(name))  // duplicate name
                {
                    continue;
                }
                var header_entry = new RawEntry {
                    Name = entry.Name
                };
                try
                {
                    header_entry.IndexName = encoding.GetBytes(name);
                }
                catch (EncoderFallbackException X)
                {
                    throw new InvalidFileName(entry.Name, arcStrings.MsgIllegalCharacters, X);
                }
                index_size += (uint)header_entry.IndexName.Length + 16;
                real_entry_list.Add(header_entry);
            }
            output.Seek(4 + index_size, SeekOrigin.Current);
            foreach (var entry in real_entry_list)
            {
                using (var input = File.Open(entry.Name, FileMode.Open, FileAccess.Read))
                {
                    var file_size = input.Length;
                    if (file_size > uint.MaxValue)
                    {
                        throw new FileSizeException();
                    }
                    entry.Offset = output.Position;
                    entry.Size   = (uint)file_size;
                    if (null != callback)
                    {
                        callback(callback_count++, entry, arcStrings.MsgAddingFile);
                    }
                    using (var stream = new SteinsGateEncryptedStream(output))
                        input.CopyTo(stream);
                }
            }
            if (null != callback)
            {
                callback(callback_count++, null, arcStrings.MsgWritingIndex);
            }
            output.Position = start_pos;
            output.WriteByte((byte)(index_size & 0xff));
            output.WriteByte((byte)((index_size >> 8) & 0xff));
            output.WriteByte((byte)((index_size >> 16) & 0xff));
            output.WriteByte((byte)((index_size >> 24) & 0xff));
            var encrypted_stream = new SteinsGateEncryptedStream(output);

            using (var header = new BinaryWriter(encrypted_stream))
            {
                header.Write(real_entry_list.Count);
                foreach (var entry in real_entry_list)
                {
                    header.Write(entry.IndexName.Length);
                    header.Write(entry.IndexName);
                    header.Write((uint)entry.Size);
                    header.Write((long)entry.Offset);
                }
            }
        }