예제 #1
0
파일: TREUtils.c 프로젝트: aivaras16/nitro
NITFPRIV(nitf_Pair*) basicIncrement(nitf_TREEnumerator* it, nitf_Error* error)
{
    /* get the next value, and increment the cursor */
    nitf_TRECursor* cursor = it ? (nitf_TRECursor*)it->data : NULL;
    nitf_Pair* data;

    if (!cursor || !nitf_TRECursor_iterate(cursor, error))
    {
        nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_OBJECT,
                "Invalid cursor, or error iterating...");
        return NULL;
    }

    if (!nitf_TRE_exists(cursor->tre, cursor->tag_str))
        goto CATCH_ERROR;

    data = nitf_HashTable_find(((nitf_TREPrivateData*)cursor->tre->priv)->hash,
            cursor->tag_str);
    if (!data)
        goto CATCH_ERROR;

    return data;

  CATCH_ERROR:
    nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_OBJECT,
            "Couldnt retrieve tag [%s]", cursor->tag_str);
    return NULL;
}
예제 #2
0
파일: TRECursor.c 프로젝트: mdaus/nitro
NITFAPI(NITF_BOOL) nitf_TRECursor_isDone(nitf_TRECursor * tre_cursor)
{
    nitf_Error error;
    int isDone = (tre_cursor->desc_ptr == tre_cursor->end_ptr);

    /* check if the passed in cursor is not at the beginning */
    if (!isDone && tre_cursor->index >= 0)
    {
        nitf_TRECursor dolly = nitf_TRECursor_clone(tre_cursor, &error);
        /* if iterate returns 0, we are done */
        isDone = !nitf_TRECursor_iterate(&dolly, &error);
        isDone = isDone || (dolly.desc_ptr == dolly.end_ptr);
        nitf_TRECursor_cleanup(&dolly);
    }
    return isDone;
}
예제 #3
0
파일: TREUtils.c 프로젝트: aivaras16/nitro
NITFAPI(int) nitf_TREUtils_computeLength(nitf_TRE * tre)
{
    int length = 0;
    int tempLength;
    nitf_Error error;
    nitf_Pair *pair; /* temp nitf_Pair */
    nitf_Field *field; /* temp nitf_Field */
    nitf_TRECursor cursor;

    /* get out if TRE is null */
    if (!tre)
        return -1;

    cursor = nitf_TRECursor_begin(tre);
    while (!nitf_TRECursor_isDone(&cursor))
    {
        if (nitf_TRECursor_iterate(&cursor, &error) == NITF_SUCCESS)
        {
            tempLength = cursor.length;
            if (tempLength == NITF_TRE_GOBBLE)
            {
                /* we don't have any other way to know the length of this
                 * field, other than to see if the field is in the hash
                 * and use the length defined when it was created.
                 * Otherwise, we don't add any length.
                 */
                tempLength = 0;
                pair = nitf_HashTable_find(
                        ((nitf_TREPrivateData*)tre->priv)->hash, cursor.tag_str);
                if (pair)
                {
                    field = (nitf_Field *) pair->data;
                    if (field)
                        tempLength = field->length;
                }
            }
            length += tempLength;
        }
    }
    nitf_TRECursor_cleanup(&cursor);
    return length;
}
예제 #4
0
파일: TREUtils.c 프로젝트: aivaras16/nitro
NITFAPI(NITF_BOOL) nitf_TREUtils_isSane(nitf_TRE * tre)
{
    int status = 1;
    nitf_Error error;
    nitf_TRECursor cursor;

    /* get out if TRE is null */
    if (!tre)
        return NITF_FAILURE;

    cursor = nitf_TRECursor_begin(tre);
    while (!nitf_TRECursor_isDone(&cursor) && status)
    {
        if (nitf_TRECursor_iterate(&cursor, &error) == NITF_SUCCESS)
            if (!nitf_TRE_exists(tre, cursor.tag_str))
                status = !status;
    }
    nitf_TRECursor_cleanup(&cursor);
    return status;
}
예제 #5
0
파일: TREUtils.c 프로젝트: aivaras16/nitro
NITFAPI(int) nitf_TREUtils_print(nitf_TRE * tre, nitf_Error * error)
{
    nitf_Pair *pair; /* temp pair */
    int status = NITF_SUCCESS;
    nitf_TRECursor cursor;

    /* get out if TRE is null */
    if (!tre)
    {
        nitf_Error_init(error, "print -> invalid tre object",
                NITF_CTXT, NITF_ERR_INVALID_PARAMETER);
        return NITF_FAILURE;
    }

    cursor = nitf_TRECursor_begin(tre);
    while (!nitf_TRECursor_isDone(&cursor) && (status == NITF_SUCCESS))
    {
        if ((status = nitf_TRECursor_iterate(&cursor, error)) == NITF_SUCCESS)
        {
            pair = nitf_HashTable_find(
                    ((nitf_TREPrivateData*)tre->priv)->hash, cursor.tag_str);
            if (!pair || !pair->data)
            {
                nitf_Error_initf(error, NITF_CTXT, NITF_ERR_UNK,
                "Unable to find tag, '%s', in TRE hash for TRE '%s'", cursor.tag_str, tre->tag);
                status = NITF_FAILURE;
            }
            else
            {
                printf("%s (%s) = [",
                cursor.desc_ptr->label == NULL ?
                "null" : cursor.desc_ptr->label, cursor.tag_str);
                nitf_Field_print((nitf_Field *) pair->data);
                printf("]\n");
            }
        }
    }
    nitf_TRECursor_cleanup(&cursor);
    return status;
}
예제 #6
0
파일: TREUtils.c 프로젝트: aivaras16/nitro
NITFAPI(NITF_BOOL) nitf_TREUtils_fillData(nitf_TRE * tre,
        const nitf_TREDescription* descrip,
        nitf_Error * error)
{
    nitf_TRECursor cursor;

    /* set the description so the cursor can use it */
    ((nitf_TREPrivateData*)tre->priv)->description =
        (nitf_TREDescription*)descrip;

    /* loop over the description, and add blank fields for the
     * "normal" fields... any special case fields (loops, conditions)
     * won't be added here
     */
    cursor = nitf_TRECursor_begin(tre);
    while (!nitf_TRECursor_isDone(&cursor))
    {
        if (nitf_TRECursor_iterate(&cursor, error))
        {
            nitf_Pair* pair = nitf_HashTable_find(
                    ((nitf_TREPrivateData*)tre->priv)->hash, cursor.tag_str);

            if (!pair || !pair->data)
            {
                nitf_Field* field = NULL;
                int fieldLength = cursor.length;

                /* If it is a GOBBLE length, there isn't really a standard
                 * on how long it can be... therefore we'll just throw in
                 * a field of size 1, just to have something...
                 */
                if (fieldLength == NITF_TRE_GOBBLE)
                {
                    fieldLength = 1;
                }

                field = nitf_Field_construct(fieldLength,
                        cursor.desc_ptr->data_type,
                        error);

                /* set the field to be resizable later on */
                if (cursor.length == NITF_TRE_GOBBLE)
                    field->resizable = 1;

                /* special case if BINARY... must set Raw Data */
                if (cursor.desc_ptr->data_type == NITF_BINARY)
                {
                    char* tempBuf = (char *) NITF_MALLOC(fieldLength);
                    if (!tempBuf)
                    {
                        nitf_Field_destruct(&field);
                        nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO),
                                NITF_CTXT, NITF_ERR_MEMORY);
                        goto CATCH_ERROR;
                    }

                    memset(tempBuf, 0, fieldLength);
                    nitf_Field_setRawData(field, (NITF_DATA *) tempBuf,
                            fieldLength, error);
                }
                else if (cursor.desc_ptr->data_type == NITF_BCS_N)
                {
                    /* this will get zero/blank filled by the function */
                    nitf_Field_setString(field, "0", error);
                }
                else
                {
                    /* this will get zero/blank filled by the function */
                    nitf_Field_setString(field, " ", error);
                }

                /* add to hash if there wasn't an entry yet */
                if (!pair)
                {
                    nitf_HashTable_insert(
                            ((nitf_TREPrivateData*)tre->priv)->hash,
                            cursor.tag_str, field, error);
                }
                /* otherwise, just set the data pointer */
                else
                {
                    pair->data = (NITF_DATA *) field;
                }
            }
        }
    }
    nitf_TRECursor_cleanup(&cursor);

    /* no problems */
    /*    return tre->descrip; */
    return NITF_SUCCESS;

  CATCH_ERROR:
    return NITF_FAILURE;
}
예제 #7
0
파일: TREUtils.c 프로젝트: aivaras16/nitro
NITFAPI(NITF_BOOL) nitf_TREUtils_setValue(nitf_TRE * tre,
                                          const char *tag,
                                          NITF_DATA * data,
                                          size_t dataLength, 
                                          nitf_Error * error)
{
    nitf_Pair *pair;
    nitf_Field *field = NULL;
    nitf_TRECursor cursor;
    NITF_BOOL done = 0;
    NITF_BOOL status = 1;
    nitf_FieldType type = NITF_BCS_A;

    /* used temporarily for storing the length */
    int length;

    /* get out if TRE is null */
    if (!tre)
    {
        nitf_Error_init(error, "setValue -> invalid tre object",
                NITF_CTXT, NITF_ERR_INVALID_PARAMETER);
        return NITF_FAILURE;
    }

    /* If the field already exists, get it and modify it */
    if (nitf_HashTable_exists(((nitf_TREPrivateData*)tre->priv)->hash, tag))
    {
        pair = nitf_HashTable_find(
                ((nitf_TREPrivateData*)tre->priv)->hash, tag);
        field = (nitf_Field *) pair->data;

        if (!field)
        {
            nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER,
                    "setValue -> invalid field object: %s", tag);
            return NITF_FAILURE;
        }

        /* check to see if the data passed in is too large or too small */
        if ((dataLength > field->length && !field->resizable) || dataLength < 1)
        {
            nitf_Error_initf(error, NITF_CTXT, NITF_ERR_INVALID_PARAMETER,
                    "setValue -> invalid dataLength for field: %s", tag);
            return NITF_FAILURE;
        }

        if (!nitf_Field_setRawData
            (field, (NITF_DATA *) data, dataLength, error))
        {
            return NITF_FAILURE;
        }
#ifdef NITF_DEBUG
        fprintf(stdout, "Setting (and filling) Field [%s] to TRE [%s]\n",
                tag, tre->tag);
#endif

        /* Now we need to fill our data */
        if (!nitf_TREUtils_fillData(tre,
                                    ((nitf_TREPrivateData*)tre->priv)->description,
                                    error))
            return NITF_FAILURE;

    }
    /* it doesn't exist in the hash yet, so we need to find it */
    else
    {

        cursor = nitf_TRECursor_begin(tre);
        while (!nitf_TRECursor_isDone(&cursor) && !done && status)
        {
            if (nitf_TRECursor_iterate(&cursor, error) == NITF_SUCCESS)
            {
                /* we found it */
                if (strcmp(tag, cursor.tag_str) == 0)
                {
                    if (cursor.desc_ptr->data_type == NITF_BCS_A)
                    {
                        type = NITF_BCS_A;
                    }
                    else if (cursor.desc_ptr->data_type == NITF_BCS_N)
                    {
                        type = NITF_BCS_N;
                    }
                    else if (cursor.desc_ptr->data_type == NITF_BINARY)
                    {
                        type = NITF_BINARY;
                    }
                    else
                    {
                        /* bad type */
                        nitf_Error_init(error,
                                "setValue -> invalid data type",
                                NITF_CTXT,
                                NITF_ERR_INVALID_PARAMETER);
                        return NITF_FAILURE;
                    }

                    length = cursor.length;
                    /* check to see if we should gobble the rest */
                    if (length == NITF_TRE_GOBBLE)
                    {
                        length = dataLength;
                    }

                    /* construct the field */
                    field = nitf_Field_construct(length, type, error);

                    /* now, set the data */
                    nitf_Field_setRawData(field, (NITF_DATA *) data,
                            dataLength, error);

#ifdef NITF_DEBUG
                    fprintf(stdout, "Adding (and filling) Field [%s] to TRE [%s]\n",
                            cursor.tag_str, tre->tag);
#endif

                    /* add to the hash */
                    nitf_HashTable_insert(
                            ((nitf_TREPrivateData*)tre->priv)->hash,
                            cursor.tag_str, field, error);


                    /* Now we need to fill our data */
                    if (!nitf_TREUtils_fillData(tre, ((nitf_TREPrivateData*)tre->priv)->description, error))
                        return NITF_FAILURE;

                    done = 1; /* set, so we break out of loop */
                }
            }
        }
        /* did we find it? */
        if (!done)
        {
            nitf_Error_initf(error, NITF_CTXT, NITF_ERR_UNK,
                    "Unable to find tag, '%s', in TRE hash for TRE '%s'",
                    tag, tre->tag);
            status = 0;
        }
        nitf_TRECursor_cleanup(&cursor);
    }
    return status;

}
예제 #8
0
파일: TREUtils.c 프로젝트: aivaras16/nitro
NITFAPI(int) nitf_TREUtils_parse(nitf_TRE * tre,
                                 char *bufptr, 
                                 nitf_Error * error)
{
    int status = 1;
    int iterStatus = NITF_SUCCESS;
    int offset = 0;
    int length;
    nitf_TRECursor cursor;
    nitf_Field *field = NULL;
    nitf_TREPrivateData *privData = NULL;

    /* get out if TRE is null */
    if (!tre)
    {
        nitf_Error_init(error, "parse -> invalid tre object",
                NITF_CTXT, NITF_ERR_INVALID_PARAMETER);
        return NITF_FAILURE;
    }

    privData = (nitf_TREPrivateData*)tre->priv;

    /* flush the hash first, to protect from duplicate entries */
    if (privData)
    {
        nitf_TREPrivateData_flush(privData, error);
    }

    cursor = nitf_TRECursor_begin(tre);
    while (offset < privData->length && status)
    {
        if ((iterStatus = 
             nitf_TRECursor_iterate(&cursor, error)) == NITF_SUCCESS)
        {
            length = cursor.length;
            if (length == NITF_TRE_GOBBLE)
            {
                length = privData->length - offset;
            }

            /* no need to call setValue, because we already know
             * it is OK for this one to be in the hash
             */

            /* construct the field */
            field = nitf_Field_construct(length,
                    cursor.desc_ptr->data_type, error);
            if (!field)
                goto CATCH_ERROR;

            /* first, check to see if we need to swap bytes */
            if (field->type == NITF_BINARY
                    && (length == NITF_INT16_SZ || length == NITF_INT32_SZ))
            {
                if (length == NITF_INT16_SZ)
                {
                    nitf_Int16 int16 =
                        (nitf_Int16)NITF_NTOHS(*((nitf_Int16 *) (bufptr + offset)));
                    status = nitf_Field_setRawData(field,
                            (NITF_DATA *) & int16, length, error);
                }
                else if (length == NITF_INT32_SZ)
                {
                    nitf_Int32 int32 =
                        (nitf_Int32)NITF_NTOHL(*((nitf_Int32 *) (bufptr + offset)));
                    status = nitf_Field_setRawData(field,
                            (NITF_DATA *) & int32, length, error);
                }
            }
            else
            {
                /* check for the other binary lengths ... */
                if (field->type == NITF_BINARY)
                {
                    /* TODO what to do??? 8 bit is ok, but what about 64? */
                    /* for now, just let it go through... */
                }

                /* now, set the data */
                status = nitf_Field_setRawData(field, (NITF_DATA *) (bufptr + offset),
                        length, error);
            }

#ifdef NITF_DEBUG
            {
                fprintf(stdout, "Adding Field [%s] to TRE [%s]\n",
                        cursor.tag_str, tre->tag);
            }
#endif

            /* add to the hash */
            nitf_HashTable_insert(((nitf_TREPrivateData*)tre->priv)->hash,
                    cursor.tag_str, field, error);

            offset += length;
        }
        /* otherwise, the iterate function thinks we are done */
        else
        {
            break;
        }
    }
    nitf_TRECursor_cleanup(&cursor);

    /* check if we still have more to parse, and throw an error if so */
    if (offset < privData->length)
    {
        nitf_Error_init(error, "TRE data is longer than it should be",
                NITF_CTXT, NITF_ERR_INVALID_OBJECT);
        status = NITF_FAILURE;
    }
    return status;

    /* deal with errors here */
    CATCH_ERROR:
    return NITF_FAILURE;
}
예제 #9
0
파일: TREUtils.c 프로젝트: aivaras16/nitro
NITFAPI(char *) nitf_TREUtils_getRawData(nitf_TRE * tre, nitf_Uint32* treLength, nitf_Error * error)
{
    int status = 1;
    int offset = 0;
    nitf_Uint32 length;
    int tempLength;

    /* data buffer - Caller must free this */
    char *data = NULL;

    /* temp data buffer */
    char *tempBuf = NULL;

    /* temp nitf_Pair */
    nitf_Pair *pair;
    
    /* temp nitf_Field */
    nitf_Field *field;

    /* the cursor */
    nitf_TRECursor cursor;

    /* get actual length of TRE */
    length = nitf_TREUtils_computeLength(tre);
    *treLength = length;

    if (length <= 0)
    {
        nitf_Error_init(error, "TRE has invalid length",
                NITF_CTXT, NITF_ERR_INVALID_OBJECT);
        return NULL;
    }

    /* allocate the memory - this does not get freed in this function */
    data = (char *) NITF_MALLOC(length + 1);
    if (!data)
    {
        nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO),
                NITF_CTXT, NITF_ERR_MEMORY);
        goto CATCH_ERROR;
    }
    memset(data, 0, length + 1);

    cursor = nitf_TRECursor_begin(tre);
    while (!nitf_TRECursor_isDone(&cursor) && status && offset < length)
    {
        if (nitf_TRECursor_iterate(&cursor, error) == NITF_SUCCESS)
        {
            pair = nitf_HashTable_find(((nitf_TREPrivateData*)tre->priv)->hash,
                    cursor.tag_str);
            if (pair && pair->data)
            {
                tempLength = cursor.length;
                if (tempLength == NITF_TRE_GOBBLE)
                {
                    tempLength = length - offset;
                }
                field = (nitf_Field *) pair->data;

                /* get the raw data */
                tempBuf = NITF_MALLOC(tempLength);
                if (!tempBuf)
                {
                    nitf_Error_init(error, NITF_STRERROR(NITF_ERRNO),
                            NITF_CTXT, NITF_ERR_MEMORY);
                    goto CATCH_ERROR;
                }
                /* get the data as raw buf */
                nitf_Field_get(field, (NITF_DATA *) tempBuf,
                        NITF_CONV_RAW, tempLength, error);

                /* first, check to see if we need to swap bytes */
                if (field->type == NITF_BINARY)
                {
                    if (tempLength == NITF_INT16_SZ)
                    {
                        nitf_Int16 int16 =
                            (nitf_Int16)NITF_HTONS(*((nitf_Int16 *) tempBuf));
                        memcpy(tempBuf, (char*)&int16, tempLength);
                    }
                    else if (tempLength == NITF_INT32_SZ)
                    {
                        nitf_Int32 int32 =
                            (nitf_Int32)NITF_HTONL(*((nitf_Int32 *) tempBuf));
                        memcpy(tempBuf, (char*)&int32, tempLength);
                    }
                    else
                    {
                        /* TODO what to do??? 8 bit is ok, but what about 64? */
                        /* for now, just let it go through... */
                    }
                }

                /* now, memcpy the data */
                memcpy(data + offset, tempBuf, tempLength);
                offset += tempLength;

                /* free the buf */
                NITF_FREE(tempBuf);
            }
            else
            {
                nitf_Error_init(error,
                "Failed due to missing TRE field(s)",
                NITF_CTXT, NITF_ERR_INVALID_OBJECT);
                goto CATCH_ERROR;
            }
        }
    }
    nitf_TRECursor_cleanup(&cursor);
    return data;

  /* deal with errors here */
  CATCH_ERROR:
    if (data)
        NITF_FREE(data);
    return NULL;
}
예제 #10
0
파일: ENGRDA.c 프로젝트: aivaras16/nitro
/* TODO  This is a cut and paste of nitf_TREUtils_parse() with a little bit
 *       of extra logic for determining the appropriate field type for
 *       engineering data.  Is there a way to reuse more of the other
 *       parse function? */
