Example #1
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;
        }
Example #2
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);
                }
            }
        }
Example #3
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);
                }
            }
        }