1 // Licensed to the .NET Foundation under one or more agreements. 2 // See the LICENSE file in the project root for more information. 3 // 4 // System.Drawing.GdiPlusStreamHelper.cs 5 // - Originally in System.Drawing.gdipFunctions.cs 6 // 7 // Authors: 8 // Alexandre Pigolkine (pigolkine@gmx.de) 9 // Jordi Mas i Hernandez (jordi@ximian.com) 10 // Sanjay Gupta (gsanjay@novell.com) 11 // Ravindra (rkumar@novell.com) 12 // Peter Dennis Bartok (pbartok@novell.com) 13 // Sebastien Pouliot <sebastien@ximian.com> 14 // 15 // Copyright (C) 2004 - 2007 Novell, Inc (http://www.novell.com) 16 // 17 // Permission is hereby granted, free of charge, to any person obtaining 18 // a copy of this software and associated documentation files (the 19 // "Software"), to deal in the Software without restriction, including 20 // without limitation the rights to use, copy, modify, merge, publish, 21 // distribute, sublicense, and/or sell copies of the Software, and to 22 // permit persons to whom the Software is furnished to do so, subject to 23 // the following conditions: 24 // 25 // The above copyright notice and this permission notice shall be 26 // included in all copies or substantial portions of the Software. 27 // 28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 29 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 30 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 31 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 32 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 33 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 34 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 35 // 36 37 using System.IO; 38 using System.Runtime.InteropServices; 39 40 namespace System.Drawing 41 { 42 internal sealed partial class GdiPlusStreamHelper 43 { 44 public Stream stream; 45 46 private StreamGetHeaderDelegate sghd = null; 47 private StreamGetBytesDelegate sgbd = null; 48 private StreamSeekDelegate skd = null; 49 private StreamPutBytesDelegate spbd = null; 50 private StreamCloseDelegate scd = null; 51 private StreamSizeDelegate ssd = null; 52 private byte[] start_buf; 53 private int start_buf_pos; 54 private int start_buf_len; 55 private byte[] managedBuf; 56 private const int default_bufsize = 4096; 57 GdiPlusStreamHelper(Stream s, bool seekToOrigin)58 public GdiPlusStreamHelper(Stream s, bool seekToOrigin) 59 { 60 managedBuf = new byte[default_bufsize]; 61 62 stream = s; 63 if (stream != null && stream.CanSeek && seekToOrigin) 64 { 65 stream.Seek(0, SeekOrigin.Begin); 66 } 67 } 68 StreamGetHeaderImpl(IntPtr buf, int bufsz)69 public int StreamGetHeaderImpl(IntPtr buf, int bufsz) 70 { 71 int bytesRead; 72 73 start_buf = new byte[bufsz]; 74 75 try 76 { 77 bytesRead = stream.Read(start_buf, 0, bufsz); 78 } 79 catch (IOException) 80 { 81 return -1; 82 } 83 84 if (bytesRead > 0 && buf != IntPtr.Zero) 85 { 86 Marshal.Copy(start_buf, 0, (IntPtr)(buf.ToInt64()), bytesRead); 87 } 88 89 start_buf_pos = 0; 90 start_buf_len = bytesRead; 91 92 return bytesRead; 93 } 94 95 public StreamGetHeaderDelegate GetHeaderDelegate 96 { 97 get 98 { 99 if (stream != null && stream.CanRead) 100 { 101 if (sghd == null) 102 { 103 sghd = new StreamGetHeaderDelegate(StreamGetHeaderImpl); 104 } 105 return sghd; 106 } 107 return null; 108 } 109 } 110 StreamGetBytesImpl(IntPtr buf, int bufsz, bool peek)111 public int StreamGetBytesImpl(IntPtr buf, int bufsz, bool peek) 112 { 113 if (buf == IntPtr.Zero && peek) 114 { 115 return -1; 116 } 117 118 if (bufsz > managedBuf.Length) 119 managedBuf = new byte[bufsz]; 120 int bytesRead = 0; 121 long streamPosition = 0; 122 123 if (bufsz > 0) 124 { 125 if (stream.CanSeek) 126 { 127 streamPosition = stream.Position; 128 } 129 if (start_buf_len > 0) 130 { 131 if (start_buf_len > bufsz) 132 { 133 Array.Copy(start_buf, start_buf_pos, managedBuf, 0, bufsz); 134 start_buf_pos += bufsz; 135 start_buf_len -= bufsz; 136 bytesRead = bufsz; 137 bufsz = 0; 138 } 139 else 140 { 141 // this is easy 142 Array.Copy(start_buf, start_buf_pos, managedBuf, 0, start_buf_len); 143 bufsz -= start_buf_len; 144 bytesRead = start_buf_len; 145 start_buf_len = 0; 146 } 147 } 148 149 if (bufsz > 0) 150 { 151 try 152 { 153 bytesRead += stream.Read(managedBuf, bytesRead, bufsz); 154 } 155 catch (IOException) 156 { 157 return -1; 158 } 159 } 160 161 if (bytesRead > 0 && buf != IntPtr.Zero) 162 { 163 Marshal.Copy(managedBuf, 0, (IntPtr)(buf.ToInt64()), bytesRead); 164 } 165 166 if (!stream.CanSeek && (bufsz == 10) && peek) 167 { 168 // Special 'hack' to support peeking of the type for gdi+ on non-seekable streams 169 } 170 171 if (peek) 172 { 173 if (stream.CanSeek) 174 { 175 // If we are peeking bytes, then go back to original position before peeking 176 stream.Seek(streamPosition, SeekOrigin.Begin); 177 } 178 else 179 { 180 throw new NotSupportedException(); 181 } 182 } 183 } 184 185 return bytesRead; 186 } 187 188 public StreamGetBytesDelegate GetBytesDelegate 189 { 190 get 191 { 192 if (stream != null && stream.CanRead) 193 { 194 if (sgbd == null) 195 { 196 sgbd = new StreamGetBytesDelegate(StreamGetBytesImpl); 197 } 198 return sgbd; 199 } 200 return null; 201 } 202 } 203 StreamSeekImpl(int offset, int whence)204 public long StreamSeekImpl(int offset, int whence) 205 { 206 // Make sure we have a valid 'whence'. 207 if ((whence < 0) || (whence > 2)) 208 return -1; 209 210 // Invalidate the start_buf if we're actually going to call a Seek method. 211 start_buf_pos += start_buf_len; 212 start_buf_len = 0; 213 214 SeekOrigin origin; 215 216 // Translate 'whence' into a SeekOrigin enum member. 217 switch (whence) 218 { 219 case 0: 220 origin = SeekOrigin.Begin; 221 break; 222 case 1: 223 origin = SeekOrigin.Current; 224 break; 225 case 2: 226 origin = SeekOrigin.End; 227 break; 228 229 // The following line is redundant but necessary to avoid a 230 // "Use of unassigned local variable" error without actually 231 // initializing 'origin' to a dummy value. 232 default: 233 return -1; 234 } 235 236 // Do the actual seek operation and return its result. 237 return stream.Seek((long)offset, origin); 238 } 239 240 public StreamSeekDelegate SeekDelegate 241 { 242 get 243 { 244 if (stream != null && stream.CanSeek) 245 { 246 if (skd == null) 247 { 248 skd = new StreamSeekDelegate(StreamSeekImpl); 249 } 250 return skd; 251 } 252 return null; 253 } 254 } 255 StreamPutBytesImpl(IntPtr buf, int bufsz)256 public int StreamPutBytesImpl(IntPtr buf, int bufsz) 257 { 258 if (bufsz > managedBuf.Length) 259 managedBuf = new byte[bufsz]; 260 Marshal.Copy(buf, managedBuf, 0, bufsz); 261 stream.Write(managedBuf, 0, bufsz); 262 return bufsz; 263 } 264 265 public StreamPutBytesDelegate PutBytesDelegate 266 { 267 get 268 { 269 if (stream != null && stream.CanWrite) 270 { 271 if (spbd == null) 272 { 273 spbd = new StreamPutBytesDelegate(StreamPutBytesImpl); 274 } 275 return spbd; 276 } 277 return null; 278 } 279 } 280 StreamCloseImpl()281 public void StreamCloseImpl() 282 { 283 stream.Dispose(); 284 } 285 286 public StreamCloseDelegate CloseDelegate 287 { 288 get 289 { 290 if (stream != null) 291 { 292 if (scd == null) 293 { 294 scd = new StreamCloseDelegate(StreamCloseImpl); 295 } 296 return scd; 297 } 298 return null; 299 } 300 } 301 StreamSizeImpl()302 public long StreamSizeImpl() 303 { 304 try 305 { 306 return stream.Length; 307 } 308 catch 309 { 310 return -1; 311 } 312 } 313 314 public StreamSizeDelegate SizeDelegate 315 { 316 get 317 { 318 if (stream != null) 319 { 320 if (ssd == null) 321 { 322 ssd = new StreamSizeDelegate(StreamSizeImpl); 323 } 324 return ssd; 325 } 326 return null; 327 } 328 } 329 } 330 } 331