zipstrm.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,276 行 · 第 1/5 页

CPP
2,276
字号
    m_inflate->avail_in = 0;
    m_pos = 0;
    m_lasterror = wxSTREAM_NO_ERROR;
    m_parent_i_stream = &stream;

    if (inflateReset(m_inflate) != Z_OK) {
        wxLogError(_("can't re-initialize zlib inflate stream"));
        m_lasterror = wxSTREAM_READ_ERROR;
        return false;
    }

    return true;
}


/////////////////////////////////////////////////////////////////////////////
// Class to hold wxZipEntry's Extra and LocalExtra fields

class wxZipMemory
{
public:
    wxZipMemory() : m_data(NULL), m_size(0), m_capacity(0), m_ref(1) { }

    wxZipMemory *AddRef() { m_ref++; return this; }
    void Release() { if (--m_ref == 0) delete this; }

    char *GetData() const { return m_data; }
    size_t GetSize() const { return m_size; }
    size_t GetCapacity() const { return m_capacity; }

    wxZipMemory *Unique(size_t size);

private:
    ~wxZipMemory() { delete [] m_data; }

    char *m_data;
    size_t m_size;
    size_t m_capacity;
    int m_ref;
};

wxZipMemory *wxZipMemory::Unique(size_t size)
{
    wxZipMemory *zm;

    if (m_ref > 1) {
        --m_ref;
        zm = new wxZipMemory;
    } else {
        zm = this;
    }

    if (zm->m_capacity < size) {
        delete [] zm->m_data;
        zm->m_data = new char[size];
        zm->m_capacity = size;
    }

    zm->m_size = size;
    return zm;
}

static inline wxZipMemory *AddRef(wxZipMemory *zm)
{
    if (zm)
        zm->AddRef();
    return zm;
}

static inline void Release(wxZipMemory *zm)
{
    if (zm)
        zm->Release();
}

static void Copy(wxZipMemory*& dest, wxZipMemory *src)
{
    Release(dest);
    dest = AddRef(src);
}

static void Unique(wxZipMemory*& zm, size_t size)
{
    if (!zm && size)
        zm = new wxZipMemory;
    if (zm)
        zm = zm->Unique(size);
}


/////////////////////////////////////////////////////////////////////////////
// Collection of weak references to entries

WX_DECLARE_HASH_MAP(long, wxZipEntry*, wxIntegerHash,
                    wxIntegerEqual, wx__OffsetZipEntryMap);

class wxZipWeakLinks
{
public:
    wxZipWeakLinks() : m_ref(1) { }

    void Release(const wxZipInputStream* WXUNUSED(x))
        { if (--m_ref == 0) delete this; }
    void Release(wxFileOffset key)
        { RemoveEntry(key); if (--m_ref == 0) delete this; }

    wxZipWeakLinks *AddEntry(wxZipEntry *entry, wxFileOffset key);
    void RemoveEntry(wxFileOffset key)
        { m_entries.erase(wx_truncate_cast(key_type, key)); }
    wxZipEntry *GetEntry(wxFileOffset key) const;
    bool IsEmpty() const { return m_entries.empty(); }

private:
    typedef wx__OffsetZipEntryMap::key_type key_type;

    ~wxZipWeakLinks() { wxASSERT(IsEmpty()); }

    int m_ref;
    wx__OffsetZipEntryMap m_entries;
};

wxZipWeakLinks *wxZipWeakLinks::AddEntry(wxZipEntry *entry, wxFileOffset key)
{
    m_entries[wx_truncate_cast(key_type, key)] = entry;
    m_ref++;
    return this;
}

wxZipEntry *wxZipWeakLinks::GetEntry(wxFileOffset key) const
{
    wx__OffsetZipEntryMap::const_iterator it =
        m_entries.find(wx_truncate_cast(key_type, key));
    return it != m_entries.end() ?  it->second : NULL;
}


/////////////////////////////////////////////////////////////////////////////
// ZipEntry

wxZipEntry::wxZipEntry(
    const wxString& name /*=wxEmptyString*/,
    const wxDateTime& dt /*=wxDateTime::Now()*/,
    wxFileOffset size    /*=wxInvalidOffset*/)
  :
    m_SystemMadeBy(wxZIP_SYSTEM_MSDOS),
    m_VersionMadeBy(wxMAJOR_VERSION * 10 + wxMINOR_VERSION),
    m_VersionNeeded(VERSION_NEEDED_TO_EXTRACT),
    m_Flags(0),
    m_Method(wxZIP_METHOD_DEFAULT),
    m_DateTime(dt),
    m_Crc(0),
    m_CompressedSize(wxInvalidOffset),
    m_Size(size),
    m_Key(wxInvalidOffset),
    m_Offset(wxInvalidOffset),
    m_DiskStart(0),
    m_InternalAttributes(0),
    m_ExternalAttributes(0),
    m_Extra(NULL),
    m_LocalExtra(NULL),
    m_zipnotifier(NULL),
    m_backlink(NULL)
{
    if (!name.empty())
        SetName(name);
}

