Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: GDAL 4 : * Purpose: gdal "vector export-schema" subcommand 5 : * Author: Alessandro Pasotti <elpaso at itopen dot it> 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2026, Alessandro Pasotti <elpaso at itopen dot it> 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #include "gdalalg_vector_export_schema.h" 14 : 15 : #include "cpl_conv.h" 16 : #include "gdal_priv.h" 17 : #include "gdal_utils.h" 18 : 19 : //! @cond Doxygen_Suppress 20 : 21 : #ifndef _ 22 : #define _(x) (x) 23 : #endif 24 : 25 : /************************************************************************/ 26 : /* GDALVectorExportSchemaAlgorithm::GDALVectorExportSchemaAlgorithm() */ 27 : /************************************************************************/ 28 : 29 87 : GDALVectorExportSchemaAlgorithm::GDALVectorExportSchemaAlgorithm( 30 87 : bool standaloneStep) 31 : : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL, 32 0 : ConstructorOptions() 33 87 : .SetStandaloneStep(standaloneStep) 34 87 : .SetInputDatasetMaxCount(1) 35 174 : .SetAddDefaultArguments(false)) 36 : { 37 87 : AddOpenOptionsArg(&m_openOptions).SetHiddenForCLI(!standaloneStep); 38 87 : AddInputFormatsArg(&m_inputFormats) 39 261 : .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES, {GDAL_DCAP_VECTOR}) 40 87 : .SetHiddenForCLI(!standaloneStep); 41 : 42 : auto &datasetArg = 43 87 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_VECTOR).AddAlias("dataset"); 44 87 : if (!standaloneStep) 45 39 : datasetArg.SetHidden(); 46 87 : auto &layerArg = AddLayerNameArg(&m_layerNames).AddAlias("layer"); 47 87 : SetAutoCompleteFunctionForLayerName(layerArg, datasetArg); 48 87 : AddOutputStringArg(&m_output); 49 87 : AddStdoutArg(&m_stdout); 50 : AddArg(GDAL_ARG_NAME_OUTPUT, 'o', 51 : _("Output file name. If not specified, output is sent to stdout"), 52 87 : &m_outputFileName); 53 : AddOverwriteArg(&m_overwrite, 54 87 : _("Whether overwriting existing output file is allowed")); 55 87 : } 56 : 57 : /************************************************************************/ 58 : /* GDALVectorExportSchemaAlgorithm::RunStep() */ 59 : /************************************************************************/ 60 : 61 7 : bool GDALVectorExportSchemaAlgorithm::RunStep(GDALPipelineStepRunContext &) 62 : { 63 7 : CPLAssert(m_inputDataset.size() == 1); 64 7 : auto poSrcDS = m_inputDataset[0].GetDatasetRef(); 65 7 : CPLAssert(poSrcDS); 66 : 67 14 : CPLStringList aosOptions; 68 : 69 7 : aosOptions.AddString("-schema"); 70 7 : aosOptions.AddString("--cli"); 71 : 72 : // Must be last, as positional 73 7 : aosOptions.AddString("dummy"); 74 : 75 7 : for (const std::string &name : m_layerNames) 76 0 : aosOptions.AddString(name.c_str()); 77 : 78 7 : if (m_layerNames.empty()) 79 : { 80 7 : aosOptions.AddString("-al"); 81 : } 82 : 83 : GDALVectorInfoOptions *psInfo = 84 7 : GDALVectorInfoOptionsNew(aosOptions.List(), nullptr); 85 : 86 7 : char *ret = GDALVectorInfo(GDALDataset::ToHandle(poSrcDS), psInfo); 87 7 : GDALVectorInfoOptionsFree(psInfo); 88 7 : if (!ret) 89 0 : return false; 90 : 91 7 : const auto outFileNameArg = GetArg(GDAL_ARG_NAME_OUTPUT); 92 7 : if (outFileNameArg && outFileNameArg->IsExplicitlySet()) 93 : { 94 : // Check if file exists 95 : VSIStatBufL sStat; 96 4 : if (VSIStatL(m_outputFileName.c_str(), &sStat) == 0) 97 : { 98 2 : const auto overwriteArg = GetArg(GDAL_ARG_NAME_OVERWRITE); 99 2 : if (overwriteArg && overwriteArg->GetType() == GAAT_BOOLEAN) 100 : { 101 2 : if (!overwriteArg->GDALAlgorithmArg::Get<bool>()) 102 : { 103 1 : CPLError(CE_Failure, CPLE_AppDefined, 104 : "File '%s' already exists. Specify the " 105 : "--overwrite option to overwrite it.", 106 : m_outputFileName.c_str()); 107 1 : CPLFree(ret); 108 1 : return false; 109 : } 110 : else 111 : { 112 1 : if (VSIUnlink(m_outputFileName.c_str()) != 0) 113 : { 114 0 : CPLError(CE_Failure, CPLE_AppDefined, 115 : "Failed to delete existing file '%s'", 116 : m_outputFileName.c_str()); 117 0 : CPLFree(ret); 118 0 : return false; 119 : } 120 : } 121 : } 122 : } 123 : 124 3 : VSILFILE *fp = VSIFOpenL(m_outputFileName.c_str(), "wb"); 125 3 : if (!fp) 126 : { 127 0 : CPLError(CE_Failure, CPLE_FileIO, "Failed to open output file '%s'", 128 : m_outputFileName.c_str()); 129 0 : CPLFree(ret); 130 0 : return false; 131 : } 132 3 : auto nBytesWritten = VSIFWriteL(ret, 1, strlen(ret), fp); 133 3 : VSIFCloseL(fp); 134 3 : if (nBytesWritten != strlen(ret)) 135 : { 136 0 : CPLError(CE_Failure, CPLE_AppDefined, 137 : "Failed to write output file '%s'", 138 : m_outputFileName.c_str()); 139 0 : CPLFree(ret); 140 0 : return false; 141 : } 142 : } 143 : else 144 : { 145 3 : m_output = ret; 146 : } 147 6 : CPLFree(ret); 148 : 149 6 : return true; 150 : } 151 : 152 : GDALVectorExportSchemaAlgorithmStandalone:: 153 : ~GDALVectorExportSchemaAlgorithmStandalone() = default; 154 : 155 : //! @endcond