Ejemplo n.º 1
0
        public override void Create(Stream output, IEnumerable<Entry> list, ResourceOptions options,
                                     EntryCallback callback)
        {
            var ypf_options = GetOptions<YpfOptions> (options);
            if (null == ypf_options)
                throw new ArgumentException ("Invalid archive creation options", "options");
            if (ypf_options.Key > 0xff)
                throw new InvalidEncryptionScheme (arcStrings.MsgCreationKeyRequired);
            if (0 == ypf_options.Version)
                throw new InvalidFormatException (arcStrings.MsgInvalidVersion);
            var scheme = new YpfScheme {
                SwapTable   = GuessSwapTable (ypf_options.Version),
                Key         = (byte)ypf_options.Key
            };
            int callback_count = 0;
            var encoding = Encodings.cp932.WithFatalFallback();

            ChecksumFunc Checksum = data => Crc32.Compute (data, 0, data.Length);

            uint data_offset = 0x20;
            var file_table = new List<YpfEntry>();
            foreach (var entry in list)
            {
                try
                {
                    string file_name = entry.Name;
                    byte[] name_buf = encoding.GetBytes (file_name);
                    if (name_buf.Length > 0xff)
                        throw new InvalidFileName (entry.Name, arcStrings.MsgFileNameTooLong);
                    uint hash = Checksum (name_buf);
                    byte file_type = GetFileType (ypf_options.Version, file_name);

                    for (int i = 0; i < name_buf.Length; ++i)
                        name_buf[i] = (byte)(name_buf[i] ^ ypf_options.Key);

                    file_table.Add (new YpfEntry {
                        Name = file_name,
                        IndexName = name_buf,
                        NameHash = hash,
                        FileType = file_type,
                        IsPacked = 0 == file_type,
                    });
                    data_offset += (uint)(0x17 + name_buf.Length);
                }
                catch (EncoderFallbackException X)
                {
                    throw new InvalidFileName (entry.Name, arcStrings.MsgIllegalCharacters, X);
                }
            }
            file_table.Sort ((a, b) => a.NameHash.CompareTo (b.NameHash));

            output.Position = data_offset;
            uint current_offset = data_offset;
            foreach (var entry in file_table)
            {
                if (null != callback)
                    callback (callback_count++, entry, arcStrings.MsgAddingFile);

                entry.Offset = current_offset;
                using (var input = File.OpenRead (entry.Name))
                {
                    var file_size = input.Length;
                    if (file_size > uint.MaxValue || current_offset + file_size > uint.MaxValue)
                        throw new FileSizeException();
                    entry.UnpackedSize = (uint)file_size;
                    using (var checked_stream = new CheckedStream (output, new Adler32()))
                    {
                        if (entry.IsPacked)
                        {
                            var start = output.Position;
                            using (var zstream = new ZLibStream (checked_stream, CompressionMode.Compress,
                                                                 CompressionLevel.Level9, true))
                            {
                                input.CopyTo (zstream);
                            }
                            entry.Size = (uint)(output.Position - start);
                        }
                        else
                        {
                            input.CopyTo (checked_stream);
                            entry.Size = entry.UnpackedSize;
                        }
                        checked_stream.Flush();
                        entry.CheckSum = checked_stream.CheckSumValue;
                        current_offset += entry.Size;
                    }
                }
            }

            if (null != callback)
                callback (callback_count++, null, arcStrings.MsgWritingIndex);

            output.Position = 0;
            using (var writer = new BinaryWriter (output, encoding, true))
            {
                writer.Write (Signature);
                writer.Write (ypf_options.Version);
                writer.Write (file_table.Count);
                writer.Write (data_offset);
                writer.BaseStream.Seek (0x20, SeekOrigin.Begin);
                foreach (var entry in file_table)
                {
                    writer.Write (entry.NameHash);
                    byte name_len = (byte)~Parser.DecryptLength (scheme.SwapTable, (byte)entry.IndexName.Length);
                    writer.Write (name_len);
                    writer.Write (entry.IndexName);
                    writer.Write (entry.FileType);
                    writer.Write (entry.IsPacked);
                    writer.Write (entry.UnpackedSize);
                    writer.Write (entry.Size);
                    writer.Write ((uint)entry.Offset);
                    writer.Write (entry.CheckSum);
                }
            }
        }
