#include "generic.h"

#pragma code_seg(_ICM2SEG)
#pragma optimize("",off)

#define TempBfSize 128
#define LINELENG   128
#ifdef ICMDLL
#define ICM2SEG
#endif

static  char    ICM2SEG NewLine[]       = "\n" ;
static  char    ICM2SEG ASCII85DecodeBegine[] = "<~";
static  char    ICM2SEG ASCII85DecodeEnd[] = "~> cvx exec ";

//******************************************************************
//   Local functions to deal with output to the memory buffer

static  SINT    CPLastError;

BOOL    EXTERN     SetCPLastError(SINT LastError)
{
    CPLastError = LastError;
    return(TRUE);
}

SINT    EXTERN     GetCPLastError()
{
    return(CPLastError);
}

BOOL    EXTERN MemAlloc(SINT Size, HGLOBAL FAR *hMemory, LPMEMPTR lpMH)
{
    HGLOBAL hMem;
    LPVOID  lpMem;

    *hMemory = 0;
    if(lpMH == NULL )
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }

    hMem = GlobalAlloc(GHND, Size) ;
    if(hMem == 0 )
    {
        SetCPLastError(CP_MEMORY_ALLOC_ERR);
        return(FALSE);
    }

    lpMem = GlobalLock(hMem);
    if(lpMem == NULL )
    {
        GlobalFree(hMem);
        SetCPLastError(CP_MEMORY_ALLOC_ERR);
        return(FALSE);
    }
    *lpMH = (MEMPTR)lpMem ;
    *hMemory = hMem;
    return (TRUE);
}

BOOL    EXTERN MemFree(HGLOBAL hMem)
{
    if(hMem == NULL )
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }

    GlobalUnlock(hMem);
    GlobalFree(hMem) ;
    return(TRUE);
}

//******************************************************************
//      Low-level Profile functions - used for individual tag access
//******************************************************************
#ifndef ICMDLL
BOOL    EXTERN LoadCP(LPCSTR filename, HGLOBAL FAR *phMem, LPCHANDLE lpCP)
{
    icHeader    CPHeader;
    HFILE       hFile;
    SINT        Res, CPSize;
    MEMPTR      mpCP;

    *phMem = 0;
    if (lpCP == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }

    hFile = _lopen(filename, READ );
    if( hFile == HFILE_ERROR )
    {
        SetCPLastError(CP_FILE_OPEN_ERR);
        return(FALSE);
    }
 
    Res = _lread(hFile, (LPVOID) &CPHeader, sizeof(CPHeader));
    if( (Res == HFILE_ERROR) ||
        (Res != sizeof(CPHeader)) )
    {
        _lclose(hFile);
        SetCPLastError(CP_FILE_READ_ERR);
        return(FALSE);
    }

    // Make the initial check for validity of the profile
    if( SigtoCSIG(CPHeader.magic) != icMagicNumber )
    {
        _lclose(hFile);
        SetCPLastError(CP_FORMAT_ERR);
        return(FALSE);
    }

    CPSize = ui32toSINT(CPHeader.size);
    if( MemAlloc(CPSize, phMem, (LPMEMPTR) &mpCP) )
    {

        *lpCP = (CHANDLE) mpCP;  // Put the memory pointer as  handle
        // Read profile into  memory
         _lseek(hFile, 0L, SEEK_SET);

        while(CPSize)
        {
            Res = _lread(hFile, (LPVOID) mpCP, 4096);
            if (Res == HFILE_ERROR) 
            {
                _lclose(hFile);
                SetCPLastError(CP_FILE_READ_ERR);
                return(FALSE);
            }
            mpCP    += Res;
            CPSize  -= Res;
        }
    }else
    {
        *phMem = 0;
        _lclose(hFile);
        return(FALSE);
    }
    _lclose(hFile);
    return (TRUE);
}

#else
//******************************************************************
//      Low-level Profile functions - used for individual tag access
//******************************************************************
BOOL    EXTERN LoadCP32(LPCSTR filename, HGLOBAL *phMem, LPCHANDLE lpCP)
{
    icHeader    CPHeader;
    HANDLE      hFile;
    SINT        Res, CPSize;
    MEMPTR      mpCP;
    BOOL        Success;

    if (lpCP == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }
    hFile = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
    if( hFile == INVALID_HANDLE_VALUE )
    {
        SetCPLastError(CP_FILE_OPEN_ERR);
        return(FALSE);
    }

    Success = ReadFile(hFile, (LPVOID) &CPHeader, sizeof(CPHeader), &Res, NULL);
    if( ( !Success ) || (Res != sizeof(CPHeader)) )
    {
        CloseHandle(hFile);
        SetCPLastError(CP_FILE_READ_ERR);
        return(FALSE);
    }

    // Make the initial check for validity of the profile
    if( SigtoCSIG(CPHeader.magic) != icMagicNumber )
    {
        CloseHandle(hFile);
        SetCPLastError(CP_FORMAT_ERR);
        return(FALSE);
    }

    CPSize = ui32toSINT(CPHeader.size);
    if( MemAlloc(CPSize, phMem, (LPMEMPTR) &mpCP) )
    {

        *lpCP = (CHANDLE) mpCP;  // Put the memory pointer as  handle
        // Read profile into  memory
        SetFilePointer(hFile, 0L, NULL, FILE_BEGIN);
        Success = ReadFile(hFile, (LPVOID) (LPVOID)mpCP, CPSize, &Res, NULL);
        if (!Success) 
        {
            CloseHandle(hFile);
            SetCPLastError(CP_FILE_READ_ERR);
            return(FALSE);
        }
    }else
    {
        CloseHandle(hFile);
        return(FALSE);
    }
    CloseHandle(hFile);
    return (TRUE);
}
#endif

BOOL    EXTERN FreeCP(HGLOBAL hMem)
{
    return( MemFree(hMem) );
}


