| /* |
| ******************************************************************************* |
| * |
| * Copyright (C) 2004-2005, International Business Machines |
| * Corporation and others. All Rights Reserved. |
| * |
| ******************************************************************************* |
| * file name: UBiDiProps.java |
| * encoding: US-ASCII |
| * tab size: 8 (not used) |
| * indentation:4 |
| * |
| * created on: 2005jan16 |
| * created by: Markus W. Scherer |
| * |
| * Low-level Unicode bidi/shaping properties access. |
| * Java port of ubidi_props.h/.c. |
| */ |
| |
| package com.ibm.icu.impl; |
| |
| import java.io.InputStream; |
| import java.io.DataInputStream; |
| import java.io.BufferedInputStream; |
| import java.io.IOException; |
| import java.util.MissingResourceException; |
| |
| import com.ibm.icu.util.VersionInfo; |
| import com.ibm.icu.util.RangeValueIterator; |
| |
| import com.ibm.icu.text.UnicodeSet; |
| |
| import com.ibm.icu.lang.UCharacter; |
| import com.ibm.icu.lang.UProperty; |
| |
| public final class UBiDiProps { |
| // constructors etc. --------------------------------------------------- *** |
| |
| // port of ubidi_openProps() |
| public UBiDiProps() throws IOException{ |
| InputStream is=ICUData.getStream(ICUResourceBundle.ICU_BUNDLE+"/"+DATA_FILE_NAME); |
| BufferedInputStream b=new BufferedInputStream(is, 4096 /* data buffer size */); |
| readData(b); |
| b.close(); |
| is.close(); |
| |
| } |
| |
| private void readData(InputStream is) throws IOException { |
| DataInputStream inputStream=new DataInputStream(is); |
| |
| // read the header |
| unicodeVersion=ICUBinary.readHeader(inputStream, FMT, new IsAcceptable()); |
| |
| // read indexes[] |
| int i, count; |
| count=inputStream.readInt(); |
| if(count<IX_INDEX_TOP) { |
| throw new IOException("indexes[0] too small in "+DATA_FILE_NAME); |
| } |
| indexes=new int[count]; |
| |
| indexes[0]=count; |
| for(i=1; i<count; ++i) { |
| indexes[i]=inputStream.readInt(); |
| } |
| |
| // read the trie |
| trie=new CharTrie(inputStream, null); |
| |
| // read mirrors[] |
| count=indexes[IX_MIRROR_LENGTH]; |
| if(count>0) { |
| mirrors=new int[count]; |
| for(i=0; i<count; ++i) { |
| mirrors[i]=inputStream.readInt(); |
| } |
| } |
| |
| // read jgArray[] |
| count=indexes[IX_JG_LIMIT]-indexes[IX_JG_START]; |
| jgArray=new byte[count]; |
| for(i=0; i<count; ++i) { |
| jgArray[i]=inputStream.readByte(); |
| } |
| } |
| |
| // implement ICUBinary.Authenticate |
| private final class IsAcceptable implements ICUBinary.Authenticate { |
| public boolean isDataVersionAcceptable(byte version[]) { |
| formatVersion=version; |
| return version[0]==1 && |
| version[2]==Trie.INDEX_STAGE_1_SHIFT_ && version[3]==Trie.INDEX_STAGE_2_SHIFT_; |
| } |
| } |
| |
| // UBiDiProps singleton |
| private static UBiDiProps gBdp=null; |
| |
| // port of ubidi_getSingleton() |
| public static final synchronized UBiDiProps getSingleton() throws IOException { |
| if(gBdp==null) { |
| gBdp=new UBiDiProps(); |
| } |
| return gBdp; |
| } |
| |
| // UBiDiProps dummy singleton |
| private static UBiDiProps gBdpDummy=null; |
| |
| private UBiDiProps(boolean makeDummy) { // ignore makeDummy, only creates a unique signature |
| formatVersion=new byte[] { 1, 0, Trie.INDEX_STAGE_1_SHIFT_, Trie.INDEX_STAGE_2_SHIFT_ }; |
| unicodeVersion=new byte[] { 2, 0, 0, 0 }; |
| indexes=new int[IX_TOP]; |
| indexes[0]=IX_TOP; |
| trie=new CharTrie(0, 0, null); // dummy trie, always returns 0 |
| } |
| |
| /** |
| * Get a singleton dummy object, one that works with no real data. |
| * This can be used when the real data is not available. |
| * Using the dummy can reduce checks for available data after an initial failure. |
| * Port of ucase_getDummy(). |
| */ |
| public static final synchronized UBiDiProps getDummy() { |
| if(gBdpDummy==null) { |
| gBdpDummy=new UBiDiProps(true); |
| } |
| return gBdpDummy; |
| } |
| |
| // set of property starts for UnicodeSet ------------------------------- *** |
| |
| public final void addPropertyStarts(UnicodeSet set) { |
| int i, length; |
| int c, start, limit; |
| |
| byte prev, jg; |
| |
| /* add the start code point of each same-value range of the trie */ |
| TrieIterator iter=new TrieIterator(trie); |
| RangeValueIterator.Element element=new RangeValueIterator.Element(); |
| |
| while(iter.next(element)){ |
| set.add(element.start); |
| } |
| |
| /* add the code points from the bidi mirroring table */ |
| length=indexes[IX_MIRROR_LENGTH]; |
| for(i=0; i<length; ++i) { |
| c=getMirrorCodePoint(mirrors[i]); |
| set.add(c, c+1); |
| } |
| |
| /* add the code points from the Joining_Group array where the value changes */ |
| start=indexes[IX_JG_START]; |
| limit=indexes[IX_JG_LIMIT]; |
| length=limit-start; |
| prev=0; |
| for(i=0; i<length; ++i) { |
| jg=jgArray[i]; |
| if(jg!=prev) { |
| set.add(start); |
| prev=jg; |
| } |
| ++start; |
| } |
| if(prev!=0) { |
| /* add the limit code point if the last value was not 0 (it is now start==limit) */ |
| set.add(limit); |
| } |
| |
| /* add code points with hardcoded properties, plus the ones following them */ |
| |
| /* (none right now) */ |
| } |
| |
| // property access functions ------------------------------------------- *** |
| |
| public final int getMaxValue(int which) { |
| int max; |
| |
| max=indexes[IX_MAX_VALUES]; |
| switch(which) { |
| case UProperty.BIDI_CLASS: |
| return (max&CLASS_MASK); |
| case UProperty.JOINING_GROUP: |
| return (max&MAX_JG_MASK)>>MAX_JG_SHIFT; |
| case UProperty.JOINING_TYPE: |
| return (max&JT_MASK)>>JT_SHIFT; |
| default: |
| return -1; /* undefined */ |
| } |
| } |
| |
| public final int getClass(int c) { |
| return getClassFromProps(trie.getCodePointValue(c)); |
| } |
| |
| public final boolean isMirrored(int c) { |
| return getFlagFromProps(trie.getCodePointValue(c), IS_MIRRORED_SHIFT); |
| } |
| |
| public final int getMirror(int c) { |
| int props; |
| int delta; |
| |
| props=trie.getCodePointValue(c); |
| delta=((short)props)>>MIRROR_DELTA_SHIFT; |
| if(delta!=ESC_MIRROR_DELTA) { |
| return c+delta; |
| } else { |
| /* look for mirror code point in the mirrors[] table */ |
| int m; |
| int i, length; |
| int c2; |
| |
| length=indexes[IX_MIRROR_LENGTH]; |
| |
| /* linear search */ |
| for(i=0; i<length; ++i) { |
| m=mirrors[i]; |
| c2=getMirrorCodePoint(m); |
| if(c==c2) { |
| /* found c, return its mirror code point using the index in m */ |
| return getMirrorCodePoint(mirrors[getMirrorIndex(m)]); |
| } else if(c<c2) { |
| break; |
| } |
| } |
| |
| /* c not found, return it itself */ |
| return c; |
| } |
| } |
| |
| public final boolean isBidiControl(int c) { |
| return getFlagFromProps(trie.getCodePointValue(c), BIDI_CONTROL_SHIFT); |
| } |
| |
| public final boolean isJoinControl(int c) { |
| return getFlagFromProps(trie.getCodePointValue(c), JOIN_CONTROL_SHIFT); |
| } |
| |
| public final int getJoiningType(int c) { |
| return (trie.getCodePointValue(c)&JT_MASK)>>JT_SHIFT; |
| } |
| |
| public final int getJoiningGroup(int c) { |
| int start, limit; |
| |
| start=indexes[IX_JG_START]; |
| limit=indexes[IX_JG_LIMIT]; |
| if(start<=c && c<limit) { |
| return (int)jgArray[c-start]&0xff; |
| } else { |
| return UCharacter.JoiningGroup.NO_JOINING_GROUP; |
| } |
| } |
| |
| // data members -------------------------------------------------------- *** |
| private int indexes[]; |
| private int mirrors[]; |
| private byte jgArray[]; |
| |
| private CharTrie trie; |
| private byte formatVersion[]; |
| private byte unicodeVersion[]; |
| |
| // data format constants ----------------------------------------------- *** |
| private static final String DATA_NAME="ubidi"; |
| private static final String DATA_TYPE="icu"; |
| private static final String DATA_FILE_NAME=DATA_NAME+"."+DATA_TYPE; |
| |
| /* format "BiDi" */ |
| private static final byte FMT[]={ 0x42, 0x69, 0x44, 0x69 }; |
| |
| /* indexes into indexes[] */ |
| private static final int IX_INDEX_TOP=0; |
| private static final int IX_LENGTH=1; |
| private static final int IX_TRIE_SIZE=2; |
| private static final int IX_MIRROR_LENGTH=3; |
| |
| private static final int IX_JG_START=4; |
| private static final int IX_JG_LIMIT=5; |
| |
| private static final int IX_MAX_VALUES=15; |
| private static final int IX_TOP=16; |
| |
| // definitions for 16-bit bidi/shaping properties word ----------------- *** |
| |
| /* CLASS_SHIFT=0, */ /* bidi class: 5 bits (4..0) */ |
| private static final int JT_SHIFT=5; /* joining type: 3 bits (7..5) */ |
| |
| /* private static final int _SHIFT=8, reserved: 2 bits (9..8) */ |
| |
| private static final int JOIN_CONTROL_SHIFT=10; |
| private static final int BIDI_CONTROL_SHIFT=11; |
| |
| private static final int IS_MIRRORED_SHIFT=12; /* 'is mirrored' */ |
| private static final int MIRROR_DELTA_SHIFT=13; /* bidi mirroring delta: 3 bits (15..13) */ |
| |
| private static final int MAX_JG_SHIFT=16; /* max JG value in indexes[MAX_VALUES_INDEX] bits 23..16 */ |
| |
| private static final int CLASS_MASK= 0x0000001f; |
| private static final int JT_MASK= 0x000000e0; |
| |
| private static final int MAX_JG_MASK= 0x00ff0000; |
| |
| private static final int getClassFromProps(int props) { |
| return props&CLASS_MASK; |
| } |
| private static final boolean getFlagFromProps(int props, int shift) { |
| return ((props>>shift)&1)!=0; |
| } |
| |
| private static final int ESC_MIRROR_DELTA=-4; |
| private static final int MIN_MIRROR_DELTA=-3; |
| private static final int MAX_MIRROR_DELTA=3; |
| |
| // definitions for 32-bit mirror table entry --------------------------- *** |
| |
| /* the source Unicode code point takes 21 bits (20..0) */ |
| private static final int MIRROR_INDEX_SHIFT=21; |
| private static final int MAX_MIRROR_INDEX=0x7ff; |
| |
| private static final int getMirrorCodePoint(int m) { |
| return m&0x1fffff; |
| } |
| private static final int getMirrorIndex(int m) { |
| return m>>>MIRROR_INDEX_SHIFT; |
| } |
| } |