Ejemplo n.º 1
0
        YpfScheme QueryEncryptionScheme(string arc_name, uint version)
        {
            var title = FormatCatalog.Instance.LookupGame(arc_name);

            if (string.IsNullOrEmpty(title))
            {
                title = FormatCatalog.Instance.LookupGame(arc_name, @"..\*.exe");
            }
            YpfScheme scheme;

            if (!string.IsNullOrEmpty(title) && KnownSchemes.TryGetValue(title, out scheme))
            {
                return(scheme);
            }
            var options = Query <YpfOptions> (arcStrings.YPFNotice);

            if (!KnownSchemes.TryGetValue(options.Scheme, out scheme) || null == scheme)
            {
                scheme = new YpfScheme {
                    SwapTable       = GuessSwapTable(version),
                    GuessKey        = true,
                    ExtraHeaderSize = version >= 0x1D9 ? 4u : 0u,
                }
            }
            ;
            return(scheme);
        }

        delegate uint ChecksumFunc(byte[] data);
Ejemplo n.º 2
0
        YpfScheme QueryEncryptionScheme(uint version)
        {
            var       options = Query <YpfOptions> (arcStrings.YPFNotice);
            YpfScheme scheme;

            if (!KnownSchemes.TryGetValue(options.Scheme, out scheme) || null == scheme)
            {
                scheme = new YpfScheme {
                    SwapTable       = GuessSwapTable(version),
                    GuessKey        = true,
                    ExtraHeaderSize = 0x1F4 == version ? 4u : 0u,
                }
            }
            ;
            return(scheme);
        }

        delegate uint ChecksumFunc(byte[] data);
Ejemplo n.º 3
0
            // int32-name_checksum, byte-name_count, *-name, byte-file_type
            // byte-pack_flag, int32-size, int32-packed_size, int32-offset, int32-file_checksum

            public List <Entry> ScanDir(YpfScheme scheme)
            {
                uint dir_offset    = 0x20;
                uint dir_remaining = m_dir_size;
                var  dir           = new List <Entry> ((int)m_count);
                byte key           = scheme.Key;
                bool guess_key     = scheme.GuessKey;
                uint extra_size    = 0x12 + scheme.ExtraHeaderSize;

                for (uint num = 0; num < m_count; ++num)
                {
                    if (dir_remaining < 5 + extra_size)
                    {
                        return(null);
                    }
                    dir_remaining -= 5 + extra_size;

                    uint name_size = DecryptLength(scheme.SwapTable, (byte)(m_file.View.ReadByte(dir_offset + 4) ^ 0xff));
                    if (name_size > dir_remaining)
                    {
                        return(null);
                    }
                    dir_remaining -= name_size;
                    dir_offset    += 5;
                    if (0 == name_size)
                    {
                        return(null);
                    }
                    byte[] raw_name = m_file.View.ReadBytes(dir_offset, name_size);
                    dir_offset += name_size;
                    if (guess_key)
                    {
                        if (name_size < 4)
                        {
                            return(null);
                        }
                        // assume filename contains '.' and 3-characters extension.
                        key       = (byte)(raw_name[name_size - 4] ^ '.');
                        guess_key = false;
                    }
                    for (uint i = 0; i < name_size; ++i)
                    {
                        raw_name[i] ^= key;
                    }
                    string name = Encodings.cp932.GetString(raw_name);
                    // 0x0F7:               0-ybn, 1-bmp, 2-png, 3-jpg, 4-gif, 5-avi, 6-wav, 7-ogg, 8-psd
                    // 0x122, 0x12C, 0x196: 0-ybn, 1-bmp, 2-png, 3-jpg, 4-gif, 5-wav, 6-ogg, 7-psd
                    // 0x1F4:               0-ybn, 1-bmp, 2-png, 3-jpg, 4-gif, 5-wav, 6-ogg, 7-psd, 8-ycg 9-psb
                    int type_id = m_file.View.ReadByte(dir_offset);
                    var entry   = FormatCatalog.Instance.Create <PackedEntry> (name);
                    if (string.IsNullOrEmpty(entry.Type))
                    {
                        switch (type_id)
                        {
                        case 0:
                            entry.Type = "script";
                            break;

                        case 1:
                        case 2:
                        case 3:
                        case 4:
                        case 8:
                            entry.Type = "image";
                            break;

                        case 5:
                            entry.Type = 0xf7 == m_version ? "video" : "audio";
                            break;

                        case 6:
                            entry.Type = "audio";
                            break;

                        case 7:
                            entry.Type = 0xf7 == m_version ? "audio" : "image";
                            break;
                        }
                    }
                    entry.IsPacked     = 0 != m_file.View.ReadByte(dir_offset + 1);
                    entry.UnpackedSize = m_file.View.ReadUInt32(dir_offset + 2);
                    entry.Size         = m_file.View.ReadUInt32(dir_offset + 6);
                    entry.Offset       = m_file.View.ReadUInt32(dir_offset + 10);
                    if (entry.CheckPlacement(m_file.MaxOffset))
                    {
                        dir.Add(entry);
                    }
                    dir_offset += extra_size;
                }
                return(dir);
            }