wxZipEntry::~wxZipEntry()
{
    if (m_backlink)
        m_backlink->Release(m_Key);
    Release(m_Extra);
    Release(m_LocalExtra);
}

wxZipEntry::wxZipEntry(const wxZipEntry& e)
  : wxArchiveEntry(e),
    m_SystemMadeBy(e.m_SystemMadeBy),
    m_VersionMadeBy(e.m_VersionMadeBy),
    m_VersionNeeded(e.m_VersionNeeded),
    m_Flags(e.m_Flags),
    m_Method(e.m_Method),
    m_DateTime(e.m_DateTime),
    m_Crc(e.m_Crc),
    m_CompressedSize(e.m_CompressedSize),
    m_Size(e.m_Size),
    m_Name(e.m_Name),
    m_Key(e.m_Key),
    m_Offset(e.m_Offset),
    m_Comment(e.m_Comment),
    m_DiskStart(e.m_DiskStart),
    m_InternalAttributes(e.m_InternalAttributes),
    m_ExternalAttributes(e.m_ExternalAttributes),
    m_Extra(AddRef(e.m_Extra)),
    m_LocalExtra(AddRef(e.m_LocalExtra)),
    m_zipnotifier(NULL),
    m_backlink(NULL)
{
}

wxZipEntry& wxZipEntry::operator=(const wxZipEntry& e)
{
    if (&e != this) {
        m_SystemMadeBy = e.m_SystemMadeBy;
        m_VersionMadeBy = e.m_VersionMadeBy;
        m_VersionNeeded = e.m_VersionNeeded;
        m_Flags = e.m_Flags;
        m_Method = e.m_Method;
        m_DateTime = e.m_DateTime;
        m_Crc = e.m_Crc;
        m_CompressedSize = e.m_CompressedSize;
        m_Size = e.m_Size;
        m_Name = e.m_Name;
        m_Key = e.m_Key;
        m_Offset = e.m_Offset;
        m_Comment = e.m_Comment;
        m_DiskStart = e.m_DiskStart;
        m_InternalAttributes = e.m_InternalAttributes;
        m_ExternalAttributes = e.m_ExternalAttributes;
        Copy(m_Extra, e.m_Extra);
        Copy(m_LocalExtra, e.m_LocalExtra);
        m_zipnotifier = NULL;
        if (m_backlink) {
            m_backlink->Release(m_Key);
            m_backlink = NULL;
        }
    }
    return *this;
}

wxString wxZipEntry::GetName(wxPathFormat format /*=wxPATH_NATIVE*/) const
{
    bool isDir = IsDir() && !m_Name.empty();

    // optimisations for common (and easy) cases
    switch (wxFileName::GetFormat(format)) {
        case wxPATH_DOS:
        {
            wxString name(isDir ? m_Name + _T("\\") : m_Name);
            for (size_t i = name.length() - 1; i > 0; --i)
                if (name[i] == _T('/'))
                    name[i] = _T('\\');
            return name;
        }

        case wxPATH_UNIX:
            return isDir ? m_Name + _T("/") : m_Name;

        default:
            ;
    }

    wxFileName fn;

    if (isDir)
        fn.AssignDir(m_Name, wxPATH_UNIX);
    else
        fn.Assign(m_Name, wxPATH_UNIX);

    return fn.GetFullPath(format);
}

// Static - Internally tars and zips use forward slashes for the path
// separator, absolute paths aren't allowed, and directory names have a
// trailing slash.  This function converts a path into this internal format,
// but without a trailing slash for a directory.
//
wxString wxZipEntry::GetInternalName(const wxString& name,
                                     wxPathFormat format /*=wxPATH_NATIVE*/,
                                     bool *pIsDir        /*=NULL*/)
{
    wxString internal;

    if (wxFileName::GetFormat(format) != wxPATH_UNIX)
        internal = wxFileName(name, format).GetFullPath(wxPATH_UNIX);
    else
        internal = name;

    bool isDir = !internal.empty() && internal.Last() == '/';
    if (pIsDir)
        *pIsDir = isDir;
    if (isDir)
        internal.erase(internal.length() - 1);

    while (!internal.empty() && *internal.begin() == '/')
        internal.erase(0, 1);
    while (!internal.empty() && internal.compare(0, 2, _T("./")) == 0)
        internal.erase(0, 2);
    if (internal == _T(".") || internal == _T(".."))
        internal = wxEmptyString;

    return internal;
}

void wxZipEntry::SetSystemMadeBy(int system)
{
    int mode = GetMode();
    bool wasUnix = IsMadeByUnix();

    m_SystemMadeBy = (wxUint8)system;

    if (!wasUnix && IsMadeByUnix()) {
        SetIsDir(IsDir());
        SetMode(mode);
    } else if (wasUnix && !IsMadeByUnix()) {
        m_ExternalAttributes &= 0xffff;
    }
}

