diff --git a/src/fileimpl.cpp b/src/fileimpl.cpp index 05d8c629..b5413df5 100644 --- a/src/fileimpl.cpp +++ b/src/fileimpl.cpp @@ -164,15 +164,35 @@ class BadSizedFile: public std::exception {}; ////////////////////////////////////////////////////////////////////// // FileImpl // - std::shared_ptr FileImpl::openSinglePieceOrSplitZimFile(const std::string& filename) { + std::shared_ptr FileImpl::openSinglePieceOrSplitZimFile(std::string fname) { + bool found = false; + std::shared_ptr fileCompound; try { - return std::shared_ptr( - new FileImpl(std::make_shared(filename)) - ); - } catch (...) { - return std::shared_ptr( - new FileImpl(std::make_shared(filename, FileCompound::MultiPartToken::Multi)) - ); + fileCompound = std::make_shared(fname); + found = true; + } catch(...) { } + if (found) { + try { + return std::shared_ptr(new FileImpl(fileCompound)); + } catch(BadSizedFile& e) { + if (fname.size() > 6 && fname.substr(fname.size()-6) == ".zimaa") { + // We have tried to open a split file. Let's continue with "aa" postfix removed. + fname.resize(fname.size()-2); + } else { + // We have found a (not split) file but it is too small. + throw ZimFileFormatError("Zim file(s) is too small."); + } + } + } + + // Either we haven't succeed to open fname (.zim) or the file (.zimaa) is too small. + // Let's try to open as split files. + fileCompound = std::make_shared(fname, FileCompound::MultiPartToken::Multi); + try { + return std::shared_ptr(new FileImpl(fileCompound)); + } catch (BadSizedFile& e) { + // BadSizedFile is internal error. + throw ZimFileFormatError("Zim file(s) is too small."); } } diff --git a/src/fileimpl.h b/src/fileimpl.h index 53ead5ba..14d8d475 100644 --- a/src/fileimpl.h +++ b/src/fileimpl.h @@ -97,7 +97,7 @@ namespace zim using FindxResult = std::pair; using FindxTitleResult = std::pair; - static std::shared_ptr openSinglePieceOrSplitZimFile(const std::string& fname); + static std::shared_ptr openSinglePieceOrSplitZimFile(std::string fname); #ifndef _WIN32 explicit FileImpl(int fd); explicit FileImpl(FdInput fd); diff --git a/test/archive.cpp b/test/archive.cpp index 230b27ef..f1d022e7 100644 --- a/test/archive.cpp +++ b/test/archive.cpp @@ -264,6 +264,31 @@ TEST(ZimArchive, openRealZimArchive) } } +TEST(ZimArchive, openSplitZimArchive) +{ + const char* fname = "wikibooks_be_all_nopic_2017-02_splitted.zim"; + + for (auto& testfile: getDataFilePath(fname)) { + const TestContext ctx{ {"path", testfile.path+"aa" } }; + std::unique_ptr archive; + EXPECT_NO_THROW( archive.reset(new zim::Archive(testfile.path+"aa")) ) << ctx; + if ( archive ) { + EXPECT_TRUE( archive->check() ) << ctx; + } + } +} + +TEST(ZimArchive, openDontFallbackOnNonSplitZimArchive) +{ + const char* fname = "wikibooks_be_all_nopic_2017-02.zim"; + + for (auto& testfile: getDataFilePath(fname)) { + const TestContext ctx{ {"path", testfile.path+"aa" } }; + std::unique_ptr archive; + EXPECT_THROW( archive.reset(new zim::Archive(testfile.path+"aa")), std::runtime_error) << ctx; + } +} + TEST(ZimArchive, randomEntry) { const char* const zimfiles[] = { @@ -404,7 +429,7 @@ TEST(ZimArchive, validate) TEST_BROKEN_ZIM_NAME( "invalid.smaller_than_header.zim", - "zim-file is too small to contain a header\n" + "Zim file(s) is too small.\n" ); TEST_BROKEN_ZIM_NAME( @@ -434,7 +459,7 @@ TEST(ZimArchive, validate) TEST_BROKEN_ZIM_NAME( "invalid.invalid_checksumpos.zim", - "Checksum position is not valid\n" + "Zim file(s) is too small.\n" ); TEST_BROKEN_ZIM_NAME(