2 *******************************************************************************
3 * Copyright (C) 1996-2010, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
7 package com.ibm.icu.impl;
9 import java.io.DataInputStream;
10 import java.io.IOException;
11 import java.io.InputStream;
12 import java.util.Arrays;
14 import com.ibm.icu.util.VersionInfo;
16 public final class ICUBinary
18 // public inner interface ------------------------------------------------
21 * Special interface for data authentication
23 public static interface Authenticate
26 * Method used in ICUBinary.readHeader() to provide data format
28 * @param version version of the current data
29 * @return true if dataformat is an acceptable version, false otherwise
31 public boolean isDataVersionAcceptable(byte version[]);
34 // public methods --------------------------------------------------------
37 * <p>ICU data header reader method.
38 * Takes a ICU generated big-endian input stream, parse the ICU standard
39 * file header and authenticates them.</p>
42 * <li> Header size (char)
43 * <li> Magic number 1 (byte)
44 * <li> Magic number 2 (byte)
45 * <li> Rest of the header size (char)
46 * <li> Reserved word (char)
47 * <li> Big endian indicator (byte)
48 * <li> Character set family indicator (byte)
49 * <li> Size of a char (byte) for c++ and c use
50 * <li> Reserved byte (byte)
51 * <li> Data format identifier (4 bytes), each ICU data has its own
52 * identifier to distinguish them. [0] major [1] minor
54 * <li> Data version (4 bytes), the change version of the ICU data
55 * [0] major [1] minor [2] milli [3] micro
56 * <li> Unicode version (4 bytes) this ICU is based on.
63 * FileInputStream input = new FileInputStream(filename);
64 * If (Utility.readICUDataHeader(input, dataformat, dataversion,
66 * System.out.println("Verified file header, this is a ICU data file");
68 * } catch (IOException e) {
69 * System.out.println("This is not a ICU data file");
73 * @param inputStream input stream that contains the ICU data header
74 * @param dataFormatIDExpected Data format expected. An array of 4 bytes
75 * information about the data format.
76 * E.g. data format ID 1.2.3.4. will became an array of
78 * @param authenticate user defined extra data authentication. This value
79 * can be null, if no extra authentication is needed.
80 * @exception IOException thrown if there is a read error or
81 * when header authentication fails.
83 public static final byte[] readHeader(InputStream inputStream,
84 byte dataFormatIDExpected[],
85 Authenticate authenticate)
88 DataInputStream input = new DataInputStream(inputStream);
89 char headersize = input.readChar();
91 //reading the header format
92 byte magic1 = input.readByte();
94 byte magic2 = input.readByte();
96 if (magic1 != MAGIC1 || magic2 != MAGIC2) {
97 throw new IOException(MAGIC_NUMBER_AUTHENTICATION_FAILED_);
100 input.readChar(); // reading size
102 input.readChar(); // reading reserved word
104 byte bigendian = input.readByte();
106 byte charset = input.readByte();
108 byte charsize = input.readByte();
110 input.readByte(); // reading reserved byte
113 byte dataFormatID[] = new byte[4];
114 input.readFully(dataFormatID);
116 byte dataVersion[] = new byte[4];
117 input.readFully(dataVersion);
119 byte unicodeVersion[] = new byte[4];
120 input.readFully(unicodeVersion);
122 if (headersize < readcount) {
123 throw new IOException("Internal Error: Header size error");
125 input.skipBytes(headersize - readcount);
127 if (bigendian != BIG_ENDIAN_ || charset != CHAR_SET_
128 || charsize != CHAR_SIZE_
129 || !Arrays.equals(dataFormatIDExpected, dataFormatID)
130 || (authenticate != null
131 && !authenticate.isDataVersionAcceptable(dataVersion))) {
132 throw new IOException(HEADER_AUTHENTICATION_FAILED_);
134 return unicodeVersion;
138 * Same as readHeader(), but returns a VersionInfo rather than a byte[].
140 public static final VersionInfo readHeaderAndDataVersion(InputStream inputStream,
141 byte dataFormatIDExpected[],
142 Authenticate authenticate)
144 byte[] dataVersion = readHeader(inputStream, dataFormatIDExpected, authenticate);
145 return VersionInfo.getInstance(dataVersion[0], dataVersion[1],
146 dataVersion[2], dataVersion[3]);
149 // private variables -------------------------------------------------
152 * Magic numbers to authenticate the data file
154 private static final byte MAGIC1 = (byte)0xda;
155 private static final byte MAGIC2 = (byte)0x27;
158 * File format authentication values
160 private static final byte BIG_ENDIAN_ = 1;
161 private static final byte CHAR_SET_ = 0;
162 private static final byte CHAR_SIZE_ = 2;
167 private static final String MAGIC_NUMBER_AUTHENTICATION_FAILED_ =
168 "ICU data file error: Not an ICU data file";
169 private static final String HEADER_AUTHENTICATION_FAILED_ =
170 "ICU data file error: Header authentication failed, please check if you have a valid ICU data file";