// PROCESS CHUNKS private static void ProcessChunks(SequentialReader reader, long maxPosition, IRiffHandler handler) { // Processing chunks. Each chunk is 8 bytes header (4 bytes CC code + 4 bytes length of chunk) + data of the chunk while (reader.Position < maxPosition - 8) { string chunkFourCc = reader.GetString(4, Encoding.ASCII); int chunkSize = reader.GetInt32(); // NOTE we fail a negative chunk size here (greater than 0x7FFFFFFF) as we cannot allocate arrays larger than this if (chunkSize < 0 || chunkSize + reader.Position > maxPosition) { throw new RiffProcessingException("Invalid RIFF chunk size"); } if (chunkFourCc == "LIST" || chunkFourCc == "RIFF") { string listName = reader.GetString(4, Encoding.ASCII); if (handler.ShouldAcceptList(listName)) { ProcessChunks(reader, reader.Position + chunkSize - 4, handler); } else { reader.Skip(chunkSize - 4); } } else { 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); } // Skip any padding byte added to keep chunks aligned to even numbers of bytes if (chunkSize % 2 == 1) { reader.Skip(1); } } } }
/// <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--; } } }
// PROCESS CHUNKS public void ProcessChunks([NotNull] SequentialReader reader, int sizeLeft, [NotNull] IRiffHandler handler) { // Processing chunks. Each chunk is 8 bytes header (4 bytes CC code + 4 bytes length of chunk) + data of the chunk while (reader.Position < sizeLeft) { // Check if end of the file is closer then 8 bytes if (reader.IsCloserToEnd(8)) { return; } string chunkFourCc = reader.GetString(4, Encoding.ASCII); int 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"); } // Check if end of the file is closer then chunkSize bytes if (reader.IsCloserToEnd(chunkSize)) { return; } if (chunkFourCc == "LIST" || chunkFourCc == "RIFF") { string listName = reader.GetString(4, Encoding.ASCII); if (handler.ShouldAcceptList(listName)) { ProcessChunks(reader, sizeLeft - 4, handler); } else { reader.Skip(sizeLeft - 4); } sizeLeft -= chunkSize; } else { 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--; } } } }