mirror of
https://github.com/microsoft/Microsoft-3D-Movie-Maker.git
synced 2024-11-22 10:22:40 +01:00
677 lines
13 KiB
C++
677 lines
13 KiB
C++
|
/* Copyright (c) Microsoft Corporation.
|
||
|
Licensed under the MIT License. */
|
||
|
|
||
|
/***************************************************************************
|
||
|
Author: ShonK
|
||
|
Project: Kauai
|
||
|
Reviewed:
|
||
|
Copyright (c) Microsoft Corporation
|
||
|
|
||
|
Data movement routines.
|
||
|
WARNING: Must be in a fixed (pre-loaded) seg on Mac.
|
||
|
|
||
|
***************************************************************************/
|
||
|
#include "util.h"
|
||
|
ASSERTNAME
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
Fill a block with a specific byte value.
|
||
|
***************************************************************************/
|
||
|
void FillPb(void *pv, long cb, byte b)
|
||
|
{
|
||
|
AssertIn(cb, 0, kcbMax);
|
||
|
AssertPvCb(pv, cb);
|
||
|
|
||
|
#ifdef IN_80386
|
||
|
|
||
|
__asm
|
||
|
{
|
||
|
// Setup the registers for using REP STOS instruction to set memory.
|
||
|
// NOTE: Alignment does not effect the speed of STOS.
|
||
|
//
|
||
|
// edi -> memory to set
|
||
|
// eax = value to store in destination
|
||
|
// direction flag is clear for auto-increment
|
||
|
|
||
|
mov edi,pv
|
||
|
mov al,b
|
||
|
|
||
|
// set the longs
|
||
|
mov ecx,cb
|
||
|
shr ecx,2
|
||
|
jz LBytes
|
||
|
|
||
|
shl eax,8
|
||
|
mov al,b
|
||
|
mov ebx,eax
|
||
|
shl eax,16
|
||
|
mov ax,bx
|
||
|
|
||
|
rep stosd
|
||
|
|
||
|
// set the extra bytes
|
||
|
LBytes:
|
||
|
mov ecx,cb
|
||
|
and ecx,3
|
||
|
rep stosb
|
||
|
}
|
||
|
|
||
|
#else //!IN_80386
|
||
|
|
||
|
byte *pb;
|
||
|
|
||
|
for (pb = (byte *)pv; cb != 0; cb--)
|
||
|
*pb++ = b;
|
||
|
|
||
|
#endif //!IN_80386
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
Clear a block.
|
||
|
***************************************************************************/
|
||
|
void ClearPb(void *pv, long cb)
|
||
|
{
|
||
|
AssertIn(cb, 0, kcbMax);
|
||
|
AssertPvCb(pv, cb);
|
||
|
|
||
|
#ifdef IN_80386
|
||
|
|
||
|
__asm
|
||
|
{
|
||
|
// Setup the registers for using REP STOS instruction to set memory.
|
||
|
// NOTE: Alignment does not effect the speed of STOS.
|
||
|
//
|
||
|
// edi -> memory to set
|
||
|
// eax = value to store in destination
|
||
|
// direction flag is clear for auto-increment
|
||
|
|
||
|
mov edi,pv
|
||
|
xor eax,eax
|
||
|
|
||
|
// clear the longs
|
||
|
mov ecx,cb
|
||
|
shr ecx,2
|
||
|
rep stosd
|
||
|
|
||
|
// clear the extra bytes
|
||
|
mov ecx,cb
|
||
|
and ecx,3
|
||
|
rep stosb
|
||
|
}
|
||
|
|
||
|
#else //!IN_80386
|
||
|
|
||
|
byte *pb;
|
||
|
|
||
|
for (pb = (byte *)pv; cb != 0; cb--)
|
||
|
*pb++ = 0;
|
||
|
|
||
|
#endif //!IN_80386
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
Reverse a block. Useful for exchanging two blocks or avoiding
|
||
|
recursion.
|
||
|
***************************************************************************/
|
||
|
void ReversePb(void *pv, long cb)
|
||
|
{
|
||
|
AssertIn(cb, 0, kcbMax);
|
||
|
AssertPvCb(pv, cb);
|
||
|
|
||
|
#ifdef IN_80386
|
||
|
|
||
|
__asm
|
||
|
{
|
||
|
// esi - high end of block
|
||
|
// edi - low end of block
|
||
|
// ecx - number of bytes to swap
|
||
|
|
||
|
mov edi,pv
|
||
|
mov esi,edi
|
||
|
add esi,cb
|
||
|
mov ecx,cb
|
||
|
shr ecx,1
|
||
|
|
||
|
or ecx,ecx
|
||
|
jz LDone
|
||
|
|
||
|
LLoop:
|
||
|
dec esi
|
||
|
mov al,[edi]
|
||
|
mov bl,[esi]
|
||
|
mov [edi],bl
|
||
|
mov [esi],al
|
||
|
|
||
|
inc edi
|
||
|
dec ecx
|
||
|
jnz LLoop
|
||
|
LDone:
|
||
|
}
|
||
|
|
||
|
#else //!IN_80386
|
||
|
|
||
|
byte *pb1, *pb2;
|
||
|
byte b;
|
||
|
|
||
|
for (pb2 = (pb1 = (byte *)pv) + cb - 1; pb1 < pb2; )
|
||
|
{
|
||
|
b = *pb1;
|
||
|
*pb1++ = *pb2;
|
||
|
*pb2-- = b;
|
||
|
}
|
||
|
|
||
|
#endif //!IN_80386
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
Reverse a list of shorts.
|
||
|
***************************************************************************/
|
||
|
void ReverseRgsw(void *pv, long csw)
|
||
|
{
|
||
|
AssertIn(csw, 0, kcbMax);
|
||
|
AssertPvCb(pv, csw * size(short));
|
||
|
|
||
|
#ifdef IN_80386
|
||
|
|
||
|
__asm
|
||
|
{
|
||
|
// esi - high end of block
|
||
|
// edi - low end of block
|
||
|
// ecx - number of shorts to swap
|
||
|
|
||
|
mov edi,pv
|
||
|
mov esi,edi
|
||
|
mov ecx,csw
|
||
|
shl ecx,1
|
||
|
add esi,ecx
|
||
|
shr ecx,2
|
||
|
|
||
|
or ecx,ecx
|
||
|
jz LDone
|
||
|
|
||
|
LLoop:
|
||
|
sub esi,2
|
||
|
mov ax,[edi]
|
||
|
mov bx,[esi]
|
||
|
mov [edi],bx
|
||
|
mov [esi],ax
|
||
|
|
||
|
add edi,2
|
||
|
dec ecx
|
||
|
jnz LLoop
|
||
|
LDone:
|
||
|
}
|
||
|
|
||
|
#else //!IN_80386
|
||
|
|
||
|
long *psw1, *psw2;
|
||
|
long sw;
|
||
|
|
||
|
for (psw2 = (psw1 = (short *)pv) + csw - 1; psw1 < psw2; )
|
||
|
{
|
||
|
sw = *psw1;
|
||
|
*psw1++ = *psw2;
|
||
|
*psw2-- = sw;
|
||
|
}
|
||
|
|
||
|
#endif //!IN_80386
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
Reverse a list of longs.
|
||
|
***************************************************************************/
|
||
|
void ReverseRglw(void *pv, long clw)
|
||
|
{
|
||
|
AssertIn(clw, 0, kcbMax);
|
||
|
AssertPvCb(pv, clw * size(long));
|
||
|
|
||
|
#ifdef IN_80386
|
||
|
|
||
|
__asm
|
||
|
{
|
||
|
// esi - high end of block
|
||
|
// edi - low end of block
|
||
|
// ecx - number of longs to swap
|
||
|
|
||
|
mov edi,pv
|
||
|
mov esi,edi
|
||
|
mov ecx,clw
|
||
|
shl ecx,2
|
||
|
add esi,ecx
|
||
|
shr ecx,3
|
||
|
|
||
|
or ecx,ecx
|
||
|
jz LDone
|
||
|
|
||
|
LLoop:
|
||
|
sub esi,4
|
||
|
mov eax,[edi]
|
||
|
mov ebx,[esi]
|
||
|
mov [edi],ebx
|
||
|
mov [esi],eax
|
||
|
|
||
|
add edi,4
|
||
|
dec ecx
|
||
|
jnz LLoop
|
||
|
LDone:
|
||
|
}
|
||
|
|
||
|
#else //!IN_80386
|
||
|
|
||
|
long *plw1, *plw2;
|
||
|
long lw;
|
||
|
|
||
|
for (plw2 = (plw1 = (long *)pv) + clw - 1; plw1 < plw2; )
|
||
|
{
|
||
|
lw = *plw1;
|
||
|
*plw1++ = *plw2;
|
||
|
*plw2-- = lw;
|
||
|
}
|
||
|
|
||
|
#endif //!IN_80386
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
Swap two adjacent blocks of size cb1 and cb2 respectively.
|
||
|
***************************************************************************/
|
||
|
void SwapBlocks(void *pv, long cb1, long cb2)
|
||
|
{
|
||
|
AssertIn(cb1, 0, kcbMax);
|
||
|
AssertIn(cb2, 0, kcbMax);
|
||
|
AssertPvCb(pv, cb1 + cb2);
|
||
|
|
||
|
ReversePb(pv, cb1);
|
||
|
ReversePb(PvAddBv(pv, cb1), cb2);
|
||
|
ReversePb(pv, cb1 + cb2);
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
Swap the contents of two blocks of the same size.
|
||
|
***************************************************************************/
|
||
|
void SwapPb(void *pv1, void *pv2, long cb)
|
||
|
{
|
||
|
AssertPvCb(pv1, cb);
|
||
|
AssertPvCb(pv2, cb);
|
||
|
AssertIn(cb, 0, kcbMax);
|
||
|
|
||
|
#ifdef IN_80386
|
||
|
|
||
|
__asm
|
||
|
{
|
||
|
// edi -> memory to swap, first pointer
|
||
|
// esi -> memory to swap, second pointer
|
||
|
|
||
|
mov edi,pv1
|
||
|
mov esi,pv2
|
||
|
|
||
|
mov ecx,cb
|
||
|
shr ecx,2
|
||
|
jz LBytes
|
||
|
|
||
|
LLongLoop:
|
||
|
mov eax,[edi]
|
||
|
mov ebx,[esi]
|
||
|
mov [edi],ebx
|
||
|
mov [esi],eax
|
||
|
|
||
|
add edi,4
|
||
|
add esi,4
|
||
|
dec ecx
|
||
|
jnz LLongLoop;
|
||
|
|
||
|
LBytes:
|
||
|
mov ecx,cb
|
||
|
and ecx,3
|
||
|
jz LDone
|
||
|
|
||
|
LByteLoop:
|
||
|
mov al,[edi]
|
||
|
mov bl,[esi]
|
||
|
mov [edi],bl
|
||
|
mov [esi],al
|
||
|
inc edi
|
||
|
inc esi
|
||
|
dec ecx
|
||
|
jnz LByteLoop
|
||
|
|
||
|
LDone:
|
||
|
}
|
||
|
|
||
|
#else //!IN_80386
|
||
|
|
||
|
byte *pb1 = (byte *)pv1;
|
||
|
byte *pb2 = (byte *)pv2;
|
||
|
byte b;
|
||
|
|
||
|
Assert(pb1 + cb <= pb2 || pb2 + cb <= pb1, "blocks overlap");
|
||
|
while (cb-- > 0)
|
||
|
{
|
||
|
b = *pb1;
|
||
|
*pb1++ = *pb2;
|
||
|
*pb2++ = b;
|
||
|
}
|
||
|
|
||
|
#endif //!IN_80386
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
Move the entry at ivSrc to be immediately before the element that is
|
||
|
currently at ivTarget. If ivTarget > ivSrc, the entry actually ends
|
||
|
up at (ivTarget - 1) and the entry at ivTarget doesn't move. If
|
||
|
ivTarget < ivSrc, the entry ends up at ivTarget and the entry at
|
||
|
ivTarget moves to (ivTarget + 1). Everything in between is shifted
|
||
|
appropriately. prgv is the array of elements and cbElement is the
|
||
|
size of each element.
|
||
|
***************************************************************************/
|
||
|
void MoveElement(void *prgv, long cbElement, long ivSrc, long ivTarget)
|
||
|
{
|
||
|
AssertIn(cbElement, 0, kcbMax);
|
||
|
AssertIn(ivSrc, 0, kcbMax);
|
||
|
AssertIn(ivTarget, 0, kcbMax);
|
||
|
AssertPvCb(prgv, LwMul(cbElement, ivSrc + 1));
|
||
|
AssertPvCb(prgv, LwMul(cbElement, ivTarget));
|
||
|
|
||
|
if (ivTarget == ivSrc || ivTarget == ivSrc + 1)
|
||
|
return;
|
||
|
|
||
|
//swap the blocks
|
||
|
if (ivSrc < ivTarget)
|
||
|
{
|
||
|
SwapBlocks(PvAddBv(prgv, LwMul(ivSrc, cbElement)),
|
||
|
cbElement, LwMul(ivTarget - 1 - ivSrc, cbElement));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SwapBlocks(PvAddBv(prgv, LwMul(ivTarget, cbElement)),
|
||
|
LwMul(ivSrc - ivTarget, cbElement), cbElement);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
Check for equality of two blocks.
|
||
|
***************************************************************************/
|
||
|
bool FEqualRgb(void *pv1, void *pv2, long cb)
|
||
|
{
|
||
|
AssertIn(cb, 0, kcbMax);
|
||
|
AssertPvCb(pv1, cb);
|
||
|
AssertPvCb(pv2, cb);
|
||
|
|
||
|
#ifdef IN_80386
|
||
|
|
||
|
bool fRet;
|
||
|
|
||
|
__asm
|
||
|
{
|
||
|
// edi -> memory to compare, first pointer
|
||
|
// esi -> memory to compare, second pointer
|
||
|
|
||
|
xor eax,eax //assume false return
|
||
|
mov edi,pv1
|
||
|
mov esi,pv2
|
||
|
|
||
|
// compare longs
|
||
|
mov ecx,cb // (ecx) = length in bytes
|
||
|
shr ecx,2 // (ecx) = length in longs
|
||
|
repe cmpsd // compare longs
|
||
|
jnz LDone // mismatch, go report
|
||
|
|
||
|
// compare extra bytes
|
||
|
mov ecx,cb
|
||
|
and ecx,3 // (ecx) = length mod 4
|
||
|
repe cmpsb // compare odd bytes
|
||
|
jnz LDone // mismatch, go report
|
||
|
|
||
|
inc eax // successful compare
|
||
|
|
||
|
LDone:
|
||
|
mov fRet,eax
|
||
|
}
|
||
|
|
||
|
return fRet;
|
||
|
|
||
|
#else //!IN_80386
|
||
|
|
||
|
byte *pb1 = (byte *)pv1;
|
||
|
byte *pb2 = (byte *)pv2;
|
||
|
|
||
|
while (cb != 0 && *pb1++ == *pb2++)
|
||
|
cb--;
|
||
|
return cb == 0;
|
||
|
|
||
|
#endif //!IN_80386
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
Compare the two buffers byte for byte and return a the number of bytes
|
||
|
that match.
|
||
|
***************************************************************************/
|
||
|
long CbEqualRgb(void *pv1, void *pv2, long cb)
|
||
|
{
|
||
|
AssertIn(cb, 0, kcbMax);
|
||
|
AssertPvCb(pv1, cb);
|
||
|
AssertPvCb(pv2, cb);
|
||
|
|
||
|
#ifdef IN_80386
|
||
|
|
||
|
byte *pb;
|
||
|
|
||
|
__asm
|
||
|
{
|
||
|
// edi -> memory to swap, first pointer
|
||
|
// esi -> memory to swap, second pointer
|
||
|
|
||
|
mov edi,pv1
|
||
|
mov esi,pv2
|
||
|
|
||
|
// compare extra bytes.
|
||
|
mov ecx,cb
|
||
|
and ecx,3 // (ecx) = length mod 4
|
||
|
repe cmpsb // compare odd bytes
|
||
|
jnz LMiss // mismatch, go report how far we got
|
||
|
|
||
|
// compare longs
|
||
|
mov ecx,cb // (ecx) = length in bytes
|
||
|
shr ecx,2 // (ecx) = length in longs
|
||
|
repe cmpsd // compare longs
|
||
|
jz LHit // matched all the way
|
||
|
|
||
|
// esi (and edi) points to the long after the one which caused the
|
||
|
// mismatch. Back up 1 long and find the byte. Since we know the
|
||
|
// long didn't match, we can assume one of the bytes won't.
|
||
|
sub esi,4 // back up
|
||
|
sub edi,4 // back up
|
||
|
mov ecx,5 // ensure that ecx doesn't count out
|
||
|
repe cmpsb // find mismatch byte
|
||
|
|
||
|
// esi points to the byte after the one that did not match.
|
||
|
LMiss:
|
||
|
dec esi
|
||
|
dec edi
|
||
|
mov pb,edi
|
||
|
}
|
||
|
|
||
|
return pb - (byte *)pv1;
|
||
|
|
||
|
LHit:
|
||
|
// We matched all the way to the end.
|
||
|
return cb;
|
||
|
|
||
|
#else //!IN_80386
|
||
|
|
||
|
byte *pb1 = (byte *)pv1;
|
||
|
byte *pb2 = (byte *)pv2;
|
||
|
|
||
|
for ( ; cb-- > 0 && *pb1 == *pb2; pb1++, pb2++)
|
||
|
;
|
||
|
return pb1 - (byte *)pv1;
|
||
|
|
||
|
#endif //!IN_80386
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
Compare the two buffers byte for byte and return an fcmp indicating
|
||
|
their relationship to each other.
|
||
|
***************************************************************************/
|
||
|
ulong FcmpCompareRgb(void *pv1, void *pv2, long cb)
|
||
|
{
|
||
|
AssertIn(cb, 0, kcbMax);
|
||
|
AssertPvCb(pv1, cb);
|
||
|
AssertPvCb(pv2, cb);
|
||
|
|
||
|
long cbMatch = CbEqualRgb(pv1, pv2, cb);
|
||
|
|
||
|
AssertIn(cbMatch, 0, cb + 1);
|
||
|
if (cb == cbMatch)
|
||
|
return fcmpEq;
|
||
|
|
||
|
return ((byte *)pv1)[cbMatch] < ((byte *)pv2)[cbMatch] ? fcmpLt : fcmpGt;
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
Copy data without overlap.
|
||
|
****************************************************************************/
|
||
|
void CopyPb(void *pv1, void *pv2, long cb)
|
||
|
{
|
||
|
AssertIn(cb, 0, kcbMax);
|
||
|
AssertPvCb(pv1, cb);
|
||
|
AssertPvCb(pv2, cb);
|
||
|
Assert((byte *)pv1 + cb <= (byte *)pv2 || (byte *)pv2 + cb <= (byte *)pv1,
|
||
|
"blocks overlap");
|
||
|
|
||
|
#ifdef IN_80386
|
||
|
|
||
|
__asm
|
||
|
{
|
||
|
// Setup the registers for using REP MOVS instruction to move memory.
|
||
|
//
|
||
|
// esi -> memory to move
|
||
|
// edi -> destination of move
|
||
|
// direction flag is clear for auto-increment
|
||
|
mov esi,pv1
|
||
|
mov edi,pv2
|
||
|
|
||
|
// move the longs
|
||
|
mov ecx,cb
|
||
|
shr ecx,2
|
||
|
rep movsd
|
||
|
|
||
|
// move the extra bytes
|
||
|
mov ecx,cb
|
||
|
and ecx,3
|
||
|
rep movsb
|
||
|
}
|
||
|
|
||
|
#else //!IN_80386
|
||
|
|
||
|
byte *pb1 = (byte *)pv1;
|
||
|
byte *pb2 = (byte *)pv2;
|
||
|
|
||
|
while (cb-- != 0)
|
||
|
*pb2++ = *pb1++;
|
||
|
|
||
|
#endif //!IN_80386
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
Copy data with possible overlap.
|
||
|
***************************************************************************/
|
||
|
void BltPb(void *pv1, void *pv2, long cb)
|
||
|
{
|
||
|
AssertIn(cb, 0, kcbMax);
|
||
|
AssertPvCb(pv1, cb);
|
||
|
AssertPvCb(pv2, cb);
|
||
|
|
||
|
#ifdef IN_80386
|
||
|
|
||
|
__asm
|
||
|
{
|
||
|
// Setup the registers for using REP MOVS instruction to move memory.
|
||
|
//
|
||
|
// esi -> memory to move
|
||
|
// edi -> destination of move
|
||
|
// direction flag is clear for auto-increment
|
||
|
|
||
|
mov esi,pv1
|
||
|
mov edi,pv2
|
||
|
mov ecx,cb
|
||
|
|
||
|
cmp esi,edi
|
||
|
ja LForward // if source > destination
|
||
|
je LDone // if source == destination
|
||
|
|
||
|
// source < destination, see if they overlap
|
||
|
mov eax,edi
|
||
|
sub eax,esi
|
||
|
cmp ecx,eax
|
||
|
jbe LForward
|
||
|
|
||
|
// they overlap with source < destination, so have to do a backward copy
|
||
|
std
|
||
|
add esi,ecx
|
||
|
add edi,ecx
|
||
|
dec esi
|
||
|
dec edi
|
||
|
|
||
|
// move the extra bytes
|
||
|
and ecx,3
|
||
|
rep movsb
|
||
|
|
||
|
// move the longs
|
||
|
mov ecx,cb
|
||
|
shr ecx,2
|
||
|
jz LDone
|
||
|
sub esi,3
|
||
|
sub edi,3
|
||
|
rep movsd
|
||
|
jmp LDone
|
||
|
|
||
|
LForward:
|
||
|
// move the longs
|
||
|
shr ecx,2
|
||
|
rep movsd
|
||
|
|
||
|
// move the extra bytes
|
||
|
mov ecx,cb
|
||
|
and ecx,3
|
||
|
rep movsb
|
||
|
|
||
|
LDone:
|
||
|
cld
|
||
|
}
|
||
|
|
||
|
#else //!IN_80386
|
||
|
|
||
|
byte *pb1 = (byte *)pv1;
|
||
|
byte *pb2 = (byte *)pv2;
|
||
|
|
||
|
if (pb1 > pb2)
|
||
|
{
|
||
|
while (cb-- != 0)
|
||
|
*pb2++ = *pb1++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pb1 += cb;
|
||
|
pb2 += cb;
|
||
|
while (cb-- != 0)
|
||
|
*--pb2 = *--pb1;
|
||
|
}
|
||
|
|
||
|
#endif //!IN_80386
|
||
|
}
|
||
|
|
||
|
|