NOISSUE tabs -> spaces
This commit is contained in:
@ -6,7 +6,7 @@ set(CMAKE_AUTOMOC ON)
|
||||
include(TestBigEndian)
|
||||
test_big_endian(BIGENDIAN)
|
||||
if(${BIGENDIAN})
|
||||
add_definitions(-DMULTIMC_BIG_ENDIAN)
|
||||
add_definitions(-DMULTIMC_BIG_ENDIAN)
|
||||
endif(${BIGENDIAN})
|
||||
|
||||
# Find Qt
|
||||
|
@ -6,80 +6,80 @@ namespace java
|
||||
{
|
||||
std::string annotation::toString()
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "Annotation type : " << type_index << " - " << pool[type_index].str_data << std::endl;
|
||||
ss << "Contains " << name_val_pairs.size() << " pairs:" << std::endl;
|
||||
for (unsigned i = 0; i < name_val_pairs.size(); i++)
|
||||
{
|
||||
std::pair<uint16_t, element_value *> &val = name_val_pairs[i];
|
||||
auto name_idx = val.first;
|
||||
ss << pool[name_idx].str_data << "(" << name_idx << ")"
|
||||
<< " = " << val.second->toString() << std::endl;
|
||||
}
|
||||
return ss.str();
|
||||
std::ostringstream ss;
|
||||
ss << "Annotation type : " << type_index << " - " << pool[type_index].str_data << std::endl;
|
||||
ss << "Contains " << name_val_pairs.size() << " pairs:" << std::endl;
|
||||
for (unsigned i = 0; i < name_val_pairs.size(); i++)
|
||||
{
|
||||
std::pair<uint16_t, element_value *> &val = name_val_pairs[i];
|
||||
auto name_idx = val.first;
|
||||
ss << pool[name_idx].str_data << "(" << name_idx << ")"
|
||||
<< " = " << val.second->toString() << std::endl;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
annotation *annotation::read(util::membuffer &input, constant_pool &pool)
|
||||
{
|
||||
uint16_t type_index = 0;
|
||||
input.read_be(type_index);
|
||||
annotation *ann = new annotation(type_index, pool);
|
||||
uint16_t type_index = 0;
|
||||
input.read_be(type_index);
|
||||
annotation *ann = new annotation(type_index, pool);
|
||||
|
||||
uint16_t num_pairs = 0;
|
||||
input.read_be(num_pairs);
|
||||
while (num_pairs)
|
||||
{
|
||||
uint16_t name_idx = 0;
|
||||
// read name index
|
||||
input.read_be(name_idx);
|
||||
auto elem = element_value::readElementValue(input, pool);
|
||||
// read value
|
||||
ann->add_pair(name_idx, elem);
|
||||
num_pairs--;
|
||||
}
|
||||
return ann;
|
||||
uint16_t num_pairs = 0;
|
||||
input.read_be(num_pairs);
|
||||
while (num_pairs)
|
||||
{
|
||||
uint16_t name_idx = 0;
|
||||
// read name index
|
||||
input.read_be(name_idx);
|
||||
auto elem = element_value::readElementValue(input, pool);
|
||||
// read value
|
||||
ann->add_pair(name_idx, elem);
|
||||
num_pairs--;
|
||||
}
|
||||
return ann;
|
||||
}
|
||||
|
||||
element_value *element_value::readElementValue(util::membuffer &input,
|
||||
java::constant_pool &pool)
|
||||
java::constant_pool &pool)
|
||||
{
|
||||
element_value_type type = INVALID;
|
||||
input.read(type);
|
||||
uint16_t index = 0;
|
||||
uint16_t index2 = 0;
|
||||
std::vector<element_value *> vals;
|
||||
switch (type)
|
||||
{
|
||||
case PRIMITIVE_BYTE:
|
||||
case PRIMITIVE_CHAR:
|
||||
case PRIMITIVE_DOUBLE:
|
||||
case PRIMITIVE_FLOAT:
|
||||
case PRIMITIVE_INT:
|
||||
case PRIMITIVE_LONG:
|
||||
case PRIMITIVE_SHORT:
|
||||
case PRIMITIVE_BOOLEAN:
|
||||
case STRING:
|
||||
input.read_be(index);
|
||||
return new element_value_simple(type, index, pool);
|
||||
case ENUM_CONSTANT:
|
||||
input.read_be(index);
|
||||
input.read_be(index2);
|
||||
return new element_value_enum(type, index, index2, pool);
|
||||
case CLASS: // Class
|
||||
input.read_be(index);
|
||||
return new element_value_class(type, index, pool);
|
||||
case ANNOTATION: // Annotation
|
||||
// FIXME: runtime visibility info needs to be passed from parent
|
||||
return new element_value_annotation(ANNOTATION, annotation::read(input, pool), pool);
|
||||
case ARRAY: // Array
|
||||
input.read_be(index);
|
||||
for (int i = 0; i < index; i++)
|
||||
{
|
||||
vals.push_back(element_value::readElementValue(input, pool));
|
||||
}
|
||||
return new element_value_array(ARRAY, vals, pool);
|
||||
default:
|
||||
throw new java::classfile_exception();
|
||||
}
|
||||
element_value_type type = INVALID;
|
||||
input.read(type);
|
||||
uint16_t index = 0;
|
||||
uint16_t index2 = 0;
|
||||
std::vector<element_value *> vals;
|
||||
switch (type)
|
||||
{
|
||||
case PRIMITIVE_BYTE:
|
||||
case PRIMITIVE_CHAR:
|
||||
case PRIMITIVE_DOUBLE:
|
||||
case PRIMITIVE_FLOAT:
|
||||
case PRIMITIVE_INT:
|
||||
case PRIMITIVE_LONG:
|
||||
case PRIMITIVE_SHORT:
|
||||
case PRIMITIVE_BOOLEAN:
|
||||
case STRING:
|
||||
input.read_be(index);
|
||||
return new element_value_simple(type, index, pool);
|
||||
case ENUM_CONSTANT:
|
||||
input.read_be(index);
|
||||
input.read_be(index2);
|
||||
return new element_value_enum(type, index, index2, pool);
|
||||
case CLASS: // Class
|
||||
input.read_be(index);
|
||||
return new element_value_class(type, index, pool);
|
||||
case ANNOTATION: // Annotation
|
||||
// FIXME: runtime visibility info needs to be passed from parent
|
||||
return new element_value_annotation(ANNOTATION, annotation::read(input, pool), pool);
|
||||
case ARRAY: // Array
|
||||
input.read_be(index);
|
||||
for (int i = 0; i < index; i++)
|
||||
{
|
||||
vals.push_back(element_value::readElementValue(input, pool));
|
||||
}
|
||||
return new element_value_array(ARRAY, vals, pool);
|
||||
default:
|
||||
throw new java::classfile_exception();
|
||||
}
|
||||
}
|
||||
}
|
@ -7,21 +7,21 @@ namespace java
|
||||
{
|
||||
enum element_value_type : uint8_t
|
||||
{
|
||||
INVALID = 0,
|
||||
STRING = 's',
|
||||
ENUM_CONSTANT = 'e',
|
||||
CLASS = 'c',
|
||||
ANNOTATION = '@',
|
||||
ARRAY = '[', // one array dimension
|
||||
PRIMITIVE_INT = 'I', // integer
|
||||
PRIMITIVE_BYTE = 'B', // signed byte
|
||||
PRIMITIVE_CHAR = 'C', // Unicode character code point in the Basic Multilingual Plane,
|
||||
// encoded with UTF-16
|
||||
PRIMITIVE_DOUBLE = 'D', // double-precision floating-point value
|
||||
PRIMITIVE_FLOAT = 'F', // single-precision floating-point value
|
||||
PRIMITIVE_LONG = 'J', // long integer
|
||||
PRIMITIVE_SHORT = 'S', // signed short
|
||||
PRIMITIVE_BOOLEAN = 'Z' // true or false
|
||||
INVALID = 0,
|
||||
STRING = 's',
|
||||
ENUM_CONSTANT = 'e',
|
||||
CLASS = 'c',
|
||||
ANNOTATION = '@',
|
||||
ARRAY = '[', // one array dimension
|
||||
PRIMITIVE_INT = 'I', // integer
|
||||
PRIMITIVE_BYTE = 'B', // signed byte
|
||||
PRIMITIVE_CHAR = 'C', // Unicode character code point in the Basic Multilingual Plane,
|
||||
// encoded with UTF-16
|
||||
PRIMITIVE_DOUBLE = 'D', // double-precision floating-point value
|
||||
PRIMITIVE_FLOAT = 'F', // single-precision floating-point value
|
||||
PRIMITIVE_LONG = 'J', // long integer
|
||||
PRIMITIVE_SHORT = 'S', // signed short
|
||||
PRIMITIVE_BOOLEAN = 'Z' // true or false
|
||||
};
|
||||
/**
|
||||
* The element_value structure is a discriminated union representing the value of an
|
||||
@ -37,21 +37,21 @@ enum element_value_type : uint8_t
|
||||
class element_value
|
||||
{
|
||||
protected:
|
||||
element_value_type type;
|
||||
constant_pool &pool;
|
||||
element_value_type type;
|
||||
constant_pool &pool;
|
||||
|
||||
public:
|
||||
element_value(element_value_type type, constant_pool &pool) : type(type), pool(pool) {};
|
||||
virtual ~element_value() {}
|
||||
element_value(element_value_type type, constant_pool &pool) : type(type), pool(pool) {};
|
||||
virtual ~element_value() {}
|
||||
|
||||
element_value_type getElementValueType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
element_value_type getElementValueType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
virtual std::string toString() = 0;
|
||||
virtual std::string toString() = 0;
|
||||
|
||||
static element_value *readElementValue(util::membuffer &input, constant_pool &pool);
|
||||
static element_value *readElementValue(util::membuffer &input, constant_pool &pool);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -62,58 +62,58 @@ public:
|
||||
class annotation
|
||||
{
|
||||
public:
|
||||
typedef std::vector<std::pair<uint16_t, element_value *>> value_list;
|
||||
typedef std::vector<std::pair<uint16_t, element_value *>> value_list;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The value of the type_index item must be a valid index into the constant_pool table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing a field descriptor representing the annotation type corresponding
|
||||
* to the annotation represented by this annotation structure.
|
||||
*/
|
||||
uint16_t type_index;
|
||||
/**
|
||||
* map between element_name_index and value.
|
||||
*
|
||||
* The value of the element_name_index item must be a valid index into the constant_pool
|
||||
*table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
*representing
|
||||
* a valid field descriptor (§4.3.2) that denotes the name of the annotation type element
|
||||
*represented
|
||||
* by this element_value_pairs entry.
|
||||
*/
|
||||
value_list name_val_pairs;
|
||||
/**
|
||||
* Reference to the parent constant pool
|
||||
*/
|
||||
constant_pool &pool;
|
||||
/**
|
||||
* The value of the type_index item must be a valid index into the constant_pool table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing a field descriptor representing the annotation type corresponding
|
||||
* to the annotation represented by this annotation structure.
|
||||
*/
|
||||
uint16_t type_index;
|
||||
/**
|
||||
* map between element_name_index and value.
|
||||
*
|
||||
* The value of the element_name_index item must be a valid index into the constant_pool
|
||||
*table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
*representing
|
||||
* a valid field descriptor (§4.3.2) that denotes the name of the annotation type element
|
||||
*represented
|
||||
* by this element_value_pairs entry.
|
||||
*/
|
||||
value_list name_val_pairs;
|
||||
/**
|
||||
* Reference to the parent constant pool
|
||||
*/
|
||||
constant_pool &pool;
|
||||
|
||||
public:
|
||||
annotation(uint16_t type_index, constant_pool &pool)
|
||||
: type_index(type_index), pool(pool) {};
|
||||
~annotation()
|
||||
{
|
||||
for (unsigned i = 0; i < name_val_pairs.size(); i++)
|
||||
{
|
||||
delete name_val_pairs[i].second;
|
||||
}
|
||||
}
|
||||
void add_pair(uint16_t key, element_value *value)
|
||||
{
|
||||
name_val_pairs.push_back(std::make_pair(key, value));
|
||||
}
|
||||
;
|
||||
value_list::const_iterator begin()
|
||||
{
|
||||
return name_val_pairs.cbegin();
|
||||
}
|
||||
value_list::const_iterator end()
|
||||
{
|
||||
return name_val_pairs.cend();
|
||||
}
|
||||
std::string toString();
|
||||
static annotation *read(util::membuffer &input, constant_pool &pool);
|
||||
annotation(uint16_t type_index, constant_pool &pool)
|
||||
: type_index(type_index), pool(pool) {};
|
||||
~annotation()
|
||||
{
|
||||
for (unsigned i = 0; i < name_val_pairs.size(); i++)
|
||||
{
|
||||
delete name_val_pairs[i].second;
|
||||
}
|
||||
}
|
||||
void add_pair(uint16_t key, element_value *value)
|
||||
{
|
||||
name_val_pairs.push_back(std::make_pair(key, value));
|
||||
}
|
||||
;
|
||||
value_list::const_iterator begin()
|
||||
{
|
||||
return name_val_pairs.cbegin();
|
||||
}
|
||||
value_list::const_iterator end()
|
||||
{
|
||||
return name_val_pairs.cend();
|
||||
}
|
||||
std::string toString();
|
||||
static annotation *read(util::membuffer &input, constant_pool &pool);
|
||||
};
|
||||
typedef std::vector<annotation *> annotation_table;
|
||||
|
||||
@ -121,158 +121,158 @@ typedef std::vector<annotation *> annotation_table;
|
||||
class element_value_simple : public element_value
|
||||
{
|
||||
protected:
|
||||
/// index of the constant in the constant pool
|
||||
uint16_t index;
|
||||
/// index of the constant in the constant pool
|
||||
uint16_t index;
|
||||
|
||||
public:
|
||||
element_value_simple(element_value_type type, uint16_t index, constant_pool &pool)
|
||||
: element_value(type, pool), index(index) {
|
||||
// TODO: verify consistency
|
||||
};
|
||||
uint16_t getIndex()
|
||||
{
|
||||
return index;
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return pool[index].toString();
|
||||
}
|
||||
;
|
||||
element_value_simple(element_value_type type, uint16_t index, constant_pool &pool)
|
||||
: element_value(type, pool), index(index) {
|
||||
// TODO: verify consistency
|
||||
};
|
||||
uint16_t getIndex()
|
||||
{
|
||||
return index;
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return pool[index].toString();
|
||||
}
|
||||
;
|
||||
};
|
||||
/// The enum_const_value item is used if the tag item is 'e'.
|
||||
class element_value_enum : public element_value
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* The value of the type_name_index item must be a valid index into the constant_pool table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing a valid field descriptor (§4.3.2) that denotes the internal form of the
|
||||
* binary
|
||||
* name (§4.2.1) of the type of the enum constant represented by this element_value
|
||||
* structure.
|
||||
*/
|
||||
uint16_t typeIndex;
|
||||
/**
|
||||
* The value of the const_name_index item must be a valid index into the constant_pool
|
||||
* table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing the simple name of the enum constant represented by this element_value
|
||||
* structure.
|
||||
*/
|
||||
uint16_t valueIndex;
|
||||
/**
|
||||
* The value of the type_name_index item must be a valid index into the constant_pool table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing a valid field descriptor (§4.3.2) that denotes the internal form of the
|
||||
* binary
|
||||
* name (§4.2.1) of the type of the enum constant represented by this element_value
|
||||
* structure.
|
||||
*/
|
||||
uint16_t typeIndex;
|
||||
/**
|
||||
* The value of the const_name_index item must be a valid index into the constant_pool
|
||||
* table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing the simple name of the enum constant represented by this element_value
|
||||
* structure.
|
||||
*/
|
||||
uint16_t valueIndex;
|
||||
|
||||
public:
|
||||
element_value_enum(element_value_type type, uint16_t typeIndex, uint16_t valueIndex,
|
||||
constant_pool &pool)
|
||||
: element_value(type, pool), typeIndex(typeIndex), valueIndex(valueIndex)
|
||||
{
|
||||
// TODO: verify consistency
|
||||
}
|
||||
uint16_t getValueIndex()
|
||||
{
|
||||
return valueIndex;
|
||||
}
|
||||
uint16_t getTypeIndex()
|
||||
{
|
||||
return typeIndex;
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "enum value";
|
||||
}
|
||||
;
|
||||
element_value_enum(element_value_type type, uint16_t typeIndex, uint16_t valueIndex,
|
||||
constant_pool &pool)
|
||||
: element_value(type, pool), typeIndex(typeIndex), valueIndex(valueIndex)
|
||||
{
|
||||
// TODO: verify consistency
|
||||
}
|
||||
uint16_t getValueIndex()
|
||||
{
|
||||
return valueIndex;
|
||||
}
|
||||
uint16_t getTypeIndex()
|
||||
{
|
||||
return typeIndex;
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "enum value";
|
||||
}
|
||||
;
|
||||
};
|
||||
|
||||
class element_value_class : public element_value
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* The class_info_index item must be a valid index into the constant_pool table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing the return descriptor (§4.3.3) of the type that is reified by the class
|
||||
* represented by this element_value structure.
|
||||
*
|
||||
* For example, 'V' for Void.class, 'Ljava/lang/Object;' for Object, etc.
|
||||
*
|
||||
* Or in plain english, you can store type information in annotations. Yay.
|
||||
*/
|
||||
uint16_t classIndex;
|
||||
/**
|
||||
* The class_info_index item must be a valid index into the constant_pool table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing the return descriptor (§4.3.3) of the type that is reified by the class
|
||||
* represented by this element_value structure.
|
||||
*
|
||||
* For example, 'V' for Void.class, 'Ljava/lang/Object;' for Object, etc.
|
||||
*
|
||||
* Or in plain english, you can store type information in annotations. Yay.
|
||||
*/
|
||||
uint16_t classIndex;
|
||||
|
||||
public:
|
||||
element_value_class(element_value_type type, uint16_t classIndex, constant_pool &pool)
|
||||
: element_value(type, pool), classIndex(classIndex)
|
||||
{
|
||||
// TODO: verify consistency
|
||||
}
|
||||
uint16_t getIndex()
|
||||
{
|
||||
return classIndex;
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "class";
|
||||
}
|
||||
;
|
||||
element_value_class(element_value_type type, uint16_t classIndex, constant_pool &pool)
|
||||
: element_value(type, pool), classIndex(classIndex)
|
||||
{
|
||||
// TODO: verify consistency
|
||||
}
|
||||
uint16_t getIndex()
|
||||
{
|
||||
return classIndex;
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "class";
|
||||
}
|
||||
;
|
||||
};
|
||||
|
||||
/// nested annotations... yay
|
||||
class element_value_annotation : public element_value
|
||||
{
|
||||
private:
|
||||
annotation *nestedAnnotation;
|
||||
annotation *nestedAnnotation;
|
||||
|
||||
public:
|
||||
element_value_annotation(element_value_type type, annotation *nestedAnnotation,
|
||||
constant_pool &pool)
|
||||
: element_value(type, pool), nestedAnnotation(nestedAnnotation) {};
|
||||
~element_value_annotation()
|
||||
{
|
||||
if (nestedAnnotation)
|
||||
{
|
||||
delete nestedAnnotation;
|
||||
nestedAnnotation = nullptr;
|
||||
}
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "nested annotation";
|
||||
}
|
||||
;
|
||||
element_value_annotation(element_value_type type, annotation *nestedAnnotation,
|
||||
constant_pool &pool)
|
||||
: element_value(type, pool), nestedAnnotation(nestedAnnotation) {};
|
||||
~element_value_annotation()
|
||||
{
|
||||
if (nestedAnnotation)
|
||||
{
|
||||
delete nestedAnnotation;
|
||||
nestedAnnotation = nullptr;
|
||||
}
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "nested annotation";
|
||||
}
|
||||
;
|
||||
};
|
||||
|
||||
/// and arrays!
|
||||
class element_value_array : public element_value
|
||||
{
|
||||
public:
|
||||
typedef std::vector<element_value *> elem_vec;
|
||||
typedef std::vector<element_value *> elem_vec;
|
||||
|
||||
protected:
|
||||
elem_vec values;
|
||||
elem_vec values;
|
||||
|
||||
public:
|
||||
element_value_array(element_value_type type, std::vector<element_value *> &values,
|
||||
constant_pool &pool)
|
||||
: element_value(type, pool), values(values) {};
|
||||
~element_value_array()
|
||||
{
|
||||
for (unsigned i = 0; i < values.size(); i++)
|
||||
{
|
||||
delete values[i];
|
||||
}
|
||||
}
|
||||
;
|
||||
elem_vec::const_iterator begin()
|
||||
{
|
||||
return values.cbegin();
|
||||
}
|
||||
elem_vec::const_iterator end()
|
||||
{
|
||||
return values.cend();
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "array";
|
||||
}
|
||||
;
|
||||
element_value_array(element_value_type type, std::vector<element_value *> &values,
|
||||
constant_pool &pool)
|
||||
: element_value(type, pool), values(values) {};
|
||||
~element_value_array()
|
||||
{
|
||||
for (unsigned i = 0; i < values.size(); i++)
|
||||
{
|
||||
delete values[i];
|
||||
}
|
||||
}
|
||||
;
|
||||
elem_vec::const_iterator begin()
|
||||
{
|
||||
return values.cbegin();
|
||||
}
|
||||
elem_vec::const_iterator end()
|
||||
{
|
||||
return values.cend();
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "array";
|
||||
}
|
||||
;
|
||||
};
|
||||
}
|
@ -11,146 +11,146 @@ namespace java
|
||||
class classfile : public util::membuffer
|
||||
{
|
||||
public:
|
||||
classfile(char *data, std::size_t size) : membuffer(data, size)
|
||||
{
|
||||
valid = false;
|
||||
is_synthetic = false;
|
||||
read_be(magic);
|
||||
if (magic != 0xCAFEBABE)
|
||||
throw new classfile_exception();
|
||||
read_be(minor_version);
|
||||
read_be(major_version);
|
||||
constants.load(*this);
|
||||
read_be(access_flags);
|
||||
read_be(this_class);
|
||||
read_be(super_class);
|
||||
classfile(char *data, std::size_t size) : membuffer(data, size)
|
||||
{
|
||||
valid = false;
|
||||
is_synthetic = false;
|
||||
read_be(magic);
|
||||
if (magic != 0xCAFEBABE)
|
||||
throw new classfile_exception();
|
||||
read_be(minor_version);
|
||||
read_be(major_version);
|
||||
constants.load(*this);
|
||||
read_be(access_flags);
|
||||
read_be(this_class);
|
||||
read_be(super_class);
|
||||
|
||||
// Interfaces
|
||||
uint16_t iface_count = 0;
|
||||
read_be(iface_count);
|
||||
while (iface_count)
|
||||
{
|
||||
uint16_t iface;
|
||||
read_be(iface);
|
||||
interfaces.push_back(iface);
|
||||
iface_count--;
|
||||
}
|
||||
// Interfaces
|
||||
uint16_t iface_count = 0;
|
||||
read_be(iface_count);
|
||||
while (iface_count)
|
||||
{
|
||||
uint16_t iface;
|
||||
read_be(iface);
|
||||
interfaces.push_back(iface);
|
||||
iface_count--;
|
||||
}
|
||||
|
||||
// Fields
|
||||
// read fields (and attributes from inside fields) (and possible inner classes. yay for
|
||||
// recursion!)
|
||||
// for now though, we will ignore all attributes
|
||||
/*
|
||||
* field_info
|
||||
* {
|
||||
* u2 access_flags;
|
||||
* u2 name_index;
|
||||
* u2 descriptor_index;
|
||||
* u2 attributes_count;
|
||||
* attribute_info attributes[attributes_count];
|
||||
* }
|
||||
*/
|
||||
uint16_t field_count = 0;
|
||||
read_be(field_count);
|
||||
while (field_count)
|
||||
{
|
||||
// skip field stuff
|
||||
skip(6);
|
||||
// and skip field attributes
|
||||
uint16_t attr_count = 0;
|
||||
read_be(attr_count);
|
||||
while (attr_count)
|
||||
{
|
||||
skip(2);
|
||||
uint32_t attr_length = 0;
|
||||
read_be(attr_length);
|
||||
skip(attr_length);
|
||||
attr_count--;
|
||||
}
|
||||
field_count--;
|
||||
}
|
||||
// Fields
|
||||
// read fields (and attributes from inside fields) (and possible inner classes. yay for
|
||||
// recursion!)
|
||||
// for now though, we will ignore all attributes
|
||||
/*
|
||||
* field_info
|
||||
* {
|
||||
* u2 access_flags;
|
||||
* u2 name_index;
|
||||
* u2 descriptor_index;
|
||||
* u2 attributes_count;
|
||||
* attribute_info attributes[attributes_count];
|
||||
* }
|
||||
*/
|
||||
uint16_t field_count = 0;
|
||||
read_be(field_count);
|
||||
while (field_count)
|
||||
{
|
||||
// skip field stuff
|
||||
skip(6);
|
||||
// and skip field attributes
|
||||
uint16_t attr_count = 0;
|
||||
read_be(attr_count);
|
||||
while (attr_count)
|
||||
{
|
||||
skip(2);
|
||||
uint32_t attr_length = 0;
|
||||
read_be(attr_length);
|
||||
skip(attr_length);
|
||||
attr_count--;
|
||||
}
|
||||
field_count--;
|
||||
}
|
||||
|
||||
// class methods
|
||||
/*
|
||||
* method_info
|
||||
* {
|
||||
* u2 access_flags;
|
||||
* u2 name_index;
|
||||
* u2 descriptor_index;
|
||||
* u2 attributes_count;
|
||||
* attribute_info attributes[attributes_count];
|
||||
* }
|
||||
*/
|
||||
uint16_t method_count = 0;
|
||||
read_be(method_count);
|
||||
while (method_count)
|
||||
{
|
||||
skip(6);
|
||||
// and skip method attributes
|
||||
uint16_t attr_count = 0;
|
||||
read_be(attr_count);
|
||||
while (attr_count)
|
||||
{
|
||||
skip(2);
|
||||
uint32_t attr_length = 0;
|
||||
read_be(attr_length);
|
||||
skip(attr_length);
|
||||
attr_count--;
|
||||
}
|
||||
method_count--;
|
||||
}
|
||||
// class methods
|
||||
/*
|
||||
* method_info
|
||||
* {
|
||||
* u2 access_flags;
|
||||
* u2 name_index;
|
||||
* u2 descriptor_index;
|
||||
* u2 attributes_count;
|
||||
* attribute_info attributes[attributes_count];
|
||||
* }
|
||||
*/
|
||||
uint16_t method_count = 0;
|
||||
read_be(method_count);
|
||||
while (method_count)
|
||||
{
|
||||
skip(6);
|
||||
// and skip method attributes
|
||||
uint16_t attr_count = 0;
|
||||
read_be(attr_count);
|
||||
while (attr_count)
|
||||
{
|
||||
skip(2);
|
||||
uint32_t attr_length = 0;
|
||||
read_be(attr_length);
|
||||
skip(attr_length);
|
||||
attr_count--;
|
||||
}
|
||||
method_count--;
|
||||
}
|
||||
|
||||
// class attributes
|
||||
// there are many kinds of attributes. this is just the generic wrapper structure.
|
||||
// type is decided by attribute name. extensions to the standard are *possible*
|
||||
// class annotations are one kind of a attribute (one per class)
|
||||
/*
|
||||
* attribute_info
|
||||
* {
|
||||
* u2 attribute_name_index;
|
||||
* u4 attribute_length;
|
||||
* u1 info[attribute_length];
|
||||
* }
|
||||
*/
|
||||
uint16_t class_attr_count = 0;
|
||||
read_be(class_attr_count);
|
||||
while (class_attr_count)
|
||||
{
|
||||
uint16_t name_idx = 0;
|
||||
read_be(name_idx);
|
||||
uint32_t attr_length = 0;
|
||||
read_be(attr_length);
|
||||
// class attributes
|
||||
// there are many kinds of attributes. this is just the generic wrapper structure.
|
||||
// type is decided by attribute name. extensions to the standard are *possible*
|
||||
// class annotations are one kind of a attribute (one per class)
|
||||
/*
|
||||
* attribute_info
|
||||
* {
|
||||
* u2 attribute_name_index;
|
||||
* u4 attribute_length;
|
||||
* u1 info[attribute_length];
|
||||
* }
|
||||
*/
|
||||
uint16_t class_attr_count = 0;
|
||||
read_be(class_attr_count);
|
||||
while (class_attr_count)
|
||||
{
|
||||
uint16_t name_idx = 0;
|
||||
read_be(name_idx);
|
||||
uint32_t attr_length = 0;
|
||||
read_be(attr_length);
|
||||
|
||||
auto name = constants[name_idx];
|
||||
if (name.str_data == "RuntimeVisibleAnnotations")
|
||||
{
|
||||
uint16_t num_annotations = 0;
|
||||
read_be(num_annotations);
|
||||
while (num_annotations)
|
||||
{
|
||||
visible_class_annotations.push_back(annotation::read(*this, constants));
|
||||
num_annotations--;
|
||||
}
|
||||
}
|
||||
else
|
||||
skip(attr_length);
|
||||
class_attr_count--;
|
||||
}
|
||||
valid = true;
|
||||
}
|
||||
;
|
||||
bool valid;
|
||||
bool is_synthetic;
|
||||
uint32_t magic;
|
||||
uint16_t minor_version;
|
||||
uint16_t major_version;
|
||||
constant_pool constants;
|
||||
uint16_t access_flags;
|
||||
uint16_t this_class;
|
||||
uint16_t super_class;
|
||||
// interfaces this class implements ? must be. investigate.
|
||||
std::vector<uint16_t> interfaces;
|
||||
// FIXME: doesn't free up memory on delete
|
||||
java::annotation_table visible_class_annotations;
|
||||
auto name = constants[name_idx];
|
||||
if (name.str_data == "RuntimeVisibleAnnotations")
|
||||
{
|
||||
uint16_t num_annotations = 0;
|
||||
read_be(num_annotations);
|
||||
while (num_annotations)
|
||||
{
|
||||
visible_class_annotations.push_back(annotation::read(*this, constants));
|
||||
num_annotations--;
|
||||
}
|
||||
}
|
||||
else
|
||||
skip(attr_length);
|
||||
class_attr_count--;
|
||||
}
|
||||
valid = true;
|
||||
}
|
||||
;
|
||||
bool valid;
|
||||
bool is_synthetic;
|
||||
uint32_t magic;
|
||||
uint16_t minor_version;
|
||||
uint16_t major_version;
|
||||
constant_pool constants;
|
||||
uint16_t access_flags;
|
||||
uint16_t this_class;
|
||||
uint16_t super_class;
|
||||
// interfaces this class implements ? must be. investigate.
|
||||
std::vector<uint16_t> interfaces;
|
||||
// FIXME: doesn't free up memory on delete
|
||||
java::annotation_table visible_class_annotations;
|
||||
};
|
||||
}
|
@ -26,58 +26,58 @@ namespace classparser
|
||||
|
||||
QString GetMinecraftJarVersion(QString jarName)
|
||||
{
|
||||
QString version;
|
||||
QString version;
|
||||
|
||||
// check if minecraft.jar exists
|
||||
QFile jar(jarName);
|
||||
if (!jar.exists())
|
||||
return version;
|
||||
// check if minecraft.jar exists
|
||||
QFile jar(jarName);
|
||||
if (!jar.exists())
|
||||
return version;
|
||||
|
||||
// open minecraft.jar
|
||||
QuaZip zip(&jar);
|
||||
if (!zip.open(QuaZip::mdUnzip))
|
||||
return version;
|
||||
// open minecraft.jar
|
||||
QuaZip zip(&jar);
|
||||
if (!zip.open(QuaZip::mdUnzip))
|
||||
return version;
|
||||
|
||||
// open Minecraft.class
|
||||
zip.setCurrentFile("net/minecraft/client/Minecraft.class", QuaZip::csSensitive);
|
||||
QuaZipFile Minecraft(&zip);
|
||||
if (!Minecraft.open(QuaZipFile::ReadOnly))
|
||||
return version;
|
||||
// open Minecraft.class
|
||||
zip.setCurrentFile("net/minecraft/client/Minecraft.class", QuaZip::csSensitive);
|
||||
QuaZipFile Minecraft(&zip);
|
||||
if (!Minecraft.open(QuaZipFile::ReadOnly))
|
||||
return version;
|
||||
|
||||
// read Minecraft.class
|
||||
qint64 size = Minecraft.size();
|
||||
char *classfile = new char[size];
|
||||
Minecraft.read(classfile, size);
|
||||
// read Minecraft.class
|
||||
qint64 size = Minecraft.size();
|
||||
char *classfile = new char[size];
|
||||
Minecraft.read(classfile, size);
|
||||
|
||||
// parse Minecraft.class
|
||||
try
|
||||
{
|
||||
char *temp = classfile;
|
||||
java::classfile MinecraftClass(temp, size);
|
||||
java::constant_pool constants = MinecraftClass.constants;
|
||||
for (java::constant_pool::container_type::const_iterator iter = constants.begin();
|
||||
iter != constants.end(); iter++)
|
||||
{
|
||||
const java::constant &constant = *iter;
|
||||
if (constant.type != java::constant_type_t::j_string_data)
|
||||
continue;
|
||||
const std::string &str = constant.str_data;
|
||||
qDebug() << QString::fromStdString(str);
|
||||
if (str.compare(0, 20, "Minecraft Minecraft ") == 0)
|
||||
{
|
||||
version = str.substr(20).data();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const java::classfile_exception &) { }
|
||||
// parse Minecraft.class
|
||||
try
|
||||
{
|
||||
char *temp = classfile;
|
||||
java::classfile MinecraftClass(temp, size);
|
||||
java::constant_pool constants = MinecraftClass.constants;
|
||||
for (java::constant_pool::container_type::const_iterator iter = constants.begin();
|
||||
iter != constants.end(); iter++)
|
||||
{
|
||||
const java::constant &constant = *iter;
|
||||
if (constant.type != java::constant_type_t::j_string_data)
|
||||
continue;
|
||||
const std::string &str = constant.str_data;
|
||||
qDebug() << QString::fromStdString(str);
|
||||
if (str.compare(0, 20, "Minecraft Minecraft ") == 0)
|
||||
{
|
||||
version = str.substr(20).data();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const java::classfile_exception &) { }
|
||||
|
||||
// clean up
|
||||
delete[] classfile;
|
||||
Minecraft.close();
|
||||
zip.close();
|
||||
jar.close();
|
||||
// clean up
|
||||
delete[] classfile;
|
||||
Minecraft.close();
|
||||
zip.close();
|
||||
jar.close();
|
||||
|
||||
return version;
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
@ -6,159 +6,159 @@ namespace java
|
||||
{
|
||||
enum class constant_type_t : uint8_t
|
||||
{
|
||||
j_hole = 0, // HACK: this is a hole in the array, because java is crazy
|
||||
j_string_data = 1,
|
||||
j_int = 3,
|
||||
j_float = 4,
|
||||
j_long = 5,
|
||||
j_double = 6,
|
||||
j_class = 7,
|
||||
j_string = 8,
|
||||
j_fieldref = 9,
|
||||
j_methodref = 10,
|
||||
j_interface_methodref = 11,
|
||||
j_nameandtype = 12
|
||||
// FIXME: missing some constant types, see https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4
|
||||
j_hole = 0, // HACK: this is a hole in the array, because java is crazy
|
||||
j_string_data = 1,
|
||||
j_int = 3,
|
||||
j_float = 4,
|
||||
j_long = 5,
|
||||
j_double = 6,
|
||||
j_class = 7,
|
||||
j_string = 8,
|
||||
j_fieldref = 9,
|
||||
j_methodref = 10,
|
||||
j_interface_methodref = 11,
|
||||
j_nameandtype = 12
|
||||
// FIXME: missing some constant types, see https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4
|
||||
};
|
||||
|
||||
struct ref_type_t
|
||||
{
|
||||
/**
|
||||
* Class reference:
|
||||
* an index within the constant pool to a UTF-8 string containing
|
||||
* the fully qualified class name (in internal format)
|
||||
* Used for j_class, j_fieldref, j_methodref and j_interface_methodref
|
||||
*/
|
||||
uint16_t class_idx;
|
||||
// used for j_fieldref, j_methodref and j_interface_methodref
|
||||
uint16_t name_and_type_idx;
|
||||
/**
|
||||
* Class reference:
|
||||
* an index within the constant pool to a UTF-8 string containing
|
||||
* the fully qualified class name (in internal format)
|
||||
* Used for j_class, j_fieldref, j_methodref and j_interface_methodref
|
||||
*/
|
||||
uint16_t class_idx;
|
||||
// used for j_fieldref, j_methodref and j_interface_methodref
|
||||
uint16_t name_and_type_idx;
|
||||
};
|
||||
|
||||
struct name_and_type_t
|
||||
{
|
||||
uint16_t name_index;
|
||||
uint16_t descriptor_index;
|
||||
uint16_t name_index;
|
||||
uint16_t descriptor_index;
|
||||
};
|
||||
|
||||
class constant
|
||||
{
|
||||
public:
|
||||
constant_type_t type = constant_type_t::j_hole;
|
||||
constant_type_t type = constant_type_t::j_hole;
|
||||
|
||||
constant(util::membuffer &buf)
|
||||
{
|
||||
buf.read(type);
|
||||
constant(util::membuffer &buf)
|
||||
{
|
||||
buf.read(type);
|
||||
|
||||
// load data depending on type
|
||||
switch (type)
|
||||
{
|
||||
case constant_type_t::j_float:
|
||||
buf.read_be(data.int_data);
|
||||
break;
|
||||
case constant_type_t::j_int:
|
||||
buf.read_be(data.int_data); // same as float data really
|
||||
break;
|
||||
case constant_type_t::j_double:
|
||||
buf.read_be(data.long_data);
|
||||
break;
|
||||
case constant_type_t::j_long:
|
||||
buf.read_be(data.long_data); // same as double
|
||||
break;
|
||||
case constant_type_t::j_class:
|
||||
buf.read_be(data.ref_type.class_idx);
|
||||
break;
|
||||
case constant_type_t::j_fieldref:
|
||||
case constant_type_t::j_methodref:
|
||||
case constant_type_t::j_interface_methodref:
|
||||
buf.read_be(data.ref_type.class_idx);
|
||||
buf.read_be(data.ref_type.name_and_type_idx);
|
||||
break;
|
||||
case constant_type_t::j_string:
|
||||
buf.read_be(data.index);
|
||||
break;
|
||||
case constant_type_t::j_string_data:
|
||||
// HACK HACK: for now, we call these UTF-8 and do no further processing.
|
||||
// Later, we should do some decoding. It's really modified UTF-8
|
||||
// * U+0000 is represented as 0xC0,0x80 invalid character
|
||||
// * any single zero byte ends the string
|
||||
// * characters above U+10000 are encoded like in CESU-8
|
||||
buf.read_jstr(str_data);
|
||||
break;
|
||||
case constant_type_t::j_nameandtype:
|
||||
buf.read_be(data.name_and_type.name_index);
|
||||
buf.read_be(data.name_and_type.descriptor_index);
|
||||
break;
|
||||
default:
|
||||
// invalid constant type!
|
||||
throw new classfile_exception();
|
||||
}
|
||||
}
|
||||
constant(int)
|
||||
{
|
||||
}
|
||||
// load data depending on type
|
||||
switch (type)
|
||||
{
|
||||
case constant_type_t::j_float:
|
||||
buf.read_be(data.int_data);
|
||||
break;
|
||||
case constant_type_t::j_int:
|
||||
buf.read_be(data.int_data); // same as float data really
|
||||
break;
|
||||
case constant_type_t::j_double:
|
||||
buf.read_be(data.long_data);
|
||||
break;
|
||||
case constant_type_t::j_long:
|
||||
buf.read_be(data.long_data); // same as double
|
||||
break;
|
||||
case constant_type_t::j_class:
|
||||
buf.read_be(data.ref_type.class_idx);
|
||||
break;
|
||||
case constant_type_t::j_fieldref:
|
||||
case constant_type_t::j_methodref:
|
||||
case constant_type_t::j_interface_methodref:
|
||||
buf.read_be(data.ref_type.class_idx);
|
||||
buf.read_be(data.ref_type.name_and_type_idx);
|
||||
break;
|
||||
case constant_type_t::j_string:
|
||||
buf.read_be(data.index);
|
||||
break;
|
||||
case constant_type_t::j_string_data:
|
||||
// HACK HACK: for now, we call these UTF-8 and do no further processing.
|
||||
// Later, we should do some decoding. It's really modified UTF-8
|
||||
// * U+0000 is represented as 0xC0,0x80 invalid character
|
||||
// * any single zero byte ends the string
|
||||
// * characters above U+10000 are encoded like in CESU-8
|
||||
buf.read_jstr(str_data);
|
||||
break;
|
||||
case constant_type_t::j_nameandtype:
|
||||
buf.read_be(data.name_and_type.name_index);
|
||||
buf.read_be(data.name_and_type.descriptor_index);
|
||||
break;
|
||||
default:
|
||||
// invalid constant type!
|
||||
throw new classfile_exception();
|
||||
}
|
||||
}
|
||||
constant(int)
|
||||
{
|
||||
}
|
||||
|
||||
std::string toString()
|
||||
{
|
||||
std::ostringstream ss;
|
||||
switch (type)
|
||||
{
|
||||
case constant_type_t::j_hole:
|
||||
ss << "Fake legacy entry";
|
||||
break;
|
||||
case constant_type_t::j_float:
|
||||
ss << "Float: " << data.float_data;
|
||||
break;
|
||||
case constant_type_t::j_double:
|
||||
ss << "Double: " << data.double_data;
|
||||
break;
|
||||
case constant_type_t::j_int:
|
||||
ss << "Int: " << data.int_data;
|
||||
break;
|
||||
case constant_type_t::j_long:
|
||||
ss << "Long: " << data.long_data;
|
||||
break;
|
||||
case constant_type_t::j_string_data:
|
||||
ss << "StrData: " << str_data;
|
||||
break;
|
||||
case constant_type_t::j_string:
|
||||
ss << "Str: " << data.index;
|
||||
break;
|
||||
case constant_type_t::j_fieldref:
|
||||
ss << "FieldRef: " << data.ref_type.class_idx << " " << data.ref_type.name_and_type_idx;
|
||||
break;
|
||||
case constant_type_t::j_methodref:
|
||||
ss << "MethodRef: " << data.ref_type.class_idx << " " << data.ref_type.name_and_type_idx;
|
||||
break;
|
||||
case constant_type_t::j_interface_methodref:
|
||||
ss << "IfMethodRef: " << data.ref_type.class_idx << " " << data.ref_type.name_and_type_idx;
|
||||
break;
|
||||
case constant_type_t::j_class:
|
||||
ss << "Class: " << data.ref_type.class_idx;
|
||||
break;
|
||||
case constant_type_t::j_nameandtype:
|
||||
ss << "NameAndType: " << data.name_and_type.name_index << " "
|
||||
<< data.name_and_type.descriptor_index;
|
||||
break;
|
||||
default:
|
||||
ss << "Invalid entry (" << int(type) << ")";
|
||||
break;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
std::string toString()
|
||||
{
|
||||
std::ostringstream ss;
|
||||
switch (type)
|
||||
{
|
||||
case constant_type_t::j_hole:
|
||||
ss << "Fake legacy entry";
|
||||
break;
|
||||
case constant_type_t::j_float:
|
||||
ss << "Float: " << data.float_data;
|
||||
break;
|
||||
case constant_type_t::j_double:
|
||||
ss << "Double: " << data.double_data;
|
||||
break;
|
||||
case constant_type_t::j_int:
|
||||
ss << "Int: " << data.int_data;
|
||||
break;
|
||||
case constant_type_t::j_long:
|
||||
ss << "Long: " << data.long_data;
|
||||
break;
|
||||
case constant_type_t::j_string_data:
|
||||
ss << "StrData: " << str_data;
|
||||
break;
|
||||
case constant_type_t::j_string:
|
||||
ss << "Str: " << data.index;
|
||||
break;
|
||||
case constant_type_t::j_fieldref:
|
||||
ss << "FieldRef: " << data.ref_type.class_idx << " " << data.ref_type.name_and_type_idx;
|
||||
break;
|
||||
case constant_type_t::j_methodref:
|
||||
ss << "MethodRef: " << data.ref_type.class_idx << " " << data.ref_type.name_and_type_idx;
|
||||
break;
|
||||
case constant_type_t::j_interface_methodref:
|
||||
ss << "IfMethodRef: " << data.ref_type.class_idx << " " << data.ref_type.name_and_type_idx;
|
||||
break;
|
||||
case constant_type_t::j_class:
|
||||
ss << "Class: " << data.ref_type.class_idx;
|
||||
break;
|
||||
case constant_type_t::j_nameandtype:
|
||||
ss << "NameAndType: " << data.name_and_type.name_index << " "
|
||||
<< data.name_and_type.descriptor_index;
|
||||
break;
|
||||
default:
|
||||
ss << "Invalid entry (" << int(type) << ")";
|
||||
break;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string str_data; /** String data in 'modified utf-8'.*/
|
||||
std::string str_data; /** String data in 'modified utf-8'.*/
|
||||
|
||||
// store everything here.
|
||||
union
|
||||
{
|
||||
int32_t int_data;
|
||||
int64_t long_data;
|
||||
float float_data;
|
||||
double double_data;
|
||||
uint16_t index;
|
||||
ref_type_t ref_type;
|
||||
name_and_type_t name_and_type;
|
||||
} data = {0};
|
||||
// store everything here.
|
||||
union
|
||||
{
|
||||
int32_t int_data;
|
||||
int64_t long_data;
|
||||
float float_data;
|
||||
double double_data;
|
||||
uint16_t index;
|
||||
ref_type_t ref_type;
|
||||
name_and_type_t name_and_type;
|
||||
} data = {0};
|
||||
};
|
||||
|
||||
/**
|
||||
@ -168,64 +168,64 @@ public:
|
||||
class constant_pool
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create a pool of constants
|
||||
*/
|
||||
constant_pool()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Load a java constant pool
|
||||
*/
|
||||
void load(util::membuffer &buf)
|
||||
{
|
||||
// FIXME: @SANITY this should check for the end of buffer.
|
||||
uint16_t length = 0;
|
||||
buf.read_be(length);
|
||||
length--;
|
||||
const constant *last_constant = nullptr;
|
||||
while (length)
|
||||
{
|
||||
const constant &cnst = constant(buf);
|
||||
constants.push_back(cnst);
|
||||
last_constant = &constants[constants.size() - 1];
|
||||
if (last_constant->type == constant_type_t::j_double ||
|
||||
last_constant->type == constant_type_t::j_long)
|
||||
{
|
||||
// push in a fake constant to preserve indexing
|
||||
constants.push_back(constant(0));
|
||||
length -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
length--;
|
||||
}
|
||||
}
|
||||
}
|
||||
typedef std::vector<java::constant> container_type;
|
||||
/**
|
||||
* Access constants based on jar file index numbers (index of the first element is 1)
|
||||
*/
|
||||
java::constant &operator[](std::size_t constant_index)
|
||||
{
|
||||
if (constant_index == 0 || constant_index > constants.size())
|
||||
{
|
||||
throw new classfile_exception();
|
||||
}
|
||||
return constants[constant_index - 1];
|
||||
}
|
||||
;
|
||||
container_type::const_iterator begin() const
|
||||
{
|
||||
return constants.begin();
|
||||
}
|
||||
;
|
||||
container_type::const_iterator end() const
|
||||
{
|
||||
return constants.end();
|
||||
}
|
||||
/**
|
||||
* Create a pool of constants
|
||||
*/
|
||||
constant_pool()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Load a java constant pool
|
||||
*/
|
||||
void load(util::membuffer &buf)
|
||||
{
|
||||
// FIXME: @SANITY this should check for the end of buffer.
|
||||
uint16_t length = 0;
|
||||
buf.read_be(length);
|
||||
length--;
|
||||
const constant *last_constant = nullptr;
|
||||
while (length)
|
||||
{
|
||||
const constant &cnst = constant(buf);
|
||||
constants.push_back(cnst);
|
||||
last_constant = &constants[constants.size() - 1];
|
||||
if (last_constant->type == constant_type_t::j_double ||
|
||||
last_constant->type == constant_type_t::j_long)
|
||||
{
|
||||
// push in a fake constant to preserve indexing
|
||||
constants.push_back(constant(0));
|
||||
length -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
length--;
|
||||
}
|
||||
}
|
||||
}
|
||||
typedef std::vector<java::constant> container_type;
|
||||
/**
|
||||
* Access constants based on jar file index numbers (index of the first element is 1)
|
||||
*/
|
||||
java::constant &operator[](std::size_t constant_index)
|
||||
{
|
||||
if (constant_index == 0 || constant_index > constants.size())
|
||||
{
|
||||
throw new classfile_exception();
|
||||
}
|
||||
return constants[constant_index - 1];
|
||||
}
|
||||
;
|
||||
container_type::const_iterator begin() const
|
||||
{
|
||||
return constants.begin();
|
||||
}
|
||||
;
|
||||
container_type::const_iterator end() const
|
||||
{
|
||||
return constants.end();
|
||||
}
|
||||
|
||||
private:
|
||||
container_type constants;
|
||||
container_type constants;
|
||||
};
|
||||
}
|
||||
|
@ -9,67 +9,67 @@ namespace util
|
||||
#ifdef MULTIMC_BIG_ENDIAN
|
||||
inline uint64_t bigswap(uint64_t x)
|
||||
{
|
||||
return x;
|
||||
return x;
|
||||
}
|
||||
;
|
||||
inline uint32_t bigswap(uint32_t x)
|
||||
{
|
||||
return x;
|
||||
return x;
|
||||
}
|
||||
;
|
||||
inline uint16_t bigswap(uint16_t x)
|
||||
{
|
||||
return x;
|
||||
return x;
|
||||
}
|
||||
;
|
||||
inline int64_t bigswap(int64_t x)
|
||||
{
|
||||
return x;
|
||||
return x;
|
||||
}
|
||||
;
|
||||
inline int32_t bigswap(int32_t x)
|
||||
{
|
||||
return x;
|
||||
return x;
|
||||
}
|
||||
;
|
||||
inline int16_t bigswap(int16_t x)
|
||||
{
|
||||
return x;
|
||||
return x;
|
||||
}
|
||||
;
|
||||
#else
|
||||
inline uint64_t bigswap(uint64_t x)
|
||||
{
|
||||
return (x >> 56) | ((x << 40) & 0x00FF000000000000) | ((x << 24) & 0x0000FF0000000000) |
|
||||
((x << 8) & 0x000000FF00000000) | ((x >> 8) & 0x00000000FF000000) |
|
||||
((x >> 24) & 0x0000000000FF0000) | ((x >> 40) & 0x000000000000FF00) | (x << 56);
|
||||
return (x >> 56) | ((x << 40) & 0x00FF000000000000) | ((x << 24) & 0x0000FF0000000000) |
|
||||
((x << 8) & 0x000000FF00000000) | ((x >> 8) & 0x00000000FF000000) |
|
||||
((x >> 24) & 0x0000000000FF0000) | ((x >> 40) & 0x000000000000FF00) | (x << 56);
|
||||
}
|
||||
|
||||
inline uint32_t bigswap(uint32_t x)
|
||||
{
|
||||
return (x >> 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x << 24);
|
||||
return (x >> 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x << 24);
|
||||
}
|
||||
|
||||
inline uint16_t bigswap(uint16_t x)
|
||||
{
|
||||
return (x >> 8) | (x << 8);
|
||||
return (x >> 8) | (x << 8);
|
||||
}
|
||||
|
||||
inline int64_t bigswap(int64_t x)
|
||||
{
|
||||
return (x >> 56) | ((x << 40) & 0x00FF000000000000) | ((x << 24) & 0x0000FF0000000000) |
|
||||
((x << 8) & 0x000000FF00000000) | ((x >> 8) & 0x00000000FF000000) |
|
||||
((x >> 24) & 0x0000000000FF0000) | ((x >> 40) & 0x000000000000FF00) | (x << 56);
|
||||
return (x >> 56) | ((x << 40) & 0x00FF000000000000) | ((x << 24) & 0x0000FF0000000000) |
|
||||
((x << 8) & 0x000000FF00000000) | ((x >> 8) & 0x00000000FF000000) |
|
||||
((x >> 24) & 0x0000000000FF0000) | ((x >> 40) & 0x000000000000FF00) | (x << 56);
|
||||
}
|
||||
|
||||
inline int32_t bigswap(int32_t x)
|
||||
{
|
||||
return (x >> 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x << 24);
|
||||
return (x >> 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x << 24);
|
||||
}
|
||||
|
||||
inline int16_t bigswap(int16_t x)
|
||||
{
|
||||
return (x >> 8) | (x << 8);
|
||||
return (x >> 8) | (x << 8);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -10,54 +10,54 @@ namespace util
|
||||
class membuffer
|
||||
{
|
||||
public:
|
||||
membuffer(char *buffer, std::size_t size)
|
||||
{
|
||||
current = start = buffer;
|
||||
end = start + size;
|
||||
}
|
||||
~membuffer()
|
||||
{
|
||||
// maybe? possibly? left out to avoid confusion. for now.
|
||||
// delete start;
|
||||
}
|
||||
/**
|
||||
* Read some value. That's all ;)
|
||||
*/
|
||||
template <class T> void read(T &val)
|
||||
{
|
||||
val = *(T *)current;
|
||||
current += sizeof(T);
|
||||
}
|
||||
/**
|
||||
* Read a big-endian number
|
||||
* valid for 2-byte, 4-byte and 8-byte variables
|
||||
*/
|
||||
template <class T> void read_be(T &val)
|
||||
{
|
||||
val = util::bigswap(*(T *)current);
|
||||
current += sizeof(T);
|
||||
}
|
||||
/**
|
||||
* Read a string in the format:
|
||||
* 2B length (big endian, unsigned)
|
||||
* length bytes data
|
||||
*/
|
||||
void read_jstr(std::string &str)
|
||||
{
|
||||
uint16_t length = 0;
|
||||
read_be(length);
|
||||
str.append(current, length);
|
||||
current += length;
|
||||
}
|
||||
/**
|
||||
* Skip N bytes
|
||||
*/
|
||||
void skip(std::size_t N)
|
||||
{
|
||||
current += N;
|
||||
}
|
||||
membuffer(char *buffer, std::size_t size)
|
||||
{
|
||||
current = start = buffer;
|
||||
end = start + size;
|
||||
}
|
||||
~membuffer()
|
||||
{
|
||||
// maybe? possibly? left out to avoid confusion. for now.
|
||||
// delete start;
|
||||
}
|
||||
/**
|
||||
* Read some value. That's all ;)
|
||||
*/
|
||||
template <class T> void read(T &val)
|
||||
{
|
||||
val = *(T *)current;
|
||||
current += sizeof(T);
|
||||
}
|
||||
/**
|
||||
* Read a big-endian number
|
||||
* valid for 2-byte, 4-byte and 8-byte variables
|
||||
*/
|
||||
template <class T> void read_be(T &val)
|
||||
{
|
||||
val = util::bigswap(*(T *)current);
|
||||
current += sizeof(T);
|
||||
}
|
||||
/**
|
||||
* Read a string in the format:
|
||||
* 2B length (big endian, unsigned)
|
||||
* length bytes data
|
||||
*/
|
||||
void read_jstr(std::string &str)
|
||||
{
|
||||
uint16_t length = 0;
|
||||
read_be(length);
|
||||
str.append(current, length);
|
||||
current += length;
|
||||
}
|
||||
/**
|
||||
* Skip N bytes
|
||||
*/
|
||||
void skip(std::size_t N)
|
||||
{
|
||||
current += N;
|
||||
}
|
||||
|
||||
private:
|
||||
char *start, *end, *current;
|
||||
char *start, *end, *current;
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user