Skip to content

Commit e0cf818

Browse files
committed
Create a base class for the stream wrapper to make it possible to have a separate stream for async operations.
1 parent 3054931 commit e0cf818

2 files changed

Lines changed: 166 additions & 138 deletions

File tree

Lines changed: 13 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -1,168 +1,43 @@
11
// Copyright Dirk Lemstra https://github.com/dlemstra/Magick.NET.
22
// Licensed under the Apache License, Version 2.0.
33

4-
using System;
54
using System.IO;
6-
using System.Runtime.InteropServices;
75

86
namespace ImageMagick;
97

10-
internal sealed unsafe class StreamWrapper : IDisposable
8+
internal sealed class StreamWrapper : StreamWrapperBase
119
{
12-
private const int BufferSize = 8192;
13-
14-
private readonly PooledByteArray _buffer;
15-
private readonly byte* _bufferStart;
16-
private readonly long _streamStart;
17-
private readonly GCHandle _handle;
18-
private Stream _stream;
10+
private readonly Stream _stream;
1911

2012
private StreamWrapper(Stream stream)
13+
: base(stream)
2114
{
2215
_stream = stream;
23-
_buffer = new PooledByteArray(BufferSize);
24-
_handle = GCHandle.Alloc(_buffer.Data, GCHandleType.Pinned);
25-
_bufferStart = (byte*)_handle.AddrOfPinnedObject().ToPointer();
26-
27-
try
28-
{
29-
_streamStart = _stream.Position;
30-
}
31-
catch
32-
{
33-
_streamStart = 0;
34-
}
3516
}
3617

3718
public static StreamWrapper CreateForReading(Stream stream)
3819
{
3920
Throw.IfFalse(stream.CanRead, nameof(stream), "The stream should be readable.");
4021

41-
return new StreamWrapper(stream);
22+
return new(stream);
4223
}
4324

4425
public static StreamWrapper CreateForWriting(Stream stream)
4526
{
4627
Throw.IfFalse(stream.CanWrite, nameof(stream), "The stream should be writable.");
4728

48-
return new StreamWrapper(stream);
49-
}
50-
51-
public void Dispose()
52-
{
53-
_handle.Free();
54-
_buffer.Dispose();
29+
return new(stream);
5530
}
5631

57-
public long Read(IntPtr data, UIntPtr count, IntPtr user_data)
58-
{
59-
var total = (long)count;
60-
if (total == 0)
61-
return 0;
62-
63-
if (data == IntPtr.Zero)
64-
return 0;
65-
66-
var destination = (byte*)data.ToPointer();
67-
long bytesRead = 0;
68-
69-
while (total > 0)
70-
{
71-
var length = Math.Min(total, BufferSize);
32+
protected override int Read(int count)
33+
=> _stream.Read(Data, 0, count);
7234

73-
try
74-
{
75-
length = _stream.Read(_buffer.Data, 0, (int)length);
76-
}
77-
catch
78-
{
79-
return -1;
80-
}
35+
protected override long Seek(long offset, SeekOrigin origin)
36+
=> _stream.Seek(offset, origin);
8137

82-
if (length == 0)
83-
break;
38+
protected override long Tell()
39+
=> _stream.Position;
8440

85-
bytesRead += length;
86-
87-
destination = ReadBuffer(destination, length);
88-
89-
total -= length;
90-
}
91-
92-
return bytesRead;
93-
}
94-
95-
public long Seek(long offset, IntPtr whence, IntPtr user_data)
96-
{
97-
try
98-
{
99-
return (SeekOrigin)whence switch
100-
{
101-
SeekOrigin.Begin => _stream.Seek(_streamStart + offset, SeekOrigin.Begin) - _streamStart,
102-
SeekOrigin.Current => _stream.Seek(offset, SeekOrigin.Current) - _streamStart,
103-
SeekOrigin.End => _stream.Seek(offset, SeekOrigin.End) - _streamStart,
104-
_ => -1,
105-
};
106-
}
107-
catch
108-
{
109-
return -1;
110-
}
111-
}
112-
113-
public long Tell(IntPtr user_data)
114-
{
115-
try
116-
{
117-
return _stream.Position - _streamStart;
118-
}
119-
catch
120-
{
121-
return -1;
122-
}
123-
}
124-
125-
public long Write(IntPtr data, UIntPtr count, IntPtr user_data)
126-
{
127-
var total = (long)count;
128-
if (total == 0)
129-
return 0;
130-
131-
if (data == IntPtr.Zero)
132-
return 0;
133-
134-
var source = (byte*)data.ToPointer();
135-
136-
while (total > 0)
137-
{
138-
var length = Math.Min(total, BufferSize);
139-
140-
source = FillBuffer(source, length);
141-
142-
try
143-
{
144-
_stream.Write(_buffer.Data, 0, (int)length);
145-
}
146-
catch
147-
{
148-
return -1;
149-
}
150-
151-
total -= length;
152-
}
153-
154-
return (long)count;
155-
}
156-
157-
private byte* FillBuffer(byte* source, long length)
158-
{
159-
NativeMemory.Copy(source, _bufferStart, length);
160-
return source + length;
161-
}
162-
163-
private byte* ReadBuffer(byte* destination, long length)
164-
{
165-
NativeMemory.Copy(_bufferStart, destination, length);
166-
return destination + length;
167-
}
41+
protected override void Write(int count)
42+
=> _stream.Write(Data, 0, count);
16843
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright Dirk Lemstra https://github.com/dlemstra/Magick.NET.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
using System;
5+
using System.IO;
6+
using System.Runtime.InteropServices;
7+
8+
namespace ImageMagick;
9+
10+
internal abstract unsafe class StreamWrapperBase : IDisposable
11+
{
12+
private const int BufferSize = 8192;
13+
14+
private readonly PooledByteArray _buffer;
15+
private readonly GCHandle _handle;
16+
private readonly byte* _bufferStart;
17+
private readonly long _streamStart;
18+
19+
protected StreamWrapperBase(Stream stream)
20+
{
21+
_buffer = new PooledByteArray(BufferSize);
22+
_handle = GCHandle.Alloc(_buffer.Data, GCHandleType.Pinned);
23+
_bufferStart = (byte*)_handle.AddrOfPinnedObject().ToPointer();
24+
25+
try
26+
{
27+
_streamStart = stream.Position;
28+
}
29+
catch
30+
{
31+
_streamStart = 0;
32+
}
33+
}
34+
35+
protected byte[] Data
36+
=> _buffer.Data;
37+
38+
public void Dispose()
39+
{
40+
_handle.Free();
41+
_buffer.Dispose();
42+
}
43+
44+
public long Read(IntPtr data, UIntPtr count, IntPtr user_data)
45+
{
46+
var total = (long)count;
47+
if (total == 0)
48+
return 0;
49+
50+
if (data == IntPtr.Zero)
51+
return 0;
52+
53+
var destination = (byte*)data.ToPointer();
54+
long bytesRead = 0;
55+
56+
while (total > 0)
57+
{
58+
var length = (int)Math.Min(total, BufferSize);
59+
60+
try
61+
{
62+
length = Read(length);
63+
if (length == 0)
64+
break;
65+
66+
NativeMemory.Copy(_bufferStart, destination, length);
67+
}
68+
catch
69+
{
70+
return -1;
71+
}
72+
73+
if (length == 0)
74+
break;
75+
76+
bytesRead += length;
77+
destination += length;
78+
total -= length;
79+
}
80+
81+
return bytesRead;
82+
}
83+
84+
public long Seek(long offset, IntPtr whence, IntPtr user_data)
85+
{
86+
try
87+
{
88+
return (SeekOrigin)whence switch
89+
{
90+
SeekOrigin.Begin => Seek(_streamStart + offset, SeekOrigin.Begin) - _streamStart,
91+
SeekOrigin.Current => Seek(offset, SeekOrigin.Current) - _streamStart,
92+
SeekOrigin.End => Seek(offset, SeekOrigin.End) - _streamStart,
93+
_ => -1,
94+
};
95+
}
96+
catch
97+
{
98+
return -1;
99+
}
100+
}
101+
102+
public long Tell(IntPtr user_data)
103+
{
104+
try
105+
{
106+
return Tell() - _streamStart;
107+
}
108+
catch
109+
{
110+
return -1;
111+
}
112+
}
113+
114+
public long Write(IntPtr data, UIntPtr count, IntPtr user_data)
115+
{
116+
var total = (long)count;
117+
if (total == 0)
118+
return 0;
119+
120+
if (data == IntPtr.Zero)
121+
return 0;
122+
123+
var source = (byte*)data.ToPointer();
124+
125+
while (total > 0)
126+
{
127+
var length = (int)Math.Min(total, BufferSize);
128+
129+
try
130+
{
131+
NativeMemory.Copy(source, _bufferStart, length);
132+
Write(length);
133+
}
134+
catch
135+
{
136+
return -1;
137+
}
138+
139+
source += length;
140+
total -= length;
141+
}
142+
143+
return (long)count;
144+
}
145+
146+
protected abstract int Read(int count);
147+
148+
protected abstract long Seek(long offset, SeekOrigin origin);
149+
150+
protected abstract long Tell();
151+
152+
protected abstract void Write(int count);
153+
}

0 commit comments

Comments
 (0)