Reformat and (slightly) decruft all the things.

This commit is contained in:
Petr Mrázek
2013-11-04 02:53:05 +01:00
parent d6e4fb2971
commit bb7e8985f6
208 changed files with 4492 additions and 3767 deletions

View File

@ -16,8 +16,7 @@
#include <QtCore/QtGlobal>
#ifdef CLASSPARSER_LIBRARY
# define CLASSPARSER_EXPORT Q_DECL_EXPORT
#define CLASSPARSER_EXPORT Q_DECL_EXPORT
#else
# define CLASSPARSER_EXPORT Q_DECL_IMPORT
#define CLASSPARSER_EXPORT Q_DECL_IMPORT
#endif

View File

@ -22,8 +22,8 @@
namespace javautils
{
/**
* @brief Get the version from a minecraft.jar by parsing its class files. Expensive!
*/
QString GetMinecraftJarVersion(QString jar);
/**
* @brief Get the version from a minecraft.jar by parsing its class files. Expensive!
*/
QString GetMinecraftJarVersion(QString jar);
}

View File

@ -4,80 +4,82 @@
namespace java
{
std::string annotation::toString()
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::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::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)
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 num_pairs = 0;
input.read_be(num_pairs);
while (num_pairs)
{
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 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--;
}
element_value* element_value::readElementValue ( util::membuffer& input, java::constant_pool& pool )
return ann;
}
element_value *element_value::readElementValue(util::membuffer &input,
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)
{
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++)
{
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();
vals.push_back(element_value::readElementValue(input, pool));
}
return new element_value_array(ARRAY, vals, pool);
default:
throw new java::classfile_exception();
}
}
}

View File

@ -5,248 +5,273 @@
namespace java
{
enum element_value_type : uint8_t
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
};
/**
* The element_value structure is a discriminated union representing the value of an
*element-value pair.
* It is used to represent element values in all attributes that describe annotations
* - RuntimeVisibleAnnotations
* - RuntimeInvisibleAnnotations
* - RuntimeVisibleParameterAnnotations
* - RuntimeInvisibleParameterAnnotations).
*
* The element_value structure has the following format:
*/
class element_value
{
protected:
element_value_type type;
constant_pool &pool;
public:
element_value(element_value_type type, constant_pool &pool) : type(type), pool(pool) {};
element_value_type getElementValueType()
{
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
};
return type;
}
virtual std::string toString() = 0;
static element_value *readElementValue(util::membuffer &input, constant_pool &pool);
};
/**
* Each value of the annotations table represents a single runtime-visible annotation on a
* program element.
* The annotation structure has the following format:
*/
class annotation
{
public:
typedef std::vector<std::pair<uint16_t, element_value *>> value_list;
protected:
/**
* The element_value structure is a discriminated union representing the value of an element-value pair.
* It is used to represent element values in all attributes that describe annotations
* - RuntimeVisibleAnnotations
* - RuntimeInvisibleAnnotations
* - RuntimeVisibleParameterAnnotations
* - RuntimeInvisibleParameterAnnotations).
* 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 element_value structure has the following format:
* 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.
*/
class element_value
{
protected:
element_value_type type;
constant_pool & pool;
public:
element_value(element_value_type type, constant_pool & pool): type(type), pool(pool) {};
element_value_type getElementValueType()
{
return type;
}
virtual std::string toString() = 0;
static element_value * readElementValue(util::membuffer & input, constant_pool & pool);
};
value_list name_val_pairs;
/**
* Each value of the annotations table represents a single runtime-visible annotation on a program element.
* The annotation structure has the following format:
* Reference to the parent constant pool
*/
class annotation
constant_pool &pool;
public:
annotation(uint16_t type_index, constant_pool &pool)
: type_index(type_index), pool(pool) {};
~annotation()
{
public:
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;
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++)
{
for(unsigned i = 0 ; i < name_val_pairs.size(); i++)
{
delete name_val_pairs[i].second;
}
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;
/// type for simple value annotation elements
class element_value_simple : public element_value
}
void add_pair(uint16_t key, element_value *value)
{
protected:
/// 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();
};
};
/// The enum_const_value item is used if the tag item is 'e'.
class element_value_enum : public element_value
name_val_pairs.push_back(std::make_pair(key, value));
}
;
value_list::const_iterator begin()
{
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;
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";
};
};
class element_value_class : public element_value
return name_val_pairs.cbegin();
}
value_list::const_iterator end()
{
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;
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";
};
};
/// nested annotations... yay
class element_value_annotation : public element_value
return name_val_pairs.cend();
}
std::string toString();
static annotation *read(util::membuffer &input, constant_pool &pool);
};
typedef std::vector<annotation *> annotation_table;
/// type for simple value annotation elements
class element_value_simple : public element_value
{
protected:
/// 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()
{
private:
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";
};
};
/// and arrays!
class element_value_array : public element_value
return index;
}
virtual std::string toString()
{
public:
typedef std::vector <element_value *> elem_vec;
protected:
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 ()
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;
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";
}
;
};
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;
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";
}
;
};
/// nested annotations... yay
class element_value_annotation : public element_value
{
private:
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)
{
for(unsigned i = 0; i < values.size();i++)
{
delete values[i];
}
};
elem_vec::const_iterator begin()
{
return values.cbegin();
delete nestedAnnotation;
nestedAnnotation = nullptr;
}
elem_vec::const_iterator end()
}
virtual std::string toString()
{
return "nested annotation";
}
;
};
/// and arrays!
class element_value_array : public element_value
{
public:
typedef std::vector<element_value *> elem_vec;
protected:
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++)
{
return values.cend();
delete values[i];
}
virtual std::string toString()
{
return "array";
};
};
}
;
elem_vec::const_iterator begin()
{
return values.cbegin();
}
elem_vec::const_iterator end()
{
return values.cend();
}
virtual std::string toString()
{
return "array";
}
;
};
}

