2 *******************************************************************************
\r
4 * Copyright (C) 2004-2010, International Business Machines
\r
5 * Corporation and others. All Rights Reserved.
\r
7 *******************************************************************************
\r
8 * file name: UBiDiProps.java
\r
10 * tab size: 8 (not used)
\r
13 * created on: 2005jan16
\r
14 * created by: Markus W. Scherer
\r
16 * Low-level Unicode bidi/shaping properties access.
\r
17 * Java port of ubidi_props.h/.c.
\r
20 package com.ibm.icu.impl;
\r
22 import java.io.BufferedInputStream;
\r
23 import java.io.DataInputStream;
\r
24 import java.io.IOException;
\r
25 import java.io.InputStream;
\r
27 import com.ibm.icu.lang.UCharacter;
\r
28 import com.ibm.icu.lang.UProperty;
\r
29 import com.ibm.icu.text.UnicodeSet;
\r
30 import com.ibm.icu.util.RangeValueIterator;
\r
32 public final class UBiDiProps {
\r
33 // constructors etc. --------------------------------------------------- ***
\r
35 // port of ubidi_openProps()
\r
36 private UBiDiProps() throws IOException{
\r
37 InputStream is=ICUData.getStream(ICUResourceBundle.ICU_BUNDLE+"/"+DATA_FILE_NAME);
\r
38 BufferedInputStream b=new BufferedInputStream(is, 4096 /* data buffer size */);
\r
44 private UBiDiProps(boolean makeDummy) { // ignore makeDummy, only creates a unique signature
\r
45 indexes=new int[IX_TOP];
\r
47 trie=new CharTrie(0, 0, null); // dummy trie, always returns 0
\r
51 private void readData(InputStream is) throws IOException {
\r
52 DataInputStream inputStream=new DataInputStream(is);
\r
55 ICUBinary.readHeader(inputStream, FMT, new IsAcceptable());
\r
59 count=inputStream.readInt();
\r
60 if(count<IX_INDEX_TOP) {
\r
61 throw new IOException("indexes[0] too small in "+DATA_FILE_NAME);
\r
63 indexes=new int[count];
\r
66 for(i=1; i<count; ++i) {
\r
67 indexes[i]=inputStream.readInt();
\r
71 trie=new CharTrie(inputStream, null);
\r
74 count=indexes[IX_MIRROR_LENGTH];
\r
76 mirrors=new int[count];
\r
77 for(i=0; i<count; ++i) {
\r
78 mirrors[i]=inputStream.readInt();
\r
83 count=indexes[IX_JG_LIMIT]-indexes[IX_JG_START];
\r
84 jgArray=new byte[count];
\r
85 for(i=0; i<count; ++i) {
\r
86 jgArray[i]=inputStream.readByte();
\r
90 // implement ICUBinary.Authenticate
\r
91 private final class IsAcceptable implements ICUBinary.Authenticate {
\r
92 public boolean isDataVersionAcceptable(byte version[]) {
\r
93 return version[0]==1 &&
\r
94 version[2]==Trie.INDEX_STAGE_1_SHIFT_ && version[3]==Trie.INDEX_STAGE_2_SHIFT_;
\r
98 // port of ubidi_getSingleton()
\r
100 // Note: Do we really need this API?
\r
101 public static UBiDiProps getSingleton() throws IOException {
\r
102 if (FULL_INSTANCE == null) {
\r
103 synchronized (UBiDiProps.class) {
\r
104 if (FULL_INSTANCE == null) {
\r
105 FULL_INSTANCE = new UBiDiProps();
\r
109 return FULL_INSTANCE;
\r
113 * Get a singleton dummy object, one that works with no real data.
\r
114 * This can be used when the real data is not available.
\r
115 * Using the dummy can reduce checks for available data after an initial failure.
\r
116 * Port of ucase_getDummy().
\r
118 // Note: do we really need this API?
\r
119 public static UBiDiProps getDummy() {
\r
120 if (DUMMY_INSTANCE == null) {
\r
121 synchronized (UBiDiProps.class) {
\r
122 if (DUMMY_INSTANCE == null) {
\r
123 DUMMY_INSTANCE = new UBiDiProps(true);
\r
127 return DUMMY_INSTANCE;
\r
130 // set of property starts for UnicodeSet ------------------------------- ***
\r
132 public final void addPropertyStarts(UnicodeSet set) {
\r
134 int c, start, limit;
\r
138 /* add the start code point of each same-value range of the trie */
\r
139 TrieIterator iter=new TrieIterator(trie);
\r
140 RangeValueIterator.Element element=new RangeValueIterator.Element();
\r
142 while(iter.next(element)){
\r
143 set.add(element.start);
\r
146 /* add the code points from the bidi mirroring table */
\r
147 length=indexes[IX_MIRROR_LENGTH];
\r
148 for(i=0; i<length; ++i) {
\r
149 c=getMirrorCodePoint(mirrors[i]);
\r
153 /* add the code points from the Joining_Group array where the value changes */
\r
154 start=indexes[IX_JG_START];
\r
155 limit=indexes[IX_JG_LIMIT];
\r
156 length=limit-start;
\r
158 for(i=0; i<length; ++i) {
\r
167 /* add the limit code point if the last value was not 0 (it is now start==limit) */
\r
171 /* add code points with hardcoded properties, plus the ones following them */
\r
173 /* (none right now) */
\r
176 // property access functions ------------------------------------------- ***
\r
178 public final int getMaxValue(int which) {
\r
181 max=indexes[IX_MAX_VALUES];
\r
183 case UProperty.BIDI_CLASS:
\r
184 return (max&CLASS_MASK);
\r
185 case UProperty.JOINING_GROUP:
\r
186 return (max&MAX_JG_MASK)>>MAX_JG_SHIFT;
\r
187 case UProperty.JOINING_TYPE:
\r
188 return (max&JT_MASK)>>JT_SHIFT;
\r
190 return -1; /* undefined */
\r
194 public final int getClass(int c) {
\r
195 return getClassFromProps(trie.getCodePointValue(c));
\r
198 public final boolean isMirrored(int c) {
\r
199 return getFlagFromProps(trie.getCodePointValue(c), IS_MIRRORED_SHIFT);
\r
202 public final int getMirror(int c) {
\r
206 props=trie.getCodePointValue(c);
\r
207 delta=((short)props)>>MIRROR_DELTA_SHIFT;
\r
208 if(delta!=ESC_MIRROR_DELTA) {
\r
211 /* look for mirror code point in the mirrors[] table */
\r
216 length=indexes[IX_MIRROR_LENGTH];
\r
218 /* linear search */
\r
219 for(i=0; i<length; ++i) {
\r
221 c2=getMirrorCodePoint(m);
\r
223 /* found c, return its mirror code point using the index in m */
\r
224 return getMirrorCodePoint(mirrors[getMirrorIndex(m)]);
\r
230 /* c not found, return it itself */
\r
235 public final boolean isBidiControl(int c) {
\r
236 return getFlagFromProps(trie.getCodePointValue(c), BIDI_CONTROL_SHIFT);
\r
239 public final boolean isJoinControl(int c) {
\r
240 return getFlagFromProps(trie.getCodePointValue(c), JOIN_CONTROL_SHIFT);
\r
243 public final int getJoiningType(int c) {
\r
244 return (trie.getCodePointValue(c)&JT_MASK)>>JT_SHIFT;
\r
247 public final int getJoiningGroup(int c) {
\r
250 start=indexes[IX_JG_START];
\r
251 limit=indexes[IX_JG_LIMIT];
\r
252 if(start<=c && c<limit) {
\r
253 return (int)jgArray[c-start]&0xff;
\r
255 return UCharacter.JoiningGroup.NO_JOINING_GROUP;
\r
259 // data members -------------------------------------------------------- ***
\r
260 private int indexes[];
\r
261 private int mirrors[];
\r
262 private byte jgArray[];
\r
264 private CharTrie trie;
\r
266 // data format constants ----------------------------------------------- ***
\r
267 private static final String DATA_NAME="ubidi";
\r
268 private static final String DATA_TYPE="icu";
\r
269 private static final String DATA_FILE_NAME=DATA_NAME+"."+DATA_TYPE;
\r
271 /* format "BiDi" */
\r
272 private static final byte FMT[]={ 0x42, 0x69, 0x44, 0x69 };
\r
274 /* indexes into indexes[] */
\r
275 private static final int IX_INDEX_TOP=0;
\r
276 //private static final int IX_LENGTH=1;
\r
277 //private static final int IX_TRIE_SIZE=2;
\r
278 private static final int IX_MIRROR_LENGTH=3;
\r
280 private static final int IX_JG_START=4;
\r
281 private static final int IX_JG_LIMIT=5;
\r
283 private static final int IX_MAX_VALUES=15;
\r
284 private static final int IX_TOP=16;
\r
286 // definitions for 16-bit bidi/shaping properties word ----------------- ***
\r
288 /* CLASS_SHIFT=0, */ /* bidi class: 5 bits (4..0) */
\r
289 private static final int JT_SHIFT=5; /* joining type: 3 bits (7..5) */
\r
291 /* private static final int _SHIFT=8, reserved: 2 bits (9..8) */
\r
293 private static final int JOIN_CONTROL_SHIFT=10;
\r
294 private static final int BIDI_CONTROL_SHIFT=11;
\r
296 private static final int IS_MIRRORED_SHIFT=12; /* 'is mirrored' */
\r
297 private static final int MIRROR_DELTA_SHIFT=13; /* bidi mirroring delta: 3 bits (15..13) */
\r
299 private static final int MAX_JG_SHIFT=16; /* max JG value in indexes[MAX_VALUES_INDEX] bits 23..16 */
\r
301 private static final int CLASS_MASK= 0x0000001f;
\r
302 private static final int JT_MASK= 0x000000e0;
\r
304 private static final int MAX_JG_MASK= 0x00ff0000;
\r
306 private static final int getClassFromProps(int props) {
\r
307 return props&CLASS_MASK;
\r
309 private static final boolean getFlagFromProps(int props, int shift) {
\r
310 return ((props>>shift)&1)!=0;
\r
313 private static final int ESC_MIRROR_DELTA=-4;
\r
314 //private static final int MIN_MIRROR_DELTA=-3;
\r
315 //private static final int MAX_MIRROR_DELTA=3;
\r
317 // definitions for 32-bit mirror table entry --------------------------- ***
\r
319 /* the source Unicode code point takes 21 bits (20..0) */
\r
320 private static final int MIRROR_INDEX_SHIFT=21;
\r
321 //private static final int MAX_MIRROR_INDEX=0x7ff;
\r
323 private static final int getMirrorCodePoint(int m) {
\r
326 private static final int getMirrorIndex(int m) {
\r
327 return m>>>MIRROR_INDEX_SHIFT;
\r
332 * public singleton instance
\r
334 public static final UBiDiProps INSTANCE;
\r
336 private static volatile UBiDiProps FULL_INSTANCE;
\r
337 private static volatile UBiDiProps DUMMY_INSTANCE;
\r
339 // This static initializer block must be placed after
\r
340 // other static member initialization
\r
344 bp = new UBiDiProps();
\r
345 FULL_INSTANCE = bp;
\r
346 } catch (IOException e) {
\r
348 bp = new UBiDiProps(true);
\r
349 DUMMY_INSTANCE = bp;
\r