#include "args.h" #include "l2su.h" #include "instance.h" #include "version.h" #include "macros.h" #include #include #include 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; }