diff --git a/test/file_zip_test.cpp b/test/file_zip_test.cpp index eab4a98..9ce84f8 100644 --- a/test/file_zip_test.cpp +++ b/test/file_zip_test.cpp @@ -46,7 +46,7 @@ SCENARIO("zipfile feed with different inputs", "[zip]") // prevent mixing the closing when both instances are freed at the end of the scope unzipper.close(); - REQUIRE(check_file_exists("test1.txt")); + REQUIRE(checkFileExists("test1.txt")); std::ifstream testfile("test1.txt"); REQUIRE(testfile.good()); @@ -73,7 +73,7 @@ SCENARIO("zipfile feed with different inputs", "[zip]") zipper::Unzipper unzipper("ziptest.zip"); - THEN("the zip file has two entrys named 'test1.txt' and 'TestFolder\\test2.dat'") + AND_THEN("the zip file has two entrys named 'test1.txt' and 'TestFolder\\test2.dat'") { REQUIRE(unzipper.entries().size() == 2); REQUIRE(unzipper.entries().front().name == "test1.txt"); @@ -84,7 +84,7 @@ SCENARIO("zipfile feed with different inputs", "[zip]") unzipper.extract(); unzipper.close(); - REQUIRE(check_file_exists("TestFolder\\test2.dat")); + REQUIRE(checkFileExists("TestFolder\\test2.dat")); std::ifstream testfile("TestFolder\\test2.dat"); REQUIRE(testfile.good()); @@ -92,10 +92,41 @@ SCENARIO("zipfile feed with different inputs", "[zip]") std::string test((std::istreambuf_iterator(testfile)), std::istreambuf_iterator()); testfile.close(); REQUIRE(test == "other data to compression test"); + + AND_WHEN("adding a folder to the zip, creates one entry for each file inside the folder with the name in zip as 'Folder\\...'") + { + makedir(currentPath() + "\\TestFiles\\subfolder"); + std::ofstream test("TestFiles\\test1.txt"); + test << "test file compression"; + test.flush(); + test.close(); + + std::ofstream test1("TestFiles\\test2.pdf"); + test1 << "test file compression"; + test1.flush(); + test1.close(); + + std::ofstream test2("TestFiles\\subfolder\\test-sub.txt"); + test2 << "test file compression"; + test2.flush(); + test2.close(); + + zipper.open(); + zipper.add("TestFiles"); + zipper.close(); + + zipper::Unzipper unzipper("ziptest.zip"); + REQUIRE(unzipper.entries().size() == 5); + + unzipper.close(); + } } } std::remove("test1.txt"); + std::remove("TestFiles\\test1.txt"); + std::remove("TestFiles\\test2.pdf"); + std::remove("TestFiles\\subfolder\\test-sub.txt"); std::remove("TestFolder\\test2.dat"); std::remove("TestFolder"); } @@ -124,7 +155,7 @@ SCENARIO("zipfile feed with different inputs", "[zip]") { unzipper.extract(); - REQUIRE(check_file_exists("strdata")); + REQUIRE(checkFileExists("strdata")); std::ifstream testfile("strdata"); REQUIRE(testfile.good()); @@ -139,7 +170,7 @@ SCENARIO("zipfile feed with different inputs", "[zip]") unzipper.extract(alt_names); - REQUIRE(check_file_exists("alternative_strdata.dat")); + REQUIRE(checkFileExists("alternative_strdata.dat")); std::ifstream testfile2("alternative_strdata.dat"); REQUIRE(testfile2.good()); diff --git a/test/memory_zip_test.cpp b/test/memory_zip_test.cpp index b35a36d..5946c5f 100644 --- a/test/memory_zip_test.cpp +++ b/test/memory_zip_test.cpp @@ -46,7 +46,7 @@ SCENARIO("zip vector feed with different inputs", "[zip]") // prevent mixing the closing when both instances are freed at the end of the scope unzipper.close(); - REQUIRE(check_file_exists("test1.txt")); + REQUIRE(checkFileExists("test1.txt")); std::ifstream testfile("test1.txt"); REQUIRE(testfile.good()); @@ -83,7 +83,7 @@ SCENARIO("zip vector feed with different inputs", "[zip]") { unzipper.extract(); - REQUIRE(check_file_exists("TestFolder\\test2.dat")); + REQUIRE(checkFileExists("TestFolder\\test2.dat")); std::ifstream testfile("TestFolder\\test2.dat"); REQUIRE(testfile.good()); @@ -136,7 +136,7 @@ SCENARIO("zip vector feed with different inputs", "[zip]") { unzipper.extract(); - REQUIRE(check_file_exists("strdata")); + REQUIRE(checkFileExists("strdata")); std::ifstream testfile("strdata"); REQUIRE(testfile.good()); diff --git a/zipper/tools.cpp b/zipper/tools.cpp index 4d73554..097f128 100644 --- a/zipper/tools.cpp +++ b/zipper/tools.cpp @@ -1,5 +1,11 @@ #include "tools.h" +#if defined(_MSC_VER) && (_MSC_VER >= 1800) +namespace fs = std::tr2::sys; +#else +namespace fs = std::experimental::filesystem; +#endif + /* calculate the CRC32 of a file, because to encrypt a file, we need known the CRC32 of the file before */ @@ -11,7 +17,7 @@ void getFileCrc(std::istream& input_stream, std::vector& buff, unsigned lo do { input_stream.read(buff.data(), buff.size()); - size_read = input_stream.gcount(); + size_read = (unsigned long)input_stream.gcount(); if (size_read>0) calculate_crc = crc32(calculate_crc, (const unsigned char*)buff.data(), size_read); @@ -34,13 +40,13 @@ bool isLargeFile(std::istream& input_stream) return pos >= 0xffffffff; } -void change_file_date(const char *filename, uLong dosdate, tm_unz tmu_date) +void changeFileDate(const std::string& filename, uLong dosdate, tm_unz tmu_date) { #ifdef _WIN32 HANDLE hFile; FILETIME ftm, ftLocal, ftCreate, ftLastAcc, ftLastWrite; - hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + hFile = CreateFileA(filename.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (hFile != INVALID_HANDLE_VALUE) { GetFileTime(hFile, &ftCreate, &ftLastAcc, &ftLastWrite); @@ -66,80 +72,69 @@ void change_file_date(const char *filename, uLong dosdate, tm_unz tmu_date) newdate.tm_isdst = -1; ut.actime = ut.modtime = mktime(&newdate); - utime(filename, &ut); + utime(filename.c_str(), &ut); #endif #endif } -bool check_file_exists(const char* filename) +bool checkFileExists(const std::string& filename) { #if defined(_MSC_VER) && (_MSC_VER >= 1800) - auto file = std::tr2::sys::path(filename); - return std::tr2::sys::exists(file); + auto file = fs::path(filename); + return fs::exists(file); #else struct stat buffer; - return (stat(filename, &buffer) == 0); + return (stat(filename.c_str(), &buffer) == 0); #endif } -bool makedir(const char *newdir) +bool makedir(const std::string& newdir) { -#if defined(_MSC_VER) && (_MSC_VER >= 1800) - auto dir = std::tr2::sys::path(newdir); - if (!dir.has_parent_path()) - return true; - - return std::tr2::sys::create_directories(dir.parent_path()); -#else - char *buffer = NULL; - char *p = NULL; - int len = (int)strlen(newdir); + auto path = fs::path(newdir); + return fs::create_directories(path); +} - if (len <= 0) - return true; +void removeFolder(const std::string& foldername) +{ + auto folder = fs::path(foldername); + fs::remove_all(folder); +} - buffer = (char*)malloc(len + 1); - if (buffer == NULL) - { - printf("Error allocating memory\n"); - return false; - } +bool isDirectory(const std::string& path) +{ + auto file = fs::path(path); + return fs::is_directory(file); +} - strcpy(buffer, newdir); +std::string parentDirectory(const std::string& filepath) +{ + return fs::path(filepath).parent_path(); +} - if (buffer[len - 1] == '/') - buffer[len - 1] = 0; +std::string currentPath() +{ + return fs::current_path().string(); +} - if (MKDIR(buffer) == 0) - { - free(buffer); - return false; - } +std::vector filesFromDirectory(const std::string& path) +{ + std::vector files; - p = buffer + 1; - while (1) + auto folder = fs::path(path); + auto it = fs::recursive_directory_iterator(folder); + for (it; it != fs::recursive_directory_iterator(); ++it) { - char hold; - while (*p && *p != '\\' && *p != '/') - p++; - hold = *p; - *p = 0; - - if ((MKDIR(buffer) == -1) && (errno == ENOENT)) - { - printf("couldn't create directory %s (%d)\n", buffer, errno); - free(buffer); - return true; - } - - if (hold == 0) - break; - - *p++ = hold; - } - - free(buffer); - return false; -#endif + // file object contains absolute path in the case of recursive iterators + const auto& file = it->path(); + if (!fs::is_directory(file)) + files.push_back(file); + } + + return files; } + +std::string fileNameFromPath(const std::string& path) +{ + return fs::path(path).filename(); +} \ No newline at end of file diff --git a/zipper/tools.h b/zipper/tools.h index 91777a0..707b135 100644 --- a/zipper/tools.h +++ b/zipper/tools.h @@ -7,10 +7,15 @@ void getFileCrc(std::istream& input_stream, std::vector& buff, unsigned long& result_crc); bool isLargeFile(std::istream& input_stream); -void change_file_date(const char *filename, uLong dosdate, tm_unz tmu_date); -bool check_file_exists(const char* filename); -bool makedir(const char *newdir); - +void changeFileDate(const std::string& filename, uLong dosdate, tm_unz tmu_date); +bool checkFileExists(const std::string& filename); +bool makedir(const std::string& newdir); +void removeFolder(const std::string& foldername); +std::string parentDirectory(const std::string& filepath); +std::string currentPath(); +bool isDirectory(const std::string& path); +std::vector filesFromDirectory(const std::string& path); +std::string fileNameFromPath(const std::string& path); diff --git a/zipper/unzipper.cpp b/zipper/unzipper.cpp index 9719278..551e490 100644 --- a/zipper/unzipper.cpp +++ b/zipper/unzipper.cpp @@ -90,7 +90,7 @@ struct Unzipper::Impl int err = UNZ_ERRNO; /* If zip entry is a directory then create it on disk */ - makedir(info.name.c_str()); + makedir(parentDirectory(info.name)); /* Create the file on disk so we can unzip to it */ std::ofstream output_file(filename); @@ -106,7 +106,7 @@ struct Unzipper::Impl tm_unz timeaux; memcpy(&timeaux, &info.unixdate, sizeof(timeaux)); - change_file_date((const char*)filename.c_str(), info.dosdate, timeaux); + changeFileDate(filename, info.dosdate, timeaux); } else output_file.close(); diff --git a/zipper/zipper.cpp b/zipper/zipper.cpp index 068c498..7c6730b 100644 --- a/zipper/zipper.cpp +++ b/zipper/zipper.cpp @@ -27,7 +27,7 @@ namespace zipper { int flags = Zipper::Append; /* open the zip file for output */ - if (check_file_exists(filename.c_str())) + if (checkFileExists(filename)) mode = (flags & Zipper::Overwrite) ? APPEND_STATUS_CREATE : APPEND_STATUS_ADDINZIP; else mode = APPEND_STATUS_CREATE; @@ -149,11 +149,8 @@ namespace zipper { err = ZIP_ERRNO; if (size_read > 0) - { err = zipWriteInFileInZip(this->m_zf, buff.data(), (unsigned int)size_read); - if (err < 0) - printf("error in writing %s in the zipfile\n", nameInZip.c_str()); - } + } while ((err == ZIP_OK) && (size_read>0)); } else @@ -254,6 +251,31 @@ namespace zipper { return m_impl->add(source, nameInZip, "", flags); } + bool Zipper::add(const std::string& fileOrFolderPath, zipFlags flags) + { + if (isDirectory(fileOrFolderPath)) + { + auto folderName = fileNameFromPath(fileOrFolderPath); + std::vector files = filesFromDirectory(fileOrFolderPath); + for (auto& f : files) + { + std::ifstream input(f); + auto nameInZip = f.substr(f.find(folderName), f.size()); + add(input, nameInZip, flags); + input.close(); + } + } + else + { + std::ifstream input(fileOrFolderPath); + add(input, fileNameFromPath(fileOrFolderPath), flags); + input.close(); + } + + return true; + } + + void Zipper::open() { if (!m_open) diff --git a/zipper/zipper.h b/zipper/zipper.h index 0a83089..d644314 100644 --- a/zipper/zipper.h +++ b/zipper/zipper.h @@ -23,6 +23,7 @@ namespace zipper { ~Zipper(void); bool add(std::istream& source, const std::string& nameInZip = std::string(), zipFlags flags = Better); + bool add(const std::string& fileOrFolderPath, zipFlags flags = Better); void open(); void close();