Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

863 lines
32 KiB

  1. /****************************************************************************/
  2. // oe2.c
  3. //
  4. // RDP field compression utility code
  5. //
  6. // Copyright (C) 1997-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <precmpdd.h>
  9. #pragma hdrstop
  10. #define TRC_FILE "oe2"
  11. #include <adcg.h>
  12. #include <adcs.h>
  13. #define DC_INCLUDE_DATA
  14. #include <ndddata.c>
  15. #undef DC_INCLUDE_DATA
  16. #include <oe2.h>
  17. #include <oe2data.c>
  18. /****************************************************************************/
  19. // Local file prototypes
  20. /****************************************************************************/
  21. BYTE *OE2EncodeFieldSingle(void *, BYTE *, unsigned, unsigned);
  22. BYTE *OE2EncodeFieldMultiple(void *, BYTE *, unsigned, unsigned, unsigned);
  23. #ifdef DC_DEBUG
  24. void OE2PerformUnitTests();
  25. #endif
  26. /****************************************************************************/
  27. // OE2_Reset
  28. //
  29. // Called on session reconnection or addition or removal of a shadower.
  30. // Clears the OE2 state to the protocol default start condition.
  31. /****************************************************************************/
  32. void OE2_Reset(void)
  33. {
  34. #ifdef DC_DEBUG
  35. OE2PerformUnitTests();
  36. #endif
  37. oe2LastOrderType = TS_ENC_PATBLT_ORDER;
  38. memset(&oe2LastBounds, 0, sizeof(oe2LastBounds));
  39. }
  40. /****************************************************************************/
  41. // OE2_CheckZeroFlagBytes
  42. //
  43. // Performs post-field-encoding logic to see if there are any zero field
  44. // encoding flag bytes, and if so shifts the entire contents of the order
  45. // bytes following the encoding flags to compensate. Returns the number of
  46. // bytes removed.
  47. /****************************************************************************/
  48. unsigned OE2_CheckZeroFlagBytes(
  49. BYTE *pControlFlags,
  50. BYTE *pFieldFlags,
  51. unsigned NumFieldBytes,
  52. unsigned PostFlagsDataLength)
  53. {
  54. int i;
  55. unsigned NumZeroBytes;
  56. DC_BEGIN_FN("OE2_CheckZeroFlagBytes");
  57. TRC_ASSERT((NumFieldBytes >= 1 && NumFieldBytes <= 3),
  58. (TB,"NumFieldBytes %u out of allowed range 1..3",
  59. NumFieldBytes));
  60. // Count how many (if any!) contiguous zero field flag bytes there are
  61. // (going from the last byte to the first).
  62. NumZeroBytes = 0;
  63. for (i = (int)(NumFieldBytes - 1); i >= 0; i--) {
  64. if (pFieldFlags[i] != 0)
  65. break;
  66. NumZeroBytes++;
  67. }
  68. if (NumZeroBytes > 0) {
  69. // There are some zero field flag bytes. We now remove them and
  70. // store the number in two bits in the control flag byte.
  71. TRC_DBG((TB,"Remove NumZeroBytes=%u", NumZeroBytes));
  72. TRC_ASSERT((NumZeroBytes <= 3),
  73. (TB,"Invalid NumZeroBytes %u", NumZeroBytes));
  74. *pControlFlags |= (NumZeroBytes << TS_ZERO_FIELD_COUNT_SHIFT);
  75. memmove(pFieldFlags + NumFieldBytes - NumZeroBytes,
  76. pFieldFlags + NumFieldBytes,
  77. PostFlagsDataLength);
  78. }
  79. DC_END_FN();
  80. return NumZeroBytes;
  81. }
  82. /****************************************************************************/
  83. // OE2_EncodeBounds
  84. //
  85. // Used by order encoding paths to encode the order bounds rect if a clip
  86. // rect is used for the order.
  87. /****************************************************************************/
  88. void OE2_EncodeBounds(
  89. BYTE *pControlFlags,
  90. BYTE **ppBuffer,
  91. RECTL *pRect)
  92. {
  93. BYTE *pFlags, *pNextFreeSpace;
  94. short Delta;
  95. DC_BEGIN_FN("OE2_EncodeBounds");
  96. *pControlFlags |= TS_BOUNDS;
  97. // The encoding used is a byte of flags followed by a variable number
  98. // of 16bit coordinate values and/or 8bit delta coordinate values.
  99. pFlags = *ppBuffer;
  100. pNextFreeSpace = pFlags + 1;
  101. *pFlags = 0;
  102. // For each of the four coordinate values in the rectangle: If the
  103. // coordinate has not changed then the encoding is null. If the
  104. // coordinate can be encoded as an 8-bit delta then do so and set the
  105. // appropriate flag. Otherwise copy the coordinate as a 16-bit value
  106. // and set the appropriate flag.
  107. TRC_ASSERT((pRect->left <= 0xFFFF),
  108. (TB,"Rect.left %d will not fit in 16-bit wire encoding",
  109. pRect->left));
  110. Delta = (short)(pRect->left - oe2LastBounds.left);
  111. if (Delta) {
  112. if (Delta != (short)(char)Delta) {
  113. *((UNALIGNED short *)pNextFreeSpace) = (short)pRect->left;
  114. pNextFreeSpace += sizeof(short);
  115. *pFlags |= TS_BOUND_LEFT;
  116. }
  117. else {
  118. *pNextFreeSpace++ = (char)Delta;
  119. *pFlags |= TS_BOUND_DELTA_LEFT;
  120. }
  121. }
  122. TRC_ASSERT((pRect->top <= 0xFFFF),
  123. (TB,"Rect.top %d will not fit in 16-bit wire encoding",
  124. pRect->top));
  125. Delta = (short)(pRect->top - oe2LastBounds.top);
  126. if (Delta) {
  127. if (Delta != (short)(char)Delta) {
  128. *((UNALIGNED short *)pNextFreeSpace) = (short)pRect->top;
  129. pNextFreeSpace += sizeof(short);
  130. *pFlags |= TS_BOUND_TOP;
  131. }
  132. else {
  133. *pNextFreeSpace++ = (char)Delta;
  134. *pFlags |= TS_BOUND_DELTA_TOP;
  135. }
  136. }
  137. TRC_ASSERT((pRect->right <= 0xFFFF),
  138. (TB,"Rect.right %d will not fit in 16-bit wire encoding",
  139. pRect->right));
  140. Delta = (short)(pRect->right - oe2LastBounds.right);
  141. if (Delta) {
  142. if (Delta != (short)(char)Delta) {
  143. *((UNALIGNED short *)pNextFreeSpace) = (short)pRect->right - 1;
  144. pNextFreeSpace += sizeof(short);
  145. *pFlags |= TS_BOUND_RIGHT;
  146. }
  147. else {
  148. *pNextFreeSpace++ = (char)Delta;
  149. *pFlags |= TS_BOUND_DELTA_RIGHT;
  150. }
  151. }
  152. TRC_ASSERT((pRect->bottom <= 0xFFFF),
  153. (TB,"Rect.bottom %d will not fit in 16-bit wire encoding",
  154. pRect->bottom));
  155. Delta = (short)(pRect->bottom - oe2LastBounds.bottom);
  156. if (Delta) {
  157. if (Delta != (short)(char)Delta) {
  158. *((UNALIGNED short *)pNextFreeSpace) = (short)pRect->bottom - 1;
  159. pNextFreeSpace += sizeof(short);
  160. *pFlags |= TS_BOUND_BOTTOM;
  161. }
  162. else {
  163. *pNextFreeSpace++ = (char)Delta;
  164. *pFlags |= TS_BOUND_DELTA_BOTTOM;
  165. }
  166. }
  167. // Copy the rectangle for reference with the next encoding.
  168. oe2LastBounds = *pRect;
  169. // If no bounds were encoded (i.e. the rectangle is identical to the
  170. // previous one) set the no-change-in-bounds flag.
  171. if (*pFlags)
  172. *ppBuffer = pNextFreeSpace;
  173. else
  174. *pControlFlags |= TS_ZERO_BOUNDS_DELTAS;
  175. DC_END_FN();
  176. }
  177. /****************************************************************************/
  178. // OE2_TableEncodeOrderFields
  179. //
  180. // Uses an order field encoding table to encode an intermediate order
  181. // format into wire format.
  182. /****************************************************************************/
  183. void OE2_TableEncodeOrderFields(
  184. BYTE *pControlFlags,
  185. PUINT32_UA pFieldFlags,
  186. BYTE **ppBuffer,
  187. PINT_FMT_FIELD pFieldTable,
  188. unsigned NumFields,
  189. BYTE *pIntFmt,
  190. BYTE *pPrevIntFmt)
  191. {
  192. BYTE UseDeltaCoords;
  193. BYTE *pNextFreeSpace;
  194. PBYTE pVariableField;
  195. UINT32 ThisFlag;
  196. unsigned i, j;
  197. unsigned NumReps;
  198. unsigned FieldLength;
  199. PINT_FMT_FIELD pTableEntry;
  200. DC_BEGIN_FN("OE2_TableEncodeOrderFields");
  201. pNextFreeSpace = *ppBuffer;
  202. // Before we do the field encoding check all the field entries flagged
  203. // as coord to see if we can switch to TS_DELTA_COORDINATES mode.
  204. pTableEntry = pFieldTable;
  205. UseDeltaCoords = TS_DELTA_COORDINATES;
  206. // Loop through each fixed field in this order structure.
  207. i = 0;
  208. while (i < NumFields && pTableEntry->FieldType & OE2_ETF_FIXED) {
  209. // If this field entry is coord then compare it to the previous
  210. // coordinate we sent for this field to determine whether we can send
  211. // it as a delta.
  212. if (pTableEntry->FieldType & OE2_ETF_COORDINATES) {
  213. // We assume that coordinates are always signed.
  214. if (pTableEntry->FieldUnencodedLen == 4) {
  215. __int32 Temp;
  216. // Most common case: 4-byte source.
  217. Temp = (*((__int32 *)(pIntFmt + pTableEntry->FieldPos)) -
  218. *((__int32 *)(pPrevIntFmt + pTableEntry->FieldPos)));
  219. if (Temp != (INT32)(char)Temp) {
  220. UseDeltaCoords = FALSE;
  221. break;
  222. }
  223. }
  224. else if (pTableEntry->FieldUnencodedLen == 2) {
  225. short Temp;
  226. // Uncommon: 2-byte source.
  227. Temp = (*((short *)(pIntFmt + pTableEntry->FieldPos)) -
  228. *((short *)(pPrevIntFmt + pTableEntry->FieldPos)));
  229. if (Temp != (short)(char)Temp) {
  230. UseDeltaCoords = FALSE;
  231. break;
  232. }
  233. }
  234. else {
  235. TRC_ASSERT((pTableEntry->FieldUnencodedLen == 2),
  236. (TB,"Unhandled field size %d",
  237. pTableEntry->FieldUnencodedLen));
  238. }
  239. TRC_DBG((TB, "Use Delta coord A %d", UseDeltaCoords));
  240. }
  241. pTableEntry++;
  242. i++;
  243. }
  244. #ifdef USE_VARIABLE_COORDS
  245. // Next loop through each of the variable fields.
  246. pVariableField = pIntFmt + pTableEntry->FieldPos;
  247. while (i < NumFields && UseDeltaCoords) {
  248. // The length of the field (in bytes) is given in the first
  249. // UINT32 of the variable sized field structure.
  250. FieldLength = *(PUINT32)pVariableField;
  251. pVariableField += sizeof(UINT32);
  252. // If this field entry is a coord then compare it to the
  253. // previous coord we sent for this field to determine whether
  254. // we can send it as a delta.
  255. if (pTableEntry->FieldType & OE2_ETF_COORDINATES) {
  256. // The number of coords is given by the number of bytes in
  257. // the field divided by the size of each entry.
  258. NumReps = FieldLength / pTableEntry->FieldUnencodedLen;
  259. // We assume that coords are always signed.
  260. if (pTableEntry->FieldUnencodedLen == 4) {
  261. __int32 Temp;
  262. // Most common case: 4-byte source.
  263. for (j = 0; j < NumReps; j++) {
  264. Temp = (*((__int32 *)(pIntFmt + pTableEntry->FieldPos)) -
  265. *((__int32 *)(pPrevIntFmt + pTableEntry->FieldPos)));
  266. if (Temp != (__int32)(char)Temp) {
  267. UseDeltaCoords = FALSE;
  268. break;
  269. }
  270. }
  271. }
  272. else if (pTableEntry->FieldUnencodedLen == 2) {
  273. short Temp;
  274. // Uncommon: 2-byte source.
  275. for (j = 0; j < NumReps; j++) {
  276. Temp = (*((short *)(pIntFmt + pTableEntry->FieldPos)) -
  277. *((short *)(pPrevIntFmt + pTableEntry->FieldPos)));
  278. if (Temp != (short)(char)Temp) {
  279. UseDeltaCoords = FALSE;
  280. break;
  281. }
  282. }
  283. }
  284. else {
  285. TRC_ASSERT((pTableEntry->FieldUnencodedLen == 2),
  286. (TB,"Unhandled field size %d",
  287. pTableEntry->FieldUnencodedLen));
  288. }
  289. TRC_DBG((TB, "Use Delta coord B %d", UseDeltaCoords));
  290. }
  291. // Move on to the next field in the order structure. Note that
  292. // variable sized fields are packed on the send side (i.e.
  293. // increment pVariableField by fieldLength not by
  294. // pTableEntry->FieldLen).
  295. pVariableField += FieldLength;
  296. pTableEntry++;
  297. i++;
  298. }
  299. #endif // USE_VARIABLE_COORDS
  300. TRC_DBG((TB, "Final UseDeltaCoords: %d", UseDeltaCoords));
  301. *pControlFlags |= UseDeltaCoords;
  302. // Now do the encoding.
  303. pTableEntry = pFieldTable;
  304. ThisFlag = 0x00000001;
  305. // First process all the fixed size fields in the order structure.
  306. // (These come before the variable sized fields.)
  307. i = 0;
  308. while (i < NumFields && pTableEntry->FieldType & OE2_ETF_FIXED) {
  309. // If the field has changed since it was previously transmitted then
  310. // we need to send it again.
  311. TRC_DBG((TB, "Processing field pos %u, type %u",
  312. pTableEntry->FieldPos, pTableEntry->FieldType));
  313. if (memcmp(pIntFmt + pTableEntry->FieldPos,
  314. pPrevIntFmt + pTableEntry->FieldPos,
  315. pTableEntry->FieldUnencodedLen)) {
  316. TRC_DBG((TB, "Bothering to encode this"));
  317. // Update the encoding flags.
  318. *pFieldFlags |= ThisFlag;
  319. // If we are encoding in delta coordinate mode and this field
  320. // is a coordinate...
  321. if (UseDeltaCoords &&
  322. (pTableEntry->FieldType & OE2_ETF_COORDINATES) != 0) {
  323. TRC_DBG((TB, "Using delta coords"));
  324. // We assume that coordinates are always signed.
  325. if (pTableEntry->FieldUnencodedLen == 4) {
  326. // Most common case: 4-byte source.
  327. *pNextFreeSpace++ =
  328. (char)(*((__int32 *)(pIntFmt + pTableEntry->FieldPos)) -
  329. *((__int32 *)(pPrevIntFmt + pTableEntry->FieldPos)));
  330. }
  331. else if (pTableEntry->FieldUnencodedLen == 2) {
  332. // Uncommon: 2-byte source.
  333. *pNextFreeSpace++ =
  334. (char)(*((short *)(pIntFmt + pTableEntry->FieldPos)) -
  335. *((short *)(pPrevIntFmt + pTableEntry->FieldPos)));
  336. }
  337. else {
  338. TRC_ASSERT((pTableEntry->FieldUnencodedLen == 2),
  339. (TB,"Unhandled field size %d",
  340. pTableEntry->FieldUnencodedLen));
  341. }
  342. }
  343. else {
  344. TRC_DBG((TB, "Regular encoding"));
  345. // Update the data to be sent.
  346. pNextFreeSpace = OE2EncodeFieldSingle(
  347. pIntFmt + pTableEntry->FieldPos,
  348. pNextFreeSpace, pTableEntry->FieldUnencodedLen,
  349. pTableEntry->FieldEncodedLen);
  350. }
  351. // Save the current value for comparison next time.
  352. memcpy(pPrevIntFmt + pTableEntry->FieldPos,
  353. pIntFmt + pTableEntry->FieldPos,
  354. pTableEntry->FieldUnencodedLen);
  355. }
  356. // Move on to the next field in the structure.
  357. ThisFlag <<= 1;
  358. pTableEntry++;
  359. i++;
  360. }
  361. // Now process the variable sized entries.
  362. pVariableField = pIntFmt + pTableEntry->FieldPos;
  363. while (i < NumFields) {
  364. // The length of the field is given in the first UINT32 of the
  365. // variable sized field structure.
  366. FieldLength = *(PUINT32)pVariableField;
  367. TRC_DBG((TB, "Var field length %u", FieldLength));
  368. // If the field has changed (either in size or in contents) then we
  369. // need to copy it across.
  370. if (memcmp(pVariableField, pPrevIntFmt + pTableEntry->FieldPos,
  371. FieldLength + sizeof(UINT32))) {
  372. // Update the encoding flags.
  373. *pFieldFlags |= ThisFlag;
  374. // Work out how many elements we are encoding for this field.
  375. NumReps = FieldLength / pTableEntry->FieldUnencodedLen;
  376. // Fill in the length of the field into the encoded buffer then
  377. // increment the pointer ready to encode the actual field.
  378. // Note that the length must always be set to the length
  379. // required for regular second level encoding of the field,
  380. // regardless of whether regular encoding or delta encoding is
  381. // used.
  382. if (pTableEntry->FieldType & OE2_ETF_LONG_VARIABLE) {
  383. *((PUINT16_UA)pNextFreeSpace) =
  384. (UINT16)(NumReps * pTableEntry->FieldEncodedLen);
  385. pNextFreeSpace += sizeof(UINT16);
  386. }
  387. else {
  388. *pNextFreeSpace++ =
  389. (BYTE)(NumReps * pTableEntry->FieldEncodedLen);
  390. }
  391. #ifdef USE_VARIABLE_COORDS
  392. // If we are encoding in delta coord mode and this field
  393. // is a coordinate...
  394. if (UseDeltaCoords &&
  395. (pTableEntry->FieldType & OE2_ETF_COORDINATES) != 0) {
  396. // We assume that coordinates are always signed.
  397. if (pTableEntry->FieldUnencodedLen == 4) {
  398. // Most common case: 4-byte source.
  399. for (j = 0; j < NumReps; j++)
  400. *pNextFreeSpace++ =
  401. (char)(((__int32 *)(pVariableField +
  402. sizeof(DWORD)))[j] -
  403. ((__int32 *)(pPrevIntFmt +
  404. pTableEntry->FieldPos + sizeof(DWORD)))[j]);
  405. }
  406. else if (pTableEntry->FieldUnencodedLen == 2) {
  407. // Uncommon: 2-byte source.
  408. for (j = 0; j < NumReps; j++)
  409. *pNextFreeSpace++ =
  410. (char)(((short *)(pVariableField +
  411. sizeof(DWORD)))[j] -
  412. ((short *)(pPrevIntFmt +
  413. pTableEntry->FieldPos + sizeof(DWORD)))[j]);
  414. }
  415. else {
  416. TRC_ASSERT((fieldLength == 2), (TB,"Unhandled field size %d",
  417. pTableEntry->FieldUnencodedLen));
  418. }
  419. }
  420. else
  421. #endif // USE_VARIABLE_COORDS
  422. {
  423. // Use regular encoding.
  424. TRC_DBG((TB, "Encode: encLen %u, unencLen %u reps %u",
  425. pTableEntry->FieldEncodedLen,
  426. pTableEntry->FieldUnencodedLen,
  427. NumReps));
  428. pNextFreeSpace = OE2EncodeFieldMultiple(
  429. pVariableField + sizeof(UINT32), pNextFreeSpace,
  430. pTableEntry->FieldUnencodedLen,
  431. pTableEntry->FieldEncodedLen, NumReps);
  432. }
  433. // Keep data for comparison next time.
  434. // Note that the variable fields of pLastOrder are not packed
  435. // (unlike the order which we are encoding), so we can use
  436. // pTableEntry->FieldPos to get the start of the field.
  437. memcpy(pPrevIntFmt + pTableEntry->FieldPos,
  438. pVariableField, FieldLength + sizeof(UINT32));
  439. }
  440. else {
  441. TRC_NRM((TB, "Duplicate var field length %u", FieldLength));
  442. }
  443. // Move on to the next field in the order structure, remembering to
  444. // step. Note that past the size field. variable sized fields are
  445. // packed on the send side. (ie increment pVariableField by
  446. // fieldLength not by pTableEntry->FieldLen).
  447. pVariableField += FieldLength + sizeof(UINT32);
  448. // Make sure that we are at the next 4-byte boundary.
  449. pVariableField = (PBYTE)DC_ROUND_UP_4((UINT_PTR)pVariableField);
  450. ThisFlag <<= 1;
  451. pTableEntry++;
  452. i++;
  453. }
  454. *ppBuffer = pNextFreeSpace;
  455. DC_END_FN();
  456. }
  457. /****************************************************************************/
  458. // OE2_EncodeOrder
  459. //
  460. // Provided with buffer space and an intermediate (OE) representation of
  461. // order data, field-encodes the order into wire (OE2) format.
  462. /****************************************************************************/
  463. unsigned OE2_EncodeOrder(
  464. BYTE *pBuffer,
  465. unsigned OrderType,
  466. unsigned NumFields,
  467. BYTE *pIntFmt,
  468. BYTE *pPrevIntFmt,
  469. PINT_FMT_FIELD pFieldTable,
  470. RECTL *pBoundRect)
  471. {
  472. BYTE *pControlFlags;
  473. PUINT32_UA pFieldFlags;
  474. unsigned NumFieldFlagBytes;
  475. DC_BEGIN_FN("OE2_EncodeOrder");
  476. TRC_ASSERT((OrderType < TS_MAX_ORDERS),
  477. (TB,"Ordertype %u exceeds max", OrderType));
  478. TRC_ASSERT((NumFields == OE2OrdAttr[OrderType].NumFields),
  479. (TB,"Ordertype %u does not have %u fields", OrderType,
  480. OE2OrdAttr[OrderType].NumFields));
  481. TRC_ASSERT((pFieldTable == OE2OrdAttr[OrderType].pFieldTable),
  482. (TB,"Ord table %p does not match ordtype %u's table %p",
  483. pFieldTable, OrderType, OE2OrdAttr[OrderType].pFieldTable));
  484. // The first byte is always a control flag byte.
  485. pControlFlags = pBuffer;
  486. *pControlFlags = TS_STANDARD;
  487. pBuffer++;
  488. // Add the order change if need be.
  489. OE2_EncodeOrderType(pControlFlags, &pBuffer, OrderType);
  490. // Make room for the field flags.
  491. pFieldFlags = (PUINT32_UA)pBuffer;
  492. *pFieldFlags = 0;
  493. NumFieldFlagBytes = ((NumFields + 1) + 7) / 8;
  494. pBuffer += NumFieldFlagBytes;
  495. // Bounds before encoded fields.
  496. if (pBoundRect != NULL)
  497. OE2_EncodeBounds(pControlFlags, &pBuffer, pBoundRect);
  498. // Use the translation table to convert the internal format to wire
  499. // format.
  500. OE2_TableEncodeOrderFields(pControlFlags, pFieldFlags, &pBuffer,
  501. pFieldTable, NumFields, pIntFmt, pPrevIntFmt);
  502. // Check to see if we can optimize the field flag bytes.
  503. pBuffer -= OE2_CheckZeroFlagBytes(pControlFlags,
  504. (BYTE *)pFieldFlags, NumFieldFlagBytes,
  505. (unsigned)(pBuffer - (BYTE *)pFieldFlags - NumFieldFlagBytes));
  506. DC_END_FN();
  507. return (unsigned)(pBuffer - pControlFlags);
  508. }
  509. /****************************************************************************/
  510. // OE2EncodeFieldSingle
  511. //
  512. // Encodes an element by copying it to the destination, doing a width
  513. // conversion if need be. Returns the new pDest value incremented by the
  514. // length used.
  515. //
  516. // We can ignore signed values since we only ever truncate the data.
  517. // Consider the case where we have a 16 bit integer that we want to
  518. // convert to 8 bits. We know our values are permissable within the
  519. // lower integer size (ie. we know the unsigned value will be less
  520. // than 256 of that a signed value will be -128 >= value >= 127), so we
  521. // just need to make sure that we have the right high bit set.
  522. // But this must be the case for a 16-bit equivalent of an 8-bit
  523. // number. No problems - just take the truncated integer.
  524. /****************************************************************************/
  525. BYTE *OE2EncodeFieldSingle(
  526. void *pSrc,
  527. BYTE *pDest,
  528. unsigned srcFieldLength,
  529. unsigned destFieldLength)
  530. {
  531. DC_BEGIN_FN("OE2EncodeFieldSingle");
  532. // Note that the source should always be aligned, but the destination
  533. // may not be.
  534. // Most common case: 4-byte source.
  535. if (srcFieldLength == 4) {
  536. // Most common case: 2-byte destination.
  537. if (destFieldLength == 2)
  538. *((UNALIGNED unsigned short *)pDest) = *((unsigned short *)pSrc);
  539. // Second most common: 1-byte destination.
  540. else if (destFieldLength == 1)
  541. *pDest = *((BYTE *)pSrc);
  542. // Only other allowed case, very rare: 4-byte destination.
  543. else if (destFieldLength == 4)
  544. *((UNALIGNED DWORD *)pDest) = *((DWORD *)pSrc);
  545. else
  546. TRC_ASSERT((destFieldLength == 4),
  547. (TB,"Src len = 4, unhandled dest len %d",
  548. destFieldLength));
  549. }
  550. // Next most common case: Color entries. Avoid pipeline-costly memcpy
  551. // since it's short.
  552. else if (srcFieldLength == 3) {
  553. pDest[0] = ((BYTE *)pSrc)[0];
  554. pDest[1] = ((BYTE *)pSrc)[1];
  555. pDest[2] = ((BYTE *)pSrc)[2];
  556. }
  557. // Somewhat common (usually cache indices): 2-byte source.
  558. else if (srcFieldLength == 2) {
  559. if (destFieldLength == 2)
  560. *((UNALIGNED unsigned short *)pDest) = *((unsigned short *)pSrc);
  561. else if (destFieldLength == 1)
  562. *pDest = *((BYTE *)pSrc);
  563. else
  564. TRC_ASSERT((destFieldLength == 1),
  565. (TB,"Src len = 2, unhandled dest len %d",
  566. destFieldLength));
  567. }
  568. // Next: Same-sized fields, including rare 1-byte fields and brushes etc.
  569. else if (srcFieldLength == destFieldLength) {
  570. memcpy(pDest, pSrc, srcFieldLength);
  571. }
  572. // We didn't handle the combination.
  573. else {
  574. TRC_ASSERT((destFieldLength == srcFieldLength),
  575. (TB,"Unhandled encode conbination, src len = %d, dest len %d",
  576. srcFieldLength, destFieldLength));
  577. }
  578. DC_END_FN();
  579. return pDest + destFieldLength;
  580. }
  581. /****************************************************************************/
  582. // OE2EncodeFieldMultiple
  583. // Encodes an array of elements by copying them to the destination, doing a
  584. // width conversion if need be. Returns the new pDest value incremented by
  585. // the length used.
  586. //
  587. // See notes for OE2EncodeFieldSingle above for signed value truncation info.
  588. /****************************************************************************/
  589. BYTE *OE2EncodeFieldMultiple(
  590. void *pSrc,
  591. BYTE *pDest,
  592. unsigned srcFieldLength,
  593. unsigned destFieldLength,
  594. unsigned numElements)
  595. {
  596. unsigned i;
  597. DC_BEGIN_FN("OE2EncodeFieldMultiple");
  598. // Note that the source should always be aligned, but the destination
  599. // may not be.
  600. // Most common case: 1-byte source to 1-byte destination.
  601. if (srcFieldLength == 1) {
  602. memcpy(pDest, pSrc, numElements);
  603. }
  604. // Next most common: 4-byte source.
  605. else if (srcFieldLength == 4) {
  606. // Common: 2-byte destination.
  607. if (destFieldLength == 2)
  608. for (i = 0; i < numElements; i++)
  609. ((UNALIGNED unsigned short *)pDest)[i] =
  610. (unsigned short)((DWORD *)pSrc)[i];
  611. // Less common: 1-byte destination.
  612. else if (destFieldLength == 1)
  613. for (i = 0; i < numElements; i++)
  614. pDest[i] = (BYTE)((DWORD *)pSrc)[i];
  615. // Rare if any: 4-byte destination.
  616. else if (destFieldLength == 4)
  617. for (i = 0; i < numElements; i++)
  618. ((UNALIGNED DWORD *)pDest)[i] = ((DWORD *)pSrc)[i];
  619. else
  620. TRC_ASSERT((destFieldLength == 4),
  621. (TB,"Src len = 4, unhandled dest len %d",
  622. destFieldLength));
  623. }
  624. // We don't handle anything else.
  625. else {
  626. TRC_ASSERT((srcFieldLength == 4),
  627. (TB,"Unhandled encode conbination, src len = %d, dest len %d",
  628. srcFieldLength, destFieldLength));
  629. }
  630. DC_END_FN();
  631. return pDest + destFieldLength * numElements;
  632. }
  633. #ifdef DC_DEBUG
  634. /****************************************************************************/
  635. // OE2PerformUnitTests
  636. //
  637. // Debug-only test code designed to ensure OE2 is functioning properly.
  638. /****************************************************************************/
  639. // Data for OE2_EncodeBounds test. Note that EncBounds converts to inclusive
  640. // coordinates.
  641. const RECTL BoundsTest1_InputRect = { 0x100, 0x200, 0x300, 0x400 };
  642. #define BoundsTest1_OutputLen 9
  643. const BYTE BoundsTest1_Output[BoundsTest1_OutputLen] =
  644. { 0x0F, 0x00, 0x01, 0x00, 0x02, 0xFF, 0x02, 0xFF, 0x03 };
  645. const RECTL BoundsTest2_InputRect = { 0x101, 0x202, 0x303, 0x404 };
  646. #define BoundsTest2_OutputLen 5
  647. const BYTE BoundsTest2_Output[BoundsTest2_OutputLen] =
  648. { 0xF0, 0x01, 0x02, 0x03, 0x04 };
  649. const RECTL BoundsTest3_InputRect = { 0x101, 0x202, 0x303, 0x404 };
  650. #define BoundsTest3_OutputLen 0
  651. // Data for ScrBlt test encoding via OE2_EncodeOrder.
  652. const SCRBLT_ORDER OrderTest1_IntOrderFmt =
  653. {
  654. 0, 0, // dest left, top
  655. 0x200, 0x100, // width, height
  656. 0xCC, // rop=copyrop
  657. 0x201, 0x101 // src left, top
  658. };
  659. SCRBLT_ORDER UnitTestPrevScrBlt;
  660. #define OrderTest1_OutputLen 12
  661. const BYTE OrderTest1_Output[OrderTest1_OutputLen] =
  662. {
  663. 0x09, // Control flags: TS_STANDARD | TS_TYPE_CHANGE
  664. TS_ENC_SCRBLT_ORDER,
  665. 0x7C, // Field flags byte: width, height, rop, srcleft, srctop
  666. 0x00, 0x02, // width
  667. 0x00, 0x01, // height
  668. 0xCC, // rop
  669. 0x01, 0x02, // srcleft
  670. 0x01, 0x01, // srctop
  671. };
  672. void OE2PerformUnitTests()
  673. {
  674. BYTE *pBuffer;
  675. BYTE ControlFlags;
  676. RECTL InputRect;
  677. BYTE OutputBuffer[256];
  678. unsigned Len;
  679. DC_BEGIN_FN("OE2PerformUnitTests");
  680. // Test OE2_EncodeBounds.
  681. // Reset the bounds, then perform a few rect encodings (regular, delta,
  682. // zero delta) to make sure the bounds are being encoded properly and
  683. // the control flags come out right.
  684. memset(&oe2LastBounds, 0, sizeof(oe2LastBounds));
  685. // First rect: should result in non-delta, non-zero-delta encoding.
  686. ControlFlags = TS_STANDARD | TS_BOUNDS;
  687. pBuffer = OutputBuffer;
  688. OE2_EncodeBounds(&ControlFlags, &pBuffer, (RECTL *)&BoundsTest1_InputRect);
  689. Len = (unsigned)(pBuffer - OutputBuffer);
  690. TRC_ASSERT((ControlFlags == (TS_STANDARD | TS_BOUNDS)),
  691. (TB,"Bounds1: Control flag value 0x%02X does not match "
  692. "expected 0x%02X", ControlFlags, (TS_STANDARD | TS_BOUNDS)));
  693. TRC_ASSERT((Len == BoundsTest1_OutputLen),
  694. (TB,"Bounds1: Len %u != expected %u", Len, BoundsTest1_OutputLen));
  695. TRC_ASSERT((!memcmp(OutputBuffer, BoundsTest1_Output, Len)),
  696. (TB,"Bounds1: Mem at %p != expected at %p (Len=%u)",
  697. OutputBuffer, BoundsTest1_Output, Len));
  698. // Second rect: should result in delta encoding.
  699. ControlFlags = TS_STANDARD | TS_BOUNDS;
  700. pBuffer = OutputBuffer;
  701. OE2_EncodeBounds(&ControlFlags, &pBuffer, (RECTL *)&BoundsTest2_InputRect);
  702. Len = (unsigned)(pBuffer - OutputBuffer);
  703. TRC_ASSERT((ControlFlags == (TS_STANDARD | TS_BOUNDS)),
  704. (TB,"Bounds2: Control flag value 0x%02X does not match "
  705. "expected 0x%02X", ControlFlags, (TS_STANDARD | TS_BOUNDS)));
  706. TRC_ASSERT((Len == BoundsTest2_OutputLen),
  707. (TB,"Bounds2: Len %u != expected %u", Len, BoundsTest2_OutputLen));
  708. TRC_ASSERT((!memcmp(OutputBuffer, BoundsTest2_Output, Len)),
  709. (TB,"Bounds2: Mem at %p != expected at %p (Len=%u)",
  710. OutputBuffer, BoundsTest2_Output, Len));
  711. // Third rect: Should result in zero-delta encoding.
  712. ControlFlags = TS_STANDARD | TS_BOUNDS;
  713. pBuffer = OutputBuffer;
  714. OE2_EncodeBounds(&ControlFlags, &pBuffer, (RECTL *)&BoundsTest3_InputRect);
  715. Len = (unsigned)(pBuffer - OutputBuffer);
  716. TRC_ASSERT((ControlFlags ==
  717. (TS_STANDARD | TS_BOUNDS | TS_ZERO_BOUNDS_DELTAS)),
  718. (TB,"Bounds3: Control flag value 0x%02X does not match "
  719. "expected 0x%02X", ControlFlags,
  720. (TS_STANDARD | TS_BOUNDS | TS_ZERO_BOUNDS_DELTAS)));
  721. TRC_ASSERT((Len == BoundsTest3_OutputLen),
  722. (TB,"Bounds3: Len %u != expected %u", Len, BoundsTest3_OutputLen));
  723. // Reset the bounds after the encoding test.
  724. memset(&oe2LastBounds, 0, sizeof(oe2LastBounds));
  725. // Test OE2_EncodeOrder by encoding a ScrBlt order. We need to make sure
  726. // oe2LastOrderType is reset to default (PatBlt). Reset the prev ScrBlt
  727. // to an initial state.
  728. oe2LastOrderType = TS_ENC_PATBLT_ORDER;
  729. memset(&UnitTestPrevScrBlt, 0, sizeof(UnitTestPrevScrBlt));
  730. Len = OE2_EncodeOrder(OutputBuffer, TS_ENC_SCRBLT_ORDER,
  731. NUM_SCRBLT_FIELDS, (BYTE *)&OrderTest1_IntOrderFmt,
  732. (BYTE *)&UnitTestPrevScrBlt, etable_SB, NULL);
  733. TRC_ASSERT((Len == OrderTest1_OutputLen),
  734. (TB,"Order1: Len %u != expected %u", Len, OrderTest1_OutputLen));
  735. TRC_ASSERT((!memcmp(OutputBuffer, OrderTest1_Output, Len)),
  736. (TB,"Order1: Mem at %p != expected at %p (Len=%u)",
  737. OutputBuffer, OrderTest1_Output, Len));
  738. DC_END_FN();
  739. }
  740. #endif // DC_DEBUG