• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4  *******************************************************************************
5  *
6  *   Copyright (C) 2004-2015, International Business Machines
7  *   Corporation and others.  All Rights Reserved.
8  *
9  *******************************************************************************
10  *   file name:  UBiDiProps.java
11  *   encoding:   US-ASCII
12  *   tab size:   8 (not used)
13  *   indentation:4
14  *
15  *   created on: 2005jan16
16  *   created by: Markus W. Scherer
17  *
18  *   Low-level Unicode bidi/shaping properties access.
19  *   Java port of ubidi_props.h/.c.
20  */
21 
22 package com.ibm.icu.impl;
23 
24 import java.io.IOException;
25 import java.nio.ByteBuffer;
26 import java.util.Iterator;
27 
28 import com.ibm.icu.lang.UCharacter;
29 import com.ibm.icu.lang.UProperty;
30 import com.ibm.icu.text.UnicodeSet;
31 import com.ibm.icu.util.ICUUncheckedIOException;
32 
33 public final class UBiDiProps {
34     // constructors etc. --------------------------------------------------- ***
35 
36     // port of ubidi_openProps()
UBiDiProps()37     private UBiDiProps() throws IOException{
38         ByteBuffer bytes=ICUBinary.getData(DATA_FILE_NAME);
39         readData(bytes);
40     }
41 
readData(ByteBuffer bytes)42     private void readData(ByteBuffer bytes) throws IOException {
43         // read the header
44         ICUBinary.readHeader(bytes, FMT, new IsAcceptable());
45 
46         // read indexes[]
47         int i, count;
48         count=bytes.getInt();
49         if(count<IX_TOP) {
50             throw new IOException("indexes[0] too small in "+DATA_FILE_NAME);
51         }
52         indexes=new int[count];
53 
54         indexes[0]=count;
55         for(i=1; i<count; ++i) {
56             indexes[i]=bytes.getInt();
57         }
58 
59         // read the trie
60         trie=Trie2_16.createFromSerialized(bytes);
61         int expectedTrieLength=indexes[IX_TRIE_SIZE];
62         int trieLength=trie.getSerializedLength();
63         if(trieLength>expectedTrieLength) {
64             throw new IOException(DATA_FILE_NAME+": not enough bytes for the trie");
65         }
66         // skip padding after trie bytes
67         ICUBinary.skipBytes(bytes, expectedTrieLength-trieLength);
68 
69         // read mirrors[]
70         count=indexes[IX_MIRROR_LENGTH];
71         if(count>0) {
72             mirrors=ICUBinary.getInts(bytes, count, 0);
73         }
74 
75         // read jgArray[]
76         count=indexes[IX_JG_LIMIT]-indexes[IX_JG_START];
77         jgArray=new byte[count];
78         bytes.get(jgArray);
79 
80         // read jgArray2[]
81         count=indexes[IX_JG_LIMIT2]-indexes[IX_JG_START2];
82         jgArray2=new byte[count];
83         bytes.get(jgArray2);
84     }
85 
86     // implement ICUBinary.Authenticate
87     private final static class IsAcceptable implements ICUBinary.Authenticate {
88         @Override
isDataVersionAcceptable(byte version[])89         public boolean isDataVersionAcceptable(byte version[]) {
90             return version[0]==2;
91         }
92     }
93 
94     // set of property starts for UnicodeSet ------------------------------- ***
95 
addPropertyStarts(UnicodeSet set)96     public final void addPropertyStarts(UnicodeSet set) {
97         int i, length;
98         int c, start, limit;
99 
100         byte prev, jg;
101 
102         /* add the start code point of each same-value range of the trie */
103         Iterator<Trie2.Range> trieIterator=trie.iterator();
104         Trie2.Range range;
105         while(trieIterator.hasNext() && !(range=trieIterator.next()).leadSurrogate) {
106             set.add(range.startCodePoint);
107         }
108 
109         /* add the code points from the bidi mirroring table */
110         length=indexes[IX_MIRROR_LENGTH];
111         for(i=0; i<length; ++i) {
112             c=getMirrorCodePoint(mirrors[i]);
113             set.add(c, c+1);
114         }
115 
116         /* add the code points from the Joining_Group array where the value changes */
117         start=indexes[IX_JG_START];
118         limit=indexes[IX_JG_LIMIT];
119         byte[] jga=jgArray;
120         for(;;) {
121             length=limit-start;
122             prev=0;
123             for(i=0; i<length; ++i) {
124                 jg=jga[i];
125                 if(jg!=prev) {
126                     set.add(start);
127                     prev=jg;
128                 }
129                 ++start;
130             }
131             if(prev!=0) {
132                 /* add the limit code point if the last value was not 0 (it is now start==limit) */
133                 set.add(limit);
134             }
135             if(limit==indexes[IX_JG_LIMIT]) {
136                 /* switch to the second Joining_Group range */
137                 start=indexes[IX_JG_START2];
138                 limit=indexes[IX_JG_LIMIT2];
139                 jga=jgArray2;
140             } else {
141                 break;
142             }
143         }
144 
145         /* add code points with hardcoded properties, plus the ones following them */
146 
147         /* (none right now) */
148     }
149 
150     // property access functions ------------------------------------------- ***
151 
getMaxValue(int which)152     public final int getMaxValue(int which) {
153         int max;
154 
155         max=indexes[IX_MAX_VALUES];
156         switch(which) {
157         case UProperty.BIDI_CLASS:
158             return (max&CLASS_MASK);
159         case UProperty.JOINING_GROUP:
160             return (max&MAX_JG_MASK)>>MAX_JG_SHIFT;
161         case UProperty.JOINING_TYPE:
162             return (max&JT_MASK)>>JT_SHIFT;
163         case UProperty.BIDI_PAIRED_BRACKET_TYPE:
164             return (max&BPT_MASK)>>BPT_SHIFT;
165         default:
166             return -1; /* undefined */
167         }
168     }
169 
getClass(int c)170     public final int getClass(int c) {
171         return getClassFromProps(trie.get(c));
172     }
173 
isMirrored(int c)174     public final boolean isMirrored(int c) {
175         return getFlagFromProps(trie.get(c), IS_MIRRORED_SHIFT);
176     }
177 
getMirror(int c, int props)178     private final int getMirror(int c, int props) {
179         int delta=getMirrorDeltaFromProps(props);
180         if(delta!=ESC_MIRROR_DELTA) {
181             return c+delta;
182         } else {
183             /* look for mirror code point in the mirrors[] table */
184             int m;
185             int i, length;
186             int c2;
187 
188             length=indexes[IX_MIRROR_LENGTH];
189 
190             /* linear search */
191             for(i=0; i<length; ++i) {
192                 m=mirrors[i];
193                 c2=getMirrorCodePoint(m);
194                 if(c==c2) {
195                     /* found c, return its mirror code point using the index in m */
196                     return getMirrorCodePoint(mirrors[getMirrorIndex(m)]);
197                 } else if(c<c2) {
198                     break;
199                 }
200             }
201 
202             /* c not found, return it itself */
203             return c;
204         }
205     }
206 
getMirror(int c)207     public final int getMirror(int c) {
208         int props=trie.get(c);
209         return getMirror(c, props);
210     }
211 
isBidiControl(int c)212     public final boolean isBidiControl(int c) {
213         return getFlagFromProps(trie.get(c), BIDI_CONTROL_SHIFT);
214     }
215 
isJoinControl(int c)216     public final boolean isJoinControl(int c) {
217         return getFlagFromProps(trie.get(c), JOIN_CONTROL_SHIFT);
218     }
219 
getJoiningType(int c)220     public final int getJoiningType(int c) {
221         return (trie.get(c)&JT_MASK)>>JT_SHIFT;
222     }
223 
getJoiningGroup(int c)224     public final int getJoiningGroup(int c) {
225         int start, limit;
226 
227         start=indexes[IX_JG_START];
228         limit=indexes[IX_JG_LIMIT];
229         if(start<=c && c<limit) {
230             return jgArray[c-start]&0xff;
231         }
232         start=indexes[IX_JG_START2];
233         limit=indexes[IX_JG_LIMIT2];
234         if(start<=c && c<limit) {
235             return jgArray2[c-start]&0xff;
236         }
237         return UCharacter.JoiningGroup.NO_JOINING_GROUP;
238     }
239 
getPairedBracketType(int c)240     public final int getPairedBracketType(int c) {
241         return (trie.get(c)&BPT_MASK)>>BPT_SHIFT;
242     }
243 
getPairedBracket(int c)244     public final int getPairedBracket(int c) {
245         int props=trie.get(c);
246         if((props&BPT_MASK)==0) {
247             return c;
248         } else {
249             return getMirror(c, props);
250         }
251     }
252 
253     // data members -------------------------------------------------------- ***
254     private int indexes[];
255     private int mirrors[];
256     private byte jgArray[];
257     private byte jgArray2[];
258 
259     private Trie2_16 trie;
260 
261     // data format constants ----------------------------------------------- ***
262     private static final String DATA_NAME="ubidi";
263     private static final String DATA_TYPE="icu";
264     private static final String DATA_FILE_NAME=DATA_NAME+"."+DATA_TYPE;
265 
266     /* format "BiDi" */
267     private static final int FMT=0x42694469;
268 
269     /* indexes into indexes[] */
270     //private static final int IX_INDEX_TOP=0;
271     //private static final int IX_LENGTH=1;
272     private static final int IX_TRIE_SIZE=2;
273     private static final int IX_MIRROR_LENGTH=3;
274 
275     private static final int IX_JG_START=4;
276     private static final int IX_JG_LIMIT=5;
277     private static final int IX_JG_START2=6;  /* new in format version 2.2, ICU 54 */
278     private static final int IX_JG_LIMIT2=7;
279 
280     private static final int IX_MAX_VALUES=15;
281     private static final int IX_TOP=16;
282 
283     // definitions for 16-bit bidi/shaping properties word ----------------- ***
284 
285                           /* CLASS_SHIFT=0, */     /* bidi class: 5 bits (4..0) */
286     private static final int JT_SHIFT=5;           /* joining type: 3 bits (7..5) */
287 
288     private static final int BPT_SHIFT=8;          /* Bidi_Paired_Bracket_Type(bpt): 2 bits (9..8) */
289 
290     private static final int JOIN_CONTROL_SHIFT=10;
291     private static final int BIDI_CONTROL_SHIFT=11;
292 
293     private static final int IS_MIRRORED_SHIFT=12;         /* 'is mirrored' */
294     private static final int MIRROR_DELTA_SHIFT=13;        /* bidi mirroring delta: 3 bits (15..13) */
295 
296     private static final int MAX_JG_SHIFT=16;              /* max JG value in indexes[MAX_VALUES_INDEX] bits 23..16 */
297 
298     private static final int CLASS_MASK=    0x0000001f;
299     private static final int JT_MASK=       0x000000e0;
300     private static final int BPT_MASK=      0x00000300;
301 
302     private static final int MAX_JG_MASK=   0x00ff0000;
303 
getClassFromProps(int props)304     private static final int getClassFromProps(int props) {
305         return props&CLASS_MASK;
306     }
getFlagFromProps(int props, int shift)307     private static final boolean getFlagFromProps(int props, int shift) {
308         return ((props>>shift)&1)!=0;
309     }
getMirrorDeltaFromProps(int props)310     private static final int getMirrorDeltaFromProps(int props) {
311         return (short)props>>MIRROR_DELTA_SHIFT;
312     }
313 
314     private static final int ESC_MIRROR_DELTA=-4;
315     //private static final int MIN_MIRROR_DELTA=-3;
316     //private static final int MAX_MIRROR_DELTA=3;
317 
318     // definitions for 32-bit mirror table entry --------------------------- ***
319 
320     /* the source Unicode code point takes 21 bits (20..0) */
321     private static final int MIRROR_INDEX_SHIFT=21;
322     //private static final int MAX_MIRROR_INDEX=0x7ff;
323 
getMirrorCodePoint(int m)324     private static final int getMirrorCodePoint(int m) {
325         return m&0x1fffff;
326     }
getMirrorIndex(int m)327     private static final int getMirrorIndex(int m) {
328         return m>>>MIRROR_INDEX_SHIFT;
329     }
330 
331 
332     /*
333      * public singleton instance
334      */
335     public static final UBiDiProps INSTANCE;
336 
337     // This static initializer block must be placed after
338     // other static member initialization
339     static {
340         try {
341             INSTANCE = new UBiDiProps();
342         } catch (IOException e) {
343             throw new ICUUncheckedIOException(e);
344         }
345     }
346 }
347