/* $Xorg: loadData.c,v 1.4 2000/08/17 19:54:13 cpqbld Exp $ */

/*
 * (c) Copyright 1990 Tektronix Inc.
 * 	All Rights Reserved
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that
 * both that copyright notice and this permission notice appear in
 * supporting documentation, and that the name of Tektronix not be used
 * in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.
 *
 * Tektronix disclaims all warranties with regard to this software, including
 * all implied warranties of merchantability and fitness, in no event shall
 * Tektronix be liable for any special, indirect or consequential damages or
 * any damages whatsoever resulting from loss of use, data or profits,
 * whether in an action of contract, negligence or other tortious action,
 * arising out of or in connection with the use or performance of this
 * software.
 *
 *
 *	NAME
 *		LoadSCCData.c
 *
 *	DESCRIPTION
 *		TekCMS API routine that reads screen data from a file
 *	        and then loads the data on the root window of the screen.
 *
 *
 *
 */
/* $XFree86: xc/programs/xcmsdb/loadData.c,v 3.3 2001/07/25 15:05:18 dawes Exp $ */

/*
 *      INCLUDES
 */

#include <X11/Xos.h>
#include <sys/stat.h>
#include <stdio.h>

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include "SCCDFile.h"


/*
 *      EXTERNS
 *              External declarations required locally to this package
 *              that are not already declared in any of the included header
 *		files (external includes or internal includes).
 */

#include <stdlib.h>

/*
 *      LOCAL TYPEDEFS
 *              typedefs local to this package (for use with local vars).
 *
 */

typedef struct _DefineEntry {
    const char	*pString;
    int		define;
} DefineEntry;


/*
 *      LOCAL VARIABLES
 */
static int linenum = 0;

static DefineEntry KeyTbl[] = {
    { SC_BEGIN_KEYWORD,			SC_BEGIN },
    { SC_END_KEYWORD,			SC_END },
    { COMMENT_KEYWORD,			COMMENT },
    { NAME_KEYWORD,			NAME },
    { MODEL_KEYWORD,			MODEL },
    { PART_NUMBER_KEYWORD,		PART_NUMBER },
    { SERIAL_NUMBER_KEYWORD,		SERIAL_NUMBER },
    { REVISION_KEYWORD,			REVISION },
    { SCREEN_CLASS_KEYWORD,		SCREEN_CLASS },
    { COLORIMETRIC_BEGIN_KEYWORD,	COLORIMETRIC_BEGIN },
    { COLORIMETRIC_END_KEYWORD,		COLORIMETRIC_END },
    { XYZTORGBMAT_BEGIN_KEYWORD,	XYZTORGBMAT_BEGIN },
    { XYZTORGBMAT_END_KEYWORD,		XYZTORGBMAT_END },
    { WHITEPT_XYZ_BEGIN_KEYWORD,	WHITEPT_XYZ_BEGIN },
    { WHITEPT_XYZ_END_KEYWORD,		WHITEPT_XYZ_END },
    { RGBTOXYZMAT_BEGIN_KEYWORD,	RGBTOXYZMAT_BEGIN },
    { RGBTOXYZMAT_END_KEYWORD,		RGBTOXYZMAT_END },
    { IPROFILE_BEGIN_KEYWORD,		IPROFILE_BEGIN },
    { IPROFILE_END_KEYWORD,		IPROFILE_END },
    { ITBL_BEGIN_KEYWORD,		ITBL_BEGIN },
    { ITBL_END_KEYWORD,			ITBL_END },
    { "",				-1 }
};

static DefineEntry ScrnClassTbl[] = {
    { VIDEO_RGB_KEYWORD,		VIDEO_RGB },
#ifdef GRAY
    { VIDEO_GRAY_KEYWORD,		VIDEO_GRAY },
#endif /* GRAY */
    { "",				-1 }
};

#define KEY_VISUALID		1
#define KEY_DEPTH		2
#define KEY_CLASS		3
#define KEY_RED_MASK		4
#define KEY_GREEN_MASK		5
#define KEY_BLUE_MASK		6
#define KEY_COLORMAP_SIZE	7
#define KEY_BITS_PER_RGB	8

static DefineEntry VisualOptKeyTbl[] = {
    { "visualid",		KEY_VISUALID },
    { "depth",			KEY_DEPTH },
    { "class",			KEY_CLASS },
    { "red_mask",		KEY_RED_MASK },
    { "green_mask",		KEY_GREEN_MASK },
    { "blue_mask",		KEY_BLUE_MASK },
    { "colormap_size",		KEY_COLORMAP_SIZE },
    { "bits_per_rgb",		KEY_BITS_PER_RGB },
    { "",			-1 }
};

static DefineEntry VisualClassTbl[] = {
    { "StaticGray",		StaticGray },
    { "GrayScale",		GrayScale },
    { "StaticColor",		StaticColor },
    { "PseudoColor",		PseudoColor },
    { "TrueColor",		TrueColor },
    { "DirectColor",		DirectColor },
    { "",			-1 }
};


/************************************************************************
 *									*
 *			 PRIVATE ROUTINES				*
 *									*
 ************************************************************************/

/*
 *	NAME
 *		StrToDefine - convert a string to a define
 *
 *	SYNOPSIS
 */
static int
StrToDefine(DefineEntry pde[],   /* IN: table of X string-define pairs     */
                                 /*     last entry must contain pair "", 0 */
            const char *pstring) /* IN: string to be looked up in that table */
/*
 *	DESCRIPTION
 *		Converts a string to an integer define.
 *
 *		Looks up the string in the table and returns the integer
 *		associated with the string.
 *
 *		Later may need similar function for unsigned long define.
 *
 *
 *
 *	RETURNS
 *		The int equivalent of the defined string.
 *		-1 if the string is not found in table
 *
 */
{
    while (strcmp(pde->pString, "") != 0) {
        if (strcmp(pde->pString, pstring) == 0) {
            return (pde->define);
        }
        pde++;
    }
    return (-1);
}

/*
 *	NAME
 *		DefineToStr
 *
 *	SYNOPSIS
 */
static const char *
DefineToStr(DefineEntry pde[],  /* IN: table of X string-define pairs */
                                /*     last entry must contain pair "", 0 */
            int id)             /* IN: id to be looked up in that table   */
/*
 *	DESCRIPTION
 *		Converts a string to an integer define.
 *
 *		Looks up the string in the table and returns the integer
 *		associated with the string.
 *
 *		Later may need similar function for unsigned long define.
 *
 *
 *
 *	RETURNS
 *		The int equivalent of the defined string.
 *		-1 if the string is not found in table
 *
 */
{
    while (pde->define != -1) {
        if (pde->define == id) {
            return (pde->pString);
        }
        pde++;
    }
    return (NULL);
}

/*
 *	NAME
 *		SCKeyOf - convert keyword into key ID
 *
 *	SYNOPSIS
 */
static int
SCKeyOf(const char *string)
/*
 *	DESCRIPTION
 *		Converts a string to an integer define.
 *
 *		Looks up the string in the table and returns the integer
 *		associated with the string.
 *
 *		Later may need similar function for unsigned long define.
 *
 *
 *
 *	RETURNS
 *		The int equivalent of the defined string.
 *		-1 if the string is not found in table
 *
 */
{
    return (StrToDefine(KeyTbl, string));
}

/*
 *	NAME
 *		SCScrnClassOf - convert screen class string into class ID
 *
 *	SYNOPSIS
 */
static int
SCScrnClassOf(const char *string)
/*
 *	DESCRIPTION
 *		Converts a string to an integer define.
 *
 *		Looks up the string in the table and returns the integer
 *		associated with the string.
 *
 *		Later may need similar function for unsigned long define.
 *
 *
 *
 *	RETURNS
 *		The int equivalent of the defined string.
 *		-1 if the string is not found in table
 *
 */
{
    return (StrToDefine(ScrnClassTbl, string));
}

