/*++

Copyright (c) 1996-1997  Microsoft Corporation

Module Name:

    mkuff.c

Abstract:


Environment:

    Windows NT PostScript driver

Revision History:

--*/

#include        "precomp.h"

//
// Macros
//

DWORD             gdwOutputFlags;

//
// Local function prototypes
//

BOOL
BiArgcheck(
    IN     INT    iArgc,
    IN     CHAR **ppArgv,
    IN OUT PWSTR   pwstrInFileName,
    IN OUT PWSTR   pwstrOutFileName);

PBYTE
PCreateUFFFileHeader(
    HANDLE    hHeap,
    PFILELIST pFileList,
    PDWORD    pdwUFFSize);

//
// Globals
//

BYTE gcstrError1[] = "Usage:  mkuff [-v] [Input Text file] [Output UFF file]\n";
BYTE gcstrError2[] = "mkuff: HeapCreate() failed\n.";
BYTE gcstrError3[] = "BGetInfo failed.\n";
BYTE gcstrError4[] = "Cannot create output file '%ws'.\n";
BYTE gcstrError5[] = "PCreateUFFFileHeader failed\n";
BYTE gcstrError6[] = "WriteFile fails: writes %ld bytes\n";
BYTE gcstrError8[] = "Cannot open file \"%ws\".\n";


INT  __cdecl
main(
    IN INT     iArgc,
    IN CHAR  **ppArgv)
