/*static char *SCCSID = "@(#)ffnalign.c 6.4 91/06/17";*/
/* ffnalign.c       -- Align a buffer after DosFindFirst or DosFindNext
 *
 * post processor for aligned data API.
 */

/***  Change History:                                             ***/
/***   noto  11/18/93  Define which segment for Page Tuning DLL   ***/
/***                                                              ***/

/* STOP_LISTING */

#define INCL_DOS
#define INCL_32
#define INCL_NOPMAPI
#define INCL_ERRORS
#include <os2.h>
#include <limits.h>
#define assert(f)

#include "align32.h"
#include "ffn.h"



/***    Define which segment for Page Tuning DLL   ***/

void FFNAlign( FFNDATA *,PVOID);

#pragma code_seg("CODE32_TUNE4", "CODE")
#pragma code_seg()

#pragma alloc_text(CODE32_TUNE4, FFNAlign)



/* START_LISTING */

/*** FFNAlign
 *
 *  Aligns a packed findbuf.
 *
 *  ARGUMENTS: ffndata -> pointer to ffndata structure.
 *             pfidnbuf -> pointer to buffer.
 *
 *  RETURNS:   Nothing
 *
 *  CALLS:     memmove
 *
 *
 */

#define ROUNDUP(a)      ((a)+3L & ~3L)

/* Three pseudo-variables.  The source buffer can be three types, but I
 * want one variable to reference them.
 */

#define pffbSrc     ((MYFFB  *)pvSrc)
#define pffb2Src    ((MYFFB2 *)pvSrc)
#define pffb3Src    ((MYFFB3 *)pvSrc)

