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
This commit is contained in:
ac-stef
2015-09-07 14:53:56 +02:00
parent 394ddd12f7
commit 04aba22e16
3 changed files with 151 additions and 5 deletions
+149 -4
View File
@@ -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<char> res;
if(!strcasecmp(which, "active"))
{
loopv(archives) cvecprintf(res, "%s ", archives[i]->name);
}
else
{
bool inactive = !strcasecmp(which, "inactive");
vector<char *> 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<const char *> files;
vector<char> 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<uchar> *v = new vector<uchar>;
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<const char *> files;
vector<char> 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<const char *> 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);