/*
 *	NAME
 *		SCScrnClassStringOf - convert screen class id into class string
 *
 *	SYNOPSIS
 */
static const char *
SCScrnClassStringOf(int id)
/*
 *	DESCRIPTION
 *		Converts a id to astring
 *
 *	RETURNS
 *		Pointer to string if found; otherwise NULL.
 *
 */
{
    return (DefineToStr(ScrnClassTbl, id));
}

/* close the stream and return any memory allocated. */
static void
closeS(FILE *stream, XDCCC_Correction *pCorrection)
{
    XDCCC_Correction *pNext;

    if (stream) {
        fclose(stream);
    }
    while (pCorrection) {
        pNext = pCorrection->next;
        free(pCorrection);
        pCorrection = pNext;
    }
}

/*
 *  Get a line of text from the stream.
 */
static char *
nextline(char *buf, int maxch, FILE *stream)
{
    linenum++;
    return (fgets(buf, maxch, stream));
}

static int
ProcessColorimetric(FILE *stream, XDCCC_Matrix *pMatrix, int VisualFlag)
{
    char buf[BUFSIZ];
    char keyword[BUFSIZ];
    char token[BUFSIZ], *ptoken;
    int  ntok;
    unsigned int matrices_processed = 0;
		/* bit 0 for XYZtoRGB matrix */
		/* bit 1 for RGBtoXYZ matrix */
    int	 state = 0;
		 /* 0 -- looking for matrix */
		 /* 1 -- processing data from matrix */
		 /* 2 -- both matrices processed */
		 /* Note: the order of the matrices is not important. */
    int	 count = -1;
    XcmsFloat *pElement = NULL;

    while ((nextline(buf, BUFSIZ, stream)) != NULL) {
        if ((ntok = sscanf(buf, "%s %s", keyword, token)) > 0) {
            switch (SCKeyOf(keyword)) {
            case XYZTORGBMAT_BEGIN:
                if (VisualFlag != VIDEO_RGB) {
                    fprintf(stderr,
                            "Line %d: Keyword XYZTORGBMAT_BEGIN mismatch for visual %s.\n",
                            linenum, SCScrnClassStringOf(VisualFlag));
                    return (0);
                }
                if (state != 0) {
                    fprintf(stderr,
                            "Line %d: Extraneous keyword %s.\n",
                            linenum, keyword);
                    return (0);
                }
                state = 1;
                count = 0;
                pElement = (XcmsFloat *) pMatrix->XYZtoRGBmatrix;
                break;
            case XYZTORGBMAT_END:
                if (VisualFlag != VIDEO_RGB) {
                    fprintf(stderr,
                            "Line %d: Keyword XYZTORGBMAT_END mismatch for visual %s.\n",
                            linenum, SCScrnClassStringOf(VisualFlag));
                    return (0);
                }
                if ((state != 1) || (count != 9)) {
                    fprintf(stderr,
                            "Line %d: Incomplete XYZtoRGB matrix -- Premature %s\n",
                            linenum, keyword);
                    return (0);
                }
                matrices_processed |= 0x1;
                if (matrices_processed == 3) {
                    state = 2;
                }
                else {
                    state = 0;
                }
                break;
            case RGBTOXYZMAT_BEGIN:
                if (VisualFlag != VIDEO_RGB) {
                    fprintf(stderr,
                            "Line %d: Keyword RGBTOXYZMAT_BEGIN mismatch for visual %s.\n",
                            linenum, SCScrnClassStringOf(VisualFlag));
                    return (0);
                }
                if (state != 0) {
                    fprintf(stderr, "Line %d: Extraneous keyword %s.\n",
                            linenum, keyword);
                    return (0);
                }
                state = 1;
                count = 0;
                pElement = (XcmsFloat *) pMatrix->RGBtoXYZmatrix;
                break;
            case RGBTOXYZMAT_END:
                if (VisualFlag != VIDEO_RGB) {
                    fprintf(stderr,
                            "Line %d: Keyword RGBTOXYZMAT_END mismatch for visual %s.\n",
                            linenum, SCScrnClassStringOf(VisualFlag));
                    return (0);
                }
                if ((state != 1) || (count != 9)) {
                    fprintf(stderr,
                            "Line %d: Incomplete RGBtoXYZ matrix -- Premature %s\n",
                            linenum, keyword);
                    return (0);
                }
                matrices_processed |= 0x2;
                if (matrices_processed == 3) {
                    state = 2;
                }
                else {
                    state = 0;
                }
                break;
#ifdef GRAY
            case WHITEPT_XYZ_BEGIN:
                if (VisualFlag != VIDEO_GRAY) {
                    fprintf(stderr,
                            "Line %d: Keyword WHITEPT_XYZ_BEGIN mismatch for visual %s.\n",
                            linenum, SCScrnClassStringOf(VisualFlag));
                    return (0);
                }
                if (state != 0) {
                    fprintf(stderr,
                            "Line %d: Extraneous keyword %s.\n",
                            linenum, keyword);
                    return (0);
                }
                state = 1;
                count = 0;
                pElement = (XcmsFloat *) pMatrix->XYZtoRGBmatrix;
                break;
            case WHITEPT_XYZ_END:
                if (VisualFlag != VIDEO_GRAY) {
                    fprintf(stderr,
                            "Line %d: Keyword WHITEPT_XYZ_END mismatch for visual %s.\n",
                            linenum, SCScrnClassStringOf(VisualFlag));
                    return (0);
                }
                if ((state != 1) || (count != 3)) {
                    fprintf(stderr,
                            "Line %d: Incomplete white point -- Premature %s\n",
                            linenum, keyword);
                    return (0);
                }
                state = 2;
                break;
#endif /* GRAY */
            case DATA:
                for (ptoken = strtok(buf, DATA_DELIMS); ptoken != NULL;
                     ptoken = strtok(NULL, DATA_DELIMS)) {
                    if (sscanf(ptoken, "%lf", pElement) != 1) {
                        if (VisualFlag == VIDEO_RGB) {
                            fprintf(stderr,
                                    "Line %d: Invalid matrix value %s.",
                                    linenum, ptoken);
                        }
                        else {
                            fprintf(stderr,
                                    "Line %d: Invalid CIEXYZ value %s.\n",
                                    linenum, ptoken);
                        }
                        return (0);
                    }
                    pElement++;
                    if (VisualFlag == VIDEO_RGB) {
                        if (++count > 9) {
                            fprintf(stderr,
                                    "Line %d: Extra matrix value %s\n",
                                    linenum, ptoken);
                            return (0);
                        }
                    }
                    else {
                        if (++count > 3) {
                            fprintf(stderr,
                                    "Line %d: Extra CIEXYZ value %s.\n",
                                    linenum, ptoken);
                            return (0);
                        }
                    }
                }
                break;
            case COLORIMETRIC_BEGIN:
                fprintf(stderr,
                        "Line %d: Extraneous keyword %s.\n", linenum, keyword);
                return (0);
            case COLORIMETRIC_END:
                if (state != 2) {
                    fprintf(stderr,
                            "Line %d: Incomplete Colorimetric data -- Premature %s\n",
                            linenum, keyword);
                    return (0);
                }
                return (1);
            case COMMENT:
                /* Currently, do nothing. */
                break;
            default:
                fprintf(stderr,
                        "Line %d: Unexpected keyword %s\n", linenum, keyword);
                return (0);
            }
        }
        else if (ntok < 0) {
            /* mismatch */
            fprintf(stderr, "Line %d: Unrecognized keyword\n", linenum);
            return (0);
        }
    }
    return (0);
}

