Beispiel #1
0
        public override ImageMetaData ReadMetaData(IBinaryStream stream)
        {
            var key = new byte[0x10];

            stream.Position = 4;
            if (key.Length != stream.Read(key, 0, key.Length))
            {
                return(null);
            }
            using (var enc = new InputProxyStream(stream.AsStream, true))
                using (var crypto = new InputCryptoStream(enc, new GaxTransform(key)))
                    using (var input = new BinaryStream(crypto, stream.Name))
                    {
                        var info = Png.ReadMetaData(input);
                        if (null == info)
                        {
                            return(null);
                        }
                        return(new GaxMetaData
                        {
                            OffsetX = info.OffsetX,
                            OffsetY = info.OffsetY,
                            Width = info.Width,
                            Height = info.Height,
                            BPP = info.BPP,
                            Key = key,
                        });
                    }
        }
Beispiel #2
0
        public override Stream OpenEntry(ArcFile arc, Entry entry)
        {
            var larc = arc as LunaArchive;

            if (null == arc || !arc.File.View.AsciiEqual(entry.Offset, "LZSS"))
            {
                return(base.OpenEntry(arc, entry));
            }

            uint   unpacked_size = arc.File.View.ReadUInt32(entry.Offset + 4);
            Stream input         = arc.File.CreateStream(entry.Offset + 8, entry.Size - 8);

            if (larc.Key != null)
            {
                var bf = new Blowfish(larc.Key);
                input = new InputCryptoStream(input, bf.CreateDecryptor());
                return(new LimitStream(input, unpacked_size));
            }
            else
            {
                var lz = new LzssStream(input);
                lz.Config.FrameInitPos = 0xFF0;
                return(lz);
            }
        }
Beispiel #3
0
 public override ImageData Read(IBinaryStream stream, ImageMetaData info)
 {
     using (var proxy = new ProxyStream(stream.AsStream, true))
         using (var crypt = new InputCryptoStream(proxy, new TigTransform()))
             using (var input = new BinaryStream(crypt, stream.Name))
                 return(base.Read(input, info));
 }
Beispiel #4
0
        void UnpackStream(byte[] output, int packed_size)
        {
            if (0 == packed_size)
            {
                m_input.Read(output, 0, output.Length);
                return;
            }
            var input     = m_input.AsStream;
            var input_pos = m_input.Position;

            if (m_info.IsEncrypted)
            {
                input = new StreamRegion(input, input_pos, packed_size, true);
                input = new InputCryptoStream(input, new SjTransform(m_info.Key));
            }
            try
            {
                UnpackRle(input, output);
            }
            finally
            {
                if (input != m_input.AsStream)
                {
                    input.Dispose();
                }
                m_input.Position = input_pos + packed_size;
            }
        }
Beispiel #5
0
 public override ImageMetaData ReadMetaData(IBinaryStream stream)
 {
     using (var sha = SHA1.Create())
     {
         var key = sha.ComputeHash(KnownKey).Take(16).ToArray();
         using (var proxy = new InputProxyStream(stream.AsStream, true))
             using (var crypto = new InputCryptoStream(proxy, new Rc4Transform(key)))
                 using (var input = new BinaryStream(crypto, stream.Name))
                 {
                     var info = base.ReadMetaData(input);
                     if (null == info)
                     {
                         return(null);
                     }
                     return(new Rc4PngMetaData
                     {
                         Width = info.Width,
                         Height = info.Height,
                         OffsetX = info.OffsetX,
                         OffsetY = info.OffsetY,
                         BPP = info.BPP,
                         Key = key,
                     });
                 }
     }
 }
Beispiel #6
0
        public ImageData Unpack()
        {
            Stream input = new StreamRegion(m_input.AsStream, 0x18, m_info.PackedLength, true);

            if (m_info.IsEncrypted)
            {
                input = new InputCryptoStream(input, new SjTransform(m_info.Key));
            }
            using (input = new LzssStream(input))
            {
                var header = new byte[0x28];
                input.Read(header, 0, header.Length);
                if (8 == m_info.BPP)
                {
                    Palette = ImageFormat.ReadPalette(input);
                }
                input.Read(m_output, 0, m_output.Length);
            }
            if (m_info.AlphaLength > 0 && m_info.BPP == 8)
            {
                m_input.Position = 0x18 + m_info.PackedLength;
                var alpha = new byte[m_info.AlphaLength];
                using (var lzss = new LzssStream(m_input.AsStream, LzssMode.Decompress, true))
                    lzss.Read(alpha, 0, alpha.Length);
                return(ApplyAlpha(alpha));
            }
            return(ImageData.CreateFlipped(m_info, Format, Palette, m_output, Stride));
        }
