Refactored progressive codec.
authorArmin Novak <armin.novak@thincast.com>
Tue, 10 Dec 2019 15:19:20 +0000 (16:19 +0100)
committerakallabeth <akallabeth@users.noreply.github.com>
Tue, 18 Feb 2020 10:13:52 +0000 (11:13 +0100)
libfreerdp/codec/progressive.c
libfreerdp/codec/progressive.h

index 9371030..02d45bf 100644 (file)
@@ -3,6 +3,8 @@
  * Progressive Codec Bitmap Compression
  *
  * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ * Copyright 2019 Armin Novak <armin.novak@thincast.com>
+ * Copyright 2019 Thincast Technologies GmbH
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -46,7 +48,7 @@ struct _RFX_PROGRESSIVE_UPGRADE_STATE
 
        /* SRL state */
 
-       int kp;
+       UINT32 kp;
        int nz;
        BOOL mode;
 };
@@ -83,23 +85,27 @@ static const char* progressive_get_block_type_string(UINT16 blockType)
                default:
                        return "PROGRESSIVE_WBT_UNKNOWN";
        }
-
-       return "PROGRESSIVE_WBT_UNKNOWN";
 }
 
-static INLINE void progressive_component_codec_quant_read(const BYTE* block,
+static INLINE void progressive_component_codec_quant_read(wStream* s,
                                                           RFX_COMPONENT_CODEC_QUANT* quantVal)
 {
-       quantVal->LL3 = block[0] & 0x0F;
-       quantVal->HL3 = block[0] >> 4;
-       quantVal->LH3 = block[1] & 0x0F;
-       quantVal->HH3 = block[1] >> 4;
-       quantVal->HL2 = block[2] & 0x0F;
-       quantVal->LH2 = block[2] >> 4;
-       quantVal->HH2 = block[3] & 0x0F;
-       quantVal->HL1 = block[3] >> 4;
-       quantVal->LH1 = block[4] & 0x0F;
-       quantVal->HH1 = block[4] >> 4;
+       BYTE b;
+       Stream_Read_UINT8(s, b);
+       quantVal->LL3 = b & 0x0F;
+       quantVal->HL3 = b >> 4;
+       Stream_Read_UINT8(s, b);
+       quantVal->LH3 = b & 0x0F;
+       quantVal->HH3 = b >> 4;
+       Stream_Read_UINT8(s, b);
+       quantVal->HL2 = b & 0x0F;
+       quantVal->LH2 = b >> 4;
+       Stream_Read_UINT8(s, b);
+       quantVal->HH2 = b & 0x0F;
+       quantVal->HL1 = b >> 4;
+       Stream_Read_UINT8(s, b);
+       quantVal->LH1 = b & 0x0F;
+       quantVal->HH1 = b >> 4;
 }
 
 static INLINE void progressive_rfx_quant_ladd(RFX_COMPONENT_CODEC_QUANT* q, int val)
@@ -116,8 +122,8 @@ static INLINE void progressive_rfx_quant_ladd(RFX_COMPONENT_CODEC_QUANT* q, int
        q->LL3 += val; /* LL3 */
 }
 
-static INLINE void progressive_rfx_quant_add(RFX_COMPONENT_CODEC_QUANT* q1,
-                                             RFX_COMPONENT_CODEC_QUANT* q2,
+static INLINE void progressive_rfx_quant_add(const RFX_COMPONENT_CODEC_QUANT* q1,
+                                             const RFX_COMPONENT_CODEC_QUANT* q2,
                                              RFX_COMPONENT_CODEC_QUANT* dst)
 {
        dst->HL1 = q1->HL1 + q2->HL1; /* HL1 */
@@ -146,8 +152,8 @@ static INLINE void progressive_rfx_quant_lsub(RFX_COMPONENT_CODEC_QUANT* q, int
        q->LL3 -= val; /* LL3 */
 }
 
-static INLINE void progressive_rfx_quant_sub(RFX_COMPONENT_CODEC_QUANT* q1,
-                                             RFX_COMPONENT_CODEC_QUANT* q2,
+static INLINE void progressive_rfx_quant_sub(const RFX_COMPONENT_CODEC_QUANT* q1,
+                                             const RFX_COMPONENT_CODEC_QUANT* q2,
                                              RFX_COMPONENT_CODEC_QUANT* dst)
 {
        dst->HL1 = q1->HL1 - q2->HL1; /* HL1 */
@@ -162,7 +168,8 @@ static INLINE void progressive_rfx_quant_sub(RFX_COMPONENT_CODEC_QUANT* q1,
        dst->LL3 = q1->LL3 - q2->LL3; /* LL3 */
 }
 
-static INLINE BOOL progressive_rfx_quant_lcmp_less_equal(RFX_COMPONENT_CODEC_QUANT* q, int val)
+static INLINE BOOL progressive_rfx_quant_lcmp_less_equal(const RFX_COMPONENT_CODEC_QUANT* q,
+                                                         int val)
 {
        if (q->HL1 > val)
                return FALSE; /* HL1 */
@@ -197,8 +204,8 @@ static INLINE BOOL progressive_rfx_quant_lcmp_less_equal(RFX_COMPONENT_CODEC_QUA
        return TRUE;
 }
 
-static INLINE BOOL progressive_rfx_quant_cmp_less_equal(RFX_COMPONENT_CODEC_QUANT* q1,
-                                                        RFX_COMPONENT_CODEC_QUANT* q2)
+static INLINE BOOL progressive_rfx_quant_cmp_less_equal(const RFX_COMPONENT_CODEC_QUANT* q1,
+                                                        const RFX_COMPONENT_CODEC_QUANT* q2)
 {
        if (q1->HL1 > q2->HL1)
                return FALSE; /* HL1 */
@@ -233,7 +240,8 @@ static INLINE BOOL progressive_rfx_quant_cmp_less_equal(RFX_COMPONENT_CODEC_QUAN
        return TRUE;
 }
 
-static INLINE BOOL progressive_rfx_quant_lcmp_greater_equal(RFX_COMPONENT_CODEC_QUANT* q, int val)
+static INLINE BOOL progressive_rfx_quant_lcmp_greater_equal(const RFX_COMPONENT_CODEC_QUANT* q,
+                                                            int val)
 {
        if (q->HL1 < val)
                return FALSE; /* HL1 */
@@ -268,8 +276,8 @@ static INLINE BOOL progressive_rfx_quant_lcmp_greater_equal(RFX_COMPONENT_CODEC_
        return TRUE;
 }
 
-static INLINE BOOL progressive_rfx_quant_cmp_greater_equal(RFX_COMPONENT_CODEC_QUANT* q1,
-                                                           RFX_COMPONENT_CODEC_QUANT* q2)
+static INLINE BOOL progressive_rfx_quant_cmp_greater_equal(const RFX_COMPONENT_CODEC_QUANT* q1,
+                                                           const RFX_COMPONENT_CODEC_QUANT* q2)
 {
        if (q1->HL1 < q2->HL1)
                return FALSE; /* HL1 */
@@ -304,8 +312,8 @@ static INLINE BOOL progressive_rfx_quant_cmp_greater_equal(RFX_COMPONENT_CODEC_Q
        return TRUE;
 }
 
-static INLINE BOOL progressive_rfx_quant_cmp_equal(RFX_COMPONENT_CODEC_QUANT* q1,
-                                                   RFX_COMPONENT_CODEC_QUANT* q2)
+static INLINE BOOL progressive_rfx_quant_cmp_equal(const RFX_COMPONENT_CODEC_QUANT* q1,
+                                                   const RFX_COMPONENT_CODEC_QUANT* q2)
 {
        if (q1->HL1 != q2->HL1)
                return FALSE; /* HL1 */
@@ -340,14 +348,6 @@ static INLINE BOOL progressive_rfx_quant_cmp_equal(RFX_COMPONENT_CODEC_QUANT* q1
        return TRUE;
 }
 
-static void progressive_rfx_quant_print(RFX_COMPONENT_CODEC_QUANT* q, const char* name)
-{
-       fprintf(stderr,
-               "%s: HL1: %" PRIu8 " LH1: %" PRIu8 " HH1: %" PRIu8 " HL2: %" PRIu8 " LH2: %" PRIu8
-               " HH2: %" PRIu8 " HL3: %" PRIu8 " LH3: %" PRIu8 " HH3: %" PRIu8 " LL3: %" PRIu8 "\n",
-               name, q->HL1, q->LH1, q->HH1, q->HL2, q->LH2, q->HH2, q->HL3, q->LH3, q->HH3, q->LL3);
-}
-
 static INLINE BOOL progressive_set_surface_data(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId,
                                                 void* pData)
 {
@@ -361,18 +361,80 @@ static INLINE BOOL progressive_set_surface_data(PROGRESSIVE_CONTEXT* progressive
        return TRUE;
 }
 
-static INLINE void* progressive_get_surface_data(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId)
+static INLINE PROGRESSIVE_SURFACE_CONTEXT*
+progressive_get_surface_data(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId)
 {
-       ULONG_PTR key;
+       void* key = (void*)(((ULONG_PTR)surfaceId) + 1);
        void* pData = NULL;
-       key = ((ULONG_PTR)surfaceId) + 1;
-       pData = HashTable_GetItemValue(progressive->SurfaceContexts, (void*)key);
+
+       if (!progressive)
+               return NULL;
+
+       pData = HashTable_GetItemValue(progressive->SurfaceContexts, key);
        return pData;
 }
 
+static void progressive_tile_free(RFX_PROGRESSIVE_TILE* tile)
+{
+       if (tile)
+       {
+               _aligned_free(tile->sign);
+               _aligned_free(tile->current);
+               _aligned_free(tile->data);
+       }
+}
+
+static void progressive_surface_context_free(PROGRESSIVE_SURFACE_CONTEXT* surface)
+{
+       UINT32 index;
+
+       for (index = 0; index < surface->gridSize; index++)
+       {
+               RFX_PROGRESSIVE_TILE* tile = &(surface->tiles[index]);
+               progressive_tile_free(tile);
+       }
+
+       free(surface->tiles);
+       free(surface);
+}
+
+static INLINE BOOL progressive_tile_allocate(RFX_PROGRESSIVE_TILE* tile)
+{
+       BOOL rc = FALSE;
+       if (!tile)
+               return FALSE;
+
+       tile->width = 64;
+       tile->height = 64;
+       tile->stride = 4 * tile->width;
+
+       {
+               size_t dataLen = tile->stride * tile->height;
+               tile->data = (BYTE*)_aligned_malloc(dataLen, 16);
+       }
+
+       {
+               size_t signLen = (8192 + 32) * 3;
+               tile->sign = (BYTE*)_aligned_malloc(signLen, 16);
+       }
+
+       {
+               size_t currentLen = (8192 + 32) * 3;
+               tile->current = (BYTE*)_aligned_malloc(currentLen, 16);
+       }
+
+       rc = tile->data && tile->sign && tile->current;
+
+       if (!rc)
+               progressive_tile_free(tile);
+
+       return rc;
+}
+
 static PROGRESSIVE_SURFACE_CONTEXT* progressive_surface_context_new(UINT16 surfaceId, UINT32 width,
                                                                     UINT32 height)
 {
+       UINT32 x;
        PROGRESSIVE_SURFACE_CONTEXT* surface;
        surface = (PROGRESSIVE_SURFACE_CONTEXT*)calloc(1, sizeof(PROGRESSIVE_SURFACE_CONTEXT));
 
@@ -392,38 +454,103 @@ static PROGRESSIVE_SURFACE_CONTEXT* progressive_surface_context_new(UINT16 surfa
                free(surface);
                return NULL;
        }
+       for (x = 0; x < surface->gridSize; x++)
+       {
+               if (!progressive_tile_allocate(&surface->tiles[x]))
+               {
+                       progressive_surface_context_free(surface);
+                       return NULL;
+               }
+       }
 
        return surface;
 }
 
-static void progressive_surface_context_free(PROGRESSIVE_SURFACE_CONTEXT* surface)
+static BOOL progressive_surface_tile_replace(PROGRESSIVE_SURFACE_CONTEXT* surface,
+                                             PROGRESSIVE_BLOCK_REGION* region,
+                                             const RFX_PROGRESSIVE_TILE* tile, BOOL upgrade)
 {
-       UINT32 index;
-       RFX_PROGRESSIVE_TILE* tile;
+       RFX_PROGRESSIVE_TILE* t;
 
-       for (index = 0; index < surface->gridSize; index++)
+       size_t zIdx;
+       if (!surface || !tile)
+               return FALSE;
+
+       zIdx = (tile->yIdx * surface->gridWidth) + tile->xIdx;
+
+       if (zIdx >= surface->gridSize)
        {
-               tile = &(surface->tiles[index]);
+               WLog_ERR(TAG, "Invalid zIndex %" PRIuz, zIdx);
+               return FALSE;
+       }
 
-               if (tile->data)
-                       _aligned_free(tile->data);
+       t = &surface->tiles[zIdx];
 
-               if (tile->sign)
-                       _aligned_free(tile->sign);
+       if (upgrade)
+       {
+               t->blockType = tile->blockType;
+               t->blockLen = tile->blockLen;
+               t->quantIdxY = tile->quantIdxY;
+               t->quantIdxCb = tile->quantIdxCb;
+               t->quantIdxCr = tile->quantIdxCr;
+               t->xIdx = tile->xIdx;
+               t->yIdx = tile->yIdx;
+               t->flags = tile->flags;
+               t->quality = tile->quality;
+               t->ySrlLen = tile->ySrlLen;
+               t->yRawLen = tile->yRawLen;
+               t->cbSrlLen = tile->cbSrlLen;
+               t->cbRawLen = tile->cbRawLen;
+               t->crSrlLen = tile->crSrlLen;
+               t->crRawLen = tile->crRawLen;
+               t->ySrlData = tile->ySrlData;
+               t->yRawData = tile->yRawData;
+               t->cbSrlData = tile->cbSrlData;
+               t->cbRawData = tile->cbRawData;
+               t->crSrlData = tile->crSrlData;
+               t->crRawData = tile->crRawData;
+               t->x = tile->xIdx * t->width;
+               t->y = tile->yIdx * t->height;
+       }
+       else
+       {
+               t->blockType = tile->blockType;
+               t->blockLen = tile->blockLen;
+               t->quantIdxY = tile->quantIdxY;
+               t->quantIdxCb = tile->quantIdxCb;
+               t->quantIdxCr = tile->quantIdxCr;
+               t->xIdx = tile->xIdx;
+               t->yIdx = tile->yIdx;
+               t->flags = tile->flags;
+               t->quality = tile->quality;
+               t->yLen = tile->yLen;
+               t->cbLen = tile->cbLen;
+               t->crLen = tile->crLen;
+               t->tailLen = tile->tailLen;
+               t->yData = tile->yData;
+               t->cbData = tile->cbData;
+               t->crData = tile->crData;
+               t->tailData = tile->tailData;
+               t->x = tile->xIdx * t->width;
+               t->y = tile->yIdx * t->height;
+       }
 
-               if (tile->current)
-                       _aligned_free(tile->current);
+       if (region->usedTiles >= region->numTiles)
+       {
+               WLog_ERR(TAG, "Invalid tile count, only expected %" PRIu16 ", got %" PRIu16,
+                        region->numTiles, region->usedTiles);
+               return FALSE;
        }
 
-       free(surface->tiles);
-       free(surface);
+       region->tiles[region->usedTiles++] = t;
+       return TRUE;
 }
 
 INT32 progressive_create_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId,
                                          UINT32 width, UINT32 height)
 {
        PROGRESSIVE_SURFACE_CONTEXT* surface;
-       surface = (PROGRESSIVE_SURFACE_CONTEXT*)progressive_get_surface_data(progressive, surfaceId);
+       surface = progressive_get_surface_data(progressive, surfaceId);
 
        if (!surface)
        {
@@ -444,8 +571,7 @@ INT32 progressive_create_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT1
 
 int progressive_delete_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId)
 {
-       PROGRESSIVE_SURFACE_CONTEXT* surface;
-       surface = (PROGRESSIVE_SURFACE_CONTEXT*)progressive_get_surface_data(progressive, surfaceId);
+       PROGRESSIVE_SURFACE_CONTEXT* surface = progressive_get_surface_data(progressive, surfaceId);
 
        if (surface)
        {
@@ -457,42 +583,41 @@ int progressive_delete_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT16
 }
 
 /*
- * Band                Offset          Dimensions      Size
+ * Band            Offset      Dimensions  Size
  *
- * HL1         0               31x33           1023
- * LH1         1023            33x31           1023
- * HH1         2046            31x31           961
+ * HL1      0           31x33       1023
+ * LH1      1023        33x31       1023
+ * HH1      2046        31x31       961
  *
- * HL2         3007            16x17           272
- * LH2         3279            17x16           272
- * HH2         3551            16x16           256
+ * HL2      3007        16x17       272
+ * LH2      3279        17x16       272
+ * HH2      3551        16x16       256
  *
- * HL3         3807            8x9             72
- * LH3         3879            9x8             72
- * HH3         3951            8x8             64
+ * HL3      3807        8x9         72
+ * LH3      3879        9x8         72
+ * HH3      3951        8x8         64
  *
- * LL3         4015            9x9             81
+ * LL3      4015        9x9         81
  */
 
-static INLINE void progressive_rfx_idwt_x(INT16* pLowBand, int nLowStep, INT16* pHighBand,
-                                          int nHighStep, INT16* pDstBand, int nDstStep,
-                                          int nLowCount, int nHighCount, int nDstCount)
+static INLINE void progressive_rfx_idwt_x(const INT16* pLowBand, size_t nLowStep,
+                                          const INT16* pHighBand, size_t nHighStep, INT16* pDstBand,
+                                          size_t nDstStep, size_t nLowCount, size_t nHighCount,
+                                          size_t nDstCount)
 {
-       int i, j;
+       size_t i;
        INT16 L0;
        INT16 H0, H1;
        INT16 X0, X1, X2;
-       INT16 *pL, *pH, *pX;
 
        for (i = 0; i < nDstCount; i++)
        {
-               pL = pLowBand;
-               pH = pHighBand;
-               pX = pDstBand;
-               H0 = *pH;
-               pH++;
-               L0 = *pL;
-               pL++;
+               size_t j;
+               const INT16* pL = pLowBand;
+               const INT16* pH = pHighBand;
+               INT16* pX = pDstBand;
+               H0 = *pH++;
+               L0 = *pL++;
                X0 = L0 - H0;
                X2 = L0 - H0;
 
@@ -547,21 +672,22 @@ static INLINE void progressive_rfx_idwt_x(INT16* pLowBand, int nLowStep, INT16*
        }
 }
 
-static INLINE void progressive_rfx_idwt_y(INT16* pLowBand, int nLowStep, INT16* pHighBand,
-                                          int nHighStep, INT16* pDstBand, int nDstStep,
-                                          int nLowCount, int nHighCount, int nDstCount)
+static INLINE void progressive_rfx_idwt_y(const INT16* pLowBand, size_t nLowStep,
+                                          const INT16* pHighBand, size_t nHighStep, INT16* pDstBand,
+                                          size_t nDstStep, size_t nLowCount, size_t nHighCount,
+                                          size_t nDstCount)
 {
-       int i, j;
+       size_t i;
        INT16 L0;
        INT16 H0, H1;
        INT16 X0, X1, X2;
-       INT16 *pL, *pH, *pX;
 
        for (i = 0; i < nDstCount; i++)
        {
-               pL = pLowBand;
-               pH = pHighBand;
-               pX = pDstBand;
+               size_t j;
+               const INT16* pL = pLowBand;
+               const INT16* pH = pHighBand;
+               INT16* pX = pDstBand;
                H0 = *pH;
                pH += nHighStep;
                L0 = *pL;
@@ -625,12 +751,12 @@ static INLINE void progressive_rfx_idwt_y(INT16* pLowBand, int nLowStep, INT16*
        }
 }
 
-static INLINE int progressive_rfx_get_band_l_count(int level)
+static INLINE size_t progressive_rfx_get_band_l_count(size_t level)
 {
        return (64 >> level) + 1;
 }
 
-static INLINE int progressive_rfx_get_band_h_count(int level)
+static INLINE size_t progressive_rfx_get_band_h_count(size_t level)
 {
        if (level == 1)
                return (64 >> 1) - 1;
@@ -638,28 +764,18 @@ static INLINE int progressive_rfx_get_band_h_count(int level)
                return (64 + (1 << (level - 1))) >> level;
 }
 
-static INLINE void progressive_rfx_dwt_2d_decode_block(INT16* buffer, INT16* temp, int level)
+static INLINE void progressive_rfx_dwt_2d_decode_block(INT16* buffer, INT16* temp, size_t level,
+                                                       BOOL extrapolate)
 {
-       int offset;
-       int nBandL;
-       int nBandH;
-       int nDstStepX;
-       int nDstStepY;
+       size_t nDstStepX;
+       size_t nDstStepY;
        INT16 *HL, *LH;
        INT16 *HH, *LL;
        INT16 *L, *H, *LLx;
-       INT16* pLowBand[3];
-       INT16* pHighBand[3];
-       INT16* pDstBand[3];
-       int nLowStep[3];
-       int nHighStep[3];
-       int nDstStep[3];
-       int nLowCount[3];
-       int nHighCount[3];
-       int nDstCount[3];
-       nBandL = progressive_rfx_get_band_l_count(level);
-       nBandH = progressive_rfx_get_band_h_count(level);
-       offset = 0;
+
+       const size_t nBandL = progressive_rfx_get_band_l_count(level);
+       const size_t nBandH = progressive_rfx_get_band_h_count(level);
+       size_t offset = 0;
        HL = &buffer[offset];
        offset += (nBandH * nBandL);
        LH = &buffer[offset];
@@ -674,46 +790,20 @@ static INLINE void progressive_rfx_dwt_2d_decode_block(INT16* buffer, INT16* tem
        offset += (nBandL * nDstStepX);
        H = &temp[offset];
        LLx = &buffer[0];
+
        /* horizontal (LL + HL -> L) */
-       pLowBand[0] = LL;
-       nLowStep[0] = nBandL;
-       pHighBand[0] = HL;
-       nHighStep[0] = nBandH;
-       pDstBand[0] = L;
-       nDstStep[0] = nDstStepX;
-       nLowCount[0] = nBandL;
-       nHighCount[0] = nBandH;
-       nDstCount[0] = nBandL;
-       progressive_rfx_idwt_x(pLowBand[0], nLowStep[0], pHighBand[0], nHighStep[0], pDstBand[0],
-                              nDstStep[0], nLowCount[0], nHighCount[0], nDstCount[0]);
+       progressive_rfx_idwt_x(LL, nBandL, HL, nBandH, L, nDstStepX, nBandL, nBandH, nBandL);
+
        /* horizontal (LH + HH -> H) */
-       pLowBand[1] = LH;
-       nLowStep[1] = nBandL;
-       pHighBand[1] = HH;
-       nHighStep[1] = nBandH;
-       pDstBand[1] = H;
-       nDstStep[1] = nDstStepX;
-       nLowCount[1] = nBandL;
-       nHighCount[1] = nBandH;
-       nDstCount[1] = nBandH;
-       progressive_rfx_idwt_x(pLowBand[1], nLowStep[1], pHighBand[1], nHighStep[1], pDstBand[1],
-                              nDstStep[1], nLowCount[1], nHighCount[1], nDstCount[1]);
+       progressive_rfx_idwt_x(LH, nBandL, HH, nBandH, H, nDstStepX, nBandL, nBandH, nBandH);
+
        /* vertical (L + H -> LL) */
-       pLowBand[2] = pDstBand[0];
-       nLowStep[2] = nDstStep[0];
-       pHighBand[2] = pDstBand[1];
-       nHighStep[2] = nDstStep[1];
-       pDstBand[2] = LLx;
-       nDstStep[2] = nDstStepY;
-       nLowCount[2] = nBandL;
-       nHighCount[2] = nBandH;
-       nDstCount[2] = nBandL + nBandH;
-       progressive_rfx_idwt_y(pLowBand[2], nLowStep[2], pHighBand[2], nHighStep[2], pDstBand[2],
-                              nDstStep[2], nLowCount[2], nHighCount[2], nDstCount[2]);
+       progressive_rfx_idwt_y(L, nDstStepX, H, nDstStepX, LLx, nDstStepY, nBandL, nBandH,
+                              nBandL + nBandH);
 }
 
 static INLINE void progressive_rfx_dwt_2d_decode(INT16* buffer, INT16* temp, INT16* current,
-                                                 INT16* sign, BOOL diff)
+                                                 INT16* sign, BOOL diff, BOOL extrapolate)
 {
        const primitives_t* prims = primitives_get();
 
@@ -721,13 +811,13 @@ static INLINE void progressive_rfx_dwt_2d_decode(INT16* buffer, INT16* temp, INT
                prims->add_16s(buffer, current, buffer, 4096);
 
        CopyMemory(current, buffer, 4096 * 2);
-       progressive_rfx_dwt_2d_decode_block(&buffer[3807], temp, 3);
-       progressive_rfx_dwt_2d_decode_block(&buffer[3007], temp, 2);
-       progressive_rfx_dwt_2d_decode_block(&buffer[0], temp, 1);
+       progressive_rfx_dwt_2d_decode_block(&buffer[3807], temp, 3, extrapolate);
+       progressive_rfx_dwt_2d_decode_block(&buffer[3007], temp, 2, extrapolate);
+       progressive_rfx_dwt_2d_decode_block(&buffer[0], temp, 1, extrapolate);
 }
 
 static INLINE void progressive_rfx_decode_block(const primitives_t* prims, INT16* buffer,
-                                                int length, UINT32 shift)
+                                                UINT32 length, UINT32 shift)
 {
        if (!shift)
                return;
@@ -736,9 +826,10 @@ static INLINE void progressive_rfx_decode_block(const primitives_t* prims, INT16
 }
 
 static INLINE int progressive_rfx_decode_component(PROGRESSIVE_CONTEXT* progressive,
-                                                   RFX_COMPONENT_CODEC_QUANT* shift,
-                                                   const BYTE* data, int length, INT16* buffer,
-                                                   INT16* current, INT16* sign, BOOL diff)
+                                                   const RFX_COMPONENT_CODEC_QUANT* shift,
+                                                   const BYTE* data, UINT32 length, INT16* buffer,
+                                                   INT16* current, INT16* sign, BOOL diff,
+                                                   BOOL subbandDiff, BOOL extrapolate)
 {
        int status;
        INT16* temp;
@@ -749,7 +840,7 @@ static INLINE int progressive_rfx_decode_component(PROGRESSIVE_CONTEXT* progress
                return status;
 
        CopyMemory(sign, buffer, 4096 * 2);
-       rfx_differential_decode(&buffer[4015], 81);                           /* LL3 */
+
        progressive_rfx_decode_block(prims, &buffer[0], 1023, shift->HL1);    /* HL1 */
        progressive_rfx_decode_block(prims, &buffer[1023], 1023, shift->LH1); /* LH1 */
        progressive_rfx_decode_block(prims, &buffer[2046], 961, shift->HH1);  /* HH1 */
@@ -759,25 +850,29 @@ static INLINE int progressive_rfx_decode_component(PROGRESSIVE_CONTEXT* progress
        progressive_rfx_decode_block(prims, &buffer[3807], 72, shift->HL3);   /* HL3 */
        progressive_rfx_decode_block(prims, &buffer[3879], 72, shift->LH3);   /* LH3 */
        progressive_rfx_decode_block(prims, &buffer[3951], 64, shift->HH3);   /* HH3 */
+       rfx_differential_decode(&buffer[4015], 81);                           /* LL3 */
        progressive_rfx_decode_block(prims, &buffer[4015], 81, shift->LL3);   /* LL3 */
+
        temp = (INT16*)BufferPool_Take(progressive->bufferPool, -1);          /* DWT buffer */
-       progressive_rfx_dwt_2d_decode(buffer, temp, current, sign, diff);
+       progressive_rfx_dwt_2d_decode(buffer, temp, current, sign, diff, extrapolate);
        BufferPool_Return(progressive->bufferPool, temp);
        return 1;
 }
 
 static INLINE int progressive_decompress_tile_first(PROGRESSIVE_CONTEXT* progressive,
-                                                    RFX_PROGRESSIVE_TILE* tile)
+                                                    RFX_PROGRESSIVE_TILE* tile,
+                                                    PROGRESSIVE_BLOCK_REGION* region,
+                                                    const PROGRESSIVE_BLOCK_CONTEXT* context)
 {
-       BOOL diff;
+       int rc;
+       BOOL diff, sub, extrapolate;
        BYTE* pBuffer;
        INT16* pSign[3];
        INT16* pSrcDst[3];
        INT16* pCurrent[3];
-       PROGRESSIVE_BLOCK_REGION* region;
-       RFX_COMPONENT_CODEC_QUANT shiftY;
-       RFX_COMPONENT_CODEC_QUANT shiftCb;
-       RFX_COMPONENT_CODEC_QUANT shiftCr;
+       RFX_COMPONENT_CODEC_QUANT shiftY = { 0 };
+       RFX_COMPONENT_CODEC_QUANT shiftCb = { 0 };
+       RFX_COMPONENT_CODEC_QUANT shiftCr = { 0 };
        RFX_COMPONENT_CODEC_QUANT* quantY;
        RFX_COMPONENT_CODEC_QUANT* quantCb;
        RFX_COMPONENT_CODEC_QUANT* quantCr;
@@ -790,6 +885,9 @@ static INLINE int progressive_decompress_tile_first(PROGRESSIVE_CONTEXT* progres
 
        tile->pass = 1;
        diff = tile->flags & RFX_TILE_DIFFERENCE;
+       sub = context->flags & RFX_SUBBAND_DIFFING;
+       extrapolate = region->flags & RFX_DWT_REDUCE_EXTRAPOLATE;
+
        WLog_Print(progressive->log, WLOG_DEBUG,
                   "ProgressiveTile%s: quantIdx Y: %" PRIu8 " Cb: %" PRIu8 " Cr: %" PRIu8
                   " xIdx: %" PRIu16 " yIdx: %" PRIu16 " flags: 0x%02" PRIX8 " quality: %" PRIu8
@@ -797,20 +895,30 @@ static INLINE int progressive_decompress_tile_first(PROGRESSIVE_CONTEXT* progres
                   (tile->blockType == PROGRESSIVE_WBT_TILE_FIRST) ? "First" : "Simple",
                   tile->quantIdxY, tile->quantIdxCb, tile->quantIdxCr, tile->xIdx, tile->yIdx,
                   tile->flags, tile->quality, tile->yLen, tile->cbLen, tile->crLen, tile->tailLen);
-       region = &(progressive->region);
 
        if (tile->quantIdxY >= region->numQuant)
+       {
+               WLog_ERR(TAG, "quantIdxY %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxY, region->numQuant);
                return -1;
+       }
 
        quantY = &(region->quantVals[tile->quantIdxY]);
 
        if (tile->quantIdxCb >= region->numQuant)
+       {
+               WLog_ERR(TAG, "quantIdxCb %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxCb,
+                        region->numQuant);
                return -1;
+       }
 
        quantCb = &(region->quantVals[tile->quantIdxCb]);
 
        if (tile->quantIdxCr >= region->numQuant)
+       {
+               WLog_ERR(TAG, "quantIdxCr %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxCr,
+                        region->numQuant);
                return -1;
+       }
 
        quantCr = &(region->quantVals[tile->quantIdxCr]);
 
@@ -821,7 +929,11 @@ static INLINE int progressive_decompress_tile_first(PROGRESSIVE_CONTEXT* progres
        else
        {
                if (tile->quality >= region->numProgQuant)
+               {
+                       WLog_ERR(TAG, "quality %" PRIu8 " > numProgQuant %" PRIu8, tile->quality,
+                                region->numProgQuant);
                        return -1;
+               }
 
                quantProgVal = &(region->quantProgVals[tile->quality]);
        }
@@ -830,12 +942,19 @@ static INLINE int progressive_decompress_tile_first(PROGRESSIVE_CONTEXT* progres
        quantProgCb = &(quantProgVal->cbQuantValues);
        quantProgCr = &(quantProgVal->crQuantValues);
 
-       CopyMemory(&(tile->yQuant), quantY, sizeof(RFX_COMPONENT_CODEC_QUANT));
-       CopyMemory(&(tile->cbQuant), quantCb, sizeof(RFX_COMPONENT_CODEC_QUANT));
-       CopyMemory(&(tile->crQuant), quantCr, sizeof(RFX_COMPONENT_CODEC_QUANT));
-       CopyMemory(&(tile->yProgQuant), quantProgY, sizeof(RFX_COMPONENT_CODEC_QUANT));
-       CopyMemory(&(tile->cbProgQuant), quantProgCb, sizeof(RFX_COMPONENT_CODEC_QUANT));
-       CopyMemory(&(tile->crProgQuant), quantProgCr, sizeof(RFX_COMPONENT_CODEC_QUANT));
+       tile->yQuant = *quantY;
+       tile->cbQuant = *quantCb;
+       tile->crQuant = *quantCr;
+       tile->yProgQuant = *quantProgY;
+       tile->cbProgQuant = *quantProgCb;
+       tile->crProgQuant = *quantProgCr;
+
+       if (!(region->flags & RFX_DWT_REDUCE_EXTRAPOLATE))
+               WLog_Print(progressive->log, WLOG_WARN,
+                          "RFX_PROGRESSIVE_REGION::flags & RFX_DWT_REDUCE_EXTRAPOLATE not set");
+
+       if (!(context->flags & RFX_SUBBAND_DIFFING))
+               WLog_WARN(TAG, "PROGRESSIVE_BLOCK_CONTEXT::flags & RFX_SUBBAND_DIFFING not set");
 
        progressive_rfx_quant_add(quantY, quantProgY, &(tile->yBitPos));
        progressive_rfx_quant_add(quantCb, quantProgCb, &(tile->cbBitPos));
@@ -847,58 +966,44 @@ static INLINE int progressive_decompress_tile_first(PROGRESSIVE_CONTEXT* progres
        progressive_rfx_quant_add(quantCr, quantProgCr, &shiftCr);
        progressive_rfx_quant_lsub(&shiftCr, 1); /* -6 + 5 = -1 */
 
-       if (!tile->data)
-       {
-               tile->data = (BYTE*)_aligned_malloc(64 * 64 * 4, 16);
-               if (!tile->data)
-                       return -1;
-       }
-
-       if (!tile->sign)
-       {
-               tile->sign = (BYTE*)_aligned_malloc((8192 + 32) * 3, 16);
-               if (!tile->sign)
-                       return -1;
-       }
-
-       if (!tile->current)
-       {
-               tile->current = (BYTE*)_aligned_malloc((8192 + 32) * 3, 16);
-               if (!tile->current)
-                       return -1;
-       }
-
-       pBuffer = tile->sign;
-       pSign[0] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 0) + 16])); /* Y/R buffer */
-       pSign[1] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
-       pSign[2] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
+       pSign[0] = (INT16*)((BYTE*)(&tile->sign[((8192 + 32) * 0) + 16])); /* Y/R buffer */
+       pSign[1] = (INT16*)((BYTE*)(&tile->sign[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
+       pSign[2] = (INT16*)((BYTE*)(&tile->sign[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
 
-       pBuffer = tile->current;
-       pCurrent[0] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 0) + 16])); /* Y/R buffer */
-       pCurrent[1] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
-       pCurrent[2] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
+       pCurrent[0] = (INT16*)((BYTE*)(&tile->current[((8192 + 32) * 0) + 16])); /* Y/R buffer */
+       pCurrent[1] = (INT16*)((BYTE*)(&tile->current[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
+       pCurrent[2] = (INT16*)((BYTE*)(&tile->current[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
 
        pBuffer = (BYTE*)BufferPool_Take(progressive->bufferPool, -1);
        pSrcDst[0] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 0) + 16])); /* Y/R buffer */
        pSrcDst[1] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
        pSrcDst[2] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
 
-       progressive_rfx_decode_component(progressive, &shiftY, tile->yData, tile->yLen, pSrcDst[0],
-                                        pCurrent[0], pSign[0], diff); /* Y */
-       progressive_rfx_decode_component(progressive, &shiftCb, tile->cbData, tile->cbLen, pSrcDst[1],
-                                        pCurrent[1], pSign[1], diff); /* Cb */
-       progressive_rfx_decode_component(progressive, &shiftCr, tile->crData, tile->crLen, pSrcDst[2],
-                                        pCurrent[2], pSign[2], diff); /* Cr */
-
-       prims->yCbCrToRGB_16s8u_P3AC4R((const INT16**)pSrcDst, 64 * 2, tile->data, tile->stride,
-                                      tile->format, &roi_64x64);
+       rc = progressive_rfx_decode_component(progressive, &shiftY, tile->yData, tile->yLen, pSrcDst[0],
+                                             pCurrent[0], pSign[0], diff, sub, extrapolate); /* Y */
+       if (rc < 0)
+               goto fail;
+       rc = progressive_rfx_decode_component(progressive, &shiftCb, tile->cbData, tile->cbLen,
+                                             pSrcDst[1], pCurrent[1], pSign[1], diff, sub,
+                                             extrapolate); /* Cb */
+       if (rc < 0)
+               goto fail;
+       rc = progressive_rfx_decode_component(progressive, &shiftCr, tile->crData, tile->crLen,
+                                             pSrcDst[2], pCurrent[2], pSign[2], diff, sub,
+                                             extrapolate); /* Cr */
+       if (rc < 0)
+               goto fail;
+
+       rc = prims->yCbCrToRGB_16s8u_P3AC4R((const INT16* const*)pSrcDst, 64 * 2, tile->data,
+                                           tile->stride, progressive->format, &roi_64x64);
+fail:
        BufferPool_Return(progressive->bufferPool, pBuffer);
-       return 1;
+       return rc;
 }
 
 static INLINE INT16 progressive_rfx_srl_read(RFX_PROGRESSIVE_UPGRADE_STATE* state, UINT32 numBits)
 {
-       int k;
+       UINT32 k;
        UINT32 bit;
        UINT32 max;
        UINT32 mag;
@@ -957,10 +1062,11 @@ static INLINE INT16 progressive_rfx_srl_read(RFX_PROGRESSIVE_UPGRADE_STATE* stat
        /* read sign bit */
        sign = (bs->accumulator & 0x80000000) ? 1 : 0;
        BitStream_Shift(bs, 1);
-       state->kp -= 6;
 
-       if (state->kp < 0)
+       if (state->kp < 6)
                state->kp = 0;
+       else
+               state->kp -= 6;
 
        if (numBits == 1)
                return sign ? -1 : 1;
@@ -984,9 +1090,12 @@ static INLINE INT16 progressive_rfx_srl_read(RFX_PROGRESSIVE_UPGRADE_STATE* stat
 
 static INLINE int progressive_rfx_upgrade_state_finish(RFX_PROGRESSIVE_UPGRADE_STATE* state)
 {
-       int pad;
+       UINT32 pad;
        wBitStream* srl;
        wBitStream* raw;
+       if (!state)
+               return -1;
+
        srl = state->srl;
        raw = state->raw;
        /* Read trailing bits from RAW/SRL bit streams */
@@ -1062,24 +1171,20 @@ static INLINE int progressive_rfx_upgrade_block(RFX_PROGRESSIVE_UPGRADE_STATE* s
        return 1;
 }
 
-static INLINE int progressive_rfx_upgrade_component(PROGRESSIVE_CONTEXT* progressive,
-                                                    RFX_COMPONENT_CODEC_QUANT* shift,
-                                                    RFX_COMPONENT_CODEC_QUANT* bitPos,
-                                                    RFX_COMPONENT_CODEC_QUANT* numBits,
-                                                    INT16* buffer, INT16* current, INT16* sign,
-                                                    const BYTE* srlData, UINT32 srlLen,
-                                                    const BYTE* rawData, UINT32 rawLen)
+static INLINE int progressive_rfx_upgrade_component(
+    PROGRESSIVE_CONTEXT* progressive, const RFX_COMPONENT_CODEC_QUANT* shift,
+    const RFX_COMPONENT_CODEC_QUANT* bitPos, const RFX_COMPONENT_CODEC_QUANT* numBits,
+    INT16* buffer, INT16* current, INT16* sign, const BYTE* srlData, UINT32 srlLen,
+    const BYTE* rawData, UINT32 rawLen, BOOL subbandDiff, BOOL extrapolate)
 {
+       int rc;
        INT16* temp;
        UINT32 aRawLen;
        UINT32 aSrlLen;
-       wBitStream s_srl;
-       wBitStream s_raw;
-       RFX_PROGRESSIVE_UPGRADE_STATE state;
+       wBitStream s_srl = { 0 };
+       wBitStream s_raw = { 0 };
+       RFX_PROGRESSIVE_UPGRADE_STATE state = { 0 };
 
-       ZeroMemory(&s_srl, sizeof(wBitStream));
-       ZeroMemory(&s_raw, sizeof(wBitStream));
-       ZeroMemory(&state, sizeof(RFX_PROGRESSIVE_UPGRADE_STATE));
        state.kp = 8;
        state.mode = 0;
        state.srl = &s_srl;
@@ -1090,29 +1195,51 @@ static INLINE int progressive_rfx_upgrade_component(PROGRESSIVE_CONTEXT* progres
        BitStream_Fetch(state.raw);
 
        state.nonLL = TRUE;
-       progressive_rfx_upgrade_block(&state, &current[0], &sign[0], 1023, shift->HL1, bitPos->HL1,
-                                     numBits->HL1); /* HL1 */
-       progressive_rfx_upgrade_block(&state, &current[1023], &sign[1023], 1023, shift->LH1,
-                                     bitPos->LH1, numBits->LH1); /* LH1 */
-       progressive_rfx_upgrade_block(&state, &current[2046], &sign[2046], 961, shift->HH1, bitPos->HH1,
-                                     numBits->HH1); /* HH1 */
-       progressive_rfx_upgrade_block(&state, &current[3007], &sign[3007], 272, shift->HL2, bitPos->HL2,
-                                     numBits->HL2); /* HL2 */
-       progressive_rfx_upgrade_block(&state, &current[3279], &sign[3279], 272, shift->LH2, bitPos->LH2,
-                                     numBits->LH2); /* LH2 */
-       progressive_rfx_upgrade_block(&state, &current[3551], &sign[3551], 256, shift->HH2, bitPos->HH2,
-                                     numBits->HH2); /* HH2 */
-       progressive_rfx_upgrade_block(&state, &current[3807], &sign[3807], 72, shift->HL3, bitPos->HL3,
-                                     numBits->HL3); /* HL3 */
-       progressive_rfx_upgrade_block(&state, &current[3879], &sign[3879], 72, shift->LH3, bitPos->LH3,
-                                     numBits->LH3); /* LH3 */
-       progressive_rfx_upgrade_block(&state, &current[3951], &sign[3951], 64, shift->HH3, bitPos->HH3,
-                                     numBits->HH3); /* HH3 */
+       rc = progressive_rfx_upgrade_block(&state, &current[0], &sign[0], 1023, shift->HL1, bitPos->HL1,
+                                          numBits->HL1); /* HL1 */
+       if (rc < 0)
+               return rc;
+       rc = progressive_rfx_upgrade_block(&state, &current[1023], &sign[1023], 1023, shift->LH1,
+                                          bitPos->LH1, numBits->LH1); /* LH1 */
+       if (rc < 0)
+               return rc;
+       rc = progressive_rfx_upgrade_block(&state, &current[2046], &sign[2046], 961, shift->HH1,
+                                          bitPos->HH1, numBits->HH1); /* HH1 */
+       if (rc < 0)
+               return rc;
+       rc = progressive_rfx_upgrade_block(&state, &current[3007], &sign[3007], 272, shift->HL2,
+                                          bitPos->HL2, numBits->HL2); /* HL2 */
+       if (rc < 0)
+               return rc;
+       rc = progressive_rfx_upgrade_block(&state, &current[3279], &sign[3279], 272, shift->LH2,
+                                          bitPos->LH2, numBits->LH2); /* LH2 */
+       if (rc < 0)
+               return rc;
+       rc = progressive_rfx_upgrade_block(&state, &current[3551], &sign[3551], 256, shift->HH2,
+                                          bitPos->HH2, numBits->HH2); /* HH2 */
+       if (rc < 0)
+               return rc;
+       rc = progressive_rfx_upgrade_block(&state, &current[3807], &sign[3807], 72, shift->HL3,
+                                          bitPos->HL3, numBits->HL3); /* HL3 */
+       if (rc < 0)
+               return rc;
+       rc = progressive_rfx_upgrade_block(&state, &current[3879], &sign[3879], 72, shift->LH3,
+                                          bitPos->LH3, numBits->LH3); /* LH3 */
+       if (rc < 0)
+               return rc;
+       rc = progressive_rfx_upgrade_block(&state, &current[3951], &sign[3951], 64, shift->HH3,
+                                          bitPos->HH3, numBits->HH3); /* HH3 */
+       if (rc < 0)
+               return rc;
 
        state.nonLL = FALSE;
-       progressive_rfx_upgrade_block(&state, &current[4015], &sign[4015], 81, shift->LL3, bitPos->LL3,
-                                     numBits->LL3); /* LL3 */
-       progressive_rfx_upgrade_state_finish(&state);
+       rc = progressive_rfx_upgrade_block(&state, &current[4015], &sign[4015], 81, shift->LL3,
+                                          bitPos->LL3, numBits->LL3); /* LL3 */
+       if (rc < 0)
+               return rc;
+       rc = progressive_rfx_upgrade_state_finish(&state);
+       if (rc < 0)
+               return rc;
        aRawLen = (state.raw->position + 7) / 8;
        aSrlLen = (state.srl->position + 7) / 8;
 
@@ -1138,31 +1265,33 @@ static INLINE int progressive_rfx_upgrade_component(PROGRESSIVE_CONTEXT* progres
 
        temp = (INT16*)BufferPool_Take(progressive->bufferPool, -1); /* DWT buffer */
        CopyMemory(buffer, current, 4096 * 2);
-       progressive_rfx_dwt_2d_decode_block(&buffer[3807], temp, 3);
-       progressive_rfx_dwt_2d_decode_block(&buffer[3007], temp, 2);
-       progressive_rfx_dwt_2d_decode_block(&buffer[0], temp, 1);
+       progressive_rfx_dwt_2d_decode_block(&buffer[3807], temp, 3, extrapolate);
+       progressive_rfx_dwt_2d_decode_block(&buffer[3007], temp, 2, extrapolate);
+       progressive_rfx_dwt_2d_decode_block(&buffer[0], temp, 1, extrapolate);
        BufferPool_Return(progressive->bufferPool, temp);
        return 1;
 }
 
 static INLINE int progressive_decompress_tile_upgrade(PROGRESSIVE_CONTEXT* progressive,
-                                                      RFX_PROGRESSIVE_TILE* tile)
+                                                      RFX_PROGRESSIVE_TILE* tile,
+                                                      PROGRESSIVE_BLOCK_REGION* region,
+                                                      const PROGRESSIVE_BLOCK_CONTEXT* context)
 {
        int status;
+       BOOL sub, extrapolate;
        BYTE* pBuffer;
-       INT16* pSign[3];
-       INT16* pSrcDst[3];
-       INT16* pCurrent[3];
-       PROGRESSIVE_BLOCK_REGION* region;
-       RFX_COMPONENT_CODEC_QUANT shiftY;
-       RFX_COMPONENT_CODEC_QUANT shiftCb;
-       RFX_COMPONENT_CODEC_QUANT shiftCr;
-       RFX_COMPONENT_CODEC_QUANT yBitPos;
-       RFX_COMPONENT_CODEC_QUANT cbBitPos;
-       RFX_COMPONENT_CODEC_QUANT crBitPos;
-       RFX_COMPONENT_CODEC_QUANT yNumBits;
-       RFX_COMPONENT_CODEC_QUANT cbNumBits;
-       RFX_COMPONENT_CODEC_QUANT crNumBits;
+       INT16* pSign[3] = { 0 };
+       INT16* pSrcDst[3] = { 0 };
+       INT16* pCurrent[3] = { 0 };
+       RFX_COMPONENT_CODEC_QUANT shiftY = { 0 };
+       RFX_COMPONENT_CODEC_QUANT shiftCb = { 0 };
+       RFX_COMPONENT_CODEC_QUANT shiftCr = { 0 };
+       RFX_COMPONENT_CODEC_QUANT yBitPos = { 0 };
+       RFX_COMPONENT_CODEC_QUANT cbBitPos = { 0 };
+       RFX_COMPONENT_CODEC_QUANT crBitPos = { 0 };
+       RFX_COMPONENT_CODEC_QUANT yNumBits = { 0 };
+       RFX_COMPONENT_CODEC_QUANT cbNumBits = { 0 };
+       RFX_COMPONENT_CODEC_QUANT crNumBits = { 0 };
        RFX_COMPONENT_CODEC_QUANT* quantY;
        RFX_COMPONENT_CODEC_QUANT* quantCb;
        RFX_COMPONENT_CODEC_QUANT* quantCr;
@@ -1172,6 +1301,10 @@ static INLINE int progressive_decompress_tile_upgrade(PROGRESSIVE_CONTEXT* progr
        RFX_PROGRESSIVE_CODEC_QUANT* quantProg;
        static const prim_size_t roi_64x64 = { 64, 64 };
        const primitives_t* prims = primitives_get();
+
+       sub = context->flags & RFX_SUBBAND_DIFFING;
+       extrapolate = region->flags & RFX_DWT_REDUCE_EXTRAPOLATE;
+
        tile->pass++;
        WLog_Print(progressive->log, WLOG_DEBUG,
                   "ProgressiveTileUpgrade: pass: %" PRIu16 " quantIdx Y: %" PRIu8 " Cb: %" PRIu8
@@ -1181,20 +1314,30 @@ static INLINE int progressive_decompress_tile_upgrade(PROGRESSIVE_CONTEXT* progr
                   tile->pass, tile->quantIdxY, tile->quantIdxCb, tile->quantIdxCr, tile->xIdx,
                   tile->yIdx, tile->quality, tile->ySrlLen, tile->yRawLen, tile->cbSrlLen,
                   tile->cbRawLen, tile->crSrlLen, tile->crRawLen);
-       region = &(progressive->region);
 
        if (tile->quantIdxY >= region->numQuant)
+       {
+               WLog_ERR(TAG, "quantIdxY %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxY, region->numQuant);
                return -1;
+       }
 
        quantY = &(region->quantVals[tile->quantIdxY]);
 
        if (tile->quantIdxCb >= region->numQuant)
+       {
+               WLog_ERR(TAG, "quantIdxCb %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxCb,
+                        region->numQuant);
                return -1;
+       }
 
        quantCb = &(region->quantVals[tile->quantIdxCb]);
 
        if (tile->quantIdxCr >= region->numQuant)
+       {
+               WLog_ERR(TAG, "quantIdxCr %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxCr,
+                        region->numQuant);
                return -1;
+       }
 
        quantCr = &(region->quantVals[tile->quantIdxCr]);
 
@@ -1205,7 +1348,11 @@ static INLINE int progressive_decompress_tile_upgrade(PROGRESSIVE_CONTEXT* progr
        else
        {
                if (tile->quality >= region->numProgQuant)
+               {
+                       WLog_ERR(TAG, "quality %" PRIu8 " > numProgQuant %" PRIu8, tile->quality,
+                                region->numProgQuant);
                        return -1;
+               }
 
                quantProg = &(region->quantProgVals[tile->quality]);
        }
@@ -1223,6 +1370,13 @@ static INLINE int progressive_decompress_tile_upgrade(PROGRESSIVE_CONTEXT* progr
        if (!progressive_rfx_quant_cmp_equal(quantCr, &(tile->crQuant)))
                WLog_Print(progressive->log, WLOG_WARN, "non-progressive quantCr has changed!");
 
+       if (!(region->flags & RFX_DWT_REDUCE_EXTRAPOLATE))
+               WLog_Print(progressive->log, WLOG_WARN,
+                          "RFX_PROGRESSIVE_REGION::flags & RFX_DWT_REDUCE_EXTRAPOLATE not set");
+
+       if (!(context->flags & RFX_SUBBAND_DIFFING))
+               WLog_WARN(TAG, "PROGRESSIVE_BLOCK_CONTEXT::flags & RFX_SUBBAND_DIFFING not set");
+
        progressive_rfx_quant_add(quantY, quantProgY, &yBitPos);
        progressive_rfx_quant_add(quantCb, quantProgCb, &cbBitPos);
        progressive_rfx_quant_add(quantCr, quantProgCr, &crBitPos);
@@ -1236,25 +1390,23 @@ static INLINE int progressive_decompress_tile_upgrade(PROGRESSIVE_CONTEXT* progr
        progressive_rfx_quant_add(quantCr, quantProgCr, &shiftCr);
        progressive_rfx_quant_lsub(&shiftCr, 1); /* -6 + 5 = -1 */
 
-       CopyMemory(&(tile->yBitPos), &yBitPos, sizeof(RFX_COMPONENT_CODEC_QUANT));
-       CopyMemory(&(tile->cbBitPos), &cbBitPos, sizeof(RFX_COMPONENT_CODEC_QUANT));
-       CopyMemory(&(tile->crBitPos), &crBitPos, sizeof(RFX_COMPONENT_CODEC_QUANT));
-       CopyMemory(&(tile->yQuant), quantY, sizeof(RFX_COMPONENT_CODEC_QUANT));
-       CopyMemory(&(tile->cbQuant), quantCb, sizeof(RFX_COMPONENT_CODEC_QUANT));
-       CopyMemory(&(tile->crQuant), quantCr, sizeof(RFX_COMPONENT_CODEC_QUANT));
-       CopyMemory(&(tile->yProgQuant), quantProgY, sizeof(RFX_COMPONENT_CODEC_QUANT));
-       CopyMemory(&(tile->cbProgQuant), quantProgCb, sizeof(RFX_COMPONENT_CODEC_QUANT));
-       CopyMemory(&(tile->crProgQuant), quantProgCr, sizeof(RFX_COMPONENT_CODEC_QUANT));
-
-       pBuffer = tile->sign;
-       pSign[0] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 0) + 16])); /* Y/R buffer */
-       pSign[1] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
-       pSign[2] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
-
-       pBuffer = tile->current;
-       pCurrent[0] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 0) + 16])); /* Y/R buffer */
-       pCurrent[1] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
-       pCurrent[2] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
+       tile->yBitPos = yBitPos;
+       tile->cbBitPos = cbBitPos;
+       tile->crBitPos = crBitPos;
+       tile->yQuant = *quantY;
+       tile->cbQuant = *quantCb;
+       tile->crQuant = *quantCr;
+       tile->yProgQuant = *quantProgY;
+       tile->cbProgQuant = *quantProgCb;
+       tile->crProgQuant = *quantProgCr;
+
+       pSign[0] = (INT16*)((BYTE*)(&tile->sign[((8192 + 32) * 0) + 16])); /* Y/R buffer */
+       pSign[1] = (INT16*)((BYTE*)(&tile->sign[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
+       pSign[2] = (INT16*)((BYTE*)(&tile->sign[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
+
+       pCurrent[0] = (INT16*)((BYTE*)(&tile->current[((8192 + 32) * 0) + 16])); /* Y/R buffer */
+       pCurrent[1] = (INT16*)((BYTE*)(&tile->current[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
+       pCurrent[2] = (INT16*)((BYTE*)(&tile->current[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
 
        pBuffer = (BYTE*)BufferPool_Take(progressive->bufferPool, -1);
        pSrcDst[0] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 0) + 16])); /* Y/R buffer */
@@ -1263,309 +1415,604 @@ static INLINE int progressive_decompress_tile_upgrade(PROGRESSIVE_CONTEXT* progr
 
        status = progressive_rfx_upgrade_component(
            progressive, &shiftY, quantProgY, &yNumBits, pSrcDst[0], pCurrent[0], pSign[0],
-           tile->ySrlData, tile->ySrlLen, tile->yRawData, tile->yRawLen); /* Y */
+           tile->ySrlData, tile->ySrlLen, tile->yRawData, tile->yRawLen, sub, extrapolate); /* Y */
 
        if (status < 0)
-               return -1;
+               goto fail;
 
-       status = progressive_rfx_upgrade_component(
-           progressive, &shiftCb, quantProgCb, &cbNumBits, pSrcDst[1], pCurrent[1], pSign[1],
-           tile->cbSrlData, tile->cbSrlLen, tile->cbRawData, tile->cbRawLen); /* Cb */
+       status = progressive_rfx_upgrade_component(progressive, &shiftCb, quantProgCb, &cbNumBits,
+                                                  pSrcDst[1], pCurrent[1], pSign[1], tile->cbSrlData,
+                                                  tile->cbSrlLen, tile->cbRawData, tile->cbRawLen, sub,
+                                                  extrapolate); /* Cb */
 
        if (status < 0)
-               return -1;
+               goto fail;
 
-       status = progressive_rfx_upgrade_component(
-           progressive, &shiftCr, quantProgCr, &crNumBits, pSrcDst[2], pCurrent[2], pSign[2],
-           tile->crSrlData, tile->crSrlLen, tile->crRawData, tile->crRawLen); /* Cr */
+       status = progressive_rfx_upgrade_component(progressive, &shiftCr, quantProgCr, &crNumBits,
+                                                  pSrcDst[2], pCurrent[2], pSign[2], tile->crSrlData,
+                                                  tile->crSrlLen, tile->crRawData, tile->crRawLen, sub,
+                                                  extrapolate); /* Cr */
 
        if (status < 0)
-               return -1;
+               goto fail;
 
-       prims->yCbCrToRGB_16s8u_P3AC4R((const INT16**)pSrcDst, 64 * 2, tile->data, tile->stride,
-                                      tile->format, &roi_64x64);
+       status = prims->yCbCrToRGB_16s8u_P3AC4R((const INT16* const*)pSrcDst, 64 * 2, tile->data,
+                                               tile->stride, progressive->format, &roi_64x64);
+fail:
        BufferPool_Return(progressive->bufferPool, pBuffer);
-       return 1;
+       return status;
+}
+
+static INLINE BOOL progressive_tile_read_upgrade(PROGRESSIVE_CONTEXT* progressive, wStream* s,
+                                                 UINT16 blockType, UINT32 blockLen,
+                                                 PROGRESSIVE_SURFACE_CONTEXT* surface,
+                                                 PROGRESSIVE_BLOCK_REGION* region,
+                                                 const PROGRESSIVE_BLOCK_CONTEXT* context)
+{
+       RFX_PROGRESSIVE_TILE tile = { 0 };
+       const size_t expect = 20;
+
+       if (Stream_GetRemainingLength(s) < expect)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR, "Expected %" PRIuz " bytes, got %" PRIuz, expect,
+                          Stream_GetRemainingLength(s));
+               return FALSE;
+       }
+
+       tile.blockType = blockType;
+       tile.blockLen = blockLen;
+       tile.flags = 0;
+
+       Stream_Read_UINT8(s, tile.quantIdxY);
+       Stream_Read_UINT8(s, tile.quantIdxCb);
+       Stream_Read_UINT8(s, tile.quantIdxCr);
+       Stream_Read_UINT16(s, tile.xIdx);
+       Stream_Read_UINT16(s, tile.yIdx);
+       Stream_Read_UINT8(s, tile.quality);
+       Stream_Read_UINT16(s, tile.ySrlLen);
+       Stream_Read_UINT16(s, tile.yRawLen);
+       Stream_Read_UINT16(s, tile.cbSrlLen);
+       Stream_Read_UINT16(s, tile.cbRawLen);
+       Stream_Read_UINT16(s, tile.crSrlLen);
+       Stream_Read_UINT16(s, tile.crRawLen);
+
+       tile.ySrlData = Stream_Pointer(s);
+       if (!Stream_SafeSeek(s, tile.ySrlLen))
+       {
+               WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.ySrlLen);
+               return FALSE;
+       }
+
+       tile.yRawData = Stream_Pointer(s);
+       if (!Stream_SafeSeek(s, tile.yRawLen))
+       {
+               WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.yRawLen);
+               return FALSE;
+       }
+
+       tile.cbSrlData = Stream_Pointer(s);
+       if (!Stream_SafeSeek(s, tile.cbSrlLen))
+       {
+               WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes",
+                          tile.cbSrlLen);
+               return FALSE;
+       }
+
+       tile.cbRawData = Stream_Pointer(s);
+       if (!Stream_SafeSeek(s, tile.cbRawLen))
+       {
+               WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes",
+                          tile.cbRawLen);
+               return FALSE;
+       }
+
+       tile.crSrlData = Stream_Pointer(s);
+       if (!Stream_SafeSeek(s, tile.crSrlLen))
+       {
+               WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes",
+                          tile.crSrlLen);
+               return FALSE;
+       }
+
+       tile.crRawData = Stream_Pointer(s);
+       if (!Stream_SafeSeek(s, tile.crRawLen))
+       {
+               WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes",
+                          tile.crRawLen);
+               return FALSE;
+       }
+
+       return progressive_surface_tile_replace(surface, region, &tile, TRUE);
+}
+
+static INLINE BOOL progressive_tile_read(PROGRESSIVE_CONTEXT* progressive, BOOL simple, wStream* s,
+                                         UINT16 blockType, UINT32 blockLen,
+                                         PROGRESSIVE_SURFACE_CONTEXT* surface,
+                                         PROGRESSIVE_BLOCK_REGION* region,
+                                         const PROGRESSIVE_BLOCK_CONTEXT* context)
+{
+       RFX_PROGRESSIVE_TILE tile = { 0 };
+       size_t expect = simple ? 16 : 17;
+
+       if (Stream_GetRemainingLength(s) < expect)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR, "Expected %" PRIuz " bytes, got %" PRIuz, expect,
+                          Stream_GetRemainingLength(s));
+               return FALSE;
+       }
+
+       tile.blockType = blockType;
+       tile.blockLen = blockLen;
+
+       Stream_Read_UINT8(s, tile.quantIdxY);
+       Stream_Read_UINT8(s, tile.quantIdxCb);
+       Stream_Read_UINT8(s, tile.quantIdxCr);
+       Stream_Read_UINT16(s, tile.xIdx);
+       Stream_Read_UINT16(s, tile.yIdx);
+       Stream_Read_UINT8(s, tile.flags);
+
+       if (!simple)
+               Stream_Read_UINT8(s, tile.quality);
+       else
+               tile.quality = 0xFF;
+       Stream_Read_UINT16(s, tile.yLen);
+       Stream_Read_UINT16(s, tile.cbLen);
+       Stream_Read_UINT16(s, tile.crLen);
+       Stream_Read_UINT16(s, tile.tailLen);
+
+       tile.yData = Stream_Pointer(s);
+       if (!Stream_SafeSeek(s, tile.yLen))
+       {
+               WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.yLen);
+               return FALSE;
+       }
+
+       tile.cbData = Stream_Pointer(s);
+       if (!Stream_SafeSeek(s, tile.cbLen))
+       {
+               WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.cbLen);
+               return FALSE;
+       }
+
+       tile.crData = Stream_Pointer(s);
+       if (!Stream_SafeSeek(s, tile.crLen))
+       {
+               WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.crLen);
+               return FALSE;
+       }
+
+       tile.tailData = Stream_Pointer(s);
+       if (!Stream_SafeSeek(s, tile.tailLen))
+       {
+               WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.tailLen);
+               return FALSE;
+       }
+
+       return progressive_surface_tile_replace(surface, region, &tile, FALSE);
 }
 
-static INLINE int progressive_process_tiles(PROGRESSIVE_CONTEXT* progressive, const BYTE* blocks,
-                                            UINT32 blocksLen,
-                                            const PROGRESSIVE_SURFACE_CONTEXT* surface)
+static INLINE int progressive_process_tiles(PROGRESSIVE_CONTEXT* progressive, wStream* s,
+                                            PROGRESSIVE_BLOCK_REGION* region,
+                                            PROGRESSIVE_SURFACE_CONTEXT* surface,
+                                            const PROGRESSIVE_BLOCK_CONTEXT* context)
 {
        int status = -1;
-       const BYTE* block;
-       UINT16 xIdx;
-       UINT16 yIdx;
-       UINT16 zIdx;
+       size_t end;
+       const size_t start = Stream_GetPosition(s);
        UINT16 index;
-       UINT32 boffset;
        UINT16 blockType;
        UINT32 blockLen;
        UINT32 count = 0;
-       UINT32 offset = 0;
-       RFX_PROGRESSIVE_TILE* tile;
-       RFX_PROGRESSIVE_TILE** tiles;
-       PROGRESSIVE_BLOCK_REGION* region;
-       region = &(progressive->region);
-       tiles = region->tiles;
 
-       while ((blocksLen - offset) >= 6)
+       if (Stream_GetRemainingLength(s) < region->tileDataSize)
        {
-               boffset = 0;
-               block = &blocks[offset];
-               blockType = *((UINT16*)&block[boffset + 0]); /* blockType (2 bytes) */
-               blockLen = *((UINT32*)&block[boffset + 2]);  /* blockLen (4 bytes) */
-               boffset += 6;
+               WLog_Print(progressive->log, WLOG_ERROR, "Short block %" PRIuz ", expected %" PRIu32,
+                          Stream_GetRemainingLength(s), region->tileDataSize);
+               return -1;
+       }
+
+       while ((Stream_GetRemainingLength(s) >= 6) &&
+              (region->tileDataSize > (Stream_GetPosition(s) - start)))
+       {
+               size_t rem;
+               const size_t pos = Stream_GetPosition(s);
+               rem = Stream_GetRemainingLength(s);
+
+               Stream_Read_UINT16(s, blockType);
+               Stream_Read_UINT32(s, blockLen);
+
                WLog_Print(progressive->log, WLOG_DEBUG, "%s",
                           progressive_get_block_type_string(blockType));
 
-               if ((blocksLen - offset) < blockLen)
+               if (rem < blockLen)
+               {
+                       WLog_Print(progressive->log, WLOG_ERROR, "Expected %" PRIu32 " remaining %" PRIuz,
+                                  blockLen, rem);
                        return -1003;
+               }
 
+               rem = Stream_GetRemainingLength(s);
                switch (blockType)
                {
                        case PROGRESSIVE_WBT_TILE_SIMPLE:
-                               if ((blockLen - boffset) < 16)
+                               if (!progressive_tile_read(progressive, TRUE, s, blockType, blockLen, surface,
+                                                          region, context))
                                        return -1022;
-
-                               xIdx = *((UINT16*)&block[boffset + 3]); /* xIdx (2 bytes) */
-                               yIdx = *((UINT16*)&block[boffset + 5]); /* yIdx (2 bytes) */
-                               zIdx = (yIdx * surface->gridWidth) + xIdx;
-
-                               if (zIdx >= surface->gridSize)
-                                       return -1;
-
-                               tiles[count] = tile = &(surface->tiles[zIdx]);
-                               tile->blockType = blockType;
-                               tile->blockLen = blockLen;
-                               tile->quality = 0xFF; /* simple tiles use no progressive techniques */
-                               tile->quantIdxY = block[boffset + 0];             /* quantIdxY (1 byte) */
-                               tile->quantIdxCb = block[boffset + 1];            /* quantIdxCb (1 byte) */
-                               tile->quantIdxCr = block[boffset + 2];            /* quantIdxCr (1 byte) */
-                               tile->xIdx = *((UINT16*)&block[boffset + 3]);     /* xIdx (2 bytes) */
-                               tile->yIdx = *((UINT16*)&block[boffset + 5]);     /* yIdx (2 bytes) */
-                               tile->flags = block[boffset + 7] & 1;             /* flags (1 byte) */
-                               tile->yLen = *((UINT16*)&block[boffset + 8]);     /* yLen (2 bytes) */
-                               tile->cbLen = *((UINT16*)&block[boffset + 10]);   /* cbLen (2 bytes) */
-                               tile->crLen = *((UINT16*)&block[boffset + 12]);   /* crLen (2 bytes) */
-                               tile->tailLen = *((UINT16*)&block[boffset + 14]); /* tailLen (2 bytes) */
-                               boffset += 16;
-
-                               if ((tile->blockLen - boffset) < tile->yLen)
-                                       return -1023;
-
-                               tile->yData = &block[boffset];
-                               boffset += tile->yLen;
-
-                               if ((tile->blockLen - boffset) < tile->cbLen)
-                                       return -1024;
-
-                               tile->cbData = &block[boffset];
-                               boffset += tile->cbLen;
-
-                               if ((tile->blockLen - boffset) < tile->crLen)
-                                       return -1025;
-
-                               tile->crData = &block[boffset];
-                               boffset += tile->crLen;
-
-                               if ((tile->blockLen - boffset) < tile->tailLen)
-                                       return -1026;
-
-                               tile->tailData = &block[boffset];
-                               boffset += tile->tailLen;
-                               tile->width = 64;
-                               tile->height = 64;
-                               tile->x = tile->xIdx * 64;
-                               tile->y = tile->yIdx * 64;
-                               tile->format = progressive->format;
-                               tile->stride = GetBytesPerPixel(tile->format) * tile->width;
-                               tile->flags &= 1;
                                break;
 
                        case PROGRESSIVE_WBT_TILE_FIRST:
-                               if ((blockLen - boffset) < 17)
+                               if (!progressive_tile_read(progressive, FALSE, s, blockType, blockLen, surface,
+                                                          region, context))
                                        return -1027;
-
-                               xIdx = *((UINT16*)&block[boffset + 3]); /* xIdx (2 bytes) */
-                               yIdx = *((UINT16*)&block[boffset + 5]); /* yIdx (2 bytes) */
-                               zIdx = (yIdx * surface->gridWidth) + xIdx;
-
-                               if (zIdx >= surface->gridSize)
-                                       return -1;
-
-                               tiles[count] = tile = &(surface->tiles[zIdx]);
-                               tile->blockType = blockType;
-                               tile->blockLen = blockLen;
-                               tile->quantIdxY = block[boffset + 0];             /* quantIdxY (1 byte) */
-                               tile->quantIdxCb = block[boffset + 1];            /* quantIdxCb (1 byte) */
-                               tile->quantIdxCr = block[boffset + 2];            /* quantIdxCr (1 byte) */
-                               tile->xIdx = *((UINT16*)&block[boffset + 3]);     /* xIdx (2 bytes) */
-                               tile->yIdx = *((UINT16*)&block[boffset + 5]);     /* yIdx (2 bytes) */
-                               tile->flags = block[boffset + 7] & 1;             /* flags (1 byte) */
-                               tile->quality = block[boffset + 8];               /* quality (1 byte) */
-                               tile->yLen = *((UINT16*)&block[boffset + 9]);     /* yLen (2 bytes) */
-                               tile->cbLen = *((UINT16*)&block[boffset + 11]);   /* cbLen (2 bytes) */
-                               tile->crLen = *((UINT16*)&block[boffset + 13]);   /* crLen (2 bytes) */
-                               tile->tailLen = *((UINT16*)&block[boffset + 15]); /* tailLen (2 bytes) */
-                               boffset += 17;
-
-                               if ((tile->blockLen - boffset) < tile->yLen)
-                                       return -1028;
-
-                               tile->yData = &block[boffset];
-                               boffset += tile->yLen;
-
-                               if ((tile->blockLen - boffset) < tile->cbLen)
-                                       return -1029;
-
-                               tile->cbData = &block[boffset];
-                               boffset += tile->cbLen;
-
-                               if ((tile->blockLen - boffset) < tile->crLen)
-                                       return -1030;
-
-                               tile->crData = &block[boffset];
-                               boffset += tile->crLen;
-
-                               if ((tile->blockLen - boffset) < tile->tailLen)
-                                       return -1031;
-
-                               tile->tailData = &block[boffset];
-                               boffset += tile->tailLen;
-                               tile->width = 64;
-                               tile->height = 64;
-                               tile->x = tile->xIdx * 64;
-                               tile->y = tile->yIdx * 64;
-                               tile->format = progressive->format;
-                               tile->stride = GetBytesPerPixel(tile->format) * tile->width;
                                break;
 
                        case PROGRESSIVE_WBT_TILE_UPGRADE:
-                               if ((blockLen - boffset) < 20)
+                               if (!progressive_tile_read_upgrade(progressive, s, blockType, blockLen, surface,
+                                                                  region, context))
                                        return -1032;
-
-                               xIdx = *((UINT16*)&block[boffset + 3]); /* xIdx (2 bytes) */
-                               yIdx = *((UINT16*)&block[boffset + 5]); /* yIdx (2 bytes) */
-                               zIdx = (yIdx * surface->gridWidth) + xIdx;
-
-                               if (zIdx >= surface->gridSize)
-                                       return -1;
-
-                               tiles[count] = tile = &(surface->tiles[zIdx]);
-                               tile->blockType = blockType;
-                               tile->blockLen = blockLen;
-                               tile->flags = 0;
-                               tile->quantIdxY = block[boffset + 0];              /* quantIdxY (1 byte) */
-                               tile->quantIdxCb = block[boffset + 1];             /* quantIdxCb (1 byte) */
-                               tile->quantIdxCr = block[boffset + 2];             /* quantIdxCr (1 byte) */
-                               tile->xIdx = *((UINT16*)&block[boffset + 3]);      /* xIdx (2 bytes) */
-                               tile->yIdx = *((UINT16*)&block[boffset + 5]);      /* yIdx (2 bytes) */
-                               tile->quality = block[boffset + 7];                /* quality (1 byte) */
-                               tile->ySrlLen = *((UINT16*)&block[boffset + 8]);   /* ySrlLen (2 bytes) */
-                               tile->yRawLen = *((UINT16*)&block[boffset + 10]);  /* yRawLen (2 bytes) */
-                               tile->cbSrlLen = *((UINT16*)&block[boffset + 12]); /* cbSrlLen (2 bytes) */
-                               tile->cbRawLen = *((UINT16*)&block[boffset + 14]); /* cbRawLen (2 bytes) */
-                               tile->crSrlLen = *((UINT16*)&block[boffset + 16]); /* crSrlLen (2 bytes) */
-                               tile->crRawLen = *((UINT16*)&block[boffset + 18]); /* crRawLen (2 bytes) */
-                               boffset += 20;
-
-                               if ((tile->blockLen - boffset) < tile->ySrlLen)
-                                       return -1033;
-
-                               tile->ySrlData = &block[boffset];
-                               boffset += tile->ySrlLen;
-
-                               if ((tile->blockLen - boffset) < tile->yRawLen)
-                                       return -1034;
-
-                               tile->yRawData = &block[boffset];
-                               boffset += tile->yRawLen;
-
-                               if ((tile->blockLen - boffset) < tile->cbSrlLen)
-                                       return -1035;
-
-                               tile->cbSrlData = &block[boffset];
-                               boffset += tile->cbSrlLen;
-
-                               if ((tile->blockLen - boffset) < tile->cbRawLen)
-                                       return -1036;
-
-                               tile->cbRawData = &block[boffset];
-                               boffset += tile->cbRawLen;
-
-                               if ((tile->blockLen - boffset) < tile->crSrlLen)
-                                       return -1037;
-
-                               tile->crSrlData = &block[boffset];
-                               boffset += tile->crSrlLen;
-
-                               if ((tile->blockLen - boffset) < tile->crRawLen)
-                                       return -1038;
-
-                               tile->crRawData = &block[boffset];
-                               boffset += tile->crRawLen;
-                               tile->width = 64;
-                               tile->height = 64;
-                               tile->x = tile->xIdx * 64;
-                               tile->y = tile->yIdx * 64;
-                               tile->format = progressive->format;
-                               tile->stride = GetBytesPerPixel(tile->format) * tile->width;
                                break;
-
                        default:
+                               WLog_ERR(TAG, "Invalid block type %04 (%s)" PRIx16, blockType,
+                                        progressive_get_block_type_string(blockType));
                                return -1039;
                }
 
-               if (boffset != blockLen)
+               rem = Stream_GetPosition(s);
+               if ((rem - pos) != blockLen)
+               {
+                       WLog_Print(progressive->log, WLOG_ERROR,
+                                  "Actual block read %" PRIuz " but expected %" PRIu32, rem - pos, blockLen);
                        return -1040;
-
-               offset += blockLen;
+               }
                count++;
        }
 
-       if (offset != blocksLen)
+       end = Stream_GetPosition(s);
+       if ((end - start) != region->tileDataSize)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR,
+                          "Actual total blocks read %" PRIuz " but expected %" PRIu32, end - start,
+                          region->tileDataSize);
                return -1041;
+       }
 
        if (count != region->numTiles)
        {
                WLog_Print(progressive->log, WLOG_WARN,
                           "numTiles inconsistency: actual: %" PRIu32 ", expected: %" PRIu16 "\n", count,
                           region->numTiles);
+               return -1044;
        }
 
        for (index = 0; index < region->numTiles; index++)
        {
-               tile = tiles[index];
+               RFX_PROGRESSIVE_TILE* tile = region->tiles[index];
 
                switch (tile->blockType)
                {
                        case PROGRESSIVE_WBT_TILE_SIMPLE:
                        case PROGRESSIVE_WBT_TILE_FIRST:
-                               status = progressive_decompress_tile_first(progressive, tile);
+                               status = progressive_decompress_tile_first(progressive, tile, region, context);
                                break;
 
                        case PROGRESSIVE_WBT_TILE_UPGRADE:
-                               status = progressive_decompress_tile_upgrade(progressive, tile);
+                               status = progressive_decompress_tile_upgrade(progressive, tile, region, context);
                                break;
+                       default:
+                               WLog_Print(progressive->log, WLOG_ERROR, "Invalid block type %04 (%s)" PRIx16,
+                                          tile->blockType, progressive_get_block_type_string(tile->blockType));
+                               return -42;
                }
 
                if (status < 0)
+               {
+                       WLog_Print(progressive->log, WLOG_ERROR, "Failed to decompress %s at %" PRIu16,
+                                  progressive_get_block_type_string(tile->blockType), index);
                        return -1;
+               }
        }
 
-       return (int)offset;
+       return (int)end - start;
 }
 
-INT32 progressive_decompress(PROGRESSIVE_CONTEXT* progressive, const BYTE* pSrcData, UINT32 SrcSize,
-                             BYTE* pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst,
-                             UINT32 nYDst, REGION16* invalidRegion, UINT16 surfaceId)
+static INLINE INT32 progressive_wb_sync(PROGRESSIVE_CONTEXT* progressive, wStream* s,
+                                        UINT16 blockType, UINT32 blockLen)
 {
-       INT32 rc = 1;
-       INT32 status;
-       const BYTE* block;
-       const BYTE* blocks;
-       UINT16 i, j;
+       const UINT32 magic = 0xCACCACCA;
+       const UINT16 version = 0x0100;
+       PROGRESSIVE_BLOCK_SYNC sync;
+
+       sync.blockType = blockType;
+       sync.blockLen = blockLen;
+
+       if (sync.blockLen != 12)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR,
+                          "PROGRESSIVE_BLOCK_SYNC::blockLen = 0x%08" PRIx32 " != 0x%08" PRIx32,
+                          sync.blockLen, 12);
+               return -1005;
+       }
+
+       if (Stream_GetRemainingLength(s) < 6)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR,
+                          "ProgressiveSync short %" PRIuz ", expected %" PRIuz,
+                          Stream_GetRemainingLength(s), 6);
+               return -1004;
+       }
+
+       WLog_Print(progressive->log, WLOG_DEBUG, "ProgressiveSync");
+
+       Stream_Read_UINT32(s, sync.magic);
+       Stream_Read_UINT16(s, sync.version);
+
+       if (sync.magic != magic)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR,
+                          "PROGRESSIVE_BLOCK_SYNC::magic = 0x%08" PRIx32 " != 0x%08" PRIx32, sync.magic,
+                          magic);
+               return -1005;
+       }
+
+       if (sync.version != 0x0100)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR,
+                          "PROGRESSIVE_BLOCK_SYNC::version = 0x%04" PRIx16 " != 0x%04" PRIu16,
+                          sync.version, version);
+               return -1006;
+       }
+
+       if ((progressive->state & FLAG_WBT_SYNC) != 0)
+               WLog_WARN(TAG, "Duplicate PROGRESSIVE_BLOCK_SYNC, ignoring");
+
+       progressive->state |= FLAG_WBT_SYNC;
+       return 1;
+}
+
+static INLINE INT32 progressive_wb_frame_begin(PROGRESSIVE_CONTEXT* progressive, wStream* s,
+                                               UINT16 blockType, UINT32 blockLen)
+{
+       PROGRESSIVE_BLOCK_FRAME_BEGIN frameBegin;
+
+       frameBegin.blockType = blockType;
+       frameBegin.blockLen = blockLen;
+
+       if (frameBegin.blockLen != 12)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR,
+                          " RFX_PROGRESSIVE_FRAME_BEGIN::blockLen = 0x%08" PRIx32 " != 0x%08" PRIx32,
+                          frameBegin.blockLen, 12);
+               return -1005;
+       }
+
+       if (Stream_GetRemainingLength(s) < 6)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR,
+                          "ProgressiveFrameBegin short %" PRIuz ", expected %" PRIuz,
+                          Stream_GetRemainingLength(s), 6);
+               return -1007;
+       }
+
+       Stream_Read_UINT32(s, frameBegin.frameIndex);
+       Stream_Read_UINT16(s, frameBegin.regionCount);
+
+       WLog_Print(progressive->log, WLOG_DEBUG,
+                  "ProgressiveFrameBegin: frameIndex: %" PRIu32 " regionCount: %" PRIu16 "",
+                  frameBegin.frameIndex, frameBegin.regionCount);
+       /**
+        * If the number of elements specified by the regionCount field is
+        * larger than the actual number of elements in the regions field,
+        * the decoder SHOULD ignore this inconsistency.
+        */
+
+       if ((progressive->state & FLAG_WBT_FRAME_BEGIN) != 0)
+       {
+               WLog_ERR(TAG, "Duplicate RFX_PROGRESSIVE_FRAME_BEGIN in stream, this is not allowed!");
+               return -1008;
+       }
+
+       if ((progressive->state & FLAG_WBT_FRAME_END) != 0)
+       {
+               WLog_ERR(TAG, "RFX_PROGRESSIVE_FRAME_BEGIN after RFX_PROGRESSIVE_FRAME_END in stream, this "
+                             "is not allowed!");
+               return -1008;
+       }
+
+       progressive->state |= FLAG_WBT_FRAME_BEGIN;
+       return 1;
+}
+
+static INLINE INT32 progressive_wb_frame_end(PROGRESSIVE_CONTEXT* progressive, wStream* s,
+                                             UINT16 blockType, UINT32 blockLen)
+{
+       PROGRESSIVE_BLOCK_FRAME_END frameEnd;
+
+       frameEnd.blockType = blockType;
+       frameEnd.blockLen = blockLen;
+
+       if (frameEnd.blockLen != 6)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR,
+                          " RFX_PROGRESSIVE_FRAME_END::blockLen = 0x%08" PRIx32 " != 0x%08" PRIx32,
+                          frameEnd.blockLen, 6);
+               return -1005;
+       }
+
+       if (Stream_GetRemainingLength(s) != 0)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR,
+                          "ProgressiveFrameEnd short %" PRIuz ", expected %" PRIuz,
+                          Stream_GetRemainingLength(s), 0);
+               return -1008;
+       }
+
+       WLog_Print(progressive->log, WLOG_DEBUG, "ProgressiveFrameEnd");
+       if ((progressive->state & FLAG_WBT_FRAME_BEGIN) == 0)
+               WLog_WARN(TAG, "RFX_PROGRESSIVE_FRAME_END before RFX_PROGRESSIVE_FRAME_BEGIN, ignoring");
+       if ((progressive->state & FLAG_WBT_FRAME_END) != 0)
+               WLog_WARN(TAG, "Duplicate RFX_PROGRESSIVE_FRAME_END, ignoring");
+
+       progressive->state |= FLAG_WBT_FRAME_END;
+       return 1;
+}
+
+static INLINE int progressive_wb_context(PROGRESSIVE_CONTEXT* progressive, wStream* s,
+                                         UINT16 blockType, UINT32 blockLen)
+{
+       PROGRESSIVE_BLOCK_CONTEXT* context = &progressive->context;
+       context->blockType = blockType;
+       context->blockLen = blockLen;
+
+       if (context->blockLen != 10)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR,
+                          "RFX_PROGRESSIVE_CONTEXT::blockLen = 0x%08" PRIx32 " != 0x%08" PRIx32,
+                          context->blockLen, 10);
+               return -1005;
+       }
+
+       if (Stream_GetRemainingLength(s) < 4)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR,
+                          "ProgressiveContext short %" PRIuz ", expected %" PRIuz,
+                          Stream_GetRemainingLength(s), 4);
+               return -1009;
+       }
+
+       Stream_Read_UINT8(s, context->ctxId);
+       Stream_Read_UINT16(s, context->tileSize);
+       Stream_Read_UINT8(s, context->flags);
+
+       if (context->ctxId != 0x00)
+               WLog_WARN(TAG, "RFX_PROGRESSIVE_CONTEXT::ctxId != 0x00: %" PRIu8, context->ctxId);
+
+       if (context->tileSize != 64)
+       {
+               WLog_ERR(TAG, "RFX_PROGRESSIVE_CONTEXT::tileSize != 0x40: %" PRIu16, context->tileSize);
+               return -1010;
+       }
+
+       if ((progressive->state & FLAG_WBT_FRAME_BEGIN) != 0)
+               WLog_WARN(TAG, "RFX_PROGRESSIVE_CONTEXT received after RFX_PROGRESSIVE_FRAME_BEGIN");
+       if ((progressive->state & FLAG_WBT_FRAME_END) != 0)
+               WLog_WARN(TAG, "RFX_PROGRESSIVE_CONTEXT received after RFX_PROGRESSIVE_FRAME_END");
+       if ((progressive->state & FLAG_WBT_CONTEXT) != 0)
+               WLog_WARN(TAG, "Duplicate RFX_PROGRESSIVE_CONTEXT received, ignoring.");
+
+       WLog_Print(progressive->log, WLOG_DEBUG, "ProgressiveContext: flags: 0x%02" PRIX8 "",
+                  context->flags);
+
+       progressive->state |= FLAG_WBT_CONTEXT;
+       return 1;
+}
+
+static INLINE INT32 progressive_wb_read_region_header(PROGRESSIVE_CONTEXT* progressive, wStream* s,
+                                                      UINT16 blockType, UINT32 blockLen,
+                                                      PROGRESSIVE_BLOCK_REGION* region)
+{
+       size_t offset, len;
+
+       if (Stream_GetRemainingLength(s) < 12)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR,
+                          "ProgressiveRegion short %" PRIuz ", expected %" PRIuz,
+                          Stream_GetRemainingLength(s), 12);
+               return -1011;
+       }
+
+       region->blockType = blockType;
+       region->blockLen = blockLen;
+       Stream_Read_UINT8(s, region->tileSize);
+       Stream_Read_UINT16(s, region->numRects);
+       Stream_Read_UINT8(s, region->numQuant);
+       Stream_Read_UINT8(s, region->numProgQuant);
+       Stream_Read_UINT8(s, region->flags);
+       Stream_Read_UINT16(s, region->numTiles);
+       Stream_Read_UINT32(s, region->tileDataSize);
+
+       if (region->tileSize != 64)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR,
+                          "ProgressiveRegion tile size %" PRIu8 ", expected %" PRIuz, region->tileSize,
+                          64);
+               return -1012;
+       }
+
+       if (region->numRects < 1)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR, "ProgressiveRegion missing rect count %" PRIu16,
+                          region->numRects);
+               return -1013;
+       }
+
+       if (region->numQuant > 7)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR,
+                          "ProgressiveRegion quant count too high %" PRIu8 ", expected < %" PRIuz,
+                          region->numQuant, 7);
+               return -1014;
+       }
+
+       len = Stream_GetRemainingLength(s);
+       offset = (region->numRects * 8);
+       if (len < offset)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR, "ProgressiveRegion data short for region->rects");
+               return -1015;
+       }
+
+       offset += (region->numQuant * 5);
+       if (len < offset)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR, "ProgressiveRegion data short for region->cQuant");
+               return -1018;
+       }
+
+       offset += (region->numProgQuant * 16);
+       if (len < offset)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR,
+                          "ProgressiveRegion data short for region->cProgQuant");
+               return -1021;
+       }
+
+       offset += region->tileDataSize;
+       if (len < offset)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR, "ProgressiveRegion data short for region->tiles");
+               return -1024;
+       }
+
+       return 0;
+}
+
+static INLINE INT32 progressive_wb_skip_region(PROGRESSIVE_CONTEXT* progressive, wStream* s,
+                                               UINT16 blockType, UINT32 blockLen)
+{
+       INT32 rc;
+       size_t total;
+       PROGRESSIVE_BLOCK_REGION region = { 0 };
+
+       rc = progressive_wb_read_region_header(progressive, s, blockType, blockLen, &region);
+       if (rc < 0)
+               return rc;
+
+       total = (region.numRects * 8);
+       total += (region.numQuant * 5);
+       total += (region.numProgQuant * 16);
+       total += region.tileDataSize;
+       if (!Stream_SafeSeek(s, total))
+               return -1111;
+
+       return 0;
+}
+
+static INLINE INT32 progressive_wb_region(PROGRESSIVE_CONTEXT* progressive, wStream* s,
+                                          UINT16 blockType, UINT32 blockLen,
+                                          PROGRESSIVE_SURFACE_CONTEXT* surface,
+                                          PROGRESSIVE_BLOCK_REGION* region)
+{
+       INT32 rc;
        UINT16 index;
        UINT16 boxLeft;
        UINT16 boxTop;
@@ -1575,345 +2022,220 @@ INT32 progressive_decompress(PROGRESSIVE_CONTEXT* progressive, const BYTE* pSrcD
        UINT16 idxTop;
        UINT16 idxRight;
        UINT16 idxBottom;
-       UINT32 boffset;
+       const PROGRESSIVE_BLOCK_CONTEXT* context = &progressive->context;
+
+       if ((progressive->state & FLAG_WBT_FRAME_BEGIN) == 0)
+       {
+               WLog_WARN(TAG, "RFX_PROGRESSIVE_REGION before RFX_PROGRESSIVE_FRAME_BEGIN, ignoring");
+               return progressive_wb_skip_region(progressive, s, blockType, blockLen);
+       }
+       if ((progressive->state & FLAG_WBT_FRAME_END) != 0)
+       {
+               WLog_WARN(TAG, "RFX_PROGRESSIVE_REGION after RFX_PROGRESSIVE_FRAME_END, ignoring");
+               return progressive_wb_skip_region(progressive, s, blockType, blockLen);
+       }
+
+       progressive->state |= FLAG_WBT_REGION;
+
+       rc = progressive_wb_read_region_header(progressive, s, blockType, blockLen, region);
+       if (rc < 0)
+               return rc;
+
+       for (index = 0; index < region->numRects; index++)
+       {
+               RFX_RECT* rect = &(region->rects[index]);
+               Stream_Read_UINT16(s, rect->x);
+               Stream_Read_UINT16(s, rect->y);
+               Stream_Read_UINT16(s, rect->width);
+               Stream_Read_UINT16(s, rect->height);
+       }
+
+       for (index = 0; index < region->numQuant; index++)
+       {
+               RFX_COMPONENT_CODEC_QUANT* quantVal = &(region->quantVals[index]);
+               progressive_component_codec_quant_read(s, quantVal);
+
+               if (!progressive_rfx_quant_lcmp_greater_equal(quantVal, 6))
+               {
+                       WLog_Print(progressive->log, WLOG_ERROR,
+                                  "ProgressiveRegion region->cQuant[%" PRIu32 "] < 6", index);
+                       return -1;
+               }
+
+               if (!progressive_rfx_quant_lcmp_less_equal(quantVal, 15))
+               {
+                       WLog_Print(progressive->log, WLOG_ERROR,
+                                  "ProgressiveRegion region->cQuant[%" PRIu32 "] > 15", index);
+                       return -1;
+               }
+       }
+
+       for (index = 0; index < region->numProgQuant; index++)
+       {
+               RFX_PROGRESSIVE_CODEC_QUANT* quantProgVal = &(region->quantProgVals[index]);
+
+               Stream_Read_UINT8(s, quantProgVal->quality);
+
+               progressive_component_codec_quant_read(s, &(quantProgVal->yQuantValues));
+               progressive_component_codec_quant_read(s, &(quantProgVal->cbQuantValues));
+               progressive_component_codec_quant_read(s, &(quantProgVal->crQuantValues));
+       }
+
+       WLog_Print(progressive->log, WLOG_DEBUG,
+                  "ProgressiveRegion: numRects: %" PRIu16 " numTiles: %" PRIu16
+                  " tileDataSize: %" PRIu32 " flags: 0x%02" PRIX8 " numQuant: %" PRIu8
+                  " numProgQuant: %" PRIu8 "",
+                  region->numRects, region->numTiles, region->tileDataSize, region->flags,
+                  region->numQuant, region->numProgQuant);
+
+       boxLeft = surface->gridWidth;
+       boxTop = surface->gridHeight;
+       boxRight = 0;
+       boxBottom = 0;
+
+       for (index = 0; index < region->numRects; index++)
+       {
+               RFX_RECT* rect = &(region->rects[index]);
+               idxLeft = rect->x / 64;
+               idxTop = rect->y / 64;
+               idxRight = (rect->x + rect->width + 63) / 64;
+               idxBottom = (rect->y + rect->height + 63) / 64;
+
+               if (idxLeft < boxLeft)
+                       boxLeft = idxLeft;
+
+               if (idxTop < boxTop)
+                       boxTop = idxTop;
+
+               if (idxRight > boxRight)
+                       boxRight = idxRight;
+
+               if (idxBottom > boxBottom)
+                       boxBottom = idxBottom;
+
+               WLog_Print(progressive->log, WLOG_DEBUG,
+                          "rect[%" PRIu16 "]: x: %" PRIu16 " y: %" PRIu16 " w: %" PRIu16 " h: %" PRIu16 "",
+                          index, rect->x, rect->y, rect->width, rect->height);
+       }
+
+       return progressive_process_tiles(progressive, s, region, surface, context);
+}
+
+INT32 progressive_decompress(PROGRESSIVE_CONTEXT* progressive, const BYTE* pSrcData, UINT32 SrcSize,
+                             BYTE* pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst,
+                             UINT32 nYDst, REGION16* invalidRegion, UINT16 surfaceId)
+{
+       INT32 rc = 1;
+       UINT16 i, j;
        UINT16 blockType;
        UINT32 blockLen;
-       UINT32 blocksLen;
        UINT32 count = 0;
-       UINT32 offset = 0;
-       RFX_RECT* rect = NULL;
+       wStream *s, ss;
+       size_t start, end;
        REGION16 clippingRects, updateRegion;
-       PROGRESSIVE_SURFACE_CONTEXT* surface;
        PROGRESSIVE_BLOCK_REGION* region;
-       surface = (PROGRESSIVE_SURFACE_CONTEXT*)progressive_get_surface_data(progressive, surfaceId);
+       PROGRESSIVE_SURFACE_CONTEXT* surface = progressive_get_surface_data(progressive, surfaceId);
 
        if (!surface)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR, "ProgressiveRegion no surface for %" PRIu16,
+                          surfaceId);
                return -1001;
+       }
 
