⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 zip.c

📁 嵌入式环境下的GUI
💻 C
📖 第 1 页 / 共 3 页
字号:
            break;        filepos -= (maxread - 4);    } /* while */    BAIL_IF_MACRO(!found, ERR_NOT_AN_ARCHIVE, -1);    if (len != NULL)        *len = filelen;    return(filepos + i);} /* zip_find_end_of_central_dir */static int ZIP_isArchive(const char *filename, int forWriting){    PHYSFS_uint32 sig;    int retval = 0;    void *in;    in = __PHYSFS_platformOpenRead(filename);    BAIL_IF_MACRO(in == NULL, NULL, 0);    /*     * The first thing in a zip file might be the signature of the     *  first local file record, so it makes for a quick determination.     */    if (readui32(in, &sig))    {        retval = (sig == ZIP_LOCAL_FILE_SIG);        if (!retval)        {            /*             * No sig...might be a ZIP with data at the start             *  (a self-extracting executable, etc), so we'll have to do             *  it the hard way...             */            retval = (zip_find_end_of_central_dir(in, NULL) != -1);        } /* if */    } /* if */    __PHYSFS_platformClose(in);    return(retval);} /* ZIP_isArchive */static void zip_free_entries(ZIPentry *entries, PHYSFS_uint32 max){    PHYSFS_uint32 i;    for (i = 0; i < max; i++)    {        ZIPentry *entry = &entries[i];        if (entry->name != NULL)            free(entry->name);    } /* for */    free(entries);} /* zip_free_entries *//* * This will find the ZIPentry associated with a path in platform-independent *  notation. Directories don't have ZIPentries associated with them, but  *  (*isDir) will be set to non-zero if a dir was hit. */static ZIPentry *zip_find_entry(ZIPinfo *info, const char *path, int *isDir){    ZIPentry *a = info->entries;    PHYSFS_sint32 pathlen = strlen(path);    PHYSFS_sint32 lo = 0;    PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);    PHYSFS_sint32 middle;    const char *thispath = NULL;    int rc;    while (lo <= hi)    {        middle = lo + ((hi - lo) / 2);        thispath = a[middle].name;        rc = strncmp(path, thispath, pathlen);        if (rc > 0)            lo = middle + 1;        else if (rc < 0)            hi = middle - 1;        else /* substring match...might be dir or entry or nothing. */        {            if (isDir != NULL)            {                *isDir = (thispath[pathlen] == '/');                if (*isDir)                    return(NULL);            } /* if */            if (thispath[pathlen] == '\0') /* found entry? */                return(&a[middle]);            else                hi = middle - 1;  /* adjust search params, try again. */        } /* if */    } /* while */    if (isDir != NULL)        *isDir = 0;    BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);} /* zip_find_entry *//* Convert paths from old, buggy DOS zippers... */static void zip_convert_dos_path(ZIPentry *entry, char *path){    PHYSFS_uint8 hosttype = (PHYSFS_uint8) ((entry->version >> 8) & 0xFF);    if (hosttype == 0)  /* FS_FAT_ */    {        while (*path)        {            if (*path == '\\')                *path = '/';            path++;        } /* while */    } /* if */} /* zip_convert_dos_path */static void zip_expand_symlink_path(char *path){    char *ptr = path;    char *prevptr = path;    while (1)    {        ptr = strchr(ptr, '/');        if (ptr == NULL)            break;        if (*(ptr + 1) == '.')        {            if (*(ptr + 2) == '/')            {                /* current dir in middle of string: ditch it. */                memmove(ptr, ptr + 2, strlen(ptr + 2) + 1);            } /* else if */            else if (*(ptr + 2) == '\0')            {                /* current dir at end of string: ditch it. */                *ptr = '\0';            } /* else if */            else if (*(ptr + 2) == '.')            {                if (*(ptr + 3) == '/')                {                    /* parent dir in middle: move back one, if possible. */                    memmove(prevptr, ptr + 4, strlen(ptr + 4) + 1);                    ptr = prevptr;                    while (prevptr != path)                    {                        prevptr--;                        if (*prevptr == '/')                        {                            prevptr++;                            break;                        } /* if */                    } /* while */                } /* if */                if (*(ptr + 3) == '\0')                {                    /* parent dir at end: move back one, if possible. */                    *prevptr = '\0';                } /* if */            } /* if */        } /* if */        else        {            prevptr = ptr;        } /* else */    } /* while */} /* zip_expand_symlink_path *//* * Look for the entry named by (path). If it exists, resolve it, and return *  a pointer to that entry. If it's another symlink, keep resolving until you *  hit a real file and then return a pointer to the final non-symlink entry. *  If there's a problem, return NULL. (path) is always free()'d by this *  function. */static ZIPentry *zip_follow_symlink(void *in, ZIPinfo *info, char *path){    ZIPentry *entry;    zip_expand_symlink_path(path);    entry = zip_find_entry(info, path, NULL);    if (entry != NULL)    {        if (!zip_resolve(in, info, entry))  /* recursive! */            entry = NULL;        else        {            if (entry->symlink != NULL)                entry = entry->symlink;        } /* else */    } /* if */    free(path);    return(entry);} /* zip_follow_symlink */static int zip_resolve_symlink(void *in, ZIPinfo *info, ZIPentry *entry){    char *path;    PHYSFS_uint32 size = entry->uncompressed_size;    int rc = 0;    /*     * We've already parsed the local file header of the symlink at this     *  point. Now we need to read the actual link from the file data and     *  follow it.     */    BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, entry->offset), NULL, 0);    path = (char *) malloc(size + 1);    BAIL_IF_MACRO(path == NULL, ERR_OUT_OF_MEMORY, 0);        if (entry->compression_method == COMPMETH_NONE)        rc = (__PHYSFS_platformRead(in, path, size, 1) == 1);    else  /* symlink target path is compressed... */    {        z_stream stream;        PHYSFS_uint32 compsize = entry->compressed_size;        PHYSFS_uint8 *compressed = (PHYSFS_uint8 *) malloc(compsize);        if (compressed != NULL)        {            if (__PHYSFS_platformRead(in, compressed, compsize, 1) == 1)            {                memset(&stream, '\0', sizeof (z_stream));                stream.next_in = compressed;                stream.avail_in = compsize;                stream.next_out = (unsigned char *) path;                stream.avail_out = size;                if (zlib_err(inflateInit2(&stream, -MAX_WBITS)) == Z_OK)                {                    rc = zlib_err(inflate(&stream, Z_FINISH));                    inflateEnd(&stream);                    /* both are acceptable outcomes... */                    rc = ((rc == Z_OK) || (rc == Z_STREAM_END));                } /* if */            } /* if */            free(compressed);        } /* if */    } /* else */    if (!rc)        free(path);    else    {        path[entry->uncompressed_size] = '\0';    /* null-terminate it. */        zip_convert_dos_path(entry, path);        entry->symlink = zip_follow_symlink(in, info, path);    } /* else */    return(entry->symlink != NULL);} /* zip_resolve_symlink *//* * Parse the local file header of an entry, and update entry->offset. */static int zip_parse_local(void *in, ZIPentry *entry){    PHYSFS_uint32 ui32;    PHYSFS_uint16 ui16;    PHYSFS_uint16 fnamelen;    PHYSFS_uint16 extralen;    /*     * crc and (un)compressed_size are always zero if this is a "JAR"     *  archive created with Sun's Java tools, apparently. We only     *  consider this archive corrupted if those entries don't match and     *  aren't zero. That seems to work well.     */    BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, entry->offset), NULL, 0);    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);    BAIL_IF_MACRO(ui32 != ZIP_LOCAL_FILE_SIG, ERR_CORRUPTED, 0);    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);    BAIL_IF_MACRO(ui16 != entry->version_needed, ERR_CORRUPTED, 0);    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);  /* general bits. */    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);    BAIL_IF_MACRO(ui16 != entry->compression_method, ERR_CORRUPTED, 0);    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);  /* date/time */    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);    BAIL_IF_MACRO(ui32 && (ui32 != entry->crc), ERR_CORRUPTED, 0);    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);    BAIL_IF_MACRO(ui32 && (ui32 != entry->compressed_size), ERR_CORRUPTED, 0);    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);    BAIL_IF_MACRO(ui32 && (ui32 != entry->uncompressed_size),ERR_CORRUPTED,0);    BAIL_IF_MACRO(!readui16(in, &fnamelen), NULL, 0);    BAIL_IF_MACRO(!readui16(in, &extralen), NULL, 0);    entry->offset += fnamelen + extralen + 30;    return(1);} /* zip_parse_local */static int zip_resolve(void *in, ZIPinfo *info, ZIPentry *entry){    int retval = 1;    ZipResolveType resolve_type = entry->resolved;    /* Don't bother if we've failed to resolve this entry before. */    BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_FILE, ERR_CORRUPTED, 0);    BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_SYMLINK, ERR_CORRUPTED, 0);    /* uhoh...infinite symlink loop! */    BAIL_IF_MACRO(resolve_type == ZIP_RESOLVING, ERR_SYMLINK_LOOP, 0);    /*     * We fix up the offset to point to the actual data on the     *  first open, since we don't want to seek across the whole file on     *  archive open (can be SLOW on large, CD-stored files), but we     *  need to check the local file header...not just for corruption,     *  but since it stores offset info the central directory does not.     */    if (resolve_type != ZIP_RESOLVED)    {        entry->resolved = ZIP_RESOLVING;        retval = zip_parse_local(in, entry);        if (retval)        {            /*             * If it's a symlink, find the original file. This will cause             *  resolution of other entries (other symlinks and, eventually,             *  the real file) if all goes well.             */            if (resolve_type == ZIP_UNRESOLVED_SYMLINK)                retval = zip_resolve_symlink(in, info, entry);        } /* if */        if (resolve_type == ZIP_UNRESOLVED_SYMLINK)            entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_SYMLINK);        else if (resolve_type == ZIP_UNRESOLVED_FILE)            entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_FILE);    } /* if */    return(retval);} /* zip_resolve */static int zip_version_does_symlinks(PHYSFS_uint32 version){    int retval = 0;    PHYSFS_uint8 hosttype = (PHYSFS_uint8) ((version >> 8) & 0xFF);    switch (hosttype)    {            /*             * These are the platforms that can NOT build an archive with             *  symlinks, according to the Info-ZIP project.             */        case 0:  /* FS_FAT_  */        case 1:  /* AMIGA_   */        case 2:  /* VMS_     */        case 4:  /* VM_CSM_  */        case 6:  /* FS_HPFS_ */        case 11: /* FS_NTFS_ */        case 14: /* FS_VFAT_ */        case 13: /* ACORN_   */        case 15: /* MVS_     */        case 18: /* THEOS_   */            break;  /* do nothing. */        default:  /* assume the rest to be unix-like. */            retval = 1;            break;    } /* switch */    return(retval);} /* zip_version_does_symlinks */static int zip_entry_is_symlink(ZIPentry *entry){    return((entry->resolved == ZIP_UNRESOLVED_SYMLINK) ||           (entry->resolved == ZIP_BROKEN_SYMLINK) ||           (entry->symlink));} /* zip_entry_is_symlink */static int zip_has_symlink_attr(ZIPentry *entry, PHYSFS_uint32 extern_attr){    PHYSFS_uint16 xattr = ((extern_attr >> 16) & 0xFFFF);    return (              (zip_version_does_symlinks(entry->version)) &&              (entry->uncompressed_size > 0) &&              ((xattr & UNIX_FILETYPE_MASK) == UNIX_FILETYPE_SYMLINK)           );} /* zip_has_symlink_attr */static PHYSFS_sint64 zip_dos_time_to_physfs_time(PHYSFS_uint32 dostime){#ifdef _WIN32_WCE	/* We have no struct tm and no mktime right now.	   FIXME: This should probably be fixed at some point.	*/    return -1;#else    PHYSFS_uint32 dosdate;    struct tm unixtime;    memset(&unixtime, '\0', sizeof (unixtime));    dosdate = (PHYSFS_uint32) ((dostime >> 16) & 0xFFFF);    dostime &= 0xFFFF;    /* dissect date */    unixtime.tm_year = ((dosdate >> 9) & 0x7F) + 80;    unixtime.tm_mon  = ((dosdate >> 5) & 0x0F) - 1;    unixtime.tm_mday = ((dosdate     ) & 0x1F);    /* dissect time */    unixtime.tm_hour = ((dostime >> 11) & 0x1F);    unixtime.tm_min  = ((dostime >>  5) & 0x3F);    unixtime.tm_sec  = ((dostime <<  1) & 0x3E);    /* let mktime calculate daylight savings time. */    unixtime.tm_isdst = -1;    return((PHYSFS_sint64) mktime(&unixtime));#endif} /* zip_dos_time_to_physfs_time */static int zip_load_entry(void *in, ZIPentry *entry, PHYSFS_uint32 ofs_fixup){    PHYSFS_uint16 fnamelen, extralen, commentlen;    PHYSFS_uint32 external_attr;    PHYSFS_uint16 ui16;    PHYSFS_uint32 ui32;    PHYSFS_sint64 si64;    /* sanity check with central directory signature... */    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);    BAIL_IF_MACRO(ui32 != ZIP_CENTRAL_DIR_SIG, ERR_CORRUPTED, 0);    /* Get the pertinent parts of the record... */    BAIL_IF_MACRO(!readui16(in, &entry->version), NULL, 0);    BAIL_IF_MACRO(!readui16(in, &entry->version_needed), NULL, 0);    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);  /* general bits */    BAIL_IF_MACRO(!readui16(in, &entry->compression_method), NULL, 0);    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);    entry->last_mod_time = zip_dos_time_to_physfs_time(ui32);    BAIL_IF_MACRO(!readui32(in, &entry->crc), NULL, 0);    BAIL_IF_MACRO(!readui32(in, &entry->compressed_size), NULL, 0);    BAIL_IF_MACRO(!readui32(in, &entry->uncompressed_size), NULL, 0);    BAIL_IF_MACRO(!readui16(in, &fnamelen), NULL, 0);    BAIL_IF_MACRO(!readui16(in, &extralen), NULL, 0);    BAIL_IF_MACRO(!readui16(in, &commentlen), NULL, 0);    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);  /* disk number start */    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);  /* internal file attribs */    BAIL_IF_MACRO(!readui32(in, &external_attr), NULL, 0);    BAIL_IF_MACRO(!readui32(in, &entry->offset), NULL, 0);    entry->offset += ofs_fixup;    entry->symlink = NULL;  /* will be resolved later, if necessary. */    entry->resolved = (zip_has_symlink_attr(entry, external_attr)) ?                            ZIP_UNRESOLVED_SYMLINK : ZIP_UNRESOLVED_FILE;    entry->name = (char *) malloc(fnamelen + 1);    BAIL_IF_MACRO(entry->name == NULL, ERR_OUT_OF_MEMORY, 0);    if (__PHYSFS_platformRead(in, entry->name, fnamelen, 1) != 1)        goto zip_load_entry_puked;    entry->name[fnamelen] = '\0';  /* null-terminate the filename. */    zip_convert_dos_path(entry, entry->name);    si64 = __PHYSFS_platformTell(in);    if (si64 == -1)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -