private bool DepthFirstImageSearch(out long offset) { bool success = false; offset = -1; int count = _r.ReadWZInt(); for (int i = 0; i < count; i++) { byte type = _r.ReadByte(); Logging(type.ToString()); switch (type) { case 1: _r.BaseStream.Seek(10, SeekOrigin.Current); continue; case 2: int x = _r.ReadInt32(); type = _r.PeekFor(() => { _r.BaseStream.Seek(x + _r.ContentsStart, SeekOrigin.Begin); return(_r.ReadByte()); }); break; case 3: case 4: _r.ReadWZString(); break; default: throw new Exception("Unknown object type in WzDirectory."); } _r.ReadWZInt(); _r.ReadWZInt(); offset = _r.BaseStream.Position; if (type == 4) { success = true; break; } if (type == 3) { try { offset = _r.PeekFor(() => { _r.BaseStream.Seek(_r.ReadWZOffset(), SeekOrigin.Begin); long o; success = DepthFirstImageSearch(out o); return(o); }); break; } catch {} } _r.BaseStream.Seek(4, SeekOrigin.Current); } return(success); }
public static IEnumerable <WZProperty> DirectoryChildren(WZProperty self) { using (WZReader reader = self.FileContainer.GetContentReader(null, self)) { reader.BaseStream.Seek(self.Offset, SeekOrigin.Begin); int count = reader.ReadWZInt(); WZProperty[] children = new WZProperty[count]; string name = null; for (int i = 0; i < count; ++i) { byte type = reader.ReadByte(); switch (type) { case 1: reader.ReadBytes(10); continue; case 2: int dedupedAt = (int)(reader.ReadInt32() + reader.ContentsStart); reader.PeekFor(() => { reader.BaseStream.Position = dedupedAt; type = reader.ReadByte(); name = reader.ReadWZString(false, self.Encrypted | self.Container.Encrypted); }); break; case 3: case 4: name = reader.ReadWZString(false, self.Encrypted | self.Container.Encrypted); break; default: throw new Exception("Unknown child type"); } if (name == null) { throw new InvalidOperationException("Found a property without a name, this shouldn't be possible."); } uint size = (uint)reader.ReadWZInt(); int checksum = reader.ReadWZInt(); uint offset = reader.ReadWZOffset(); WZProperty childProperty = new WZProperty( name, self != null ? Path.Combine(self.Path, name) : name, reader.Package, type == 3 ? PropertyType.Directory : type == 4 ? PropertyType.Image : throw new InvalidOperationException("Not sure what this is, but I don't handle it"), self, size, checksum, offset ); // These can be lazy loaded yield return(Resolve(reader.Package, childProperty)); } } }
static WZProperty Canvas(WZReader reader, WZProperty self) { // Define the variables ahead of time that way we can come back to them int width = 0, height = 0, format1 = 0, format2 = 0; uint blockLen = 0, position = 0; // Define what well be doing once we come back WZProperty result = new WZPropertyWeak <Image <Rgba32> >( () => { using (reader = self.FileContainer.GetContentReader(null, self)) { reader.BaseStream.Seek(position + 1, SeekOrigin.Begin); ushort header = reader.PeekFor(() => reader.ReadUInt16()); return(reader.ParsePNG( width, height, format1 + format2, header != 0x9C78 && header != 0xDA78, blockLen - 1 )); } }, self ); reader.BaseStream.Seek(1, SeekOrigin.Current); if (reader.ReadByte() == 1) // Has children { reader.BaseStream.Seek(2, SeekOrigin.Current); result.Children = PropertyList(reader, result).ToArray(); } else { result.Children = new WZProperty[0]; } width = reader.ReadWZInt(); // width height = reader.ReadWZInt(); // height format1 = reader.ReadWZInt(); // format 1 format2 = reader.ReadByte(); // format 2 reader.BaseStream.Seek(4, SeekOrigin.Current); blockLen = (uint)reader.ReadInt32(); result.Size = (uint)blockLen; position = (uint)reader.BaseStream.Position; return(result); }
public static byte[] ResolveHash(WZProperty prop) { using (WZReader reader = prop.FileContainer.GetContentReader(null, prop)) using (SHA1 sha = SHA1.Create()) { reader.BaseStream.Position = prop.Offset; switch (prop.Type) { case PropertyType.Image: reader.BaseStream.Position = prop.ContainerStartLocation; byte imgType = reader.ReadByte(); if (imgType == 1) { byte unk = reader.ReadByte(); return(reader.GetLuaScriptBytes().ToArray()); } else { return(new byte[0]); } case PropertyType.Directory: return(new byte[0]); case PropertyType.SubProperty: return(new byte[0]); case PropertyType.Convex: return(new byte[0]); case PropertyType.Vector2: return(sha.ComputeHash(reader.GetWZIntBytes().Concat(reader.GetWZIntBytes()).ToArray())); case PropertyType.UOL: return(sha.ComputeHash(reader.GetWZStringBlockBytes(prop.Encrypted | prop.Container.Encrypted))); case PropertyType.Audio: using (Stream sub = new SubStream(reader.BaseStream, (int)reader.BaseStream.Position, prop.Size)) return(sha.ComputeHash(sub)); case PropertyType.Canvas: reader.BaseStream.Seek(1, SeekOrigin.Current); byte[][] childHashes; if (reader.ReadByte() == 1) { reader.BaseStream.Seek(2, SeekOrigin.Current); childHashes = PropertyList(reader, prop).ToArray().Select(c => ResolveHash(c)).ToArray(); } else { childHashes = new byte[0][]; } int width = reader.ReadWZInt(); // width int height = reader.ReadWZInt(); // height int format1 = reader.ReadWZInt(); // format 1 byte format2 = reader.ReadByte(); // format 2 reader.BaseStream.Seek(4, SeekOrigin.Current); uint blockLen = (uint)reader.ReadInt32(); ushort header = reader.PeekFor(() => reader.ReadUInt16()); byte[] imageHash = new byte[0]; using (Stream sub = new SubStream(reader.BaseStream, reader.BaseStream.Position, blockLen - 1)) imageHash = sha.ComputeHash(sub); if (childHashes.Length > 0) { return(calcAggregateHash(sha, childHashes.Prepend(imageHash).ToArray())); } else { return(imageHash); } default: byte[] nameHash = sha.ComputeHash(reader.GetWZStringBlockBytes(prop.Encrypted | prop.Container.Encrypted)); byte type = reader.ReadByte(); switch (type) { case 0: return(nameHash); case 0x10: return(calcAggregateHash(sha, nameHash, sha.ComputeHash(reader.ReadBytes(1)))); case 0x11: return(calcAggregateHash(sha, nameHash, sha.ComputeHash(reader.ReadBytes(1)))); case 0x0B: case 2: case 0x12: return(calcAggregateHash(sha, nameHash, sha.ComputeHash(reader.ReadBytes(2)))); case 3: return(calcAggregateHash(sha, nameHash, sha.ComputeHash(reader.GetWZIntBytes()))); case 19: return(calcAggregateHash(sha, nameHash, sha.ComputeHash(reader.GetWZIntBytes()))); case 4: return(calcAggregateHash(sha, nameHash, sha.ComputeHash(reader.GetWZSingleBytes()))); case 5: return(calcAggregateHash(sha, nameHash, sha.ComputeHash(reader.ReadBytes(8)))); case 8: return(calcAggregateHash(sha, nameHash, sha.ComputeHash(reader.GetWZStringBlockBytes(prop.Container.Encrypted)))); case 9: return(calcAggregateHash(sha, nameHash, sha.ComputeHash(reader.ReadBytes(reader.ReadInt32())))); case 20: return(calcAggregateHash(sha, nameHash, sha.ComputeHash(reader.GetWZLongBytes()))); case 21: return(calcAggregateHash(sha, nameHash, sha.ComputeHash(reader.GetWZLongBytes()))); default: System.Diagnostics.Debugger.Break(); Console.WriteLine("Wow"); if (type > 100) { throw new Exception("Unknown property type at ParsePropertyList"); } else { return(new byte[0]); } } } } }