Author: abock
Date: 2006-06-09 17:10:21 -0400 (Fri, 09 Jun 2006)
New Revision: 61609
Added:
trunk/ipod-sharp/ipod-sharp.mdp
trunk/ipod-sharp/ipod-sharp.mds
trunk/ipod-sharp/src/DmgImage.cs
trunk/ipod-sharp/src/DmgPartition.cs
trunk/ipod-sharp/tools/DmgIsoExtract.cs
Modified:
trunk/ipod-sharp/ChangeLog
trunk/ipod-sharp/src/Makefile.am
trunk/ipod-sharp/tools/Makefile.am
Log:
2006-06-09 Aaron Bockover <[EMAIL PROTECTED]>
* src/DmgImage.cs: Parse DMG partitions from a DMG image file; writes
HFS+ ISO from DMG image
* src/DmgPartition.cs: Read DMG partition information from plist XML
node and extract HFS+ ISO image partition
* tools/DmgIsoExtract.cs: Command line tool to convert DMG images to
HFS+ ISO images
* src/Makefile.am: Added DmgImage.cs and DmgPartition.cs to build
* tools/Makefile.am: Build dmg-iso-extract.exe tool
* ipod-sharp.mds:
* ipod-sharp.mdp: Added MonoDevelop project
Modified: trunk/ipod-sharp/ChangeLog
===================================================================
--- trunk/ipod-sharp/ChangeLog 2006-06-09 21:07:29 UTC (rev 61608)
+++ trunk/ipod-sharp/ChangeLog 2006-06-09 21:10:21 UTC (rev 61609)
@@ -1,3 +1,21 @@
+2006-06-09 Aaron Bockover <[EMAIL PROTECTED]>
+
+ * src/DmgImage.cs: Parse DMG partitions from a DMG image file; writes
+ HFS+ ISO from DMG image
+
+ * src/DmgPartition.cs: Read DMG partition information from plist XML
+ node and extract HFS+ ISO image partition
+
+ * tools/DmgIsoExtract.cs: Command line tool to convert DMG images to
+ HFS+ ISO images
+
+ * src/Makefile.am: Added DmgImage.cs and DmgPartition.cs to build
+
+ * tools/Makefile.am: Build dmg-iso-extract.exe tool
+
+ * ipod-sharp.mds:
+ * ipod-sharp.mdp: Added MonoDevelop project
+
2006-06-02 James Willcox <[EMAIL PROTECTED]>
* Track.cs: add Type property
Added: trunk/ipod-sharp/ipod-sharp.mdp
===================================================================
--- trunk/ipod-sharp/ipod-sharp.mdp 2006-06-09 21:07:29 UTC (rev 61608)
+++ trunk/ipod-sharp/ipod-sharp.mdp 2006-06-09 21:10:21 UTC (rev 61609)
@@ -0,0 +1,47 @@
+<Project name="ipod-sharp" fileversion="2.0" language="C#"
clr-version="Net_1_1" ctype="DotNetProject">
+ <Configurations active="Debug">
+ <Configuration name="Debug" ctype="DotNetProjectConfiguration">
+ <Output directory="./src" assembly="ipod-sharp" />
+ <Build debugmode="True" target="Library" />
+ <Execution runwithwarnings="True" consolepause="True" runtime="MsNet"
clr-version="Net_1_1" />
+ <CodeGeneration compiler="Csc" warninglevel="4" optimize="True"
unsafecodeallowed="True" generateoverflowchecks="True" mainclass=""
generatexmldocumentation="False" ctype="CSharpCompilerParameters" />
+ </Configuration>
+ <Configuration name="Release" ctype="DotNetProjectConfiguration">
+ <Output directory="./src" assembly="ipod-sharp" />
+ <Build debugmode="False" target="Library" />
+ <Execution runwithwarnings="True" consolepause="True" runtime="MsNet"
clr-version="Net_1_1" />
+ <CodeGeneration compiler="Csc" warninglevel="4" optimize="True"
unsafecodeallowed="True" generateoverflowchecks="True" mainclass=""
generatexmldocumentation="False" ctype="CSharpCompilerParameters" />
+ </Configuration>
+ </Configurations>
+ <DeploymentInformation strategy="File">
+ <excludeFiles />
+ </DeploymentInformation>
+ <Contents>
+ <File name="./src/DatabaseReadException.cs" subtype="Code"
buildaction="Compile" />
+ <File name="./src/DatabaseWriteException.cs" subtype="Code"
buildaction="Compile" />
+ <File name="./src/Device.cs" subtype="Code" buildaction="Compile" />
+ <File name="./src/DeviceAddedHandler.cs" subtype="Code"
buildaction="Compile" />
+ <File name="./src/DeviceBusyException.cs" subtype="Code"
buildaction="Compile" />
+ <File name="./src/DeviceEventListener.cs" subtype="Code"
buildaction="Compile" />
+ <File name="./src/DeviceException.cs" subtype="Code" buildaction="Compile"
/>
+ <File name="./src/DeviceGeneration.cs" subtype="Code"
buildaction="Compile" />
+ <File name="./src/DeviceModel.cs" subtype="Code" buildaction="Compile" />
+ <File name="./src/DeviceRemovedHandler.cs" subtype="Code"
buildaction="Compile" />
+ <File name="./src/EndianBinaryWriter.cs" subtype="Code"
buildaction="Compile" />
+ <File name="./src/Equalizer.cs" subtype="Code" buildaction="Compile" />
+ <File name="./src/Initializer.cs" subtype="Code" buildaction="Compile" />
+ <File name="./src/Playlist.cs" subtype="Code" buildaction="Compile" />
+ <File name="./src/ShuffleTrackDatabase.cs" subtype="Code"
buildaction="Compile" />
+ <File name="./src/Track.cs" subtype="Code" buildaction="Compile" />
+ <File name="./src/TrackDatabase.cs" subtype="Code" buildaction="Compile" />
+ <File name="./src/Utility.cs" subtype="Code" buildaction="Compile" />
+ <File name="./src/DmgImage.cs" subtype="Code" buildaction="Compile" />
+ <File name="./src/DmgPartition.cs" subtype="Code" buildaction="Compile" />
+ <File name="./tools/DmgIsoExtract.cs" subtype="Code" buildaction="Compile"
/>
+ <File name="./tools/PodTool.cs" subtype="Code" buildaction="Compile" />
+ </Contents>
+ <References>
+ <ProjectReference type="Gac" localcopy="True" refto="glib-sharp,
Version=2.8.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
+ <ProjectReference type="Gac" localcopy="True" refto="Mono.Posix,
Version=1.0.5000.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" />
+ </References>
+</Project>
\ No newline at end of file
Added: trunk/ipod-sharp/ipod-sharp.mds
===================================================================
--- trunk/ipod-sharp/ipod-sharp.mds 2006-06-09 21:07:29 UTC (rev 61608)
+++ trunk/ipod-sharp/ipod-sharp.mds 2006-06-09 21:10:21 UTC (rev 61609)
@@ -0,0 +1,16 @@
+<Combine name="ipod-sharp" fileversion="2.0">
+ <Configurations active="Debug">
+ <Configuration name="Debug" ctype="CombineConfiguration">
+ <Entry build="True" name="ipod-sharp" configuration="Debug" />
+ </Configuration>
+ <Configuration name="Release" ctype="CombineConfiguration">
+ <Entry build="True" name="ipod-sharp" configuration="Debug" />
+ </Configuration>
+ </Configurations>
+ <StartMode startupentry="ipod-sharp" single="True">
+ <Execute type="None" entry="ipod-sharp" />
+ </StartMode>
+ <Entries>
+ <Entry filename="./ipod-sharp.mdp" />
+ </Entries>
+</Combine>
\ No newline at end of file
Added: trunk/ipod-sharp/src/DmgImage.cs
===================================================================
--- trunk/ipod-sharp/src/DmgImage.cs 2006-06-09 21:07:29 UTC (rev 61608)
+++ trunk/ipod-sharp/src/DmgImage.cs 2006-06-09 21:10:21 UTC (rev 61609)
@@ -0,0 +1,113 @@
+//
+// DmgImage.cs: Parses DMG partitions from a DMG image
+// to build an HFS+ ISO image suitable for mounting
+//
+// Authors:
+// Aaron Bockover ([EMAIL PROTECTED])
+//
+// (C) 2006 Aaron Bockover
+//
+
+using System;
+using System.IO;
+using System.Net;
+using System.Text;
+using System.Xml;
+using System.Collections;
+
+namespace Dmg
+{
+ public class Image : IEnumerable
+ {
+ private static readonly long PLIST_START = 0x1e0;
+ private static readonly long PLIST_END = 0x128;
+
+ private Stream dmg_stream;
+ private BinaryReader dmg_reader;
+ private XmlDocument plist_doc;
+
+ private ArrayList partitions = new ArrayList();
+
+ public Image(Stream dmgStream)
+ {
+ dmg_stream = dmgStream;
+ dmg_reader = new BinaryReader(dmg_stream);
+
+ ReadImage();
+ }
+
+ public void SavePartitionsXml(Stream stream)
+ {
+ plist_doc.Save(stream);
+ }
+
+ public void Extract(Stream isoStream)
+ {
+ long out_offset = 0;
+ foreach(Partition partition in partitions) {
+ partition.Extract(dmg_stream, isoStream, ref out_offset);
+ }
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return partitions.GetEnumerator();
+ }
+
+ private void ReadImage()
+ {
+ long plist_address = LocateVerifyPlist();
+ ExtractPlistXmlDocument(plist_address);
+ XmlNode partitions_node = LocatePartitionsNode(plist_doc);
+
+ foreach(XmlNode partition_node in partitions_node) {
+ partitions.Add(new Partition(partition_node));
+ }
+ }
+
+ private long LocateVerifyPlist()
+ {
+ dmg_stream.Seek(-PLIST_START, SeekOrigin.End);
+ long address = dmg_reader.ReadInt64();
+ dmg_stream.Seek(-PLIST_END, SeekOrigin.End);
+ if(dmg_reader.ReadInt64() != address) {
+ throw new IOException("Could not verify plist addresses");
+ }
+
+ return IPAddress.HostToNetworkOrder(address);
+ }
+
+ private void ExtractPlistXmlDocument(long address)
+ {
+ dmg_stream.Seek(address, SeekOrigin.Begin);
+ byte [] tail_bytes = dmg_reader.ReadBytes((int)(dmg_stream.Length
- address));
+
+ string raw_xml = Encoding.UTF8.GetString(tail_bytes);
+ raw_xml = raw_xml.Substring(0, raw_xml.LastIndexOf("</plist>") +
8);
+
+ plist_doc = new XmlDocument();
+ plist_doc.LoadXml(raw_xml);
+ }
+
+ private XmlNode LocatePartitionsNode(XmlDocument plistDoc)
+ {
+ foreach(XmlNode key_node in
plistDoc.SelectNodes("/plist/dict/key")) {
+ if(key_node.InnerText != "resource-fork") {
+ continue;
+ }
+
+ XmlNode dict_node = key_node.NextSibling;
+
+ foreach(XmlNode node in dict_node.ChildNodes) {
+ if(node.Name == "key" && node.InnerText == "blkx") {
+ return node.NextSibling;
+ }
+ }
+
+ break;
+ }
+
+ throw new ApplicationException("Could not read partition table
from plist");
+ }
+ }
+}
Added: trunk/ipod-sharp/src/DmgPartition.cs
===================================================================
--- trunk/ipod-sharp/src/DmgPartition.cs 2006-06-09 21:07:29 UTC (rev
61608)
+++ trunk/ipod-sharp/src/DmgPartition.cs 2006-06-09 21:10:21 UTC (rev
61609)
@@ -0,0 +1,201 @@
+//
+// DmgPartition.cs: Parses a DMG partition from the image
+// plist XML and can perform data extraction for generating
+// an HFS+ ISO image partition
+//
+// Authors:
+// Aaron Bockover ([EMAIL PROTECTED])
+//
+// (C) 2006 Aaron Bockover
+//
+
+using System;
+using System.IO;
+using System.Net;
+using System.Text;
+using System.Xml;
+using System.Collections;
+using ICSharpCode.SharpZipLib.Zip.Compression;
+
+namespace Dmg
+{
+ public class Partition
+ {
+ private enum BlockType : uint
+ {
+ Copy = 0x00000001,
+ Zero = 0x00000002,
+ End = 0xffffffff,
+ Zlib = 0x80000005,
+ Unknown = 0x7ffffffe
+ }
+
+ private Hashtable table = new Hashtable();
+
+ private Partition()
+ {
+ }
+
+ internal Partition(XmlNode node)
+ {
+ ParsePartition(node);
+ }
+
+ private void ParsePartition(XmlNode node)
+ {
+ foreach(XmlNode key_node in node.SelectNodes("key")) {
+ XmlNode value_node = key_node.NextSibling;
+ if(value_node == null) {
+ continue;
+ }
+
+ object value = ParseValue(value_node);
+ if(value != null) {
+ table.Add(key_node.InnerText.ToLower(), value);
+ }
+ }
+ }
+
+ private object ParseValue(XmlNode node)
+ {
+ if(node.Name == "string") {
+ return node.InnerText.Trim();
+ } else if(node.Name == "data") {
+ return Convert.FromBase64String(node.InnerText);
+ }
+
+ return null;
+ }
+
+ internal void Extract(Stream dmgStream, Stream isoStream, ref long
lastOutOffset)
+ {
+ MemoryStream stream = new MemoryStream(Data);
+ BinaryReader reader = new BinaryReader(stream);
+
+ byte [] temp = new byte[0x40000];
+ byte [] otemp = new byte[0x40000];
+ byte [] zeroblock = new byte[4096];
+
+ int offset = 0xcc;
+ long total_size = 0;
+ long block_count = 0;
+
+ BlockType block_type = BlockType.Zero;
+
+ while(block_type != BlockType.End) {
+ stream.Seek(offset, SeekOrigin.Begin);
+ block_type = (BlockType)EndianSwap(reader.ReadInt32());
+
+ stream.Seek(offset + 12, SeekOrigin.Begin);
+ long out_offset = EndianSwap(reader.ReadInt32()) * 0x200;
+
+ stream.Seek(offset + 20, SeekOrigin.Begin);
+ long out_size = EndianSwap(reader.ReadInt32()) * 0x200;
+
+ stream.Seek(offset + 28, SeekOrigin.Begin);
+ long in_offset = EndianSwap(reader.ReadInt32());
+
+ stream.Seek(offset + 36, SeekOrigin.Begin);
+ long in_size = EndianSwap(reader.ReadInt32());
+
+ out_offset += lastOutOffset;
+
+ if(block_type == BlockType.Zlib) {
+ dmgStream.Seek(in_offset, SeekOrigin.Begin);
+ if(temp.Length < in_size) {
+ temp = new byte[in_size];
+ }
+
+ long total_bytes_read = 0;
+ while(total_bytes_read < in_size) {
+ total_bytes_read += dmgStream.Read(temp, 0,
+ Math.Min((int)(in_size - total_bytes_read),
temp.Length));
+ }
+
+ Inflater inflater = new Inflater();
+ inflater.SetInput(temp, 0, (int)total_bytes_read);
+
+ if(otemp.Length < out_size + 4) {
+ otemp = new byte[out_size + 4];
+ }
+
+ inflater.Inflate(otemp);
+ if(inflater.RemainingInput > 0) {
+ throw new ApplicationException("Could not inflate
entire block");
+ }
+
+ isoStream.Write(otemp, 0, (int)out_size);
+ } else if(block_type == BlockType.Copy) {
+ dmgStream.Seek(in_offset, SeekOrigin.Begin);
+
+ int bytes_read = dmgStream.Read(temp, 0,
Math.Min((int)in_size, temp.Length));
+ long total_bytes_read = bytes_read;
+
+ while(bytes_read != -1) {
+ isoStream.Write(temp, 0, bytes_read);
+ if(total_bytes_read >= in_size) {
+ break;
+ }
+
+ bytes_read = dmgStream.Read(temp, 0,
+ Math.Min((int)(in_size - total_bytes_read),
temp.Length));
+
+ if(bytes_read > 0) {
+ total_bytes_read += bytes_read;
+ }
+ }
+ } else if(block_type == BlockType.Zero) {
+ long zero_block_count = out_size / zeroblock.Length;
+
+ for(int i = 0; i < zero_block_count; ++i) {
+ isoStream.Write(zeroblock, 0, zeroblock.Length);
+ }
+
+ isoStream.Write(zeroblock, 0, (int)(out_size %
zeroblock.Length));
+ } else if(block_type == BlockType.End) {
+ lastOutOffset = out_offset;
+ }
+
+ offset += 0x28;
+ block_count++;
+ total_size += out_size;
+ }
+ }
+
+ private static int EndianSwap(int input)
+ {
+ return IPAddress.HostToNetworkOrder(input);
+ }
+
+ public object this[string key] {
+ get { return table[key]; }
+ }
+
+ public string ID {
+ get { return table["id"] as string; }
+ }
+
+ public string Name {
+ get { return table["name"] as string; }
+ }
+
+ public string Attributes {
+ get { return table["attributes"] as string; }
+ }
+
+ public int AttributesNumeric {
+ get {
+ if(Attributes.StartsWith("0x")) {
+ return Int32.Parse(Attributes.Substring(2),
+ System.Globalization.NumberStyles.AllowHexSpecifier);
+ }
+
+ return 0;
+ }
+ }
+
+ public byte [] Data {
+ get { return table["data"] as byte []; }
+ }
+ }
+}
Modified: trunk/ipod-sharp/src/Makefile.am
===================================================================
--- trunk/ipod-sharp/src/Makefile.am 2006-06-09 21:07:29 UTC (rev 61608)
+++ trunk/ipod-sharp/src/Makefile.am 2006-06-09 21:10:21 UTC (rev 61609)
@@ -28,7 +28,9 @@
$(srcdir)/Track.cs \
$(srcdir)/TrackDatabase.cs \
$(srcdir)/Utility.cs \
- $(srcdir)/ShuffleTrackDatabase.cs
+ $(srcdir)/ShuffleTrackDatabase.cs \
+ $(srcdir)/DmgImage.cs \
+ $(srcdir)/DmgPartition.cs
ASSEMBLY_RESOURCES =
@@ -43,7 +45,7 @@
all: $(ASSEMBLY)
$(ASSEMBLY): $(ASSEMBLY_SOURCES) $(ASSEMBLY_RESOURCES)
- $(MCS) $(MCS_FLAGS) -unsafe -keyfile:$(top_srcdir)/ipod-sharp.snk
-target:library -out:$@ $(ASSEMBLY_SOURCES) $(ASSEMBLY_RESOURCES:%=-resource:%)
-r:Mono.Posix -pkg:gtk-sharp-2.0
+ $(MCS) $(MCS_FLAGS) -unsafe -keyfile:$(top_srcdir)/ipod-sharp.snk
-target:library -out:$@ $(ASSEMBLY_SOURCES) $(ASSEMBLY_RESOURCES:%=-resource:%)
-r:Mono.Posix -pkg:gtk-sharp-2.0 -r:ICSharpCode.SharpZipLib
update-docs: $(ASSEMBLY)
$(DOC_UPDATER) -assembly:$(ASSEMBLY) -path:en
Added: trunk/ipod-sharp/tools/DmgIsoExtract.cs
===================================================================
--- trunk/ipod-sharp/tools/DmgIsoExtract.cs 2006-06-09 21:07:29 UTC (rev
61608)
+++ trunk/ipod-sharp/tools/DmgIsoExtract.cs 2006-06-09 21:10:21 UTC (rev
61609)
@@ -0,0 +1,79 @@
+using System;
+using System.IO;
+using Dmg;
+
+public static class DmgIsoExtract
+{
+ public static int Main(string [] args)
+ {
+ string dmg_file = null;
+ string iso_file = null;
+ string plist_file = null;
+ bool list_partitions = false;
+
+ if(args.Length < 1) {
+ ShowHelp();
+ return 1;
+ }
+
+ for(int i = 0; i < args.Length; i++) {
+ switch(args[i]) {
+ case "--list-partitions":
+ list_partitions = true;
+ break;
+ case "--dump-plist":
+ plist_file = args[++i];
+ break;
+ case "--help":
+ ShowHelp();
+ return 1;
+ default:
+ if(dmg_file == null) {
+ dmg_file = args[i];
+ } else if(iso_file == null) {
+ iso_file = args[i];
+ } else {
+ Console.Error.WriteLine("Invalid argument: `{0}'",
args[0]);
+ return 1;
+ }
+ break;
+ }
+ }
+
+ if(!File.Exists(dmg_file)) {
+ Console.Error.WriteLine("DMG file `{0}' does not exist", dmg_file);
+ return 1;
+ }
+
+ FileStream dmg_stream = new FileStream(dmg_file, FileMode.Open);
+ Image image = new Image(dmg_stream);
+
+ if(list_partitions) {
+ foreach(Partition partition in image) {
+ Console.WriteLine("ID = {0}, Name = {1}, Attributes =
0x{2:x2}",
+ partition.ID, partition.Name, partition.AttributesNumeric);
+ }
+ }
+
+ if(plist_file != null) {
+ image.SavePartitionsXml(new FileStream(plist_file,
FileMode.Create));
+ }
+
+ if(iso_file != null) {
+ image.Extract(new FileStream(iso_file, FileMode.Create));
+ }
+
+ return 0;
+ }
+
+ private static void ShowHelp()
+ {
+ Console.Error.WriteLine("Usage: dmg-iso-extract <dmg-file>
[<iso-file>] [--list-partitions]");
+ Console.Error.WriteLine(" [--dump-plist <plist-file>]\n");
+ Console.Error.WriteLine(" <dmg-file> DMG input file
to read (required)");
+ Console.Error.WriteLine(" <iso-file> HFS+ ISO file
to output (optional)");
+ Console.Error.WriteLine(" --list-partitions Show the
partitions in the DMG image");
+ Console.Error.WriteLine(" --dump-plist <plist-file> Dump the raw
plist XML to file\n");
+ Console.Error.WriteLine(" --help Show this
help\n");
+ }
+}
Modified: trunk/ipod-sharp/tools/Makefile.am
===================================================================
--- trunk/ipod-sharp/tools/Makefile.am 2006-06-09 21:07:29 UTC (rev 61608)
+++ trunk/ipod-sharp/tools/Makefile.am 2006-06-09 21:10:21 UTC (rev 61609)
@@ -1,14 +1,20 @@
-
MCS_FLAGS = -debug
-TOOLS = ipod-tool.exe
+TOOLS = ipod-tool.exe dmg-iso-extract.exe
IPOD_TOOL_SOURCES = $(srcdir)/PodTool.cs
+DMG_ISO_EXTRACT_SRC = \
+ $(srcdir)/DmgIsoExtract.cs \
+ $(top_builddir)/src/Dmg*.cs
all: $(TOOLS)
ipod-tool.exe: $(IPOD_TOOL_SOURCES)
$(MCS) $(MCS_FLAGS) -r:$(top_builddir)/src/ipod-sharp.dll -target:exe
-out:$@ $(IPOD_TOOL_SOURCES)
-EXTRA_DIST = $(IPOD_TOOL_SOURCES)
+dmg-iso-extract.exe: $(DMG_ISO_EXTRACT_SRC)
+ $(MCS) $(MCS_FLAGS) -r:ICSharpCode.SharpZipLib -target:exe -out:$@
$(DMG_ISO_EXTRACT_SRC)
+
+EXTRA_DIST = $(IPOD_TOOL_SOURCES) $(DMG_ISO_EXTRACT_SRC)
CLEANFILES = $(TOOLS)
+
_______________________________________________
Mono-patches maillist - [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches