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