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.zstdsafe;
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.zstdsafe.Constants.*;
49  
50  /**
51   * ZSTD Safe Codec implementation
52   */
53  public class ZstdSafeCodec implements CompressorCodec {
54    private final ZstdFrameDecompressor decompressor =
55        new ZstdFrameDecompressor();
56  
57    /**
58     * Used to get the maximum size of a compressed buffer
59     *
60     * @param uncompressedSize
61     *
62     * @return the maximum size
63     */
64    public static int maxCompressedSize(final int uncompressedSize) {
65      int result = uncompressedSize + (uncompressedSize >>> 8);
66      if (uncompressedSize < MAX_BLOCK_SIZE) {
67        result += (MAX_BLOCK_SIZE - uncompressedSize) >>> 11;
68      }
69      return result;
70    }
71  
72    @Override
73    public final int maxCompressedLength(final int uncompressedSize) {
74      return maxCompressedSize(uncompressedSize);
75    }
76  
77    @Override
78    public final byte[] compress(final byte[] input, final int length) {
79      try {
80        final int len = maxCompressedLength(length);
81        final byte[] temp = new byte[len];
82        final int finalLen = compress(input, input.length, temp, len);
83        return Arrays.copyOf(temp, finalLen);
84      } catch (final Exception e) {
85        throw new MalformedInputException(e);
86      }
87    }
88  
89    @Override
90    public final int compress(final byte[] input, final int inputLength,
91                              final byte[] output, final int maxOutputLength) {
92      try {
93        return ZstdFrameCompressor.compress(input, 0, inputLength, output, 0,
94                                            maxOutputLength,
95                                            CompressionParameters.DEFAULT_COMPRESSION_LEVEL);
96      } catch (final Exception e) {
97        throw new MalformedInputException(e);
98      }
99    }
100 
101   @Override
102   public final byte[] decompress(final byte[] input, final int length)
103       throws MalformedInputException {
104     try {
105       final int finalLen =
106           ZstdFrameDecompressor.getDecompressedSize(input, 0, length);
107       final byte[] decompressed = new byte[finalLen];
108       decompress(input, input.length, decompressed, finalLen);
109       return decompressed;
110     } catch (final Exception e) {
111       throw new MalformedInputException(e);
112     }
113   }
114 
115   @Override
116   public final long compress(final File input, final File output)
117       throws MalformedInputException {
118     InputStream inputStream = null;
119     OutputStream outputStream = null;
120     try {
121       final byte[] buffer;
122       inputStream = new FileInputStream(input);
123       buffer = ByteStreams.toByteArray(inputStream);
124       outputStream = new FileOutputStream(output);
125       final byte[] bufferCompression =
126           new byte[maxCompressedLength(buffer.length)];
127       final int length = compress(buffer, buffer.length, bufferCompression,
128                                   bufferCompression.length);
129       outputStream.write(bufferCompression, 0, length);
130       outputStream.flush();
131       FileUtils.close(outputStream);
132       outputStream = null;
133       return output.length();
134     } catch (final Exception e) {
135       throw new MalformedInputException(e);
136     } finally {
137       FileUtils.close(inputStream);
138       FileUtils.close(outputStream);
139     }
140   }
141 
142   @Override
143   public final int decompress(final byte[] input, final int inputLength,
144                               final byte[] output, final int maxOutputLength)
145       throws MalformedInputException {
146     try {
147       return decompressor.decompress(input, 0, inputLength, output, 0,
148                                      maxOutputLength);
149     } catch (final Exception e) {
150       throw new MalformedInputException(e);
151     }
152   }
153 
154   @Override
155   public final long decompress(final File input, final File output)
156       throws MalformedInputException {
157     InputStream inputStream = null;
158     OutputStream outputStream = null;
159     try {
160       final byte[] buffer;
161       inputStream = new FileInputStream(input);
162       final byte[] sourceArray = ByteStreams.toByteArray(inputStream);
163       outputStream = new FileOutputStream(output);
164       buffer = new byte[getDecompressedSize(sourceArray, sourceArray.length)];
165       final int length =
166           decompress(sourceArray, sourceArray.length, buffer, buffer.length);
167       outputStream.write(buffer, 0, length);
168       outputStream.flush();
169       FileUtils.close(outputStream);
170       outputStream = null;
171       return output.length();
172     } catch (final Exception e) {
173       throw new MalformedInputException(e);
174     } finally {
175       FileUtils.close(inputStream);
176       FileUtils.close(outputStream);
177     }
178   }
179 
180   @Override
181   public final int getDecompressedSize(final byte[] input, final int length) {
182     return ZstdFrameDecompressor.getDecompressedSize(input, 0, input.length);
183   }
184 }