• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2015 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.dec;
8 
9 import java.nio.ByteBuffer;
10 
11 /**
12  * Collection of static dictionary words.
13  *
14  * <p>Dictionary content is loaded from binary resource when {@link #getData()} is executed for the
15  * first time. Consequently, it saves memory and CPU in case dictionary is not required.
16  *
17  * <p>One possible drawback is that multiple threads that need dictionary data may be blocked (only
18  * once in each classworld). To avoid this, it is enough to call {@link #getData()} proactively.
19  */
20 public final class Dictionary {
21   static final int MIN_DICTIONARY_WORD_LENGTH = 4;
22   static final int MAX_DICTIONARY_WORD_LENGTH = 31;
23 
24   private static ByteBuffer data;
25   static final int[] offsets = new int[32];
26   static final int[] sizeBits = new int[32];
27 
28   private static class DataLoader {
29     static final boolean OK;
30 
31     static {
32       boolean ok = true;
33       try {
34         Class.forName(Dictionary.class.getPackage().getName() + ".DictionaryData");
35       } catch (Throwable ex) {
36         ok = false;
37       }
38       OK = ok;
39     }
40   }
41 
setData(ByteBuffer data, int[] sizeBits)42   public static void setData(ByteBuffer data, int[] sizeBits) {
43     if (!data.isDirect() || !data.isReadOnly()) {
44       throw new BrotliRuntimeException("data must be a direct read-only byte buffer");
45     }
46     // TODO: is that so?
47     if (sizeBits.length > MAX_DICTIONARY_WORD_LENGTH) {
48       throw new BrotliRuntimeException(
49           "sizeBits length must be at most " + MAX_DICTIONARY_WORD_LENGTH);
50     }
51     for (int i = 0; i < MIN_DICTIONARY_WORD_LENGTH; ++i) {
52       if (sizeBits[i] != 0) {
53         throw new BrotliRuntimeException("first " + MIN_DICTIONARY_WORD_LENGTH + " must be 0");
54       }
55     }
56     int[] dictionaryOffsets = Dictionary.offsets;
57     int[] dictionarySizeBits = Dictionary.sizeBits;
58     System.arraycopy(sizeBits, 0, dictionarySizeBits, 0, sizeBits.length);
59     int pos = 0;
60     int limit = data.capacity();
61     for (int i = 0; i < sizeBits.length; ++i) {
62       dictionaryOffsets[i] = pos;
63       int bits = dictionarySizeBits[i];
64       if (bits != 0) {
65         if (bits >= 31) {
66           throw new BrotliRuntimeException("sizeBits values must be less than 31");
67         }
68         pos += i << bits;
69         if (pos <= 0 || pos > limit) {
70           throw new BrotliRuntimeException("sizeBits is inconsistent: overflow");
71         }
72       }
73     }
74     for (int i = sizeBits.length; i < 32; ++i) {
75       dictionaryOffsets[i] = pos;
76     }
77     if (pos != limit) {
78       throw new BrotliRuntimeException("sizeBits is inconsistent: underflow");
79     }
80     Dictionary.data = data;
81   }
82 
getData()83   public static ByteBuffer getData() {
84     if (data != null) {
85       return data;
86     }
87     if (!DataLoader.OK) {
88       throw new BrotliRuntimeException("brotli dictionary is not set");
89     }
90     /* Might have been set when {@link DictionaryData} was loaded.*/
91     return data;
92   }
93 }
94