protected int WriteData(TextElement data, bool closing = false)
{
// Set file access to writing
CurrentAccess = FileAccess.Write;
if (!CanWrite) return -1;
Debug.Assert(!data.IsNull);
int consumed = data.Length;
writeFilteredCount += consumed;
if (writeFilters != null)
{
// Process the data through the custom write filters first.
foreach (IFilter f in writeFilters)
{
if (data.IsNull)
{
// When closing, feed all the filters with data.
if (closing) data = TextElement.Empty;
else return consumed; // Eaten all
}
data = f.Filter(_ctx, data, closing);
if (closing) f.OnClose();
}
}
if (textWriteFilter != null)
{
// Then pass it through the text-conversion filter if any.
data = textWriteFilter.Filter(_ctx, data, closing);
}
// From now on, the data is treated just as binary
byte[] bin = data.AsBytes(_ctx.StringEncoding);
if (bin.Length == 0)
{
return consumed;
}
// Append the resulting data to the output buffer if any.
if (IsWriteBuffered)
{
// Is this the first access?
if (writeBuffer == null)
{
writeBuffer = new byte[writeBufferSize];
writePosition = 0;
}
// The whole binary data fits in the buffer, great!
if (writeBufferSize - writePosition > bin.Length)
{
Array.Copy(bin, 0, writeBuffer, writePosition, bin.Length);
writePosition += bin.Length;
return consumed;
}
int copied = 0;
// Use the buffer for small data only
if (writeBufferSize > bin.Length)
{
// Otherwise fill the buffer and flush it.
copied = writeBufferSize - writePosition;
Array.Copy(bin, 0, writeBuffer, writePosition, copied);
writePosition += copied;
}
// Flush the buffer
if ((writePosition > 0) && (!FlushWriteBuffer()))
return (copied > 0) ? copied : -1; // It is an error but still some output was written.
if (bin.Length - copied >= writeBufferSize)
{
// If the binary data is really big, write it directly to stream.
while (copied < bin.Length)
{
int written = RawWrite(bin, copied, bin.Length - copied);
if (written <= 0)
{
PhpException.Throw(PhpError.Warning, ErrResources.stream_write_failed, copied.ToString(), bin.Length.ToString());
return (copied > 0) ? copied : -1; // It is an error but still some output was written.
}
copied += written;
writeOffset += written;
}
}
else
{
// Otherwise just start a new buffer with the rest of the data.
Array.Copy(bin, copied, writeBuffer, 0, bin.Length - copied);
writePosition = bin.Length - copied;
}
return consumed;
}
else
{
// No write buffer. Write the data directly.
int copied = 0;
while (copied < bin.Length)
{
int written = RawWrite(bin, copied, bin.Length - copied);
if (written <= 0)
{
PhpException.Throw(PhpError.Warning, ErrResources.stream_write_failed, copied.ToString(), bin.Length.ToString());
return (copied > 0) ? copied : -1; // ERROR but maybe some was written.
}
copied += written;
writeOffset += written;
}
return consumed;
}
}