static int
ProcessIProfile(FILE *stream, XDCCC_Correction *pCorrection)
{
    char buf[BUFSIZ];
    char *keyword;
    char *tableStr, *sizeStr, *ptoken;
    int  size;
    int  state = 0;
         /************************************************
	  * 0 -- Looking for Intensity Table(s)          *
	  * 1 -- Processing Intensity Table(s)           *
          ************************************************/
    int  nTbl = 0;
    int  count = 0;
    IntensityRec *pIRec = NULL;

    while ((nextline(buf, BUFSIZ, stream)) != NULL) {
        ptoken = keyword = strtok(buf, DATA_DELIMS);
        if (keyword != NULL) {
            switch (SCKeyOf(keyword)) {
            case ITBL_BEGIN:
                if (state != 0) {
                    fprintf(stderr, "Line %d: unexpected keyword %s\n",
                            linenum, keyword);
                    return (0);
                }
                tableStr = strtok(NULL, DATA_DELIMS);
                sizeStr = strtok(NULL, DATA_DELIMS);
                if ((sizeStr == NULL) ||
                    sscanf(sizeStr, "%d", &size) != 1) {
                    fprintf(stderr,
                            "Line %d: invalid Intensity Table size, %s.\n",
                            linenum, sizeStr);
                    return (0);
                }
                if (size < 0) {
                    fprintf(stderr,
                            "Line %d: count %d < 0 for Intensity Table.\n",
                            linenum, size);
                    return (0);
                }
                if (strcmp(tableStr, "GREEN") == 0) {
                    if (pCorrection->nTables != 3) {
                        fprintf(stderr, "Line %d: incorrect number of tables\n",
                                linenum);
                        return (0);
                    }
                    if (pCorrection->pGreenTbl->pBase != NULL) {
                        fprintf(stderr,
                                "Line %d: multiple GREEN Intensity Profiles\n",
                                linenum);
                        return (0);
                    }
                    pCorrection->pGreenTbl->nEntries = size;
                    pCorrection->pGreenTbl->pBase =
                        calloc(size, sizeof(IntensityRec));
                    if (pCorrection->pGreenTbl->pBase == NULL) {
                        fprintf(stderr,
                                "Line %d: Unable to allocate space for GREEN Intensity Profile\n",
                                linenum);
                        return (0);
                    }
                    pIRec = pCorrection->pGreenTbl->pBase;
                }
                else if (strcmp(tableStr, "BLUE") == 0) {
                    if (pCorrection->nTables != 3) {
                        fprintf(stderr,
                                "Line %d: incorrect number of tables\n",
                                linenum);
                        return (0);
                    }
                    if (pCorrection->pBlueTbl->pBase != NULL) {
                        fprintf(stderr,
                                "Line %d: multiple BLUE Intensity Profiles\n",
                                linenum);
                        return (0);
                    }
                    pCorrection->pBlueTbl->nEntries = size;
                    pCorrection->pBlueTbl->pBase =
                        calloc(size, sizeof(IntensityRec));
                    if (pCorrection->pBlueTbl->pBase == NULL) {
                        fprintf(stderr,
                                "Line %d: Unable to allocate space for BLUE Intensity Profile\n",
                                linenum);
                        return (0);
                    }
                    pIRec = pCorrection->pBlueTbl->pBase;
                }
                else {
                    if (!strcmp(tableStr, "RGB") && pCorrection->nTables != 1) {
                        fprintf(stderr,
                                "Line %d: multiple RGB Intensity Tables",
                                linenum);
                        return (0);
                    }
                    if (pCorrection->pRedTbl->pBase != NULL) {
                        fprintf(stderr,
                                "Line %d: multiple RED or GREEN or BLUE Intensity Tables\n",
                                linenum);
                        return (0);
                    }
                    pCorrection->pRedTbl->nEntries = size;
                    pCorrection->pRedTbl->pBase =
                        calloc(size, sizeof(IntensityRec));
                    if (pCorrection->pRedTbl->pBase == NULL) {
                        fprintf(stderr,
                                "Line %d: Unable to allocate space for intensity table\n",
                                linenum);
                        return (0);
                    }
                    pIRec = pCorrection->pRedTbl->pBase;
                }
                state = 1;
                count = 0;
                break;
            case ITBL_END:
                if ((state != 1) || (count != size)) {
                    fprintf(stderr,
                            "Line %d: incomplete Intensity Table -- Premature %s\n",
                            linenum, keyword);
                    return (0);
                }
                nTbl++;
                state = 0;
                break;
            case DATA:
                if (pIRec == NULL) {
                    fprintf(stderr,
                            "Line %d: Invalid Intensity Profile -- Premature %s\n",
                            linenum, keyword);
                    return (0);
                }
                do {
                    /********************************************************
		     * Note: tableType should only be 0 or 1 at this point.
		     *       0 indicates value and intensity stored.
		     *       1 indicates only intensity stored.
		     ********************************************************/
                    if (pCorrection->tableType) {
                        if (sscanf(ptoken, "%lf", &pIRec->intensity) != 1) {
                            fprintf(stderr,
                                    "Line %d: invalid Intensity Profile value %s\n",
                                    linenum, ptoken);
                            return (0);
                        }
                        /* With tableType 1 only store the intensity. */
                        pIRec++;
                    }
                    else {
                        short tmp;

                        /* Note ANSI C can handle 0x preceding hex number */
                        if (sscanf(ptoken, "%hi", &tmp) != 1) {
                            fprintf(stderr,
                                    "Line %d: invalid Intensity Profile value %s\n",
                                    linenum, ptoken);
                            return (0);
                        }
                        else
                            pIRec->value = tmp;
                        if ((ptoken = strtok(NULL, DATA_DELIMS)) == NULL) {
                            fprintf(stderr,
                                    "Line %d: missing Intensity Profile value\n",
                                    linenum);
                            return (0);
                        }
                        if (sscanf(ptoken, "%lf", &pIRec->intensity) != 1) {
                            fprintf(stderr,
                                    "Line %d: invalid Intensity Profile intensity %s\n",
                                    linenum, ptoken);
                            return (0);
                        }
                        /* With tableType 0 only store both value & intensity */
                        pIRec++;
                    }
                    if (++count > size) {
                        fprintf(stderr,
                                "Line %d: extra Intensity value %s\n",
                                linenum, ptoken);
                        return (0);
                    }
                    ptoken = strtok(NULL, DATA_DELIMS);
                } while (ptoken != NULL);
                break;
            case IPROFILE_BEGIN:
                fprintf(stderr, "Line %d: extraneous keyword %s\n",
                        linenum, keyword);
                return (0);
            case IPROFILE_END:
                if ((state != 0) || (nTbl != pCorrection->nTables)) {
                    fprintf(stderr,
                            "Line %d: incomplete Intensity Profile data -- Premature %s\n",
                            linenum, keyword);
                    return (0);
                }
                return (1);
            case COMMENT:
                /* ignore line */
                break;
            default:
                fprintf(stderr, "Line %d: unexpected keyword %s\n",
                        linenum, keyword);
                return (0);
            }
        }                       /* else its was just a blank line */
    }
    return (0);
}

static void
PutTableType0Card8(IntensityTbl *pTbl, unsigned char **pCard8)
{
    unsigned int count;
    IntensityRec *pIRec;

    pIRec = pTbl->pBase;
    count = pTbl->nEntries;
    **pCard8 = count - 1;
    *pCard8 += 1;
    for (; count; count--, pIRec++) {
        **pCard8 = pIRec->value >> 8;
        *pCard8 += 1;
        **pCard8 = pIRec->intensity * 255.0;
        *pCard8 += 1;
    }
}

