Added zip reader support (only works with non-compressed files)

This commit is contained in:
Alex Zolotarev 2011-07-02 20:14:34 +03:00 committed by Alex Zolotarev
parent f2f968c546
commit f65c4fef95
7 changed files with 115 additions and 9 deletions

View file

@ -23,7 +23,8 @@ SOURCES += \
base64.cpp \
sha2.cpp \
multilang_utf8_string.cpp \
reader.cpp
reader.cpp \
zip_reader.cpp \
HEADERS += \
internal/xmlparser.h \
@ -81,3 +82,4 @@ HEADERS += \
value_opt_string.hpp \
multilang_utf8_string.hpp \
url_encode.hpp \
zip_reader.hpp \

View file

@ -37,6 +37,7 @@ SOURCES += ../../testing/testingmain.cpp \
value_opt_string_test.cpp \
multilang_utf8_string_test.cpp \
file_data_test.cpp \
zip_reader_test.cpp \
HEADERS += \
reader_test.hpp \

View file

@ -0,0 +1,70 @@
#include "../../testing/testing.hpp"
#include "../zip_reader.hpp"
#include "../file_writer.hpp"
#include "../../base/logging.hpp"
#include "../../base/macros.hpp"
char const zipBytes[] = "PK\003\004\n\0\0\0\0\0\222\226\342>\302\032"
"x\372\005\0\0\0\005\0\0\0\b\0\034\0te"
"st.txtUT\t\0\003\303>\017N\017"
"?\017Nux\v\0\001\004\365\001\0\0\004P\0"
"\0\0Test\nPK\001\002\036\003\n\0\0"
"\0\0\0\222\226\342>\302\032x\372\005\0\0\0\005"
"\0\0\0\b\0\030\0\0\0\0\0\0\0\0\0\244"
"\201\0\0\0\0test.txtUT\005"
"\0\003\303>\017Nux\v\0\001\004\365\001\0\0"
"\004P\0\0\0PK\005\006\0\0\0\0\001\0\001"
"\0N\0\0\0G\0\0\0\0\0";
UNIT_TEST(ZipReaderSmoke)
{
string const ZIPFILE = "smoke_test.zip";
{
FileWriter f(ZIPFILE);
f.Write(zipBytes, ARRAY_SIZE(zipBytes) - 1);
}
bool noException = true;
try
{
ZipFileReader r(ZIPFILE, "test.txt");
string s;
r.ReadAsString(s);
TEST_EQUAL(s, "Test\n", ("Invalid zip file contents"));
}
catch (FileReader::Exception const & e)
{
noException = false;
LOG(LERROR, (e.what()));
}
TEST(noException, ("Unhandled exception"));
// invalid zip
noException = true;
try
{
ZipFileReader r("some_nonexisting_filename", "test.txt");
}
catch (FileReader::Exception const &)
{
noException = false;
}
TEST(!noException, ());
// invalid file inside zip
noException = true;
try
{
ZipFileReader r(ZIPFILE, "test");
}
catch (FileReader::Exception const &)
{
noException = false;
}
TEST(!noException, ());
FileWriter::DeleteFileX(ZIPFILE);
}

View file

@ -101,3 +101,10 @@ FileReader * FileReader::CreateSubReader(uint64_t pos, uint64_t size) const
ASSERT_LESS_OR_EQUAL(pos + size, Size(), (pos, size));
return new FileReader(*this, m_Offset + pos, size);
}
void FileReader::SetOffsetAndSize(uint64_t offset, uint64_t size)
{
ASSERT_LESS_OR_EQUAL(offset + size, Size(), (offset, size));
m_Offset = offset;
m_Size = size;
}

View file

@ -22,6 +22,10 @@ public:
FileReader SubReader(uint64_t pos, uint64_t size) const;
FileReader * CreateSubReader(uint64_t pos, uint64_t size) const;
protected:
// Used in special derived readers.
void SetOffsetAndSize(uint64_t offset, uint64_t size);
private:
FileReader(FileReader const & reader, uint64_t offset, uint64_t size);

View file

@ -10,7 +10,7 @@
ZipFileReader::ZipFileReader(string const & container, string const & file)
: base_type(container)
{
unzFile zip = unzOpen(container.c_str());
unzFile zip = unzOpen64(container.c_str());
if (!zip)
MYTHROW(OpenZipException, ("Can't get zip file handle", container));
@ -19,18 +19,23 @@ ZipFileReader::ZipFileReader(string const & container, string const & file)
if (UNZ_OK != unzLocateFile(zip, file.c_str(), 1))
MYTHROW(LocateZipException, ("Can't locate file inside zip", file));
unz_file_pos filePos;
if (UNZ_OK != unzGetFilePos(zip, &filePos))
MYTHROW(LocateZipException, ("Can't locate file offset inside zip", file));
if (UNZ_OK != unzOpenCurrentFile(zip))
MYTHROW(LocateZipException, ("Can't open file inside zip", file));
unz_file_info fileInfo;
if (UNZ_OK != unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0))
uint64_t offset = unzGetCurrentFileZStreamPos64(zip);
unzCloseCurrentFile(zip);
if (offset > Size())
MYTHROW(LocateZipException, ("Invalid offset inside zip", file));
unz_file_info64 fileInfo;
if (UNZ_OK != unzGetCurrentFileInfo64(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0))
MYTHROW(LocateZipException, ("Can't get uncompressed file size inside zip", file));
if (fileInfo.compressed_size != fileInfo.uncompressed_size)
MYTHROW(InvalidZipException, ("File should be uncompressed inside zip", file));
LOG(LDEBUG, (file, "offset:", filePos.pos_in_zip_directory, "size:", fileInfo.uncompressed_size));
LOG(LDEBUG, (file, "offset:", offset, "size:", fileInfo.uncompressed_size));
SetOffsetAndSize(filePos.pos_in_zip_directory, fileInfo.uncompressed_size);
SetOffsetAndSize(offset, fileInfo.uncompressed_size);
}

17
coding/zip_reader.hpp Normal file
View file

@ -0,0 +1,17 @@
#pragma once
#include "file_reader.hpp"
#include "../base/exception.hpp"
class ZipFileReader : public FileReader
{
typedef FileReader base_type;
public:
DECLARE_EXCEPTION(OpenZipException, OpenException);
DECLARE_EXCEPTION(LocateZipException, OpenException);
DECLARE_EXCEPTION(InvalidZipException, OpenException);
ZipFileReader(string const & container, string const & file);
};