aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChrisEt <ChrisEt@users.noreply.github.com>2019-12-02 18:15:09 +0100
committerChrisEt <ChrisEt@users.noreply.github.com>2020-03-27 17:07:51 +0100
commit1d37ef5fe647a5b2c285ef3d8cb7d003579775fe (patch)
tree38676ccd59fa9b3d96d7131aff8c7f8759736f95
parent365650875096120a52fa16073f8cea44e16e1f84 (diff)
added support for ZIP extended local headers
-rw-r--r--cmake/installdata/test-reference-data.txt1
-rw-r--r--xbmc/filesystem/ZipFile.cpp41
-rw-r--r--xbmc/filesystem/ZipManager.h1
-rw-r--r--xbmc/filesystem/test/TestZipFile.cpp24
-rw-r--r--xbmc/filesystem/test/extendedlocalheader.zipbin0 -> 15352 bytes
5 files changed, 62 insertions, 5 deletions
diff --git a/cmake/installdata/test-reference-data.txt b/cmake/installdata/test-reference-data.txt
index b6c94a7f7d..8bc1c03adc 100644
--- a/cmake/installdata/test-reference-data.txt
+++ b/cmake/installdata/test-reference-data.txt
@@ -1,5 +1,6 @@
xbmc/utils/test/CXBMCTinyXML-test.xml
xbmc/utils/test/data/language/Spanish/strings.po
+xbmc/filesystem/test/extendedlocalheader.zip
xbmc/filesystem/test/reffile.txt
xbmc/filesystem/test/reffile.txt.rar
xbmc/filesystem/test/reffile.txt.zip
diff --git a/xbmc/filesystem/ZipFile.cpp b/xbmc/filesystem/ZipFile.cpp
index 071f926914..46e06c785f 100644
--- a/xbmc/filesystem/ZipFile.cpp
+++ b/xbmc/filesystem/ZipFile.cpp
@@ -398,12 +398,47 @@ int CZipFile::UnpackFromMemory(std::string& strDest, const std::string& strInput
if (!isGZ)
{
CZipManager::readHeader(strInput.data()+iPos,mZipItem);
- if( mZipItem.header != ZIP_LOCAL_HEADER )
+ if (mZipItem.header == ZIP_DATA_RECORD_HEADER)
+ {
+ // this header concerns a file we already processed, so we can just skip it
+ iPos += DREC_SIZE;
+ continue;
+ }
+ if (mZipItem.header != ZIP_LOCAL_HEADER)
return iResult;
if( (mZipItem.flags & 8) == 8 )
{
- CLog::Log(LOGERROR,"FileZip: extended local header, not supported!");
- return iResult;
+ // if an extended local header (=data record header) is present,
+ // the following fields are 0 in the local header and we need to read
+ // them from the extended local header
+
+ // search for the extended local header
+ unsigned int i = iPos + LHDR_SIZE + mZipItem.flength + mZipItem.elength;
+ while (1)
+ {
+ if (i + DREC_SIZE > strInput.size())
+ {
+ CLog::Log(LOGERROR, "FileZip: extended local header expected, but not present!");
+ return iResult;
+ }
+ if ((strInput[i] == 0x50) && (strInput[i + 1] == 0x4b) &&
+ (strInput[i + 2] == 0x07) && (strInput[i + 3] == 0x08))
+ break; // header found
+ i++;
+ }
+ // ZIP is little endian:
+ mZipItem.crc32 = static_cast<uint8_t>(strInput[i + 4]) |
+ static_cast<uint8_t>(strInput[i + 5]) << 8 |
+ static_cast<uint8_t>(strInput[i + 6]) << 16 |
+ static_cast<uint8_t>(strInput[i + 7]) << 24;
+ mZipItem.csize = static_cast<uint8_t>(strInput[i + 8]) |
+ static_cast<uint8_t>(strInput[i + 9]) << 8 |
+ static_cast<uint8_t>(strInput[i + 10]) << 16 |
+ static_cast<uint8_t>(strInput[i + 11]) << 24;
+ mZipItem.usize = static_cast<uint8_t>(strInput[i + 12]) |
+ static_cast<uint8_t>(strInput[i + 13]) << 8 |
+ static_cast<uint8_t>(strInput[i + 14]) << 16 |
+ static_cast<uint8_t>(strInput[i + 15]) << 24;
}
}
if (!InitDecompress())
diff --git a/xbmc/filesystem/ZipManager.h b/xbmc/filesystem/ZipManager.h
index f24d45944c..45754152eb 100644
--- a/xbmc/filesystem/ZipManager.h
+++ b/xbmc/filesystem/ZipManager.h
@@ -15,6 +15,7 @@
#define ZIP_END_CENTRAL_HEADER 0x06054b50
#define ZIP_SPLIT_ARCHIVE_HEADER 0x30304b50
#define LHDR_SIZE 30
+#define DREC_SIZE 16
#define CHDR_SIZE 46
#define ECDREC_SIZE 22
diff --git a/xbmc/filesystem/test/TestZipFile.cpp b/xbmc/filesystem/test/TestZipFile.cpp
index 5029cf73d0..4ac3690bff 100644
--- a/xbmc/filesystem/test/TestZipFile.cpp
+++ b/xbmc/filesystem/test/TestZipFile.cpp
@@ -9,12 +9,13 @@
#include "ServiceBroker.h"
#include "filesystem/Directory.h"
#include "filesystem/File.h"
-#include "utils/StringUtils.h"
-#include "utils/URIUtils.h"
+#include "filesystem/ZipFile.h"
#include "FileItem.h"
#include "settings/Settings.h"
#include "settings/SettingsComponent.h"
#include "test/TestUtils.h"
+#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
#include "URL.h"
#include <errno.h>
@@ -207,3 +208,22 @@ TEST_F(TestZipFile, CorruptedFile)
file->Close();
XBMC_DELETETEMPFILE(file);
}
+
+TEST_F(TestZipFile, ExtendedLocalHeader)
+{
+ XFILE::CFile file;
+ ssize_t readlen;
+ char zipdata[20000]; // size of zip file is 15352 Bytes
+
+ ASSERT_TRUE(file.Open(XBMC_REF_FILE_PATH("xbmc/filesystem/test/extendedlocalheader.zip")));
+ readlen = file.Read(zipdata, sizeof(zipdata));
+ EXPECT_TRUE(readlen);
+
+ XFILE::CZipFile zipfile;
+ std::string strBuffer;
+
+ int iSize = zipfile.UnpackFromMemory(strBuffer, std::string(zipdata, readlen), false);
+ EXPECT_EQ(152774, iSize); // sum of uncompressed size of all files in zip
+ EXPECT_TRUE(strBuffer.substr(0, 6) == "<Data>");
+ file.Close();
+}
diff --git a/xbmc/filesystem/test/extendedlocalheader.zip b/xbmc/filesystem/test/extendedlocalheader.zip
new file mode 100644
index 0000000000..b30d92e128
--- /dev/null
+++ b/xbmc/filesystem/test/extendedlocalheader.zip
Binary files differ