Beispiel #7
0
        public override ImageData Read(IBinaryStream stream, ImageMetaData info)
        {
            var meta = (GaxMetaData)info;

            using (var enc = new StreamRegion(stream.AsStream, 0x14, true))
                using (var crypto = new InputCryptoStream(enc, new GaxTransform(meta.Key)))
                    using (var input = new BinaryStream(crypto, stream.Name))
                        return(Png.Read(input, info));
        }
Beispiel #8
0
        public override ImageData Read(IBinaryStream stream, ImageMetaData info)
        {
            var rc4 = (Rc4PngMetaData)info;

            using (var sha = SHA1.Create())
                using (var proxy = new InputProxyStream(stream.AsStream, true))
                    using (var crypto = new InputCryptoStream(proxy, new Rc4Transform(rc4.Key)))
                        using (var input = new BinaryStream(crypto, stream.Name))
                            return(base.Read(input, info));
        }
Beispiel #9
0
        internal IBinaryStream OpenEncrypted(IBinaryStream stream, bool seekable = false)
        {
            Stream input = new ProxyStream(stream.AsStream, true);

            input = new InputCryptoStream(input, new TigTransform());
            if (seekable)
            {
                input = new SeekableStream(input);
            }
            return(new BinaryStream(input, stream.Name));
        }
Beispiel #10
0
        public override SoundInput TryOpen(IBinaryStream file)
        {
            uint   key   = file.Signature ^ 0x46464952u;
            Stream input = new InputCryptoStream(file.AsStream, new Ags32Transform(key));

            input = new SeekableStream(input);
            var header = new byte[12];

            input.Read(header, 0, 12);
            if (!header.AsciiEqual(8, "WAVE"))
            {
                return(null);
            }
            input.Position = 0;
            return(new WaveInput(input));
        }
Beispiel #11
0
            bool ReadV1(Stream input, int entry_size)
            {
                // NOTE CryptoStream will close an input stream
                using (var proxy = new InputProxyStream(input, true))
                    using (var xored = new InputCryptoStream(proxy, new NotTransform()))
                        using (var lzss = new LzssStream(xored))
                            if (m_index.Length != lzss.Read(m_index, 0, m_index.Length))
                            {
                                return(false);
                            }

                int index_offset = Array.IndexOf <byte> (m_index, 0);

                if (-1 == index_offset || 0 == index_offset)
                {
                    return(false);
                }
                Password = m_index.Take(index_offset++).ToArray();
                long base_offset = 0x20 + m_packed_size;

                for (int i = 0; i < m_count; ++i)
                {
                    var entry = new PackedEntry();
                    entry.Offset = LittleEndian.ToUInt32(m_index, index_offset) + base_offset;
                    entry.Size   = LittleEndian.ToUInt32(m_index, index_offset + 4);
                    if (!entry.CheckPlacement(m_file.MaxOffset))
                    {
                        return(false);
                    }
                    entry.UnpackedSize = LittleEndian.ToUInt32(m_index, index_offset + 8);
                    entry.IsPacked     = entry.UnpackedSize != 0;
                    if (!entry.IsPacked)
                    {
                        entry.UnpackedSize = entry.Size;
                    }
                    int name_len = LittleEndian.ToInt32(m_index, index_offset + 0xC);
                    if (name_len <= 0 || name_len > 0x100)
                    {
                        return(false);
                    }
                    entry.Name = Encodings.cp932.GetString(m_index, index_offset + entry_size, name_len);
                    entry.Type = FormatCatalog.Instance.GetTypeFromName(entry.Name);
                    m_dir.Value.Add(entry);
                    index_offset += entry_size + name_len;
                }
                return(true);
            }
