Index: /trunk/psLib/src/astronomy/psMetadata.c
===================================================================
--- /trunk/psLib/src/astronomy/psMetadata.c	(revision 1314)
+++ /trunk/psLib/src/astronomy/psMetadata.c	(revision 1314)
@@ -0,0 +1,295 @@
+/** @file  psMetadata.c
+ *
+ *
+ *  @brief Contains metadata struuctures, enumerations and functions prototypes
+ *
+ *  This file defines metadata item, metadata type, metadata flags, metadata containers, and function
+ *  prototypes necessary creating psLib metadata APIs
+ *
+ *  @ingroup Metadata
+ *
+ *  @author Ross Harman, MHPCC
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-07-28 23:51:42 $
+ *
+ *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
+ */
+
+/******************************************************************************/
+/*  INCLUDE FILES                                                             */
+/******************************************************************************/
+#include<stdio.h>
+#include<stdarg.h>
+#include<string.h>
+
+#include "psType.h"
+#include "psMemory.h"
+#include "psError.h"
+#include "psAbort.h"
+#include "psList.h"
+#include "psHash.h"
+#include "psMetadata.h"
+
+
+/******************************************************************************/
+/*  DEFINE STATEMENTS                                                         */
+/******************************************************************************/
+
+// None
+
+/******************************************************************************/
+/*  TYPE DEFINITIONS                                                          */
+/******************************************************************************/
+
+// None
+
+/*****************************************************************************/
+/*  GLOBAL VARIABLES                                                         */
+/*****************************************************************************/
+
+// None
+
+/*****************************************************************************/
+/*  FILE STATIC VARIABLES                                                    */
+/*****************************************************************************/
+
+static int metadataId = 0;
+
+/*****************************************************************************/
+/*  FUNCTION IMPLEMENTATION - LOCAL                                          */
+/*****************************************************************************/
+static void p_psMetadataItemFree(psMetadataItem *metadataItem)
+{
+    psMetadataType type;
+
+    type = metadataItem->type;
+
+    if (metadataItem == NULL) {
+        return;
+    }
+
+    psFree(metadataItem->name);
+    psFree(metadataItem->comment);
+
+    if(type==PS_META_STR || type==PS_META_IMG || type==PS_META_JPEG || type==PS_META_PNG ||
+            type==PS_META_ASTROM || type==PS_META_UNKNOWN) {
+        psFree(metadataItem->data.V);
+    }
+
+    psFree(metadataItem->items);
+}
+
+static void p_psMetadataFree(psMetadata *metadata)
+{
+    if (metadata == NULL) {
+        return;
+    }
+
+    psFree(metadata->list);
+    psFree(metadata->table);
+}
+
+/*****************************************************************************/
+/* FUNCTION IMPLEMENTATION - PUBLIC                                          */
+/*****************************************************************************/
+
+psMetadataItem *psMetadataItemAlloc(const char *name, psMetadataType type, const char *comment, ...)
+{
+    va_list argPtr = NULL;
+    psMetadataItem *metadataItem = NULL;
+
+    // Get the variable list parameters to pass to allocation function
+    va_start(argPtr, comment);
+
+    // Call metadata item allocation
+    metadataItem = psMetadataItemAllocV(name, type, comment, argPtr);
+
+    // Clean up stack after variable arguement has been used
+    va_end(argPtr);
+
+    return metadataItem;
+}
+
+psMetadataItem *psMetadataItemAllocV(const char *name, psMetadataType type, const char *comment, va_list argPtr)
+{
+    psMetadataItem *metadataItem = NULL;
+
+    if(name == NULL) {
+        psError(__func__, "Null value for string not allowed");
+        return NULL;
+    }
+
+    // Allocate metadata item
+    metadataItem = (psMetadataItem *)psAlloc(sizeof(psMetadataItem));
+    if(metadataItem == NULL) {
+        psAbort(__func__,"Failed to allocate memory");
+    }
+
+    // Set deallocator
+    p_psMemSetDeallocator(metadataItem,(psFreeFcn)p_psMetadataItemFree);
+
+    // 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
+        strncpy(metadataItem->comment, "", MAX_STRING_LENGTH);
+    } else {
+        strncpy(metadataItem->comment, comment, MAX_STRING_LENGTH);
+    }
+
+    // Set metadata item id
+    *(int*)metadataItem->id = ++metadataId;
+
+    // Set metadata item type
+    metadataItem->type = type;
+
+    // Set metadata item value
+    switch(type) {
+    case PS_META_S32:
+        metadataItem->data.S32 = va_arg(argPtr, psS32);
+        break;
+    case PS_META_F32:
+        metadataItem->data.F32 = (psF32)va_arg(argPtr, psF64);
+        break;
+    case PS_META_F64:
+        metadataItem->data.F64 = va_arg(argPtr, psF64);
+        break;
+    case PS_META_STR:
+    case PS_META_IMG:
+    case PS_META_JPEG:
+    case PS_META_PNG:
+    case PS_META_ASTROM:
+    case PS_META_UNKNOWN:
+        metadataItem->data.V = psMemIncrRefCounter(va_arg(argPtr, psPTR));
+        break;
+    default:
+        psError(__func__, " Invalid psMetadataType: %d", type);
+    }
+
+    // Allocate and set metadata item name
+    metadataItem->name = (char *)psAlloc(sizeof(char)*MAX_STRING_LENGTH);
+    vsprintf(metadataItem->name, name, argPtr);
+
+    // Allocate metadata items with same name.
+    metadataItem->items = psListAlloc(NULL);
+
+    return metadataItem;
+}
+
+psMetadata *psMetadataAlloc(void)
+{
+    psList *list = NULL;
+    psHash *table = NULL;
+    psMetadata *metadata = NULL;
+
+    // Allocate metadata
+    metadata = (psMetadata *)psAlloc(sizeof(psMetadata));
+    if(metadata == NULL) {
+        psAbort(__func__,"Failed to allocate metadata");
+    }
+
+    // Set deallocator
+    p_psMemSetDeallocator(metadata,(psFreeFcn)p_psMetadataFree);
+
+    // Allocate internal containers
+    list = (psList *)psAlloc(sizeof(psList));
+    if(list == NULL) {
+        psAbort(__func__,"Failed to allocate list");
+    }
+
+    table = (psHash *)psAlloc(sizeof(psHash));
+    if(table == NULL) {
+        psAbort(__func__,"Failed to allocate table");
+    }
+
+    return metadata;
+}
+
+bool psMetadataAddItem(psMetadata *restrict md, int where, psMetadataItem *restrict metadataItem)
+{
+    char *key = NULL;
+    psHash *mdTable = NULL;
+    psList *mdList = NULL;
+    psMetadataItem *value = NULL;
+    psMetadataType type = PS_META_ITEM_SET;
+
+    if(md == NULL) {
+        psError(__func__, "Null metadata collection not allowed");
+        return false;
+    }
+
+    if(metadataItem == NULL) {
+        psError(__func__, "Null metadata item not allowed");
+        return false;
+    }
+
+    type = metadataItem->type;
+
+    mdTable = md->table;
+    if(mdTable == NULL) {
+        psError(__func__, "Null metadata table not allowed");
+        return false;
+    }
+
+    mdList = md->list;
+    if(mdList == NULL) {
+        psError(__func__, "Null metadata list not allowed");
+        return false;
+    }
+
+    key = metadataItem->name;
+    if(key == NULL) {
+        psError(__func__, "Null key item not allowed");
+        return false;
+    }
+
+    // Check if key is already in table
+    value = (psMetadataItem*)psHashLookup(mdTable, key);
+    if(value!=NULL && type!=PS_META_ITEM_SET) {
+
+        // The key was found and the new metadata item is a leaf node (its type isn't PS_META_ITEM_SET), so
+        // add the new metadata item as a child of the existing metadata item folder node.
+        if(!psListAdd(value->items, metadataItem, where)) {
+            psError(__func__, "Couldn't add metadata item to items list. Name: %s",
+                    metadataItem->name);
+            return false;
+        }
+    } else if(value != NULL) {
+
+        // The key was found and the new metadata item is a folder node. Don't add new metadata item, since
+        // it will wipe out existing node.
+        psError(__func__, "Metadata already exists in metadata collection. Item not added. Name: %s",
+                metadataItem->name);
+        return false;
+    } else {
+
+        // Duplicate key not found. Add new metadata item to metadata collection's hash and list containers
+        if(!psHashAdd(mdTable, key, metadataItem)) {
+            psError(__func__, "Couldn't add metadata item to metadata collection table. Name: %s",
+                    metadataItem->name);
+            return false;
+        }
+
+        if(!psListAdd(md->list, metadataItem, where)) {
+            psError(__func__, "Couldn't add metadata item to metadata collection list. Name: %s",
+                    metadataItem->name);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool psMetadataAdd(psMetadata *restrict md, int where, const char *name, psMetadataType type,
+                   const char *comment, ...)
+{
+    va_list argPtr = NULL;
+    psMetadataItem *metadataItem = NULL;
+
+    va_start(argPtr, comment);
+    metadataItem = psMetadataItemAllocV(name, type, comment, argPtr);
+    va_end(argPtr);
+
+    return psMetadataAddItem(md, where, metadataItem);
+}
Index: /trunk/psLib/src/collections/psMetadata.c
===================================================================
--- /trunk/psLib/src/collections/psMetadata.c	(revision 1314)
+++ /trunk/psLib/src/collections/psMetadata.c	(revision 1314)
@@ -0,0 +1,295 @@
+/** @file  psMetadata.c
+ *
+ *
+ *  @brief Contains metadata struuctures, enumerations and functions prototypes
+ *
+ *  This file defines metadata item, metadata type, metadata flags, metadata containers, and function
+ *  prototypes necessary creating psLib metadata APIs
+ *
+ *  @ingroup Metadata
+ *
+ *  @author Ross Harman, MHPCC
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-07-28 23:51:42 $
+ *
+ *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
+ */
+
+/******************************************************************************/
+/*  INCLUDE FILES                                                             */
+/******************************************************************************/
+#include<stdio.h>
+#include<stdarg.h>
+#include<string.h>
+
+#include "psType.h"
+#include "psMemory.h"
+#include "psError.h"
+#include "psAbort.h"
+#include "psList.h"
+#include "psHash.h"
+#include "psMetadata.h"
+
+
+/******************************************************************************/
+/*  DEFINE STATEMENTS                                                         */
+/******************************************************************************/
+
+// None
+
+/******************************************************************************/
+/*  TYPE DEFINITIONS                                                          */
+/******************************************************************************/
+
+// None
+
+/*****************************************************************************/
+/*  GLOBAL VARIABLES                                                         */
+/*****************************************************************************/
+
+// None
+
+/*****************************************************************************/
+/*  FILE STATIC VARIABLES                                                    */
+/*****************************************************************************/
+
+static int metadataId = 0;
+
+/*****************************************************************************/
+/*  FUNCTION IMPLEMENTATION - LOCAL                                          */
+/*****************************************************************************/
+static void p_psMetadataItemFree(psMetadataItem *metadataItem)
+{
+    psMetadataType type;
+
+    type = metadataItem->type;
+
+    if (metadataItem == NULL) {
+        return;
+    }
+
+    psFree(metadataItem->name);
+    psFree(metadataItem->comment);
+
+    if(type==PS_META_STR || type==PS_META_IMG || type==PS_META_JPEG || type==PS_META_PNG ||
+            type==PS_META_ASTROM || type==PS_META_UNKNOWN) {
+        psFree(metadataItem->data.V);
+    }
+
+    psFree(metadataItem->items);
+}
+
+static void p_psMetadataFree(psMetadata *metadata)
+{
+    if (metadata == NULL) {
+        return;
+    }
+
+    psFree(metadata->list);
+    psFree(metadata->table);
+}
+
+/*****************************************************************************/
+/* FUNCTION IMPLEMENTATION - PUBLIC                                          */
+/*****************************************************************************/
+
+psMetadataItem *psMetadataItemAlloc(const char *name, psMetadataType type, const char *comment, ...)
+{
+    va_list argPtr = NULL;
+    psMetadataItem *metadataItem = NULL;
+
+    // Get the variable list parameters to pass to allocation function
+    va_start(argPtr, comment);
+
+    // Call metadata item allocation
+    metadataItem = psMetadataItemAllocV(name, type, comment, argPtr);
+
+    // Clean up stack after variable arguement has been used
+    va_end(argPtr);
+
+    return metadataItem;
+}
+
+psMetadataItem *psMetadataItemAllocV(const char *name, psMetadataType type, const char *comment, va_list argPtr)
+{
+    psMetadataItem *metadataItem = NULL;
+
+    if(name == NULL) {
+        psError(__func__, "Null value for string not allowed");
+        return NULL;
+    }
+
+    // Allocate metadata item
+    metadataItem = (psMetadataItem *)psAlloc(sizeof(psMetadataItem));
+    if(metadataItem == NULL) {
+        psAbort(__func__,"Failed to allocate memory");
+    }
+
+    // Set deallocator
+    p_psMemSetDeallocator(metadataItem,(psFreeFcn)p_psMetadataItemFree);
+
+    // 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
+        strncpy(metadataItem->comment, "", MAX_STRING_LENGTH);
+    } else {
+        strncpy(metadataItem->comment, comment, MAX_STRING_LENGTH);
+    }
+
+    // Set metadata item id
+    *(int*)metadataItem->id = ++metadataId;
+
+    // Set metadata item type
+    metadataItem->type = type;
+
+    // Set metadata item value
+    switch(type) {
+    case PS_META_S32:
+        metadataItem->data.S32 = va_arg(argPtr, psS32);
+        break;
+    case PS_META_F32:
+        metadataItem->data.F32 = (psF32)va_arg(argPtr, psF64);
+        break;
+    case PS_META_F64:
+        metadataItem->data.F64 = va_arg(argPtr, psF64);
+        break;
+    case PS_META_STR:
+    case PS_META_IMG:
+    case PS_META_JPEG:
+    case PS_META_PNG:
+    case PS_META_ASTROM:
+    case PS_META_UNKNOWN:
+        metadataItem->data.V = psMemIncrRefCounter(va_arg(argPtr, psPTR));
+        break;
+    default:
+        psError(__func__, " Invalid psMetadataType: %d", type);
+    }
+
+    // Allocate and set metadata item name
+    metadataItem->name = (char *)psAlloc(sizeof(char)*MAX_STRING_LENGTH);
+    vsprintf(metadataItem->name, name, argPtr);
+
+    // Allocate metadata items with same name.
+    metadataItem->items = psListAlloc(NULL);
+
+    return metadataItem;
+}
+
+psMetadata *psMetadataAlloc(void)
+{
+    psList *list = NULL;
+    psHash *table = NULL;
+    psMetadata *metadata = NULL;
+
+    // Allocate metadata
+    metadata = (psMetadata *)psAlloc(sizeof(psMetadata));
+    if(metadata == NULL) {
+        psAbort(__func__,"Failed to allocate metadata");
+    }
+
+    // Set deallocator
+    p_psMemSetDeallocator(metadata,(psFreeFcn)p_psMetadataFree);
+
+    // Allocate internal containers
+    list = (psList *)psAlloc(sizeof(psList));
+    if(list == NULL) {
+        psAbort(__func__,"Failed to allocate list");
+    }
+
+    table = (psHash *)psAlloc(sizeof(psHash));
+    if(table == NULL) {
+        psAbort(__func__,"Failed to allocate table");
+    }
+
+    return metadata;
+}
+
+bool psMetadataAddItem(psMetadata *restrict md, int where, psMetadataItem *restrict metadataItem)
+{
+    char *key = NULL;
+    psHash *mdTable = NULL;
+    psList *mdList = NULL;
+    psMetadataItem *value = NULL;
+    psMetadataType type = PS_META_ITEM_SET;
+
+    if(md == NULL) {
+        psError(__func__, "Null metadata collection not allowed");
+        return false;
+    }
+
+    if(metadataItem == NULL) {
+        psError(__func__, "Null metadata item not allowed");
+        return false;
+    }
+
+    type = metadataItem->type;
+
+    mdTable = md->table;
+    if(mdTable == NULL) {
+        psError(__func__, "Null metadata table not allowed");
+        return false;
+    }
+
+    mdList = md->list;
+    if(mdList == NULL) {
+        psError(__func__, "Null metadata list not allowed");
+        return false;
+    }
+
+    key = metadataItem->name;
+    if(key == NULL) {
+        psError(__func__, "Null key item not allowed");
+        return false;
+    }
+
+    // Check if key is already in table
+    value = (psMetadataItem*)psHashLookup(mdTable, key);
+    if(value!=NULL && type!=PS_META_ITEM_SET) {
+
+        // The key was found and the new metadata item is a leaf node (its type isn't PS_META_ITEM_SET), so
+        // add the new metadata item as a child of the existing metadata item folder node.
+        if(!psListAdd(value->items, metadataItem, where)) {
+            psError(__func__, "Couldn't add metadata item to items list. Name: %s",
+                    metadataItem->name);
+            return false;
+        }
+    } else if(value != NULL) {
+
+        // The key was found and the new metadata item is a folder node. Don't add new metadata item, since
+        // it will wipe out existing node.
+        psError(__func__, "Metadata already exists in metadata collection. Item not added. Name: %s",
+                metadataItem->name);
+        return false;
+    } else {
+
+        // Duplicate key not found. Add new metadata item to metadata collection's hash and list containers
+        if(!psHashAdd(mdTable, key, metadataItem)) {
+            psError(__func__, "Couldn't add metadata item to metadata collection table. Name: %s",
+                    metadataItem->name);
+            return false;
+        }
+
+        if(!psListAdd(md->list, metadataItem, where)) {
+            psError(__func__, "Couldn't add metadata item to metadata collection list. Name: %s",
+                    metadataItem->name);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool psMetadataAdd(psMetadata *restrict md, int where, const char *name, psMetadataType type,
+                   const char *comment, ...)
+{
+    va_list argPtr = NULL;
+    psMetadataItem *metadataItem = NULL;
+
+    va_start(argPtr, comment);
+    metadataItem = psMetadataItemAllocV(name, type, comment, argPtr);
+    va_end(argPtr);
+
+    return psMetadataAddItem(md, where, metadataItem);
+}
Index: /trunk/psLib/src/types/psMetadata.c
===================================================================
--- /trunk/psLib/src/types/psMetadata.c	(revision 1314)
+++ /trunk/psLib/src/types/psMetadata.c	(revision 1314)
@@ -0,0 +1,295 @@
+/** @file  psMetadata.c
+ *
+ *
+ *  @brief Contains metadata struuctures, enumerations and functions prototypes
+ *
+ *  This file defines metadata item, metadata type, metadata flags, metadata containers, and function
+ *  prototypes necessary creating psLib metadata APIs
+ *
+ *  @ingroup Metadata
+ *
+ *  @author Ross Harman, MHPCC
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-07-28 23:51:42 $
+ *
+ *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
+ */
+
+/******************************************************************************/
+/*  INCLUDE FILES                                                             */
+/******************************************************************************/
+#include<stdio.h>
+#include<stdarg.h>
+#include<string.h>
+
+#include "psType.h"
+#include "psMemory.h"
+#include "psError.h"
+#include "psAbort.h"
+#include "psList.h"
+#include "psHash.h"
+#include "psMetadata.h"
+
+
+/******************************************************************************/
+/*  DEFINE STATEMENTS                                                         */
+/******************************************************************************/
+
+// None
+
+/******************************************************************************/
+/*  TYPE DEFINITIONS                                                          */
+/******************************************************************************/
+
+// None
+
+/*****************************************************************************/
+/*  GLOBAL VARIABLES                                                         */
+/*****************************************************************************/
+
+// None
+
+/*****************************************************************************/
+/*  FILE STATIC VARIABLES                                                    */
+/*****************************************************************************/
+
+static int metadataId = 0;
+
+/*****************************************************************************/
+/*  FUNCTION IMPLEMENTATION - LOCAL                                          */
+/*****************************************************************************/
+static void p_psMetadataItemFree(psMetadataItem *metadataItem)
+{
+    psMetadataType type;
+
+    type = metadataItem->type;
+
+    if (metadataItem == NULL) {
+        return;
+    }
+
+    psFree(metadataItem->name);
+    psFree(metadataItem->comment);
+
+    if(type==PS_META_STR || type==PS_META_IMG || type==PS_META_JPEG || type==PS_META_PNG ||
+            type==PS_META_ASTROM || type==PS_META_UNKNOWN) {
+        psFree(metadataItem->data.V);
+    }
+
+    psFree(metadataItem->items);
+}
+
+static void p_psMetadataFree(psMetadata *metadata)
+{
+    if (metadata == NULL) {
+        return;
+    }
+
+    psFree(metadata->list);
+    psFree(metadata->table);
+}
+
+/*****************************************************************************/
+/* FUNCTION IMPLEMENTATION - PUBLIC                                          */
+/*****************************************************************************/
+
+psMetadataItem *psMetadataItemAlloc(const char *name, psMetadataType type, const char *comment, ...)
+{
+    va_list argPtr = NULL;
+    psMetadataItem *metadataItem = NULL;
+
+    // Get the variable list parameters to pass to allocation function
+    va_start(argPtr, comment);
+
+    // Call metadata item allocation
+    metadataItem = psMetadataItemAllocV(name, type, comment, argPtr);
+
+    // Clean up stack after variable arguement has been used
+    va_end(argPtr);
+
+    return metadataItem;
+}
+
+psMetadataItem *psMetadataItemAllocV(const char *name, psMetadataType type, const char *comment, va_list argPtr)
+{
+    psMetadataItem *metadataItem = NULL;
+
+    if(name == NULL) {
+        psError(__func__, "Null value for string not allowed");
+        return NULL;
+    }
+
+    // Allocate metadata item
+    metadataItem = (psMetadataItem *)psAlloc(sizeof(psMetadataItem));
+    if(metadataItem == NULL) {
+        psAbort(__func__,"Failed to allocate memory");
+    }
+
+    // Set deallocator
+    p_psMemSetDeallocator(metadataItem,(psFreeFcn)p_psMetadataItemFree);
+
+    // 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
+        strncpy(metadataItem->comment, "", MAX_STRING_LENGTH);
+    } else {
+        strncpy(metadataItem->comment, comment, MAX_STRING_LENGTH);
+    }
+
+    // Set metadata item id
+    *(int*)metadataItem->id = ++metadataId;
+
+    // Set metadata item type
+    metadataItem->type = type;
+
+    // Set metadata item value
+    switch(type) {
+    case PS_META_S32:
+        metadataItem->data.S32 = va_arg(argPtr, psS32);
+        break;
+    case PS_META_F32:
+        metadataItem->data.F32 = (psF32)va_arg(argPtr, psF64);
+        break;
+    case PS_META_F64:
+        metadataItem->data.F64 = va_arg(argPtr, psF64);
+        break;
+    case PS_META_STR:
+    case PS_META_IMG:
+    case PS_META_JPEG:
+    case PS_META_PNG:
+    case PS_META_ASTROM:
+    case PS_META_UNKNOWN:
+        metadataItem->data.V = psMemIncrRefCounter(va_arg(argPtr, psPTR));
+        break;
+    default:
+        psError(__func__, " Invalid psMetadataType: %d", type);
+    }
+
+    // Allocate and set metadata item name
+    metadataItem->name = (char *)psAlloc(sizeof(char)*MAX_STRING_LENGTH);
+    vsprintf(metadataItem->name, name, argPtr);
+
+    // Allocate metadata items with same name.
+    metadataItem->items = psListAlloc(NULL);
+
+    return metadataItem;
+}
+
+psMetadata *psMetadataAlloc(void)
+{
+    psList *list = NULL;
+    psHash *table = NULL;
+    psMetadata *metadata = NULL;
+
+    // Allocate metadata
+    metadata = (psMetadata *)psAlloc(sizeof(psMetadata));
+    if(metadata == NULL) {
+        psAbort(__func__,"Failed to allocate metadata");
+    }
+
+    // Set deallocator
+    p_psMemSetDeallocator(metadata,(psFreeFcn)p_psMetadataFree);
+
+    // Allocate internal containers
+    list = (psList *)psAlloc(sizeof(psList));
+    if(list == NULL) {
+        psAbort(__func__,"Failed to allocate list");
+    }
+
+    table = (psHash *)psAlloc(sizeof(psHash));
+    if(table == NULL) {
+        psAbort(__func__,"Failed to allocate table");
+    }
+
+    return metadata;
+}
+
+bool psMetadataAddItem(psMetadata *restrict md, int where, psMetadataItem *restrict metadataItem)
+{
+    char *key = NULL;
+    psHash *mdTable = NULL;
+    psList *mdList = NULL;
+    psMetadataItem *value = NULL;
+    psMetadataType type = PS_META_ITEM_SET;
+
+    if(md == NULL) {
+        psError(__func__, "Null metadata collection not allowed");
+        return false;
+    }
+
+    if(metadataItem == NULL) {
+        psError(__func__, "Null metadata item not allowed");
+        return false;
+    }
+
+    type = metadataItem->type;
+
+    mdTable = md->table;
+    if(mdTable == NULL) {
+        psError(__func__, "Null metadata table not allowed");
+        return false;
+    }
+
+    mdList = md->list;
+    if(mdList == NULL) {
+        psError(__func__, "Null metadata list not allowed");
+        return false;
+    }
+
+    key = metadataItem->name;
+    if(key == NULL) {
+        psError(__func__, "Null key item not allowed");
+        return false;
+    }
+
+    // Check if key is already in table
+    value = (psMetadataItem*)psHashLookup(mdTable, key);
+    if(value!=NULL && type!=PS_META_ITEM_SET) {
+
+        // The key was found and the new metadata item is a leaf node (its type isn't PS_META_ITEM_SET), so
+        // add the new metadata item as a child of the existing metadata item folder node.
+        if(!psListAdd(value->items, metadataItem, where)) {
+            psError(__func__, "Couldn't add metadata item to items list. Name: %s",
+                    metadataItem->name);
+            return false;
+        }
+    } else if(value != NULL) {
+
+        // The key was found and the new metadata item is a folder node. Don't add new metadata item, since
+        // it will wipe out existing node.
+        psError(__func__, "Metadata already exists in metadata collection. Item not added. Name: %s",
+                metadataItem->name);
+        return false;
+    } else {
+
+        // Duplicate key not found. Add new metadata item to metadata collection's hash and list containers
+        if(!psHashAdd(mdTable, key, metadataItem)) {
+            psError(__func__, "Couldn't add metadata item to metadata collection table. Name: %s",
+                    metadataItem->name);
+            return false;
+        }
+
+        if(!psListAdd(md->list, metadataItem, where)) {
+            psError(__func__, "Couldn't add metadata item to metadata collection list. Name: %s",
+                    metadataItem->name);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool psMetadataAdd(psMetadata *restrict md, int where, const char *name, psMetadataType type,
+                   const char *comment, ...)
+{
+    va_list argPtr = NULL;
+    psMetadataItem *metadataItem = NULL;
+
+    va_start(argPtr, comment);
+    metadataItem = psMetadataItemAllocV(name, type, comment, argPtr);
+    va_end(argPtr);
+
+    return psMetadataAddItem(md, where, metadataItem);
+}
