001: /*
002: * Portions Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: /*
027: *******************************************************************************
028: * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved *
029: * *
030: * The original version of this source code and documentation is copyrighted *
031: * and owned by IBM, These materials are provided under terms of a License *
032: * Agreement between IBM and Sun. This technology is protected by multiple *
033: * US and International patents. This notice and attribution to IBM may not *
034: * to removed. *
035: *******************************************************************************
036: */
037:
038: package sun.text.normalizer;
039:
040: import java.io.InputStream;
041: import java.io.DataInputStream;
042: import java.io.IOException;
043: import java.util.Arrays;
044:
045: public final class ICUBinary {
046: // public inner interface ------------------------------------------------
047:
048: /**
049: * Special interface for data authentication
050: */
051: public static interface Authenticate {
052: /**
053: * Method used in ICUBinary.readHeader() to provide data format
054: * authentication.
055: * @param version version of the current data
056: * @return true if dataformat is an acceptable version, false otherwise
057: */
058: public boolean isDataVersionAcceptable(byte version[]);
059: }
060:
061: // public methods --------------------------------------------------------
062:
063: /**
064: * <p>ICU data header reader method.
065: * Takes a ICU generated big-endian input stream, parse the ICU standard
066: * file header and authenticates them.</p>
067: * <p>Header format:
068: * <ul>
069: * <li> Header size (char)
070: * <li> Magic number 1 (byte)
071: * <li> Magic number 2 (byte)
072: * <li> Rest of the header size (char)
073: * <li> Reserved word (char)
074: * <li> Big endian indicator (byte)
075: * <li> Character set family indicator (byte)
076: * <li> Size of a char (byte) for c++ and c use
077: * <li> Reserved byte (byte)
078: * <li> Data format identifier (4 bytes), each ICU data has its own
079: * identifier to distinguish them. [0] major [1] minor
080: * [2] milli [3] micro
081: * <li> Data version (4 bytes), the change version of the ICU data
082: * [0] major [1] minor [2] milli [3] micro
083: * <li> Unicode version (4 bytes) this ICU is based on.
084: * </ul>
085: * </p>
086: * <p>
087: * Example of use:<br>
088: * <pre>
089: * try {
090: * FileInputStream input = new FileInputStream(filename);
091: * If (Utility.readICUDataHeader(input, dataformat, dataversion,
092: * unicode) {
093: * System.out.println("Verified file header, this is a ICU data file");
094: * }
095: * } catch (IOException e) {
096: * System.out.println("This is not a ICU data file");
097: * }
098: * </pre>
099: * </p>
100: * @param inputStream input stream that contains the ICU data header
101: * @param dataFormatIDExpected Data format expected. An array of 4 bytes
102: * information about the data format.
103: * E.g. data format ID 1.2.3.4. will became an array of
104: * {1, 2, 3, 4}
105: * @param authenticate user defined extra data authentication. This value
106: * can be null, if no extra authentication is needed.
107: * @exception IOException thrown if there is a read error or
108: * when header authentication fails.
109: * @draft 2.1
110: */
111: public static final byte[] readHeader(InputStream inputStream,
112: byte dataFormatIDExpected[], Authenticate authenticate)
113: throws IOException {
114: DataInputStream input = new DataInputStream(inputStream);
115: char headersize = input.readChar();
116: int readcount = 2;
117: //reading the header format
118: byte magic1 = input.readByte();
119: readcount++;
120: byte magic2 = input.readByte();
121: readcount++;
122: if (magic1 != MAGIC1 || magic2 != MAGIC2) {
123: throw new IOException(MAGIC_NUMBER_AUTHENTICATION_FAILED_);
124: }
125:
126: input.readChar(); // reading size
127: readcount += 2;
128: input.readChar(); // reading reserved word
129: readcount += 2;
130: byte bigendian = input.readByte();
131: readcount++;
132: byte charset = input.readByte();
133: readcount++;
134: byte charsize = input.readByte();
135: readcount++;
136: input.readByte(); // reading reserved byte
137: readcount++;
138:
139: byte dataFormatID[] = new byte[4];
140: input.readFully(dataFormatID);
141: readcount += 4;
142: byte dataVersion[] = new byte[4];
143: input.readFully(dataVersion);
144: readcount += 4;
145: byte unicodeVersion[] = new byte[4];
146: input.readFully(unicodeVersion);
147: readcount += 4;
148: if (headersize < readcount) {
149: throw new IOException("Internal Error: Header size error");
150: }
151: input.skipBytes(headersize - readcount);
152:
153: if (bigendian != BIG_ENDIAN_
154: || charset != CHAR_SET_
155: || charsize != CHAR_SIZE_
156: || !Arrays.equals(dataFormatIDExpected, dataFormatID)
157: || (authenticate != null && !authenticate
158: .isDataVersionAcceptable(dataVersion))) {
159: throw new IOException(HEADER_AUTHENTICATION_FAILED_);
160: }
161: return unicodeVersion;
162: }
163:
164: // private variables -------------------------------------------------
165:
166: /**
167: * Magic numbers to authenticate the data file
168: */
169: private static final byte MAGIC1 = (byte) 0xda;
170: private static final byte MAGIC2 = (byte) 0x27;
171:
172: /**
173: * File format authentication values
174: */
175: private static final byte BIG_ENDIAN_ = 1;
176: private static final byte CHAR_SET_ = 0;
177: private static final byte CHAR_SIZE_ = 2;
178:
179: /**
180: * Error messages
181: */
182: private static final String MAGIC_NUMBER_AUTHENTICATION_FAILED_ = "ICU data file error: Not an ICU data file";
183: private static final String HEADER_AUTHENTICATION_FAILED_ = "ICU data file error: Header authentication failed, please check if you have a valid ICU data file";
184: }
|