303 lines
9.9 KiB
C++
303 lines
9.9 KiB
C++
/******************************************************************************
|
|
*
|
|
* Project: GDAL Utilities
|
|
* Purpose: Command line utility for GDAL identify, delete, rename and copy
|
|
* (by file) operations.
|
|
* Author: Frank Warmerdam, warmerdam@pobox.com
|
|
*
|
|
* ****************************************************************************
|
|
* Copyright (c) 2007, Frank Warmerdam
|
|
* Copyright (c) 2008-2009, Even Rouault <even dot rouault at spatialys.com>
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
****************************************************************************/
|
|
|
|
#include "cpl_string.h"
|
|
#include "cpl_conv.h"
|
|
#include "gdal_version.h"
|
|
#include "gdal.h"
|
|
#include "commonutils.h"
|
|
#include "gdalargumentparser.h"
|
|
|
|
/************************************************************************/
|
|
/* GDALManageOptions() */
|
|
/************************************************************************/
|
|
|
|
struct GDALManageOptions
|
|
{
|
|
bool bRecursive = false;
|
|
bool bForceRecurse = false;
|
|
bool bReportFailures = false;
|
|
std::string osNewName;
|
|
std::string osDatasetName;
|
|
std::vector<std::string> aosDatasetNames;
|
|
std::string osDriverName;
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* ProcessIdentifyTarget() */
|
|
/************************************************************************/
|
|
|
|
static void ProcessIdentifyTarget(const char *pszTarget,
|
|
char **papszSiblingList, bool bRecursive,
|
|
bool bReportFailures, bool bForceRecurse)
|
|
|
|
{
|
|
GDALDriverH hDriver;
|
|
VSIStatBufL sStatBuf;
|
|
int i;
|
|
|
|
hDriver = GDALIdentifyDriver(pszTarget, papszSiblingList);
|
|
|
|
if (hDriver != nullptr)
|
|
printf("%s: %s\n", pszTarget, GDALGetDriverShortName(hDriver));
|
|
else if (bReportFailures)
|
|
printf("%s: unrecognized\n", pszTarget);
|
|
|
|
if (!bForceRecurse && (!bRecursive || hDriver != nullptr))
|
|
return;
|
|
|
|
if (VSIStatL(pszTarget, &sStatBuf) != 0 || !VSI_ISDIR(sStatBuf.st_mode))
|
|
return;
|
|
|
|
papszSiblingList = VSIReadDir(pszTarget);
|
|
for (i = 0; papszSiblingList && papszSiblingList[i]; i++)
|
|
{
|
|
if (EQUAL(papszSiblingList[i], "..") || EQUAL(papszSiblingList[i], "."))
|
|
continue;
|
|
|
|
CPLString osSubTarget =
|
|
CPLFormFilename(pszTarget, papszSiblingList[i], nullptr);
|
|
|
|
ProcessIdentifyTarget(osSubTarget, papszSiblingList, bRecursive,
|
|
bReportFailures, bForceRecurse);
|
|
}
|
|
CSLDestroy(papszSiblingList);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALManageAppOptionsGetParser() */
|
|
/************************************************************************/
|
|
|
|
static std::unique_ptr<GDALArgumentParser>
|
|
GDALManageAppOptionsGetParser(GDALManageOptions *psOptions)
|
|
{
|
|
auto argParser = std::make_unique<GDALArgumentParser>(
|
|
"gdalmanage", /* bForBinary */ true);
|
|
|
|
argParser->add_description(
|
|
_("Identify, delete, rename and copy raster data files."));
|
|
argParser->add_epilog(_("For more details, consult the full documentation "
|
|
"for the gdalmanage utility "
|
|
"https://gdal.org/programs/gdalmanage.html"));
|
|
|
|
auto addCommonOptions = [psOptions](GDALArgumentParser *subParser)
|
|
{
|
|
subParser->add_argument("-f")
|
|
.metavar("<format>")
|
|
.store_into(psOptions->osDriverName)
|
|
.help(_("Specify format of raster file if unknown by the "
|
|
"application."));
|
|
|
|
subParser->add_argument("newdatasetname")
|
|
.metavar("<newdatasetname>")
|
|
.store_into(psOptions->osNewName)
|
|
.help(_("Name of the new file."));
|
|
};
|
|
|
|
// Identify
|
|
|
|
auto identifyParser =
|
|
argParser->add_subparser("identify", /* bForBinary */ true);
|
|
identifyParser->add_description(_("List data format of file(s)."));
|
|
|
|
identifyParser->add_argument("-r")
|
|
.flag()
|
|
.store_into(psOptions->bRecursive)
|
|
.help(_("Recursively scan files/folders for raster files."));
|
|
|
|
identifyParser->add_argument("-fr")
|
|
.flag()
|
|
.store_into(psOptions->bRecursive)
|
|
.store_into(psOptions->bForceRecurse)
|
|
.help(_("Recursively scan folders for raster files, forcing "
|
|
"recursion in folders recognized as valid formats."));
|
|
|
|
identifyParser->add_argument("-u")
|
|
.flag()
|
|
.store_into(psOptions->bReportFailures)
|
|
.help(_("Report failures if file type is unidentified."));
|
|
|
|
// Note: this accepts multiple files
|
|
identifyParser->add_argument("datasetname")
|
|
.metavar("<datasetname>")
|
|
.store_into(psOptions->aosDatasetNames)
|
|
.remaining()
|
|
.help(_("Name(s) of the file(s) to identify."));
|
|
|
|
// Copy
|
|
|
|
auto copyParser = argParser->add_subparser("copy", /* bForBinary */ true);
|
|
copyParser->add_description(
|
|
_("Create a copy of the raster file with a new name."));
|
|
|
|
addCommonOptions(copyParser);
|
|
|
|
copyParser->add_argument("datasetname")
|
|
.metavar("<datasetname>")
|
|
.store_into(psOptions->osDatasetName)
|
|
.help(_("Name of the file to copy."));
|
|
|
|
// Rename
|
|
|
|
auto renameParser =
|
|
argParser->add_subparser("rename", /* bForBinary */ true);
|
|
renameParser->add_description(_("Change the name of the raster file."));
|
|
|
|
addCommonOptions(renameParser);
|
|
|
|
renameParser->add_argument("datasetname")
|
|
.metavar("<datasetname>")
|
|
.store_into(psOptions->osDatasetName)
|
|
.help(_("Name of the file to rename."));
|
|
|
|
// Delete
|
|
|
|
auto deleteParser =
|
|
argParser->add_subparser("delete", /* bForBinary */ true);
|
|
deleteParser->add_description(_("Delete the raster file(s)."));
|
|
|
|
// Note: this accepts multiple files
|
|
deleteParser->add_argument("datasetname")
|
|
.metavar("<datasetname>")
|
|
.store_into(psOptions->aosDatasetNames)
|
|
.remaining()
|
|
.help(_("Name(s) of the file(s) to delete."));
|
|
|
|
deleteParser->add_argument("-f")
|
|
.metavar("<format>")
|
|
.store_into(psOptions->osDriverName)
|
|
.help(
|
|
_("Specify format of raster file if unknown by the application."));
|
|
|
|
return argParser;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* main() */
|
|
/************************************************************************/
|
|
|
|
MAIN_START(argc, argv)
|
|
|
|
{
|
|
|
|
EarlySetConfigOptions(argc, argv);
|
|
|
|
argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
|
|
if (argc < 1)
|
|
exit(-argc);
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Parse arguments. */
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
if (argc < 2)
|
|
{
|
|
try
|
|
{
|
|
GDALManageOptions sOptions;
|
|
auto argParser = GDALManageAppOptionsGetParser(&sOptions);
|
|
fprintf(stderr, "%s\n", argParser->usage().c_str());
|
|
}
|
|
catch (const std::exception &err)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Unexpected exception: %s",
|
|
err.what());
|
|
}
|
|
CSLDestroy(argv);
|
|
exit(1);
|
|
}
|
|
|
|
GDALAllRegister();
|
|
|
|
GDALManageOptions psOptions;
|
|
auto argParser = GDALManageAppOptionsGetParser(&psOptions);
|
|
|
|
try
|
|
{
|
|
argParser->parse_args_without_binary_name(argv + 1);
|
|
CSLDestroy(argv);
|
|
}
|
|
catch (const std::exception &error)
|
|
{
|
|
argParser->display_error_and_usage(error);
|
|
CSLDestroy(argv);
|
|
exit(1);
|
|
}
|
|
|
|
// For some obscure reason datasetname is parsed as mandatory
|
|
// if used with remaining() in a subparser
|
|
if (psOptions.aosDatasetNames.empty() && psOptions.osDatasetName.empty())
|
|
{
|
|
std::invalid_argument error(
|
|
_("No dataset name provided. At least one dataset "
|
|
"name is required."));
|
|
argParser->display_error_and_usage(error);
|
|
exit(1);
|
|
}
|
|
|
|
GDALDriverH hDriver = nullptr;
|
|
if (!psOptions.osDriverName.empty())
|
|
{
|
|
hDriver = GDALGetDriverByName(psOptions.osDriverName.c_str());
|
|
if (hDriver == nullptr)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Failed to find driver '%s'.",
|
|
psOptions.osDriverName.c_str());
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Split out based on operation. */
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
if (argParser->is_subcommand_used("identify"))
|
|
{
|
|
// Process all files in aosDatasetName
|
|
for (const auto &datasetName : psOptions.aosDatasetNames)
|
|
{
|
|
ProcessIdentifyTarget(
|
|
datasetName.c_str(), nullptr, psOptions.bRecursive,
|
|
psOptions.bReportFailures, psOptions.bForceRecurse);
|
|
}
|
|
}
|
|
else if (argParser->is_subcommand_used("copy"))
|
|
{
|
|
GDALCopyDatasetFiles(hDriver, psOptions.osDatasetName.c_str(),
|
|
psOptions.osNewName.c_str());
|
|
}
|
|
else if (argParser->is_subcommand_used("rename"))
|
|
{
|
|
GDALRenameDataset(hDriver, psOptions.osDatasetName.c_str(),
|
|
psOptions.osNewName.c_str());
|
|
}
|
|
else if (argParser->is_subcommand_used("delete"))
|
|
{
|
|
// Process all files in aosDatasetName
|
|
for (const auto &datasetName : psOptions.aosDatasetNames)
|
|
{
|
|
GDALDeleteDataset(hDriver, datasetName.c_str());
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALDestroy();
|
|
|
|
exit(0);
|
|
}
|
|
|
|
MAIN_END
|