Beispiel #12
0
        internal Stream OpenEncryptedEntry(AgsiArchive arc, AgsiEntry entry)
        {
            uint enc_size = entry.Size;

            if (enc_size > 1024)
            {
                enc_size = 1032;
            }
            using (var des = DES.Create())
            {
                des.Key     = arc.Key;
                des.Mode    = CipherMode.ECB;
                des.Padding = PaddingMode.Zeros;
                using (var enc = arc.File.CreateStream(entry.Offset, enc_size))
                    using (var dec = new InputCryptoStream(enc, des.CreateDecryptor()))
                    {
                        var output = new byte[enc_size];
                        dec.Read(output, 0, output.Length);
                        int header_size;
                        if (!entry.IsSpecial)
                        {
                            header_size = output.ToInt32(output.Length - 4);
                            if (header_size > entry.UnpackedSize)
                            {
                                throw new InvalidEncryptionScheme();
                            }
                        }
                        else
                        {
                            header_size = (int)entry.UnpackedSize;
                        }
                        if (!entry.IsSpecial && entry.Size > enc_size)
                        {
                            var header = new byte[header_size];
                            Buffer.BlockCopy(output, 0, header, 0, header_size);
                            var input = arc.File.CreateStream(entry.Offset + enc_size, entry.Size - enc_size);
                            return(new PrefixStream(header, input));
                        }
                        else
                        {
                            return(new BinMemoryStream(output, 0, header_size, entry.Name));
                        }
                    }
            }
        }
Beispiel #13
0
 bool ReadBlock()
 {
     if (m_position >= m_length)
     {
         return(false);
     }
     m_block_start  = m_position & ~0xFFFL;
     m_block_length = m_view.Read(m_block_start, m_block, 0, 0x1000);
     if (m_block_length != 0x1000)
     {
         return(false);
     }
     using (var decryptor = m_encryption.CreateDecryptor((int)(m_block_start >> 12)))
         using (var enc = new BinMemoryStream(m_block))
             using (var dec = new InputCryptoStream(enc, decryptor))
                 dec.Read(m_block, 0, m_block_length);
     return(true);
 }
Beispiel #14
0
 static byte[] CzDecryptData(byte[] data)
 {
     int padded_size = data.Length - 5;
     int original_size = padded_size - (data[padded_size+1] ^ data[padded_size]);
     uint iv_seed = data.ToUInt32 (padded_size+1) ^ CzIvSeed;
     using (var aes = Aes.Create())
     {
         aes.Mode = CipherMode.CBC;
         aes.Padding = PaddingMode.Zeros;
         aes.Key = CzDefaultKey;
         aes.IV = CzCreateIV (iv_seed);
         using (var enc = new MemoryStream (data, 0, padded_size))
         using (var dec = new InputCryptoStream (enc, aes.CreateDecryptor()))
         {
             var original = new byte[original_size];
             dec.Read (original, 0, original_size);
             return original;
         }
     }
 }
Beispiel #15
0
        public override Stream OpenEntry(ArcFile arc, Entry entry)
        {
            var    parc      = (PckArchive)arc;
            var    pent      = (PackedEntry)entry;
            byte   data_type = arc.File.View.ReadByte(pent.Offset);
            Stream input     = arc.File.CreateStream(pent.Offset + 1, pent.Size);

            if (data_type != 0)
            {
                input = new InputCryptoStream(input, parc.Encryption.CreateDecryptor());
                if (data_type != 3)
                {
                    input = new LimitStream(input, pent.UnpackedSize);
                }
                else
                {
                    input = new BZip2InputStream(input);
                }
            }
            return(input);
        }
Beispiel #16
0
        internal override Stream DecryptEntry(Stream input, PazEntry entry)
        {
            input = new InputCryptoStream(input, Encryption.CreateDecryptor());
            var key = entry.Key;

            if (null == key)
            {
                return(input);
            }
            var rc4 = new Rc4Transform(key);

            if (Version >= 2)
            {
                uint crc         = Crc32.Compute(key, 0, key.Length);
                int  skip_rounds = (int)(crc >> 12) & 0xFF;
                for (int i = 0; i < skip_rounds; ++i)
                {
                    rc4.NextByte();
                }
            }
            return(new InputCryptoStream(input, rc4));
        }
