private void makePatch_Click(object sender, EventArgs e) { Patch patch = new Patch(); patch.Name = patchName.Text; patch.Description = patchDescription.Text; patch.Author = patchAuthor.Text; IReader originalReader = new EndianReader(File.OpenRead(unmoddedPath.Text), Endian.BigEndian); IReader newReader = new EndianReader(File.OpenRead(moddedPath.Text), Endian.BigEndian); ThirdGenVersionInfo version = new ThirdGenVersionInfo(originalReader); BuildInfoLoader loader = new BuildInfoLoader(XDocument.Load(@"Formats\SupportedBuilds.xml"), @"Formats\"); BuildInformation buildInfo = loader.LoadBuild(version.BuildString); ThirdGenCacheFile originalFile = new ThirdGenCacheFile(originalReader, buildInfo, version.BuildString); ThirdGenCacheFile newFile = new ThirdGenCacheFile(newReader, buildInfo, version.BuildString); MetaComparer.CompareMeta(originalFile, originalReader, newFile, newReader, patch); LocaleComparer.CompareLocales(originalFile, originalReader, newFile, newReader, patch); originalReader.Close(); newReader.Close(); IWriter output = new EndianWriter(File.OpenWrite(outPath.Text), Endian.BigEndian); AssemblyPatchWriter.WritePatch(patch, output); output.Close(); MessageBox.Show("Done!"); }
/// <summary> /// Extracts a Wwise OGG and converts it to a "regular" OGG file. /// </summary> /// <param name="reader">The stream to read from.</param> /// <param name="offset">The offset of the data to extract.</param> /// <param name="size">The size of the data to extract.</param> /// <param name="outPath">The path of the file to save to.</param> public static void ExtractWwiseToOGG(EndianReader reader, int offset, int size, string outPath) { // Just extract the RIFX to a temporary file string tempFile = Path.GetTempFileName(); try { using (EndianWriter output = new EndianWriter(File.OpenWrite(tempFile), EndianFormat.BigEndian)) { reader.SeekTo(offset); StreamUtil.Copy(reader, output, size); } // Run ww2ogg to convert the resulting RIFX to an OGG RunProgramSilently("Helpers/ww2ogg.exe", string.Format("\"{0}\" -o \"{1}\" --pcb Helpers/packed_codebooks_aoTuV_603.bin", tempFile, outPath), Directory.GetCurrentDirectory()); // Run revorb to fix up the OGG RunProgramSilently("Helpers/revorb.exe", "\"" + outPath + "\"", Directory.GetCurrentDirectory()); } finally { // Delete the old RIFX file if (File.Exists(tempFile)) File.Delete(tempFile); } }
public void WriteTo([NotNull] Stream stream) { if (stream == null) throw new ArgumentNullException(nameof(stream)); var writer = new EndianWriter(stream, Endianness.BigEndian); writer.Write(ChannelIdentifier); writer.Write(PaketSequence); stream.Write(Data.Array, Data.Offset, Data.Count); }
/// <summary> /// Extracts the raw contents of a sound to a file. /// </summary> /// <param name="reader">The stream to read from.</param> /// <param name="offset">The offset of the data to extract.</param> /// <param name="size">The size of the data to extract.</param> /// <param name="outPath">The path of the file to save to.</param> public static void ExtractRaw(EndianReader reader, int offset, int size, string outPath) { using (EndianWriter output = new EndianWriter(File.OpenWrite(outPath), EndianFormat.BigEndian)) { // Just copy the data over to the output stream reader.SeekTo(offset); StreamUtil.Copy(reader, output, size); } }
/// <summary> /// Initializes a new instance of the <see cref="EndianStream"/> class. /// </summary> /// <param name="stream">The stream to read from and write to.</param> /// <param name="endianness">The initial endianness to use when operating on the stream.</param> /// <exception cref="System.ArgumentException">Thrown if <paramref name="stream"/> is not both readable and writable.</exception> public EndianStream(Stream stream, Endian endianness) { if (!stream.CanRead || !stream.CanWrite) throw new ArgumentException("The input stream must be both readable and writable."); _stream = stream; _reader = new EndianReader(stream, endianness); _writer = new EndianWriter(stream, endianness); }
public static void Copy(EndianReader input, EndianWriter output) { const int BufferSize = 0x1000; var buffer = new byte[BufferSize]; int read; while ((read = input.ReadBlock(buffer, 0, BufferSize)) > 0) output.WriteBlock(buffer, 0, read); }
/// <summary> /// Constructs a new EndianStream based off of a Stream object. /// </summary> /// <param name="stream">The Stream to use. It must at least be available for reading or writing.</param> /// <param name="endianness">The endianness to use when performing I/O operations.</param> public EndianStream(Stream stream, Endian endianness) { _stream = stream; if (stream.CanRead) _reader = new EndianReader(stream, endianness); if (stream.CanWrite) _writer = new EndianWriter(stream, endianness); if (_reader == null && _writer == null) throw new ArgumentException("The input stream cannot be read from or written to."); }
/// <summary> /// Creates a BinaryWriter to write to the stream managed by <paramref name="writer"/> /// using the provided Endian setting. <paramref name="marker"/> is written to the /// stream to mark the Endian setting used. /// </summary> public static BinaryWriter WriteEndianMarker(this BinaryWriter writer, Endian endian, uint marker) { BinaryWriter result = writer; if (endian != Endian.Native) { var endianWriter = new EndianWriter(writer) {Endian = endian}; result = endianWriter; } writer.Write(marker); return result; }
public void WriteTo([NotNull] Stream stream) { if (stream == null) throw new ArgumentNullException(nameof(stream)); var writer = new EndianWriter(stream, Endianness.BigEndian); writer.Write(ChannelIdentifier); writer.Write(CommandIdentifier); writer.Write((byte)((PayloadLength >> 8) & 0xFF)); writer.Write((byte)((PayloadLength >> 0) & 0xFF)); stream.Write(Data.Array, Data.Offset, Data.Count); }
/// <exception cref="U2FException"/> /// <exception cref="System.IO.IOException"/> static void SendResponse(Stream outputStream, byte[] encodedBytes) { if (encodedBytes.Length > 65535) { throw new U2FException("Message is too long to be transmitted over this protocol"); } using (var dataOutputStream = new EndianWriter(outputStream, Endianness.BigEndian)) { dataOutputStream.Write((short)encodedBytes.Length); dataOutputStream.Write(encodedBytes); } }
public static ArraySegment<byte> EncodeResponse(ApduResponse response) { var buffer = new byte[response.ResponseData.Count + 2]; using (var stream = new EndianWriter(new MemoryStream(buffer), Endianness.BigEndian)) { stream.Write(response.ResponseData.Array, response.ResponseData.Offset, response.ResponseData.Count); var status = (short)response.Status; stream.Write(status); } return buffer.Segment(); }
public EndianIO(string fileName, EndianType endiantype, bool Open, bool IsNewFile) { EndianType = endiantype; FileName = fileName; var mode = IsNewFile ? FileMode.Create : FileMode.Open; try { Stream = new FileStream(FileName, mode); Reader = new EndianReader(Stream, EndianType); Writer = new EndianWriter(Stream, EndianType); if (!Open) { Close(); } } catch { } }
public static byte[] BuildBinary(Endianness endianess, params object[] args) { using (var stream = new MemoryStream(64)) { var writer = new EndianWriter(stream, endianess); foreach (var arg in args) { var type = arg.GetType(); if (type == typeof(uint)) { writer.Write((uint)arg); } else if (type == typeof(ushort)) { writer.Write((ushort)arg); } else if (type == typeof(byte)) { writer.Write((byte)arg); } else if (type == typeof(BytesHolder)) { var holder = ((BytesHolder)arg); writer.Write(holder.Bytes); } else if (type == typeof(ArraySegment<byte>)) { var segment = (ArraySegment<byte>)arg; writer.Write(segment.Array, segment.Offset, segment.Count); } else if (type == typeof(byte[])) { var array = (byte[])arg; writer.Write(array); } } return stream.GetBuffer(); } }
private void button1_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); if (ofd.ShowDialog() == DialogResult.OK) { FileStream stream = new FileStream(ofd.FileName, FileMode.Open); EndianReader reader = new EndianReader(stream, EndianType.BigEndian); EndianWriter writer = new EndianWriter(stream, EndianType.BigEndian); int CSum = 0; reader.BaseStream.Position = 0xD000; for (int i = 0; i < 0x768; i += 4) CSum += reader.ReadInt32(); writer.Write(CSum); writer.Flush(); writer.Close(); reader.Close(); MessageBox.Show("New Checksum: " + CSum.ToString("X2"), "Done!"); } }
/// <summary> /// Reads a shader from a stream and then serializes it into a byte array which can then be exported. /// </summary> /// <param name="reader">The stream to read from. It should be positioned at the beginning of the shader pointer.</param> /// <param name="type">The type of shader to read.</param> /// <returns> /// The serialized shader data, or <c>null</c> if reading failed. /// </returns> public byte[] ExportShader(IReader reader, ShaderType type) { var info = ReadShaderInfo(reader, type); if (info == null) return null; using (var memStream = new MemoryStream()) { using (var writer = new EndianWriter(memStream, Endian.BigEndian)) { writer.WriteInt32(SerializationMagic); writer.WriteByte((byte)type); // Write the layout size for compatibility checking when deserializing if (type == ShaderType.Pixel) writer.WriteInt32(_pixelShaderInfoLayout.Size); else writer.WriteInt32(_vertexShaderInfoLayout.Size); // Write the raw debug info reader.SeekTo(info.DebugInfoOffset); writer.WriteUInt32(info.DebugInfoSize); writer.WriteBlock(reader.ReadBlock((int)info.DebugInfoSize)); // Write the raw shader data var dataOffset = _cacheFile.MetaArea.PointerToOffset(info.DataAddress); reader.SeekTo(dataOffset); writer.WriteUInt32(info.DataSize); writer.WriteBlock(reader.ReadBlock((int)info.DataSize)); // Create the result from the memory stream's buffer var result = new byte[memStream.Length]; Buffer.BlockCopy(memStream.GetBuffer(), 0, result, 0, (int)memStream.Length); return result; } } }
public ushort CreateIndexBuffer(RenderGeometryApiResourceDefinition resourceDefinition, Stream outputStream, List <ushort> buffer) { resourceDefinition.IndexBuffers.Add(new TagStructureReference <IndexBufferDefinition> { Definition = new IndexBufferDefinition { Format = IndexBufferFormat.TriangleStrip, Data = new TagData { Size = buffer.Count() * 2, Unused4 = 0, Unused8 = 0, Address = new CacheAddress(), Unused10 = 0 } } }); var indexBuffer = resourceDefinition.IndexBuffers.Last().Definition; var indexCount = indexBuffer.Data.Size / 2; var outIndexStream = new EndianWriter( outputStream, EndianFormat.LittleEndian); StreamUtil.Align(outputStream, 4); indexBuffer.Data.Address = new CacheAddress(CacheAddressType.Resource, (int)outputStream.Position); for (var j = 0; j < indexCount; j++) { outIndexStream.Write((short)buffer[j]); } return((ushort)resourceDefinition.IndexBuffers.IndexOf(resourceDefinition.IndexBuffers.Last())); }
public void SingleMixed(ByteOrder readOrder, ByteOrder writeOrder) { using (var stream = new MemoryStream()) using (var reader = new EndianReader(stream, readOrder)) using (var writer = new EndianWriter(stream, writeOrder)) { var rand = BitConverter.ToSingle(BitConverter.GetBytes(new Random().NextDouble() * uint.MaxValue).Reverse().ToArray(), 0); var bytes = BitConverter.GetBytes((float)rand); Array.Reverse(bytes); writer.Write(float.Epsilon); writer.Write(float.MinValue); writer.Write(float.MaxValue); writer.Write(float.NaN); writer.Write(float.NegativeInfinity); writer.Write(float.PositiveInfinity); writer.Write(rand); Assert.AreEqual(stream.Length, 28); stream.Position = 0; Assert.AreEqual(BitConverter.ToSingle(BitConverter.GetBytes(float.Epsilon).Reverse().ToArray(), 0), reader.PeekSingle()); Assert.AreEqual(0, stream.Position); Assert.AreEqual(BitConverter.ToSingle(BitConverter.GetBytes(float.Epsilon).Reverse().ToArray(), 0), reader.ReadSingle()); Assert.AreEqual(BitConverter.ToSingle(BitConverter.GetBytes(float.MinValue).Reverse().ToArray(), 0), reader.ReadSingle()); Assert.AreEqual(BitConverter.ToSingle(BitConverter.GetBytes(float.MaxValue).Reverse().ToArray(), 0), reader.ReadSingle()); Assert.AreEqual(BitConverter.ToSingle(BitConverter.GetBytes(float.NaN).Reverse().ToArray(), 0), reader.ReadSingle()); Assert.AreEqual(BitConverter.ToSingle(BitConverter.GetBytes(float.NegativeInfinity).Reverse().ToArray(), 0), reader.ReadSingle()); Assert.AreEqual(BitConverter.ToSingle(BitConverter.GetBytes(float.PositiveInfinity).Reverse().ToArray(), 0), reader.ReadSingle()); Assert.AreEqual(BitConverter.ToSingle(BitConverter.GetBytes(rand).Reverse().ToArray(), 0), reader.ReadSingle()); Assert.AreEqual(reader.BaseStream.Position, stream.Length); } }
private void WriteTagNamesSection(EndianWriter writer, DataSerializationContext context, TagSerializer serializer) { //prepare tag names var names = new Dictionary <int, string>(); foreach (var entry in Tags.Index) { if (entry != null && entry.Name != null) { names.Add(entry.Index, entry.Name); } } // create entry and immediatly write the tag names table GenericSectionEntry mapEntry = new GenericSectionEntry(names.Count, (int)writer.BaseStream.Position + 0x8); mapEntry.Write(writer); foreach (var entry in names) { var tagNameEntry = new ModPackageTagNamesEntry(entry.Key, entry.Value); serializer.Serialize(context, tagNameEntry); } }
public override void WriteValue(EndianWriter writer) { writer.Seek(ValueAddress, SeekOrigin.Begin); var parsed = float.Parse(Value.ToString()); switch (FieldDefinition.ValueType) { case MetaValueType.SByte: writer.Write((sbyte)parsed); break; case MetaValueType.Int16: writer.Write((short)parsed); break; case MetaValueType.Int32: writer.Write((int)parsed); break; case MetaValueType.Int64: writer.Write((long)parsed); break; case MetaValueType.Byte: writer.Write((byte)parsed); break; case MetaValueType.UInt16: writer.Write((ushort)parsed); break; case MetaValueType.UInt32: writer.Write((uint)parsed); break; case MetaValueType.UInt64: writer.Write((ulong)parsed); break; case MetaValueType.Angle: case MetaValueType.Float32: writer.Write((float)parsed); break; case MetaValueType.Undefined: default: writer.Write((int)parsed); break; } IsDirty = false; }
public void GuidMixed(ByteOrder readOrder, ByteOrder writeOrder) { using (var stream = new MemoryStream()) using (var reader = new EndianReader(stream, readOrder)) using (var writer = new EndianWriter(stream, writeOrder)) { var guidX = new Guid("863b519c-6942-4b65-adfa-55874889fecd"); var guidY = new Guid("9c513b86-4269-654b-adfa-55874889fecd"); writer.Write(guidX, ByteOrder.LittleEndian); writer.Write(guidY, ByteOrder.LittleEndian); writer.Write(guidX, ByteOrder.BigEndian); writer.Write(guidY, ByteOrder.BigEndian); stream.Position = 0; Assert.AreEqual(guidY, reader.ReadGuid(ByteOrder.BigEndian)); Assert.AreEqual(guidX, reader.ReadGuid(ByteOrder.BigEndian)); Assert.AreEqual(guidY, reader.ReadGuid(ByteOrder.LittleEndian)); Assert.AreEqual(guidX, reader.ReadGuid(ByteOrder.LittleEndian)); } }
public override object Execute(List <string> args) { string modelFileName; if (args.Count == 1) { modelFileName = args[0]; } else { return(false); } if (Definition.Geometry.Resource == null) { Console.WriteLine("Render model does not have a resource associated with it"); return(true); } BlamModelFile geometryFormat = new BlamModelFile(); using (var stream = Cache.OpenCacheRead()) { var resource = Cache.ResourceCache.GetRenderGeometryApiResourceDefinition(Definition.Geometry.Resource); Definition.Geometry.SetResourceBuffers(resource); geometryFormat.InitGen3(Cache, Definition); using (var modelStream = new FileStream($"{modelFileName}.bmf", FileMode.Create)) using (var writer = new EndianWriter(modelStream)) { geometryFormat.SerializeToFile(writer); } } return(true); }
private void button1_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); if (ofd.ShowDialog() == DialogResult.OK) { FileStream stream = new FileStream(ofd.FileName, FileMode.Open); EndianReader reader = new EndianReader(stream, EndianType.BigEndian); EndianWriter writer = new EndianWriter(stream, EndianType.BigEndian); int CSum = 0; reader.BaseStream.Position = 0xD000; for (int i = 0; i < 0x768; i += 4) { CSum += reader.ReadInt32(); } writer.Write(CSum); writer.Flush(); writer.Close(); reader.Close(); MessageBox.Show("New Checksum: " + CSum.ToString("X2"), "Done!"); } }
public void Enums01(ByteOrder order) { var rng = new Random(); var obj = new DataClass12 { Property1 = (Enum01)rng.Next(1, 4), Property2 = (Enum02)rng.Next(4, 7), Property3 = (Enum03)rng.Next(7, 10), Property4 = (Enum04)rng.Next(10, 13), }; using (var stream = new MemoryStream()) using (var reader = new EndianReader(stream, order)) using (var writer = new EndianWriter(stream, order)) { writer.WriteObject(obj); stream.Position = 0; Assert.AreEqual((byte)obj.Property1, reader.ReadByte()); Assert.AreEqual((short)obj.Property2, reader.ReadInt16()); Assert.AreEqual((int)obj.Property3, reader.ReadInt32()); Assert.AreEqual((long)obj.Property4, reader.ReadInt64()); } }
/// <summary> /// GenerateForBlenderPhmoJson /// </summary> /// <param name="jsonString">String containing blender exported JSON using the jsonPhmoExporter plugin.</param> /// <returns>A memory stream with Havok 6.5.0 moppcode block</returns> public static MemoryStream GenerateForBlenderPhmoJson(string jsonString) { JsonToMopp jtm = new JsonToMopp(); MemoryStream moppStream = jtm.CreateMopp(jsonString); moppStream.Position = 0; CollisionMoppCode resource = SynthesizeMoppBlock(moppStream); MemoryStream outStream = null; #if !DEBUG try { #endif var resourceWriter = new EndianWriter(new MemoryStream(), EndianFormat.LittleEndian); var dataContext = new DataSerializationContext(null, resourceWriter); var block = dataContext.CreateBlock(); var info = TagStructure.GetTagStructureInfo(resource.GetType(), CacheVersion.HaloOnline235640); new TagSerializer(CacheVersion.HaloOnline235640).Serialize(dataContext, resource); block.Stream.Position = 0; outStream = block.Stream; #if !DEBUG } catch { return(null); } #endif outStream.Position = 48; //position of Data member. Data will be inlined moppStream.CopyTo(outStream); //remainder of moppStream is mopp program outStream.Position = 0; return(outStream); //this is the one with serialized data in it }
public void DataLength01(ByteOrder order) { var rng = new Random(); using (var stream = new MemoryStream(new byte[500])) using (var reader = new EndianReader(stream, order)) using (var writer = new EndianWriter(stream, order)) { var obj = new DataClass14 { Property1 = 5, Property2 = 100 }; writer.WriteObject(obj); Assert.AreEqual(100, stream.Position); stream.Position = 0; Assert.AreEqual(5, reader.ReadInt32()); Assert.AreEqual(100, reader.ReadInt32()); stream.Position = 0; obj = new DataClass14 { Property1 = 7, Property2 = 45 }; writer.WriteObject(obj); Assert.AreEqual(45, stream.Position); stream.Position = 0; Assert.AreEqual(7, reader.ReadInt32()); Assert.AreEqual(45, reader.ReadInt32()); } }
private void WriteDataBlock(DataBlock block, SegmentPointer location, IStream stream, ITag tag = null) { if (tag == null && _dataBlockAddresses.ContainsKey(block)) // Don't write anything if the block has already been written return; // Associate the location with the block _dataBlockAddresses[block] = location.AsPointer(); // Create a MemoryStream and write the block data to it (so fixups can be performed before writing it to the file) using (var buffer = new MemoryStream(block.Data.Length)) { var bufferWriter = new EndianWriter(buffer, stream.Endianness); bufferWriter.WriteBlock(block.Data); // Apply fixups FixBlockReferences(block, bufferWriter, stream); FixTagReferences(block, bufferWriter, stream); FixResourceReferences(block, bufferWriter, stream); FixStringIdReferences(block, bufferWriter); if (tag != null) FixUnicListReferences(block, tag, bufferWriter, stream); // Write the buffer to the file stream.SeekTo(location.AsOffset()); stream.WriteBlock(buffer.GetBuffer(), 0, (int) buffer.Length); } // Write shader fixups (they can't be done in-memory because they require cache file expansion) FixShaderReferences(block, stream, location); }
internal void Write(EndianWriter writer) { uint bindPoint = 0; foreach (var bufferParam in shaderSubprogram.BufferParameters) { //Resource bindings //nameOffset writer.Write(nameLookup[bufferParam.Name]); //shader input type writer.Write((uint)ShaderInputType.Structured); //Resource return type writer.Write((uint)ResourceReturnType.Mixed); //Resource view dimension writer.Write((uint)ShaderResourceViewDimension.Buffer); //Number of samples writer.Write((uint)56); //TODO: Check this //Bind point writer.Write((uint)bufferParam.Index); bindPoint += 1; //Bind count writer.Write((uint)1); //Shader input flags writer.Write((uint)ShaderInputFlags.None); } bindPoint = 0; foreach (var textureParam in shaderSubprogram.TextureParameters) { //Resource bindings //nameOffset writer.Write(nameLookup[textureParam.Name]); //shader input type writer.Write((uint)ShaderInputType.Sampler); //Resource return type writer.Write((uint)ResourceReturnType.NotApplicable); //Resource view dimension writer.Write((uint)ShaderResourceViewDimension.Unknown); //Number of samples writer.Write((uint)0); //Bind point writer.Write((uint)textureParam.Index); bindPoint += 1; //Bind count writer.Write((uint)1); //Shader input flags writer.Write((uint)ShaderInputFlags.None); } bindPoint = 0; foreach (var textureParam in shaderSubprogram.TextureParameters) { //Resource bindings //nameOffset writer.Write(nameLookup[textureParam.Name]); //shader input type writer.Write((uint)ShaderInputType.Texture); //Resource return type writer.Write((uint)ResourceReturnType.NotApplicable); //Resource view dimension writer.Write((uint)textureParam.Dim); //Number of samples writer.Write(uint.MaxValue); //Bind point writer.Write((uint)textureParam.Index); bindPoint += 1; //Bind count writer.Write((uint)1); //Shader input flags writer.Write((uint)ShaderInputFlags.None); } bindPoint = 0; foreach (var constantBuffer in shaderSubprogram.ConstantBufferBindings) { //Resource bindings //nameOffset writer.Write(nameLookup[constantBuffer.Name]); //shader input type writer.Write((uint)ShaderInputType.CBuffer); //Resource return type writer.Write((uint)ResourceReturnType.NotApplicable); //Resource view dimension writer.Write((uint)ShaderResourceViewDimension.Unknown); //Number of samples writer.Write((uint)0); //Bind point writer.Write((uint)constantBuffer.Index); bindPoint += 1; //Bind count writer.Write((uint)1); //Shader input flags writer.Write((uint)ShaderInputFlags.None); } foreach (var bufferParam in shaderSubprogram.BufferParameters) { writer.WriteStringZeroTerm(bufferParam.Name); } foreach (var textureParam in shaderSubprogram.TextureParameters) { writer.WriteStringZeroTerm(textureParam.Name); } foreach (var constantBuffer in shaderSubprogram.ConstantBufferBindings) { writer.WriteStringZeroTerm(constantBuffer.Name); } }
public override void Write(EndianWriter bw) { bw.Write(X); bw.Write(Y); }
public void SaveStrings(IStream stream, List<LocalizedString> locales) { var offsetData = new MemoryStream(); var stringData = new MemoryStream(); var offsetWriter = new EndianWriter(offsetData, Endian.BigEndian); var stringWriter = new EndianWriter(stringData, Endian.BigEndian); try { // Write the string and offset data to buffers foreach (LocalizedString locale in locales) { WriteLocalePointer(offsetWriter, locale.Key, (int) stringWriter.Position); stringWriter.WriteUTF8(locale.Value); } // Round the size of the string data up var dataSize = (int) ((stringData.Position + _sizeAlign - 1) & ~(_sizeAlign - 1)); stringData.SetLength(dataSize); // Update the two locale data hashes if we need to // (the hash arrays are set to null if the build doesn't need them) if (IndexTableHash != null) IndexTableHash = SHA1.Transform(offsetData.GetBuffer(), 0, (int) offsetData.Length); if (StringDataHash != null) StringDataHash = SHA1.Transform(stringData.GetBuffer(), 0, dataSize); // Make sure there's free space for the offset table and then write it to the file LocaleIndexTable.Resize((int) offsetData.Length, stream); stream.SeekTo(LocaleIndexTableLocation.AsOffset()); stream.WriteBlock(offsetData.GetBuffer(), 0, (int) offsetData.Length); // Encrypt the string data if necessary byte[] strings = stringData.GetBuffer(); if (_encryptionKey != null) strings = AES.Encrypt(strings, 0, dataSize, _encryptionKey.Key, _encryptionKey.IV); // Make sure there's free space for the string data and then write it to the file LocaleData.Resize(dataSize, stream); stream.SeekTo(LocaleDataLocation.AsOffset()); stream.WriteBlock(strings, 0, dataSize); // Update the string count and recalculate the language table offsets StringCount = locales.Count; } finally { offsetWriter.Close(); stringWriter.Close(); } }
/// <summary> /// Write the chunk to a stream /// </summary> /// <param name="writer">Output stream</param> public virtual void Write(EndianWriter writer) { writer.WriteUInt16((ushort)((byte)Type | (ushort)(Attributes << 8))); }
public abstract void WriteValue(EndianWriter writer);
public void Open() { try { Stream = new FileStream(FileName, FileMode.Open); Reader = new EndianReader(Stream, EndianType); Writer = new EndianWriter(Stream, EndianType); } catch { } }
protected override void LoadResourceData(BlamCacheFile cacheFile, ref Resource resourceRef) { bool[] convertedVertexBuffers = new bool[100]; bool[] convertedIndexBuffers = new bool[100]; using (EndianWriter writer = new EndianWriter(new MemoryStream(resourceRef.Info), Endian.LittleEndian)) { foreach (ResourceFixup fixup in resourceRef.ResourceFixups) { BlamCacheAddress address = new BlamCacheAddress(fixup.Address); writer.SeekTo(fixup.Offset); writer.WriteUInt32(address.Value); } } byte[] primaryResource = ReadResourcePageData(cacheFile, resourceRef.Location.PrimaryPage); byte[] secondaryResource = ReadResourcePageData(cacheFile, resourceRef.Location.SecondaryPage); //The using keyword will automatically call IDisposable.Dispose at the end of scope //Automatically freeing up our resources and closing our file streams using (EndianReader definitionReader = new EndianReader(new MemoryStream(resourceRef.Info), Endian.LittleEndian)) using (EndianReader primaryReader = new EndianReader(new MemoryStream(primaryResource), Endian.LittleEndian)) using (EndianReader secondaryReader = new EndianReader(new MemoryStream(secondaryResource), Endian.LittleEndian)) { BlamCacheAddress cacheAddress = new BlamCacheAddress((uint)resourceRef.BaseDefinitionAddress); Logger.AssertMsg(cacheAddress.Type == BlamCacheAddressType.Definition, "INVALID CACHE ADDRESS"); definitionReader.SeekTo(cacheAddress.Offset); StructureLayout layout = cacheFile.GetLayout("render geometry api resource definition"); StructureValueCollection values = StructureReader.ReadStructure(definitionReader, layout); //Won't be useless eventually ulong numberOfUselessCrap3 = values.GetInteger("number of useless crap3"); ulong numberOfUselessCrap4 = values.GetInteger("number of useless crap4"); BlamCacheAddress uselessCrap3Address = new BlamCacheAddress((uint)values.GetInteger("address of useless crap3 table")); BlamCacheAddress uselessCrap4Address = new BlamCacheAddress((uint)values.GetInteger("address of useless crap4 table")); StructureLayout vertexBufferDefinitionLayout = new StructureLayout(); vertexBufferDefinitionLayout.AddBasicField("vertex count", StructureValueType.Int32, 0x0); vertexBufferDefinitionLayout.AddBasicField("vertex format", StructureValueType.Int16, 0x4); vertexBufferDefinitionLayout.AddBasicField("vertex byte size", StructureValueType.Int16, 0x6); vertexBufferDefinitionLayout.AddBasicField("vertex buffer size", StructureValueType.Int32, 0x8); vertexBufferDefinitionLayout.AddBasicField("vertex buffer address", StructureValueType.UInt32, 0x14); //Vertex buffer data should be aligned to 0x4 StructureLayout indexBufferDefinitionLayout = new StructureLayout(); indexBufferDefinitionLayout.AddBasicField("index format", StructureValueType.Int16, 0x0); //Vertex buffer definitions //All of the vertex buffer definitions exist in a table of D3DPointer container structs //Each D3DPointer contains the address of the contained type (this is the only value we care about) //For example D3DPointer<Float> the first value might be 0x20000000 which would be an address containing some float VertexBufferDefinitions = new BlamD3DPointer <VertexBufferDefinition> [numberOfUselessCrap3]; StructureLayout d3dStructureLayout = BlamD3DPointer <VertexBufferDefinition> .Layout(); for (int i = 0; i < (int)numberOfUselessCrap3; i++) { //Read each D3DPointer struct (Make a class for this too) long offset = (i * d3dStructureLayout.Size); long readAddr = uselessCrap3Address.Offset + offset; definitionReader.SeekTo(readAddr); StructureValueCollection d3dStructureValues = StructureReader.ReadStructure(definitionReader, d3dStructureLayout); //Grab the pointer to the contained value (in our case it will be a VertexBufferDefinition) BlamCacheAddress vertexBufferDefinitionAddress = new BlamCacheAddress((uint)d3dStructureValues.GetInteger("address")); Logger.AssertMsg(vertexBufferDefinitionAddress.Type == BlamCacheAddressType.Definition, "Invalid vertex buffer definition address!"); //Read our vertex buffer definition (Make a class for this) definitionReader.SeekTo(vertexBufferDefinitionAddress.Offset); StructureValueCollection vertexBufferDefinitionValues = StructureReader.ReadStructure(definitionReader, vertexBufferDefinitionLayout); //Grab our vertex buffer address BlamCacheAddress vertexBufferAddress = new BlamCacheAddress((uint)vertexBufferDefinitionValues.GetInteger("vertex buffer address")); EndianReader vertexBufferReader = null; //Determine where to read the vertex data from switch (vertexBufferAddress.Type) { case BlamCacheAddressType.Data: vertexBufferReader = primaryReader; break; case BlamCacheAddressType.SecondaryData: vertexBufferReader = secondaryReader; break; case BlamCacheAddressType.Definition: vertexBufferReader = definitionReader; break; } Logger.AssertMsg(vertexBufferReader != null, "INVALID VERTEX BUFFER ADDRESS"); //Need to make a class for this too, BUT the layout depends on what type of vertex it is... //See https://github.com/MadJayQ/MCCEditor/blob/master/Blamite/Formats/Reach/Reach_VertexBuffer.xml //This is for Reach but it's the best we got ATM... StructureLayout vertexBufferLayout = new StructureLayout(); vertexBufferLayout.AddBasicField("posX", StructureValueType.Float32, 0x0); vertexBufferLayout.AddBasicField("posY", StructureValueType.Float32, 0x4); vertexBufferLayout.AddBasicField("posZ", StructureValueType.Float32, 0x8); vertexBufferLayout.AddBasicField("posW", StructureValueType.Float32, 0x10); //Read our vertex data buffer block long vertexByteSize = (long)vertexBufferDefinitionValues.GetInteger("vertex byte size"); long vertexBufferTotalSize = (long)vertexBufferDefinitionValues.GetInteger("vertex buffer size"); long vertexCount = (long)vertexBufferDefinitionValues.GetInteger("vertex count"); Logger.AssertMsgFormat(vertexBufferTotalSize == (vertexByteSize * vertexCount), "Malformed vertex buffer, vertex byte size and vertex count do not add up to the total vertex buffer size! Total: {0}, Vertex Size: {1}, Vertex Count: {2}", vertexBufferTotalSize, vertexByteSize, vertexCount); vertexBufferReader.SeekTo(vertexBufferAddress.Offset); byte[] vertexBlock = vertexBufferReader.ReadBlock((int)vertexBufferDefinitionValues.GetInteger("vertex buffer size")); using (EndianReader vertexBufferStreamReader = new EndianReader(new MemoryStream(vertexBlock), Endian.LittleEndian)) { for (int vertexIdx = 0; vertexIdx < vertexCount; vertexIdx++) { long vertexBlockOffset = (vertexIdx * vertexByteSize); StructureValueCollection vertexValues = StructureReader.ReadStructure(vertexBufferStreamReader, vertexBufferLayout); } } } //Index buffer definitions for (int i = 0; i < (int)numberOfUselessCrap4; i++) { long offset = (i * 0xC); long readAddr = uselessCrap4Address.Offset + offset; definitionReader.SeekTo(readAddr); StructureValueCollection d3dStructureValues = StructureReader.ReadStructure(definitionReader, d3dStructureLayout); BlamCacheAddress indexBufferDefinitionAddress = new BlamCacheAddress((uint)d3dStructureValues.GetInteger("address")); Logger.AssertMsg(indexBufferDefinitionAddress.Type == BlamCacheAddressType.Definition, "Invalid index buffer definition address!"); definitionReader.SeekTo(indexBufferDefinitionAddress.Offset); StructureValueCollection indexBufferDefinitionValues = StructureReader.ReadStructure(definitionReader, indexBufferDefinitionLayout); } } }
private void BasicProjectileSwap(string command) { command = command.ToLowerInvariant(); var targetWeaponTag = _tagEntries.FirstOrDefault(t => t.TagClass == "weap" && t.TagAliasNames.Contains("assault rifle")); if (targetWeaponTag == null) return; var newProjectileTag = _tagEntries.FirstOrDefault(t => t.TagClass == "proj" && t.TagAliasNames.Contains(command)); if (newProjectileTag == null) return; const uint baseOffset = 0xbf126690 + 0x98; // Tag Block Address + Initial Projectile Offset Gain var writer = new EndianWriter(_xbdm.MemoryStream, Endian.BigEndian); writer.SeekTo(baseOffset); writer.WriteUInt32((UInt32) newProjectileTag.Tag.Class.Magic); writer.WriteBlock(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); writer.WriteUInt32(newProjectileTag.Tag.Index.Value); }
public static void InsertBytes(string filePath, int startOffset, int size) { var input = new FileStream(filePath, FileMode.Open); var er = new EndianReader(input) { BaseStream = { Position = startOffset } }; var buffer = er.ReadBytes(((int)er.BaseStream.Length) - ((int)er.BaseStream.Position)); er.Close(); input.Close(); input = new FileStream(filePath, FileMode.Open); var ew = new EndianWriter(input) { BaseStream = { Position = startOffset } }; ew.Write(new byte[size]); ew.Write(buffer); input.Close(); ew.Close(); }
// Patch Creation private void btnCreatePatch_Click(object sender, RoutedEventArgs e) { try { // Check the user isn't completly retarded if (!CheckAllCreateMandatoryFields()) { return; } // Check the user isn't a skid if (!CheckAllCreateMetaFilesExists()) { return; } // Paths string cleanMapPath = txtCreatePatchUnModifiedMap.Text; string moddedMapPath = txtCreatePatchModifiedMap.Text; string outputPath = txtCreatePatchOutputPatch.Text; string previewImage = txtCreatePatchPreviewImage.Text; // Details string author = txtCreatePatchContentAuthor.Text; string desc = txtCreatePatchContentDescription.Text; string name = txtCreatePatchContentName.Text; string outputName = txtCreatePatchOutputName.Text; // Make dat patch var patch = new Patch { Author = author, Description = desc, Name = name, OutputName = outputName, Screenshot = String.IsNullOrEmpty(previewImage) ? null : File.ReadAllBytes(previewImage), BuildString = _buildInfo.Version, PC = String.IsNullOrEmpty(_buildInfo.GameExecutable) ? false : true }; EndianReader originalReader = null; EndianReader newReader = null; try { originalReader = new EndianReader(File.OpenRead(cleanMapPath), Endian.BigEndian); newReader = new EndianReader(File.OpenRead(moddedMapPath), Endian.BigEndian); ICacheFile originalFile = CacheFileLoader.LoadCacheFile(originalReader, cleanMapPath, App.AssemblyStorage.AssemblySettings.DefaultDatabase); ICacheFile newFile = CacheFileLoader.LoadCacheFile(newReader, moddedMapPath, App.AssemblyStorage.AssemblySettings.DefaultDatabase); if (cbCreatePatchHasCustomMeta.IsChecked != null && (bool)cbCreatePatchHasCustomMeta.IsChecked && cboxCreatePatchTargetGame.SelectedIndex < 4) { var targetGame = (TargetGame)cboxCreatePatchTargetGame.SelectedIndex; byte[] mapInfo = File.ReadAllBytes(txtCreatePatchMapInfo.Text); var mapInfoFileInfo = new FileInfo(txtCreatePatchMapInfo.Text); FileInfo blfFileInfo; patch.CustomBlfContent = new BlfContent(mapInfoFileInfo.FullName, mapInfo, targetGame); #region Blf Data if (PatchCreationBlfOption0.Visibility == Visibility.Visible) { blfFileInfo = new FileInfo(txtCreatePatchblf0.Text); patch.CustomBlfContent.BlfContainerEntries.Add(new BlfContainerEntry(blfFileInfo.Name, File.ReadAllBytes(blfFileInfo.FullName))); } if (PatchCreationBlfOption1.Visibility == Visibility.Visible) { blfFileInfo = new FileInfo(txtCreatePatchblf1.Text); patch.CustomBlfContent.BlfContainerEntries.Add(new BlfContainerEntry(blfFileInfo.Name, File.ReadAllBytes(blfFileInfo.FullName))); } if (PatchCreationBlfOption2.Visibility == Visibility.Visible) { blfFileInfo = new FileInfo(txtCreatePatchblf2.Text); patch.CustomBlfContent.BlfContainerEntries.Add(new BlfContainerEntry(blfFileInfo.Name, File.ReadAllBytes(blfFileInfo.FullName))); } if (PatchCreationBlfOption3.Visibility == Visibility.Visible) { blfFileInfo = new FileInfo(txtCreatePatchblf3.Text); patch.CustomBlfContent.BlfContainerEntries.Add(new BlfContainerEntry(blfFileInfo.Name, File.ReadAllBytes(blfFileInfo.FullName))); } #endregion } PatchBuilder.BuildPatch(originalFile, originalReader, newFile, newReader, patch); } finally { if (originalReader != null) { originalReader.Dispose(); } if (newReader != null) { newReader.Dispose(); } } IWriter output = new EndianWriter(File.Open(outputPath, FileMode.Create, FileAccess.Write), Endian.BigEndian); AssemblyPatchWriter.WritePatch(patch, output); output.Dispose(); MetroMessageBox.Show("Patch Created!", "Your patch has been created in the designated location. Happy sailing, modder!"); } catch (Exception ex) { MetroException.Show(ex); } }
/// <summary> /// Writes the field in a compiled state to the stream specified. /// </summary> /// <param name="bw">Stream to write the field to.</param> /// <param name="magic">Virtual address modifier value for the specified stream.</param> public override void Write(EndianWriter bw, int magic) { Write(bw); }
private void WriteDataBlock(DataBlock block, SegmentPointer location, IStream stream) { // Don't write anything if the block has already been written if (_dataBlockAddresses.ContainsKey(block)) return; // Associate the location with the block _dataBlockAddresses[block] = location.AsPointer(); // Create a MemoryStream and write the block data to it (so fixups can be performed before writing it to the file) using (var buffer = new MemoryStream(block.Data.Length)) { var bufferWriter = new EndianWriter(buffer, stream.Endianness); bufferWriter.WriteBlock(block.Data); // Apply fixups FixBlockReferences(block, bufferWriter, stream); FixTagReferences(block, bufferWriter, stream); FixResourceReferences(block, bufferWriter, stream); FixStringIDReferences(block, bufferWriter); // Write the buffer to the file stream.SeekTo(location.AsOffset()); stream.WriteBlock(buffer.GetBuffer(), 0, (int) buffer.Length); } }
/// <summary> /// Extracts an XMA sound and converts it to a WAV. /// </summary> /// <param name="reader">The stream to read from.</param> /// <param name="offset">The offset of the data to extract.</param> /// <param name="rifx">The RIFX data for the sound.</param> /// <param name="outPath">The path of the file to save to.</param> public static void ExtractXMAToWAV(EndianReader reader, int offset, RIFX rifx, string outPath) { // Create a temporary file to write an XMA to string tempFile = Path.GetTempFileName(); try { using (EndianWriter output = new EndianWriter(File.OpenWrite(tempFile), EndianFormat.BigEndian)) { // Generate an XMA header // ADAPTED FROM wwisexmabank - I DO NOT TAKE ANY CREDIT WHATSOEVER FOR THE FOLLOWING CODE. // See http://hcs64.com/vgm_ripping.html for more information output.Write(0x52494646); // 'RIFF' output.EndianType = EndianFormat.LittleEndian; output.Write(rifx.DataSize + 0x34); output.EndianType = EndianFormat.BigEndian; output.Write(RIFFFormat.WAVE); // Generate the 'fmt ' chunk output.Write(0x666D7420); // 'fmt ' output.EndianType = EndianFormat.LittleEndian; output.Write(0x20); output.Write((short)0x165); // WAVE_FORMAT_XMA output.Write((short)16); // 16 bits per sample output.Write((short)0); // encode options ** output.Write((short)0); // largest skip output.Write((short)1); // # streams output.Write((byte)0); // loops output.Write((byte)3); // encoder version output.Write(0); // bytes per second ** output.Write(rifx.SampleRate); // sample rate output.Write(0); // loop start output.Write(0); // loop end output.Write((byte)0); // subframe loop data output.Write((byte)rifx.ChannelCount); // channels output.Write((short)0x0002);// channel mask // 'data' chunk output.EndianType = EndianFormat.BigEndian; output.Write(0x64617461); // 'data' output.EndianType = EndianFormat.LittleEndian; output.Write(rifx.DataSize); // Copy the data chunk contents from the original RIFX reader.SeekTo(offset + rifx.DataOffset); StreamUtil.Copy(reader, output, rifx.DataSize); // END ADAPTED CODE } // Convert it with towav RunProgramSilently("Helpers/towav.exe", "\"" + Path.GetFileName(tempFile) + "\"", Path.GetDirectoryName(tempFile)); // Move the WAV to the destination path if (File.Exists(outPath)) File.Delete(outPath); File.Move(Path.ChangeExtension(tempFile, "wav"), outPath); } finally { // Delete the temporary XMA file if (File.Exists(tempFile)) File.Delete(tempFile); } }
public static void DeleteBytes(string filePath, int startOffset, int size) { var input = new FileStream(filePath, FileMode.Open); var er = new EndianReader(input); var buffer = er.ReadBytes(startOffset); var baseStream = er.BaseStream; baseStream.Position += size; var buffer2 = er.ReadBytes(((int)er.BaseStream.Length) - ((int)er.BaseStream.Position)); er.Close(); input.Close(); input = new FileStream(filePath, FileMode.Create); var ew = new EndianWriter(input); ew.Write(buffer); ew.Write(buffer2); input.Close(); ew.Close(); }
public static byte[] GetXMA(byte[] buffer, SampleRate sRate, SoundType sType) { int rate; switch (sRate) { case SampleRate._22050Hz: rate = 22050; break; case SampleRate._44100Hz: rate = 44100; break; default: rate = 44100; break; //throw new Exception("Check sample rate."); } int cCount; switch (sType) { case SoundType.Mono: cCount = 1; break; case SoundType.Stereo: cCount = 2; break; //case SoundType.Unknown2: // cCount = 2; // footer = stereoFooter; // break; //case SoundType.Unknown3: // cCount = 2; // footer = stereoFooter; // break; default: throw new NotSupportedException("Unsupported Sound Type."); } var ms = new MemoryStream(); EndianWriter sw = new EndianWriter(ms, EndianFormat.BigEndian); sw.Write(0x52494646); // 'RIFF' sw.EndianType = EndianFormat.LittleEndian; sw.Write(buffer.Length + 0x34); sw.EndianType = EndianFormat.BigEndian; sw.Write(RIFFFormat.WAVE); // Generate the 'fmt ' chunk sw.Write(0x666D7420); // 'fmt ' sw.EndianType = EndianFormat.LittleEndian; sw.Write(0x20); sw.Write((short)0x165); sw.Write((short)16); sw.Write((short)0); sw.Write((short)0); sw.Write((short)1); sw.Write((byte)0); sw.Write((byte)3); sw.Write(0); sw.Write(rate); sw.Write(0); sw.Write(0); sw.Write((byte)0); sw.Write((byte)cCount); sw.Write((short)0x0002); // 'data' chunk sw.EndianType = EndianFormat.BigEndian; sw.Write(0x64617461); // 'data' sw.EndianType = EndianFormat.LittleEndian; sw.Write(buffer.Length); sw.Write(buffer); sw.Close(); sw.Dispose(); return(ms.ToArray()); }
/// <summary> /// Writes the field in a decompiled state to the stream specified. /// </summary> /// <param name="bw">Stream to write the field to.</param> public override void Write(EndianWriter bw) { bw.Write(To); bw.Write(From); }
public override void Serialize(EndianWriter writer) { throw new NotImplementedException(); }
public void SaveStrings(IStream stream, LocaleTable locales) { MemoryStream offsetData = new MemoryStream(); MemoryStream stringData = new MemoryStream(); IWriter offsetWriter = new EndianWriter(offsetData, Endian.BigEndian); IWriter stringWriter = new EndianWriter(stringData, Endian.BigEndian); try { // Write the string and offset data to buffers foreach (Locale locale in locales.Strings) { WriteLocalePointer(offsetWriter, locale.ID, (int)stringWriter.Position); stringWriter.WriteUTF8(locale.Value); } // Round the size of the string data up to the nearest multiple of 0x10 (AES block size) stringData.SetLength((stringData.Position + 0xF) & ~0xF); // Update the two locale data hashes if we need to // (the hash arrays are set to null if the build doesn't need them) if (IndexTableHash != null) IndexTableHash = SHA1.Transform(offsetData.GetBuffer(), 0, (int)offsetData.Length); if (StringDataHash != null) StringDataHash = SHA1.Transform(stringData.GetBuffer(), 0, (int)stringData.Length); // Make sure there's free space for the offset table and then write it to the file LocaleDataLocation += StreamUtil.MakeFreeSpace(stream, LocaleIndexTableLocation.AsOffset(), LocaleDataLocation.AsOffset(), offsetData.Length, _pageSize); stream.SeekTo(LocaleIndexTableLocation.AsOffset()); stream.WriteBlock(offsetData.GetBuffer(), 0, (int)offsetData.Length); // Encrypt the string data if necessary byte[] strings = stringData.GetBuffer(); if (_encryptionKey != null) strings = AES.Encrypt(strings, 0, (int)stringData.Length, _encryptionKey.Key, _encryptionKey.IV); // Make free space for the string data uint oldDataEnd = (uint)((LocaleDataLocation.AsOffset() + LocaleTableSize + _pageSize - 1) & ~(_pageSize - 1)); // Add the old table size and round it up StreamUtil.MakeFreeSpace(stream, LocaleDataLocation.AsOffset(), oldDataEnd, stringData.Length, _pageSize); LocaleTableSize = (int)stringData.Length; // Write it to the file stream.SeekTo(LocaleDataLocation.AsOffset()); stream.WriteBlock(strings, 0, (int)stringData.Length); // Update the string count and recalculate the language table offsets StringCount = locales.Strings.Count; int localePointerSize = (int)(offsetData.Length / locales.Strings.Count); _languageGlobals.RecalculateLanguageOffsets(localePointerSize); } finally { offsetWriter.Close(); stringWriter.Close(); } }
public override void Serialize(EndianWriter writer) { writer.WriteBE(TitleId); }
private void contextExtract_Click(object sender, RoutedEventArgs e) { // Get the menu item and the tag var item = e.Source as MenuItem; if (item == null) return; var tag = item.DataContext as TagEntry; if (tag == null) return; // Ask where to save the extracted tag collection var sfd = new SaveFileDialog { Title = "Save Tag Set", Filter = "Tag Container Files|*.tagc" }; bool? result = sfd.ShowDialog(); if (!result.Value) return; // Make a tag container var container = new TagContainer(); // Recursively extract tags var tagsToProcess = new Queue<ITag>(); var tagsProcessed = new HashSet<ITag>(); var resourcesToProcess = new Queue<DatumIndex>(); var resourcesProcessed = new HashSet<DatumIndex>(); var resourcePagesProcessed = new HashSet<ResourcePage>(); tagsToProcess.Enqueue(tag.RawTag); ResourceTable resources = null; using (IReader reader = _mapManager.OpenRead()) { while (tagsToProcess.Count > 0) { ITag currentTag = tagsToProcess.Dequeue(); if (tagsProcessed.Contains(currentTag)) continue; // Get the plugin path string className = VariousFunctions.SterilizeTagClassName(CharConstant.ToString(currentTag.Class.Magic)).Trim(); string pluginPath = string.Format("{0}\\{1}\\{2}.xml", VariousFunctions.GetApplicationLocation() + @"Plugins", _buildInfo.Settings.GetSetting<string>("plugins"), className); // Extract dem data blocks var blockBuilder = new DataBlockBuilder(reader, currentTag.MetaLocation, _cacheFile, _buildInfo); using (XmlReader pluginReader = XmlReader.Create(pluginPath)) AssemblyPluginLoader.LoadPlugin(pluginReader, blockBuilder); foreach (DataBlock block in blockBuilder.DataBlocks) container.AddDataBlock(block); // Add data for the tag that was extracted string tagName = _cacheFile.FileNames.GetTagName(currentTag) ?? currentTag.Index.ToString(); var extractedTag = new ExtractedTag(currentTag.Index, currentTag.MetaLocation.AsPointer(), currentTag.Class.Magic, tagName); container.AddTag(extractedTag); // Mark the tag as processed and then enqueue all of its child tags and resources tagsProcessed.Add(currentTag); foreach (DatumIndex tagRef in blockBuilder.ReferencedTags) tagsToProcess.Enqueue(_cacheFile.Tags[tagRef]); foreach (DatumIndex resource in blockBuilder.ReferencedResources) resourcesToProcess.Enqueue(resource); } // Load the resource table in if necessary if (resourcesToProcess.Count > 0) resources = _cacheFile.Resources.LoadResourceTable(reader); } // Extract resource info if (resources != null) { while (resourcesToProcess.Count > 0) { DatumIndex index = resourcesToProcess.Dequeue(); if (resourcesProcessed.Contains(index)) continue; // Add the resource Resource resource = resources.Resources[index.Index]; container.AddResource(new ExtractedResourceInfo(resource)); // Add data for its pages if (resource.Location == null) continue; if (resource.Location.PrimaryPage != null && !resourcePagesProcessed.Contains(resource.Location.PrimaryPage)) { container.AddResourcePage(resource.Location.PrimaryPage); resourcePagesProcessed.Add(resource.Location.PrimaryPage); } if (resource.Location.SecondaryPage == null || resourcePagesProcessed.Contains(resource.Location.SecondaryPage)) continue; container.AddResourcePage(resource.Location.SecondaryPage); resourcePagesProcessed.Add(resource.Location.SecondaryPage); } } // Write it to a file using (var writer = new EndianWriter(File.Open(sfd.FileName, FileMode.Create, FileAccess.Write), Endian.BigEndian)) TagContainerWriter.WriteTagContainer(container, writer); // YAY! MetroMessageBox.Show("Extraction Successful", "Extracted " + container.Tags.Count + " tag(s), " + container.DataBlocks.Count + " data block(s), " + container.ResourcePages.Count + " resource page pointer(s), and " + container.Resources.Count + " resource pointer(s)."); }
public override object Execute(List <string> args) { if (args.Count < 1 || args.Count > 2) { return(false); } if (args.Count == 2 && (args[0].ToLower() != "raw")) { return(false); } var file = ""; if (args.Count == 1) { file = args[0]; } else { file = args[1]; } var resourceContext = new ResourceSerializationContext(CacheContext, Geometry.Resource); var definition = CacheContext.Deserializer.Deserialize <RenderGeometryApiResourceDefinition>(resourceContext); if (args.Count == 2) { using (var edResourceStream = new MemoryStream()) using (var edResourceReader = new EndianReader(edResourceStream, EndianFormat.LittleEndian)) { var directory = args[1]; if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } var dataOutDir = directory; for (var i = 0; i < definition.VertexBuffers.Count; i++) { edResourceStream.Position = definition.VertexBuffers[i].Definition.Data.Address.Offset; var vertexBuffer = definition.VertexBuffers[i].Definition; dataOutDir = Path.Combine(directory, $"{i}_{vertexBuffer.Format}_{vertexBuffer.Count}"); using (EndianWriter output = new EndianWriter(File.OpenWrite(dataOutDir), EndianFormat.LittleEndian)) { byte[] data = edResourceReader.ReadBytes((int)vertexBuffer.Data.Size); output.WriteBlock(data); } } } } else { // // Convert Blam data to ElDorado data // using (var fileStream = File.Create(file)) using (var fileWriter = new StreamWriter(fileStream)) { using (var edResourceStream = new MemoryStream()) using (var edResourceReader = new EndianReader(edResourceStream, EndianFormat.LittleEndian)) { // // Convert Blam vertex buffers // Console.Write("Converting vertex buffers..."); CacheContext.ExtractResource(Geometry.Resource, edResourceStream); for (var i = 0; i < definition.VertexBuffers.Count; i++) { edResourceStream.Position = definition.VertexBuffers[i].Definition.Data.Address.Offset; var vertexBuffer = definition.VertexBuffers[i].Definition; //fileWriter.WriteLine($"Offset = {vertexBuffer.Data.Address.Offset.ToString("X8")} Count = {vertexBuffer.Count} Size = {vertexBuffer.VertexSize}, Format = {vertexBuffer.Format.ToString()}"); //fileWriter.WriteLine(Environment.NewLine); //fileWriter.WriteLine($"Vertex buffer index: {i}"); switch (vertexBuffer.Format) { case VertexBufferFormat.TinyPosition: for (var j = 0; j < vertexBuffer.Count; j++) { fileWriter.WriteLine($"Position = ({edResourceReader.ReadUInt16().ToString("X4")},{edResourceReader.ReadUInt16().ToString("X4")},{edResourceReader.ReadUInt16().ToString("X4")},{edResourceReader.ReadUInt16().ToString("X4")})"); fileWriter.WriteLine($"Normal = ({edResourceReader.ReadByte().ToString("X2")},{edResourceReader.ReadByte().ToString("X2")},{edResourceReader.ReadByte().ToString("X2")},{edResourceReader.ReadByte().ToString("X2")})"); fileWriter.WriteLine($"Color = {edResourceReader.ReadUInt32().ToString("X8")}"); } break; case VertexBufferFormat.StaticPerVertex: for (var j = 0; j < vertexBuffer.Count; j++) { fileWriter.WriteLine($"{vertexBuffer.Format} index: {j}:"); fileWriter.WriteLine($"Texcoord = " + edResourceReader.ReadUInt32().ToString("X8")); fileWriter.WriteLine($"Texcoord = " + edResourceReader.ReadUInt32().ToString("X8")); fileWriter.WriteLine($"Texcoord = " + edResourceReader.ReadUInt32().ToString("X8")); fileWriter.WriteLine($"Texcoord = " + edResourceReader.ReadUInt32().ToString("X8")); fileWriter.WriteLine($"Texcoord = " + edResourceReader.ReadUInt32().ToString("X8")); fileWriter.WriteLine($"End of {vertexBuffer.Format} index: {j}"); fileWriter.WriteLine(Environment.NewLine); } break; case VertexBufferFormat.Skinned: for (var j = 0; j < vertexBuffer.Count; j++) { fileWriter.WriteLine($"{j}:"); fileWriter.WriteLine($"Position X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle()); fileWriter.WriteLine($"Texcoord U = " + edResourceReader.ReadSingle() + " V = " + edResourceReader.ReadSingle()); fileWriter.WriteLine($"Normal X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle()); fileWriter.WriteLine($"Tangent X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle()); fileWriter.WriteLine($"Binormal X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle()); edResourceReader.ReadUInt32(); edResourceReader.ReadUInt32(); } break; /* * case VertexBufferFormat.Unknown1B: * var goodCount = 0; * for (var j = 0; j < vertexBuffer.Count; j++) * { * //fileWriter.WriteLine($"Index: {j}:"); * string values = $"({ edResourceReader.ReadSingle()},{ edResourceReader.ReadSingle()}," + * $"{edResourceReader.ReadSingle()},{edResourceReader.ReadSingle()},{edResourceReader.ReadSingle()},{edResourceReader.ReadSingle()}" + * $",{edResourceReader.ReadSingle()},{edResourceReader.ReadSingle()},{edResourceReader.ReadSingle()})"; * if(values != "(0,0,0,0,0,0,0,0,0)") * { * goodCount++; * //fileWriter.WriteLine($"(1,2,3,4,5,6,7,8,9) = "+values); * } * * * /* * fileWriter.WriteLine($"Unknown 1 = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Unknown 2 = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Unknown 3 = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Unknown 4 = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Unknown 5 = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Unknown 6 = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Unknown 7 = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Unknown 8 = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Unknown 9 = " + edResourceReader.ReadSingle()); * * } * //fileWriter.WriteLine($"Valid Unknown1B count = {goodCount}"); * break; * * case VertexBufferFormat.Unknown1A: * for (var j = 0; j < vertexBuffer.Count; j++) * { * //fileWriter.WriteLine($"Index: {j}:"); * //fileWriter.WriteLine($"Unknown 1 = " + edResourceReader.ReadUInt32().ToString("X8")); * fileWriter.WriteLine($"(1,2,3) = ({edResourceReader.ReadUInt32().ToString("X8")},{edResourceReader.ReadUInt32().ToString("X8")},{edResourceReader.ReadUInt32().ToString("X8")})"); * } * break; * * case VertexBufferFormat.Rigid: * for (var j = 0; j < vertexBuffer.Count; j++) * { * fileWriter.WriteLine($"{j}:"); * fileWriter.WriteLine($"Position X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Texcoord U = " + edResourceReader.ReadSingle() + " V = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Normal X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Tangent X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Binormal X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle()); * } * break; * * case VertexBufferFormat.StaticPerPixel: * for (var j = 0; j < vertexBuffer.Count; j++) * { * fileWriter.WriteLine($"{j} U = " + edResourceReader.ReadSingle() + " V = " + edResourceReader.ReadSingle()); * //fileWriter.WriteLine(Environment.NewLine); * } * break; * * case VertexBufferFormat.AmbientPrt: * for (var j = 0; j < vertexBuffer.Count; j++) * { * fileWriter.WriteLine($"{j} Blend weight = " + edResourceReader.ReadSingle()); * //fileWriter.WriteLine(Environment.NewLine); * } * break; * * * case VertexBufferFormat.World: * for (var j = 0; j < vertexBuffer.Count; j++) * { * fileWriter.WriteLine($"{j}:"); * fileWriter.WriteLine($"Position X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Texcoord U = " + edResourceReader.ReadSingle() + " V = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Normal X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Tangent X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Binormal X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle()); * } * break; * * * */ /* * case VertexBufferFormat.QuadraticPrt: * for (var j = 0; j < vertexBuffer.Count; j++) * { * fileWriter.WriteLine($"{vertexBuffer.Format} index: {j}:"); * fileWriter.WriteLine($"A X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"B X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"C X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"End of {vertexBuffer.Format} index: {j}"); * fileWriter.WriteLine(Environment.NewLine); * } * break; * * * * case VertexBufferFormat.Unknown1B: * for (var j = 0; j < vertexBuffer.Count; j++) * { * fileWriter.WriteLine($"{vertexBuffer.Format} index: {j}:"); * fileWriter.WriteLine($"Unknown 1 = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Unknown 2 = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Unknown 3 = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Unknown 4 = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Unknown 5 = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Unknown 6 = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Unknown 7 = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Unknown 8 = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Unknown 9 = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"End of {vertexBuffer.Format} index: {j}"); * fileWriter.WriteLine(Environment.NewLine); * } * break; * * case VertexBufferFormat.Decorator: * for (var j = 0; j < vertexBuffer.Count; j++) * { * fileWriter.WriteLine($"{vertexBuffer.Format} index: {j}:"); * fileWriter.WriteLine($"Position X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Texcoord U = " + edResourceReader.ReadSingle() + " V = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"Normal X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle()); * fileWriter.WriteLine($"End of {vertexBuffer.Format} index: {j}"); * fileWriter.WriteLine(Environment.NewLine); * } * break; * * case VertexBufferFormat.LinearPrt: * for (var j = 0; j < vertexBuffer.Count; j++) * { * fileWriter.WriteLine($"{vertexBuffer.Format} index: {j}:"); * fileWriter.WriteLine($"Hex : " + edResourceReader.ReadUInt32().ToString("X8")); * fileWriter.WriteLine($"End of {vertexBuffer.Format} index: {j}"); * fileWriter.WriteLine(Environment.NewLine); * } * break; */ } //fileWriter.WriteLine($"End of Vertex Buffer index: {i}"); //fileWriter.WriteLine(Environment.NewLine); } } } } return(true); }
internal override void SerializeStreamer(EndianWriter writer) { throw new NotImplementedException(); }
private void WriteDataBlock(DataBlock block, SegmentPointer location, IStream stream, ITag tag = null) { if (tag == null && _dataBlockAddresses.ContainsKey(block)) // Don't write anything if the block has already been written { return; } // Associate the location with the block _dataBlockAddresses[block] = location.AsPointer(); // Create a MemoryStream and write the block data to it (so fixups can be performed before writing it to the file) using (var buffer = new MemoryStream(block.Data.Length)) { var bufferWriter = new EndianWriter(buffer, stream.Endianness); bufferWriter.WriteBlock(block.Data); // Apply fixups FixBlockReferences(block, bufferWriter, stream); FixTagReferences(block, bufferWriter, stream); FixResourceReferences(block, bufferWriter, stream); FixStringIdReferences(block, bufferWriter); if (tag != null) { FixUnicListReferences(block, tag, bufferWriter, stream); } FixInteropReferences(block, bufferWriter, stream, location); FixEffectReferences(block, bufferWriter); if (!_dupeReuseSoundGestalt) { FixSoundReferences(block, bufferWriter, stream); } // sort after fixups if (block.Sortable && block.EntrySize >= 4) { var entries = new List <Tuple <uint, byte[]> >(); var bufferReader = new EndianReader(buffer, stream.Endianness); for (int i = 0; i < block.EntryCount; i++) { buffer.Position = i * block.EntrySize; uint sid = bufferReader.ReadUInt32(); byte[] rest = bufferReader.ReadBlock(block.EntrySize - 4); entries.Add(new Tuple <uint, byte[]>(sid, rest)); } buffer.Position = 0; foreach (var entry in entries.OrderBy(e => e.Item1)) { bufferWriter.WriteUInt32(entry.Item1); bufferWriter.WriteBlock(entry.Item2); } } // Write the buffer to the file stream.SeekTo(location.AsOffset()); stream.WriteBlock(buffer.ToArray(), 0, (int)buffer.Length); } // Write shader fixups (they can't be done in-memory because they require cache file expansion) FixShaderReferences(block, stream, location); }
public override void WriteValue(EndianWriter writer) { }
private Sound ConvertSound(Stream cacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, Sound sound, string blamTag_Name) { if (BlamSoundGestalt == null) { BlamSoundGestalt = PortingContextFactory.LoadSoundGestalt(CacheContext, ref BlamCache); } if (!File.Exists(@"Tools\ffmpeg.exe") || !File.Exists(@"Tools\towav.exe")) { Console.WriteLine("Failed to locate sound conversion tools, please install ffmpeg and towav in the Tools folder"); return(null); } // // Convert Sound Tag Data // var platformCodec = BlamSoundGestalt.PlatformCodecs[sound.SoundReference.PlatformCodecIndex]; var playbackParameters = BlamSoundGestalt.PlaybackParameters[sound.SoundReference.PlaybackParameterIndex]; var scale = BlamSoundGestalt.Scales[sound.SoundReference.ScaleIndex]; var promotion = sound.SoundReference.PromotionIndex != -1 ? BlamSoundGestalt.Promotions[sound.SoundReference.PromotionIndex] : new Promotion(); var customPlayBack = sound.SoundReference.CustomPlaybackIndex != -1 ? new List <CustomPlayback> { BlamSoundGestalt.CustomPlaybacks[sound.SoundReference.CustomPlaybackIndex] } : new List <CustomPlayback>(); var loop = sound.Flags.HasFlag(Sound.FlagsValue.LoopingSound); sound.PlaybackParameters = playbackParameters; sound.Scale = scale; sound.PlatformCodec = platformCodec.DeepClone(); sound.Promotion = promotion; sound.CustomPlayBacks = customPlayBack; // // Tag fixes // sound.SampleRate = platformCodec.SampleRate; sound.ImportType = ImportType.SingleLayer; // helps looping sound? there is another value, 10 for Unknown2 but I don't know when to activate it. if (sound.SoundReference.PitchRangeCount > 1) { sound.ImportType = ImportType.MultiLayer; } sound.PlatformCodec.LoadMode = 0; // // Process all the pitch ranges // var xmaFileSize = BlamSoundGestalt.GetFileSize(sound.SoundReference.PitchRangeIndex, sound.SoundReference.PitchRangeCount); if (xmaFileSize < 0) { return(null); } var xmaData = BlamCache.GetSoundRaw(sound.SoundReference.ZoneAssetHandle, xmaFileSize); if (xmaData == null) { return(null); } sound.PitchRanges = new List <PitchRange>(sound.SoundReference.PitchRangeCount); var soundDataAggregate = new byte[0].AsEnumerable(); var currentSoundDataOffset = 0; var totalSampleCount = (uint)0; for (int pitchRangeIndex = sound.SoundReference.PitchRangeIndex; pitchRangeIndex < sound.SoundReference.PitchRangeIndex + sound.SoundReference.PitchRangeCount; pitchRangeIndex++) { totalSampleCount += BlamSoundGestalt.GetSamplesPerPitchRange(pitchRangeIndex); // // Convert Blam pitch range to ElDorado format // var pitchRange = BlamSoundGestalt.PitchRanges[pitchRangeIndex]; pitchRange.ImportName = ConvertStringId(BlamSoundGestalt.ImportNames[pitchRange.ImportNameIndex].Name); pitchRange.PitchRangeParameters = BlamSoundGestalt.PitchRangeParameters[pitchRange.PitchRangeParametersIndex]; pitchRange.Unknown1 = 0; pitchRange.Unknown2 = 0; pitchRange.Unknown3 = 0; pitchRange.Unknown4 = 0; pitchRange.Unknown5 = -1; pitchRange.Unknown6 = -1; //I suspect this unknown7 to be a flag to tell if there is a Unknownblock in extrainfo. (See a sound in udlg for example) pitchRange.Unknown7 = 0; pitchRange.PermutationCount = (byte)BlamSoundGestalt.GetPermutationCount(pitchRangeIndex); pitchRange.Unknown8 = -1; // Add pitch range to ED sound sound.PitchRanges.Add(pitchRange); var newPitchRangeIndex = pitchRangeIndex - sound.SoundReference.PitchRangeIndex; sound.PitchRanges[newPitchRangeIndex].Permutations = new List <Permutation>(); // // Determine the audio channel count // var channelCount = Encoding.GetChannelCount(sound.PlatformCodec.Encoding); // // Set compression format // sound.PlatformCodec.Compression = Compression.MP3; // // Convert Blam permutations to ElDorado format // var useCache = Sounds.UseAudioCacheCommand.AudioCacheDirectory != null; var basePermutationCacheName = Path.Combine( useCache ? Sounds.UseAudioCacheCommand.AudioCacheDirectory.FullName : TempDirectory.FullName, GetTagFileFriendlyName(blamTag_Name)); var permutationCount = BlamSoundGestalt.GetPermutationCount(pitchRangeIndex); var permutationOrder = BlamSoundGestalt.GetPermutationOrder(pitchRangeIndex); var relativePitchRangeIndex = pitchRangeIndex - sound.SoundReference.PitchRangeIndex; for (int i = 0; i < permutationCount; i++) { var permutationIndex = pitchRange.FirstPermutationIndex + i; var permutationSize = BlamSoundGestalt.GetPermutationSize(permutationIndex); var permutationOffset = BlamSoundGestalt.GetPermutationOffset(permutationIndex); var permutation = BlamSoundGestalt.GetPermutation(permutationIndex).DeepClone(); permutation.ImportName = ConvertStringId(BlamSoundGestalt.ImportNames[permutation.ImportNameIndex].Name); permutation.SkipFraction = new Bounds <float>(0.0f, permutation.Gain); permutation.PermutationChunks = new List <PermutationChunk>(); permutation.PermutationNumber = (uint)permutationOrder[i]; permutation.IsNotFirstPermutation = (uint)(permutation.PermutationNumber == 0 ? 0 : 1); string permutationName = $"{basePermutationCacheName}_{relativePitchRangeIndex}_{i}"; string extension = "mp3"; var cacheFileName = $"{permutationName}.{extension}"; bool exists = File.Exists(cacheFileName); byte[] permutationData = null; if (!exists || !useCache) { BlamSound blamSound = SoundConverter.ConvertGen3Sound(BlamCache, BlamSoundGestalt, sound, relativePitchRangeIndex, i, xmaData); permutationData = blamSound.Data; if (useCache) { using (EndianWriter output = new EndianWriter(new FileStream(cacheFileName, FileMode.Create, FileAccess.Write, FileShare.None), EndianFormat.BigEndian)) { output.WriteBlock(blamSound.Data); } } } else { permutationData = File.ReadAllBytes(cacheFileName); } permutation.PermutationChunks.Add(new PermutationChunk(currentSoundDataOffset, permutationData.Length)); currentSoundDataOffset += permutationData.Length; pitchRange.Permutations.Add(permutation); soundDataAggregate = soundDataAggregate.Concat(permutationData); } } sound.Promotion.LongestPermutationDuration = (uint)sound.SoundReference.MaximumPlayTime; sound.Promotion.TotalSampleSize = totalSampleCount; // // Convert Blam extra info to ElDorado format // var extraInfo = new ExtraInfo() { LanguagePermutations = new List <ExtraInfo.LanguagePermutation>(), EncodedPermutationSections = new List <ExtraInfo.EncodedPermutationSection>() }; for (int u = 0; u < sound.SoundReference.PitchRangeCount; u++) { var pitchRange = BlamSoundGestalt.PitchRanges[sound.SoundReference.PitchRangeIndex + u]; for (int i = 0; i < pitchRange.PermutationCount; i++) { var permutation = BlamSoundGestalt.GetPermutation(pitchRange.FirstPermutationIndex + i); var permutationChunk = BlamSoundGestalt.GetPermutationChunk(permutation.FirstPermutationChunkIndex); extraInfo.LanguagePermutations.Add(new ExtraInfo.LanguagePermutation { RawInfo = new List <ExtraInfo.LanguagePermutation.RawInfoBlock> { new ExtraInfo.LanguagePermutation.RawInfoBlock { SkipFractionName = StringId.Invalid, UnknownList = new List <ExtraInfo.LanguagePermutation.RawInfoBlock.Unknown> { new ExtraInfo.LanguagePermutation.RawInfoBlock.Unknown { Unknown1 = permutationChunk.UnknownA, Unknown2 = permutationChunk.UnknownSize, Unknown3 = 0, Unknown4 = permutation.SampleSize, Unknown5 = 0, Unknown6 = permutationChunk.EncodedSize & 0xFFFF } }, Compression = 8, ResourceSampleSize = pitchRange.Permutations[i].SampleSize, ResourceSampleOffset = (uint)pitchRange.Permutations[i].PermutationChunks[0].Offset, SampleCount = (uint)pitchRange.Permutations[i].PermutationChunks[0].EncodedSize & 0x3FFFFFF, //SampleCount = (uint)Math.Floor(pitchRange.Permutations[i].SampleSize * 128000.0 / (8 * sound.SampleRate.GetSampleRateHz())), Unknown24 = 480 } } }); } } if (sound.SoundReference.ExtraInfoIndex != -1) { foreach (var section in BlamSoundGestalt.ExtraInfo[sound.SoundReference.ExtraInfoIndex].EncodedPermutationSections) { var newSection = section.DeepClone(); foreach (var info in newSection.SoundDialogueInfo) { for (var i = ((info.MouthDataLength % 2) == 0 ? 0 : 1); (i + 1) < info.MouthDataLength; i += 2) { Array.Reverse(newSection.EncodedData, (int)(info.MouthDataOffset + i), 2); } for (var i = ((info.LipsyncDataLength % 2) == 0 ? 0 : 1); (i + 1) < info.LipsyncDataLength; i += 2) { Array.Reverse(newSection.EncodedData, (int)(info.LipsyncDataOffset + i), 2); } } extraInfo.EncodedPermutationSections.Add(newSection); } } sound.ExtraInfo = new List <ExtraInfo> { extraInfo }; // // Convert Blam languages to ElDorado format // if (sound.SoundReference.LanguageIndex != -1) { sound.Languages = new List <LanguageBlock>(); foreach (var language in BlamSoundGestalt.Languages) { sound.Languages.Add(new LanguageBlock { Language = language.Language, PermutationDurations = new List <LanguageBlock.PermutationDurationBlock>(), PitchRangeDurations = new List <LanguageBlock.PitchRangeDurationBlock>(), }); //Add all the Pitch Range Duration block (pitch range count dependent) var curLanguage = sound.Languages.Last(); for (int i = 0; i < sound.SoundReference.PitchRangeCount; i++) { curLanguage.PitchRangeDurations.Add(language.PitchRangeDurations[sound.SoundReference.LanguageIndex + i]); } //Add all the Permutation Duration Block and adjust offsets for (int i = 0; i < curLanguage.PitchRangeDurations.Count; i++) { var curPRD = curLanguage.PitchRangeDurations[i]; //Get current block count for new index short newPermutationIndex = (short)curLanguage.PermutationDurations.Count(); for (int j = curPRD.PermutationStartIndex; j < curPRD.PermutationStartIndex + curPRD.PermutationCount; j++) { curLanguage.PermutationDurations.Add(language.PermutationDurations[j]); } //apply new index curPRD.PermutationStartIndex = newPermutationIndex; } } } // // Prepare resource // sound.Unused = new byte[] { 0, 0, 0, 0 }; sound.Unknown12 = 0; sound.Resource = new PageableResource { Page = new RawPage { Index = -1, }, Resource = new TagResourceGen3 { ResourceType = TagResourceTypeGen3.Sound, DefinitionData = new byte[20], DefinitionAddress = new CacheResourceAddress(CacheResourceAddressType.Definition, 536870912), ResourceFixups = new List <TagResourceGen3.ResourceFixup>(), ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(), Unknown2 = 1 } }; var data = soundDataAggregate.ToArray(); var resourceContext = new ResourceSerializationContext(CacheContext, sound.Resource); CacheContext.Serializer.Serialize(resourceContext, new SoundResourceDefinition { Data = new TagData(data.Length, new CacheResourceAddress(CacheResourceAddressType.Resource, 0)) }); var definitionFixup = new TagResourceGen3.ResourceFixup() { BlockOffset = 12, Address = new CacheResourceAddress(CacheResourceAddressType.Resource, 1073741824) }; sound.Resource.Resource.ResourceFixups.Add(definitionFixup); sound.Resource.ChangeLocation(ResourceLocation.Audio); var resource = sound.Resource; if (resource == null) { throw new ArgumentNullException("resource"); } var cache = CacheContext.GetResourceCache(ResourceLocation.Audio); if (!resourceStreams.ContainsKey(ResourceLocation.Audio)) { resourceStreams[ResourceLocation.Audio] = FlagIsSet(PortingFlags.Memory) ? new MemoryStream() : (Stream)CacheContext.OpenResourceCacheReadWrite(ResourceLocation.Audio); if (FlagIsSet(PortingFlags.Memory)) { using (var resourceStream = CacheContext.OpenResourceCacheRead(ResourceLocation.Audio)) resourceStream.CopyTo(resourceStreams[ResourceLocation.Audio]); } } resource.Page.Index = cache.Add(resourceStreams[ResourceLocation.Audio], data, out uint compressedSize); resource.Page.CompressedBlockSize = compressedSize; resource.Page.UncompressedBlockSize = (uint)data.Length; resource.DisableChecksum(); for (int i = 0; i < 4; i++) { sound.Resource.Resource.DefinitionData[i] = (byte)(sound.Resource.Page.UncompressedBlockSize >> (i * 8)); } return(sound); }
/// <summary> /// Saves selected permutations of a sound tag. /// </summary> /// <param name="Folder">The folder to save all files in. Each file will be named as the permutation name.</param> /// <param name="Cache">The CacheFile containing the tag.</param> /// <param name="Tag">The sound tag.</param> /// <param name="Format">The format in which to save the data.</param> /// <param name="Indices">The indices of the permutations to extract.</param> public static void SaveSelected(string Folder, CacheBase Cache, CacheBase.IndexItem Tag, SoundFormat Format, List <int> Indices, bool Overwrite) { var snd_ = DefinitionsManager.snd_(Cache, Tag); List <byte[]> perms = new List <byte[]>(); var ugh_ = Cache.ugh_; var playback = ugh_.PlayBacks[snd_.PlaybackIndex]; var data = Cache.GetSoundRaw(snd_.RawID, GetTotalSize(ugh_, playback)); if (playback.PermutationCount == 1) { perms.Add(data); } else { Folder = Directory.GetParent(Folder) + "\\" + Path.GetFileNameWithoutExtension(Folder); for (int i = 0; i < playback.PermutationCount; i++) { var perm = Cache.ugh_.SoundPermutations[playback.FirstPermutation + i]; perms.Add(GetPermData(data, ugh_, perm)); } } #region XMA if (Format == SoundFormat.XMA) { foreach (int index in Indices) { string Filename = (playback.PermutationCount == 1) ? Folder : Folder + "\\" + ugh_.SoundNames[ugh_.SoundPermutations[playback.FirstPermutation + index].NameIndex].Name + ".xma"; if (!Filename.EndsWith(".xma")) { Filename += ".xma"; } if (File.Exists(Filename) && !Overwrite) { continue; } byte[] buffer = perms[index]; var codec = Cache.ugh_.Codecs[snd_.CodecIndex]; var xma = GetXMA(buffer, snd_.SampleRate, codec.Type); if (!Directory.GetParent(Filename).Exists) { Directory.GetParent(Filename).Create(); } var fs = new FileStream(Filename, FileMode.Create); EndianWriter sw = new EndianWriter(fs, EndianFormat.BigEndian); sw.Write(xma); sw.Close(); sw.Dispose(); } } #endregion #region WAV else if (Format == SoundFormat.WAV) { foreach (int index in Indices) { string Filename = (playback.PermutationCount == 1) ? Folder : Folder + "\\" + ugh_.SoundNames[ugh_.SoundPermutations[playback.FirstPermutation + index].NameIndex].Name + ".wav"; if (!Filename.EndsWith(".wav")) { Filename += ".wav"; } if (File.Exists(Filename) && !Overwrite) { continue; } var tempName = Path.GetTempFileName(); #region Write XMA var buffer = perms[index]; var codec = Cache.ugh_.Codecs[snd_.CodecIndex]; var xma = GetXMA(buffer, snd_.SampleRate, codec.Type); var fs = File.OpenWrite(tempName); EndianWriter sw = new EndianWriter(fs, EndianFormat.BigEndian); sw.Write(xma); sw.Close(); sw.Dispose(); #endregion var info = new ProcessStartInfo(towav, tempName) { CreateNoWindow = true, UseShellExecute = false, WorkingDirectory = Directory.GetParent(tempName).FullName }; Process.Start(info).WaitForExit(); if (File.Exists(Filename)) { File.Delete(Filename); } if (!Directory.GetParent(Filename).Exists) { Directory.GetParent(Filename).Create(); } File.Move(Path.ChangeExtension(tempName, "wav"), Filename); if (File.Exists(tempName)) { File.Delete(tempName); } } } #endregion #region RAW else if (Format == SoundFormat.RAW) { foreach (int index in Indices) { string Filename = (playback.PermutationCount == 1) ? Folder : Folder + "\\" + ugh_.SoundNames[ugh_.SoundPermutations[playback.FirstPermutation + index].NameIndex].Name + ".bin"; if (!Filename.EndsWith(".bin")) { Filename += ".bin"; } if (File.Exists(Filename) && !Overwrite) { continue; } byte[] buffer = perms[index]; if (!Directory.GetParent(Filename).Exists) { Directory.GetParent(Filename).Create(); } var fs = new FileStream(Filename, FileMode.Create); BinaryWriter sw = new BinaryWriter(fs); sw.Write(buffer); sw.Close(); sw.Dispose(); } } #endregion }
private void UpdateMeta(MetaWriter.SaveType type, bool onlyUpdateChanged, bool showActionDialog = true) { if (type == MetaWriter.SaveType.File) { using (EndianWriter writer = new EndianWriter(_streamManager.OpenWrite(), Endian.BigEndian)) { MetaWriter metaUpdate = new MetaWriter(writer, _tag.RawTag.MetaLocation.AsOffset(), _cache, type, _fileChanges); metaUpdate.WriteFields(_pluginVisitor.Values); _fileChanges.MarkAllUnchanged(); } if (showActionDialog) MetroMessageBox.Show("Meta Saved", "The metadata has been saved back to the original file."); } else { if (Settings.xbdm.Connect()) { FieldChangeSet changes = onlyUpdateChanged ? _memoryChanges : null; MetaWriter metaUpdate = new MetaWriter(Settings.xbdm.MemoryStream, _tag.RawTag.MetaLocation.AsAddress(), _cache, type, changes); metaUpdate.WriteFields(_pluginVisitor.Values); _memoryChanges.MarkAllUnchanged(); if (showActionDialog) { if (onlyUpdateChanged) MetroMessageBox.Show("Meta Poked", "All changed metadata has been poked to your Xbox 360 console."); else MetroMessageBox.Show("Meta Poked", "The metadata has been poked to your Xbox 360 console."); } } else { MetroMessageBox.Show("Connection Error", "Unable to connect to your Xbox 360 console. Make sure that XBDM is enabled, you have the Xbox 360 SDK installed, and that your console's IP has been set correctly."); } } }
/// <summary> /// Saves all permutations of a sound tag concatenated as a single sound file. /// </summary> /// <param name="Filename">The file to save the data to.</param> /// <param name="Cache">The CacheFile containing the tag.</param> /// <param name="Tag">The sound tag.</param> /// <param name="Format">The format in which to save the data.</param> public static void SaveAllAsSingle(string Filename, CacheBase Cache, CacheBase.IndexItem Tag, SoundFormat Format) { var snd_ = DefinitionsManager.snd_(Cache, Tag); #region XMA if (Format == SoundFormat.XMA) { var total = GetTotalSize(Cache.ugh_, Cache.ugh_.PlayBacks[snd_.PlaybackIndex]); byte[] buffer = Cache.GetSoundRaw(snd_.RawID, total); if (buffer.Length == 0) { throw new Exception("Empty raw data."); } var codec = Cache.ugh_.Codecs[snd_.CodecIndex]; var xma = GetXMA(buffer, snd_.SampleRate, codec.Type); if (!Directory.GetParent(Filename).Exists) { Directory.GetParent(Filename).Create(); } var fs = File.OpenWrite(Filename); EndianWriter sw = new EndianWriter(fs, EndianFormat.BigEndian); sw.Write(xma); sw.Close(); sw.Dispose(); } #endregion #region WAV else if (Format == SoundFormat.WAV) { var tempName = Path.GetTempFileName(); SaveAllAsSingle(tempName, Cache, Tag, SoundFormat.XMA); var info = new ProcessStartInfo(towav, tempName) { CreateNoWindow = true, UseShellExecute = false, WorkingDirectory = Directory.GetParent(tempName).FullName }; Process.Start(info).WaitForExit(); if (File.Exists(Filename)) { File.Delete(Filename); } if (!Directory.GetParent(Filename).Exists) { Directory.GetParent(Filename).Create(); } File.Move(Path.ChangeExtension(tempName, "wav"), Filename); if (File.Exists(tempName)) { File.Delete(tempName); } } #endregion #region RAW else if (Format == SoundFormat.RAW) { byte[] buffer = Cache.GetSoundRaw(snd_.RawID, GetTotalSize(Cache.ugh_, Cache.ugh_.PlayBacks[snd_.PlaybackIndex])); if (!Directory.GetParent(Filename).Exists) { Directory.GetParent(Filename).Create(); } var fs = new FileStream(Filename, FileMode.Create); BinaryWriter sw = new BinaryWriter(fs); sw.Write(buffer); sw.Close(); sw.Dispose(); } #endregion #region Other else { throw new InvalidOperationException("Invalid sound format received."); } #endregion }
public abstract void Serialize(EndianWriter writer);
/// <summary> /// Extracts an xWMA sound and converts it to WAV. /// </summary> /// <param name="reader">The stream to read from.</param> /// <param name="offset">The offset of the data to extract.</param> /// <param name="rifx">The RIFX data for the sound.</param> /// <param name="outPath">The path of the file to save to.</param> public static void ExtractXWMAToWAV(EndianReader reader, int offset, RIFX rifx, string outPath) { // Create a temporary file to write an XWMA to string tempFile = Path.GetTempFileName(); try { using (EndianWriter output = new EndianWriter(File.OpenWrite(tempFile), EndianFormat.BigEndian)) { // Generate a little-endian XWMA header // TODO: move this into a class? output.Write(0x52494646); // 'RIFF' // Recompute the file size because the one Wwise gives us is trash // fileSize = header size (always 0x2C) + dpds data size + data header size (always 0x8) + data size int fileSize = 0x2C + rifx.SeekOffsets.Length * 0x4 + 0x8 + rifx.DataSize; output.EndianType = EndianFormat.LittleEndian; output.Write(fileSize); output.EndianType = EndianFormat.BigEndian; output.Write(RIFFFormat.XWMA); // Generate the 'fmt ' chunk output.Write(0x666D7420); // 'fmt ' output.EndianType = EndianFormat.LittleEndian; output.Write(0x18); // Chunk size output.Write(rifx.Codec); output.Write(rifx.ChannelCount); output.Write(rifx.SampleRate); output.Write(rifx.BytesPerSecond); output.Write(rifx.BlockAlign); output.Write(rifx.BitsPerSample); // Write the extradata // Bytes 4 and 5 have to be flipped because they make up an int16 // TODO: add error checking to make sure the extradata is the correct size (0x6) output.Write((short)0x6); output.WriteBlock(rifx.ExtraData, 0, 4); output.Write(rifx.ExtraData[5]); output.Write(rifx.ExtraData[4]); // Generate the 'dpds' chunk // It's really just the 'seek' chunk from the original data but renamed output.EndianType = EndianFormat.BigEndian; output.Write(0x64706473); // 'dpds' output.EndianType = EndianFormat.LittleEndian; output.Write(rifx.SeekOffsets.Length * 4); // One uint32 per offset foreach (int seek in rifx.SeekOffsets) output.Write(seek); // 'data' chunk output.EndianType = EndianFormat.BigEndian; output.Write(0x64617461); // 'data' output.EndianType = EndianFormat.LittleEndian; output.Write(rifx.DataSize); // Copy the data chunk contents from the original RIFX reader.SeekTo(offset + rifx.DataOffset); StreamUtil.Copy(reader, output, rifx.DataSize); } // Convert it with xWMAEncode RunProgramSilently("Helpers/xWMAEncode.exe", "\"" + tempFile + "\" \"" + outPath + "\"", Directory.GetCurrentDirectory()); } finally { // Delete the temporary XWMA file if (File.Exists(tempFile)) File.Delete(tempFile); } }
// Patch Creation private void btnCreatePatch_Click(object sender, RoutedEventArgs e) { try { // Check the user isn't completly retarded if (!CheckAllCreateMandatoryFields()) return; // Check the user isn't a skid if (!CheckAllCreateMetaFilesExists()) return; // Paths string cleanMapPath = txtCreatePatchUnModifiedMap.Text; string moddedMapPath = txtCreatePatchModifiedMap.Text; string outputPath = txtCreatePatchOutputPatch.Text; string previewImage = txtCreatePatchPreviewImage.Text; // Details string author = txtCreatePatchContentAuthor.Text; string desc = txtCreatePatchContentDescription.Text; string name = txtCreatePatchContentName.Text; string outputName = txtCreatePatchOutputName.Text; // Make dat patch var patch = new Patch { Author = author, Description = desc, Name = name, OutputName = outputName, Screenshot = String.IsNullOrEmpty(previewImage) ? null : File.ReadAllBytes(previewImage) }; EndianReader originalReader = null; EndianReader newReader = null; try { originalReader = new EndianReader(File.OpenRead(cleanMapPath), Endian.BigEndian); newReader = new EndianReader(File.OpenRead(moddedMapPath), Endian.BigEndian); ICacheFile originalFile = CacheFileLoader.LoadCacheFile(originalReader, App.AssemblyStorage.AssemblySettings.DefaultDatabase); ICacheFile newFile = CacheFileLoader.LoadCacheFile(newReader, App.AssemblyStorage.AssemblySettings.DefaultDatabase); if (cbCreatePatchHasCustomMeta.IsChecked != null && (bool) cbCreatePatchHasCustomMeta.IsChecked && cboxCreatePatchTargetGame.SelectedIndex < 4) { var targetGame = (TargetGame) cboxCreatePatchTargetGame.SelectedIndex; byte[] mapInfo = File.ReadAllBytes(txtCreatePatchMapInfo.Text); var mapInfoFileInfo = new FileInfo(txtCreatePatchMapInfo.Text); FileInfo blfFileInfo; patch.CustomBlfContent = new BlfContent(mapInfoFileInfo.FullName, mapInfo, targetGame); #region Blf Data if (PatchCreationBlfOption0.Visibility == Visibility.Visible) { blfFileInfo = new FileInfo(txtCreatePatchblf0.Text); patch.CustomBlfContent.BlfContainerEntries.Add(new BlfContainerEntry(blfFileInfo.Name, File.ReadAllBytes(blfFileInfo.FullName))); } if (PatchCreationBlfOption1.Visibility == Visibility.Visible) { blfFileInfo = new FileInfo(txtCreatePatchblf1.Text); patch.CustomBlfContent.BlfContainerEntries.Add(new BlfContainerEntry(blfFileInfo.Name, File.ReadAllBytes(blfFileInfo.FullName))); } if (PatchCreationBlfOption2.Visibility == Visibility.Visible) { blfFileInfo = new FileInfo(txtCreatePatchblf2.Text); patch.CustomBlfContent.BlfContainerEntries.Add(new BlfContainerEntry(blfFileInfo.Name, File.ReadAllBytes(blfFileInfo.FullName))); } if (PatchCreationBlfOption3.Visibility == Visibility.Visible) { blfFileInfo = new FileInfo(txtCreatePatchblf3.Text); patch.CustomBlfContent.BlfContainerEntries.Add(new BlfContainerEntry(blfFileInfo.Name, File.ReadAllBytes(blfFileInfo.FullName))); } #endregion } PatchBuilder.BuildPatch(originalFile, originalReader, newFile, newReader, patch); } finally { if (originalReader != null) originalReader.Close(); if (newReader != null) newReader.Close(); } IWriter output = new EndianWriter(File.Open(outputPath, FileMode.Create, FileAccess.Write), Endian.BigEndian); AssemblyPatchWriter.WritePatch(patch, output); output.Close(); MetroMessageBox.Show("Patch Created!", "Your patch has been created in the designated location. Happy sailing, modder!"); } catch (Exception ex) { MetroException.Show(ex); } }
public override void Write(EndianWriter s) { s.Write(Directory); s.Write(Files.Count); foreach (string str in Files.Keys) { List<string> files = Files[str]; s.Write(str); s.Write(files.Count); foreach (string file in files) s.Write(file); } }
public void Write(EndianWriter writer, double?version) => writer.Write(Value);
private void extractTags(bool withRaw, TagEntry tag) { // Ask where to save the extracted tag collection var sfd = new SaveFileDialog { Title = "Save Tag Set", Filter = "Tag Container Files|*.tagc" }; bool? result = sfd.ShowDialog(); if (!result.Value) return; // Make a tag container var container = new TagContainer(); // Recursively extract tags var tagsToProcess = new Queue<ITag>(); var tagsProcessed = new HashSet<ITag>(); var resourcesToProcess = new Queue<DatumIndex>(); var resourcesProcessed = new HashSet<DatumIndex>(); var resourcePagesProcessed = new HashSet<ResourcePage>(); tagsToProcess.Enqueue(tag.RawTag); ResourceTable resources = null; using (var reader = _mapManager.OpenRead()) { while (tagsToProcess.Count > 0) { var currentTag = tagsToProcess.Dequeue(); if (tagsProcessed.Contains(currentTag)) continue; // Get the plugin path var className = VariousFunctions.SterilizeTagClassName(CharConstant.ToString(currentTag.Class.Magic)).Trim(); var pluginPath = string.Format("{0}\\{1}\\{2}.xml", VariousFunctions.GetApplicationLocation() + @"Plugins", _buildInfo.Settings.GetSetting<string>("plugins"), className); // Extract dem data blocks var blockBuilder = new DataBlockBuilder(reader, currentTag, _cacheFile, _buildInfo); using (var pluginReader = XmlReader.Create(pluginPath)) AssemblyPluginLoader.LoadPlugin(pluginReader, blockBuilder); foreach (var block in blockBuilder.DataBlocks) container.AddDataBlock(block); // Add data for the tag that was extracted var tagName = _cacheFile.FileNames.GetTagName(currentTag) ?? currentTag.Index.ToString(); var extractedTag = new ExtractedTag(currentTag.Index, currentTag.MetaLocation.AsPointer(), currentTag.Class.Magic, tagName); container.AddTag(extractedTag); // Mark the tag as processed and then enqueue all of its child tags and resources tagsProcessed.Add(currentTag); foreach (var tagRef in blockBuilder.ReferencedTags) tagsToProcess.Enqueue(_cacheFile.Tags[tagRef]); foreach (var resource in blockBuilder.ReferencedResources) resourcesToProcess.Enqueue(resource); } // Load the resource table in if necessary if (resourcesToProcess.Count > 0) resources = _cacheFile.Resources.LoadResourceTable(reader); } // Extract resource info if (resources != null) { while (resourcesToProcess.Count > 0) { var index = resourcesToProcess.Dequeue(); if (resourcesProcessed.Contains(index)) continue; // Add the resource var resource = resources.Resources[index.Index]; container.AddResource(new ExtractedResourceInfo(index, resource)); // Add data for its pages if (resource.Location == null) continue; if (resource.Location.PrimaryPage != null && !resourcePagesProcessed.Contains(resource.Location.PrimaryPage)) { container.AddResourcePage(resource.Location.PrimaryPage); resourcePagesProcessed.Add(resource.Location.PrimaryPage); if (withRaw) { using (var fileStream = File.OpenRead(_cacheLocation)) { var resourceFile = _cacheFile; Stream resourceStream = fileStream; if (resource.Location.PrimaryPage.FilePath != null) { var resourceCacheInfo = App.AssemblyStorage.AssemblySettings.HalomapResourceCachePaths.FirstOrDefault( r => r.EngineName == _buildInfo.Name); var resourceCachePath = (resourceCacheInfo != null) ? resourceCacheInfo.ResourceCachePath : Path.GetDirectoryName(_cacheLocation); resourceCachePath = Path.Combine(resourceCachePath ?? "", Path.GetFileName(resource.Location.PrimaryPage.FilePath)); if (!File.Exists(resourceCachePath)) { MetroMessageBox.Show("Unable to extract tag", "Unable to extract tag, because a resource it relies on is in a external cache '{0}' that could not be found. Check Assembly's settings and set the file path to resource caches."); return; } resourceStream = File.OpenRead(resourceCachePath); resourceFile = new ThirdGenCacheFile(new EndianReader(resourceStream, Endian.BigEndian), _buildInfo, _cacheFile.BuildString); } var extractor = new ResourcePageExtractor(resourceFile); byte[] pageData; using (var pageStream = new MemoryStream()) { extractor.ExtractPage(resource.Location.PrimaryPage, resourceStream, pageStream); pageData = new byte[pageStream.Length]; Buffer.BlockCopy(pageStream.GetBuffer(), 0, pageData, 0, (int) pageStream.Length); } container.AddExtractedResourcePage(new ExtractedPage(pageData, resource.Location.PrimaryPage.Index)); } } } if (resource.Location.SecondaryPage == null || resourcePagesProcessed.Contains(resource.Location.SecondaryPage)) continue; container.AddResourcePage(resource.Location.SecondaryPage); resourcePagesProcessed.Add(resource.Location.SecondaryPage); if (withRaw) { using (var fileStream = File.OpenRead(_cacheLocation)) { var resourceFile = _cacheFile; Stream resourceStream = fileStream; if (resource.Location.SecondaryPage.FilePath != null) { var resourceCacheInfo = App.AssemblyStorage.AssemblySettings.HalomapResourceCachePaths.FirstOrDefault( r => r.EngineName == _buildInfo.Name); var resourceCachePath = (resourceCacheInfo != null) ? resourceCacheInfo.ResourceCachePath : Path.GetDirectoryName(_cacheLocation); resourceCachePath = Path.Combine(resourceCachePath ?? "", Path.GetFileName(resource.Location.SecondaryPage.FilePath)); if (!File.Exists(resourceCachePath)) { MetroMessageBox.Show("Unable to extract tag", "Unable to extract tag, because a resource it relies on is in a external cache '{0}' that could not be found. Check Assembly's settings and set the file path to resource caches."); return; } resourceStream = File.OpenRead(resourceCachePath); resourceFile = new ThirdGenCacheFile(new EndianReader(resourceStream, Endian.BigEndian), _buildInfo, _cacheFile.BuildString); } var extractor = new ResourcePageExtractor(resourceFile); byte[] pageData; using (var pageStream = new MemoryStream()) { extractor.ExtractPage(resource.Location.SecondaryPage, resourceStream, pageStream); pageData = new byte[pageStream.Length]; Buffer.BlockCopy(pageStream.GetBuffer(), 0, pageData, 0, (int)pageStream.Length); } container.AddExtractedResourcePage(new ExtractedPage(pageData, resource.Location.SecondaryPage.Index)); } } } } // Write it to a file using (var writer = new EndianWriter(File.Open(sfd.FileName, FileMode.Create, FileAccess.Write), Endian.BigEndian)) TagContainerWriter.WriteTagContainer(container, writer); // YAY! MetroMessageBox.Show("Extraction Successful", "Extracted " + container.Tags.Count + " tag(s), " + container.DataBlocks.Count + " data block(s), " + container.ResourcePages.Count + " resource page pointer(s), " + container.ExtractedResourcePages.Count + " extracted resource page(s), and " + container.Resources.Count + " resource pointer(s)."); }