aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <[email protected]>2024-01-05 04:53:20 -0600
committerLibravatar bigfoot547 <[email protected]>2024-01-05 04:53:20 -0600
commit11672146b9bf67cae05e8e3207c9bd1e47d52220 (patch)
tree4d72fd88efbabeeb37509cdc99c5404528183ca1
parentdownloads assets correctly (diff)
extracts natives
-rw-r--r--meson.build11
-rw-r--r--src/args.c206
-rw-r--r--src/args.h13
-rw-r--r--src/assets.c14
-rw-r--r--src/cmd-version.c32
-rw-r--r--src/config.h.in4
-rw-r--r--src/l2su.h2
-rw-r--r--src/launch.c31
-rw-r--r--src/launcherutil.c8
-rw-r--r--src/macros.h5
-rw-r--r--src/meson.build2
-rw-r--r--src/version.c148
-rw-r--r--src/version.h11
13 files changed, 467 insertions, 20 deletions
diff --git a/meson.build b/meson.build
index 0b18d02..c5588b7 100644
--- a/meson.build
+++ b/meson.build
@@ -4,6 +4,7 @@ add_global_arguments('-D_XOPEN_SOURCE=700', '-DPCRE2_CODE_UNIT_WIDTH=8', languag
curl_dep = dependency('libcurl')
jansson_dep = dependency('jansson')
pcre2_dep = dependency('libpcre2-8')
+libzip_dep = dependency('libzip')
config_data = configuration_data()
@@ -82,6 +83,14 @@ endif
message('Using launcher OS', launcher_os)
config_data.set_quoted('L2SU_LAUNCHER_OS', launcher_os)
+if launcher_os == 'linux'
+ config_data.set('L2SU_LAUNCHER_IS_LINUX', true)
+elif launcher_os == 'osx'
+ config_data.set('L2SU_LAUNCHER_IS_OSX', true)
+elif launcher_os == 'windows'
+ config_data.set('L2SU_LAUNCHER_IS_WINDOWS', true)
+endif
+
message('Using launcher arch bits', launcher_arch_bits)
config_data.set_quoted('L2SU_LAUNCHER_ARCH_BITS', launcher_arch_bits)
@@ -96,4 +105,4 @@ if launcher_jre_arch == 'gamecore'
endif
subdir('src')
-executable('l2su', launcher_srcs, dependencies : [curl_dep, jansson_dep, pcre2_dep], include_directories : [config_include_dir], override_options : {'c_std': 'c99'})
+executable('l2su', launcher_srcs, dependencies : [curl_dep, jansson_dep, pcre2_dep, libzip_dep], include_directories : [config_include_dir], override_options : {'c_std': 'c99'})
diff --git a/src/args.c b/src/args.c
new file mode 100644
index 0000000..7b307a8
--- /dev/null
+++ b/src/args.c
@@ -0,0 +1,206 @@
+#include "args.h"
+#include "l2su.h"
+#include "instance.h"
+#include "version.h"
+#include "macros.h"
+
+#include <jansson.h>
+#include <stdarg.h>
+#include <string.h>
+
+int l2_args__get_game_args(l2_subst_t *subst, const char *argsline, l2_version_feature_match_proc_t *feature_matcher, char ***out_args, size_t *out_nargs);
+int l2_args__get_args_json(l2_subst_t *subst, json_t *jargs, l2_version_feature_match_proc_t *feature_matcher, char ***out_args, size_t *out_nargs);
+
+int l2_args_get_game_args(json_t *version, l2_subst_t *subst, l2_version_feature_match_proc_t *feature_matcher, char ***out_args, size_t *out_nargs)
+{
+ const char *mc_args = NULL;
+ json_t *jargs = NULL;
+
+ if (json_unpack(version, "{s?:{s:o}, s?:s}", "arguments", "game", &jargs, "minecraftArguments", &mc_args) < 0) {
+ return -1;
+ }
+
+ if (jargs) {
+ if (!json_is_array(jargs)) return -1;
+
+
+ return l2_args__get_args_json(subst, jargs, feature_matcher, out_args, out_nargs);
+ } else if (mc_args) {
+ return l2_args__get_game_args(subst, mc_args, feature_matcher, out_args, out_nargs);
+ } else {
+ return -1;
+ }
+}
+
+int L2_SENTINEL l2_args__array_append(l2_subst_t *sp, char ***arr, size_t *nargs, ...)
+{
+ size_t nadd = 0;
+ const char *to_add;
+
+ va_list parg;
+ va_start(parg, nargs);
+ do {
+ to_add = va_arg(parg, const char *);
+ ++nadd;
+ } while (to_add);
+ --nadd;
+ va_end(parg);
+
+ char **temp = realloc(*arr, (*nargs + nadd) * sizeof(char *));
+ if (!temp) return -1;
+ *arr = temp;
+
+ memset(temp + *nargs, 0, sizeof(char *) * nadd);
+
+ va_start(parg, nargs);
+
+ for (; nadd; --nadd) {
+ if (l2_subst_apply(sp, va_arg(parg, const char *), temp + (*nargs)++) < 0) goto cleanup;
+ }
+
+ va_end(parg);
+ return 0;
+
+cleanup:
+ va_end(parg);
+ return -1;
+}
+
+int l2_args__get_game_args(l2_subst_t *subst, const char *argsline, l2_version_feature_match_proc_t *feature_matcher, char ***out_args, size_t *out_nargs)
+{
+ char **args = NULL;
+ size_t nargs = 0;
+
+ char *arg_start;
+ size_t sz;
+ L2_ASTRDUP(arg_start, sz, argsline);
+
+ for (char *argcur = arg_start; *argcur; ++argcur) {
+ if (*argcur == ' ') {
+ *argcur = '\0';
+ if (l2_args__array_append(subst, &args, &nargs, arg_start, NULL) < 0) goto cleanup;
+ arg_start = argcur + 1;
+ }
+ }
+
+ if (*arg_start && l2_args__array_append(subst, &args, &nargs, arg_start, NULL) < 0) goto cleanup;
+
+ if ((*feature_matcher)("is_demo_user", json_true())) {
+ if (l2_args__array_append(subst, &args, &nargs, "--demo", NULL) < 0) goto cleanup;
+ }
+
+ if ((*feature_matcher)("has_custom_resolution", json_true())) {
+ if (l2_args__array_append(subst, &args, &nargs, "--width", "${resolution_width}", "--height", "${resolution_height}", NULL) < 0) goto cleanup;
+ }
+
+ *out_args = args;
+ *out_nargs = nargs;
+ return 0;
+
+cleanup:
+ for (char **cur = args; nargs; --nargs, ++cur) {
+ free(*cur);
+ }
+
+ free(args);
+
+ return -1;
+}
+
+int l2_args_get_jvm_args(json_t *version, l2_subst_t *subst, l2_version_feature_match_proc_t *feature_matcher, char ***out_args, size_t *out_nargs)
+{
+ json_t *jarguments = json_object_get(version, "arguments");
+ if (!jarguments) {
+ char **args = NULL;
+ size_t nargs = 0;
+
+ if (l2_args__array_append(subst, &args, &nargs,
+#ifdef L2SU_LAUNCHER_IS_WINDOWS
+ "-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump",
+#endif
+#ifdef L2SU_LAUNCHER_IS_OSX
+ "-Xdock:icon=${asset=icons/minecraft.icns}",
+ "-Xdock:name=Minecraft",
+#endif
+ "-Djava.library.path=${natives_directory}",
+ "-Dminecraft.launcher.brand=${launcher_name}",
+ "-Dminecraft.launcher.version=${launcher_version}",
+ "-Dminecraft.client.jar=${primary_jar}",
+ "-cp",
+ "${classpath}",
+ NULL) < 0) {
+ return -1;
+ }
+
+ *out_args = args;
+ *out_nargs = nargs;
+
+ return 0;
+ } else if (!json_is_object(jarguments)) {
+ return -1;
+ }
+
+ json_t *jjvmargs = json_object_get(jarguments, "jvm");
+ if (!json_is_array(jjvmargs)) {
+ return -1;
+ }
+
+ return l2_args__get_args_json(subst, jjvmargs, feature_matcher, out_args, out_nargs);
+}
+
+int l2_args__get_args_json(l2_subst_t *subst, json_t *jargs, l2_version_feature_match_proc_t *feature_matcher, char ***out_args, size_t *out_nargs)
+{
+ char **args = NULL;
+ size_t nargs = 0;
+
+ size_t idx;
+ json_t *value;
+
+ json_array_foreach(jargs, idx, value) {
+ if (json_is_string(value)) {
+ if (l2_args__array_append(subst, &args, &nargs, json_string_value(value), NULL) < 0) goto cleanup;
+ } else if (json_is_object(value)) {
+ json_t *rules;
+ json_t *values;
+ if (json_unpack(value, "{s:o, s:o}", "rules", &rules, "value", &values) < 0) {
+ goto cleanup;
+ }
+
+ if (!json_is_array(rules)) goto cleanup;
+
+ switch (l2_version_check_rules(rules, feature_matcher)) {
+ case RULE_CHECK_ALLOW: {
+ json_t *argval;
+ size_t argidx;
+ if (json_is_string(values)) {
+ if (l2_args__array_append(subst, &args, &nargs, json_string_value(values), NULL) < 0) goto cleanup;
+ } else {
+ /* this code strongly prefers brevity over performance (breaking news) */
+ json_array_foreach(values, argidx, argval) {
+ if (!json_is_string(argval)) goto cleanup;
+ if (l2_args__array_append(subst, &args, &nargs, json_string_value(argval), NULL) < 0) goto cleanup;
+ }
+ }
+ break;
+ }
+ case RULE_CHECK_ERROR:
+ goto cleanup;
+ default:
+ continue;
+ }
+ }
+ }
+
+ *out_args = args;
+ *out_nargs = nargs;
+ return 0;
+
+cleanup:
+ for (char **cur = args; nargs; --nargs, ++cur) {
+ free(*cur);
+ }
+
+ free(args);
+
+ return -1;
+}
diff --git a/src/args.h b/src/args.h
new file mode 100644
index 0000000..3f15c61
--- /dev/null
+++ b/src/args.h
@@ -0,0 +1,13 @@
+#ifndef L2SU_ARGS_H_INCLUDED
+#define L2SU_ARGS_H_INCLUDED
+
+#include <jansson.h>
+#include <stddef.h>
+
+#include "l2su.h"
+#include "version.h"
+
+int l2_args_get_game_args(json_t *version, l2_subst_t *subst, l2_version_feature_match_proc_t *feature_matcher, char ***out_args, size_t *out_nargs);
+int l2_args_get_jvm_args(json_t *version, l2_subst_t *subst, l2_version_feature_match_proc_t *feature_matcher, char ***out_args, size_t *out_nargs);
+
+#endif /* include guard */
diff --git a/src/assets.c b/src/assets.c
index 7699d33..695e0ab 100644
--- a/src/assets.c
+++ b/src/assets.c
@@ -28,7 +28,9 @@ struct l2_assets__download_info {
l2_sha1_state_t digest_state;
size_t recv_size;
+#ifndef NDEBUG
char errbuf[CURL_ERROR_SIZE];
+#endif
struct l2_assets__download_info *next;
};
@@ -64,12 +66,14 @@ int l2_assets__download_asset_init(CURL *curl, void *user)
return -1;
}
- CMD_DEBUG("asset url %s", info->url);
-
curl_easy_setopt(curl, CURLOPT_URL, info->url);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, info);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &l2_assets__download_asset_dlcb);
+
+#ifndef NDEBUG
+ memset(&info->errbuf, 0, sizeof(info->errbuf));
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, info->errbuf);
+#endif
return 0;
}
@@ -84,7 +88,9 @@ int l2_assets__download_asset_complete(CURL *curl, CURLcode code, void *user)
if (code != CURLE_OK) {
CMD_WARN("Failed to download asset %s: %s", info->name, curl_easy_strerror(code));
- CMD_DEBUG("Info for %s: %s", info->name, info->errbuf);
+#ifndef NDEBUG
+ CMD_DEBUG("Debug info for %s: %s", info->name, info->errbuf);
+#endif
return -1;
}
@@ -238,6 +244,7 @@ int l2_assets__download_assets(json_t *asset_index, char **path)
res = -1;
goto cleanup;
}
+ CMD_INFO0("Successfully downloaded assets.");
} else {
CMD_INFO0("No assets to download.");
res = 0;
@@ -261,7 +268,6 @@ int l2_assets__download_assets(json_t *asset_index, char **path)
*path = resbasepath;
resbasepath = NULL; /* prevent out variable from being freed */
- CMD_INFO0("Successfully downloaded assets.");
res = 0;
cleanup:
diff --git a/src/cmd-version.c b/src/cmd-version.c
index bb02d90..4ee4309 100644
--- a/src/cmd-version.c
+++ b/src/cmd-version.c
@@ -4,6 +4,7 @@
#include "version.h"
#include "l2su.h"
#include "macros.h"
+#include "args.h"
#include <jansson.h>
#include <stdio.h>
@@ -87,6 +88,37 @@ unsigned cmd_version_install(struct l2_context_node *ctx, char **args)
CMD_FATAL0("Failed to download assets.");
}
+ char *nativesdir = NULL;
+ CMD_INFO0("Extracting natives...");
+ if ((res = l2_version_extract_natives(libs, &nativesdir)) != VERSION_SUCCESS) {
+ CMD_FATAL("Failed to extract natives: %s", l2_version_strerror(res));
+ }
+
+ char **game_args;
+ size_t ngame_args;
+ l2_subst_t *st;
+ l2_subst_init(&st);
+ l2_subst_add(st, "version_name", "1.8.9");
+ if (l2_args_get_game_args(js, st, &feat_match_cb, &game_args, &ngame_args) < 0) {
+ CMD_FATAL0("Failed to find game arguments");
+ }
+ for (size_t n = 0; n < ngame_args; ++n) {
+ CMD_DEBUG("arg: %s", game_args[n]);
+ free(game_args[n]);
+ }
+ free(game_args);
+
+ if (l2_args_get_jvm_args(js, st, &feat_match_cb, &game_args, &ngame_args) < 0) {
+ CMD_FATAL0("Failed to find JVM arguments");
+ }
+ for (size_t n = 0; n < ngame_args; ++n) {
+ CMD_DEBUG("jvm arg: %s", game_args[n]);
+ free(game_args[n]);
+ }
+ free(game_args);
+
+ l2_subst_free(st);
+
CMD_INFO("Assets base: %s", assetsbase);
free(assetsbase);
diff --git a/src/config.h.in b/src/config.h.in
index ffb2c41..5584e92 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -12,4 +12,8 @@
#mesondefine L2SU_LAUNCHER_ARCH
#mesondefine L2SU_JRE_ARCH
+#mesondefine L2SU_LAUNCHER_IS_LINUX
+#mesondefine L2SU_LAUNCHER_IS_OSX
+#mesondefine L2SU_LAUNCHER_IS_WINDOWS
+
#endif /* include guard */
diff --git a/src/l2su.h b/src/l2su.h
index 8c77e14..e46aa12 100644
--- a/src/l2su.h
+++ b/src/l2su.h
@@ -11,6 +11,7 @@
#include <time.h>
#include <curl/curl.h>
#include <stdio.h>
+#include <stdbool.h>
struct l2_user_paths {
const char *config;
@@ -33,6 +34,7 @@ extern struct tag_l2_state_t l2_state;
/* homecooked string methods */
char *l2_launcher_strapp(char *target, const char *src);
+bool l2_launcher_strpre(const char *pre, const char *text);
char *l2_launcher_sprintf_alloc(const char *fmt, ...) L2_FORMAT(printf, 1, 2);
diff --git a/src/launch.c b/src/launch.c
new file mode 100644
index 0000000..cc0721f
--- /dev/null
+++ b/src/launch.c
@@ -0,0 +1,31 @@
+#include "l2su.h"
+
+/* TODO launch struct */
+
+int l2_launch_fill_substitutor(l2_subst_t *st, void *reserved, json_t *version, struct l2_instance *inst)
+{
+#define L2_LAUNCH_ADD_SUB(_st, _name, _val) \
+ if (l2_subst_add(_st, _name, _val) < 0) return -1
+
+ const char *ver_name;
+ if (json_unpack(version, "{s:s}", "id", &ver_name) < 0) {
+ return -1;
+ }
+
+ /* auth_access_token */
+ /* user_properties */
+ /* user_property_map */
+ L2_LAUNCH_ADD_SUB(st, "auth_session", "-");
+
+ L2_LAUNCH_ADD_SUB(st, "auth_player_name", "figboot");
+ L2_LAUNCH_ADD_SUB(st, "auth_uuid", "00000000000000000000000000000000");
+ L2_LAUNCH_ADD_SUB(st, "user_type", "legacy");
+
+ L2_LAUNCH_ADD_SUB(st, "profile_name", inst->name);
+ L2_LAUNCH_ADD_SUB(st, "version_name", ver_name);
+ L2_LAUNCH_ADD_SUB(st, "game_directory", ".");
+
+
+ return 0;
+#undef L2_LAUNCH_ADD_SUB
+}
diff --git a/src/launcherutil.c b/src/launcherutil.c
index 2db6238..e1e8c40 100644
--- a/src/launcherutil.c
+++ b/src/launcherutil.c
@@ -36,6 +36,14 @@ char *l2_launcher_strapp(char *buf, const char *src)
return ret;
}
+bool l2_launcher_strpre(const char *pre, const char *text)
+{
+ while (*pre) {
+ if (*(pre++) != *(text++)) return false;
+ }
+ return true;
+}
+
char *l2_launcher_sprintf_alloc(const char *fmt, ...)
{
va_list pva;
diff --git a/src/macros.h b/src/macros.h
index 91924ca..668816c 100644
--- a/src/macros.h
+++ b/src/macros.h
@@ -46,7 +46,10 @@
#define L2_URL_RESOURCES_BASE "https://resources.download.minecraft.net"
#ifdef __GNUC__
-#define L2_FORMAT(_flavor, _stridx, _argidx) __attribute__((format (_flavor, _stridx, _argidx)))
+#define L2_GNU_ATTRIBUTE(_x) __attribute__(_x)
+
+#define L2_FORMAT(_flavor, _stridx, _argidx) L2_GNU_ATTRIBUTE((format (_flavor, _stridx, _argidx)))
+#define L2_SENTINEL L2_GNU_ATTRIBUTE((sentinel))
#else
#define L2_FORMAT(_unused1, _unused2, _unused3)
#endif
diff --git a/src/meson.build b/src/meson.build
index 86728a6..9c9e545 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -1,4 +1,4 @@
-launcher_srcs = files('l2su.c', 'command.c', 'cmd-instance.c', 'uuid/uuid.c', 'launcherutil.c', 'instance.c', 'cmd-version.c', 'digest/sha1.c', 'version.c', 'subst.c', 'downloadpool.c', 'assets.c')
+launcher_srcs = files('l2su.c', 'command.c', 'cmd-instance.c', 'uuid/uuid.c', 'launcherutil.c', 'instance.c', 'cmd-version.c', 'digest/sha1.c', 'version.c', 'subst.c', 'downloadpool.c', 'assets.c', 'args.c')
configure_file(input : 'config.h.in', output : 'config.h', configuration : config_data)
config_include_dir = include_directories('.')
diff --git a/src/version.c b/src/version.c
index 3568cf2..af7b56e 100644
--- a/src/version.c
+++ b/src/version.c
@@ -17,6 +17,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include <pcre2.h>
+#include <zip.h>
const char *const l2_version__messages[] = {
"Success",
@@ -27,6 +28,7 @@ const char *const l2_version__messages[] = {
"Error downloading version",
"Version not found",
"Max recursion depth exceeded",
+ "JAR format error",
NULL
};
@@ -971,13 +973,7 @@ unsigned l2_version__gen_one_library(json_t *lib, l2_subst_t *subst, struct l2_v
goto cleanup;
}
- if (classifier) {
- retlib->extract.extracttype = EXTRACT_OLD;
- } else if (has_class) {
- retlib->extract.extracttype = EXTRACT_NEW;
- } else {
- retlib->extract.extracttype = EXTRACT_NONE;
- }
+ retlib->extract.extract = !!json_is_object(json_object_get(lib, "natives"));
/* first, find the URL of the library */
json_t *jurl = json_object_get(lib, "url");
@@ -1367,3 +1363,141 @@ unsigned l2_version_download_jar(json_t *version, const char *specifier, char **
*path = pathstr;
return VERSION_SUCCESS;
}
+
+unsigned l2_version__extract_one_file(zip_t *archive, const char *dbg_libname, char **exclude, const char *template, zip_int64_t idx)
+{
+#define EXTRACT_READBUF_SIZE (4096)
+ unsigned res = VERSION_SUCCESS;
+ char *fname;
+ size_t sz;
+
+ FILE *ofile = NULL;
+ zip_file_t *file = NULL;
+ unsigned char buf[EXTRACT_READBUF_SIZE];
+
+ const char *entname = zip_get_name(archive, idx, ZIP_FL_ENC_GUESS);
+ if (!entname) {
+ CMD_WARN("Failed to get entry name in library %s: %s", dbg_libname, zip_strerror(archive));
+ res = VERSION_EZIP;
+ goto cleanup;
+ }
+
+ if (exclude) {
+ for (char **cur = exclude; *cur; ++cur) {
+ if (l2_launcher_strpre(*cur, entname)) {
+ res = VERSION_SUCCESS;
+ goto cleanup;
+ }
+ }
+ }
+
+ file = zip_fopen_index(archive, idx, 0);
+ if (!file) {
+ CMD_WARN("Failed to open entry in library %s: %s", dbg_libname, zip_strerror(archive));
+ res = VERSION_EZIP;
+ goto cleanup;
+ }
+
+ L2_ASPRINTF(fname, sz, "%s/%s", template, entname);
+ if (l2_launcher_mkdir_parents_ex(fname, 1) < 0) { /* TODO: maybe don't repeatedly check if /tmp exists lol */
+ CMD_WARN("Failed to extract entry %s from library %s: error making directory", entname, dbg_libname);
+ res = VERSION_ERRNO;
+ goto cleanup;
+ }
+
+ ofile = fopen(fname, "wb");
+ if (!ofile) {
+ CMD_WARN("Failed to open %s to extract %s from library %s: %s", fname, entname, dbg_libname, strerror(errno));
+ res = VERSION_ERRNO;
+ goto cleanup;
+ }
+
+ zip_int64_t nread;
+ while ((nread = zip_fread(file, buf, EXTRACT_READBUF_SIZE)) > 0) {
+ if (fwrite(buf, 1, nread, ofile) < (size_t)nread) {
+ CMD_WARN("Partial write while extracting %s from library %s", entname, dbg_libname);
+ res = VERSION_ERRNO;
+ goto cleanup;
+ }
+ }
+
+ CMD_DEBUG("Extracted %s for library %s", entname, dbg_libname);
+ res = VERSION_SUCCESS;
+
+cleanup:
+ if (file) zip_fclose(file);
+ if (ofile) fclose(ofile);
+ return res;
+
+#undef EXTRACT_READBUF_SIZE
+}
+
+unsigned l2_version__extract_lib_natives(struct l2_version_library *lib, const char *template)
+{
+ int err = 0;
+ unsigned res = VERSION_SUCCESS;
+ zip_t *archive = zip_open(lib->fullpath, ZIP_RDONLY, &err);
+
+ if (!archive) {
+ zip_error_t ze;
+ zip_error_init_with_code(&ze, err);
+ CMD_WARN("Failed to open library jar %s: %s", lib->artifactpath, zip_error_strerror(&ze));
+ zip_error_fini(&ze);
+ return VERSION_EZIP;
+ }
+
+ zip_int64_t nentry = zip_get_num_entries(archive, 0);
+ for (zip_int64_t idx = 0; idx < nentry; ++idx) {
+ if ((res = l2_version__extract_one_file(archive, lib->artifactpath, lib->extract.exclude, template, idx)) != VERSION_SUCCESS) {
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ if (archive) {
+ zip_discard(archive);
+ }
+
+ return res;
+}
+
+unsigned l2_version_extract_natives(struct l2_version_library *libs, char **out_nativesdir)
+{
+ char template[] = "/tmp/l2su-natives-XXXXXX"; /* TODO: make portable */
+ char *nativesdir;
+
+ for (struct l2_version_library *cur = libs; cur; cur = cur->next) {
+ if (cur->extract.extract) goto found;
+ }
+
+ CMD_INFO0("Not extracting natives, there are no libraries that require it.");
+ return 0;
+
+found:
+
+ if (!mkdtemp(template)) {
+ CMD_WARN("Failed to create directory for extracted natives: %s", strerror(errno));
+ return VERSION_ERRNO;
+ }
+
+ nativesdir = strdup(template);
+ if (!nativesdir) {
+ return VERSION_EALLOC;
+ }
+
+ unsigned res;
+ for (struct l2_version_library *cur = libs; cur; cur = cur->next) {
+ if (!cur->extract.extract) continue;
+ if ((res = l2_version__extract_lib_natives(cur, template)) != VERSION_SUCCESS) {
+ goto cleanup;
+ }
+ }
+
+ res = VERSION_SUCCESS;
+ *out_nativesdir = nativesdir;
+ nativesdir = NULL;
+
+cleanup:
+ free(nativesdir);
+ return res;
+}
diff --git a/src/version.h b/src/version.h
index c008481..89341cb 100644
--- a/src/version.h
+++ b/src/version.h
@@ -14,7 +14,8 @@ enum {
VERSION_ERRNO,
VERSION_EDOWNLOAD,
VERSION_ENOTFOUND,
- VERSION_ERECURSE
+ VERSION_ERECURSE,
+ VERSION_EZIP
};
struct l2_version_remote {
@@ -64,11 +65,7 @@ struct l2_version_library {
size_t size;
struct {
- enum {
- EXTRACT_NONE, /* do not extract anything */
- EXTRACT_OLD, /* extract whole jar, preserving entries that are not excluded */
- EXTRACT_NEW /* extract only .dll, .so, .dylib from jar */
- } extracttype;
+ bool extract;
char **exclude;
} extract;
@@ -101,4 +98,6 @@ void l2_version_free_libraries(struct l2_version_library *libs);
unsigned l2_version_download_jar(json_t *version, const char *specifier, char **path);
+unsigned l2_version_extract_natives(struct l2_version_library *libs, char **nativesdir);
+
#endif /* include guard */