Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: S-57 Translator
4 : * Purpose: Implements S57Writer class.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2003, Frank Warmerdam
9 : * Copyright (c) 2013, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_conv.h"
31 : #include "cpl_string.h"
32 : #include "ogr_api.h"
33 : #include "s57.h"
34 :
35 : /************************************************************************/
36 : /* S57Writer() */
37 : /************************************************************************/
38 :
39 19 : S57Writer::S57Writer()
40 : : poModule(nullptr), nNext0001Index(0), poRegistrar(nullptr),
41 : poClassContentExplorer(nullptr), m_nCOMF(nDEFAULT_COMF),
42 19 : m_nSOMF(nDEFAULT_SOMF)
43 : {
44 19 : }
45 :
46 : /************************************************************************/
47 : /* ~S57Writer() */
48 : /************************************************************************/
49 :
50 38 : S57Writer::~S57Writer()
51 :
52 : {
53 19 : Close();
54 19 : }
55 :
56 : /************************************************************************/
57 : /* Close() */
58 : /* */
59 : /* Close the current S-57 dataset. */
60 : /************************************************************************/
61 :
62 57 : bool S57Writer::Close()
63 :
64 : {
65 57 : if (poModule != nullptr)
66 : {
67 18 : poModule->Close();
68 18 : delete poModule;
69 18 : poModule = nullptr;
70 : }
71 57 : return true;
72 : }
73 :
74 : /************************************************************************/
75 : /* CreateS57File() */
76 : /* */
77 : /* Create a new output ISO8211 file with all the S-57 data */
78 : /* definitions. */
79 : /************************************************************************/
80 :
81 19 : bool S57Writer::CreateS57File(const char *pszFilename)
82 :
83 : {
84 : // TODO: What was oModule for if it was unused?
85 : // DDFModule oModule;
86 19 : Close();
87 :
88 19 : nNext0001Index = 1;
89 :
90 : /* -------------------------------------------------------------------- */
91 : /* Create and initialize new module. */
92 : /* -------------------------------------------------------------------- */
93 19 : poModule = new DDFModule();
94 19 : poModule->Initialize();
95 :
96 : /* -------------------------------------------------------------------- */
97 : /* Create the '0000' definition. */
98 : /* -------------------------------------------------------------------- */
99 19 : DDFFieldDefn *poFDefn = new DDFFieldDefn();
100 :
101 19 : poFDefn->Create("0000", "",
102 : "0001DSIDDSIDDSSI0001DSPM0001VRIDVRIDATTVVRIDVRPCVRID"
103 : "VRPTVRIDSGCCVRIDSG2DVRIDSG3D0001FRIDFRIDFOIDFRIDATTF"
104 : "FRIDNATFFRIDFFPCFRIDFFPTFRIDFSPCFRIDFSPT",
105 : dsc_elementary, dtc_char_string);
106 :
107 19 : poModule->AddField(poFDefn);
108 :
109 : /* -------------------------------------------------------------------- */
110 : /* Create the '0001' definition. */
111 : /* -------------------------------------------------------------------- */
112 19 : poFDefn = new DDFFieldDefn();
113 :
114 19 : poFDefn->Create("0001", "ISO 8211 Record Identifier", "", dsc_elementary,
115 : dtc_bit_string, "(b12)");
116 :
117 19 : poModule->AddField(poFDefn);
118 :
119 : /* -------------------------------------------------------------------- */
120 : /* Create the DSID field. */
121 : /* -------------------------------------------------------------------- */
122 19 : poFDefn = new DDFFieldDefn();
123 :
124 19 : poFDefn->Create("DSID", "Data set identification field", "", dsc_vector,
125 : dtc_mixed_data_type);
126 :
127 19 : poFDefn->AddSubfield("RCNM", "b11");
128 19 : poFDefn->AddSubfield("RCID", "b14");
129 19 : poFDefn->AddSubfield("EXPP", "b11");
130 19 : poFDefn->AddSubfield("INTU", "b11");
131 19 : poFDefn->AddSubfield("DSNM", "A");
132 19 : poFDefn->AddSubfield("EDTN", "A");
133 19 : poFDefn->AddSubfield("UPDN", "A");
134 19 : poFDefn->AddSubfield("UADT", "A(8)");
135 19 : poFDefn->AddSubfield("ISDT", "A(8)");
136 19 : poFDefn->AddSubfield("STED", "R(4)");
137 19 : poFDefn->AddSubfield("PRSP", "b11");
138 19 : poFDefn->AddSubfield("PSDN", "A");
139 19 : poFDefn->AddSubfield("PRED", "A");
140 19 : poFDefn->AddSubfield("PROF", "b11");
141 19 : poFDefn->AddSubfield("AGEN", "b12");
142 19 : poFDefn->AddSubfield("COMT", "A");
143 :
144 19 : poModule->AddField(poFDefn);
145 :
146 : /* -------------------------------------------------------------------- */
147 : /* Create the DSSI field. */
148 : /* -------------------------------------------------------------------- */
149 19 : poFDefn = new DDFFieldDefn();
150 :
151 19 : poFDefn->Create("DSSI", "Data set structure information field", "",
152 : dsc_vector, dtc_mixed_data_type);
153 :
154 19 : poFDefn->AddSubfield("DSTR", "b11");
155 19 : poFDefn->AddSubfield("AALL", "b11");
156 19 : poFDefn->AddSubfield("NALL", "b11");
157 19 : poFDefn->AddSubfield("NOMR", "b14");
158 19 : poFDefn->AddSubfield("NOCR", "b14");
159 19 : poFDefn->AddSubfield("NOGR", "b14");
160 19 : poFDefn->AddSubfield("NOLR", "b14");
161 19 : poFDefn->AddSubfield("NOIN", "b14");
162 19 : poFDefn->AddSubfield("NOCN", "b14");
163 19 : poFDefn->AddSubfield("NOED", "b14");
164 19 : poFDefn->AddSubfield("NOFA", "b14");
165 :
166 19 : poModule->AddField(poFDefn);
167 :
168 : /* -------------------------------------------------------------------- */
169 : /* Create the DSPM field. */
170 : /* -------------------------------------------------------------------- */
171 19 : poFDefn = new DDFFieldDefn();
172 :
173 19 : poFDefn->Create("DSPM", "Data set parameter field", "", dsc_vector,
174 : dtc_mixed_data_type);
175 :
176 19 : poFDefn->AddSubfield("RCNM", "b11");
177 19 : poFDefn->AddSubfield("RCID", "b14");
178 19 : poFDefn->AddSubfield("HDAT", "b11");
179 19 : poFDefn->AddSubfield("VDAT", "b11");
180 19 : poFDefn->AddSubfield("SDAT", "b11");
181 19 : poFDefn->AddSubfield("CSCL", "b14");
182 19 : poFDefn->AddSubfield("DUNI", "b11");
183 19 : poFDefn->AddSubfield("HUNI", "b11");
184 19 : poFDefn->AddSubfield("PUNI", "b11");
185 19 : poFDefn->AddSubfield("COUN", "b11");
186 19 : poFDefn->AddSubfield("COMF", "b14");
187 19 : poFDefn->AddSubfield("SOMF", "b14");
188 19 : poFDefn->AddSubfield("COMT", "A");
189 :
190 19 : poModule->AddField(poFDefn);
191 :
192 : /* -------------------------------------------------------------------- */
193 : /* Create the VRID field. */
194 : /* -------------------------------------------------------------------- */
195 19 : poFDefn = new DDFFieldDefn();
196 :
197 19 : poFDefn->Create("VRID", "Vector record identifier field", "", dsc_vector,
198 : dtc_mixed_data_type);
199 :
200 19 : poFDefn->AddSubfield("RCNM", "b11");
201 19 : poFDefn->AddSubfield("RCID", "b14");
202 19 : poFDefn->AddSubfield("RVER", "b12");
203 19 : poFDefn->AddSubfield("RUIN", "b11");
204 :
205 19 : poModule->AddField(poFDefn);
206 :
207 : /* -------------------------------------------------------------------- */
208 : /* Create the VRPC field. */
209 : /* -------------------------------------------------------------------- */
210 19 : poFDefn = new DDFFieldDefn();
211 :
212 19 : poFDefn->Create("VRPC", "Vector Record Pointer Control field", "",
213 : dsc_vector, dtc_mixed_data_type);
214 :
215 19 : poFDefn->AddSubfield("VPUI", "b11");
216 19 : poFDefn->AddSubfield("VPIX", "b12");
217 19 : poFDefn->AddSubfield("NVPT", "b12");
218 :
219 19 : poModule->AddField(poFDefn);
220 :
221 : /* -------------------------------------------------------------------- */
222 : /* Create the VRPT field. */
223 : /* -------------------------------------------------------------------- */
224 19 : poFDefn = new DDFFieldDefn();
225 :
226 19 : poFDefn->Create("VRPT", "Vector record pointer field", "*", dsc_array,
227 : dtc_mixed_data_type);
228 :
229 19 : poFDefn->AddSubfield("NAME", "B(40)");
230 19 : poFDefn->AddSubfield("ORNT", "b11");
231 19 : poFDefn->AddSubfield("USAG", "b11");
232 19 : poFDefn->AddSubfield("TOPI", "b11");
233 19 : poFDefn->AddSubfield("MASK", "b11");
234 :
235 19 : poModule->AddField(poFDefn);
236 :
237 : /* -------------------------------------------------------------------- */
238 : /* Create the ATTV field. */
239 : /* -------------------------------------------------------------------- */
240 19 : poFDefn = new DDFFieldDefn();
241 :
242 19 : poFDefn->Create("ATTV", "Vector record attribute field", "*", dsc_array,
243 : dtc_mixed_data_type);
244 :
245 19 : poFDefn->AddSubfield("ATTL", "b12");
246 19 : poFDefn->AddSubfield("ATVL", "A");
247 :
248 19 : poModule->AddField(poFDefn);
249 :
250 : /* -------------------------------------------------------------------- */
251 : /* Create the SGCC field. */
252 : /* -------------------------------------------------------------------- */
253 19 : poFDefn = new DDFFieldDefn();
254 :
255 19 : poFDefn->Create("SGCC", "Coordinate Control Field", "", dsc_vector,
256 : dtc_mixed_data_type);
257 :
258 19 : poFDefn->AddSubfield("CCUI", "b11");
259 19 : poFDefn->AddSubfield("CCIX", "b12");
260 19 : poFDefn->AddSubfield("CCNC", "b12");
261 :
262 19 : poModule->AddField(poFDefn);
263 :
264 : /* -------------------------------------------------------------------- */
265 : /* Create the SG2D field. */
266 : /* -------------------------------------------------------------------- */
267 19 : poFDefn = new DDFFieldDefn();
268 :
269 19 : poFDefn->Create("SG2D", "2-D coordinate field", "*", dsc_array,
270 : dtc_bit_string);
271 :
272 19 : poFDefn->AddSubfield("YCOO", "b24");
273 19 : poFDefn->AddSubfield("XCOO", "b24");
274 :
275 19 : poModule->AddField(poFDefn);
276 :
277 : /* -------------------------------------------------------------------- */
278 : /* Create the SG3D field. */
279 : /* -------------------------------------------------------------------- */
280 19 : poFDefn = new DDFFieldDefn();
281 :
282 19 : poFDefn->Create("SG3D", "3-D coordinate (sounding array) field", "*",
283 : dsc_array, dtc_bit_string);
284 :
285 19 : poFDefn->AddSubfield("YCOO", "b24");
286 19 : poFDefn->AddSubfield("XCOO", "b24");
287 19 : poFDefn->AddSubfield("VE3D", "b24");
288 :
289 19 : poModule->AddField(poFDefn);
290 :
291 : /* -------------------------------------------------------------------- */
292 : /* Create the FRID field. */
293 : /* -------------------------------------------------------------------- */
294 19 : poFDefn = new DDFFieldDefn();
295 :
296 19 : poFDefn->Create("FRID", "Feature record identifier field", "", dsc_vector,
297 : dtc_mixed_data_type);
298 :
299 19 : poFDefn->AddSubfield("RCNM", "b11");
300 19 : poFDefn->AddSubfield("RCID", "b14");
301 19 : poFDefn->AddSubfield("PRIM", "b11");
302 19 : poFDefn->AddSubfield("GRUP", "b11");
303 19 : poFDefn->AddSubfield("OBJL", "b12");
304 19 : poFDefn->AddSubfield("RVER", "b12");
305 19 : poFDefn->AddSubfield("RUIN", "b11");
306 :
307 19 : poModule->AddField(poFDefn);
308 :
309 : /* -------------------------------------------------------------------- */
310 : /* Create the FOID field. */
311 : /* -------------------------------------------------------------------- */
312 19 : poFDefn = new DDFFieldDefn();
313 :
314 19 : poFDefn->Create("FOID", "Feature object identifier field", "", dsc_vector,
315 : dtc_mixed_data_type);
316 :
317 19 : poFDefn->AddSubfield("AGEN", "b12");
318 19 : poFDefn->AddSubfield("FIDN", "b14");
319 19 : poFDefn->AddSubfield("FIDS", "b12");
320 :
321 19 : poModule->AddField(poFDefn);
322 :
323 : /* -------------------------------------------------------------------- */
324 : /* Create the ATTF field. */
325 : /* -------------------------------------------------------------------- */
326 19 : poFDefn = new DDFFieldDefn();
327 :
328 19 : poFDefn->Create("ATTF", "Feature record attribute field", "*", dsc_array,
329 : dtc_mixed_data_type);
330 :
331 19 : poFDefn->AddSubfield("ATTL", "b12");
332 19 : poFDefn->AddSubfield("ATVL", "A");
333 :
334 19 : poModule->AddField(poFDefn);
335 :
336 : /* -------------------------------------------------------------------- */
337 : /* Create the NATF field. */
338 : /* -------------------------------------------------------------------- */
339 19 : poFDefn = new DDFFieldDefn();
340 :
341 19 : poFDefn->Create("NATF", "Feature record national attribute field", "*",
342 : dsc_array, dtc_mixed_data_type);
343 :
344 19 : poFDefn->AddSubfield("ATTL", "b12");
345 19 : poFDefn->AddSubfield("ATVL", "A");
346 :
347 19 : poModule->AddField(poFDefn);
348 :
349 : /* -------------------------------------------------------------------- */
350 : /* Create the FFPC field. */
351 : /* -------------------------------------------------------------------- */
352 19 : poFDefn = new DDFFieldDefn();
353 :
354 19 : poFDefn->Create("FFPC",
355 : "Feature record to feature object pointer control field",
356 : "", dsc_vector, dtc_mixed_data_type);
357 :
358 19 : poFDefn->AddSubfield("FFUI", "b11");
359 19 : poFDefn->AddSubfield("FFIX", "b12");
360 19 : poFDefn->AddSubfield("NFPT", "b12");
361 :
362 19 : poModule->AddField(poFDefn);
363 :
364 : /* -------------------------------------------------------------------- */
365 : /* Create the FFPT field. */
366 : /* -------------------------------------------------------------------- */
367 19 : poFDefn = new DDFFieldDefn();
368 :
369 19 : poFDefn->Create("FFPT", "Feature record to feature object pointer field",
370 : "*", dsc_array, dtc_mixed_data_type);
371 :
372 19 : poFDefn->AddSubfield("LNAM", "B(64)");
373 19 : poFDefn->AddSubfield("RIND", "b11");
374 19 : poFDefn->AddSubfield("COMT", "A");
375 :
376 19 : poModule->AddField(poFDefn);
377 :
378 : /* -------------------------------------------------------------------- */
379 : /* Create the FSPC field. */
380 : /* -------------------------------------------------------------------- */
381 19 : poFDefn = new DDFFieldDefn();
382 :
383 19 : poFDefn->Create("FSPC",
384 : "Feature record to spatial record pointer control field",
385 : "", dsc_vector, dtc_mixed_data_type);
386 :
387 19 : poFDefn->AddSubfield("FSUI", "b11");
388 19 : poFDefn->AddSubfield("FSIX", "b12");
389 19 : poFDefn->AddSubfield("NSPT", "b12");
390 :
391 19 : poModule->AddField(poFDefn);
392 :
393 : /* -------------------------------------------------------------------- */
394 : /* Create the FSPT field. */
395 : /* -------------------------------------------------------------------- */
396 19 : poFDefn = new DDFFieldDefn();
397 :
398 19 : poFDefn->Create("FSPT", "Feature record to spatial record pointer field",
399 : "*", dsc_array, dtc_mixed_data_type);
400 :
401 19 : poFDefn->AddSubfield("NAME", "B(40)");
402 19 : poFDefn->AddSubfield("ORNT", "b11");
403 19 : poFDefn->AddSubfield("USAG", "b11");
404 19 : poFDefn->AddSubfield("MASK", "b11");
405 :
406 19 : poModule->AddField(poFDefn);
407 :
408 : /* -------------------------------------------------------------------- */
409 : /* Create file. */
410 : /* -------------------------------------------------------------------- */
411 19 : if (!poModule->Create(pszFilename))
412 : {
413 1 : delete poModule;
414 1 : poModule = nullptr;
415 1 : return false;
416 : }
417 :
418 18 : return true;
419 : }
420 :
421 : /************************************************************************/
422 : /* WriteDSID() */
423 : /************************************************************************/
424 :
425 18 : bool S57Writer::WriteDSID(int nEXPP, int nINTU, const char *pszDSNM,
426 : const char *pszEDTN, const char *pszUPDN,
427 : const char *pszUADT, const char *pszISDT,
428 : const char *pszSTED, int nAGEN, const char *pszCOMT,
429 : int nAALL, int nNALL, int nNOMR, int nNOGR, int nNOLR,
430 : int nNOIN, int nNOCN, int nNOED)
431 :
432 : {
433 : /* -------------------------------------------------------------------- */
434 : /* Default values. */
435 : /* -------------------------------------------------------------------- */
436 18 : if (pszDSNM == nullptr)
437 0 : pszDSNM = "";
438 18 : if (pszEDTN == nullptr)
439 18 : pszEDTN = "2";
440 18 : if (pszUPDN == nullptr)
441 18 : pszUPDN = "0";
442 18 : if (pszISDT == nullptr)
443 18 : pszISDT = "20030801";
444 18 : if (pszUADT == nullptr)
445 18 : pszUADT = pszISDT;
446 18 : if (pszSTED == nullptr)
447 18 : pszSTED = "03.1";
448 18 : if (pszCOMT == nullptr)
449 18 : pszCOMT = "";
450 :
451 : /* -------------------------------------------------------------------- */
452 : /* Add the DSID field. */
453 : /* -------------------------------------------------------------------- */
454 18 : DDFRecord *poRec = MakeRecord();
455 :
456 : // DDFField *poField =
457 18 : poRec->AddField(poModule->FindFieldDefn("DSID"));
458 :
459 18 : poRec->SetIntSubfield("DSID", 0, "RCNM", 0, 10);
460 18 : poRec->SetIntSubfield("DSID", 0, "RCID", 0, 1);
461 18 : poRec->SetIntSubfield("DSID", 0, "EXPP", 0, nEXPP);
462 18 : poRec->SetIntSubfield("DSID", 0, "INTU", 0, nINTU);
463 18 : poRec->SetStringSubfield("DSID", 0, "DSNM", 0, pszDSNM);
464 18 : poRec->SetStringSubfield("DSID", 0, "EDTN", 0, pszEDTN);
465 18 : poRec->SetStringSubfield("DSID", 0, "UPDN", 0, pszUPDN);
466 18 : poRec->SetStringSubfield("DSID", 0, "UADT", 0, pszUADT);
467 18 : poRec->SetStringSubfield("DSID", 0, "ISDT", 0, pszISDT);
468 18 : poRec->SetStringSubfield("DSID", 0, "STED", 0, pszSTED);
469 18 : poRec->SetIntSubfield("DSID", 0, "PRSP", 0, 1);
470 18 : poRec->SetStringSubfield("DSID", 0, "PSDN", 0, "");
471 18 : poRec->SetStringSubfield("DSID", 0, "PRED", 0, "2.0");
472 18 : poRec->SetIntSubfield("DSID", 0, "PROF", 0, 1);
473 18 : poRec->SetIntSubfield("DSID", 0, "AGEN", 0, nAGEN);
474 18 : poRec->SetStringSubfield("DSID", 0, "COMT", 0, pszCOMT);
475 :
476 : /* -------------------------------------------------------------------- */
477 : /* Add the DSSI record. Eventually we will need to return and */
478 : /* correct these when we are finished writing. */
479 : /* -------------------------------------------------------------------- */
480 18 : /* poField = */ poRec->AddField(poModule->FindFieldDefn("DSSI"));
481 :
482 18 : poRec->SetIntSubfield("DSSI", 0, "DSTR", 0, 2); // "Chain node"
483 18 : poRec->SetIntSubfield("DSSI", 0, "AALL", 0, nAALL);
484 18 : poRec->SetIntSubfield("DSSI", 0, "NALL", 0, nNALL);
485 18 : poRec->SetIntSubfield("DSSI", 0, "NOMR", 0, nNOMR); // Meta records
486 : // Cartographic records are not permitted in ENC.
487 18 : poRec->SetIntSubfield("DSSI", 0, "NOCR", 0, 0);
488 18 : poRec->SetIntSubfield("DSSI", 0, "NOGR", 0, nNOGR); // Geo records
489 : // Collection records.
490 18 : poRec->SetIntSubfield("DSSI", 0, "NOLR", 0, nNOLR);
491 : // Isolated node records.
492 18 : poRec->SetIntSubfield("DSSI", 0, "NOIN", 0, nNOIN);
493 : // Connected node records.
494 18 : poRec->SetIntSubfield("DSSI", 0, "NOCN", 0, nNOCN);
495 18 : poRec->SetIntSubfield("DSSI", 0, "NOED", 0, nNOED); // Edge records
496 : // Face are not permitted in chain node structure.
497 18 : poRec->SetIntSubfield("DSSI", 0, "NOFA", 0, 0);
498 :
499 : /* -------------------------------------------------------------------- */
500 : /* Write out the record. */
501 : /* -------------------------------------------------------------------- */
502 18 : poRec->Write();
503 18 : delete poRec;
504 :
505 18 : return true;
506 : }
507 :
508 : /************************************************************************/
509 : /* WriteDSPM() */
510 : /************************************************************************/
511 :
512 18 : bool S57Writer::WriteDSPM(int nHDAT, int nVDAT, int nSDAT, int nCSCL, int nCOMF,
513 : int nSOMF)
514 :
515 : {
516 18 : m_nCOMF = nCOMF;
517 18 : m_nSOMF = nSOMF;
518 :
519 : /* -------------------------------------------------------------------- */
520 : /* Add the DSID field. */
521 : /* -------------------------------------------------------------------- */
522 18 : DDFRecord *poRec = MakeRecord();
523 :
524 : // DDFField *poField =
525 18 : poRec->AddField(poModule->FindFieldDefn("DSPM"));
526 :
527 18 : poRec->SetIntSubfield("DSPM", 0, "RCNM", 0, 20);
528 18 : poRec->SetIntSubfield("DSPM", 0, "RCID", 0, 1);
529 : // Must be 2 for ENC.
530 18 : poRec->SetIntSubfield("DSPM", 0, "HDAT", 0, nHDAT);
531 18 : poRec->SetIntSubfield("DSPM", 0, "VDAT", 0, nVDAT);
532 18 : poRec->SetIntSubfield("DSPM", 0, "SDAT", 0, nSDAT);
533 18 : poRec->SetIntSubfield("DSPM", 0, "CSCL", 0, nCSCL);
534 18 : poRec->SetIntSubfield("DSPM", 0, "DUNI", 0, 1);
535 18 : poRec->SetIntSubfield("DSPM", 0, "HUNI", 0, 1);
536 18 : poRec->SetIntSubfield("DSPM", 0, "PUNI", 0, 1);
537 18 : poRec->SetIntSubfield("DSPM", 0, "COUN", 0, 1);
538 18 : poRec->SetIntSubfield("DSPM", 0, "COMF", 0, nCOMF);
539 18 : poRec->SetIntSubfield("DSPM", 0, "SOMF", 0, nSOMF);
540 :
541 : /* -------------------------------------------------------------------- */
542 : /* Write out the record. */
543 : /* -------------------------------------------------------------------- */
544 18 : poRec->Write();
545 18 : delete poRec;
546 :
547 18 : return true;
548 : }
549 :
550 : /************************************************************************/
551 : /* MakeRecord() */
552 : /* */
553 : /* Create a new empty record, and append a 0001 field with a */
554 : /* properly set record index in it. */
555 : /************************************************************************/
556 :
557 154 : DDFRecord *S57Writer::MakeRecord()
558 :
559 : {
560 : unsigned char abyData[2] = {
561 154 : static_cast<unsigned char>(nNext0001Index % 256),
562 154 : static_cast<unsigned char>(nNext0001Index / 256)};
563 :
564 154 : DDFRecord *poRec = new DDFRecord(poModule);
565 154 : DDFField *poField = poRec->AddField(poModule->FindFieldDefn("0001"));
566 154 : poRec->SetFieldRaw(poField, 0, (const char *)abyData, 2);
567 :
568 154 : nNext0001Index++;
569 :
570 154 : return poRec;
571 : }
572 :
573 : /************************************************************************/
574 : /* WriteGeometry() */
575 : /************************************************************************/
576 :
577 70 : bool S57Writer::WriteGeometry(DDFRecord *poRec, int nVertCount,
578 : const double *padfX, const double *padfY,
579 : const double *padfZ)
580 :
581 : {
582 70 : const char *pszFieldName = "SG2D";
583 :
584 70 : if (padfZ != nullptr)
585 4 : pszFieldName = "SG3D";
586 :
587 70 : DDFField *poField = poRec->AddField(poModule->FindFieldDefn(pszFieldName));
588 :
589 70 : const int nRawDataSize = padfZ ? 12 * nVertCount : 8 * nVertCount;
590 :
591 : unsigned char *pabyRawData =
592 70 : static_cast<unsigned char *>(CPLMalloc(nRawDataSize));
593 :
594 252 : for (int i = 0; i < nVertCount; i++)
595 : {
596 182 : const GInt32 nXCOO =
597 182 : CPL_LSBWORD32(static_cast<GInt32>(floor(padfX[i] * m_nCOMF + 0.5)));
598 182 : const GInt32 nYCOO =
599 182 : CPL_LSBWORD32(static_cast<GInt32>(floor(padfY[i] * m_nCOMF + 0.5)));
600 :
601 182 : if (padfZ == nullptr)
602 : {
603 160 : memcpy(pabyRawData + i * 8, &nYCOO, 4);
604 160 : memcpy(pabyRawData + i * 8 + 4, &nXCOO, 4);
605 : }
606 : else
607 : {
608 22 : const GInt32 nVE3D = CPL_LSBWORD32(
609 : static_cast<GInt32>(floor(padfZ[i] * m_nSOMF + 0.5)));
610 22 : memcpy(pabyRawData + i * 12, &nYCOO, 4);
611 22 : memcpy(pabyRawData + i * 12 + 4, &nXCOO, 4);
612 22 : memcpy(pabyRawData + i * 12 + 8, &nVE3D, 4);
613 : }
614 : }
615 :
616 70 : const bool nSuccess = CPL_TO_BOOL(poRec->SetFieldRaw(
617 : poField, 0, reinterpret_cast<const char *>(pabyRawData), nRawDataSize));
618 :
619 70 : CPLFree(pabyRawData);
620 :
621 70 : return nSuccess;
622 : }
623 :
624 : /************************************************************************/
625 : /* WritePrimitive() */
626 : /************************************************************************/
627 :
628 94 : bool S57Writer::WritePrimitive(OGRFeature *poFeature)
629 :
630 : {
631 94 : DDFRecord *poRec = MakeRecord();
632 94 : const OGRGeometry *poGeom = poFeature->GetGeometryRef();
633 :
634 : /* -------------------------------------------------------------------- */
635 : /* Add the VRID field. */
636 : /* -------------------------------------------------------------------- */
637 :
638 : // DDFField *poField =
639 94 : poRec->AddField(poModule->FindFieldDefn("VRID"));
640 :
641 94 : poRec->SetIntSubfield("VRID", 0, "RCNM", 0,
642 : poFeature->GetFieldAsInteger("RCNM"));
643 94 : poRec->SetIntSubfield("VRID", 0, "RCID", 0,
644 : poFeature->GetFieldAsInteger("RCID"));
645 94 : poRec->SetIntSubfield("VRID", 0, "RVER", 0, 1);
646 94 : poRec->SetIntSubfield("VRID", 0, "RUIN", 0, 1);
647 :
648 94 : bool bRet = true;
649 :
650 : /* -------------------------------------------------------------------- */
651 : /* Handle simple point. */
652 : /* -------------------------------------------------------------------- */
653 94 : if (poGeom != nullptr && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
654 : {
655 40 : const OGRPoint *poPoint = poGeom->toPoint();
656 :
657 40 : CPLAssert(poFeature->GetFieldAsInteger("RCNM") == RCNM_VI ||
658 : poFeature->GetFieldAsInteger("RCNM") == RCNM_VC);
659 :
660 40 : const double adfX[1] = {poPoint->getX()};
661 40 : const double adfY[1] = {poPoint->getY()};
662 40 : const double adfZ[1] = {poPoint->getZ()};
663 :
664 40 : if (adfZ[0] == 0.0)
665 40 : bRet = WriteGeometry(poRec, 1, &adfX[0], &adfY[0], nullptr);
666 : else
667 0 : bRet = WriteGeometry(poRec, 1, &adfX[0], &adfY[0], &adfZ[0]);
668 : }
669 :
670 : /* -------------------------------------------------------------------- */
671 : /* For multipoints we assuming SOUNDG, and write out as SG3D. */
672 : /* -------------------------------------------------------------------- */
673 108 : else if (poGeom != nullptr &&
674 54 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
675 : {
676 4 : const OGRMultiPoint *poMP = poGeom->toMultiPoint();
677 4 : const int nVCount = poMP->getNumGeometries();
678 :
679 4 : CPLAssert(poFeature->GetFieldAsInteger("RCNM") == RCNM_VI ||
680 : poFeature->GetFieldAsInteger("RCNM") == RCNM_VC);
681 :
682 4 : double *padfX = (double *)CPLMalloc(sizeof(double) * nVCount);
683 4 : double *padfY = (double *)CPLMalloc(sizeof(double) * nVCount);
684 4 : double *padfZ = (double *)CPLMalloc(sizeof(double) * nVCount);
685 :
686 26 : for (int i = 0; i < nVCount; i++)
687 : {
688 22 : const OGRPoint *poPoint = poMP->getGeometryRef(i);
689 22 : padfX[i] = poPoint->getX();
690 22 : padfY[i] = poPoint->getY();
691 22 : padfZ[i] = poPoint->getZ();
692 : }
693 :
694 4 : bRet = WriteGeometry(poRec, nVCount, padfX, padfY, padfZ);
695 :
696 4 : CPLFree(padfX);
697 4 : CPLFree(padfY);
698 4 : CPLFree(padfZ);
699 : }
700 :
701 : /* -------------------------------------------------------------------- */
702 : /* Handle LINESTRINGs (edge) geometry. */
703 : /* -------------------------------------------------------------------- */
704 100 : else if (poGeom != nullptr &&
705 50 : wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
706 : {
707 50 : const OGRLineString *poLS = poGeom->toLineString();
708 50 : const int nVCount = poLS->getNumPoints();
709 :
710 50 : CPLAssert(poFeature->GetFieldAsInteger("RCNM") == RCNM_VE);
711 :
712 50 : double *padfX = (double *)CPLMalloc(sizeof(double) * nVCount);
713 50 : double *padfY = (double *)CPLMalloc(sizeof(double) * nVCount);
714 :
715 170 : for (int i = 0; i < nVCount; i++)
716 : {
717 120 : padfX[i] = poLS->getX(i);
718 120 : padfY[i] = poLS->getY(i);
719 : }
720 :
721 50 : if (nVCount)
722 26 : bRet = WriteGeometry(poRec, nVCount, padfX, padfY, nullptr);
723 :
724 50 : CPLFree(padfX);
725 50 : CPLFree(padfY);
726 : }
727 :
728 : /* -------------------------------------------------------------------- */
729 : /* edge node linkages. */
730 : /* -------------------------------------------------------------------- */
731 94 : if (poFeature->GetDefnRef()->GetFieldIndex("NAME_RCNM_0") >= 0)
732 : {
733 50 : CPLAssert(poFeature->GetFieldAsInteger("NAME_RCNM_0") == RCNM_VC);
734 :
735 : // DDFField *poField =
736 50 : poRec->AddField(poModule->FindFieldDefn("VRPT"));
737 :
738 50 : const int nRCID0 = poFeature->GetFieldAsInteger("NAME_RCID_0");
739 50 : char szName0[5] = {RCNM_VC, static_cast<char>(nRCID0 & 0xff),
740 50 : static_cast<char>((nRCID0 & 0xff00) >> 8),
741 50 : static_cast<char>((nRCID0 & 0xff0000) >> 16),
742 50 : static_cast<char>((nRCID0 & 0xff000000) >> 24)};
743 :
744 50 : poRec->SetStringSubfield("VRPT", 0, "NAME", 0, szName0, 5);
745 50 : poRec->SetIntSubfield("VRPT", 0, "ORNT", 0,
746 : poFeature->GetFieldAsInteger("ORNT_0"));
747 50 : poRec->SetIntSubfield("VRPT", 0, "USAG", 0,
748 : poFeature->GetFieldAsInteger("USAG_0"));
749 50 : poRec->SetIntSubfield("VRPT", 0, "TOPI", 0,
750 : poFeature->GetFieldAsInteger("TOPI_0"));
751 50 : poRec->SetIntSubfield("VRPT", 0, "MASK", 0,
752 : poFeature->GetFieldAsInteger("MASK_0"));
753 :
754 50 : const int nRCID1 = poFeature->GetFieldAsInteger("NAME_RCID_1");
755 50 : const char szName1[5] = {
756 : RCNM_VC, static_cast<char>(nRCID1 & 0xff),
757 50 : static_cast<char>((nRCID1 & 0xff00) >> 8),
758 50 : static_cast<char>((nRCID1 & 0xff0000) >> 16),
759 50 : static_cast<char>((nRCID1 & 0xff000000) >> 24)};
760 :
761 50 : poRec->SetStringSubfield("VRPT", 0, "NAME", 1, szName1, 5);
762 50 : poRec->SetIntSubfield("VRPT", 0, "ORNT", 1,
763 : poFeature->GetFieldAsInteger("ORNT_1"));
764 50 : poRec->SetIntSubfield("VRPT", 0, "USAG", 1,
765 : poFeature->GetFieldAsInteger("USAG_1"));
766 50 : poRec->SetIntSubfield("VRPT", 0, "TOPI", 1,
767 : poFeature->GetFieldAsInteger("TOPI_1"));
768 50 : poRec->SetIntSubfield("VRPT", 0, "MASK", 1,
769 : poFeature->GetFieldAsInteger("MASK_1"));
770 : }
771 :
772 : /* -------------------------------------------------------------------- */
773 : /* Write out the record. */
774 : /* -------------------------------------------------------------------- */
775 94 : if (!poRec->Write())
776 0 : bRet = false;
777 94 : delete poRec;
778 :
779 94 : return bRet;
780 : }
781 :
782 : /************************************************************************/
783 : /* GetHEXChar() */
784 : /************************************************************************/
785 :
786 0 : static char GetHEXChar(const char *pszSrcHEXString)
787 :
788 : {
789 0 : if (pszSrcHEXString[0] == '\0' || pszSrcHEXString[1] == '\0')
790 0 : return (char)0;
791 :
792 0 : int nResult = 0;
793 :
794 0 : if (pszSrcHEXString[0] >= '0' && pszSrcHEXString[0] <= '9')
795 0 : nResult += (pszSrcHEXString[0] - '0') * 16;
796 0 : else if (pszSrcHEXString[0] >= 'a' && pszSrcHEXString[0] <= 'f')
797 0 : nResult += (pszSrcHEXString[0] - 'a' + 10) * 16;
798 0 : else if (pszSrcHEXString[0] >= 'A' && pszSrcHEXString[0] <= 'F')
799 0 : nResult += (pszSrcHEXString[0] - 'A' + 10) * 16;
800 :
801 0 : if (pszSrcHEXString[1] >= '0' && pszSrcHEXString[1] <= '9')
802 0 : nResult += pszSrcHEXString[1] - '0';
803 0 : else if (pszSrcHEXString[1] >= 'a' && pszSrcHEXString[1] <= 'f')
804 0 : nResult += pszSrcHEXString[1] - 'a' + 10;
805 0 : else if (pszSrcHEXString[1] >= 'A' && pszSrcHEXString[1] <= 'F')
806 0 : nResult += pszSrcHEXString[1] - 'A' + 10;
807 :
808 0 : return (char)nResult;
809 : }
810 :
811 : /************************************************************************/
812 : /* WriteCompleteFeature() */
813 : /************************************************************************/
814 :
815 118 : bool S57Writer::WriteCompleteFeature(OGRFeature *poFeature)
816 :
817 : {
818 118 : OGRFeatureDefn *poFDefn = poFeature->GetDefnRef();
819 :
820 : /* -------------------------------------------------------------------- */
821 : /* We handle primitives in a separate method. */
822 : /* -------------------------------------------------------------------- */
823 118 : if (EQUAL(poFDefn->GetName(), OGRN_VI) ||
824 192 : EQUAL(poFDefn->GetName(), OGRN_VC) ||
825 74 : EQUAL(poFDefn->GetName(), OGRN_VE))
826 94 : return WritePrimitive(poFeature);
827 :
828 : /* -------------------------------------------------------------------- */
829 : /* Create the record. */
830 : /* -------------------------------------------------------------------- */
831 24 : DDFRecord *poRec = MakeRecord();
832 :
833 : /* -------------------------------------------------------------------- */
834 : /* Add the FRID. */
835 : /* -------------------------------------------------------------------- */
836 : // DDFField *poField =
837 24 : poRec->AddField(poModule->FindFieldDefn("FRID"));
838 :
839 24 : poRec->SetIntSubfield("FRID", 0, "RCNM", 0, 100);
840 24 : poRec->SetIntSubfield("FRID", 0, "RCID", 0,
841 : poFeature->GetFieldAsInteger("RCID"));
842 24 : poRec->SetIntSubfield("FRID", 0, "PRIM", 0,
843 : poFeature->GetFieldAsInteger("PRIM"));
844 24 : poRec->SetIntSubfield("FRID", 0, "GRUP", 0,
845 : poFeature->GetFieldAsInteger("GRUP"));
846 24 : poRec->SetIntSubfield("FRID", 0, "OBJL", 0,
847 : poFeature->GetFieldAsInteger("OBJL"));
848 24 : poRec->SetIntSubfield("FRID", 0, "RVER", 0, 1); /* always new insert*/
849 24 : poRec->SetIntSubfield("FRID", 0, "RUIN", 0, 1);
850 :
851 : /* -------------------------------------------------------------------- */
852 : /* Add the FOID */
853 : /* -------------------------------------------------------------------- */
854 24 : /*poField = */ poRec->AddField(poModule->FindFieldDefn("FOID"));
855 :
856 24 : poRec->SetIntSubfield("FOID", 0, "AGEN", 0,
857 : poFeature->GetFieldAsInteger("AGEN"));
858 24 : poRec->SetIntSubfield("FOID", 0, "FIDN", 0,
859 : poFeature->GetFieldAsInteger("FIDN"));
860 24 : poRec->SetIntSubfield("FOID", 0, "FIDS", 0,
861 : poFeature->GetFieldAsInteger("FIDS"));
862 :
863 : /* -------------------------------------------------------------------- */
864 : /* ATTF support. */
865 : /* -------------------------------------------------------------------- */
866 :
867 72 : if (poRegistrar != nullptr &&
868 24 : poClassContentExplorer->SelectClass(
869 48 : poFeature->GetDefnRef()->GetName()) &&
870 24 : !WriteATTF(poRec, poFeature))
871 : {
872 0 : delete poRec;
873 0 : return false;
874 : }
875 :
876 : /* -------------------------------------------------------------------- */
877 : /* Add the FSPT if needed. */
878 : /* -------------------------------------------------------------------- */
879 24 : if (poFeature->IsFieldSetAndNotNull(poFeature->GetFieldIndex("NAME_RCNM")))
880 : {
881 24 : int nItemCount = 0;
882 :
883 : const int *panRCNM =
884 24 : poFeature->GetFieldAsIntegerList("NAME_RCNM", &nItemCount);
885 : const int *panRCID =
886 24 : poFeature->GetFieldAsIntegerList("NAME_RCID", &nItemCount);
887 : const int *panORNT =
888 24 : poFeature->GetFieldAsIntegerList("ORNT", &nItemCount);
889 : const int *panUSAG =
890 24 : poFeature->GetFieldAsIntegerList("USAG", &nItemCount);
891 : const int *panMASK =
892 24 : poFeature->GetFieldAsIntegerList("MASK", &nItemCount);
893 :
894 : // cppcheck-suppress duplicateExpression
895 : CPLAssert(sizeof(int) == sizeof(GInt32));
896 :
897 24 : const int nRawDataSize = nItemCount * 8;
898 24 : unsigned char *pabyRawData = (unsigned char *)CPLMalloc(nRawDataSize);
899 :
900 124 : for (int i = 0; i < nItemCount; i++)
901 : {
902 100 : GInt32 nRCID = CPL_LSBWORD32(panRCID[i]);
903 :
904 100 : pabyRawData[i * 8 + 0] = (GByte)panRCNM[i];
905 100 : memcpy(pabyRawData + i * 8 + 1, &nRCID, 4);
906 100 : pabyRawData[i * 8 + 5] = (GByte)panORNT[i];
907 100 : pabyRawData[i * 8 + 6] = (GByte)panUSAG[i];
908 100 : pabyRawData[i * 8 + 7] = (GByte)panMASK[i];
909 : }
910 :
911 24 : DDFField *poField = poRec->AddField(poModule->FindFieldDefn("FSPT"));
912 24 : poRec->SetFieldRaw(poField, 0, (const char *)pabyRawData, nRawDataSize);
913 24 : CPLFree(pabyRawData);
914 : }
915 :
916 : /* -------------------------------------------------------------------- */
917 : /* Add the FFPT if needed. */
918 : /* -------------------------------------------------------------------- */
919 24 : char **papszLNAM_REFS = poFeature->GetFieldAsStringList("LNAM_REFS");
920 :
921 24 : if (CSLCount(papszLNAM_REFS) > 0)
922 : {
923 0 : int i, nRefCount = CSLCount(papszLNAM_REFS);
924 : const int *panRIND =
925 0 : poFeature->GetFieldAsIntegerList("FFPT_RIND", nullptr);
926 :
927 0 : poRec->AddField(poModule->FindFieldDefn("FFPT"));
928 :
929 0 : for (i = 0; i < nRefCount; i++)
930 : {
931 : char szLNAM[9];
932 :
933 0 : if (strlen(papszLNAM_REFS[i]) < 16)
934 0 : continue;
935 :
936 : // AGEN
937 0 : szLNAM[1] = GetHEXChar(papszLNAM_REFS[i] + 0);
938 0 : szLNAM[0] = GetHEXChar(papszLNAM_REFS[i] + 2);
939 :
940 : // FIDN
941 0 : szLNAM[5] = GetHEXChar(papszLNAM_REFS[i] + 4);
942 0 : szLNAM[4] = GetHEXChar(papszLNAM_REFS[i] + 6);
943 0 : szLNAM[3] = GetHEXChar(papszLNAM_REFS[i] + 8);
944 0 : szLNAM[2] = GetHEXChar(papszLNAM_REFS[i] + 10);
945 :
946 : // FIDS
947 0 : szLNAM[7] = GetHEXChar(papszLNAM_REFS[i] + 12);
948 0 : szLNAM[6] = GetHEXChar(papszLNAM_REFS[i] + 14);
949 :
950 0 : szLNAM[8] = '\0';
951 :
952 0 : poRec->SetStringSubfield("FFPT", 0, "LNAM", i, (char *)szLNAM, 8);
953 0 : poRec->SetIntSubfield("FFPT", 0, "RIND", i, panRIND[i]);
954 : }
955 : }
956 :
957 : /* -------------------------------------------------------------------- */
958 : /* Write out the record. */
959 : /* -------------------------------------------------------------------- */
960 24 : poRec->Write();
961 24 : delete poRec;
962 :
963 24 : return true;
964 : }
965 :
966 : /************************************************************************/
967 : /* SetClassBased() */
968 : /************************************************************************/
969 :
970 18 : void S57Writer::SetClassBased(S57ClassRegistrar *poReg,
971 : S57ClassContentExplorer *poClassContentExplorerIn)
972 :
973 : {
974 18 : poRegistrar = poReg;
975 18 : poClassContentExplorer = poClassContentExplorerIn;
976 18 : }
977 :
978 : /************************************************************************/
979 : /* WriteATTF() */
980 : /************************************************************************/
981 :
982 24 : bool S57Writer::WriteATTF(DDFRecord *poRec, OGRFeature *poFeature)
983 : {
984 24 : CPLAssert(poRegistrar != nullptr);
985 :
986 : /* -------------------------------------------------------------------- */
987 : /* Loop over all attributes. */
988 : /* -------------------------------------------------------------------- */
989 24 : int nRawSize = 0;
990 24 : int nACount = 0;
991 24 : char achRawData[5000] = {};
992 :
993 24 : char **papszAttrList = poClassContentExplorer->GetAttributeList(nullptr);
994 :
995 414 : for (int iAttr = 0; papszAttrList[iAttr] != nullptr; iAttr++)
996 : {
997 390 : const int iField = poFeature->GetFieldIndex(papszAttrList[iAttr]);
998 390 : if (iField < 0)
999 363 : continue;
1000 :
1001 : const OGRFieldType eFldType =
1002 390 : poFeature->GetDefnRef()->GetFieldDefn(iField)->GetType();
1003 :
1004 390 : if (!poFeature->IsFieldSetAndNotNull(iField))
1005 363 : continue;
1006 :
1007 : const int nATTLInt =
1008 27 : poRegistrar->FindAttrByAcronym(papszAttrList[iAttr]);
1009 27 : if (nATTLInt == -1)
1010 0 : continue;
1011 :
1012 27 : GUInt16 nATTL = (GUInt16)nATTLInt;
1013 27 : CPL_LSBPTR16(&nATTL);
1014 27 : memcpy(achRawData + nRawSize, &nATTL, 2);
1015 27 : nRawSize += 2;
1016 :
1017 27 : CPLString osATVL;
1018 27 : if (eFldType == OFTStringList)
1019 : {
1020 : const char *const *papszTokens =
1021 6 : poFeature->GetFieldAsStringList(iField);
1022 12 : for (auto papszIter = papszTokens; papszIter && *papszIter;
1023 : ++papszIter)
1024 : {
1025 6 : if (!osATVL.empty())
1026 0 : osATVL += ',';
1027 6 : osATVL += *papszIter;
1028 : }
1029 : }
1030 : else
1031 : {
1032 21 : osATVL = poFeature->GetFieldAsString(iField);
1033 : }
1034 :
1035 : // Special hack to handle special "empty" marker in integer fields.
1036 48 : if ((eFldType == OFTInteger || eFldType == OFTReal) &&
1037 21 : atoi(osATVL) == EMPTY_NUMBER_MARKER)
1038 0 : osATVL.clear();
1039 :
1040 : // Watch for really long data.
1041 27 : if (osATVL.size() + nRawSize + 10 > sizeof(achRawData))
1042 : {
1043 0 : CPLError(CE_Failure, CPLE_AppDefined,
1044 : "Too much ATTF data for fixed buffer size.");
1045 0 : return false;
1046 : }
1047 :
1048 : // copy data into record buffer.
1049 27 : if (!osATVL.empty())
1050 : {
1051 27 : memcpy(achRawData + nRawSize, osATVL.data(), osATVL.size());
1052 27 : nRawSize += static_cast<int>(osATVL.size());
1053 : }
1054 27 : achRawData[nRawSize++] = DDF_UNIT_TERMINATOR;
1055 :
1056 27 : nACount++;
1057 : }
1058 :
1059 : /* -------------------------------------------------------------------- */
1060 : /* If we got no attributes, return without adding ATTF. */
1061 : /* -------------------------------------------------------------------- */
1062 24 : if (nACount == 0)
1063 5 : return true;
1064 :
1065 : /* -------------------------------------------------------------------- */
1066 : /* Write the new field value. */
1067 : /* -------------------------------------------------------------------- */
1068 19 : DDFField *poField = poRec->AddField(poModule->FindFieldDefn("ATTF"));
1069 :
1070 19 : return CPL_TO_BOOL(poRec->SetFieldRaw(poField, 0, achRawData, nRawSize));
1071 : }
|