Home | History | Annotate | Download | only in common
      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    */
     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    */
     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    */
     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    */
     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    */
     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    */
     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    */
    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