private void WriteSsbh(SsbhFile file, bool isLastWrite) { foreach (var prop in file.GetType().GetProperties()) { // Some more matl hacks. if (ParseTag.ShouldSkipProperty(prop)) { continue; } // Check for types that use offsets. if (prop.PropertyType == typeof(string)) { // TODO: Is this check necessary? if (prop.GetValue(file) == null) { // Write placeholder relative offset. Write(0L); continue; } objectWriteQueue.Enqueue(new ObjectWriteInfo(prop.GetValue(file), (uint)Position)); // Write placeholder relative offset. Write(0L); } else if (prop.PropertyType.IsArray) { var array = (prop.GetValue(file) as Array); if (array.Length > 0) { objectWriteQueue.Enqueue(new ObjectWriteInfo(array, (uint)Position)); } else { objectWriteQueue.Enqueue(new ObjectWriteInfo(array)); } // Write placeholder relative offset. Write(0L); Write((long)array.Length); } else if (prop.PropertyType == typeof(SsbhOffset)) { // HACK: for materials var dataObject = file.GetType().GetProperty("DataObject").GetValue(file); var matEntry = new MaterialEntry(dataObject); objectWriteQueue.Enqueue(new ObjectWriteInfo(matEntry, (uint)Position)); // Write placeholder relative offset. Write(0L); } else { WriteProperty(prop.GetValue(file), isLastWrite); } } }
public void WriteSsbhFile(SsbhFile file) { // The header is 16-byte aligned. Write(new char[] { 'H', 'B', 'S', 'S' }); // TODO: This value is always present. Write(0x40); Pad(0x10); // write file contents AddSsbhFile(file); // TODO: padding? //exporter.Pad(0x4); }
private bool Skip(SsbhFile file, PropertyInfo prop) { object[] attrs = prop.GetCustomAttributes(true); bool skip = false; foreach (object attr in attrs) { if (attr is ParseTag tag) { if (tag.Ignore) { return(true); } } } return(skip); }
public static void WriteSsbhFile(string fileName, SsbhFile file, bool writeHeader = true) { using (SsbhExporter exporter = new SsbhExporter(new FileStream(fileName, FileMode.Create))) { // write ssbh header if (writeHeader) { exporter.Write(new char[] { 'H', 'B', 'S', 'S' }); exporter.Write(0x40); exporter.Pad(0x10); } // write file contents exporter.AddSsbhFile(file); exporter.Pad(4); } }
public static void WriteSsbhFile(string fileName, SsbhFile file, bool writeHeader = true) { using (SsbhExporter exporter = new SsbhExporter(new FileStream(fileName, FileMode.Create))) { // write ssbh header if (writeHeader) { // The header is 16-byte aligned. exporter.Write(new char[] { 'H', 'B', 'S', 'S' }); // TODO: This value is always present. exporter.Write(0x40); exporter.Pad(0x10); } // write file contents exporter.AddSsbhFile(file); exporter.Pad(4); } }
public bool TryParse(out SsbhFile file) { file = null; if (FileSize < 4) { return(false); } string fileMagic = new string(ReadChars(4)); Seek(Position - 4); if (fileMagic.Equals("HBSS")) { Seek(0x10); fileMagic = new string(ReadChars(4)); Seek(0x10); } if (parseMethodByMagic.ContainsKey(fileMagic)) { file = parseMethodByMagic[fileMagic](this); return(true); } // The type is not known, so do a very slow check to find it. foreach (var type in issbhTypes) { if (type.GetCustomAttributes(typeof(SsbhFileAttribute), true).FirstOrDefault() is SsbhFileAttribute attr) { if (attr.Magic.Equals(fileMagic)) { MethodInfo parseMethod = typeof(SsbhParser).GetMethod("Parse"); parseMethod = parseMethod.MakeGenericMethod(type); file = (SsbhFile)parseMethod.Invoke(this, null); return(true); } } } return(false); }
private void AddSsbhFile(SsbhFile file) { objectWriteQueue.Enqueue(new ObjectWriteInfo(file)); while (objectWriteQueue.Count > 0) { var writeInfo = objectWriteQueue.Dequeue(); if (writeInfo.Data == null) { continue; } // 8-byte alignment for arrays and matl data objects. if (writeInfo.Data is Array || (writeInfo.Data is MaterialEntry entry && entry.Object is MatlAttribute.MatlString)) { Pad(0x8); } // 4-byte alignment for strings. if (writeInfo.Data is string) { Pad(0x4); } // Fill in the temporary relative offset with the correct value. if (writeInfo.RelativeOffsetStartPosition.HasValue) { WriteRelativeOffset(writeInfo); } var isLastWrite = objectWriteQueue.Count == 0; if (writeInfo.Data is Array array) { WriteArray(array, isLastWrite); } else { WriteProperty(writeInfo.Data, isLastWrite); } } }
private void AddSsbhFile(SsbhFile file) { objectQueue.AddFirst(file); while (objectQueue.Count > 0) { var obj = objectQueue.First(); objectQueue.RemoveFirst(); if (obj == null) { continue; } // I guess? if (obj is Array || obj is MaterialEntry entry && entry.Object is Formats.Materials.MatlAttribute.MatlString) { Pad(0x8); } // not sure if 4 or 8 if (obj is string) { Pad(0x4); } if (objectOffset.ContainsValue(obj)) { long key = objectOffset.FirstOrDefault(x => x.Value == obj).Key; if (key != 0) { long temp = Position; BaseStream.Position = key; WriteProperty(temp - key); BaseStream.Position = temp; objectOffset.Remove((uint)key); } } if (obj is Array array) { if (array.GetType() == typeof(byte[])) { foreach (byte o in array) { Write(o); } } else { LinkedList <object> objectQueueTemp = objectQueue; objectQueue = new LinkedList <object>(); foreach (object o in array) { WriteProperty(o); } foreach (object o in objectQueueTemp) { objectQueue.AddLast(o); } } } else { WriteProperty(obj); } } }
private void WriteSsbhFile(SsbhFile file) { foreach (var prop in file.GetType().GetProperties()) { if (Skip(file, prop)) { continue; } if (prop.PropertyType == typeof(string)) { if (prop.GetValue(file) == null) { Write((long)0); continue; } objectQueue.AddLast(prop.GetValue(file)); objectOffset.Add((uint)Position, prop.GetValue(file)); Write((long)0); } else if (prop.PropertyType.IsArray) { var array = (prop.GetValue(file) as Array); bool inline = false; if (prop.GetCustomAttribute(typeof(ParseTag)) != null) { inline = ((ParseTag)prop.GetCustomAttribute(typeof(ParseTag))).InLine; } if (!inline) { if (array.Length > 0) { objectOffset.Add((uint)Position, array); } objectQueue.AddLast(array); Write((long)0); Write((long)array.Length); } else { // inline array foreach (object o in array) { WriteProperty(o); } } } else if (prop.PropertyType == typeof(SsbhOffset)) { // HACK: for materials var dataObject = file.GetType().GetProperty("DataObject").GetValue(file); var matentry = new MaterialEntry(dataObject); objectOffset.Add((uint)Position, matentry); objectQueue.AddLast(matentry); Write((long)0); } else { WriteProperty(prop.GetValue(file)); } } // TODO: Post Write is only used for materials. file.PostWrite(this); }