Exemplo n.º 1
0
        /// <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));
        }