/*++

Routine Description:

    main

Arguments:

    iArgc - Number of parameters in the following
    ppArgv - The parameters, starting with our name

Return Value:

    Return error code 

Note:


--*/
{

    HANDLE hHeap, hInFile, hOutput;
    PBYTE  pInFile, pUFFFile;
    DWORD  dwInFileSize, dwI, dwUFFHeaderSize, dwWrittenSize, dwFileSize;

    PWSTR  wstrInFileName[FILENAME_SIZE];
    PWSTR  wstrOutFileName[FILENAME_SIZE];

    FILELIST FileList;
    DATA_HEADER DataHeader;
    PCARTLIST pCartList;
    PDATAFILE pDataTmp;
    PDATAFILE pFontFile;
    HANDLE hFontFile;
    PBYTE pFontData;

    if (gdwOutputFlags & OUTPUT_VERBOSE)
    {
        fprintf( stdout, "Start mkuff\n");
    }

    if (!BiArgcheck(iArgc, ppArgv, (PWSTR)wstrInFileName, (PWSTR)wstrOutFileName))
    {
        fprintf( stderr, gcstrError1);
        return  -1;
    }

    if (gdwOutputFlags & OUTPUT_VERBOSE)
    {
        fprintf( stdout, "InFile: %ws\nOutFile: %ws\n", wstrInFileName, wstrOutFileName);
    }

    //
    // Heap Creation
    //

    if (!(hHeap = HeapCreate( HEAP_NO_SERIALIZE, 0x10000, 0x10000)))
    {
        fprintf( stderr, gcstrError2);
        ERR(("CreateHeap failed: %d\n", GetLastError()));
        return -2;
    }

    hInFile = MapFileIntoMemory((PWSTR)wstrInFileName,
                                (PVOID)&pInFile,
                                &dwInFileSize );

    ZeroMemory(&FileList, sizeof(FILELIST));

    if (!BGetInfo(hHeap, pInFile, dwInFileSize, &FileList))
    {
        fprintf( stderr, gcstrError3);
        ERR(("CreateHeap failed: %d\n", GetLastError()));
        return -3;
    }

    if (gdwOutputFlags & OUTPUT_VERBOSE)
    {
        PDATAFILE pFontFile;
        PDATAFILE pTransFile;
        PCARTLIST pCartList;

        printf("\n");
        printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
        printf("FileList\n");

        pCartList = FileList.pCartList;

        for (dwI = 0; dwI < FileList.dwCartridgeNum; dwI ++, pCartList = pCartList->pNext)
        {
            if (pCartList->pwstrCartName)
                fprintf( stdout, "CartRidge(%d): ""%ws""\n", dwI, pCartList->pwstrCartName);
            pFontFile = pCartList->pFontFile;
            while( pFontFile )
            {
                fprintf( stdout, "FontFile(%d): %ws, FontName:%ws\n", pFontFile->rcID, pFontFile->pwstrFileName, pFontFile->pwstrDataName);
                pFontFile = pFontFile->pNext;
            }

            pTransFile = pCartList->pTransFile;
            while( pTransFile )
            {
                fprintf( stdout, "TransFile(%d): %ws\n", pTransFile->rcID, pTransFile->pwstrFileName);
                pTransFile = pTransFile->pNext;
            }
        }
    }

    UnmapFileFromMemory(hInFile);

    pUFFFile = PCreateUFFFileHeader(hHeap, &FileList, &dwUFFHeaderSize);

    if (pUFFFile == NULL)
    {
        fprintf( stderr, gcstrError5);
        return -5;

    }

    hOutput = CreateFile((PWSTR)wstrOutFileName,
                         GENERIC_WRITE,
                         0,
                         NULL,
                         CREATE_ALWAYS,
                         FILE_ATTRIBUTE_NORMAL,
                         NULL );

    if( hOutput == INVALID_HANDLE_VALUE )
    {
        fprintf( stderr, gcstrError4,  wstrOutFileName);
        return -4;
    }

    WriteFile( hOutput,
               pUFFFile,
               dwUFFHeaderSize,
               &dwWrittenSize,
               NULL );

    if( dwWrittenSize != dwUFFHeaderSize)
    {
        fprintf( stderr, gcstrError6, dwWrittenSize);
        return  -6;
    }

    //
    // Open font file and write data
    //

    pCartList = FileList.pCartList;
    while (pCartList)
    {
        pDataTmp = pCartList->pFontFile;
        while (pDataTmp)
        {
            hFontFile = MapFileIntoMemory(pDataTmp->pwstrFileName,
                                          (PVOID)&pFontData,
                                          &dwFileSize );

            DataHeader.dwSignature = pDataTmp->dwSignature;
            DataHeader.wSize = sizeof(DATA_HEADER);
            DataHeader.wDataID = (WORD)pDataTmp->rcID;
            DataHeader.dwDataSize = (WORD)dwFileSize;
            DataHeader.dwReserved = 0;

            if (hFontFile)
            {
                WriteFile( hOutput,
                           &DataHeader,
                           sizeof(DATA_HEADER),
                           &dwWrittenSize,
                           NULL);

                if( dwWrittenSize != sizeof(DATA_HEADER))
                {
                    fprintf( stderr, gcstrError6, dwWrittenSize);
                    return  -6;
                }

                WriteFile( hOutput,
                           pFontData,
                           dwFileSize,
                           &dwWrittenSize,
                           NULL);

                if( dwWrittenSize != dwFileSize)
                {
                    fprintf( stderr, gcstrError6, dwWrittenSize);
                    return  -6;
                }

                UnmapFileFromMemory(hFontFile);
            }
            else
                break;

            pDataTmp = pDataTmp->pNext;
        }
        pDataTmp = pCartList->pTransFile;
        while (pDataTmp)
        {
            hFontFile = MapFileIntoMemory(pDataTmp->pwstrFileName,
                                          (PVOID)&pFontData,
                                          &dwFileSize );
            DataHeader.dwSignature = pDataTmp->dwSignature;
            DataHeader.wSize = sizeof(DATA_HEADER);
            DataHeader.wDataID = (WORD)pDataTmp->rcID;
            DataHeader.dwDataSize = (WORD)dwFileSize;
            DataHeader.dwReserved = 0;

            if (hFontFile)
            {
                WriteFile( hOutput,
                           &DataHeader,
                           sizeof(DATA_HEADER),
                           &dwWrittenSize,
                           NULL);

                if( dwWrittenSize != sizeof(DATA_HEADER))
                {
                    fprintf( stderr, gcstrError6, dwWrittenSize);
                    return  -6;
                }
                WriteFile( hOutput,
                           pFontData,
                           dwFileSize,
                           &dwWrittenSize,
                           NULL);

                if( dwWrittenSize != dwFileSize)
                {
                    fprintf( stderr, gcstrError6, dwWrittenSize);
                    return  -6;
                }

                UnmapFileFromMemory(hFontFile);
            }
            else
                break;

            pDataTmp = pDataTmp->pNext;
        }

        pCartList = pCartList->pNext;
    }

    CloseHandle(hOutput);

    HeapDestroy(hHeap);

    return  0;

}


BOOL
BiArgcheck(
    IN     INT    iArgc,
    IN     CHAR **ppArgv,
    IN OUT PWSTR   pwstrInFileName,
    IN OUT PWSTR   pwstrOutFileName)
