View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  
21  /*
22   * Licensed under the Apache License, Version 2.0 (the "License");
23   * you may not use this file except in compliance with the License.
24   * You may obtain a copy of the License at
25   *
26   *     http://www.apache.org/licenses/LICENSE-2.0
27   *
28   * Unless required by applicable law or agreed to in writing, software
29   * distributed under the License is distributed on an "AS IS" BASIS,
30   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31   * See the License for the specific language governing permissions and
32   * limitations under the License.
33   */
34  package org.waarp.compress.zstdunsafe;
35  
36  import com.google.common.io.ByteStreams;
37  import org.waarp.common.file.FileUtils;
38  import org.waarp.compress.CompressorCodec;
39  import org.waarp.compress.MalformedInputException;
40  
41  import java.io.File;
42  import java.io.FileInputStream;
43  import java.io.FileOutputStream;
44  import java.io.InputStream;
45  import java.io.OutputStream;
46  import java.util.Arrays;
47  
48  import static org.waarp.compress.zstdunsafe.Constants.*;
49  import static sun.misc.Unsafe.*;
50  
51  /**
52   * ZSTD Unsafe Codec implementation
53   */
54  public class ZstdUnsafeCodec implements CompressorCodec {
55    private final ZstdFrameDecompressor decompressor =
56        new ZstdFrameDecompressor();
57  
58    @Override
59    public final int getDecompressedSize(final byte[] input, final int length) {
60      final long baseAddress = ARRAY_BYTE_BASE_OFFSET;
61      return (int) ZstdFrameDecompressor.getDecompressedSize(input, baseAddress,
62                                                             baseAddress +
63                                                             length);
64    }
65  
66    @Override
67    public final int maxCompressedLength(final int uncompressedSize) {
68      long result = (long) uncompressedSize + (uncompressedSize >>> 8);
69      if (uncompressedSize < MAX_BLOCK_SIZE) {
70        result += (MAX_BLOCK_SIZE - uncompressedSize) >>> 11;
71      }
72      return (int) result;
73    }
74  
75    @Override
76    public final byte[] compress(final byte[] input, final int length) {
77      try {
78        final int len = maxCompressedLength(length);
79        final byte[] temp = new byte[len];
80        final int finalLen = compress(input, input.length, temp, len);
81        return Arrays.copyOf(temp, finalLen);
82      } catch (final Exception e) {
83        throw new MalformedInputException(e);
84      }
85    }
86  
87    @Override
88    public final int compress(final byte[] input, final int inputLength,
89                              final byte[] output, final int maxOutputLength) {
90      try {
91        final long inputAddress = ARRAY_BYTE_BASE_OFFSET;
92        final long outputAddress = ARRAY_BYTE_BASE_OFFSET;
93        return ZstdFrameCompressor.compress(input, inputAddress,
94                                            inputAddress + inputLength, output,
95                                            outputAddress,
96                                            outputAddress + maxOutputLength,
97                                            CompressionParameters.DEFAULT_COMPRESSION_LEVEL);
98      } catch (final Exception e) {
99        throw new MalformedInputException(e);
100     }
101   }
102 
103   @Override
104   public final byte[] decompress(final byte[] input, final int length)
105       throws MalformedInputException {
106     try {
107       final int finalLen = getDecompressedSize(input, length);
108       final byte[] decompressed = new byte[finalLen];
109       decompress(input, input.length, decompressed, finalLen);
110       return decompressed;
111     } catch (final Exception e) {
112       throw new MalformedInputException(e);
113     }
114   }
115 
116   @Override
117   public final long compress(final File input, final File output)
118       throws MalformedInputException {
119     InputStream inputStream = null;
120     OutputStream outputStream = null;
121     try {
122       final byte[] buffer;
123       inputStream = new FileInputStream(input);
124       buffer = ByteStreams.toByteArray(inputStream);
125       outputStream = new FileOutputStream(output);
126       final byte[] bufferCompression =
127           new byte[maxCompressedLength(buffer.length)];
128       final int length = compress(buffer, buffer.length, bufferCompression,
129                                   bufferCompression.length);
130       outputStream.write(bufferCompression, 0, length);
131       outputStream.flush();
132       FileUtils.close(outputStream);
133       outputStream = null;
134       return output.length();
135     } catch (final Exception e) {
136       throw new MalformedInputException(e);
137     } finally {
138       FileUtils.close(inputStream);
139       FileUtils.close(outputStream);
140     }
141   }
142 
143   @Override
144   public final int decompress(final byte[] input, final int inputLength,
145                               final byte[] output, final int maxOutputLength)
146       throws MalformedInputException {
147     try {
148       final long inputAddress = ARRAY_BYTE_BASE_OFFSET;
149       final long inputLimit = inputAddress + inputLength;
150       final long outputAddress = ARRAY_BYTE_BASE_OFFSET;
151       final long outputLimit = outputAddress + maxOutputLength;
152 
153       return decompressor.decompress(input, inputAddress, inputLimit, output,
154                                      outputAddress, outputLimit);
155     } catch (final Exception e) {
156       throw new MalformedInputException(e);
157     }
158   }
159 
160   @Override
161   public final long decompress(final File input, final File output)
162       throws MalformedInputException {
163     InputStream inputStream = null;
164     OutputStream outputStream = null;
165     try {
166       final byte[] buffer;
167       inputStream = new FileInputStream(input);
168       final byte[] sourceArray = ByteStreams.toByteArray(inputStream);
169       outputStream = new FileOutputStream(output);
170       buffer = new byte[getDecompressedSize(sourceArray, sourceArray.length)];
171       final int length =
172           decompress(sourceArray, sourceArray.length, buffer, buffer.length);
173       outputStream.write(buffer, 0, length);
174       outputStream.flush();
175       FileUtils.close(outputStream);
176       outputStream = null;
177       return output.length();
178     } catch (final Exception e) {
179       throw new MalformedInputException(e);
180     } finally {
181       FileUtils.close(inputStream);
182       FileUtils.close(outputStream);
183     }
184   }
185 }