View File

@ -5,149 +5,152 @@
#include <map>
namespace java
{
/**
* Class representing a Java .class file
*/
class classfile : public util::membuffer
/**
* Class representing a Java .class file
*/
class classfile : public util::membuffer
{
public:
classfile(char *data, std::size_t size) : membuffer(data, size)
{
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);
// Interfaces
uint16_t iface_count = 0;
read_be(iface_count);
while (iface_count)
{
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 --;
}
// 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 --;
}
uint16_t iface;
read_be(iface);
interfaces.push_back(iface);
iface_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 )
// 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(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);
skip(2);
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 --;
skip(attr_length);
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;
};
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 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;
};
}

View File

@ -4,209 +4,217 @@
namespace java
{
class constant
class constant
{
public:
enum type_t : uint8_t
{
public:
enum 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
} type;
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
} type;
constant(util::membuffer & buf )
constant(util::membuffer &buf)
{
buf.read(type);
// invalid constant type!
if (type > j_nameandtype || type == (type_t)0 || type == (type_t)2)
throw new classfile_exception();
// load data depending on type
switch (type)
{
buf.read(type);
// invalid constant type!
if(type > j_nameandtype || type == (type_t)0 || type == (type_t)2)
throw new classfile_exception();
// load data depending on type
switch(type)
{
case j_float:
case j_int:
buf.read_be(int_data); // same as float data really
break;
case j_double:
case j_long:
buf.read_be(long_data); // same as double
break;
case j_class:
buf.read_be(ref_type.class_idx);
break;
case j_fieldref:
case j_methodref:
case j_interface_methodref:
buf.read_be(ref_type.class_idx);
buf.read_be(ref_type.name_and_type_idx);
break;
case j_string:
buf.read_be(index);
break;
case 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 j_nameandtype:
buf.read_be(name_and_type.name_index);
buf.read_be(name_and_type.descriptor_index);
break;
}
case j_float:
case j_int:
buf.read_be(int_data); // same as float data really
break;
case j_double:
case j_long:
buf.read_be(long_data); // same as double
break;
case j_class:
buf.read_be(ref_type.class_idx);
break;
case j_fieldref:
case j_methodref:
case j_interface_methodref:
buf.read_be(ref_type.class_idx);
buf.read_be(ref_type.name_and_type_idx);
break;
case j_string:
buf.read_be(index);
break;
case 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 j_nameandtype:
buf.read_be(name_and_type.name_index);
buf.read_be(name_and_type.descriptor_index);
break;
}
}
constant(int fake)
constant(int fake)
{
type = j_hole;
}
std::string toString()
{
std::ostringstream ss;
switch (type)
{
type = j_hole;
case j_hole:
ss << "Fake legacy entry";
break;
case j_float:
ss << "Float: " << float_data;
break;
case j_double:
ss << "Double: " << double_data;
break;
case j_int:
ss << "Int: " << int_data;
break;
case j_long:
ss << "Long: " << long_data;
break;
case j_string_data:
ss << "StrData: " << str_data;
break;
case j_string:
ss << "Str: " << index;
break;
case j_fieldref:
ss << "FieldRef: " << ref_type.class_idx << " " << ref_type.name_and_type_idx;
break;
case j_methodref:
ss << "MethodRef: " << ref_type.class_idx << " " << ref_type.name_and_type_idx;
break;
case j_interface_methodref:
ss << "IfMethodRef: " << ref_type.class_idx << " " << ref_type.name_and_type_idx;
break;
case j_class:
ss << "Class: " << ref_type.class_idx;
break;
case j_nameandtype:
ss << "NameAndType: " << name_and_type.name_index << " "
<< name_and_type.descriptor_index;
break;
}
return ss.str();
}
std::string toString()
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;
struct
{
std::ostringstream ss;
switch(type)
{
case j_hole:
ss << "Fake legacy entry";
break;
case j_float:
ss << "Float: " << float_data;
break;
case j_double:
ss << "Double: " << double_data;
break;
case j_int:
ss << "Int: " << int_data;
break;
case j_long:
ss << "Long: " << long_data;
break;
case j_string_data:
ss << "StrData: " << str_data;
break;
case j_string:
ss << "Str: " << index;
break;
case j_fieldref:
ss << "FieldRef: " << ref_type.class_idx << " " << ref_type.name_and_type_idx;
break;
case j_methodref:
ss << "MethodRef: " << ref_type.class_idx << " " << ref_type.name_and_type_idx;
break;
case j_interface_methodref:
ss << "IfMethodRef: " << ref_type.class_idx << " " << ref_type.name_and_type_idx;
break;
case j_class:
ss << "Class: " << ref_type.class_idx;
break;
case j_nameandtype:
ss << "NameAndType: " << name_and_type.name_index << " " << name_and_type.descriptor_index;
break;
}
return ss.str();
}
std::string str_data; /** String data in 'modified utf-8'.*/
// store everything here.
union
/**
* 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;
} ref_type;
struct
{
int32_t int_data;
int64_t long_data;
float float_data;
double double_data;
uint16_t index;
struct
{
/**
* 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;
} ref_type;
struct
{
uint16_t name_index;
uint16_t descriptor_index;
} name_and_type;
};
uint16_t name_index;
uint16_t descriptor_index;
} name_and_type;
};
};
/**
* A helper class that represents the custom container used in Java class file for storage of
* constants
*/
class constant_pool
{
public:
/**
* A helper class that represents the custom container used in Java class file for storage of constants
* Create a pool of constants
*/
class constant_pool
constant_pool()
{
public:
/**
* Create a pool of constants
*/
constant_pool(){}
/**
* Load a java constant pool
*/
void load(util::membuffer & buf)
}
/**
* Load a java constant pool
*/
void load(util::membuffer &buf)
{
uint16_t length = 0;
buf.read_be(length);
length--;
uint16_t index = 1;
const constant *last_constant = nullptr;
while (length)
{
uint16_t length = 0;
buf.read_be(length);
length --;
uint16_t index = 1;
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::j_double ||
last_constant->type == constant::j_long)
{
const constant & cnst = constant(buf);
constants.push_back(cnst);
last_constant = &constants[constants.size() - 1];
if(last_constant->type == constant::j_double || last_constant->type == constant::j_long)
{
// push in a fake constant to preserve indexing
constants.push_back(constant(0));
length-=2;
index+=2;
}
else
{
length--;
index++;
}
// push in a fake constant to preserve indexing
constants.push_back(constant(0));
length -= 2;
index += 2;
}
else
{
length--;
index++;
}
}
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)
}
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())
{
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();
throw new classfile_exception();
}
private:
container_type constants;
};
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;
};
}

