1 /*
2 * Copyright (C) 2012-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9 #include "APKDirectory.h"
10
11 #include "APKFile.h"
12 #include "FileItem.h"
13 #include "utils/CharsetConverter.h"
14 #include "utils/StringUtils.h"
15 #include "utils/URIUtils.h"
16 #include "utils/log.h"
17
18 #include <zip.h>
19
20 using namespace XFILE;
21
22 // Android apk directory i/o. Depends on libzip
23 // Basically the same format as zip.
24 // We might want to refactor CZipDirectory someday...
25 //////////////////////////////////////////////////////////////////////
GetDirectory(const CURL & url,CFileItemList & items)26 bool CAPKDirectory::GetDirectory(const CURL& url, CFileItemList &items)
27 {
28 // uses a <fully qualified path>/filename.apk/...
29 std::string path = url.GetFileName();
30 const std::string& host = url.GetHostName();
31 URIUtils::AddSlashAtEnd(path);
32
33 int zip_flags = 0, zip_error = 0;
34 struct zip *zip_archive;
35 zip_archive = zip_open(host.c_str(), zip_flags, &zip_error);
36 if (!zip_archive || zip_error)
37 {
38 CLog::Log(LOGERROR, "CAPKDirectory::GetDirectory: Unable to open archive : '%s'",
39 host.c_str());
40 return false;
41 }
42
43 std::string test_name;
44 int numFiles = zip_get_num_files(zip_archive);
45 for (int zip_index = 0; zip_index < numFiles; zip_index++)
46 {
47 test_name = zip_get_name(zip_archive, zip_index, zip_flags);
48
49 // check for non matching path.
50 if (!StringUtils::StartsWith(test_name, path))
51 continue;
52
53 // libzip does not index folders, only filenames. We search for a /,
54 // add it if it's not in our list already, and hope that no one has
55 // any "file/name.exe" files in a zip.
56
57 size_t dir_marker = test_name.find('/', path.size() + 1);
58 if (dir_marker != std::string::npos)
59 {
60 // return items relative to path
61 test_name=test_name.substr(0, dir_marker);
62
63 if (items.Contains(host + "/" + test_name))
64 continue;
65 }
66
67 struct zip_stat sb;
68 zip_stat_init(&sb);
69 if (zip_stat_index(zip_archive, zip_index, zip_flags, &sb) != -1)
70 {
71 g_charsetConverter.unknownToUTF8(test_name);
72 CFileItemPtr pItem(new CFileItem(test_name));
73 pItem->m_dwSize = sb.size;
74 pItem->m_dateTime = sb.mtime;
75 pItem->m_bIsFolder = dir_marker > 0 ;
76 pItem->SetPath(host + "/" + test_name);
77 pItem->SetLabel(test_name.substr(path.size()));
78 items.Add(pItem);
79 }
80 }
81 zip_close(zip_archive);
82
83 return true;
84 }
85
ContainsFiles(const CURL & url)86 bool CAPKDirectory::ContainsFiles(const CURL& url)
87 {
88 //! @todo why might we need this ?
89 return false;
90 }
91
GetCacheType(const CURL & url) const92 DIR_CACHE_TYPE CAPKDirectory::GetCacheType(const CURL& url) const
93 {
94 return DIR_CACHE_ALWAYS;
95 }
96
Exists(const CURL & url)97 bool CAPKDirectory::Exists(const CURL& url)
98 {
99 // uses a <fully qualified path>/filename.apk/...
100 CAPKFile apk;
101 return apk.Exists(url);
102 }
103