Index: trunk/psLib/src/collections/psMetadata.c
===================================================================
--- trunk/psLib/src/collections/psMetadata.c	(revision 3938)
+++ trunk/psLib/src/collections/psMetadata.c	(revision 3945)
@@ -12,6 +12,6 @@
 *  @author Ross Harman, MHPCC
 *
-*  @version $Revision: 1.61 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2005-04-28 19:52:48 $
+*  @version $Revision: 1.62 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2005-05-16 19:43:53 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -38,6 +38,34 @@
 #include "psAstronomyErrors.h"
 #include "psConstants.h"
+#include "psLogMsg.h"
+
+/******************************************************************************/
+/*  DEFINE STATEMENTS                                                         */
+/******************************************************************************/
+
+/** Maximum size of a string */
+#define MAX_STRING_LENGTH 1024
+
+/******************************************************************************/
+/*  TYPE DEFINITIONS                                                          */
+/******************************************************************************/
+
+// None
+
+/*****************************************************************************/
+/*  GLOBAL VARIABLES                                                         */
+/*****************************************************************************/
+
+// None
+
+/*****************************************************************************/
+/*  FILE STATIC VARIABLES                                                    */
+/*****************************************************************************/
 
 static psS32 metadataId = 0;
+
+/*****************************************************************************/
+/*  FUNCTION IMPLEMENTATION - LOCAL                                          */
+/*****************************************************************************/
 
 static psMetadataItem* makeMetaMulti(psHash* table, const char* key, psMetadataItem* existing)
@@ -48,11 +76,11 @@
     }
 
+    // move any existing entry into a psList
+    psList* newList = psListAlloc(existing);
 
     psMetadataItem* item = psMetadataItemAlloc(key,
                            PS_META_MULTI,
-                           "List of Metadata Items",
-                           NULL);
-
-    psListAdd(item->data.list,PS_LIST_TAIL,existing);
+                           "",
+                           newList);
 
     if (existing != NULL) {
@@ -60,7 +88,8 @@
     }
 
-    psHashAdd(table, key, item); // put in the new MULTI list entry
-
-    // free local references of newly allocated item.
+    psHashAdd(table, key, item); // put in the new entry
+
+    // free local references of newly allocated items.
+    psFree(newList);
     psFree(item);
 
@@ -80,5 +109,6 @@
     psFree(metadataItem->name);
     psFree(metadataItem->comment);
-    if (! PS_META_IS_PRIMITIVE(type)) {
+
+    if(!PS_META_IS_PRIMITIVE(type)) {
         psFree(metadataItem->data.V);
     }
@@ -104,4 +134,5 @@
     psFree(metadata->list);
     psFree(metadata->table);
+
 }
 
@@ -146,6 +177,5 @@
 {
     psMetadataItem* metadataItem = NULL;
-    char tmp;
-    int nBytes;
+
 
     PS_PTR_CHECK_NULL(name,NULL);
@@ -158,10 +188,11 @@
     psMemSetDeallocator(metadataItem, (psFreeFcn) metadataItemFree);
 
-    // set metadata item comment
+    // Allocate and set metadata item comment
+    metadataItem->comment = (char *)psAlloc(sizeof(char) * MAX_STRING_LENGTH);
     if (comment == NULL) {
         // Per SDRS, null isn't allowed, must use "" instead
-        metadataItem->comment = psStringCopy("");
+        strncpy(metadataItem->comment, "", MAX_STRING_LENGTH);
     } else {
-        metadataItem->comment = psStringCopy(comment);
+        strncpy(metadataItem->comment, comment, MAX_STRING_LENGTH);
     }
 
@@ -173,6 +204,5 @@
 
     // Allocate and set metadata item name
-    nBytes = vsnprintf(&tmp, 0, name, argPtr) + 1;
-    metadataItem->name = (char *)psAlloc(sizeof(char) * nBytes);
+    metadataItem->name = (char *)psAlloc(sizeof(char) * MAX_STRING_LENGTH);
     vsprintf(metadataItem->name, name, argPtr);
 
@@ -193,9 +223,5 @@
     case PS_META_STR:
         // Perform copy of input strings
-        metadataItem->data.V = psStringCopy(va_arg(argPtr, char *));
-        break;
-    case PS_META_MULTI:
-        // MULTI needs to create a psList entry, value must be NULL
-        metadataItem->data.list = psListAlloc(NULL);
+        metadataItem->data.V = psStringNCopy(va_arg(argPtr, char *), MAX_STRING_LENGTH);
         break;
     case PS_META_LIST:
@@ -207,4 +233,6 @@
     case PS_META_ASTROM:
     case PS_META_UNKNOWN:
+    case PS_META_META:
+    case PS_META_MULTI:
         // Copy of input data not performed due to variability of data types
         metadataItem->data.V = psMemIncrRefCounter(va_arg(argPtr, psPtr));
@@ -258,55 +286,70 @@
 
     // See if key is already in table
-    existingEntry = psMetadataLookup(md, key);
-
-    // if replace is set, remove any existing items of the same key
-    if (existingEntry != NULL && (flags & PS_META_REPLACE) != 0) {
-        psMetadataRemove(md,0,key);
-        existingEntry = NULL;
-    }
-
-    // if the metadataItem is MULTI, just create a MULTI node.
+    existingEntry = (psMetadataItem*)psHashLookup(mdTable, key);
+
     if (metadataItem->type == PS_META_MULTI) {
-        if (metadataItem->data.list == NULL || metadataItem->data.list->size > 0) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE,true,
-                    "Specified PS_META_MULTI item is not defined properly "
-                    "(list allocated with zero size).");
-            return false;
-        }
-
-        // make sure the existing entry is PS_META_MULTI
+        // the incoming entry is PS_META_MULTI
+
+        // force the hash entry to be PS_META_MULTI
         existingEntry = makeMetaMulti(mdTable,key,existingEntry);
 
+        // add all the items in the incoming entry to metadata
+        psList* list = metadataItem->data.list;
+        if (list != NULL) {
+            psListIterator* iter = psListIteratorAlloc(list,PS_LIST_HEAD,true);
+            psMetadataItem* listItem;
+            while ((listItem=(psMetadataItem*)psListGetAndIncrement(iter)) != NULL) {
+                psMetadataAddItem(md,listItem,location,flags);
+            }
+            psFree(iter);
+        }
+
         return true; // all done.
     }
 
     // how the item is added to the hash depends on prior existence, flags, etc.
