LCOV - code coverage report
Current view: top level - apps - sozip.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 138 152 90.8 %
Date: 2025-05-15 13:16:46 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Utilities
       4             :  * Purpose:  Command line application to build seek-optimized ZIP files
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2022, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_string.h"
      14             : #include "gdalalgorithm.h"
      15             : #include "commonutils.h"
      16             : #include "gdalargumentparser.h"
      17             : 
      18             : #include <cassert>
      19             : 
      20             : /************************************************************************/
      21             : /*                                main()                                */
      22             : /************************************************************************/
      23             : 
      24          11 : MAIN_START(nArgc, papszArgv)
      25             : {
      26          11 :     EarlySetConfigOptions(nArgc, papszArgv);
      27          11 :     nArgc = GDALGeneralCmdLineProcessor(nArgc, &papszArgv, 0);
      28          21 :     CPLStringList aosArgv;
      29          11 :     aosArgv.Assign(papszArgv, /* bTakeOwnership= */ true);
      30          11 :     if (nArgc < 1)
      31           1 :         std::exit(-nArgc);
      32             : 
      33          30 :     GDALArgumentParser argParser(aosArgv[0], /* bForBinary=*/true);
      34             : 
      35          10 :     argParser.add_description(_("Generate a seek-optimized ZIP (SOZip) file."));
      36             : 
      37             :     argParser.add_epilog(
      38          10 :         _("For more details, consult https://gdal.org/programs/sozip.html"));
      39             : 
      40          20 :     std::string osZipFilename;
      41          10 :     argParser.add_argument("zip_filename")
      42          20 :         .metavar("<zip_filename>")
      43          10 :         .store_into(osZipFilename)
      44          10 :         .help(_("ZIP filename."));
      45             : 
      46          10 :     bool bRecurse = false;
      47          10 :     argParser.add_argument("-r", "--recurse-paths")
      48          10 :         .store_into(bRecurse)
      49             :         .help(_("Travels the directory structure of the specified directories "
      50          10 :                 "recursively."));
      51             : 
      52          10 :     bool bOverwrite = false;
      53             :     {
      54          10 :         auto &group = argParser.add_mutually_exclusive_group();
      55          10 :         group.add_argument("-g", "--grow")
      56          10 :             .flag()  // Default mode. Nothing to do
      57             :             .help(
      58             :                 _("Grow an existing zip file with the content of the specified "
      59          10 :                   "filename(s). Default mode."));
      60          10 :         group.add_argument("--overwrite")
      61          10 :             .store_into(bOverwrite)
      62          10 :             .help(_("Overwrite the target zip file if it already exists."));
      63             :     }
      64             : 
      65          10 :     bool bList = false;
      66          10 :     bool bValidate = false;
      67          20 :     std::string osOptimizeFrom;
      68          20 :     std::vector<std::string> aosFiles;
      69             :     {
      70          10 :         auto &group = argParser.add_mutually_exclusive_group();
      71          10 :         group.add_argument("-l", "--list")
      72          10 :             .store_into(bList)
      73          10 :             .help(_("List the files contained in the zip file."));
      74          10 :         group.add_argument("--validate")
      75          10 :             .store_into(bValidate)
      76          10 :             .help(_("Validates a ZIP/SOZip file."));
      77          10 :         group.add_argument("--optimize-from")
      78          20 :             .metavar("<input.zip>")
      79          10 :             .store_into(osOptimizeFrom)
      80             :             .help(
      81          10 :                 _("Re-process {input.zip} to generate a SOZip-optimized .zip"));
      82          10 :         group.add_argument("input_files")
      83          20 :             .metavar("<input_files>")
      84          10 :             .store_into(aosFiles)
      85          20 :             .help(_("Filename of the file to add."))
      86          10 :             .nargs(argparse::nargs_pattern::any);
      87             :     }
      88             : 
      89          10 :     bool bQuiet = false;
      90          10 :     bool bVerbose = false;
      91          10 :     argParser.add_group("Advanced options");
      92             :     {
      93          10 :         auto &group = argParser.add_mutually_exclusive_group();
      94          10 :         group.add_argument("--quiet").store_into(bQuiet).help(
      95             :             _("Quiet mode. No progress message is emitted on the standard "
      96          10 :               "output."));
      97          10 :         group.add_argument("--verbose")
      98          10 :             .store_into(bVerbose)
      99          10 :             .help(_("Verbose mode."));
     100             :     }
     101          10 :     bool bJunkPaths = false;
     102          10 :     argParser.add_argument("-j", "--junk-paths")
     103          10 :         .store_into(bJunkPaths)
     104             :         .help(
     105             :             _("Store just the name of a saved file (junk the path), and do not "
     106          10 :               "store directory names."));
     107             : 
     108          20 :     CPLStringList aosOptions;
     109          10 :     argParser.add_argument("--enable-sozip")
     110          10 :         .choices("auto", "yes", "no")
     111          20 :         .metavar("auto|yes|no")
     112           3 :         .action([&aosOptions](const std::string &s)
     113          13 :                 { aosOptions.SetNameValue("SOZIP_ENABLED", s.c_str()); })
     114             :         .help(_("In auto mode, a file is seek-optimized only if its size is "
     115             :                 "above the value of\n"
     116             :                 "--sozip-chunk-size. In yes mode, all input files will be "
     117             :                 "seek-optimized.\n"
     118          10 :                 "In no mode, no input files will be seek-optimized."));
     119          10 :     argParser.add_argument("--sozip-chunk-size")
     120          20 :         .metavar("<value in bytes or with K/M suffix>")
     121           4 :         .action([&aosOptions](const std::string &s)
     122          14 :                 { aosOptions.SetNameValue("SOZIP_CHUNK_SIZE", s.c_str()); })
     123             :         .help(_(
     124          10 :             "Chunk size for a seek-optimized file. Defaults to 32768 bytes."));
     125          10 :     argParser.add_argument("--sozip-min-file-size")
     126          20 :         .metavar("<value in bytes or with K/M/G suffix>")
     127           1 :         .action([&aosOptions](const std::string &s)
     128          11 :                 { aosOptions.SetNameValue("SOZIP_MIN_FILE_SIZE", s.c_str()); })
     129             :         .help(
     130             :             _("Minimum file size to decide if a file should be seek-optimized. "
     131          10 :               "Defaults to 1 MB byte."));
     132          10 :     argParser.add_argument("--content-type")
     133          20 :         .metavar("<string>")
     134           1 :         .action([&aosOptions](const std::string &s)
     135          11 :                 { aosOptions.SetNameValue("CONTENT_TYPE", s.c_str()); })
     136          10 :         .help(_("Store the Content-Type for the file being added."));
     137             : 
     138             :     try
     139             :     {
     140          10 :         argParser.parse_args(aosArgv);
     141             :     }
     142           0 :     catch (const std::exception &err)
     143             :     {
     144           0 :         argParser.display_error_and_usage(err);
     145           0 :         std::exit(1);
     146             :     }
     147             : 
     148          10 :     if (!bList && !bValidate && osOptimizeFrom.empty() && aosFiles.empty())
     149             :     {
     150           0 :         std::cerr << _("Missing source filename(s)") << std::endl << std::endl;
     151           0 :         std::cerr << argParser << std::endl;
     152           0 :         std::exit(1);
     153             :     }
     154             : 
     155          10 :     const char *pszZipFilename = osZipFilename.c_str();
     156          10 :     if (!EQUAL(CPLGetExtensionSafe(pszZipFilename).c_str(), "zip"))
     157             :     {
     158           0 :         std::cerr << _("Extension of zip filename should be .zip") << std::endl
     159           0 :                   << std::endl;
     160           0 :         std::cerr << argParser << std::endl;
     161           0 :         std::exit(1);
     162             :     }
     163             : 
     164          10 :     auto alg = GDALGlobalAlgorithmRegistry::GetSingleton().Instantiate(
     165          30 :         GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME);
     166          10 :     assert(alg);
     167             : 
     168          20 :     std::vector<std::string> args;
     169          10 :     args.push_back("vsi");
     170          10 :     args.push_back("sozip");
     171             : 
     172          10 :     if (bValidate)
     173             :     {
     174           3 :         args.push_back("validate");
     175           3 :         if (bVerbose)
     176           1 :             args.push_back("--verbose");
     177           3 :         args.push_back(pszZipFilename);
     178             :     }
     179           7 :     else if (bList)
     180             :     {
     181           1 :         args.push_back("list");
     182           1 :         args.push_back(pszZipFilename);
     183             :     }
     184             :     else
     185             :     {
     186           6 :         args.push_back(osOptimizeFrom.empty() ? "create" : "optimize");
     187           6 :         if (bRecurse)
     188           1 :             args.push_back("--recurse");
     189           6 :         if (bJunkPaths)
     190           5 :             args.push_back("--junk-paths");
     191           6 :         if (bOverwrite)
     192           1 :             args.push_back("--overwrite");
     193           6 :         if (const char *val = aosOptions.FetchNameValue("SOZIP_ENABLED"))
     194             :         {
     195           3 :             args.push_back("--enable-sozip");
     196           3 :             args.push_back(val);
     197             :         }
     198           6 :         if (const char *val = aosOptions.FetchNameValue("SOZIP_CHUNK_SIZE"))
     199             :         {
     200           4 :             args.push_back("--sozip-chunk-size");
     201           4 :             args.push_back(val);
     202             :         }
     203           6 :         if (const char *val = aosOptions.FetchNameValue("SOZIP_MIN_FILE_SIZE"))
     204             :         {
     205           1 :             args.push_back("--sozip-min-file-size");
     206           1 :             args.push_back(val);
     207             :         }
     208           6 :         if (const char *val = aosOptions.FetchNameValue("CONTENT_TYPE"))
     209             :         {
     210           1 :             args.push_back("--content-type");
     211           1 :             args.push_back(val);
     212             :         }
     213           6 :         if (osOptimizeFrom.empty())
     214             :         {
     215          10 :             for (const auto &s : aosFiles)
     216             :             {
     217           5 :                 args.push_back(s);
     218             :             }
     219             :         }
     220             :         else
     221             :         {
     222           1 :             args.push_back(std::move(osOptimizeFrom));
     223             :         }
     224           6 :         args.push_back(pszZipFilename);
     225             :     }
     226             : 
     227          10 :     if (!alg->ParseCommandLineArguments(args))
     228             :     {
     229           0 :         fprintf(stderr, "%s", alg->GetUsageForCLI(true).c_str());
     230           0 :         return 1;
     231             :     }
     232             : 
     233             :     {
     234          10 :         const auto stdoutArg = alg->GetActualAlgorithm().GetArg("stdout");
     235          10 :         if (stdoutArg && stdoutArg->GetType() == GAAT_BOOLEAN)
     236           9 :             stdoutArg->Set(true);
     237             :     }
     238             : 
     239             :     GDALProgressFunc pfnProgress =
     240          10 :         alg->IsProgressBarRequested() ? GDALTermProgress : nullptr;
     241          10 :     void *pProgressData = nullptr;
     242             : 
     243          10 :     alg->SetCalledFromCommandLine();
     244             : 
     245          10 :     int ret = 0;
     246          10 :     if (alg->Run(pfnProgress, pProgressData) && alg->Finalize())
     247             :     {
     248             :         const auto outputArg =
     249          10 :             alg->GetActualAlgorithm().GetArg("output-string");
     250          20 :         if (outputArg && outputArg->GetType() == GAAT_STRING &&
     251          10 :             outputArg->IsOutput())
     252             :         {
     253          10 :             printf("%s", outputArg->Get<std::string>().c_str());
     254             :         }
     255             :     }
     256             :     else
     257             :     {
     258           0 :         ret = 1;
     259             :     }
     260             : 
     261          10 :     return ret;
     262             : }
     263             : 
     264           0 : MAIN_END

Generated by: LCOV version 1.14