static void
PutTableType1Card8(IntensityTbl *pTbl, unsigned char **pCard8)
{
    unsigned int count;
    IntensityRec *pIRec;

    pIRec = pTbl->pBase;
    count = pTbl->nEntries;
    **pCard8 = count - 1;
    *pCard8 += 1;
    for (; count; count--, pIRec++) {
        **pCard8 = pIRec->intensity * 255.0;
        *pCard8 += 1;
    }
}

static void
PutTableType0Card16(IntensityTbl *pTbl, unsigned short **pCard16)
{
    unsigned int count;
    IntensityRec *pIRec;

    pIRec = pTbl->pBase;
    count = pTbl->nEntries;
    **pCard16 = count - 1;
    *pCard16 += 1;
    for (; count; count--, pIRec++) {
        **pCard16 = pIRec->value;
        *pCard16 += 1;
        **pCard16 = pIRec->intensity * 65535.0;
        *pCard16 += 1;
    }
}

static void
PutTableType1Card16(IntensityTbl *pTbl, unsigned short **pCard16)
{
    unsigned int count;
    IntensityRec *pIRec;

    pIRec = pTbl->pBase;
    count = pTbl->nEntries;
    **pCard16 = count - 1;
    *pCard16 += 1;
    for (; count; count--, pIRec++) {
        **pCard16 = pIRec->intensity * 65535.0;
        *pCard16 += 1;
    }
}

static void
PutTableType0Card32(IntensityTbl *pTbl, unsigned long **pCard32)
{
    unsigned int count;
    IntensityRec *pIRec;

    pIRec = pTbl->pBase;
    count = pTbl->nEntries;
    **pCard32 = count - 1;
    *pCard32 += 1;
    for (; count; count--, pIRec++) {
        **pCard32 = pIRec->value;
        *pCard32 += 1;
        **pCard32 = pIRec->intensity * 4294967295.0;
        *pCard32 += 1;
    }
}

static void
PutTableType1Card32(IntensityTbl *pTbl, unsigned long **pCard32)
{
    unsigned int count;
    IntensityRec *pIRec;

    pIRec = pTbl->pBase;
    count = pTbl->nEntries;
    **pCard32 = count - 1;
    *pCard32 += 1;
    for (; count; count--, pIRec++) {
        **pCard32 = pIRec->intensity * 4294967295.0;
        *pCard32 += 1;
    }
}

static void
LoadMatrix(Display * pDpy, Window root, XDCCC_Matrix * pMatrix)
{
    int count;
    unsigned long *pCard32;
    unsigned long Card32Array[18];
    Atom MatricesAtom;
    XcmsFloat *pValue;

    /*
     * Store the XDCCC_LINEAR_RGB_MATRICES
     */
    pCard32 = Card32Array;
    pValue = (XcmsFloat *) pMatrix->XYZtoRGBmatrix;
    for (count = 0; count < 9; count++) {
        *pCard32++ = (unsigned long) (*pValue++ * (XcmsFloat) XDCCC_NUMBER);
    }
    pValue = (XcmsFloat *) pMatrix->RGBtoXYZmatrix;
    for (count = 0; count < 9; count++) {
        *pCard32++ = (unsigned long) (*pValue++ * (XcmsFloat) XDCCC_NUMBER);
    }
    MatricesAtom = XInternAtom(pDpy, XDCCC_MATRIX_ATOM_NAME, False);
    XChangeProperty(pDpy, root, MatricesAtom, XA_INTEGER, 32,
                    PropModeReplace, (unsigned char *) Card32Array, 18);
}

