Index: trunk/psLib/src/xml/psXML.c
===================================================================
--- trunk/psLib/src/xml/psXML.c	(revision 2318)
+++ trunk/psLib/src/xml/psXML.c	(revision 2521)
@@ -9,10 +9,11 @@
 *  @author Ross Harman, MHPCC
 *
-*  @version $Revision: 1.9 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2004-11-10 18:26:46 $
+*  @version $Revision: 1.10 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2004-11-30 00:27:40 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
 */
 
+#include <libxml/parser.h>
 #include <fitsio.h>
 #include <string.h>
@@ -32,4 +33,10 @@
 #include "psAstronomyErrors.h"
 
+
+typedef struct
+{
+    int y;
+}
+myStruct;
 
 /******************************************************************************/
@@ -103,4 +110,8 @@
 /*****************************************************************************/
 
+void p_saxEndElement(void *ctx, const xmlChar *tagName);
+void p_psInitVectorXml(void *ctx, char *tagName);
+void p_psInitMetadataItemXml(void *ctx, char *tagName);
+void p_saxStartElement(void *ctx, const xmlChar *tagName, const xmlChar **atts);
 
 /** Determines if a line is blank (whitespace only) or a commentline. It returns true if so. The input string
@@ -329,7 +340,5 @@
         break;
     default:
-        psError(PS_ERR_BAD_PARAMETER_TYPE,true,
-                PS_ERRORTEXT_psMetadata_METATYPE_INVALID,
-                (int)type);
+        psError(PS_ERR_BAD_PARAMETER_TYPE,true, PS_ERRORTEXT_psMetadata_METATYPE_INVALID, (int)type);
     }
 }
@@ -680,2 +689,448 @@
     return failedLines;
 }
+
+void saxStartElement(void *ctx, const xmlChar *tagName, const xmlChar **atts)
+{
+    psU64 i = 0;
+    psU64 lineNumber = 0;
+    char* psTagName = NULL;
+    char *psAttName = NULL;
+    char *psAttValue = NULL;
+    const xmlChar *attName = NULL;
+    const xmlChar *attValue = NULL;
+    psMetadata* md = NULL;
+    psHash* htAtts = NULL;
+    xmlParserCtxtPtr ctxt = NULL;
+    xmlParserInputPtr input = NULL;
+
+
+    // Get and check initial data pointers
+    ctxt = (xmlParserCtxtPtr)ctx;
+    PS_PTR_CHECK_NULL_GENERAL(ctxt, return);
+    md = (psMetadata*)ctxt->sax->_private;
+    PS_PTR_CHECK_NULL_GENERAL(md, return);
+    input = (xmlParserInputPtr)ctxt->input;
+    PS_PTR_CHECK_NULL_GENERAL(input, return);
+
+    // Copy XML strings to psStrings to avoid libxml2/psLib memory corruption problems
+    psTagName = psStringCopy(tagName);
+
+    // Metadata containter for housing element attributes used by other SAX events
+    htAtts = psHashAlloc(10);
+
+    // Get tag name
+    if(psTagName != NULL) {
+        psHashAdd(htAtts, "tagName", psTagName);
+    } else {
+        PS_PTR_CHECK_NULL_GENERAL(psTagName, return);
+        psFree(htAtts);
+        psFree(psTagName);
+        return;
+    }
+
+    // Get all attribute names and attribute values
+    if(atts != NULL) {
+        attName = atts[i++];
+        attValue = atts[i++];
+        while(attName != NULL) {
+            if(attValue != NULL) {
+
+                // Copy XML strings to psStrings to avoid libxml2/psLib memory corruption problems
+                psAttName = psStringCopy(attName);
+                psAttValue = psStringCopy(attValue);
+                psHashAdd(htAtts, psAttName, psAttValue);
+                psFree(psAttName);
+                psFree(psAttValue);
+            } else {
+                PS_PTR_CHECK_NULL_GENERAL(psAttValue, return);
+                psFree(htAtts);
+                psFree(psTagName);
+                return;
+            }
+            attName = atts[i++];
+            attValue = atts[i++];
+        }
+    }
+
+    // Add attributes to metadata
+    psMetadataAdd(md, PS_LIST_TAIL, "htAtts", PS_META_HASH, NULL, htAtts);
+
+    psFree(psTagName);
+
+    return;
+}
+
+void p_psInitMetadataItemXml(void *ctx, char *tagName)
+{
+    psBool overwrite = false;
+    psBool tempBool = false;
+    psS32 status = 0;
+    psU64 lineNumber = 0;
+    psF64 tempDbl = 0.0;
+    psS32 tempInt = 0.0;
+    psElemType elemType;
+    psMetadataType mdType;
+    char *fileName = NULL;
+    char *strName = NULL;
+    char *strType = NULL;
+    char *strValue = NULL;
+    psMetadata* md = NULL;
+    psHash* htAtts = NULL;
+    psMetadataItem *metadataItem = NULL;
+    xmlParserCtxtPtr ctxt = NULL;
+    xmlParserInputPtr input = NULL;
+
+
+    // Get and check initial data pointers
+    ctxt = (xmlParserCtxtPtr)ctx;
+    PS_PTR_CHECK_NULL_GENERAL(ctxt, return);
+    md = (psMetadata*)ctxt->sax->_private;
+    PS_PTR_CHECK_NULL_GENERAL(md, return);
+    input = (xmlParserInputPtr)ctxt->input;
+    PS_PTR_CHECK_NULL_GENERAL(input, return);
+    metadataItem = psMetadataLookup(md, "htAtts");
+    PS_PTR_CHECK_NULL_GENERAL(metadataItem, return);
+    PS_PTR_CHECK_NULL_GENERAL(metadataItem->items, return);
+    psListSetIterator(metadataItem->items, PS_LIST_TAIL);
+    metadataItem = (psMetadataItem*)psListGetCurrent(metadataItem->items);
+    htAtts = (psHash*)metadataItem->data.V;
+    PS_PTR_CHECK_NULL_GENERAL(htAtts, return);
+    fileName = (char*)input->filename;
+    PS_PTR_CHECK_NULL_GENERAL(fileName, return);
+    lineNumber = input->line;
+
+    // Get attribute name
+    strName = psHashLookup(htAtts, "name");
+    if(strName == NULL) {
+        psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_NO_NAME, lineNumber, fileName);
+        return;
+    }
+
+    // Get attribute type, if there is one
+    strType = psHashLookup(htAtts, "psType");
+    if(strType!= NULL) {
+        if(xmlStrEqual(BAD_CAST strType, BAD_CAST "psString")) {
+            mdType = PS_META_STR;
+            elemType = PS_TYPE_PTR;
+        } else if(xmlStrEqual(BAD_CAST strType, BAD_CAST "psBool")) {
+            mdType = PS_META_BOOL;
+            elemType = PS_TYPE_U8;
+        } else if(xmlStrEqual(BAD_CAST strType, BAD_CAST "psS32")) {
+            mdType = PS_META_S32;
+            elemType = PS_TYPE_S32;
+        } else if(xmlStrEqual(BAD_CAST strType, BAD_CAST "psF32")) {
+            mdType = PS_META_F32;
+            elemType = PS_TYPE_F32;
+        } else if(xmlStrEqual(BAD_CAST strType, BAD_CAST "psF64")) {
+            mdType = PS_META_F64;
+            elemType = PS_TYPE_F64;
+        } else {
+            psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_TYPE_INVALID_LINE_FILE, strType, lineNumber,
+                    fileName);
+            return;
+        }
+    }
+
+    // Get attribute value, if there is one
+    strValue = psHashLookup(htAtts, "value");
+
+    /* If metadata item is found, and is not a folder node, and overwrite is allowed, then remove
+    existing and allow switch/case below to add new item. If overwrite is false, then report error. If
+    found item is folder node, then psMetadataAdd will automatically add a new child. */
+    metadataItem = psMetadataLookup(md, "overwrite");
+    if(metadataItem != NULL) {
+        overwrite = parseBool((char*)strValue, &status);
+        if(status) {
+            status = 0;
+            psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_PARSE_FAILED, strValue, strName, strType,
+                    lineNumber, fileName);
+        }
+        metadataItem = psMetadataLookup(md, strName);
+        if(metadataItem != NULL) {
+            if(metadataItem->type != PS_META_ITEM_SET) {
+                if(overwrite) {
+                    psMetadataRemove(md, PS_LIST_UNKNOWN, strName);
+                } else {
+                    psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_OVERWRITE_ITEM, strName, lineNumber,
+                            fileName);
+                    return;
+                }
+            }
+        }
+    }
+
+    // Create metadata item and add to metadata
+    switch(mdType) {
+    case PS_META_ITEM_SET:
+        psMetadataAdd(md, PS_LIST_TAIL, strName, mdType, NULL, NULL);
+        break;
+    case PS_META_BOOL:
+        tempBool = parseBool((char*)strValue, &status);
+        if(!status) {
+            psMetadataAdd(md, PS_LIST_TAIL, strName, mdType, NULL, tempBool);
+        } else {
+            status = 0;
+            psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_PARSE_FAILED, strValue, strName, strType,
+                    lineNumber, fileName);
+        }
+        break;
+    case PS_META_S32:
+        tempInt = (psS32)parseValue((char*)strValue, &status);
+        if(!status) {
+            psMetadataAdd(md, PS_LIST_TAIL, strName, mdType, NULL, tempInt);
+        } else {
+            status = 0;
+            psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_PARSE_FAILED, strValue, strName, strType,
+                    lineNumber, fileName);
+        }
+        break;
+    case PS_META_F32:
+    case PS_META_F64:
+        tempDbl = parseValue((char*)strValue, &status);
+        if(!status) {
+            psMetadataAdd(md, PS_LIST_TAIL, strName, mdType, NULL, tempDbl);
+        } else {
+            status = 0;
+            psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_PARSE_FAILED, strValue, strName, strType,
+                    lineNumber, fileName);
+        }
+        break;
+    case PS_META_STR:
+        psMetadataAdd(md, PS_LIST_TAIL, strName, mdType, NULL, strValue);
+        break;
+    default:
+        psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_TYPE_INVALID, strType, lineNumber, fileName);
+    } // End switch
+
+    return;
+}
+
+
+void p_psInitVectorXml(void *ctx, char *tagName)
+{
+    bool overwrite = false;
+    psS32 status = 0;
+    psU64 lineNumber = 0;
+    psElemType elemType;
+    psMetadataType mdType;
+    char *strName = NULL;
+    char *strType = NULL;
+    char *strValue = NULL;
+    char *fileName = NULL;
+    psMetadataItem *table = NULL;
+    psMetadataItem *tables = NULL;
+    psMetadataItem *metadataItem = NULL;
+    psVector *vec = NULL;
+    psMetadata* md = NULL;
+    psHash* htAtts = NULL;
+    xmlParserCtxtPtr ctxt = NULL;
+    xmlParserInputPtr input = NULL;
+
+
+    // Get and check initial data pointers
+    ctxt = (xmlParserCtxtPtr)ctx;
+    PS_PTR_CHECK_NULL_GENERAL(ctxt, return);
+    md = (psMetadata*)ctxt->sax->_private;
+    PS_PTR_CHECK_NULL_GENERAL(md, return);
+    input = (xmlParserInputPtr)ctxt->input;
+    PS_PTR_CHECK_NULL_GENERAL(input, return);
+    tables = psMetadataLookup(md, "htAtts");
+    PS_PTR_CHECK_NULL_GENERAL(tables, return);
+    PS_PTR_CHECK_NULL_GENERAL(tables->items, return);
+    psListSetIterator(tables->items, PS_LIST_TAIL);
+    table = (psMetadataItem*)psListGetCurrent(tables->items);
+    htAtts = (psHash*)table->data.V;
+    PS_PTR_CHECK_NULL_GENERAL(htAtts, return);
+    fileName = (char*)input->filename;
+    PS_PTR_CHECK_NULL_GENERAL(fileName, return);
+    lineNumber = input->line;
+
+    // Get attribute name
+    strName = psHashLookup(htAtts, "name");
+    if(strName == NULL) {
+        psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_NO_NAME, lineNumber, fileName);
+        return;
+    }
+
+    // Get attribute type, if there is one
+    strType = psHashLookup(htAtts, "psType");
+    if(strType!= NULL) {
+        if(xmlStrEqual(BAD_CAST strType, BAD_CAST "psString")) {
+            mdType = PS_META_STR;
+            elemType = PS_TYPE_PTR;
+        } else if(xmlStrEqual(BAD_CAST strType, BAD_CAST "psBool")) {
+            mdType = PS_META_BOOL;
+            elemType = PS_TYPE_U8;
+        } else if(xmlStrEqual(BAD_CAST strType, BAD_CAST "psS32")) {
+            mdType = PS_META_S32;
+            elemType = PS_TYPE_S32;
+        } else if(xmlStrEqual(BAD_CAST strType, BAD_CAST "psF32")) {
+            mdType = PS_META_F32;
+            elemType = PS_TYPE_F32;
+        } else if(xmlStrEqual(BAD_CAST strType, BAD_CAST "psF64")) {
+            mdType = PS_META_F64;
+            elemType = PS_TYPE_F64;
+        } else {
+            psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_TYPE_INVALID_LINE_FILE, strName, lineNumber,
+                    fileName);
+            return;
+        }
+    }
+
+    strValue = psHashLookup(htAtts, "value");
+    PS_PTR_CHECK_NULL_GENERAL(strValue, return);
+
+
+    /* If metadata item is found, and is not a folder node, and overwrite is allowed, then remove
+    existing and allow switch/case below to add new item. If overwrite is false, then report error. If
+    found item is folder node, then psMetadataAdd will automatically add a new child. */
+    metadataItem = psMetadataLookup(md, "overwrite");
+    if(metadataItem != NULL) {
+        overwrite = parseBool((char*)strValue, &status);
+        if(status) {
+            status = 0;
+            psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_PARSE_FAILED, strValue, strName, strType,
+                    input->line, input->filename);
+        }
+        metadataItem = psMetadataLookup(md, strName);
+        if(metadataItem != NULL) {
+            if(metadataItem->type != PS_META_ITEM_SET) {
+                if(overwrite) {
+                    psMetadataRemove(md, PS_LIST_UNKNOWN, strName);
+                } else {
+                    psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_OVERWRITE_ITEM, strName, lineNumber,
+                            fileName);
+                    return;
+                }
+            }
+        }
+    }
+
+    // Get value
+    vec = parseVector((char*)strValue, elemType, &status);
+    if(!status) {
+        psMetadataAdd(md, PS_LIST_TAIL, strName+1, mdType, NULL, vec);
+    } else {
+        psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_PARSE_FAILED, strValue, strName, strType,
+                lineNumber, fileName);
+    }
+    psFree(vec);
+}
+
+void saxEndElement(void *ctx, const xmlChar *tagName)
+{
+    psU64 lineNumber = 0;
+    char *psStartTagName = NULL;
+    char *psEndTagName = NULL;
+    psMetadataType mdType;
+    psMetadata* md = NULL;
+    psHash* htAtts = NULL;
+    psMetadataItem *table = NULL;
+    psMetadataItem *tables = NULL;
+    xmlParserCtxtPtr ctxt = NULL;
+    xmlParserInputPtr input = NULL;
+
+
+    // Get and check initial data pointers
+    ctxt = (xmlParserCtxtPtr)ctx;
+    PS_PTR_CHECK_NULL_GENERAL(ctxt, return);
+    md = (psMetadata*)ctxt->sax->_private;
+    PS_PTR_CHECK_NULL_GENERAL(md, return);
+    input = (xmlParserInputPtr)ctxt->input;
+    PS_PTR_CHECK_NULL_GENERAL(input, return);
+    tables = psMetadataLookup(md, "htAtts");
+    PS_PTR_CHECK_NULL_GENERAL(tables, return);
+    PS_PTR_CHECK_NULL_GENERAL(tables->items, return);
+    psListSetIterator(tables->items, PS_LIST_TAIL);
+    table = (psMetadataItem*)psListGetCurrent(tables->items);
+    htAtts = (psHash*)table->data.V;
+    PS_PTR_CHECK_NULL_GENERAL(htAtts, return);
+
+    // Copy XML strings to psStrings to avoid libxml2/psLib memory corruption problems
+    psEndTagName = psStringCopy(tagName);
+
+    // Compare start and end tag names
+    psStartTagName = psHashLookup(htAtts, "tagName");
+    PS_PTR_CHECK_NULL_GENERAL(psStartTagName, return);
+    if(strcmp(psEndTagName, psStartTagName)) {
+        psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_TAG_MISMATCH, psStartTagName, psEndTagName);
+    }
+
+    // Initialize psLib structs
+    if(!strcmp(psEndTagName, "psMetadataItem")) {
+        p_psInitMetadataItemXml(ctx, psEndTagName);
+    } else if(!strcmp(psEndTagName, "psVector")) {
+        p_psInitVectorXml(ctx, psEndTagName);
+    } else if(strcmp(psEndTagName, "psRoot")) {
+        psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_TAG_UNKNOWN, psEndTagName);
+    }
+
+    // Free temporary metadata item and its hash table
+    psListRemove(tables->items, PS_LIST_TAIL, table);
+
+    psFree(psEndTagName);
+
+    return;
+}
+
+psS32 psMetadataParseConfigXml(psMetadata** md, const char *fileName)
+{
+    psS32 status = 0;
+    FILE *fp = NULL;
+    xmlSAXHandler saxHandler;
+
+
+    // Error checks
+    PS_PTR_CHECK_NULL(fileName,-1);
+
+    // Allocate metadata if necessary
+    if (*md == NULL) {
+        *md = psMetadataAlloc();
+    }
+
+    // Sax handler initializations
+    saxHandler.internalSubset           = NULL;
+    saxHandler.isStandalone             = NULL;
+    saxHandler.hasInternalSubset        = NULL;
+    saxHandler.hasExternalSubset        = NULL;
+    saxHandler.resolveEntity            = NULL;
+    saxHandler.getEntity                = NULL;
+    saxHandler.entityDecl               = NULL;
+    saxHandler.notationDecl             = NULL;
+    saxHandler.attributeDecl            = NULL;
+    saxHandler.elementDecl              = NULL;
+    saxHandler.unparsedEntityDecl       = NULL;
+    saxHandler.setDocumentLocator       = NULL;
+    saxHandler.startDocument            = NULL;
+    saxHandler.endDocument              = NULL;
+    saxHandler.startElement             = saxStartElement;
+    saxHandler.endElement               = saxEndElement;
+    saxHandler.reference                = NULL;
+    saxHandler.characters               = NULL;
+    saxHandler.ignorableWhitespace      = NULL;
+    saxHandler.processingInstruction    = NULL;
+    saxHandler.comment                  = NULL;
+    saxHandler.warning                  = xmlParserError;
+    saxHandler.error                    = xmlParserError;
+    saxHandler.fatalError               = xmlParserError;
+    saxHandler.getParameterEntity       = NULL;
+    saxHandler.cdataBlock               = NULL;
+    saxHandler.externalSubset           = NULL;
+    saxHandler.initialized              = 1;
+    saxHandler._private                 = *md;
+    saxHandler.startElementNs           = NULL;
+    saxHandler.endElementNs             = NULL;
+    saxHandler.serror                   = NULL;
+
+    // Parse XML file
+    if (xmlSAXUserParseFile(&saxHandler, NULL, fileName)) {
+        psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_OPEN_FAILED, fileName);
+        return -1;
+    }
+
+    // Parser and memory cleanups for libxml2
+    xmlCleanupParser();
+    xmlMemoryDump();
+
+    return 0;
+}
