Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1776 lines
61 KiB

#include "precomp.h"
//
// OD2.CPP
// Order Decoding Second Level
//
// Copyright(c) Microsoft 1997-
//
#define MLZ_FILE_ZONE ZONE_ORDER
//
// OD2_ViewStarting()
//
// For 3.0 nodes, we create the decoding data each time they start hosting.
// For 2.x nodes, we create the decoding data once and use it until they
// leave the share.
//
BOOL ASShare::OD2_ViewStarting(ASPerson * pasPerson)
{
PPARTYORDERDATA pThisParty;
BOOL rc = FALSE;
DebugEntry(ASShare::OD2_ViewStarting);
ValidatePerson(pasPerson);
if (pasPerson->od2Party != NULL)
{
ASSERT(pasPerson->cpcCaps.general.version < CAPS_VERSION_30);
TRACE_OUT(("OD2_ViewStarting: Reusing od2 data for 2.x node [%d]",
pasPerson->mcsID));
rc = TRUE;
DC_QUIT;
}
//
// Allocate memory for the required structure.
//
pThisParty = new PARTYORDERDATA;
pasPerson->od2Party = pThisParty;
if (!pThisParty)
{
ERROR_OUT(( "Failed to get memory for od2Party entry"));
DC_QUIT;
}
//
// Ensure the pointers are correctly set up.
//
ZeroMemory(pThisParty, sizeof(*pThisParty));
SET_STAMP(pThisParty, PARTYORDERDATA);
pThisParty->LastOrder[OE2_DSTBLT_ORDER ] = &pThisParty->LastDstblt;
pThisParty->LastOrder[OE2_PATBLT_ORDER ] = &pThisParty->LastPatblt;
pThisParty->LastOrder[OE2_SCRBLT_ORDER ] = &pThisParty->LastScrblt;
pThisParty->LastOrder[OE2_MEMBLT_ORDER ] = &pThisParty->LastMemblt;
pThisParty->LastOrder[OE2_MEM3BLT_ORDER ] = &pThisParty->LastMem3blt;
pThisParty->LastOrder[OE2_TEXTOUT_ORDER ] = &pThisParty->LastTextOut;
pThisParty->LastOrder[OE2_EXTTEXTOUT_ORDER] = &pThisParty->LastExtTextOut;
pThisParty->LastOrder[OE2_RECTANGLE_ORDER ] = &pThisParty->LastRectangle;
pThisParty->LastOrder[OE2_LINETO_ORDER ] = &pThisParty->LastLineTo;
pThisParty->LastOrder[OE2_OPAQUERECT_ORDER] = &pThisParty->LastOpaqueRect;
pThisParty->LastOrder[OE2_SAVEBITMAP_ORDER] = &pThisParty->LastSaveBitmap;
pThisParty->LastOrder[OE2_DESKSCROLL_ORDER] = &pThisParty->LastDeskScroll;
pThisParty->LastOrder[OE2_MEMBLT_R2_ORDER ] = &pThisParty->LastMembltR2;
pThisParty->LastOrder[OE2_MEM3BLT_R2_ORDER] = &pThisParty->LastMem3bltR2;
pThisParty->LastOrder[OE2_POLYGON_ORDER ] = &pThisParty->LastPolygon;
pThisParty->LastOrder[OE2_PIE_ORDER ] = &pThisParty->LastPie;
pThisParty->LastOrder[OE2_ELLIPSE_ORDER ] = &pThisParty->LastEllipse;
pThisParty->LastOrder[OE2_ARC_ORDER ] = &pThisParty->LastArc;
pThisParty->LastOrder[OE2_CHORD_ORDER ] = &pThisParty->LastChord;
pThisParty->LastOrder[OE2_POLYBEZIER_ORDER] = &pThisParty->LastPolyBezier;
pThisParty->LastOrder[OE2_ROUNDRECT_ORDER] = &pThisParty->LastRoundRect;
OD2_SyncIncoming(pasPerson);
rc = TRUE;
DC_EXIT_POINT:
DebugExitBOOL(ASShare::OD2_ViewStarting, rc);
return(rc);
}
//
// OD2_SyncIncoming()
// Called when NEW dude starts to share, a share is created, or someone new
// joins the share.
//
void ASShare::OD2_SyncIncoming(ASPerson * pasPerson)
{
PPARTYORDERDATA pThisParty;
DebugEntry(ASShare::OD2_SyncIncoming);
ValidateView(pasPerson);
pThisParty = pasPerson->od2Party;
pThisParty->LastOrderType = OE2_PATBLT_ORDER;
pThisParty->pLastOrder =
(LPCOM_ORDER)(pThisParty->LastOrder[pThisParty->LastOrderType]);
//
// Set all buffers to NULL Fill in the datalength fields and the type
// field. Note that because the type field is always the first one in
// an order we can cast each pointer to a TEXTOUT order to get the
// correct position for this field
//
#define Reset(field, ord) \
{ \
ZeroMemory(&pThisParty->field, sizeof(pThisParty->field)); \
((LPCOM_ORDER_HEADER)pThisParty->field)->cbOrderDataLength = \
sizeof(pThisParty->field) - sizeof(COM_ORDER_HEADER); \
TEXTFIELD(((LPCOM_ORDER)pThisParty->field))->type = LOWORD(ord); \
}
//
// The compiler generates a warning for our use of LOWORD here on a
// constant. We disable the warning just for now.
//
Reset(LastDstblt, ORD_DSTBLT);
Reset(LastPatblt, ORD_PATBLT);
Reset(LastScrblt, ORD_SCRBLT);
Reset(LastMemblt, ORD_MEMBLT);
Reset(LastMem3blt, ORD_MEM3BLT);
Reset(LastTextOut, ORD_TEXTOUT);
Reset(LastExtTextOut, ORD_EXTTEXTOUT);
Reset(LastRectangle, ORD_RECTANGLE);
Reset(LastLineTo, ORD_LINETO);
Reset(LastOpaqueRect, ORD_OPAQUERECT);
Reset(LastSaveBitmap, ORD_SAVEBITMAP);
Reset(LastDeskScroll, ORD_DESKSCROLL);
Reset(LastMembltR2, ORD_MEMBLT_R2);
Reset(LastMem3bltR2, ORD_MEM3BLT_R2);
Reset(LastPolygon, ORD_POLYGON);
Reset(LastPie, ORD_PIE);
Reset(LastEllipse, ORD_ELLIPSE);
Reset(LastArc, ORD_ARC);
Reset(LastChord, ORD_CHORD);
Reset(LastPolyBezier, ORD_POLYBEZIER);
Reset(LastRoundRect, ORD_ROUNDRECT);
//
// Reset the bounds rectangle
//
ZeroMemory(&pThisParty->LastBounds, sizeof(pThisParty->LastBounds));
//
// The sender and the receiver both set their structures to the same
// NULL state and the sender only ever sends differences from the
// current state. However the fontID fields in the received orders
// refer to the sender, so we must actually set our fontID fields to
// the local equivalent of the NULL entries just set.
// We cannot do this until we have actually received the font details
// so set the field to a dummy value we can recognise later.
//
TEXTFIELD(((LPCOM_ORDER)pThisParty->LastTextOut))->common.FontIndex =
DUMMY_FONT_ID;
EXTTEXTFIELD(((LPCOM_ORDER)pThisParty->LastExtTextOut))->common.
FontIndex = DUMMY_FONT_ID;
DebugExitVOID(ASShare::OD2_SyncIncoming);
}
//
// OD2_ViewEnded()
//
void ASShare::OD2_ViewEnded(ASPerson * pasPerson)
{
DebugEntry(ASShare::OD2_ViewEnded);
ValidatePerson(pasPerson);
//
// For 3.0 nodes, we can free the decode data; 3.0 senders clear theirs
// every time they host.
// For 2.x nodes, we must keep it around while they are in the share.
//
if (pasPerson->cpcCaps.general.version >= CAPS_VERSION_30)
{
OD2FreeIncoming(pasPerson);
}
else
{
TRACE_OUT(("OD2_ViewEnded: Keeping od2 data for 2.x node [%d]",
pasPerson->mcsID));
}
DebugExitVOID(ASShare::OD2_ViewEnded);
}
//
// OD2_PartyLeftShare()
// For 2.x nodes, frees the incoming OD2 data
//
void ASShare::OD2_PartyLeftShare(ASPerson * pasPerson)
{
DebugEntry(ASShare::OD2_PartyLeftShare);
ValidatePerson(pasPerson);
if (pasPerson->cpcCaps.general.version >= CAPS_VERSION_30)
{
// This should be gone!
ASSERT(pasPerson->od2Party == NULL);
}
else
{
TRACE_OUT(("OD2_PartyLeftShare: Freeing od2 data for 2.x node [%d]",
pasPerson->mcsID));
OD2FreeIncoming(pasPerson);
}
DebugExitVOID(ASShare::OD2_PartyLeftShare);
}
//
// OD2FreeIncoming()
// Frees per-party incoming OD2 resources
//
void ASShare::OD2FreeIncoming(ASPerson * pasPerson)
{
DebugEntry(OD2FreeIncoming);
if (pasPerson->od2Party != NULL)
{
if (pasPerson->od2Party->LastHFONT != NULL)
{
if (pasPerson->m_pView)
{
// For 3.0 nodes, pView won't be NULL; for 2.x nodes it may.
//
// This font might be currently selected into the DC for
// this person's desktop. Select it out.
//
SelectFont(pasPerson->m_pView->m_usrDC, (HFONT)GetStockObject(SYSTEM_FONT));
}
DeleteFont(pasPerson->od2Party->LastHFONT);
pasPerson->od2Party->LastHFONT = NULL;
}
delete pasPerson->od2Party;
pasPerson->od2Party = NULL;
}
DebugExitVOID(ASShare::OD2FreeIncoming);
}
//
// OD2_DecodeOrder()
//
LPCOM_ORDER ASShare::OD2_DecodeOrder
(
void * pEOrder,
LPUINT pLengthDecoded,
ASPerson * pasPerson
)
{
POE2ETFIELD pTableEntry;
UINT FieldChangedBits;
UINT FieldsChanged;
LPBYTE pNextDataToCopy;
RECT Rect;
LPBYTE pControlFlags;
LPTSHR_UINT32_UA pEncodingFlags;
LPSTR pEncodedOrder;
UINT numEncodingFlagBytes;
UINT encodedFieldLength;
UINT unencodedFieldLength;
UINT numReps;
UINT i;
LPBYTE pDest;
DebugEntry(ASShare::OD2_DecodeOrder);
ValidatePerson(pasPerson);
//
// Set up some local variables to access the encoding buffer in various
// ways.
//
pControlFlags = &((PDCEO2ORDER)pEOrder)->ControlFlags;
pEncodedOrder = (LPSTR)&((PDCEO2ORDER)pEOrder)->EncodedOrder[0];
pEncodingFlags = (LPTSHR_UINT32_UA)pEncodedOrder;
if ( (*pControlFlags & OE2_CF_STANDARD_ENC) == 0)
{
ERROR_OUT(("Specially encoded order received from %d", pasPerson));
return(NULL);
}
//
// If the unencoded flag is set, the order has not been encoded, so
// just return a pointer to the start of the data.
//
if ( (*pControlFlags & OE2_CF_UNENCODED) != 0)
{
//
// Convert the fields of the order header from wire format. Note
// that unencoded orders are also PRIVATE, and hence do not
// actually have the rcsDst field.
//
*pLengthDecoded = sizeof(COM_ORDER_HEADER)
+ EXTRACT_TSHR_UINT16_UA(
&(((LPCOM_ORDER_UA)pEncodedOrder)->OrderHeader.cbOrderDataLength))
+ FIELD_OFFSET(DCEO2ORDER, EncodedOrder);
TRACE_OUT(("Person [%d] Returning unencoded buffer length %u",
pasPerson->mcsID, *pLengthDecoded));
return((LPCOM_ORDER)pEncodedOrder);
}
//
// If type has changed, new type will be first byte in encoded order.
// Get pointer to last order of this type. The encoding flags follow
// this byte (if it is present).
//
if ( (*pControlFlags & OE2_CF_TYPE_CHANGE) != 0)
{
TRACE_OUT(("Person [%d] change type from %d to %d", pasPerson->mcsID,
(UINT)pasPerson->od2Party->LastOrderType,
(UINT)*(LPBYTE)pEncodedOrder));
pasPerson->od2Party->LastOrderType = *(LPTSHR_UINT8)pEncodedOrder;
pasPerson->od2Party->pLastOrder =
(LPCOM_ORDER)(pasPerson->od2Party->LastOrder[pasPerson->od2Party->LastOrderType]);
pEncodingFlags = (LPTSHR_UINT32_UA)&pEncodedOrder[1];
}
else
{
pEncodingFlags = (LPTSHR_UINT32_UA)&pEncodedOrder[0];
}
TRACE_OUT(("Person [%d] type %x", pasPerson->mcsID, pasPerson->od2Party->LastOrderType));
//
// Work out how many bytes we will need to store the encoding flags in.
// (We have a flag for each field in the order structure). This code
// we have written will cope with up to a DWORD of encoding flags.
//
numEncodingFlagBytes = (s_etable.NumFields[pasPerson->od2Party->LastOrderType]+7)/8;
if (numEncodingFlagBytes > 4)
{
ERROR_OUT(( "[%#lx] Too many flag bytes (%d) for this code",
pasPerson, numEncodingFlagBytes));
}
//
// Now we know how many bytes make up the flags we can get a pointer
// to the position at which to start encoding the orders fields into.
//
pNextDataToCopy = (LPBYTE)pEncodingFlags + numEncodingFlagBytes;
//
// Reset the flags field to zero
//
pasPerson->od2Party->pLastOrder->OrderHeader.fOrderFlags = 0;
//
// Rebuild the Order Common Header in the same order as it was
// encoded:
//
//
// If a bounding rectangle is included, copy it into the order header
//
if ( *pControlFlags & OE2_CF_BOUNDS )
{
OD2DecodeBounds((LPTSHR_UINT8*)&pNextDataToCopy,
&pasPerson->od2Party->pLastOrder->OrderHeader.rcsDst,
pasPerson);
}
//
// locate entry in encoding table for this ORDER type and extract the
// encoded order flags from the Encoded order
//
pTableEntry = s_etable.pFields[pasPerson->od2Party->LastOrderType];
FieldChangedBits = 0;
for (i=numEncodingFlagBytes; i>0; i--)
{
FieldChangedBits = FieldChangedBits << 8;
FieldChangedBits |= (UINT)((LPBYTE)pEncodingFlags)[i-1];
}
//
// We need to keep a record of which fields we change.
//
FieldsChanged = FieldChangedBits;
//
// Now decode the order: While field changed bits are non-zero
// If rightmost bit is non-zero
// copy data from the buffer to the copy of this order type
// skip to next entry in Encoding table
// shift field changed bits right one bit
//
while (FieldChangedBits != 0)
{
//
// If this field was encoded (ie changed since the last order)...
//
if ((FieldChangedBits & 1) != 0)
{
//
// Set up a pointer to the destination (unencoded) field.
//
pDest = ((LPBYTE)pasPerson->od2Party->pLastOrder)
+ pTableEntry->FieldPos
+ sizeof(COM_ORDER_HEADER);
//
// If the field type is OE2_ETF_DATA, we just copy the number
// of bytes given by the encoded length in the table.
//
if ((pTableEntry->FieldType & OE2_ETF_DATA) != 0)
{
encodedFieldLength = 1;
unencodedFieldLength = 1;
numReps = pTableEntry->FieldEncodedLen;
TRACE_OUT(("Byte data field, len %d", numReps));
}
else
{
//
// This is not a straightforward data copy. The length of
// the source and destination data is given in the table in
// the FieldEncodedLen and FieldUnencodedLen elements
// respectively.
//
encodedFieldLength = pTableEntry->FieldEncodedLen;
unencodedFieldLength = pTableEntry->FieldUnencodedLen;
if ((pTableEntry->FieldType & OE2_ETF_FIXED) != 0)
{
//
// If the field type is fixed (OE2_ETF_FIXED is set),
// we just have to decode one element of the given
// size.
//
numReps = 1;
TRACE_OUT(("Fixed fld: encoded size %d, unencoded size %d",
encodedFieldLength,
unencodedFieldLength));
}
else
{
//
// This is a variable field. The next byte to be
// decoded contains the number of BYTES of encoded data
// (not elements), so divide by the encoded field size
// to get numReps.
//
numReps = *pNextDataToCopy / encodedFieldLength;
TRACE_OUT(("Var field: encoded size %d, unencoded size " \
"%d, reps %d",
encodedFieldLength,
unencodedFieldLength,
numReps));
//
// Step past the length field in the encoded order
//
pNextDataToCopy++;
//
// For a variable length field, the unencoded version
// contains a UINT for the length (in bytes) of the
// following variable data, followed by the actual
// data. Fill in the length field in the unencoded
// order.
//
*(LPTSHR_UINT32)pDest = numReps * unencodedFieldLength;
pDest += sizeof(TSHR_UINT32);
}
}
//
// If the order was encoded using delta coordinate mode and
// this field is a coordinate then convert the coordinate from
// the single byte sized delta to a value of the size given by
// unencodedFieldLen...
//
// Note that we've already handled the leading length field of
// variable length fields above, so we don't have to worry
// about FIXED / VARIABLE issues here.
//
if ( (*pControlFlags & OE2_CF_DELTACOORDS) &&
(pTableEntry->FieldType & OE2_ETF_COORDINATES) )
{
//
// NOTE:
// numReps can be zero in the case of an EXTTEXTOUT
// order that needs the opaque rect but has no absolute
// char positioning
//
OD2CopyFromDeltaCoords((LPTSHR_INT8*)&pNextDataToCopy,
pDest,
unencodedFieldLength,
pTableEntry->FieldSigned,
numReps);
}
else
{
if ((pasPerson->od2Party->LastOrderType == OE2_POLYGON_ORDER) ||
(pasPerson->od2Party->LastOrderType == OE2_POLYBEZIER_ORDER))
{
//
// numReps can never be zero in this case
//
ASSERT(numReps);
}
OD2DecodeField(&pNextDataToCopy,
pDest,
encodedFieldLength,
unencodedFieldLength,
pTableEntry->FieldSigned,
numReps);
}
}
//
// Move on to the next field in the order structure...
//
FieldChangedBits = FieldChangedBits >> 1;
pTableEntry++;
}
//
// Check to see if we just got a font handle.
// Because of the rather nasty test against an unnamed bit in the
// FieldsChanged bits, we have a compile time check against the number
// of fields in the TEXT orders structures.
// The requirement for this code not to break is that the font handle
// field must stay as the 13th field (hence 1 << 12).
//
#if (OE2_NUM_TEXTOUT_FIELDS != 15) || (OE2_NUM_EXTTEXTOUT_FIELDS != 22)
#error code breaks if font handle not 13th field
#endif // OE2_NUM_TEXTOUT_FIELDS is 15 or 22
if (((pasPerson->od2Party->LastOrderType == OE2_EXTTEXTOUT_ORDER) &&
((FieldsChanged & (1 << 12)) ||
(EXTTEXTFIELD(((LPCOM_ORDER)pasPerson->od2Party->LastExtTextOut))->common.
FontIndex == DUMMY_FONT_ID))) ||
((pasPerson->od2Party->LastOrderType == OE2_TEXTOUT_ORDER) &&
((FieldsChanged & (1 << 12)) ||
(TEXTFIELD(((LPCOM_ORDER)pasPerson->od2Party->LastTextOut))->common.
FontIndex == DUMMY_FONT_ID))))
{
//
// This was a text order, and the font changed for it.
//
FH_ConvertAnyFontIDToLocal(pasPerson->od2Party->pLastOrder, pasPerson);
}
//
// if the OE2_CF_BOUNDS flag is not set, we have not yet constructed
// the bounding rectangle, so call OD2ReconstructBounds to do so
//
if ( (*pControlFlags & OE2_CF_BOUNDS) == 0)
{
OD2_CalculateBounds(pasPerson->od2Party->pLastOrder,
&Rect,
TRUE,
pasPerson);
pasPerson->od2Party->pLastOrder->OrderHeader.rcsDst.left
= (TSHR_INT16)Rect.left;
pasPerson->od2Party->pLastOrder->OrderHeader.rcsDst.right
= (TSHR_INT16)Rect.right;
pasPerson->od2Party->pLastOrder->OrderHeader.rcsDst.top
= (TSHR_INT16)Rect.top;
pasPerson->od2Party->pLastOrder->OrderHeader.rcsDst.bottom
= (TSHR_INT16)Rect.bottom;
pasPerson->od2Party->pLastOrder->OrderHeader.fOrderFlags |= OF_NOTCLIPPED;
}
//
// Return the decoded order length and a pointer to the order.
//
*pLengthDecoded = (UINT)(pNextDataToCopy - (LPBYTE)pEOrder);
TRACE_OUT(("Person [%d] Return decoded order length %u",
pasPerson->mcsID, *pLengthDecoded));
DebugExitPVOID(ASShare::OD2_DecodeOrder, pasPerson->od2Party->pLastOrder);
return(pasPerson->od2Party->pLastOrder);
}
//
// FUNCTION: OD2UseFont
//
// DESCRIPTION:
//
// Selects the font described by the parameters into the person's DC.
// so that we can then query the text extent etc.
// The queried metrics are available from pasPerson->od2Party->LastFontMetrics.
//
// PARAMETERS:
//
// RETURNS: TRUE if successful, FALSE otherwise.
//
//
BOOL ASShare::OD2UseFont
(
ASPerson * pasPerson,
LPSTR pName,
UINT facelength,
UINT codePage,
UINT MaxHeight,
UINT Height,
UINT Width,
UINT Weight,
UINT flags
)
{
BOOL rc = TRUE;
DebugEntry(ASShare::OD2UseFont);
ValidatePerson(pasPerson);
if ((pasPerson->od2Party->LastFontFaceLen != facelength ) ||
(memcmp((LPSTR)(pasPerson->od2Party->LastFaceName),pName,
facelength) != 0 ) ||
(pasPerson->od2Party->LastCodePage != codePage) ||
(pasPerson->od2Party->LastFontHeight != Height ) ||
(pasPerson->od2Party->LastFontWidth != Width ) ||
(pasPerson->od2Party->LastFontWeight != Weight ) ||
(pasPerson->od2Party->LastFontFlags != flags ))
{
TRACE_OUT(("Person [%d] Font %s (CP%d,w%d,h%d,f%04X,wgt%d) to %s (CP%d,w%d,h%d,f%04X,wgt%d)",
pasPerson->mcsID, pasPerson->od2Party->LastFaceName,
pasPerson->od2Party->LastCodePage, pasPerson->od2Party->LastFontWidth,
pasPerson->od2Party->LastFontHeight,
pasPerson->od2Party->LastFontFlags,
pasPerson->od2Party->LastFontWeight,
pName,
codePage,
Width,
Height,
flags,
Weight ));
memcpy(pasPerson->od2Party->LastFaceName,pName,facelength);
pasPerson->od2Party->LastFontFaceLen = facelength;
pasPerson->od2Party->LastFaceName[facelength] = '\0';
pasPerson->od2Party->LastFontHeight = Height;
pasPerson->od2Party->LastCodePage = codePage;
pasPerson->od2Party->LastFontWidth = Width;
pasPerson->od2Party->LastFontWeight = Weight;
pasPerson->od2Party->LastFontFlags = flags;
rc = USR_UseFont(pasPerson->m_pView->m_usrDC,
&pasPerson->od2Party->LastHFONT,
&pasPerson->od2Party->LastFontMetrics,
(LPSTR)pasPerson->od2Party->LastFaceName,
codePage,
MaxHeight,
Height,
Width,
Weight,
flags);
}
else
{
//
// The font hasn't changed, so LastHFONT should be the one we
// want. We must still select it in however, since several fonts
// get selected into usrDC.
//
ASSERT(pasPerson->od2Party->LastHFONT != NULL);
SelectFont(pasPerson->m_pView->m_usrDC, pasPerson->od2Party->LastHFONT);
}
DebugExitBOOL(ASShare::OD2UseFont, rc);
return(rc);
}
//
// OD2_CalculateTextOutBounds()
//
void ASShare::OD2_CalculateTextOutBounds
(
LPTEXTOUT_ORDER pTextOut,
LPRECT pRect,
BOOL fDecoding,
ASPerson * pasPerson
)
{
LPSTR pString;
int cbString;
BOOL fExtTextOut;
LPEXTTEXTOUT_ORDER pExtTextOut = NULL;
LPCOMMON_TEXTORDER pCommon;
LPSTR faceName;
UINT faceNameLength;
BOOL fFontSelected;
UINT FontIndex;
UINT width;
UINT maxFontHeight;
UINT nFontFlags;
UINT nCodePage;
DebugEntry(ASShare::OD2_CalculateTextOutBounds);
ValidatePerson(pasPerson);
//
// Workout if this is a TextOut or ExtTextOut order.
//
if (pTextOut->type == ORD_EXTTEXTOUT_TYPE)
{
fExtTextOut = TRUE;
pExtTextOut = (LPEXTTEXTOUT_ORDER)pTextOut;
pCommon = &(pExtTextOut->common);
//
// This code does not cope with calculating the bounds of an
// ExtTextOut order with a delta X array. We return a NULL
// rectangle in this case to force the OE2 code to transmit the
// bounds explicitly. However if we are decoding then we must
// calculate the rectangle (even though it may be wrong) to
// maintain backward compatability to previous versions of the
// product (R11) which did not return a NULL rect if delta-x was
// present.
//
if ( (pExtTextOut->fuOptions & ETO_LPDX)
&& (!fDecoding) )
{
TRACE_OUT(( "Delta X so return NULL rect"));
pRect->left = 0;
pRect->right = 0;
pRect->top = 0;
pRect->bottom = 0;
return;
}
}
else if (pTextOut->type == ORD_TEXTOUT_TYPE)
{
fExtTextOut = FALSE;
pCommon = &(pTextOut->common);
}
else
{
ERROR_OUT(( "{%p} Unexpected order type %x",
pasPerson, (int)pTextOut->type));
return;
}
//
// The order structures both have the variableString as their first
// variable field. If this were not the case then the code here would
// have to take into account that the encoding side packs variable
// sized fields while the decoding side does not pack them.
//
if (fExtTextOut)
{
cbString = pExtTextOut->variableString.len;
pString = (LPSTR)&pExtTextOut->variableString.string;
}
else
{
cbString = pTextOut->variableString.len;
pString = (LPSTR)&pTextOut->variableString.string;
}
FontIndex = pCommon->FontIndex;
width = pCommon->FontWidth;
//
// Get the facename from the handle, and get the various font width/
// height adjusted values.
//
faceName = FH_GetFaceNameFromLocalHandle(FontIndex,
&faceNameLength);
maxFontHeight = (UINT)FH_GetMaxHeightFromLocalHandle(FontIndex);
//
// Get the local font flags for the font, so that we can merge in any
// specific local flag information when setting up the font. The prime
// example of this is whether the local font we matched is TrueType or
// not, which information is not sent over the wire, but does need to
// be used when setting up the font - or else we may draw using a local
// fixed font of the same facename.
//
nFontFlags = FH_GetFontFlagsFromLocalHandle(FontIndex);
//
// Get the local codePage for the font.
//
nCodePage = FH_GetCodePageFromLocalHandle(FontIndex);
//
// Hosting only version does not ever decode orders.
//
//
// Select the font into the appropriate DC and query the text extent.
//
if (fDecoding)
{
fFontSelected = OD2UseFont(pasPerson,
faceName,
faceNameLength,
nCodePage,
maxFontHeight,
pCommon->FontHeight,
width,
pCommon->FontWeight,
pCommon->FontFlags
| (nFontFlags & NF_LOCAL));
if (!fFontSelected)
{
//
// We failed to select the correct font - so we cannot
// calculate the bounds correctly. However, the fact that we
// are in this routine means that on the host the text was
// unclipped. Therefore we just return a (fairly arbitrary)
// very big rect.
//
// This is far from a perfect answer (for example, it will
// force a big repaint), but allow us to keep running in a
// difficult situation (i.e. acute resource shortage).
//
pRect->left = 0;
pRect->right = 2000;
pRect->top = -2000;
pRect->bottom = 2000;
return;
}
OE_GetStringExtent(pasPerson->m_pView->m_usrDC,
&pasPerson->od2Party->LastFontMetrics,
pString, cbString, pRect );
}
else
{
ASSERT(m_pHost);
fFontSelected = m_pHost->OE2_UseFont(faceName,
(TSHR_UINT16)faceNameLength,
(TSHR_UINT16)nCodePage,
(TSHR_UINT16)maxFontHeight,
(TSHR_UINT16)pCommon->FontHeight,
(TSHR_UINT16)width,
(TSHR_UINT16)pCommon->FontWeight,
(TSHR_UINT16)(pCommon->FontFlags
| (nFontFlags & NF_LOCAL)));
if (!fFontSelected)
{
//
// We failed to select the correct font. We return a NULL
// rectangle in this case to force the OE2 code to transmit
// the bounds explicitly.
//
pRect->left = 0;
pRect->right = 0;
pRect->top = 0;
pRect->bottom = 0;
return;
}
OE_GetStringExtent(m_pHost->m_usrWorkDC, NULL, pString, cbString, pRect );
}
//
// We have a rectangle with the text extent in it relative to (0,0) so
// add in the text starting position to this to give us the bounding
// rectangle. At the same time we will convert the exclusive rect
// returned by OE_GetStringExtent to an inclusive rectangle as us
//
pRect->left += pCommon->nXStart;
pRect->right += pCommon->nXStart - 1;
pRect->top += pCommon->nYStart;
pRect->bottom += pCommon->nYStart - 1;
//
// If this is an ExtTextOut order then we must take into account the
// opaque/clipping rectangle if there is one.
//
if (fExtTextOut)
{
//
// If the rectangle is an opaque rectangle then expand the bounding
// rectangle to bound the opaque rectangle also.
//
if (pExtTextOut->fuOptions & ETO_OPAQUE)
{
pRect->left = min(pExtTextOut->rectangle.left, pRect->left);
pRect->right = max(pExtTextOut->rectangle.right,
pRect->right);
pRect->top = min(pExtTextOut->rectangle.top,
pRect->top);
pRect->bottom = max(pExtTextOut->rectangle.bottom,
pRect->bottom);
}
//
// If the rectangle is a clip rectangle then restrict the bounding
// rectangle to be within the clip rectangle.
//
if (pExtTextOut->fuOptions & ETO_CLIPPED)
{
pRect->left = max(pExtTextOut->rectangle.left,
pRect->left);
pRect->right = min(pExtTextOut->rectangle.right,
pRect->right);
pRect->top = max(pExtTextOut->rectangle.top,
pRect->top);
pRect->bottom = min(pExtTextOut->rectangle.bottom,
pRect->bottom);
}
}
DebugExitVOID(ASShare::OD2_CalculateTextOutBounds);
}
//
// OD2_CalculateBounds()
//
void ASShare::OD2_CalculateBounds
(
LPCOM_ORDER pOrder,
LPRECT pRect,
BOOL fDecoding,
ASPerson * pasPerson
)
{
UINT i;
UINT numPoints;
DebugEntry(ASShare::OD2_CalculateBounds);
ValidatePerson(pasPerson);
//
// Calculate the bounds according to the order type.
// All blts can be handled in the same way.
//
switch ( ((LPPATBLT_ORDER)pOrder->abOrderData)->type )
{
//
// Calculate bounds for the blts.
// This is the destination rectangle. Bounds are inclusive.
//
case ORD_DSTBLT_TYPE:
pRect->left =
((LPDSTBLT_ORDER)(pOrder->abOrderData))->nLeftRect;
pRect->top = ((LPDSTBLT_ORDER)(pOrder->abOrderData))->nTopRect;
pRect->right = pRect->left
+ ((LPDSTBLT_ORDER)(pOrder->abOrderData))->nWidth
- 1;
pRect->bottom = pRect->top
+ ((LPDSTBLT_ORDER)(pOrder->abOrderData))->nHeight
- 1;
break;
case ORD_PATBLT_TYPE:
pRect->left =
((LPPATBLT_ORDER)(pOrder->abOrderData))->nLeftRect;
pRect->top =
((LPPATBLT_ORDER)(pOrder->abOrderData))->nTopRect;
pRect->right =
pRect->left +
((LPPATBLT_ORDER)(pOrder->abOrderData))->nWidth - 1;
pRect->bottom =
pRect->top +
((LPPATBLT_ORDER)(pOrder->abOrderData))->nHeight - 1;
break;
case ORD_SCRBLT_TYPE:
pRect->left =
((LPSCRBLT_ORDER)(pOrder->abOrderData))->nLeftRect;
pRect->top =
((LPSCRBLT_ORDER)(pOrder->abOrderData))->nTopRect;
pRect->right =
pRect->left +
((LPSCRBLT_ORDER)(pOrder->abOrderData))->nWidth - 1;
pRect->bottom =
pRect->top +
((LPSCRBLT_ORDER)(pOrder->abOrderData))->nHeight - 1;
break;
case ORD_MEMBLT_TYPE:
pRect->left =
((LPMEMBLT_ORDER)(pOrder->abOrderData))->nLeftRect;
pRect->top =
((LPMEMBLT_ORDER)(pOrder->abOrderData))->nTopRect;
pRect->right =
pRect->left +
((LPMEMBLT_ORDER)(pOrder->abOrderData))->nWidth - 1;
pRect->bottom =
pRect->top +
((LPMEMBLT_ORDER)(pOrder->abOrderData))->nHeight - 1;
break;
case ORD_MEM3BLT_TYPE:
pRect->left =
((LPMEM3BLT_ORDER)(pOrder->abOrderData))->nLeftRect;
pRect->top =
((LPMEM3BLT_ORDER)(pOrder->abOrderData))->nTopRect;
pRect->right =
pRect->left +
((LPMEM3BLT_ORDER)(pOrder->abOrderData))->nWidth - 1;
pRect->bottom =
pRect->top +
((LPMEM3BLT_ORDER)(pOrder->abOrderData))->nHeight - 1;
break;
case ORD_MEMBLT_R2_TYPE:
pRect->left =
((LPMEMBLT_R2_ORDER)(pOrder->abOrderData))->nLeftRect;
pRect->top =
((LPMEMBLT_R2_ORDER)(pOrder->abOrderData))->nTopRect;
pRect->right =
pRect->left +
((LPMEMBLT_R2_ORDER)(pOrder->abOrderData))->nWidth - 1;
pRect->bottom =
pRect->top +
((LPMEMBLT_R2_ORDER)(pOrder->abOrderData))->nHeight - 1;
break;
case ORD_MEM3BLT_R2_TYPE:
pRect->left =
((LPMEM3BLT_R2_ORDER)(pOrder->abOrderData))->nLeftRect;
pRect->top =
((LPMEM3BLT_R2_ORDER)(pOrder->abOrderData))->nTopRect;
pRect->right =
pRect->left +
((LPMEM3BLT_R2_ORDER)(pOrder->abOrderData))->nWidth - 1;
pRect->bottom =
pRect->top +
((LPMEM3BLT_R2_ORDER)(pOrder->abOrderData))->nHeight - 1;
break;
//
// Calculate bounds for Rectangle.
// This is the rectangle itself. Bounds are inclusive.
//
case ORD_RECTANGLE_TYPE:
pRect->left =
((LPRECTANGLE_ORDER)(pOrder->abOrderData))->nLeftRect;
pRect->top =
((LPRECTANGLE_ORDER)(pOrder->abOrderData))->nTopRect;
pRect->right =
((LPRECTANGLE_ORDER)(pOrder->abOrderData))->nRightRect;
pRect->bottom =
((LPRECTANGLE_ORDER)(pOrder->abOrderData))->nBottomRect;
break;
case ORD_ROUNDRECT_TYPE:
pRect->left =
((LPROUNDRECT_ORDER)(pOrder->abOrderData))->nLeftRect;
pRect->top =
((LPROUNDRECT_ORDER)(pOrder->abOrderData))->nTopRect;
pRect->right =
((LPROUNDRECT_ORDER)(pOrder->abOrderData))->nRightRect;
pRect->bottom =
((LPROUNDRECT_ORDER)(pOrder->abOrderData))->nBottomRect;
break;
case ORD_POLYGON_TYPE:
//
// Calculate bounds for Polygon.
//
pRect->left = 0x7fff;
pRect->right = 0;
pRect->top = 0x7fff;
pRect->bottom = 0;
//
// BOGUS! LAURABU BUGBUG
//
// In NM 2.0, the wrong fields were being compared. x to top/
// bottom, and y to left/right.
//
// Effectively, this meant that we never matched the bounds
// in the rcsDst rect.
//
numPoints = ((LPPOLYGON_ORDER)(pOrder->abOrderData))->
variablePoints.len
/ sizeof(((LPPOLYGON_ORDER)(pOrder->abOrderData))->
variablePoints.aPoints[0]);
for (i = 0; i < numPoints; i++ )
{
if ( ((LPPOLYGON_ORDER)(pOrder->abOrderData))
->variablePoints.aPoints[i].y > pRect->bottom )
{
pRect->bottom = ((LPPOLYGON_ORDER)(pOrder->abOrderData))
->variablePoints.aPoints[i].y;
}
if ( ((LPPOLYGON_ORDER)(pOrder->abOrderData))
->variablePoints.aPoints[i].y < pRect->top )
{
pRect->top = ((LPPOLYGON_ORDER)(pOrder->abOrderData))
->variablePoints.aPoints[i].y;
}
if ( ((LPPOLYGON_ORDER)(pOrder->abOrderData))
->variablePoints.aPoints[i].x > pRect->right )
{
pRect->right = ((LPPOLYGON_ORDER)(pOrder->abOrderData))
->variablePoints.aPoints[i].x;
}
if ( ((LPPOLYGON_ORDER)(pOrder->abOrderData))
->variablePoints.aPoints[i].x < pRect->left )
{
pRect->left = ((LPPOLYGON_ORDER)(pOrder->abOrderData))
->variablePoints.aPoints[i].x;
}
}
TRACE_OUT(("Poly bounds: left:%d, right:%d, top:%d, bottom:%d",
pRect->left, pRect->right, pRect->top, pRect->bottom ));
break;
case ORD_PIE_TYPE:
//
// Pull out the bounding rectangle directly from the PIE order.
//
pRect->left = ((LPPIE_ORDER)(pOrder->abOrderData))->nLeftRect;
pRect->top = ((LPPIE_ORDER)(pOrder->abOrderData))->nTopRect;
pRect->right = ((LPPIE_ORDER)(pOrder->abOrderData))->nRightRect;
pRect->bottom = ((LPPIE_ORDER)(pOrder->abOrderData))->nBottomRect;
break;
case ORD_ELLIPSE_TYPE:
//
// Pull out the bounding rectangle directly from ELLIPSE order.
//
pRect->left = ((LPELLIPSE_ORDER)(pOrder->abOrderData))->nLeftRect;
pRect->top = ((LPELLIPSE_ORDER)(pOrder->abOrderData))->nTopRect;
pRect->right =
((LPELLIPSE_ORDER)(pOrder->abOrderData))->nRightRect;
pRect->bottom =
((LPELLIPSE_ORDER)(pOrder->abOrderData))->nBottomRect;
break;
case ORD_ARC_TYPE:
//
// Pull out the bounding rectangle directly from the ARC order.
//
pRect->left = ((LPARC_ORDER)(pOrder->abOrderData))->nLeftRect;
pRect->top = ((LPARC_ORDER)(pOrder->abOrderData))->nTopRect;
pRect->right = ((LPARC_ORDER)(pOrder->abOrderData))->nRightRect;
pRect->bottom = ((LPARC_ORDER)(pOrder->abOrderData))->nBottomRect;
break;
case ORD_CHORD_TYPE:
//
// Pull out the bounding rectangle directly from the CHORD
// order.
//
pRect->left = ((LPCHORD_ORDER)(pOrder->abOrderData))->nLeftRect;
pRect->top = ((LPCHORD_ORDER)(pOrder->abOrderData))->nTopRect;
pRect->right = ((LPCHORD_ORDER)(pOrder->abOrderData))->nRightRect;
pRect->bottom =
((LPCHORD_ORDER)(pOrder->abOrderData))->nBottomRect;
break;
case ORD_POLYBEZIER_TYPE:
//
// Calculate bounds for PolyBezier.
//
pRect->left = 0x7fff;
pRect->right = 0;
pRect->top = 0x7fff;
pRect->bottom = 0;
numPoints = ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))->
variablePoints.len
/ sizeof(((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))->
variablePoints.aPoints[0]);
//
// BOGUS! LAURABU BUGBUG
//
// In NM 2.0, the wrong fields were being compared. x to top/
// bottom, and y to left/right.
//
// Effectively, this meant that we never matched the bounds
// in the rcsDst rect.
//
for (i = 0; i < numPoints; i++ )
{
if ( ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))
->variablePoints.aPoints[i].y > pRect->bottom )
{
pRect->bottom = ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))
->variablePoints.aPoints[i].y;
}
if ( ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))
->variablePoints.aPoints[i].y < pRect->top )
{
pRect->top = ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))
->variablePoints.aPoints[i].y;
}
if ( ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))
->variablePoints.aPoints[i].x > pRect->right )
{
pRect->right = ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))
->variablePoints.aPoints[i].x;
}
if ( ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))
->variablePoints.aPoints[i].x < pRect->left )
{
pRect->left = ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))
->variablePoints.aPoints[i].x;
}
}
TRACE_OUT((
"PolyBezier bounds: left:%d, right:%d, top:%d, bot:%d",
pRect->left, pRect->right, pRect->top, pRect->bottom));
break;
case ORD_LINETO_TYPE:
//
// Calculate bounds for LineTo. This is the rectangle with
// opposite vertices on the start and end points of the line.
// The gradient of the line determines whether the start or end
// point provides the top or bottom, left or right of the
// rectangle. Bounds are inclusive.
//
if ( ((LPLINETO_ORDER)(pOrder->abOrderData))->nXStart <
((LPLINETO_ORDER)(pOrder->abOrderData))->nXEnd )
{
pRect->left =
((LPLINETO_ORDER)(pOrder->abOrderData))->nXStart;
pRect->right =
((LPLINETO_ORDER)(pOrder->abOrderData))->nXEnd;
}
else
{
pRect->right =
((LPLINETO_ORDER)pOrder->abOrderData)->nXStart;
pRect->left =
((LPLINETO_ORDER)pOrder->abOrderData)->nXEnd;
}
if ( ((LPLINETO_ORDER)pOrder->abOrderData)->nYStart <
((LPLINETO_ORDER)pOrder->abOrderData)->nYEnd )
{
pRect->top =
((LPLINETO_ORDER)pOrder->abOrderData)->nYStart;
pRect->bottom =
((LPLINETO_ORDER)pOrder->abOrderData)->nYEnd;
}
else
{
pRect->bottom =
((LPLINETO_ORDER)pOrder->abOrderData)->nYStart;
pRect->top =
((LPLINETO_ORDER)pOrder->abOrderData)->nYEnd;
}
break;
case ORD_OPAQUERECT_TYPE:
//
// Calculate bounds for OpaqueRect. This is the rectangle
// itself. Bounds are inclusive.
//
pRect->left =
((LPOPAQUERECT_ORDER)(pOrder->abOrderData))->nLeftRect;
pRect->top =
((LPOPAQUERECT_ORDER)(pOrder->abOrderData))->nTopRect;
pRect->right =
pRect->left +
((LPOPAQUERECT_ORDER)(pOrder->abOrderData))->nWidth - 1;
pRect->bottom =
pRect->top +
((LPOPAQUERECT_ORDER)(pOrder->abOrderData))->nHeight - 1;
break;
case ORD_SAVEBITMAP_TYPE:
//
// Calculate bounds for SaveBitmap. This is the rectangle
// itself. Bounds are inclusive.
//
pRect->left =
((LPSAVEBITMAP_ORDER)(pOrder->abOrderData))->nLeftRect;
pRect->top =
((LPSAVEBITMAP_ORDER)(pOrder->abOrderData))->nTopRect;
pRect->bottom =
((LPSAVEBITMAP_ORDER)(pOrder->abOrderData))->nBottomRect;
pRect->right =
((LPSAVEBITMAP_ORDER)(pOrder->abOrderData))->nRightRect;
break;
case ORD_TEXTOUT_TYPE:
case ORD_EXTTEXTOUT_TYPE:
//
// TextOut and ExtTextOut bounds calculations are done by the
// OD2_CalculateTextOutBounds function.
//
OD2_CalculateTextOutBounds((LPTEXTOUT_ORDER)pOrder->abOrderData,
pRect,
fDecoding,
pasPerson);
break;
case ORD_DESKSCROLL_TYPE:
pRect->left = 0;
pRect->top = 0;
pRect->right = 0;
pRect->bottom = 0;
break;
default:
ERROR_OUT((
"{%p} unrecognized type passed to OD2ReconstructBounds: %d",
pasPerson,
(int)((LPPATBLT_ORDER)pOrder->abOrderData)->type));
break;
}
DebugExitVOID(ASShare::OD2_CalculateBounds);
}
//
// OD2DecodeBounds()
//
void ASShare::OD2DecodeBounds
(
LPBYTE* ppNextDataToCopy,
LPTSHR_RECT16 pRect,
ASPerson * pasPerson
)
{
LPBYTE pFlags;
DebugEntry(ASShare::OD2DecodeBounds);
ValidatePerson(pasPerson);
//
// The encoding used is a byte of flags followed by a variable number
// of 16bit coordinate values and 8bit delta coordinate values (which
// may be interleaved).
//
//
// The first byte of the encoding will contain the flags that represent
// how the coordinates of the rectangle were encoded.
//
pFlags = *ppNextDataToCopy;
(*ppNextDataToCopy)++;
//
// Initialise the rectangle with the last decoded coordinates.
//
*pRect = pasPerson->od2Party->LastBounds;
//
// If the flags indicate that none of the coordinates have changed then
// fast path and exit now.
//
if (*pFlags == 0)
{
return;
}
//
// For each of the four coordinate values in the rectangle: If the
// coordinate was encoded as an 8bit delta then add on the delta to the
// previous value. If the coordinate was encoded as a 16bit value
// then copy the value across. Otherwise the coordinate was the same
// as the previous one so leave it alone.
//
if (*pFlags & OE2_BCF_DELTA_LEFT)
{
OD2CopyFromDeltaCoords((LPTSHR_INT8*)ppNextDataToCopy,
&pRect->left,
sizeof(pRect->left),
TRUE, // The value is signed
1);
}
else if (*pFlags & OE2_BCF_LEFT)
{
pRect->left = EXTRACT_TSHR_INT16_UA(*ppNextDataToCopy);
(*ppNextDataToCopy) += sizeof(TSHR_INT16);
}
if (*pFlags & OE2_BCF_DELTA_TOP)
{
OD2CopyFromDeltaCoords((LPTSHR_INT8*)ppNextDataToCopy,
&pRect->top,
sizeof(pRect->top),
TRUE, // The value is signed
1);
}
else if (*pFlags & OE2_BCF_TOP)
{
pRect->top = EXTRACT_TSHR_INT16_UA(*ppNextDataToCopy);
(*ppNextDataToCopy) += sizeof(TSHR_INT16);
}
if (*pFlags & OE2_BCF_DELTA_RIGHT)
{
OD2CopyFromDeltaCoords((LPTSHR_INT8*)ppNextDataToCopy,
&pRect->right,
sizeof(pRect->right),
TRUE, // The value is signed
1);
}
else if (*pFlags & OE2_BCF_RIGHT)
{
pRect->right = EXTRACT_TSHR_INT16_UA(*ppNextDataToCopy);
(*ppNextDataToCopy) += sizeof(TSHR_INT16);
}
if (*pFlags & OE2_BCF_DELTA_BOTTOM)
{
OD2CopyFromDeltaCoords((LPTSHR_INT8*)ppNextDataToCopy,
&pRect->bottom,
sizeof(pRect->bottom),
TRUE, // The value is signed
1);
}
else if (*pFlags & OE2_BCF_BOTTOM)
{
pRect->bottom = EXTRACT_TSHR_INT16_UA(*ppNextDataToCopy);
(*ppNextDataToCopy) += sizeof(TSHR_INT16);
}
//
// Copy the rectangle for reference with the next encoding.
//
pasPerson->od2Party->LastBounds = *pRect;
DebugExitVOID(ASShare::OD2DecodeBounds);
}
//
// Copy an array of source elements to an array of destination elements,
// converting the types as the copy takes place.
//
// DESTARRAY - The destination array
// SRCARRAY - The source array
// DESTTYPE - The type of the elements in the destination array
// NUMELEMENTS - The number of elements in the array
//
//
#define CONVERT_ARRAY(DESTARRAY, SRCARRAY, DESTTYPE, NUMELEMENTS) \
{ \
UINT index; \
for (index=0 ; index<(NUMELEMENTS) ; index++) \
{ \
(DESTARRAY)[index] = (DESTTYPE)(SRCARRAY)[index]; \
} \
}
//
// Copy an array of source elements to an array of destination elements,
// converting the types as the copy takes place. This version allows for
// unaligned INT16 pointers
//
// DESTARRAY - The destination array
// SRCARRAY - The source array
// DESTTYPE - The type of the elements in the destination array
// NUMELEMENTS - The number of elements in the array
//
//
#define CONVERT_ARRAY_INT16_UA(DESTARRAY, SRCARRAY, DESTTYPE, NUMELEMENTS) \
{ \
UINT index; \
TSHR_INT16 value; \
for (index=0 ; index<(NUMELEMENTS) ; index++) \
{ \
value = EXTRACT_TSHR_INT16_UA((SRCARRAY)+index); \
(DESTARRAY)[index] = (DESTTYPE)value; \
} \
}
//
// Copy an array of source elements to an array of destination elements,
// converting the types as the copy takes place. This version allows for
// unaligned TSHR_UINT16 pointers
//
// DESTARRAY - The destination array
// SRCARRAY - The source array
// DESTTYPE - The type of the elements in the destination array
// NUMELEMENTS - The number of elements in the array
//
//
#define CONVERT_ARRAY_UINT16_UA(DESTARRAY, SRCARRAY, DESTTYPE, NUMELEMENTS) \
{ \
UINT index; \
TSHR_UINT16 value; \
for (index=0 ; index<(NUMELEMENTS) ; index++) \
{ \
value = EXTRACT_TSHR_UINT16_UA((SRCARRAY)+index); \
(DESTARRAY)[index] = (DESTTYPE)((TSHR_INT16)value); \
} \
}
//
// OD2DecodeField()
//
void ASShare::OD2DecodeField
(
LPBYTE* ppSrc,
LPVOID pDst,
UINT cbSrcField,
UINT cbDstField,
BOOL fSigned,
UINT numElements
)
{
LPTSHR_UINT8 pDst8 = (LPTSHR_UINT8)pDst;
LPTSHR_INT16 pDst16Signed = (LPTSHR_INT16)pDst;
LPTSHR_INT32 pDst32Signed = (LPTSHR_INT32)pDst;
LPTSHR_UINT16 pDst16Unsigned = (LPTSHR_UINT16)pDst;
LPTSHR_UINT32 pDst32Unsigned = (LPTSHR_UINT32)pDst;
LPTSHR_INT8 pSrc8Signed = (LPTSHR_INT8)*ppSrc;
LPTSHR_UINT8 pSrc8Unsigned = (LPTSHR_UINT8)*ppSrc;
LPTSHR_INT16_UA pSrc16Signed = (LPTSHR_INT16_UA)*ppSrc;
LPTSHR_UINT16_UA pSrc16Unsigned = (LPTSHR_UINT16_UA)*ppSrc;
//
// Note that the source fields may not be aligned correctly, so we use
// unaligned pointers. The destination is aligned correctly.
//
DebugEntry(ASShare::OD2DecodeField);
//
// Make sure that the destination field length is larger or equal to
// the source field length. If it isn't, something has gone wrong.
//
if (cbDstField < cbSrcField)
{
ERROR_OUT(( "Source field length %d is larger than destination %d",
cbSrcField,
cbDstField));
DC_QUIT;
}
//
// If the source and destination field lengths are the same, we can
// just do a copy (no type conversion required).
//
if (cbSrcField == cbDstField)
{
memcpy(pDst8, *ppSrc, cbDstField * numElements);
}
else
{
//
// We know that cbDstField must be greater than cbSrcField
// because of our checks above. So there are only three
// conversions to consider:
//
// 8 bit -> 16 bit
// 8 bit -> 32 bit
// 16 bit -> 32 bit
//
// We also have to get the signed / unsigned attributes correct. If
// we try to promote a signed value using unsigned pointers, we
// will get the wrong result.
//
// e.g. Consider converting the value -1 from a TSHR_INT16 to TSHR_INT32
// using unsigned pointers.
//
// -1 -> TSHR_UINT16 == 65535
// -> UINT == 65535
// -> TSHR_INT32 == 65535
//
//
if ((cbDstField == 4) && (cbSrcField == 1))
{
if (fSigned)
{
CONVERT_ARRAY(pDst32Signed,
pSrc8Signed,
TSHR_INT32,
numElements);
}
else
{
CONVERT_ARRAY(pDst32Unsigned,
pSrc8Unsigned,
TSHR_UINT32,
numElements);
}
}
else if ((cbDstField == 4) && (cbSrcField == 2))
{
if (fSigned)
{
CONVERT_ARRAY_INT16_UA(pDst32Signed,
pSrc16Signed,
TSHR_INT32,
numElements);
}
else
{
CONVERT_ARRAY_UINT16_UA(pDst32Unsigned,
pSrc16Unsigned,
TSHR_UINT32,
numElements);
}
}
else if ((cbDstField == 2) && (cbSrcField == 1))
{
if (fSigned)
{
CONVERT_ARRAY(pDst16Signed,
pSrc8Signed,
TSHR_INT16,
numElements);
}
else
{
CONVERT_ARRAY(pDst16Unsigned,
pSrc8Unsigned,
TSHR_UINT16,
numElements);
}
}
else
{
ERROR_OUT(( "Bad conversion, dest length = %d, src length = %d",
cbDstField,
cbSrcField));
}
}
DC_EXIT_POINT:
*ppSrc += cbSrcField * numElements;
DebugExitVOID(ASShare::OD2DecodeField);
}
//
// Given two arrays, a source array and an array of deltas, add each delta
// to the corresponding element in the source array, storing the results in
// the source array.
//
// srcArray - The array of source values
// srcArrayType - The type of the array of source values
// deltaArray - The array of deltas
// numElements - The number of elements in the arrays
//
//
#define COPY_DELTA_ARRAY(srcArray, srcArrayType, deltaArray, numElements) \
{ \
UINT index; \
for (index = 0; index < (numElements); index++) \
{ \
(srcArray)[index] = (srcArrayType) \
((srcArray)[index] + (deltaArray)[index]); \
} \
}
//
// OD2CopyFromDeltaCoords()
//
void ASShare::OD2CopyFromDeltaCoords
(
LPTSHR_INT8* ppSrc,
LPVOID pDst,
UINT cbDstField,
BOOL fSigned,
UINT numElements
)
{
LPTSHR_INT8 pDst8Signed = (LPTSHR_INT8)pDst;
LPTSHR_INT16 pDst16Signed = (LPTSHR_INT16)pDst;
LPTSHR_INT32 pDst32Signed = (LPTSHR_INT32)pDst;
LPTSHR_UINT8 pDst8Unsigned = (LPTSHR_UINT8)pDst;
LPTSHR_UINT16 pDst16Unsigned = (LPTSHR_UINT16)pDst;
LPTSHR_UINT32 pDst32Unsigned = (LPTSHR_UINT32)pDst;
DebugEntry(ASShare::OD2CopyFromDeltaCoords);
switch (cbDstField)
{
case 1:
if (fSigned)
{
COPY_DELTA_ARRAY(pDst8Signed, TSHR_INT8, *ppSrc, numElements);
}
else
{
COPY_DELTA_ARRAY(pDst8Unsigned, TSHR_UINT8, *ppSrc, numElements);
}
break;
case 2:
if (fSigned)
{
COPY_DELTA_ARRAY(pDst16Signed, TSHR_INT16, *ppSrc, numElements);
}
else
{
COPY_DELTA_ARRAY(pDst16Unsigned, TSHR_UINT16, *ppSrc, numElements);
}
break;
case 4:
if (fSigned)
{
COPY_DELTA_ARRAY(pDst32Signed, TSHR_INT32, *ppSrc, numElements);
}
else
{
COPY_DELTA_ARRAY(pDst32Unsigned, TSHR_UINT32, *ppSrc, numElements);
}
break;
default:
ERROR_OUT(( "Bad destination field length %d",
cbDstField));
DC_QUIT;
// break;
}
DC_EXIT_POINT:
*ppSrc += numElements;
DebugExitVOID(ASShare::OD2CopyFromDeltaCoords);
}