diff options
69 files changed, 16978 insertions, 27 deletions
@@ -1 +1,6 @@ Thumbs.db +.kdev4 +MultiMC5.kdev4 +build +resources/CMakeFiles +resources/MultiMCLauncher.jar diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..45f1ddb0 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,132 @@ +cmake_minimum_required(VERSION 2.8.9) +project(multimc5) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + + +#### Check for machine endianness #### +INCLUDE(TestBigEndian) +TEST_BIG_ENDIAN(BIGENDIAN) +IF(${BIGENDIAN}) + ADD_DEFINITIONS(-DMULTIMC_BIG_ENDIAN) +ENDIF(${BIGENDIAN}) + + +#### Find the required Qt parts #### +find_package(Qt5Widgets) +#find_package(Qt5Declarative) + +include_directories(${Qt5Widgets_INCLUDE_DIRS}) + +# find ZLIB for quazip +find_package(ZLIB REQUIRED) + +# Find boost. +set(Boost_USE_STATIC_LIBS ON) +MESSAGE(STATUS "** Finding Boost...") +find_package(Boost 1.46.0 REQUIRED) +MESSAGE(STATUS "** Boost Include: ${Boost_INCLUDE_DIR}") +MESSAGE(STATUS "** Boost Libraries: ${Boost_LIBRARY_DIRS}") + +# Include boost. +include_directories("${Boost_INCLUDE_DIRS}") + +# Add quazip +add_subdirectory(quazip) + +# Add bspatch +add_subdirectory(patchlib) +include_directories(patchlib) + +# add the java launcher +add_subdirectory(launcher) + +IF(UNIX) + # assume GCC, add C++0x/C++11 stuff + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") +ELSEIF(MINGW) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") +ENDIF() + +# Set the path where CMake will look for modules. +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}") + + +set(MultiMC_VERSION_MAJOR 5) +set(MultiMC_VERSION_MINOR 0) +set(MultiMC_VERSION_REV 0) + +SET(MultiMC_VERSION_BUILD 0 CACHE STRING "Build number.") +message(STATUS "MultiMC build #${MultiMC_VERSION_BUILD}") + +IF (DEFINED MultiMC_BUILD_TAG) + message(STATUS "Build tag: ${MultiMC_BUILD_TAG}") +ELSE () + message(STATUS "No build tag specified.") +ENDIF () + +if( CMAKE_SIZEOF_VOID_P EQUAL 8 ) + set (MultiMC_ARCH "x64" + CACHE STRING "Architecture we're building for.") +else() + set (MultiMC_ARCH "x86" + CACHE STRING "Architecture we're building for.") +endif() +message (STATUS "Architecture is ${MultiMC_ARCH}") + +SET(MultiMC_Extra_Label "") + +IF (WIN32) + SET(MultiMC_JOB_NAME "MultiMC4Windows" CACHE STRING "Jenkins job name.") +ELSEIF(UNIX AND APPLE) + SET(MultiMC_JOB_NAME "MultiMC4OSX" CACHE STRING "Jenkins job name.") + # This is here because the scheme doesn't exactly apply to every kind of build... + SET(MultiMC_Extra_Label ",label=osx") +ELSE() + SET(MultiMC_JOB_NAME "MultiMC4Linux" CACHE STRING "Jenkins job name.") +ENDIF() + +SET(MultiMC_JOB_URL "http://ci.forkk.net/job/${MultiMC_JOB_NAME}/arch=${MultiMC_ARCH}${MultiMC_Extra_Label}/" + CACHE STRING "URL of the jenkins job to pull updates from.") +message(STATUS "Job URL: ${MultiMC_JOB_URL}") + +configure_file("${PROJECT_SOURCE_DIR}/config.h.in" + "${PROJECT_BINARY_DIR}/config.h") + + +SET(MULTIMC_SOURCES +main.cpp +gui/mainwindow.cpp +data/instancebase.cpp +util/pathutils.cpp + +java/javautils.cpp +java/annotations.cpp +) + +SET(MULTIMC_HEADERS +gui/mainwindow.h +data/instancebase.h +util/pathutils.h +multimc_pragma.h + +java/annotations.h +java/classfile.h +java/constants.h +java/endian.h +java/errors.h +java/javautils.h +java/membuffer.h +) + +SET_SOURCE_FILES_PROPERTIES(resources/MultiMCLauncher.jar GENERATED) + +QT5_WRAP_UI(MULTIMC_UI gui/mainwindow.ui) +QT5_ADD_RESOURCES(MULTIMC_QRC multimc.qrc) + +add_executable(multimc5 ${MULTIMC_SOURCES} ${MULTIMC_HEADERS} ${MULTIMC_UI} ${MULTIMC_QRC}) +qt5_use_modules(multimc5 Widgets) +link_libraries(multimc5 quazip patchlib) +add_dependencies(multimc5 MultiMCLauncher) +install(TARGETS multimc5 RUNTIME DESTINATION bin) diff --git a/config.h.in b/config.h.in new file mode 100644 index 00000000..de53ac93 --- /dev/null +++ b/config.h.in @@ -0,0 +1,17 @@ +#define VERSION_MAJOR @MultiMC_VERSION_MAJOR@ +#define VERSION_MINOR @MultiMC_VERSION_MINOR@ +#define VERSION_REVISION @MultiMC_VERSION_REV@ +#define VERSION_BUILD @MultiMC_VERSION_BUILD@ + +#define VERSION_STR "@MultiMC_VERSION_MAJOR@.@MultiMC_VERSION_MINOR@.@MultiMC_VERSION_REV@.@MultiMC_VERSION_BUILD@" + +#define x86 1 +#define x64 2 + +#define ARCH @MultiMC_ARCH@ + +#define JENKINS_BUILD_TAG "@MultiMC_BUILD_TAG@" + +#define JENKINS_JOB_URL "@MultiMC_JOB_URL@" + +#define USE_HTTPS @MultiMC_USE_HTTPS@ diff --git a/java/annotations.cpp b/java/annotations.cpp new file mode 100644 index 00000000..fc0c98fa --- /dev/null +++ b/java/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/java/annotations.h b/java/annotations.h new file mode 100644 index 00000000..b115dc0b --- /dev/null +++ b/java/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/java/classfile.h b/java/classfile.h new file mode 100644 index 00000000..33207e99 --- /dev/null +++ b/java/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 ifac |