-    if(existingEntry == NULL) { // no prior existence
-        // Node doesn't already exist - Add new metadata item to metadata collection's hash
-        if(!psHashAdd(mdTable, key, metadataItem)) {
-            psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_TABLE_FAILED,key);
-            return false;
-        }
-    } else {
+    if(existingEntry != NULL) { // prior existence
         if (existingEntry->type == PS_META_MULTI || (flags & PS_META_DUPLICATE_OK) != 0) {
             // duplicate entries allowed - add another entry.
 
-            // make sure the existing hash entry is PS_META_MULTI
+            // make sure the existing entry is PS_META_MULTI
             existingEntry = makeMetaMulti(mdTable,key,existingEntry);
 
-            // add to the hash key's list of entries
+            // add to the hash's list of duplicate entries
             if (! psListAdd(existingEntry->data.list, PS_LIST_TAIL, metadataItem) ) {
                 psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_COLLECTION_FAILED,key);
                 return false;
             }
+        } else if ((flags & PS_META_REPLACE) != 0) {
+            // replace entry instead of creating a duplicate entry.
+
+            // remove the existing entry from metadata
+            psMetadataRemove(md,0,key);
+
+            // treat as if new (added to list below)
+            if(!psHashAdd(mdTable, key, metadataItem)) {
+                psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_TABLE_FAILED,key);
+                return false;
+            }
+
+            // Generate warning that item has been replaced
+            psLogMsg(__func__,PS_LOG_WARN,"Metadata item %s has been replaced",
+                     existingEntry->name);
         } else {
-            // error on duplicate entry.
+            // default is to error on duplicate entry.
             psError(PS_ERR_BAD_PARAMETER_VALUE, true,
                     PS_ERRORTEXT_psMetadata_DUPLICATE_NOT_ALLOWED);
             return false;
         }
-    }
-
-    // finally, add the metadataItem to the metadata's list.
+    } else {
+        // OK, this is a new item.
+
+        // Node doesn't exist - Add new metadata item to metadata collection's hash
+        if(!psHashAdd(mdTable, key, metadataItem)) {
+            psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_TABLE_FAILED,key);
+            return false;
+        }
+    }
+
     if(!psListAdd(mdList, location, metadataItem)) {
         psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_COLLECTION_FAILED,key);
@@ -363,4 +406,5 @@
 METADATA_ADD_TYPE(LookupTable,psLookupTable*,PS_META_LOOKUPTABLE)
 METADATA_ADD_TYPE(Unknown,void*,PS_META_UNKNOWN)
+METADATA_ADD_TYPE(Metadata,psMetadata*,PS_META_META)
 
 psBool psMetadataRemove(psMetadata *md, psS32 where, const char *key)
Index: trunk/psLib/src/collections/psMetadata.h
===================================================================
--- trunk/psLib/src/collections/psMetadata.h	(revision 3938)
+++ trunk/psLib/src/collections/psMetadata.h	(revision 3945)
@@ -11,6 +11,6 @@
 *  @author Ross Harman, MHPCC
 *
-*  @version $Revision: 1.44 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2005-04-08 17:58:57 $
+*  @version $Revision: 1.45 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2005-05-16 19:43:53 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -51,5 +51,6 @@
     PS_META_ASTROM,                    ///< Astrometric coefficients (Stored as item.data.V).
     PS_META_UNKNOWN,                   ///< Other data (Stored as item.data.V).
-    PS_META_MULTI                      ///< Used internally, do not create an metadata item of this type.
+    PS_META_MULTI,                     ///< Used internally, do not create an metadata item of this type.
+    PS_META_META                       ///< Metadata data (Stored as item.data.md).
 } psMetadataType;
 
@@ -105,5 +106,4 @@
 }
 psMetadataIterator;
-
 
 /** Metadata item data structure.
@@ -316,4 +316,6 @@
 psBool psMetadataAddUnknown(psMetadata* md, psS32 location, const char* name,
                             const char* comment, psPtr value);
+psBool psMetadataAddMetadata(psMetadata* md, psS32 location, const char* name,
+                             const char* comment, psMetadata* value);
 
 /** Remove an item from metadata collection.
Index: trunk/psLib/src/collections/psMetadataIO.c
===================================================================
--- trunk/psLib/src/collections/psMetadataIO.c	(revision 3938)
+++ trunk/psLib/src/collections/psMetadataIO.c	(revision 3945)
@@ -8,7 +8,8 @@
 *
 *  @author Ross Harman, MHPCC
+*  @author Eric Van Alst, MHPCC
 *
-*  @version $Revision: 1.25 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2005-04-26 19:53:30 $
+*  @version $Revision: 1.26 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2005-05-16 19:43:53 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -33,5 +34,4 @@
 #include "psConstants.h"
 #include "psAstronomyErrors.h"
-
 
 /******************************************************************************/
@@ -53,23 +53,4 @@
 return NULL;
 
-/** Free and null temporary variables used by config file parser */
-#define CLEAR_TEMPS()                                                                                        \
-if(strName) {                                                                                                \
-    psFree(strName);                                                                                         \
-    strName = NULL;                                                                                          \
-}                                                                                                            \
-if(strType) {                                                                                                \
-    psFree(strType);                                                                                         \
-    strType = NULL;                                                                                          \
-}                                                                                                            \
-if(strValue) {                                                                                               \
-    psFree(strValue);                                                                                        \
-    strValue = NULL;                                                                                         \
-}                                                                                                            \
-if(strComment) {                                                                                             \
-    psFree(strComment);                                                                                      \
-    strComment = NULL;                                                                                       \
-}
-
 /** Maximum size of a FITS line */
 #define FITS_LINE_SIZE 80
@@ -105,7 +86,24 @@
 static void initMetadataItemXml(void *ctx, char *tagName);
 static void 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