Ejemplo n.º 2
0
        // files inside archive are aligned to 0x10 boundary.
        // to convert DateTime structure into entry time:
        // entry.FileTime = file_info.CreationTimeUtc.Ticks;
        //
        // last two bytes of archive is CRC16 of the whole file
        public override void Create(Stream output, IEnumerable<Entry> list, ResourceOptions options,
                                     EntryCallback callback)
        {
            const long data_offset = 0x10;
            var encoding = Encodings.cp932.WithFatalFallback();
            int callback_count = 0;

            var output_list = new List<OutputEntry> (list.Count());
            foreach (var entry in list)
            {
                try
                {
                    string name = Path.GetFileNameWithoutExtension (entry.Name);
                    string ext  = Path.GetExtension (entry.Name);
                    byte[] name_buf = new byte[0x15];
                    byte[] ext_buf  = new byte[3];
                    encoding.GetBytes (name, 0, name.Length, name_buf, 0);
                    if (!string.IsNullOrEmpty (ext))
                    {
                        ext = ext.TrimStart ('.').ToLowerInvariant();
                        encoding.GetBytes (ext, 0, ext.Length, ext_buf, 0);
                    }
                    var out_entry = new OutputEntry
                    {
                        Name      = entry.Name,
                        IndexName = name_buf,
                        IndexExt  = ext_buf,
                    };
                    output_list.Add (out_entry);
                }
                catch (EncoderFallbackException X)
                {
                    throw new InvalidFileName (entry.Name, arcStrings.MsgIllegalCharacters, X);
                }
                catch (ArgumentException X)
                {
                    throw new InvalidFileName (entry.Name, arcStrings.MsgFileNameTooLong, X);
                }
            }

            if (null != callback)
                callback (output_list.Count+2, null, null);

            output.Position = data_offset;
            uint current_offset = 0;
            foreach (var entry in output_list)
            {
                if (null != callback)
                    callback (callback_count++, entry, arcStrings.MsgAddingFile);

                entry.FileTime = File.GetCreationTimeUtc (entry.Name).Ticks;
                entry.Offset = current_offset;
                entry.CompressionType = 0;
                using (var input = File.OpenRead (entry.Name))
                {
                    var size = input.Length;
                    if (size > uint.MaxValue || current_offset + size + 0x0f > uint.MaxValue)
                        throw new FileSizeException();
                    entry.Size = (uint)size;
                    entry.UnpackedSize = entry.Size;
                    using (var checked_stream = new CheckedStream (output, new Crc16()))
                    {
                        input.CopyTo (checked_stream);
                        entry.HasCheckSum = true;
                        entry.CheckSum = (ushort)checked_stream.CheckSumValue;
                    }
                    current_offset += (uint)size + 0x0f;
                    current_offset &= ~0x0fu;
                    output.Position = data_offset + current_offset;
                }
            }

            if (null != callback)
                callback (callback_count++, null, arcStrings.MsgUpdatingIndex);

            // at last, go back to directory and write offset/sizes
            uint index_offset = current_offset;
            using (var index = new BinaryWriter (output, encoding, true))
            {
                foreach (var entry in output_list)
                {
                    index.Write (entry.IndexName);
                    index.Write (entry.IndexExt);
                    index.Write ((uint)entry.Offset);
                    index.Write (entry.UnpackedSize);
                    index.Write (entry.Size);
                    index.Write (entry.CompressionType);
                    index.Write (entry.HasCheckSum);
                    index.Write (entry.CheckSum);
                    index.Write (entry.FileTime);
                }
                index.BaseStream.Position = 0;
                index.Write (Signature);
                index.Write (0x03006b63);
                index.Write (index_offset);
                index.Write (output_list.Count);

                if (null != callback)
                    callback (callback_count++, null, arcStrings.MsgCalculatingChecksum);

                output.Position = 0;
                using (var checked_stream = new CheckedStream (output, new Crc16()))
                {
                    checked_stream.CopyTo (Stream.Null);
                    index.Write ((ushort)checked_stream.CheckSumValue);
                }
            }
        }
Ejemplo n.º 3
0
 private void InitCompress(Stream stream, CompressionLevel level)
 {
     int flevel = (int)level;
     System.IO.Compression.CompressionLevel sys_level;
     if (0 == flevel)
     {
         sys_level = System.IO.Compression.CompressionLevel.NoCompression;
     }
     else if (flevel > 5)
     {
         sys_level = System.IO.Compression.CompressionLevel.Optimal;
         flevel = 3;
     }
     else
     {
         sys_level = System.IO.Compression.CompressionLevel.Fastest;
         flevel = 1;
     }
     int cmf = 0x7800 | flevel << 6;
     cmf = ((cmf + 30) / 31) * 31;
     stream.WriteByte ((byte)(cmf >> 8));
     stream.WriteByte ((byte)cmf);
     m_stream = new DeflateStream (stream, sys_level, true);
     m_adler  = new CheckedStream (m_stream, new Adler32());
     m_writing = true;
 }