Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
VirtualFileStream.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.IO;
5 using SiliconStudio.Core.IO;
6 
7 namespace SiliconStudio.Core.Serialization
8 {
9  /// <summary>
10  /// A multithreaded wrapper over a Stream, used by the VirtualFileSystem.
11  /// It also allows restricted access to subparts of the Stream (useful for serialization and data streaming).
12  /// </summary>
14  {
15  public Stream InternalStream { get; internal protected set; }
17  protected readonly long startPosition;
18  protected readonly long endPosition;
19  private readonly bool disposeInternalStream;
20 
21  public long StartPosition
22  {
23  get { return startPosition; }
24  }
25 
26  public long EndPosition
27  {
28  get { return endPosition; }
29  }
30 
31  /// <summary>
32  /// Initializes a new instance of the <see cref="VirtualFileStream" /> class.
33  /// </summary>
34  /// <param name="internalStream">The internal stream.</param>
35  /// <param name="startPosition">The start position.</param>
36  /// <param name="endPosition">The end position.</param>
37  /// <param name="disposeInternalStream">if set to <c>true</c> this instance has ownership of the internal stream and will dispose it].</param>
38  /// <exception cref="System.ArgumentException">startPosition and endPosition doesn't fit inside current bounds</exception>
39  /// <exception cref="System.NotSupportedException">Attempted to create a VirtualFileStream from a Stream which doesn't support seeking.</exception>
40  public VirtualFileStream(Stream internalStream, long startPosition = 0, long endPosition = -1, bool disposeInternalStream = true, bool seekToBeginning = true)
41  {
42  this.disposeInternalStream = disposeInternalStream;
43 
44  if (internalStream is VirtualFileStream)
45  {
46  virtualFileStream = (VirtualFileStream)internalStream;
47  internalStream = virtualFileStream.InternalStream;
48  startPosition += virtualFileStream.startPosition;
49  if (endPosition == -1)
50  endPosition = virtualFileStream.endPosition;
51  else
52  endPosition += virtualFileStream.startPosition;
53  if (startPosition < virtualFileStream.startPosition || ((endPosition < startPosition || endPosition > virtualFileStream.endPosition) && virtualFileStream.endPosition != -1))
54  throw new ArgumentException("startPosition and endPosition doesn't fit inside current bounds");
55 
56  if (!virtualFileStream.disposeInternalStream)
57  this.disposeInternalStream = false;
58  }
59 
60  InternalStream = internalStream;
61  this.startPosition = startPosition;
62  this.endPosition = endPosition;
63 
64  if (seekToBeginning)
65  InternalStream.Seek(startPosition, SeekOrigin.Begin);
66  }
67 
68  protected override void Dispose(bool disposing)
69  {
70  if (virtualFileStream != null)
71  virtualFileStream.Dispose();
72  virtualFileStream = null;
73 
74  if (disposeInternalStream && InternalStream != null)
75  {
76  InternalStream.Dispose();
77  }
78 
79  InternalStream = null;
80  base.Dispose(disposing);
81  }
82 
83  /// <inheritdoc/>
84  public override bool CanRead
85  {
86  get { return InternalStream.CanRead; }
87  }
88 
89  /// <inheritdoc/>
90  public override bool CanSeek
91  {
92  get { return InternalStream.CanSeek; }
93  }
94 
95  /// <inheritdoc/>
96  public override bool CanWrite
97  {
98  get { return InternalStream.CanWrite; }
99  }
100 
101  /// <inheritdoc/>
102  public override void Flush()
103  {
104  InternalStream.Flush();
105  }
106 
107  /// <inheritdoc/>
108  public override long Length
109  {
110  get
111  {
112  if (endPosition == -1) // Use underlying stream if not a substream
113  return InternalStream.Length - startPosition;
114  return endPosition - startPosition;
115  }
116  }
117 
118  /// <inheritdoc/>
119  public override long Position
120  {
121  get { return InternalStream.Position - startPosition; }
122  set { InternalStream.Position = startPosition + value; }
123  }
124 
125  /// <inheritdoc/>
126  public override int Read(byte[] buffer, int offset, int count)
127  {
128  if (endPosition != -1)
129  {
130  var maxCount = (int)(endPosition - InternalStream.Position);
131  if (count > maxCount)
132  count = maxCount;
133  }
134 
135  var bytesProcessed = InternalStream.Read(buffer, offset, count);
136  return bytesProcessed;
137  }
138 
139  /// <inheritdoc/>
140  public override int ReadByte()
141  {
142  if (endPosition != -1 && InternalStream.Position >= endPosition)
143  {
144  return -1;
145  }
146 
147  return InternalStream.ReadByte();
148  }
149 
150  /// <inheritdoc/>
151  public override long Seek(long offset, SeekOrigin origin)
152  {
153  switch (origin)
154  {
155  case SeekOrigin.Begin:
156  InternalStream.Seek(startPosition + offset, SeekOrigin.Begin);
157  break;
158  case SeekOrigin.Current:
159  InternalStream.Seek(offset, SeekOrigin.Current);
160  break;
161  case SeekOrigin.End:
162  // Maybe we don't know the actual file size (full file)
163  if (endPosition == -1)
164  {
165  InternalStream.Seek(offset, SeekOrigin.End);
166  }
167  else
168  {
169  InternalStream.Seek(endPosition - startPosition + offset, SeekOrigin.Begin);
170  }
171  break;
172  }
173 
174  var newPosition = InternalStream.Position;
175  if (newPosition < startPosition || (endPosition != -1 && newPosition > endPosition))
176  {
177  InternalStream.Position = startPosition;
178  throw new InvalidOperationException("Seek position is out of bound.");
179  }
180 
181  return newPosition;
182  }
183 
184  /// <inheritdoc/>
185  public override void SetLength(long value)
186  {
187  if (endPosition != -1)
188  {
189  throw new InvalidOperationException("Can't resize VirtualFileStream if endPosition is not -1.");
190  }
191 
192  InternalStream.SetLength(value);
193  }
194 
195  /// <inheritdoc/>
196  public override void Write(byte[] buffer, int offset, int count)
197  {
198  if (endPosition != -1 && count > endPosition - InternalStream.Position)
199  {
200  throw new NotSupportedException("Can't write beyond end of stream.");
201  }
202 
203  InternalStream.Write(buffer, offset, count);
204  }
205 
206  /// <inheritdoc/>
207  public override void WriteByte(byte value)
208  {
209  if (endPosition != -1 && InternalStream.Position >= endPosition)
210  {
211  throw new NotSupportedException("Can't write beyond end of stream.");
212  }
213 
214  InternalStream.WriteByte(value);
215  }
216  }
217 }
override int Read(byte[] buffer, int offset, int count)
override void Write(byte[] buffer, int offset, int count)
VirtualFileStream(Stream internalStream, long startPosition=0, long endPosition=-1, bool disposeInternalStream=true, bool seekToBeginning=true)
Initializes a new instance of the VirtualFileStream class.
_In_ size_t count
Definition: DirectXTexP.h:174
override long Seek(long offset, SeekOrigin origin)
A Stream with additional methods for native read and write operations using IntPtr.
Definition: NativeStream.cs:11
A multithreaded wrapper over a Stream, used by the VirtualFileSystem. It also allows restricted acces...