Beispiel #17
0
        public override Stream OpenEntry(ArcFile arc, Entry entry)
        {
            var    a3ent = entry as Arc3Entry;
            Stream input = arc.File.CreateStream(entry.Offset, entry.Size);

            if (null == entry)
            {
                return(input);
            }
            if (a3ent.IsEncrypted)
            {
                input = new InputCryptoStream(input, new NotTransform());
            }
            if (!a3ent.IsPacked)
            {
                return(input);
            }
            using (input)
            {
                var data = UnpackLze(input, a3ent.UnpackedSize);
                return(new BinMemoryStream(data, entry.Name));
            }
        }
Beispiel #18
0
        Stream UnpackCps(IBinaryStream input)
        {
            input.Seek(-4, SeekOrigin.End);
            uint key_offset = input.ReadUInt32() - 0x7534682;

            input.Position = key_offset;
            uint key = input.ReadUInt32() + key_offset + 0x3786425;

            var header        = input.ReadHeader(0x10);
            int packed_size   = header.ToInt32(4);
            int compression   = header.ToUInt16(0xA);
            int unpacked_size = header.ToInt32(0xC);

            var decryptor = new CpsTransform(packed_size, (int)key_offset, key);

            using (var decoded = new InputCryptoStream(input.AsStream, decryptor))
                using (var cps = new BinaryStream(decoded, input.Name))
                {
                    var output = new byte[unpacked_size];
                    if ((compression & 1) != 0)
                    {
                        cps.ReadInt32();
                        UnpackLnd(cps, output);
                    }
                    else if ((compression & 2) != 0)
                    {
                        UnpackLnd16(cps, output);
                    }
                    else
                    {
                        cps.ReadInt32();
                        cps.Read(output, 0, unpacked_size);
                    }
                    return(new BinMemoryStream(output));
                }
        }
Beispiel #19
0
        public override ArcFile TryOpen(ArcView file)
        {
            if (!file.Name.HasExtension(".bin"))
            {
                return(null);
            }
            var idx_name = Path.ChangeExtension(file.Name, "idx");

            if (!VFS.FileExists(idx_name))
            {
                return(null);
            }
            var scheme = QueryScheme(file.Name);

            if (null == scheme)
            {
                return(null);
            }
            var dir = new List <Entry>();

            using (var idx = VFS.OpenBinaryStream(idx_name))
                using (var aes = Aes.Create())
                {
                    aes.Padding = PaddingMode.PKCS7;
                    aes.Mode    = CipherMode.CBC;
                    aes.KeySize = 128;
                    aes.Key     = scheme.Key;
                    aes.IV      = scheme.IV;
                    var input_buffer = new byte[0x100];
                    var unpacker     = new BinDeserializer();
                    while (idx.PeekByte() != -1)
                    {
                        int length = idx.ReadInt32();
                        if (length <= 0)
                        {
                            return(null);
                        }
                        if (length > input_buffer.Length)
                        {
                            input_buffer = new byte[length];
                        }
                        if (idx.Read(input_buffer, 0, length) < length)
                        {
                            return(null);
                        }
                        using (var decryptor = aes.CreateDecryptor())
                            using (var encrypted = new MemoryStream(input_buffer, 0, length))
                                using (var input = new InputCryptoStream(encrypted, decryptor))
                                {
                                    var info     = unpacker.DeserializeEntry(input);
                                    var filename = info["fileName"] as string;
                                    if (string.IsNullOrEmpty(filename))
                                    {
                                        return(null);
                                    }
                                    filename = filename.TrimStart('/', '\\');
                                    var entry = Create <Entry> (filename);
                                    entry.Offset = Convert.ToInt64(info["index"]);
                                    entry.Size   = Convert.ToUInt32(info["size"]);
                                    if (!entry.CheckPlacement(file.MaxOffset))
                                    {
                                        return(null);
                                    }
                                    dir.Add(entry);
                                }
                    }
                }
            if (0 == dir.Count)
            {
                return(null);
            }
            var arc_aes = Aes.Create();

            arc_aes.Padding = PaddingMode.PKCS7;
            arc_aes.Mode    = CipherMode.CBC;
            arc_aes.KeySize = 256;
            arc_aes.Key     = scheme.Key;
            arc_aes.IV      = scheme.IV;
            return(new BinArchive(file, this, dir, arc_aes));
        }
