diff options
author | jan.nijtmans <nijtmans@users.sourceforge.net> | 2017-07-14 15:03:29 (GMT) |
---|---|---|
committer | jan.nijtmans <nijtmans@users.sourceforge.net> | 2017-07-14 15:03:29 (GMT) |
commit | e213c36286fab987488d2dc11622b92813a51e10 (patch) | |
tree | ec2a3d4d6ea5e98a3965f1a60ffe366661660ed8 | |
parent | 874dc1515544af77f4b08dcde6b16df18db09c87 (diff) | |
parent | 80272e6e9728da345d243a0af6def26dbc86b255 (diff) | |
download | tcl-e213c36286fab987488d2dc11622b92813a51e10.zip tcl-e213c36286fab987488d2dc11622b92813a51e10.tar.gz tcl-e213c36286fab987488d2dc11622b92813a51e10.tar.bz2 |
merge rfe-6c0d7aec67
Adapt upstream Androwish improvements
-rw-r--r-- | generic/tclInt.h | 2 | ||||
-rw-r--r-- | generic/tclPathObj.c | 88 | ||||
-rw-r--r-- | generic/zipfs.c | 91 |
3 files changed, 120 insertions, 61 deletions
diff --git a/generic/tclInt.h b/generic/tclInt.h index ed867d8..2f830cc 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -4359,7 +4359,7 @@ MODULE_SCOPE void TclDbInitNewObj(Tcl_Obj *objPtr, const char *file, #define TclUtfToUniChar(str, chPtr) \ ((((unsigned char) *(str)) < 0xC0) ? \ - ((*(chPtr) = (Tcl_UniChar) *(str)), 1) \ + ((*(chPtr) = (unsigned char) *(str)), 1) \ : Tcl_UtfToUniChar(str, chPtr)) /* diff --git a/generic/tclPathObj.c b/generic/tclPathObj.c index 60aafdf..8ee4869 100644 --- a/generic/tclPathObj.c +++ b/generic/tclPathObj.c @@ -13,6 +13,7 @@ #include "tclInt.h" #include "tclFileSystem.h" +#include <assert.h> /* * Prototypes for functions defined later in this file. @@ -849,18 +850,20 @@ TclJoinPath( int elements, Tcl_Obj * const objv[]) { - Tcl_Obj *res = NULL; /* Resulting path object (container of join) */ - Tcl_Obj *elt; /* Path part (result if returns part of path) */ + Tcl_Obj *res = NULL; int i; const Tcl_Filesystem *fsPtr = NULL; - for (i = 0; i < elements; i++) { - int driveNameLength, strEltLen, length; - Tcl_PathType type; - char *strElt, *ptr; - Tcl_Obj *driveName = NULL; - - elt = objv[i]; + assert ( elements >= 0 ); + + if (elements == 0) { + return Tcl_NewObj(); + } + + assert ( elements > 0 ); + + if (elements == 2) { + Tcl_Obj *elt = objv[0]; /* * This is a special case where we can be much more efficient, where @@ -869,18 +872,17 @@ TclJoinPath( * object which can be normalized more efficiently. Currently we only * use the special case when we have exactly two elements, but we * could expand that in the future. - * - * Bugfix [a47641a0]. TclNewFSPathObj requires first argument - * to be an absolute path. Added a check for that elt is absolute. + * + * Bugfix [a47641a0]. TclNewFSPathObj requires first argument + * to be an absolute path. Added a check for that elt is absolute. */ - if ((i == (elements-2)) && (i == 0) - && (elt->typePtr == &tclFsPathType) + if ((elt->typePtr == &tclFsPathType) && !((elt->bytes != NULL) && (elt->bytes[0] == '\0')) && TclGetPathType(elt, NULL, NULL, NULL) == TCL_PATH_ABSOLUTE) { - Tcl_Obj *tailObj = objv[i+1]; + Tcl_Obj *tailObj = objv[1]; + Tcl_PathType type = TclGetPathType(tailObj, NULL, NULL, NULL); - type = TclGetPathType(tailObj, NULL, NULL, NULL); if (type == TCL_PATH_RELATIVE) { const char *str; int len; @@ -893,7 +895,7 @@ TclJoinPath( * the base itself is just fine! */ - goto partReturn; /* return elt; */ + return elt; } /* @@ -914,20 +916,17 @@ TclJoinPath( */ if ((tclPlatform != TCL_PLATFORM_WINDOWS) - || (strchr(Tcl_GetString(elt), '\\') == NULL) - ) { + || (strchr(Tcl_GetString(elt), '\\') == NULL)) { + if (PATHFLAGS(elt)) { - elt = TclNewFSPathObj(elt, str, len); - goto partReturn; /* return elt; */ + return TclNewFSPathObj(elt, str, len); } if (TCL_PATH_ABSOLUTE != Tcl_FSGetPathType(elt)) { - elt = TclNewFSPathObj(elt, str, len); - goto partReturn; /* return elt; */ + return TclNewFSPathObj(elt, str, len); } (void) Tcl_FSGetNormalizedPath(NULL, elt); if (elt == PATHOBJ(elt)->normPathPtr) { - elt = TclNewFSPathObj(elt, str, len); - goto partReturn; /* return elt; */ + return TclNewFSPathObj(elt, str, len); } } } @@ -937,19 +936,28 @@ TclJoinPath( * more general code below handle things. */ } else if (tclPlatform == TCL_PLATFORM_UNIX) { - elt = tailObj; - goto partReturn; /* return elt; */ + return tailObj; } else { const char *str = TclGetString(tailObj); if (tclPlatform == TCL_PLATFORM_WINDOWS) { if (strchr(str, '\\') == NULL) { - elt = tailObj; - goto partReturn; /* return elt; */ + return tailObj; } } } } + } + + assert ( res == NULL ); + + for (i = 0; i < elements; i++) { + int driveNameLength, strEltLen, length; + Tcl_PathType type; + char *strElt, *ptr; + Tcl_Obj *driveName = NULL; + Tcl_Obj *elt = objv[i]; + strElt = Tcl_GetStringFromObj(elt, &strEltLen); driveNameLength = 0; type = TclGetPathType(elt, &fsPtr, &driveNameLength, &driveName); @@ -1024,12 +1032,16 @@ TclJoinPath( } ptr++; } + if (res != NULL) { + TclDecrRefCount(res); + } + /* * This element is just what we want to return already; no further * manipulation is requred. */ - goto partReturn; /* return elt; */ + return elt; } /* @@ -1040,8 +1052,10 @@ TclJoinPath( noQuickReturn: if (res == NULL) { res = Tcl_NewObj(); + ptr = Tcl_GetStringFromObj(res, &length); + } else { + ptr = Tcl_GetStringFromObj(res, &length); } - ptr = Tcl_GetStringFromObj(res, &length); /* * Strip off any './' before a tilde, unless this is the beginning of @@ -1074,7 +1088,7 @@ TclJoinPath( if (sep != NULL) { separator = TclGetString(sep)[0]; - TclDecrRefCount(sep); + Tcl_DecrRefCount(sep); } /* Safety check in case the VFS driver caused sharing */ if (Tcl_IsShared(res)) { @@ -1110,16 +1124,8 @@ TclJoinPath( Tcl_SetObjLength(res, length); } } - if (res == NULL) { - res = Tcl_NewObj(); - } + assert ( res != NULL ); return res; - -partReturn: - if (res != NULL) { - TclDecrRefCount(res); - } - return elt; } /* diff --git a/generic/zipfs.c b/generic/zipfs.c index b47ded7..785d2bc 100644 --- a/generic/zipfs.c +++ b/generic/zipfs.c @@ -3,7 +3,7 @@ * * Implementation of the ZIP filesystem used in AndroWish. * - * Copyright (c) 2013-2015 Christian Werner <chw@ch-werner.de> + * Copyright (c) 2013-2017 Christian Werner <chw@ch-werner.de> * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -11,7 +11,7 @@ #include "tclInt.h" #include "tclFileSystem.h" -#include "tclZipfs.h" +#include "zipfs.h" #if !defined(_WIN32) && !defined(_WIN64) #include <sys/mman.h> @@ -165,7 +165,7 @@ typedef struct ZipEntry { int nbyte; /* Uncompressed size of the virtual file */ int nbytecompr; /* Compressed size of the virtual file */ int cmeth; /* Compress method */ - int isdir; /* Set to 1 if directory */ + int isdir; /* Set to 1 if directory, -1 if root */ int depth; /* Number of slashes in path. */ int crc32; /* CRC-32 */ int timestamp; /* Modification time */ @@ -187,7 +187,7 @@ typedef struct ZipChannel { unsigned long nread; /* Pos of next byte to be read from the channel */ unsigned char *ubuf; /* Pointer to the uncompressed data */ int iscompr; /* True if data is compressed */ - int isdir; /* Set to 1 if directory */ + int isdir; /* Set to 1 if directory, -1 if root */ int isenc; /* True if data is encrypted */ int iswr; /* True if open for writing */ unsigned long keys[3]; /* Key for decryption */ @@ -519,7 +519,7 @@ CanonicalPath(const char *root, const char *tail, Tcl_DString *dsPtr) path[j++] = c; } if (j == 0) { - path[j++] = '/'; + path[j++] = '/'; } path[j] = 0; Tcl_DStringSetLength(dsPtr, j); @@ -751,8 +751,10 @@ ZipFSCloseArchive(Tcl_Interp *interp, ZipFile *zf) Tcl_Free((char *) zf->tofree); zf->tofree = NULL; } - Tcl_Close(interp, zf->chan); - zf->chan = NULL; + if (zf->chan != NULL) { + Tcl_Close(interp, zf->chan); + zf->chan = NULL; + } } /* @@ -1173,7 +1175,7 @@ Tclzipfs_Mount(Tcl_Interp *interp, const char *zipname, const char *mntpt, z->tnext = NULL; z->depth = CountSlashes(mntpt); z->zipfile = zf; - z->isdir = 1; + z->isdir = (zf->baseoffs == 0) ? 1 : -1; /* root marker */ z->isenc = 0; z->offset = zf->baseoffs; z->crc32 = 0; @@ -1752,6 +1754,24 @@ ZipChannelRead(ClientData instanceData, char *buf, int toRead, int *errloc) ZipChannel *info = (ZipChannel *) instanceData; unsigned long nextpos; + if (info->isdir < 0) { + /* + * Special case: when executable combined with ZIP archive file + * read data in front of ZIP, i.e. the executable itself. + */ + nextpos = info->nread + toRead; + if (nextpos > info->zipfile->baseoffs) { + toRead = info->zipfile->baseoffs - info->nread; + nextpos = info->zipfile->baseoffs; + } + if (toRead == 0) { + return 0; + } + memcpy(buf, info->zipfile->data, toRead); + info->nread = nextpos; + *errloc = 0; + return toRead; + } if (info->isdir) { *errloc = EISDIR; return -1; @@ -1843,17 +1863,26 @@ static int ZipChannelSeek(ClientData instanceData, long offset, int mode, int *errloc) { ZipChannel *info = (ZipChannel *) instanceData; + unsigned long end; - if (info->isdir) { + if (!info->iswr && (info->isdir < 0)) { + /* + * Special case: when executable combined with ZIP archive file, + * seek within front of ZIP, i.e. the executable itself. + */ + end = info->zipfile->baseoffs; + } else if (info->isdir) { *errloc = EINVAL; return -1; + } else { + end = info->nbyte; } switch (mode) { case SEEK_CUR: offset += info->nread; break; case SEEK_END: - offset += info->nbyte; + offset += end; break; case SEEK_SET: break; @@ -1873,7 +1902,7 @@ ZipChannelSeek(ClientData instanceData, long offset, int mode, int *errloc) if ((unsigned long) offset > info->nbyte) { info->nbyte = offset; } - } else if ((unsigned long) offset > info->nbyte) { + } else if ((unsigned long) offset > end) { *errloc = EINVAL; return -1; } @@ -2476,6 +2505,7 @@ Zip_FSMatchInDirectoryProc(Tcl_Interp* interp, Tcl_Obj *result, int scnt, len, l, dirOnly = -1, prefixLen, strip = 0, matchHidden = 0; char *pat, *prefix, *path, *p; #if HAS_DRIVES + int drive = 0; char drivePrefix[3]; #endif Tcl_DString ds, dsPref; @@ -2528,6 +2558,10 @@ Zip_FSMatchInDirectoryProc(Tcl_Interp* interp, Tcl_Obj *result, prefixLen++; } prefix = Tcl_DStringValue(&dsPref); + drive = prefix[0]; + if ((drive >= 'a') && (drive <= 'z')) { + drive -= 'a' - 'A'; + } #else Tcl_DStringAppend(&dsPref, "/", 1); prefixLen++; @@ -2549,10 +2583,15 @@ Zip_FSMatchInDirectoryProc(Tcl_Interp* interp, Tcl_Obj *result, if ((pattern == NULL) || (pattern[0] == '\0')) { pattern = "*"; } - hPtr = Tcl_FirstHashEntry(&ZipFS.zipHash, &search); - while (hPtr != NULL) { + for (hPtr = Tcl_FirstHashEntry(&ZipFS.zipHash, &search); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { ZipFile *zf = (ZipFile *) Tcl_GetHashValue(hPtr); +#if HAS_DRIVES + if (drive && (drive != zf->mntdrv)) { + continue; + } +#endif if (zf->mntptlen == 0) { ZipEntry *z = zf->topents; @@ -2606,7 +2645,6 @@ nextent: Tcl_NewStringObj(zf->mntpt, zf->mntptlen)); } } - hPtr = Tcl_NextHashEntry(&search); } goto end; } @@ -2615,6 +2653,11 @@ nextent: if (hPtr != NULL) { ZipEntry *z = (ZipEntry *) Tcl_GetHashValue(hPtr); +#if HAS_DRIVES + if (drive && (drive != z->zipfile->mntdrv)) { + goto end; + } +#endif if ((dirOnly < 0) || (!dirOnly && !z->isdir) || (dirOnly && z->isdir)) { @@ -2652,6 +2695,11 @@ nextent: ((dirOnly && !z->isdir) || (!dirOnly && z->isdir))) { continue; } +#if HAS_DRIVES + if (drive && (drive != z->zipfile->mntdrv)) { + continue; + } +#endif if ((z->depth == scnt) && Tcl_StringCaseMatch(z->name, pat, 0)) { if (!matchHidden) { p = strrchr(z->name, '/'); @@ -2843,7 +2891,7 @@ Zip_FSListVolumesProc(void) */ #if HAS_DRIVES if (zf->mntpt[0]) { - vol = Tcl_ObjPrintf("%c:%s", zf->mntdrv, zf->mtntp); + vol = Tcl_ObjPrintf("%c:%s", zf->mntdrv, zf->mntpt); Tcl_ListObjAppendElement(NULL, vols, vol); } #else @@ -3267,13 +3315,18 @@ Zipfs_doInit(Tcl_Interp *interp, int safe) Tcl_InitHashTable(&ZipFS.fileHash, TCL_STRING_KEYS); Tcl_InitHashTable(&ZipFS.zipHash, TCL_STRING_KEYS); ZipFS.initialized = ZipFS.idCount = 1; - Tcl_StaticPackage(interp, "zipfs", Tclzipfs_Init, Tclzipfs_SafeInit); +#if defined(ZIPFS_IN_TCL) || defined(ZIPFS_IN_TK) + if (interp != NULL) { + Tcl_StaticPackage(interp, "zipfs", Tclzipfs_Init, Tclzipfs_SafeInit); + } +#endif } Unlock(); - TclMakeEnsemble(interp, "zipfs", safe ? initSafeMap : initMap); - - Tcl_PkgProvide(interp, "zipfs", "1.0"); + if (interp != NULL) { + TclMakeEnsemble(interp, "zipfs", safe ? initSafeMap : initMap); + Tcl_PkgProvide(interp, "zipfs", "1.0"); + } return TCL_OK; #else if (interp != NULL) { |