BOOL    EXTERN GetCPElementCount(CHANDLE CP, LPSINT lpCount)
{
    lpcpTagList lpTL;
    if (lpCount == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }
    lpTL = (lpcpTagList) &(((lpcpProfile)CP)->count);
    *lpCount = ui32toSINT(lpTL->count);
    return(TRUE);
}


BOOL    EXTERN GetCPElementInfo(CHANDLE CP, SINT Index,
                                LPMEMPTR lpTagData, LPMEMPTR lpElemData)
{
    SINT    Count;
    lpcpTagList lpTL;

    if ( (lpTagData == NULL) || (lpElemData == NULL) )
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }

    lpTL = (lpcpTagList) &(((lpcpProfile)CP)->count);
    Count   = ui32toSINT(lpTL->count);
    if ( Count <= Index )
    {
        SetCPLastError(CP_OUT_OF_RANGE_ERR);
        return(FALSE);
    }
    *lpTagData      = ((MEMPTR) &(lpTL->tags[0])) + (Index * sizeof(icTag)) ;
    *lpElemData     = ((MEMPTR) CP) +
                                ui32toSINT( ((lpcpTag)*lpTagData)->offset);
    return(TRUE);
}


/* Checks if the profile has all required fields  for
    this specific type of the color profile             */
BOOL    EXTERN ValidateCP(CHANDLE CP)
{
    BOOL    Result;
    CSIG    ProfileClass;

    if(GetCPClass(CP, (LPCSIG) &ProfileClass) )
    {
        // All profiles must have a ProfileDescription and
        //  a Copyright  tags.

        if( !DoesCPTagExist(CP, icSigProfileDescriptionTag) || 
            !DoesCPTagExist(CP, icSigCopyrightTag ) )
        {
            SetCPLastError(CP_NOT_FOUND_ERR);
            return(FALSE);
        }

        // All profiles, except Device-link, must have a mediaWhitePoint Tag
        switch( ProfileClass )
        {
            case     icSigLinkClass :        /* 'link' */
                if( DoesCPTagExist(CP, icSigAToB0Tag) &&
                    DoesCPTagExist(CP, icSigProfileSequenceDescTag)
                  )
                {
                    Result = TRUE;
                }else
                {
                    Result = FALSE;
                }
                break;

            case     icSigInputClass:       /* 'scnr' */
                if( DoesCPTagExist(CP, icSigGrayTRCTag) ||
                    DoesCPTagExist(CP, icSigAToB0Tag)      )
                {
                    Result = TRUE;
                }else if( DoesCPTagExist(CP, icSigGreenColorantTag) )
                {
                    if( DoesCPTagExist(CP, icSigRedColorantTag) &&
                        DoesCPTagExist(CP, icSigBlueColorantTag) &&
                        DoesCPTagExist(CP, icSigRedTRCTag) &&
                        DoesCPTagExist(CP, icSigGreenTRCTag) &&
                        DoesCPTagExist(CP, icSigBlueTRCTag)
                      )
                    {
                        Result = TRUE;
                    }else
                    {
                        Result = FALSE;
                    }
                }else
                {
                    Result = FALSE;
                }
                Result  &= DoesCPTagExist(CP, icSigMediaWhitePointTag);
                break;

            case     icSigDisplayClass:     /* 'mntr' */
                if( DoesCPTagExist(CP, icSigGrayTRCTag) )
                {
                    Result = TRUE;
                }else if( DoesCPTagExist(CP, icSigGreenColorantTag) )
                {
                    if( DoesCPTagExist(CP, icSigRedColorantTag) &&
                        DoesCPTagExist(CP, icSigBlueColorantTag) &&
                        DoesCPTagExist(CP, icSigRedTRCTag) &&
                        DoesCPTagExist(CP, icSigGreenTRCTag) &&
                        DoesCPTagExist(CP, icSigBlueTRCTag)
                      )
                    {
                        Result = TRUE;
                    }else
                    {
                        Result = FALSE;
                    }
                }else
                {
                    Result = FALSE;
                }
                Result  &= DoesCPTagExist(CP, icSigMediaWhitePointTag);
                break;

            case     icSigOutputClass:      /* 'prtr' */
                if( DoesCPTagExist(CP, icSigGrayTRCTag) )
                {
                    Result = TRUE;
                }else if( DoesCPTagExist(CP, icSigAToB0Tag) &&
                          DoesCPTagExist(CP, icSigAToB1Tag) &&
                          DoesCPTagExist(CP, icSigAToB2Tag) &&
                          DoesCPTagExist(CP, icSigBToA0Tag) &&
                          DoesCPTagExist(CP, icSigBToA1Tag) &&
                          DoesCPTagExist(CP, icSigBToA2Tag) &&
                          DoesCPTagExist(CP, icSigGamutTag) 
                        )
                {
                    Result = TRUE;
                }else
                {
                    Result = FALSE;
                }
                Result  &= DoesCPTagExist(CP, icSigMediaWhitePointTag);
                break;

            case     icSigAbstractClass:    /* 'abst' */
                if( DoesCPTagExist(CP, icSigAToB0Tag) )
                {
                    Result = TRUE;
                }else
                {
                    Result = FALSE;
                }
                Result  &= DoesCPTagExist(CP, icSigMediaWhitePointTag);
                break;

            case     icSigColorSpaceClass:  /* 'spac' */
                if( DoesCPTagExist(CP, icSigAToB0Tag) &&
                    DoesCPTagExist(CP, icSigBToA0Tag)
                  )
                {
                    Result = TRUE;
                }else
                {
                    Result = FALSE;
                }
                Result  &= DoesCPTagExist(CP, icSigMediaWhitePointTag);
                break;

            default:
                Result = FALSE;
                break;
        }
    }else
    {
        return(FALSE);
    }
    if( Result == FALSE )
    {
        SetCPLastError(CP_NOT_FOUND_ERR);
    }
    return(Result);
}

