/****************************************************************************/ // oe2.h // // Header for RDP field compression. // // Copyright (C) 1997-2000 Microsoft Corporation /****************************************************************************/ #ifndef __OE2_H #define __OE2_H /****************************************************************************/ // Field compression (OE2) overview // // OE2 compression maintains a copy of each field value of the last order // sent, plus other state information like the last bounding rectangle used // and the last order type. OE2 encoding involves comparing a new display // order to the last copy, and sending only the fields which have changed. // Other specialized encoding occurs for certain fields declared to be of // "coord" type, meaning that a one-byte delta can be sent instead of a // 2-byte value, if the delta will fit into 8 bits. // // The wire format for OE2 encoded orders consists of the following fields: // // +------------+------+-------------+--------+----------------+ // | Ctrl flags | Type | Field flags | Bounds | Encoded Fields | // +------------+------+-------------+--------+----------------+ // // Control flags: Required byte, corresponding to a TS_ORDER_HEADER and // available flags. Always contains at least TS_STANDARD flag. These // flags describe the following encoding; flag meanings are discussed // below. // // Type: If TS_TYPE_CHANGE is present in the control flags, this is a one- // byte order type value. The initial value agreed-on by both server // and client is TS_ENC_PATBLT_ORDER. // // Field flags: One or more bytes, where the number of bytes is ceil(((number // of order fields) + 1) / 8). The "+ 1" in that equation is historical // and means that the first byte of field flags can only encompass 7 // flag bits. The presence of these flags is also governed by the control // flags TS_ZERO_FIELD_BYTE_BIT0 and TS_ZERO_FIELD_BYTE_BIT1 // (see at128.h description). The ordering of the bytes is as a DWORD // -- the low order byte is first. The field flags indicate the presence // of an order field in the encoded fields portion of the packet. // The ordering of the flags proceeds from 0x01 corresponding to the // first order field, 0x02 the second, 0x04 the third, etc. // // Bounds: The presence of this field is governed by the TS_BOUNDS control // flag, which indicates the order must have a bounding region applied. // If control flag TS_ZERO_BOUNDS_DELTAS is set, the bound rect to be // used is the same as the last bound rect used. Otherwise, the // bounds are encoded as an encoding description byte followed by one // or more encoded bounds. The description byte contains two flags // for each of the left, top, right, and bottom rect components. // One flag (TS_BOUND_XXX) indicates that the component is present // and encoded as a 2-byte Intel-ordering value. The other flag // (TS_BOUND_DELTA_XXX) indicates the component is present and encoded // as a one-byte value used as an offset (-128 to 127) from the previous // value of the component. If neither flag is present the component // value is the same as used last. The initial value for the bounds // agreed-on by both server and client is the zero rect (0, 0, 0, 0). // // Encoded fields: These are the encoded order field values whose presence // is governed by the field flags. The fields are encoded in order if // present. The control flag TS_DELTA_COORDINATES is set if all COORD // type fields in the order can be specified as a one-byte delta from // their last values. If a field is not present its value is the same // as the last value sent. The initial values the client and server // use for all fields is zero. See the order field description tables in // noe2disp.c for specific order information. /****************************************************************************/ /****************************************************************************/ // Defines /****************************************************************************/ #define MAX_BOUNDS_ENCODE_SIZE 9 #define MAX_REPLAY_CLIPPED_ORDER_SIZE (1 + MAX_BOUNDS_ENCODE_SIZE) #define OE2_CONTROL_FLAGS_FIELD_SIZE 1 #define OE2_TYPE_FIELD_SIZE 1 #define OE2_MAX_FIELD_FLAG_BYTES 3 #define MAX_ENCODED_ORDER_PREFIX_BYTES (OE2_CONTROL_FLAGS_FIELD_SIZE + \ OE2_TYPE_FIELD_SIZE + OE2_MAX_FIELD_FLAG_BYTES + \ MAX_BOUNDS_ENCODE_SIZE) // Max size: 1 control flag + 1 type change byte + num field flag bytes + // 9 bounds bytes + fields. #define MAX_ORDER_SIZE(_NumRects, _NumFieldFlagBytes, _MaxFieldSize) \ (2 + (_NumFieldFlagBytes) + ((_NumRects == 0) ? 0 : 9) + \ (_MaxFieldSize)) /****************************************************************************/ // Types /****************************************************************************/ // INT_FMT_FIELD: Const data definitions for table-based OE2 order translation. // Describes the source intermediate and destination wire data formats. // // FieldPos: Byte offset into the source intermediate format for the field. // FieldUnencodedLen: Length of the source field. // FieldEncodedLen: Length of the destination field (wore format). // FieldSigned: Flag for signed field value. // FieldType: Descriptor that specifies how to translate the field. typedef struct { unsigned FieldPos; unsigned FieldUnencodedLen; unsigned FieldEncodedLen; BOOL FieldSigned; unsigned FieldType; } INT_FMT_FIELD; typedef INT_FMT_FIELD const *PINT_FMT_FIELD; /****************************************************************************/ // Prototypes and inlines /****************************************************************************/ void OE2_Reset(void); void OE2_EncodeBounds(BYTE *, BYTE **, RECTL *); unsigned OE2_CheckZeroFlagBytes(BYTE *, BYTE *, unsigned, unsigned); void OE2_TableEncodeOrderFields(BYTE *, PUINT32_UA, BYTE **, PINT_FMT_FIELD, unsigned, BYTE *, BYTE *); unsigned OE2_EncodeOrder(BYTE *, unsigned, unsigned, BYTE *, BYTE *, PINT_FMT_FIELD, RECTL *); /****************************************************************************/ // OE2_EncodeOrderType // // Used by order encoding paths to encode the order type byte if different // from the last order. // // void OE2_EncodeOrderType( // BYTE *pControlFlags, // BYTE **ppBuffer, // unsigned OrderType); /****************************************************************************/ #define OE2_EncodeOrderType(_pControlFlags, _ppBuffer, _OrderType) \ { \ if (oe2LastOrderType != (_OrderType)) { \ *(_pControlFlags) |= TS_TYPE_CHANGE; \ **(_ppBuffer) = (BYTE)(_OrderType); \ (*(_ppBuffer))++; \ oe2LastOrderType = (_OrderType); \ } \ } /****************************************************************************/ // OE2_CheckOneZeroFlagByte // // 1-field-flag-byte version of OE2_CheckZeroFlagBytes(), optimizes out the // generalized loop. /****************************************************************************/ __inline unsigned OE2_CheckOneZeroFlagByte( BYTE *pControlFlags, BYTE *pFieldFlag, unsigned PostFlagsDataLength) { if (*pFieldFlag != 0) { return 0; } else { *pControlFlags |= (1 << TS_ZERO_FIELD_COUNT_SHIFT); memmove(pFieldFlag, pFieldFlag + 1, PostFlagsDataLength); return 1; } } /****************************************************************************/ // OE2_CheckTwoZeroFlagBytes // // 2-field-flag-byte version of OE2_CheckZeroFlagBytes(), optimizes out the // generalized loop. /****************************************************************************/ __inline unsigned OE2_CheckTwoZeroFlagBytes( BYTE *pControlFlags, BYTE *pFieldFlags, unsigned PostFlagsDataLength) { if (pFieldFlags[1] != 0) { return 0; } else if (pFieldFlags[0] != 0) { *pControlFlags |= (1 << TS_ZERO_FIELD_COUNT_SHIFT); memmove(pFieldFlags + 1, pFieldFlags + 2, PostFlagsDataLength); return 1; } else { *pControlFlags |= (2 << TS_ZERO_FIELD_COUNT_SHIFT); memmove(pFieldFlags, pFieldFlags + 2, PostFlagsDataLength); return 2; } } /****************************************************************************/ // OE2_EmitClippedReplayOrder // // Creates a "play-it-again" order -- same order type and all fields // the same as previous, except with a different bound rect. // // void OE2_EmitClippedReplayOrder( // BYTE **ppBuffer, // unsigned NumFieldFlagBytes, // RECTL *pClipRect) /****************************************************************************/ #define OE2_EmitClippedReplayOrder(_ppBuffer, _NumFieldFlagBytes, _pClipRect) \ { \ BYTE *pBuffer = *(_ppBuffer); \ \ /* Control flags are primary order plus all field flags bytes zero. */ \ *pBuffer++ = TS_STANDARD | TS_BOUNDS | \ ((_NumFieldFlagBytes) << TS_ZERO_FIELD_COUNT_SHIFT); \ \ /* Construct the new bounds rect just after this. */ \ OE2_EncodeBounds(pBuffer - 1, &pBuffer, (_pClipRect)); \ \ *(_ppBuffer) = pBuffer; \ } #endif // __OE2_H