FreeRDP/libfreerdp/gdi/test/TestGdiRop3.c
2024-09-12 13:29:58 +02:00

220 lines
4.5 KiB
C

#include <winpr/crt.h>
#include <winpr/winpr.h>
#include <winpr/collections.h>
/**
* Ternary Raster Operations:
* See "Windows Graphics Programming: Win32 GDI and DirectDraw", chapter 11. Advanced Bitmap
* Graphics
*
* Operators:
*
* AND & a
* OR | o
* NOT ~ n
* XOR ^ x
*
* Operands:
*
* Pen/Brush P
* Destination D
* Source S
*
* Example:
*
* Raster operation which returns P if S is 1 or D otherwise:
* (rop_S & rop_P) | (~rop_S & rop_D); -> 0xE2 (0x00E20746)
*
* Postfix notation: DSPDxax
* Infix notation: D^(S&(P^D))), (S&P)|(~S&D)
*
* DSPDxax using D^(S&(P^D)):
*
* mov eax, P // P
* xor eax, D // P^D
* and eax, S // S&(P^D)
* xor eax, D // D^(S&(P^D))
* mov D, eax // write result
*
* DSPDxax using (S&P)|(~S&D):
*
* mov eax, S // S
* and eax, P // S&P
* mov ebx, S // S
* not ebx // ~S
* and ebx, D // ~D&D
* or eax, ebx // (S&P)|(~S&D)
* mov D, eax // write result
*
* Raster operation lower word encoding:
*
* _______________________________________________________________________________
* | | | | | | | | | | | | | | | | |
* | Op5 | Op4 | Op3 | Op2 | Op1 | Not| Parse String | Offset |
* |____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|
* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
*
* Operator:
* 0: NOT
* 1: XOR
* 2: OR
* 3: AND
*
* Parse String:
* 0: SPDDDDDD
* 1: SPDSPDSP
* 2: SDPSDPSD
* 3: DDDDDDDD
* 4: DDDDDDDD
* 5: S+SP-DSS
* 6: S+SP-PDS
* 7: S+SD-PDS
*
* The lower word for 0x00E20746 is 0x0746 (00000111 01000110)
*
* 00 Op5 (NOT, n)
* 00 Op4 (NOT, n)
* 01 Op3 (XOR, x)
* 11 Op2 (AND, a)
* 01 Op1 (XOR, x)
* 0 Not (unused)
* 001 String (SPDSPDSP)
* 10 Offset (2)
*
* We shift SPDSPDSP to the left by 2: DSPDSPSP
*
* We have 5 operators: 3 binary operators and the last two are unary operators,
* so only four operands are needed. The parse string is truncated to reflect
* the number of operands we need: DSPD
*
* The operator string (from Op1 to Op5) is xaxnn, which can be simplified to xax
*
* The complete string representing the operation is DSPDxax
*
*/
static char* gdi_convert_postfix_to_infix(const char* postfix)
{
BOOL unary = 0;
size_t al = 0;
size_t bl = 0;
wStack* stack = Stack_New(FALSE);
size_t length = strlen(postfix);
for (size_t i = 0; i < length; i++)
{
BOOL success = FALSE;
if ((postfix[i] == 'P') || (postfix[i] == 'D') || (postfix[i] == 'S'))
{
/* token is an operand, push on the stack */
char* a = malloc(2);
if (!a)
goto end;
a[0] = postfix[i];
a[1] = '\0';
// printf("Operand: %s\n", a);
Stack_Push(stack, a);
}
else
{
char* a = NULL;
char* b = NULL;
/* token is an operator */
unary = FALSE;
char* c = malloc(2);
if (!c)
goto fail;
c[0] = postfix[i];
c[1] = '\0';
if (c[0] == 'a')
{
c[0] = '&';
}
else if (c[0] == 'o')
{
c[0] = '|';
}
else if (c[0] == 'n')
{
c[0] = '~';
unary = TRUE;
}
else if (c[0] == 'x')
{
c[0] = '^';
}
else
{
printf("invalid operator: %c\n", c[0]);
}
// printf("Operator: %s\n", c);
a = (char*)Stack_Pop(stack);
if (!a)
goto fail;
if (!unary)
b = (char*)Stack_Pop(stack);
al = strlen(a);
if (b)
bl = strlen(b);
size_t cl = 1;
size_t dl = al + bl + cl + 3;
char* d = malloc(dl + 1);
if (!d)
goto fail;
(void)sprintf_s(d, dl, "(%s%s%s)", b ? b : "", c, a);
Stack_Push(stack, d);
success = TRUE;
fail:
free(a);
free(b);
free(c);
if (!success)
goto end;
}
}
char* d = (char*)Stack_Pop(stack);
Stack_Free(stack);
return d;
end:
Stack_Free(stack);
return NULL;
}
static const char* test_ROP3[] = { "DSPDxax", "PSDPxax", "SPna", "DSna", "DPa",
"PDxn", "DSxn", "PSDnox", "PDSona", "DSPDxox",
"DPSDonox", "SPDSxax", "DPon", "DPna", "Pn",
"PDna", "DPan", "DSan", "DSxn", "DPa",
"D", "DPno", "SDno", "PDno", "DPo" };
int TestGdiRop3(int argc, char* argv[])
{
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
for (size_t index = 0; index < sizeof(test_ROP3) / sizeof(test_ROP3[0]); index++)
{
const char* postfix = test_ROP3[index];
char* infix = gdi_convert_postfix_to_infix(postfix);
if (!infix)
return -1;
printf("%s\t\t%s\n", postfix, infix);
free(infix);
}
return 0;
}