/*
tlv_object.c
BER-TLV (Basic Encoding Rules - Tag Length Value) decoding
This file is part of the Unix driver for Towitoko smartcard readers
Copyright (C) 2002 Carlos Prados <cprados@yahoo.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include "defines.h"
#include "tlv_object.h"
/*
* Exported functions definition
*/
TLV_Object *
TLV_Object_New (void* data, TLV_Object_GetData get_data, unsigned short data_length, unsigned short address)
{
TLV_Object * tlv;
BYTE buffer[2];
unsigned i;
tlv = (TLV_Object *) malloc (sizeof(TLV_Object));
if (tlv != NULL)
{
tlv->data = data;
tlv->get_data = get_data;
tlv->data_length = data_length;
tlv->address = address;
/* Get Tag */
i=0;
if ((address >= data_length) || !((*get_data)(data, address, 1, buffer)))
{
free (tlv);
return NULL;
}
/* Two bytes tag */
if ((buffer[0] & 0x1F) == 0x1F)
{
i++;
if ((address+i >= data_length) || !((*get_data)(data, address+i, 1, buffer+i)))
{
free (tlv);
return NULL;
}
tlv->tag = (buffer[0] << 8) | buffer[1];
}
/* One byte tag */
else
tlv->tag = 0x00FF & buffer[0];
/* Get length */
i++;
if ((address+i >= data_length) || !((*get_data)(data, address+i, 1, buffer)))
{
free (tlv);
return NULL;
}
/* Length > 127 */
if ((buffer[0] & 0x80) == 0x80)
{
i++;
/* 256 > length > 127 */
if ((buffer[0] & 0x7F) == 0x01)
{
if ((address+i >= data_length) || !((*get_data)(data, address+i, 1, buffer)))
{
free (tlv);
return NULL;
}
tlv->length = 0x00FF & buffer[0];
i++;
}
/* 65536 > length > 255 */
else if ((buffer[0] & 0x7F) == 0x02)
{
if ((address+i+1 >= data_length) || !((*get_data)(data, address+i, 2, buffer)))
{
free (tlv);
return NULL;
}
tlv->length = (buffer[0] << 8) | buffer[1];
i+=2;
}
else
{
free (tlv);
return NULL;
}
}
/* Length < 128 */
else
{
i++;
tlv->length = 0x7F & buffer[0];
}
/* Get value address */
if (address+i >= data_length)
{
free (tlv);
return NULL;
}
tlv->value = address + i;
/* Round tlv object length to fit within available data */
tlv->length = MIN (tlv->length, data_length - tlv->value);
}
return tlv;
}
void
TLV_Object_Delete (TLV_Object * tlv)
{
free (tlv);
}
unsigned short
TLV_Object_GetTag (TLV_Object * tlv)
{
return tlv->tag;
}
unsigned short
TLV_Object_GetLength (TLV_Object * tlv)
{
return tlv->length;
}
bool
TLV_Object_GetValue (TLV_Object * tlv, BYTE * value, unsigned short *length)
{
(*length) = MIN ((*length), tlv->length);
if ((*length) == 0)
return TRUE;
return ((*(tlv->get_data)) (tlv->data, tlv->value, (*length), value));
}
bool
TLV_Object_CompareValue (TLV_Object * tlv, BYTE * value, unsigned short *length)
{
BYTE * buffer;
bool ret;
buffer = (BYTE *) calloc ((*length), sizeof (BYTE));
if (TLV_Object_GetValue (tlv, buffer, length))
ret = !(memcmp (value, buffer, (*length)));
else
ret = FALSE;
return ret;
}
bool
TLV_Object_Shift (TLV_Object ** tlv)
{
TLV_Object * aux;
aux = TLV_Object_New ((*tlv)->data, (*tlv)->get_data, (*tlv)->data_length , (*tlv)->value + (*tlv)->length);
TLV_Object_Delete (*tlv);
(*tlv) = aux;
return (aux != NULL);
}
bool
TLV_Object_Iterate (TLV_Object * tlv, TLV_Object ** iterator)
{
TLV_Object * next;
if ((*iterator) == NULL)
next = TLV_Object_New (tlv->data, tlv->get_data, tlv->data_length, tlv->value);
else
{
next = (*iterator);
if (next->value + next->length < tlv->value + tlv->length)
TLV_Object_Shift (&next);
else
{
TLV_Object_Delete (next);
next = NULL;
}
}
return (((*iterator) = next) != NULL);
}
TLV_Object *
TLV_Object_GetObjectByTag (TLV_Object * tlv, unsigned short tag)
{
TLV_Object * aux;
aux = TLV_Object_New (tlv->data, tlv->get_data, tlv->data_length, tlv->value);
while ((aux) && (TLV_Object_GetTag (aux) != tag))
{
if (aux->value + aux->length < tlv->value + tlv->length)
TLV_Object_Shift (&aux);
else
{
TLV_Object_Delete (aux);
aux = NULL;
}
}
return aux;
}
TLV_Object *
TLV_Object_GetObjectBySec (TLV_Object * tlv, unsigned short sec)
{
TLV_Object * aux;
unsigned short i;
aux = TLV_Object_New (tlv->data, tlv->get_data, tlv->data_length, tlv->value);
for (i=0; ((i<sec) && (aux)); i++)
{
if (aux->value + aux->length < tlv->value + tlv->length)
TLV_Object_Shift(&aux);
else
{
TLV_Object_Delete(aux);
aux = NULL;
}
}
return aux;
}
unsigned short
TLV_Object_GetRawLength (TLV_Object * tlv)
{
return (tlv->length + (tlv->value - tlv->address));
}
unsigned short
TLV_Object_GetAddress (TLV_Object * tlv)
{
return tlv->address;
}
syntax highlighted by Code2HTML, v. 0.9.1