ArcFile Open(byte[] basename, ArcView file, EncryptionScheme scheme, Key key) { uint key1 = scheme.BaseKey.Key1; uint key2 = scheme.BaseKey.Key2; for (int b = 0, e = basename.Length-1; e >= 0; ++b, --e) { key1 ^= basename[e]; key2 ^= basename[b]; key1 = Binary.RotR (key1, 7); key2 = Binary.RotL (key2, 7); } if (null != key) { key1 ^= key.Key1; key2 ^= key.Key2; } uint code = file.View.ReadUInt32 (4) ^ key2; int index_size = (int)(code & 0xffffff); byte flags = (byte)(code >> 24); if (0 != (flags & 1)) index_size = (index_size << 11) - 8; if (index_size < 5 || index_size >= file.MaxOffset) return null; var index = new byte[index_size]; if (index_size != file.View.Read (8, index, 0, (uint)index_size)) return null; DecryptIndex (index, index_size, key2, scheme.RotatePattern); var lpk_info = new LpkInfo { AlignedOffset = 0 != (flags & 1), Flag1 = 0 != (flags & 2), IsEncrypted = 0 != (flags & 4), PackedEntries = 0 != (flags & 8), WholeCrypt = 0 != (flags & 0x10), Key = key1 }; var reader = new IndexReader (lpk_info); var dir = reader.Read (index); if (null == dir) return null; // this condition is fishy, probably patch files have additional bitflag set if (lpk_info.WholeCrypt && Binary.AsciiEqual (basename, "PATCH")) lpk_info.WholeCrypt = false; return new LuciArchive (file, this, dir, scheme, reader.Info); }
public LuciArchive(ArcView arc, ArchiveFormat impl, ICollection<Entry> dir, EncryptionScheme scheme, LpkInfo info) : base(arc, impl, dir) { Info = info; Scheme = scheme; }
public override ArcFile TryOpen(ArcView file) { string name = Path.GetFileName (file.Name).ToUpperInvariant(); if (string.IsNullOrEmpty (name)) return null; Key file_key = null; var basename = Encodings.cp932.GetBytes (Path.GetFileNameWithoutExtension (name)); if (name != "SCRIPT.LPK") CurrentFileMap.TryGetValue (name, out file_key); try { var arc = Open (basename, file, CurrentScheme, file_key); if (null != arc) return arc; } catch { /* unknown encryption, ignore parse errors */ } var new_scheme = QueryEncryptionScheme(); if (new_scheme == CurrentScheme && !CurrentScheme.ImportGameInit) return null; CurrentScheme = new_scheme; if (name != "SCRIPT.LPK" && CurrentScheme.ImportGameInit) { if (0 == CurrentFileMap.Count) ImportKeys (file.Name); } if (CurrentFileMap.Count > 0 && !CurrentFileMap.TryGetValue (name, out file_key)) return null; return Open (basename, file, CurrentScheme, file_key); }