static int
LoadCorrections(Display *pDpy, Window root, XDCCC_Correction *pCorrection,
                int targetFormat)
{
    unsigned char *pCard8;
    unsigned char *pCard8Array = NULL;
    unsigned short *pCard16;
    unsigned short *pCard16Array = NULL;
    unsigned long *pCard32;
    unsigned long *pCard32Array = NULL;
    Atom CorrectAtom;
    int total;
    int i;

    /*
     * Store each XDCCC_CORRECTION into XDCCC_LINEAR_RGB_CORRECTION property
     */
    CorrectAtom = XInternAtom(pDpy, XDCCC_CORRECT_ATOM_NAME, False);

    for (i = 0; pCorrection; i++, pCorrection = pCorrection->next) {
        if ((pCorrection->tableType != 0) && (pCorrection->tableType != 1)) {
            if (pCorrection->visual_info.visualid) {
                fprintf(stderr,
                        "RGB Correction for visualid %ld: Invalid intensity table type %d.\n",
                        pCorrection->visual_info.visualid,
                        pCorrection->tableType);
            }
            else {
                fprintf(stderr,
                        "Global RGB Correction: Invalid intensity table type %d.\n",
                        pCorrection->tableType);
            }
            return (0);
        }

        if (pCorrection->nTables != 1 && pCorrection->nTables != 3) {
            if (pCorrection->visual_info.visualid) {
                fprintf(stderr,
                        "RGB Correction for visualid %ld: %d invalid number of tables.\n",
                        pCorrection->visual_info.visualid,
                        pCorrection->nTables);
            }
            else {
                fprintf(stderr,
                        "Global RGB Correction: %d invalid number of tables.\n",
                        pCorrection->nTables);
            }
            return (0);
        }

        if (pCorrection->nTables == 1) {
            if (pCorrection->pRedTbl->nEntries < 2) {
                if (pCorrection->visual_info.visualid) {
                    fprintf(stderr,
                            "RGB Correction for visualid %ld: Illegal number of entries in table\n",
                            pCorrection->visual_info.visualid);
                }
                else {
                    fprintf(stderr,
                            "Global RGB Correction: Illegal number of entries in table\n");
                }
                return (0);
            }
            switch (targetFormat) {
            case 8:
                total = 7 + (pCorrection->pRedTbl->nEntries *
                             (pCorrection->tableType == 0 ? 2 : 1));
                pCard8 = pCard8Array = calloc(total, sizeof(unsigned char));
                if (pCard8 == NULL) {
                    fprintf(stderr, "Unable allocate array of ints\n");
                    return (0);
                }
                *pCard8++ = (pCorrection->visual_info.visualid >> 24) & 0xFF;
                *pCard8++ = (pCorrection->visual_info.visualid >> 16) & 0xFF;
                *pCard8++ = (pCorrection->visual_info.visualid >> 8) & 0xFF;
                *pCard8++ = (pCorrection->visual_info.visualid) & 0xFF;
                *pCard8++ = pCorrection->tableType;     /* type */
                *pCard8++ = 1;  /* number of tables = 1 */
                if (pCorrection->tableType == 0) {
                    PutTableType0Card8(pCorrection->pRedTbl, &pCard8);
                }
                else {
                    PutTableType1Card8(pCorrection->pRedTbl, &pCard8);
                }
                XChangeProperty(pDpy, root, CorrectAtom, XA_INTEGER, 8,
                                i ? PropModeAppend : PropModeReplace,
                                (unsigned char *) pCard8Array, total);
                free(pCard8Array);
                break;
            case 16:
                total = 5 + (pCorrection->pRedTbl->nEntries *
                             (pCorrection->tableType == 0 ? 2 : 1));
                pCard16 = pCard16Array = calloc(total, sizeof (unsigned short));
                if (pCard16 == NULL) {
                    fprintf(stderr, "Unable allocate array of ints\n");
                    return (0);
                }
                *pCard16++ = (pCorrection->visual_info.visualid >> 16) & 0xFFFF;
                *pCard16++ = (pCorrection->visual_info.visualid) & 0xFFFF;
                *pCard16++ = pCorrection->tableType;    /* type */
                *pCard16++ = 1; /* number of tables = 1 */
                if (pCorrection->tableType == 0) {
                    PutTableType0Card16(pCorrection->pRedTbl, &pCard16);
                }
                else {
                    PutTableType1Card16(pCorrection->pRedTbl, &pCard16);
                }
                XChangeProperty(pDpy, root, CorrectAtom, XA_INTEGER, 16,
                                i ? PropModeAppend : PropModeReplace,
                                (unsigned char *) pCard16Array, total);
                free(pCard16Array);
                break;
            case 32:
                total = 4 + (pCorrection->pRedTbl->nEntries *
                             (pCorrection->tableType == 0 ? 2 : 1));
                pCard32 = pCard32Array = calloc(total, sizeof(unsigned long));
                if (pCard32 == NULL) {
                    fprintf(stderr, "Unable allocate array of ints\n");
                    return (0);
                }
                *pCard32++ = pCorrection->visual_info.visualid;
                *pCard32++ = pCorrection->tableType;    /* type */
                *pCard32++ = 1; /* number of tables = 1 */
                if (pCorrection->tableType == 0) {
                    PutTableType0Card32(pCorrection->pRedTbl, &pCard32);
                }
                else {
                    PutTableType1Card32(pCorrection->pRedTbl, &pCard32);
                }
                XChangeProperty(pDpy, root, CorrectAtom, XA_INTEGER, 32,
                                i ? PropModeAppend : PropModeReplace,
                                (unsigned char *) pCard32Array, total);
                free(pCard32Array);
                break;
            default:
                if (pCorrection->visual_info.visualid) {
                    fprintf(stderr,
                            "RGB Correction for visualid %ld: Invalid property format\n",
                            pCorrection->visual_info.visualid);
                }
                else {
                    fprintf(stderr,
                            "Global RGB Correction: Invalid property format\n");
                }
                return (0);
            }
        }
        else {                  /* pCorrection->nTables == 3 */
            if ((pCorrection->pRedTbl->nEntries < 2) ||
                (pCorrection->pGreenTbl->nEntries < 2) ||
                (pCorrection->pBlueTbl->nEntries < 2)) {
                if (pCorrection->visual_info.visualid) {
                    fprintf(stderr,
                            "RGB Correction for visualid %ld: Illegal number of entries in table\n",
                            pCorrection->visual_info.visualid);
                }
                else {
                    fprintf(stderr,
                            "Global RGB Correction: Illegal number of entries in table\n");
                }
                return (0);
            }
            switch (targetFormat) {
            case 8:
                total = 9 +     /* visualID, type, and 3 lengths */
                    (pCorrection->pRedTbl->nEntries *
                     (pCorrection->tableType == 0 ? 2 : 1)) +
                    (pCorrection->pGreenTbl->nEntries *
                     (pCorrection->tableType == 0 ? 2 : 1)) +
                    (pCorrection->pBlueTbl->nEntries *
                     (pCorrection->tableType == 0 ? 2 : 1));
                pCard8 = pCard8Array = calloc(total, sizeof(unsigned char));
                if (pCard8 == NULL) {
                    fprintf(stderr, "Unable allocate array of ints\n");
                    return (0);
                }
                *pCard8++ = (pCorrection->visual_info.visualid >> 24) & 0xFF;
                *pCard8++ = (pCorrection->visual_info.visualid >> 16) & 0xFF;
                *pCard8++ = (pCorrection->visual_info.visualid >> 8) & 0xFF;
                *pCard8++ = (pCorrection->visual_info.visualid) & 0xFF;
                *pCard8++ = pCorrection->tableType;     /* type */
                *pCard8++ = 3;  /* number of tables = 3 */
                if (pCorrection->tableType == 0) {
                    PutTableType0Card8(pCorrection->pRedTbl, &pCard8);
                    PutTableType0Card8(pCorrection->pGreenTbl, &pCard8);
                    PutTableType0Card8(pCorrection->pBlueTbl, &pCard8);
                }
                else {
                    PutTableType1Card8(pCorrection->pRedTbl, &pCard8);
                    PutTableType1Card8(pCorrection->pGreenTbl, &pCard8);
                    PutTableType1Card8(pCorrection->pBlueTbl, &pCard8);
                }
                XChangeProperty(pDpy, root, CorrectAtom, XA_INTEGER, 8,
                                i ? PropModeAppend : PropModeReplace,
                                (unsigned char *) pCard8Array, total);
                free(pCard8Array);
                break;
            case 16:
                total = 7 +     /* visualID, type, and 3 lengths */
                    (pCorrection->pRedTbl->nEntries *
                     (pCorrection->tableType == 0 ? 2 : 1)) +
                    (pCorrection->pGreenTbl->nEntries *
                     (pCorrection->tableType == 0 ? 2 : 1)) +
                    (pCorrection->pBlueTbl->nEntries *
                     (pCorrection->tableType == 0 ? 2 : 1));
                pCard16 = pCard16Array = calloc(total, sizeof(unsigned short));
                if (pCard16 == NULL) {
                    fprintf(stderr, "Unable allocate array of ints\n");
                    return (0);
                }
                *pCard16++ = (pCorrection->visual_info.visualid >> 16) & 0xFFFF;
                *pCard16++ = (pCorrection->visual_info.visualid) & 0xFFFF;
                *pCard16++ = pCorrection->tableType;    /* type = 0 */
                *pCard16++ = 3; /* number of tables = 3 */
                if (pCorrection->tableType == 0) {
                    PutTableType0Card16(pCorrection->pRedTbl, &pCard16);
                    PutTableType0Card16(pCorrection->pGreenTbl, &pCard16);
                    PutTableType0Card16(pCorrection->pBlueTbl, &pCard16);
                }
                else {
                    PutTableType1Card16(pCorrection->pRedTbl, &pCard16);
                    PutTableType1Card16(pCorrection->pGreenTbl, &pCard16);
                    PutTableType1Card16(pCorrection->pBlueTbl, &pCard16);
                }
                XChangeProperty(pDpy, root, CorrectAtom, XA_INTEGER, 16,
                                i ? PropModeAppend : PropModeReplace,
                                (unsigned char *) pCard16Array, total);
                free(pCard16Array);
                break;
            case 32:
                total = 6 +     /* visualID, type, and 3 lengths */
                    (pCorrection->pRedTbl->nEntries *
                     (pCorrection->tableType == 0 ? 2 : 1)) +
                    (pCorrection->pGreenTbl->nEntries *
                     (pCorrection->tableType == 0 ? 2 : 1)) +
                    (pCorrection->pBlueTbl->nEntries *
                     (pCorrection->tableType == 0 ? 2 : 1));
                pCard32 = pCard32Array = calloc(total, sizeof(unsigned long));
                if (pCard32 == NULL) {
                    fprintf(stderr, "Unable allocate array of ints\n");
                    return (0);
                }
                *pCard32++ = pCorrection->visual_info.visualid;
                *pCard32++ = pCorrection->tableType;    /* type */
                *pCard32++ = 3; /* number of tables = 3 */
                if (pCorrection->tableType == 0) {
                    PutTableType0Card32(pCorrection->pRedTbl, &pCard32);
                    PutTableType0Card32(pCorrection->pGreenTbl, &pCard32);
                    PutTableType0Card32(pCorrection->pBlueTbl, &pCard32);
                }
                else {
                    PutTableType1Card32(pCorrection->pRedTbl, &pCard32);
                    PutTableType1Card32(pCorrection->pGreenTbl, &pCard32);
                    PutTableType1Card32(pCorrection->pBlueTbl, &pCard32);
                }
                XChangeProperty(pDpy, root, CorrectAtom, XA_INTEGER, 32,
                                i ? PropModeAppend : PropModeReplace,
                                (unsigned char *) pCard32Array, total);
                free(pCard32Array);
                break;
            default:
                if (pCorrection->visual_info.visualid) {
                    fprintf(stderr,
                            "RGB Correction for visualid %ld: Invalid property format\n",
                            pCorrection->visual_info.visualid);
                }
                else {
                    fprintf(stderr,
                            "Global RGB Correction: Invalid property format\n");
                }
                return (0);
            }
        }
    }

    return (1);
}

