Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
RiffParser.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 //
4 // Copyright (c) 2010-2013 SharpDX - Alexandre Mutel
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 // THE SOFTWARE.
23 using System;
24 using System.Collections;
25 using System.Collections.Generic;
26 using System.IO;
27 
28 namespace SiliconStudio.Paradox.Audio.Wave
29 {
30  /// <summary>
31  /// Riff chunk enumerator.
32  /// </summary>
33  internal class RiffParser : IEnumerator<RiffChunk>, IEnumerable<RiffChunk>
34  {
35  private readonly Stream input;
36  private readonly long startPosition;
37  private readonly BinaryReader reader;
38  private readonly Stack<RiffChunk> chunckStack;
39  private bool descendNext;
40  private bool isEndOfRiff;
41  private bool isErrorState;
42  private RiffChunk current;
43 
44  /// <summary>
45  /// Initializes a new instance of the <see cref="RiffParser"/> class.
46  /// </summary>
47  /// <param name="input">The input.</param>
48  public RiffParser(Stream input)
49  {
50  this.input = input;
51  startPosition = input.Position;
52  reader = new BinaryReader(input);
53  chunckStack = new Stack<RiffChunk>();
54  }
55 
56  /// <summary>
57  /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
58  /// </summary>
59  public void Dispose()
60  {
61  // Nothing to dispose.
62  }
63 
64  /// <summary>
65  /// Advances the enumerator to the next element of the collection.
66  /// </summary>
67  /// <returns>
68  /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
69  /// </returns>
70  /// <exception cref="T:System.InvalidOperationException">
71  /// The collection was modified after the enumerator was created.
72  /// </exception>
73  public bool MoveNext()
74  {
75  CheckState();
76 
77  if (current != null)
78  {
79  // By default, set the starting position to the data of the chunk
80  long nextOffset = current.DataPosition;
81  // If we descend
82  if (descendNext)
83  {
84  // Next time, proceed chunk sequentially
85  descendNext = false;
86  }
87  else
88  {
89  // Else, go to next chunk
90  nextOffset += current.Size;
91  // Pad DWORD
92  if ((nextOffset & 1) != 0)
93  nextOffset++;
94  }
95  input.Position = nextOffset;
96 
97  // Check that moveNext is not going outside a parent chunk.
98  // If yes, pop the last chunk from the stack
99  var currentChunkContainer = chunckStack.Peek();
100  long endOfOuterChunk = currentChunkContainer.DataPosition + currentChunkContainer.Size;
101  if (input.Position >= endOfOuterChunk)
102  chunckStack.Pop();
103 
104  // If there are no more chunk in the
105  if (chunckStack.Count == 0)
106  {
107  isEndOfRiff = true;
108  return false;
109  }
110  }
111 
112  var fourCC = ((FourCC)reader.ReadUInt32());
113  bool isList = (fourCC == "LIST");
114  bool isHeader = (fourCC == "RIFF");
115 
116  if (input.Position == (startPosition + 4) && !isHeader)
117  {
118  isErrorState = true;
119  throw new InvalidOperationException("Invalid RIFF file format");
120  }
121 
122  // Read chunk size
123  var chunkSize = reader.ReadUInt32();
124 
125  // If list or header
126  if (isList || isHeader)
127  {
128  // Check filesize
129  if (isHeader && chunkSize > (input.Length - 8))
130  {
131  isErrorState = true;
132  throw new InvalidOperationException("Invalid RIFF file format");
133  }
134  chunkSize -= 4;
135  fourCC = reader.ReadUInt32();
136  }
137 
138  // Read RIFF type and create chunk
139  current = new RiffChunk(input, fourCC, chunkSize, (uint)input.Position, isList, isHeader);
140  return true;
141  }
142 
143  private void CheckState()
144  {
145  if (isEndOfRiff)
146  throw new InvalidOperationException("End of Riff. Cannot MoveNext");
147 
148  if (isErrorState)
149  throw new InvalidOperationException("The enumerator is in an error state");
150  }
151 
152  /// <summary>
153  /// Gets the current stack of chunks.
154  /// </summary>
155  public Stack<RiffChunk> ChunkStack { get { return chunckStack; } }
156 
157  /// <summary>
158  /// Sets the enumerator to its initial position, which is before the first element in the collection.
159  /// </summary>
160  /// <exception cref="T:System.InvalidOperationException">
161  /// The collection was modified after the enumerator was created.
162  /// </exception>
163  public void Reset()
164  {
165  CheckState();
166  current = null;
167  input.Position = startPosition;
168  }
169 
170  /// <summary>
171  /// Ascends to the outer chunk.
172  /// </summary>
173  public void Ascend()
174  {
175  CheckState();
176  var outerChunk = chunckStack.Pop();
177  input.Position = outerChunk.DataPosition + outerChunk.Size;
178  }
179 
180  /// <summary>
181  /// Descends to the current chunk.
182  /// </summary>
183  public void Descend()
184  {
185  CheckState();
186  chunckStack.Push(current);
187  descendNext = true;
188  }
189 
190  /// <summary>
191  /// Gets all chunks.
192  /// </summary>
193  /// <returns></returns>
194  public IList<RiffChunk> GetAllChunks()
195  {
196  var chunks = new List<RiffChunk>();
197  foreach (var riffChunk in this)
198  chunks.Add(riffChunk);
199  return chunks;
200  }
201 
202  /// <summary>
203  /// Gets the element in the collection at the current position of the enumerator.
204  /// </summary>
205  /// <returns>
206  /// The element in the collection at the current position of the enumerator.
207  /// </returns>
208  public RiffChunk Current
209  {
210  get
211  {
212  CheckState();
213  return current;
214  }
215  }
216 
217  /// <summary>
218  /// Returns an enumerator that iterates through the collection.
219  /// </summary>
220  /// <returns>
221  /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
222  /// </returns>
223  public IEnumerator<RiffChunk> GetEnumerator()
224  {
225  return this;
226  }
227 
228  object IEnumerator.Current
229  {
230  get
231  {
232  CheckState();
233  return Current;
234  }
235  }
236 
237  IEnumerator IEnumerable.GetEnumerator()
238  {
239  return GetEnumerator();
240  }
241  }
242 }
The device failed due to a badly formed command. This is a run-time issue; The application should des...