internal bool TryPlpBytesLeft(TdsParserStateObject stateObj, out ulong left) { if ((stateObj._longlen != 0) && (stateObj._longlenleft == 0)) { if (!stateObj.TryReadPlpLength(false, out left)) { return false; } } left = stateObj._longlenleft; return true; }
// Reads the requested number of chars from a plp data stream, or the entire data if // requested length is -1 or larger than the actual length of data. First call to this method // should be preceeded by a call to ReadPlpLength or ReadDataLength. // Returns the actual chars read. internal bool TryReadPlpUnicodeChars(ref char[] buff, int offst, int len, TdsParserStateObject stateObj, out int totalCharsRead) { int charsRead = 0; int charsLeft = 0; char[] newbuf; if (stateObj._longlen == 0) { Debug.Assert(stateObj._longlenleft == 0); totalCharsRead = 0; return true; // No data } Debug.Assert(((ulong)stateObj._longlen != TdsEnums.SQL_PLP_NULL), "Out of sync plp read request"); Debug.Assert((buff == null && offst == 0) || (buff.Length >= offst + len), "Invalid length sent to ReadPlpUnicodeChars()!"); charsLeft = len; // If total length is known up front, allocate the whole buffer in one shot instead of realloc'ing and copying over each time if (buff == null && stateObj._longlen != TdsEnums.SQL_PLP_UNKNOWNLEN) { buff = new char[(int)Math.Min((int)stateObj._longlen, len)]; } if (stateObj._longlenleft == 0) { ulong ignored; if (!stateObj.TryReadPlpLength(false, out ignored)) { totalCharsRead = 0; return false; } if (stateObj._longlenleft == 0) { // Data read complete totalCharsRead = 0; return true; } } totalCharsRead = 0; while (charsLeft > 0) { charsRead = (int)Math.Min((stateObj._longlenleft + 1) >> 1, (ulong)charsLeft); if ((buff == null) || (buff.Length < (offst + charsRead))) { // Grow the array newbuf = new char[offst + charsRead]; if (buff != null) { Buffer.BlockCopy(buff, 0, newbuf, 0, offst * 2); } buff = newbuf; } if (charsRead > 0) { if (!TryReadPlpUnicodeCharsChunk(buff, offst, charsRead, stateObj, out charsRead)) { return false; } charsLeft -= charsRead; offst += charsRead; totalCharsRead += charsRead; } // Special case single byte left if (stateObj._longlenleft == 1 && (charsLeft > 0)) { byte b1; if (!stateObj.TryReadByte(out b1)) { return false; } stateObj._longlenleft--; ulong ignored; if (!stateObj.TryReadPlpLength(false, out ignored)) { return false; } Debug.Assert((stateObj._longlenleft != 0), "ReadPlpUnicodeChars: Odd byte left at the end!"); byte b2; if (!stateObj.TryReadByte(out b2)) { return false; } stateObj._longlenleft--; // Put it at the end of the array. At this point we know we have an extra byte. buff[offst] = (char)(((b2 & 0xff) << 8) + (b1 & 0xff)); offst = checked((int)offst + 1); charsRead++; charsLeft--; totalCharsRead++; } if (stateObj._longlenleft == 0) { // Read the next chunk or cleanup state if hit the end ulong ignored; if (!stateObj.TryReadPlpLength(false, out ignored)) { return false; } } if (stateObj._longlenleft == 0) // Data read complete break; } return true; }
internal bool TrySkipPlpValue(ulong cb, TdsParserStateObject stateObj, out ulong totalBytesSkipped) { // Read and skip cb bytes or until ReadPlpLength returns 0. int bytesSkipped; totalBytesSkipped = 0; if (stateObj._longlenleft == 0) { ulong ignored; if (!stateObj.TryReadPlpLength(false, out ignored)) { return false; } } while ((totalBytesSkipped < cb) && (stateObj._longlenleft > 0)) { if (stateObj._longlenleft > Int32.MaxValue) bytesSkipped = Int32.MaxValue; else bytesSkipped = (int)stateObj._longlenleft; bytesSkipped = ((cb - totalBytesSkipped) < (ulong)bytesSkipped) ? (int)(cb - totalBytesSkipped) : bytesSkipped; if (!stateObj.TrySkipBytes(bytesSkipped)) { return false; } stateObj._longlenleft -= (ulong)bytesSkipped; totalBytesSkipped += (ulong)bytesSkipped; if (stateObj._longlenleft == 0) { ulong ignored; if (!stateObj.TryReadPlpLength(false, out ignored)) { return false; } } } return true; }
// // Returns the data stream length of the data identified by tds type or SqlMetaData returns // Returns either the total size or the size of the first chunk for partially length prefixed types. // internal bool TryGetDataLength(SqlMetaDataPriv colmeta, TdsParserStateObject stateObj, out ulong length) { // Handle Yukon specific tokens if (colmeta.metaType.IsPlp) { Debug.Assert(colmeta.tdsType == TdsEnums.SQLXMLTYPE || colmeta.tdsType == TdsEnums.SQLBIGVARCHAR || colmeta.tdsType == TdsEnums.SQLBIGVARBINARY || colmeta.tdsType == TdsEnums.SQLNVARCHAR || // Large UDTs is WinFS-only colmeta.tdsType == TdsEnums.SQLUDT, "GetDataLength:Invalid streaming datatype"); return stateObj.TryReadPlpLength(true, out length); } else { int intLength; if (!TryGetTokenLength(colmeta.tdsType, stateObj, out intLength)) { length = 0; return false; } length = (ulong)intLength; return true; } }