#ifdef GRAY

static int
LoadDataGray(Display *pDpy, window root, int tableType,
             LINEAR_RGB_SCCData *pScreenData, int targetFormat)
{
    unsigned char *ret_prop;
    int count;
    int nLevels;
    unsigned char *pCard8;
    unsigned char *pCard8Array = NULL;
    unsigned short *pCard16;
    unsigned short *pCard16Array = NULL;
    unsigned long *pCard32;
    unsigned long *pCard32Array = NULL;
    unsigned long Card32Array[18];
    int ret_format;
    unsigned long ret_len, ret_after;
    Atom MatricesAtom, CorrectAtom, ret_atom;
    XcmsFloat *pValue;
    int total;

    /* Now store the XDCCC_SCREENWHITEPT */
    pCard32 = Card32Array;
    pValue = (XcmsFloat *) pScreenData->XYZtoRGBmatrix;
    for (count = 0; count < 3; count++) {
        *pCard32++ = (unsigned long) (*pValue++ * (XcmsFloat) XDCCC_NUMBER);
    }
    MatricesAtom = XInternAtom(pDpy, XDCCC_SCREENWHITEPT_ATOM_NAME, False);
    XChangeProperty(pDpy, root, MatricesAtom, XA_INTEGER, 32,
                    PropModeReplace, (unsigned char *) Card32Array, 3);

    /* Now store the XDCCC_GRAY_CORRECTION */
    CorrectAtom = XInternAtom(pDpy, XDCCC_GRAY_CORRECT_ATOM_NAME, False);

    if (tableType == CORR_TYPE_NONE) {
        XGetWindowProperty(pDpy, root, CorrectAtom,
                           0, 5, False, XA_INTEGER,
                           &ret_atom, &ret_format, &ret_len, &ret_after,
                           &ret_prop);
        if (ret_format != 0) {
            XDeleteProperty(pDpy, root, CorrectAtom);
            XFree(ret_prop);
        }
        return (1);
    }
    nLevels = pScreenData->pRedTbl->nEntries;
    if (nLevels < 2) {
        fprintf(stderr, "Illegal number of entries in table\n");
        return (0);
    }
    switch (targetFormat) {
    case 8:
        total = 6               /* visualID, type, length */
            + (nLevels * (tableType == 0 ? 2 : 1));
        pCard8 = pCard8Array = calloc(total, sizeof(unsigned char));
        if (pCard8 == NULL) {
            fprintf(stderr, "Unable allocate array of Card8\n");
            return (0);
        }
        *pCard8++ = 0;          /* VisualID = 0 */
        *pCard8++ = 0;          /* VisualID = 0 */
        *pCard8++ = 0;          /* VisualID = 0 */
        *pCard8++ = 0;          /* VisualID = 0 */
        *pCard8++ = tableType;  /* type */
        if (tableType == 0) {
            PutTableType0Card8(pScreenData->pRedTbl, &pCard8);
        }
        else {                  /* tableType == 1 */
            PutTableType1Card8(pScreenData->pRedTbl, &pCard8);
        }
        XChangeProperty(pDpy, root, CorrectAtom, XA_INTEGER, 8,
                        PropModeReplace, (unsigned char *) pCard8Array, total);
        free(pCard8Array);
        break;
    case 16:
        total = 4               /* visualID, type, length */
            + (nLevels * (tableType == 0 ? 2 : 1));
        pCard16 = pCard16Array = calloc(total, sizeof(unsigned short));
        if (pCard16 == NULL) {
            fprintf(stderr, "Unable allocate array of Card16\n");
            return (0);
        }
        *pCard16++ = 0;         /* VisualID = 0 */
        *pCard16++ = 0;         /* VisualID = 0 */
        *pCard16++ = tableType; /* type */
        if (tableType == 0) {
            PutTableType0Card16(pScreenData->pRedTbl, &pCard16);
        }
        else {                  /* tableType == 1 */
            PutTableType1Card16(pScreenData->pRedTbl, &pCard16);
        }
        XChangeProperty(pDpy, root, CorrectAtom, XA_INTEGER, 16,
                        PropModeReplace, (unsigned char *) pCard16Array, total);
        free(pCard16Array);
        break;
    case 32:
        total = 3               /* visualID, type, length */
            + (nLevels * (tableType == 0 ? 2 : 1));
        pCard32 = pCard32Array = calloc(total, sizeof(unsigned long));
        if ((pCard32 == NULL) {
            fprintf(stderr, "Unable allocate array of Card32\n");
            return (0);
        }
        *pCard32++ = 0;         /* VisualID = 0 */
        *pCard32++ = tableType; /* type */
        if (tableType == 0) {
            PutTableType0Card32(pScreenData->pRedTbl, &pCard32);
        }
        else {                  /* tableType == 1 */
            PutTableType1Card32(pScreenData->pRedTbl, &pCard32);
        }
        XChangeProperty(pDpy, root, CorrectAtom, XA_INTEGER, 32,
                        PropModeReplace, (unsigned char *) pCard32Array, total);
        free(pCard32Array);
        break;
    default:
        fprintf(stderr, "Invalid property format\n");
        return (0);
    }
    return (1);
}
#endif                          /* GRAY */

static void
PrintVisualOptions(XDCCC_Correction * pCorrection)
{
    if (pCorrection->visual_info_mask & VisualIDMask) {
        fprintf(stderr, "\t%s:0x%lx\n",
                DefineToStr(VisualOptKeyTbl, KEY_VISUALID),
                (unsigned long) pCorrection->visual_info.visualid);
    }
    if (pCorrection->visual_info_mask & VisualDepthMask) {
        fprintf(stderr, "\t%s:%d\n",
                DefineToStr(VisualOptKeyTbl, KEY_DEPTH),
                pCorrection->visual_info.depth);
    }
    if (pCorrection->visual_info_mask & VisualClassMask) {
        fprintf(stderr, "\t%s:%s\n",
                DefineToStr(VisualOptKeyTbl, KEY_CLASS),
                DefineToStr(VisualClassTbl, pCorrection->visual_info.class));
    }
    if (pCorrection->visual_info_mask & VisualRedMaskMask) {
        fprintf(stderr, "\t%s:0x%lx\n",
                DefineToStr(VisualOptKeyTbl, KEY_RED_MASK),
                pCorrection->visual_info.red_mask);
    }
    if (pCorrection->visual_info_mask & VisualGreenMaskMask) {
        fprintf(stderr, "\t%s:0x%lx\n",
                DefineToStr(VisualOptKeyTbl, KEY_GREEN_MASK),
                pCorrection->visual_info.green_mask);
    }
    if (pCorrection->visual_info_mask & VisualBlueMaskMask) {
        fprintf(stderr, "\t%s:0x%lx\n",
                DefineToStr(VisualOptKeyTbl, KEY_BLUE_MASK),
                pCorrection->visual_info.blue_mask);
    }
    if (pCorrection->visual_info_mask & VisualColormapSizeMask) {
        fprintf(stderr, "\t%s:0x%x\n",
                DefineToStr(VisualOptKeyTbl, KEY_COLORMAP_SIZE),
                pCorrection->visual_info.colormap_size);
    }
    if (pCorrection->visual_info_mask & VisualBitsPerRGBMask) {
        fprintf(stderr, "\t%s:%d\n",
                DefineToStr(VisualOptKeyTbl, KEY_BITS_PER_RGB),
                pCorrection->visual_info.bits_per_rgb);
    }
}

static int
ParseVisualOptions(Display *pDpy, XDCCC_Correction *pCorrection, char *pbuf)
{
    char *key;
    char *value;
    XVisualInfo *vinfo;
    int n_matches;
    char delims[8];

    strcpy(delims, DATA_DELIMS);
    strcat(delims, ":");
    pCorrection->visual_info_mask = VisualNoMask;
    key = strtok(pbuf, delims);
    do {
        long tmp;

        value = strtok(NULL, delims);
        if ((key == NULL) || (value == NULL)) {
            return (0);
        }
        switch (StrToDefine(VisualOptKeyTbl, key)) {
        case KEY_VISUALID:
            if (sscanf(value, "%li", &tmp) != 1) {
                fprintf(stderr,
                        "Line %d: invalid VisualID specified, %s\n",
                        linenum, value);
                return (0);
            }
            else
                pCorrection->visual_info.visualid = tmp;
            pCorrection->visual_info_mask |= VisualIDMask;
            break;
        case KEY_DEPTH:
            if (sscanf(value, "%i", &pCorrection->visual_info.depth) != 1) {
                fprintf(stderr,
                        "Line %d: invalid depth specified, %s\n",
                        linenum, value);
                return (0);
            }
            pCorrection->visual_info_mask |= VisualDepthMask;
            break;
        case KEY_CLASS:
            switch (pCorrection->visual_info.class =
                    StrToDefine(VisualClassTbl, value)) {
            case StaticColor:
                break;
            case PseudoColor:
                break;
            case TrueColor:
                break;
            case DirectColor:
                break;
            case StaticGray:
                /* invalid, fall through */
            case GrayScale:
                /* invalid, fall through */
            default:
                fprintf(stderr,
                        "Line %d: invalid Visual Class -- %s\n",
                        linenum, value);
                return (0);
            }
            pCorrection->visual_info_mask |= VisualClassMask;
            break;
        case KEY_RED_MASK:
            if (sscanf(value, "%li", &tmp) != 1) {
                fprintf(stderr,
                        "Line %d: invalid red_mask specified -- %s\n",
                        linenum, value);
                return (0);
            }
            else
                pCorrection->visual_info.red_mask = tmp;
            pCorrection->visual_info_mask |= VisualRedMaskMask;
            break;
        case KEY_GREEN_MASK:
            if (sscanf(value, "%li", &tmp) != 1) {
                fprintf(stderr,
                        "Line %d: invalid green_mask specified -- %s\n",
                        linenum, value);
                return (0);
            }
            else
                pCorrection->visual_info.green_mask = tmp;
            pCorrection->visual_info_mask |= VisualGreenMaskMask;
            break;
        case KEY_BLUE_MASK:
            if (sscanf(value, "%li", &tmp) != 1) {
                fprintf(stderr,
                        "Line %d: invalid blue_mask specified -- %s\n",
                        linenum, value);
                return (0);
            }
            else
                pCorrection->visual_info.blue_mask = tmp;
            pCorrection->visual_info_mask |= VisualBlueMaskMask;
            break;
        case KEY_COLORMAP_SIZE:
            if (sscanf(value, "%i", &pCorrection->visual_info.colormap_size) !=
                1) {
                fprintf(stderr,
                        "Line %d: invalid colormap_size specified -- %s\n",
                        linenum, value);
                return (0);
            }
            pCorrection->visual_info_mask |= VisualColormapSizeMask;
            break;
        case KEY_BITS_PER_RGB:
            if (sscanf(value, "%i", &pCorrection->visual_info.bits_per_rgb) !=
                1) {
                fprintf(stderr,
                        "Line %d: invalid bits_per_rgb specified -- %s\n",
                        linenum, value);
                return (0);
            }
            pCorrection->visual_info_mask |= VisualBitsPerRGBMask;
            break;
        default:
            fprintf(stderr, "Line %d: invalid keyword %s\n", linenum, key);
            return (0);
        }
        key = strtok(NULL, delims);
    } while (key != NULL);

    vinfo = XGetVisualInfo(pDpy,
                           pCorrection->visual_info_mask,
                           &pCorrection->visual_info, &n_matches);

    if (!n_matches) {
        fprintf(stderr, "Line %d: Cannot find visual matching ...\n", linenum);
        PrintVisualOptions(pCorrection);
        fprintf(stderr, "\n");
        return (0);
    }
    if (n_matches > 1) {
        fprintf(stderr, "Line %d: Found more than one visual matching ...\n",
                linenum);
        PrintVisualOptions(pCorrection);
        fprintf(stderr, "    Using VisualId 0x%lx\n",
                (unsigned long) vinfo->visualid);
    }
    memcpy(&pCorrection->visual_info, vinfo, sizeof(XVisualInfo));
    return (1);
}

/************************************************************************
 *									*
 *			 PUBLIC ROUTINES				*
 *									*
 ************************************************************************/

/*
 *	NAME
 *		LoadSCCData - Read and store the screen data
 *
 *	SYNOPSIS
 */
int
LoadSCCData(Display *pDpy, int screenNumber, const char *filename,
            int targetFormat)

/*
 *	DESCRIPTION
 *		Using the X Device Color Characterization Convention (XDCCC)
 *		read the screen data and store it on the root window of the
 *		screen.
 *
 *	RETURNS
 *		Returns 0 if failed; otherwise 1.
 *
 */
{
    FILE *stream;
    char *pStr;
    char buf[BUFSIZ];
    char *keyword, *token1, *token2, *token3;
    int state = 0;
    int VisualFlag = -2;
    Window root;
    XDCCC_Matrix matrix;
    XDCCC_Correction *CorrectionTail = NULL;
    XDCCC_Correction *CorrectionHead = NULL;
    XDCCC_Correction *pCurrent;

    if (screenNumber < 0) {
        fprintf(stderr, "Invalid Screen Number %d\n", screenNumber);
        return (0);
    }
    root = RootWindow(pDpy, screenNumber);

    if (!root) {
        /* if no root window is available then return an error */
        fprintf(stderr, "Could not open root window supplied.\n ");
        return (0);
    }
    /*
     * Open the file, determine its size, then read it into memory.
     */
    if (filename == NULL) {
        stream = stdin;
        filename = "stdin";
    }
    else if ((stream = fopen(filename, "r")) == NULL) {
        fprintf(stderr, "Could not open file %s.\n", filename);
        return (0);
    }

    /*
     * Advance to starting keyword
     * Anything before this keyword is just treated as comments.
     */

    while ((pStr = nextline(buf, BUFSIZ, stream)) != NULL) {
        keyword = strtok(buf, DATA_DELIMS);
        if (keyword != NULL &&
            (strcmp(keyword, SC_BEGIN_KEYWORD) == 0)) {
            break;
        }                       /* else ignore the line */
    }

    if (pStr == NULL) {
        fprintf(stderr, "File %s is missing %s\n", filename, SC_BEGIN_KEYWORD);
        closeS(stream, CorrectionHead);
        return (0);
    }

    token1 = strtok(NULL, DATA_DELIMS);
    if (token1 && (strcmp(token1, TXT_FORMAT_VERSION) != 0) &&
        (strcmp(token1, "0.3") != 0)) {
        fprintf(stderr,
                "Screen data format version mismatch in file %s-- expected %s, found %s\n",
                filename, TXT_FORMAT_VERSION, token1);
        closeS(stream, CorrectionHead);
        return (0);
    }

    while ((pStr = nextline(buf, BUFSIZ, stream)) != NULL) {
        keyword = strtok(buf, DATA_DELIMS);
        if (keyword != NULL) {
            switch (SCKeyOf(keyword)) {
            case COMMENT:
            case NAME:
            case PART_NUMBER:
            case MODEL:
            case SERIAL_NUMBER:
            case REVISION:
                /* Do nothing */
                break;
            case SCREEN_CLASS:
                token1 = strtok(NULL, DATA_DELIMS);
                token2 = strtok(NULL, DATA_DELIMS);
                if ((token1 == NULL)
                    || ((VisualFlag = SCScrnClassOf(token1)) == -1)) {
                    closeS(stream, CorrectionHead);
                    return (0);
                }
                /*include code to handle screen number input */
                if (token2 != NULL) {
                    screenNumber = atoi(token2);

                    if (screenNumber < 0) {
                        fprintf(stderr, "Invalid Screen Number %d\n",
                                screenNumber);
                    }
                    else {
                        root = RootWindow(pDpy, screenNumber);
                        if (!root) {
                            /* if no root window is available then return an error */
                            fprintf(stderr,
                                    "Could not open root window supplied.\n ");
                            return (0);
                        }
                    }
                }
                break;
            case COLORIMETRIC_BEGIN:
                if (VisualFlag == -2) {
                    closeS(stream, CorrectionHead);
                    return (0);
                }
                if (!ProcessColorimetric(stream, &matrix, VisualFlag)) {
                    closeS(stream, CorrectionHead);
                    return (0);
                }
                state |= 0x02;
                break;
            case IPROFILE_BEGIN:
                if (VisualFlag == -2) {
                    closeS(stream, CorrectionHead);
                    return (0);
                }
                token1 = strtok(NULL, DATA_DELIMS);
                token2 = strtok(NULL, DATA_DELIMS);
                if ((token1 == NULL) || (token2 == NULL)) {
                    fprintf(stderr,
                            "Line %d: Intensity profile missing TableType and/or nTables.",
                            linenum);
                    closeS(stream, CorrectionHead);
                    return (0);
                }

                pCurrent = calloc(1, sizeof(XDCCC_Correction));
                if (pCurrent  == NULL) {
                    fprintf(stderr,
                            "Line %d: Could not allocate memory for intensity profile.",
                            linenum);
                    closeS(stream, CorrectionHead);
                    return (0);
                }

                if (sscanf(token1, "%d", &pCurrent->tableType) != 1 ||
                    (pCurrent->tableType < 0 || pCurrent->tableType > 1)) {
                    fprintf(stderr,
                            "Line %d: invalid table type specified -- %s\n",
                            linenum, buf);
                    closeS(stream, CorrectionHead);
                    free(pCurrent);
                    return (0);
                }

                if ((VisualFlag == VIDEO_RGB) && (token2 == NULL)) {
                    fprintf(stderr,
                            "Line %d: invalid number of tables specified -- %s\n",
                            linenum, buf);
                    closeS(stream, CorrectionHead);
                    free(pCurrent);
                    return (0);
                }

                if (VisualFlag == VIDEO_RGB) {
                    if (sscanf(token2, "%d", &pCurrent->nTables) != 1 ||
                        (pCurrent->nTables != 0 && pCurrent->nTables != 1
                         && pCurrent->nTables != 3)) {
                        fprintf(stderr,
                                "Line %d: invalid number of tables (must be 0, 1, or 3)\n",
                                linenum);
                        closeS(stream, CorrectionHead);
                        free(pCurrent);
                        return (0);
                    }
                }
                else {
                    pCurrent->nTables = 0;
                }

                token3 = strtok(NULL, "\n");
                if (token3 != NULL) {
                    if (!ParseVisualOptions(pDpy, pCurrent, token3)) {
                        goto ByPassThisIProfile;
                    }
                }

                switch (pCurrent->nTables) {
                case 3:
                    pCurrent->pRedTbl = calloc(1, sizeof(IntensityTbl));
                    if (pCurrent->pRedTbl == NULL) {
                        fprintf(stderr,
                                "Line %d: Could not allocate Red Intensity Table\n",
                                linenum);
                        closeS(stream, CorrectionHead);
                        free(pCurrent);
                        return (0);
                    }
                    pCurrent->pGreenTbl = calloc(1, sizeof(IntensityTbl));
                    if (pCurrent->pGreenTbl == NULL) {
                        fprintf(stderr,
                                "Line %d: Could not allocate Green Intensity Table\n",
                                linenum);
                        closeS(stream, CorrectionHead);
                        free(pCurrent->pRedTbl);
                        free(pCurrent);
                        return (0);
                    }
                    pCurrent->pBlueTbl = calloc(1, sizeof(IntensityTbl));
                    if (pCurrent->pBlueTbl == NULL) {
                        fprintf(stderr,
                                "Line %d: Could not allocate Blue Intensity Table",
                                linenum);
                        closeS(stream, CorrectionHead);
                        free(pCurrent->pRedTbl);
                        free(pCurrent->pGreenTbl);
                        free(pCurrent);
                        return (0);
                    }
                    if (!ProcessIProfile(stream, pCurrent)) {
                        goto ByPassThisIProfile;
                    }
                    break;
                case 1:
                    pCurrent->pRedTbl = calloc(1, sizeof(IntensityTbl));
                    if (pCurrent->pRedTbl == NULL) {
                        fprintf(stderr,
                                "Line %d: Could not allocate Red Intensity Table",
                                linenum);
                        closeS(stream, CorrectionHead);
                        free(pCurrent);
                        return (0);
                    }
                    pCurrent->pGreenTbl = pCurrent->pRedTbl;
                    pCurrent->pBlueTbl = pCurrent->pRedTbl;
                    if (!ProcessIProfile(stream, pCurrent)) {
                        goto ByPassThisIProfile;
                    }
                    break;
                default:
                    /* do nothing */
                    break;
                }

                if (CorrectionHead == NULL) {
                    CorrectionHead = CorrectionTail = pCurrent;
                }
                else {
                    CorrectionTail->next = pCurrent;
                    CorrectionTail = pCurrent;
                }
                state |= 0x04;
                break;
 ByPassThisIProfile:
                /* read till INTENSITY_PROFILE_END */
                while ((pStr = nextline(buf, BUFSIZ, stream)) != NULL) {
                    keyword = strtok(buf, DATA_DELIMS);
                    if (keyword != NULL) {
                        switch (SCKeyOf(keyword)) {
                        case ITBL_BEGIN:
                        case ITBL_END:
                        case COMMENT:
                        case DATA:
                            break;
                        case IPROFILE_END:
                            goto IProfileProcessed;
                        default:
                            closeS(stream, CorrectionHead);
                            return (0);
                        }
                    }
                }
                free(pCurrent);
 IProfileProcessed:
                state |= 0x04;
                break;
            case SC_END:
                if (!(state & 0x02)) {
                    fprintf(stderr,
                            "File %s is missing Colorimetric data.\n",
                            filename);
                    closeS(stream, CorrectionHead);
                    return (0);
                }
                if (!(state & 0x04)) {
                    fprintf(stderr,
                            "File %s is missing Intensity Profile Data.\n",
                            filename);
                }
                if (VisualFlag == VIDEO_RGB) {
                    LoadMatrix(pDpy, root, &matrix);
                    if (!LoadCorrections(pDpy, root, CorrectionHead,
                                         targetFormat)) {
                        closeS(stream, CorrectionHead);
                        return (0);
                    }
#ifdef GRAY
                }
                else if (VisualFlag == VIDEO_GRAY) {
                    if (!LoadDataGray(pDpy, root,
                                      pCurrent->tableType, pScreenData,
                                      targetFormat)) {
                        closeS(stream, CorrectionHead);
                        return (0);
                    }
#endif                          /* GRAY */
                }
                else {
                    fprintf(stderr, "File %s Visual missing.", filename);
                }
                closeS(stream, CorrectionHead);
                return (1);

            default:
                fprintf(stderr, "Line %d: extraneous keyword %s\n",
                        linenum, keyword);
                closeS(stream, CorrectionHead);
                return (0);

            }
        }                       /* else it was just a blank line */
    }
    closeS(stream, CorrectionHead);
    return (1);
}