/*++

Routine Description:

    iArgcheck

Arguments:

    iArgc - Number of parameters in the following
    ppArgv - The parameters, starting with our name
    pwstrInFileName -
    pwstrOutFileName -

Return Value:

    If TRUE, function succeeded. Othewise FALSE.

Note:


--*/
{
    INT iI;
    INT iRet;

    if (iArgc > 4 || iArgc < 3)
    {
        return  FALSE;
    }

    if (iArgc == 4)
    {
        gdwOutputFlags |= OUTPUT_VERBOSE;
        ppArgv++;
    }

    ppArgv++;
    iRet = MultiByteToWideChar(CP_ACP, 0, *ppArgv, strlen(*ppArgv), pwstrInFileName, FILENAME_SIZE);
    *(pwstrInFileName + iRet) = (WCHAR)NULL;
    ppArgv++;
    iRet = MultiByteToWideChar(CP_ACP, 0, *ppArgv, strlen(*ppArgv), pwstrOutFileName, FILENAME_SIZE);
    *(pwstrOutFileName + iRet) = (WCHAR)NULL;




    return TRUE;
}


PBYTE
PCreateUFFFileHeader(
    HANDLE hHeap,
    PFILELIST pFileList,
    PDWORD pdwUFFHeaderSize)
{
    HANDLE hFontFile;
    PDATAFILE pFontFile, pTransFile;
    PCARTLIST pCartList;
    PDATAFILE pDataTmp;
    PUFF_FILEHEADER pUFFHeader;
    PUFF_FONTDIRECTORY pUFFFontDir, pFirstFontDir;
    
    PBYTE pFontData;
    DWORD dwNumOfFontNameChars, dwNumOfData, dwNumOfFonts, dwNumOfTrans, dwUFFHeaderSize, dwFileSize, dwNumOfCartNameChars, dwI;
    DWORD dwOffset, offCartridgeName;
    PWSTR pwstrCartNameBuf, pwstrFontNameBuf;

    *pdwUFFHeaderSize = 0;

    dwNumOfFontNameChars = dwNumOfCartNameChars = dwNumOfFonts = dwNumOfTrans = 0;
    pCartList = pFileList->pCartList;
    while (pCartList)
    {
        pDataTmp = pCartList->pFontFile;
        while (pDataTmp)
        {
            dwNumOfFontNameChars += 1 + wcslen(pDataTmp->pwstrDataName);
            pDataTmp = pDataTmp->pNext;
            dwNumOfFonts ++;
        }

        pDataTmp = pCartList->pTransFile;
        while (pDataTmp)
        {
            pDataTmp = pDataTmp->pNext;
            dwNumOfTrans ++;
        }

        if (pCartList->pwstrCartName)
            dwNumOfCartNameChars += 1 + wcslen(pCartList->pwstrCartName);

        pCartList = pCartList->pNext;
    }

    dwNumOfData = dwNumOfFonts + dwNumOfTrans;

    dwUFFHeaderSize = sizeof(UFF_FILEHEADER) +
                      sizeof(UFF_FONTDIRECTORY) * dwNumOfFonts +
                      dwNumOfCartNameChars * sizeof(WCHAR) +
                      dwNumOfFontNameChars * sizeof(WCHAR);

    pUFFHeader = (PUFF_FILEHEADER)HeapAlloc(hHeap, 0, dwUFFHeaderSize);

    if (pUFFHeader == NULL)
    {
        return NULL;
    }

    //
    // Fill in header.
    //

    pUFFHeader->dwSignature = UFF_FILE_MAGIC;
    pUFFHeader->dwVersion   = UFF_VERSION_NUMBER;
    pUFFHeader->dwSize      = sizeof(UFF_FILEHEADER);
    pUFFHeader->nFonts      = dwNumOfFonts;
    pUFFHeader->nGlyphSets  = dwNumOfTrans;
    pUFFHeader->nVarData    = 0;
    pUFFHeader->offFontDir  = sizeof(UFF_FILEHEADER);
    pUFFHeader->dwFlags     = 0;
    pUFFHeader->dwReserved[0] = 0;
    pUFFHeader->dwReserved[1] = 0;
    pUFFHeader->dwReserved[2] = 0;
    pUFFHeader->dwReserved[3] = 0;


    //
    // Fill in UFF_FONTDIRECTORY
    //
    // ------------------
    // UFF_FONTHEADER
    // ------------------
    // UFF_FONTDIRECTORY * (Number of fonts)
    // ------------------
    // Cartridge name
    // ------------------
    // Font name
    // ------------------
    // First cartridge font data
    // ------------------
    // First cartridge glyph data
    // ------------------
    // Second cartridge font data
    // ------------------
    // Second cartridge glyph data
    // ------------------
    //

    pUFFFontDir = (PUFF_FONTDIRECTORY)(pUFFHeader + 1);
    pwstrCartNameBuf = (PWSTR)(pUFFFontDir + dwNumOfFonts);
    pwstrFontNameBuf = pwstrCartNameBuf + dwNumOfCartNameChars;
    pCartList = pFileList->pCartList;
    dwOffset = sizeof(UFF_FILEHEADER) +
               sizeof(UFF_FONTDIRECTORY) * dwNumOfFonts +
               dwNumOfCartNameChars * sizeof(WCHAR) +
               dwNumOfFontNameChars * sizeof(WCHAR);

    while(pCartList)
    {
        pFontFile  = pCartList->pFontFile;
        pTransFile = pCartList->pTransFile;
        pFirstFontDir = pUFFFontDir;
        if (pCartList->pwstrCartName)
        {
            offCartridgeName = (PBYTE)pwstrCartNameBuf - (PBYTE)pUFFHeader;
            wcscpy(pwstrCartNameBuf, pCartList->pwstrCartName);
            pwstrCartNameBuf += wcslen(pCartList->pwstrCartName) + 1;
        }
        else
            offCartridgeName = (DWORD)NULL;

        while (pFontFile)
        {
            hFontFile = MapFileIntoMemory(pFontFile->pwstrFileName,
                                          (PVOID)&pFontData,
                                          &dwFileSize );
            if (hFontFile)
            {
                pFontFile->dwSize = dwFileSize;

                if (1)
                {
                    pFontFile->dwSignature = DATA_IFI_SIG;
                    pFontFile->rcTrans = ((FI_DATA_HEADER*)pFontData)->u.sCTTid;
                }
                else
                {
                    pFontFile->dwSignature = DATA_UFM_SIG;
                    pFontFile->rcTrans = (SHORT)((UNIFM_HDR*)pFontData)->lGlyphSetDataRCID;
                }

                UnmapFileFromMemory(hFontFile);
            }
            else
                return NULL;


            pUFFFontDir->dwSignature    = FONT_REC_SIG;
            pUFFFontDir->wSize          = sizeof(UFF_FONTDIRECTORY);
            pUFFFontDir->wFontID        = (WORD)pFontFile->rcID;
            pUFFFontDir->sGlyphID       = (SHORT)pFontFile->rcTrans;
            pUFFFontDir->wFlags         = 0;
            pUFFFontDir->dwInstallerSig = WINNT_INSTALLER_SIG;

            if (pFontFile->pwstrDataName)
            {
                pUFFFontDir->offFontName = (PBYTE)pwstrFontNameBuf - (PBYTE)pUFFHeader;
                wcscpy(pwstrFontNameBuf, pFontFile->pwstrDataName);
                pwstrFontNameBuf += wcslen(pFontFile->pwstrDataName) + 1;
            }
            else
                pUFFFontDir->offFontName = (DWORD)NULL;

                
            pUFFFontDir->offCartridgeName = offCartridgeName;
            pUFFFontDir->offFontData      = dwOffset;
            pUFFFontDir->offGlyphData     = 0;
            pUFFFontDir->offVarData       = 0;
            pUFFFontDir++;

            dwOffset += pFontFile->dwSize + sizeof(DATA_HEADER);
            pFontFile = pFontFile->pNext;
        }
        while (pTransFile)
        {
            hFontFile = MapFileIntoMemory(pTransFile->pwstrFileName,
                                          (PVOID)&pFontData,
                                          &dwFileSize );
            if (1)
            {
                pTransFile->dwSignature = DATA_RLE_SIG;
            }
            else
                pTransFile->dwSignature = DATA_GTT_SIG;

            if (hFontFile)
            {
                pTransFile->dwSize = dwFileSize;
                while (pFirstFontDir < pUFFFontDir)
                {
                    if (pFirstFontDir->sGlyphID == (SHORT)pTransFile->rcID)
                        pFirstFontDir->offGlyphData = dwOffset;
                    pFirstFontDir ++;
                }
                dwOffset += dwFileSize + sizeof(DATA_HEADER);

                UnmapFileFromMemory(hFontFile);
            }
            else
                return NULL;

            pTransFile = pTransFile->pNext;
        }

        pCartList = pCartList->pNext;
    }

    if (gdwOutputFlags & OUTPUT_VERBOSE)
    {
        BDumpUFF(pUFFHeader);
    }

    *pdwUFFHeaderSize = dwUFFHeaderSize;

    return (PBYTE)pUFFHeader;
}