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