Switch to compiler-tester
[mono.git] / mcs / class / System.Drawing / System.Drawing / ComIStreamWrapper.cs
1 //
2 // System.Drawing.ComIStreamWrapper.cs
3 //
4 // Author:
5 //   Kornél Pál <http://www.kornelpal.hu/>
6 //
7 // Copyright (C) 2005 Kornél Pál
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System;
32 using System.IO;
33 using System.Reflection;
34 using System.Runtime.InteropServices;
35 #if NET_2_0
36 using System.Runtime.InteropServices.ComTypes;
37 using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG;
38 #else
39 using IStream = System.Runtime.InteropServices.UCOMIStream;
40 #endif
41
42 namespace System.Drawing
43 {
44         // Stream to IStream wrapper for COM interop
45         internal sealed class ComIStreamWrapper : IStream
46         {
47                 private const int STG_E_INVALIDFUNCTION = unchecked((int)0x80030001);
48
49                 private readonly Stream baseStream;
50                 private long position = -1;
51
52                 internal ComIStreamWrapper(Stream stream)
53                 {
54                         baseStream = stream;
55                 }
56
57                 private void SetSizeToPosition()
58                 {
59                         if (position != -1)
60                         {
61                                 if (position > baseStream.Length)
62                                         baseStream.SetLength(position);
63                                 baseStream.Position = position;
64                                 position = -1;
65                         }
66                 }
67
68                 public void Read(byte[] pv, int cb, IntPtr pcbRead)
69                 {
70                         int read = 0;
71
72                         if (cb != 0)
73                         {
74                                 SetSizeToPosition();
75
76                                 read = baseStream.Read(pv, 0, cb);
77                         }
78
79                         if (pcbRead != IntPtr.Zero)
80                                 Marshal.WriteInt32(pcbRead, read);
81                 }
82
83                 public void Write(byte[] pv, int cb, IntPtr pcbWritten)
84                 {
85                         if (cb != 0)
86                         {
87                                 SetSizeToPosition();
88
89                                 baseStream.Write(pv, 0, cb);
90                         }
91
92                         if (pcbWritten != IntPtr.Zero)
93                                 Marshal.WriteInt32(pcbWritten, cb);
94                 }
95
96                 public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
97                 {
98                         long newPosition;
99
100                         if (baseStream.CanWrite)
101                         {
102                                 switch ((SeekOrigin)dwOrigin)
103                                 {
104                                         case SeekOrigin.Begin:
105                                                 newPosition = dlibMove;
106                                                 break;
107                                         case SeekOrigin.Current:
108                                                 if ((newPosition = position) == -1)
109                                                         newPosition = baseStream.Position;
110                                                 newPosition += dlibMove;
111                                                 break;
112                                         case SeekOrigin.End:
113                                                 newPosition = baseStream.Length + dlibMove;
114                                                 break;
115                                         default:
116                                                 throw new ExternalException(null, STG_E_INVALIDFUNCTION);
117                                 }
118
119                                 if (newPosition > baseStream.Length)
120                                         position = newPosition;
121                                 else
122                                 {
123                                         baseStream.Position = newPosition;
124                                         position = -1;
125                                 }
126                         }
127                         else
128                         {
129                                 try
130                                 {
131                                         newPosition = baseStream.Seek(dlibMove, (SeekOrigin)dwOrigin);
132                                 }
133                                 catch (ArgumentException)
134                                 {
135                                         throw new ExternalException(null, STG_E_INVALIDFUNCTION);
136                                 }
137                                 position = -1;
138                         }
139
140                         if (plibNewPosition != IntPtr.Zero)
141                                 Marshal.WriteInt64(plibNewPosition, newPosition);
142                 }
143
144                 public void SetSize(long libNewSize)
145                 {
146                         baseStream.SetLength(libNewSize);
147                 }
148
149                 public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
150                 {
151                         byte[] buffer = new byte[4096];
152                         long written = 0;
153                         int read;
154
155                         if (cb != 0)
156                         {
157                                 SetSizeToPosition();
158                                 do
159                                 {
160                                         int count = 4096;
161
162                                         if (written + 4096 > cb)
163                                                 count = (int)(cb - written);
164
165                                         if ((read = baseStream.Read(buffer, 0, count)) == 0)
166                                                 break;
167                                         pstm.Write(buffer, read, IntPtr.Zero);
168                                         written += read;
169                                 } while (written < cb);
170                         }
171
172                         if (pcbRead != IntPtr.Zero)
173                                 Marshal.WriteInt64(pcbRead, written);
174                         if (pcbWritten != IntPtr.Zero)
175                                 Marshal.WriteInt64(pcbWritten, written);
176                 }
177
178                 public void Commit(int grfCommitFlags)
179                 {
180                         baseStream.Flush();
181                 }
182
183                 public void Revert()
184                 {
185                         throw new ExternalException(null, STG_E_INVALIDFUNCTION);
186                 }
187
188                 public void LockRegion(long libOffset, long cb, int dwLockType)
189                 {
190                         throw new ExternalException(null, STG_E_INVALIDFUNCTION);
191                 }
192
193                 public void UnlockRegion(long libOffset, long cb, int dwLockType)
194                 {
195                         throw new ExternalException(null, STG_E_INVALIDFUNCTION);
196                 }
197
198                 public void Stat(out STATSTG pstatstg, int grfStatFlag)
199                 {
200                         pstatstg = new STATSTG();
201                         pstatstg.cbSize = baseStream.Length;
202                 }
203
204                 public void Clone(out IStream ppstm)
205                 {
206                         ppstm = null;
207                         throw new ExternalException(null, STG_E_INVALIDFUNCTION);
208                 }
209         }
210 }