/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by the Board of Trustees of the University of Illinois.         *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the files COPYING and Copyright.html.  COPYING can be found at the root   *
 * of the source code distribution tree; Copyright.html can be found at the  *
 * root level of an installed copy of the electronic HDF5 document set and   *
 * is linked from the top-level documents page.  It can also be found at     *
 * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html.  If you do not have     *
 * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* Programmer: Robb Matzke <matzke@llnl.gov>
 *	       Friday, September 19, 1997
 *
 */
#define H5F_PACKAGE		/*suppress error about including H5Fpkg	  */
#define H5G_PACKAGE		/*suppress error about including H5Gpkg	  */


/* Packages needed by this file... */
#include "H5private.h"		/* Generic Functions			*/
#include "H5Eprivate.h"		/* Error handling		  	*/
#include "H5Fpkg.h"		/* File access				*/
#include "H5Gpkg.h"		/* Groups		  		*/
#include "H5HLprivate.h"	/* Local Heaps				*/
#include "H5Iprivate.h"		/* IDs			  		*/
#include "H5MMprivate.h"	/* Memory management			*/

/* Private typedefs */
/* User data for finding a name in the link messages */
typedef struct {
    /* downward */
    H5F_t      *f;              /* Pointer to file for insertion */
    const char *name;           /* Name to search for */

    /* upward */
    H5G_entry_t *ent;           /* Entry to update when match found */
} H5G_stab_ud1_t;

/* User data for finding object info from B-tree */
typedef struct {
    /* downward */
    H5O_loc_t *grp_oloc;        /* Object location of group */
    hid_t       dxpl_id;        /* DXPL during operation */
    haddr_t     heap_addr;      /* Local heap address for group */

    /* upward */
    H5G_stat_t *statbuf;        /* Caller's statbuf */
} H5G_stab_fnd_ud1_t;

/* User data for finding link information from B-tree */
typedef struct {
    /* downward */
    H5F_t      *file;           /* Pointer to file for query */
    hid_t       dxpl_id;        /* DXPL during operation */
    const char *name;           /* Name to search for */
    haddr_t     heap_addr;      /* Local heap address for group */

    /* upward */
    H5O_link_t *lnk;            /* Caller's link location */
} H5G_stab_fnd_ud2_t;

/* User data for finding object location from B-tree */
typedef struct {
    /* downward */
    H5F_t      *file;           /* Pointer to file for query */
    size_t      size;           /* Buffer size for link value */
    haddr_t     heap_addr;      /* Local heap address for group */
    hid_t       dxpl_id;        /* DXPL during operation */

    /* upward */
    char *buf;                  /* Buffer to fill with link value */
} H5G_stab_fnd_ud3_t;

/* Private prototypes */


/*-------------------------------------------------------------------------
 * Function:	H5G_stab_create_components
 *
 * Purpose:	Creates the components for a new, empty, symbol table (name heap
 *		and B-tree).  The caller can specify an initial size for the
 *		name heap.
 *
 *		In order for the B-tree to operate correctly, the first
 *		item in the heap is the empty string, and must appear at
 *		heap offset zero.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Quincey Koziol
 *		koziol@ncsa.uiuc.edu
 *		Nov  7 2005
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5G_stab_create_components(H5F_t *f, H5O_stab_t *stab, size_t size_hint, hid_t dxpl_id)
{
    size_t	name_offset;	        /* Offset of "" name	*/
    herr_t      ret_value = SUCCEED;    /* Return value */

    FUNC_ENTER_NOAPI(H5G_stab_create_components, FAIL)

    /*
     * Check arguments.
     */
    HDassert(f);
    HDassert(stab);
    HDassert(size_hint > 0);

    /* Create the B-tree */
    if(H5B_create(f, dxpl_id, H5B_SNODE, NULL, &(stab->btree_addr)/*out*/) < 0)
	HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create B-tree")

    /* Create symbol table private heap */
    if(H5HL_create(f, dxpl_id, size_hint, &(stab->heap_addr)/*out*/) < 0)
	HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create heap")
    name_offset = H5HL_insert(f, dxpl_id, stab->heap_addr, 1, "");
    if((size_t)(-1) == name_offset)
	HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't initialize heap")

    /*
     * B-tree's won't work if the first name isn't at the beginning
     * of the heap.
     */
    HDassert(0 == name_offset);

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5G_stab_create_components() */


