summaryrefslogtreecommitdiffstats
path: root/depends/classparser
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2013-08-17 13:40:51 +0200
committerPetr Mrázek <peterix@gmail.com>2013-08-17 13:40:51 +0200
commit253067c782955380bbf66ac0475dc954375b1ff4 (patch)
treeca97e231fd3a764256d95b5fc8d08fc25ff72161 /depends/classparser
parent77e80665422c4e97e2286418ab55e20c4030023b (diff)
downloadMultiMC-253067c782955380bbf66ac0475dc954375b1ff4.tar
MultiMC-253067c782955380bbf66ac0475dc954375b1ff4.tar.gz
MultiMC-253067c782955380bbf66ac0475dc954375b1ff4.tar.lz
MultiMC-253067c782955380bbf66ac0475dc954375b1ff4.tar.xz
MultiMC-253067c782955380bbf66ac0475dc954375b1ff4.zip
Move all the things (YES. Move them.)
Also, implemented some basic modlist logic, to be wired up.
Diffstat (limited to 'depends/classparser')
-rw-r--r--depends/classparser/CMakeLists.txt41
-rw-r--r--depends/classparser/include/classparser_config.h23
-rw-r--r--depends/classparser/include/javautils.h29
-rw-r--r--depends/classparser/src/annotations.cpp83
-rw-r--r--depends/classparser/src/annotations.h252
-rw-r--r--depends/classparser/src/classfile.h153
-rw-r--r--depends/classparser/src/constants.h212
-rw-r--r--depends/classparser/src/errors.h6
-rw-r--r--depends/classparser/src/javaendian.h62
-rw-r--r--depends/classparser/src/javautils.cpp81
-rw-r--r--depends/classparser/src/membuffer.h64
11 files changed, 1006 insertions, 0 deletions
diff --git a/depends/classparser/CMakeLists.txt b/depends/classparser/CMakeLists.txt
new file mode 100644
index 00000000..5a48e002
--- /dev/null
+++ b/depends/classparser/CMakeLists.txt
@@ -0,0 +1,41 @@
+project(classparser)
+
+set(CMAKE_AUTOMOC ON)
+
+# Find Qt
+find_package(Qt5Core REQUIRED)
+
+# Include Qt headers.
+include_directories(${Qt5Base_INCLUDE_DIRS})
+
+SET(CLASSPARSER_HEADERS
+include/classparser_config.h
+
+# Public headers
+include/javautils.h
+
+# Private headers
+src/annotations.h
+src/classfile.h
+src/constants.h
+src/errors.h
+src/javaendian.h
+src/membuffer.h
+)
+
+SET(CLASSPARSER_SOURCES
+src/javautils.cpp
+src/annotations.cpp
+)
+
+# Set the include dir path.
+SET(LIBGROUPVIEW_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE)
+
+# Include self.
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
+include_directories(${CMAKE_BINARY_DIR}/include)
+
+add_definitions(-DCLASSPARSER_LIBRARY)
+
+add_library(classparser SHARED ${CLASSPARSER_SOURCES} ${CLASSPARSER_HEADERS})
+qt5_use_modules(classparser Core)
diff --git a/depends/classparser/include/classparser_config.h b/depends/classparser/include/classparser_config.h
new file mode 100644
index 00000000..fe6a2ab9
--- /dev/null
+++ b/depends/classparser/include/classparser_config.h
@@ -0,0 +1,23 @@
+/* Copyright 2013 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QtCore/QtGlobal>
+
+#ifdef CLASSPARSER_LIBRARY
+# define CLASSPARSER_EXPORT Q_DECL_EXPORT
+#else
+# define CLASSPARSER_EXPORT Q_DECL_IMPORT
+#endif
+
diff --git a/depends/classparser/include/javautils.h b/depends/classparser/include/javautils.h
new file mode 100644
index 00000000..63e5ec26
--- /dev/null
+++ b/depends/classparser/include/javautils.h
@@ -0,0 +1,29 @@
+/* Copyright 2013 MultiMC Contributors
+ *
+ * Authors: Orochimarufan <orochimarufan.x3@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+#include <QString>
+#include "classparser_config.h"
+
+#define MCVer_Unknown "Unknown"
+
+namespace javautils
+{
+ /**
+ * @brief Get the version from a minecraft.jar by parsing its class files. Expensive!
+ */
+ QString GetMinecraftJarVersion(QString jar);
+}
diff --git a/depends/classparser/src/annotations.cpp b/depends/classparser/src/annotations.cpp
new file mode 100644
index 00000000..fc0c98fa
--- /dev/null
+++ b/depends/classparser/src/annotations.cpp
@@ -0,0 +1,83 @@
+#include "classfile.h"
+#include "annotations.h"
+#include <sstream>
+
+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();
+ }
+
+ 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 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 )
+ {
+ 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();
+ }
+ }
+} \ No newline at end of file
diff --git a/depends/classparser/src/annotations.h b/depends/classparser/src/annotations.h
new file mode 100644
index 00000000..b115dc0b
--- /dev/null
+++ b/depends/classparser/src/annotations.h
@@ -0,0 +1,252 @@
+#pragma once
+#include "classfile.h"
+#include <map>
+#include <vector>
+
+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
+ };
+ /**
+ * 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()
+ {
+ 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 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);
+ };
+ 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()
+ {
+ 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;
+ 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)
+ {
+ 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;
+ 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++)
+ {
+ 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";
+ };
+ };
+} \ No newline at end of file
diff --git a/depends/classparser/src/classfile.h b/depends/classparser/src/classfile.h
new file mode 100644
index 00000000..33207e99
--- /dev/null
+++ b/depends/classparser/src/classfile.h
@@ -0,0 +1,153 @@
+#pragma once
+#include "membuffer.h"
+#include "constants.h"
+#include "annotations.h"
+#include <map>
+namespace java
+{
+ /**
+ * Class representing a Java .class file
+ */
+ 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);
+
+ // 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 --;
+ }
+
+ // 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;
+ };
+} \ No newline at end of file
diff --git a/depends/classparser/src/constants.h b/depends/classparser/src/constants.h
new file mode 100644
index 00000000..61aa5687
--- /dev/null
+++ b/depends/classparser/src/constants.h
@@ -0,0 +1,212 @@
+#pragma once
+#include "errors.h"
+#include <sstream>
+
+namespace java
+{
+ class constant
+ {
+ 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;
+
+ 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)
+ {
+ 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)
+ {
+ type = j_hole;
+ }
+
+ std::string toString()
+ {
+ 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
+ {
+ 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;
+ };
+ };
+
+ /**
+ * A helper class that represents the custom container used in Java class file for storage of constants
+ */
+ class constant_pool
+ {
+ public:
+ /**
+ * Create a pool of constants
+ */
+ constant_pool(){}
+ /**
+ * 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)
+ {
+ 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++;
+ }
+ }
+ }
+ 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;
+ };
+}
diff --git a/depends/classparser/src/errors.h b/depends/classparser/src/errors.h
new file mode 100644
index 00000000..c02b07c8
--- /dev/null
+++ b/depends/classparser/src/errors.h
@@ -0,0 +1,6 @@
+#pragma once
+#include <exception>
+namespace java
+{
+ class classfile_exception : public std::exception {};
+}
diff --git a/depends/classparser/src/javaendian.h b/depends/classparser/src/javaendian.h
new file mode 100644
index 00000000..fa6207fe
--- /dev/null
+++ b/depends/classparser/src/javaendian.h
@@ -0,0 +1,62 @@
+#pragma once
+#include <stdint.h>
+
+/**
+ * Swap bytes between big endian and local number representation
+ */
+namespace util
+{
+#ifdef MULTIMC_BIG_ENDIAN
+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);
+};
+inline uint32_t bigswap(uint32_t x)
+{
+ return (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24);
+};
+inline uint16_t bigswap(uint16_t x)
+{
+ 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);
+};
+inline int32_t bigswap(int32_t x)
+{
+ return (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24);
+};
+inline int16_t bigswap(int16_t x)
+{
+ return (x>>8) | (x<<8);
+};
+#endif
+}
diff --git a/depends/classparser/src/javautils.cpp b/depends/classparser/src/javautils.cpp
new file mode 100644
index 00000000..4a359031
--- /dev/null
+++ b/depends/classparser/src/javautils.cpp
@@ -0,0 +1,81 @@
+/* Copyright 2013 MultiMC Contributors
+ *
+ * Authors: Orochimarufan <orochimarufan.x3@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "multimc_pragma.h"
+#include "classfile.h"
+#include "javautils.h"
+
+#include <QFile>
+#include <quazipfile.h>
+
+namespace javautils
+{
+
+QString GetMinecraftJarVersion(QString jarName)
+{
+ QString version = MCVer_Unknown;
+
+ // 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.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);
+
+ // 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::j_string_data)
+ continue;
+ 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 &) {}
+
+ // clean up
+ delete[] classfile;
+ Minecraft.close();
+ zip.close();
+ jar.close();
+
+ return version;
+}
+
+}
diff --git a/depends/classparser/src/membuffer.h b/depends/classparser/src/membuffer.h
new file mode 100644
index 00000000..2ea3a69b
--- /dev/null
+++ b/depends/classparser/src/membuffer.h
@@ -0,0 +1,64 @@
+#pragma once
+#include <stdint.h>
+#include <string>
+#include <vector>
+#include <exception>
+#include "javaendian.h"
+
+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;
+ }
+ private:
+ char * start, *end, *current;
+ };
+}