Looking up an archive entry by name

Archive formats such as zip

Also see wxFileSystem for a higher level interface that is more convenient for accessing archive entries by name.

To open just one entry in an archive, the most efficient way is to simply search for it linearly by calling GetNextEntry() until the required entry is found. This works both for archives on seekable and non-seekable streams.

The format of filenames in the archive is likely to be different from the local filename format. For example zips and tars use unix style names, with forward slashes as the path separator, and absolute paths are not allowed. So if on Windows the file "C:$\backslash$MYDIR$\backslash$MYFILE.TXT" is stored, then when reading the entry back GetName() will return "MYDIR$\backslash$MYFILE.TXT". The conversion into the internal format and back has lost some information.

So to avoid ambiguity when searching for an entry matching a local name, it is better to convert the local name to the archive's internal format and search for that:

    // 'smart pointer' type created with wxDEFINE_SCOPED_PTR_TYPE
    wxZipEntryPtr entry;

    // convert the local name we are looking for into the internal format
    wxString name = wxZipEntry::GetInternalName(localname);

    // open the zip
    wxFFileInputStream in(_T("test.zip"));
    wxZipInputStream zip(in);

    // call GetNextEntry() until the required internal name is found
    do {
        entry.reset(zip.GetNextEntry());
    }
    while (entry.get() != NULL && entry->GetInternalName() != name);

    if (entry.get() != NULL) {
        // read the entry's data...
    }

To access several entries randomly, it is most efficient to transfer the entire catalogue of entries to a container such as a std::map or a wxHashMap then entries looked up by name can be opened using the OpenEntry() method.

    WX_DECLARE_STRING_HASH_MAP(wxZipEntry*, ZipCatalog);
    ZipCatalog::iterator it;
    wxZipEntry *entry;
    ZipCatalog cat;

    // open the zip
    wxFFileInputStream in(_T("test.zip"));
    wxZipInputStream zip(in);

    // load the zip catalog
    while ((entry = zip.GetNextEntry()) != NULL) {
        wxZipEntry*& current = cat[entry->GetInternalName()];
        // some archive formats can have multiple entries with the same name
        // (e.g. tar) though it is an error in the case of zip
        delete current;
        current = entry;
    }

    // open an entry by name
    if ((it = cat.find(wxZipEntry::GetInternalName(localname))) != cat.end()) {
        zip.OpenEntry(*it->second);
        // ... now read entry's data
    }

To open more than one entry simultaneously you need more than one underlying stream on the same archive:

    // opening another entry without closing the first requires another
    // input stream for the same file
    wxFFileInputStream in2(_T("test.zip"));
    wxZipInputStream zip2(in2);
    if ((it = cat.find(wxZipEntry::GetInternalName(local2))) != cat.end())
        zip2.OpenEntry(*it->second);

ymasuda 平成17年11月19日