                 reader.offset -= 4
             }
         }
-        // TODO: Checksum
+        if contentSizePresent {
+            guard out.count == contentSize
+                else { throw DataError.corrupted }
+        }
+        if contentChecksumPresent {
+            guard XxHash32.hash(data: out) == reader.uint32()
+                else { throw DataError.checksumMismatch([out]) }
+        }
         return out
     }
 
-    // TODO: Multi-frame decoding (similar to XZArchive.splitUnarchive).
-    // TODO: Multi-thread decoding of blocks if they are independent.
+    // TODO: Multi-frame decoding (similar to XZArchive.splitUnarchive or GzipArchive.multiUnarchive).
 
     private static func processBlock(_ reader: LittleEndianByteReader) throws -> Data {
         fatalError("Not implemented yet")

        // TODO: Switch between frame and block decoding modes?
        // TODO: Small/empty data size check + Tests! (bytesLeft >= 4 + 3 + 4?)
        // TODO: Test various advanced options of LZ4.

        // Magic number.
        guard reader.uint32() == 0x184D2204

            contentSize = Int(truncatingIfNeeded: rawContentSize)
        }

        guard !dictIdPresent
            else { throw DataError.unsupportedFeature }

        // Header doesn't include magic number.
        let headerData = data[data.startIndex + 4..<data.startIndex + 4 + 2 + (contentSizePresent ? 8 : 0) + (dictIdPresent ? 4 : 0)]