View File

@ -2,5 +2,7 @@
#include <exception>
namespace java
{
class classfile_exception : public std::exception {};
class classfile_exception : public std::exception
{
};
}

View File

@ -10,53 +10,67 @@ namespace util
inline uint64_t bigswap(uint64_t x)
{
return x;
};
}
;
inline uint32_t bigswap(uint32_t x)
{
return x;
};
}
;
inline uint16_t bigswap(uint16_t x)
{
return x;
};
}
;
inline int64_t bigswap(int64_t x)
{
return x;
};
}
;
inline int32_t bigswap(int32_t x)
{
return x;
};
}
;
inline int16_t bigswap(int16_t 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
}

View File

@ -49,24 +49,28 @@ QString GetMinecraftJarVersion(QString jarName)
Minecraft.read(classfile, size);
// parse Minecraft.class
try {
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++)
for (java::constant_pool::container_type::const_iterator iter = constants.begin();
iter != constants.end(); iter++)
{
const java::constant & constant = *iter;
const java::constant &constant = *iter;
if (constant.type != java::constant::j_string_data)
continue;
const std::string & str = constant.str_data;
const std::string &str = constant.str_data;
if (str.compare(0, 20, "Minecraft Minecraft ") == 0)
{
version = str.substr(20).data();
break;
}
}
} catch(java::classfile_exception &) {}
}
catch (java::classfile_exception &)
{
}
// clean up
delete[] classfile;
@ -76,5 +80,4 @@ QString GetMinecraftJarVersion(QString jarName)
return version;
}
}

View File

@ -7,58 +7,57 @@
namespace util
{
class membuffer
class membuffer
{
public:
membuffer(char *buffer, std::size_t size)
{
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;
}
private:
char * start, *end, *current;
};
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;
};
}