1/*
2 * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25/*
26 *******************************************************************************
27 *
28 *   Copyright (C) 2004-2014, International Business Machines
29 *   Corporation and others.  All Rights Reserved.
30 *
31 *******************************************************************************
32 *   file name:  UBiDiProps.java
33 *   encoding:   US-ASCII
34 *   tab size:   8 (not used)
35 *   indentation:4
36 *
37 *   created on: 2005jan16
38 *   created by: Markus W. Scherer
39 *
40 *   Low-level Unicode bidi/shaping properties access.
41 *   Java port of ubidi_props.h/.c.
42 */
43
44package sun.text.normalizer;
45
46import java.io.IOException;
47import java.nio.ByteBuffer;
48import java.util.MissingResourceException;
49
50public final class UBiDiProps {
51    // constructors etc. --------------------------------------------------- ***
52
53    // port of ubidi_openProps()
54    private UBiDiProps() throws IOException{
55        ByteBuffer bytes=ICUBinary.getRequiredData(DATA_FILE_NAME);
56        readData(bytes);
57    }
58
59    private void readData(ByteBuffer bytes) throws IOException {
60        // read the header
61        ICUBinary.readHeader(bytes, FMT, new IsAcceptable());
62
63        // read indexes[]
64        int i, count;
65        count=bytes.getInt();
66        if(count<IX_TOP) {
67            throw new IOException("indexes[0] too small in "+DATA_FILE_NAME);
68        }
69        indexes=new int[count];
70
71        indexes[0]=count;
72        for(i=1; i<count; ++i) {
73            indexes[i]=bytes.getInt();
74        }
75
76        // read the trie
77        trie=Trie2_16.createFromSerialized(bytes);
78        int expectedTrieLength=indexes[IX_TRIE_SIZE];
79        int trieLength=trie.getSerializedLength();
80        if(trieLength>expectedTrieLength) {
81            throw new IOException(DATA_FILE_NAME+": not enough bytes for the trie");
82        }
83        // skip padding after trie bytes
84        ICUBinary.skipBytes(bytes, expectedTrieLength-trieLength);
85
86        // read mirrors[]
87        count=indexes[IX_MIRROR_LENGTH];
88        if(count>0) {
89            mirrors=new int[count];
90            for(i=0; i<count; ++i) {
91                mirrors[i]=bytes.getInt();
92            }
93        }
94
95        // read jgArray[]
96        count=indexes[IX_JG_LIMIT]-indexes[IX_JG_START];
97        jgArray=new byte[count];
98        for(i=0; i<count; ++i) {
99            jgArray[i]=bytes.get();
100        }
101
102        // read jgArray2[]
103        count=indexes[IX_JG_LIMIT2]-indexes[IX_JG_START2];
104        jgArray2=new byte[count];
105        for(i=0; i<count; ++i) {
106            jgArray2[i]=bytes.get();
107        }
108    }
109
110    // implement ICUBinary.Authenticate
111    private static final class IsAcceptable implements ICUBinary.Authenticate {
112        public boolean isDataVersionAcceptable(byte version[]) {
113            return version[0]==2;
114        }
115    }
116
117    // property access functions ------------------------------------------- ***
118
119    public final int getClass(int c) {
120        return getClassFromProps(trie.get(c));
121    }
122
123    private final int getMirror(int c, int props) {
124        int delta=getMirrorDeltaFromProps(props);
125        if(delta!=ESC_MIRROR_DELTA) {
126            return c+delta;
127        } else {
128            /* look for mirror code point in the mirrors[] table */
129            int m;
130            int i, length;
131            int c2;
132
133            length=indexes[IX_MIRROR_LENGTH];
134
135            /* linear search */
136            for(i=0; i<length; ++i) {
137                m=mirrors[i];
138                c2=getMirrorCodePoint(m);
139                if(c==c2) {
140                    /* found c, return its mirror code point using the index in m */
141                    return getMirrorCodePoint(mirrors[getMirrorIndex(m)]);
142                } else if(c<c2) {
143                    break;
144                }
145            }
146
147            /* c not found, return it itself */
148            return c;
149        }
150    }
151
152    public final int getMirror(int c) {
153        int props=trie.get(c);
154        return getMirror(c, props);
155    }
156
157    public final int getJoiningType(int c) {
158        return (trie.get(c)&JT_MASK)>>JT_SHIFT;
159    }
160
161    public final int getJoiningGroup(int c) {
162        int start, limit;
163
164        start=indexes[IX_JG_START];
165        limit=indexes[IX_JG_LIMIT];
166        if(start<=c && c<limit) {
167            return (int)jgArray[c-start]&0xff;
168        }
169        start=indexes[IX_JG_START2];
170        limit=indexes[IX_JG_LIMIT2];
171        if(start<=c && c<limit) {
172            return (int)jgArray2[c-start]&0xff;
173        }
174        return UCharacter.JoiningGroup.NO_JOINING_GROUP;
175    }
176
177    public final int getPairedBracketType(int c) {
178        return (trie.get(c)&BPT_MASK)>>BPT_SHIFT;
179    }
180
181    public final int getPairedBracket(int c) {
182        int props=trie.get(c);
183        if((props&BPT_MASK)==0) {
184            return c;
185        } else {
186            return getMirror(c, props);
187        }
188    }
189
190    // data members -------------------------------------------------------- ***
191    private int indexes[];
192    private int mirrors[];
193    private byte jgArray[];
194    private byte jgArray2[];
195
196    private Trie2_16 trie;
197
198    // data format constants ----------------------------------------------- ***
199    private static final String DATA_FILE_NAME = "/sun/text/resources/ubidi.icu";
200
201    /* format "BiDi" */
202    private static final int FMT=0x42694469;
203
204    /* indexes into indexes[] */
205    private static final int IX_TRIE_SIZE=2;
206    private static final int IX_MIRROR_LENGTH=3;
207
208    private static final int IX_JG_START=4;
209    private static final int IX_JG_LIMIT=5;
210    private static final int IX_JG_START2=6;  /* new in format version 2.2, ICU 54 */
211    private static final int IX_JG_LIMIT2=7;
212
213    private static final int IX_TOP=16;
214
215    // definitions for 16-bit bidi/shaping properties word ----------------- ***
216
217                          /* CLASS_SHIFT=0, */     /* bidi class: 5 bits (4..0) */
218    private static final int JT_SHIFT=5;           /* joining type: 3 bits (7..5) */
219
220    private static final int BPT_SHIFT=8;          /* Bidi_Paired_Bracket_Type(bpt): 2 bits (9..8) */
221
222    private static final int MIRROR_DELTA_SHIFT=13;        /* bidi mirroring delta: 3 bits (15..13) */
223
224    private static final int CLASS_MASK=    0x0000001f;
225    private static final int JT_MASK=       0x000000e0;
226    private static final int BPT_MASK=      0x00000300;
227
228    private static final int getClassFromProps(int props) {
229        return props&CLASS_MASK;
230    }
231    private static final boolean getFlagFromProps(int props, int shift) {
232        return ((props>>shift)&1)!=0;
233    }
234    private static final int getMirrorDeltaFromProps(int props) {
235        return (short)props>>MIRROR_DELTA_SHIFT;
236    }
237
238    private static final int ESC_MIRROR_DELTA=-4;
239
240    // definitions for 32-bit mirror table entry --------------------------- ***
241
242    /* the source Unicode code point takes 21 bits (20..0) */
243    private static final int MIRROR_INDEX_SHIFT=21;
244
245    private static final int getMirrorCodePoint(int m) {
246        return m&0x1fffff;
247    }
248    private static final int getMirrorIndex(int m) {
249        return m>>>MIRROR_INDEX_SHIFT;
250    }
251
252
253    /*
254     * public singleton instance
255     */
256    public static final UBiDiProps INSTANCE;
257
258    // This static initializer block must be placed after
259    // other static member initialization
260    static {
261        try {
262            INSTANCE = new UBiDiProps();
263        } catch (IOException e) {
264            throw new MissingResourceException(e.getMessage(),DATA_FILE_NAME,"");
265        }
266    }
267}
268