From 0e723ff0866919cbc4ddfc3d7773c3485252eba3 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Thu, 24 Sep 2015 14:59:26 +0200 Subject: Bug 1231: Add Windows x86_64 test executable ; Use 'WinMain' for Windows test-executable ; Use CustomInflate for Performance - Use 'WinMain' for Windows test-executable This may have little difference than using std 'main' entry - Add Windows x86_64 test executable Since the reporter claims the test executable works well on Windows i386, maybe utilizing a x86_64 test executable on same VM fixes the issue - Use CustomInflate for Performance - Skips GZIP header - Adds own custom header [magic, deflate-size, inflate-size] - Own header allows simplified I/O read and deflation --- .../com/jogamp/common/util/CustomCompress.java | 121 +++++++++++++++++++++ src/java/com/jogamp/common/util/IOUtil.java | 63 +++++------ .../util/bin/exe-windows-i386-2048b.bin.316b.gz | Bin 316 -> 0 bytes .../jogamp/common/util/bin/exe-windows-i386.defl | Bin 0 -> 305 bytes .../jogamp/common/util/bin/exe-windows-x86_64.defl | Bin 0 -> 353 bytes .../com/jogamp/common/util/CustomDeflate.java | 115 ++++++++++++++++++++ .../com/jogamp/common/util/CustomInflate.java | 68 ++++++++++++ src/native/tinype/make.sh | 16 ++- src/native/tinype/tiny.c | 9 +- src/native/tinype/tiny2.c | 17 ++- 10 files changed, 366 insertions(+), 43 deletions(-) create mode 100644 src/java/com/jogamp/common/util/CustomCompress.java delete mode 100755 src/java/com/jogamp/common/util/bin/exe-windows-i386-2048b.bin.316b.gz create mode 100644 src/java/com/jogamp/common/util/bin/exe-windows-i386.defl create mode 100644 src/java/com/jogamp/common/util/bin/exe-windows-x86_64.defl create mode 100644 src/junit/com/jogamp/common/util/CustomDeflate.java create mode 100644 src/junit/com/jogamp/common/util/CustomInflate.java diff --git a/src/java/com/jogamp/common/util/CustomCompress.java b/src/java/com/jogamp/common/util/CustomCompress.java new file mode 100644 index 0000000..6850873 --- /dev/null +++ b/src/java/com/jogamp/common/util/CustomCompress.java @@ -0,0 +1,121 @@ +/** + * Copyright 2015 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.common.util; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +/** + * All in memory inflater / deflator for small chunks using streams + *

+ * Stream format for deflated data: + *

+ *

+ */ +public class CustomCompress { + public static final int MAGIC = 0xDEF1A7E0; + + public static byte[] inflateFromStream(final InputStream in) throws IOException { + final int inSize; + final int outSize; + { + final DataInputStream din = new DataInputStream(in); + final int _magic = din.readInt(); + if( _magic != MAGIC ) { + throw new IOException("wrong magic: "+Integer.toHexString(_magic)+", expected "+Integer.toHexString(MAGIC)); + } + inSize = din.readInt(); + outSize = din.readInt(); + } + if( 0 >= inSize ) { + throw new IOException("Invalid deflated-size "+inSize); + } + if( 0 >= outSize ) { + throw new IOException("Invalid inflated-size "+outSize); + } + final byte[] input = new byte[inSize]; + int numBytes = 0; + try { + while (true) { + final int remBytes = inSize - numBytes; + int count; + if ( 0 >= remBytes || (count = in.read(input, numBytes, remBytes)) == -1 ) { + break; + } + numBytes += count; + } + } finally { + in.close(); + } + if( inSize != numBytes ) { + throw new IOException("Got "+numBytes+" bytes != expected "+inSize); + } + final byte[] output = new byte[outSize]; + try { + final Inflater inflater = new Inflater(); + inflater.setInput(input, 0, inSize); + final int outSize2 = inflater.inflate(output, 0, outSize); + inflater.end(); + if( outSize != outSize2 ) { + throw new IOException("Got inflated "+outSize2+" bytes != expected "+outSize); + } + } catch(final DataFormatException dfe) { + throw new IOException(dfe); + } + return output; + } + + public static int deflateToStream(final byte[] input, final OutputStream out) throws IOException { + final byte[] output = new byte[input.length]; + final Deflater deflater = new Deflater(); + deflater.setInput(input, 0, input.length); + deflater.finish(); + final int outSize = deflater.deflate(output, 0, output.length); + deflater.end(); + { + final DataOutputStream dout = new DataOutputStream(out); + dout.writeInt(CustomCompress.MAGIC); + dout.writeInt(outSize); + dout.writeInt(input.length); + } + out.write(output, 0, outSize); + return outSize; + } + +} diff --git a/src/java/com/jogamp/common/util/IOUtil.java b/src/java/com/jogamp/common/util/IOUtil.java index 26e1f74..0638f11 100644 --- a/src/java/com/jogamp/common/util/IOUtil.java +++ b/src/java/com/jogamp/common/util/IOUtil.java @@ -48,7 +48,6 @@ import java.net.URL; import java.net.URLConnection; import java.nio.ByteBuffer; import java.util.regex.Pattern; -import java.util.zip.GZIPInputStream; import jogamp.common.Debug; import jogamp.common.os.AndroidUtils; @@ -706,52 +705,44 @@ public class IOUtil { return new String[] { scriptFile }; } } - private static final byte[] getBytesFromRelFile(final byte[] res, final String fname, final int iSize, final int dSize) throws IOException { + + private static final byte[] readCode(final String fname) throws IOException { final URLConnection con = IOUtil.getResource(IOUtil.class, fname); - final InputStream in = ( dSize > 0 && dSize < iSize ) ? - new GZIPInputStream(con.getInputStream(), dSize) : - con.getInputStream(); - int numBytes = 0; + final InputStream in = con.getInputStream(); + byte[] output = null; try { - while (true) { - final int remBytes = iSize - numBytes; - int count; - if ( 0 >= remBytes || (count = in.read(res, numBytes, remBytes)) == -1 ) { - break; - } - numBytes += count; - } + output = CustomCompress.inflateFromStream(in); } finally { in.close(); } - if( iSize != numBytes ) { - throw new IOException("Got "+numBytes+" bytes != expected "+iSize); - } - return res; + return output; } - private static final Object exeTestBytesLock = new Object(); - private static WeakReference exeTestBytesRef = null; + private static final Object exeTestLock = new Object(); + private static WeakReference exeTestCodeRef = null; private static void fillExeTestFile(final File exefile) throws IOException { if( Platform.OSType.WINDOWS == PlatformPropsImpl.OS_TYPE && Platform.CPUFamily.X86 == PlatformPropsImpl.CPU_ARCH.family ) { - final int gzipSize = 316; - final int codeSize = 2048; - final byte[] code; - synchronized ( exeTestBytesLock ) { - byte[] _code; - if( null == exeTestBytesRef || null == ( _code = exeTestBytesRef.get() ) ) { - // code = getBytesFromRelFile(new byte[codeSize], "bin/exe-windows-i386-2048b.bin", codeSize, 0); - code = getBytesFromRelFile(new byte[codeSize], "bin/exe-windows-i386-2048b.bin.316b.gz", codeSize, gzipSize); - exeTestBytesRef = new WeakReference(code); + final byte[] exeTestCode; + synchronized ( exeTestLock ) { + byte[] _exeTestCode = null; + if( null == exeTestCodeRef || null == ( _exeTestCode = exeTestCodeRef.get() ) ) { + final String fname; + if( Platform.CPUType.X86_64 == PlatformPropsImpl.CPU_ARCH ) { + fname = "bin/exe-windows-x86_64.defl"; + } else { + fname = "bin/exe-windows-i386.defl"; + } + exeTestCode = readCode(fname); + exeTestCodeRef = new WeakReference(exeTestCode); } else { - code = _code; + exeTestCode = _exeTestCode; } } final FileOutputStream out = new FileOutputStream(exefile); try { - out.write(code, 0, codeSize); + out.write(exeTestCode, 0, exeTestCode.length); try { out.getFD().sync(); } catch (final SyncFailedException sfe) { @@ -938,6 +929,7 @@ public class IOUtil { return false; } final long t1 = debug ? System.currentTimeMillis() : 0; + long t2; int res = -1; int exitValue = -1; if( existingExe || exeTestFile.setExecutable(true /* exec */, true /* ownerOnly */) ) { @@ -946,6 +938,7 @@ public class IOUtil { if( !existingExe ) { fillExeTestFile(exeTestFile); } + t2 = debug ? System.currentTimeMillis() : 0; // Using 'Process.exec(String[])' avoids StringTokenizer of 'Process.exec(String)' // and hence splitting up command by spaces! // Note: All no-exec cases throw an IOExceptions at ProcessBuilder.start(), i.e. below exec() call! @@ -959,6 +952,7 @@ public class IOUtil { } catch (final SecurityException se) { throw se; // fwd Security exception } catch (final Throwable t) { + t2 = debug ? System.currentTimeMillis() : 0; res = -2; if( debug ) { System.err.println("IOUtil.testDirExec: <"+exeTestFile.getAbsolutePath()+">: Caught "+t.getClass().getSimpleName()+": "+t.getMessage()); @@ -976,16 +970,19 @@ public class IOUtil { } } } + } else { + t2 = debug ? System.currentTimeMillis() : 0; } + final boolean ok = 0 == res; if( !DEBUG_EXE && !existingExe ) { exeTestFile.delete(); } if( debug ) { - final long t2 = System.currentTimeMillis(); + final long t3 = System.currentTimeMillis(); System.err.println("IOUtil.testDirExec(): test-exe <"+exeTestFile.getAbsolutePath()+">, existingFile "+existingExe+", returned "+exitValue); System.err.println("IOUtil.testDirExec(): abs-path <"+dir.getAbsolutePath()+">: res "+res+" -> "+ok); - System.err.println("IOUtil.testDirExec(): total "+(t2-t0)+"ms, create "+(t1-t0)+"ms, execute "+(t2-t1)+"ms"); + System.err.println("IOUtil.testDirExec(): total "+(t3-t0)+"ms, create "+(t1-t0)+"ms, fill "+(t2-t1)+"ms, execute "+(t3-t2)+"ms"); } return ok; } diff --git a/src/java/com/jogamp/common/util/bin/exe-windows-i386-2048b.bin.316b.gz b/src/java/com/jogamp/common/util/bin/exe-windows-i386-2048b.bin.316b.gz deleted file mode 100755 index e070061..0000000 Binary files a/src/java/com/jogamp/common/util/bin/exe-windows-i386-2048b.bin.316b.gz and /dev/null differ diff --git a/src/java/com/jogamp/common/util/bin/exe-windows-i386.defl b/src/java/com/jogamp/common/util/bin/exe-windows-i386.defl new file mode 100644 index 0000000..9e68aea Binary files /dev/null and b/src/java/com/jogamp/common/util/bin/exe-windows-i386.defl differ diff --git a/src/java/com/jogamp/common/util/bin/exe-windows-x86_64.defl b/src/java/com/jogamp/common/util/bin/exe-windows-x86_64.defl new file mode 100644 index 0000000..e4b8d8d Binary files /dev/null and b/src/java/com/jogamp/common/util/bin/exe-windows-x86_64.defl differ diff --git a/src/junit/com/jogamp/common/util/CustomDeflate.java b/src/junit/com/jogamp/common/util/CustomDeflate.java new file mode 100644 index 0000000..876c6e4 --- /dev/null +++ b/src/junit/com/jogamp/common/util/CustomDeflate.java @@ -0,0 +1,115 @@ +/** + * Copyright 2015 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.common.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class CustomDeflate { + public static void main(final String[] args) { + if (args.length != 2) { + System.err.println("Usage: java "+CustomDeflate.class.getName()+" file-in file-out"); + } else { + final File fileIn = new File(args[0]); + final File fileOut = new File(args[1]); + final int inSize; + { + final long _inSize = fileIn.length(); + if( 0 >= _inSize || _inSize > Integer.MAX_VALUE ) { + throw new IllegalArgumentException(""); + } + inSize = (int) _inSize; + } + final byte[] input = new byte[inSize]; + InputStream in = null; + OutputStream out = null; + try { + in = new FileInputStream(fileIn); + int numBytes = 0; + try { + while (true) { + final int remBytes = inSize - numBytes; + int count; + if ( 0 >= remBytes || (count = in.read(input, numBytes, remBytes)) == -1 ) { + break; + } + numBytes += count; + } + } finally { + in.close(); + } + if( inSize != numBytes ) { + throw new IOException("Got "+numBytes+" bytes != expected "+inSize); + } + out = new FileOutputStream(fileOut); + CustomCompress.deflateToStream(input, out); + } catch (final IOException ioe) { + ioe.printStackTrace(); + } finally { + if( null != in ) { + try { in.close(); } catch (final IOException e) { } + } + if( null != out ) { + try { out.close(); } catch (final IOException e) { } + } + } + + // + // Test + // + in = null; + out = null; + try { + in = new FileInputStream(fileOut); + final byte[] compare = CustomCompress.inflateFromStream(in); + if( compare.length != inSize ) { + throw new InternalError("Inflated Size Mismatch: Has "+compare.length+", expected "+inSize); + } + for(int i=0; i tiny-win32-i386.exe.gz +java -cp "$jardir/test/build/gluegen-test.jar;$jardir/gluegen-rt.jar" com.jogamp.common.util.CustomDeflate tiny-win32-i386.exe exe-windows-i386.defl -#/cygdrive/c/mingw64/bin/gcc -nodefaultlibs -nostdlib -s -Os -mwindows -o tiny-win32-x86_64.exe tiny.c -#gzip -9 -c tiny-win32-x86_64.exe > tiny-win32-x86_64.exe.gz +/cygdrive/c/mingw64/bin/gcc -nodefaultlibs -nostdlib -s -Os -mwindows -o tiny-win32-x86_64.exe tiny.c +java -cp "$jardir/test/build/gluegen-test.jar;$jardir/gluegen-rt.jar" com.jogamp.common.util.CustomDeflate tiny-win32-x86_64.exe exe-windows-x86_64.defl diff --git a/src/native/tinype/tiny.c b/src/native/tinype/tiny.c index 80f9518..6d2de3a 100644 --- a/src/native/tinype/tiny.c +++ b/src/native/tinype/tiny.c @@ -1,6 +1,13 @@ +#undef UNICODE +#define UNICODE +#include + // const char * id = "JogAmp Windows Universal Test PE Executable"; -int __main() +// int __main() +// int main() +// int main( int argc, char* argv[] ) +int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { return 0; } diff --git a/src/native/tinype/tiny2.c b/src/native/tinype/tiny2.c index d24c287..6330911 100644 --- a/src/native/tinype/tiny2.c +++ b/src/native/tinype/tiny2.c @@ -1,8 +1,15 @@ -#include -const char * id = "JogAmp Windows Universal Test PE Executable"; +#undef UNICODE +#define UNICODE +#include -int main() +const wchar_t * id = L"JogAmp Windows Universal Test PE Executable"; +const wchar_t * cap = L"JogAmp"; + +// int __main() +// int main() +// int main( int argc, char* argv[] ) +int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { - fprintf(stderr, "%s\n", id); - return 42; + MessageBox(0, id, cap, MB_SETFOREGROUND | MB_OK); + return 0; } -- cgit v1.2.3