BOOL    EXTERN DoesCPTagExist(CHANDLE CP, CSIG CPTag)
{
    SINT    Count;
    MEMPTR   Data;
    lpcpTagList lpTL;

    lpTL = (lpcpTagList) &(((lpcpProfile)CP)->count);
    Count   = ui32toSINT(lpTL->count);
    Data    = (MEMPTR)  &(lpTL->tags[0]) ; 
    while ( Count-- )
    {
        if(  SigtoCSIG( ((lpcpTag)Data)->sig) == CPTag )
        {
            return(TRUE);
        }else
        {
            Data    += sizeof(icTag);   // Bump pointer to the next tag
        }
    }
    return(FALSE);
}


BOOL    EXTERN GetCPTagIndex(CHANDLE CP, CSIG CPTag, LPSINT lpIndex)
{
    SINT    Count;
    MEMPTR   Data;
    SINT    i;
    lpcpTagList lpTL;

    if (lpIndex == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }

    lpTL = (lpcpTagList) &(((lpcpProfile)CP)->count);
    Count   = ui32toSINT(lpTL->count);
    Data    = (MEMPTR)  &(lpTL->tags[0]) ;

    for (i = 0; i < Count; i++ )
    {
        if(  SigtoCSIG( ((lpcpTag)Data)->sig) == CPTag )
        {
            *lpIndex = i;
            return(TRUE);
        }else
        {
            Data    += sizeof(icTag);   // Bump pointer to the next tag
        }
    }

    SetCPLastError(CP_NOT_FOUND_ERR);
    return(FALSE);
}



BOOL    EXTERN GetCPTagSig(CHANDLE CP, SINT Index, LPCSIG lpCPTag)
{
    MEMPTR   TagData, ElemData;
    if (lpCPTag == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }
    if ( GetCPElementInfo(CP, Index, (LPMEMPTR) &TagData,
            (LPMEMPTR) &ElemData) )
    {
        *lpCPTag    = SigtoCSIG( ((lpcpTag)TagData)->sig ) ;
    }else
    {
        return(FALSE);
    }
    return(TRUE);
}

//***************************************************************
//      Function applicable to the elements
//
//***************************************************************

BOOL    EXTERN GetCPElementType(CHANDLE CP, SINT Index, LPCSIG lpCSig)
{
    MEMPTR   TagData, ElemData;
    if ( GetCPElementInfo(CP, Index, (LPMEMPTR) &TagData,
            (LPMEMPTR) &ElemData) )
    {
        *lpCSig    = SigtoCSIG( ((lpcpTagBase)ElemData)->sig ) ;
    }else
    {
        return(FALSE);
    }
    return(TRUE);
}



BOOL    EXTERN GetCPElementSize(CHANDLE CP, SINT Index, LPSINT lpSize)
{
    MEMPTR   TagData, ElemData;
    if (lpSize == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }

    if ( GetCPElementInfo(CP, Index, (LPMEMPTR) &TagData,
            (LPMEMPTR) &ElemData) )
    {
        *lpSize     = ui32toSINT( ((lpcpTag)TagData)->size );
    }else
    {
        return(FALSE);
    }

    return(TRUE);
}

BOOL    EXTERN GetCPElementDataSize(CHANDLE CP, SINT Index, LPSINT lpSize)
{
    MEMPTR  TagData, ElemData;
    if (lpSize == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }

    if ( GetCPElementInfo(CP, Index, (LPMEMPTR) &TagData,
            (LPMEMPTR) &ElemData) )
    {
//  Changed by jjia 8/24/95
//        *lpSize     = ui32toSINT( ((lpcpTag)TagData)->size ) -
//                                             sizeof(lpcpTagBase);
    *lpSize    = ui32toSINT( ((lpcpTag)TagData)->size) - 
                    sizeof(icTagBase) - sizeof(icUInt32Number);
    }else
    {
        return(FALSE);
    }

    return(TRUE);
}

//***************************************************************
//  The difference between GetCPElement and GetCPElementData
//  is that GetCPElement reads all fields of the element,
//  including the data tag, reserved fields and element data,
//  while GetCPElementData only reads the actual data.
//  Number of bytes that are required to hold the whole data element can be
//  obtained by calling the function GetCPElementSize().
//  The actulal number of data bytes is determined by
//  the call to GetCPElementDataSize().
//***************************************************************
BOOL    EXTERN GetCPElement(CHANDLE CP, SINT Index,
                               MEMPTR lpData, SINT Size)
{
    SINT        ElemSize;
    MEMPTR      TagData, ElemData;
    if (lpData == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }

    if ( !GetCPElementInfo(CP, Index, (LPMEMPTR) &TagData,
            (LPMEMPTR) &ElemData) )
    {
        return(FALSE);
    }
    ElemSize    = ui32toSINT( ((lpcpTag)TagData)->size);
    if(ElemSize > Size )
    {
        SetCPLastError(CP_NO_MEMORY_ERR);
        return(FALSE);
    }
    MemCopy(lpData, ElemData, ElemSize);
    return(TRUE);

}


BOOL    EXTERN GetCPElementData(CHANDLE CP, SINT Index,
                                MEMPTR lpData, SINT Size)
{
    SINT     ElemSize;
    MEMPTR   TagData, ElemData;
    if (lpData == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }

    if ( !GetCPElementInfo(CP, Index, (LPMEMPTR) &TagData,
            (LPMEMPTR) &ElemData) )
    {
        return(FALSE);
    }
//  Changed by jjia 8/24/95
//    ElemData    +=  sizeof(lpcpTagBase);
//    ElemSize    = ui32toSINT( ((lpcpTag)TagData)->size) - 
//                     sizeof(lpcpTagBase);
    ElemData    +=  sizeof(icTagBase) + sizeof(icUInt32Number);
    ElemSize    = ui32toSINT( ((lpcpTag)TagData)->size) - 
                    sizeof(icTagBase) - sizeof(icUInt32Number);

    if(ElemSize > Size )
    {
        SetCPLastError(CP_NO_MEMORY_ERR);
        return(FALSE);
    }

    MemCopy(lpData, ElemData, ElemSize);
    return(TRUE);
}

// Check the data format is binary or ascii    8/22/95  jjia

