From 04aba22e167422ba457a460246baa1c789671d0b Mon Sep 17 00:00:00 2001 From: ac-stef Date: Mon, 31 Aug 2015 15:38:35 +0200 Subject: [PATCH] more commands to manage zipped mod packages addzipmod zipname Add the zip package file "mods/zipname.zip" to the virtual file system. Only files below the path "packages/" are added (and also files below "config/", if zipname starts with "###"). If the size of the zip file is below zipcachemaxsize, the whole zip file is cached in memory. (Un-cached zip files are kept open at all time, so caching keeps the number of simultaneously opened files lower.) zipmodremove zipname Removes one zip file from the virtual file system. zipmodclear Removes all zip files from the virtual file system. zipmodlist [what] Lists zip files in "mods/". By default, or if "what" is "all", all zips are listed. If "what" is "active", only those zips, that are already in use, are listed. If "what" is "inactive", only the unused zip files are listed. zipmodgetdesc zipfile Reads and returns the first 11 lines from the file "desc.txt" in the named zip file. The first line is supposed to contain a descriptive title for the zip (for use in menus) and the next 10 lines should contain a more detailed description (also for use in menus). The command also unpacks "preview.jpg" from the zip and mounts it as a temporary file under the name "packages/modpreviews/zipname.jpg". zipmodgetfiles zipfile Returns the list of files contained in a zip file. zipmodgetrevision zipfile Returns the revision number of the zip file. The number is supposed to be part of a filename: "revision_n". If no such file is found in the zip file, the return value is zero. The content of the revision file is not relevant and a file size of zero is recommended. DOCREF addzipmod zipmodremove zipmodclear zipcachemaxsize DOCREF zipmodlist zipmodgetdesc zipmodgetfiles zipmodgetrevision --- config/scripts.cfg | 1 + source/src/protocol.h | 2 +- source/src/zip.cpp | 153 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 151 insertions(+), 5 deletions(-) diff --git a/config/scripts.cfg b/config/scripts.cfg index 0230c04a..e2a43f8a 100644 --- a/config/scripts.cfg +++ b/config/scripts.cfg @@ -84,6 +84,7 @@ looplist [ ] [ cmd options ] [ listcomplete $cmd (listoptions $options) ] listcomplete getvarrange "min max default" +looplist [ addzipmod zipmodremove zipmodgetdesc ] cmd [complete $cmd "mods" zip] // set up list of skymaps push skies "" diff --git a/source/src/protocol.h b/source/src/protocol.h index 3da9cb80..b16d3120 100644 --- a/source/src/protocol.h +++ b/source/src/protocol.h @@ -175,4 +175,4 @@ enum #define FTXT__GLOBALNAME (FTXT_NOWHITE | FTXT_NOCOLOR | FTXT_FILLBLANKS) #define FTXT__MEDIAFILENAME (FTXT_FILENAME) #define FTXT__MEDIAFILEPATH (FTXT_FILENAME | FTXT_ALLOWSLASH) - +#define FTXT__ZIPDESC (FTXT_NOWHITE | FTXT_ALLOWBLANKS | FTXT_TABTOBLANK | FTXT_NOCOLOR | FTXT_SAFECS) diff --git a/source/src/zip.cpp b/source/src/zip.cpp index 5959ac02..a906dac8 100644 --- a/source/src/zip.cpp +++ b/source/src/zip.cpp @@ -477,8 +477,6 @@ void listmemfiles() COMMAND(listmemfiles, ""); #endif -#endif - // manage zipped mod packages in subdirectory "mods/" including description and preview images // zip packages are restricted to contain files below "packages/" only - unless the zip filename starts with "###", which additionally allows files below "config/" @@ -488,8 +486,6 @@ ziparchive *findzip(const char *name) return NULL; } -#ifndef STANDALONE - const char *fixzipname(char *name) // check, if valid path + filename, based on mods/, return NULL if invalid { string tmp; @@ -556,6 +552,155 @@ void addzipmod(char *name) } COMMAND(addzipmod, "s"); +void zipmodremove(char *name) +{ + const char *pname = fixzipname(name); + ziparchive *exists = pname ? findzip(name) : NULL; + if(!exists) + { + conoutf("zip %s is not loaded", name); + return; + } + if(exists->openfiles) + { + conoutf("zip %s has %d open files", name, exists->openfiles); + return; + } + conoutf("removed zip %s", exists->name); + archives.removeobj(exists); + rebuildzipfilehashtable(); + delete exists; +} +COMMAND(zipmodremove, "s"); + +void zipmodclear() +{ + loopvrev(archives) + { + ziparchive *a = archives[i]; + if(a->openfiles) + { + conoutf("zip %s has %d open files", a->name, a->openfiles); + continue; + } + delete archives.remove(i); + } + rebuildzipfilehashtable(); +} +COMMAND(zipmodclear, ""); + +void zipmodlist(char *which) // "active", "inactive", "all"(default) +{ + vector res; + if(!strcasecmp(which, "active")) + { + loopv(archives) cvecprintf(res, "%s ", archives[i]->name); + } + else + { + bool inactive = !strcasecmp(which, "inactive"); + vector files; + listfilesrecursive("mods", files); + files.sort(stringsort); + loopvrev(files) if(files.inrange(i + 1) && !strcmp(files[i], files[i + 1])) delstring(files.remove(i + 1)); // remove doubles + loopv(files) + { + char *f = files[i]; + if(!strncmp(f, "mods/", 5) && !strncmp(f + strlen(f) - 4, ".zip", 4)) + { + f += 5; + f[strlen(f) - 4] = '\0'; + if(fixzipname(f) && (!inactive || !findzip(f))) cvecprintf(res, "%s ", f); + } + } + files.deletearrays(); + } + if(res.length()) res.last() = '\0'; + else res.add('\0'); + result(res.getbuf()); +} +COMMAND(zipmodlist, "s"); + +const char *desctxt = "desc.txt", *previewjpg = "preview.jpg", *modrev = "revision_"; // special files in zip containing description or preview + +void zipmodgetdesc(char *name) // open zip, read desc.txt and mount preview picture +{ + const char *pname = fixzipname(name); + stream *f = pname ? openfile(pname, "rb") : NULL, *zf = NULL; + vector files; + vector res; + void *mz = zipmanualopen(f, files); + string tmp; + if(!f || !mz) conoutf("failed to read/open zip file %s", pname); + else + { + loopv(files) + { + if(!strcmp(files[i], desctxt)) + { + if((zf = zipmanualstream(mz, i))) loopk(11) + { + zf->getline(tmp, MAXSTRLEN / 2); + filtertext(tmp, tmp, FTXT__ZIPDESC); + if(*tmp) cvecprintf(res, "%s\n", escapestring(tmp)); + else break; + } + } + else if(!strcmp(files[i], previewjpg)) + { + vector *v = new vector; + zf = openvecfile(v); + int got = zipmanualread(mz, i, zf, 128 * 1024); // max. file size for preview.jpg is 128k + formatstring(tmp)("packages/modpreviews/%s.jpg", name); + addmemfile(tmp, v->getbuf(), got); + if(got == 128 * 1024) conoutf("\f3preview.jpg in zip file %s exceeds maximum file size: file truncated", pname); + } + DELETEP(zf); + } + zipmanualclose(mz); + } + if(res.length()) res.last() = '\0'; + else res.add('\0'); + result(res.getbuf()); +} +COMMAND(zipmodgetdesc, "s"); + +void zipmodgetfiles(char *name) // open zip, read list of files +{ + const char *pname = fixzipname(name); + stream *f = pname ? openfile(pname, "rb") : NULL; + vector files; + vector res; + void *mz = zipmanualopen(f, files); + if(!f || !mz) conoutf("failed to read/open zip file %s", pname); + else + { + loopv(files) cvecprintf(res, "%s\n", escapestring(files[i])); + zipmanualclose(mz); + } + if(res.length()) res.last() = '\0'; + else res.add('\0'); + result(res.getbuf()); +} +COMMAND(zipmodgetfiles, "s"); + +void zipmodgetrevision(char *name) // open zip, read list of files +{ + const char *pname = fixzipname(name); + stream *f = pname ? openfile(pname, "rb") : NULL; + vector files; + int res = 0, modrevlen = (int)strlen(modrev); + void *mz = zipmanualopen(f, files); + if(!f || !mz) conoutf("failed to read/open zip file %s", pname); + else + { + loopv(files) if(!strncasecmp(files[i], modrev, modrevlen)) res = atoi(files[i] + modrevlen); + zipmanualclose(mz); + } + intret(res); +} +COMMAND(zipmodgetrevision, "s"); + void writezipmodconfig(stream *f) { f->printf("zipcachemaxsize %d\n", zipcachemaxsize);