/// <summary> /// Reads an ICU data header, checks the data format, and returns the data version. /// </summary> /// <remarks> /// Assumes that the <see cref="ByteBuffer"/> position is 0 on input. /// <para/> /// The buffer byte order is set according to the data. /// The buffer position is advanced past the header (including UDataInfo and comment). /// <para/> /// See C++ ucmndata.h and unicode/udata.h. /// </remarks> /// <returns>dataVersion</returns> /// <exception cref="IOException">If this is not a valid ICU data item of the expected dataFormat.</exception> public static int ReadHeader(ByteBuffer bytes, int dataFormat, IAuthenticate authenticate) { Debug.Assert(bytes != null && bytes.Position == 0); byte magic1 = bytes.Get(2); byte magic2 = bytes.Get(3); if (magic1 != MAGIC1 || magic2 != MAGIC2) { throw new IOException(MAGIC_NUMBER_AUTHENTICATION_FAILED_); } byte isBigEndian = bytes.Get(8); byte charsetFamily = bytes.Get(9); byte sizeofUChar = bytes.Get(10); if (isBigEndian < 0 || 1 < isBigEndian || charsetFamily != CHAR_SET_ || sizeofUChar != CHAR_SIZE_) { throw new IOException(HEADER_AUTHENTICATION_FAILED_); } bytes.Order = isBigEndian != 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; int headerSize = bytes.GetChar(0); int sizeofUDataInfo = bytes.GetChar(4); if (sizeofUDataInfo < 20 || headerSize < (sizeofUDataInfo + 4)) { throw new IOException("Internal Error: Header size error"); } // TODO: Change Authenticate to take int major, int minor, int milli, int micro // to avoid array allocation. byte[] formatVersion = new byte[] { bytes.Get(16), bytes.Get(17), bytes.Get(18), bytes.Get(19) }; if (bytes.Get(12) != (byte)(dataFormat >> 24) || bytes.Get(13) != (byte)(dataFormat >> 16) || bytes.Get(14) != (byte)(dataFormat >> 8) || bytes.Get(15) != (byte)dataFormat || (authenticate != null && !authenticate.IsDataVersionAcceptable(formatVersion))) { // "; data format %02x%02x%02x%02x, format version %d.%d.%d.%d" throw new IOException(HEADER_AUTHENTICATION_FAILED_ + string.Format("; data format {0:x2}{1:x2}{2:x2}{3:x2}, format version {4}.{5}.{6}.{7}", bytes.Get(12), bytes.Get(13), bytes.Get(14), bytes.Get(15), formatVersion[0] & 0xff, formatVersion[1] & 0xff, formatVersion[2] & 0xff, formatVersion[3] & 0xff)); } bytes.Position = headerSize; return // dataVersion ((bytes.Get(20) << 24) | ((bytes.Get(21) & 0xff) << 16) | ((bytes.Get(22) & 0xff) << 8) | (bytes.Get(23) & 0xff)); }