BOOL    EXTERN GetCPElementDataType(CHANDLE CP, SINT Index, long far *lpDataType)
{
    MEMPTR   TagData, ElemData;

    if (lpDataType == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }

    if ( !GetCPElementInfo(CP, Index, (LPMEMPTR) &TagData,
            (LPMEMPTR) &ElemData) )
    {
        return(FALSE);
    }
    ElemData    +=  sizeof(icTagBase);
    *lpDataType = ui32toSINT( ((icData __huge *)ElemData)->dataFlag);
    return (TRUE);
}

BOOL    EXTERN ValidateCPElement(CHANDLE CP, SINT Index)
{
    CSIG    TagSig, DataSig;
    BOOL    Result;
    if( GetCPTagSig(CP, Index, (LPCSIG) &TagSig) &&
        GetCPElementType(CP, Index, (LPCSIG) &DataSig) )
    {
        switch(TagSig)
        {
            case     icSigAToB0Tag:
            case     icSigAToB1Tag:
            case     icSigAToB2Tag:
            case     icSigBToA0Tag:
            case     icSigBToA1Tag:
            case     icSigBToA2Tag:
            case     icSigGamutTag:
            case     icSigPreview0Tag:
            case     icSigPreview1Tag:
            case     icSigPreview2Tag:
                Result = (DataSig == icSigLut16Type) ||
                         (DataSig == icSigLut8Type) ;
                break;

            case     icSigRedColorantTag: 
            case     icSigGreenColorantTag:
            case     icSigBlueColorantTag:
            case     icSigLuminanceTag:
            case     icSigMediaBlackPointTag:
            case     icSigMediaWhitePointTag:
                Result = (DataSig == icSigXYZType);
                break;

            case     icSigRedTRCTag:
            case     icSigGreenTRCTag:
            case     icSigBlueTRCTag:
            case     icSigGrayTRCTag:
                Result = (DataSig == icSigCurveType);
                break;

            case     icSigPs2CRD0Tag:
            case     icSigPs2CRD1Tag:
            case     icSigPs2CRD2Tag:
            case     icSigPs2CRD3Tag:
            case     icSigPs2CSATag:
            case     icSigPs2Intent0Tag:
            case     icSigPs2Intent1Tag:
            case     icSigPs2Intent2Tag:
            case     icSigPs2Intent3Tag:
                Result = (DataSig == icSigDataType);
                break;

            case     icSigCharTargetTag:
            case     icSigCopyrightTag:
                Result = (DataSig == icSigTextType);
                break;

            case     icSigCalibrationDateTimeTag:
                Result = (DataSig == icSigDateTimeType);
                break;

            case     icSigDeviceMfgDescTag:
            case     icSigDeviceModelDescTag:
            case     icSigProfileDescriptionTag:
            case     icSigScreeningDescTag:
            case     icSigViewingCondDescTag:
                Result = (DataSig == icSigTextDescriptionType);
                break;

            case     icSigMeasurementTag:
                Result = (DataSig == icSigMeasurementTag);
                break;

            case     icSigNamedColorTag:
                Result = (DataSig == icSigNamedColorTag);
                break;
        
            case      icSigProfileSequenceDescTag:
                Result = (DataSig == icSigProfileSequenceDescTag);
                break;

            case     icSigScreeningTag:
                Result = (DataSig == icSigScreeningTag);
                break;

            case     icSigTechnologyTag:
                Result = (DataSig == icSigSignatureType);
                break;

            case     icSigUcrBgTag:
                Result = (DataSig == icSigUcrBgTag);
                break;

            case     icSigViewingConditionsTag:
                Result = (DataSig == icSigViewingConditionsTag);
                break;

            default:
                Result = TRUE;
                break;
        }
    }else
    {
        Result = FALSE;
    }
    return(Result);
}

//******************************************************************
// Functions that get all information from the Color Profile Header
//******************************************************************
BOOL    EXTERN GetCPSize(CHANDLE CP, LPSINT lpSize)
{
    if (lpSize == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }
    *lpSize    = ui32toSINT( ((lpcpHeader)CP)->size);
    return(TRUE);
}

BOOL    EXTERN GetCPCMMType(CHANDLE CP, LPCSIG lpType)
{
    if (lpType == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }
    *lpType    = SigtoCSIG( ((lpcpHeader)CP)->cmmId);
    return(TRUE);
}

BOOL    EXTERN GetCPVersion(CHANDLE CP, LPSINT lpVers)
{
    if (lpVers == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }
    *lpVers    = ui32toSINT( ((lpcpHeader)CP)->version);
    return(TRUE);
}

BOOL    EXTERN GetCPClass(CHANDLE CP, LPCSIG lpClass)
{
    if (lpClass == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }
    *lpClass    = SigtoCSIG( ((lpcpHeader)CP)->deviceClass);
    return(TRUE);
}

BOOL    EXTERN GetCPDevSpace(CHANDLE CP, LPCSIG lpInSpace)
{
    if (lpInSpace == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }
    *lpInSpace    = SigtoCSIG( ((lpcpHeader)CP)->colorSpace);
    return(TRUE);
}

BOOL    EXTERN GetCPConnSpace(CHANDLE CP, LPCSIG lpOutSpace)
{
    if (lpOutSpace == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }
    *lpOutSpace    = SigtoCSIG( ((lpcpHeader)CP)->pcs);
    return(TRUE);
}

BOOL    EXTERN GetCPTarget(CHANDLE CP, LPCSIG lpTarget)
{
    if (lpTarget == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }
    *lpTarget    = SigtoCSIG( ((lpcpHeader)CP)->platform);
    return(TRUE);
}

BOOL    EXTERN GetCPManufacturer(CHANDLE CP, LPCSIG lpManuf)
{
    if (lpManuf == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }
    *lpManuf    = SigtoCSIG( ((lpcpHeader)CP)->manufacturer);
    return(TRUE);
}