/*-------------------------------------------------------------------------
 * Function:	H5G_stab_create
 *
 * Purpose:	Creates a new empty symbol table (object header, name heap,
 *		and B-tree).  The caller can specify an initial size for the
 *		name heap.  The object header of the group is opened for
 *		write access.
 *
 *		In order for the B-tree to operate correctly, the first
 *		item in the heap is the empty string, and must appear at
 *		heap offset zero.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Robb Matzke
 *		matzke@llnl.gov
 *		Aug  1 1997
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5G_stab_create(H5O_loc_t *grp_oloc, H5O_stab_t *stab, hid_t dxpl_id)
{
#ifdef H5_GROUP_REVISION
    H5O_ginfo_t	ginfo;	                /* Group info message   */
    size_t      heap_hint;              /* Local heap size hint */
#endif /* H5_GROUP_REVISION */
    size_t      size_hint;              /* Local heap size hint */
    herr_t      ret_value = SUCCEED;    /* Return value */

    FUNC_ENTER_NOAPI(H5G_stab_create, FAIL)

    /*
     * Check arguments.
     */
    HDassert(grp_oloc);
    HDassert(stab);

#ifdef H5_GROUP_REVISION
    /* Get the group info */
    if(NULL == H5O_read(grp_oloc, H5O_GINFO_ID, 0, &ginfo, dxpl_id))
	HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't get group info")

    /* Adjust the size hint, if necessary */
    if(ginfo.lheap_size_hint == 0)
        heap_hint = ginfo.est_num_entries * (ginfo.est_name_len + 1);
    else
        heap_hint = ginfo.lheap_size_hint;
    size_hint = MAX(heap_hint, H5HL_SIZEOF_FREE(grp_oloc->file) + 2);
#else /* H5_GROUP_REVISION */
    size_hint = 4 * (H5HL_SIZEOF_FREE(grp_oloc->file) + 2);
#endif /* H5_GROUP_REVISION */

    if(H5G_stab_create_components(grp_oloc->file, stab, size_hint, dxpl_id) < 0)
	HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create symbol table components")

    /*
     * Insert the symbol table message into the object header and the symbol
     * table entry.
     */
    if(H5O_modify(grp_oloc, H5O_STAB_ID, H5O_NEW_MESG, 0, H5O_UPDATE_TIME, stab, dxpl_id) < 0)
	HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message")

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5G_stab_create() */


/*-------------------------------------------------------------------------
 * Function:	H5G_stab_insert_real
 *
 * Purpose:	Insert a new symbol into a table.
 *		The name of the new symbol is NAME and its symbol
 *		table entry is OBJ_LNK.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Quincey Koziol
 *		koziol@uiuc.edu
 *		Nov  7 2005
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5G_stab_insert_real(H5F_t *f, H5O_stab_t *stab, const char *name,
    H5O_link_t *obj_lnk, hid_t dxpl_id)
{
    H5G_bt_ud1_t	udata;		/* Data to pass through B-tree	*/
    herr_t              ret_value = SUCCEED;       /* Return value */

    FUNC_ENTER_NOAPI(H5G_stab_insert_real, FAIL)

    /* check arguments */
    HDassert(f);
    HDassert(stab);
    HDassert(name && *name);
    HDassert(obj_lnk);

    /* Initialize data to pass through B-tree */
    udata.common.name = name;
    udata.common.heap_addr = stab->heap_addr;
    udata.lnk = obj_lnk;

    /* Insert into symbol table */
    if(H5B_insert(f, dxpl_id, H5B_SNODE, stab->btree_addr, &udata) < 0)
        HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert entry")

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5G_stab_insert_real() */


/*-------------------------------------------------------------------------
 * Function:	H5G_stab_insert
 *
 * Purpose:	Insert a new symbol into the table described by GRP_ENT in
 *		file F.	 The name of the new symbol is NAME and its symbol
 *		table entry is OBJ_ENT.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Robb Matzke
 *		matzke@llnl.gov
 *		Aug  1 1997
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5G_stab_insert(H5O_loc_t *grp_oloc, const char *name, H5O_link_t *obj_lnk,
    hid_t dxpl_id)
{
    H5O_stab_t		stab;		/* Symbol table message		*/
    herr_t              ret_value = SUCCEED;       /* Return value */

    FUNC_ENTER_NOAPI(H5G_stab_insert, FAIL)

    /* check arguments */
    HDassert(grp_oloc && grp_oloc->file);
    HDassert(name && *name);
    HDassert(obj_lnk);

    /* Retrieve symbol table message */
    if(NULL == H5O_read(grp_oloc, H5O_STAB_ID, 0, &stab, dxpl_id))
        HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "not a symbol table")

    if(H5G_stab_insert_real(grp_oloc->file, &stab, name, obj_lnk, dxpl_id) < 0)
        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, H5B_ITER_ERROR, "unable to insert the name")

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5G_stab_insert() */


