public TextElement ReadData(int length, bool ending)
{
if (length == 0) return TextElement.Null;
// Allow length to be -1 for ReadLine.
Debug.Assert((length > 0) || ending);
Debug.Assert(length >= -1);
// Set file access to reading
CurrentAccess = FileAccess.Read;
if (!CanRead) return TextElement.Null;
// If (length < 0) read up to \n, otherwise up to length bytes
// Unbuffered works only for Read not for ReadLine (blocks).
if (!IsReadBuffered && (readBuffers == null))
{
// The stream is a "pure" unbuffered. Read just the first packet.
var packet = TextElement.Null;
bool done = false;
while (!done)
{
int count = (length > 0) ? length : readChunkSize;
packet = ReadFiltered(count);
if (packet.IsNull) return TextElement.Null;
int filteredLength = packet.Length;
done = filteredLength > 0;
readFilteredCount += filteredLength;
if (length < 0)
{
// If the data contains the EOLN, store the rest into the buffers, otherwise return the whole packet.
int eoln = FindEoln(packet, 0);
if (eoln > 0)
{
TextElement rv, enq;
SplitData(packet, eoln, out rv, out enq);
if (enq.Length != 0) EnqueueReadBuffer(enq);
return rv;
}
}
}
return packet;
}
// Try to fill the buffers with enough data (to satisfy length).
int nlpos, buffered = ReadBufferScan(out nlpos), read = 0, newLength = length;
TextElement data = TextElement.Null;
if (ending && (nlpos >= readPosition))
{
// Found a \n in the buffered data (return the line inluding the EOLN).
// Network-based streams may be satisfied too.
newLength = nlpos - readPosition + 1;
}
else if ((length > 0) && (buffered >= length))
{
// Great! Just take some of the data in the buffers.
// NOP
}
else if (!IsReadBuffered && (buffered > 0))
{
// Use the first available packet for network-based streams.
newLength = buffered;
}
else
{
// There is not enough data in the buffers, read more.
for (;;)
{
data = ReadFiltered(readChunkSize);
if (data.IsNull)
{
// There is an EOF, return as much data as possible.
newLength = buffered;
break;
}
read = data.Length;
readFilteredCount += read;
if (read > 0) EnqueueReadBuffer(data);
buffered += read;
// For unbuffered streams accept the first packet and go check for EOLN.
if (!IsReadBuffered) newLength = buffered;
// First check for satisfaciton of the ending.
if (ending && !data.IsNull)
{
// Find the EOLN in the most recently read buffer.
int eoln = FindEoln(data, 0);
if (eoln >= 0)
{
// Read all the data up to (and including) the EOLN.
newLength = buffered - read + eoln + 1;
break;
}
}
// Check if there is enough data in the buffers (first packet etc).
if (length > 0)
{
if (buffered >= length) break;
}
}
}
// Apply the restriction of available data size or newline position
if ((newLength < length) || (length == -1)) length = newLength;
// Eof?
if ((readBuffers == null) || (readBuffers.Count == 0))
return TextElement.Null;
// Read the rest of the buffered data if no \n is found and there is an EOF.
if (length < 0) length = buffered;
if (this.IsText)
return new TextElement(ReadTextBuffer(length));
else
return new TextElement(ReadBinaryBuffer(length));
// Data may only be a string or PhpBytes (and consistently throughout all the buffers).
}