]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.fastlz/src/org/simantics/fastlz/FastLZ.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.fastlz / src / org / simantics / fastlz / FastLZ.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.fastlz;\r
13 \r
14 import java.io.File;\r
15 import java.io.FileNotFoundException;\r
16 import java.io.FileOutputStream;\r
17 import java.io.IOException;\r
18 import java.io.InputStream;\r
19 import java.io.OutputStream;\r
20 import java.io.UnsupportedEncodingException;\r
21 import java.net.URL;\r
22 import java.net.URLDecoder;\r
23 import java.nio.ByteBuffer;\r
24 \r
25 import org.simantics.compressions.impl.Buffers;\r
26 import org.simantics.fastlz.impl.FastLZConfig;\r
27 import org.simantics.fastlz.impl.FastLZInputStream;\r
28 import org.simantics.fastlz.impl.FastLZOutputStream;\r
29 import org.simantics.fastlz.impl.OS;\r
30 import org.simantics.fastlz.java.FastLZJavaInputStream;\r
31 import org.simantics.fastlz.java.FastLZJavaOutputStream;\r
32 \r
33 /**\r
34  * @author Tuukka Lehtonen\r
35  */\r
36 @SuppressWarnings("resource")\r
37 public class FastLZ {\r
38 \r
39     private static boolean nativeInitialized = false;\r
40 \r
41     public static boolean isNativeInitialized() {\r
42         return nativeInitialized;\r
43     }\r
44 \r
45     private static boolean isNativeDisabled() {\r
46         return "false".equalsIgnoreCase(System.getProperty("fastlz.native", "true"));\r
47     }\r
48 \r
49     public synchronized static void initialize(File path) {\r
50         if (nativeInitialized || isNativeDisabled())\r
51             return;\r
52 \r
53 //        System.out.println("INITIALIZE FASTLZ: " + path);\r
54 \r
55         String osName = System.getProperty("os.name");\r
56         String osArch = System.getProperty("os.arch");\r
57         String lib = "fastlz";\r
58 \r
59         try {\r
60             if (path == null) {\r
61                 lib += OS.formOsArchSuffix();\r
62                 System.loadLibrary(lib);\r
63             } else {\r
64                 if (path.isDirectory()) {\r
65                     lib = System.mapLibraryName(lib + OS.formOsArchSuffix());\r
66                     lib = new File(path, lib).toString();\r
67                 } else if (path.isFile()) {\r
68                     lib = path.toString();\r
69                 } else {\r
70                     throw new IllegalArgumentException("Invalid path for FastLZ library: " + path);\r
71                 }\r
72                 try {\r
73                     System.load(lib);\r
74                 } catch (UnsatisfiedLinkError e) {\r
75                     String fallback = "fastlz";\r
76                     fallback += OS.formOsArchSuffix();\r
77                     System.loadLibrary(fallback);\r
78                 }\r
79             }\r
80             nativeInitialized = true;\r
81         } catch (UnsatisfiedLinkError e) {\r
82             System.err.println("Couldn't load library '" + lib + "' for os '" + osName + "' and architecture '" + osArch + "'");\r
83             e.printStackTrace();\r
84         }\r
85     }\r
86 \r
87     static {\r
88         if (!isNativeDisabled() && FastLZConfig.attemptStaticInitialization) {\r
89             String osName = System.getProperty("os.name");\r
90             String osArch = System.getProperty("os.arch");\r
91             String libName = OS.resolveLibName();\r
92             URL libURL = FastLZ.class.getResource("/" + libName);\r
93 //            System.out.println("FastLZ libURL: " + libURL);\r
94 //            System.out.println(".: " + FastLZ.class.getResource("."));\r
95 //            System.out.println("..: " + FastLZ.class.getResource("../../../" + resolveLibName()));\r
96 //            System.out.println("libname: " + FastLZ.class.getResource(resolveLibName()));\r
97 //            System.out.println("/libname: " + FastLZ.class.getResource("/" + resolveLibName()));\r
98 //            System.out.println("libname stream: " + FastLZ.class.getResourceAsStream(resolveLibName()));\r
99 //            System.out.println("/libname stream: " + FastLZ.class.getResourceAsStream("/" + resolveLibName()));\r
100             if (libURL != null) {\r
101                 if ("file".equals(libURL.getProtocol())) {\r
102                     try {\r
103                         File path = new File(URLDecoder.decode(libURL.getPath(), "UTF-8"));\r
104                         initialize(path);\r
105                     } catch (UnsupportedEncodingException e) {\r
106                         e.printStackTrace();\r
107                     }\r
108                 } else if ("jar".equals(libURL.getProtocol())) {\r
109                     try {\r
110                         File libFile = OS.extractLib(libURL, libName);\r
111                         initialize(libFile);\r
112                     } catch (FileNotFoundException e) {\r
113                         e.printStackTrace();\r
114                     } catch (IOException e) {\r
115                         e.printStackTrace();\r
116                     }\r
117                 } else {\r
118                     System.err.println("Unsupported URL protocol '" + libURL + "' for FastLZ native library file '" + libName + "' for os '" + osName + "' and architecture '" + osArch + "'");\r
119                 }\r
120             } else {\r
121                 initialize(null); // Final fallback. (Needed when running DB tests by ant script).\r
122             }\r
123         }\r
124     }\r
125 \r
126     /**\r
127      * The output buffer must be at least 5% larger than the input buffer and\r
128      * can not be smaller than 66 bytes.\r
129      * \r
130      * @param inputSize size of uncompressed input data in bytes\r
131      * @return maximum amount of bytes needed for the compressed data\r
132      */\r
133     public static int compressBound(int inputSize) {\r
134         return Math.max(66, inputSize + inputSize/20+1);\r
135     }\r
136 \r
137     /**\r
138      * Compress a block of data in the input buffer and returns the size of\r
139      * compressed block. The size of input buffer is specified by length. The\r
140      * minimum input buffer size is 16.\r
141      * \r
142      * <p>\r
143      * The output buffer must be at least 5% larger than the input buffer and\r
144      * can not be smaller than 66 bytes.\r
145      * \r
146      * <p>\r
147      * If the input is not compressible, the return value might be larger than\r
148      * length (input buffer size).\r
149      * \r
150      * <p>\r
151      * The input buffer and the output buffer can not overlap.\r
152      * \r
153      * <p>\r
154      * The input and output buffers are assumed to be direct byte buffers.\r
155      */\r
156     static native int compress(ByteBuffer input, int inputOffset, int length,\r
157             ByteBuffer output, int outputOffset);\r
158 \r
159     /**\r
160      * Decompress a block of compressed data and returns the size of the\r
161      * decompressed block. If error occurs, e.g. the compressed data is\r
162      * corrupted or the output buffer is not large enough, then 0 (zero) will be\r
163      * returned instead.\r
164      * \r
165      * <p>\r
166      * The input buffer and the output buffer can not overlap.\r
167      * \r
168      * <p>\r
169      * Decompression is memory safe and guaranteed not to write the output\r
170      * buffer more than what is specified in maxout.\r
171      * \r
172      * <p>\r
173      * The input and output buffers are assumed to be direct byte buffers.\r
174      */\r
175     static native int decompress(ByteBuffer input, int inputOffset, int length,\r
176             ByteBuffer output, int outputOffset, int maxout);\r
177 \r
178     /**\r
179      * Compress a block of data in the input buffer and returns the size of\r
180      * compressed block. The size of input buffer is specified by length. The\r
181      * minimum input buffer size is 16.\r
182      * \r
183      * <p>\r
184      * The output buffer must be at least 5% larger than the input buffer and\r
185      * can not be smaller than 66 bytes.\r
186      * \r
187      * <p>\r
188      * If the input is not compressible, the return value might be larger than\r
189      * length (input buffer size).\r
190      * \r
191      * <p>\r
192      * The input buffer and the output buffer can not overlap.\r
193      * \r
194      * <p>\r
195      * It is recommended to have both input buffers as direct or heap buffers,\r
196      * not mixed. Mixing different types of buffers will hurt performance a lot.\r
197      * If both buffers are direct byte buffers and native decompression is\r
198      * available, it will be employed.\r
199      */\r
200     public static int compressBuffer(ByteBuffer input, int inputOffset, int length,\r
201             ByteBuffer output, int outputOffset) {\r
202         if (output.isReadOnly())\r
203             throw new IllegalArgumentException("read-only output buffer");\r
204 \r
205         if (isNativeInitialized()) {\r
206             if (input.isDirect() && output.isDirect())\r
207                 return compress(input, inputOffset, length, output, outputOffset);\r
208         }\r
209 \r
210         byte[] inarr = Buffers.getInputArray(input);\r
211         byte[] outarr = Buffers.getOutputArray(output);\r
212         int result = FastLZJava.compress(inarr, inputOffset, length, outarr, outputOffset);\r
213         Buffers.writeOutput(output, outarr);\r
214         return result;\r
215     }\r
216 \r
217     /**\r
218      * Decompress a block of compressed data and returns the size of the\r
219      * decompressed block. If error occurs, e.g. the compressed data is\r
220      * corrupted or the output buffer is not large enough, then 0 (zero) will be\r
221      * returned instead.\r
222      * \r
223      * <p>\r
224      * The input buffer and the output buffer can not overlap.\r
225      * \r
226      * <p>\r
227      * Decompression is memory safe and guaranteed not to write the output\r
228      * buffer more than what is specified in maxout.\r
229      * \r
230      * <p>\r
231      * It is recommended to have both input buffers as direct or heap buffers,\r
232      * not mixed. Mixing different types of buffers will hurt performance a lot.\r
233      * If both buffers are direct byte buffers and native decompression is\r
234      * available, it will be employed.\r
235      */\r
236     public static int decompressBuffer(ByteBuffer input, int inputOffset, int length,\r
237             ByteBuffer output, int outputOffset, int maxout) {\r
238         if (output.isReadOnly())\r
239             throw new IllegalArgumentException("read-only output buffer");\r
240 \r
241         if (isNativeInitialized()) {\r
242             if (input.isDirect() && output.isDirect())\r
243                 return decompress(input, inputOffset, length, output, outputOffset, maxout);\r
244         }\r
245 \r
246         byte[] inarr = Buffers.getInputArray(input);\r
247         byte[] outarr = Buffers.getOutputArray(output);\r
248         int result = FastLZJava.decompress(inarr, inputOffset, length, outarr, outputOffset, maxout);\r
249         Buffers.writeOutput(output, outarr);\r
250         return result;\r
251     }\r
252 \r
253     /**\r
254      * @param file the FastLZ-compressed file to read\r
255      * @return input stream that decompresses its output using the FastLZ\r
256      *         algorithm. Caller is responsible of closing the returned stream.\r
257      * @throws FileNotFoundException see\r
258      *         {@link FileOutputStream#FileOutputStream(File)} for when this is\r
259      *         thrown\r
260      */\r
261     public static InputStream read(File file) throws FileNotFoundException {\r
262         return nativeInitialized ? new FastLZInputStream(file)\r
263                 : new FastLZJavaInputStream(file);\r
264     }\r
265 \r
266     /**\r
267      * @param input\r
268      * @return\r
269      * @param input\r
270      *            the input stream to decompress\r
271      * @return a stream that decompresses the specified FastLZ compressed input\r
272      *         stream\r
273      */\r
274     public static InputStream read(InputStream input) {\r
275         return nativeInitialized ? new FastLZInputStream(input)\r
276                 : new FastLZJavaInputStream(input);\r
277     }\r
278 \r
279     /**\r
280      * @param file the FastLZ-compressed file to write\r
281      * @return output stream that compresses its input using the FastLZ\r
282      *         algorithm. Caller is responsible of closing the returned stream.\r
283      * @throws FileNotFoundException see\r
284      *         {@link FileOutputStream#FileOutputStream(File)} for when this is\r
285      *         thrown\r
286      */\r
287     public static OutputStream write(File file) throws FileNotFoundException {\r
288         return nativeInitialized ? new FastLZOutputStream(file)\r
289                 : new FastLZJavaOutputStream(file);\r
290     }\r
291 \r
292     /**\r
293      * @param output\r
294      *            the stream to write compressed output into\r
295      * @return a stream that compresses into the specified output stream with\r
296      *         FastLZ\r
297      */\r
298     public static OutputStream write(OutputStream output) {\r
299         return nativeInitialized ? new FastLZOutputStream(output)\r
300                 : new FastLZJavaOutputStream(output);\r
301     }\r
302 \r
303     /**\r
304      * Warning: custom utility for performance reasons. Only used by\r
305      * org.simantics.db.procore. Do not use elsewhere.\r
306      * \r
307      * @param deflated\r
308      * @param deflatedSize\r
309      * @param inflatedSize\r
310      * @param arrays\r
311      * @return\r
312      */\r
313     public static synchronized native int decompressCluster(ByteBuffer deflated, int deflatedSize, int inflatedSize, Object[] arrays);\r
314 \r
315 }\r