         return size + 4
     }
 
-    private static func process(legacyFrame data: Data) throws -> Data {
+    // The functions below return uncompressed data and the offset to the next byte after the processed frame (even if
+    // the end of the input data was reached). The offset is needed to make multiDecompress function work.
+
+    private static func process(legacyFrame data: Data) throws -> (Data, Data.Index) {
         let reader = LittleEndianByteReader(data: data)
         var out = Data()
         // The end of a frame is determined is either by end-of-file or by encountering a valid frame magic number.

        // Valid LZ4 frame must contain at least a magic number (4 bytes).
        guard data.count >= 4
            else { throw DataError.truncated }
        // TODO: Switch between frame and block decoding modes?
        // TODO: Tests for data truncated at various places.

        // Magic number.
        let magic = data[data.startIndex..<data.startIndex + 4].withUnsafeBytes { $0.bindMemory(to: UInt32.self)[0] }
        switch magic {
        case 0x184D2204:
            return try LZ4.process(frame: data[(data.startIndex + 4)...], dictionary, dictionaryID)
        case 0x184D2A50...0x184D2A5F:
            let frameSize = try process(skippableFrame: data[(data.startIndex + 4)...])
            return try LZ4.decompress(data: data[(data.startIndex + 4 + frameSize)...])
        case 0x184C2102:
            return try LZ4.process(legacyFrame: data[(data.startIndex + 4)...])
        default:
            throw DataError.corrupted
        }
    }

    private static func process(skippableFrame data: Data) throws -> Data.Index {


public enum LZ4: DecompressionAlgorithm {

    // TODO: Tests for data truncated at various places.

    public static func decompress(data: Data) throws -> Data {
        return try LZ4.decompress(data: data, dictionary: nil)
    }
