1 /*--------------------------------------------------------------------------
2  *  Copyright 2011 Taro L. Saito
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  *--------------------------------------------------------------------------*/
16 //--------------------------------------
17 // snappy-java Project
18 //
19 // Snappy.java
20 // Since: 2011/03/29
21 //
22 // $URL$
23 // $Author$
24 //--------------------------------------
25 package org.xerial.snappy;
26 
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.UnsupportedEncodingException;
30 import java.net.URL;
31 import java.nio.ByteBuffer;
32 import java.nio.charset.Charset;
33 import java.util.Properties;
34 
35 /**
36  * Snappy API for data compression/decompression
37  * <p/>
38  * Note: if the native libraries cannot be loaded, an ExceptionInInitializerError
39  * will be thrown at first use of this class.
40  *
41  * @author Taro L. Saito
42  */
43 public class Snappy
44 {
45     static {
46         try {
47             impl = SnappyLoader.loadSnappyApi();
48         }
49         catch (Exception e) {
50             throw new ExceptionInInitializerError(e);
51         }
52     }
53 
54     /**
55      * An instance of SnappyNative
56      */
57     private static SnappyNative impl;
58 
59     /**
60      * Clean up a temporary file (native lib) generated by snappy-java.
61      * General users do not need to call this method, since the native library extracted in snappy-java
62      * is deleted upon JVM termination (vie deleteOnExit()).
63      * This method is useful when using a J2EE container, which will restart servlet containers multiple times without
64      * restarting JVM.
65      */
cleanUp()66     public static void cleanUp()
67     {
68         SnappyLoader.cleanUpExtractedNativeLib();
69         SnappyLoader.setSnappyApi(null);
70     }
71 
72     /**
73      * Copy bytes from source to destination
74      *
75      * @param src pointer to the source array
76      * @param offset byte offset in the source array
77      * @param byteLength the number of bytes to copy
78      * @param dest pointer to the destination array
79      * @param dest_offset byte offset in the destination array
80      * @throws IOException
81      */
arrayCopy(Object src, int offset, int byteLength, Object dest, int dest_offset)82     public static void arrayCopy(Object src, int offset, int byteLength, Object dest, int dest_offset)
83             throws IOException
84     {
85         impl.arrayCopy(src, offset, byteLength, dest, dest_offset);
86     }
87 
88     /**
89      * High-level API for compressing the input byte array. This method performs
90      * array copy to generate the result. If you want to reduce the memory copy
91      * cost, use {@link #compress(byte[], int, int, byte[], int)} or
92      * {@link #compress(ByteBuffer, ByteBuffer)}.
93      *
94      * @param input the input data
95      * @return the compressed byte array
96      * @throws IOException
97      */
compress(byte[] input)98     public static byte[] compress(byte[] input)
99             throws IOException
100     {
101         return rawCompress(input, input.length);
102     }
103 
104     /**
105      * Compress the input buffer content in [inputOffset,
106      * ...inputOffset+inputLength) then output to the specified output buffer.
107      *
108      * @param input
109      * @param inputOffset
110      * @param inputLength
111      * @param output
112      * @param outputOffset
113      * @return byte size of the compressed data
114      * @throws IOException when failed to access the input/output buffer
115      */
compress(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset)116     public static int compress(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset)
117             throws IOException
118     {
119         return rawCompress(input, inputOffset, inputLength, output, outputOffset);
120     }
121 
122     /**
123      * Compress the content in the given input buffer. After the compression,
124      * you can retrieve the compressed data from the output buffer [pos() ...
125      * limit()) (compressed data size = limit() - pos() = remaining())
126      *
127      * @param uncompressed buffer[pos() ... limit()) containing the input data
128      * @param compressed output of the compressed data. Uses range [pos()..].
129      * @return byte size of the compressed data.
130      * @throws SnappyError when the input is not a direct buffer
131      */
compress(ByteBuffer uncompressed, ByteBuffer compressed)132     public static int compress(ByteBuffer uncompressed, ByteBuffer compressed)
133             throws IOException
134     {
135 
136         if (!uncompressed.isDirect()) {
137             throw new SnappyError(SnappyErrorCode.NOT_A_DIRECT_BUFFER, "input is not a direct buffer");
138         }
139         if (!compressed.isDirect()) {
140             throw new SnappyError(SnappyErrorCode.NOT_A_DIRECT_BUFFER, "destination is not a direct buffer");
141         }
142 
143         // input: uncompressed[pos(), limit())
144         // output: compressed
145         int uPos = uncompressed.position();
146         int uLen = uncompressed.remaining();
147         int compressedSize = impl.rawCompress(uncompressed, uPos, uLen, compressed,
148                 compressed.position());
149 
150         //         pos  limit
151         // [ ......BBBBBBB.........]
152         compressed.limit(compressed.position() + compressedSize);
153 
154         return compressedSize;
155     }
156 
157     /**
158      * Compress the input char array
159      *
160      * @param input
161      * @return the compressed data
162      */
compress(char[] input)163     public static byte[] compress(char[] input)
164             throws IOException
165     {
166         return rawCompress(input, input.length * 2); // char uses 2 bytes
167     }
168 
169     /**
170      * Compress the input double array
171      *
172      * @param input
173      * @return the compressed data
174      */
compress(double[] input)175     public static byte[] compress(double[] input)
176             throws IOException
177     {
178         return rawCompress(input, input.length * 8); // double uses 8 bytes
179     }
180 
181     /**
182      * Compress the input float array
183      *
184      * @param input
185      * @return the compressed data
186      */
compress(float[] input)187     public static byte[] compress(float[] input)
188             throws IOException
189     {
190         return rawCompress(input, input.length * 4); // float uses 4 bytes
191     }
192 
193     /**
194      * Compress the input int array
195      *
196      * @param input
197      * @return the compressed data
198      */
compress(int[] input)199     public static byte[] compress(int[] input)
200             throws IOException
201     {
202         return rawCompress(input, input.length * 4); // int uses 4 bytes
203     }
204 
205     /**
206      * Compress the input long array
207      *
208      * @param input
209      * @return the compressed data
210      */
compress(long[] input)211     public static byte[] compress(long[] input)
212             throws IOException
213     {
214         return rawCompress(input, input.length * 8); // long uses 8 bytes
215     }
216 
217     /**
218      * Compress the input short array
219      *
220      * @param input
221      * @return the compressed data
222      */
compress(short[] input)223     public static byte[] compress(short[] input)
224             throws IOException
225     {
226         return rawCompress(input, input.length * 2); // short uses 2 bytes
227     }
228 
229     /**
230      * Compress the input String
231      *
232      * @param s
233      * @return the compressed data
234      * @throws IOException
235      */
compress(String s)236     public static byte[] compress(String s)
237             throws IOException
238     {
239         try {
240             return compress(s, "UTF-8");
241         }
242         catch (UnsupportedEncodingException e) {
243             throw new IllegalStateException("UTF-8 encoder is not found");
244         }
245     }
246 
247     /**
248      * Compress the input string using the given encoding
249      *
250      * @param s
251      * @param encoding
252      * @return the compressed data
253      * @throws UnsupportedEncodingException
254      * @throws IOException
255      */
compress(String s, String encoding)256     public static byte[] compress(String s, String encoding)
257             throws UnsupportedEncodingException, IOException
258     {
259         byte[] data = s.getBytes(encoding);
260         return compress(data);
261     }
262 
263     /**
264      * Compress the input string using the given encoding
265      *
266      * @param s
267      * @param encoding
268      * @return the compressed data
269      * @throws UnsupportedEncodingException
270      * @throws IOException
271      */
compress(String s, Charset encoding)272     public static byte[] compress(String s, Charset encoding)
273             throws IOException
274     {
275         byte[] data = s.getBytes(encoding);
276         return compress(data);
277     }
278 
279     /**
280      * Get the native library version of the snappy
281      *
282      * @return native library version
283      */
getNativeLibraryVersion()284     public static String getNativeLibraryVersion()
285     {
286         URL versionFile = SnappyLoader.class.getResource("/org/xerial/snappy/VERSION");
287 
288         String version = "unknown";
289         try {
290             if (versionFile != null) {
291                 InputStream in = null;
292                 try {
293                     Properties versionData = new Properties();
294                     in = versionFile.openStream();
295                     versionData.load(in);
296                     version = versionData.getProperty("version", version);
297                     if (version.equals("unknown")) {
298                         version = versionData.getProperty("SNAPPY_VERSION", version);
299                     }
300                     version = version.trim().replaceAll("[^0-9\\.]", "");
301                 }
302                 finally {
303                     if(in != null) {
304                         in.close();
305                     }
306                 }
307             }
308         }
309         catch (IOException e) {
310             e.printStackTrace();
311         }
312         return version;
313     }
314 
315     /**
316      * Returns true iff the contents of compressed buffer [offset,
317      * offset+length) can be uncompressed successfully. Does not return the
318      * uncompressed data. Takes time proportional to the input length, but is
319      * usually at least a factor of four faster than actual decompression.
320      */
isValidCompressedBuffer(byte[] input, int offset, int length)321     public static boolean isValidCompressedBuffer(byte[] input, int offset, int length)
322             throws IOException
323     {
324         if (input == null) {
325             throw new NullPointerException("input is null");
326         }
327         return impl.isValidCompressedBuffer(input, offset, length);
328     }
329 
330     /**
331      * Returns true iff the contents of compressed buffer [offset,
332      * offset+length) can be uncompressed successfully. Does not return the
333      * uncompressed data. Takes time proportional to the input length, but is
334      * usually at least a factor of four faster than actual decompression.
335      */
isValidCompressedBuffer(byte[] input)336     public static boolean isValidCompressedBuffer(byte[] input)
337             throws IOException
338     {
339         return isValidCompressedBuffer(input, 0, input.length);
340     }
341 
342     /**
343      * Returns true iff the contents of compressed buffer [pos() ... limit())
344      * can be uncompressed successfully. Does not return the uncompressed data.
345      * Takes time proportional to the input length, but is usually at least a
346      * factor of four faster than actual decompression.
347      */
isValidCompressedBuffer(ByteBuffer compressed)348     public static boolean isValidCompressedBuffer(ByteBuffer compressed)
349             throws IOException
350     {
351         return impl.isValidCompressedBuffer(compressed, compressed.position(),
352                 compressed.remaining());
353     }
354 
355     /**
356      * Returns true iff the contents of compressed buffer [offset,
357      * offset+length) can be uncompressed successfully. Does not return the
358      * uncompressed data. Takes time proportional to the input length, but is
359      * usually at least a factor of four faster than actual decompression.
360      */
isValidCompressedBuffer(long inputAddr, long offset, long length)361     public static boolean isValidCompressedBuffer(long inputAddr, long offset, long length)
362             throws IOException
363     {
364         return impl.isValidCompressedBuffer(inputAddr, offset, length);
365     }
366 
367     /**
368      * Get the maximum byte size needed for compressing data of the given byte
369      * size.
370      *
371      * @param byteSize byte size of the data to compress
372      * @return maximum byte size of the compressed data
373      */
maxCompressedLength(int byteSize)374     public static int maxCompressedLength(int byteSize)
375     {
376         return impl.maxCompressedLength(byteSize);
377     }
378 
379     /**
380      * Zero-copy compress using memory addresses.
381      *
382      * @param inputAddr input memory address
383      * @param inputSize input byte size
384      * @param destAddr destination address of the compressed data
385      * @return the compressed data size
386      * @throws IOException
387      */
rawCompress(long inputAddr, long inputSize, long destAddr)388     public static long rawCompress(long inputAddr, long inputSize, long destAddr)
389             throws IOException
390     {
391         return impl.rawCompress(inputAddr, inputSize, destAddr);
392     }
393 
394     /**
395      * Zero-copy decompress using memory addresses.
396      *
397      * @param inputAddr input memory address
398      * @param inputSize input byte size
399      * @param destAddr destination address of the uncompressed data
400      * @return the uncompressed data size
401      * @throws IOException
402      */
rawUncompress(long inputAddr, long inputSize, long destAddr)403     public static long rawUncompress(long inputAddr, long inputSize, long destAddr)
404             throws IOException
405     {
406         return impl.rawUncompress(inputAddr, inputSize, destAddr);
407     }
408 
409     /**
410      * Compress the input data and produce a byte array of the uncompressed data
411      *
412      * @param data input array. The input MUST be an array type
413      * @param byteSize the input byte size
414      * @return compressed data
415      */
rawCompress(Object data, int byteSize)416     public static byte[] rawCompress(Object data, int byteSize)
417             throws IOException
418     {
419         byte[] buf = new byte[Snappy.maxCompressedLength(byteSize)];
420         int compressedByteSize = impl.rawCompress(data, 0, byteSize, buf, 0);
421         byte[] result = new byte[compressedByteSize];
422         System.arraycopy(buf, 0, result, 0, compressedByteSize);
423         return result;
424     }
425 
426     /**
427      * Compress the input buffer [offset,... ,offset+length) contents, then
428      * write the compressed data to the output buffer[offset, ...)
429      *
430      * @param input input array. This MUST be a primitive array type
431      * @param inputOffset byte offset at the output array
432      * @param inputLength byte length of the input data
433      * @param output output array. This MUST be a primitive array type
434      * @param outputOffset byte offset at the output array
435      * @return byte size of the compressed data
436      * @throws IOException
437      */
rawCompress(Object input, int inputOffset, int inputLength, byte[] output, int outputOffset)438     public static int rawCompress(Object input, int inputOffset, int inputLength, byte[] output, int outputOffset)
439             throws IOException
440     {
441         if (input == null || output == null) {
442             throw new NullPointerException("input or output is null");
443         }
444 
445         int compressedSize = impl
446                 .rawCompress(input, inputOffset, inputLength, output, outputOffset);
447         return compressedSize;
448     }
449 
450     /**
451      * Uncompress the content in the input buffer. The uncompressed data is
452      * written to the output buffer.
453      * <p/>
454      * Note that if you pass the wrong data or the range [inputOffset,
455      * inputOffset + inputLength) that cannot be uncompressed, your JVM might
456      * crash due to the access violation exception issued in the native code
457      * written in C++. To avoid this type of crash, use
458      * {@link #isValidCompressedBuffer(byte[], int, int)} first.
459      *
460      * @param input input byte array
461      * @param inputOffset byte offset in the input byte array
462      * @param inputLength byte length of the input data
463      * @param output output buffer, MUST be a primitive type array
464      * @param outputOffset byte offset in the output buffer
465      * @return the byte size of the uncompressed data
466      * @throws IOException when failed to uncompress the input data
467      */
rawUncompress(byte[] input, int inputOffset, int inputLength, Object output, int outputOffset)468     public static int rawUncompress(byte[] input, int inputOffset, int inputLength, Object output, int outputOffset)
469             throws IOException
470     {
471         if (input == null || output == null) {
472             throw new NullPointerException("input or output is null");
473         }
474         return impl.rawUncompress(input, inputOffset, inputLength, output, outputOffset);
475     }
476 
477     /**
478      * High-level API for uncompressing the input byte array.
479      *
480      * @param input
481      * @return the uncompressed byte array
482      * @throws IOException
483      */
uncompress(byte[] input)484     public static byte[] uncompress(byte[] input)
485             throws IOException
486     {
487         byte[] result = new byte[Snappy.uncompressedLength(input)];
488         Snappy.uncompress(input, 0, input.length, result, 0);
489         return result;
490     }
491 
492     /**
493      * Uncompress the content in the input buffer. The uncompressed data is
494      * written to the output buffer.
495      * <p/>
496      * Note that if you pass the wrong data or the range [inputOffset,
497      * inputOffset + inputLength) that cannot be uncompressed, your JVM might
498      * crash due to the access violation exception issued in the native code
499      * written in C++. To avoid this type of crash, use
500      * {@link #isValidCompressedBuffer(byte[], int, int)} first.
501      *
502      * @param input
503      * @param inputOffset
504      * @param inputLength
505      * @param output
506      * @param outputOffset
507      * @return the byte size of the uncompressed data
508      * @throws IOException
509      */
uncompress(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset)510     public static int uncompress(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset)
511             throws IOException
512     {
513         return rawUncompress(input, inputOffset, inputLength, output, outputOffset);
514     }
515 
516     /**
517      * Uncompress the content in the input buffer. The result is dumped to the
518      * specified output buffer.
519      * <p/>
520      * Note that if you pass the wrong data or the range [pos(), limit()) that
521      * cannot be uncompressed, your JVM might crash due to the access violation
522      * exception issued in the native code written in C++. To avoid this type of
523      * crash, use {@link #isValidCompressedBuffer(ByteBuffer)} first.
524      *
525      * @param compressed buffer[pos() ... limit()) containing the input data
526      * @param uncompressed output of the the uncompressed data. It uses buffer[pos()..]
527      * @return uncompressed data size
528      * @throws IOException when failed to uncompress the given input
529      * @throws SnappyError when the input is not a direct buffer
530      */
uncompress(ByteBuffer compressed, ByteBuffer uncompressed)531     public static int uncompress(ByteBuffer compressed, ByteBuffer uncompressed)
532             throws IOException
533     {
534 
535         if (!compressed.isDirect()) {
536             throw new SnappyError(SnappyErrorCode.NOT_A_DIRECT_BUFFER, "input is not a direct buffer");
537         }
538         if (!uncompressed.isDirect()) {
539             throw new SnappyError(SnappyErrorCode.NOT_A_DIRECT_BUFFER, "destination is not a direct buffer");
540         }
541 
542         int cPos = compressed.position();
543         int cLen = compressed.remaining();
544 
545         //         pos  limit
546         // [ ......UUUUUU.........]
547         int decompressedSize = impl.rawUncompress(compressed, cPos, cLen, uncompressed,
548                 uncompressed.position());
549         uncompressed.limit(uncompressed.position() + decompressedSize);
550 
551         return decompressedSize;
552     }
553 
554     /**
555      * Uncompress the input data as char array
556      *
557      * @param input
558      * @return the uncompressed data
559      * @throws IOException
560      */
uncompressCharArray(byte[] input)561     public static char[] uncompressCharArray(byte[] input)
562             throws IOException
563     {
564         return uncompressCharArray(input, 0, input.length);
565     }
566 
567     /**
568      * Uncompress the input[offset, .., offset+length) as a char array
569      *
570      * @param input
571      * @param offset
572      * @param length
573      * @return the uncompressed data
574      * @throws IOException
575      */
uncompressCharArray(byte[] input, int offset, int length)576     public static char[] uncompressCharArray(byte[] input, int offset, int length)
577             throws IOException
578     {
579         int uncompressedLength = Snappy.uncompressedLength(input, offset, length);
580         char[] result = new char[uncompressedLength / 2];
581         impl.rawUncompress(input, offset, length, result, 0);
582         return result;
583     }
584 
585     /**
586      * Uncompress the input as a double array
587      *
588      * @param input
589      * @return the uncompressed data
590      * @throws IOException
591      */
uncompressDoubleArray(byte[] input)592     public static double[] uncompressDoubleArray(byte[] input)
593             throws IOException
594     {
595         int uncompressedLength = Snappy.uncompressedLength(input, 0, input.length);
596         double[] result = new double[uncompressedLength / 8];
597         impl.rawUncompress(input, 0, input.length, result, 0);
598         return result;
599     }
600 
601     /**
602      * Get the uncompressed byte size of the given compressed input. This
603      * operation takes O(1) time.
604      *
605      * @param input
606      * @return uncompressed byte size of the the given input data
607      * @throws IOException when failed to uncompress the given input. The error code is
608      * {@link SnappyErrorCode#PARSING_ERROR}
609      */
uncompressedLength(byte[] input)610     public static int uncompressedLength(byte[] input)
611             throws IOException
612     {
613         return impl.uncompressedLength(input, 0, input.length);
614     }
615 
616     /**
617      * Get the uncompressed byte size of the given compressed input. This
618      * operation takes O(1) time.
619      *
620      * @param input
621      * @param offset
622      * @param length
623      * @return uncompressed byte size of the the given input data
624      * @throws IOException when failed to uncompress the given input. The error code is
625      * {@link SnappyErrorCode#PARSING_ERROR}
626      */
uncompressedLength(byte[] input, int offset, int length)627     public static int uncompressedLength(byte[] input, int offset, int length)
628             throws IOException
629     {
630         if (input == null) {
631             throw new NullPointerException("input is null");
632         }
633 
634         return impl.uncompressedLength(input, offset, length);
635     }
636 
637     /**
638      * Get the uncompressed byte size of the given compressed input. This
639      * operation takes O(1) time.
640      *
641      * @param compressed input data [pos() ... limit())
642      * @return uncompressed byte length of the given input
643      * @throws IOException when failed to uncompress the given input. The error code is
644      * {@link SnappyErrorCode#PARSING_ERROR}
645      * @throws SnappyError when the input is not a direct buffer
646      */
uncompressedLength(ByteBuffer compressed)647     public static int uncompressedLength(ByteBuffer compressed)
648             throws IOException
649     {
650         if (!compressed.isDirect()) {
651             throw new SnappyError(SnappyErrorCode.NOT_A_DIRECT_BUFFER, "input is not a direct buffer");
652         }
653 
654         return impl.uncompressedLength(compressed, compressed.position(), compressed.remaining());
655     }
656 
657     /**
658      * Get the uncompressed byte size of the given compressed input. This operation takes O(1) time.
659      *
660      * @param inputAddr compressed data address
661      * @param len byte length of the input
662      * @return uncompressed byte length of the given input
663      * @throws IOException when failed to uncompress the given input. The error code is
664      * {@link SnappyErrorCode#PARSING_ERROR}
665      */
uncompressedLength(long inputAddr, long len)666     public static long uncompressedLength(long inputAddr, long len)
667             throws IOException
668     {
669         return impl.uncompressedLength(inputAddr, len);
670     }
671 
672     /**
673      * Uncompress the input as a float array
674      *
675      * @param input
676      * @return the uncompressed data
677      * @throws IOException
678      */
uncompressFloatArray(byte[] input)679     public static float[] uncompressFloatArray(byte[] input)
680             throws IOException
681     {
682         return uncompressFloatArray(input, 0, input.length);
683     }
684 
685     /**
686      * Uncompress the input[offset, offset+length) as a float array
687      *
688      * @param input
689      * @param offset
690      * @param length
691      * @return the uncompressed data
692      * @throws IOException
693      */
uncompressFloatArray(byte[] input, int offset, int length)694     public static float[] uncompressFloatArray(byte[] input, int offset, int length)
695             throws IOException
696     {
697         int uncompressedLength = Snappy.uncompressedLength(input, offset, length);
698         float[] result = new float[uncompressedLength / 4];
699         impl.rawUncompress(input, offset, length, result, 0);
700         return result;
701     }
702 
703     /**
704      * Uncompress the input data as an int array
705      *
706      * @param input
707      * @return the uncompressed data
708      * @throws IOException
709      */
uncompressIntArray(byte[] input)710     public static int[] uncompressIntArray(byte[] input)
711             throws IOException
712     {
713         return uncompressIntArray(input, 0, input.length);
714     }
715 
716     /**
717      * Uncompress the input[offset, offset+length) as an int array
718      *
719      * @param input
720      * @param offset
721      * @param length
722      * @return the uncompressed data
723      * @throws IOException
724      */
uncompressIntArray(byte[] input, int offset, int length)725     public static int[] uncompressIntArray(byte[] input, int offset, int length)
726             throws IOException
727     {
728         int uncompressedLength = Snappy.uncompressedLength(input, offset, length);
729         int[] result = new int[uncompressedLength / 4];
730         impl.rawUncompress(input, offset, length, result, 0);
731         return result;
732     }
733 
734     /**
735      * Uncompress the input data as a long array
736      *
737      * @param input
738      * @return the uncompressed data
739      * @throws IOException
740      */
uncompressLongArray(byte[] input)741     public static long[] uncompressLongArray(byte[] input)
742             throws IOException
743     {
744         return uncompressLongArray(input, 0, input.length);
745     }
746 
747     /**
748      * Uncompress the input[offset, offset+length) as a long array
749      *
750      * @param input
751      * @param offset
752      * @param length
753      * @return the uncompressed data
754      * @throws IOException
755      */
uncompressLongArray(byte[] input, int offset, int length)756     public static long[] uncompressLongArray(byte[] input, int offset, int length)
757             throws IOException
758     {
759         int uncompressedLength = Snappy.uncompressedLength(input, offset, length);
760         long[] result = new long[uncompressedLength / 8];
761         impl.rawUncompress(input, offset, length, result, 0);
762         return result;
763     }
764 
765     /**
766      * Uncompress the input as a short array
767      *
768      * @param input
769      * @return the uncompressed data
770      * @throws IOException
771      */
uncompressShortArray(byte[] input)772     public static short[] uncompressShortArray(byte[] input)
773             throws IOException
774     {
775         return uncompressShortArray(input, 0, input.length);
776     }
777 
778     /**
779      * Uncompress the input[offset, offset+length) as a short array
780      *
781      * @param input
782      * @param offset
783      * @param length
784      * @return the uncompressed data
785      * @throws IOException
786      */
uncompressShortArray(byte[] input, int offset, int length)787     public static short[] uncompressShortArray(byte[] input, int offset, int length)
788             throws IOException
789     {
790         int uncompressedLength = Snappy.uncompressedLength(input, offset, length);
791         short[] result = new short[uncompressedLength / 2];
792         impl.rawUncompress(input, offset, length, result, 0);
793         return result;
794     }
795 
796     /**
797      * Uncompress the input as a String
798      *
799      * @param input
800      * @return the uncompressed dasta
801      * @throws IOException
802      */
uncompressString(byte[] input)803     public static String uncompressString(byte[] input)
804             throws IOException
805     {
806         try {
807             return uncompressString(input, "UTF-8");
808         }
809         catch (UnsupportedEncodingException e) {
810             throw new IllegalStateException("UTF-8 decoder is not found");
811         }
812     }
813 
814     /**
815      * Uncompress the input[offset, offset+length) as a String
816      *
817      * @param input
818      * @param offset
819      * @param length
820      * @return the uncompressed data
821      * @throws IOException
822      */
uncompressString(byte[] input, int offset, int length)823     public static String uncompressString(byte[] input, int offset, int length)
824             throws IOException
825     {
826         try {
827             return uncompressString(input, offset, length, "UTF-8");
828         }
829         catch (UnsupportedEncodingException e) {
830             throw new IllegalStateException("UTF-8 decoder is not found");
831         }
832     }
833 
834     /**
835      * Uncompress the input[offset, offset+length) as a String of the given
836      * encoding
837      *
838      * @param input
839      * @param offset
840      * @param length
841      * @param encoding
842      * @return the uncompressed data
843      * @throws IOException
844      */
uncompressString(byte[] input, int offset, int length, String encoding)845     public static String uncompressString(byte[] input, int offset, int length, String encoding)
846             throws IOException,
847             UnsupportedEncodingException
848     {
849         byte[] uncompressed = new byte[uncompressedLength(input, offset, length)];
850         uncompress(input, offset, length, uncompressed, 0);
851         return new String(uncompressed, encoding);
852     }
853 
854     /**
855      * Uncompress the input[offset, offset+length) as a String of the given
856      * encoding
857      *
858      * @param input
859      * @param offset
860      * @param length
861      * @param encoding
862      * @return the uncompressed data
863      * @throws IOException
864      */
uncompressString(byte[] input, int offset, int length, Charset encoding)865     public static String uncompressString(byte[] input, int offset, int length, Charset encoding)
866             throws IOException,
867             UnsupportedEncodingException
868     {
869         byte[] uncompressed = new byte[uncompressedLength(input, offset, length)];
870         uncompress(input, offset, length, uncompressed, 0);
871         return new String(uncompressed, encoding);
872     }
873 
874     /**
875      * Uncompress the input as a String of the given encoding
876      *
877      * @param input
878      * @param encoding
879      * @return the uncompressed data
880      * @throws IOException
881      * @throws UnsupportedEncodingException
882      */
uncompressString(byte[] input, String encoding)883     public static String uncompressString(byte[] input, String encoding)
884             throws IOException,
885             UnsupportedEncodingException
886     {
887         byte[] uncompressed = uncompress(input);
888         return new String(uncompressed, encoding);
889     }
890 
891     /**
892      * Uncompress the input as a String of the given encoding
893      *
894      * @param input
895      * @param encoding
896      * @return the uncompressed data
897      * @throws IOException
898      */
uncompressString(byte[] input, Charset encoding)899     public static String uncompressString(byte[] input, Charset encoding)
900             throws IOException,
901             UnsupportedEncodingException
902     {
903         byte[] uncompressed = uncompress(input);
904         return new String(uncompressed, encoding);
905     }
906 }
907