private void ReadData(ByteBuffer bytes) { // read the header ICUBinary.ReadHeader(bytes, FMT, new IsAcceptable()); // read indexes[] int i, count; count = bytes.GetInt32(); if (count < IX_TOP) { throw new IOException("indexes[0] too small in " + DATA_FILE_NAME); } indexes = new int[count]; indexes[0] = count; for (i = 1; i < count; ++i) { indexes[i] = bytes.GetInt32(); } // read the trie trie = Trie2_16.CreateFromSerialized(bytes); int expectedTrieLength = indexes[IX_TRIE_SIZE]; int trieLength = trie.SerializedLength; if (trieLength > expectedTrieLength) { throw new IOException(DATA_FILE_NAME + ": not enough bytes for the trie"); } // skip padding after trie bytes ICUBinary.SkipBytes(bytes, expectedTrieLength - trieLength); // read mirrors[] count = indexes[IX_MIRROR_LENGTH]; if (count > 0) { mirrors = ICUBinary.GetInt32s(bytes, count, 0); } // read jgArray[] count = indexes[IX_JG_LIMIT] - indexes[IX_JG_START]; jgArray = new byte[count]; bytes.Get(jgArray); // read jgArray2[] count = indexes[IX_JG_LIMIT2] - indexes[IX_JG_START2]; jgArray2 = new byte[count]; bytes.Get(jgArray2); }
private void ReadData(ByteBuffer bytes) { // read the header ICUBinary.ReadHeader(bytes, FMT, new IsAcceptable()); // read indexes[] int count = bytes.GetInt32(); if (count < IX_TOP) { throw new IOException("indexes[0] too small in " + DATA_FILE_NAME); } indexes = new int[count]; indexes[0] = count; for (int i = 1; i < count; ++i) { indexes[i] = bytes.GetInt32(); } // read the trie trie = Trie2_16.CreateFromSerialized(bytes); int expectedTrieLength = indexes[IX_TRIE_SIZE]; int trieLength = trie.GetSerializedLength(); if (trieLength > expectedTrieLength) { throw new IOException(DATA_FILE_NAME + ": not enough bytes for the trie"); } // skip padding after trie bytes ICUBinary.SkipBytes(bytes, expectedTrieLength - trieLength); // read exceptions[] count = indexes[IX_EXC_LENGTH]; if (count > 0) { exceptions = ICUBinary.GetString(bytes, count, 0); } // read unfold[] count = indexes[IX_UNFOLD_LENGTH]; if (count > 0) { unfold = ICUBinary.GetChars(bytes, count, 0); } }
/// <summary> /// Create a <see cref="Trie2"/> from its serialized form. Inverse of utrie2_serialize(). /// </summary> /// <remarks> /// Reads from the current position and leaves the buffer after the end of the trie. /// <para/> /// The serialized format is identical between ICU4C, ICU4J, and ICU4N, so this function /// will work with serialized <see cref="Trie2"/>s from any. /// <para/> /// The actual type of the returned <see cref="Trie2"/> will be either <see cref="Trie2_16"/> or <see cref="Trie2_32"/>, depending /// on the width of the data. /// <para/> /// To obtain the width of the <see cref="Trie2"/>, check the actual class type of the returned <see cref="Trie2"/>. /// Or use the <see cref="Trie2_16.CreateFromSerialized(ByteBuffer)"/> or <see cref="Trie2_32.CreateFromSerialized(ByteBuffer)"/> method, which will /// return only <see cref="Trie"/>s of their specific type/size. /// <para/> /// The serialized <see cref="Trie2"/> on the stream may be in either little or big endian byte order. /// This allows using serialized <see cref="Trie"/>s from ICU4C without needing to consider the /// byte order of the system that created them. /// </remarks> /// <param name="bytes">A byte buffer to the serialized form of a UTrie2.</param> /// <returns>An unserialized <see cref="Trie2"/>, ready for use.</returns> /// <exception cref="ArgumentException">If the stream does not contain a serialized <see cref="Trie2"/>.</exception> /// <exception cref="IOException">If a read error occurs in the buffer.</exception> public static Trie2 CreateFromSerialized(ByteBuffer bytes) // ICU4N TODO: API Create overload that accepts byte[] { // From ICU4C utrie2_impl.h // * Trie2 data structure in serialized form: // * // * UTrie2Header header; // * uint16_t index[header.index2Length]; // * uint16_t data[header.shiftedDataLength<<2]; -- or uint32_t data[...] // * @internal // */ // typedef struct UTrie2Header { // /** "Tri2" in big-endian US-ASCII (0x54726932) */ // uint32_t signature; // /** // * options bit field: // * 15.. 4 reserved (0) // * 3.. 0 UTrie2ValueBits valueBits // */ // uint16_t options; // // /** UTRIE2_INDEX_1_OFFSET..UTRIE2_MAX_INDEX_LENGTH */ // uint16_t indexLength; // // /** (UTRIE2_DATA_START_OFFSET..UTRIE2_MAX_DATA_LENGTH)>>UTRIE2_INDEX_SHIFT */ // uint16_t shiftedDataLength; // // /** Null index and data blocks, not shifted. */ // uint16_t index2NullOffset, dataNullOffset; // // /** // * First code point of the single-value range ending with U+10ffff, // * rounded up and then shifted right by UTRIE2_SHIFT_1. // */ // uint16_t shiftedHighStart; // } UTrie2Header; ByteOrder outerByteOrder = bytes.Order; try { UTrie2Header header = new UTrie2Header(); /* check the signature */ header.signature = bytes.GetInt32(); switch (header.signature) { case 0x54726932: // The buffer is already set to the trie data byte order. break; case 0x32697254: // Temporarily reverse the byte order. bool isBigEndian = outerByteOrder == ByteOrder.BigEndian; bytes.Order = isBigEndian ? ByteOrder.LittleEndian : ByteOrder.BigEndian; header.signature = 0x54726932; break; default: throw new ArgumentException("Buffer does not contain a serialized UTrie2"); } header.options = bytes.GetChar(); header.indexLength = bytes.GetChar(); header.shiftedDataLength = bytes.GetChar(); header.index2NullOffset = bytes.GetChar(); header.dataNullOffset = bytes.GetChar(); header.shiftedHighStart = bytes.GetChar(); // Trie2 data width - 0: 16 bits // 1: 32 bits if ((header.options & UTRIE2_OPTIONS_VALUE_BITS_MASK) > 1) { throw new ArgumentException("UTrie2 serialized format error."); } ValueWidth width; Trie2 This; if ((header.options & UTRIE2_OPTIONS_VALUE_BITS_MASK) == 0) { width = ValueWidth.BITS_16; This = new Trie2_16(); } else { width = ValueWidth.BITS_32; This = new Trie2_32(); } This.header = header; /* get the length values and offsets */ This.indexLength = header.indexLength; This.dataLength = header.shiftedDataLength << UTRIE2_INDEX_SHIFT; This.index2NullOffset = header.index2NullOffset; This.dataNullOffset = header.dataNullOffset; This.highStart = header.shiftedHighStart << UTRIE2_SHIFT_1; This.highValueIndex = This.dataLength - UTRIE2_DATA_GRANULARITY; if (width == ValueWidth.BITS_16) { This.highValueIndex += This.indexLength; } // Allocate the Trie2 index array. If the data width is 16 bits, the array also // includes the space for the data. int indexArraySize = This.indexLength; if (width == ValueWidth.BITS_16) { indexArraySize += This.dataLength; } /* Read in the index */ This.index = ICUBinary.GetChars(bytes, indexArraySize, 0); /* Read in the data. 16 bit data goes in the same array as the index. * 32 bit data goes in its own separate data array. */ if (width == ValueWidth.BITS_16) { This.data16 = This.indexLength; } else { This.data32 = ICUBinary.GetInt32s(bytes, This.dataLength, 0); } switch (width) { case ValueWidth.BITS_16: This.data32 = null; This.initialValue = This.index[This.dataNullOffset]; This.errorValue = This.index[This.data16 + UTRIE2_BAD_UTF8_DATA_OFFSET]; break; case ValueWidth.BITS_32: This.data16 = 0; This.initialValue = This.data32[This.dataNullOffset]; This.errorValue = This.data32[UTRIE2_BAD_UTF8_DATA_OFFSET]; break; default: throw new ArgumentException("UTrie2 serialized format error."); } return(This); } finally { bytes.Order = outerByteOrder; } }