- *  must be null terminated. */
+static psMetadata* getMetadataType(char *linePtr);
+static psMetadata* setMetadataItem(psMetadata* template, char* linePtr)
+;
+static void parseLevelInfoFree(p_psParseLevelInfo* info);
+static psBool parseLine(psS32* level,   psArray* levelArray,
+                        char*  linePtr, psS32 lineCount,     char* fileName, psBool overwrite);
+static psBool parseMetadataItem(char* keyName, psS32* level,     psArray* levelArray,
+                                char* linePtr, psS32  lineCount, char*    fileName,    psMetadataFlags flags);
+
+static void parseLevelInfoFree(p_psParseLevelInfo* info)
+{
+    psFree(info->nonUniqueKeyArray);
+    psFree(info->typeArray);
+    psFree(info->templateArray);
+    psFree(info->name);
+    psFree(info->metadata);
+}
+
+// Determines if a line is blank (whitespace only) or a commentline. It returns true if so. The input string
+// must be null terminated.
 psBool ignoreLine(char *inString)
 {
@@ -121,7 +119,7 @@
 
 
-/** Removes leading and trailing whitespace and # characters from a string. The cleaned string is a new null
- *  terminated copy of the original input string. */
-char *cleanString(char *inString, psS32 sLen)
+//  Removes leading and trailing whitespace and # characters from a string. The cleaned string is a new null
+//  terminated copy of the original input string.
+char *cleanString(char *inString, psS32 sLen, psBool ignoreComment)
 {
     char *ptrB = NULL;
@@ -129,16 +127,28 @@
     char *cleaned = NULL;
 
-
+    // Initialize begining of string pointer
     ptrB = inString;
 
-    /* Skip over leading # or whitespace */
-    while (isspace(*ptrB) || *ptrB=='#') {
-        ptrB++;
-    }
-
-    /* Skip over trailing whitespace, null terminators, and # characters */
+    // Skip over leading # or whitespace
+    if(ignoreComment) {
+        while (isspace(*ptrB) || *ptrB=='#') {
+            ptrB++;
+        }
+    } else {
+        while (isspace(*ptrB)) {
+            ptrB++;
+        }
+    }
+
+    // Skip over trailing whitespace, null terminators, and # characters
     ptrE = inString + sLen;
-    while(isspace(*ptrE) || *ptrE=='\0' || *ptrE=='#') {
-        ptrE--;
+    if(ignoreComment) {
+        while(isspace(*ptrE) || *ptrE=='\0' || *ptrE=='#') {
+            ptrE--;
+        }
+    } else {
+        while(isspace(*ptrE) || *ptrE=='\0') {
+            ptrE--;
+        }
     }
 
@@ -152,9 +162,8 @@
 }
 
-/** Count repeat occurances of a single character within a line. The input string must be null terminated. */
+// Count repeat occurances of a single character within a line. The input string must be null terminated.
 psS32 repeatedChars(char *inString, char ch)
 {
     psS32 count = 0;
-
 
     while(*inString!='\0') {
@@ -168,11 +177,16 @@
 }
 
-/** Returns cleaned token based on delimiter, but not including delimiter. Also changes the pointer location
- * the beginning of the string. Tokens are newly allocated null terminated strings. */
-char* getToken(char **inString, char *delimiter, psS32 *status)
+// Returns cleaned token based on delimiter, but not including delimiter. Also changes the pointer location
+// the beginning of the string. Tokens are newly allocated null terminated strings.
+char* getToken(char **inString, char *delimiter, psS32 *status, psBool ignoreComment)
 {
     char *cleanToken = NULL;
+    char *convertChar = NULL;
     psS32 sLen = 0;
 
+    // Convert tab characters to white space
+    while((convertChar=strchr(*inString,'\t')) != NULL ) {
+        *convertChar = ' ';
+    }
 
     // Skip over leading whitespace
@@ -186,5 +200,5 @@
 
         // Create new, cleaned, and null terminated token
-        cleanToken = cleanString(*inString, sLen);
+        cleanToken = cleanString(*inString, sLen,ignoreComment);
 
         // Move to end of token
@@ -197,11 +211,10 @@
 }
 
-/** Returns single parsed value as a double precision number. The input string must be cleaned and null
- * terminated. */
+// Returns single parsed value as a double precision number. The input string must be cleaned and null
+// terminated.
 double parseValue(char *inString, psS32 *status)
 {
     char *end = NULL;
     double value = 0.0;
-
 
     value = strtod(inString, &end);
@@ -235,11 +248,10 @@
 psVector* parseVector(char *inString, psElemType elemType, psS32 *status)
 {
-    char *end = NULL;
-    char *saveValue = NULL;
-    psS32 i = 0;
-    psS32 numValues = 0;
-    double value = 0.0;
-    psVector *vec = NULL;
-
+    char*      end       = NULL;
+    char*      saveValue = NULL;
+    psS32      i         = 0;
+    psS32      numValues = 0;
+    double     value     = 0.0;
+    psVector*  vec       = NULL;
 
     // Cycle through string and count entries
@@ -274,6 +286,24 @@
                 vec->data.U8[i++] = (psU8)value;
                 break;
+            case PS_TYPE_U16:
+                vec->data.U16[i++] = (psU16)value;
+                break;
+            case PS_TYPE_U32:
+                vec->data.U32[i++] = (psU32)value;
+                break;
+            case PS_TYPE_U64:
+                vec->data.U64[i++] = (psU64)value;
+                break;
+            case PS_TYPE_S8:
+                vec->data.S8[i++] = (psS8)value;
+                break;
+            case PS_TYPE_S16:
+                vec->data.S16[i++] = (psS16)value;
+                break;
             case PS_TYPE_S32:
                 vec->data.S32[i++] = (psS32)value;
+                break;
+            case PS_TYPE_S64:
+                vec->data.S64[i++] = (psS64)value;
                 break;
             case PS_TYPE_F32:
@@ -303,4 +333,33 @@
 /* FUNCTION IMPLEMENTATION - PUBLIC                                          */
 /*****************************************************************************/
+
+p_psParseLevelInfo* p_psParseLevelInfoAlloc(void)
+{
+
+    p_psParseLevelInfo* info = NULL;
+
+    // Allocate memory for parse level info
+    info = (p_psParseLevelInfo*)psAlloc(sizeof(p_psParseLevelInfo));
+
+    // If allocation successful then initialize members
+    if(info != NULL) {
+
+        info->nonUniqueKeyArray = psArrayAlloc(10);
+        info->nonUniqueKeyArray->n = 0;
+
+        info->typeArray = psArrayAlloc(10);
+        info->typeArray->n = 0;
+
+        info->templateArray = psArrayAlloc(10);
+        info->templateArray->n = 0;
+
+        info->metadata = NULL;
+        info->name = NULL;
+
+        // Set memory deallocator
+        psMemSetDeallocator(info,(psFreeFcn)parseLevelInfoFree);
+    }
+    return info;
+}
 
 bool psMetadataItemPrint(FILE * fd, const char *format, const psMetadataItem* metadataItem)
@@ -500,26 +559,537 @@
 }
 
+static psMetadata* getMetadataType(char* linePtr)
+{
+    psMetadata*     metadataTemplate = NULL;
+    psS32           status           = 0;
+    char*           token            = NULL;
+    psMetadataItem* tempItem         = NULL;
+
+    // Loop through line and generate metadata items for each token found
+    while((token = getToken(&linePtr," ",&status,false)) != NULL ) {
+
+        // If not allocated then allocate new metadata
+        if(metadataTemplate == NULL) {
+            metadataTemplate = psMetadataAlloc();
+        }
+
+        // Look for comment indicator #
+        if(strstr(token,"#") != 0) {
+            psFree(token);
+            break;
+        }
+
+        // Create metadata item to represent token read
+        tempItem = psMetadataItemAllocStr(token,"","");
+        if(tempItem == NULL) {
+            psFree(metadataTemplate);
+            psFree(token);
+            metadataTemplate = NULL;
+            break;
+        }
+
+        // Add item to template
+        if(!psMetadataAddItem(metadataTemplate, tempItem, PS_LIST_TAIL, PS_META_DEFAULT)) {
+            psFree(metadataTemplate);
+            psFree(tempItem);
+            psFree(token);
+            metadataTemplate = NULL;
+            break;
+        }
+        psFree(tempItem);
+        psFree(token);
+    }
+
+    return metadataTemplate;
+}
+
+static psMetadata* setMetadataItem(psMetadata* template, char* linePtr)
+{
+    psMetadata*      md           = NULL;
+    psS32            items        = 0;
+    char*            token        = NULL;
+    psS32            status       = 0;
+    psMetadataItem*  mdItem       = NULL;
+    psMetadataItem*  templateItem = NULL;
+    psListIterator*  iter         = NULL;
+
+    // Determine the number of items in template
+    items = template->list->size;
+    if(items > 0 ) {
+
+        // Allocate metadata
+        md = psMetadataAlloc()
+             ;
+
+        // Point to first item in template
+        iter = psListIteratorAlloc(template->
+                                   list,PS_LIST_HEAD,true);
+
+        // For each item in template parse line string for values
+        for(psS32 i = 0;
+                i < items;
+                i++) {
+
+            // Get template item
+            templateItem = psListGetAndIncrement(iter)
+                           ;
+            if(templateItem == NULL) {
+                psFree(md);
+                md = NULL;
+                break;
+            }
+
+            // Get the next token on the line
+            token = getToken(&linePtr," ",&status,false);
+            if(token != NULL) {
+                // Allocate metadata item
+                mdItem = psMetadataItemAllocStr(templateItem->name,templateItem->comment,token);
+                if(mdItem == NULL) {
+                    psFree(md);
+                    md = NULL;
+                    psFree(token);
+                    break;
+                }
+                // Add item to metadata
+                if(!psMetadataAddItem(md, mdItem, PS_LIST_TAIL, PS_META_DEFAULT)) {
+                    psFree(md);
+                    md = NULL;
+                    psFree(mdItem);
+                    psFree(token);
+                    break;
+                }
+                psFree(mdItem);
+            } else {
+                // Missing items
+                psFree(md);
+                md = NULL;
+                break;
+            }
+
+            psFree(token);
+        }
+        psFree(iter);
+    }
+    return md;
+}
+
+psBool parseMetadataItem(char* keyName, psS32* level,     psArray* levelArray,
+                         char* linePtr, psS32  lineCount, char*    fileName,   psMetadataFlags flags)
+{
+    psBool               returnValue   = true;
+    psBool               addStatus     = false;
+    psMetadataType       mdType        = PS_META_UNKNOWN;
+    psElemType           vectorType    = PS_TYPE_S8;
+    char*                strType       = NULL;
+    char*                strValue      = NULL;
+    char*                strComment    = NULL;
+    psS32                status        = 0;
+    psMetadata*          md            = NULL;
+    psF64                tempDbl       = 0.0;
+    psBool               tempBool      = false;
+    psS32                tempInt       = 0;
+    psVector*            tempVec       = NULL;
+    char*                tempStr       = NULL;
+    psArray*             nonUniqueKeys = NULL;
+    psBool               typeFound     = false;
+    psArray*             typeArray     = NULL;
+    psArray*             templateArray = NULL;
+    psMetadata*          tempMeta      = NULL;
+    p_psParseLevelInfo*  nextLevelInfo = NULL;
+
+    // Get the metadata item type
+    strType = getToken(&linePtr, " ", &status,true);
+
+    // Check for no type
+    if(strType==NULL) {
+        psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_ELEMENT_NULL, "type",lineCount,
+                fileName);
+        returnValue = false;
+    } else {
+
+        // Set metadata type based on type token
+
+        // Check if the keyName specifies a vector and if so use strType token to find vector type
+        if(*keyName == '@') {
+            mdType = PS_META_VEC;
+            // Get the type of vector
+            if(!strncmp(strType, "U8", 2)) {
+                vectorType = PS_TYPE_U8;
+            } else if (!strncmp(strType,"U16",3)) {
+                vectorType = PS_TYPE_U16;
+            } else if (!strncmp(strType,"U32",3)) {
+                vectorType = PS_TYPE_U32;
+            } else if (!strncmp(strType,"U64",3)) {
+                vectorType = PS_TYPE_U64;
+            } else if (!strncmp(strType,"S8",2)) {
+                vectorType = PS_TYPE_S8;
+            } else if (!strncmp(strType,"S16",3)) {
+                vectorType = PS_TYPE_S16;
+            } else if (!strncmp(strType,"S32",3)) {
+                vectorType = PS_TYPE_S32;
+            } else if (!strncmp(strType,"S64",3)) {
+                vectorType = PS_TYPE_S64;
+            } else if (!strncmp(strType,"F32",3)) {
+                vectorType = PS_TYPE_F32;
+            } else if (!strncmp(strType,"F64",3)) {
+                vectorType = PS_TYPE_F64;
+            } else {
+                psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_PARSE_FAILED, "", keyName,
+                        strType, lineCount, fileName);
+                psFree(strType);
+                return false;
+            }
+        } else if(!strncmp(strType, "STR", 3)) {
+            mdType = PS_META_STR;
+        } else if(!strncmp(strType, "BOOL", 4)) {
+            mdType = PS_META_BOOL;
+        } else if(!strncmp(strType, "S32", 3)) {
+            mdType = PS_META_S32;
+        } else if(!strncmp(strType, "F32", 3)) {
+            mdType = PS_META_F32;
+        } else if(!strncmp(strType, "F64", 3)) {
+            mdType = PS_META_F64;
+        } else if(!strncmp(strType, "MULTI", 5)) {
+            mdType = PS_META_MULTI;
+        } else if(!strncmp(strType, "METADATA", 8)) {
+            mdType = PS_META_META;
+        } else {
+            // Search through user types
+            typeArray = ((p_psParseLevelInfo*)(levelArray->data[*level]))->typeArray;
+            templateArray = ((p_psParseLevelInfo*)(levelArray->data[*level]))->templateArray;
+            for(psS32 k = 0; k < typeArray->n; k++) {
+                if(strcmp(strType,(char*)typeArray->data[k]) == 0) {
+                    tempMeta = setMetadataItem((psMetadata*)templateArray->data[k],linePtr);
+                    if(tempMeta != NULL) {
+                        // Add metadata item
+                        md = ((p_psParseLevelInfo*)(levelArray->data[*level]))->metadata;
+                        addStatus = psMetadataAdd(md,PS_LIST_TAIL,keyName,PS_META_META | flags,"",tempMeta);
+                        // Check for add failure
+                        if (! addStatus) {
+                            psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_OVERWRITE_ITEM,
+                                    keyName, lineCount, fileName);
+                            psFree(strType);
+                            psFree(tempMeta);
+                            return false;
+                        }
+                        psFree(tempMeta);
+                    } else {
+                        // Metadata type read error
+                        psError(PS_ERR_IO,true,PS_ERRORTEXT_psMetadataIO_FILE_ELEMENT_NULL,
+                                keyName,lineCount,fileName);
+                        psFree(strType);
+                        return false;
+                    }
+                    typeFound = true;
+                    break;
+                }
+            }
+            if(!typeFound) {
+                psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_TYPE_INVALID,
+                        strType, lineCount,fileName);
+                psFree(strType);
+                return false;
+            } else {
+                psFree(strType);
+                return true;
+            }
+        }
+    }
+
+    // If type is not MULTI or META then get the value and comment
+    if((mdType != PS_META_MULTI) && (mdType != PS_META_META)) {
+        // Get the metadata item value if there is one.
+        status = 0;
+        strValue = getToken(&linePtr, "#", &status,true);
+        if(status) {
+            psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_ELEMENT_NULL, "value", lineCount,
+                    fileName);
+            psFree(strType);
+            psFree(strValue);
+            return false;
+        }
+        if(strValue==NULL) {
+            psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_ELEMENT_NULL, "value", lineCount,
+                    fileName);
+            psFree(strType);
+            psFree(strValue);
+            return false;
+        }
+        // Not all lines will have comments, so NULL is ok.
+        status = 0;
+        strComment = getToken(&linePtr,"~", &status,true);
+        if(status) {
+            psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_ELEMENT_NULL, "comment", lineCount,
+                    fileName);
+            psFree(strType);
+            psFree(strValue);
+            psFree(strComment);
+        }
+    }
+
+    // Need to add item to metadata so get pointer to metadata
+    status = 0;
+    md = ((p_psParseLevelInfo*)(levelArray->data[*level]))->metadata;
+    nonUniqueKeys = ((p_psParseLevelInfo*)(levelArray->data[*level]))->nonUniqueKeyArray;
+    switch(mdType) {
+    case PS_META_STR:
+        addStatus = psMetadataAdd(md, PS_LIST_TAIL, keyName,
+                                  mdType | flags,
+                                  strComment, strValue);
+        break;
+    case PS_META_BOOL:
+        tempBool = parseBool(strValue, &status);
+        if(!status) {
+            addStatus = psMetadataAdd(md, PS_LIST_TAIL, keyName,
+                                      mdType | flags,
+                                      strComment, tempBool);
+        } else {
+            psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_PARSE_FAILED, strValue, keyName,
+                    strType, lineCount, fileName);
+            returnValue = false;
+        }
+        break;
+    case PS_META_F32:
+    case PS_META_F64:
+        tempDbl = parseValue(strValue, &status);
+        if(!status) {
+            addStatus = psMetadataAdd(md, PS_LIST_TAIL, keyName,
+                                      mdType | flags,
+                                      strComment, tempDbl);
+        } else {
+            psError(PS_ERR_IO, true,
+                    PS_ERRORTEXT_psMetadataIO_PARSE_FAILED, strValue, keyName, strType, lineCount,
+                    fileName);
+            returnValue = false;
+        }
+        break;
+    case PS_META_S32:
+        tempInt = (psS32)parseValue(strValue, &status);
+        if(!status) {
+            addStatus = psMetadataAdd(md, PS_LIST_TAIL, keyName,
+                                      mdType | flags,
+                                      strComment, tempInt);
+        } else {
+            psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_PARSE_FAILED, strValue, keyName,
+                    strType, lineCount, fileName);
+            returnValue = false;
+        }
+        break;
+    case PS_META_VEC:
+        tempVec = parseVector(strValue, vectorType, &status);
+        if(!status) {
+            addStatus = psMetadataAdd(md, PS_LIST_TAIL, keyName+1,
+                                      mdType | flags,
+                                      strComment, tempVec);
+        } else {
+            psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_PARSE_FAILED, strValue, keyName,
+                    strType, lineCount, fileName);
+            returnValue = false;
+        }
+        psFree(tempVec);
+        break;
+    case PS_META_MULTI:
+        // Add key to non-unique array of keys
+        // Check for duplicate MULTI lines
+        addStatus = true;
+        for(psS32 k=0; k < nonUniqueKeys->n; k++) {
+            if(strcmp(keyName,(char*)nonUniqueKeys->data[k]) == 0) {
+                psError(PS_ERR_IO,true,PS_ERRORTEXT_psMetadataIO_DUPLICATE_MULTI,
+                        lineCount,fileName);
+                psFree(strType);
+                return false;
+            }
+        }
+        tempStr = psStringCopy(keyName);
+        nonUniqueKeys = psArrayAdd(nonUniqueKeys,0,tempStr);
+        addStatus = true;
+        psFree(tempStr);
+        break;
+    case PS_META_META:
+        // Create next level info
+        nextLevelInfo = p_psParseLevelInfoAlloc();
+        // Create new metadata
+        nextLevelInfo->metadata = psMetadataAlloc();
+        // Save name of metadata
+        nextLevelInfo->name = psStringCopy(keyName);
+        // Add next level to levelArray
+        levelArray = psArrayAdd(levelArray,1,nextLevelInfo);
+        psFree(nextLevelInfo);
+        // Increment level counter
+        (*level)++;
+        addStatus = true;
+        break;
+    default:
+        psError(PS_ERR_IO,true,PS_ERRORTEXT_psMetadataIO_FILE_TYPE_INVALID,
+                lineCount,fileName);
+        break;
+    }
+
+    // Check if the add status was successful
+    if (! addStatus) {
+        //        psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_OVERWRITE_ITEM, keyName, lineCount,
+        //                fileName);
+        returnValue = false;
+    }
+
+    psFree(strComment);
+    psFree(strValue);
+    psFree(strType);
+
+    return returnValue;
+}
+
+psBool parseLine(psS32* level,     psArray* levelArray, char*  linePtr,
+                 psS32  lineCount, char*    fileName,   psBool overwrite)
+{
+    psBool              returnValue    = true;
+    psMetadataFlags     flags          = PS_META_DEFAULT;
+    char*               keyName        = NULL;
+    psS32               status         = 0;
+    psS32               limit          = 0;
+    psMetadata*         tempTemplate   = NULL;
+    char*               strType        = NULL;
+    psArray*            typeArray      = NULL;
+    psArray*            templateArray  = NULL;
+    p_psParseLevelInfo* upperLevelInfo = NULL;
+    p_psParseLevelInfo* lowerLevelInfo = NULL;
+    psBool              addStatus      = 0;
+
+    // Set flags if overwrite specified
+    if(overwrite) {
+        flags = PS_META_REPLACE;
+    }
+
+    // If line is not a comment or blank, then extract data
+    if(!ignoreLine(linePtr)) {
+
+        // Check for more than one '@' in a line
+        if(repeatedChars(linePtr, '@') > 1) {
+            psError(PS_ERR_IO, true,
+                    PS_ERRORTEXT_psMetadataIO_FILE_MULTIPLE_CHAR, '@', lineCount, fileName);
+            return false;
+        }
+
+        // Get metadata item name
+        keyName = getToken(&linePtr, " ", &status,true);
+        if(status) {
+            psError(PS_ERR_IO, true,
+                    PS_ERRORTEXT_psMetadataIO_FILE_ELEMENT_NULL, "keyName", lineCount, fileName);
+            psFree(keyName);
+            return false;
+        }
+
+        // Check for special keyName values "TYPE", "END"
+        if(strcmp(keyName,"TYPE") == 0 ) {
+            // Get the type name
+            strType = getToken(&linePtr," ",&status,true);
+            if(strType == NULL) {
+                psError(PS_ERR_IO,true,PS_ERRORTEXT_psMetadataIO_FILE_ELEMENT_NULL,"type",lineCount,
+                        fileName);
+                psFree(keyName);
+                return false;
+            }
+            tempTemplate = getMetadataType(linePtr);
+            // Check if type was parsed succesfully
+            if(tempTemplate != NULL) {
+                // Access type array
+                typeArray = ((p_psParseLevelInfo*)(levelArray->data[*level]))->typeArray;
+                // Check if type already exists in array
+                for(psS32 k=0; k < typeArray->n; k++) {
+                    // Compare type name with the list of current types
+                    if(strcmp(strType,(char*)typeArray->data[k]) == 0) {
+                        psError(PS_ERR_IO,true,PS_ERRORTEXT_psMetadataIO_TYPE_DUPLICATE,
+                                strType,lineCount,fileName);
+                        psFree(tempTemplate);
+                        psFree(keyName);
+                        psFree(strType);
+                        return false;
+                    }
+                }
+                // Add key name to array of type
+                typeArray = psArrayAdd(typeArray,1,strType);
+                // Add template to array of templates
+                templateArray = ((p_psParseLevelInfo*)(levelArray->data[*level]))->templateArray;
+                templateArray = psArrayAdd(templateArray,1,tempTemplate);
+                psFree(tempTemplate);
+            } else {
+                psError(PS_ERR_IO,true,PS_ERRORTEXT_psMetadataIO_FILE_TYPE_INVALID,
+                        strType,lineCount,fileName);
+                psFree(keyName);
+                psFree(strType);
+                return false;
+            }
+            psFree(strType);
+        } else if (strcmp(keyName,"END") == 0 ) {
+            if(*level > 0) {
+                upperLevelInfo = ((p_psParseLevelInfo*)(levelArray->data[*level-1]));
+                lowerLevelInfo = ((p_psParseLevelInfo*)(levelArray->data[*level]));
+                // Check name in nonunique list
+                for(psS32 k=0; k < upperLevelInfo->nonUniqueKeyArray->n; k++) {
+                    if(strcmp(upperLevelInfo->nonUniqueKeyArray->data[k],lowerLevelInfo->name) == 0) {
+                        flags = PS_META_DUPLICATE_OK;
+                        break;
+                    }
+                }
+                // Add metadata to upper level metadata
+                addStatus = psMetadataAdd(upperLevelInfo->metadata,
+                                          PS_LIST_TAIL,lowerLevelInfo->name,
+                                          PS_META_META | flags,
+                                          "",
+                                          lowerLevelInfo->metadata);
+                if(!addStatus) {
+                    psFree(keyName);
+                    return false;
+                } else {
+                    // Remove lower info level
+                    if(!psArrayRemove(levelArray,levelArray->data[*level])) {
+                        psFree(keyName);
+                        return false;
+                    }
+                    psFree(lowerLevelInfo);
+                    (*level)--;
+                }
+            } else {
+                psFree(keyName);
+                return false;
+            }
+        } else {
+            // Check if key name present in array of non-unique key names
+            limit = ((p_psParseLevelInfo*)(levelArray->data[*level]))->nonUniqueKeyArray->n;
+            for(psS32 k=0; k < limit; k++) {
+                char* name = (char*)((p_psParseLevelInfo*)
+                                     (levelArray->data[*level]))->nonUniqueKeyArray->data[k];
+                if(strcmp(name,keyName) == 0) {
+                    flags = PS_META_DUPLICATE_OK;
+                }
+            }
+            // Parse metadataItem
+            if(!parseMetadataItem(keyName,level, levelArray, linePtr, lineCount, fileName, flags)) {
+                psFree(keyName);
+                return false;
+            }
+        }
+        psFree(keyName);
+    }
+    return returnValue;
+}
+
 psMetadata* psMetadataParseConfig(psMetadata* md, psU32 *nFail, const char *fileName, psBool overwrite)
 {
-    psBool tempBool;
-    char *line = NULL;
-    char *strName = NULL;
-    char *strType = NULL;
-    char *strValue = NULL;
-    char *strComment = NULL;
-    char *linePtr = NULL;
-    psElemType vecType = 0;
-    psS32 status = 0;
-    psU32 lineCount = 0;
-    psF64 tempDbl = 0.0;
-    psS32 tempInt = 0.0;
-    psVector *tempVec = NULL;
-    FILE *fp = NULL;
-    psMetadataType mdType;
-    psMetadataFlags flags;
-    psBool addStatus;
-
-    // Check for nulls
+    FILE*               fp                   = NULL;
+    char*               line                 = NULL;
+    char*               linePtr              = NULL;
+    psArray*            parseLevelInfoArray  = NULL;
+    psS32               lineCount            = 0;
+    psS32               nestingLevel         = 0;
+    p_psParseLevelInfo* topLevelInfo         = NULL;
+
+    // Check for NULL file name
     PS_PTR_CHECK_NULL(fileName,NULL);
+
+    // Check for NULL nFail
+    PS_PTR_CHECK_NULL(nFail,NULL);
+
+    // Attempt to open specified file
     if((fp=fopen(fileName, "r")) == NULL) {
         psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_OPEN_FAILED, fileName);
@@ -532,4 +1102,14 @@
     }
 
