Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: SDTS Translator 4 : * Purpose: Various utility functions that apply to all SDTS profiles. 5 : * SDTSModId, and SDTSFeature methods. 6 : * Author: Frank Warmerdam, warmerdam@pobox.com 7 : * 8 : ****************************************************************************** 9 : * Copyright (c) 1999, Frank Warmerdam 10 : * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com> 11 : * 12 : * SPDX-License-Identifier: MIT 13 : ****************************************************************************/ 14 : 15 : #include "sdts_al.h" 16 : #include "cpl_string.h" 17 : 18 : #include <set> 19 : 20 : /************************************************************************/ 21 : /* SDTSFeature() */ 22 : /************************************************************************/ 23 : 24 572 : SDTSFeature::SDTSFeature() : nAttributes(0), paoATID(nullptr) 25 : { 26 572 : } 27 : 28 : /************************************************************************/ 29 : /* SDTSFeature::ApplyATID() */ 30 : /************************************************************************/ 31 : 32 12 : void SDTSFeature::ApplyATID(DDFField *poField) 33 : 34 : { 35 12 : DDFSubfieldDefn *poMODN = poField->GetFieldDefn()->FindSubfieldDefn("MODN"); 36 12 : if (poMODN == nullptr) 37 : { 38 : // CPLAssert( false ); 39 0 : return; 40 : } 41 : 42 12 : bool bUsualFormat = poMODN->GetWidth() == 4; 43 12 : const int nRepeatCount = poField->GetRepeatCount(); 44 24 : for (int iRepeat = 0; iRepeat < nRepeatCount; iRepeat++) 45 : { 46 12 : paoATID = reinterpret_cast<SDTSModId *>( 47 12 : CPLRealloc(paoATID, sizeof(SDTSModId) * (nAttributes + 1))); 48 : 49 12 : SDTSModId *poModId = paoATID + nAttributes; 50 12 : *poModId = SDTSModId(); 51 : 52 12 : if (bUsualFormat) 53 : { 54 : const char *pabyData = 55 12 : poField->GetSubfieldData(poMODN, nullptr, iRepeat); 56 12 : if (pabyData == nullptr || strlen(pabyData) < 5) 57 0 : return; 58 : 59 12 : memcpy(poModId->szModule, pabyData, 4); 60 12 : poModId->szModule[4] = '\0'; 61 12 : poModId->nRecord = atoi(pabyData + 4); 62 12 : poModId->szOBRP[0] = '\0'; 63 : } 64 : else 65 : { 66 0 : poModId->Set(poField); 67 : } 68 : 69 12 : nAttributes++; 70 : } 71 : } 72 : 73 : /************************************************************************/ 74 : /* ~SDTSFeature() */ 75 : /************************************************************************/ 76 : 77 1144 : SDTSFeature::~SDTSFeature() 78 : 79 : { 80 572 : CPLFree(paoATID); 81 572 : paoATID = nullptr; 82 572 : } 83 : 84 : /************************************************************************/ 85 : /* SDTSModId::Set() */ 86 : /* */ 87 : /* Set a module from a field. We depend on our pre-knowledge */ 88 : /* of the data layout to fetch more efficiently. */ 89 : /************************************************************************/ 90 : 91 827 : int SDTSModId::Set(DDFField *poField) 92 : 93 : { 94 827 : const char *pachData = poField->GetData(); 95 827 : DDFFieldDefn *poDefn = poField->GetFieldDefn(); 96 : 97 1654 : if (poDefn->GetSubfieldCount() >= 2 && 98 827 : poDefn->GetSubfield(0)->GetWidth() == 4) 99 : { 100 825 : if (strlen(pachData) < 5) 101 0 : return FALSE; 102 : 103 825 : memcpy(szModule, pachData, 4); 104 825 : szModule[4] = '\0'; 105 : 106 825 : nRecord = atoi(pachData + 4); 107 : } 108 : else 109 : { 110 : DDFSubfieldDefn *poSF = 111 2 : poField->GetFieldDefn()->FindSubfieldDefn("MODN"); 112 2 : if (poSF == nullptr) 113 0 : return FALSE; 114 : int nBytesRemaining; 115 2 : pachData = poField->GetSubfieldData(poSF, &nBytesRemaining); 116 2 : if (pachData == nullptr) 117 0 : return FALSE; 118 2 : snprintf(szModule, sizeof(szModule), "%s", 119 : poSF->ExtractStringData(pachData, nBytesRemaining, nullptr)); 120 : 121 2 : poSF = poField->GetFieldDefn()->FindSubfieldDefn("RCID"); 122 2 : if (poSF != nullptr) 123 : { 124 2 : pachData = poField->GetSubfieldData(poSF, &nBytesRemaining); 125 2 : if (pachData != nullptr) 126 2 : nRecord = 127 2 : poSF->ExtractIntData(pachData, nBytesRemaining, nullptr); 128 : } 129 : } 130 : 131 827 : if (poDefn->GetSubfieldCount() == 3) 132 : { 133 : DDFSubfieldDefn *poSF = 134 219 : poField->GetFieldDefn()->FindSubfieldDefn("OBRP"); 135 219 : if (poSF != nullptr) 136 : { 137 : int nBytesRemaining; 138 219 : pachData = poField->GetSubfieldData(poSF, &nBytesRemaining); 139 219 : if (pachData != nullptr) 140 : { 141 219 : snprintf(szOBRP, sizeof(szOBRP), "%s", 142 : poSF->ExtractStringData(pachData, nBytesRemaining, 143 : nullptr)); 144 : } 145 : } 146 : } 147 : 148 827 : return FALSE; 149 : } 150 : 151 : /************************************************************************/ 152 : /* SDTSModId::GetName() */ 153 : /************************************************************************/ 154 : 155 0 : const char *SDTSModId::GetName() 156 : 157 : { 158 0 : snprintf(szName, sizeof(szName), "%s:%d", szModule, nRecord); 159 : 160 0 : return szName; 161 : } 162 : 163 : /************************************************************************/ 164 : /* SDTSScanModuleReferences() */ 165 : /* */ 166 : /* Find all modules references by records in this module based */ 167 : /* on a particular field name. That field must be in module */ 168 : /* reference form (contain MODN/RCID subfields). */ 169 : /************************************************************************/ 170 : 171 5 : char **SDTSScanModuleReferences(DDFModule *poModule, const char *pszFName) 172 : 173 : { 174 : /* -------------------------------------------------------------------- */ 175 : /* Identify the field, and subfield we are interested in. */ 176 : /* -------------------------------------------------------------------- */ 177 5 : DDFFieldDefn *poIDField = poModule->FindFieldDefn(pszFName); 178 : 179 5 : if (poIDField == nullptr) 180 2 : return nullptr; 181 : 182 3 : DDFSubfieldDefn *poMODN = poIDField->FindSubfieldDefn("MODN"); 183 3 : if (poMODN == nullptr) 184 0 : return nullptr; 185 : 186 : /* -------------------------------------------------------------------- */ 187 : /* Scan the file. */ 188 : /* -------------------------------------------------------------------- */ 189 3 : poModule->Rewind(); 190 : 191 3 : DDFRecord *poRecord = nullptr; 192 6 : CPLStringList aosModnList; 193 6 : std::set<std::string> aoSetModNames; 194 153 : while ((poRecord = poModule->ReadRecord()) != nullptr) 195 : { 196 679 : for (int iField = 0; iField < poRecord->GetFieldCount(); iField++) 197 : { 198 529 : DDFField *poField = poRecord->GetField(iField); 199 : 200 529 : if (poField->GetFieldDefn() == poIDField) 201 : { 202 12 : for (int i = 0; i < poField->GetRepeatCount(); i++) 203 : { 204 : const char *pszModName = 205 6 : poField->GetSubfieldData(poMODN, nullptr, i); 206 : 207 6 : if (pszModName == nullptr || strlen(pszModName) < 4) 208 0 : continue; 209 : 210 : char szName[5]; 211 6 : strncpy(szName, pszModName, 4); 212 6 : szName[4] = '\0'; 213 : 214 6 : if (aoSetModNames.find(szName) == aoSetModNames.end()) 215 : { 216 1 : aoSetModNames.insert(szName); 217 1 : aosModnList.AddString(szName); 218 : } 219 : } 220 : } 221 : } 222 : } 223 : 224 3 : poModule->Rewind(); 225 : 226 3 : return aosModnList.StealList(); 227 : }