BOOL    EXTERN GetCPModel(CHANDLE CP, LPCSIG lpModel)
{
    if (lpModel == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }
    *lpModel    = SigtoCSIG( ((lpcpHeader)CP)->model);
    return(TRUE);
}

BOOL    EXTERN GetCPFlags(CHANDLE CP, LPSINT lpFlags)
{
    if (lpFlags == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }
    *lpFlags    = ui32toSINT( ((lpcpHeader)CP)->flags);
    return(TRUE);
}

BOOL    EXTERN GetCPRenderIntent(CHANDLE CP, LPSINT lpIntent)
{
    if (lpIntent == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }
    *lpIntent    = ui32toSINT( ((lpcpHeader)CP)->renderingIntent);
    return(TRUE);
}

BOOL    EXTERN GetCPWhitePoint(CHANDLE CP,  LPSFLOAT lpWP)
{
    if (lpWP == NULL)
    {
        SetCPLastError(CP_NULL_POINTER_ERR);
        return(FALSE);
    }
    lpWP[0]    = (SFLOAT) si16f16toSFLOAT( ((lpcpHeader)CP)->illuminant.X);
    lpWP[1]    = (SFLOAT) si16f16toSFLOAT( ((lpcpHeader)CP)->illuminant.Y);
    lpWP[2]    = (SFLOAT) si16f16toSFLOAT( ((lpcpHeader)CP)->illuminant.Z);
    return(TRUE);
}

BOOL    EXTERN GetCPAttributes(CHANDLE CP, LPATTRIB lpAttributes)
{
    return(TRUE);
}

BOOL    EXTERN GetCPMediaWhitePoint(CHANDLE cp,  LPSFLOAT lpMediaWP)
{
    HGLOBAL   hTempMem;
    SINT      TempSize;
    MEMPTR    TempBuff;
    MEMPTR    lpTable;
    SINT      i, Index;

    if (DoesCPTagExist (cp, icSigMediaWhitePointTag) &&
        GetCPTagIndex (cp, icSigMediaWhitePointTag, (LPSINT) & Index) &&
        GetCPElementSize (cp, Index, (LPSINT) & TempSize) &&
        MemAlloc (TempSize, (HGLOBAL *) & hTempMem, (LPMEMPTR) & TempBuff) &&
        GetCPElement (cp, Index, TempBuff, TempSize))
    {
        lpTable = (MEMPTR) & (((lpcpXYZType) TempBuff)->data);
        for (i = 0; i < 3; i++)
        {
            lpMediaWP[i] = (SFLOAT) si16f16toSFLOAT (lpTable);
            lpTable += sizeof (icS15Fixed16Number);
        }
        MemFree (hTempMem);
        return (TRUE);
    }
    return (FALSE);
}

/***************************************************************************
*                               GetPS2ColorRenderingIntent
*  function:
*    this is the function which creates the Intent string 
*    from the data supplied in the Profile that can be used
*    in --findcolorrendering-- operator.
*  prototype:
*       BOOL EXTERN GetPS2ColorRenderingIntent(
*                          char         *FileName,
*                          DWORD        Intent, 
*                          MEMPTR       lpMem,
*                          LPDWORD      lpcbSize )
*  parameters:
*       FileName    --  Color Profile Filename
*       Intent      --  Intent 
*       lpMem       --  Pointer to the memory block
*       lpcbSize        --  Size of the memory block
*                       Returns number of bytes required/transferred
*  returns:
*       BOOL        --  TRUE   if the function was successful,
*                       FALSE  otherwise.
***************************************************************************/
BOOL EXTERN GetPS2ColorRenderingIntent(CHANDLE cp, DWORD Intent,
                                       MEMPTR lpMem, LPDWORD lpcbSize)
{
    SINT       Index;
    SINT       Size;
        
    if (!cp)
        return FALSE;

    Size = (SINT) *lpcbSize;
    if( ( lpMem == NULL ) || ( Size == 0 ) )
    {
        lpMem = NULL;
        Size = 0;
        *lpcbSize = 0;
    }
        
    switch(Intent)
    {
        case icPerceptual:
        if( DoesCPTagExist(cp, icSigPs2Intent0Tag) &&
            GetCPTagIndex(cp, icSigPs2Intent0Tag, (LPSINT) &Index) &&
            GetCPElementDataSize(cp, Index, (LPSINT) &Size) &&
            ( ( lpMem == NULL ) ||
                GetCPElementData(cp, Index, lpMem, Size) ) )
        {
        }
        break;
        
        case icRelativeColorimetric:
        if( DoesCPTagExist(cp, icSigPs2Intent1Tag) &&
            GetCPTagIndex(cp, icSigPs2Intent1Tag, (LPSINT) &Index) &&
            GetCPElementDataSize(cp, Index, (LPSINT) &Size) &&
            ( ( lpMem == NULL ) ||
                GetCPElementData(cp, Index, lpMem, Size) ) )
        {
        }
        break;
    
        case icSaturation:
        if( DoesCPTagExist(cp, icSigPs2Intent2Tag) &&
            GetCPTagIndex(cp, icSigPs2Intent2Tag, (LPSINT) &Index) &&
            GetCPElementDataSize(cp, Index, (LPSINT) &Size) &&
            ( ( lpMem == NULL ) ||
                GetCPElementData(cp, Index, lpMem, Size ) )
          )
        {
        }
        break;
        case icAbsoluteColorimetric:
        if( DoesCPTagExist(cp, icSigPs2Intent3Tag) &&
            GetCPTagIndex(cp, icSigPs2Intent3Tag, (LPSINT) &Index) &&
            GetCPElementDataSize(cp, Index, (LPSINT) &Size) &&
            ( ( lpMem == NULL ) ||
                GetCPElementData(cp, Index, lpMem, Size) ) )
        {
        }
        break;
        default:
            Size = 0 ;
        break;
    }
        
    if (Size != 0)
    {
        if (lpMem)
        {
            lpMem[Size] = '\0';
        }
        Size ++;
        *lpcbSize = (DWORD) Size;
        return (TRUE);
    }
    else
    {
        return(FALSE);
    }
}