-       blocks = pSrcData;
-       blocksLen = SrcSize;
-       region = &(progressive->region);
-       progressive->format = DstFormat;
-
-       while ((blocksLen - offset) >= 6)
-       {
-               PROGRESSIVE_BLOCK_SYNC sync;
-               PROGRESSIVE_BLOCK_CONTEXT context;
-               PROGRESSIVE_BLOCK_FRAME_BEGIN frameBegin;
-               PROGRESSIVE_BLOCK_FRAME_END frameEnd;
-               RFX_COMPONENT_CODEC_QUANT* quantVal;
-               RFX_PROGRESSIVE_CODEC_QUANT* quantProgVal;
-               boffset = 0;
-               block = &blocks[offset];
-               blockType = *((UINT16*)&block[boffset + 0]); /* blockType (2 bytes) */
-               blockLen = *((UINT32*)&block[boffset + 2]);  /* blockLen (4 bytes) */
-               boffset += 6;
-
-               if ((blocksLen - offset) < blockLen)
-                       return -1003;
+       region = calloc(1, sizeof(PROGRESSIVE_BLOCK_REGION));
+       if (!region)
+               return -1111;
 
-               switch (blockType)
-               {
-                       case PROGRESSIVE_WBT_SYNC:
-                               WLog_Print(progressive->log, WLOG_DEBUG, "ProgressiveSync");
-                               sync.blockType = blockType;
-                               sync.blockLen = blockLen;
+       Stream_StaticInit(&ss, pSrcData, SrcSize);
+       s = &ss;
+
+       switch (DstFormat)
+       {
+               case PIXEL_FORMAT_RGBA32:
+               case PIXEL_FORMAT_RGBX32:
+               case PIXEL_FORMAT_BGRA32:
+               case PIXEL_FORMAT_BGRX32:
+                       progressive->format = DstFormat;
+                       break;
+               default:
+                       progressive->format = PIXEL_FORMAT_XRGB32;
+                       break;
+       }
 
-                               if ((blockLen - boffset) != 6)
-                                       return -1004;
+       start = Stream_GetPosition(s);
+       progressive->state = 0; /* Set state to not initialized */
+       while (Stream_GetRemainingLength(s) >= 6)
+       {
+               size_t rem, st, e;
 
-                               sync.magic = (UINT32) * ((UINT32*)&block[boffset + 0]);   /* magic (4 bytes) */
-                               sync.version = (UINT32) * ((UINT16*)&block[boffset + 4]); /* version (2 bytes) */
-                               boffset += 6;
+               st = Stream_GetPosition(s);
+               rem = Stream_GetRemainingLength(s);
 
-                               if (sync.magic != 0xCACCACCA)
-                                       return -1005;
+               Stream_Read_UINT16(s, blockType);
+               Stream_Read_UINT32(s, blockLen);
 
-                               if (sync.version != 0x0100)
-                                       return -1006;
+               if (rem < blockLen)
+               {
+                       WLog_Print(progressive->log, WLOG_ERROR, "Short block %" PRIuz ", expected %" PRIu32,
+                                  rem, blockLen);
+                       rc = -1003;
+                       goto fail;
+               }
 
+               rem = Stream_GetRemainingLength(s);
+               switch (blockType)
+               {
+                       case PROGRESSIVE_WBT_SYNC:
+                               rc = progressive_wb_sync(progressive, s, blockType, blockLen);
                                break;
 
                        case PROGRESSIVE_WBT_FRAME_BEGIN:
-                               frameBegin.blockType = blockType;
-                               frameBegin.blockLen = blockLen;
-
-                               if ((blockLen - boffset) < 6)
-                                       return -1007;
-
-                               frameBegin.frameIndex =
-                                   (UINT32) * ((UINT32*)&block[boffset + 0]); /* frameIndex (4 bytes) */
-                               frameBegin.regionCount =
-                                   (UINT32) * ((UINT16*)&block[boffset + 4]); /* regionCount (2 bytes) */
-                               boffset += 6;
-                               WLog_Print(progressive->log, WLOG_DEBUG,
-                                          "ProgressiveFrameBegin: frameIndex: %" PRIu32 " regionCount: %" PRIu16
-                                          "",
-                                          frameBegin.frameIndex, frameBegin.regionCount);
-                               /**
-                                * If the number of elements specified by the regionCount field is
-                                * larger than the actual number of elements in the regions field,
-                                * the decoder SHOULD ignore this inconsistency.
-                                */
+                               rc = progressive_wb_frame_begin(progressive, s, blockType, blockLen);
                                break;
 
                        case PROGRESSIVE_WBT_FRAME_END:
-                               WLog_Print(progressive->log, WLOG_DEBUG, "ProgressiveFrameEnd");
-                               frameEnd.blockType = blockType;
-                               frameEnd.blockLen = blockLen;
-
-                               if ((blockLen - boffset) != 0)
-                                       return -1008;
-
+                               rc = progressive_wb_frame_end(progressive, s, blockType, blockLen);
                                break;
 
                        case PROGRESSIVE_WBT_CONTEXT:
-                               context.blockType = blockType;
-                               context.blockLen = blockLen;
-
-                               if ((blockLen - boffset) != 4)
-                                       return -1009;
-
-                               context.ctxId = block[boffset + 0];                 /* ctxId (1 byte) */
-                               context.tileSize = *((UINT16*)&block[boffset + 1]); /* tileSize (2 bytes) */
-                               context.flags = block[boffset + 3];                 /* flags (1 byte) */
-                               boffset += 4;
-
-                               if (context.tileSize != 64)
-                                       return -1010;
-
-                               WLog_Print(progressive->log, WLOG_DEBUG,
-                                          "ProgressiveContext: flags: 0x%02" PRIX8 "", context.flags);
-
-                               if (!(context.flags & RFX_SUBBAND_DIFFING))
-                                       WLog_Print(progressive->log, WLOG_WARN, "RFX_SUBBAND_DIFFING is not set");
-
+                               rc = progressive_wb_context(progressive, s, blockType, blockLen);
                                break;
 
                        case PROGRESSIVE_WBT_REGION:
-                               region->blockType = blockType;
-                               region->blockLen = blockLen;
-
-                               if ((blockLen - boffset) < 12)
-                                       return -1011;
-
-                               region->tileSize = block[boffset + 0];                  /* tileSize (1 byte) */
-                               region->numRects = *((UINT16*)&block[boffset + 1]);     /* numRects (2 bytes) */
-                               region->numQuant = block[boffset + 3];                  /* numQuant (1 byte) */
-                               region->numProgQuant = block[boffset + 4];              /* numProgQuant (1 byte) */
-                               region->flags = block[boffset + 5];                     /* flags (1 byte) */
-                               region->numTiles = *((UINT16*)&block[boffset + 6]);     /* numTiles (2 bytes) */
-                               region->tileDataSize = *((UINT32*)&block[boffset + 8]); /* tileDataSize (4 bytes) */
-                               boffset += 12;
-
-                               if (region->tileSize != 64)
-                                       return -1012;
-
-                               if (region->numRects < 1)
-                                       return -1013;
-
-                               if (region->numQuant > 7)
-                                       return -1014;
-
-                               if ((blockLen - boffset) < (region->numRects * 8))
-                                       return -1015;
-
-                               if (region->numRects > progressive->cRects)
-                               {
-                                       RFX_RECT* tmpBuf =
-                                           (RFX_RECT*)realloc(progressive->rects, region->numRects * sizeof(RFX_RECT));
-                                       if (!tmpBuf)
-                                               return -1016;
-
-                                       progressive->rects = tmpBuf;
-                                       progressive->cRects = region->numRects;
-                               }
-
-                               region->rects = progressive->rects;
-
-                               if (!region->rects)
-                                       return -1017;
-
-                               for (index = 0; index < region->numRects; index++)
-                               {
-                                       rect = &(region->rects[index]);
-                                       rect->x = *((UINT16*)&block[boffset + 0]);
-                                       rect->y = *((UINT16*)&block[boffset + 2]);
-                                       rect->width = *((UINT16*)&block[boffset + 4]);
-                                       rect->height = *((UINT16*)&block[boffset + 6]);
-                                       boffset += 8;
-                               }
-
-                               if ((blockLen - boffset) < (region->numQuant * 5))
-                                       return -1018;
-
-                               if (region->numQuant > progressive->cQuant)
-                               {
-                                       RFX_COMPONENT_CODEC_QUANT* tmpBuf = (RFX_COMPONENT_CODEC_QUANT*)realloc(
-                                           progressive->quantVals,
-                                           region->numQuant * sizeof(RFX_COMPONENT_CODEC_QUANT));
-                                       if (!tmpBuf)
-                                               return -1019;
-
-                                       progressive->quantVals = tmpBuf;
-                                       progressive->cQuant = region->numQuant;
-                               }
-
-                               region->quantVals = progressive->quantVals;
-
-                               if (!region->quantVals)
-                                       return -1020;
-
-                               for (index = 0; index < region->numQuant; index++)
-                               {
-                                       quantVal = &(region->quantVals[index]);
-                                       progressive_component_codec_quant_read(&block[boffset], quantVal);
-                                       boffset += 5;
-
-                                       if (!progressive_rfx_quant_lcmp_greater_equal(quantVal, 6))
-                                               return -1;
-
-                                       if (!progressive_rfx_quant_lcmp_less_equal(quantVal, 15))
-                                               return -1;
-                               }
-
-                               if ((blockLen - boffset) < (region->numProgQuant * 16))
-                                       return -1021;
-
-                               if (region->numProgQuant > progressive->cProgQuant)
-                               {
-                                       RFX_PROGRESSIVE_CODEC_QUANT* tmpBuf = (RFX_PROGRESSIVE_CODEC_QUANT*)realloc(
-                                           progressive->quantProgVals,
-                                           region->numProgQuant * sizeof(RFX_PROGRESSIVE_CODEC_QUANT));
-                                       if (!tmpBuf)
-                                               return -1022;
-
-                                       progressive->quantProgVals = tmpBuf;
-                                       progressive->cProgQuant = region->numProgQuant;
-                               }
-
-                               region->quantProgVals = progressive->quantProgVals;
-
-                               if (!region->quantProgVals)
-                                       return -1023;
-
-                               for (index = 0; index < region->numProgQuant; index++)
-                               {
-                                       quantProgVal = &(region->quantProgVals[index]);
-                                       quantProgVal->quality = block[boffset + 0];
-                                       progressive_component_codec_quant_read(&block[boffset + 1],
-                                                                              &(quantProgVal->yQuantValues));
-                                       progressive_component_codec_quant_read(&block[boffset + 6],
-                                                                              &(quantProgVal->cbQuantValues));
-                                       progressive_component_codec_quant_read(&block[boffset + 11],
-                                                                              &(quantProgVal->crQuantValues));
-                                       boffset += 16;
-                               }
-
-                               if ((blockLen - boffset) < region->tileDataSize)
-                                       return -1024;
-
-                               if (progressive->cTiles < surface->gridSize)
-                               {
-                                       RFX_PROGRESSIVE_TILE** tmpBuf = (RFX_PROGRESSIVE_TILE**)realloc(
-                                           progressive->tiles, surface->gridSize * sizeof(RFX_PROGRESSIVE_TILE*));
-                                       if (!tmpBuf)
-                                               return -1025;
-
-                                       progressive->tiles = tmpBuf;
-                                       progressive->cTiles = surface->gridSize;
-                               }
-
-                               region->tiles = progressive->tiles;
-
-                               if (!region->tiles)
-                                       return -1;
-
-                               WLog_Print(progressive->log, WLOG_DEBUG,
-                                          "ProgressiveRegion: numRects: %" PRIu16 " numTiles: %" PRIu16
-                                          " tileDataSize: %" PRIu32 " flags: 0x%02" PRIX8 " numQuant: %" PRIu8
-                                          " numProgQuant: %" PRIu8 "",
-                                          region->numRects, region->numTiles, region->tileDataSize, region->flags,
-                                          region->numQuant, region->numProgQuant);
-
-                               if (!(region->flags & RFX_DWT_REDUCE_EXTRAPOLATE))
-                                       WLog_Print(progressive->log, WLOG_WARN,
-                                                  "RFX_DWT_REDUCE_EXTRAPOLATE is not set");
-
-                               boxLeft = surface->gridWidth;
-                               boxTop = surface->gridHeight;
-                               boxRight = 0;
-                               boxBottom = 0;
-
-                               for (index = 0; index < region->numRects; index++)
-                               {
-                                       rect = &(region->rects[index]);
-                                       idxLeft = rect->x / 64;
-                                       idxTop = rect->y / 64;
-                                       idxRight = (rect->x + rect->width + 63) / 64;
-                                       idxBottom = (rect->y + rect->height + 63) / 64;
-
-                                       if (idxLeft < boxLeft)
-                                               boxLeft = idxLeft;
-
-                                       if (idxTop < boxTop)
-                                               boxTop = idxTop;
-
-                                       if (idxRight > boxRight)
-                                               boxRight = idxRight;
-
-                                       if (idxBottom > boxBottom)
-                                               boxBottom = idxBottom;
-
-                                       WLog_Print(progressive->log, WLOG_DEBUG,
-                                                  "rect[%" PRIu16 "]: x: %" PRIu16 " y: %" PRIu16 " w: %" PRIu16
-                                                  " h: %" PRIu16 "",
-                                                  index, rect->x, rect->y, rect->width, rect->height);
-                               }
-
-                               status = progressive_process_tiles(progressive, &block[boffset],
-                                                                  region->tileDataSize, surface);
-
-                               if (status < 0)
-                                       return status;
-
-                               region->numTiles = 0;
-
-                               for (index = 0; index < surface->gridSize; index++)
-                               {
-                                       RFX_PROGRESSIVE_TILE* tile = &(surface->tiles[index]);
-
-                                       if (!tile->data)
-                                               continue;
-
-                                       if ((tile->xIdx < boxLeft) || (tile->xIdx > boxRight))
-                                               continue;
-
-                                       if ((tile->yIdx < boxTop) || (tile->yIdx > boxBottom))
-                                               continue;
-
-                                       region->tiles[region->numTiles++] = tile;
-                               }
-
-                               boffset += (UINT32)status;
+                               rc = progressive_wb_region(progressive, s, blockType, blockLen, surface, region);
                                break;
 
                        default:
-                               return -1039;
-                               break;
+                               WLog_Print(progressive->log, WLOG_ERROR, "Invalid block type %04" PRIx16,
+                                          blockType);
+                               rc = -1039;
                }
 
-               if (boffset != blockLen)
-                       return -1040;
+               if (rc < 0)
+                       goto fail;
 
-               offset += blockLen;
+               e = Stream_GetPosition(s);
+               if ((e - st) != blockLen)
+               {
+                       WLog_Print(progressive->log, WLOG_ERROR,
+                                  "block len %" PRIuz " does not match read data %" PRIu32, e - st, blockLen);
+                       rc = -1040;
+                       goto fail;
+               }
                count++;
        }
 
-       if (offset != blocksLen)
-               return -1041;
+       end = Stream_GetPosition(s);
+       if ((end - start) != SrcSize)
+       {
+               WLog_Print(progressive->log, WLOG_ERROR,
+                          "total block len %" PRIuz " does not match read data %" PRIu32, end - start,
+                          SrcSize);
+               rc = -1041;
+               goto fail;
+       }
 
-       region = &(progressive->region);
        region16_init(&clippingRects);
 
        for (i = 0; i < region->numRects; i++)
@@ -1933,6 +2255,7 @@ INT32 progressive_decompress(PROGRESSIVE_CONTEXT* progressive, const BYTE* pSrcD
                const RECTANGLE_16* updateRects;
                RECTANGLE_16 updateRect;
                RFX_PROGRESSIVE_TILE* tile = region->tiles[i];
+
                updateRect.left = nXDst + tile->x;
                updateRect.top = nYDst + tile->y;
                updateRect.right = updateRect.left + 64;
@@ -1950,8 +2273,8 @@ INT32 progressive_decompress(PROGRESSIVE_CONTEXT* progressive, const BYTE* pSrcD
                        const UINT32 height = rect->bottom - rect->top;
 
                        if (!freerdp_image_copy(pDstData, DstFormat, nDstStep, rect->left, rect->top, width,
-                                               height, tile->data, tile->format, tile->stride, nXSrc, nYSrc,
-                                               NULL, FREERDP_FLIP_NONE))
+                                               height, tile->data, progressive->format, tile->stride, nXSrc,
+                                               nYSrc, NULL, FREERDP_FLIP_NONE))
                        {
                                rc = -42;
                                break;
@@ -1965,6 +2288,9 @@ INT32 progressive_decompress(PROGRESSIVE_CONTEXT* progressive, const BYTE* pSrcD
        }
 
        region16_uninit(&clippingRects);
+
+fail:
+       free(region);
        return rc;
 }
 
@@ -1991,32 +2317,6 @@ PROGRESSIVE_CONTEXT* progressive_context_new(BOOL Compressor)
        {
                progressive->Compressor = Compressor;
                progressive->bufferPool = BufferPool_New(TRUE, (8192 + 32) * 3, 16);
-               progressive->cRects = 64;
-               progressive->rects = (RFX_RECT*)calloc(progressive->cRects, sizeof(RFX_RECT));
-
-               if (!progressive->rects)
-                       goto cleanup;
-
-               progressive->cTiles = 64;
-               progressive->tiles =
-                   (RFX_PROGRESSIVE_TILE**)calloc(progressive->cTiles, sizeof(RFX_PROGRESSIVE_TILE*));
-
-               if (!progressive->tiles)
-                       goto cleanup;
-
-               progressive->cQuant = 8;
-               progressive->quantVals = (RFX_COMPONENT_CODEC_QUANT*)calloc(
-                   progressive->cQuant, sizeof(RFX_COMPONENT_CODEC_QUANT));
-
-               if (!progressive->quantVals)
-                       goto cleanup;
-
-               progressive->cProgQuant = 8;
-               progressive->quantProgVals = (RFX_PROGRESSIVE_CODEC_QUANT*)calloc(
-                   progressive->cProgQuant, sizeof(RFX_PROGRESSIVE_CODEC_QUANT));
-
-               if (!progressive->quantProgVals)
-                       goto cleanup;
 
                ZeroMemory(&(progressive->quantProgValFull), sizeof(RFX_PROGRESSIVE_CODEC_QUANT));
                progressive->quantProgValFull.quality = 100;
@@ -2026,9 +2326,6 @@ PROGRESSIVE_CONTEXT* progressive_context_new(BOOL Compressor)
        }
 
        return progressive;
-cleanup:
-       progressive_context_free(progressive);
-       return NULL;
 }
 
 void progressive_context_free(PROGRESSIVE_CONTEXT* progressive)
@@ -2042,10 +2339,6 @@ void progressive_context_free(PROGRESSIVE_CONTEXT* progressive)
                return;
 
        BufferPool_Free(progressive->bufferPool);
-       free(progressive->rects);
-       free(progressive->tiles);
-       free(progressive->quantVals);
-       free(progressive->quantProgVals);
 
        if (progressive->SurfaceContexts)
        {
index e54ed98..edd3e47 100644 (file)
@@ -133,7 +133,6 @@ struct _RFX_PROGRESSIVE_TILE
        UINT32 y;
        UINT32 width;
        UINT32 height;
-       UINT32 format;
        UINT32 stride;
 
        BYTE* data;
@@ -141,6 +140,7 @@ struct _RFX_PROGRESSIVE_TILE
 
        UINT16 pass;
        BYTE* sign;
+
        RFX_COMPONENT_CODEC_QUANT yBitPos;
        RFX_COMPONENT_CODEC_QUANT cbBitPos;
        RFX_COMPONENT_CODEC_QUANT crBitPos;
@@ -164,11 +164,12 @@ struct _PROGRESSIVE_BLOCK_REGION
        BYTE numProgQuant;
        BYTE flags;
        UINT16 numTiles;
+       UINT16 usedTiles;
        UINT32 tileDataSize;
-       RFX_RECT* rects;
-       RFX_COMPONENT_CODEC_QUANT* quantVals;
-       RFX_PROGRESSIVE_CODEC_QUANT* quantProgVals;
-       RFX_PROGRESSIVE_TILE** tiles;
+       RFX_RECT rects[0x10000];
+       RFX_COMPONENT_CODEC_QUANT quantVals[0x100];
+       RFX_PROGRESSIVE_CODEC_QUANT quantProgVals[0x100];
+       RFX_PROGRESSIVE_TILE* tiles[0x10000];
 };
 typedef struct _PROGRESSIVE_BLOCK_REGION PROGRESSIVE_BLOCK_REGION;
 
@@ -202,26 +203,26 @@ struct _PROGRESSIVE_SURFACE_CONTEXT
 };
 typedef struct _PROGRESSIVE_SURFACE_CONTEXT PROGRESSIVE_SURFACE_CONTEXT;
 
+enum _WBT_STATE_FLAG
+{
+       FLAG_WBT_SYNC = 0x01,
+       FLAG_WBT_FRAME_BEGIN = 0x02,
+       FLAG_WBT_FRAME_END = 0x04,
+       FLAG_WBT_CONTEXT = 0x08,
+       FLAG_WBT_REGION = 0x10
+};
+typedef enum _WBT_STATE_FLAG WBT_STATE_FLAG;
+
 struct _PROGRESSIVE_CONTEXT
 {
        BOOL Compressor;
 
        wBufferPool* bufferPool;
 
-       UINT32 cRects;
-       RFX_RECT* rects;
-
        UINT32 format;
+       UINT32 state;
 
-       UINT32 cTiles;
-       RFX_PROGRESSIVE_TILE** tiles;
-
-       UINT32 cQuant;
-       RFX_COMPONENT_CODEC_QUANT* quantVals;
-
-       UINT32 cProgQuant;
-       RFX_PROGRESSIVE_CODEC_QUANT* quantProgVals;
-
+       PROGRESSIVE_BLOCK_CONTEXT context;
        PROGRESSIVE_BLOCK_REGION region;
        RFX_PROGRESSIVE_CODEC_QUANT quantProgValFull;