void FFNAlign( FFNDATA *ffndata,
               PVOID    pfindbuf ) {

    ULONG   ulInfoLevel = ffndata->ulInfoLevel;
    ULONG   cbPrev = ffndata->cbPrev;
    PVOID   pvSrc = (PBYTE)pfindbuf + ffndata->cbSrc;
    PVOID   pvDest = (PBYTE)pfindbuf + ffndata->cbDest;
    PVOID   pvTop;
    ULONG   cbTmp;

    if (ffndata->ffnFlags & FFN_EAS_DIDNT_FIT)
        ulInfoLevel = 2;

    switch (ulInfoLevel) {
        case 1: {
            do {
                // save the end of the pvDest for oNextEntryOffset
                pvTop = pvDest;

                // Decrement pvSrc to point to the start of the previous element.
                // and pvDest to point to the start of the element to unpack to.

                // BUGBUG!! Is there supposed to be a +1 on the end of this?
                (PBYTE)pffbSrc -= sizeof( MYFFB ) + cbPrev - CCHMAXPATHCOMP + 1;
                (PBYTE)pvDest -= ROUNDUP( sizeof( FFBU ) + cbPrev - CCHMAXPATHCOMP + 1);

                // fix the back-linked field.

                cbTmp = cbPrev;
                cbPrev = pffbSrc->ffb.cchName;

                // Now pvSrc and pvDest each point to the start of thier respective
                // buffers, and cbTmp is the cbName for the current buffer.

                // copy name
                memmove( ((FFBU *)pvDest)->achName, pffbSrc->ffb.achName, cbTmp+1 );
                ((FFBU *)pvDest)->cchName = cbTmp;

                ((FFBU *)pvDest)->attrFile          = pffbSrc->ffb.attrFile;
                ((FFBU *)pvDest)->cbFileAlloc       = pffbSrc->ffb.cbFileAlloc;
                ((FFBU *)pvDest)->cbFile            = pffbSrc->ffb.cbFile;
                ((FFBU *)pvDest)->ftimeLastWrite    = pffbSrc->ffb.ftimeLastWrite;
                ((FFBU *)pvDest)->fdateLastWrite    = pffbSrc->ffb.fdateLastWrite;
                ((FFBU *)pvDest)->ftimeLastAccess   = pffbSrc->ffb.ftimeLastAccess;
                ((FFBU *)pvDest)->fdateLastAccess   = pffbSrc->ffb.fdateLastAccess;
                ((FFBU *)pvDest)->ftimeCreation     = pffbSrc->ffb.ftimeCreation;
                ((FFBU *)pvDest)->fdateCreation     = pffbSrc->ffb.fdateCreation;
                ((FFBU *)pvDest)->oNextEntryOffset  = (PBYTE) pvTop - (PBYTE) pvDest;
                assert (((FFBU *)pvDest)->oNextEntryOffset % 4 == 0 );
            } while ( cbPrev );
            pvTop = (PBYTE)pfindbuf + ffndata->cbDest - ROUNDUP( sizeof( FFBU ) + ffndata->cbPrev - CCHMAXPATHCOMP+1);
            ((FFBU *)pvTop)->oNextEntryOffset = 0L;
        }
            break;

        case 2: {
            do {
                // save the end of the pvDest for oNextEntryOffset
                pvTop = pvDest;

                // Decrement pvSrc to point to the start of the previous element.
                // and pvDest to point to the start of the element to unpack to.

                // BUGBUG!! I should have to add 1 to the next expression, but it seems
                // that the compilier is doing it for me.
                (PBYTE)pffb2Src -= sizeof( MYFFB2 ) + cbPrev - CCHMAXPATHCOMP;
                (PBYTE)pvDest -= ROUNDUP( sizeof( FFB2U ) + cbPrev - CCHMAXPATHCOMP + 1);

                // fix the back-linked field.

                cbTmp = cbPrev;
                cbPrev = pffb2Src->ffb.cchName;

                // Now pvSrc and pvDest each point to the start of thier respective
                // buffers, and cbTmp is the cbName for the current buffer.

                // copy name
                memmove( ((FFB2U *)pvDest)->achName, pffb2Src->ffb.achName, cbTmp+1 );
                ((FFB2U *)pvDest)->cchName = cbTmp;

        if (pffb2Src->ffb.cbList == 4)
        {
                    ((FFB2U *)pvDest)->cbList       = pffb2Src->ffb.cbList;
        }
        else if ((pffb2Src->ffb.cbList * 2) > 65535)
        {
                ((FFB2U *)pvDest)->cbList        = 65535;
        }
        else
        {
                ((FFB2U *)pvDest)->cbList        = pffb2Src->ffb.cbList * 2;
        }
                ((FFB2U *)pvDest)->attrFile         = pffb2Src->ffb.attrFile;
                ((FFB2U *)pvDest)->cbFileAlloc      = pffb2Src->ffb.cbFileAlloc;
                ((FFB2U *)pvDest)->cbFile           = pffb2Src->ffb.cbFile;
                ((FFB2U *)pvDest)->ftimeLastWrite   = pffb2Src->ffb.ftimeLastWrite;
                ((FFB2U *)pvDest)->fdateLastWrite   = pffb2Src->ffb.fdateLastWrite;
                ((FFB2U *)pvDest)->ftimeLastAccess  = pffb2Src->ffb.ftimeLastAccess;
                ((FFB2U *)pvDest)->fdateLastAccess  = pffb2Src->ffb.fdateLastAccess;
                ((FFB2U *)pvDest)->ftimeCreation    = pffb2Src->ffb.ftimeCreation;
                ((FFB2U *)pvDest)->fdateCreation    = pffb2Src->ffb.fdateCreation;
                ((FFB2U *)pvDest)->oNextEntryOffset = (PBYTE) pvTop - (PBYTE) pvDest;
                assert (((FFB2U *)pvDest)->oNextEntryOffset % 4 == 0 );
            } while ( cbPrev );

            pvTop = (PBYTE)pfindbuf + ffndata->cbDest - ROUNDUP( sizeof( FFB2U ) + ffndata->cbPrev - CCHMAXPATHCOMP+1);
            if (ffndata->ffnFlags & FFN_EAS_DIDNT_FIT) {
                /* There is an EAOP structure at the beginning of the buffer
                 *
                 * WARINING: This relies on the fact that EAOP and EAOP2 are
                 *           the same size!
                 */
                pvTop = (PBYTE)pvTop + sizeof(EAOP2);
            }
            ((FFB2U *)pvTop)->oNextEntryOffset = 0L;
        }
            break;

    case 3:
        case 4: {
            PVOID   pvTmpSrc;
            PVOID   pvTopFFB = pvDest;
            PFEA    pfea;
            PFEA2   pfea2Top;
            ULONG   cbTopFEA;
            ULONG   cbPrevFEA;
            ULONG   cchName;
            ULONG   cbList;

            // (PBYTE)pvSrc += sizeof (EAOP2);

            do {
                // save the end of the dest for oNextEntryOffset
                pvTop = pvDest;

                // Decrement pvSrc to point to the start of the previous element.

                (PBYTE)pvSrc -= cbPrev;

                // Get the size of the previous FFB

                cbPrev = pffb3Src->ffb.cbPrevFFB;

                // Now pvSrc points to the start of the element to unpack, and
                // dest points to the end of it.

                // copy achName

                pvTmpSrc = (PBYTE)(pffb3Src->ffb.afea) + pffb3Src->ffb.cbList - 4;
                cchName = *(PBYTE)pvTmpSrc;

                ((PBYTE)pvTmpSrc)++;                // points to achName now...

                // the file name must be one word above the DWORD boundry
                // leaving room for cchName and the \0.

                (PBYTE)pvDest -= ROUNDUP( cchName + 2 ) - 1;

                memmove( pvDest, pvTmpSrc, cchName + 1);

                ((PBYTE)pvDest)--;

                // This leaves cchName dword aligned, which in turn (more
                // importantly) allows the previous FEA to be padded up to
                // the DWORD boundry.

                *((PBYTE) pvDest) = cchName;        // copy cchName

                // now copy and unpack the FEA list
                if (pffb3Src->ffb.cbList > sizeof (ULONG) ) {
                    pfea = pffb3Src->ffb.afea;
                    pfea2Top = pvDest;

                    // Determine the size of the last FEA
                    cbTopFEA = cbPrevFEA = pfea->cbValue;

                    // Flag the first FEA so we now when to stop
                    pfea->cbValue = 0;

                    (PBYTE)pfea += pffb3Src->ffb.cbList - 4;

                    // Now pfea points to the end of the last FEA, dest points
                    // to the end of where the last FEA2 will be, and cbPrevFEA
                    // holds the size of the last FEA

                    do {
                        // The FEA2 has space allocated for the \0, the FEA doesn't
                        (PBYTE)pvDest -= ROUNDUP( sizeof( FEA2 ) + cbPrevFEA);
                        (PBYTE)pfea -= sizeof( FEA ) + cbPrevFEA + 1;
                        cbTmp = cbPrevFEA;
                        cbPrevFEA = pfea->cbValue;

                        memmove( ((PFEA2)pvDest)->szName, ((PBYTE)pfea+sizeof(FEA)), cbTmp + 1 );   // BUGBUG What about the \0?
                        ((PFEA2)pvDest)->cbValue = cbTmp - pfea->cbName;
                        ((PFEA2)pvDest)->cbName = pfea->cbName;
                        ((PFEA2)pvDest)->fEA = pfea->fEA;
                        // On the last FEA2, oNext is zero.
                        ((PFEA2)pvDest)->oNextEntryOffset = ROUNDUP(sizeof( FEA2 ) + cbTmp);
                    } while ( cbPrevFEA );

                    // Use pfea to point to the last FEA2 copied, in order
                    // to zero out the oNextEntryOffset

                    pfea = (PFEA)((PBYTE)pfea2Top - ROUNDUP(sizeof (FEA2) + cbTopFEA));
                    ((PFEA2)pfea)->oNextEntryOffset = 0;
                    cbList = (PBYTE)pfea2Top - (PBYTE)pvDest;
                }
                else {
                    // No FEA list to unpack.
                    cbList = 0;
                }

                // pvDest now points to the start of the first FEA
                // Make pbDest point to the start of the unpacked FFB3 (FFB3U)

                (PBYTE)pvDest -= ROUNDUP( sizeof(FFB3) - sizeof( FEA ) + 4 );

                ((FFB3U *)pvDest)->cbList = cbList + sizeof (cbList);

                // Now pvSrc and dest each point to the start of thier respective
                // buffers.

                ((FFB3U *)pvDest)->attrFile          = pffb3Src->ffb.attrFile;
                ((FFB3U *)pvDest)->cbFileAlloc       = pffb3Src->ffb.cbFileAlloc;
                ((FFB3U *)pvDest)->cbFile            = pffb3Src->ffb.cbFile;
                ((FFB3U *)pvDest)->ftimeLastWrite    = pffb3Src->ffb.ftimeLastWrite;
                ((FFB3U *)pvDest)->fdateLastWrite    = pffb3Src->ffb.fdateLastWrite;
                ((FFB3U *)pvDest)->ftimeLastAccess   = pffb3Src->ffb.ftimeLastAccess;
                ((FFB3U *)pvDest)->fdateLastAccess   = pffb3Src->ffb.fdateLastAccess;
                ((FFB3U *)pvDest)->ftimeCreation     = pffb3Src->ffb.ftimeCreation;
                ((FFB3U *)pvDest)->fdateCreation     = pffb3Src->ffb.fdateCreation;
                if (pvTop == pvTopFFB)
                    ((FFB3U *)pvDest)->oNextEntryOffset  = 0L;
                else
                    ((FFB3U *)pvDest)->oNextEntryOffset  = (PBYTE) pvTop - (PBYTE) pvDest;
                assert (((FFB3U *)pvDest)->oNextEntryOffset % 4 == 0 );
            } while ( cbPrev );
        }
    }
}