/***************************************************************************
*
*  Function to check if color matching mathod and icc profile type is 
*       supported by driver.
*  parameters:
*
*  returns:
*       BOOL:   TRUE or FALSE.
*
***************************************************************************/

#ifndef ICMDLL
BOOL EXTERN ValidColorSpace(LPPDEVICE lppd, LPICMINFO lpICMI, LPCSIG lpDevCS )
{
    icHeader    CPHeader;
    HFILE       hFile;
    SINT        Res;
    CSIG        CPColorSpaceTag;

    if (NULL == lpICMI)
    {
        return(FALSE);
    }
    hFile = _lopen(lpICMI->lcsDestFilename, READ);
    if( hFile == HFILE_ERROR )
    {
        return(FALSE);
    }

    Res = _lread(hFile, (LPVOID) &CPHeader, sizeof(CPHeader));
    _lclose(hFile);
    if( (Res == HFILE_ERROR) || (Res != sizeof(CPHeader)) )
    {
        return(FALSE);
    }

    // Make the initial check for validity of the profile
    if( SigtoCSIG(CPHeader.magic) != icMagicNumber )
    {
        return(FALSE);
    }
    // Make sure the profile is 'prtr'
    // SRGB98
    // if( SigtoCSIG(CPHeader.deviceClass) != icSigOutputClass )
    // {
    //     return(FALSE);
    // }
    CPColorSpaceTag = SigtoCSIG(CPHeader.colorSpace);
    *lpDevCS = CPColorSpaceTag;             // 247974

    switch ( lppd->lpPSExtDevmode->dm.iColorMatchingMethod )
    {
        case COLOR_MATCHING_ON_HOST:
            if ((CPColorSpaceTag == icSigCmyData))
//                (CPColorSpaceTag == icSigRgbData))
//                (CPColorSpaceTag == icSigGrayData))
            {
                return(FALSE);
            }
            break;
            case COLOR_MATCHING_ON_PRINTER:
            if ((CPColorSpaceTag == icSigCmyData))
//                (CPColorSpaceTag == icSigGrayData))
            {
                return(FALSE);
            }
            break;
        case COLOR_MATCHING_PRINTER_CALIBRATION:
        default:
            break;
    }
    return (TRUE);
}
#endif

//***************************************************************************
//
//      Set of functions to output data into memory buffer
//
//***************************************************************************


/***************************************************************************
*
*   Function to put the chunk of memory as string of Hex
*
***************************************************************************/
SINT    WriteHexBuffer(MEMPTR lpMem, MEMPTR lpBuff, MEMPTR lpLineStart, DWORD dwBytes)
{
    SINT    Res;
    char    TempArray[TempBfSize];
    MEMPTR  lpOldPtr = lpMem;

    for ( ; dwBytes ; dwBytes-- )
    {
        Res = wsprintf( (MEMPTR)TempArray, (LPSTR) "%2.2x", *lpBuff );
        *lpMem++ = TempArray[0];
        *lpMem++ = TempArray[1];
        lpBuff++;
        if (((SINT)(lpMem - lpLineStart)) > MAX_LINELENG)
        {
            lpLineStart = lpMem;
            lpMem += WriteObject(lpMem,  NewLine);
        }
    }
    return( (SINT)(lpMem - lpOldPtr)); 
}

/***************************************************************************
*
*   Function to put the string into the buffer
*
***************************************************************************/
SINT    WriteNewLineObject(MEMPTR lpMem, MEMPTR Obj)
{
    SINT    Res1, Res2;

    Res1 = lstrlen(NewLine);
    MemCopy(lpMem, NewLine, Res1);

    lpMem += Res1;
    Res2 = lstrlen(Obj);
    MemCopy(lpMem, Obj, Res2);
    return( Res1 + Res2 );
}

SINT    WriteObject(MEMPTR lpMem, MEMPTR Obj)
{
    SINT    Res;

    Res = lstrlen(Obj);
    MemCopy(lpMem, Obj, Res);
    return( Res );
}

SINT    WriteObjectN(MEMPTR lpMem, MEMPTR Obj, SINT n)
{
    MemCopy(lpMem, Obj, n);
    return( n );
}
/***************************************************************************
*
*   Function to write the integer into the buffer
*
***************************************************************************/
SINT WriteInt(MEMPTR lpMem, SINT Number)
{
    SINT    Res;
    char    TempArray[TempBfSize];
    
    Res = wsprintf( (MEMPTR)TempArray, "%lu ", Number );
    MemCopy(lpMem, TempArray, lstrlen(TempArray));
    return( Res );
}

/***************************************************************************
*
*   Function to write the integer into the buffer as hex
*
***************************************************************************/
SINT WriteHex(MEMPTR lpMem, SINT Number)
{
    SINT    Res;
    char    TempArray[TempBfSize];

    Res = wsprintf( TempArray, "%2.2x", (int)(Number & 0x00FF) );
    MemCopy(lpMem, TempArray, lstrlen(TempArray));
    return( Res );
}

/***************************************************************************
*
*   Function to write the float into the buffer
*
***************************************************************************/

SINT WriteFloat(MEMPTR lpMem, double dFloat)
{
    char    cSign;
    double  dInt ;
    double  dFract ;
    LONG    lFloat ;
    SINT    Res;
    char    TempArray[TempBfSize];

    lFloat = (LONG) floor( dFloat * 10000.0 + 0.5);

    dFloat = lFloat  / 10000.0 ;

    dInt = floor(fabs(dFloat));
    dFract =  fabs(dFloat) - dInt ;

    cSign   = ' ' ;
    if ( dFloat < 0 )
    {
        cSign   = '-' ;
    }

    Res = wsprintf( (LPSTR) TempArray, (LPSTR) "%c%d.%0.4lu ",
       cSign, (WORD) dInt , (DWORD) (dFract *10000.0)  );
    MemCopy(lpMem, TempArray, lstrlen(TempArray));
    return ( Res );
}