Beispiel #20
0
        public override ArcFile TryOpen(ArcView file)
        {
            uint flags = file.View.ReadUInt32(4);

            if ((flags & 0x7FFFFFFF) != 0x10000)
            {
                return(null);
            }
            int count = file.View.ReadInt32(8);

            if (!IsSaneCount(count))
            {
                return(null);
            }
            bool           is_encrypted = (flags >> 31) != 0;
            uint           index_size   = (uint)((count * 24 + 31) & -4096) + 0xFE0u;
            uint           names_size   = file.View.ReadUInt32(12);
            var            arc_md5      = file.View.ReadBytes(0x10, 0x10);
            var            index        = new byte[index_size + names_size];
            CsafEncryption enc          = null;

            try
            {
                if (is_encrypted)
                {
                    file.View.Read(0x20, index, 0, index_size);
                    enc = new CsafEncryption(DefaultKey, DefaultIV);
                    using (var decryptor = enc.CreateDecryptor(0))
                        using (var enc_names = file.CreateStream(0x20 + index_size, names_size))
                            using (var dec_names = new InputCryptoStream(enc_names, decryptor))
                            {
                                dec_names.Read(index, (int)index_size, (int)names_size);
                            }
                }
                else
                {
                    file.View.Read(0x20, index, 0, index_size + names_size);
                }
                using (var md5 = MD5.Create())
                {
                    var hash = md5.ComputeHash(index);
                    if (!hash.SequenceEqual(arc_md5))
                    {
                        return(null);
                    }
                    int index_pos = 0x10;
                    int name_pos  = (int)index_size;
                    var dir       = new List <Entry> (count);
                    for (int i = 0; i < count; ++i)
                    {
                        int j;
                        for (j = name_pos; j + 1 < index.Length; j += 2)
                        {
                            if (index[j] == 0 && index[j + 1] == 0)
                            {
                                break;
                            }
                        }
                        int name_length = j - name_pos;
                        var name        = Encoding.Unicode.GetString(index, name_pos, name_length);
//                        hash = md5.ComputeHash (index, name_pos, name_length); // == [index_pos-0x10]
                        name_pos += name_length + 10;

                        var entry = Create <Entry> (name);
                        entry.Offset = (long)index.ToUInt32(index_pos) << 12;
                        entry.Size   = index.ToUInt32(index_pos + 4);
                        index_pos   += 0x18;
                        if (!entry.CheckPlacement(file.MaxOffset))
                        {
                            return(null);
                        }
                        dir.Add(entry);
                    }
                    if (!is_encrypted)
                    {
                        return(new ArcFile(file, this, dir));
                    }
                    var arc = new CsafArchive(file, this, dir, enc);
                    enc = null;
                    return(arc);
                }
            }
            finally
            {
                if (enc != null)
                {
                    enc.Dispose();
                }
            }
        }
Beispiel #21
0
        public Stream TransformStream(Stream input, byte[] key, uint flags)
        {
            var key1 = GenerateKey(key);
            var iv   = GenerateKey(key1);

            ICryptoTransform decryptor;

            switch (flags & 0xF0000)
            {
            case 0x10000:
                decryptor = new Primel1Encyption(key1, iv);
                break;

            case 0x20000:
                decryptor = new Primel2Encyption(key1, iv);
                break;

            case 0x30000:
                decryptor = new Primel3Encyption(key1, iv);
                break;

            case 0x80000: // RC6
                decryptor = new GameRes.Cryptography.RC6(key1, iv);
                break;

            case 0xA0000: // AES
                using (var aes = Rijndael.Create())
                {
                    aes.Mode    = CipherMode.CFB;
                    aes.Padding = PaddingMode.Zeros;
                    decryptor   = aes.CreateDecryptor(key1, iv);
                }
                break;

            default: // not encrypted
                return(input);
            }
            input = new InputCryptoStream(input, decryptor);
            try
            {
                if (0 != (flags & 0xFF))
                {
                    input = new RangePackedStream(input);
                }
                switch (flags & 0xF00)
                {
                case 0x400:
                    input = new RlePackedStream(input);
                    input = new MtfPackedStream(input);
                    break;

                case 0x700:
                    input = new LzssPackedStream(input);
                    break;
                }
                return(input);
            }
            catch
            {
                input.Dispose();
                throw;
            }
        }
