220 lines
4.5 KiB
C
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;
|
|
}
|