blob: ad866bdc0800626f1c391363b210b62c9a96a50e [file] [log] [blame]
/*
* cafebabe - the class loader library in C
* Copyright (C) 2008 Vegard Nossum <vegardno@ifi.uio.no>
*
* This file is released under the GPL version 2 with the following
* clarification and special exception:
*
* Linking this library statically or dynamically with other modules is
* making a combined work based on this library. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* As a special exception, the copyright holders of this library give you
* permission to link this library with independent modules to produce an
* executable, regardless of the license terms of these independent
* modules, and to copy and distribute the resulting executable under terms
* of your choice, provided that you also meet, for each linked independent
* module, the terms and conditions of the license of that module. An
* independent module is a module which is not derived from or based on
* this library. If you modify this library, you may extend this exception
* to your version of the library, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*
* Please refer to the file LICENSE for details.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cafebabe/constant_pool.h"
#include "cafebabe/stream.h"
static int
cafebabe_constant_info_utf8_init(struct cafebabe_constant_info_utf8 *utf8,
struct cafebabe_stream *s)
{
if (cafebabe_stream_read_uint16(s, &utf8->length))
goto out;
utf8->bytes = cafebabe_stream_malloc(s, utf8->length);
if (!utf8->bytes)
goto out;
for (uint16_t i = 0; i < utf8->length; ++i) {
if (cafebabe_stream_read_uint8(s, &utf8->bytes[i]))
goto out_bytes;
}
return 0;
out_bytes:
free(utf8->bytes);
out:
return 1;
}
static void
cafebabe_constant_info_utf8_deinit(struct cafebabe_constant_info_utf8 *utf8)
{
free(utf8->bytes);
}
static int
cafebabe_constant_info_integer_init(struct cafebabe_constant_info_integer *i,
struct cafebabe_stream *s)
{
return cafebabe_stream_read_uint32(s, &i->bytes);
}
static void
cafebabe_constant_info_integer_deinit(struct cafebabe_constant_info_integer *i)
{
}
static int
cafebabe_constant_info_float_init(struct cafebabe_constant_info_float *f,
struct cafebabe_stream *s)
{
return cafebabe_stream_read_uint32(s, &f->bytes);
}
static void
cafebabe_constant_info_float_deinit(struct cafebabe_constant_info_float *f)
{
}
static int
cafebabe_constant_info_long_init(struct cafebabe_constant_info_long *l,
struct cafebabe_stream *s)
{
if (cafebabe_stream_read_uint32(s, &l->high_bytes))
return 1;
if (cafebabe_stream_read_uint32(s, &l->low_bytes))
return 1;
return 0;
}
static void
cafebabe_constant_info_long_deinit(struct cafebabe_constant_info_long *l)
{
}
static int
cafebabe_constant_info_double_init(struct cafebabe_constant_info_double *d,
struct cafebabe_stream *s)
{
if (cafebabe_stream_read_uint32(s, &d->high_bytes))
return 1;
if (cafebabe_stream_read_uint32(s, &d->low_bytes))
return 1;
return 0;
}
static void
cafebabe_constant_info_double_deinit(struct cafebabe_constant_info_double *d)
{
}
static int
cafebabe_constant_info_class_init(struct cafebabe_constant_info_class *c,
struct cafebabe_stream *s)
{
if (cafebabe_stream_read_uint16(s, &c->name_index))
return 1;
return 0;
}
static void
cafebabe_constant_info_class_deinit(struct cafebabe_constant_info_class *c)
{
}
static int
cafebabe_constant_info_string_init(struct cafebabe_constant_info_string *str,
struct cafebabe_stream *s)
{
return cafebabe_stream_read_uint16(s, &str->string_index);
}
static void
cafebabe_constant_info_string_deinit(struct cafebabe_constant_info_string *str)
{
}
static int
cafebabe_constant_info_field_ref_init(
struct cafebabe_constant_info_field_ref *fr,
struct cafebabe_stream *s)
{
if (cafebabe_stream_read_uint16(s, &fr->class_index))
return 1;
if (cafebabe_stream_read_uint16(s, &fr->name_and_type_index))
return 1;
return 0;
}
static void
cafebabe_constant_info_field_ref_deinit(
struct cafebabe_constant_info_field_ref *r)
{
}
static int
cafebabe_constant_info_method_ref_init(
struct cafebabe_constant_info_method_ref *mr,
struct cafebabe_stream *s)
{
if (cafebabe_stream_read_uint16(s, &mr->class_index))
return 1;
if (cafebabe_stream_read_uint16(s, &mr->name_and_type_index))
return 1;
return 0;
}
static void
cafebabe_constant_info_method_ref_deinit(struct
cafebabe_constant_info_method_ref *r)
{
}
static int
cafebabe_constant_info_interface_method_ref_init(
struct cafebabe_constant_info_interface_method_ref *r,
struct cafebabe_stream *s)
{
if (cafebabe_stream_read_uint16(s, &r->class_index))
return 1;
if (cafebabe_stream_read_uint16(s, &r->name_and_type_index))
return 1;
return 0;
}
static void
cafebabe_constant_info_interface_method_ref_deinit(
struct cafebabe_constant_info_interface_method_ref *r)
{
}
static int
cafebabe_constant_info_name_and_type_init(
struct cafebabe_constant_info_name_and_type *nat,
struct cafebabe_stream *s)
{
if (cafebabe_stream_read_uint16(s, &nat->name_index))
return 1;
if (cafebabe_stream_read_uint16(s, &nat->descriptor_index))
return 1;
return 0;
}
static void
cafebabe_constant_info_name_and_type_deinit(
struct cafebabe_constant_info_name_and_type *nat)
{
}
int
cafebabe_constant_pool_init(struct cafebabe_constant_pool *cp,
struct cafebabe_stream *s)
{
uint8_t tag;
if (cafebabe_stream_read_uint8(s, &tag))
goto out;
cp->tag = tag;
switch (cp->tag) {
case CAFEBABE_CONSTANT_TAG_UTF8:
if (cafebabe_constant_info_utf8_init(&cp->utf8, s))
goto out;
break;
case CAFEBABE_CONSTANT_TAG_INTEGER:
if (cafebabe_constant_info_integer_init(&cp->integer_, s))
goto out;
break;
case CAFEBABE_CONSTANT_TAG_FLOAT:
if (cafebabe_constant_info_float_init(&cp->float_, s))
goto out;
break;
case CAFEBABE_CONSTANT_TAG_LONG:
if (cafebabe_constant_info_long_init(&cp->long_, s))
goto out;
break;
case CAFEBABE_CONSTANT_TAG_DOUBLE:
if (cafebabe_constant_info_double_init(&cp->double_, s))
goto out;
break;
case CAFEBABE_CONSTANT_TAG_CLASS:
if (cafebabe_constant_info_class_init(&cp->class, s))
goto out;
break;
case CAFEBABE_CONSTANT_TAG_STRING:
if (cafebabe_constant_info_string_init(&cp->string, s))
goto out;
break;
case CAFEBABE_CONSTANT_TAG_FIELD_REF:
if (cafebabe_constant_info_field_ref_init(&cp->field_ref, s))
goto out;
break;
case CAFEBABE_CONSTANT_TAG_METHOD_REF:
if (cafebabe_constant_info_method_ref_init(&cp->method_ref, s))
goto out;
break;
case CAFEBABE_CONSTANT_TAG_INTERFACE_METHOD_REF:
if (cafebabe_constant_info_interface_method_ref_init(
&cp->interface_method_ref, s))
{
goto out;
}
break;
case CAFEBABE_CONSTANT_TAG_NAME_AND_TYPE:
if (cafebabe_constant_info_name_and_type_init(
&cp->name_and_type, s))
{
goto out;
}
break;
default:
s->cafebabe_errno = CAFEBABE_ERROR_BAD_CONSTANT_TAG;
goto out;
}
return 0;
out:
return 1;
}
void
cafebabe_constant_pool_deinit(struct cafebabe_constant_pool *cp)
{
switch (cp->tag) {
case CAFEBABE_CONSTANT_TAG_UTF8:
cafebabe_constant_info_utf8_deinit(&cp->utf8);
break;
case CAFEBABE_CONSTANT_TAG_INTEGER:
cafebabe_constant_info_integer_deinit(&cp->integer_);
break;
case CAFEBABE_CONSTANT_TAG_FLOAT:
cafebabe_constant_info_float_deinit(&cp->float_);
break;
case CAFEBABE_CONSTANT_TAG_LONG:
cafebabe_constant_info_long_deinit(&cp->long_);
break;
case CAFEBABE_CONSTANT_TAG_DOUBLE:
cafebabe_constant_info_double_deinit(&cp->double_);
break;
case CAFEBABE_CONSTANT_TAG_CLASS:
cafebabe_constant_info_class_deinit(&cp->class);
break;
case CAFEBABE_CONSTANT_TAG_STRING:
cafebabe_constant_info_string_deinit(&cp->string);
break;
case CAFEBABE_CONSTANT_TAG_FIELD_REF:
cafebabe_constant_info_field_ref_deinit(&cp->field_ref);
break;
case CAFEBABE_CONSTANT_TAG_METHOD_REF:
cafebabe_constant_info_method_ref_deinit(&cp->method_ref);
break;
case CAFEBABE_CONSTANT_TAG_INTERFACE_METHOD_REF:
cafebabe_constant_info_interface_method_ref_deinit(
&cp->interface_method_ref);
break;
case CAFEBABE_CONSTANT_TAG_NAME_AND_TYPE:
cafebabe_constant_info_name_and_type_deinit(
&cp->name_and_type);
break;
default:
break;
}
}
int
cafebabe_constant_info_utf8_compare(
const struct cafebabe_constant_info_utf8 *s1, const char *s2)
{
unsigned int s2_length = strlen(s2);
if (s1->length != s2_length) {
if (s1->length < s2_length)
return -1;
return 1;
}
return strncmp((const char *) s1->bytes, s2, s1->length);
}