Ejemplo n.º 4
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.º 5
0
            // int32-name_checksum, byte-name_count, *-name, byte-file_type
            // byte-pack_flag, int32-size, int32-packed_size, int32-offset, int32-file_checksum
            public List<Entry> ScanDir(YpfScheme scheme)
            {
                uint dir_offset = 0x20;
                uint dir_remaining = m_dir_size;
                var dir = new List<Entry> ((int)m_count);
                byte key = scheme.Key;
                bool guess_key = scheme.GuessKey;
                uint extra_size = 0x12 + scheme.ExtraHeaderSize;
                for (uint num = 0; num < m_count; ++num)
                {
                    if (dir_remaining < 5+extra_size)
                        return null;
                    dir_remaining -= 5+extra_size;

                    uint name_size = DecryptLength (scheme.SwapTable, (byte)(m_file.View.ReadByte (dir_offset+4) ^ 0xff));
                    if (name_size > dir_remaining)
                        return null;
                    dir_remaining -= name_size;
                    dir_offset += 5;
                    if (0 == name_size)
                        return null;
                    byte[] raw_name = m_file.View.ReadBytes (dir_offset, name_size);
                    dir_offset += name_size;
                    if (guess_key)
                    {
                        if (name_size < 4)
                            return null;
                        // assume filename contains '.' and 3-characters extension.
                        key = (byte)(raw_name[name_size-4] ^ '.');
                        guess_key = false;
                    }
                    for (uint i = 0; i < name_size; ++i)
                    {
                        raw_name[i] ^= key;
                    }
                    string name = Encodings.cp932.GetString (raw_name);
                    // 0x0F7:               0-ybn, 1-bmp, 2-png, 3-jpg, 4-gif, 5-avi, 6-wav, 7-ogg, 8-psd
                    // 0x122, 0x12C, 0x196: 0-ybn, 1-bmp, 2-png, 3-jpg, 4-gif, 5-wav, 6-ogg, 7-psd
                    // 0x1F4:               0-ybn, 1-bmp, 2-png, 3-jpg, 4-gif, 5-wav, 6-ogg, 7-psd, 8-ycg 9-psb
                    int type_id = m_file.View.ReadByte (dir_offset);
                    var entry = FormatCatalog.Instance.Create<PackedEntry> (name);
                    if (string.IsNullOrEmpty (entry.Type))
                    {
                        switch (type_id)
                        {
                        case 0:
                            entry.Type = "script";
                            break;
                        case 1: case 2: case 3: case 4: case 8:
                            entry.Type = "image";
                            break;
                        case 5:
                            entry.Type = 0xf7 == m_version ? "video" : "audio";
                            break;
                        case 6:
                            entry.Type = "audio";
                            break;
                        case 7:
                            entry.Type = 0xf7 == m_version ? "audio" : "image";
                            break;
                        }
                    }
                    entry.IsPacked      = 0 != m_file.View.ReadByte (dir_offset+1);
                    entry.UnpackedSize  = m_file.View.ReadUInt32 (dir_offset+2);
                    entry.Size          = m_file.View.ReadUInt32 (dir_offset+6);
                    entry.Offset        = m_file.View.ReadUInt32 (dir_offset+10);
                    if (entry.CheckPlacement (m_file.MaxOffset))
                        dir.Add (entry);
                    dir_offset += extra_size;
                }
                return dir;
            }
Ejemplo n.º 6
0
 YpfScheme QueryEncryptionScheme(uint version)
 {
     var options = Query<YpfOptions> (arcStrings.YPFNotice);
     YpfScheme scheme;
     if (!KnownSchemes.TryGetValue (options.Scheme, out scheme) || null == scheme)
         scheme = new YpfScheme {
             SwapTable   = GuessSwapTable (version),
             GuessKey    = true,
             ExtraHeaderSize = 0x1F4 == version || 0x1E1 == version ? 4u : 0u,
         };
     return scheme;
 }
Ejemplo n.º 7
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);
                }
            }
        }