diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1e45146e1..19d21193c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -105,7 +105,7 @@ jobs: container: ${{ matrix.container }} strategy: matrix: - container: ['ubuntu:20.04', 'ubuntu:22.04', 'ubuntu:23.04', 'ubuntu:23.10'] + container: ['ubuntu:20.04', 'ubuntu:22.04', 'ubuntu:23.10'] env: DEBIAN_FRONTEND: noninteractive DEBFULLNAME: github-actions diff --git a/examples/DigiDocCSharp/DigiDocCSharp.csproj b/examples/DigiDocCSharp/DigiDocCSharp.csproj index 9ed490dbe..39be3b098 100644 --- a/examples/DigiDocCSharp/DigiDocCSharp.csproj +++ b/examples/DigiDocCSharp/DigiDocCSharp.csproj @@ -2,7 +2,7 @@ Debug - x86 + x64 8.0.30703 2.0 {DDEE2029-EA2A-49D2-80CB-F0E2E396B005} @@ -10,12 +10,11 @@ Properties DigiDocCSharp DigiDocCSharp - v4.0 - Client + v4.7.2 512 - - x86 + + x64 true full false @@ -25,8 +24,8 @@ 4 true - - x86 + + x64 pdbonly true bin\Release\ diff --git a/examples/DigiDocCSharp/DigiDocCSharp.sln b/examples/DigiDocCSharp/DigiDocCSharp.sln index 7cdf7b5e2..c599b3085 100644 --- a/examples/DigiDocCSharp/DigiDocCSharp.sln +++ b/examples/DigiDocCSharp/DigiDocCSharp.sln @@ -5,14 +5,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DigiDocCSharp", "DigiDocCSh EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x86 = Debug|x86 - Release|x86 = Release|x86 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {DDEE2029-EA2A-49D2-80CB-F0E2E396B005}.Debug|x86.ActiveCfg = Debug|x86 - {DDEE2029-EA2A-49D2-80CB-F0E2E396B005}.Debug|x86.Build.0 = Debug|x86 - {DDEE2029-EA2A-49D2-80CB-F0E2E396B005}.Release|x86.ActiveCfg = Release|x86 - {DDEE2029-EA2A-49D2-80CB-F0E2E396B005}.Release|x86.Build.0 = Release|x86 + {DDEE2029-EA2A-49D2-80CB-F0E2E396B005}.Debug|x64.ActiveCfg = Debug|x64 + {DDEE2029-EA2A-49D2-80CB-F0E2E396B005}.Debug|x64.Build.0 = Debug|x64 + {DDEE2029-EA2A-49D2-80CB-F0E2E396B005}.Release|x64.ActiveCfg = Release|x64 + {DDEE2029-EA2A-49D2-80CB-F0E2E396B005}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/examples/DigiDocCSharp/Program.cs b/examples/DigiDocCSharp/Program.cs index 731d69af5..4e0dab4b9 100644 --- a/examples/DigiDocCSharp/Program.cs +++ b/examples/DigiDocCSharp/Program.cs @@ -184,7 +184,8 @@ private static void Verify(string file) try { Console.WriteLine("Opening file: " + file); - Container b = Container.open(file); + var cb = new ContainerOpen(); + Container b = Container.open(file, cb); Console.WriteLine("Files:"); foreach (DataFile d in b.dataFiles()) @@ -226,4 +227,9 @@ private static void Version() " libdigidocpp " + digidoc.digidoc.version()); } } + + class ContainerOpen : ContainerOpenCB + { + override public bool validateOnline() { return true; } + } } diff --git a/examples/java/README.md b/examples/java/README.md index 0aeebec8f..62857a779 100644 --- a/examples/java/README.md +++ b/examples/java/README.md @@ -6,4 +6,4 @@ ## Run - java -Djava.library.path=/Library/libdigidocpp/lib -jar build/libs/libdigidoc.jar \ No newline at end of file + java -Djava.library.path=/some/path/lib -jar build/libs/libdigidoc.jar \ No newline at end of file diff --git a/examples/java/gradle/wrapper/gradle-wrapper.jar b/examples/java/gradle/wrapper/gradle-wrapper.jar index ccebba771..7f93135c4 100644 Binary files a/examples/java/gradle/wrapper/gradle-wrapper.jar and b/examples/java/gradle/wrapper/gradle-wrapper.jar differ diff --git a/examples/java/gradle/wrapper/gradle-wrapper.properties b/examples/java/gradle/wrapper/gradle-wrapper.properties index c30b486a8..3fa8f862f 100644 --- a/examples/java/gradle/wrapper/gradle-wrapper.properties +++ b/examples/java/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/examples/java/gradlew b/examples/java/gradlew index 79a61d421..0adc8e1a5 100755 --- a/examples/java/gradlew +++ b/examples/java/gradlew @@ -83,10 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,10 +131,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -197,6 +198,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in diff --git a/examples/java/src/main/java/ee/ria/libdigidocpp/libdigidocpp.java b/examples/java/src/main/java/ee/ria/libdigidocpp/libdigidocpp.java index 5fdabd498..5ff995e76 100644 --- a/examples/java/src/main/java/ee/ria/libdigidocpp/libdigidocpp.java +++ b/examples/java/src/main/java/ee/ria/libdigidocpp/libdigidocpp.java @@ -133,7 +133,8 @@ static void verify(String file) { try { System.out.println("Opening file: " + file); - Container b = Container.open(file); + ContainerOpen cb = new ContainerOpen(); + Container b = Container.open(file, cb); assert b != null; System.out.println("Files:"); @@ -200,4 +201,10 @@ static byte[] fromHex(String s) { } return data; } + + static private class ContainerOpen extends ContainerOpenCB + { + @Override + public boolean validateOnline() { return true; } + } } diff --git a/examples/python/main.py b/examples/python/main.py index 05e4249bb..68e687eaf 100644 --- a/examples/python/main.py +++ b/examples/python/main.py @@ -2,6 +2,13 @@ import sys import os +class ContainerOpenCB(digidoc.ContainerOpenCB): + + def __init__(self): + digidoc.ContainerOpenCB.__init__(self) + + def validateOnline(self): + return True class Program: digidoc.initialize() @@ -78,7 +85,8 @@ def sign(self, args): def verify(self, file): print("Opening file: " + file) - doc = digidoc.Container.open(file) + cb = ContainerOpenCB() + doc = digidoc.Container.open(file, cb) print("Files:") for d in doc.dataFiles(): diff --git a/libdigidocpp.dox b/libdigidocpp.dox index 9375cb6d5..031ec80f1 100644 --- a/libdigidocpp.dox +++ b/libdigidocpp.dox @@ -1380,6 +1380,8 @@ Signature Validation Policy Default POLv2 http://open-eid.github.io/SiVa/siva/appendix/validation_policy/ +\-\-offline Optional +open container offline (eg. Don't send to SiVa) \-\-warnings= (ignore, warning, error) Optional diff --git a/libdigidocpp.i b/libdigidocpp.i index f265c3322..f64ba3ee0 100644 --- a/libdigidocpp.i +++ b/libdigidocpp.i @@ -19,7 +19,7 @@ // digidocpp.i - SWIG interface for libdigidocpp library -%module digidoc +%module(directors="1") digidoc %begin %{ #ifdef _MSC_VER @@ -231,6 +231,8 @@ extern "C" %newobject digidoc::Container::open; %newobject digidoc::Container::create; +%feature("director") digidoc::ContainerOpenCB; + %typemap(javacode) digidoc::Conf %{ public Conf transfer() { swigCMemOwn = false; @@ -318,16 +320,21 @@ namespace std { } } %extend digidoc::Container { + static digidoc::Container* open(const std::string &path, digidoc::ContainerOpenCB *cb) + { + return digidoc::Container::openPtr(path, cb).release(); + } + digidoc::Signature* prepareWebSignature(const std::vector &cert, const std::string &profile = {}, const std::vector &roles = {}, const std::string &city = {}, const std::string &state = {}, const std::string &postalCode = {}, const std::string &country = {}) { - class : public digidoc::Signer + class final: public digidoc::Signer { public: - digidoc::X509Cert cert() const override { return _cert; } - std::vector sign(const std::string &, const std::vector &) const override + digidoc::X509Cert cert() const final { return _cert; } + std::vector sign(const std::string &, const std::vector &) const final { THROW("Not implemented"); } diff --git a/src/ASiC_S.cpp b/src/ASiC_S.cpp index f7c7e6fec..15e0d2151 100644 --- a/src/ASiC_S.cpp +++ b/src/ASiC_S.cpp @@ -102,7 +102,7 @@ void ASiC_S::addAdESSignature(istream & /*signature*/) THROW("Not implemented."); } -unique_ptr ASiC_S::openInternal(const string &path) +unique_ptr ASiC_S::openInternal(const string &path, ContainerOpenCB * /*cb*/) { if (!isContainerSimpleFormat(path)) return {}; diff --git a/src/ASiC_S.h b/src/ASiC_S.h index 95c9483ef..3af245268 100644 --- a/src/ASiC_S.h +++ b/src/ASiC_S.h @@ -41,7 +41,7 @@ namespace digidoc Signature* sign(Signer* signer) override; static std::unique_ptr createInternal(const std::string &path); - static std::unique_ptr openInternal(const std::string &path); + static std::unique_ptr openInternal(const std::string &path, ContainerOpenCB *cb); private: ASiC_S(); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c55e19fb4..0d257c71a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -271,13 +271,11 @@ if(SWIG_FOUND) target_include_directories(digidoc_java PRIVATE ${JAVA_INCLUDE_PATH} $<$:${JAVA_INCLUDE_PATH2}>) target_compile_definitions(digidoc_java PRIVATE TARGET_NAME="$") target_link_libraries(digidoc_java digidocpp digidocpp_util digidocpp_ver) - set_property(TARGET digidoc_java PROPERTY SWIG_COMPILE_DEFINITIONS $<$:SWIGWIN>) - if(APPLE) - set_target_properties(digidoc_java PROPERTIES MACOSX_RPATH YES INSTALL_RPATH /Library/Frameworks) - install(TARGETS digidoc_java DESTINATION /Library/Java/Extensions) - else() - install(TARGETS digidoc_java DESTINATION ${CMAKE_INSTALL_LIBDIR}) - endif() + set_target_properties(digidoc_java PROPERTIES + INSTALL_RPATH $<$:/Library/Frameworks> + SWIG_COMPILE_DEFINITIONS $<$:SWIGWIN> + ) + install(TARGETS digidoc_java DESTINATION $,/Library/Java/Extensions,${CMAKE_INSTALL_LIBDIR}>) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/java/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ee/ria/libdigidocpp FILES_MATCHING PATTERN "*.java") if(WIN32) install(FILES $ DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL) @@ -289,7 +287,6 @@ if(SWIG_FOUND) swig_add_library(digidoc_python LANGUAGE python SOURCES ../libdigidocpp.i) target_compile_definitions(digidoc_python PRIVATE TARGET_NAME="$") target_link_libraries(digidoc_python digidocpp digidocpp_util digidocpp_ver Python3::Module) - set_property(TARGET digidoc_python PROPERTY SWIG_COMPILE_DEFINITIONS $<$:SWIGWIN>) #configure_file(setup.py.cmake setup.py) #install(CODE "execute_process(COMMAND python3 ${CMAKE_CURRENT_BINARY_DIR}/setup.py install)") if(NOT Python3_SITELIB) @@ -303,6 +300,10 @@ if(SWIG_FOUND) else() set_target_properties(digidoc_python PROPERTIES SUFFIX .so) endif() + set_target_properties(digidoc_python PROPERTIES + INSTALL_RPATH $<$:/Library/Frameworks> + SWIG_COMPILE_DEFINITIONS $<$:SWIGWIN> + ) install(TARGETS digidoc_python DESTINATION ${Python3_SITELIB}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/digidoc.py DESTINATION ${Python3_SITELIB}) endif() diff --git a/src/Container.cpp b/src/Container.cpp index d8bca3069..8592a5d35 100644 --- a/src/Container.cpp +++ b/src/Container.cpp @@ -68,7 +68,8 @@ namespace digidoc static string m_appName = "libdigidocpp"; static string m_userAgent = "libdigidocpp"; static vector m_createList {}; -static vector m_openList {}; +using OpenCB = std::unique_ptr (*)(const std::string &path, ContainerOpenCB *cb); +static vector m_openList {}; } /** @@ -96,14 +97,7 @@ string digidoc::userAgent() { return m_userAgent; } * Returns libdigidocpp library version */ string digidoc::version() { - string ver = FILE_VER_STR; -#if defined(DYNAMIC_LIBDIGIDOC) || defined(LINKED_LIBDIGIDOC) - ver += "_ddoc"; -#endif -#ifdef PDF_SUPPORT - ver += "_siva"; -#endif - return ver; + return FILE_VER_STR; } /** @@ -348,10 +342,22 @@ Container* Container::open(const string &path) * @throws Exception */ unique_ptr Container::openPtr(const string &path) +{ + return openPtr(path, {}); +} + +/** + * Opens container from a file + * + * @param path + * @param cb Callback called when needed + * @throws Exception + */ +unique_ptr Container::openPtr(const string &path, ContainerOpenCB *cb) { for(auto open: m_openList) { - if(unique_ptr container = open(path)) + if(unique_ptr container = open(path, cb)) return container; } return ASiC_E::openInternal(path); @@ -417,7 +423,7 @@ unique_ptr Container::openPtr(const string &path) * * It must contain static members: * * static Container* createInternal(const std::string &path); - * * static Container* openInternal(const std::string &path); + * * static Container* openInternal(const std::string &path, digidoc::ContainerOpenCB *cb); * * @see Container::create, Container::open */ diff --git a/src/Container.h b/src/Container.h index c2f9ac6d7..92655e978 100644 --- a/src/Container.h +++ b/src/Container.h @@ -40,6 +40,11 @@ DIGIDOCPP_EXPORT void terminate(); DIGIDOCPP_EXPORT std::string userAgent(); DIGIDOCPP_EXPORT std::string version(); +struct ContainerOpenCB { + virtual ~ContainerOpenCB() = default; + virtual bool validateOnline() const { return true; } +}; + class DIGIDOCPP_EXPORT Container { public: @@ -66,6 +71,7 @@ class DIGIDOCPP_EXPORT Container static std::unique_ptr createPtr(const std::string &path); DIGIDOCPP_DEPRECATED static Container* open(const std::string &path); static std::unique_ptr openPtr(const std::string &path); + static std::unique_ptr openPtr(const std::string &path, digidoc::ContainerOpenCB *cb); template static void addContainerImplementation(); diff --git a/src/SiVaContainer.cpp b/src/SiVaContainer.cpp index 180612146..efafa5494 100644 --- a/src/SiVaContainer.cpp +++ b/src/SiVaContainer.cpp @@ -144,15 +144,14 @@ void SignatureSiVa::validate(const string &policy) const } -SiVaContainer::SiVaContainer(const string &path, bool useHashCode) +SiVaContainer::SiVaContainer(const string &path, ContainerOpenCB *cb, bool useHashCode) : d(make_unique()) { - string ext = File::fileExtension(path); - DEBUG("SiVaContainer::SiVaContainer(%s, %s, %d)", path.c_str(), ext.c_str(), useHashCode); + DEBUG("SiVaContainer::SiVaContainer(%s, %d)", path.c_str(), useHashCode); unique_ptr ifs = make_unique(File::encodeName(d->path = path), ifstream::binary); auto fileName = File::fileName(path); + auto ext = File::fileExtension(path); istream *is = ifs.get(); - static const array asic {"asice", "sce", "asics", "scs"}; if(ext == "ddoc") { d->mediaType = "application/x-ddoc"; @@ -165,8 +164,10 @@ SiVaContainer::SiVaContainer(const string &path, bool useHashCode) d->mediaType = "application/pdf"; d->dataFiles.push_back(new DataFilePrivate(std::move(ifs), fileName, "application/pdf")); } - else if(find(asic.cbegin(), asic.cend(), ext) != asic.cend()) + else if(static const array asic {"asice", "sce", "asics", "scs"}; + find(asic.cbegin(), asic.cend(), ext) != asic.cend()) { + static const string_view metaInf = "META-INF/"; ZipSerialize z(path, false); vector list = z.list(); if(list.empty() || list.front() != "mimetype") @@ -174,13 +175,16 @@ SiVaContainer::SiVaContainer(const string &path, bool useHashCode) if(d->mediaType = ASiContainer::readMimetype(z); d->mediaType != ASiContainer::MIMETYPE_ASIC_E && d->mediaType != ASiContainer::MIMETYPE_ASIC_S) THROW("Unknown file"); - if(none_of(list.cbegin(), list.cend(), [](const string &file) { return file.find("p7s") != string::npos; })) + if(static const string_view suffix = "META-INF/"; + none_of(list.cbegin(), list.cend(), [](const string &file) { + auto index = file.size() - suffix.size(); + return file.size() > suffix.size() && file.rfind(metaInf, 0) == 0 && file.find(suffix, index) == index; + })) THROW("Unknown file"); - static const string metaInf = "META-INF/"; for(const string &file: list) { - if(file == "mimetype" || file.substr(0, metaInf.size()) == metaInf) + if(file == "mimetype" || file.rfind(metaInf, 0) == 0) continue; const auto directory = File::directory(file); if(directory.empty() || directory == "/" || directory == "./") @@ -194,6 +198,9 @@ SiVaContainer::SiVaContainer(const string &path, bool useHashCode) else THROW("Unknown file"); + if(cb && !cb->validateOnline()) + THROW("Online validation disabled"); + array buf{}; string b64; is->clear(); @@ -220,6 +227,7 @@ SiVaContainer::SiVaContainer(const string &path, bool useHashCode) Connect::Result r = Connect(CONF(verifyServiceUri), "POST", 0, CONF(verifyServiceCerts)).exec({ {"Content-Type", "application/json;charset=UTF-8"} }, (const unsigned char*)req.c_str(), req.size()); + req.clear(); if(!r.isOK() && !r.isStatusCode("400")) THROW("Failed to send request to SiVa"); @@ -287,7 +295,7 @@ SiVaContainer::SiVaContainer(const string &path, bool useHashCode) for(const json &error: signature.value("errors", {})) { string message = error["content"]; - if(message.find("Bad digest for DataFile") == 0 && useHashCode) + if(message.find("Bad digest for DataFile", 0) != string::npos && useHashCode) THROW("%s", message.c_str()); s->_exceptions.emplace_back(EXCEPTION_PARAMS("%s", message.c_str())); } @@ -298,7 +306,7 @@ SiVaContainer::SiVaContainer(const string &path, bool useHashCode) if(message == "X509IssuerName has none or invalid namespace: null" || message == "X509SerialNumber has none or invalid namespace: null") ex.setCode(Exception::IssuerNameSpaceWarning); - else if(message.find("Bad digest for DataFile") == 0) + else if(message.find("Bad digest for DataFile") != string::npos) ex.setCode(Exception::DataFileNameSpaceWarning); else if(message == "Old and unsupported format: SK-XML version: 1.0") continue; @@ -344,15 +352,15 @@ vector SiVaContainer::dataFiles() const return d->dataFiles; } -unique_ptr SiVaContainer::openInternal(const string &path) +unique_ptr SiVaContainer::openInternal(const string &path, ContainerOpenCB *cb) { try { - return unique_ptr(new SiVaContainer(path, true)); + return unique_ptr(new SiVaContainer(path, cb, true)); } catch(const Exception &e) { - if(e.msg().find("Bad digest for DataFile") == 0) - return unique_ptr(new SiVaContainer(path, false)); + if(e.msg().find("Bad digest for DataFile") != string::npos) + return unique_ptr(new SiVaContainer(path, cb, false)); if(e.msg() == "Unknown file") - return {}; + return {}; throw; } } diff --git a/src/SiVaContainer.h b/src/SiVaContainer.h index ce93edff7..9624771ff 100644 --- a/src/SiVaContainer.h +++ b/src/SiVaContainer.h @@ -99,13 +99,13 @@ class SiVaContainer final: public Container Signature* sign(Signer* signer) final; static std::unique_ptr createInternal(const std::string &path); - static std::unique_ptr openInternal(const std::string &path); + static std::unique_ptr openInternal(const std::string &path, ContainerOpenCB *cb); private: - SiVaContainer(const std::string &path, bool useHashCode); + SiVaContainer(const std::string &path, ContainerOpenCB *cb, bool useHashCode); DISABLE_COPY(SiVaContainer); - std::unique_ptr parseDDoc(bool useHashCode); + std::unique_ptr parseDDoc(bool useHashCode); class Private; std::unique_ptr d; diff --git a/src/digidoc-tool.1.cmake b/src/digidoc-tool.1.cmake index 79c2b5844..857a9e18d 100644 --- a/src/digidoc-tool.1.cmake +++ b/src/digidoc-tool.1.cmake @@ -27,6 +27,7 @@ Command open: http://open-eid.github.io/SiVa/siva/appendix/validation_policy/ --extractAll[=path] - extracts documents without validating signatures (to path when provided) --validateOnExtract - validates container before extracting files + --offline - open container offline (eg. Don't send to SiVa) Command add: Example: digidoc-tool add --file=file1.txt container-file.asice diff --git a/src/digidoc-tool.cpp b/src/digidoc-tool.cpp index 70e496f49..dd67d56b4 100644 --- a/src/digidoc-tool.cpp +++ b/src/digidoc-tool.cpp @@ -326,6 +326,7 @@ static int printUsage(const char *executable) << " http://open-eid.github.io/SiVa/siva/appendix/validation_policy/" << endl << " --extractAll[=path] - extracts documents without validating signatures (to path when provided)" << endl << " --validateOnExtract - validates container before extracting files" << endl << endl + << " --offline - open container offline (eg. Don't send to SiVa)" << endl << endl << " Command add:" << endl << " Example: " << executable << " add --file=file1.txt container-file.asice" << endl << " Available options:" << endl @@ -539,6 +540,11 @@ static int open(int argc, char* argv[]) fs::path extractPath; bool validateOnExtract = false; int returnCode = EXIT_SUCCESS; + struct OpenCB final: public ContainerOpenCB + { + bool online = true; + bool validateOnline() const final { return online; } + } cb; // Parse command line arguments. for(int i = 2; i < argc; i++) @@ -566,6 +572,8 @@ static int open(int argc, char* argv[]) validateOnExtract = true; else if(arg.find("--policy=") == 0) policy = arg.substr(9); + else if(arg.find("--offline") == 0) + cb.online = false; else path = arg; } @@ -575,7 +583,7 @@ static int open(int argc, char* argv[]) unique_ptr doc; try { - doc = Container::openPtr(path); + doc = Container::openPtr(path, &cb); } catch(const Exception &e) { cout << "Failed to parse container" << endl; cout << " Exception:" << endl << e;