static bool add_files_to_zip_renamed(const char *zipfile, const char *dir, const char *pat, const char *newdir, const char *newname, const char *newext, bool compress, bool executable, uint8_t platform) { CSimpleGlobTempl<char> glob(SG_GLOB_ONLYFILE); char *pattern = am_format("%s%c%s", dir, AM_PATH_SEP, pat); glob.Add(pattern); free(pattern); for (int n = 0; n < glob.FileCount(); ++n) { char *file = glob.File(n); size_t len; void *buf = am_read_file(file, &len); if (buf == NULL) return false; char *name; if (newname == NULL) { name = am_format("%s/%s", newdir, file + strlen(dir) + 1); } else if (newext == NULL) { name = am_format("%s/%s", newdir, newname); } else { name = am_format("%s/%s%s", newdir, newname, newext); } if (!mz_zip_add_mem_to_archive_file_in_place(zipfile, name, buf, len, "", 0, compress ? MZ_BEST_COMPRESSION : 0, executable ? 0100755 : 0100644, platform)) { free(buf); free(name); fprintf(stderr, "Error: failed to add %s to archive\n", file); return false; } free(name); free(buf); } return true; }
static bool create_ios_lproj_dirs(const char *zipname, const char *dir, export_config *conf) { const char *ptr = conf->supported_languages; char lang[100]; while (*ptr == ' ') ptr++; while (*ptr != 0) { int i = 0; while (*ptr != 0 && *ptr != ',') { if (i >= 100) { fprintf(stderr, "conf.lua: language id too long\n"); return false; } lang[i] = *ptr; i++; ptr++; } lang[i] = 0; char *name = am_format("%s/%s.lproj/x", dir, lang); if (!mz_zip_add_mem_to_archive_file_in_place(zipname, name, "x", 1, "", 0, 0, 0100644, ZIP_PLATFORM_UNIX)) { free(name); return false; } free(name); while (*ptr == ',' || *ptr == ' ') ptr++; } return true; }
static bool build_ios_export(export_config *conf) { char *zipname = get_export_zip_name(conf, "ios"); if (am_file_exists(zipname)) am_delete_file(zipname); char *binpath = get_bin_path(conf, "ios"); if (binpath == NULL) return true; if (!create_ios_info_plist(binpath, AM_TMP_DIR AM_PATH_SEP_STR "Info.plist", conf)) return false; if (!create_ios_pkginfo(AM_TMP_DIR AM_PATH_SEP_STR "PkgInfo")) return false; if (!create_ios_icon_files(AM_TMP_DIR, conf)) return false; if (!create_ios_launch_images(AM_TMP_DIR, conf)) return false; const char *name = conf->shortname; char *appdir = am_format("Payload/%s.app", name); bool ok = add_files_to_dist(zipname, am_opt_data_dir, "*.txt", appdir, NULL, NULL, true, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, binpath, "amulet_license.txt", appdir, NULL, NULL, true, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, binpath, "amulet", appdir, name, NULL, true, true, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, ".", conf->pakfile, appdir, "data.pak", NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "Info.plist", appdir, NULL, NULL, true, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "PkgInfo", appdir, NULL, NULL, true, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "Icon.png", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "*****@*****.**", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "icon40.png", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "icon57.png", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "icon72.png", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "icon76.png", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "icon80.png", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "icon114.png", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "icon120.png", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "icon144.png", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "icon152.png", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "icon180.png", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "iTunesArtwork", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "Default.png", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "*****@*****.**", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "*****@*****.**", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "*****@*****.**", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "*****@*****.**", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "Default-Landscape@2x~ipad.png", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "Default-Landscape~ipad.png", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "Default-Portrait@2x~ipad.png", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && add_files_to_dist(zipname, AM_TMP_DIR, "Default-Portrait~ipad.png", appdir, NULL, NULL, false, false, ZIP_PLATFORM_UNIX) && create_ios_lproj_dirs(zipname, appdir, conf) && true; free(appdir); am_delete_file(AM_TMP_DIR AM_PATH_SEP_STR "Info.plist"); am_delete_file(AM_TMP_DIR AM_PATH_SEP_STR "PkgInfo"); printf("Generated %s\n", zipname); free(zipname); free(binpath); return ok; }
static char *get_bin_path(export_config *conf, const char *platform) { const char *builds_path = conf->basepath; if (strcmp(conf->basepath, "/usr/local/bin/") == 0) { builds_path = "/usr/local/share/amulet/"; } else if (strcmp(conf->basepath, "/usr/bin/") == 0) { builds_path = "/usr/share/amulet/"; } char *bin_path = am_format("%sbuilds/%s/%s/%s/bin", builds_path, platform, conf->luavm, conf->grade); if (!am_file_exists(bin_path)) { free(bin_path); return NULL; } return bin_path; }
static char *get_bin_path(export_config *conf, const char *platform) { const char *builds_path = conf->basepath; if (strcmp(conf->basepath, "/usr/local/bin/") == 0) { builds_path = "/usr/local/share/amulet/"; } else if (strcmp(conf->basepath, "/usr/bin/") == 0) { builds_path = "/usr/share/amulet/"; } char *bin_path = am_format("%sbuilds/%s/%s/%s/bin", builds_path, platform, conf->luavm, conf->grade); if (!am_file_exists(bin_path)) { fprintf(stderr, "Error: export configuration %s/%s/%s not available in your installation.\n", platform, conf->luavm, conf->grade); fprintf(stderr, "(the path %s does not exist)\n", bin_path); free(bin_path); return NULL; } return bin_path; }
static bool resize_image(void *img_data, int in_w, int in_h, const char *dir, const char *filename, int out_w, int out_h) { void *out_data = malloc(out_w * out_h * 4); double in_aspect = (double)in_w / (double)in_h; double out_aspect = (double)out_w / (double)out_h; if (fabs(in_aspect - out_aspect) < 0.05) { stbir_resize_uint8((const unsigned char*)img_data, in_w, in_h, 0, (unsigned char *)out_data, out_w, out_h, 0, 4); } else { uint32_t *pxl_data = (uint32_t*)out_data; uint32_t bg = ((uint32_t*)img_data)[0]; for (int i = 0; i < out_w * out_h; i++) { pxl_data[i] = bg; } double scaling_x = (double)out_w / (double)in_w; double scaling_y = (double)out_h / (double)in_h; double scaling = fmin(scaling_x, scaling_y); int scaled_w = (int)floor((double)in_w * scaling); int scaled_h = (int)floor((double)in_h * scaling); int x_os = (out_w - scaled_w) / 2; int y_os = (out_h - scaled_h) / 2; void *tmp_data = malloc(scaled_w * scaled_h * 4); stbir_resize_uint8((const unsigned char*)img_data, in_w, in_h, 0, (unsigned char *)tmp_data, scaled_w, scaled_h, 0, 4); uint32_t *tmp_pxl_data = (uint32_t*)tmp_data; for (int i = 0; i < scaled_w; i++) { for (int j = 0; j < scaled_h; j++) { pxl_data[(i + x_os) + (j + y_os) * out_w] = tmp_pxl_data[i + j * scaled_w]; } } free(tmp_data); } size_t len; void *png_data = tdefl_write_image_to_png_file_in_memory_ex( out_data, out_w, out_h, 4, &len, MZ_DEFAULT_LEVEL, 0); free(out_data); char *path = am_format("%s%c%s", dir, AM_PATH_SEP, filename); FILE *f = fopen(path, "wb"); free(path); if (f == NULL) { fprintf(stderr, "Error: cannot open %s for writing\n", filename); return false; } fwrite(png_data, len, 1, f); fclose(f); free(png_data); return true; }
static bool build_data_pak_2(int level, const char *rootdir, const char *dir, const char *pakfile) { if (level >= RECURSE_LIMIT) { fprintf(stderr, "Error: maximum directory recursion depth reached (%d)\n", RECURSE_LIMIT); return false; } if (!add_data_files_to_zip(pakfile, rootdir, dir)) { return false; } CSimpleGlobTempl<char> glob(SG_GLOB_ONLYDIR | SG_GLOB_NODOT); char *pattern = am_format("%s%c*", dir, AM_PATH_SEP); glob.Add(pattern); free(pattern); for (int n = 0; n < glob.FileCount(); ++n) { char *subdir = glob.File(n); if (!build_data_pak_2(level + 1, rootdir, subdir, pakfile)) { return false; } } return true; }
static bool add_matching_files_to_zip(const char *zipfile, const char *rootdir, const char *dir, const char *pat, bool compress, uint8_t platform) { CSimpleGlobTempl<char> glob(SG_GLOB_ONLYFILE); char *pattern = am_format("%s%c%s", dir, AM_PATH_SEP, pat); glob.Add(pattern); free(pattern); for (int n = 0; n < glob.FileCount(); ++n) { char *file = glob.File(n); size_t len; void *buf = am_read_file(file, &len); if (buf == NULL) return false; if (!mz_zip_add_mem_to_archive_file_in_place(zipfile, file + strlen(rootdir) + 1, buf, len, "", 0, compress ? MZ_BEST_COMPRESSION : 0, 0100644, platform)) { free(buf); fprintf(stderr, "Error: failed to add %s to archive\n", file); return false; } free(buf); } return true; }
static bool file_exists(const char *filename) { char *path = am_format("%s%c%s", am_opt_data_dir, AM_PATH_SEP, filename); bool exists = am_file_exists(path); free(path); return exists; }
static char *get_export_zip_name(export_config *conf, const char *platname) { return am_format("%s-%s-%s.zip", conf->appshortname, conf->appversion, platname); }
static bool create_ios_info_plist(const char *binpath, const char *filename, export_config *conf) { FILE *f = fopen(filename, "w"); if (f == NULL) { fprintf(stderr, "Error: unable to create file %s", filename); return false; } char *template_filename = am_format("%s%c%s", binpath, AM_PATH_SEP, "Info.plist"); char *template_fmt = (char*)am_read_file(template_filename, NULL); free(template_filename); if (template_fmt == NULL) return false; const char *orientation_xml = ""; switch (conf->orientation) { case AM_DISPLAY_ORIENTATION_ANY: orientation_xml = "<key>UISupportedInterfaceOrientations</key>" "<array>" "<string>UIInterfaceOrientationPortrait</string>" "<string>UIInterfaceOrientationPortraitUpsideDown</string>" "<string>UIInterfaceOrientationLandscapeLeft</string>" "<string>UIInterfaceOrientationLandscapeRight</string>" "</array>" "<key>UISupportedInterfaceOrientations~ipad</key>" "<array>" "<string>UIInterfaceOrientationPortrait</string>" "<string>UIInterfaceOrientationPortraitUpsideDown</string>" "<string>UIInterfaceOrientationLandscapeLeft</string>" "<string>UIInterfaceOrientationLandscapeRight</string>" "</array>"; break; case AM_DISPLAY_ORIENTATION_PORTRAIT: orientation_xml = "<key>UISupportedInterfaceOrientations</key>" "<array>" "<string>UIInterfaceOrientationPortrait</string>" "<string>UIInterfaceOrientationPortraitUpsideDown</string>" "</array>" "<key>UISupportedInterfaceOrientations~ipad</key>" "<array>" "<string>UIInterfaceOrientationPortrait</string>" "<string>UIInterfaceOrientationPortraitUpsideDown</string>" "</array>"; break; case AM_DISPLAY_ORIENTATION_LANDSCAPE: orientation_xml = "<key>UISupportedInterfaceOrientations</key>" "<array>" "<string>UIInterfaceOrientationLandscapeLeft</string>" "<string>UIInterfaceOrientationLandscapeRight</string>" "</array>" "<key>UISupportedInterfaceOrientations~ipad</key>" "<array>" "<string>UIInterfaceOrientationLandscapeLeft</string>" "<string>UIInterfaceOrientationLandscapeRight</string>" "</array>"; break; } fprintf(f, template_fmt, conf->title, // CFBundleName conf->display_name, // CFBundleDisplayName conf->dev_region, // CFBundleDevelopmentRegion conf->version, // CFBundleShortVersionString conf->version, // CFBundleVersion conf->shortname, // CFBundleExecutable conf->appid, // CFBundleIdentifier orientation_xml ); fclose(f); return true; }
static char *get_export_zip_name(export_config *conf, const char *platname) { const char *ext = "zip"; if (strcmp(platname, "ios") == 0) ext = "ipa"; return am_format("%s-%s-%s.%s", conf->shortname, conf->version, platname, ext); }