• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2017 Google Inc. All Rights Reserved.
2 
3    Distributed under MIT license.
4    See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5 */
6 
7 package org.brotli.wrapper.common;
8 
9 import java.io.IOException;
10 import java.io.InputStream;
11 import java.nio.ByteBuffer;
12 import java.util.Arrays;
13 
14 /**
15  * JNI wrapper for brotli common.
16  */
17 public class BrotliCommon {
18   public static final int RFC_DICTIONARY_SIZE = 122784;
19 
20   /* 96cecd2ee7a666d5aa3627d74735b32a */
21   private static final byte[] RFC_DICTIONARY_MD5 = {
22     -106, -50, -51, 46, -25, -90, 102, -43, -86, 54, 39, -41, 71, 53, -77, 42
23   };
24 
25   /* 72b41051cb61a9281ba3c4414c289da50d9a7640 */
26   private static final byte[] RFC_DICTIONARY_SHA_1 = {
27     114, -76, 16, 81, -53, 97, -87, 40, 27, -93, -60, 65, 76, 40, -99, -91, 13, -102, 118, 64
28   };
29 
30   /* 20e42eb1b511c21806d4d227d07e5dd06877d8ce7b3a817f378f313653f35c70 */
31   private static final byte[] RFC_DICTIONARY_SHA_256 = {
32     32, -28, 46, -79, -75, 17, -62, 24, 6, -44, -46, 39, -48, 126, 93, -48,
33     104, 119, -40, -50, 123, 58, -127, 127, 55, -113, 49, 54, 83, -13, 92, 112
34   };
35 
36   private static boolean isDictionaryDataSet;
37   private static final Object mutex = new Object();
38 
39   /**
40    * Checks if the given checksum matches MD5 checksum of the RFC dictionary.
41    */
checkDictionaryDataMd5(byte[] digest)42   public static boolean checkDictionaryDataMd5(byte[] digest) {
43     return Arrays.equals(RFC_DICTIONARY_MD5, digest);
44   }
45 
46   /**
47    * Checks if the given checksum matches SHA-1 checksum of the RFC dictionary.
48    */
checkDictionaryDataSha1(byte[] digest)49   public static boolean checkDictionaryDataSha1(byte[] digest) {
50     return Arrays.equals(RFC_DICTIONARY_SHA_1, digest);
51   }
52 
53   /**
54    * Checks if the given checksum matches SHA-256 checksum of the RFC dictionary.
55    */
checkDictionaryDataSha256(byte[] digest)56   public static boolean checkDictionaryDataSha256(byte[] digest) {
57     return Arrays.equals(RFC_DICTIONARY_SHA_256, digest);
58   }
59 
60   /**
61    * Copy bytes to a new direct ByteBuffer.
62    *
63    * Direct byte buffers are used to supply native code with large data chunks.
64    */
makeNative(byte[] data)65   public static ByteBuffer makeNative(byte[] data) {
66     ByteBuffer result = ByteBuffer.allocateDirect(data.length);
67     result.put(data);
68     return result;
69   }
70 
71   /**
72    * Copies data and sets it to be brotli dictionary.
73    */
setDictionaryData(byte[] data)74   public static void setDictionaryData(byte[] data) {
75     if (data.length != RFC_DICTIONARY_SIZE) {
76       throw new IllegalArgumentException("invalid dictionary size");
77     }
78     synchronized (mutex) {
79       if (isDictionaryDataSet) {
80         return;
81       }
82       setDictionaryData(makeNative(data));
83     }
84   }
85 
86   /**
87    * Reads data and sets it to be brotli dictionary.
88    */
setDictionaryData(InputStream src)89   public static void setDictionaryData(InputStream src) throws IOException {
90     synchronized (mutex) {
91       if (isDictionaryDataSet) {
92         return;
93       }
94       ByteBuffer copy = ByteBuffer.allocateDirect(RFC_DICTIONARY_SIZE);
95       byte[] buffer = new byte[4096];
96       int readBytes;
97       while ((readBytes = src.read(buffer)) != -1) {
98         if (copy.remaining() < readBytes) {
99           throw new IllegalArgumentException("invalid dictionary size");
100         }
101         copy.put(buffer, 0, readBytes);
102       }
103       if (copy.remaining() != 0) {
104         throw new IllegalArgumentException("invalid dictionary size " + copy.remaining());
105       }
106       setDictionaryData(copy);
107     }
108   }
109 
110   /**
111    * Sets data to be brotli dictionary.
112    */
setDictionaryData(ByteBuffer data)113   public static void setDictionaryData(ByteBuffer data) {
114     if (!data.isDirect()) {
115       throw new IllegalArgumentException("direct byte buffer is expected");
116     }
117     if (data.capacity() != RFC_DICTIONARY_SIZE) {
118       throw new IllegalArgumentException("invalid dictionary size");
119     }
120     synchronized (mutex) {
121       if (isDictionaryDataSet) {
122         return;
123       }
124       if (!CommonJNI.nativeSetDictionaryData(data)) {
125         throw new RuntimeException("setting dictionary failed");
126       }
127       isDictionaryDataSet = true;
128     }
129   }
130 }
131