Beispiel #22
0
        public override ArcFile TryOpen(ArcView file)
        {
            if (!file.Name.HasExtension(".paz"))
            {
                return(null);
            }
            uint signature = file.View.ReadUInt32(0);
            // XXX encryption is queried for every .paz file
            var  scheme       = QueryEncryption(file.Name, signature);
            uint start_offset = scheme.Version > 0 ? 0x20u : 0u;
            uint index_size   = file.View.ReadUInt32(start_offset);

            start_offset += 4;
            byte xor_key = (byte)(index_size >> 24);

            if (xor_key != 0)
            {
                index_size ^= (uint)(xor_key << 24 | xor_key << 16 | xor_key << 8 | xor_key);
            }
            if (0 != (index_size & 7) || index_size + start_offset >= file.MaxOffset)
            {
                return(null);
            }

            var  arc_list   = new List <Entry>();
            var  arc_dir    = VFS.GetDirectoryName(file.Name);
            long max_offset = file.MaxOffset;

            for (char suffix = 'A'; suffix <= 'Z'; ++suffix)
            {
                var part_name = VFS.CombinePath(arc_dir, file.Name + suffix);
                if (!VFS.FileExists(part_name))
                {
                    break;
                }
                var part = VFS.FindFile(part_name);
                arc_list.Add(part);
                max_offset += part.Size;
            }
            var    arc_name = Path.GetFileNameWithoutExtension(file.Name).ToLowerInvariant();
            bool   is_audio = AudioPazNames.Contains(arc_name);
            bool   is_video = VideoPazNames.Contains(arc_name);
            Stream input    = file.CreateStream(start_offset, index_size);

            byte[]       video_key = null;
            List <Entry> dir;

            try
            {
                if (xor_key != 0)
                {
                    input = new XoredStream(input, xor_key);
                }
                var enc = new Blowfish(scheme.ArcKeys[arc_name].IndexKey);
                input = new InputCryptoStream(input, enc.CreateDecryptor());
                using (var index = new ArcView.Reader(input))
                {
                    int count = index.ReadInt32();
                    if (!IsSaneCount(count))
                    {
                        return(null);
                    }
                    if (is_video)
                    {
                        video_key = index.ReadBytes(0x100);
                    }

                    dir = new List <Entry> (count);
                    for (int i = 0; i < count; ++i)
                    {
                        var name  = index.BaseStream.ReadCString();
                        var entry = FormatCatalog.Instance.Create <PazEntry> (name);
                        entry.Offset       = index.ReadInt64();
                        entry.UnpackedSize = index.ReadUInt32();
                        entry.Size         = index.ReadUInt32();
                        entry.AlignedSize  = index.ReadUInt32();
                        if (!entry.CheckPlacement(max_offset))
                        {
                            return(null);
                        }
                        entry.IsPacked = index.ReadInt32() != 0;
                        if (string.IsNullOrEmpty(entry.Type) && is_audio)
                        {
                            entry.Type = "audio";
                        }
                        if (scheme.Version > 0)
                        {
                            string password = "";
                            if (!entry.IsPacked && scheme.TypeKeys != null)
                            {
                                password = scheme.GetTypePassword(name, is_audio);
                            }
                            if (!string.IsNullOrEmpty(password) || is_video)
                            {
                                password  = string.Format("{0} {1:X08} {2}", name.ToLowerInvariant(), entry.UnpackedSize, password);
                                entry.Key = Encodings.cp932.GetBytes(password);
                            }
                        }
                        dir.Add(entry);
                    }
                }
            }
            finally
            {
                input.Dispose();
            }
            List <ArcView> parts = null;

            if (arc_list.Count > 0)
            {
                parts = new List <ArcView> (arc_list.Count);
                try
                {
                    foreach (var arc_entry in arc_list)
                    {
                        var arc_file = VFS.OpenView(arc_entry);
                        parts.Add(arc_file);
                    }
                }
                catch
                {
                    foreach (var part in parts)
                    {
                        part.Dispose();
                    }
                    throw;
                }
            }
            if (is_video)
            {
                if (scheme.Version < 1)
                {
                    var table = new byte[0x100];
                    for (int i = 0; i < 0x100; ++i)
                    {
                        table[video_key[i]] = (byte)i;
                    }
                    video_key = table;
                }
                return(new MovPazArchive(file, this, dir, scheme.Version, xor_key, video_key, parts));
            }
            return(new PazArchive(file, this, dir, scheme.Version, xor_key, scheme.ArcKeys[arc_name].DataKey, parts));
        }