                     state -= 6
                 }
                 uncompressedSize -= 1
+                continue
+            }
+
+            var len: Int
+            if rangeDecoder.decode(bitWithProb: &isRep[state], pointerData: &pointerData) != 0 {
+                if uncompressedSize == 0 {
+                    // TODO: throw error
+                }
+                if outWindow.isEmpty {
+                    // TODO: throw error
+                }
+                if rangeDecoder.decode(bitWithProb: &isRepG0[state], pointerData: &pointerData) == 0 {
+                    if rangeDecoder.decode(bitWithProb: &isRep0Long[(state << Constants.numPosBitsMax) + posState],
+                                           pointerData: &pointerData) == 0 {
+                        state = state < 7 ? 9 : 11
+                        let byte = outWindow.byte(at: rep0 + 1)
+                        outWindow.put(byte: byte)
+                        if uncompressedSize > 0 {
+                            out[outIndex] = byte
+                            outIndex += 1
+                        } else {
+                            out.append(byte)
+                        }
+                        uncompressedSize -= 1
+                        continue
+                    }
+                } else {
+                    let dist: Int
+                    if rangeDecoder.decode(bitWithProb: &isRepG1[state], pointerData: &pointerData) == 0 {
+                        dist = rep1
+                    } else {
+                        if rangeDecoder.decode(bitWithProb: &isRepG2[state], pointerData: &pointerData) == 0 {
+                            dist = rep2
+                        } else {
+                            dist = rep3
+                            rep3 = rep2
+                        }
+                        rep2 = rep1
+                    }
+                    rep1 = rep0
+                    rep0 = dist
+                }
+                len = repLenDecoder.decode(with: rangeDecoder, posState: posState, pointerData: &pointerData)
+                state = state < 7 ? 8 : 11
+            } else {
+                rep3 = rep2
+                rep2 = rep1
+                rep1 = rep0
+                len = lenDecoder.decode(with: rangeDecoder, posState: posState, pointerData: &pointerData)
+                state = state < 7 ? 7 : 10
+                rep0 = decodeDistance(len)
+                // Check if finished marker is encoutered.
+                if rep0 == 0xFFFFFFFF {
+                    if rangeDecoder.isFinishedOK {
+                        break
+                    } else {
+                        // TODO: throw error.
+                    }
+                }
+
+                if uncompressedSize == 0 {
+                    // TODO: throw error.
+                }
+                if rep0 >= dictionarySize || !outWindow.check(distance: rep0) {
+                    // TODO: throw error.
+                }
+            }
+            len += Constants.matchMinLen
+            var isError = false
+            if uncompressedSize > -1 && uncompressedSize < len {
+                len = uncompressedSize
+                isError = true
+            }
+            outWindow.copyMatch(at: rep0 + 1, length: len)
+            uncompressedSize -= len
+            if isError {
+                // TODO: throw error.
             }
 
         }

        private var range: Int
        private var code: Int
        private(set) var isCorrupted: Bool

        init?(pointerData: inout DataWithPointer) {
            self.isCorrupted = false

            return distance <= self.position || self.isFull
        }

    }

    final class RangeDecoder {
