1 /*
2  * PROJECT:     ReactOS Zip Shell Extension
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     CZipEnumerator
5  * COPYRIGHT:   Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
6  *              Copyright 2023 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
7  */
8 
9 struct CZipEnumerator
10 {
11 private:
12     CComPtr<IZip> m_Zip;
13     bool m_First;
14     CAtlList<CStringW> m_Returned;
15     UINT m_nCodePage;
16 public:
CZipEnumeratorCZipEnumerator17     CZipEnumerator()
18         : m_First(true)
19         , m_nCodePage(GetZipCodePage(TRUE))
20     {
21     }
22 
initializeCZipEnumerator23     bool initialize(IZip* zip)
24     {
25         m_Zip = zip;
26         return reset();
27     }
28 
resetCZipEnumerator29     bool reset()
30     {
31         unzFile uf = m_Zip->getZip();
32         m_First = true;
33         if (unzGoToFirstFile(uf) != UNZ_OK)
34             return false;
35         m_Returned.RemoveAll();
36         return true;
37     }
38 
next_uniqueCZipEnumerator39     bool next_unique(PCWSTR prefix, CStringW& name, bool& folder, unz_file_info64& info)
40     {
41         size_t len = wcslen(prefix);
42         CStringW tmp;
43         while (next(tmp, info))
44         {
45             if (!_wcsnicmp(tmp, prefix, len))
46             {
47                 int pos = tmp.Find(L'/', len);
48                 if (pos < 0)
49                 {
50                     name = tmp.Mid(len);
51                     folder = false;
52                 }
53                 else
54                 {
55                     name = tmp.Mid(len, pos - len);
56                     folder = true;
57                 }
58                 tmp = name;
59                 tmp.MakeLower();
60 
61                 POSITION it = m_Returned.Find(tmp);
62                 if (!name.IsEmpty() && !it)
63                 {
64                     m_Returned.AddTail(tmp);
65                     return true;
66                 }
67             }
68         }
69         return false;
70     }
71 
nextCZipEnumerator72     bool next(CStringW& name, unz_file_info64& info)
73     {
74         int err;
75 
76         unzFile uf = m_Zip->getZip();
77         if (!m_First)
78         {
79             err = unzGoToNextFile(uf);
80             if (err == UNZ_END_OF_LIST_OF_FILE)
81             {
82                 return false;
83             }
84         }
85         m_First = false;
86 
87         err = unzGetCurrentFileInfo64(uf, &info, NULL, 0, NULL, 0, NULL, 0);
88         if (err == UNZ_OK)
89         {
90             CStringA nameA;
91             PSTR buf = nameA.GetBuffer(info.size_filename);
92             err = unzGetCurrentFileInfo64(uf, NULL, buf, nameA.GetAllocLength(), NULL, 0, NULL, 0);
93             nameA.ReleaseBuffer(info.size_filename);
94             nameA.Replace('\\', '/');
95 
96             if (info.flag & MINIZIP_UTF8_FLAG)
97                 name = CA2WEX<MAX_PATH>(nameA, CP_UTF8);
98             else
99                 name = CA2WEX<MAX_PATH>(nameA, m_nCodePage);
100         }
101         return err == UNZ_OK;
102     }
103 };
104 
105