/***************************************************************************
*
*   Function to write the string token into the buffer
*
***************************************************************************/

SINT    WriteStringToken(MEMPTR lpMem, BYTE Token, SINT sNum)
{
    *lpMem++ = Token;
    *lpMem++ = (BYTE)((sNum & 0xFF00) >> 8);
    *lpMem++ = (BYTE)(sNum & 0x00FF);
    return (3);
}

/***************************************************************************
*
*   Function to write the Homogeneous Number Array token into the buffer
*
***************************************************************************/

SINT    WriteHNAToken(MEMPTR lpMem, BYTE Token, SINT sNum)
{
    *lpMem++ = Token;
    *lpMem++ = 32;       // 16-bit fixed integer, high-order byte first
    *lpMem++ = (BYTE)((sNum & 0xFF00) >> 8);
    *lpMem++ = (BYTE)(sNum & 0x00FF);
    return (4);
}

/***************************************************************************
*
*   Function to convert 2-bytes unsigned integer to 2-bytes signed 
*   integer(-32768) and write them to the buffer. High byte first.
*
***************************************************************************/

SINT    WriteIntStringU2S(MEMPTR lpMem, MEMPTR lpBuff, SINT sNum)
{
    SINT    i;
    SINT    Temp;

    for (i = 0; i < sNum; i ++)
    {
        Temp = ui16toSINT( lpBuff) - 32768;
        *lpMem++ = (BYTE)((Temp & 0xFF00) >> 8);
        *lpMem++ = (BYTE)(Temp & 0x00FF);
        lpBuff += sizeof(icUInt16Number);
    }
    return(sNum * 2); 
}

/***************************************************************************
*
*   Function to convert 2-bytes unsigned integer to 2-bytes signed 
*   integer(-32768) and write them to the buffer. Low-order byte first.
*
***************************************************************************/

SINT    WriteIntStringU2S_L(MEMPTR lpMem, MEMPTR lpBuff, SINT sNum)
{
    SINT    i;
    SINT    Temp;

    for (i = 0; i < sNum; i ++)
    {
        Temp = (SINT)*((PUSHORT)lpBuff) - 32768;
        *lpMem++ = (BYTE)((Temp & 0xFF00) >> 8);
        *lpMem++ = (BYTE)(Temp & 0x00FF);
        lpBuff += sizeof(icUInt16Number);
    }
    return(sNum * 2); 
}

/***************************************************************************
*
*   Function to put the chunk of memory into buffer
*
***************************************************************************/
SINT    WriteByteString(MEMPTR lpMem, MEMPTR lpBuff, SINT sBytes)
{
    SINT    i;

    for (i = 0; i < sBytes; i ++)
        *lpMem++ = *lpBuff++;
    
    return(sBytes); 
}

/***************************************************************************
*
*   Function to put the chunk of memory into buffer
*
***************************************************************************/
SINT    WriteInt2ByteString(MEMPTR lpMem, MEMPTR lpBuff, SINT sBytes)
{
    SINT    i;

       for( i = 0; i < sBytes ; i++)
    {
        *lpMem++ = (BYTE)(ui16toSINT( lpBuff)/256) ;
        lpBuff += sizeof(icUInt16Number);
    }
    return(sBytes); 
}

/***************************************************************************
*
*  Function to control ascii85 encoding.
*  parameters:
*       lpDest      --  Pointer to the encording result buffer.
*       BufSize     --  Size of encording result buffer. 
*       lpSource    --  Pointer to the input buffer
*       DataSize    --  Size of the input buffer
*  returns:
*       SINT        --  Number of bytes actually outputed.
*
****************************************************************************/

SINT    WriteASCII85Cont(MEMPTR lpDest, SINT BufSize, MEMPTR lpSource, SINT DataSize)
{
   SINT     incount;
   MEMPTR   lpPtr, lpSave;
   SINT     rem;
   SINT     bcount;
   SINT     dex;
   unsigned long word;
   
   /* encode the initial 4-tuples */
   lpSave = lpDest;
   lpPtr  = lpSource;
   word   = 0UL;
   bcount = 0;

   for (incount = 0; incount < DataSize; incount ++)
   {
      if ( incount  && ((incount % LINELENG) == 0) )
      lpDest += WriteObject(lpDest,  NewLine);
      word = (word<<8);
      word |= (BYTE)*lpPtr++;
      if (bcount == 3)
      {
         lpDest += WriteAscii85(lpDest, word, 5);
         word = 0UL;
         bcount = 0;
      }
      else
      {
         bcount ++;
      }
   }
   
   /* now do the last partial 4-tuple -- if there is one */
   /* see the Red Book spec for the rules on how this is done */
   if (bcount > 0)
   {
      rem = 4 - bcount;  /* count the remaining bytes */
      for (dex = 0; dex < rem; dex ++) /* shift left for each of them */
      {
         word = (word<<8);      /* (equivalent to adding in ZERO's)*/
         word |= (BYTE)32;
      }
//      lpDest += WriteAscii85(lpDest, word, (bcount + 1));  /* output only meaningful
      lpDest += WriteAscii85(lpDest, word, 5);               /* output only meaningful bytes + 1 */
   }
   return (lpDest - lpSave);
}

/************************************************************************
*
*  Function to convert 4 bytes binary data to 5 bytes ascii85 encorded data.
*  parameters:
*       lpDest      --  Pointer to the encording result buffer.
*       inWord      --  Input word (4-bytes) 
*       nBytes      --  Number of bytes should be outputed.
*  returns:
*       SINT        --  Number of bytes actually outputed.
* 
*************************************************************************/

SINT    WriteAscii85(MEMPTR lpDest, unsigned long inWord, SINT nBytes)
{
    unsigned long divisor;
    int      bcount;
    BYTE     outchar;
    MEMPTR   lpSave = lpDest;

    if ((inWord == 0UL) && (nBytes == 5))
        *lpDest++ = 'z';
    else
    {
        divisor = 52200625UL;
        for (bcount = 0; bcount < nBytes; bcount ++)
        { 
            outchar = (BYTE)((int)(inWord/divisor) + (int)'!');
            *lpDest++ = outchar;
            if (bcount < 4)
            {
                inWord = (inWord % divisor);
                divisor =(divisor / 85);
            }
        }
    }
    return (SINT)(lpDest - lpSave);
}