/*-------------------------------------------------------------------------
 * Function:	H5G_stab_remove
 *
 * Purpose:	Remove NAME from a symbol table.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Robb Matzke
 *              Thursday, September 17, 1998
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5G_stab_remove(H5O_loc_t *loc, const char *name, H5G_obj_t *obj_type, hid_t dxpl_id)
{
    H5O_stab_t		stab;		/*symbol table message		*/
    H5G_bt_ud2_t	udata;		/*data to pass through B-tree	*/
    herr_t              ret_value = SUCCEED;       /* Return value */

    FUNC_ENTER_NOAPI(H5G_stab_remove, FAIL)

    HDassert(loc && loc->file);
    HDassert(name && *name);

    /* Read in symbol table message */
    if(NULL == H5O_read(loc, H5O_STAB_ID, 0, &stab, dxpl_id))
        HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "not a symbol table")

    /* Initialize data to pass through B-tree */
    udata.common.name = name;
    udata.common.heap_addr = stab.heap_addr;
    udata.adj_link = TRUE;
    udata.obj_type = obj_type;

    /* Remove from symbol table */
    if(H5B_remove(loc->file, dxpl_id, H5B_SNODE, stab.btree_addr, &udata) < 0)
        HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to remove entry")

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5G_stab_remove() */


/*-------------------------------------------------------------------------
 * Function:	H5G_stab_delete
 *
 * Purpose:	Delete entire symbol table information from file
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Quincey Koziol
 *              Thursday, March 20, 2003
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5G_stab_delete(H5F_t *f, hid_t dxpl_id, const H5O_stab_t *stab, hbool_t adj_link)
{
    H5G_bt_ud2_t	udata;		/*data to pass through B-tree	*/
    herr_t  ret_value = SUCCEED;

    FUNC_ENTER_NOAPI(H5G_stab_delete, FAIL);

    assert(f);
    assert(stab);
    assert(H5F_addr_defined(stab->btree_addr));
    assert(H5F_addr_defined(stab->heap_addr));

    /* Set up user data for B-tree deletion */
    udata.common.name = NULL;
    udata.common.heap_addr = stab->heap_addr;
    udata.adj_link = adj_link;

    /* Delete entire B-tree */
    if(H5B_delete(f, dxpl_id, H5B_SNODE, stab->btree_addr, &udata)<0)
        HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete symbol table B-tree");

    /* Delete local heap for names */
    if(H5HL_delete(f, dxpl_id, stab->heap_addr)<0)
        HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete symbol table heap");

done:
    FUNC_LEAVE_NOAPI(ret_value);
} /* end H5G_stab_delete() */


/*-------------------------------------------------------------------------
 * Function:	H5G_stab_iterate
 *
 * Purpose:	Iterate over the objects in a group
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Quincey Koziol
 *              Monday, October  3, 2005
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5G_stab_iterate(H5O_loc_t *oloc, hid_t gid, int skip, int *last_obj,
    H5G_iterate_t op, void *op_data, hid_t dxpl_id)
{
    H5G_bt_it_ud1_t	udata;                  /* User data to pass to B-tree callback */
    H5O_stab_t		stab;		        /* Info about symbol table */
    herr_t		ret_value;

    FUNC_ENTER_NOAPI(H5G_stab_iterate, FAIL)

    /* Sanity check */
    HDassert(oloc);
    HDassert(H5I_GROUP == H5I_get_type(gid));
    HDassert(last_obj);
    HDassert(op);

    /* Get the B-tree info */
    if(NULL == H5O_read(oloc, H5O_STAB_ID, 0, &stab, dxpl_id))
	HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to determine local heap address")

    /* Build udata to pass through H5B_iterate() to H5G_node_iterate() */
    udata.group_id = gid;
    udata.skip = skip;
    udata.heap_addr = stab.heap_addr;
    udata.op = op;
    udata.op_data = op_data;
    udata.final_ent = last_obj;

    /* Iterate over the group members */
    if((ret_value = H5B_iterate(oloc->file, H5AC_dxpl_id, H5B_SNODE,
              H5G_node_iterate, stab.btree_addr, &udata))<0)
        HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5G_stab_iterate() */