NITFPRIV(int) ENGRDA_parse(nitf_TRE * tre,
                           char *bufptr,
                           nitf_Error * error)
{
    int status = 1;
    int iterStatus = NITF_SUCCESS;
    int offset = 0;
    int length;
    nitf_TRECursor cursor;
    nitf_Field *field = NULL;
    nitf_TREPrivateData *privData = NULL;
    nitf_FieldType prevValueType;
    nitf_FieldType fieldType;

    /* get out if TRE is null */
    if (!tre)
    {
        nitf_Error_init(error, "parse -> invalid tre object",
                NITF_CTXT, NITF_ERR_INVALID_PARAMETER);
        return NITF_FAILURE;
    }

    privData = (nitf_TREPrivateData*)tre->priv;

    /* flush the hash first, to protect from duplicate entries */
    if (privData)
    {
        nitf_TREPrivateData_flush(privData, error);
    }

    cursor = nitf_TRECursor_begin(tre);
    prevValueType = NITF_BINARY;
    while (offset < privData->length && status)
    {
        if ((iterStatus =
             nitf_TRECursor_iterate(&cursor, error)) == NITF_SUCCESS)
        {
            length = cursor.length;
            if (length == NITF_TRE_GOBBLE)
            {
                length = privData->length - offset;
            }

            /* no need to call setValue, because we already know
             * it is OK for this one to be in the hash
             */

            /* for engineering data, the TREDescription specifies the type as
             * binary but in reality it's based on the value type field.  this
             * will be saved off for us below.  it's also critical to set this
             * correctly so that string types don't get endian swapped. */
            fieldType =
                !strncmp(cursor.tag_str, "ENGDATA", 7) ?
                    prevValueType : cursor.desc_ptr->data_type;

            /* construct the field */
            field = nitf_Field_construct(length, fieldType, error);
            if (!field)
                goto CATCH_ERROR;

            /* first, check to see if we need to swap bytes */
            if (field->type == NITF_BINARY
                    && (length == NITF_INT16_SZ || length == NITF_INT32_SZ))
            {
                if (length == NITF_INT16_SZ)
                {
                    nitf_Int16 int16 =
                        (nitf_Int16)NITF_NTOHS(*((nitf_Int16 *) (bufptr + offset)));
                    status = nitf_Field_setRawData(field,
                            (NITF_DATA *) & int16, length, error);
                }
                else if (length == NITF_INT32_SZ)
                {
                    nitf_Int32 int32 =
                        (nitf_Int32)NITF_NTOHL(*((nitf_Int32 *) (bufptr + offset)));
                    status = nitf_Field_setRawData(field,
                            (NITF_DATA *) & int32, length, error);
                }
            }
            else
            {
                /* check for the other binary lengths ... */
                if (field->type == NITF_BINARY)
                {
                    /* TODO what to do??? 8 bit is ok, but what about 64? */
                    /* for now, just let it go through... */
                }

                /* now, set the data */
                status = nitf_Field_setRawData(field, (NITF_DATA *) (bufptr + offset),
                        length, error);
            }

            /* when we see the value type, save it off
             * we'll eventually read this when we get to the engineering data
             * itself */
            if (!strncmp(cursor.tag_str, "ENGTYP", 6) &&
                field->type == NITF_BCS_A &&
                field->length == 1)
            {
                prevValueType = (field->raw[0] == 'A') ?
                    NITF_BCS_A : NITF_BINARY;
            }

#ifdef NITF_DEBUG
            {
                fprintf(stdout, "Adding Field [%s] to TRE [%s]\n",
                        cursor.tag_str, tre->tag);
            }
#endif

            /* add to the hash */
            nitf_HashTable_insert(((nitf_TREPrivateData*)tre->priv)->hash,
                    cursor.tag_str, field, error);

            offset += length;
        }
        /* otherwise, the iterate function thinks we are done */
        else
        {
            break;
        }
    }
    nitf_TRECursor_cleanup(&cursor);

    /* check if we still have more to parse, and throw an error if so */
    if (offset < privData->length)
    {
        nitf_Error_init(error, "TRE data is longer than it should be",
                NITF_CTXT, NITF_ERR_INVALID_OBJECT);
        status = NITF_FAILURE;
    }
    return status;

    /* deal with errors here */
    CATCH_ERROR:
    return NITF_FAILURE;
}
예제 #11
0
파일: TRECursor.c 프로젝트: mdaus/nitro
NITFAPI(int) nitf_TRECursor_iterate(nitf_TRECursor * tre_cursor,
                                    nitf_Error * error)
{
    nitf_TREDescription *dptr;

    int *stack;                 /* used for in conjuction with the stacks */
    int index;                  /* used for in conjuction with the stacks */

    int loopCount = 0;          /* tells how many times to loop */
    int loop_rtni = 0;          /* used for temp storage */
    int loop_idxi = 0;          /* used for temp storage */

    int numIfs = 0;             /* used to keep track of nested Ifs */
    int numLoops = 0;           /* used to keep track of nested Loops */
    int done = 0;               /* flag used for special cases */

    char idx_str[10][10];       /* used for keeping track of indexes */

    if (!tre_cursor->loop || !tre_cursor->loop_idx
        || !tre_cursor->loop_rtn)
    {
        /* not initialized */
        nitf_Error_init(error, "Unhandled TRE Value data type",
                        NITF_CTXT, NITF_ERR_INVALID_PARAMETER);
        return NITF_FAILURE;
    }

    /* count how many descriptions there are */

	dptr = ((nitf_TREPrivateData*)tre_cursor->tre->priv)->description;

    while (!done)
    {
        done = 1;               /* set the flag */

        /* iterate the index */
        tre_cursor->index++;

        if (tre_cursor->index < tre_cursor->numItems)
        {
            memset(tre_cursor->tag_str, 0, TAG_BUF_LEN);

            tre_cursor->prev_ptr = tre_cursor->desc_ptr;
            tre_cursor->desc_ptr = &dptr[tre_cursor->index];

            /* if already in a loop, prepare the array of values */
            if (tre_cursor->looping)
            {
                stack = tre_cursor->loop_idx->st;
                /* assert, because we only prepare for 10 */
                assert(tre_cursor->looping <= 10);

                for (index = 0; index < tre_cursor->looping; index++)
                {
                    NITF_SNPRINTF(idx_str[index], TAG_BUF_LEN,
                                  "[%d]", stack[index]);
                }
            }

            /* check if it is an actual item now */
            /* ASCII string */
            if ((tre_cursor->desc_ptr->data_type == NITF_BCS_A) ||
                    /* ASCII number */
                    (tre_cursor->desc_ptr->data_type == NITF_BCS_N) ||
                    /* raw bytes */
                    (tre_cursor->desc_ptr->data_type == NITF_BINARY))
            {
                NITF_SNPRINTF(tre_cursor->tag_str, TAG_BUF_LEN, "%s",
                        tre_cursor->desc_ptr->tag);
                /* check if data is part of an array */
                if (tre_cursor->looping)
                {
                    stack = tre_cursor->loop_idx->st;
                    for (index = 0; index < tre_cursor->looping; index++)
                    {
                        char entry[64];
                        NITF_SNPRINTF(entry, 64, "[%d]", stack[index]);
                        strcat(tre_cursor->tag_str, entry);
                    }
                }

                /* check to see if we don't know the length */
                if (tre_cursor->desc_ptr->data_count ==
                        NITF_TRE_CONDITIONAL_LENGTH)
                {
                    /* compute it from the function given */
                    if (tre_cursor->desc_ptr->special)
                    {
                        /* evaluate the special string as a postfix expression */
                        tre_cursor->length =
                            nitf_TRECursor_evaluatePostfix(
                                tre_cursor->tre,
                                idx_str,
                                tre_cursor->looping,
                                tre_cursor->desc_ptr->special,
                                error);

                        if (tre_cursor->length < 0)
                        {
                            /* error! */
                            nitf_Error_print(error, stderr, "TRE expression error:");
                            return NITF_FAILURE;
                        }
                    }
                    else
                    {
                        /* should we return failure here? */
                        /* for now, just set the length to 0, which forces an
                           iteration... */
                        tre_cursor->length = 0;
                    }

                    if (tre_cursor->length == 0)
                    {
                        return nitf_TRECursor_iterate(tre_cursor, error);
                    }
                }
                else
                {
                    /* just set the length that was in the TREDescription */
                    tre_cursor->length = tre_cursor->desc_ptr->data_count;
                }
            }
            /* NITF_LOOP, NITF_IF, etc. */
            else if ((tre_cursor->desc_ptr->data_type >=
                      NITF_LOOP)
                     && (tre_cursor->desc_ptr->data_type < NITF_END))
            {
                done = 0;       /* set the flag */

                /* start of a loop */
                if (tre_cursor->desc_ptr->data_type == NITF_LOOP)
                {
                    loopCount =
                        nitf_TRECursor_evalLoops(tre_cursor->tre,
                                       tre_cursor->desc_ptr, idx_str,
                                       tre_cursor->looping, error);
                    if (loopCount > 0)
                    {
                        tre_cursor->looping++;
                        /* record loopcount in @loop stack */
                        nitf_IntStack_push(tre_cursor->loop, loopCount,
                                           error);
                        /* record i in @loop_rtn stack */
                        nitf_IntStack_push(tre_cursor->loop_rtn,
                                           tre_cursor->index, error);
                        /* record a 0 in @loop_idx stack */
                        nitf_IntStack_push(tre_cursor->loop_idx, 0, error);
                    }
                    else
                    {
                        numLoops = 1;
                        /* skip until we see the matching ENDLOOP */
                        while (numLoops
                                && (++tre_cursor->index <
                                    tre_cursor->numItems))
                        {
                            tre_cursor->desc_ptr =
                                &dptr[tre_cursor->index];
                            if (tre_cursor->desc_ptr->data_type ==
                                    NITF_LOOP)
                                numLoops++;
                            else if (tre_cursor->desc_ptr->data_type ==
                                     NITF_ENDLOOP)
                                numLoops--;
                        }
                    }
                }
                /* end of a loop */
                else if (tre_cursor->desc_ptr->data_type == NITF_ENDLOOP)
                {
                    /* retrieve loopcount from @loop stack */
                    loopCount = nitf_IntStack_pop(tre_cursor->loop, error);
                    /* retrieve loop_rtn from @loop_rtn stack */
                    loop_rtni =
                        nitf_IntStack_pop(tre_cursor->loop_rtn, error);
                    /* retrieve loop_idx from @loop_idx stack */
                    loop_idxi =
                        nitf_IntStack_pop(tre_cursor->loop_idx, error);

                    if (--loopCount > 0)
                    {
                        /* record loopcount in @loop stack */
                        nitf_IntStack_push(tre_cursor->loop, loopCount,
                                           error);
                        /* record i in @loop_rtn stack */
                        nitf_IntStack_push(tre_cursor->loop_rtn, loop_rtni,
                                           error);
                        /* record idx in @loop_idx stack */
                        nitf_IntStack_push(tre_cursor->loop_idx,
                                           ++loop_idxi, error);
                        /* jump to the start of the loop */
                        tre_cursor->index = loop_rtni;
                    }
                    else
                    {
                        --tre_cursor->looping;
                    }
                }
                /* an if clause */
                else if (tre_cursor->desc_ptr->data_type == NITF_IF)
                {
                    if (!nitf_TRECursor_evalIf
                            (tre_cursor->tre,
                             tre_cursor->desc_ptr,
                             idx_str,
                             tre_cursor->looping, error))
                    {
                        numIfs = 1;
                        /* skip until we see the matching ENDIF */
                        while (numIfs
                                && (++tre_cursor->index <
                                    tre_cursor->numItems))
                        {
                            tre_cursor->desc_ptr =
                                &dptr[tre_cursor->index];
                            if (tre_cursor->desc_ptr->data_type == NITF_IF)
                                numIfs++;
                            else if (tre_cursor->desc_ptr->data_type ==
                                     NITF_ENDIF)
                                numIfs--;
                        }
                    }
                }
            }
            else
            {
                nitf_Error_init(error, "Unhandled TRE Value data type",
                                NITF_CTXT, NITF_ERR_INVALID_PARAMETER);
                return NITF_FAILURE;
            }
        }
        else
        {
            /* should return FALSE instead. signifies we are DONE iterating! */
            return NITF_FAILURE;
        }
    }
    return NITF_SUCCESS;
}