void wxZipEntry::SetIsDir(bool isDir /*=true*/)
{
    if (isDir)
        m_ExternalAttributes |= wxZIP_A_SUBDIR;
    else
        m_ExternalAttributes &= ~wxZIP_A_SUBDIR;

    if (IsMadeByUnix()) {
        m_ExternalAttributes &= ~wxZIP_S_IFMT;
        if (isDir)
            m_ExternalAttributes |= wxZIP_S_IFDIR;
        else
            m_ExternalAttributes |= wxZIP_S_IFREG;
    }
}

// Return unix style permission bits
//
int wxZipEntry::GetMode() const
{
    // return unix permissions if present
    if (IsMadeByUnix())
        return (m_ExternalAttributes >> 16) & 0777;

    // otherwise synthesize from the dos attribs
    int mode = 0644;
    if (m_ExternalAttributes & wxZIP_A_RDONLY)
        mode &= ~0200;
    if (m_ExternalAttributes & wxZIP_A_SUBDIR)
        mode |= 0111;

    return mode;
}

// Set unix permissions
//
void wxZipEntry::SetMode(int mode)
{
    // Set dos attrib bits to be compatible
    if (mode & 0222)
        m_ExternalAttributes &= ~wxZIP_A_RDONLY;
    else
        m_ExternalAttributes |= wxZIP_A_RDONLY;

    // set the actual unix permission bits if the system type allows
    if (IsMadeByUnix()) {
        m_ExternalAttributes &= ~(0777L << 16);
        m_ExternalAttributes |= (mode & 0777L) << 16;
    }
}

const char *wxZipEntry::GetExtra() const
{
    return m_Extra ? m_Extra->GetData() : NULL;
}

size_t wxZipEntry::GetExtraLen() const
{
    return m_Extra ? m_Extra->GetSize() : 0;
}

void wxZipEntry::SetExtra(const char *extra, size_t len)
{
    Unique(m_Extra, len);
    if (len)
        memcpy(m_Extra->GetData(), extra, len);
}

const char *wxZipEntry::GetLocalExtra() const
{
    return m_LocalExtra ? m_LocalExtra->GetData() : NULL;
}

size_t  wxZipEntry::GetLocalExtraLen() const
{
    return m_LocalExtra ? m_LocalExtra->GetSize() : 0;
}

void wxZipEntry::SetLocalExtra(const char *extra, size_t len)
{
    Unique(m_LocalExtra, len);
    if (len)
        memcpy(m_LocalExtra->GetData(), extra, len);
}

void wxZipEntry::SetNotifier(wxZipNotifier& notifier)
{
    wxArchiveEntry::UnsetNotifier();
    m_zipnotifier = &notifier;
    m_zipnotifier->OnEntryUpdated(*this);
}

void wxZipEntry::Notify()
{
    if (m_zipnotifier)
        m_zipnotifier->OnEntryUpdated(*this);
    else if (GetNotifier())
        GetNotifier()->OnEntryUpdated(*this);
}

void wxZipEntry::UnsetNotifier()
{
    wxArchiveEntry::UnsetNotifier();
    m_zipnotifier = NULL;
}

size_t wxZipEntry::ReadLocal(wxInputStream& stream, wxMBConv& conv)
{
    wxUint16 nameLen, extraLen;
    wxUint32 compressedSize, size, crc;

    wxDataInputStream ds(stream);

    ds >> m_VersionNeeded >> m_Flags >> m_Method;
    SetDateTime(wxDateTime().SetFromDOS(ds.Read32()));
    ds >> crc >> compressedSize >> size >> nameLen >> extraLen;

    bool sumsValid = (m_Flags & wxZIP_SUMS_FOLLOW) == 0;

    if (sumsValid || crc)
        m_Crc = crc;
    if ((sumsValid || compressedSize) || m_Method == wxZIP_METHOD_STORE)
        m_CompressedSize = compressedSize;
    if ((sumsValid || size) || m_Method == wxZIP_METHOD_STORE)
        m_Size = size;

    SetName(ReadString(stream, nameLen, conv), wxPATH_UNIX);

    if (extraLen || GetLocalExtraLen()) {
        Unique(m_LocalExtra, extraLen);
        if (extraLen)
            stream.Read(m_LocalExtra->GetData(), extraLen);
    }

    return LOCAL_SIZE + nameLen + extraLen;
}

size_t wxZipEntry::WriteLocal(wxOutputStream& stream, wxMBConv& conv) const
{
    wxString unixName = GetName(wxPATH_UNIX);
    const wxWX2MBbuf name_buf = conv.cWX2MB(unixName);
    const char *name = name_buf;
    if (!name) name = "";
    wxUint16 nameLen = wx_truncate_cast(wxUint16, strlen(name));

    wxDataOutputStream ds(stream);

⌨️ 快捷键说明

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