using System;
using System.IO;
using System.Runtime.InteropServices;
using CC = System.Runtime.InteropServices.CallingConvention;
namespace MuPdfSharp
{
sealed class MuStream : IDisposable
{
const int __CompressionBomb = 100 << 20;
#region 非托管资源成员
readonly StreamHandle _stream;
readonly ContextHandle _context;
GCHandle _data;
#endregion
#region 托管资源成员
readonly int _knownDataLength;
readonly bool _sharedContext;
/// 获取或设置游标位置。
public int Position {
get => NativeMethods.GetPosition(_context, _stream);
set => Seek(value, SeekOrigin.Begin);
}
#endregion
internal MuStream(byte[] data) {
var ctx = ContextHandle.Create();
_knownDataLength = data.Length;
_data = GCHandle.Alloc(data, GCHandleType.Pinned);
_stream = new StreamHandle(ctx, NativeMethods.OpenMemory(ctx, _data.AddrOfPinnedObject(), _knownDataLength));
_context = ctx;
}
internal MuStream(ContextHandle ctx, string fileName) {
_stream = new StreamHandle(ctx, fileName);
_knownDataLength = -1;
_sharedContext = true;
}
private MuStream(ContextHandle ctx, StreamHandle stream) {
_context = ctx;
_stream = stream;
NativeMethods.Keep(ctx, stream);
_sharedContext = true;
}
///
/// 读取 字节到缓冲数组 。(可能抛出异常)
///
/// 放置读取数据的数组。
/// 要读取的数据长度。
/// 实际读取的长度。
public int Read(byte[] buffer, int length) {
return NativeMethods.Read(_context, _stream, buffer, length);
}
///
/// 读取流的所有内容到字节数组。(可能抛出异常)
///
/// 包含流中所有内容的数组。
public byte[] ReadAll(int initialSize) {
if (_knownDataLength > 0) {
var b = new byte[_knownDataLength];
NativeMethods.Read(_context, _stream, b, _knownDataLength);
return b;
}
else {
var b = new byte[initialSize];
int l;
using (var ms = new MemoryStream(initialSize))
using (var mw = new BinaryWriter(ms)) {
while ((l = NativeMethods.Read(_context, _stream, b, initialSize)) > 0) {
mw.Write(b, 0, l);
if (ms.Length >= __CompressionBomb && ms.Length / 200 > initialSize) {
throw new IOException("Compression bomb detected.");
}
}
ms.Flush();
return ms.ToArray();
}
}
}
///
/// 跳转到流的指定位置。
///
/// 偏移位置。
/// 跳转方式。
public void Seek(int offset, SeekOrigin origin) {
NativeMethods.Seek(_context, _stream, offset, origin == SeekOrigin.Begin ? 0 : origin == SeekOrigin.Current ? 1 : 2);
}
///
/// 将当前流视为以 CCITT Fax 压缩的图像来解压缩。
///
/// 图像宽度。
/// 图像高度。
///
///
///
///
///
/// 解压缩后的图像数据。
public MuStream DecodeTiffFax(int width, int height, int k, bool endOfLine, bool encodedByteAlign, bool endOfBlock, bool blackIs1) {
return new MuStream(
_context,
new StreamHandle(_context, NativeMethods.DecodeCcittFax(_context, _stream, k, endOfLine ? 1 : 0, encodedByteAlign ? 1 : 0, width, height, endOfBlock ? 1 : 0, blackIs1 ? 1 : 0))
);
}
#region 实现 IDisposable 接口的属性和方法
private bool disposed;
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this); // 抑制析构函数
}
/// 释放由 MuPdfPage 占用的资源。
/// 是否手动释放托管资源。
void Dispose(bool disposing) {
if (!disposed) {
if (disposing) {
#region 释放托管资源
//_components.Dispose ();
#endregion
}
#region 释放非托管资源
// 注意这里不是线程安全的
if (_stream.IsValid()) {
_stream.Dispose();
}
if (_sharedContext == false && _context.IsValid()) {
_context.Dispose();
}
if (_data.IsAllocated) {
_data.Free();
}
#endregion
}
disposed = true;
}
// 析构函数只在未调用 Dispose 方法时调用
// 派生类中不必再提供析构函数
~MuStream() {
Dispose(false);
}
#endregion
}
}