changeset 5636:89b46b3257cb

Tools for launcher, Maven part
author Milan Kubec <milan.kubec@oracle.com>
date Tue, 05 Nov 2013 13:27:04 +0100
parents 1c3b39a00d7e
children 270d5f4e10b2
files tools/ios/Maven/NetBeansMobileCenter/pom.xml tools/ios/Maven/NetBeansMobileCenter/src/main/java/com/sun/javafx/appmanager/BootstrapApplication.java tools/ios/Maven/NetBeansMobileCenter/src/main/java/com/sun/javafx/appmanager/FxApplicationInstance.java tools/ios/Maven/NetBeansMobileCenter/src/main/java/com/sun/javafx/appmanager/FxApplicationManager.java tools/ios/Maven/NetBeansMobileCenter/src/main/java/com/sun/javafx/stage/WindowManager.java tools/ios/Maven/NetBeansMobileCenter/src/main/java/org/netbeans/mobilecenter/BackgroundService.java tools/ios/Maven/NetBeansMobileCenter/src/main/java/org/netbeans/mobilecenter/MobileCenter.java tools/ios/Maven/NetBeansMobileCenter/src/main/java/org/netbeans/mobilecenter/Redeploy.java tools/ios/Maven/ios-maven-plugin/pom.xml tools/ios/Maven/ios-maven-plugin/src/main/java/org/netbeans/ibrwsr/maven/plugin/IPAddressMojo.java tools/ios/Maven/ios-maven-plugin/src/main/scripts/ios.maven.plugin.build.xml tools/ios/Maven/ios-maven-plugin/src/main/scripts/ios.maven.plugin.mojos.xml tools/ios/Maven/ipack/pom.xml tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/blobs/Blob.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/blobs/SuperBlob.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/blobs/VirtualBlob.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/blobs/WrapperBlob.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/macho/CodeSignatureCommand.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/macho/LinkeditDataCommand.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/macho/MachoCommand.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/macho/MachoHeader.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/macho/SegmentCommand.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/macho/UnknownCommand.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/main/Main.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/packer/ExecutablePacker.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/packer/Packer.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/packer/ResourcePacker.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/resources/CodeResources.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/resources/ResourceRules.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/signature/CodeDirectoryBlob.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/signature/EmbeddedSignatureBlob.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/signature/Requirement.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/signature/RequirementBlob.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/signature/RequirementsBlob.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/signature/SpecialSlotConstants.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/signer/Signer.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/Base64.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/DataCopier.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/HashingOutputStream.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/LsbDataInputStream.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/LsbDataOutputStream.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/NullOutputStream.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/PageHashingOutputStream.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/ResourceDescriptor.java tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/Util.java tools/ios/Maven/pom.xml tools/ios/Maven/test-simple-ipa/pom.xml tools/ios/Maven/test-simple-ipa/src/main/java/org/netbeans/ios/test/simple/ipa/Main.java tools/ios/Maven/test-simple-ipa/src/test/java/org/netbeans/ios/test/simple/ipa/VerifyIPATest.java
diffstat 49 files changed, 6171 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/NetBeansMobileCenter/pom.xml	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,66 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.netbeans.ios</groupId>
+    <artifactId>mobile-center</artifactId>
+    <version>0.6-SNAPSHOT</version>
+    <parent>
+        <groupId>org.netbeans.ios</groupId>
+        <artifactId>Maven</artifactId>
+        <version>0.6-SNAPSHOT</version>
+    </parent>
+    <packaging>jar</packaging>
+
+    <name>NetBeansMobileCenter</name>
+    <url>http://maven.apache.org</url>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>2.3.2</version>
+                <configuration>
+                    <source>1.7</source>
+                    <target>1.7</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>com.oracle</groupId>
+            <artifactId>javafx</artifactId>
+            <version>8.0</version>
+            <scope>system</scope>
+            <systemPath>${jfxrt.jar}</systemPath>
+        </dependency>
+    </dependencies>
+   <profiles>
+      <profile>
+          <id>jdk8</id>
+          <activation>
+              <file>
+                  <exists>${java.home}/lib/ext/jfxrt.jar</exists>
+              </file>
+          </activation>
+          <properties>
+            <jfxrt.jar>${java.home}/lib/ext/jfxrt.jar</jfxrt.jar>
+          </properties>
+      </profile>
+      <profile>
+          <id>jdk7</id>
+          <activation>
+              <file>
+                  <exists>${java.home}/lib/jfxrt.jar</exists>
+              </file>
+          </activation>
+          <properties>
+            <jfxrt.jar>${java.home}/lib/jfxrt.jar</jfxrt.jar>
+          </properties>
+      </profile>
+  </profiles>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/NetBeansMobileCenter/src/main/java/com/sun/javafx/appmanager/BootstrapApplication.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javafx.appmanager;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.concurrent.CountDownLatch;
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.scene.Node;
+import javafx.scene.Scene;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextArea;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.text.Font;
+import javafx.stage.Stage;
+
+public final class BootstrapApplication extends Application {
+    private static final CountDownLatch appStartedLatch =
+            new CountDownLatch(1);
+
+    @Override
+    public void start(final Stage primaryStage) {
+//        Platform.setImplicitExit(false);
+        final BorderPane root = new BorderPane();
+        root.setCenter(new Label("Mobile Center"));
+        root.setBottom(createOutputArea());
+
+        primaryStage.setTitle("Mobile Center");
+        primaryStage.setScene(new Scene(root));
+        primaryStage.show();
+
+        appStartedLatch.countDown();
+    }
+
+    public static void waitForStart() throws InterruptedException {
+        appStartedLatch.await();
+    }
+
+    private static Node createOutputArea() {
+        final TextArea textArea = new TextArea();
+        textArea.setPrefColumnCount(80);
+        textArea.setPrefRowCount(25);
+        textArea.setEditable(false);
+        textArea.setFont(Font.font("Monospaced"));
+        textArea.setWrapText(true);
+
+        final OutputStream textAreaStream = new TextAreaStream(textArea);
+        System.setOut(new PrintStream(textAreaStream, true));
+        System.setErr(new PrintStream(textAreaStream, true));
+
+        return textArea;
+    }
+
+    private static final class TextAreaStream extends OutputStream
+                                              implements Runnable {
+        private final TextArea textArea;
+        private final ByteArrayOutputStream byteBuffer;
+        private final StringBuilder textToAppend;
+
+        public TextAreaStream(final TextArea textArea) {
+            this.textArea = textArea;
+            this.byteBuffer = new ByteArrayOutputStream();
+            this.textToAppend = new StringBuilder();
+        }
+
+        @Override
+        public void write(final int value) {
+            synchronized (byteBuffer) {
+                byteBuffer.write(value);
+            }
+        }
+
+        @Override
+        public void write(final byte buffer[], final int offset,
+                          final int length) {
+            synchronized (byteBuffer) {
+                byteBuffer.write(buffer, offset, length);
+            }
+        }
+
+        @Override
+        public synchronized void flush() throws IOException {
+            final byte[] bytes;
+            synchronized (byteBuffer) {
+                byteBuffer.flush();
+                if (byteBuffer.size() == 0) {
+                    return;
+                }
+
+                bytes = byteBuffer.toByteArray();
+                byteBuffer.reset();
+            }
+
+            synchronized (textToAppend) {
+                if (textToAppend.length() == 0) {
+                    // no flush has been schedulet yet
+                    Platform.runLater(this);
+                }
+
+                textToAppend.append(new String(bytes));
+            }
+        }
+
+        @Override
+        public void run() {
+            final String newText;
+            synchronized (textToAppend) {
+                newText = textToAppend.toString();
+                textToAppend.setLength(0);
+            }
+
+            textArea.appendText(newText);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/NetBeansMobileCenter/src/main/java/com/sun/javafx/appmanager/FxApplicationInstance.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javafx.appmanager;
+
+public interface FxApplicationInstance {
+    void stop();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/NetBeansMobileCenter/src/main/java/com/sun/javafx/appmanager/FxApplicationManager.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javafx.appmanager;
+
+import com.sun.javafx.stage.WindowManager;
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.stage.Stage;
+
+public final class FxApplicationManager {
+    private static FxApplicationManager instance;
+
+    public static synchronized FxApplicationManager getInstance() {
+        if (instance == null) {
+            initializePlatform();
+            instance = new FxApplicationManager();
+        }
+
+        return instance;
+    }
+
+    public FxApplicationInstance start(
+            final ClassLoader appClassLoader,
+            final String appClass) throws Exception {
+        final Application application =
+                createFxApplication(appClassLoader, appClass);
+        application.init();
+
+        final StartAction startAction =
+                new StartAction(appClassLoader, application);
+        Platform.runLater(startAction);
+
+        return startAction.getResult();
+    }
+
+    private static void initializePlatform() {
+        final ThreadGroup fxPlatformThreadGroup =
+                new ThreadGroup(getTopLevelThreadGroup(), "FX Platform");
+        new Thread(fxPlatformThreadGroup, "FX Platform") {
+            @Override
+            public void run() {
+                Application.launch(BootstrapApplication.class);
+            }
+        }.start();
+        try {
+            BootstrapApplication.waitForStart();
+        } catch (final InterruptedException e) {
+            // ignore
+        }
+    }
+
+    private static Application createFxApplication(
+            final ClassLoader appClassLoader,
+            final String appClassName) throws ClassNotFoundException,
+                                              InstantiationException,
+                                              IllegalAccessException {
+        final Class<?> appClass = appClassLoader.loadClass(appClassName);
+        if (!Application.class.isAssignableFrom(appClass)) {
+            throw new ClassNotFoundException("FX application class not found");
+        }
+
+        return ((Class<Application>) appClass).newInstance();
+    }
+
+    private static ThreadGroup getTopLevelThreadGroup() {
+        ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
+        while (threadGroup.getParent() != null) {
+            threadGroup = threadGroup.getParent();
+        }
+
+        return threadGroup;
+    }
+
+    private static final class AppInstanceImpl
+            implements FxApplicationInstance {
+        private final ClassLoader appClassLoader;
+        private final Application application;
+
+        public AppInstanceImpl(final ClassLoader appClassLoader,
+                               final Application application) {
+            this.appClassLoader = appClassLoader;
+            this.application = application;
+        }
+
+        @Override
+        public void stop() {
+            final StopAction stopAction = new StopAction(appClassLoader,
+                                                         application);
+
+            Platform.runLater(stopAction);
+            try {
+                stopAction.waitForCompletion();
+            } catch (final InterruptedException e) {
+                // ignore
+            }
+        }
+    }
+
+    private static final class StartAction implements Runnable {
+        private final ClassLoader appClassLoader;
+        private final Application application;
+
+        private Exception exception;
+        private FxApplicationInstance result;
+
+        public StartAction(final ClassLoader appClassLoader,
+                           final Application application) {
+            this.appClassLoader = appClassLoader;
+            this.application = application;
+        }
+
+        @Override
+        public void run() {
+            final Thread currentThread = Thread.currentThread();
+            final ClassLoader oldContextClassLoader =
+                    currentThread.getContextClassLoader();
+
+            currentThread.setContextClassLoader(appClassLoader);
+            try {
+                try {
+                    final Stage appPrimaryStage = new Stage();
+                    appPrimaryStage.impl_setPrimary(true);
+                    application.start(appPrimaryStage);
+                } finally {
+                    currentThread.setContextClassLoader(oldContextClassLoader);
+                }
+            } catch (final Exception e) {
+                synchronized (this) {
+                    exception = e;
+                    notifyAll();
+                }
+                return;
+            }
+
+            synchronized (this) {
+                result = new AppInstanceImpl(appClassLoader, application);
+                notifyAll();
+            }
+        }
+
+        public synchronized FxApplicationInstance getResult() throws Exception {
+            while (result == null) {
+                if (exception != null) {
+                    throw exception;
+                }
+
+                wait();
+            }
+
+            return result;
+        }
+    }
+
+    private static final class StopAction implements Runnable {
+        private final ClassLoader appClassLoader;
+        private final Application application;
+
+        private boolean finished;
+
+        public StopAction(final ClassLoader appClassLoader,
+                          final Application application) {
+            this.appClassLoader = appClassLoader;
+            this.application = application;
+        }
+
+        @Override
+        public void run() {
+            try {
+                WindowManager.closeApplicationWindows(appClassLoader);
+                try {
+                    application.stop();
+                } catch (final Exception e) {
+                }
+            } finally {
+                synchronized (this) {
+                    finished = true;
+                    notifyAll();
+                }
+            }
+        }
+
+        public synchronized void waitForCompletion()
+                throws InterruptedException {
+            while (!finished) {
+                wait();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/NetBeansMobileCenter/src/main/java/com/sun/javafx/stage/WindowManager.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javafx.stage;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javafx.stage.Stage;
+import javafx.stage.Window;
+
+public final class WindowManager {
+    private WindowManager() {
+    }
+
+    public static void closeApplicationWindows(
+            final ClassLoader appClassLoader) {
+        final List<Window> selectedWindows = new ArrayList<Window>();
+        final Iterator<Window> allWindows = Window.impl_getWindows();
+        while (allWindows.hasNext()) {
+            final Window window = allWindows.next();
+            if (matches(window, appClassLoader)) {
+                selectedWindows.add(window);
+            }
+        }
+
+        for (int i = selectedWindows.size() - 1; i >= 0; --i) {
+            selectedWindows.get(i).hide();
+        }
+    }
+
+    private static boolean matches(final Window window,
+                                   final ClassLoader appClassLoader) {
+        // hack to be used until context class loader association with FX
+        // windows is pushed to JavaFX codebase
+        if (window instanceof Stage) {
+            return !"Mobile Center".equals(((Stage) window).getTitle());
+        }
+
+        return true;
+
+        /*
+        return isEqualToOrAncestorOf(
+                   appClassLoader,
+                   WindowHelper.getContextClassLoader(window));
+         */
+    }
+
+    /*
+    private static boolean isEqualToOrAncestorOf(
+            final ClassLoader fixedClassLoader,
+            ClassLoader testedClassLoader) {
+        if (fixedClassLoader == null) {
+            return true;
+        }
+
+        while (testedClassLoader != null) {
+            if (fixedClassLoader == testedClassLoader) {
+                return true;
+            }
+            testedClassLoader = testedClassLoader.getParent();
+        }
+
+        return false;
+    }
+     */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/NetBeansMobileCenter/src/main/java/org/netbeans/mobilecenter/BackgroundService.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.netbeans.mobilecenter;
+
+import com.sun.javafx.appmanager.FxApplicationInstance;
+import com.sun.javafx.appmanager.FxApplicationManager;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.lang.reflect.Method;
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+import java.net.MulticastSocket;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Enumeration;
+import java.util.jar.Manifest;
+
+final class BackgroundService {
+
+    public static final String GROUP_ADDRESS = "225.10.10.0";
+    public static final int PORT = 44445;
+    public static final int PORT_FILE = 44446;
+    public static final int PACKET_LENGTH = 1024;
+    public static final String MULTICAST_DISCOVERY = "NetBeansMulticastDiscovery";
+
+    private ThreadGroup threadGroup;
+
+    public void loop() {
+        boolean firstRun = true;
+        try (MulticastSocket socket = new MulticastSocket(PORT)) {
+            InetAddress group = InetAddress.getByName(GROUP_ADDRESS);
+            socket.joinGroup(group);
+
+            while (true) {
+                String appJarPath = null;
+
+                if (!firstRun) {
+                    DatagramPacket packet;
+                    byte[] buf = new byte[PACKET_LENGTH];
+                    packet = new DatagramPacket(buf, buf.length);
+                    socket.receive(packet);
+
+                    String received = new String(packet.getData());
+                    if (!received.trim().equals(MULTICAST_DISCOVERY)) {
+                        break;
+                    }
+
+                    buf = String.valueOf(PORT_FILE).getBytes();
+                    packet = new DatagramPacket(buf, buf.length, packet.getSocketAddress());
+                    socket.send(packet);
+                    appJarPath = receiveFile();
+                } else {
+                    firstRun = false;
+                }
+
+                final String filePath = appJarPath;
+                stopThreadGroup();
+                threadGroup = new ThreadGroup("Mobile Center Group");
+                synchronized (threadGroup) {
+                    new Thread(threadGroup, new Runnable() {
+                        @Override
+                        public void run() {
+                            try {
+                                invokeMainMethod(filePath);
+                            } catch (ThreadDeath td) {
+                                throw td;
+                            } catch (Throwable t) {
+                                t.printStackTrace();
+                            }
+                        }
+                    }, "Mobile Center Main").start();
+                }
+            }
+            socket.leaveGroup(group);
+            System.exit(0);
+        } catch (IOException ex) {
+            System.err.println(ex.getMessage());
+        }
+    }
+
+    private String receiveFile() {
+        try (ServerSocket serverSocket = new ServerSocket(PORT_FILE);
+                Socket socket = serverSocket.accept();
+                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream())) {
+            Object receivedObject = ois.readObject();
+            if (receivedObject instanceof byte[]) {
+                File targetFile = File.createTempFile("Debug", ".jar");
+                byte[] buffer = (byte[]) receivedObject;
+                try (OutputStream out = new FileOutputStream(targetFile)) {
+                    out.write(buffer);
+                }
+                return targetFile.getAbsolutePath();
+            }
+            return null;
+        } catch (IOException | ClassNotFoundException ex) {
+            System.out.println(ex.getMessage());
+            return null;
+        }
+    }
+
+    private FxApplicationInstance lastFxApplication;
+
+    public void invokeMainMethod(String jarPath) {
+        try {
+            ClassLoader sysClassLoader = ClassLoader.getSystemClassLoader();
+            URL[] cpURLs = ((URLClassLoader) sysClassLoader).getURLs();
+            URL[] classLoaderURLs = new URL[cpURLs.length];
+            System.arraycopy(cpURLs, 0, classLoaderURLs, 0, cpURLs.length);
+
+            String appJarName = System.getProperty("bgReloadJar");
+            String jarWithManifest = appJarName;
+            if (jarPath != null) {
+                URL appURL = new File(jarPath).toURI().toURL();
+                for (int i = 0; i < classLoaderURLs.length; i++) {
+                    if (classLoaderURLs[i].getPath().endsWith(appJarName)) {
+                        classLoaderURLs[i] = appURL;
+                    }
+                }
+                jarWithManifest = new File(jarPath).getName();
+            }
+
+            URLClassLoader classLoader = URLClassLoader.newInstance(classLoaderURLs, ClassLoader.getSystemClassLoader().getParent());
+
+            boolean fxEnabled = isFXApplication(classLoader, jarWithManifest);
+
+            if (lastFxApplication != null) {
+                lastFxApplication.stop();
+                lastFxApplication = null;
+            }
+
+            if (fxEnabled) {
+                final FxApplicationManager appManager =
+                        FxApplicationManager.getInstance();
+                final String appClass =
+                        findMainClass(classLoader, jarWithManifest);
+                lastFxApplication = appManager.start(classLoader, appClass);
+            } else {
+                Thread.currentThread().setContextClassLoader(classLoader);
+
+                Class clazz = classLoader.loadClass(findMainClass(classLoader, jarWithManifest));
+                Method method = clazz.getDeclaredMethod("main", String[].class);
+                method.setAccessible(true);
+                String[] params = null;
+                OutputStream os = new ByteArrayOutputStream();
+                System.setOut(new PrintStream(os));
+                method.invoke(classLoader, (Object) params);
+            }
+        } catch (Exception ex) {
+            System.err.println(ex.getClass().getName() + ": " + ex.getMessage());
+        }
+    }
+
+    private void stopThreadGroup() {
+        if (threadGroup == null) {
+            return;
+        }
+        synchronized (threadGroup) {
+            int count = threadGroup.activeCount();
+            Thread[] threads = new Thread[count];
+            threadGroup.enumerate(threads, true);
+            for (Thread t : threads) {
+                t.stop();
+            }
+        }
+    }
+
+    private static String findMainClass(final ClassLoader cl, String jarWithManifest) throws IOException {
+        String mainClass = null;
+        Enumeration<URL> en = cl.getResources("META-INF/MANIFEST.MF");
+        while (en.hasMoreElements()) {
+            URL url = en.nextElement();
+            Manifest mf;
+            try (InputStream is = url.openStream()) {
+                mf = new Manifest(is);
+            }
+            String mc = mf.getMainAttributes().getValue("JavaFX-Application-Class");
+            if (mc == null || mc.isEmpty()) {
+                mc = mf.getMainAttributes().getValue("Main-Class");
+            }
+            if (mc != null && url.getPath().contains(jarWithManifest)) {
+                mainClass = mc;
+                break;
+            }
+        }
+        return mainClass;
+    }
+
+    private static boolean isFXApplication(final ClassLoader cl, String jarWithManifest) throws IOException {
+        boolean fxApp = false;
+        Enumeration<URL> en = cl.getResources("META-INF/MANIFEST.MF");
+        while (en.hasMoreElements()) {
+            URL url = en.nextElement();
+            Manifest mf;
+            try (InputStream is = url.openStream()) {
+                mf = new Manifest(is);
+            }
+            String mc = mf.getMainAttributes().getValue("JavaFX-Version");
+            if (mc != null && url.getPath().contains(jarWithManifest)) {
+                fxApp = true;
+                break;
+            }
+        }
+        return fxApp;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/NetBeansMobileCenter/src/main/java/org/netbeans/mobilecenter/MobileCenter.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.netbeans.mobilecenter;
+
+public class MobileCenter {
+
+    public static void main(String[] args) throws InterruptedException {
+        new BackgroundService().loop();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/NetBeansMobileCenter/src/main/java/org/netbeans/mobilecenter/Redeploy.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.netbeans.mobilecenter;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.nio.file.Files;
+
+public final class Redeploy {
+    private Redeploy() {
+    }
+
+    public static void main(String... args) {
+        if (args.length != 1) {
+            System.err.println("Usage: <jar_file_to_deploy>");
+            System.exit(5);
+        }
+        File f = new File(args[0]);
+        if (!f.exists()) {
+            System.err.println("File " + f + " does not exist");
+            System.exit(1);
+        }
+
+        deploy(f);
+        System.err.println("Success!");
+        System.exit(0);
+    }
+
+    public static final String MULTICAST_DISCOVERY = "NetBeansMulticastDiscovery";
+    public static final String GROUP_ADDRESS = "225.10.10.0";
+    public static final int PORT = 44445;
+    public static final int PACKET_LENGTH = 1024;
+    public static final int TIMEOUT = 5000;
+
+    private static void deploy(File f) {
+        DatagramSocket datagramSocket = null;
+
+        try {
+            byte[] buf = new byte[PACKET_LENGTH];
+            buf = MULTICAST_DISCOVERY.getBytes();
+            datagramSocket = new DatagramSocket();
+            InetAddress group = InetAddress.getByName(GROUP_ADDRESS);
+            DatagramPacket packet = new DatagramPacket(buf, buf.length, group, PORT);
+            datagramSocket.send(packet);
+
+            buf = new byte[PACKET_LENGTH];
+            datagramSocket.setSoTimeout(TIMEOUT);
+            packet = new DatagramPacket(buf, buf.length);
+            datagramSocket.receive(packet);
+            String received = new String(packet.getData()).trim();
+            if (!received.equals("firstRun")) {
+                Thread.sleep(1000);
+                sendFile(f, packet.getAddress(), Integer.parseInt(received));
+            }
+            //JOptionPane.showMessageDialog(null, "Found iOS device on IP: " + received);
+        } catch (SocketTimeoutException ex) {
+            System.err.println("No iOS devices were found");
+            System.exit(2);
+        } catch (IOException | InterruptedException ex) {
+            ex.printStackTrace();
+            System.exit(3);
+        } finally {
+            if (datagramSocket != null) {
+                datagramSocket.close();
+            }
+        }
+    }
+
+    private static void sendFile(File f, InetAddress iOSAddress, int port) throws IOException {
+        System.err.println("Deploying " + f + " to " + iOSAddress + ":" + port);
+        try (Socket socket = new Socket(iOSAddress, port)) {
+            byte[] buffer = Files.readAllBytes(f.toPath());
+            try (ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream())) {
+                oos.writeObject(buffer);
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ios-maven-plugin/pom.xml	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,182 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.netbeans.ios</groupId>
+    <artifactId>ios-maven-plugin</artifactId>
+    <version>0.6-SNAPSHOT</version>
+    <parent>
+        <groupId>org.netbeans.ios</groupId>
+        <artifactId>Maven</artifactId>
+        <version>0.6-SNAPSHOT</version>
+    </parent>
+    <packaging>maven-plugin</packaging>
+
+    <name>iOS Maven Plugin</name>
+
+    <url>http://bck2brwsr.apidesign.org/</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-plugin-api</artifactId>
+            <version>3.0.5</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>plexus-utils</artifactId>
+                    <groupId>org.codehaus.plexus</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.plugin-tools</groupId>
+            <artifactId>maven-plugin-annotations</artifactId>
+            <version>3.2</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.plexus</groupId>
+            <artifactId>plexus-utils</artifactId>
+            <version>3.0.10</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.plugin-tools</groupId>
+            <artifactId>maven-script-ant</artifactId>
+            <version>3.2</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>plexus-utils</artifactId>
+                    <groupId>org.codehaus.plexus</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.plexus</groupId>
+            <artifactId>plexus-archiver</artifactId>
+            <version>2.4.1</version>
+        </dependency>
+        
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant-nodeps</artifactId>
+            <version>1.8.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant</artifactId>
+            <version>1.8.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-core</artifactId>
+            <version>3.0.5</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>plexus-utils</artifactId>
+                    <groupId>org.codehaus.plexus</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.ios</groupId>
+            <artifactId>mobile-center</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant-launcher</artifactId>
+            <version>1.8.1</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antrun-plugin</artifactId>
+                <version>1.7</version>
+                <executions>
+                    <execution>
+                        <id>copy-resources</id>
+                        <phase>process-resources</phase>
+                        <configuration>
+                            <target>
+                                <property name="main.destdir" value="./target/classes/ios-maven-plugin/JFXLauncher" />
+                                <property name="launcher.builddir" value="../../build/JFXLauncher" />
+                                <delete dir="${main.destdir}" />
+                                <mkdir dir="${main.destdir}"/>
+                                <copy todir="${main.destdir}">
+                                    <fileset dir="${launcher.builddir}" />
+                                </copy>                             
+                            </target>
+                        </configuration>
+                        <goals>
+                            <goal>run</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>          
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <version>2.8</version>
+                <executions>
+                    <execution>
+                        <id>bundle-mobilecenter</id>
+                        <phase>process-resources</phase>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.netbeans.ios</groupId>
+                                    <artifactId>mobile-center</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>jar</type>                                        
+                                    <overWrite>true</overWrite>
+                                    <outputDirectory>${project.build.directory}/classes/ios-maven-plugin</outputDirectory>
+                                    <destFileName>mobilecenter.jar</destFileName>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                        <goals>
+                            <goal>copy</goal>                           
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-plugin-plugin</artifactId>
+                <version>3.2</version>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.maven.plugin-tools</groupId>
+                        <artifactId>maven-plugin-tools-ant</artifactId>
+                        <version>3.2</version>
+                    </dependency>
+                </dependencies>
+                <configuration>
+                    <goalPrefix>ios</goalPrefix>
+                    <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>mojo-descriptor</id>
+                        <goals>
+                            <goal>descriptor</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>help-goal</id>
+                        <goals>
+                            <goal>helpmojo</goal>
+                        </goals>
+                    </execution>
+                </executions>                
+            </plugin>
+        </plugins>
+    </build>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ios-maven-plugin/src/main/java/org/netbeans/ibrwsr/maven/plugin/IPAddressMojo.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.netbeans.ibrwsr.maven.plugin;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
+
+/**
+ * Goal which sets current IP address.
+ *
+ */
+@Mojo(name = "ipaddress", requiresDependencyResolution = ResolutionScope.RUNTIME, defaultPhase = LifecyclePhase.COMPILE)
+public class IPAddressMojo extends AbstractMojo {
+
+    @Parameter(defaultValue = "${project}")
+    MavenProject project;
+
+    public void execute() throws MojoExecutionException {
+        try {
+            String ipAddress = InetAddress.getLocalHost().getHostAddress();
+            project.getProperties().put("ip.address", ipAddress);
+            System.out.println("IP: " + ipAddress);
+        } catch (UnknownHostException ex) {
+            throw new MojoExecutionException("IP address cannot be resolved", ex);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ios-maven-plugin/src/main/scripts/ios.maven.plugin.build.xml	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+-->
+<project>
+    <property name="jfxlauncher" value="${basedir}/target/jfxlauncher"/>
+    <property name="jdk8mobile.sdk.root" value="./jdk8-mobile-ios-ejdk"/>
+    <property name="jfx.ios.artifacts.root" value="./JFXLibs"/>
+
+    <available property="jfxlauncher.exists" file="${jfxlauncher}/build.xml"/>
+    <target name="-copy-launcher" unless="jfxlauncher.exists">
+        <mkdir dir="${jfxlauncher}"/>
+        <copy todir="${jfxlauncher}">
+            <fileset dir="${basedir}/target/ios-maven-plugin/JFXLauncher">
+                <exclude name="**/*.pbxproj"/>
+            </fileset>
+        </copy>
+        <copy todir="${jfxlauncher}">
+            <fileset dir="${basedir}/target/ios-maven-plugin/JFXLauncher">
+                <include name="**/*.pbxproj"/>
+            </fileset>
+            <filterset>
+                <filter token="JVMROOT_TOKEN" value="${jdk8mobile.sdk.root}"/>
+                <filter token="JFXSDKROOT_TOKEN" value="${jfx.ios.artifacts.root}"/>
+                <filter token="RESDIR_TOKEN" value="${resourcesDirResolved}"/>
+                <filter token="APPLICATIONJAR_TOKEN" value="${jarfile}"/>
+                <filter token="JAVA_PROFILE_TOKEN" value="${javaProfile}"/>
+            </filterset>
+        </copy>
+        <chmod dir="${jfxlauncher}" perm="a+x" includes="*.sh,ios-sim"/>
+    </target>
+
+    <condition property="do.fast.deploy">
+        <and>
+            <equals arg1="true" arg2="${fastDeploy}"/>
+            <not>
+                <isset property="jpdaAddress"/>
+            </not>
+        </and>
+    </condition>
+    <condition property="resourcesDirResolved" value="${basedir}/${resourcesDir}">
+        <isset property="resourcesDir"/>
+    </condition>
+    <property name="resourcesDirResolved" value=""/>
+
+    <target name="-fast-deploy" depends="-copy-launcher" if="do.fast.deploy">
+        <java fork="true" failonerror="false" classname="org.netbeans.mobilecenter.Redeploy"
+          resultproperty="deploy.result"
+        >
+            <classpath>
+                <pathelement location="${basedir}/target/ios-maven-plugin/mobilecenter.jar"/>
+            </classpath>
+            <arg value="${jarfile}"/>
+        </java>
+        <condition property="skip.run" value="true">
+            <equals arg1="0" arg2="${deploy.result}"/>
+        </condition>
+        <pathconvert property="appjarDebugName">
+            <flattenmapper/>
+            <path>
+                <pathelement path="${jarfile}"/>
+            </path>
+        </pathconvert>
+    </target>
+
+    <target name="runJFXLauncher" depends="-copy-launcher,-fast-deploy" unless="skip.run">
+        <property name="runtime.classpath.tmp" refid="maven.runtime.classpath"/>
+        <condition value="${runtime.classpath.tmp}:${basedir}/target/ios-maven-plugin/mobilecenter.jar" property="runtime.classpath">
+            <isset property="fastDeploy"/>
+        </condition>
+        <property name="runtime.classpath" value="${runtime.classpath.tmp}"/>
+
+        <condition value="org.netbeans.mobilecenter.MobileCenter" property="app.main.class">
+            <isset property="fastDeploy"/>
+        </condition>
+        <property name="app.main.class" value="${mainclass}"/>
+
+        <antcall target="write.plist.debug">
+            <param name="ipAddress" value="127.0.0.1" />
+            <param name="jpdaAddress" value="${jpdaAddress}" />
+        </antcall>
+        <antcall target="write.appjar.debug">
+            <param name="appjarDebugName" value="${appjarDebugName}" />
+        </antcall>
+        <ant dir="${jfxlauncher}" target="runsim-mvn">
+            <property name="mvn.classpath" value="${runtime.classpath}"/>
+            <property name="mvn.app.jar" value="${jarfile}"/>
+            <property name="launcher.CFBundleDisplayName" value="${title}"/>
+            <property name="application.title" value="${title}"/>
+            <property name="javafx.enable" value="${javafx}"/>
+            <property name="launcher.javaMainClass" value="${app.main.class}"/>
+            <property name="product.config" value="${runMode}" />
+            <property name="resources.dir" value="${resourcesDirResolved}"/>
+            <property name="launcher.IconImagesDir" value="${basedir}/${iconsDir}" />
+            <property name="launcher.DefaultImagesDir" value="${basedir}/${imagesDir}" />
+            <property name="launcher.MinimumOSVersion" value="${deploymentTarget}" />
+            <property name="launcher.UIDeviceFamily" value="${targetDevices}" />
+            <property name="launcher.UISupportedInterfaceOrientations" value="${supportedInterfaceOrientations}" />
+            <property name="launcher.UISupportedInterfaceOrientations~ipad" value="${iPadSupportedInterfaceOrientations}" />
+            <property name="launcher.UIPrerenderedIcon" value="${prerenderedIcons}" />
+            <property name="launcher.CFBundleIdentifier" value="${bundleId}" />
+            <property name="provisioning.profile" value="${provisioningProfile}" />
+        </ant>
+        <delete dir="${basedir}/target/ios-maven-plugin" />
+    </target>
+
+    <!-- ************* DEBUG helpers ************* -->
+    <target name="write.plist.debug">
+        <property name="plist.file" value="${jfxlauncher}/jfx-runjava.properties" />
+        <echo message="jpdaAddress=${ipAddress}:${jpdaAddress}${line.separator}" file="${plist.file}" append="true" />
+    </target>
+    <target name="write.appjar.debug" if="fastDeploy" >
+        <property name="plist.file" value="${jfxlauncher}/jfx-runjava.properties" />
+        <echo message="bgReloadJar=${appjarDebugName}${line.separator}" file="${plist.file}" append="true" />
+    </target>
+
+    <!-- ************* BUILD IPA TARGET ************* -->
+    <target name="buildIPA" depends="-copy-launcher">
+        <property name="runtime.classpath.tmp" refid="maven.runtime.classpath"/>
+        <condition value="${runtime.classpath.tmp}:${basedir}/target/ios-maven-plugin/mobilecenter.jar" property="runtime.classpath">
+            <isset property="fastDeploy"/>
+        </condition>
+        <property name="runtime.classpath" value="${runtime.classpath.tmp}"/>
+
+        <condition value="org.netbeans.mobilecenter.MobileCenter" property="app.main.class">
+            <isset property="fastDeploy"/>
+        </condition>
+        <property name="app.main.class" value="${mainclass}"/>
+
+        <chmod dir="${basedir}/target/ios-maven-plugin/JFXLauncher" perm="ugo+rx" includes="**/*"/>
+        <antcall target="write.plist.debug">
+            <param name="ipAddress" value="${ipAddress}" />
+            <param name="jpdaAddress" value="${jpdaAddress}" />
+        </antcall>
+        <antcall target="write.appjar.debug">
+            <param name="appjarDebugName" value="${appjarDebugName}" />
+        </antcall>
+        <ant dir="${jfxlauncher}" target="package-mvn">
+            <property name="mvn.classpath" value="${runtime.classpath}"/>
+            <property name="mvn.app.jar" value="${jarfile}"/>
+            <property name="launcher.CFBundleDisplayName" value="${title}"/>
+            <property name="application.title" value="${title}"/>
+            <property name="javafx.enable" value="${javafx}"/>
+            <property name="launcher.javaMainClass" value="${app.main.class}"/>
+            <property name="product.config" value="${runMode}" />
+            <property name="provisioning.profile" value="${provisioningProfile}" />
+            <property name="resources.dir" value="${resourcesDirResolved}"/>
+            <property name="launcher.IconImagesDir" value="${basedir}/${iconsDir}" />
+            <property name="launcher.DefaultImagesDir" value="${basedir}/${imagesDir}" />
+            <property name="launcher.MinimumOSVersion" value="${deploymentTarget}" />
+            <property name="launcher.UIDeviceFamily" value="${targetDevices}" />
+            <property name="launcher.UISupportedInterfaceOrientations" value="${supportedInterfaceOrientations}" />
+            <property name="launcher.UISupportedInterfaceOrientations~ipad" value="${iPadSupportedInterfaceOrientations}" />
+            <property name="launcher.UIPrerenderedIcon" value="${prerenderedIcons}" />
+            <property name="launcher.CFBundleIdentifier" value="${bundleId}" />
+            <property name="provisioning.profile" value="${provisioningProfile}" />
+        </ant>
+        <copy file="${jfxlauncher}/build/${title}.ipa" tofile="${basedir}/target/${title}.ipa" />
+        <ant dir="${jfxlauncher}" target="open-ipa-in-itunes-mvn">
+            <property name="application.title" value="${title}"/>
+            <property name="project.target" value="${basedir}/target" />
+        </ant>
+        <delete dir="${basedir}/target/ios-maven-plugin" />
+    </target>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ios-maven-plugin/src/main/scripts/ios.maven.plugin.mojos.xml	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,327 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+-->
+<pluginMetadata xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/plugin-metadata-1.0.0.xsd">
+    <mojos>
+        <mojo>
+            <!-- target name to call in ant script -->
+            <call>runJFXLauncher</call>
+            <!-- mojo goal name -->
+            <goal>deploy</goal>
+            <requiresDependencyResolution>runtime</requiresDependencyResolution>
+            <parameters>
+                <parameter>
+                    <name>jarfile</name>
+                    <expression>${jarfile}</expression>
+                    <required>true</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                </parameter>
+                <parameter>
+                    <name>title</name>
+                    <expression>${title}</expression>
+                    <required>true</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                </parameter>
+                <parameter>
+                    <name>javafx</name>
+                    <expression>${javafx}</expression>
+                    <required>true</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.Boolean</type>
+                    <defaultValue>true</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>javaProfile</name>
+                    <expression>${javaProfile}</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                    <defaultValue>compact1</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>mainclass</name>
+                    <expression>${mainclass}</expression>
+                    <required>true</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                </parameter>
+                <parameter>
+                    <name>runMode</name>
+                    <expression>runMode</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                    <defaultValue>Release</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>jpdaAddress</name>
+                    <expression>jpdaAddress</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                </parameter>
+                <parameter>
+                    <name>fastDeploy</name>
+                    <expression>fastDeploy</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>boolean</type>
+                </parameter>
+                <parameter>
+                    <name>iconsDir</name>
+                    <expression>${iconsDir}</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                    <defaultValue>src/main/ios-icons</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>imagesDir</name>
+                    <expression>${imagesDir}</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                    <defaultValue>src/main/ios-images</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>targetDevices</name>
+                    <expression>${deviceType}</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                    <defaultValue>1,2</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>bundleId</name>
+                    <expression>${groupId}:${artifactId}</expression>
+                    <required>true</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                </parameter>
+                <parameter>
+                    <name>deploymentTarget</name>
+                    <expression>${deploymentTarget}</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                    <defaultValue>6.1</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>supportedInterfaceOrientations</name>
+                    <expression>${supportedInterfaceOrientations}</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                    <defaultValue>UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationPortrait, UIInterfaceOrientationLandscapeRight, UIInterfaceOrientationPortraitUpsideDown</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>iPadSupportedInterfaceOrientations</name>
+                    <expression>${iPadSupportedInterfaceOrientations}</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                    <defaultValue>UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationPortrait, UIInterfaceOrientationLandscapeRight, UIInterfaceOrientationPortraitUpsideDown</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>prerenderedIcons</name>
+                    <expression>${prerenderedIcons}</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.Boolean</type>
+                    <defaultValue>false</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>resourcesDir</name>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                </parameter>
+                <parameter>
+                    <name>provisioningProfile</name>
+                    <expression>${provisioningProfile}</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                </parameter>
+            </parameters>
+        </mojo>
+        <mojo>
+            <!-- target name to call in ant script -->
+            <call>buildIPA</call>
+            <!-- mojo goal name -->
+            <goal>build-IPA</goal>
+            <requiresDependencyResolution>runtime</requiresDependencyResolution>
+            <parameters>
+                <parameter>
+                    <name>jarfile</name>
+                    <expression>${jarfile}</expression>
+                    <required>true</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                </parameter>
+                <parameter>
+                    <name>title</name>
+                    <expression>${title}</expression>
+                    <required>true</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                </parameter>
+                <parameter>
+                    <name>javafx</name>
+                    <expression>${javafx}</expression>
+                    <required>true</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.Boolean</type>
+                    <defaultValue>true</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>javaProfile</name>
+                    <expression>${java.profile}</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                    <defaultValue>compact1</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>mainclass</name>
+                    <expression>${mainclass}</expression>
+                    <required>true</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                </parameter>
+                <parameter>
+                    <name>runMode</name>
+                    <expression>runMode</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                    <defaultValue>Release</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>provisioningProfile</name>
+                    <expression>provisioningProfile</expression>
+                    <required>true</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                </parameter>
+                <parameter>
+                    <name>ipAddress</name>
+                    <expression>ipAddress</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                </parameter>
+                <parameter>
+                    <name>jpdaAddress</name>
+                    <expression>jpdaAddress</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                </parameter>
+                <parameter>
+                    <name>appjarDebug</name>
+                    <expression>appjarDebug</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                </parameter>
+                <parameter>
+                    <name>appjarDebugName</name>
+                    <expression>appjarDebugName</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                </parameter>
+                <parameter>
+                    <name>iconsDir</name>
+                    <expression>${iconsDir}</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                    <defaultValue>src/main/ios-icons</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>imagesDir</name>
+                    <expression>${imagesDir}</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                    <defaultValue>src/main/ios-images</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>resourcesDir</name>
+                    <expression>${resourcesDir}</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                </parameter>
+                <parameter>
+                    <name>targetDevices</name>
+                    <expression>${deviceType}</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                    <defaultValue>1,2</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>bundleId</name>
+                    <expression>${groupId}:${artifactId}</expression>
+                    <required>true</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                </parameter>
+                <parameter>
+                    <name>deploymentTarget</name>
+                    <expression>${deploymentTarget}</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                    <defaultValue>6.1</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>supportedInterfaceOrientations</name>
+                    <expression>${supportedInterfaceOrientations}</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                    <defaultValue>UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationPortrait, UIInterfaceOrientationLandscapeRight, UIInterfaceOrientationPortraitUpsideDown</defaultValue>
+                </parameter>
+                <parameter>
+                    <name>iPadSupportedInterfaceOrientations</name>
+                    <expression>${iPadSupportedInterfaceOrientations}</expression>
+                    <required>false</required>
+                    <readonly>false</readonly>
+                    <type>java.lang.String</type>
+                    <defaultValue>UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationPortrait, UIInterfaceOrientationLandscapeRight, UIInterfaceOrientationPortraitUpsideDown</defaultValue>
+                </parameter>
+            </parameters>
+        </mojo>
+    </mojos>
+</pluginMetadata>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/pom.xml	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,61 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.oracle.ios</groupId>
+    <artifactId>ipack</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <name>ipack</name>
+    <url>http://maven.apache.org</url>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk15on</artifactId>
+            <version>1.49</version>
+        </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcpkix-jdk15on</artifactId>
+            <version>1.49</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.4</version>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <addClasspath>true</addClasspath>
+                            <classpathPrefix>lib/</classpathPrefix>
+                            <mainClass>com.oracle.ipack.main.Main</mainClass>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <version>2.8</version>
+                <executions>
+                    <execution>
+                        <id>copy-dependencies</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
+                        </configuration>                    
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/blobs/Blob.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.blobs;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+public abstract class Blob {
+    public final int getSize() {
+        return 8 + getPayloadSize();
+    }
+
+    public final void write(final DataOutput dataOutput) throws IOException {
+        dataOutput.writeInt(getMagic());
+        dataOutput.writeInt(getSize());
+        writePayload(dataOutput);
+    }
+
+    protected abstract int getMagic();
+
+    protected abstract int getPayloadSize();
+
+    protected abstract void writePayload(DataOutput dataOutput)
+            throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/blobs/SuperBlob.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.blobs;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+public abstract class SuperBlob<T extends Blob> extends Blob {
+    private final SubBlob<T>[] subBlobs;
+
+    protected SuperBlob(final int numberOfSubBlobs) {
+        this.subBlobs = allocateSubBlobs(numberOfSubBlobs);
+    }
+
+    public final T getSubBlob(final int index) {
+        return subBlobs[index].getBlob();
+    }
+
+    public final void setSubBlob(final int index, final int type,
+                                 final T blob) {
+        subBlobs[index].setType(type);
+        subBlobs[index].setBlob(blob);
+    }
+
+    @Override
+    protected final int getPayloadSize() {
+        int size = 4 + subBlobs.length * 8;
+        for (int i = 0; i < subBlobs.length; ++i) {
+            size += subBlobs[i].getBlob().getSize();
+        }
+
+        return size;
+    }
+
+    @Override
+    protected final void writePayload(final DataOutput dataOutput)
+            throws IOException {
+        dataOutput.writeInt(subBlobs.length);
+        int offset = 8 + 4 + subBlobs.length * 8;
+        for (int i = 0; i < subBlobs.length; ++i) {
+            dataOutput.writeInt(subBlobs[i].getType());
+            dataOutput.writeInt(offset);
+
+            offset += subBlobs[i].getBlob().getSize();
+        }
+
+        for (int i = 0; i < subBlobs.length; ++i) {
+            subBlobs[i].getBlob().write(dataOutput);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T extends Blob> SubBlob<T>[] allocateSubBlobs(
+            final int numberOfSubBlobs) {
+        final SubBlob<T>[] subBlobs = new SubBlob[numberOfSubBlobs];
+        for (int i = 0; i < numberOfSubBlobs; ++i) {
+            subBlobs[i] = new SubBlob<T>();
+        }
+
+        return subBlobs;
+    }
+
+    private static final class SubBlob<T extends Blob> {
+        private int type;
+        private T blob;
+
+        public int getType() {
+            return type;
+        }
+
+        public void setType(final int type) {
+            this.type = type;
+        }
+
+        public T getBlob() {
+            return blob;
+        }
+
+        public void setBlob(final T blob) {
+            this.blob = blob;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/blobs/VirtualBlob.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.blobs;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+public final class VirtualBlob extends Blob {
+    private final int magic;
+    private final int payloadSize;
+
+    public VirtualBlob(final int magic, final int payloadSize) {
+        this.magic = magic;
+        this.payloadSize = payloadSize;
+    }
+
+    @Override
+    protected int getMagic() {
+        return magic;
+    }
+
+    @Override
+    protected int getPayloadSize() {
+        return payloadSize;
+    }
+
+    @Override
+    protected void writePayload(final DataOutput dataOutput)
+            throws IOException {
+        for (int i = 0; i < payloadSize; ++i) {
+            dataOutput.write(i);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/blobs/WrapperBlob.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.blobs;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+public final class WrapperBlob extends Blob {
+    private final byte[] data;
+
+    public WrapperBlob(final byte[] data) {
+        this.data = data;
+    }
+
+    @Override
+    protected int getMagic() {
+        return 0xfade0b01;
+    }
+
+    @Override
+    protected int getPayloadSize() {
+        return data.length;
+    }
+
+    @Override
+    protected void writePayload(final DataOutput dataOutput)
+            throws IOException {
+        dataOutput.write(data);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/macho/CodeSignatureCommand.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.macho;
+
+public final class CodeSignatureCommand extends LinkeditDataCommand {
+    @Override
+    public int getId() {
+        return LC_CODE_SIGNATURE;
+    }
+
+    @Override
+    protected String getName() {
+        return "CodeSignatureCommand";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/macho/LinkeditDataCommand.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.macho;
+
+import com.oracle.ipack.util.Util;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+public abstract class LinkeditDataCommand extends MachoCommand {
+    private int dataOffset;
+    private int dataSize;
+
+    public final int getDataOffset() {
+        return dataOffset;
+    }
+
+    public final void setDataOffset(final int dataOffset) {
+        this.dataOffset = dataOffset;
+    }
+
+    public final int getDataSize() {
+        return dataSize;
+    }
+
+    public final void setDataSize(final int dataSize) {
+        this.dataSize = dataSize;
+    }
+
+    @Override
+    public final String toString() {
+        return getName() + " { dataOffset: 0x" + Util.hex32(dataOffset)
+                       + ", dataSize: 0x" + Util.hex32(dataSize) + " }";
+    }
+
+    protected abstract String getName();
+
+    @Override
+    protected final int getPayloadSize() {
+        return 8;
+    }
+
+    @Override
+    protected final void readPayload(final DataInput dataInput)
+            throws IOException {
+        dataOffset = dataInput.readInt();
+        dataSize = dataInput.readInt();
+    }
+
+    @Override
+    protected final void writePayload(final DataOutput dataOutput)
+            throws IOException {
+        dataOutput.writeInt(dataOffset);
+        dataOutput.writeInt(dataSize);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/macho/MachoCommand.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.macho;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+public abstract class MachoCommand {
+    public static final int LC_SEGMENT = 0x1;
+    public static final int LC_CODE_SIGNATURE = 0x1d;
+
+    public abstract int getId();
+
+    public final int getSize() {
+        return 8 + getPayloadSize();
+    }
+
+    public static MachoCommand read(final DataInput dataInput)
+            throws IOException {
+        final int commandId = dataInput.readInt();
+        final int commandSize = dataInput.readInt();
+        MachoCommand command;
+        switch (commandId) {
+            case LC_SEGMENT:
+                command = new SegmentCommand();
+                break;
+            case LC_CODE_SIGNATURE:
+                command = new CodeSignatureCommand();
+                break;
+            default:
+                command = new UnknownCommand(commandId, commandSize - 8);
+                break;
+        }
+
+        command.readPayload(dataInput);
+        if (command.getSize() != commandSize) {
+            throw new IOException("Can't decode command in mach-o header");
+        }
+
+        return command;
+    }
+
+    public final void write(final DataOutput dataOutput) throws IOException {
+        dataOutput.writeInt(getId());
+        dataOutput.writeInt(getSize());
+        writePayload(dataOutput);
+    }
+
+    protected abstract int getPayloadSize();
+
+    protected abstract void readPayload(final DataInput dataInput)
+            throws IOException;
+
+    protected abstract void writePayload(final DataOutput dataOutput)
+            throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/macho/MachoHeader.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.macho;
+
+import com.oracle.ipack.util.Util;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.ArrayList;
+
+public final class MachoHeader {
+    private ArrayList<MachoCommand> commands;
+
+    private int magic;
+    private int cpuType;
+    private int cpuSubType;
+    private int fileType;
+    private int flags;
+
+    public MachoHeader() {
+        commands = new ArrayList<MachoCommand>();
+    }
+
+    public MachoCommand findCommand(final int commandId) {
+        for (final MachoCommand command: commands) {
+            if (command.getId() == commandId) {
+                return command;
+            }
+        }
+
+        return null;
+    }
+
+    public SegmentCommand findSegment(final String segmentName) {
+        for (final MachoCommand command: commands) {
+            if (command.getId() == MachoCommand.LC_SEGMENT) {
+                final SegmentCommand segmentCommand = (SegmentCommand) command;
+                if (segmentName.equals(segmentCommand.getSegmentName())) {
+                    return segmentCommand;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public void addCommand(final MachoCommand command) {
+        commands.add(command);
+    }
+
+    public static MachoHeader read(final DataInput dataInput)
+            throws IOException {
+        final MachoHeader header = new MachoHeader();
+        header.readImpl(dataInput);
+        return header;
+    }
+
+    public int getSize() {
+        int size = 7 * 4;
+        for (final MachoCommand command: commands) {
+            size += command.getSize();
+        }
+
+        return size;
+    }
+
+    public int getMagic() {
+        return magic;
+    }
+
+    public void setMagic(final int magic) {
+        this.magic = magic;
+    }
+
+    public int getCpuType() {
+        return cpuType;
+    }
+
+    public void setCpuType(final int cpuType) {
+        this.cpuType = cpuType;
+    }
+
+    public int getCpuSubType() {
+        return cpuSubType;
+    }
+
+    public void setCpuSubType(final int cpuSubType) {
+        this.cpuSubType = cpuSubType;
+    }
+
+    public int getFileType() {
+        return fileType;
+    }
+
+    public void setFileType(final int fileType) {
+        this.fileType = fileType;
+    }
+
+    public int getFlags() {
+        return flags;
+    }
+
+    public void setFlags(final int flags) {
+        this.flags = flags;
+    }
+
+    public void write(final DataOutput dataOutput) throws IOException {
+        dataOutput.writeInt(magic);
+        dataOutput.writeInt(cpuType);
+        dataOutput.writeInt(cpuSubType);
+        dataOutput.writeInt(fileType);
+        dataOutput.writeInt(commands.size());
+        dataOutput.writeInt(getSizeOfCommands());
+        dataOutput.writeInt(flags);
+
+        for (final MachoCommand command: commands) {
+            command.write(dataOutput);
+        }
+    }
+
+    private void readImpl(final DataInput dataInput) throws IOException {
+        magic = dataInput.readInt();
+        cpuType = dataInput.readInt();
+        cpuSubType = dataInput.readInt();
+        fileType = dataInput.readInt();
+        final int numberOfCommands = dataInput.readInt();
+        final int sizeOfCommands = dataInput.readInt();
+        flags = dataInput.readInt();
+
+        int sizeOfReadCommands = 0;
+        commands.clear();
+        commands.ensureCapacity(numberOfCommands);
+        for (int i = 0; i < numberOfCommands; ++i) {
+            final MachoCommand command = MachoCommand.read(dataInput);
+            commands.add(command);
+            sizeOfReadCommands += command.getSize();
+        }
+
+        if (sizeOfCommands != sizeOfReadCommands) {
+            throw new IOException("Failed to decode commands");
+        }
+    }
+
+    private int getSizeOfCommands() {
+        int sizeOfCommands = 0;
+        for (final MachoCommand command: commands) {
+            sizeOfCommands += command.getSize();
+        }
+
+        return sizeOfCommands;
+    }
+
+    @Override
+    public String toString() {
+        return "Header { magic: 0x" + Util.hex32(magic)
+                         + ", cpuType: " + cpuType
+                         + ", cpuSubType: " + cpuSubType
+                         + ", fileType: " + fileType
+                         + ", flags: 0x" + Util.hex32(flags)
+                         + ", commands: " + commands + " }";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/macho/SegmentCommand.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.macho;
+
+import com.oracle.ipack.util.Util;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.ArrayList;
+
+public final class SegmentCommand extends MachoCommand {
+    private final ArrayList<Section> sections;
+
+    private String segmentName;
+    private int vmAddress;
+    private int vmSize;
+    private int fileOffset;
+    private int fileSize;
+    private int maxVmProtection;
+    private int initVmProtection;
+    private int flags;
+
+    public SegmentCommand() {
+        sections = new ArrayList<Section>();
+    }
+
+    @Override
+    public int getId() {
+        return LC_SEGMENT;
+    }
+
+    public Section findSection(final String sectionName) {
+        for (final Section section: sections) {
+            if (sectionName.equals(section.getSectionName())) {
+                return section;
+            }
+        }
+
+        return null;
+    }
+
+    public String getSegmentName() {
+        return segmentName;
+    }
+
+    public void setSegmentName(final String segmentName) {
+        this.segmentName = segmentName;
+    }
+
+    public int getVmAddress() {
+        return vmAddress;
+    }
+
+    public void setVmAddress(final int vmAddress) {
+        this.vmAddress = vmAddress;
+    }
+
+    public int getVmSize() {
+        return vmSize;
+    }
+
+    public void setVmSize(final int vmSize) {
+        this.vmSize = vmSize;
+    }
+
+    public int getFileOffset() {
+        return fileOffset;
+    }
+
+    public void setFileOffset(final int fileOffset) {
+        this.fileOffset = fileOffset;
+    }
+
+    public int getFileSize() {
+        return fileSize;
+    }
+
+    public void setFileSize(final int fileSize) {
+        this.fileSize = fileSize;
+    }
+
+    public int getMaxVmProtection() {
+        return maxVmProtection;
+    }
+
+    public void setMaxVmProtection(final int maxVmProtection) {
+        this.maxVmProtection = maxVmProtection;
+    }
+
+    public int getInitVmProtection() {
+        return initVmProtection;
+    }
+
+    public void setInitVmProtection(final int initVmProtection) {
+        this.initVmProtection = initVmProtection;
+    }
+
+    public int getFlags() {
+        return flags;
+    }
+
+    public void setFlags(final int flags) {
+        this.flags = flags;
+    }
+
+    @Override
+    public String toString() {
+        return "SegmentCommand { segmentName: \"" + segmentName + "\""
+                       + ", vmAddress: 0x" + Util.hex32(vmAddress)
+                       + ", vmSize: 0x" + Util.hex32(vmSize)
+                       + ", fileOffset: 0x" + Util.hex32(fileOffset)
+                       + ", fileSize: 0x" + Util.hex32(fileSize)
+                       + ", maxVmProtection: " + maxVmProtection
+                       + ", initVmProtection: " + initVmProtection
+                       + ", flags: 0x" + Util.hex32(flags)
+                       + ", sections: " + sections + " }";
+    }
+
+    @Override
+    protected int getPayloadSize() {
+        return 16 + 4 * 8 + 68 * sections.size();
+    }
+
+    @Override
+    protected void readPayload(final DataInput dataInput) throws IOException {
+        segmentName = Util.readString(dataInput, 16).trim();
+        vmAddress = dataInput.readInt();
+        vmSize = dataInput.readInt();
+        fileOffset = dataInput.readInt();
+        fileSize = dataInput.readInt();
+        maxVmProtection = dataInput.readInt();
+        initVmProtection = dataInput.readInt();
+        final int numberOfSections = dataInput.readInt();
+        flags = dataInput.readInt();
+
+        sections.clear();
+        sections.ensureCapacity(numberOfSections);
+        for (int i = 0; i < numberOfSections; ++i) {
+            final Section section = new Section();
+            section.readImpl(dataInput);
+            sections.add(section);
+        }
+    }
+
+    @Override
+    protected void writePayload(final DataOutput dataOutput)
+            throws IOException {
+        Util.writeString(dataOutput, segmentName, 16, '\0');
+        dataOutput.writeInt(vmAddress);
+        dataOutput.writeInt(vmSize);
+        dataOutput.writeInt(fileOffset);
+        dataOutput.writeInt(fileSize);
+        dataOutput.writeInt(maxVmProtection);
+        dataOutput.writeInt(initVmProtection);
+        dataOutput.writeInt(sections.size());
+        dataOutput.writeInt(flags);
+
+        for (final Section section: sections) {
+            section.write(dataOutput);
+        }
+    }
+
+    public static final class Section {
+        private String sectionName;
+        private String segmentName;
+        private int address;
+        private int size;
+        private int offset;
+        private int align;
+        private int relocationOffset;
+        private int numberOfRelocations;
+        private int flags;
+        private int reserved1;
+        private int reserved2;
+
+        public String getSectionName() {
+            return sectionName;
+        }
+
+        public void setSectionName(final String sectionName) {
+            this.sectionName = sectionName;
+        }
+
+        public String getSegmentName() {
+            return segmentName;
+        }
+
+        public void setSegmentName(final String segmentName) {
+            this.segmentName = segmentName;
+        }
+
+        public int getAddress() {
+            return address;
+        }
+
+        public void setAddress(final int address) {
+            this.address = address;
+        }
+
+        public int getSize() {
+            return size;
+        }
+
+        public void setSize(final int size) {
+            this.size = size;
+        }
+
+        public int getOffset() {
+            return offset;
+        }
+
+        public void setOffset(final int offset) {
+            this.offset = offset;
+        }
+
+        public int getAlign() {
+            return align;
+        }
+
+        public void setAlign(final int align) {
+            this.align = align;
+        }
+
+        public int getRelocationOffset() {
+            return relocationOffset;
+        }
+
+        public void setRelocationOffset(final int relocationOffset) {
+            this.relocationOffset = relocationOffset;
+        }
+
+        public int getNumberOfRelocations() {
+            return numberOfRelocations;
+        }
+
+        public void setNumberOfRelocations(final int numberOfRelocations) {
+            this.numberOfRelocations = numberOfRelocations;
+        }
+
+        public int getFlags() {
+            return flags;
+        }
+
+        public void setFlags(final int flags) {
+            this.flags = flags;
+        }
+
+        public int getReserved1() {
+            return reserved1;
+        }
+
+        public void setReserved1(final int reserved1) {
+            this.reserved1 = reserved1;
+        }
+
+        public int getReserved2() {
+            return reserved2;
+        }
+
+        public void setReserved2(final int reserved2) {
+            this.reserved2 = reserved2;
+        }
+
+        public void write(final DataOutput dataOutput) throws IOException {
+            Util.writeString(dataOutput, sectionName, 16, '\0');
+            Util.writeString(dataOutput, segmentName, 16, '\0');
+            dataOutput.writeInt(address);
+            dataOutput.writeInt(size);
+            dataOutput.writeInt(offset);
+            dataOutput.writeInt(align);
+            dataOutput.writeInt(relocationOffset);
+            dataOutput.writeInt(numberOfRelocations);
+            dataOutput.writeInt(flags);
+            dataOutput.writeInt(reserved1);
+            dataOutput.writeInt(reserved2);
+        }
+
+        private void readImpl(final DataInput dataInput) throws IOException {
+            sectionName = Util.readString(dataInput, 16).trim();
+            segmentName = Util.readString(dataInput, 16).trim();
+            address = dataInput.readInt();
+            size = dataInput.readInt();
+            offset = dataInput.readInt();
+            align = dataInput.readInt();
+            relocationOffset = dataInput.readInt();
+            numberOfRelocations = dataInput.readInt();
+            flags = dataInput.readInt();
+            reserved1 = dataInput.readInt();
+            reserved2 = dataInput.readInt();
+        }
+
+        @Override
+        public String toString() {
+            return "Section { sectionName: \"" + sectionName + "\""
+                             + ", segmentName: \"" + segmentName + "\""
+                             + ", address: 0x" + Util.hex32(address)
+                             + ", size: 0x" + Util.hex32(size)
+                             + ", offset: 0x" + Util.hex32(offset)
+                             + ", align: " + align
+                             + ", relocationOffset: 0x"
+                                     + Util.hex32(relocationOffset)
+                             + ", numberOfRelocations: " + numberOfRelocations
+                             + ", flags: 0x" + Util.hex32(flags)
+                             + ", reserved1: " + reserved1
+                             + ", reserved2: " + reserved2 + " }";
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/macho/UnknownCommand.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.macho;
+
+import com.oracle.ipack.util.Util;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+public final class UnknownCommand extends MachoCommand {
+    private final int id;
+    private final byte[] data;
+
+    public UnknownCommand(final int id, final int payloadSize) {
+        this.id = id;
+        this.data = new byte[payloadSize];
+    }
+
+    @Override
+    public int getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return "UnknownCommand { id: 0x" + Util.hex32(id)
+                       + ", payloadSize: " + data.length + " }";
+    }
+
+    @Override
+    protected int getPayloadSize() {
+        return data.length;
+    }
+
+    @Override
+    protected void readPayload(final DataInput dataInput) throws IOException {
+        dataInput.readFully(data);
+    }
+
+    @Override
+    protected void writePayload(DataOutput dataOutput) throws IOException {
+        dataOutput.write(data);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/main/Main.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.main;
+
+import com.oracle.ipack.packer.Packer;
+import com.oracle.ipack.signer.Signer;
+import com.oracle.ipack.util.ResourceDescriptor;
+import java.io.File;
+import java.io.IOException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Security;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.List;
+import javax.naming.InvalidNameException;
+import org.bouncycastle.cms.CMSException;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.OperatorCreationException;
+
+public final class Main {
+    private static final String USAGE =
+            "Usage:\n"
+            + "\n"
+            + " ipack <archive> <signing opts> <application opts>"
+                    + " [ <application opts> ... ]\n"
+            + "\n"
+            + "Signing options:\n"
+            + "\n"
+            + " -keystore <keystore>   "
+                  + "keystore to use for signing\n"
+            + " -storepass <password>  "
+                  + "keystore password\n"
+            + " -alias <alias>         "
+                  + "alias for the signing certificate chain and\n"
+            + "                        the associated private key\n"
+            + " -keypass <password>    "
+                  + "password for the private key\n"
+            + "\n"
+            + "Application options:\n"
+            + "\n"
+            + " -basedir <directory>   "
+                  + "base directory from which to derive relative paths\n"
+            + " -appdir <directory>    "
+                  + "directory with the application executable and resources\n"
+            + " -appname <file>        "
+                  + "name of the application executable\n"
+            + " -appid <id>            "
+                  + "application identifier\n"
+            + "\n"
+            + "Example:\n"
+            + "\n"
+            + " ipack MyApplication.ipa -keystore ipack.ks"
+                  + " -storepass keystorepwd\n"
+            + "                        "
+                  + " -alias mycert -keypass keypwd\n"
+            + "                        "
+                  + " -basedir mysources/MyApplication/dist\n"
+            + "                        "
+                  + " -appdir Payload/MyApplication.app\n"
+            + "                        "
+                  + " -appname MyApplication"
+                  + " -appid com.myorg.MyApplication";
+
+    private Main() {
+    }
+
+    public static void main(final String... args) throws IOException {
+        if (args.length == 0) {
+            System.out.println(USAGE);
+            return;
+        }
+
+        Security.addProvider(new BouncyCastleProvider());
+
+        try {
+            execute(args);
+        } catch (final RuntimeException e) {
+            System.err.println(e.getMessage());
+            System.exit(1);
+        }
+    }
+
+    private static void execute(final String... args) throws RuntimeException {
+        final SigningArgs signingArgs = new SigningArgs();
+
+        File destFile = null;
+
+        File baseDir = null;
+        File appBaseDir = null;
+        String appDir = null;
+        String appName = null;
+        String appId = null;
+
+        final List<ApplicationArgs> appArgsList =
+                new ArrayList<ApplicationArgs>();
+
+        for (int i = 0; i < args.length; ++i) {
+            final String argument = args[i];
+            if (!argument.startsWith("-")) {
+                if (destFile != null) {
+                    throw new RuntimeException(
+                            "Destination file already specified");
+                }
+
+                destFile = new File(argument);
+                continue;
+            }
+
+            if (i == (args.length - 1)) {
+                throw new RuntimeException("Value missing for " + argument);
+            }
+
+            final String value = args[++i];
+            if (value.startsWith("-")) {
+                throw new RuntimeException("Illegal value for " + argument);
+            }
+
+            if ("-keystore".equalsIgnoreCase(argument)) {
+                final File keyStore = new File(value);
+                if (!keyStore.exists()) {
+                    throw new RuntimeException("Keystore \"" + keyStore
+                                                   + "\" doesn't exist");
+                }
+                signingArgs.setKeyStore(keyStore);
+            } else if ("-storepass".equalsIgnoreCase(argument)) {
+                signingArgs.setStorePass(value);
+            } else if ("-alias".equalsIgnoreCase(argument)) {
+                signingArgs.setAlias(value);
+            } else if ("-keypass".equalsIgnoreCase(argument)) {
+                signingArgs.setKeyPass(value);
+            } else if ("-basedir".equalsIgnoreCase(argument)) {
+                baseDir = new File(value);
+                if (!baseDir.isDirectory()) {
+                    throw new RuntimeException("Base directory \"" + value
+                                                   + "\" doesn't exist");
+                }
+            } else if ("-appdir".equalsIgnoreCase(argument)) {
+                if (appDir != null) {
+                    appArgsList.add(createApplicationArgs(
+                                        appBaseDir, appDir, appName, appId));
+                    appName = null;
+                    appId = null;
+                }
+
+                appDir = value;
+                appBaseDir = baseDir;
+            } else if ("-appname".equalsIgnoreCase(argument)) {
+                if (appName != null) {
+                    appArgsList.add(createApplicationArgs(
+                                        appBaseDir, appDir, appName, appId));
+                    appDir = null;
+                    appId = null;
+                }
+
+                appName = value;
+            } else if ("-appid".equalsIgnoreCase(argument)) {
+                if (appId != null) {
+                    appArgsList.add(createApplicationArgs(
+                                        appBaseDir, appDir, appName, appId));
+                    appDir = null;
+                    appName = null;
+                }
+
+                appId = value;
+            }
+        }
+
+        if ((appName != null) || (appId != null) || (appDir != null)) {
+            appArgsList.add(createApplicationArgs(
+                                appBaseDir, appDir, appName, appId));
+        }
+
+        if (destFile == null) {
+            throw new RuntimeException("Destination file not specified");
+        }
+
+        if (appArgsList.isEmpty()) {
+            throw new RuntimeException("No application specified");
+        }
+
+        signingArgs.validate();
+        execute(destFile, signingArgs, appArgsList);
+    }
+
+    private static void execute(
+            final File destFile,
+            final SigningArgs signingArgs,
+            final List<ApplicationArgs> appArgsList) throws RuntimeException {
+        final Signer signer = createSigner(signingArgs);
+
+        final Packer packer;
+        try {
+            packer = new Packer(destFile, signer);
+        } catch (final IOException e) {
+            throw new RuntimeException(
+                    constructExceptionMessage("Failed to create packer", e));
+        }
+
+        try {
+            for (final ApplicationArgs appArgs: appArgsList) {
+                try {
+                    packer.storeApplication(
+                            appArgs.getBaseDir(),
+                            appArgs.getAppDir(),
+                            appArgs.getAppName(),
+                            appArgs.getAppId());
+                } catch (final IOException e) {
+                    throw new RuntimeException(
+                            constructExceptionMessage(
+                                "Failed to pack " + appArgs.getAppId(), e));
+                }
+            }
+        } finally {
+            packer.close();
+        }
+    }
+
+    private static ApplicationArgs createApplicationArgs(
+            final File baseDir,
+            final String appDir,
+            final String appName,
+            final String appId) throws RuntimeException {
+        final ApplicationArgs applicationArgs = new ApplicationArgs();
+        if (baseDir != null) {
+            applicationArgs.setBaseDir(baseDir);
+        }
+        if (appDir != null) {
+            applicationArgs.setAppDir(appDir);
+        }
+        if (appName != null) {
+            applicationArgs.setAppName(appName);
+        }
+        if (appId != null) {
+            applicationArgs.setAppId(appId);
+        }
+
+        applicationArgs.validate();
+        return applicationArgs;
+    }
+
+    private static Signer createSigner(final SigningArgs signingArgs)
+            throws RuntimeException {
+        Exception exception;
+        try {
+            return Signer.create(signingArgs.getKeyStore(),
+                                 signingArgs.getStorePass(),
+                                 signingArgs.getAlias(),
+                                 signingArgs.getKeyPass());
+        } catch (final KeyStoreException e) {
+            exception = e;
+        } catch (final NoSuchAlgorithmException e) {
+            exception = e;
+        } catch (final CertificateException e) {
+            exception = e;
+        } catch (final UnrecoverableKeyException e) {
+            exception = e;
+        } catch (final OperatorCreationException e) {
+            exception = e;
+        } catch (final CMSException e) {
+            exception = e;
+        } catch (final InvalidNameException e) {
+            exception = e;
+        } catch (final IOException e) {
+            exception = e;
+        }
+
+        throw new RuntimeException(
+                constructExceptionMessage("Failed to create signer",
+                                          exception));
+    }
+
+    private static String constructExceptionMessage(
+            final String mainMessage,
+            final Exception exception) {
+        final StringBuilder sb = new StringBuilder(mainMessage);
+        final String nl = System.getProperty("line.separator");
+
+        Throwable cause = exception;
+        while (cause != null) {
+            final String detail = cause.getMessage();
+            if (detail != null) {
+                sb.append(nl).append(detail);
+            }
+
+            cause = cause.getCause();
+        }
+
+        return sb.toString();
+    }
+
+    private static final class SigningArgs {
+        private File keyStore;
+        private String storePass;
+        private String alias;
+        private String keyPass;
+
+        public SigningArgs() {
+            storePass = "";
+            keyPass = "";
+        }
+
+        public File getKeyStore() {
+            return keyStore;
+        }
+
+        public void setKeyStore(final File keyStore) {
+            this.keyStore = keyStore;
+        }
+
+        public String getStorePass() {
+            return storePass;
+        }
+
+        public void setStorePass(final String storePass) {
+            this.storePass = storePass;
+        }
+
+        public String getAlias() {
+            return alias;
+        }
+
+        public void setAlias(final String alias) {
+            this.alias = alias;
+        }
+
+        public String getKeyPass() {
+            return keyPass;
+        }
+
+        public void setKeyPass(final String keyPass) {
+            this.keyPass = keyPass;
+        }
+
+        public void validate() throws RuntimeException {
+            if (keyStore == null) {
+                throw new RuntimeException("Key store not specified");
+            }
+
+            if (alias == null) {
+                throw new RuntimeException("Signing key not specified");
+            }
+        }
+    }
+
+    private static final class ApplicationArgs {
+        private File baseDir;
+        private String appDir;
+        private String appName;
+        private String appId;
+
+        public ApplicationArgs() {
+            baseDir = new File("");
+            appDir = "";
+        }
+
+        public File getBaseDir() {
+            return baseDir;
+        }
+
+        public void setBaseDir(final File baseDir) {
+            this.baseDir = baseDir;
+        }
+
+        public String getAppDir() {
+            return appDir;
+        }
+
+        public void setAppDir(final String appDir) {
+            this.appDir = appDir;
+        }
+
+        public String getAppName() {
+            return appName;
+        }
+
+        public void setAppName(final String appName) {
+            this.appName = appName;
+        }
+
+        public String getAppId() {
+            return appId;
+        }
+
+        public void setAppId(final String appId) {
+            this.appId = appId;
+        }
+
+        public void validate() throws RuntimeException {
+            final ResourceDescriptor appDirDescriptor =
+                    new ResourceDescriptor(baseDir, appDir);
+
+            if (!appDirDescriptor.getFile().exists()) {
+                throw new RuntimeException("Directory \"" + appDir
+                                               + "\" doesn't exist");
+            }
+
+            if (appName == null) {
+                throw new RuntimeException(
+                        "Application name not specified for " + appId);
+            }
+
+            final ResourceDescriptor appExeDescriptor =
+                    new ResourceDescriptor(appDirDescriptor.getFile(),
+                                           appName);
+            if (!appExeDescriptor.getFile().exists()) {
+                throw new RuntimeException(
+                        "Application \"" + appName + "\" doesn't exist");
+            }
+
+            if (appId == null) {
+                throw new RuntimeException(
+                        "Application id not specified for " + appName);
+            }
+
+            // all ok, store normalized paths
+            baseDir = appDirDescriptor.getBaseDir();
+            appDir = appDirDescriptor.getRelativePath();
+            appName = appExeDescriptor.getRelativePath();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/packer/ExecutablePacker.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.packer;
+
+import com.oracle.ipack.blobs.VirtualBlob;
+import com.oracle.ipack.blobs.WrapperBlob;
+import com.oracle.ipack.macho.CodeSignatureCommand;
+import com.oracle.ipack.macho.MachoCommand;
+import com.oracle.ipack.macho.MachoHeader;
+import com.oracle.ipack.macho.SegmentCommand;
+import com.oracle.ipack.signature.CodeDirectoryBlob;
+import com.oracle.ipack.signature.EmbeddedSignatureBlob;
+import com.oracle.ipack.signature.Requirement;
+import com.oracle.ipack.signature.RequirementBlob;
+import com.oracle.ipack.signature.RequirementsBlob;
+import com.oracle.ipack.signer.Signer;
+import com.oracle.ipack.util.DataCopier;
+import com.oracle.ipack.util.HashingOutputStream;
+import com.oracle.ipack.util.LsbDataInputStream;
+import com.oracle.ipack.util.LsbDataOutputStream;
+import com.oracle.ipack.util.NullOutputStream;
+import com.oracle.ipack.util.PageHashingOutputStream;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import org.bouncycastle.cms.CMSException;
+
+final class ExecutablePacker {
+    private static final int RESERVED_SIGNATURE_BLOB_SIZE = 9000;
+
+    private final ZipOutputStream zipStream;
+    private final File baseDir;
+    private final String appPath;
+    private final String appName;
+    private final String appIdentifier;
+    private final Signer signer;
+
+    private byte[] codeResourcesHash;
+    private byte[] infoPlistHash;
+
+    ExecutablePacker(final ZipOutputStream zipStream,
+                     final File baseDir,
+                     final String appPath,
+                     final String appName,
+                     final String appIdentifier,
+                     final Signer signer) {
+        this.zipStream = zipStream;
+        this.baseDir = baseDir;
+        this.appPath = appPath;
+        this.appName = appName;
+        this.appIdentifier = appIdentifier;
+        this.signer = signer;
+    }
+
+    void setCodeResourcesHash(final byte[] codeResourcesHash) {
+        this.codeResourcesHash = codeResourcesHash;
+    }
+
+    void setInfoPlistHash(final byte[] infoPlistHash) {
+        this.infoPlistHash = infoPlistHash;
+    }
+
+    void execute() throws IOException {
+        final InputStream execInputStream =
+                new BufferedInputStream(new FileInputStream(
+                        new File(baseDir, appPath + appName)));
+        try {
+            final MachoHeader header =
+                    MachoHeader.read(new LsbDataInputStream(execInputStream));
+            final int oldHeaderSize = header.getSize();
+
+            final SegmentCommand linkeditSegment =
+                    header.findSegment("__LINKEDIT");
+            if (linkeditSegment == null) {
+                throw new IOException("Linkedit segment not found");
+            }
+
+            CodeSignatureCommand codeSignatureCommand =
+                    (CodeSignatureCommand) header.findCommand(
+                                               MachoCommand.LC_CODE_SIGNATURE);
+            if (codeSignatureCommand == null) {
+                // no previous signature in the executable
+                codeSignatureCommand = new CodeSignatureCommand();
+                codeSignatureCommand.setDataOffset(
+                        linkeditSegment.getFileOffset()
+                            + linkeditSegment.getFileSize());
+                header.addCommand(codeSignatureCommand);
+            }
+
+            final int codeLimit = codeSignatureCommand.getDataOffset();
+            final EmbeddedSignatureBlob embeddedSignatureBlob =
+                    createEmbeddedSignatureBlob(
+                            appIdentifier,
+                            signer.getSubjectName(),
+                            codeLimit);
+
+            // update the header with information about the new embedded
+            // code signature
+            final int reservedForEmbeddedSignature =
+                    (embeddedSignatureBlob.getSize() + 15) & ~15;
+            codeSignatureCommand.setDataSize(reservedForEmbeddedSignature);
+            final int newLinkeditSize =
+                    codeLimit - linkeditSegment.getFileOffset()
+                              + reservedForEmbeddedSignature;
+            linkeditSegment.setFileSize(newLinkeditSize);
+            linkeditSegment.setVmSize((newLinkeditSize + 0xfff) & ~0xfff);
+            final int newHeaderSize = header.getSize();
+
+            final int firstSectionOffset = getFirstSectionFileOffset(header);
+            if (newHeaderSize > firstSectionOffset) {
+                throw new IOException("Patched header too long");
+            }
+
+            // we assume that there is only padding between the header and the
+            // first section, so we can skip some of it in the input stream
+
+            execInputStream.skip(newHeaderSize - oldHeaderSize);
+
+            // start the executable zip entry
+            final String entryName = appPath + appName;
+            System.out.println("Adding " + entryName);
+            zipStream.putNextEntry(new ZipEntry(entryName));
+            try {
+                final PageHashingOutputStream hashingStream =
+                        new PageHashingOutputStream(zipStream);
+
+                // store the patched header
+                writeHeader(hashingStream, header);
+
+                // copy the rest of the executable up to the codeLimit
+                final DataCopier dataCopier = new DataCopier();
+                // no need to use buffered stream, because the data is copied in
+                // large chunks
+                dataCopier.copyStream(hashingStream, execInputStream,
+                                      codeLimit - newHeaderSize);
+
+                // finalize the last page hash
+                hashingStream.flush();
+                hashingStream.commitPageHash();
+
+                // update the code directory blob with hashes
+                final byte[] requirementsBlobHash =
+                        calculateRequirementsBlobHash(
+                            embeddedSignatureBlob.getRequirementsSubBlob());
+                updateHashes(embeddedSignatureBlob.getCodeDirectorySubBlob(),
+                             hashingStream.getPageHashes(),
+                             infoPlistHash,
+                             requirementsBlobHash,
+                             codeResourcesHash);
+
+                // sign the embedded signature blob
+                signEmbeddedSignatureBlob(embeddedSignatureBlob, signer);
+
+                // write the embedded signature blob and padding
+                writeEmbeddedSignatureBlob(zipStream, embeddedSignatureBlob,
+                                           reservedForEmbeddedSignature);
+
+            } finally {
+                zipStream.closeEntry();
+            }
+        } finally {
+            execInputStream.close();
+        }
+
+    }
+
+    private static int getFirstSectionFileOffset(final MachoHeader header)
+            throws IOException {
+        // assumes that the first section in the file is a text section of the
+        // text segment
+
+        final SegmentCommand textSegment = header.findSegment("__TEXT");
+        if (textSegment == null) {
+            System.out.println(header);
+            throw new IOException("Text segment not found");
+        }
+
+        final SegmentCommand.Section textSection =
+                textSegment.findSection("__text");
+        if (textSection == null) {
+            throw new IOException("Text section not found");
+        }
+
+        return textSection.getOffset();
+    }
+
+
+    private static EmbeddedSignatureBlob createEmbeddedSignatureBlob(
+            final String appIdentifier,
+            final String subjectName,
+            final int codeLimit) {
+        final CodeDirectoryBlob codeDirectoryBlob =
+                new CodeDirectoryBlob(appIdentifier, codeLimit);
+
+        final RequirementsBlob requirementsBlob = new RequirementsBlob(1);
+        final RequirementBlob designatedRequirementBlob =
+                new RequirementBlob(
+                    Requirement.createDefault(appIdentifier, subjectName));
+        requirementsBlob.setSubBlob(
+                0, RequirementsBlob.KSEC_DESIGNATED_REQUIREMENT_TYPE,
+                designatedRequirementBlob);
+
+        final VirtualBlob reservedForSignatureBlob =
+                new VirtualBlob(0, RESERVED_SIGNATURE_BLOB_SIZE - 8);
+
+        final EmbeddedSignatureBlob embeddedSignatureBlob =
+                new EmbeddedSignatureBlob();
+        embeddedSignatureBlob.setCodeDirectorySubBlob(codeDirectoryBlob);
+        embeddedSignatureBlob.setRequirementsSubBlob(requirementsBlob);
+        embeddedSignatureBlob.setSignatureSubBlob(reservedForSignatureBlob);
+
+        return embeddedSignatureBlob;
+    }
+
+    private static void signEmbeddedSignatureBlob(
+            final EmbeddedSignatureBlob embeddedSignatureBlob,
+            final Signer signer) throws IOException {
+        final CodeDirectoryBlob codeDirectoryBlob =
+                embeddedSignatureBlob.getCodeDirectorySubBlob();
+        final ByteArrayOutputStream bos =
+                new ByteArrayOutputStream(codeDirectoryBlob.getSize());
+        final DataOutputStream os = new DataOutputStream(bos);
+        try {
+            codeDirectoryBlob.write(os);
+        } finally {
+            os.close();
+        }
+
+        final byte[] signature;
+        try {
+            signature = signer.sign(bos.toByteArray());
+        } catch (final CMSException e) {
+            throw new IOException("Failed to sign executable", e);
+        }
+
+        embeddedSignatureBlob.setSignatureSubBlob(
+                new WrapperBlob(signature));
+    }
+
+    private static void writeHeader(
+            final OutputStream dataStream,
+            final MachoHeader header) throws IOException {
+        final LsbDataOutputStream headerStream =
+                new LsbDataOutputStream(new BufferedOutputStream(dataStream));
+
+        try {
+            header.write(headerStream);
+        } finally {
+            headerStream.flush();
+        }
+    }
+
+    private static void writeEmbeddedSignatureBlob(
+            final OutputStream dataStream,
+            final EmbeddedSignatureBlob embeddedSignatureBlob,
+            final int reservedForEmbeddedSignature) throws IOException {
+        final int realEmbeddedSignatureSize =
+                embeddedSignatureBlob.getSize();
+        if (realEmbeddedSignatureSize > reservedForEmbeddedSignature) {
+            throw new IOException("Embedded signature too large");
+        }
+
+        final DataOutputStream signatureStream =
+                new DataOutputStream(new BufferedOutputStream(dataStream));
+        try {
+            embeddedSignatureBlob.write(signatureStream);
+
+            // add padding
+            for (int i = reservedForEmbeddedSignature
+                             - realEmbeddedSignatureSize; i > 0; --i) {
+                signatureStream.writeByte(0);
+            }
+        } finally {
+            signatureStream.flush();
+        }
+    }
+
+    private static void updateHashes(
+            final CodeDirectoryBlob codeDirectoryBlob,
+            final List<byte[]> pageHashes,
+            final byte[] infoPlistHash,
+            final byte[] requirementsHash,
+            final byte[] codeResourcesHash) {
+        int i = 0;
+        for (final byte[] pageHash: pageHashes) {
+            codeDirectoryBlob.setCodeSlot(i++, pageHash);
+        }
+
+        if (infoPlistHash != null) {
+            codeDirectoryBlob.setInfoPlistSlot(infoPlistHash);
+        }
+
+        if (requirementsHash != null) {
+            codeDirectoryBlob.setRequirementsSlot(requirementsHash);
+        }
+
+        if (codeResourcesHash != null) {
+            codeDirectoryBlob.setCodeResourcesSlot(codeResourcesHash);
+        }
+    }
+
+    private static byte[] calculateRequirementsBlobHash(
+            final RequirementsBlob requirementsBlob) {
+        final HashingOutputStream hashingStream =
+                new HashingOutputStream(new NullOutputStream());
+
+        try {
+            final DataOutputStream dataStream =
+                    new DataOutputStream(hashingStream);
+            try {
+                requirementsBlob.write(dataStream);
+            } finally {
+                dataStream.close();
+            }
+
+            return hashingStream.calculateHash();
+        } catch (final IOException e) {
+            // won't happen
+            return null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/packer/Packer.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.packer;
+
+import com.oracle.ipack.signer.Signer;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+public final class Packer {
+    private final ZipOutputStream zipStream;
+    private final Signer signer;
+
+    public Packer(final File destFile,
+                  final Signer signer) throws FileNotFoundException {
+        this.zipStream = new ZipOutputStream(
+                             new BufferedOutputStream(
+                                 new FileOutputStream(destFile)));
+        this.signer = signer;
+    }
+
+    public void storeApplication(
+            final File baseDir,
+            final String appPath,
+            final String appName,
+            final String appIdentifier) throws IOException {
+        final String normalizedAppPath = normalizePath(appPath);
+
+        if (!normalizedAppPath.isEmpty()) {
+            storeDirEntry(normalizedAppPath);
+        }
+
+        final ResourcePacker resourcePacker =
+                new ResourcePacker(zipStream, baseDir, normalizedAppPath,
+                                   appName);
+        resourcePacker.execute();
+
+        final ExecutablePacker executablePacker =
+                new ExecutablePacker(zipStream, baseDir, normalizedAppPath,
+                                     appName,
+                                     appIdentifier,
+                                     signer);
+
+        executablePacker.setCodeResourcesHash(
+                resourcePacker.getCodeResourcesHash());
+        executablePacker.setInfoPlistHash(
+                resourcePacker.getInfoPlistHash());
+        executablePacker.execute();
+    }
+
+    public void close() {
+        try {
+            zipStream.close();
+        } catch (final IOException e) {
+            // ignore
+        }
+    }
+
+    private void storeDirEntry(final String entryName) throws IOException {
+        // TODO: intermediate dirs
+        zipStream.putNextEntry(new ZipEntry(entryName));
+        zipStream.closeEntry();
+    }
+
+    private static String normalizePath(final String path) {
+        if (path.isEmpty() || path.endsWith("/")) {
+            return path;
+        }
+
+        return path + '/';
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/packer/ResourcePacker.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.packer;
+
+import com.oracle.ipack.resources.CodeResources;
+import com.oracle.ipack.resources.ResourceRules;
+import com.oracle.ipack.util.DataCopier;
+import com.oracle.ipack.util.HashingOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+final class ResourcePacker {
+    private final ZipOutputStream zipStream;
+    private final File baseDir;
+    private final String appPath;
+
+    private final DataCopier dataCopier;
+    private final ResourceRules resourceRules;
+    private final HashingOutputStream dataStream;
+
+    private byte[] codeResourcesHash;
+    private byte[] infoPlistHash;
+
+    ResourcePacker(final ZipOutputStream zipStream,
+                   final File baseDir,
+                   final String appPath,
+                   final String appName) {
+        this.zipStream = zipStream;
+        this.baseDir = baseDir;
+        this.appPath = appPath;
+
+        dataCopier = new DataCopier();
+        dataStream = new HashingOutputStream(zipStream);
+
+        resourceRules = new ResourceRules();
+        resourceRules.addExclude(appName, -1);
+        resourceRules.addExclude("_CodeSignature", -1);
+        resourceRules.addExclude("Info.plist", 10);
+        resourceRules.addExclude("ResourceRules.plist", 100);
+    }
+
+    void execute() throws IOException {
+        final CodeResources codeResources = new CodeResources(resourceRules);
+
+        storeResourceFiles(codeResources);
+        codeResourcesHash = storeCodeResources(codeResources);
+
+        final String infoPlistName = appPath + "Info.plist";
+        infoPlistHash =
+                storeFileEntry(infoPlistName, new File(baseDir, infoPlistName));
+    }
+
+    byte[] getCodeResourcesHash() {
+        return codeResourcesHash;
+    }
+
+    byte[] getInfoPlistHash() {
+        return infoPlistHash;
+    }
+
+    private void storeResourceFiles(final CodeResources codeResources)
+            throws IOException {
+        final List<String> resources =
+                resourceRules.collectResources(
+                        new File(baseDir, appPath));
+
+        for (final String resourceName: resources) {
+            final String fullResourceName =
+                    appPath + resourceName;
+            if (resourceName.endsWith("/")) {
+                storeDirEntry(fullResourceName);
+                continue;
+            }
+
+            final byte[] resourceHash =
+                    storeFileEntry(fullResourceName,
+                                   new File(baseDir, fullResourceName));
+            codeResources.addHashedResource(resourceName, resourceHash);
+        }
+    }
+
+    private byte[] storeCodeResources(final CodeResources codeResources)
+            throws IOException {
+        storeDirEntry(appPath + "_CodeSignature/");
+
+        final String codeResourcesName =
+                appPath + "_CodeSignature/CodeResources";
+
+        System.out.println("Adding " + codeResourcesName);
+        zipStream.putNextEntry(new ZipEntry(codeResourcesName));
+        try {
+            codeResources.write(dataStream);
+        } finally {
+            dataStream.flush();
+            zipStream.closeEntry();
+        }
+
+        return dataStream.calculateHash();
+    }
+
+    private void storeDirEntry(final String entryName) throws IOException {
+        zipStream.putNextEntry(new ZipEntry(entryName));
+        zipStream.closeEntry();
+    }
+
+    private byte[] storeFileEntry(final String entryName,
+                                  final File file) throws IOException {
+        System.out.println("Adding " + entryName);
+        zipStream.putNextEntry(new ZipEntry(entryName));
+        try {
+            dataCopier.copyFile(dataStream, file);
+        } finally {
+            dataStream.flush();
+            zipStream.closeEntry();
+        }
+
+        return dataStream.calculateHash();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/resources/CodeResources.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.resources;
+
+import com.oracle.ipack.resources.ResourceRules.Exclude;
+import com.oracle.ipack.util.Base64;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+public final class CodeResources {
+    private final ResourceRules resourceRules;
+    private final List<HashedResource> hashedResources;
+
+    public CodeResources(final ResourceRules resourceRules) {
+        this.resourceRules = resourceRules;
+        this.hashedResources = new ArrayList<HashedResource>();
+    }
+
+    public void addHashedResource(
+            final String resourceName,
+            final byte[] resourceHash) {
+        hashedResources.add(
+                new HashedResource(resourceName,
+                                   Base64.byteArrayToBase64(resourceHash)));
+    }
+
+    public void write(final OutputStream os) throws IOException {
+        final PrintWriter pw =
+                new PrintWriter(
+                    new BufferedWriter(
+                        new OutputStreamWriter(os, "UTF-8")));
+
+        pw.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+                      + "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\""
+                      + " \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+                      + "<plist version=\"1.0\">\n"
+                      + "<dict>\n"
+                      + "\t<key>files</key>\n"
+                      + "\t<dict>\n");
+
+        for (final HashedResource hashedResource: hashedResources) {
+            appendResource(pw, hashedResource);
+        }
+
+        pw.append("\t</dict>\n"
+                      + "\t<key>rules</key>\n"
+                      + "\t<dict>\n"
+                      + "\t\t<key>.*</key>\n"
+                      + "\t\t<true/>\n");
+
+        for (final Exclude exclude: resourceRules.getExcludes()) {
+            if (exclude.getWeight() >= 0) {
+                appendExclude(pw, exclude);
+            }
+        }
+
+        pw.append("\t</dict>\n"
+                      + "</dict>\n"
+                      + "</plist>\n");
+        pw.flush();
+    }
+
+    private static void appendResource(final PrintWriter pw,
+                                       final HashedResource hashedResource) {
+        pw.append("\t\t<key>").append(hashedResource.getName())
+                              .append("</key>\n")
+          .append("\t\t<data>\n")
+          .append("\t\t").append(hashedResource.getHash()).append('\n')
+          .append("\t\t</data>\n");
+    }
+
+    private static void appendExclude(final PrintWriter pw,
+                                      final Exclude exclude) {
+        pw.append("\t\t<key>").append(exclude.getName()).append("</key>\n")
+          .append("\t\t<dict>\n")
+          .append("\t\t\t<key>omit</key>\n")
+          .append("\t\t\t<true/>\n")
+          .append("\t\t\t<key>weight</key>\n")
+          .append("\t\t\t<real>");
+        pw.print(exclude.getWeight());
+        pw.append("</real>\n")
+          .append("\t\t</dict>\n");
+    }
+
+    private static final class HashedResource {
+        private final String name;
+        private final String hash;
+
+        public HashedResource(final String name, final String hash) {
+            this.name = name;
+            this.hash = hash;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String getHash() {
+            return hash;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/resources/ResourceRules.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.resources;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public final class ResourceRules {
+    private final List<Exclude> excludes;
+    private final Set<String> excludesLookup;
+
+    public ResourceRules() {
+        this.excludes = new ArrayList<Exclude>();
+        this.excludesLookup = new HashSet<String>();
+    }
+
+    public void addExclude(final String name, final int weight) {
+        excludes.add(new Exclude(name, weight));
+        excludesLookup.add(name);
+    }
+
+    public List<Exclude> getExcludes() {
+        return Collections.unmodifiableList(excludes);
+    }
+
+    public List<String> collectResources(final File baseDirectory) {
+        final List<String> resources = new ArrayList<String>();
+        collectResources(resources, baseDirectory, "");
+
+        return Collections.unmodifiableList(resources);
+    }
+
+    private void collectResources(final List<String> resources,
+                                  final File resourceFile,
+                                  final String resourceName) {
+        if (excludesLookup.contains(resourceName)) {
+            return;
+        }
+
+        if (resourceFile.isDirectory()) {
+            if (!resourceName.isEmpty()) {
+                resources.add(resourceName + '/');
+            }
+
+            final String[] childNames = resourceFile.list();
+            for (final String childName: childNames) {
+                collectResources(resources,
+                                 new File(resourceFile, childName),
+                                 constructResourceName(
+                                         resourceName, childName));
+            }
+
+            return;
+        }
+
+        if (resourceFile.isFile()) {
+            resources.add(resourceName);
+            return;
+        }
+
+        System.err.println("Skipping " + resourceName);
+    }
+
+    public static final class Exclude {
+        private final String name;
+        private final int weight;
+
+        public Exclude(final String name, final int weight) {
+            this.name = name;
+            this.weight = weight;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public int getWeight() {
+            return weight;
+        }
+    }
+
+    private static String constructResourceName(final String parentResource,
+                                                final String childResource) {
+        return parentResource.isEmpty()
+                ? childResource
+                : parentResource + '/' + childResource;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/signature/CodeDirectoryBlob.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.signature;
+
+import com.oracle.ipack.blobs.Blob;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+public final class CodeDirectoryBlob extends Blob {
+    private final byte[] identifierBytes;
+
+    private final int numberOfSpecialSlots;
+    private final int numberOfCodeSlots;
+    private final byte[] specialSlots;
+    private final byte[] codeSlots;
+
+    private final int codeLimit;
+    private final int hashSize;
+    private final int hashType;
+    private final int pageSize;
+
+    private int flags;
+
+    public CodeDirectoryBlob(final String identifier,
+                             final int codeLimit) {
+        this(identifier, codeLimit, 3, 4096, 20, 1);
+    }
+
+    public CodeDirectoryBlob(final String identifier,
+                             final int codeLimit,
+                             final int numberOfSpecialSlots,
+                             final int pageSize,
+                             final int hashSize,
+                             final int hashType) {
+        this.identifierBytes = identifierBytes(identifier);
+
+        this.numberOfSpecialSlots = numberOfSpecialSlots;
+        this.numberOfCodeSlots = (codeLimit + pageSize - 1) / pageSize;
+
+        this.specialSlots = new byte[numberOfSpecialSlots * hashSize];
+        this.codeSlots = new byte[numberOfCodeSlots * hashSize];
+
+        this.codeLimit = codeLimit;
+        this.hashSize = hashSize;
+        this.hashType = hashType;
+        this.pageSize = pageSize;
+    }
+
+    public int getFlags() {
+        return flags;
+    }
+
+    public void setFlags(final int flags) {
+        this.flags = flags;
+    }
+
+    public void setInfoPlistSlot(final byte[] hash) {
+        setSpecialSlot(SpecialSlotConstants.CD_INFO_SLOT, hash);
+    }
+
+    public void setRequirementsSlot(final byte[] hash) {
+        setSpecialSlot(SpecialSlotConstants.CD_REQUIREMENTS_SLOT, hash);
+    }
+
+    public void setCodeResourcesSlot(final byte[] hash) {
+        setSpecialSlot(SpecialSlotConstants.CD_RESOURCE_DIR_SLOT, hash);
+    }
+
+    public void setSpecialSlot(final int index, final byte[] hash) {
+        System.arraycopy(hash, 0, specialSlots,
+                         specialSlots.length - index * hashSize,
+                         hashSize);
+    }
+
+    public void setCodeSlot(final int index, final byte[] hash) {
+        System.arraycopy(hash, 0, codeSlots, index * hashSize, hashSize);
+    }
+
+    @Override
+    protected int getMagic() {
+        return 0xfade0c02;
+    }
+
+    @Override
+    protected int getPayloadSize() {
+        return 4 * 10 + identifierBytes.length
+                      + specialSlots.length
+                      + codeSlots.length;
+    }
+
+    @Override
+    protected void writePayload(final DataOutput dataOutput)
+            throws IOException {
+        final int identOffset = 8 + 4 * 10;
+        final int hashOffset = identOffset + identifierBytes.length
+                                           + specialSlots.length;
+        final int pageSizeShift = 31 - Integer.numberOfLeadingZeros(pageSize);
+
+        dataOutput.writeInt(0x20100); // version
+        dataOutput.writeInt(flags);
+        dataOutput.writeInt(hashOffset);
+        dataOutput.writeInt(identOffset);
+        dataOutput.writeInt(numberOfSpecialSlots);
+        dataOutput.writeInt(numberOfCodeSlots);
+        dataOutput.writeInt(codeLimit);
+        dataOutput.writeByte(hashSize);
+        dataOutput.writeByte(hashType);
+        dataOutput.writeByte(0); // spare1
+        dataOutput.writeByte(pageSizeShift);
+        dataOutput.writeInt(0); // spare2
+        dataOutput.writeInt(0); // scatterOffset
+
+        dataOutput.write(identifierBytes);
+        dataOutput.write(specialSlots);
+        dataOutput.write(codeSlots);
+    }
+
+    private byte[] identifierBytes(final String identifier) {
+        try {
+            return (identifier + '\0').getBytes("UTF-8");
+        } catch (final UnsupportedEncodingException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/signature/EmbeddedSignatureBlob.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.signature;
+
+import com.oracle.ipack.blobs.Blob;
+import com.oracle.ipack.blobs.SuperBlob;
+
+public final class EmbeddedSignatureBlob extends SuperBlob<Blob> {
+    public EmbeddedSignatureBlob() {
+        super(3);
+    }
+
+    public CodeDirectoryBlob getCodeDirectorySubBlob() {
+        return (CodeDirectoryBlob) getSubBlob(0);
+    }
+
+    public void setCodeDirectorySubBlob(final CodeDirectoryBlob codeDirectory) {
+        setSubBlob(0, SpecialSlotConstants.CD_CODE_DIRECTORY_SLOT,
+                   codeDirectory);
+    }
+
+    public RequirementsBlob getRequirementsSubBlob() {
+        return (RequirementsBlob) getSubBlob(1);
+    }
+
+    public void setRequirementsSubBlob(
+            final RequirementsBlob requirementsBlob) {
+        setSubBlob(1, SpecialSlotConstants.CD_REQUIREMENTS_SLOT,
+                   requirementsBlob);
+    }
+
+    public Blob getSignatureSubBlob() {
+        return getSubBlob(2);
+    }
+
+    public void setSignatureSubBlob(final Blob signatureBlob) {
+        setSubBlob(2, SpecialSlotConstants.CD_SIGNATURE_SLOT,
+                   signatureBlob);
+    }
+
+    @Override
+    protected int getMagic() {
+        return 0xfade0cc0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/signature/Requirement.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.signature;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+public abstract class Requirement {
+    private static final Requirement APPLE_GENERIC_ANCHOR =
+            new Anchor(0xf);
+    private static final Match MATCH_EXISTS =
+            new Match(0);
+
+    public static Requirement createDefault(
+            final String appIdent,
+            final String subjectName) {
+        final byte[] oid = {
+            (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7,
+            (byte) 0x63, (byte) 0x64, (byte) 0x06, (byte) 0x02, (byte) 0x01
+        };
+
+        return and(ident(appIdent),
+                   and(appleGenericAnchor(),
+                       and(certField(0, "subject.CN",
+                                     matchEqual(subjectName)),
+                           certGeneric(1, oid, matchExists()))));
+    }
+
+    public static Requirement and(final Requirement left,
+                                  final Requirement right) {
+        return new BinaryOp(6, left, right);
+    }
+
+    public static Requirement ident(final String value) {
+        return new Ident(value);
+    }
+
+    public static Requirement appleGenericAnchor() {
+        return APPLE_GENERIC_ANCHOR;
+    }
+
+    public static Requirement certField(final int certIndex,
+                                        final String fielName,
+                                        final Match match) {
+        return new CertField(certIndex, fielName, match);
+    }
+
+    public static Requirement certGeneric(final int certIndex,
+                                          final byte[] oid,
+                                          final Match match) {
+        return new CertGeneric(certIndex, (byte[]) oid.clone(), match);
+    }
+
+    public static Match matchExists() {
+        return MATCH_EXISTS;
+    }
+
+    public static Match matchEqual(final String value) {
+        return new MatchEqual(value);
+    }
+
+    private Requirement() {
+    }
+
+    public final int getSize() {
+        return 4 + getPayloadSize();
+    }
+
+    public final void write(final DataOutput dataOutput) throws IOException {
+        dataOutput.writeInt(getIdent());
+        writePayload(dataOutput);
+    }
+
+    protected abstract int getIdent();
+
+    protected abstract int getPayloadSize();
+
+    protected abstract void writePayload(DataOutput dataOutput)
+            throws IOException;
+
+    private static final class BinaryOp extends Requirement {
+        private final int ident;
+        private final Requirement left;
+        private final Requirement right;
+
+        public BinaryOp(final int ident,
+                        final Requirement left,
+                        final Requirement right) {
+            this.ident = ident;
+            this.left = left;
+            this.right = right;
+        }
+
+        @Override
+        protected int getIdent() {
+            return ident;
+        }
+
+        @Override
+        protected int getPayloadSize() {
+            return left.getSize() + right.getSize();
+        }
+
+        @Override
+        protected void writePayload(final DataOutput dataOutput)
+                throws IOException {
+            left.write(dataOutput);
+            right.write(dataOutput);
+        }
+    }
+
+    private static final class Ident extends Requirement {
+        private final StringData value;
+
+        public Ident(final String value) {
+            this.value = new StringData(value);
+        }
+
+        @Override
+        protected int getIdent() {
+            return 2;
+        }
+
+        @Override
+        protected int getPayloadSize() {
+            return value.getSize();
+        }
+
+        @Override
+        protected void writePayload(final DataOutput dataOutput)
+                throws IOException {
+            value.write(dataOutput);
+        }
+    }
+
+    private static final class Anchor extends Requirement {
+        private final int ident;
+
+        public Anchor(final int ident) {
+            this.ident = ident;
+        }
+
+        @Override
+        protected int getIdent() {
+            return ident;
+        }
+
+        @Override
+        protected int getPayloadSize() {
+            return 0;
+        }
+
+        @Override
+        protected void writePayload(final DataOutput dataOutput)
+                throws IOException {
+        }
+    }
+
+    private static final class CertField extends Requirement {
+        private final int certIndex;
+        private final StringData fieldName;
+        private final Match match;
+
+        public CertField(final int certIndex,
+                         final String fieldName,
+                         final Match match) {
+            this.certIndex = certIndex;
+            this.fieldName = new StringData(fieldName);
+            this.match = match;
+        }
+
+        @Override
+        protected int getIdent() {
+            return 0xb;
+        }
+
+        @Override
+        protected int getPayloadSize() {
+            return 4 + fieldName.getSize() + match.getSize();
+        }
+
+        @Override
+        protected void writePayload(final DataOutput dataOutput)
+                throws IOException {
+            dataOutput.writeInt(certIndex);
+            fieldName.write(dataOutput);
+            match.write(dataOutput);
+        }
+    }
+
+    private static final class CertGeneric extends Requirement {
+        private final int certIndex;
+        private final BinaryData oid;
+        private final Match match;
+
+        public CertGeneric(final int certIndex,
+                           final byte[] oid,
+                           final Match match) {
+            this.certIndex = certIndex;
+            this.oid = new BinaryData(oid);
+            this.match = match;
+        }
+
+        @Override
+        protected int getIdent() {
+            return 0xe;
+        }
+
+        @Override
+        protected int getPayloadSize() {
+            return 4 + oid.getSize() + match.getSize();
+        }
+
+        @Override
+        protected void writePayload(final DataOutput dataOutput)
+                throws IOException {
+            dataOutput.writeInt(certIndex);
+            oid.write(dataOutput);
+            match.write(dataOutput);
+        }
+    }
+
+    private static class BinaryData {
+        private byte[] bytes;
+
+        public BinaryData(final byte[] bytes) {
+            this.bytes = bytes;
+        }
+
+        public int getSize() {
+            final int rawSize = 4 + bytes.length;
+            return (rawSize + 3) & ~3;
+        }
+
+        public void write(final DataOutput dataOutput) throws IOException {
+            dataOutput.writeInt(bytes.length);
+            dataOutput.write(bytes);
+            final int padding = getSize() - 4 - bytes.length;
+            for (int i = 0; i < padding; ++i) {
+                dataOutput.write(0);
+            }
+        }
+    }
+
+    private static final class StringData extends BinaryData {
+        public StringData(final String value) {
+            super(getBytes(value));
+        }
+
+        private static byte[] getBytes(final String value) {
+            try {
+                return value.getBytes("UTF-8");
+            } catch (final UnsupportedEncodingException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+    }
+
+    public static class Match {
+        private final int ident;
+
+        private Match(final int ident) {
+            this.ident = ident;
+        }
+
+        public final int getSize() {
+            return 4 + getArgSize();
+        }
+
+        public final void write(final DataOutput dataOutput)
+                throws IOException {
+            dataOutput.writeInt(ident);
+            writeArg(dataOutput);
+        }
+
+        protected int getArgSize() {
+            return 0;
+        }
+
+        protected void writeArg(final DataOutput dataOutput)
+                throws IOException {
+        }
+    }
+
+    private static final class MatchEqual extends Match {
+        private final StringData arg;
+
+        public MatchEqual(final String arg) {
+            super(1);
+            this.arg = new StringData(arg);
+        }
+
+        @Override
+        protected int getArgSize() {
+            return arg.getSize();
+        }
+
+        @Override
+        protected void writeArg(final DataOutput dataOutput)
+                throws IOException {
+            arg.write(dataOutput);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/signature/RequirementBlob.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.signature;
+
+import com.oracle.ipack.blobs.Blob;
+import java.io.DataOutput;
+import java.io.IOException;
+
+public final class RequirementBlob extends Blob {
+    private final Requirement requirement;
+
+    public RequirementBlob(final Requirement requirement) {
+        this.requirement = requirement;
+    }
+
+    @Override
+    protected int getMagic() {
+        return 0xfade0c00;
+    }
+
+    @Override
+    protected int getPayloadSize() {
+        return 4 + requirement.getSize();
+    }
+
+    @Override
+    protected void writePayload(
+            final DataOutput dataOutput) throws IOException {
+        dataOutput.writeInt(1); // expression form of requirement
+        requirement.write(dataOutput);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/signature/RequirementsBlob.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.signature;
+
+import com.oracle.ipack.blobs.SuperBlob;
+
+public final class RequirementsBlob extends SuperBlob<RequirementBlob> {
+    /* what hosts may run us */
+    public static final int KSEC_HOST_REQUIREMENT_TYPE = 1;
+    /* what guests we may run */
+    public static final int KSEC_GUEST_REQUIREMENT_TYPE = 2;
+    /* designated requirement */
+    public static final int KSEC_DESIGNATED_REQUIREMENT_TYPE = 3;
+    /* what libraries we may link against */
+    public static final int KSEC_LIBRARY_REQUIREMENT_TYPE = 4;
+    /* what plug-ins we may load */
+    public static final int KSEC_PLUGIN_REQUIREMENT_TYPE = 5;
+
+    public RequirementsBlob(final int numberOfSubBlobs) {
+        super(numberOfSubBlobs);
+    }
+
+    @Override
+    protected int getMagic() {
+        return 0xfade0c01;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/signature/SpecialSlotConstants.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.signature;
+
+public final class SpecialSlotConstants {
+    /* Info.plist */
+    public static final int CD_INFO_SLOT = 1;
+    /* internal requirements */
+	public static final int CD_REQUIREMENTS_SLOT = 2;
+    /* resource directory */
+	public static final int CD_RESOURCE_DIR_SLOT = 3;
+    /* Application specific slot */
+	public static final int CD_APPLICATION_SLOT = 4;
+    /* embedded entitlement configuration */
+    public static final int CD_ENTITLEMENT_SLOT = 5;
+    /* CodeDirectory */
+	public static final int CD_CODE_DIRECTORY_SLOT = 0;
+    /* CMS signature */
+	public static final int CD_SIGNATURE_SLOT = 0x10000;
+
+    private SpecialSlotConstants() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/signer/Signer.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.signer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+import org.bouncycastle.cert.jcajce.JcaCertStore;
+import org.bouncycastle.cms.CMSException;
+import org.bouncycastle.cms.CMSProcessableByteArray;
+import org.bouncycastle.cms.CMSSignedData;
+import org.bouncycastle.cms.CMSSignedDataGenerator;
+import org.bouncycastle.cms.CMSTypedData;
+import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.util.Store;
+
+public final class Signer {
+    private final CMSSignedDataGenerator signatureGenerator;
+    private final String subjectName;
+
+    private Signer(final CMSSignedDataGenerator signatureGenerator,
+                   final String subjectName) {
+        this.signatureGenerator = signatureGenerator;
+        this.subjectName = subjectName;
+    }
+
+    public static Signer create(
+            final File keystoreFile,
+            final String keystorePassword,
+            final String signingAlias,
+            final String keyPassword) throws IOException,
+                                             KeyStoreException,
+                                             NoSuchAlgorithmException,
+                                             CertificateException,
+                                             UnrecoverableKeyException,
+                                             OperatorCreationException,
+                                             CMSException,
+                                             InvalidNameException {
+        final KeyStore jksKeyStore = KeyStore.getInstance("JKS");
+        final InputStream is = new FileInputStream(keystoreFile);
+        try {
+            jksKeyStore.load(is, keystorePassword.toCharArray());
+        } finally {
+            is.close();
+        }
+
+        final PrivateKey privateKey =
+                (PrivateKey) jksKeyStore.getKey(signingAlias,
+                                                keyPassword.toCharArray());
+        final Certificate[] certChain =
+                jksKeyStore.getCertificateChain(signingAlias);
+        if (certChain == null) {
+            throw new CertificateException(
+                    "Certificate chain not found under \"" + signingAlias
+                                                           + "\"");
+        }
+
+        final X509Certificate signingCert = (X509Certificate) certChain[0];
+        final String subjectName = getSubjectName(signingCert);
+
+        final Store certs = new JcaCertStore(Arrays.asList(certChain));
+        final CMSSignedDataGenerator signatureGenerator =
+                new CMSSignedDataGenerator();
+
+        signatureGenerator.addSignerInfoGenerator(
+                new JcaSimpleSignerInfoGeneratorBuilder()
+                            .setProvider("BC")
+                            .build("SHA1withRSA", privateKey, signingCert));
+        signatureGenerator.addCertificates(certs);
+
+        return new Signer(signatureGenerator, subjectName);
+    }
+
+    public byte[] sign(final byte[] data) throws CMSException, IOException {
+        final CMSTypedData typedData = new CMSProcessableByteArray(data);
+        final CMSSignedData signedData = signatureGenerator.generate(typedData);
+
+        return signedData.getEncoded();
+    }
+
+    public String getSubjectName() {
+        return subjectName;
+    }
+
+    private static String getSubjectName(final X509Certificate cert)
+            throws InvalidNameException {
+        final String fullSubjectDn = cert.getSubjectX500Principal().getName();
+        final LdapName fullSubjectLn = new LdapName(fullSubjectDn);
+        for (final Rdn rdn: fullSubjectLn.getRdns()) {
+            if ("CN".equalsIgnoreCase(rdn.getType())) {
+                return rdn.getValue().toString();
+            }
+        }
+
+        throw new InvalidNameException("Common name not found");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/Base64.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.util;
+
+/**
+ * Static methods for translating Base64 encoded strings to byte arrays
+ * and vice-versa.
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @since   1.4
+ */
+public final class Base64 {
+    /**
+     * Translates the specified byte array into a Base64 string as per
+     * Preferences.put(byte[]).
+     */
+    public static String byteArrayToBase64(byte[] a) {
+        return byteArrayToBase64(a, false);
+    }
+
+    /**
+     * Translates the specified byte array into an "alternate representation"
+     * Base64 string.  This non-standard variant uses an alphabet that does
+     * not contain the uppercase alphabetic characters, which makes it
+     * suitable for use in situations where case-folding occurs.
+     */
+    public static String byteArrayToAltBase64(byte[] a) {
+        return byteArrayToBase64(a, true);
+    }
+
+    private static String byteArrayToBase64(byte[] a, boolean alternate) {
+        int aLen = a.length;
+        int numFullGroups = aLen/3;
+        int numBytesInPartialGroup = aLen - 3*numFullGroups;
+        int resultLen = 4*((aLen + 2)/3);
+        StringBuffer result = new StringBuffer(resultLen);
+        char[] intToAlpha = (alternate ? intToAltBase64 : intToBase64);
+
+        // Translate all full groups from byte array elements to Base64
+        int inCursor = 0;
+        for (int i=0; i<numFullGroups; i++) {
+            int byte0 = a[inCursor++] & 0xff;
+            int byte1 = a[inCursor++] & 0xff;
+            int byte2 = a[inCursor++] & 0xff;
+            result.append(intToAlpha[byte0 >> 2]);
+            result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]);
+            result.append(intToAlpha[(byte1 << 2)&0x3f | (byte2 >> 6)]);
+            result.append(intToAlpha[byte2 & 0x3f]);
+        }
+
+        // Translate partial group if present
+        if (numBytesInPartialGroup != 0) {
+            int byte0 = a[inCursor++] & 0xff;
+            result.append(intToAlpha[byte0 >> 2]);
+            if (numBytesInPartialGroup == 1) {
+                result.append(intToAlpha[(byte0 << 4) & 0x3f]);
+                result.append("==");
+            } else {
+                // assert numBytesInPartialGroup == 2;
+                int byte1 = a[inCursor++] & 0xff;
+                result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]);
+                result.append(intToAlpha[(byte1 << 2)&0x3f]);
+                result.append('=');
+            }
+        }
+        // assert inCursor == a.length;
+        // assert result.length() == resultLen;
+        return result.toString();
+    }
+
+    /**
+     * This array is a lookup table that translates 6-bit positive integer
+     * index values into their "Base64 Alphabet" equivalents as specified
+     * in Table 1 of RFC 2045.
+     */
+    private static final char intToBase64[] = {
+        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+    };
+
+    /**
+     * This array is a lookup table that translates 6-bit positive integer
+     * index values into their "Alternate Base64 Alphabet" equivalents.
+     * This is NOT the real Base64 Alphabet as per in Table 1 of RFC 2045.
+     * This alternate alphabet does not use the capital letters.  It is
+     * designed for use in environments where "case folding" occurs.
+     */
+    private static final char intToAltBase64[] = {
+        '!', '"', '#', '$', '%', '&', '\'', '(', ')', ',', '-', '.', ':',
+        ';', '<', '>', '@', '[', ']', '^',  '`', '_', '{', '|', '}', '~',
+        'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm',
+        'n', 'o', 'p', 'q', 'r', 's', 't',  'u', 'v', 'w', 'x', 'y', 'z',
+        '0', '1', '2', '3', '4', '5', '6',  '7', '8', '9', '+', '?'
+    };
+
+    /**
+     * Translates the specified Base64 string (as per Preferences.get(byte[]))
+     * into a byte array.
+     *
+     * @throw IllegalArgumentException if <tt>s</tt> is not a valid Base64
+     *        string.
+     */
+    public static byte[] base64ToByteArray(String s) {
+        return base64ToByteArray(s, false);
+    }
+
+    /**
+     * Translates the specified "alternate representation" Base64 string
+     * into a byte array.
+     *
+     * @throw IllegalArgumentException or ArrayOutOfBoundsException
+     *        if <tt>s</tt> is not a valid alternate representation
+     *        Base64 string.
+     */
+    public static byte[] altBase64ToByteArray(String s) {
+        return base64ToByteArray(s, true);
+    }
+
+    private static byte[] base64ToByteArray(String s, boolean alternate) {
+        byte[] alphaToInt = (alternate ?  altBase64ToInt : base64ToInt);
+        int sLen = s.length();
+        int numGroups = sLen/4;
+        if (4*numGroups != sLen)
+            throw new IllegalArgumentException(
+                "String length must be a multiple of four.");
+        int missingBytesInLastGroup = 0;
+        int numFullGroups = numGroups;
+        if (sLen != 0) {
+            if (s.charAt(sLen-1) == '=') {
+                missingBytesInLastGroup++;
+                numFullGroups--;
+            }
+            if (s.charAt(sLen-2) == '=')
+                missingBytesInLastGroup++;
+        }
+        byte[] result = new byte[3*numGroups - missingBytesInLastGroup];
+
+        // Translate all full groups from base64 to byte array elements
+        int inCursor = 0, outCursor = 0;
+        for (int i=0; i<numFullGroups; i++) {
+            int ch0 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            int ch1 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            int ch2 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            int ch3 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4));
+            result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2));
+            result[outCursor++] = (byte) ((ch2 << 6) | ch3);
+        }
+
+        // Translate partial group, if present
+        if (missingBytesInLastGroup != 0) {
+            int ch0 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            int ch1 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4));
+
+            if (missingBytesInLastGroup == 1) {
+                int ch2 = base64toInt(s.charAt(inCursor++), alphaToInt);
+                result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2));
+            }
+        }
+        // assert inCursor == s.length()-missingBytesInLastGroup;
+        // assert outCursor == result.length;
+        return result;
+    }
+
+    /**
+     * Translates the specified character, which is assumed to be in the
+     * "Base 64 Alphabet" into its equivalent 6-bit positive integer.
+     *
+     * @throw IllegalArgumentException or ArrayOutOfBoundsException if
+     *        c is not in the Base64 Alphabet.
+     */
+    private static int base64toInt(char c, byte[] alphaToInt) {
+        int result = alphaToInt[c];
+        if (result < 0)
+            throw new IllegalArgumentException("Illegal character " + c);
+        return result;
+    }
+
+    /**
+     * This array is a lookup table that translates unicode characters
+     * drawn from the "Base64 Alphabet" (as specified in Table 1 of RFC 2045)
+     * into their 6-bit positive integer equivalents.  Characters that
+     * are not in the Base64 alphabet but fall within the bounds of the
+     * array are translated to -1.
+     */
+    private static final byte base64ToInt[] = {
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54,
+        55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
+        5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+        24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+        35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
+    };
+
+    /**
+     * This array is the analogue of base64ToInt, but for the nonstandard
+     * variant that avoids the use of uppercase alphabetic characters.
+     */
+    private static final byte altBase64ToInt[] = {
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1,
+        2, 3, 4, 5, 6, 7, 8, -1, 62, 9, 10, 11, -1 , 52, 53, 54, 55, 56, 57,
+        58, 59, 60, 61, 12, 13, 14, -1, 15, 63, 16, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, 17, -1, 18, 19, 21, 20, 26, 27, 28, 29, 30, 31, 32, 33,
+        34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+        51, 22, 23, 24, 25
+    };
+
+    public static void main(String args[]) {
+        int numRuns  = Integer.parseInt(args[0]);
+        int numBytes = Integer.parseInt(args[1]);
+        java.util.Random rnd = new java.util.Random();
+        for (int i=0; i<numRuns; i++) {
+            for (int j=0; j<numBytes; j++) {
+                byte[] arr = new byte[j];
+                for (int k=0; k<j; k++)
+                    arr[k] = (byte)rnd.nextInt();
+
+                String s = byteArrayToBase64(arr);
+                byte [] b = base64ToByteArray(s);
+                if (!java.util.Arrays.equals(arr, b))
+                    System.out.println("Dismal failure!");
+
+                s = byteArrayToAltBase64(arr);
+                b = altBase64ToByteArray(s);
+                if (!java.util.Arrays.equals(arr, b))
+                    System.out.println("Alternate dismal failure!");
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/DataCopier.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public final class DataCopier {
+    private final byte[] buffer;
+
+    public DataCopier() {
+        buffer = new byte[65536];
+    }
+
+    public void copyFile(final OutputStream os, final File file)
+            throws IOException {
+        final InputStream is = new FileInputStream(file);
+        try {
+            copyStream(os, is);
+        } finally {
+            try {
+                is.close();
+            } catch (final IOException e) {
+                // ignore
+            }
+        }
+    }
+
+    public void copyStream(final OutputStream os, final InputStream is)
+            throws IOException {
+        int read;
+        while ((read = is.read(buffer)) != -1) {
+            os.write(buffer, 0, read);
+        }
+    }
+
+    public void copyStream(final OutputStream os,
+                           final InputStream is,
+                           final int limit) throws IOException {
+        int remaining = limit;
+        while (remaining > 0) {
+            final int chunkSize = (remaining < buffer.length)
+                                          ? remaining
+                                          : buffer.length;
+            final int read = is.read(buffer, 0, chunkSize);
+            if (read == -1) {
+                // end of stream
+                return;
+            }
+
+            os.write(buffer, 0, read);
+            remaining -= read;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/HashingOutputStream.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.util;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class HashingOutputStream extends FilterOutputStream {
+    private final MessageDigest messageDigest;
+
+    public HashingOutputStream(final OutputStream out) {
+        super(out);
+        try {
+            messageDigest = MessageDigest.getInstance("SHA1");
+        } catch (final NoSuchAlgorithmException e) {
+            throw new IllegalStateException("Can't create message digest", e);
+        }
+    }
+
+    @Override
+    public void write(final int byteValue) throws IOException {
+        out.write(byteValue);
+        messageDigest.update((byte) byteValue);
+    }
+
+    @Override
+    public void write(final byte[] buffer, final int offset, final int length)
+            throws IOException {
+        out.write(buffer, offset, length);
+        messageDigest.update(buffer, offset, length);
+    }
+
+    public byte[] calculateHash() {
+        return messageDigest.digest();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/LsbDataInputStream.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.util;
+
+import java.io.DataInput;
+import java.io.EOFException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public final class LsbDataInputStream extends FilterInputStream
+                                      implements DataInput {
+    public LsbDataInputStream(final InputStream is) {
+        super(is);
+    }
+
+    @Override
+    public void readFully(final byte[] buffer) throws IOException {
+        readFully(buffer, 0, buffer.length);
+    }
+
+    @Override
+    public void readFully(final byte[] buffer,
+                          final int offset,
+                          final int length) throws IOException {
+        int wrpos = offset;
+        int remaining = length;
+        while (remaining > 0) {
+            final int read = in.read(buffer, wrpos, remaining);
+            if (read == -1) {
+                throw new EOFException("No more data");
+            }
+
+            wrpos += read;
+            remaining -= read;
+        }
+    }
+
+    @Override
+    public int skipBytes(int n) throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public boolean readBoolean() throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public byte readByte() throws IOException {
+        final int value = in.read();
+        if (value == -1) {
+            throw new EOFException("No more data");
+        }
+        return (byte) value;
+    }
+
+    @Override
+    public int readUnsignedByte() throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public short readShort() throws IOException {
+        return (short) ((readByte() & 0xff) | (readByte() << 8));
+    }
+
+    @Override
+    public int readUnsignedShort() throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public char readChar() throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public int readInt() throws IOException {
+        return ((readByte() & 0xff) | ((readByte() & 0xff) << 8)
+                                    | ((readByte() & 0xff) << 16)
+                                    | ((readByte() << 24)));
+    }
+
+    @Override
+    public long readLong() throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public float readFloat() throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public double readDouble() throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public String readLine() throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public String readUTF() throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/LsbDataOutputStream.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.util;
+
+import java.io.DataOutput;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public final class LsbDataOutputStream extends FilterOutputStream
+                                       implements DataOutput {
+    public LsbDataOutputStream(final OutputStream os) {
+        super(os);
+    }
+
+    @Override
+    public void writeBoolean(boolean v) throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public void writeByte(final int value) throws IOException {
+        out.write(value);
+    }
+
+    @Override
+    public void writeShort(final int value) throws IOException {
+        writeByte(value);
+        writeByte(value >> 8);
+    }
+
+    @Override
+    public void writeChar(int v) throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public void writeInt(final int value) throws IOException {
+        writeByte(value);
+        writeByte(value >> 8);
+        writeByte(value >> 16);
+        writeByte(value >> 24);
+    }
+
+    @Override
+    public void writeLong(long v) throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public void writeFloat(float v) throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public void writeDouble(double v) throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public void writeBytes(String s) throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public void writeChars(String s) throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public void writeUTF(String s) throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/NullOutputStream.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.util;
+
+import java.io.OutputStream;
+
+public final class NullOutputStream extends OutputStream {
+
+    public void write(final int value) {
+    }
+
+    public void write(final byte buffer[]) {
+    }
+
+    public void write(final byte buffer[], final int offset, final int length) {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/PageHashingOutputStream.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.util;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Similar to HashingOutputStream, but calculates and stores a hash for each
+ * page of the input stream.
+ */
+public final class PageHashingOutputStream extends FilterOutputStream {
+    private final MessageDigest messageDigest;
+    private final List<byte[]> pageHashes;
+    private final int pageSize;
+
+    private int pageRemaining;
+
+    public PageHashingOutputStream(final OutputStream out) {
+        this(out, 4096);
+    }
+
+    public PageHashingOutputStream(final OutputStream out, final int pageSize) {
+        super(out);
+        try {
+            messageDigest = MessageDigest.getInstance("SHA1");
+        } catch (final NoSuchAlgorithmException e) {
+            throw new IllegalStateException("Can't create message digest", e);
+        }
+        pageHashes = new ArrayList<byte[]>();
+        this.pageSize = pageSize;
+        this.pageRemaining = pageSize;
+    }
+
+    public List<byte[]> getPageHashes() {
+        return Collections.unmodifiableList(pageHashes);
+    }
+
+    @Override
+    public void write(final int byteValue) throws IOException {
+        out.write(byteValue);
+        messageDigest.update((byte) byteValue);
+        --pageRemaining;
+        if (pageRemaining == 0) {
+            commitPageHashImpl();
+        }
+    }
+
+    @Override
+    public void write(final byte[] buffer, final int offset, final int length)
+            throws IOException {
+        out.write(buffer, offset, length);
+
+        int hashRemaining = length;
+        int hashOffset = offset;
+        while (hashRemaining > 0) {
+            final int chunkLength =
+                    (pageRemaining < hashRemaining) ? pageRemaining
+                                                    : hashRemaining;
+
+            messageDigest.update(buffer, hashOffset, chunkLength);
+
+            hashOffset += chunkLength;
+            hashRemaining -= chunkLength;
+            pageRemaining -= chunkLength;
+
+            if (pageRemaining == 0) {
+                commitPageHashImpl();
+            }
+        }
+    }
+
+    /**
+     * Creates a new page hash from the remaining data.
+     *
+     * If there are some data which haven't been included in the previous page
+     * hash, this methods adds a new page hash for them even if they don't
+     * fill up a complete page.
+     */
+    public void commitPageHash() {
+        if (pageRemaining != pageSize) {
+            // we do have some data for hashing
+            commitPageHashImpl();
+        }
+    }
+
+    private void commitPageHashImpl() {
+        pageHashes.add(messageDigest.digest());
+        pageRemaining = pageSize;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/ResourceDescriptor.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.util;
+
+import java.io.File;
+
+public final class ResourceDescriptor {
+    private final File baseDir;
+    private final File file;
+    private final String relativePath;
+
+    public ResourceDescriptor(final File baseDir, final String path) {
+        this(baseDir, createFile(baseDir, path));
+    }
+
+    public ResourceDescriptor(final File baseDir, final File file) {
+        final File nrmFile = normalizeFile(file);
+        if (nrmFile == null) {
+            throw new IllegalArgumentException("Invalid file specified");
+        }
+
+        if (baseDir != null) {
+            final File nrmBaseDir = normalizeFile(baseDir);
+            if (nrmBaseDir == null) {
+                throw new IllegalArgumentException("Invalid basedir specified");
+            }
+
+            if (nrmFile.equals(nrmBaseDir)) {
+                this.file = nrmFile;
+                this.baseDir = nrmFile;
+                this.relativePath = "";
+                return;
+            }
+
+            final StringBuilder relativePathBuilder =
+                    new StringBuilder(nrmFile.getName());
+
+            File tempFile = nrmFile.getParentFile();
+            while (tempFile != null) {
+                if (tempFile.equals(nrmBaseDir)) {
+                    this.file = nrmFile;
+                    this.baseDir = nrmBaseDir;
+                    this.relativePath = relativePathBuilder.toString();
+                    return;
+                }
+
+                relativePathBuilder.insert(0, '/');
+                relativePathBuilder.insert(0, tempFile.getName());
+                tempFile = tempFile.getParentFile();
+            }
+        }
+
+        final File nrmParentFile = nrmFile.getParentFile();
+
+        this.file = nrmFile;
+        this.baseDir = (nrmParentFile != null) ? nrmParentFile : nrmFile;
+        this.relativePath = nrmFile.getName();
+    }
+
+    public File getBaseDir() {
+        return baseDir;
+    }
+
+    public File getFile() {
+        return file;
+    }
+
+    public String getRelativePath() {
+        return relativePath;
+    }
+
+    private static File normalizeFile(final File inputFile) {
+        return normalizeFileImpl(inputFile.getAbsoluteFile());
+    }
+
+    private static File normalizeFileImpl(final File inputFile) {
+        if (inputFile.getParentFile() == null) {
+            return inputFile;
+        }
+
+        final File partiallyNormalizedFile =
+                normalizeFileImpl(inputFile.getParentFile());
+
+        if (partiallyNormalizedFile == null) {
+            // error
+            return null;
+        }
+
+        final String fileName = inputFile.getName();
+
+        if (fileName.equals(".")) {
+            // ignore this path element
+            return partiallyNormalizedFile;
+        }
+
+        if (fileName.equals("..")) {
+            // remove the last path element
+            return partiallyNormalizedFile.getParentFile();
+        }
+
+        return new File(partiallyNormalizedFile, fileName);
+    }
+
+    private static File createFile(final File baseDir, final String path) {
+        final File testFile = new File(path);
+        return testFile.isAbsolute()
+                   ? testFile
+                   : new File(baseDir == null
+                                  ? null
+                                  : baseDir.getAbsolutePath(),
+                              path);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/ipack/src/main/java/com/oracle/ipack/util/Util.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.ipack.util;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+public final class Util {
+    private static final char[] HEX_SYMBOLS = {
+            '0', '1', '2', '3', '4', '5', '6', '7',
+            '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+        };
+
+    private Util() {
+    }
+
+    public static String hex(final byte[] value) {
+        final char[] buffer = new char[value.length * 2];
+        for (int i = 0; i < value.length; ++i) {
+            Util.addHex8(buffer, i * 2, value[i]);
+        }
+        return String.valueOf(buffer);
+    }
+
+    public static String hex32(final int value) {
+        final char[] buffer = new char[8];
+        addHex32(buffer, 0, value);
+        return String.valueOf(buffer);
+    }
+
+    public static String hex16(final int value) {
+        final char[] buffer = new char[4];
+        addHex16(buffer, 0, value);
+        return String.valueOf(buffer);
+    }
+
+    public static String hex8(final int value) {
+        final char[] buffer = new char[2];
+        addHex8(buffer, 0, value);
+        return String.valueOf(buffer);
+    }
+
+    public static void dumpHex(final byte[] data) {
+        dumpHex(data, 0, data.length);
+    }
+
+    public static void dumpHex(final byte[] data,
+                               final int offset,
+                               final int length) {
+        final int fullLinesMax = offset + length & ~15;
+        int i;
+
+        for (i = offset; i < fullLinesMax; i += 16) {
+            dumpHexLine(data, i, 16);
+        }
+
+        if (i != (offset + length)) {
+            dumpHexLine(data, i, offset + length - i);
+        }
+    }
+
+    public static String readString(final DataInput dataInput,
+                                    final int numBytes) throws IOException {
+        final byte[] buffer = new byte[numBytes];
+        dataInput.readFully(buffer);
+        return new String(buffer);
+    }
+
+    public static String readString(final DataInput dataInput)
+            throws IOException {
+        final StringBuilder sb = new StringBuilder();
+        byte b;
+        while ((b = dataInput.readByte()) != 0) {
+            sb.append((char) (b & 0xff));
+        }
+
+        return sb.toString();
+    }
+
+    public static void writeString(final DataOutput dataOutput,
+                                   final String value,
+                                   final int size,
+                                   final char paddingChar)
+            throws IOException {
+        final byte[] valueBytes = value.getBytes();
+        final int numValueBytesToStore = (valueBytes.length < size)
+                                                 ? valueBytes.length
+                                                 : size;
+        dataOutput.write(valueBytes, 0, numValueBytesToStore);
+
+        if (numValueBytesToStore == size) {
+            return;
+        }
+
+        final byte paddingByte = (byte) paddingChar;
+        for (int i = size - numValueBytesToStore; i > 0; --i) {
+            dataOutput.writeByte(paddingByte);
+        }
+    }
+
+    public static void addHex32(final char[] buffer,
+                                final int offset,
+                                final int value) {
+        addHex16(buffer, offset, value >> 16);
+        addHex16(buffer, offset + 4, value);
+    }
+
+    public static void addHex16(final char[] buffer,
+                                final int offset,
+                                final int value) {
+        addHex8(buffer, offset, value >> 8);
+        addHex8(buffer, offset + 2, value);
+    }
+
+    public static void addHex8(final char[] buffer,
+                               final int offset,
+                               final int value) {
+        buffer[offset] = HEX_SYMBOLS[(value >> 4) & 0xf];
+        buffer[offset + 1] = HEX_SYMBOLS[value & 0xf];
+    }
+
+    private static void dumpHexLine(final byte[] data,
+                                    final int offset,
+                                    final int length) {
+        if (length > 0) {
+            final char[] lineBuffer = new char[length * 2 + length - 1];
+            addHex8(lineBuffer, 0, data[offset]);
+            for (int i = 1; i < length; ++i) {
+                lineBuffer[3 * i - 1] = ' ';
+                addHex8(lineBuffer, 3 * i, data[offset + i]);
+            }
+
+            System.out.print(String.valueOf(lineBuffer));
+        }
+        System.out.println();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/pom.xml	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.netbeans.ios</groupId>
+    <artifactId>Maven</artifactId>
+    <version>0.6-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    <name>Maven</name>
+  
+  <modules>        
+    <module>NetBeansMobileCenter</module>
+    <module>ios-maven-plugin</module>
+<!--    <module>test-simple-ipa</module> -->
+  </modules>  
+  
+  <properties>
+      <ios.maven.version>${project.version}</ios.maven.version>
+  </properties> 
+  
+  <dependencyManagement>
+      <dependencies>
+        <dependency>
+          <groupId>org.testng</groupId>
+          <artifactId>testng</artifactId>
+          <version>6.7</version>
+          <scope>test</scope>
+          <type>jar</type>
+          <exclusions>
+              <exclusion>
+                  <groupId>org.junit</groupId>
+                  <artifactId>junit</artifactId>
+              </exclusion>
+          </exclusions>
+        </dependency>
+      </dependencies>
+  </dependencyManagement>
+                   
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/test-simple-ipa/pom.xml	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.netbeans.ios</groupId>
+    <artifactId>Maven</artifactId>
+    <version>0.6-SNAPSHOT</version>
+  </parent>
+  <groupId>org.netbeans.ios</groupId>
+  <artifactId>test-simple-ipa</artifactId>
+  <version>0.6-SNAPSHOT</version>
+  <name>test-simple-ipa</name>
+  <url>http://maven.apache.org</url>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.testng</groupId>
+      <artifactId>testng</artifactId>
+    </dependency>
+  </dependencies>
+  <profiles>
+      <profile>
+          <id>build-ipa-on-mac</id>
+          <activation>
+              <os>
+                  <family>mac</family>
+              </os>
+          </activation>
+          <build>
+              <plugins>
+                  <plugin>
+                      <groupId>org.netbeans.ios</groupId>
+                      <artifactId>ios-maven-plugin</artifactId>
+                      <version>${ios.maven.version}</version>
+                      <executions>
+                          <execution>
+                              <id>before-test</id>
+                              <phase>generate-test-resources</phase>
+                              <goals>
+                                  <goal>build-IPA</goal>
+                              </goals>
+                          </execution>
+                      </executions>
+                      <configuration>
+                          <jarfile>${project.build.directory}/${project.build.finalName}.jar</jarfile>
+                          <title>${project.name}</title>
+                          <mainclass>org.netbeans.ios.test.simple.ipa.Main</mainclass>
+                      </configuration>
+                  </plugin>
+              </plugins>
+          </build>
+      </profile>
+  </profiles>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/test-simple-ipa/src/main/java/org/netbeans/ios/test/simple/ipa/Main.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+ package org.netbeans.ios.test.simple.ipa;
+
+public class Main {
+    public static void main( String[] args ) {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ios/Maven/test-simple-ipa/src/test/java/org/netbeans/ios/test/simple/ipa/VerifyIPATest.java	Tue Nov 05 13:27:04 2013 +0100
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.netbeans.ios.test.simple.ipa;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import org.testng.SkipException;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/** Checks that the IPA has been created on Mac.
+ *
+ * @author Jaroslav Tulach <jtulach@netbeans.org>
+ */
+public class VerifyIPATest {
+    private static File ipa;
+
+    @BeforeClass public static void findTheIPAFile() {
+        if (!System.getProperty("os.name").toLowerCase().contains("mac")) {
+            throw new SkipException("Can run only on Mac OS X!");
+        }
+
+        File baseDir = new File(System.getProperty("basedir"));
+        assertTrue(baseDir.isDirectory(), "Base dir exists: " + baseDir);
+        ipa = new File(new File(baseDir, "target"), "test-simple-ipa.ipa");
+        assertTrue(ipa.isFile(), "IPA file has been generated: " + ipa);
+    }
+
+    @Test public void verifyContent() throws IOException {
+        ZipFile zip = new ZipFile(ipa);
+        ZipEntry infoPList = zip.getEntry("Payload/test-simple-ipa.app/Info.plist");
+        assertNotNull(infoPList, "Info.pllist property found");
+    }
+}