You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by cd...@apache.org on 2016/07/27 17:24:06 UTC

git commit: [flex-utilities] [refs/heads/feature/flash-downloader] - - Implement a Flash auto downloader

Repository: flex-utilities
Updated Branches:
  refs/heads/feature/flash-downloader [created] cf75f0e01


- Implement a Flash auto downloader


Project: http://git-wip-us.apache.org/repos/asf/flex-utilities/repo
Commit: http://git-wip-us.apache.org/repos/asf/flex-utilities/commit/cf75f0e0
Tree: http://git-wip-us.apache.org/repos/asf/flex-utilities/tree/cf75f0e0
Diff: http://git-wip-us.apache.org/repos/asf/flex-utilities/diff/cf75f0e0

Branch: refs/heads/feature/flash-downloader
Commit: cf75f0e014a29d1c354f3f33b339a60f3d180b0f
Parents: e5c3d36
Author: Christofer Dutz <ch...@codecentric.de>
Authored: Wed Jul 27 19:23:50 2016 +0200
Committer: Christofer Dutz <ch...@codecentric.de>
Committed: Wed Jul 27 19:23:50 2016 +0200

----------------------------------------------------------------------
 flex-maven-tools/flex-sdk-converter/cli/pom.xml |   5 +
 .../converter/core/SdkConverterCLI.java         |  14 +-
 flex-maven-tools/flex-sdk-converter/pom.xml     |   4 +-
 .../retrievers/download/pom.xml                 |  25 ++
 .../retrievers/download/DownloadRetriever.java  |  81 +++++
 .../retrievers/download/utils/DmgExtractor.java | 319 +++++++++++++++++++
 .../download/utils/utils/ApplePartitionMap.java | 197 ++++++++++++
 .../utils/utils/DmgBlockChunkEntry.java         |  96 ++++++
 .../utils/utils/DmgPropertyListMishBlock.java   | 101 ++++++
 .../download/utils/utils/DmgTrailer.java        | 158 +++++++++
 .../download/utils/utils/DmgUdifChecksum.java   |  42 +++
 .../download/utils/utils/DriverDescriptor.java  |  38 +++
 .../utils/utils/DriverDescriptorMap.java        |  85 +++++
 .../download/utils/utils/HFSPlusExtent.java     |  40 +++
 .../download/utils/utils/HFSPlusForkData.java   |  59 ++++
 .../utils/utils/HFSPlusVolumeHeader.java        | 217 +++++++++++++
 .../download/utils/utils/HFSVolumeFactory.java  |  24 ++
 .../download/utils/utils/HFSVolumeHeader.java   |  13 +
 .../download/utils/utils/IHFSVolumeHeader.java  |  10 +
 19 files changed, 1520 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/cli/pom.xml
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/cli/pom.xml b/flex-maven-tools/flex-sdk-converter/cli/pom.xml
index 7176ed1..095617f 100644
--- a/flex-maven-tools/flex-sdk-converter/cli/pom.xml
+++ b/flex-maven-tools/flex-sdk-converter/cli/pom.xml
@@ -104,6 +104,11 @@
             <version>3.3.2</version>
         </dependency>
         <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.4</version>
