diff --git a/include/freerdp/codec/mppc.h b/include/freerdp/codec/mppc.h index a4eae83c2..174820474 100644 --- a/include/freerdp/codec/mppc.h +++ b/include/freerdp/codec/mppc.h @@ -29,10 +29,8 @@ struct _MPPC_CONTEXT { wBitStream* bs; BOOL Compressor; - UINT32 HistoryPtr; - BYTE* pHistoryPtr; + BYTE* HistoryPtr; UINT32 HistoryOffset; - BYTE* pHistoryOffset; UINT32 HistoryBufferSize; BYTE HistoryBuffer[65536]; UINT16 MatchBuffer[32768]; @@ -45,6 +43,7 @@ extern "C" { #endif FREERDP_API UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* pSize); +FREERDP_API UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UINT32* pSize, UINT32 flags); FREERDP_API MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor); FREERDP_API void mppc_context_free(MPPC_CONTEXT* mppc); diff --git a/libfreerdp/codec/mppc.c b/libfreerdp/codec/mppc.c index 51b2dc5b5..bdcd681a5 100644 --- a/libfreerdp/codec/mppc.c +++ b/libfreerdp/codec/mppc.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include @@ -72,271 +72,675 @@ const UINT32 MPPC_MATCH_TABLE[256] = //#define DEBUG_MPPC 1 -UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* pSize) +UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UINT32* pSize, UINT32 flags) { - BYTE* pEnd; - UINT32 Flags; - BYTE* pMatch; - UINT32 MatchIndex; + BYTE Literal; + BYTE* SrcPtr; + UINT32 CopyOffset; + UINT32 LengthOfMatch; UINT32 accumulator; + BYTE* HistoryBuffer; + BYTE* HistoryPtr; + UINT32 HistoryOffset; + UINT32 CompressionLevel; + wBitStream* bs = mppc->bs; - Flags = mppc->CompressionLevel; + HistoryBuffer = mppc->HistoryBuffer; + CompressionLevel = mppc->CompressionLevel; - BitStream_Attach(mppc->bs, pDstData, *pSize); + *ppDstData = HistoryBuffer; - if (((mppc->HistoryOffset + *pSize) < (mppc->HistoryBufferSize - 3)) /* && mppc->HistoryOffset */) + BitStream_Attach(bs, pSrcData, *pSize); + BitStream_Fetch(bs); + + if (flags & PACKET_AT_FRONT) { - /* SrcData fits into HistoryBuffer? (YES) */ - - CopyMemory(&(mppc->HistoryBuffer[mppc->HistoryOffset]), pSrcData, *pSize); - - mppc->HistoryPtr = 0; - mppc->pHistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryPtr]); - - mppc->HistoryOffset += *pSize; - mppc->pHistoryOffset = &(mppc->HistoryBuffer[mppc->HistoryOffset]); - } - else - { - /* SrcData fits into HistoryBuffer? (NO) */ - - mppc->HistoryOffset = 0; - mppc->pHistoryOffset = &(mppc->HistoryBuffer[mppc->HistoryOffset]); - - Flags |= PACKET_AT_FRONT; + mppc->HistoryPtr = &(HistoryBuffer[0]); } - if (mppc->HistoryPtr < mppc->HistoryOffset) + if (flags & PACKET_FLUSHED) { - /* HistoryPtr < HistoryOffset? (YES) */ + mppc->HistoryPtr = &(HistoryBuffer[0]); + ZeroMemory(HistoryBuffer, mppc->HistoryBufferSize); + } - /* - * Search for a match of at least 3 bytes from the start of the history buffer - * to (HistoryPtr - 1) for the data that immediately follows HistoryPtr + if (!(flags & PACKET_COMPRESSED)) + { + CopyMemory(mppc->HistoryPtr, pSrcData, *pSize); + mppc->HistoryPtr += *pSize; + return 0; + } + + HistoryPtr = mppc->HistoryPtr; + HistoryOffset = mppc->HistoryOffset; + + while ((bs->length - bs->position) >= 8) + { + accumulator = bs->accumulator; + + /** + * Literal Encoding */ - mppc->HistoryPtr = 0; - mppc->pHistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryPtr]); - - pEnd = &(mppc->HistoryBuffer[*pSize - 1]); - - while (mppc->pHistoryPtr < (pEnd - 2)) + if ((accumulator & 0x80000000) == 0x00000000) { - MatchIndex = MPPC_MATCH_INDEX(mppc->pHistoryPtr[0], mppc->pHistoryPtr[1], mppc->pHistoryPtr[2]); + /** + * Literal, less than 0x80 + * bit 0 followed by the lower 7 bits of the literal + */ - pMatch = &(mppc->HistoryBuffer[mppc->MatchBuffer[MatchIndex]]); + Literal = ((accumulator & 0x7F000000) >> 24); - mppc->MatchBuffer[MatchIndex] = (UINT16) mppc->HistoryPtr; + *(HistoryPtr) = Literal; + HistoryPtr++; - if ((mppc->pHistoryPtr[0] != pMatch[0]) || (mppc->pHistoryPtr[1] != pMatch[1]) || - (mppc->pHistoryPtr[2] != pMatch[2]) || (mppc->pHistoryPtr == pMatch)) + BitStream_Shift(bs, 8); + + continue; + } + else if ((accumulator & 0xC0000000) == 0x80000000) + { + /** + * Literal, greater than 0x7F + * bits 10 followed by the lower 7 bits of the literal + */ + + Literal = ((accumulator & 0x3F800000) >> 23) + 0x80; + + *(HistoryPtr) = Literal; + HistoryPtr++; + + BitStream_Shift(bs, 9); + + continue; + } + + /** + * CopyOffset Encoding + */ + + CopyOffset = 0; + + if (CompressionLevel) /* RDP5 */ + { + if ((accumulator & 0xF8000000) == 0xF8000000) { - accumulator = *(mppc->pHistoryPtr); + /** + * CopyOffset, range [0, 63] + * bits 11111 + lower 6 bits of CopyOffset + */ -#ifdef DEBUG_MPPC - printf("0x%02X", accumulator); -#endif + CopyOffset = ((accumulator >> 21) & 0x3F); + BitStream_Shift(bs, 11); + } + else if ((accumulator & 0xF8000000) == 0xF0000000) + { + /** + * CopyOffset, range [64, 319] + * bits 11110 + lower 8 bits of (CopyOffset - 64) + */ - if (accumulator < 0x80) - { - /* 8 bits of literal are encoded as-is */ - BitStream_Write_Bits(mppc->bs, accumulator, 8); - } - else - { - /* bits 10 followed by lower 7 bits of literal */ - accumulator = 0x100 | (accumulator & 0x7F); - BitStream_Write_Bits(mppc->bs, accumulator, 9); - } + CopyOffset = ((accumulator >> 19) & 0xFF) + 64; + BitStream_Shift(bs, 13); + } + else if ((accumulator & 0xF0000000) == 0xE0000000) + { + /** + * CopyOffset, range [320, 2367] + * bits 1110 + lower 11 bits of (CopyOffset - 320) + */ - mppc->HistoryPtr++; - mppc->pHistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryPtr]); + CopyOffset = ((accumulator >> 17) & 0x7FF) + 320; + BitStream_Shift(bs, 15); + } + else if ((accumulator & 0xE0000000) == 0xC0000000) + { + /** + * CopyOffset, range [2368, ] + * bits 110 + lower 16 bits of (CopyOffset - 2368) + */ + + CopyOffset = ((accumulator >> 13) & 0xFFFF) + 2368; + BitStream_Shift(bs, 19); } else { - DWORD CopyOffset; - DWORD LengthOfMatch = 1; + /* Invalid CopyOffset Encoding */ + } + } + else /* RDP4 */ + { + if ((accumulator & 0xF0000000) == 0xF0000000) + { + /** + * CopyOffset, range [0, 63] + * bits 1111 + lower 6 bits of CopyOffset + */ - CopyOffset = (DWORD) (mppc->pHistoryPtr - pMatch); + CopyOffset = ((accumulator >> 22) & 0x3F); + BitStream_Shift(bs, 10); + } + else if ((accumulator & 0xF0000000) == 0xE0000000) + { + /** + * CopyOffset, range [64, 319] + * bits 1110 + lower 8 bits of (CopyOffset - 64) + */ - while ((mppc->pHistoryPtr[LengthOfMatch] == pMatch[LengthOfMatch]) && - ((mppc->HistoryPtr + LengthOfMatch) < (*pSize - 1))) - { - MatchIndex = MPPC_MATCH_INDEX(mppc->pHistoryPtr[LengthOfMatch], - mppc->pHistoryPtr[LengthOfMatch + 1], mppc->pHistoryPtr[LengthOfMatch + 2]); + CopyOffset = ((accumulator >> 20) & 0xFF) + 64; + BitStream_Shift(bs, 12); + } + else if ((accumulator & 0xE0000000) == 0xC0000000) + { + /** + * CopyOffset, range [320, 8191] + * bits 110 + lower 13 bits of (CopyOffset - 320) + */ - mppc->MatchBuffer[MatchIndex] = (UINT16) (mppc->HistoryPtr + LengthOfMatch); - - LengthOfMatch++; - } - -#ifdef DEBUG_MPPC - printf("<%d,%d>", (int) CopyOffset, (int) LengthOfMatch); -#endif - - /* Encode CopyOffset */ - - if (CopyOffset < 64) - { - /* 11111 + lower 6 bits of CopyOffset */ - accumulator = 0x07C0 | (CopyOffset & 0x003F); - BitStream_Write_Bits(mppc->bs, accumulator, 11); - } - else if ((CopyOffset >= 64) && (CopyOffset < 320)) - { - /* 11110 + lower 8 bits of (CopyOffset - 64) */ - accumulator = 0x1E00 | ((CopyOffset - 64) & 0x00FF); - BitStream_Write_Bits(mppc->bs, accumulator, 13); - } - else if ((CopyOffset >= 320) && (CopyOffset < 2368)) - { - /* 1110 + lower 11 bits of (CopyOffset - 320) */ - accumulator = 0x7000 | ((CopyOffset - 320) & 0x07FF); - BitStream_Write_Bits(mppc->bs, accumulator, 15); - } - else - { - /* 110 + lower 16 bits of (CopyOffset - 2368) */ - accumulator = 0x060000 | ((CopyOffset - 2368) & 0xFFFF); - BitStream_Write_Bits(mppc->bs, accumulator, 19); - } - - /* Encode LengthOfMatch */ - - if (LengthOfMatch == 3) - { - /* 0 + 0 lower bits of LengthOfMatch */ - BitStream_Write_Bits(mppc->bs, 0, 1); - } - else if ((LengthOfMatch >= 4) && (LengthOfMatch < 8)) - { - /* 10 + 2 lower bits of LengthOfMatch */ - accumulator = 0x0008 | (LengthOfMatch & 0x0003); - BitStream_Write_Bits(mppc->bs, accumulator, 4); - } - else if ((LengthOfMatch >= 8) && (LengthOfMatch < 16)) - { - /* 110 + 3 lower bits of LengthOfMatch */ - accumulator = 0x0030 | (LengthOfMatch & 0x0007); - BitStream_Write_Bits(mppc->bs, accumulator, 6); - } - else if ((LengthOfMatch >= 16) && (LengthOfMatch < 32)) - { - /* 1110 + 4 lower bits of LengthOfMatch */ - accumulator = 0x00E0 | (LengthOfMatch & 0x000F); - BitStream_Write_Bits(mppc->bs, accumulator, 8); - } - else if ((LengthOfMatch >= 32) && (LengthOfMatch < 64)) - { - /* 11110 + 5 lower bits of LengthOfMatch */ - accumulator = 0x03C0 | (LengthOfMatch & 0x001F); - BitStream_Write_Bits(mppc->bs, accumulator, 10); - } - else if ((LengthOfMatch >= 64) && (LengthOfMatch < 128)) - { - /* 111110 + 6 lower bits of LengthOfMatch */ - accumulator = 0x0F80 | (LengthOfMatch & 0x003F); - BitStream_Write_Bits(mppc->bs, accumulator, 12); - } - else if ((LengthOfMatch >= 128) && (LengthOfMatch < 256)) - { - /* 1111110 + 7 lower bits of LengthOfMatch */ - accumulator = 0x3F00 | (LengthOfMatch & 0x007F); - BitStream_Write_Bits(mppc->bs, accumulator, 14); - } - else if ((LengthOfMatch >= 256) && (LengthOfMatch < 512)) - { - /* 11111110 + 8 lower bits of LengthOfMatch */ - accumulator = 0xFE00 | (LengthOfMatch & 0x00FF); - BitStream_Write_Bits(mppc->bs, accumulator, 16); - } - else if ((LengthOfMatch >= 512) && (LengthOfMatch < 1024)) - { - /* 111111110 + 9 lower bits of LengthOfMatch */ - accumulator = 0x3FC00 | (LengthOfMatch & 0x01FF); - BitStream_Write_Bits(mppc->bs, accumulator, 18); - } - else if ((LengthOfMatch >= 1024) && (LengthOfMatch < 2048)) - { - /* 1111111110 + 10 lower bits of LengthOfMatch */ - accumulator = 0xFF800 | (LengthOfMatch & 0x03FF); - BitStream_Write_Bits(mppc->bs, accumulator, 20); - } - else if ((LengthOfMatch >= 2048) && (LengthOfMatch < 4096)) - { - /* 11111111110 + 11 lower bits of LengthOfMatch */ - accumulator = 0x3FF000 | (LengthOfMatch & 0x07FF); - BitStream_Write_Bits(mppc->bs, accumulator, 22); - } - else if ((LengthOfMatch >= 4096) && (LengthOfMatch < 8192)) - { - /* 111111111110 + 12 lower bits of LengthOfMatch */ - accumulator = 0xFFE000 | (LengthOfMatch & 0x0FFF); - BitStream_Write_Bits(mppc->bs, accumulator, 24); - } - else if ((LengthOfMatch >= 8192) && (LengthOfMatch < 16384)) - { - /* 1111111111110 + 13 lower bits of LengthOfMatch */ - accumulator = 0x3FFC000 | (LengthOfMatch & 0x1FFF); - BitStream_Write_Bits(mppc->bs, accumulator, 26); - } - else if ((LengthOfMatch >= 16384) && (LengthOfMatch < 32768)) - { - /* 11111111111110 + 14 lower bits of LengthOfMatch */ - accumulator = 0xFFF8000 | (LengthOfMatch & 0x3FFF); - BitStream_Write_Bits(mppc->bs, accumulator, 28); - } - else if ((LengthOfMatch >= 32768) && (LengthOfMatch < 65536)) - { - /* 111111111111110 + 15 lower bits of LengthOfMatch */ - accumulator = 0x3FFF0000 | (LengthOfMatch & 0x7FFF); - BitStream_Write_Bits(mppc->bs, accumulator, 30); - } - - mppc->HistoryPtr += LengthOfMatch; - mppc->pHistoryPtr += LengthOfMatch; + CopyOffset = ((accumulator >> 16) & 0x1FFF) + 320; + BitStream_Shift(bs, 16); + } + else + { + /* Invalid CopyOffset Encoding */ } } - /* Encode trailing symbols as literals */ + /** + * LengthOfMatch Encoding + */ - while (mppc->pHistoryPtr <= pEnd) + LengthOfMatch = 0; + accumulator = bs->accumulator; + + if ((accumulator & 0x80000000) == 0x00000000) { - MatchIndex = MPPC_MATCH_INDEX(mppc->pHistoryPtr[0], mppc->pHistoryPtr[1], mppc->pHistoryPtr[2]); + /** + * LengthOfMatch [3] + * bit 0 + 0 lower bits of LengthOfMatch + */ - pMatch = &(mppc->HistoryBuffer[mppc->MatchBuffer[MatchIndex]]); + LengthOfMatch = 3; + BitStream_Shift(bs, 1); + } + else if ((accumulator & 0xC0000000) == 0x80000000) + { + /** + * LengthOfMatch [4, 7] + * bits 10 + 2 lower bits of LengthOfMatch + */ - mppc->MatchBuffer[MatchIndex] = (UINT16) mppc->HistoryPtr; + LengthOfMatch = ((accumulator >> 28) & 0x0003) + 0x0004; + BitStream_Shift(bs, 4); + } + else if ((accumulator & 0xE0000000) == 0xC0000000) + { + /** + * LengthOfMatch [8, 15] + * bits 110 + 3 lower bits of LengthOfMatch + */ - accumulator = *(mppc->pHistoryPtr); + LengthOfMatch = ((accumulator >> 26) & 0x0007) + 0x0008; + BitStream_Shift(bs, 6); + } + else if ((accumulator & 0xF0000000) == 0xE0000000) + { + /** + * LengthOfMatch [16, 31] + * bits 1110 + 4 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 24) & 0x000F) + 0x0010; + BitStream_Shift(bs, 8); + } + else if ((accumulator & 0xF8000000) == 0xF0000000) + { + /** + * LengthOfMatch [32, 63] + * bits 11110 + 5 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 22) & 0x001F) + 0x0020; + BitStream_Shift(bs, 10); + } + else if ((accumulator & 0xFC000000) == 0xF8000000) + { + /** + * LengthOfMatch [64, 127] + * bits 111110 + 6 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 20) & 0x003F) + 0x0040; + BitStream_Shift(bs, 12); + } + else if ((accumulator & 0xFE000000) == 0xFC000000) + { + /** + * LengthOfMatch [128, 255] + * bits 1111110 + 7 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 18) & 0x007F) + 0x0080; + BitStream_Shift(bs, 14); + } + else if ((accumulator & 0xFF000000) == 0xFE000000) + { + /** + * LengthOfMatch [256, 511] + * bits 11111110 + 8 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 16) & 0x00FF) + 0x0100; + BitStream_Shift(bs, 16); + } + else if ((accumulator & 0xFF800000) == 0xFF000000) + { + /** + * LengthOfMatch [512, 1023] + * bits 111111110 + 9 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 14) & 0x01FF) + 0x0200; + BitStream_Shift(bs, 18); + } + else if ((accumulator & 0xFFC00000) == 0xFF800000) + { + /** + * LengthOfMatch [1024, 2047] + * bits 1111111110 + 10 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 12) & 0x03FF) + 0x0400; + BitStream_Shift(bs, 20); + } + else if ((accumulator & 0xFFE00000) == 0xFFC00000) + { + /** + * LengthOfMatch [2048, 4095] + * bits 11111111110 + 11 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 10) & 0x07FF) + 0x0800; + BitStream_Shift(bs, 22); + } + else if ((accumulator & 0xFFF00000) == 0xFFE00000) + { + /** + * LengthOfMatch [4096, 8191] + * bits 111111111110 + 12 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 8) & 0x0FFF) + 0x1000; + BitStream_Shift(bs, 24); + } + else if (((accumulator & 0xFFF80000) == 0xFFF00000) && CompressionLevel) /* RDP5 */ + { + /** + * LengthOfMatch [8192, 16383] + * bits 1111111111110 + 13 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 6) & 0x1FFF) + 0x2000; + BitStream_Shift(bs, 26); + } + else if (((accumulator & 0xFFFC0000) == 0xFFF80000) && CompressionLevel) /* RDP5 */ + { + /** + * LengthOfMatch [16384, 32767] + * bits 11111111111110 + 14 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 4) & 0x3FFF) + 0x4000; + BitStream_Shift(bs, 28); + } + else if (((accumulator & 0xFFFE0000) == 0xFFFC0000) && CompressionLevel) /* RDP5 */ + { + /** + * LengthOfMatch [32768, 65535] + * bits 111111111111110 + 15 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 2) & 0x7FFF) + 0x8000; + BitStream_Shift(bs, 30); + } + else + { + /* Invalid LengthOfMatch Encoding */ + } #ifdef DEBUG_MPPC - printf("%c", accumulator); + printf("<%d,%d>\n", (int) CopyOffset, (int) LengthOfMatch); #endif + SrcPtr = HistoryPtr - CopyOffset; + + while (LengthOfMatch > 0) + { + *(HistoryPtr) = *SrcPtr; + + HistoryPtr++; + SrcPtr++; + + LengthOfMatch--; + } + } + + *pSize = (UINT32) (HistoryPtr - mppc->HistoryPtr); + + mppc->HistoryPtr = HistoryPtr; + + return 0; +} + +UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* pSize) +{ + UINT32 Flags; + BYTE* pSrcEnd; + BYTE* pDstEnd; + BYTE* MatchPtr; + UINT32 MatchIndex; + UINT32 accumulator; + DWORD CopyOffset; + DWORD LengthOfMatch; + BYTE* HistoryBuffer; + BYTE* HistoryPtr; + UINT32 HistoryOffset; + UINT32 HistoryBufferSize; + UINT32 CompressionLevel; + wBitStream* bs = mppc->bs; + + HistoryBuffer = mppc->HistoryBuffer; + HistoryBufferSize = mppc->HistoryBufferSize; + CompressionLevel = mppc->CompressionLevel; + + HistoryPtr = mppc->HistoryPtr; + HistoryOffset = mppc->HistoryOffset; + + BitStream_Attach(bs, pDstData, *pSize); + + CopyMemory(&(HistoryBuffer[HistoryOffset]), pSrcData, *pSize); + + if (((HistoryOffset + *pSize) < (HistoryBufferSize - 3)) && HistoryOffset) + { + Flags = 0; + } + else + { + HistoryOffset = 0; + Flags = PACKET_AT_FRONT; + } + + HistoryPtr = &(HistoryBuffer[HistoryOffset]); + HistoryOffset += *pSize; + + pSrcEnd = &(HistoryBuffer[*pSize - 1]); + pDstEnd = &(pDstData[*pSize - 1]); + + while (HistoryPtr < (pSrcEnd - 2)) + { + MatchIndex = MPPC_MATCH_INDEX(HistoryPtr[0], HistoryPtr[1], HistoryPtr[2]); + MatchPtr = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]); + + /* if (&MatchPtr[1] != HistoryPtr) */ + mppc->MatchBuffer[MatchIndex] = (UINT16) (HistoryPtr - HistoryBuffer); + + if (mppc->HistoryPtr < HistoryPtr) + mppc->HistoryPtr = HistoryPtr; + + if ((HistoryPtr[0] != MatchPtr[0]) || (HistoryPtr[1] != MatchPtr[1]) || + (HistoryPtr[2] != MatchPtr[2]) || (&MatchPtr[2] > mppc->HistoryPtr) || + (MatchPtr == HistoryPtr) || (&MatchPtr[1] == HistoryPtr) || + (MatchPtr == HistoryBuffer)) + { + accumulator = *(HistoryPtr); + +#ifdef DEBUG_MPPC + //printf("%c", accumulator); +#endif + + if (((bs->position / 8) + 2) > (*pSize - 1)) + { + Flags = PACKET_FLUSHED; + ZeroMemory(HistoryBuffer, HistoryBufferSize); + ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer)); + return Flags; + } + if (accumulator < 0x80) { /* 8 bits of literal are encoded as-is */ - BitStream_Write_Bits(mppc->bs, accumulator, 8); + BitStream_Write_Bits(bs, accumulator, 8); } else { /* bits 10 followed by lower 7 bits of literal */ accumulator = 0x100 | (accumulator & 0x7F); - BitStream_Write_Bits(mppc->bs, accumulator, 9); + BitStream_Write_Bits(bs, accumulator, 9); } - mppc->HistoryPtr++; - mppc->pHistoryPtr++; + HistoryPtr++; + } + else + { + LengthOfMatch = 3; + HistoryPtr += 3; + MatchPtr += 3; + + CopyOffset = (HistoryBufferSize - 1) & (HistoryPtr - MatchPtr); + + while ((*HistoryPtr == *MatchPtr) && /* (MatchPtr <= mppc->HistoryPtr) && */ + ((HistoryPtr - HistoryBuffer) < (*pSize - 1))) + { + LengthOfMatch++; + HistoryPtr++; + MatchPtr++; + } + +#ifdef DEBUG_MPPC + printf("<%d,%d>\n", (int) CopyOffset, (int) LengthOfMatch); +#endif + + /* Encode CopyOffset */ + + if (((bs->position / 8) + 7) > (*pSize - 1)) + { + Flags = PACKET_FLUSHED; + ZeroMemory(HistoryBuffer, HistoryBufferSize); + ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer)); + return Flags; + } + + if (CompressionLevel) /* RDP5 */ + { + if (CopyOffset < 64) + { + /* bits 11111 + lower 6 bits of CopyOffset */ + accumulator = 0x07C0 | (CopyOffset & 0x003F); + BitStream_Write_Bits(bs, accumulator, 11); + } + else if ((CopyOffset >= 64) && (CopyOffset < 320)) + { + /* bits 11110 + lower 8 bits of (CopyOffset - 64) */ + accumulator = 0x1E00 | ((CopyOffset - 64) & 0x00FF); + BitStream_Write_Bits(bs, accumulator, 13); + } + else if ((CopyOffset >= 320) && (CopyOffset < 2368)) + { + /* bits 1110 + lower 11 bits of (CopyOffset - 320) */ + accumulator = 0x7000 | ((CopyOffset - 320) & 0x07FF); + BitStream_Write_Bits(bs, accumulator, 15); + } + else + { + /* bits 110 + lower 16 bits of (CopyOffset - 2368) */ + accumulator = 0x060000 | ((CopyOffset - 2368) & 0xFFFF); + BitStream_Write_Bits(bs, accumulator, 19); + } + } + else /* RDP4 */ + { + if (CopyOffset < 64) + { + /* bits 1111 + lower 6 bits of CopyOffset */ + accumulator = 0x03C0 | (CopyOffset & 0x003F); + BitStream_Write_Bits(bs, accumulator, 10); + } + else if ((CopyOffset >= 64) && (CopyOffset < 320)) + { + /* bits 1110 + lower 8 bits of (CopyOffset - 64) */ + accumulator = 0x0E00 | ((CopyOffset - 64) & 0x00FF); + BitStream_Write_Bits(bs, accumulator, 12); + } + else if ((CopyOffset >= 320) && (CopyOffset < 8192)) + { + /* bits 110 + lower 13 bits of (CopyOffset - 320) */ + accumulator = 0xC000 | ((CopyOffset - 320) & 0x1FFF); + BitStream_Write_Bits(bs, accumulator, 16); + } + } + + /* Encode LengthOfMatch */ + + if (LengthOfMatch == 3) + { + /* 0 + 0 lower bits of LengthOfMatch */ + BitStream_Write_Bits(bs, 0, 1); + } + else if ((LengthOfMatch >= 4) && (LengthOfMatch < 8)) + { + /* 10 + 2 lower bits of LengthOfMatch */ + accumulator = 0x0008 | (LengthOfMatch & 0x0003); + BitStream_Write_Bits(bs, accumulator, 4); + } + else if ((LengthOfMatch >= 8) && (LengthOfMatch < 16)) + { + /* 110 + 3 lower bits of LengthOfMatch */ + accumulator = 0x0030 | (LengthOfMatch & 0x0007); + BitStream_Write_Bits(bs, accumulator, 6); + } + else if ((LengthOfMatch >= 16) && (LengthOfMatch < 32)) + { + /* 1110 + 4 lower bits of LengthOfMatch */ + accumulator = 0x00E0 | (LengthOfMatch & 0x000F); + BitStream_Write_Bits(bs, accumulator, 8); + } + else if ((LengthOfMatch >= 32) && (LengthOfMatch < 64)) + { + /* 11110 + 5 lower bits of LengthOfMatch */ + accumulator = 0x03C0 | (LengthOfMatch & 0x001F); + BitStream_Write_Bits(bs, accumulator, 10); + } + else if ((LengthOfMatch >= 64) && (LengthOfMatch < 128)) + { + /* 111110 + 6 lower bits of LengthOfMatch */ + accumulator = 0x0F80 | (LengthOfMatch & 0x003F); + BitStream_Write_Bits(bs, accumulator, 12); + } + else if ((LengthOfMatch >= 128) && (LengthOfMatch < 256)) + { + /* 1111110 + 7 lower bits of LengthOfMatch */ + accumulator = 0x3F00 | (LengthOfMatch & 0x007F); + BitStream_Write_Bits(bs, accumulator, 14); + } + else if ((LengthOfMatch >= 256) && (LengthOfMatch < 512)) + { + /* 11111110 + 8 lower bits of LengthOfMatch */ + accumulator = 0xFE00 | (LengthOfMatch & 0x00FF); + BitStream_Write_Bits(bs, accumulator, 16); + } + else if ((LengthOfMatch >= 512) && (LengthOfMatch < 1024)) + { + /* 111111110 + 9 lower bits of LengthOfMatch */ + accumulator = 0x3FC00 | (LengthOfMatch & 0x01FF); + BitStream_Write_Bits(bs, accumulator, 18); + } + else if ((LengthOfMatch >= 1024) && (LengthOfMatch < 2048)) + { + /* 1111111110 + 10 lower bits of LengthOfMatch */ + accumulator = 0xFF800 | (LengthOfMatch & 0x03FF); + BitStream_Write_Bits(bs, accumulator, 20); + } + else if ((LengthOfMatch >= 2048) && (LengthOfMatch < 4096)) + { + /* 11111111110 + 11 lower bits of LengthOfMatch */ + accumulator = 0x3FF000 | (LengthOfMatch & 0x07FF); + BitStream_Write_Bits(bs, accumulator, 22); + } + else if ((LengthOfMatch >= 4096) && (LengthOfMatch < 8192)) + { + /* 111111111110 + 12 lower bits of LengthOfMatch */ + accumulator = 0xFFE000 | (LengthOfMatch & 0x0FFF); + BitStream_Write_Bits(bs, accumulator, 24); + } + else if (((LengthOfMatch >= 8192) && (LengthOfMatch < 16384)) && CompressionLevel) /* RDP5 */ + { + /* 1111111111110 + 13 lower bits of LengthOfMatch */ + accumulator = 0x3FFC000 | (LengthOfMatch & 0x1FFF); + BitStream_Write_Bits(bs, accumulator, 26); + } + else if (((LengthOfMatch >= 16384) && (LengthOfMatch < 32768)) && CompressionLevel) /* RDP5 */ + { + /* 11111111111110 + 14 lower bits of LengthOfMatch */ + accumulator = 0xFFF8000 | (LengthOfMatch & 0x3FFF); + BitStream_Write_Bits(bs, accumulator, 28); + } + else if (((LengthOfMatch >= 32768) && (LengthOfMatch < 65536)) && CompressionLevel) /* RDP5 */ + { + /* 111111111111110 + 15 lower bits of LengthOfMatch */ + accumulator = 0x3FFF0000 | (LengthOfMatch & 0x7FFF); + BitStream_Write_Bits(bs, accumulator, 30); + } } } - /* HistoryPtr < HistoryOffset? (NO) */ + /* Encode trailing symbols as literals */ + + while (HistoryPtr <= pSrcEnd) + { + MatchIndex = MPPC_MATCH_INDEX(HistoryPtr[0], HistoryPtr[1], HistoryPtr[2]); + MatchPtr = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]); + mppc->MatchBuffer[MatchIndex] = (UINT16) (HistoryPtr - HistoryBuffer); + + accumulator = *(HistoryPtr); + +#ifdef DEBUG_MPPC + //printf("%c", accumulator); +#endif + + if (((bs->position / 8) + 2) > (*pSize - 1)) + { + Flags = PACKET_FLUSHED; + ZeroMemory(HistoryBuffer, HistoryBufferSize); + ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer)); + return Flags; + } + + if (accumulator < 0x80) + { + /* 8 bits of literal are encoded as-is */ + BitStream_Write_Bits(bs, accumulator, 8); + } + else + { + /* bits 10 followed by lower 7 bits of literal */ + accumulator = 0x100 | (accumulator & 0x7F); + BitStream_Write_Bits(bs, accumulator, 9); + } + + HistoryPtr++; + } + + BitStream_Flush(bs); Flags |= PACKET_COMPRESSED; + *pSize = ((bs->position + 7) / 8); - BitStream_Flush(mppc->bs); - *pSize = (mppc->bs->position / 8); + mppc->HistoryPtr = HistoryPtr; + mppc->HistoryOffset = HistoryPtr - HistoryBuffer; + +#ifdef DEBUG_MPPC + printf("\n"); +#endif return Flags; } @@ -366,6 +770,9 @@ MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor) ZeroMemory(&(mppc->MatchBuffer), sizeof(mppc->MatchBuffer)); mppc->bs = BitStream_New(); + + mppc->HistoryPtr = &(mppc->HistoryBuffer[0]); + mppc->HistoryOffset = 0; } return mppc; diff --git a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c index 78565c58d..720a78ce6 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -684,39 +685,375 @@ int test_mppc_old() return 0; } -const char TEST_MPPC_BELL_TOLLS[] = "for.whom.the.bell.tolls,.the.bell.tolls.for.thee!"; +/** + * + * for.whom.the.bell.tolls,.the.bell.tolls.for.thee! + * + * for.whom.the.bell.tolls,<16,15>.<40,4><19,3>e! ([MS-RDPBCGR]) + * + * <16,15> : ".the.bell.tolls" + * <40,4> : "for." + * <19,3> : "the" + * + * for.whom.the.bell.tolls,<16,15>.f<40,3><35,3>e! (Microsoft implementation) + * + * <16,15> : ".the.bell.tolls" + * <40,3> : "or." + * <19,3> " "the" + * + * RDP5: + * 01100110 Literal 'f' + * 01101111 Literal 'o' + * 01110010 Literal 'r' + * 00101110 Literal '.' + * 01110111 Literal 'w' + * 01101000 Literal 'h' + * 01101111 Literal 'o' + * 01101101 Literal 'm' + * 00101110 Literal '.' + * 01110100 Literal 't' + * 01101000 Literal 'h' + * 01100101 Literal 'e' + * 00101110 Literal '.' + * 01100010 Literal 'b' + * 01100101 Literal 'e' + * 01101100 Literal 'l' + * 01101100 Literal 'l' + * 00101110 Literal '.' + * 01110100 Literal 't' + * 01101111 Literal 'o' + * 01101100 Literal 'l' + * 01101100 Literal 'l' + * 01110011 Literal 's' + * 00101100 Literal ',' + * 11111+010000 CopyOffset 16 + * 110+111 LengthOfMatch 15 + * 00101110 Literal '.' + * 01100110 Literal 'f' + * 11111+101000 CopyOffset 40 + * 0 LengthOfMatch 3 + * 11111+100011 CopyOffset 35 + * 0 LengthOfMatch 3 + * 01100101 Literal 'e' + * 00100001 Literal '!' + * 0000000 Trailing Bits + * + * RDP4: + * 01100110 Literal 'f' + * 01101111 Literal 'o' + * 01110010 Literal 'r' + * 00101110 Literal '.' + * 01110111 Literal 'w' + * 01101000 Literal 'h' + * 01101111 Literal 'o' + * 01101101 Literal 'm' + * 00101110 Literal '.' + * 01110100 Literal 't' + * 01101000 Literal 'h' + * 01100101 Literal 'e' + * 00101110 Literal '.' + * 01100010 Literal 'b' + * 01100101 Literal 'e' + * 01101100 Literal 'l' + * 01101100 Literal 'l' + * 00101110 Literal '.' + * 01110100 Literal 't' + * 01101111 Literal 'o' + * 01101100 Literal 'l' + * 01101100 Literal 'l' + * 01110011 Literal 's' + * 00101100 Literal ',' + * 1111+010000 CopyOffset 16 + * 110+111 LengthOfMatch 15 + * 00101110 Literal '.' + * 01100110 Literal 'f' + * 1111+101000 CopyOffset 40 + * 0 LengthOfMatch 3 + * 1111+100011 CopyOffset 35 + * 0 LengthOfMatch 3 + * 01100101 Literal 'e' + * 00100001 Literal '!' + * 00 Trailing Bits + */ -int TestFreeRDPCodecMppc(int argc, char* argv[]) +const BYTE TEST_MPPC_BELLS[] = "for.whom.the.bell.tolls,.the.bell.tolls.for.thee!"; + +/* Flags: 0x0060 Length: 33 */ + +const BYTE TEST_MPPC_BELLS_RDP4[] = + "\x66\x6f\x72\x2e\x77\x68\x6f\x6d\x2e\x74\x68\x65\x2e\x62\x65\x6c" + "\x6c\x2e\x74\x6f\x6c\x6c\x73\x2c\xf4\x37\x2e\x66\xfa\x1f\x19\x94" + "\x84"; + +/* Flags: 0x0061 Length: 34 */ + +const BYTE TEST_MPPC_BELLS_RDP5[] = + "\x66\x6f\x72\x2e\x77\x68\x6f\x6d\x2e\x74\x68\x65\x2e\x62\x65\x6c" + "\x6c\x2e\x74\x6f\x6c\x6c\x73\x2c\xfa\x1b\x97\x33\x7e\x87\xe3\x32" + "\x90\x80"; + +int test_MppcCompressBellsRdp5() { UINT32 size; UINT32 flags; BYTE* pSrcData; MPPC_CONTEXT* mppc; + UINT32 expectedSize; BYTE OutputBuffer[65536]; mppc = mppc_context_new(1, TRUE); -#if 0 - size = sizeof(TEST_MPPC_BELL_TOLLS) - 1; - pSrcData = (BYTE*) TEST_MPPC_BELL_TOLLS; - - printf("%s\n", pSrcData); - flags = mppc_compress(mppc, pSrcData, OutputBuffer, &size); - printf("flags: 0x%04X size: %d\n", flags, size); -#endif - - size = sizeof(TEST_RDP5_UNCOMPRESSED_DATA); - pSrcData = (BYTE*) TEST_RDP5_UNCOMPRESSED_DATA; + size = sizeof(TEST_MPPC_BELLS) - 1; + pSrcData = (BYTE*) TEST_MPPC_BELLS; + expectedSize = sizeof(TEST_MPPC_BELLS_RDP5) - 1; flags = mppc_compress(mppc, pSrcData, OutputBuffer, &size); + printf("flags: 0x%04X size: %d\n", flags, size); - winpr_HexDump(OutputBuffer, size); - //winpr_HexDump(TEST_RDP5_COMPRESSED_DATA, sizeof(TEST_RDP5_COMPRESSED_DATA)); + if (size != expectedSize) + { + printf("MppcCompressBellsRdp5: output size mismatch: Actual: %d, Expected: %d\n", size, expectedSize); + return -1; + } - printf("sizeof(TEST_RDP5_COMPRESSED_DATA): %d\n", (int) sizeof(TEST_RDP5_COMPRESSED_DATA)); + if (memcmp(OutputBuffer, TEST_MPPC_BELLS_RDP5, size) != 0) + { + printf("MppcCompressBellsRdp5: output mismatch\n"); + + printf("Actual\n"); + BitDump(OutputBuffer, size * 8, 0); + + printf("Expected\n"); + BitDump(TEST_MPPC_BELLS_RDP5, size * 8, 0); + + return -1; + } mppc_context_free(mppc); return 0; } + +int test_MppcCompressBellsRdp4() +{ + UINT32 size; + UINT32 flags; + BYTE* pSrcData; + MPPC_CONTEXT* mppc; + UINT32 expectedSize; + BYTE OutputBuffer[65536]; + + mppc = mppc_context_new(0, TRUE); + + size = sizeof(TEST_MPPC_BELLS) - 1; + pSrcData = (BYTE*) TEST_MPPC_BELLS; + expectedSize = sizeof(TEST_MPPC_BELLS_RDP4) - 1; + + flags = mppc_compress(mppc, pSrcData, OutputBuffer, &size); + + printf("flags: 0x%04X size: %d\n", flags, size); + + if (size != expectedSize) + { + printf("MppcCompressBellsRdp4: output size mismatch: Actual: %d, Expected: %d\n", size, expectedSize); + return -1; + } + + if (memcmp(OutputBuffer, TEST_MPPC_BELLS_RDP4, size) != 0) + { + printf("MppcCompressBellsRdp4: output mismatch\n"); + + printf("Actual\n"); + BitDump(OutputBuffer, size * 8, 0); + + printf("Expected\n"); + BitDump(TEST_MPPC_BELLS_RDP4, size * 8, 0); + + return -1; + } + + mppc_context_free(mppc); + + return 0; +} + +int test_MppcDecompressBellsRdp5() +{ + UINT32 size; + UINT32 flags; + BYTE* pSrcData; + MPPC_CONTEXT* mppc; + UINT32 expectedSize; + BYTE* pDstData = NULL; + + mppc = mppc_context_new(1, FALSE); + + size = sizeof(TEST_MPPC_BELLS_RDP5) - 1; + pSrcData = (BYTE*) TEST_MPPC_BELLS_RDP5; + flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1; + expectedSize = sizeof(TEST_MPPC_BELLS) - 1; + + flags = mppc_decompress(mppc, pSrcData, &pDstData, &size, flags); + printf("flags: 0x%04X size: %d\n", flags, size); + + if (size != expectedSize) + { + printf("MppcDecompressBellsRdp5: output size mismatch: Actual: %d, Expected: %d\n", size, expectedSize); + return -1; + } + + if (memcmp(pDstData, TEST_MPPC_BELLS, size) != 0) + { + printf("MppcDecompressBellsRdp5: output mismatch\n"); + return -1; + } + + mppc_context_free(mppc); + + return 0; +} + +int test_MppcDecompressBellsRdp4() +{ + UINT32 size; + UINT32 flags; + BYTE* pSrcData; + MPPC_CONTEXT* mppc; + UINT32 expectedSize; + BYTE* pDstData = NULL; + + mppc = mppc_context_new(0, FALSE); + + size = sizeof(TEST_MPPC_BELLS_RDP4) - 1; + pSrcData = (BYTE*) TEST_MPPC_BELLS_RDP4; + flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 0; + expectedSize = sizeof(TEST_MPPC_BELLS) - 1; + + flags = mppc_decompress(mppc, pSrcData, &pDstData, &size, flags); + printf("flags: 0x%04X size: %d\n", flags, size); + + if (size != expectedSize) + { + printf("MppcDecompressBellsRdp4: output size mismatch: Actual: %d, Expected: %d\n", size, expectedSize); + return -1; + } + + if (memcmp(pDstData, TEST_MPPC_BELLS, size) != 0) + { + printf("MppcDecompressBellsRdp4: output mismatch\n"); + return -1; + } + + mppc_context_free(mppc); + + return 0; +} + +int test_MppcCompressBufferRdp5() +{ + UINT32 size; + UINT32 flags; + BYTE* pSrcData; + MPPC_CONTEXT* mppc; + UINT32 expectedSize; + BYTE OutputBuffer[65536]; + MPPC_CONTEXT* mppcRecv; + BYTE* pDstData = NULL; + + mppc = mppc_context_new(1, TRUE); + + size = sizeof(TEST_RDP5_UNCOMPRESSED_DATA); + pSrcData = (BYTE*) TEST_RDP5_UNCOMPRESSED_DATA; + expectedSize = sizeof(TEST_RDP5_COMPRESSED_DATA); + + flags = mppc_compress(mppc, pSrcData, OutputBuffer, &size); + printf("flags: 0x%04X size: %d\n", flags, size); + + mppcRecv = mppc_context_new(1, FALSE); + + pSrcData = (BYTE*) OutputBuffer; + flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1; + expectedSize = sizeof(TEST_RDP5_UNCOMPRESSED_DATA); + + flags = mppc_decompress(mppcRecv, pSrcData, &pDstData, &size, flags); + printf("flags: 0x%04X size: %d\n", flags, size); + + if (size != expectedSize) + { + printf("MppcCompressBufferRdp5: output size mismatch: Actual: %d, Expected: %d\n", size, expectedSize); + return -1; + } + + if (memcmp(pDstData, TEST_RDP5_UNCOMPRESSED_DATA, size) != 0) + { + printf("MppcCompressBufferRdp5: output mismatch: Decompress(Compress(X)) != X\n"); + return -1; + } + + mppc_context_free(mppc); + mppc_context_free(mppcRecv); + + return 0; +} + +int test_MppcDecompressBufferRdp5() +{ + UINT32 size; + UINT32 flags; + BYTE* pSrcData; + MPPC_CONTEXT* mppc; + UINT32 expectedSize; + BYTE* pDstData = NULL; + + mppc = mppc_context_new(1, FALSE); + + size = sizeof(TEST_RDP5_COMPRESSED_DATA); + pSrcData = (BYTE*) TEST_RDP5_COMPRESSED_DATA; + flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1; + expectedSize = sizeof(TEST_RDP5_UNCOMPRESSED_DATA); + + flags = mppc_decompress(mppc, pSrcData, &pDstData, &size, flags); + printf("flags: 0x%04X size: %d\n", flags, size); + + if (size != expectedSize) + { + printf("MppcDecompressBufferRdp5: output size mismatch: Actual: %d, Expected: %d\n", size, expectedSize); + return -1; + } + + if (memcmp(pDstData, TEST_RDP5_UNCOMPRESSED_DATA, size) != 0) + { + printf("MppcDecompressBufferRdp5: output mismatch\n"); + return -1; + } + + mppc_context_free(mppc); + + return 0; +} + +int TestFreeRDPCodecMppc(int argc, char* argv[]) +{ + if (test_MppcCompressBellsRdp5() < 0) + return -1; + + if (test_MppcDecompressBellsRdp5() < 0) + return -1; + + if (test_MppcCompressBellsRdp4() < 0) + return -1; + + if (test_MppcDecompressBellsRdp4() < 0) + return -1; + + if (test_MppcCompressBufferRdp5() < 0) + return -1; + + if (test_MppcDecompressBufferRdp5() < 0) + return -1; + + //test_mppc_old(); + + return 0; +} diff --git a/winpr/include/winpr/bitstream.h b/winpr/include/winpr/bitstream.h new file mode 100644 index 000000000..4f988b6e2 --- /dev/null +++ b/winpr/include/winpr/bitstream.h @@ -0,0 +1,65 @@ +/* + * WinPR: Windows Portable Runtime + * BitStream Utils + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WINPR_UTILS_BITSTREAM_H +#define WINPR_UTILS_BITSTREAM_H + +#include +#include + +#include + +struct _wBitStream +{ + BYTE* buffer; + BYTE* pointer; + DWORD position; + DWORD length; + DWORD capacity; + UINT32 mask; + UINT32 offset; + UINT32 prefetch; + UINT32 accumulator; +}; +typedef struct _wBitStream wBitStream; + +#define BITDUMP_MSB_FIRST 0x00000001 +#define BITDUMP_STDERR 0x00000002 + +#ifdef __cplusplus +extern "C" { +#endif + +WINPR_API void BitStream_Attach(wBitStream* bs, BYTE* buffer, UINT32 capacity); +WINPR_API void BitStream_Write_Bits(wBitStream* bs, UINT32 bits, UINT32 nbits); +WINPR_API void BitStream_Flush(wBitStream* bs); +WINPR_API void BitStream_Prefetch(wBitStream* bs); +WINPR_API void BitStream_Fetch(wBitStream* bs); +WINPR_API void BitStream_Shift(wBitStream* bs, UINT32 nbits); + +WINPR_API void BitDump(const BYTE* buffer, UINT32 length, UINT32 flags); + +WINPR_API wBitStream* BitStream_New(); +WINPR_API void BitStream_Free(wBitStream* bs); + +#ifdef __cplusplus +} +#endif + +#endif /* WINPR_UTILS_BITSTREAM_H */ diff --git a/winpr/include/winpr/collections.h b/winpr/include/winpr/collections.h index 6268a9817..86bd34a87 100644 --- a/winpr/include/winpr/collections.h +++ b/winpr/include/winpr/collections.h @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -596,65 +597,8 @@ WINPR_API int PubSub_OnEvent(wPubSub* pubSub, const char* EventName, void* conte WINPR_API wPubSub* PubSub_New(BOOL synchronized); WINPR_API void PubSub_Free(wPubSub* pubSub); -/* BitStream */ - -struct _wBitStream -{ - BYTE* buffer; - BYTE* pointer; - DWORD position; - DWORD length; - DWORD capacity; - UINT32 offset; - UINT32 accumulator; -}; -typedef struct _wBitStream wBitStream; - -#define BitStream_Attach(_bs, _buffer, _capacity) { \ - _bs->position = 0; \ - _bs->buffer = _buffer; \ - _bs->offset = 0; \ - _bs->accumulator = 0; \ - _bs->pointer = _bs->buffer; \ - _bs->capacity = _capacity; \ - _bs->length = _bs->capacity; \ -} - -#define BitStream_Write_Bits(_bs, _bits, _nbits) { \ - _bs->accumulator |= (_bits << _bs->offset); \ - _bs->position += _nbits; \ - _bs->offset += _nbits; \ - if (_bs->offset >= 32) { \ - *(_bs->pointer + 0) = (_bs->accumulator >> 0); \ - *(_bs->pointer + 1) = (_bs->accumulator >> 8); \ - *(_bs->pointer + 2) = (_bs->accumulator >> 16); \ - *(_bs->pointer + 3) = (_bs->accumulator >> 24); \ - _bs->offset = _bs->offset - 32; \ - _bs->accumulator = _bits >> (_nbits - _bs->offset); \ - _bs->pointer += 4; \ - } \ -} - -#define BitStream_Flush(_bs) { \ - if ((_bs->pointer - _bs->buffer) > 0) \ - *(_bs->pointer + 0) = (_bs->accumulator >> 0); \ - if ((_bs->pointer - _bs->buffer) > 1) \ - *(_bs->pointer + 1) = (_bs->accumulator >> 8); \ - if ((_bs->pointer - _bs->buffer) > 2) \ - *(_bs->pointer + 2) = (_bs->accumulator >> 16); \ - if ((_bs->pointer - _bs->buffer) > 3) \ - *(_bs->pointer + 3) = (_bs->accumulator >> 24); \ -} - -#define BITDUMP_MSB_FIRST 0x00000001 -#define BITDUMP_STDERR 0x00000002 - -WINPR_API void BitDump(BYTE* buffer, UINT32 length, UINT32 flags); - -WINPR_API wBitStream* BitStream_New(); -WINPR_API void BitStream_Free(wBitStream* bs); - #ifdef __cplusplus } #endif + #endif /* WINPR_COLLECTIONS_H */ diff --git a/winpr/libwinpr/utils/collections/BitStream.c b/winpr/libwinpr/utils/collections/BitStream.c index a2cb244e6..2a1b2ccd7 100644 --- a/winpr/libwinpr/utils/collections/BitStream.c +++ b/winpr/libwinpr/utils/collections/BitStream.c @@ -21,7 +21,7 @@ #include "config.h" #endif -#include +#include const char* BYTE_BIT_STRINGS_LSB[256] = { @@ -159,7 +159,7 @@ const char* BYTE_BIT_STRINGS_MSB[256] = "00111111", "10111111", "01111111", "11111111" }; -void BitDump(BYTE* buffer, UINT32 length, UINT32 flags) +void BitDump(const BYTE* buffer, UINT32 length, UINT32 flags) { DWORD i; int nbits; @@ -174,12 +174,126 @@ void BitDump(BYTE* buffer, UINT32 length, UINT32 flags) nbits = (length - i) > 8 ? 8 : (length - i); + if ((i % 64) == 0) + printf("\n"); + printf("%.*s ", nbits, str); } printf("\n"); } +void BitStream_Attach(wBitStream* bs, BYTE* buffer, UINT32 capacity) +{ + bs->position = 0; + bs->buffer = buffer; + bs->offset = 0; + bs->accumulator = 0; + bs->pointer = bs->buffer; + bs->capacity = capacity; + bs->length = bs->capacity * 8; +} + +void BitStream_Flush(wBitStream* bs) +{ + if ((bs->pointer - bs->buffer) < (bs->capacity + 0)) + *(bs->pointer + 0) = (bs->accumulator >> 24); + if ((bs->pointer - bs->buffer) < (bs->capacity + 1)) + *(bs->pointer + 1) = (bs->accumulator >> 16); + if ((bs->pointer - bs->buffer) < (bs->capacity + 2)) + *(bs->pointer + 2) = (bs->accumulator >> 8); + if ((bs->pointer - bs->buffer) < (bs->capacity + 3)) + *(bs->pointer + 3) = (bs->accumulator >> 0); +} + +void BitStream_Prefetch(wBitStream* bs) +{ + (bs->prefetch) = 0; + if ((bs->pointer - bs->buffer) < (bs->capacity + 4)) + (bs->prefetch) |= (*(bs->pointer + 4) << 24); + if ((bs->pointer - bs->buffer) < (bs->capacity + 5)) + (bs->prefetch) |= (*(bs->pointer + 5) << 16); + if ((bs->pointer - bs->buffer) < (bs->capacity + 6)) + (bs->prefetch) |= (*(bs->pointer + 6) << 8); + if ((bs->pointer - bs->buffer) < (bs->capacity + 7)) + (bs->prefetch) |= (*(bs->pointer + 7) << 0); +} + +void BitStream_Fetch(wBitStream* bs) +{ + (bs->accumulator) = 0; + + if ((bs->pointer - bs->buffer) < (bs->capacity + 0)) + (bs->accumulator) |= (*(bs->pointer + 0) << 24); + if ((bs->pointer - bs->buffer) < (bs->capacity + 1)) + (bs->accumulator) |= (*(bs->pointer + 1) << 16); + if ((bs->pointer - bs->buffer) < (bs->capacity + 2)) + (bs->accumulator) |= (*(bs->pointer + 2) << 8); + if ((bs->pointer - bs->buffer) < (bs->capacity + 3)) + (bs->accumulator) |= (*(bs->pointer + 3) << 0); + + BitStream_Prefetch(bs); +} + +void BitStream_Write_Bits(wBitStream* bs, UINT32 bits, UINT32 nbits) +{ + bs->position += nbits; + bs->offset += nbits; + + if (bs->offset < 32) + { + bs->accumulator |= (bits << (32 - bs->offset)); + } + else + { + bs->offset -= 32; + bs->mask = ((1 << (nbits - bs->offset)) - 1); + bs->accumulator |= ((bits >> bs->offset) & bs->mask); + + BitStream_Flush(bs); + bs->accumulator = 0; + bs->pointer += 4; + + if (bs->offset) + { + bs->mask = ((1 << bs->offset) - 1); + bs->accumulator |= ((bits & bs->mask) << (32 - bs->offset)); + } + } +} + +void BitStream_Shift(wBitStream* bs, UINT32 nbits) +{ + bs->accumulator <<= nbits; + bs->position += nbits; + bs->offset += nbits; + + if (bs->offset < 32) + { + bs->mask = ((1 << nbits) - 1); + bs->accumulator |= ((bs->prefetch >> (32 - nbits)) & bs->mask); + bs->prefetch <<= nbits; + } + else + { + bs->mask = ((1 << nbits) - 1); + bs->accumulator |= ((bs->prefetch >> (32 - nbits)) & bs->mask); + bs->prefetch <<= nbits; + + bs->offset -= 32; + bs->pointer += 4; + + BitStream_Prefetch(bs); + + if (bs->offset) + { + bs->mask = ((1 << bs->offset) - 1); + bs->accumulator |= ((bs->prefetch >> (32 - bs->offset)) & bs->mask); + bs->prefetch <<= bs->offset; + } + } +} + wBitStream* BitStream_New() { wBitStream* bs = NULL; diff --git a/winpr/libwinpr/utils/test/TestBitStream.c b/winpr/libwinpr/utils/test/TestBitStream.c index 4afbb575e..ec1d0d25b 100644 --- a/winpr/libwinpr/utils/test/TestBitStream.c +++ b/winpr/libwinpr/utils/test/TestBitStream.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include void BitStrGen() {