+    // Allocate array to store parse level information
+    parseLevelInfoArray = psArrayAlloc(10);
+    parseLevelInfoArray->n = 0;
+
+    // Set parse level info for the top level
+    topLevelInfo = p_psParseLevelInfoAlloc();
+    topLevelInfo->metadata = psMemIncrRefCounter(md);
+    parseLevelInfoArray = psArrayAdd(parseLevelInfoArray,1,topLevelInfo);
+    psFree(topLevelInfo);
+
     // Create reusable line for continuous read
     line = (char*)psAlloc(MAX_STRING_LENGTH*sizeof(char));
@@ -541,189 +1121,22 @@
         linePtr = line;
         lineCount++;
-        CLEAR_TEMPS();
-
-        // If line is not a comment or blank, then extract data
-        if(!ignoreLine(linePtr)) {
-
-            // Check for more than one '*' or '@' in a line
-            if(repeatedChars(linePtr, '@') > 1) {
-                (*nFail)++;
-                psError(PS_ERR_IO, true,
-                        PS_ERRORTEXT_psMetadataIO_FILE_MULTIPLE_CHAR, '@', lineCount, fileName);
-                continue;
-            } else if(repeatedChars(linePtr, '*') > 1) {
-                (*nFail)++;
-                psError(PS_ERR_IO, true,
-                        PS_ERRORTEXT_psMetadataIO_FILE_MULTIPLE_CHAR, '*', lineCount, fileName);
-                continue;
-            } else if(repeatedChars(linePtr, '~') > 0) {
-                (*nFail)++;
-                psError(PS_ERR_IO, true,
-                        PS_ERRORTEXT_psMetadataIO_FILE_MULTIPLE_CHAR, '~', lineCount, fileName);
-                continue;
-            }
-
-            // Get metadata item name
-            strName = getToken(&linePtr, " ", &status);
-            if(strName==NULL || status) {
-                (*nFail)++;
-                status = 0;
-                psError(PS_ERR_IO, true,
-                        PS_ERRORTEXT_psMetadataIO_FILE_ELEMENT_NULL, "name", lineCount, fileName);
-                continue;
-            }
-
-            flags = (overwrite) ? PS_META_REPLACE : PS_META_DEFAULT;
-
-            // Get the metadata item type
-            strType = getToken(&linePtr, " ", &status);
-            if(strType==NULL) {
-                (*nFail)++;
-                status = 0;
-                psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_ELEMENT_NULL, "type",lineCount,
-                        fileName);
-                continue;
-            } else {
-                char* tempStrType = strType;
-                if(*strType == '*') {
-                    flags = PS_META_DUPLICATE_OK;
-                    tempStrType = strType+1;
-                }
-
-                if(!strncmp(tempStrType, "STR", 3)) {
-                    mdType = PS_META_STR;
-                } else if(!strncmp(tempStrType, "BOOL", 4)) {
-                    mdType = PS_META_BOOL;
-                } else if(!strncmp(tempStrType, "S32", 3)) {
-                    mdType = PS_META_S32;
-                } else if(!strncmp(tempStrType, "F32", 3)) {
-                    mdType = PS_META_F32;
-                } else if(!strncmp(tempStrType, "F64", 3)) {
-                    mdType = PS_META_F64;
-                } else {
-                    (*nFail)++;
-                    psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_TYPE_INVALID, strType, lineCount,
-                            fileName);
-                    continue;
-                }
-            }
-
-            if(*strName == '@') {
-                vecType = PS_META_PRIMITIVE_TYPE(mdType);
-                mdType = PS_META_VEC;
-            }
-
-            // Get the metadata item value if there is one.
-            strValue = getToken(&linePtr, "#", &status);
-            if(status) {
-                (*nFail)++;
-                status = 0;
-                psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_ELEMENT_NULL, "comment", lineCount,
-                        fileName);
-                continue;
-            }
-            if(strValue==NULL) {
-                (*nFail)++;
-                status = 0;
-                psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_ELEMENT_NULL, "value", lineCount,
-                        fileName);
-                continue;
-            }
-
-            // Not all lines will have comments, so NULL is ok.
-            strComment = getToken(&linePtr,"~", &status);
-            if(status) {
-                (*nFail)++;
-                status = 0;
-                psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_ELEMENT_NULL, "comment", lineCount,
-                        fileName);
-                continue;
-            }
-
-            // Create and add metadata item to metadata and parse values
-            switch (mdType) {
-            case PS_META_STR:
-                addStatus = psMetadataAdd(md, PS_LIST_TAIL, strName,
-                                          mdType | flags,
-                                          strComment, strValue);
-                break;
-            case PS_META_VEC:
-                tempVec = parseVector(strValue, vecType, &status);
-                if(!status) {
-                    addStatus = psMetadataAdd(md, PS_LIST_TAIL, strName+1,
-                                              mdType | flags,
-                                              strComment, tempVec);
-                } else {
-                    status = 0;
-                    (*nFail)++;
-                    psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_PARSE_FAILED, strValue, strName,
-                            strType, lineCount, fileName);
-                    continue;
-                }
-                psFree(tempVec);
-                break;
-            case PS_META_BOOL:
-                tempBool = parseBool(strValue, &status);
-                if(!status) {
-                    addStatus = psMetadataAdd(md, PS_LIST_TAIL, strName,
-                                              mdType | flags,
-                                              strComment, tempBool);
-                } else {
-                    status = 0;
-                    (*nFail)++;
-                    psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_PARSE_FAILED, strValue, strName,
-                            strType, lineCount, fileName);
-                    continue;
-                }
-                break;
-            case PS_META_S32:
-                tempInt = (psS32)parseValue(strValue, &status);
-                if(!status) {
-                    addStatus = psMetadataAdd(md, PS_LIST_TAIL, strName,
-                                              mdType | flags,
-                                              strComment, tempInt);
-                } else {
-                    status = 0;
-                    (*nFail)++;
-                    psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_PARSE_FAILED, strValue, strName,
-                            strType, lineCount, fileName);
-                    continue;
-                }
-                break;
-            case PS_META_F32:
-            case PS_META_F64:
-                tempDbl = parseValue(strValue, &status);
-                if(!status) {
-                    addStatus = psMetadataAdd(md, PS_LIST_TAIL, strName,
-                                              mdType | flags,
-                                              strComment, tempDbl);
-                } else {
-                    status = 0;
-                    (*nFail)++;
-                    psError(PS_ERR_IO, true,
-                            PS_ERRORTEXT_psMetadataIO_PARSE_FAILED, strValue, strName, strType, lineCount,
-                            fileName);
-                    continue;
-                }
-                break;
-            default:
-                (*nFail)++;
-                psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_TYPE_INVALID, mdType, lineCount,
-                        fileName);
-                continue;
-            } // switch
-            if (! addStatus) {
-                (*nFail)++;
-                psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_OVERWRITE_ITEM, strName, lineCount,
-                        fileName);
-            }
-
-        } // if ignoreLine
-    } // while loop
-
+
+        if(!parseLine(&nestingLevel,parseLevelInfoArray,linePtr,lineCount,(char*)fileName,overwrite)) {
+            (*nFail)++;
+        }
+    }
+
+    // Free parse array and line buffer
+    psFree(parseLevelInfoArray);
     psFree(line);
 