/*-------------------------------------------------------------------------
 * Function:	H5G_stab_count
 *
 * Purpose:	Count the # of objects in a group
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Quincey Koziol
 *              Tuesday, September  6, 2005
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5G_stab_count(H5O_loc_t *oloc, hsize_t *num_objs, hid_t dxpl_id)
{
    H5O_stab_t		stab;		        /* Info about symbol table */
    herr_t		ret_value;

    FUNC_ENTER_NOAPI(H5G_stab_count, FAIL)

    /* Sanity check */
    HDassert(oloc);
    HDassert(num_objs);

    /* Reset the number of objects in the group */
    *num_objs = 0;

    /* Get the B-tree info */
    if(NULL == H5O_read(oloc, H5O_STAB_ID, 0, &stab, dxpl_id))
	HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to determine local heap address")

    /* Iterate over the group members */
    if((ret_value = H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, H5G_node_sumup, stab.btree_addr, num_objs)) < 0)
        HERROR(H5E_SYM, H5E_CANTINIT, "iteration operator failed");

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5G_stab_count() */


/*-------------------------------------------------------------------------
 * Function:	H5G_stab_get_name_by_idx
 *
 * Purpose:     Returns the name of objects in the group by giving index.
 *
 * Return:	Success:        Non-negative
 *		Failure:	Negative
 *
 * Programmer:	Raymond Lu
 *	        Nov 20, 2002
 *
 *-------------------------------------------------------------------------
 */
ssize_t
H5G_stab_get_name_by_idx(H5O_loc_t *oloc, hsize_t idx, char* name,
    size_t size, hid_t dxpl_id)
{
    H5O_stab_t		stab;	        /* Info about local heap & B-tree */
    H5G_bt_it_ud2_t	udata;          /* Iteration information */
    ssize_t		ret_value;      /* Return value */

    FUNC_ENTER_NOAPI(H5G_stab_get_name_by_idx, FAIL)

    /* Sanity check */
    HDassert(oloc);

    /* Get the B-tree & local heap info */
    if(NULL == H5O_read(oloc, H5O_STAB_ID, 0, &stab, dxpl_id))
	HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to determine local heap address")

    /* Set iteration information */
    udata.idx = idx;
    udata.num_objs = 0;
    udata.heap_addr = stab.heap_addr;
    udata.name = NULL;

    /* Iterate over the group members */
    if((ret_value = H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, H5G_node_name, stab.btree_addr, &udata))<0)
	HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "iteration operator failed")

    /* If we don't know the name now, we almost certainly went out of bounds */
    if(udata.name==NULL)
	HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "index out of bound")

    /* Get the length of the name */
    ret_value = (ssize_t)HDstrlen(udata.name);

    /* Copy the name into the user's buffer, if given */
    if(name) {
        HDstrncpy(name, udata.name, MIN((size_t)(ret_value+1),size));
        if((size_t)ret_value >= size)
            name[size-1]='\0';
    } /* end if */

done:
    /* Free the duplicated name */
    if(udata.name!=NULL)
        H5MM_xfree(udata.name);
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5G_stab_get_name_by_idx() */


/*-------------------------------------------------------------------------
 * Function:	H5G_get_objtype_by_idx
 *
 * Purpose:     Private function for H5Gget_objtype_by_idx.
 *              Returns the type of objects in the group by giving index.
 *
 * Return:	Success:        H5G_GROUP(1), H5G_DATASET(2), H5G_TYPE(3)
 *
 *		Failure:	UNKNOWN
 *
 * Programmer:	Raymond Lu
 *	        Nov 20, 2002
 *
 *-------------------------------------------------------------------------
 */
H5G_obj_t
H5G_stab_get_type_by_idx(H5O_loc_t *oloc, hsize_t idx, hid_t dxpl_id)
{
    H5O_stab_t		stab;	        /* Info about local heap & B-tree */
    H5G_bt_it_ud3_t	udata;          /* User data for B-tree callback */
    H5G_obj_t		ret_value;      /* Return value */

    FUNC_ENTER_NOAPI(H5G_stab_get_type_by_idx, H5G_UNKNOWN)

    /* Sanity check */
    HDassert(oloc);

    /* Get the B-tree & local heap info */
    if(NULL == H5O_read(oloc, H5O_STAB_ID, 0, &stab, dxpl_id))
	HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5G_UNKNOWN, "unable to determine local heap address")

    /* Set iteration information */
    udata.idx = idx;
    udata.num_objs = 0;
    udata.type = H5G_UNKNOWN;

    /* Iterate over the group members */
    if(H5B_iterate(oloc->file, dxpl_id, H5B_SNODE, H5G_node_type, stab.btree_addr, &udata) < 0)
	HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5G_UNKNOWN, "iteration operator failed")

    /* If we don't know the type now, we almost certainly went out of bounds */
    if(udata.type == H5G_UNKNOWN)
	HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5G_UNKNOWN, "index out of bound")

    /* Set the return value */
    ret_value = udata.type;

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5G_stab_get_type_by_idx() */


