/// <summary>Encode the given crazy code bytes into the given byte stream.</summary> /// <remarks>Encode the given crazy code bytes into the given byte stream.</remarks> /// <exception cref="System.IO.IOException"></exception> private static void WriteCrazyCodes(ByteUtil.ByteStream crazyCodes, ByteUtil.ByteStream bout) { // CRAZY_CODE_2 flags at the end are ignored, so ditch them TrimExtraCodes(crazyCodes, CRAZY_CODE_2, CRAZY_CODE_2); if (crazyCodes.GetLength() > 0) { // the crazy codes get encoded into 6 bit sequences where each code is 2 // bits (where the first 2 bits in the byte are a common prefix). byte curByte = CRAZY_CODE_START; int idx = 0; for (int i = 0; i < crazyCodes.GetLength(); ++i) { byte nextByte = crazyCodes.Get(i); nextByte <<= ((2 - idx) * 2); curByte |= nextByte; ++idx; if (idx == 3) { // write current byte and reset bout.Write(curByte); curByte = CRAZY_CODE_START; idx = 0; } } // write last byte if (idx > 0) { bout.Write(curByte); } } // write crazy code suffix (note, we write this even if all the codes are // trimmed bout.Write(CRAZY_CODES_SUFFIX); }
/// <summary> /// Trims any bytes in the given range off of the end of the given stream, /// returning whether or not there are any bytes left in the given stream /// after trimming. /// </summary> /// <remarks> /// Trims any bytes in the given range off of the end of the given stream, /// returning whether or not there are any bytes left in the given stream /// after trimming. /// </remarks> /// <exception cref="System.IO.IOException"></exception> private static bool TrimExtraCodes(ByteUtil.ByteStream extraCodes, byte minTrimCode , byte maxTrimCode) { if (extraCodes == null) { return(false); } extraCodes.TrimTrailing(minTrimCode, maxTrimCode); // anything left? return(extraCodes.GetLength() > 0); }
/// <summary> /// Converts an index value for a text column into the entry value (which /// is based on a variety of nifty codes). /// </summary> /// <remarks> /// Converts an index value for a text column into the entry value (which /// is based on a variety of nifty codes). /// </remarks> /// <exception cref="System.IO.IOException"></exception> internal virtual void WriteNonNullIndexTextValue(object value, ByteUtil.ByteStream bout, bool isAscending) { // first, convert to string string str = Column.ToCharSequence(value).ToString(); // all text columns (including memos) are only indexed up to the max // number of chars in a VARCHAR column if (str.Length > MAX_TEXT_INDEX_CHAR_LENGTH) { str = Sharpen.Runtime.Substring(str, 0, MAX_TEXT_INDEX_CHAR_LENGTH); } // record pprevious entry length so we can do any post-processing // necessary for this entry (handling descending) int prevLength = bout.GetLength(); // now, convert each character to a "code" of one or more bytes GeneralLegacyIndexCodes.ExtraCodesStream extraCodes = null; ByteUtil.ByteStream unprintableCodes = null; ByteUtil.ByteStream crazyCodes = null; int charOffset = 0; for (int i = 0; i < str.Length; ++i) { char c = str[i]; GeneralLegacyIndexCodes.CharHandler ch = GetCharHandler(c); int curCharOffset = charOffset; byte[] bytes = ch.GetInlineBytes(); if (bytes != null) { // write the "inline" codes immediately bout.Write(bytes); // only increment the charOffset for chars with inline codes ++charOffset; } if (ch.GetEncodingType() == GeneralLegacyIndexCodes.Type.SIMPLE) { // common case, skip further code handling continue; } bytes = ch.GetExtraBytes(); byte extraCodeModifier = ch.GetExtraByteModifier(); if ((bytes != null) || (extraCodeModifier != 0)) { if (extraCodes == null) { extraCodes = new GeneralLegacyIndexCodes.ExtraCodesStream(str.Length); } // keep track of the extra codes for later WriteExtraCodes(curCharOffset, bytes, extraCodeModifier, extraCodes); } bytes = ch.GetUnprintableBytes(); if (bytes != null) { if (unprintableCodes == null) { unprintableCodes = new ByteUtil.ByteStream(); } // keep track of the unprintable codes for later WriteUnprintableCodes(curCharOffset, bytes, unprintableCodes, extraCodes); } byte crazyFlag = ch.GetCrazyFlag(); if (crazyFlag != 0) { if (crazyCodes == null) { crazyCodes = new ByteUtil.ByteStream(); } // keep track of the crazy flags for later crazyCodes.Write(crazyFlag); } } // write end text flag bout.Write(END_TEXT); bool hasExtraCodes = TrimExtraCodes(extraCodes, unchecked ((byte)0), INTERNATIONAL_EXTRA_PLACEHOLDER ); bool hasUnprintableCodes = (unprintableCodes != null); bool hasCrazyCodes = (crazyCodes != null); if (hasExtraCodes || hasUnprintableCodes || hasCrazyCodes) { // we write all the international extra bytes first if (hasExtraCodes) { extraCodes.WriteTo(bout); } if (hasCrazyCodes || hasUnprintableCodes) { // write 2 more end flags bout.Write(END_TEXT); bout.Write(END_TEXT); // next come the crazy flags if (hasCrazyCodes) { WriteCrazyCodes(crazyCodes, bout); // if we are writing unprintable codes after this, tack on another // code if (hasUnprintableCodes) { bout.Write(CRAZY_CODES_UNPRINT_SUFFIX); } } // then we write all the unprintable extra bytes if (hasUnprintableCodes) { // write another end flag bout.Write(END_TEXT); unprintableCodes.WriteTo(bout); } } } // handle descending order by inverting the bytes if (!isAscending) { // we actually write the end byte before flipping the bytes, and write // another one after flipping bout.Write(END_EXTRA_TEXT); // flip the bytes that we have written thus far for this text value IndexData.FlipBytes(bout.GetBytes(), prevLength, (bout.GetLength() - prevLength)); } // write end extra text bout.Write(END_EXTRA_TEXT); }