/***************************************************************************
*
*  Function to convert binary data to ascii by performing ASCII85 encording
*  parameters:
*       lpMem       --  A pointer to the buffer. 
*                       as input: contains binary data; 
*                       as output: contains ascii data. 
*       DataSize    --  The size of input binary data. 
*       BufSize     --  The size of buffer pointed by lpMem.
*  returns:
*       SINT        --  Number of bytes actually outputed.
*
***************************************************************************/

SINT    ConvertBinaryData2Ascii(MEMPTR lpMem, SINT DataSize, SINT BufSize)
{
    MEMPTR      intrbuf, Temp;
    HANDLE      intrhandle;
    SINT        AsciiDataSize = 0;

    if (BufSize >= (SINT)(DataSize/4*5 + sizeof(ASCII85DecodeBegine)+sizeof(ASCII85DecodeEnd) + 2048))
    {
        if ((intrhandle = GlobalAlloc(GHND, BufSize)) != NULL)
        {
            if ((intrbuf = (MEMPTR) GlobalLock(intrhandle)) != NULL)
            {
                Temp = intrbuf;
                Temp += WriteObject(Temp,  NewLine);
                Temp += WriteObject(Temp,  ASCII85DecodeBegine);
                Temp += WriteObject(Temp,  NewLine);
                Temp += WriteASCII85Cont(Temp, BufSize, lpMem, DataSize);
                Temp += WriteObject(Temp,  ASCII85DecodeEnd);
                AsciiDataSize = (SINT)(Temp - intrbuf);
                lstrcpyn(lpMem, intrbuf, (WORD)AsciiDataSize); 
                GlobalUnlock(intrhandle);
            }
        }
        GlobalFree(intrhandle);
   }
   return (AsciiDataSize);
}

/***************************************************************************
*
*  Function to check if it is need to convert a CRD from binary to ascii
*  parameters:
*       CP          --  Handle of memory block which contains icm profile.
*       Index       --  Index of the element data of the profile.
*       lpData      --  A pointer to the buffer. 
*                       as input: contains binary data; 
*                       as output: contains ascii data. 
*       BufSize     --  The size of the buffer pointed by lpData.
*       DataSize    --  The size of input binary data.
*       AllowBinary --  Allow binary or not(1/0).
*  returns:
*       SINT        --  Number of bytes required/actually outputed.
*
***************************************************************************/

SINT    Convert2Ascii(CHANDLE CP, SINT Index,
                      MEMPTR lpData, SINT BufSize, 
                      SINT DataSize, BOOL AllowBinary)
{
    long    DataType;

    GetCPElementDataType(CP, Index, &DataType);
    if (BufSize == 0)
    {
        if (AllowBinary)
            return (DataSize);
        else if (DataType == 0)    // Ascii data in Profile 
            return (DataSize);
        else                       // Keep space for ascii85 encoding.
            return (DataSize / 4 * 5 + sizeof(ASCII85DecodeBegine)+sizeof(ASCII85DecodeEnd) + 2048);
    }
    else
    {
        if (AllowBinary)
            return (DataSize);
        else if(DataType == 0) 
            return (DataSize);
        else 
            return (ConvertBinaryData2Ascii(lpData, DataSize, BufSize) );
    }
}

#ifdef ICMDLL
SINT    MemCopy(MEMPTR Dest, MEMPTR Source, SINT Length)
{
    SINT    i;

    for (i = 0; i < Length; i++)
    {
        Dest[i] = Source[i];
    }
    return( Length );
}

// SRGB98
BOOL EXTERN InvertMatrix (double FAR * lpInMatrix,
                   double FAR * lpOutMatrix)
{
    double det;

    double FAR *a;
    double FAR *b;
    double FAR *c;
    if ((NULL == lpInMatrix) ||
        (NULL == lpOutMatrix))
    {
        return (FALSE);
    }
    a = (double FAR *) &(lpInMatrix[0]);
    b = (double FAR *) &(lpInMatrix[3]);
    c = (double FAR *) &(lpInMatrix[6]);

    det = a[0] * b[1] * c[2] + a[1] * b[2] * c[0] + a[2] * b[0] * c[1] -
        (a[2] * b[1] * c[0] + a[1] * b[0] * c[2] + a[0] * b[2] * c[1]);

    if (det == 0.0)                     // What to do?
    {
        lpOutMatrix[0] = 1.0;
        lpOutMatrix[1] = 0.0;
        lpOutMatrix[2] = 0.0;

        lpOutMatrix[3] = 0.0;
        lpOutMatrix[4] = 1.0;
        lpOutMatrix[5] = 0.0;

        lpOutMatrix[6] = 0.0;
        lpOutMatrix[7] = 0.0;
        lpOutMatrix[8] = 1.0;
        return (FALSE);
    } else
    {
        lpOutMatrix[0] = (b[1] * c[2] - b[2] * c[1]) / det;
        lpOutMatrix[3] = -(b[0] * c[2] - b[2] * c[0]) / det;
        lpOutMatrix[6] = (b[0] * c[1] - b[1] * c[0]) / det;

        lpOutMatrix[1] = -(a[1] * c[2] - a[2] * c[1]) / det;
        lpOutMatrix[4] = (a[0] * c[2] - a[2] * c[0]) / det;
        lpOutMatrix[7] = -(a[0] * c[1] - a[1] * c[0]) / det;

        lpOutMatrix[2] = (a[1] * b[2] - a[2] * b[1]) / det;
        lpOutMatrix[5] = -(a[0] * b[2] - a[2] * b[0]) / det;
        lpOutMatrix[8] = (a[0] * b[1] - a[1] * b[0]) / det;
        return (TRUE);
    }
}

#endif

