/// <summary>Processes a RIFF data sequence.</summary> /// <param name="reader">The <see cref="SequentialReader"/> from which the data should be read.</param> /// <param name="handler">The <see cref="IRiffHandler"/> that will coordinate processing and accept read values.</param> /// <exception cref="RiffProcessingException">An error occurred during the processing of RIFF data that could not be ignored or recovered from.</exception> /// <exception cref="System.IO.IOException">an error occurred while accessing the required data</exception> public void ProcessRiff([NotNull] SequentialReader reader, [NotNull] IRiffHandler handler) { // RIFF files are always little-endian reader = reader.WithByteOrder(isMotorolaByteOrder: false); // PROCESS FILE HEADER var fileFourCc = reader.GetString(4, Encoding.ASCII); if (fileFourCc != "RIFF") { throw new RiffProcessingException("Invalid RIFF header: " + fileFourCc); } // The total size of the chunks that follow plus 4 bytes for the 'WEBP' or 'AVI ' FourCC int fileSize = reader.GetInt32(); int sizeLeft = fileSize; string identifier = reader.GetString(4, Encoding.ASCII); sizeLeft -= 4; if (!handler.ShouldAcceptRiffIdentifier(identifier)) { return; } ProcessChunks(reader, sizeLeft, handler); }
/// <summary>Processes a RIFF data sequence.</summary> /// <param name="reader">The <see cref="SequentialReader"/> from which the data should be read.</param> /// <param name="handler">The <see cref="IRiffHandler"/> that will coordinate processing and accept read values.</param> /// <exception cref="RiffProcessingException">An error occurred during the processing of RIFF data that could not be ignored or recovered from.</exception> /// <exception cref="System.IO.IOException">an error occurred while accessing the required data</exception> public void ProcessRiff([NotNull] SequentialReader reader, [NotNull] IRiffHandler handler) { // RIFF files are always little-endian reader = reader.WithByteOrder(isMotorolaByteOrder: false); // PROCESS FILE HEADER var fileFourCc = reader.GetString(4, Encoding.UTF8); if (fileFourCc != "RIFF") { throw new RiffProcessingException("Invalid RIFF header: " + fileFourCc); } // The total size of the chunks that follow plus 4 bytes for the 'WEBP' FourCC var fileSize = reader.GetInt32(); var sizeLeft = fileSize; var identifier = reader.GetString(4, Encoding.UTF8); sizeLeft -= 4; if (!handler.ShouldAcceptRiffIdentifier(identifier)) { return; } // PROCESS CHUNKS while (sizeLeft != 0) { var chunkFourCc = reader.GetString(4, Encoding.UTF8); var chunkSize = reader.GetInt32(); sizeLeft -= 8; // NOTE we fail a negative chunk size here (greater than 0x7FFFFFFF) as we cannot allocate arrays larger than this if (chunkSize < 0 || sizeLeft < chunkSize) { throw new RiffProcessingException("Invalid RIFF chunk size"); } if (handler.ShouldAcceptChunk(chunkFourCc)) { // TODO is it feasible to avoid copying the chunk here, and to pass the sequential reader to the handler? handler.ProcessChunk(chunkFourCc, reader.GetBytes(chunkSize)); } else { reader.Skip(chunkSize); } sizeLeft -= chunkSize; // Skip any padding byte added to keep chunks aligned to even numbers of bytes if (chunkSize % 2 == 1) { reader.GetSByte(); sizeLeft--; } } }