/*-------------------------------------------------------------------------
 * Function:	H5G_stab_lookup_cb
 *
 * Purpose:     B-tree 'find' callback to retrieve location for an object
 *
 * Return:	Success:        Non-negative
 *
 *		Failure:	Negative
 *
 * Programmer:	Quincey Koziol
 *	        Sep 20, 2005
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5G_stab_lookup_cb(const H5G_entry_t *ent, void *_udata)
{
    H5G_stab_fnd_ud2_t *udata = (H5G_stab_fnd_ud2_t *)_udata;   /* 'User data' passed in */
    herr_t ret_value = SUCCEED; /* Return value */

    FUNC_ENTER_NOAPI_NOINIT(H5G_stab_lookup_cb)

    /* Set link info */
    if(udata->lnk) {
        /* Set (default) common info for link */
        udata->lnk->cset = H5T_CSET_ASCII;
        udata->lnk->ctime = 0;
        udata->lnk->name = H5MM_xstrdup(udata->name);

        /* Object is a symbolic link */
        if(H5G_CACHED_SLINK == ent->type) {
            const char *s;          /* Pointer to link value */
            const H5HL_t *heap;     /* Pointer to local heap for group */

            /* Lock the local heap */
            if(NULL == (heap = H5HL_protect(udata->file, udata->dxpl_id, udata->heap_addr)))
                HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to read protect link value")

            s = H5HL_offset_into(udata->file, heap, ent->cache.slink.lval_offset);

            /* Copy the link value */
            udata->lnk->u.soft.name = H5MM_xstrdup(s);

            /* Release the local heap */
            if(H5HL_unprotect(udata->file, udata->dxpl_id, heap, udata->heap_addr, H5AC__NO_FLAGS_SET) < 0)
                HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to read unprotect link value")

            /* Set link type */
            udata->lnk->type = H5G_LINK_SOFT;
        } /* end if */
        else {
            /* Set address of object */
            udata->lnk->u.hard.addr = ent->header;

            /* Set link type */
            udata->lnk->type = H5G_LINK_HARD;
        } /* end else */
    } /* end if */

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5G_stab_lookup_cb() */


/*-------------------------------------------------------------------------
 * Function:	H5G_stab_lookup
 *
 * Purpose:	Look up an object relative to a group, using symbol table
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Quincey Koziol
 *		koziol@ncsa.uiuc.edu
 *		Sep 20 2005
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5G_stab_lookup(H5O_loc_t *grp_oloc, const char *name, H5O_link_t *lnk,
    hid_t dxpl_id)
{
    H5G_bt_ud3_t bt_udata;      /* Data to pass through B-tree	*/
    H5G_stab_fnd_ud2_t udata;   /* 'User data' to give to callback */
    H5O_stab_t stab;		/* Symbol table message		*/
    herr_t     ret_value = SUCCEED;     /* Return value */

    FUNC_ENTER_NOAPI(H5G_stab_lookup, FAIL)

    /* check arguments */
    HDassert(grp_oloc && grp_oloc->file);
    HDassert(name && *name);
    HDassert(lnk);

    /* Set up user data to pass to 'find' operation callback */
    udata.file = grp_oloc->file;
    udata.dxpl_id = dxpl_id;
    udata.name = name;
    udata.lnk = lnk;

    /* Set up the user data for actual B-tree find operation */
    if(NULL == H5O_read(grp_oloc, H5O_STAB_ID, 0, &stab, dxpl_id))
        HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't read message")
    bt_udata.common.name = name;
    bt_udata.common.heap_addr = stab.heap_addr;
    bt_udata.op = H5G_stab_lookup_cb;
    bt_udata.op_data = &udata;

    /* Finish up user data to pass to 'find' operation callback */
    udata.heap_addr = stab.heap_addr;

    /* Search the B-tree */
    if(H5B_find(grp_oloc->file, dxpl_id, H5B_SNODE, stab.btree_addr, &bt_udata) < 0)
        HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "not found")

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5G_stab_lookup() */