diff --git a/DiscImageChef.DiscImages/DiscImageChef.cs b/DiscImageChef.DiscImages/DiscImageChef.cs index 257be90d..18a67633 100644 --- a/DiscImageChef.DiscImages/DiscImageChef.cs +++ b/DiscImageChef.DiscImages/DiscImageChef.cs @@ -75,6 +75,8 @@ using System.Linq; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; +using System.Xml; +using System.Xml.Serialization; using CUETools.Codecs; using CUETools.Codecs.FLAKE; using DiscImageChef.Checksums; @@ -743,6 +745,38 @@ namespace DiscImageChef.DiscImages imageInfo.HasPartitions = true; imageInfo.HasSessions = true; + break; + // CICM XML metadata block + case BlockType.CicmBlock: + CicmMetadataBlock cicmBlock = new CicmMetadataBlock(); + structureBytes = new byte[Marshal.SizeOf(cicmBlock)]; + imageStream.Read(structureBytes, 0, structureBytes.Length); + structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(cicmBlock)); + Marshal.Copy(structureBytes, 0, structurePointer, Marshal.SizeOf(cicmBlock)); + cicmBlock = (CicmMetadataBlock)Marshal.PtrToStructure(structurePointer, typeof(GeometryBlock)); + Marshal.FreeHGlobal(structurePointer); + if(cicmBlock.identifier != BlockType.CicmBlock) break; + + DicConsole.DebugWriteLine("DiscImageChef format plugin", + "Found CICM XML metadata block at position {0}", entry.offset); + + byte[] cicmBytes = new byte[cicmBlock.length]; + imageStream.Read(cicmBytes, 0, cicmBytes.Length); + MemoryStream cicmMs = new MemoryStream(cicmBytes); + XmlSerializer cicmXs = new XmlSerializer(typeof(CICMMetadataType)); + try + { + StreamReader sr = new StreamReader(cicmMs); + CicmMetadata = (CICMMetadataType)cicmXs.Deserialize(sr); + sr.Close(); + } + catch(XmlException ex) + { + DicConsole.DebugWriteLine("DiscImageChef format plugin", + "Exception {0} processing CICM XML metadata block", ex.Message); + CicmMetadata = null; + } + break; } } @@ -2041,6 +2075,40 @@ namespace DiscImageChef.DiscImages } foundUserDataDdt = true; + break; + // CICM XML metadata block + case BlockType.CicmBlock: + CicmMetadataBlock cicmBlock = new CicmMetadataBlock(); + structureBytes = new byte[Marshal.SizeOf(cicmBlock)]; + imageStream.Read(structureBytes, 0, structureBytes.Length); + structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(cicmBlock)); + Marshal.Copy(structureBytes, 0, structurePointer, Marshal.SizeOf(cicmBlock)); + cicmBlock = + (CicmMetadataBlock)Marshal.PtrToStructure(structurePointer, typeof(GeometryBlock)); + Marshal.FreeHGlobal(structurePointer); + if(cicmBlock.identifier != BlockType.CicmBlock) break; + + DicConsole.DebugWriteLine("DiscImageChef format plugin", + "Found CICM XML metadata block at position {0}", entry.offset); + + byte[] cicmBytes = new byte[cicmBlock.length]; + imageStream.Read(cicmBytes, 0, cicmBytes.Length); + MemoryStream cicmMs = new MemoryStream(cicmBytes); + XmlSerializer cicmXs = new XmlSerializer(typeof(CICMMetadataType)); + try + { + StreamReader sr = new StreamReader(cicmMs); + CicmMetadata = (CICMMetadataType)cicmXs.Deserialize(sr); + sr.Close(); + } + catch(XmlException ex) + { + DicConsole.DebugWriteLine("DiscImageChef format plugin", + "Exception {0} processing CICM XML metadata block", + ex.Message); + CicmMetadata = null; + } + break; } } @@ -2736,6 +2804,38 @@ namespace DiscImageChef.DiscImages index.Add(idxEntry); } + // If we have CICM XML metadata, write it + if(CicmMetadata != null) + { + MemoryStream cicmMs = new MemoryStream(); + XmlSerializer xmlSer = new XmlSerializer(typeof(CICMMetadataType)); + xmlSer.Serialize(cicmMs, CicmMetadata); + + idxEntry = new IndexEntry + { + blockType = BlockType.CicmBlock, + dataType = DataType.NoData, + offset = (ulong)imageStream.Position + }; + + DicConsole.DebugWriteLine("DiscImageChef format plugin", "Writing CICM XML block to position {0}", + idxEntry.offset); + + CicmMetadataBlock cicmBlock = + new CicmMetadataBlock {identifier = BlockType.CicmBlock, length = (uint)cicmMs.Length}; + structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(cicmBlock)); + structureBytes = new byte[Marshal.SizeOf(cicmBlock)]; + Marshal.StructureToPtr(cicmBlock, structurePointer, true); + Marshal.Copy(structurePointer, structureBytes, 0, structureBytes.Length); + Marshal.FreeHGlobal(structurePointer); + imageStream.Write(structureBytes, 0, structureBytes.Length); + imageStream.Write(cicmMs.ToArray(), 0, (int)cicmMs.Length); + + index.RemoveAll(t => t.blockType == BlockType.CicmBlock && t.dataType == DataType.NoData); + + index.Add(idxEntry); + } + // If the DDT is in-memory, write it to disk if(inMemoryDdt) { @@ -3483,8 +3583,8 @@ namespace DiscImageChef.DiscImages public bool SetCicmMetadata(CICMMetadataType metadata) { - // TODO: Implement - return false; + CicmMetadata = metadata; + return true; } /// @@ -4027,7 +4127,7 @@ namespace DiscImageChef.DiscImages MetadataBlock = 0x4154454D, /// Block containing optical disc tracks TracksBlock = 0x534B5254, - /// TODO: Block containing CICM XML metadata + /// Block containing CICM XML metadata CicmBlock = 0x4D434943, /// TODO: Block containing contents checksums ChecksumBlock = 0x4D534B43, @@ -4247,5 +4347,14 @@ namespace DiscImageChef.DiscImages /// Track flags public byte flags; } + + /// Geometry block, contains physical geometry information + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct CicmMetadataBlock + { + /// Identifier, + public BlockType identifier; + public uint length; + } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/ConvertImage.cs b/DiscImageChef/Commands/ConvertImage.cs index 0d388a5d..da15e3f9 100644 --- a/DiscImageChef/Commands/ConvertImage.cs +++ b/DiscImageChef/Commands/ConvertImage.cs @@ -645,7 +645,7 @@ namespace DiscImageChef.Commands } ret = false; - if(resume != null || dumpHardware != null) + if(sidecar != null || cicmMetadata != null) { if(sidecar != null) ret = outputFormat.SetCicmMetadata(sidecar); else if(cicmMetadata != null) diff --git a/templates/dicformat.bt b/templates/dicformat.bt index cf34e2f9..9ccf3d2c 100644 --- a/templates/dicformat.bt +++ b/templates/dicformat.bt @@ -759,6 +759,13 @@ typedef struct TrackEntry tracks[entries]; } TracksHeader; +typedef struct +{ + BlockType identifier; + uint length; + char xml[length]; +} CicmMetadataBlock; + LittleEndian(); local int i; @@ -849,5 +856,8 @@ for(i = 0; i < index.entries; i++) case 0x534B5254: TracksHeader tracks; break; + case 0x4D434943: + CicmMetadataBlock cicmMetadata; + break; } } \ No newline at end of file