1/*
2 *******************************************************************************
3 * Copyright (C) 1996-2014, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
6 */
7
8package com.ibm.icu.impl;
9
10import java.io.IOException;
11import java.nio.ByteBuffer;
12import java.util.Arrays;
13
14/**
15* <p>Internal reader class for ICU data file uname.dat containing
16* Unicode codepoint name data.</p>
17* <p>This class simply reads unames.icu, authenticates that it is a valid
18* ICU data file and split its contents up into blocks of data for use in
19* <a href=UCharacterName.html>com.ibm.icu.impl.UCharacterName</a>.
20* </p>
21* <p>unames.icu which is in big-endian format is jared together with this
22* package.</p>
23* @author Syn Wee Quek
24* @since release 2.1, February 1st 2002
25*/
26
27final class UCharacterNameReader implements ICUBinary.Authenticate
28{
29    // public methods ----------------------------------------------------
30
31    public boolean isDataVersionAcceptable(byte version[])
32    {
33        return version[0] == 1;
34    }
35
36    // protected constructor ---------------------------------------------
37
38    /**
39    * <p>Protected constructor.</p>
40    * @param bytes ICU uprop.dat file buffer
41    * @exception IOException throw if data file fails authentication
42    */
43    protected UCharacterNameReader(ByteBuffer bytes) throws IOException
44    {
45        ICUBinary.readHeader(bytes, DATA_FORMAT_ID_, this);
46        m_byteBuffer_ = bytes;
47    }
48
49    // protected methods -------------------------------------------------
50
51    /**
52    * Read and break up the stream of data passed in as arguments
53    * and fills up UCharacterName.
54    * If unsuccessful false will be returned.
55    * @param data instance of datablock
56    * @exception IOException thrown when there's a data error.
57    */
58    protected void read(UCharacterName data) throws IOException
59    {
60        // reading index
61        m_tokenstringindex_ = m_byteBuffer_.getInt();
62        m_groupindex_       = m_byteBuffer_.getInt();
63        m_groupstringindex_ = m_byteBuffer_.getInt();
64        m_algnamesindex_    = m_byteBuffer_.getInt();
65
66        // reading tokens
67        int count = m_byteBuffer_.getChar();
68        char token[] = new char[count];
69        for (char i = 0; i < count; i ++) {
70            token[i] = m_byteBuffer_.getChar();
71        }
72        int size = m_groupindex_ - m_tokenstringindex_;
73        byte tokenstr[] = new byte[size];
74        m_byteBuffer_.get(tokenstr);
75        data.setToken(token, tokenstr);
76
77        // reading the group information records
78        count = m_byteBuffer_.getChar();
79        data.setGroupCountSize(count, GROUP_INFO_SIZE_);
80        count *= GROUP_INFO_SIZE_;
81        char group[] = new char[count];
82        for (int i = 0; i < count; i ++) {
83            group[i] = m_byteBuffer_.getChar();
84        }
85
86        size = m_algnamesindex_ - m_groupstringindex_;
87        byte groupstring[] = new byte[size];
88        m_byteBuffer_.get(groupstring);
89
90        data.setGroup(group, groupstring);
91
92        count = m_byteBuffer_.getInt();
93        UCharacterName.AlgorithmName alg[] =
94                                 new UCharacterName.AlgorithmName[count];
95
96        for (int i = 0; i < count; i ++)
97        {
98            UCharacterName.AlgorithmName an = readAlg();
99            if (an == null) {
100                throw new IOException("unames.icu read error: Algorithmic names creation error");
101            }
102            alg[i] = an;
103        }
104        data.setAlgorithm(alg);
105    }
106
107    /**
108    * <p>Checking the file for the correct format.</p>
109    * @param dataformatid
110    * @param dataformatversion
111    * @return true if the file format version is correct
112    */
113    ///CLOVER:OFF
114    protected boolean authenticate(byte dataformatid[],
115                                   byte dataformatversion[])
116    {
117        return Arrays.equals(
118                ICUBinary.getVersionByteArrayFromCompactInt(DATA_FORMAT_ID_),
119                dataformatid) &&
120               isDataVersionAcceptable(dataformatversion);
121    }
122    ///CLOVER:ON
123
124    // private variables -------------------------------------------------
125
126    /**
127    * Byte buffer for names
128    */
129    private ByteBuffer m_byteBuffer_;
130    /**
131    * Size of the group information block in number of char
132    */
133    private static final int GROUP_INFO_SIZE_ = 3;
134
135    /**
136    * Index of the offset information
137    */
138    private int m_tokenstringindex_;
139    private int m_groupindex_;
140    private int m_groupstringindex_;
141    private int m_algnamesindex_;
142
143    /**
144    * Size of an algorithmic name information group
145    * start code point size + end code point size + type size + variant size +
146    * size of data size
147    */
148    private static final int ALG_INFO_SIZE_ = 12;
149
150    /**
151    * File format id that this class understands.
152    */
153    private static final int DATA_FORMAT_ID_ = 0x756E616D;
154
155    // private methods ---------------------------------------------------
156
157    /**
158    * Reads an individual record of AlgorithmNames
159    * @return an instance of AlgorithNames if read is successful otherwise null
160    * @exception IOException thrown when file read error occurs or data is corrupted
161    */
162    private UCharacterName.AlgorithmName readAlg() throws IOException
163    {
164        UCharacterName.AlgorithmName result =
165                                       new UCharacterName.AlgorithmName();
166        int rangestart = m_byteBuffer_.getInt();
167        int rangeend   = m_byteBuffer_.getInt();
168        byte type      = m_byteBuffer_.get();
169        byte variant   = m_byteBuffer_.get();
170        if (!result.setInfo(rangestart, rangeend, type, variant)) {
171            return null;
172        }
173
174        int size = m_byteBuffer_.getChar();
175        if (type == UCharacterName.AlgorithmName.TYPE_1_)
176        {
177            char factor[] = new char[variant];
178            for (int j = 0; j < variant; j ++) {
179                factor[j] = m_byteBuffer_.getChar();
180            }
181
182            result.setFactor(factor);
183            size -= (variant << 1);
184        }
185
186        StringBuilder prefix = new StringBuilder();
187        char c = (char)(m_byteBuffer_.get() & 0x00FF);
188        while (c != 0)
189        {
190            prefix.append(c);
191            c = (char)(m_byteBuffer_.get() & 0x00FF);
192        }
193
194        result.setPrefix(prefix.toString());
195
196        size -= (ALG_INFO_SIZE_ + prefix.length() + 1);
197
198        if (size > 0)
199        {
200            byte string[] = new byte[size];
201            m_byteBuffer_.get(string);
202            result.setFactorString(string);
203        }
204        return result;
205    }
206}
207