+        </dependency>
+        <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-simple</artifactId>
             <version>1.7.7</version>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/cli/src/main/java/org/apache/flex/utilities/converter/core/SdkConverterCLI.java
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/cli/src/main/java/org/apache/flex/utilities/converter/core/SdkConverterCLI.java b/flex-maven-tools/flex-sdk-converter/cli/src/main/java/org/apache/flex/utilities/converter/core/SdkConverterCLI.java
index 8cf0522..eb85d70 100644
--- a/flex-maven-tools/flex-sdk-converter/cli/src/main/java/org/apache/flex/utilities/converter/core/SdkConverterCLI.java
+++ b/flex-maven-tools/flex-sdk-converter/cli/src/main/java/org/apache/flex/utilities/converter/core/SdkConverterCLI.java
@@ -301,12 +301,14 @@ public class SdkConverterCLI {
 
                 String flashVersions = cmd.getOptionValue(OPTION_FLASH_VERSIONS, "");
                 if(!flashVersions.isEmpty()) {
-                    for(String flashVersion : flashVersions.split(",")) {
-                        System.out.println("- Downloading Flash SDK version: " + flashVersion +
-                                " to directory: " + fdkDir.getAbsolutePath());
-                        File flashDownloadDiretory = retriever.retrieve(SdkType.FLASH, flashVersion);
-                        // Integrate the download into  the FDK directory.
-                        mergeDirectories(flashDownloadDiretory, fdkDir);
+                    for(PlatformType platformType : platforms) {
+                        for (String flashVersion : flashVersions.split(",")) {
+                            System.out.println("- Downloading Flash SDK version: " + flashVersion +
+                                    " to directory: " + fdkDir.getAbsolutePath());
+                            File flashDownloadDirectory = retriever.retrieve(SdkType.FLASH, flashVersion, platformType);
+                            // Integrate the download into the FDK directory.
+                            mergeDirectories(flashDownloadDirectory, fdkDir);
+                        }
                     }
                 }
 

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/pom.xml
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/pom.xml b/flex-maven-tools/flex-sdk-converter/pom.xml
index 81109d9..f044a18 100644
--- a/flex-maven-tools/flex-sdk-converter/pom.xml
+++ b/flex-maven-tools/flex-sdk-converter/pom.xml
@@ -71,8 +71,8 @@
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <configuration>
-                    <source>1.5</source>
-                    <target>1.5</target>
+                    <source>1.6</source>
+                    <target>1.6</target>
                     <encoding>${project.build.sourceEncoding}</encoding>
                 </configuration>
             </plugin>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/retrievers/download/pom.xml
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/retrievers/download/pom.xml b/flex-maven-tools/flex-sdk-converter/retrievers/download/pom.xml
index ffa2665..bfb3cbf 100644
--- a/flex-maven-tools/flex-sdk-converter/retrievers/download/pom.xml
+++ b/flex-maven-tools/flex-sdk-converter/retrievers/download/pom.xml
@@ -44,6 +44,31 @@
         </dependency>
 
         <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.4</version>
+        </dependency>
+
+        <!-- 7Zip with JNI Wrapper to call it from Java -->
+        <dependency>
+            <groupId>net.sf.sevenzipjbinding</groupId>
+            <artifactId>sevenzipjbinding</artifactId>
+            <version>9.20-2.00beta</version>
+        </dependency>
+        <dependency>
+            <groupId>net.sf.sevenzipjbinding</groupId>
+            <artifactId>sevenzipjbinding-all-platforms</artifactId>
+            <version>9.20-2.00beta</version>
+        </dependency>
+        <!--dependency>
+            <groupId>org.catacombae</groupId>
+            <artifactId>dmgextractor</artifactId>
+            <version>0.7</version>
+            <scope>system</scope>
+            <systemPath>${basedir}/libs/dmgextractor-0_70-standalone.jar</systemPath>
+        </dependency-->
+
+        <dependency>
             <groupId>org.mock-server</groupId>
             <artifactId>mockserver-netty</artifactId>
             <version>RELEASE</version>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/DownloadRetriever.java
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/DownloadRetriever.java b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/DownloadRetriever.java
index 6843d17..e1570e7 100644
--- a/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/DownloadRetriever.java
+++ b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/DownloadRetriever.java
@@ -16,6 +16,10 @@
  */
 package org.apache.flex.utilities.converter.retrievers.download;
 
+import net.sf.sevenzipjbinding.ArchiveFormat;
+import net.sf.sevenzipjbinding.IInArchive;
+import net.sf.sevenzipjbinding.SevenZip;
+import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
 import org.apache.flex.utilities.converter.api.ProxySettings;
@@ -129,6 +133,7 @@ public class DownloadRetriever extends BaseRetriever {
                 ////////////////////////////////////////////////////////////////////////////////
 
                 if (type.equals(SdkType.FLASH)) {
+                    // Initialize the framework libs.
                     final File targetDirectory = new File(targetFile.getParent(),
                             targetFile.getName().substring(0, targetFile.getName().lastIndexOf(".") - 1));
                     final File libDestFile = new File(targetDirectory, "frameworks/libs/player/" + version +
@@ -139,6 +144,58 @@ public class DownloadRetriever extends BaseRetriever {
                         }
                     }
                     FileUtils.moveFile(targetFile, libDestFile);
+
+                    ///////////////////////////////////////////////////////////////
+                    // Download the Flash projector for the given flash version
+                    // NOTE: This is not part of the official Flex SDK !!!
+                    ///////////////////////////////////////////////////////////////
+
+                    // Initialize the runtime resources.
+                    String executableName = (platformType == PlatformType.WINDOWS) ? "flashplayer.exe" : "flashplayer";
+                    final File runtimeDestFile = new File(targetDirectory, "runtimes/flash/" + platformType.name() +
+                            "/" + version + "/" + executableName);
+                    final String majorVersion = version.contains(".") ?
+                            version.substring(0, version.indexOf(".")) : version;
+
+                    // The urls for downloading are:
+                    // https://fpdownload.macromedia.com/pub/flashplayer/updaters/19/flashplayer_19_sa_debug.exe
+                    // https://fpdownload.macromedia.com/pub/flashplayer/updaters/19/flashplayer_19_sa_debug.dmg
+                    // https://fpdownload.macromedia.com/pub/flashplayer/updaters/11/flashplayer_11_sa_debug.i386.tar.gz
+                    String flashplayerUrl = "https://fpdownload.macromedia.com/pub/flashplayer/updaters/" +
+                            majorVersion + "/flashplayer_" + majorVersion + "_sa_debug";
+                    String fileEnding = "";
+                    switch (platformType) {
+                        case LINUX:
+                            fileEnding = ".i386.tar.gz";
+                            break;
+                        case MAC:
+                            fileEnding = ".dmg";
+                            break;
+                        case WINDOWS:
+                            fileEnding = ".exe";
+                            break;
+                    }
+                    flashplayerUrl += fileEnding;
+                    final File runtimeTargetFile = File.createTempFile("FlashRuntime-" + version + "-" + platformType +
+                            "-", fileEnding);
+                    performFastDownload(new URL(flashplayerUrl), runtimeTargetFile);
+
+                    // The Windows version of the download is executable directly, for all others
+                    // we have to unpack the downloaded archive and extract the content.
+                    if(platformType != PlatformType.WINDOWS) {
+                        extractArchive(runtimeTargetFile, new File(runtimeTargetFile.getParentFile(), runtimeTargetFile.getName()));
+                        switch (platformType) {
+                            case LINUX:
+                                extractArchive(runtimeTargetFile, new File(runtimeTargetFile.getParentFile(), runtimeTargetFile.getName()));
+                                break;
+                            case MAC:
+                                extractArchive(runtimeTargetFile, new File(runtimeTargetFile.getParentFile(), runtimeTargetFile.getName()));
+                                break;
+                        }
+                    }
+
+
+
                     return targetDirectory;
                 } else {
                     System.out.println("Extracting archive to temp directory.");
@@ -499,4 +556,28 @@ public class DownloadRetriever extends BaseRetriever {
         }
         return result;
     }
+
+    protected void extractArchive(File archive, File targetDirectory) throws RetrieverException {
+
+    }
+
+    public static void main(String[] args) throws Exception {
+        String[] upargs = new String[] {"/Users/christoferdutz/Downloads/install_flash_player_18_osx.dmg", "/Users/christoferdutz/Temp/unpack/test.img"};
+
+        IInArchive archive;
+        RandomAccessFile randomAccessFile;
+
+        randomAccessFile = new RandomAccessFile(new File("/Users/christoferdutz/Downloads/install_flash_player_18_osx.dmg"), "r");
+
+        archive = SevenZip.openInArchive(ArchiveFormat.ISO, // null - autodetect
+                new RandomAccessFileInStream(
+                        randomAccessFile));
+
+        int numberOfItems = archive.getNumberOfItems();
+
+        archive.close();
+        randomAccessFile.close();
+
+        System.out.println(numberOfItems);
+    }
 }

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/DmgExtractor.java
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/DmgExtractor.java b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/DmgExtractor.java
new file mode 100644
index 0000000..8c4b768
--- /dev/null
+++ b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/DmgExtractor.java
@@ -0,0 +1,319 @@
+package org.apache.flex.utilities.converter.retrievers.download.utils;
+
+import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
+import org.apache.commons.io.input.NullInputStream;
+import org.apache.flex.utilities.converter.retrievers.download.utils.utils.*;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import javax.xml.bind.DatatypeConverter;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Tool to read and unpack a dmg image. Based upon the format description at:
+ * http://newosxbook.com/DMG.html
+ *
+ * HFSleuth> fs flashplayer_20_sa_debug.dmg
+ * KOLY header found at 14457517:
+ *         UDIF version 4, Header Size: 512
+ *         Flags:1
+ *         Rsrc fork: None
+ *         Data fork: from 0, spanning 14444891 bytes
+ *         XML plist: from 14444891, spanning 12626 bytes (to 14457517)
+ *         Segment #: 1, Count: 1
+ *         Segment UUID: 8a7e1df1-6648ad9f-78cb06a4-2c5be967
+ *         Running Data fork offset 0
+ *         Sectors: 70816
+ * Apple_HFS detected
+ * Found Terminator in last block. Good
+ * decompression done - Writing to /tmp/decompressed.dmg..
+ * processBTree: Node kind 0, 0 records - should be kind 1, 3 records - but it isn't!
+ * node is 0
+ * RC was 0
+ *
+ * Created by christoferdutz on 24.02.16.
+ */
+public class DmgExtractor {
+
+    // Hex for "koly", which are the DMG magic bytes.
+    private static final byte[] DMG_TRAILER_MAGIC_BYTES = {0x6B, 0x6F, 0x6C, 0x79};
+
+    public File extract(File inputFile) {
+        try {
+            // Try to find the DMG trailer.
+            // (A header containing the metadata, but located at the end)
+            DmgTrailer dmgTrailer = findDmgTrailer(inputFile);
+            if(dmgTrailer != null) {
+                float sizeInMegabytes = dmgTrailer.getDataForkLength() / (1024 * 1024);
+                System.out.println(" - Preparing to extract " + sizeInMegabytes + " MB");
+
+                // Read the property-list Xml document in the DMG file.
+                List<DmgPropertyListMishBlock> mishBlocks = getPropertyList(inputFile, dmgTrailer);
+
+                byte[] buffer = new byte[1024];
+                int blockCounter = 0;
+                for(DmgPropertyListMishBlock mishBlock : mishBlocks) {
+                    System.out.println("   - Processing block: " + blockCounter + " - " + mishBlock.getBlockName());
+                    int chunkCounter = 0;
+                    for(DmgBlockChunkEntry blockChunkEntry : mishBlock.getBlockChunkEntries()) {
+                        System.out.println("     - Processing chunk: " + chunkCounter + " - " + blockChunkEntry.toString());
+                        FileInputStream fis = new FileInputStream(inputFile);
+
+                        try {
+                            // Position the read head at the beginning of this entry.
+                            fis.skip(mishBlock.getDataOffset() + blockChunkEntry.getCompressedOffset());
+
+                            // Depending on the chunk entry type, process the input data.
+                            InputStream is = null;
+                            switch (blockChunkEntry.getEntryType()) {
+                                case 0x00000000:
+                                    //entryTypeName = "Zero-Fill";
+                                    is = new NullInputStream(blockChunkEntry.getCompressedLength());
+                                    break;
+                                case 0x00000001:
+                                    //entryTypeName = "UDRW/UDRO - RAW or NULL compression (uncompressed)";
+                                    is = fis;
+                                    break;
+                                case 0x00000002:
+                                    //entryTypeName = "Ignored/unknown";
+                                    // TODO: Implement
+                                    break;
+                                case 0x80000004:
+                                    //entryTypeName = "UDCO - Apple Data Compression (ADC)";
+                                    // TODO: Implement
+                                    break;
+                                case 0x80000005:
+                                    //entryTypeName = "UDZO - zLib data compression";
+                                    // TODO: Implement
+                                    break;
+                                case 0x80000006:
+                                    //entryTypeName = "UDBZ - bz2lib data compression";
+                                    is = new BZip2CompressorInputStream(fis);
+                                    break;
+                                case 0x7ffffffe:
+                                    //entryTypeName = "No blocks - Comment: +beg and +end";
+                                    // TODO: Implement
+                                default:
+                            }
+
+                            if (is != null) {
+                                // Read the data into a byte-buffer.
+                                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                                int n;
+                                while ((n = is.read(buffer)) != -1) {
+                                    baos.write(buffer, 0, n);
+                                }
+
+                                System.out.println("        - Number of sectors: " + blockChunkEntry.getSectorCount() +
+                                        " sector size: " + (baos.size() / blockChunkEntry.getSectorCount()));
+
+                                ByteArrayInputStream bis = new ByteArrayInputStream(baos.toByteArray());
+                                DataInputStream dis = new DataInputStream(bis);
+                                // Depending on the type, process the data in the buffer.
+                                if (mishBlock.getBlockName().contains("Driver Descriptor Map")) {
+                                    DriverDescriptorMap driverDescriptorMap = new DriverDescriptorMap(dis);
+                                    System.out.println("        - " + driverDescriptorMap.toString());
+                                }
+                                if (mishBlock.getBlockName().contains("Apple_partition_map")) {
+                                    List<ApplePartitionMap> partitionMaps =
+                                            new ArrayList<ApplePartitionMap>((int) blockChunkEntry.getSectorCount());
+                                    for(int i = 0; i < blockChunkEntry.getSectorCount(); i++) {
+                                        try {
+                                            ApplePartitionMap partitionMap = new ApplePartitionMap(dis);
+                                            System.out.println("        - Partition " + i + " - " +
+                                                    partitionMap.getTypeOfPartition() + " - " +
+                                                    partitionMap.toString());
+                                            partitionMaps.add(partitionMap);
+                                        } catch(Exception e) {
+                                            break;
+                                        }
+                                    }
+                                }
+                                // See: https://en.wikipedia.org/wiki/Hierarchical_File_System
+                                else if (mishBlock.getBlockName().contains("Apple_HFS")) {
+                                    // Block 0 and 1 contain the boot blocks (each 512 bytes)
+                                    // We need to skip these.
+                                    // TODO: Eventually implement.
+                                    dis.skipBytes(1024);
+                                    System.out.println("        - Skipped boot block (0 and 1)");
+                                    // Block 2 contains the master directory block
+                                    // TODO: Actually this could also be a normal HFS volume ...
+                                    IHFSVolumeHeader iHfsVolumeHeader = HFSVolumeFactory.readHfsVolumeHeader(dis);
+                                    System.out.println("        - " + iHfsVolumeHeader.toString());
+                                    // In the old HFS format the third block contains the volume
+                                    // bitmap, in HFS+ this is located as a normal file in the volume.
+                                    if(iHfsVolumeHeader instanceof HFSVolumeHeader) {
+                                        HFSVolumeHeader hfsVolumeHeader = (HFSVolumeHeader) iHfsVolumeHeader;
+                                        // Block 3 contains the volume bitmap
+                                        // (one bit represents the usage of one block)
+                                        // https://en.wikipedia.org/wiki/Hierarchical_File_System
+                                        /*int volumeBitmapSize = hfsVolumeHeader.getTotalBlocks() / 8;
+                                        byte[] volumeBitmap = new byte[volumeBitmapSize];
+                                        dis.read(volumeBitmap);
+                                        System.out.println(volumeBitmap);*/
+                                    }
+                                    else if(iHfsVolumeHeader instanceof HFSPlusVolumeHeader) {
+                                        HFSPlusVolumeHeader hfsPlusVolumeHeader =
+                                                (HFSPlusVolumeHeader) iHfsVolumeHeader;
+                                        // https://en.wikipedia.org/wiki/HFS_Plus
+                                        // http://pages.cs.wisc.edu/~legault/miniproj-736.pdf
+                                    }
+                                }
+                                chunkCounter++;
+                            }
+                        } catch(IOException ioe) {
+                            ioe.printStackTrace();
+                        } finally {
+                            try {
+                                fis.close();
+                            } catch(IOException e) {
+                                // Ignore
+                            }
+                        }
+                    }
+                    blockCounter++;
+                }
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } catch (ParserConfigurationException e) {
+            e.printStackTrace();
+        } catch (SAXException e) {
+            e.printStackTrace();
+        } catch (XPathExpressionException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    private DmgTrailer findDmgTrailer(File inputFile) throws IOException {
+        long startTime = new Date().getTime();
+
+        RandomAccessFile raf = new RandomAccessFile(inputFile, "r");
+        // The size of the DMG trailer is 512 bytes. As it's located at the
+        // end of the file there is no use starting to search for it from the
+        // beginning. So we read a block that's slightly bigger than the
+        // trailer and search for the magic words in this block.
+        long curBlockStartPosition = raf.length() - 600;
+        long dmgTrailerPosition = -1;
+        do {
+            // Position the read "head".
+            raf.seek(curBlockStartPosition);
+
+            // Read a block of 600 bytes.
+            byte[] curBlock = new byte[600];
+            raf.read(curBlock);
+
+            // Scan the current block for the magic bytes.
+            int curMagicWordPosition = 0;
+            for (int curBlockPosition = 0; curBlockPosition < 600; curBlockPosition++) {
+                if (curBlock[curBlockPosition] == DMG_TRAILER_MAGIC_BYTES[curMagicWordPosition]) {
+                    curMagicWordPosition++;
+                } else {
+                    curMagicWordPosition = 0;
+                }
+                if (curMagicWordPosition == 4) {
+                    // We are just comparing the last byte of the magic word
+                    // so we only have to go back 3 bytes.
+                    dmgTrailerPosition = curBlockStartPosition + (long) curBlockPosition - 3;
+                    break;
+                }
+            }
+
+            // If we were in the first block, quit searching.
+            if(curBlockStartPosition == 0) {
+                break;
+            }
+            // We shift the search box back, but keep 4 bytes of overlap
+            // just in case the magic word was at the boundary of the block.
+            // This way we will be able to read it in the next pass.
+            curBlockStartPosition = Math.max(0, curBlockStartPosition - 596);
+        } while(dmgTrailerPosition == -1);
+        long endTime = new Date().getTime();
+        System.out.println("Found DMG trailer at position " + dmgTrailerPosition + " in " + (endTime - startTime) + "ms");
+
+        // Read and parse the trailer data.
+        if(dmgTrailerPosition != -1) {
+            raf.seek(dmgTrailerPosition);
+            byte[] dmgTrailerData = new byte[512];
+            raf.read(dmgTrailerData);
+            return new DmgTrailer(dmgTrailerData);
+        }
+
+        return null;
+    }
+
+    private List<DmgPropertyListMishBlock> getPropertyList(File inputFile, DmgTrailer dmgTrailer) throws IOException,
+            ParserConfigurationException, SAXException, XPathExpressionException {
+        // Read the block of bytes containing the property list data.
+        byte[] propertyListData = new byte[(int) dmgTrailer.getXmlLength()];
+        RandomAccessFile raf = new RandomAccessFile(inputFile, "r");
+        raf.seek(dmgTrailer.getXmlOffset());
+        raf.read(propertyListData);
+
+        // Parse the xml document data.
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        factory.setNamespaceAware(true);
+        DocumentBuilder builder = factory.newDocumentBuilder();
+        Document propertyListDoc = builder.parse(new ByteArrayInputStream(propertyListData));
+
+        try {
+            TransformerFactory tf = TransformerFactory.newInstance();
+            Transformer transformer = tf.newTransformer();
+            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
+            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+
+            transformer.transform(new DOMSource(propertyListDoc),
+                    new StreamResult(new OutputStreamWriter(System.out, "UTF-8")));
+        } catch(Exception e) {
+            // Ignore ...
+        }
+
+        List<DmgPropertyListMishBlock> mishBlocks = new ArrayList<DmgPropertyListMishBlock>();
+        XPath xPath = XPathFactory.newInstance().newXPath();
+        NodeList nodes = (NodeList) xPath.evaluate("//array/dict[key='CFName']/data",
+                propertyListDoc.getDocumentElement(), XPathConstants.NODESET);
+        for (int i = 0; i < nodes.getLength(); ++i) {
+            Element dataElement = (Element) nodes.item(i);
+            Element nameElement = (Element) dataElement.getPreviousSibling().getPreviousSibling()
+                    .getPreviousSibling().getPreviousSibling();
+            byte[] dataBlock = DatatypeConverter.parseBase64Binary(dataElement.getTextContent());
+            DmgPropertyListMishBlock mishBlock = new DmgPropertyListMishBlock(nameElement.getTextContent(), dataBlock);
+            mishBlocks.add(mishBlock);
+        }
+        return mishBlocks;
+    }
+
+    public static void main(String[] args) throws Exception {
+        File input = new File("/Users/christoferdutz/Downloads/flashplayer_20_sa_debug.dmg");
+        DmgExtractor dmgExtractor = new DmgExtractor();
+        dmgExtractor.extract(input);
+    }
+
+    public static String getStringFromZeroTerminatedByteArray(byte[] data) {
+        int i;
+        for (i = 0; i < data.length && data[i] != 0; i++) { }
+        return new String(data, 0, i);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/ApplePartitionMap.java
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/ApplePartitionMap.java b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/ApplePartitionMap.java
new file mode 100644
index 0000000..07a7211
--- /dev/null
+++ b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/ApplePartitionMap.java
@@ -0,0 +1,197 @@
+package org.apache.flex.utilities.converter.retrievers.download.utils.utils;
+
+import org.apache.flex.utilities.converter.retrievers.download.utils.DmgExtractor;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * https://en.wikipedia.org/wiki/Apple_Partition_Map
+ *
+ * Created by christoferdutz on 25.02.16.
+ */
+public class ApplePartitionMap {
+
+    public static int STATUS_ENTRY_IS_VALID                             = 0x00000001;
+    public static int STATUS_ENTRY_IS_ALLOCATED                         = 0x00000002;
+    public static int STATUS_ENTRY_IN_USE                               = 0x00000004;
+    public static int STATUS_ENTRY_CONTAINS_BOOT_INFORMATION            = 0x00000008;
+    public static int STATUS_PARTITION_IS_READABLE                      = 0x00000010;
+    public static int STATUS_PARTITION_IS_WRITABLE                      = 0x00000020;
+    public static int STATUS_BOOT_CODE_IS_POSITION_INDEPENDENT          = 0x00000040;
+    public static int STATUS_PARTITION_CONTAINS_CHAIN_COMPATIBLE_DRIVER = 0x00000100;
+    public static int STATUS_PARTITION_CONTAINS_A_REAL_DRIVER           = 0x00000200;
+    public static int STATUS_PARTITION_CONTAINS_A_CHAIN_DRIVER          = 0x00000400;
+    public static int STATUS_AUTOMATICALLY_MOUNT_AT_STARTUP             = 0x40000000;
+    public static int STATUS_THE_STARTUP_PARTITION                      = 0x80000000;
+
+    private int numPartitions;
+    private int startingSectorOfPartition;
+    private int sizeOfPartitionInSectors;
+    private String nameOfPartition;
+    private String typeOfPartition;
+    private int startingSectorOfDataAreaInPartition;
+    private int sizeOfDataAreaInPartitionInSectors;
+    private int statusOfPartition;
+    private int startingSectorOfBootCode;
+    private int sizeOfBootCodeInSectors;
+    private int addressOfBootloaderCode;
+    private int bootCodeEntryPoint;
+    private int bootCodeChecksum;
+    private String processorType;
+
+    public ApplePartitionMap(DataInputStream dis) {
+        // Initialize the fields by parsing the input bytes.
+        try {
+            if(dis.readShort() != 0x504D) {
+                throw new IllegalArgumentException("Invalid ApplePartitionMap data. Expected magic number 0x504D");
+            }
+            dis.skipBytes(2);
+            numPartitions = dis.readInt();
+            startingSectorOfPartition = dis.readInt();
+            sizeOfPartitionInSectors = dis.readInt();
+            byte[] buffer = new byte[32];
+            dis.read(buffer);
+            nameOfPartition = DmgExtractor.getStringFromZeroTerminatedByteArray(buffer);
+            buffer = new byte[32];
+            dis.read(buffer);
+            typeOfPartition = DmgExtractor.getStringFromZeroTerminatedByteArray(buffer);
+            startingSectorOfDataAreaInPartition = dis.readInt();
+            sizeOfDataAreaInPartitionInSectors = dis.readInt();
+            statusOfPartition = dis.readInt();
+            startingSectorOfBootCode = dis.readInt();
+            sizeOfBootCodeInSectors = dis.readInt();
+            addressOfBootloaderCode = dis.readInt();
+            dis.skipBytes(4);
+            bootCodeEntryPoint = dis.readInt();
+            dis.skipBytes(4);
+            bootCodeChecksum = dis.readInt();
+            buffer = new byte[16];
+            dis.read(buffer);
+            processorType = DmgExtractor.getStringFromZeroTerminatedByteArray(buffer);
+            dis.skipBytes(376);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Invalid DmgPropertyListMishBlock data.");
+        }
+    }
+
+    public int getNumPartitions() {
+        return numPartitions;
+    }
+
+    public int getStartingSectorOfPartition() {
+        return startingSectorOfPartition;
+    }
+
+    public int getSizeOfPartitionInSectors() {
+        return sizeOfPartitionInSectors;
+    }
+
+    public String getNameOfPartition() {
+        return nameOfPartition;
+    }
+
+    public String getTypeOfPartition() {
+        return typeOfPartition;
+    }
+
+    public int getStartingSectorOfDataAreaInPartition() {
+        return startingSectorOfDataAreaInPartition;
+    }
+
+    public int getSizeOfDataAreaInPartitionInSectors() {
+        return sizeOfDataAreaInPartitionInSectors;
+    }
+
+    public int getStatusOfPartition() {
+        return statusOfPartition;
+    }
+
+    public String getStatusOfPartitionName() {
+        StringBuilder sb = new StringBuilder();
+        if((statusOfPartition & STATUS_ENTRY_IS_VALID) != 0) {
+            sb.append(", Entry is valid");
+        }
+        if((statusOfPartition & STATUS_ENTRY_IS_ALLOCATED) != 0) {
+            sb.append(", Entry is allocated");
+        }
+        if((statusOfPartition & STATUS_ENTRY_IN_USE) != 0) {
+            sb.append(", Entry in use");
+        }
+        if((statusOfPartition & STATUS_ENTRY_CONTAINS_BOOT_INFORMATION) != 0) {
+            sb.append(", Entry contains boot information");
+        }
+        if((statusOfPartition & STATUS_PARTITION_IS_READABLE) != 0) {
+            sb.append(", Partition is readable");
+        }
+        if((statusOfPartition & STATUS_PARTITION_IS_WRITABLE) != 0) {
+            sb.append(", Partition is writable");
+        }
+        if((statusOfPartition & STATUS_BOOT_CODE_IS_POSITION_INDEPENDENT) != 0) {
+            sb.append(", Boot code is position independent");
+        }
+        if((statusOfPartition & STATUS_PARTITION_CONTAINS_CHAIN_COMPATIBLE_DRIVER) != 0) {
+            sb.append(", Partition contains chain-compatible driver");
+        }
+        if((statusOfPartition & STATUS_PARTITION_CONTAINS_A_REAL_DRIVER) != 0) {
+            sb.append(", Partition contains a real driver");
+        }
+        if((statusOfPartition & STATUS_PARTITION_CONTAINS_A_CHAIN_DRIVER) != 0) {
+            sb.append(", Partition contains a chain driver");
+        }
+        if((statusOfPartition & STATUS_AUTOMATICALLY_MOUNT_AT_STARTUP) != 0) {
+            sb.append(", Automatically mount at startup");
+        }
+        if((statusOfPartition & STATUS_THE_STARTUP_PARTITION) != 0) {
+            sb.append(", The startup partition");
+        }
+        if(sb.length() > 0) {
+            return sb.toString().substring(2);
+        }
+        return "- none -";
+    }
+
+    public int getStartingSectorOfBootCode() {
+        return startingSectorOfBootCode;
+    }
+
+    public int getSizeOfBootCodeInSectors() {
+        return sizeOfBootCodeInSectors;
+    }
+
+    public int getAddressOfBootloaderCode() {
+        return addressOfBootloaderCode;
+    }
+
+    public int getBootCodeEntryPoint() {
+        return bootCodeEntryPoint;
+    }
+
+    public int getBootCodeChecksum() {
+        return bootCodeChecksum;
+    }
+
+    public String getProcessorType() {
+        return processorType;
+    }
+
+    @Override
+    public String toString() {
+        return "ApplePartitionMap{" +
+                "numPartitions=" + numPartitions +
+                ", startingSectorOfPartition=" + startingSectorOfPartition +
+                ", sizeOfPartitionInSectors=" + sizeOfPartitionInSectors +
+                ", nameOfPartition='" + nameOfPartition + '\'' +
+                ", typeOfPartition='" + typeOfPartition + '\'' +
+                ", startingSectorOfDataAreaInPartition=" + startingSectorOfDataAreaInPartition +
+                ", sizeOfDataAreaInPartitionInSectors=" + sizeOfDataAreaInPartitionInSectors +
+                ", statusOfPartition=" + statusOfPartition +
+                ", startingSectorOfBootCode=" + startingSectorOfBootCode +
+                ", sizeOfBootCodeInSectors=" + sizeOfBootCodeInSectors +
+                ", addressOfBootloaderCode=" + addressOfBootloaderCode +
+                ", bootCodeEntryPoint=" + bootCodeEntryPoint +
+                ", bootCodeChecksum=" + bootCodeChecksum +
+                ", processorType='" + processorType + '\'' +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DmgBlockChunkEntry.java
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DmgBlockChunkEntry.java b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DmgBlockChunkEntry.java
new file mode 100644
index 0000000..58c4737
--- /dev/null
+++ b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DmgBlockChunkEntry.java
@@ -0,0 +1,96 @@
+package org.apache.flex.utilities.converter.retrievers.download.utils.utils;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * Created by christoferdutz on 25.02.16.
+ */
+public class DmgBlockChunkEntry {
+
+    int entryType;          // Compression type used or entry type (see next table)
+    int comment;            // "+beg" or "+end", if EntryType is comment (0x7FFFFFFE). Else reserved.
+    long sectorNumber;      // Start sector of this chunk
+    long sectorCount;       // Number of sectors in this chunk
+    long compressedOffset;  // Start of chunk in data fork
+    long compressedLength;  // Count of bytes of chunk, in data fork
+
+    public DmgBlockChunkEntry(byte[] data) {
+        // Initialize the fields by parsing the input bytes.
+        ByteArrayInputStream bis = new ByteArrayInputStream(data);
+        DataInputStream dis = new DataInputStream(bis);
+        try {
+            entryType = dis.readInt();
+            comment = dis.readInt();
+            sectorNumber = dis.readLong();
+            sectorCount = dis.readLong();
+            compressedOffset = dis.readLong();
+            compressedLength = dis.readLong();
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Invalid DmgBlockChunkEntry data.");
+        }
+    }
+
+    public int getEntryType() {
+        return entryType;
+    }
+
+    public int getComment() {
+        return comment;
+    }
+
+    public long getSectorNumber() {
+        return sectorNumber;
+    }
+
+    public long getSectorCount() {
+        return sectorCount;
+    }
+
+    public long getCompressedOffset() {
+        return compressedOffset;
+    }
+
+    public long getCompressedLength() {
+        return compressedLength;
+    }
+
+    @Override
+    public String toString() {
+        String entryTypeName;
+        switch(entryType) {
+            case 0x00000000:
+                entryTypeName = "Zero-Fill";
+                break;
+            case 0x00000001:
+                entryTypeName = "UDRW/UDRO - RAW or NULL compression (uncompressed)";
+                break;
+            case 0x00000002:
+                entryTypeName = "Ignored/unknown";
+                break;
+            case 0x80000004:
+                entryTypeName = "UDCO - Apple Data Compression (ADC)";
+                break;
+            case 0x80000005:
+                entryTypeName = "UDZO - zLib data compression";
+                break;
+            case 0x80000006:
+                entryTypeName = "UDBZ - bz2lib data compression";
+                break;
+            case 0x7ffffffe:
+                entryTypeName = "No blocks - Comment: +beg and +end";
+            default:
+                entryTypeName = "Unknown entry type " + entryType;
+        }
+        return "DmgBlockChunkEntry{" +
+                "entryType=" + entryTypeName +
+                ", comment=" + comment +
+                ", sectorNumber=" + sectorNumber +
+                ", sectorCount=" + sectorCount +
+                ", compressedOffset=" + compressedOffset +
+                ", compressedLength=" + compressedLength +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DmgPropertyListMishBlock.java
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DmgPropertyListMishBlock.java b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DmgPropertyListMishBlock.java
new file mode 100644
index 0000000..a5b4e02
--- /dev/null
+++ b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DmgPropertyListMishBlock.java
@@ -0,0 +1,101 @@
+package org.apache.flex.utilities.converter.retrievers.download.utils.utils;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by christoferdutz on 25.02.16.
+ */
+public class DmgPropertyListMishBlock {
+
+    private String blockName;
+
+    private int version;             // Current version is 1
+    private long sectorNumber;       // Starting disk sector in this blkx descriptor
+    private long sectorCount;        // Number of disk sectors in this blkx descriptor
+
+    private long dataOffset;
+    private int buffersNeeded;
+    private int blockDescriptors;    // Number of descriptors
+
+    private DmgUdifChecksum checksum;
+
+    private List<DmgBlockChunkEntry> blockChunkEntries;
+
+    public DmgPropertyListMishBlock(String blockName, byte[] data) {
+        this.blockName = blockName;
+
+        // Initialize the fields by parsing the input bytes.
+        ByteArrayInputStream bis = new ByteArrayInputStream(data);
+        DataInputStream dis = new DataInputStream(bis);
+        try {
+            dis.readInt();
+            version = dis.readInt();
+            sectorNumber = dis.readLong();
+            sectorCount = dis.readLong();
+            dataOffset = dis.readLong();
+            buffersNeeded = dis.readInt();
+            blockDescriptors = dis.readInt();
+            dis.skipBytes(24);
+            byte[] checksumData = new byte[136];
+            dis.read(checksumData, 0, 136);
+            checksum = new DmgUdifChecksum(checksumData);
+            int numberOfBlockChunks = dis.readInt();
+
+            blockChunkEntries = new ArrayList<DmgBlockChunkEntry>();
+            byte[] blockChunkData = new byte[40];
+            for(int i = 0; i < numberOfBlockChunks; i++) {
+                dis.read(blockChunkData);
+                DmgBlockChunkEntry entry = new DmgBlockChunkEntry(blockChunkData);
+                // The block with the type "0xFFFFFFFF" is the end-block and contains
+                // no data we could need, so we simply end here.
+                if(entry.getEntryType() == 0xFFFFFFFF) {
+                    break;
+                }
+                blockChunkEntries.add(entry);
+            }
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Invalid DmgPropertyListMishBlock data.");
+        }
+    }
+
+    public String getBlockName() {
+        return blockName;
+    }
+
+    public int getVersion() {
+        return version;
+    }
+
+    public long getSectorNumber() {
+        return sectorNumber;
+    }
+
+    public long getSectorCount() {
+        return sectorCount;
+    }
+
+    public long getDataOffset() {
+        return dataOffset;
+    }
+
+    public int getBuffersNeeded() {
+        return buffersNeeded;
+    }
+
+    public int getBlockDescriptors() {
+        return blockDescriptors;
+    }
+
+    public DmgUdifChecksum getChecksum() {
+        return checksum;
+    }
+
+    public List<DmgBlockChunkEntry> getBlockChunkEntries() {
+        return blockChunkEntries;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DmgTrailer.java
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DmgTrailer.java b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DmgTrailer.java
new file mode 100644
index 0000000..aa0ba9e
--- /dev/null
+++ b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DmgTrailer.java
@@ -0,0 +1,158 @@
+package org.apache.flex.utilities.converter.retrievers.download.utils.utils;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * Created by christoferdutz on 24.02.16.
+ */
+public class DmgTrailer {
+
+    private int version;                // Current version is 4
+    private int headerSize;             // sizeof(this), always 512
+    private int flags;                  // Flags
+    private long runningDataForkOffset; //
+    private long dataForkOffset;        // Data fork offset (usually 0, beginning of file)
+    private long dataForkLength;        // Size of data fork (usually up to the XMLOffset, below)
+    private long rsrcForkOffset;        // Resource fork offset, if any
+    private long rsrcForkLength;        // Resource fork length, if any
+    private int segmentNumber;          // Usually 1, may be 0
+    private int segmentCount;           // Usually 1, may be 0
+    private byte[] segmentID;           // 128-bit (16 byte) GUID identifier of segment (if SegmentNumber !=0)
+
+    private int dataChecksumType;       // Data fork
+    private int dataChecksumSize;       //  Checksum Information
+    private byte[] dataChecksum;        // Up to 128-bytes (32 x 4) of checksum
+
+    private long xmlOffset;             // Offset of property list in DMG, from beginning
+    private long xmlLength;             // Length of property list
+
+    private int checksumType;           // Master
+    private int checksumSize;           // Checksum information
+    private byte[] checksum;            // Up to 128-bytes (32 x 4) of checksum
+
+    private int imageVariant;           // Commonly 1
+    private long sectorCount;           // Size of DMG when expanded, in sectors
+
+    public DmgTrailer(byte[] data) {
+        // Initialize the fields by parsing the input bytes.
+        ByteArrayInputStream bis = new ByteArrayInputStream(data);
+        DataInputStream dis = new DataInputStream(bis);
+        try {
+            dis.readInt();
+            version = dis.readInt();
+            headerSize = dis.readInt();
+            flags = dis.readInt();
+            runningDataForkOffset = dis.readLong();
+            dataForkOffset = dis.readLong();
+            dataForkLength = dis.readLong();
+            rsrcForkOffset = dis.readLong();
+            rsrcForkLength = dis.readLong();
+            segmentNumber = dis.readInt();
+            segmentCount = dis.readInt();
+            segmentID = new byte[16];
+            dis.read(segmentID, 0, 16);
+            dataChecksumType = dis.readInt();
+            dataChecksumSize = dis.readInt();
+            dataChecksum = new byte[128];
+            dis.read(dataChecksum, 0, 128);
+            xmlOffset = dis.readLong();
+            xmlLength = dis.readLong();
+            byte[] reserved = new byte[120];
+            dis.read(reserved, 0, 120);
+            checksumType = dis.readInt();
+            checksumSize = dis.readInt();
+            checksum = new byte[120];
+            dis.read(checksum, 0, 120);
+            imageVariant = dis.readInt();
+            sectorCount = dis.readLong();
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Invalid DmgTrailer data.");
+        }
+    }
+
+    public int getVersion() {
+        return version;
+    }
+
+    public int getHeaderSize() {
+        return headerSize;
+    }
+
+    public int getFlags() {
+        return flags;
+    }
+
+    public long getRunningDataForkOffset() {
+        return runningDataForkOffset;
+    }
+
+    public long getDataForkOffset() {
+        return dataForkOffset;
+    }
+
+    public long getDataForkLength() {
+        return dataForkLength;
+    }
+
+    public long getRsrcForkOffset() {
+        return rsrcForkOffset;
+    }
+
+    public long getRsrcForkLength() {
+        return rsrcForkLength;
+    }
+
+    public int getSegmentNumber() {
+        return segmentNumber;
+    }
+
+    public int getSegmentCount() {
+        return segmentCount;
+    }
+
+    public byte[] getSegmentID() {
+        return segmentID;
+    }
+
+    public int getDataChecksumType() {
+        return dataChecksumType;
+    }
+
+    public int getDataChecksumSize() {
+        return dataChecksumSize;
+    }
+
+    public byte[] getDataChecksum() {
+        return dataChecksum;
+    }
+
+    public long getXmlOffset() {
+        return xmlOffset;
+    }
+
+    public long getXmlLength() {
+        return xmlLength;
+    }
+
+    public int getChecksumType() {
+        return checksumType;
+    }
+
+    public int getChecksumSize() {
+        return checksumSize;
+    }
+
+    public byte[] getChecksum() {
+        return checksum;
+    }
+
+    public int getImageVariant() {
+        return imageVariant;
+    }
+
+    public long getSectorCount() {
+        return sectorCount;
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DmgUdifChecksum.java
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DmgUdifChecksum.java b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DmgUdifChecksum.java
new file mode 100644
index 0000000..52ec113
--- /dev/null
+++ b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DmgUdifChecksum.java
@@ -0,0 +1,42 @@
+package org.apache.flex.utilities.converter.retrievers.download.utils.utils;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * Created by christoferdutz on 25.02.16.
+ */
+public class DmgUdifChecksum {
+
+    private int type;
+    private int size;
+    private byte[] data;
+
+    public DmgUdifChecksum(byte[] data) {
+        // Initialize the fields by parsing the input bytes.
+        ByteArrayInputStream bis = new ByteArrayInputStream(data);
+        DataInputStream dis = new DataInputStream(bis);
+        try {
+            type = dis.readInt();
+            size = dis.readInt();
+            this.data = new byte[128];
+            dis.read(this.data, 0, 128);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Invalid DmgUdifChecksum data.");
+        }
+    }
+
+    public int getType() {
+        return type;
+    }
+
+    public int getSize() {
+        return size;
+    }
+
+    public byte[] getData() {
+        return data;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DriverDescriptor.java
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DriverDescriptor.java b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DriverDescriptor.java
new file mode 100644
index 0000000..61beb26
--- /dev/null
+++ b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DriverDescriptor.java
@@ -0,0 +1,38 @@
+package org.apache.flex.utilities.converter.retrievers.download.utils.utils;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * Created by christoferdutz on 26.02.16.
+ */
+public class DriverDescriptor {
+
+    private int driverBlockStart;
+    private short driverBlockCount;
+    private short driverSystemType;
+
+    public DriverDescriptor(DataInputStream dis) {
+        // Initialize the fields by parsing the input bytes.
+        try {
+            driverBlockStart = dis.readInt();
+            driverBlockCount = dis.readShort();
+            driverSystemType = dis.readShort();
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Invalid DriverDescriptor data.");
+        }
+    }
+
+    public int getDriverBlockStart() {
+        return driverBlockStart;
+    }
+
+    public short getDriverBlockCount() {
+        return driverBlockCount;
+    }
+
+    public short getDriverSystemType() {
+        return driverSystemType;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DriverDescriptorMap.java
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DriverDescriptorMap.java b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DriverDescriptorMap.java
new file mode 100644
index 0000000..da9117a
--- /dev/null
+++ b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/DriverDescriptorMap.java
@@ -0,0 +1,85 @@
+package org.apache.flex.utilities.converter.retrievers.download.utils.utils;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by christoferdutz on 26.02.16.
+ */
+public class DriverDescriptorMap {
+
+    private short blockSize;
+    private int blockCount;
+    private short deviceType;
+    private short deviceId;
+    private int driverData;
+    private short driverDescriptorCount;
+    private List<DriverDescriptor> driverDescroiptors;
+
+    public DriverDescriptorMap(DataInputStream dis) {
+        // Initialize the fields by parsing the input bytes.
+        try {
+            if (dis.readShort() != 0x4552) {
+                throw new IllegalArgumentException("Invalid DriverDescriptorMap data. Expected magic number 0x4552");
+            }
+            blockSize = dis.readShort();
+            blockCount = dis.readInt();
+            deviceType = dis.readShort();
+            deviceId = dis.readShort();
+            driverData = dis.readInt();
+            driverDescriptorCount = dis.readShort();
+            driverDescroiptors = new ArrayList<DriverDescriptor>();
+            for(int i = 0; i < 8; i++) {
+                DriverDescriptor dd = new DriverDescriptor(dis);
+                driverDescroiptors.add(dd);
+            }
+            dis.skipBytes(430);
+
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Invalid DriverDescriptorMap data.");
+        }
+    }
+
+    public short getBlockSize() {
+        return blockSize;
+    }
+
+    public int getBlockCount() {
+        return blockCount;
+    }
+
+    public short getDeviceType() {
+        return deviceType;
+    }
+
+    public short getDeviceId() {
+        return deviceId;
+    }
+
+    public int getDriverData() {
+        return driverData;
+    }
+
+    public short getDriverDescriptorCount() {
+        return driverDescriptorCount;
+    }
+
+    public List<DriverDescriptor> getDriverDescroiptors() {
+        return driverDescroiptors;
+    }
+
+    @Override
+    public String toString() {
+        return "DriverDescriptorMap{" +
+                "blockSize=" + blockSize +
+                ", blockCount=" + blockCount +
+                ", deviceType=" + deviceType +
+                ", deviceId=" + deviceId +
+                ", driverData=" + driverData +
+                ", driverDescriptorCount=" + driverDescriptorCount +
+                ", driverDescroiptors=" + driverDescroiptors +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSPlusExtent.java
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSPlusExtent.java b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSPlusExtent.java
new file mode 100644
index 0000000..a0dd5c9
--- /dev/null
+++ b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSPlusExtent.java
@@ -0,0 +1,40 @@
+package org.apache.flex.utilities.converter.retrievers.download.utils.utils;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * Created by christoferdutz on 27.02.16.
+ */
+public class HFSPlusExtent {
+
+    private int startBlock;
+    private int blockCount;
+
+    public HFSPlusExtent(DataInputStream dis) {
+        try {
+            startBlock = dis.readInt();
+            blockCount = dis.readInt();
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Invalid HFSPlusVolumeHeader data.");
+        }
+    }
+
+    public int getStartBlock() {
+        return startBlock;
+    }
+
+    public int getBlockCount() {
+        return blockCount;
+    }
+
+    @Override
+    public String toString() {
+        return "HFSPlusExtent{" +
+                "startBlock=" + startBlock +
+                ", blockCount=" + blockCount +
+                '}';
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSPlusForkData.java
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSPlusForkData.java b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSPlusForkData.java
new file mode 100644
index 0000000..dcec76f
--- /dev/null
+++ b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSPlusForkData.java
@@ -0,0 +1,59 @@
+package org.apache.flex.utilities.converter.retrievers.download.utils.utils;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by christoferdutz on 26.02.16.
+ */
+public class HFSPlusForkData {
+
+    private long logicalSize;
+    int clumpSize;
+    int totalBlocks;
+    List<HFSPlusExtent> extents;
+
+    public HFSPlusForkData(DataInputStream dis) {
+        try {
+            logicalSize = dis.readLong();
+            clumpSize = dis.readInt();
+            totalBlocks = dis.readInt();
+            extents = new ArrayList<HFSPlusExtent>(8);
+            for(int i = 0; i < 8; i++) {
+                HFSPlusExtent extent = new HFSPlusExtent(dis);
+                extents.add(extent);
+            }
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Invalid HFSPlusVolumeHeader data.");
+        }
+    }
+
+    public long getLogicalSize() {
+        return logicalSize;
+    }
+
+    public int getClumpSize() {
+        return clumpSize;
+    }
+
+    public int getTotalBlocks() {
+        return totalBlocks;
+    }
+
+    public List<HFSPlusExtent> getExtents() {
+        return extents;
+    }
+
+    @Override
+    public String toString() {
+        return "HFSPlusForkData{" +
+                "logicalSize=" + logicalSize +
+                ", clumpSize=" + clumpSize +
+                ", totalBlocks=" + totalBlocks +
+                ", extents=" + extents +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSPlusVolumeHeader.java
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSPlusVolumeHeader.java b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSPlusVolumeHeader.java
new file mode 100644
index 0000000..b355c05
--- /dev/null
+++ b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSPlusVolumeHeader.java
@@ -0,0 +1,217 @@
+package org.apache.flex.utilities.converter.retrievers.download.utils.utils;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * http://www.dubeyko.com/development/FileSystems/HFSPLUS/hexdumps/hfsplus_volume_header.html
+ *
+ * Created by christoferdutz on 24.02.16.
+ */
+public class HFSPlusVolumeHeader implements IHFSVolumeHeader {
+
+    private short version;
+    private int attributes;
+    private int lastMountedVersion;
+    private int journalInfoBlock;
+
+    private int createDate;
+    private int modifyDate;
+    private int backupDate;
+    private int checkedDate;
+
+    private int fileCount;
+    private int folderCount;
+
+    private int blockSize;
+    private int totalBlocks;
+    private int freeBlocks;
+
+    private int nextAllocation;
+    private int rsrcClumpSize;
+    private int nextCatalogID;
+    private int dataClumpSize;
+
+    private int writeCount;
+    private long encodingsBitmap;
+
+    private byte[] finderInfo;
+
+    private HFSPlusForkData allocationFile;
+    private HFSPlusForkData extentsFile;
+    private HFSPlusForkData catalogFile;
+    private HFSPlusForkData attributesFile;
+    private HFSPlusForkData startupFile;
+
+    public HFSPlusVolumeHeader(DataInputStream dis) {
+        try {
+            version = dis.readShort();
+            attributes = dis.readInt();
+            lastMountedVersion = dis.readInt();
+            journalInfoBlock = dis.readInt();
+
+            createDate = dis.readInt();
+            modifyDate = dis.readInt();
+            backupDate = dis.readInt();
+            checkedDate = dis.readInt();
+
+            fileCount = dis.readInt();
+            folderCount = dis.readInt();
+
+            blockSize = dis.readInt();
+            totalBlocks = dis.readInt();
+            freeBlocks = dis.readInt();
+
+            nextAllocation = dis.readInt();
+            rsrcClumpSize = dis.readInt();
+            dataClumpSize = dis.readInt();
+            nextCatalogID = dis.readInt();
+
+            writeCount = dis.readInt();
+            encodingsBitmap = dis.readLong();
+
+            finderInfo = new byte[32];
+            dis.read(finderInfo);
+
+            allocationFile = new HFSPlusForkData(dis);
+            extentsFile = new HFSPlusForkData(dis);
+            catalogFile = new HFSPlusForkData(dis);
+            attributesFile = new HFSPlusForkData(dis);
+            startupFile = new HFSPlusForkData(dis);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Invalid HFSPlusVolumeHeader data.");
+        }
+    }
+
+    public short getVersion() {
+        return version;
+    }
+
+    public int getAttributes() {
+        return attributes;
+    }
+
+    public int getLastMountedVersion() {
+        return lastMountedVersion;
+    }
+
+    public int getJournalInfoBlock() {
+        return journalInfoBlock;
+    }
+
+    public int getCreateDate() {
+        return createDate;
+    }
+
+    public int getModifyDate() {
+        return modifyDate;
+    }
+
+    public int getBackupDate() {
+        return backupDate;
+    }
+
+    public int getCheckedDate() {
+        return checkedDate;
+    }
+
+    public int getFileCount() {
+        return fileCount;
+    }
+
+    public int getFolderCount() {
+        return folderCount;
+    }
+
+    public int getBlockSize() {
+        return blockSize;
+    }
+
+    public int getTotalBlocks() {
+        return totalBlocks;
+    }
+
+    public int getFreeBlocks() {
+        return freeBlocks;
+    }
+
+    public int getNextAllocation() {
+        return nextAllocation;
+    }
+
+    public int getRsrcClumpSize() {
+        return rsrcClumpSize;
+    }
+
+    public int getDataClumpSize() {
+        return dataClumpSize;
+    }
+
+    public int getWriteCount() {
+        return writeCount;
+    }
+
+    public long getEncodingsBitmap() {
+        return encodingsBitmap;
+    }
+
+    public int getNextCatalogID() {
+        return nextCatalogID;
+    }
+
+    public byte[] getFinderInfo() {
+        return finderInfo;
+    }
+
+    public HFSPlusForkData getAllocationFile() {
+        return allocationFile;
+    }
+
+    public HFSPlusForkData getExtentsFile() {
+        return extentsFile;
+    }
+
+    public HFSPlusForkData getCatalogFile() {
+        return catalogFile;
+    }
+
+    public HFSPlusForkData getAttributesFile() {
+        return attributesFile;
+    }
+
+    public HFSPlusForkData getStartupFile() {
+        return startupFile;
+    }
+
+    @Override
+    public String toString() {
+        return "HFSPlusVolumeHeader{" +
+                "version=" + version +
+                ", attributes=" + attributes +
+                ", lastMountedVersion=" + lastMountedVersion +
+                ", journalInfoBlock=" + journalInfoBlock +
+                ", createDate=" + createDate +
+                ", modifyDate=" + modifyDate +
+                ", backupDate=" + backupDate +
+                ", checkedDate=" + checkedDate +
+                ", fileCount=" + fileCount +
+                ", folderCount=" + folderCount +
+                ", blockSize=" + blockSize +
+                ", totalBlocks=" + totalBlocks +
+                ", freeBlocks=" + freeBlocks +
+                ", nextAllocation=" + nextAllocation +
+                ", rsrcClumpSize=" + rsrcClumpSize +
+                ", nextCatalogID=" + nextCatalogID +
+                ", dataClumpSize=" + dataClumpSize +
+                ", writeCount=" + writeCount +
+                ", encodingsBitmap=" + encodingsBitmap +
+                ", finderInfo=" + Arrays.toString(finderInfo) +
+                ", allocationFile=" + allocationFile +
+                ", extentsFile=" + extentsFile +
+                ", catalogFile=" + catalogFile +
+                ", attributesFile=" + attributesFile +
+                ", startupFile=" + startupFile +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSVolumeFactory.java
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSVolumeFactory.java b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSVolumeFactory.java
new file mode 100644
index 0000000..24536e3
--- /dev/null
+++ b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSVolumeFactory.java
@@ -0,0 +1,24 @@
+package org.apache.flex.utilities.converter.retrievers.download.utils.utils;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * Created by christoferdutz on 27.02.16.
+ */
+public class HFSVolumeFactory {
+
+    public static IHFSVolumeHeader readHfsVolumeHeader(DataInputStream dis) {
+        try {
+            short magicNumber = dis.readShort();
+            if(magicNumber == 0x482B) {
+                return new HFSPlusVolumeHeader(dis);
+            } else {
+                return new HFSVolumeHeader(dis);
+            }
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Invalid IHFSPVolumeHeader data.");
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSVolumeHeader.java
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSVolumeHeader.java b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSVolumeHeader.java
new file mode 100644
index 0000000..e2bb8b3
--- /dev/null
+++ b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/HFSVolumeHeader.java
@@ -0,0 +1,13 @@
+package org.apache.flex.utilities.converter.retrievers.download.utils.utils;
+
+import java.io.DataInputStream;
+
+/**
+ * Created by christoferdutz on 27.02.16.
+ */
+public class HFSVolumeHeader implements IHFSVolumeHeader {
+
+    public HFSVolumeHeader(DataInputStream dis) {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/cf75f0e0/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/IHFSVolumeHeader.java
----------------------------------------------------------------------
diff --git a/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/IHFSVolumeHeader.java b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/IHFSVolumeHeader.java
new file mode 100644
index 0000000..470fad0
--- /dev/null
+++ b/flex-maven-tools/flex-sdk-converter/retrievers/download/src/main/java/org/apache/flex/utilities/converter/retrievers/download/utils/utils/IHFSVolumeHeader.java
@@ -0,0 +1,10 @@
+package org.apache.flex.utilities.converter.retrievers.download.utils.utils;
+
+/**
+ * http://www.dubeyko.com/development/FileSystems/HFSPLUS/hexdumps/hfsplus_volume_header.html
+ *
+ * Created by christoferdutz on 24.02.16.
+ */
+public interface IHFSVolumeHeader {
+
+}