+    // Check if any failed lined detected
+    if( (*nFail) != 0) {
+        psFree(md);
+        md = NULL;
+    }
     return md;
 }
+
 
 static void saxStartElement(void *ctx, const xmlChar *tagName, const xmlChar **atts)
@@ -750,5 +1163,5 @@
 
     // Copy XML strings to psStrings to avoid libxml2/psLib memory corruption problems
-    psTagName = psStringCopy((const char*)tagName);
+    psTagName = psStringCopy(tagName);
 
     // Metadata containter for housing element attributes used by other SAX events
@@ -774,6 +1187,6 @@
 
                 // Copy XML strings to psStrings to avoid libxml2/psLib memory corruption problems
-                psAttName = psStringCopy((const char*)attName);
-                psAttValue = psStringCopy((const char*)attValue);
+                psAttName = psStringCopy(attName);
+                psAttValue = psStringCopy(attValue);
                 psHashAdd(htAtts, psAttName, psAttValue);
                 psFree(psAttName);
@@ -1082,5 +1495,5 @@
 
     // Copy XML strings to psStrings to avoid libxml2/psLib memory corruption problems
-    psEndTagName = psStringCopy((const char*)tagName);
+    psEndTagName = psStringCopy(tagName);
 
     // Compare start and end tag names
Index: trunk/psLib/src/collections/psMetadataIO.h
===================================================================
--- trunk/psLib/src/collections/psMetadataIO.h	(revision 3938)
+++ trunk/psLib/src/collections/psMetadataIO.h	(revision 3945)
@@ -10,6 +10,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.9 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2005-03-07 20:58:50 $
+ *  @version $Revision: 1.10 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-05-16 19:43:53 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -21,4 +21,15 @@
 /// @{
 
+typedef struct
+{
+    psArray*    nonUniqueKeyArray;
+    psArray*    typeArray;
+    psArray*    templateArray;
+    psMetadata* metadata;
+    char*       name;
+}
+p_psParseLevelInfo;
+
+p_psParseLevelInfo* p_psParseLevelInfoAlloc(void);
 
 /** Print metadata item to file.
