Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: ISO 8211 Access
4 : * Purpose: Implements the DDFRecord class.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Frank Warmerdam
9 : * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "iso8211.h"
16 :
17 : #include <cstddef>
18 : #include <cstdio>
19 : #include <cstring>
20 :
21 : #include "cpl_conv.h"
22 : #include "cpl_error.h"
23 : #include "cpl_vsi.h"
24 :
25 : constexpr int nLeaderSize = 24;
26 :
27 : /************************************************************************/
28 : /* DDFRecord() */
29 : /************************************************************************/
30 :
31 31944 : DDFRecord::DDFRecord(DDFModule *poModuleIn)
32 31944 : : poModule(poModuleIn), _sizeFieldTag(poModuleIn->GetSizeFieldTag())
33 : {
34 31944 : }
35 :
36 : /************************************************************************/
37 : /* ~DDFRecord() */
38 : /************************************************************************/
39 :
40 31944 : DDFRecord::~DDFRecord()
41 :
42 : {
43 31944 : Clear();
44 31944 : }
45 :
46 : /************************************************************************/
47 : /* GetFields() */
48 : /************************************************************************/
49 :
50 : /**
51 : * Return all fields of the specified name.
52 : */
53 :
54 : std::vector<const DDFField *>
55 24248 : DDFRecord::GetFields(const char *pszFieldName) const
56 : {
57 24248 : std::vector<const DDFField *> res;
58 99515 : for (auto &field : apoFields)
59 : {
60 75267 : if (strcmp(field->GetFieldDefn()->GetName(), pszFieldName) == 0)
61 10481 : res.push_back(field.get());
62 : }
63 24248 : return res;
64 : }
65 :
66 : /************************************************************************/
67 : /* GetFields() */
68 : /************************************************************************/
69 :
70 : /**
71 : * Return all fields of the specified name.
72 : */
73 :
74 1052 : std::vector<DDFField *> DDFRecord::GetFields(const char *pszFieldName)
75 : {
76 1052 : std::vector<DDFField *> res;
77 4629 : for (auto &field : apoFields)
78 : {
79 3577 : if (strcmp(field->GetFieldDefn()->GetName(), pszFieldName) == 0)
80 338 : res.push_back(field.get());
81 : }
82 1052 : return res;
83 : }
84 :
85 : /************************************************************************/
86 : /* Dump() */
87 : /************************************************************************/
88 :
89 : /**
90 : * Write out record contents to debugging file.
91 : *
92 : * A variety of information about this record, and all its fields and
93 : * subfields is written to the given debugging file handle. Note that
94 : * field definition information (ala DDFFieldDefn) isn't written.
95 : *
96 : * @param fp The standard IO file handle to write to. i.e. stderr
97 : */
98 :
99 0 : void DDFRecord::Dump(FILE *fp, int nNestingLevel) const
100 :
101 : {
102 0 : std::string osIndent;
103 0 : for (int i = 0; i < nNestingLevel; ++i)
104 0 : osIndent += " ";
105 :
106 : #define Print(...) \
107 : do \
108 : { \
109 : fprintf(fp, "%s", osIndent.c_str()); \
110 : fprintf(fp, __VA_ARGS__); \
111 : } while (0)
112 :
113 0 : Print("DDFRecord:\n");
114 0 : Print(" bReuseHeader = %d\n", bReuseHeader);
115 0 : Print(" nDataSize = %d\n", GetDataSize());
116 0 : Print(" _sizeFieldLength=%d, _sizeFieldPos=%d, _sizeFieldTag=%d\n",
117 : _sizeFieldLength, _sizeFieldPos, _sizeFieldTag);
118 :
119 0 : for (const auto &poField : apoFields)
120 : {
121 0 : poField->Dump(fp, nNestingLevel + 1);
122 : }
123 0 : }
124 :
125 : /************************************************************************/
126 : /* Read() */
127 : /* */
128 : /* Read a record of data from the file, and parse the header to */
129 : /* build a field list for the record (or reuse the existing one */
130 : /* if reusing headers). It is expected that the file pointer */
131 : /* will be positioned at the beginning of a data record. It is */
132 : /* the DDFModule's responsibility to do so. */
133 : /* */
134 : /* This method should only be called by the DDFModule class. */
135 : /************************************************************************/
136 :
137 31846 : int DDFRecord::Read()
138 :
139 : {
140 : /* -------------------------------------------------------------------- */
141 : /* Redefine the record on the basis of the header if needed. */
142 : /* As a side effect this will read the data for the record as well.*/
143 : /* -------------------------------------------------------------------- */
144 31846 : if (!bReuseHeader)
145 : {
146 31846 : return ReadHeader();
147 : }
148 0 : if (nFieldOffset < 0)
149 0 : return FALSE;
150 :
151 : /* -------------------------------------------------------------------- */
152 : /* Otherwise we read just the data and carefully overlay it on */
153 : /* the previous records data without disturbing the rest of the */
154 : /* record. */
155 : /* -------------------------------------------------------------------- */
156 : size_t nReadBytes;
157 :
158 0 : CPLAssert(nFieldOffset <= static_cast<int>(osData.size()));
159 0 : nReadBytes = VSIFReadL(osData.data() + nFieldOffset, 1,
160 0 : osData.size() - nFieldOffset, poModule->GetFP());
161 0 : if (nReadBytes != osData.size() - nFieldOffset && nReadBytes == 0 &&
162 0 : VSIFEofL(poModule->GetFP()))
163 : {
164 0 : return FALSE;
165 : }
166 0 : else if (nReadBytes != osData.size() - nFieldOffset)
167 : {
168 0 : CPLError(CE_Failure, CPLE_FileIO, "Data record is short on DDF file.");
169 :
170 0 : return FALSE;
171 : }
172 :
173 : // notdef: eventually we may have to do something at this point to
174 : // notify the DDFField's that their data values have changed.
175 :
176 0 : return TRUE;
177 : }
178 :
179 : /************************************************************************/
180 : /* Write() */
181 : /************************************************************************/
182 :
183 : /**
184 : * Write record out to module.
185 : *
186 : * This method writes the current record to the module to which it is
187 : * attached. Normally this would be at the end of the file, and only used
188 : * for modules newly created with DDFModule::Create(). Rewriting existing
189 : * records is not supported at this time. Calling Write() multiple times
190 : * on a DDFRecord will result it multiple copies being written at the end of
191 : * the module.
192 : *
193 : * @return TRUE on success or FALSE on failure.
194 : */
195 :
196 1355 : int DDFRecord::Write()
197 :
198 : {
199 1355 : ResetDirectory();
200 :
201 : /* -------------------------------------------------------------------- */
202 : /* Prepare leader. */
203 : /* -------------------------------------------------------------------- */
204 : char szLeader[nLeaderSize + 1];
205 :
206 1355 : memset(szLeader, ' ', nLeaderSize);
207 :
208 1355 : snprintf(szLeader + 0, sizeof(szLeader) - 0, "%05d",
209 1355 : static_cast<int>(osData.size() + nLeaderSize));
210 1355 : szLeader[5] = ' ';
211 1355 : szLeader[6] = 'D';
212 :
213 1355 : snprintf(szLeader + 12, sizeof(szLeader) - 12, "%05d",
214 1355 : static_cast<int>(nFieldOffset + nLeaderSize));
215 1355 : szLeader[17] = ' ';
216 :
217 1355 : szLeader[20] = static_cast<char>('0' + _sizeFieldLength);
218 1355 : szLeader[21] = static_cast<char>('0' + _sizeFieldPos);
219 1355 : szLeader[22] = '0';
220 1355 : szLeader[23] = static_cast<char>('0' + _sizeFieldTag);
221 :
222 : /* notdef: lots of stuff missing */
223 :
224 : /* -------------------------------------------------------------------- */
225 : /* Write the leader. */
226 : /* -------------------------------------------------------------------- */
227 1355 : int bRet = VSIFWriteL(szLeader, nLeaderSize, 1, poModule->GetFP()) > 0;
228 :
229 : /* -------------------------------------------------------------------- */
230 : /* Write the remainder of the record. */
231 : /* -------------------------------------------------------------------- */
232 1355 : bRet &= VSIFWriteL(osData.data(), osData.size(), 1, poModule->GetFP()) > 0;
233 :
234 1355 : return bRet ? TRUE : FALSE;
235 : }
236 :
237 : /************************************************************************/
238 : /* Clear() */
239 : /* */
240 : /* Clear any information associated with the last header in */
241 : /* preparation for reading a new header. */
242 : /************************************************************************/
243 :
244 63790 : void DDFRecord::Clear()
245 :
246 : {
247 63790 : apoFields.clear();
248 63790 : osData.clear();
249 63790 : bReuseHeader = FALSE;
250 63790 : }
251 :
252 : /************************************************************************/
253 : /* ReadHeader() */
254 : /* */
255 : /* This perform the header reading and parsing job for the */
256 : /* Read() method. It reads the header, and builds a field */
257 : /* list. */
258 : /************************************************************************/
259 :
260 31846 : int DDFRecord::ReadHeader()
261 :
262 : {
263 : /* -------------------------------------------------------------------- */
264 : /* Clear any existing information. */
265 : /* -------------------------------------------------------------------- */
266 31846 : Clear();
267 :
268 : /* -------------------------------------------------------------------- */
269 : /* Read the 24 byte leader. */
270 : /* -------------------------------------------------------------------- */
271 : char achLeader[nLeaderSize];
272 : int nReadBytes;
273 :
274 31846 : nReadBytes = static_cast<int>(
275 31846 : VSIFReadL(achLeader, 1, nLeaderSize, poModule->GetFP()));
276 31846 : if (nReadBytes == 0 && VSIFEofL(poModule->GetFP()))
277 : {
278 560 : nFieldOffset = -1;
279 560 : return FALSE;
280 : }
281 : // The ASRP and USRP specifications mentions that 0x5E / ^ character can be
282 : // used as a padding byte so that the file size is a multiple of 8192.
283 31286 : else if (achLeader[0] == '^')
284 : {
285 8 : nFieldOffset = -1;
286 8 : return FALSE;
287 : }
288 31278 : else if (nReadBytes != static_cast<int>(nLeaderSize))
289 : {
290 0 : CPLError(CE_Failure, CPLE_FileIO, "Leader is short on DDF file.");
291 0 : nFieldOffset = -1;
292 0 : return FALSE;
293 : }
294 :
295 : /* -------------------------------------------------------------------- */
296 : /* Extract information from leader. */
297 : /* -------------------------------------------------------------------- */
298 : int _recLength, _fieldAreaStart;
299 : char _leaderIden;
300 :
301 31278 : _recLength = DDFScanInt(achLeader + 0, 5);
302 31278 : _leaderIden = achLeader[6];
303 31278 : _fieldAreaStart = DDFScanInt(achLeader + 12, 5);
304 :
305 31278 : _sizeFieldLength = achLeader[20] - '0';
306 31278 : _sizeFieldPos = achLeader[21] - '0';
307 31278 : _sizeFieldTag = achLeader[23] - '0';
308 :
309 31278 : if (_sizeFieldLength <= 0 || _sizeFieldLength > 9 || _sizeFieldPos <= 0 ||
310 31278 : _sizeFieldPos > 9 || _sizeFieldTag <= 0 || _sizeFieldTag > 9)
311 : {
312 0 : CPLError(CE_Failure, CPLE_AppDefined,
313 : "ISO8211 record leader appears to be corrupt.");
314 0 : nFieldOffset = -1;
315 0 : return FALSE;
316 : }
317 :
318 31278 : if (_leaderIden == 'R')
319 0 : bReuseHeader = TRUE;
320 :
321 31278 : nFieldOffset = _fieldAreaStart - nLeaderSize;
322 :
323 : /* -------------------------------------------------------------------- */
324 : /* Is there anything seemly screwy about this record? */
325 : /* -------------------------------------------------------------------- */
326 31278 : if (((_recLength <= 24 || _recLength > 100000000) && (_recLength != 0)) ||
327 31278 : _fieldAreaStart < 24 || _fieldAreaStart > 100000)
328 : {
329 0 : CPLError(
330 : CE_Failure, CPLE_FileIO,
331 : "Data record appears to be corrupt on DDF file.\n"
332 : " -- ensure that the files were uncompressed without modifying\n"
333 : "carriage return/linefeeds (by default WINZIP does this).");
334 0 : nFieldOffset = -1;
335 0 : return FALSE;
336 : }
337 :
338 : /* ==================================================================== */
339 : /* Handle the normal case with the record length available. */
340 : /* ==================================================================== */
341 31278 : if (_recLength != 0)
342 : {
343 : /* --------------------------------------------------------------------
344 : */
345 : /* Read the remainder of the record. */
346 : /* --------------------------------------------------------------------
347 : */
348 31277 : int nDataSize = _recLength - nLeaderSize;
349 31277 : osData.resize(nDataSize);
350 :
351 62554 : if (VSIFReadL(osData.data(), 1, osData.size(), poModule->GetFP()) !=
352 31277 : osData.size())
353 : {
354 0 : CPLError(CE_Failure, CPLE_FileIO,
355 : "Data record is short on DDF file.");
356 0 : nFieldOffset = -1;
357 0 : return FALSE;
358 : }
359 :
360 : /* --------------------------------------------------------------------
361 : */
362 : /* If we don't find a field terminator at the end of the record */
363 : /* we will read extra bytes till we get to it. */
364 : /* --------------------------------------------------------------------
365 : */
366 31279 : while (!osData.empty() && osData.back() != DDF_FIELD_TERMINATOR &&
367 1 : (osData.size() < 2 ||
368 1 : osData[osData.size() - 2] != DDF_FIELD_TERMINATOR))
369 : {
370 0 : osData.resize(osData.size() + 1);
371 :
372 0 : if (VSIFReadL(&(osData.back()), 1, 1, poModule->GetFP()) != 1)
373 : {
374 0 : CPLError(CE_Failure, CPLE_FileIO,
375 : "Data record is short on DDF file.");
376 0 : nFieldOffset = -1;
377 0 : return FALSE;
378 : }
379 : static bool bFirstTime = true;
380 0 : if (bFirstTime)
381 : {
382 0 : bFirstTime = false;
383 0 : CPLDebug("ISO8211",
384 : "Didn't find field terminator, read one more byte.");
385 : }
386 : }
387 :
388 31277 : if (nFieldOffset >= static_cast<int>(osData.size()))
389 : {
390 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
391 : "nFieldOffset < static_cast<int>(osData.size())");
392 0 : nFieldOffset = -1;
393 0 : return FALSE;
394 : }
395 :
396 : /* --------------------------------------------------------------------
397 : */
398 : /* Loop over the directory entries, making a pass counting them. */
399 : /* --------------------------------------------------------------------
400 : */
401 : int i;
402 : int nFieldEntryWidth;
403 :
404 31277 : nFieldEntryWidth = _sizeFieldLength + _sizeFieldPos + _sizeFieldTag;
405 31277 : if (nFieldEntryWidth <= 0)
406 : {
407 0 : CPLError(CE_Failure, CPLE_FileIO, "Invalid entry width = %d",
408 : nFieldEntryWidth);
409 0 : nFieldOffset = -1;
410 0 : return FALSE;
411 : }
412 :
413 31277 : int nFieldCount = 0;
414 151856 : for (i = 0; i + nFieldEntryWidth <= static_cast<int>(osData.size());
415 120579 : i += nFieldEntryWidth)
416 : {
417 151817 : if (osData[i] == DDF_FIELD_TERMINATOR)
418 31238 : break;
419 :
420 120579 : nFieldCount++;
421 : }
422 :
423 : /* --------------------------------------------------------------------
424 : */
425 : /* Allocate, and read field definitions. */
426 : /* --------------------------------------------------------------------
427 : */
428 31277 : apoFields.resize(nFieldCount);
429 :
430 31277 : int nLastFieldPos = 0;
431 31277 : int nLastFieldLength = 0;
432 151855 : for (i = 0; i < nFieldCount; i++)
433 : {
434 : char szTag[128];
435 120579 : int nEntryOffset = i * nFieldEntryWidth;
436 : int nFieldLength, nFieldPos;
437 :
438 : /* --------------------------------------------------------------------
439 : */
440 : /* Read the position information and tag. */
441 : /* --------------------------------------------------------------------
442 : */
443 120579 : strncpy(szTag, osData.c_str() + nEntryOffset, _sizeFieldTag);
444 120579 : szTag[_sizeFieldTag] = '\0';
445 :
446 120579 : nEntryOffset += _sizeFieldTag;
447 : nFieldLength =
448 120579 : DDFScanInt(osData.c_str() + nEntryOffset, _sizeFieldLength);
449 :
450 120579 : nEntryOffset += _sizeFieldLength;
451 : nFieldPos =
452 120579 : DDFScanInt(osData.c_str() + nEntryOffset, _sizeFieldPos);
453 :
454 : /* --------------------------------------------------------------------
455 : */
456 : /* Find the corresponding field in the module directory. */
457 : /* --------------------------------------------------------------------
458 : */
459 120579 : DDFFieldDefn *poFieldDefn = poModule->FindFieldDefn(szTag);
460 :
461 120579 : if (poFieldDefn == nullptr || nFieldLength < 0 || nFieldPos < 0)
462 : {
463 0 : CPLError(CE_Failure, CPLE_AppDefined,
464 : "Undefined field `%s' encountered in data record.",
465 : szTag);
466 1 : return FALSE;
467 : }
468 :
469 241158 : if (_fieldAreaStart + nFieldPos - nLeaderSize < 0 ||
470 120579 : static_cast<int>(osData.size()) -
471 120579 : (_fieldAreaStart + nFieldPos - nLeaderSize) <
472 : nFieldLength)
473 : {
474 0 : CPLError(CE_Failure, CPLE_AppDefined,
475 : "Not enough byte to initialize field `%s'.", szTag);
476 0 : nFieldOffset = -1;
477 0 : return FALSE;
478 : }
479 :
480 : // This check is not strictly needed for reading scenarios, but
481 : // in update scenarios (such as S57/S101), it is essential to avoid
482 : // issues when resizing fields.
483 120579 : if (nFieldPos < nLastFieldPos + nLastFieldLength)
484 : {
485 1 : CPLError(CE_Failure, CPLE_AppDefined,
486 : "Field `%s' overlapping with previous one.", szTag);
487 1 : nFieldOffset = -1;
488 1 : return FALSE;
489 : }
490 :
491 : /* --------------------------------------------------------------------
492 : */
493 : /* Assign info the DDFField. */
494 : /* --------------------------------------------------------------------
495 : */
496 120578 : apoFields[i] = std::make_unique<DDFField>();
497 120578 : apoFields[i]->Initialize(poFieldDefn,
498 120578 : osData.c_str() + _fieldAreaStart +
499 120578 : nFieldPos - nLeaderSize,
500 : nFieldLength, true);
501 :
502 120578 : nLastFieldPos = nFieldPos;
503 120578 : nLastFieldLength = nFieldLength;
504 : }
505 :
506 31276 : return TRUE;
507 : }
508 : /* ==================================================================== */
509 : /* Handle the exceptional case where the record length is */
510 : /* zero. In this case we have to read all the data based on */
511 : /* the size of data items as per ISO8211 spec Annex C, 1.5.1. */
512 : /* */
513 : /* See Bugzilla bug 181 and test with file US4CN21M.000. */
514 : /* ==================================================================== */
515 : else
516 : {
517 1 : CPLDebug("ISO8211",
518 : "Record with zero length, use variant (C.1.5.1) logic.");
519 :
520 : /* ----------------------------------------------------------------- */
521 : /* _recLength == 0, handle the large record. */
522 : /* */
523 : /* Read the remainder of the record. */
524 : /* ----------------------------------------------------------------- */
525 1 : osData.clear();
526 :
527 : /* ----------------------------------------------------------------- */
528 : /* Loop over the directory entries, making a pass counting them. */
529 : /* ----------------------------------------------------------------- */
530 1 : int nFieldEntryWidth = _sizeFieldLength + _sizeFieldPos + _sizeFieldTag;
531 1 : int nFieldCount = 0;
532 1 : int i = 0;
533 :
534 1 : if (nFieldEntryWidth == 0)
535 : {
536 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
537 : "Invalid record buffer size : %d.", nFieldEntryWidth);
538 0 : nFieldOffset = -1;
539 0 : return FALSE;
540 : }
541 :
542 2 : std::string osEntry;
543 1 : osEntry.resize(nFieldEntryWidth);
544 :
545 : // while we're not at the end, store this entry,
546 : // and keep on reading...
547 2 : do
548 : {
549 : // read an Entry:
550 3 : if (nFieldEntryWidth !=
551 3 : static_cast<int>(VSIFReadL(osEntry.data(), 1, nFieldEntryWidth,
552 3 : poModule->GetFP())))
553 : {
554 0 : CPLError(CE_Failure, CPLE_FileIO,
555 : "Data record is short on DDF file.");
556 0 : nFieldOffset = -1;
557 0 : return FALSE;
558 : }
559 :
560 3 : osData.append(osEntry.c_str(), nFieldEntryWidth);
561 :
562 3 : if (DDF_FIELD_TERMINATOR != osEntry[0])
563 : {
564 2 : nFieldCount++;
565 2 : if (nFieldCount == 1000)
566 : {
567 0 : CPLError(CE_Failure, CPLE_FileIO,
568 : "Too many fields in DDF file.");
569 0 : nFieldOffset = -1;
570 0 : return FALSE;
571 : }
572 : }
573 3 : } while (DDF_FIELD_TERMINATOR != osEntry[0]);
574 :
575 : // --------------------------------------------------------------------
576 : // Now, rewind a little. Only the TERMINATOR should have been read
577 : // --------------------------------------------------------------------
578 1 : int rewindSize = nFieldEntryWidth - 1;
579 1 : VSILFILE *fp = poModule->GetFP();
580 1 : vsi_l_offset pos = VSIFTellL(fp) - rewindSize;
581 1 : if (VSIFSeekL(fp, pos, SEEK_SET) < 0)
582 0 : return FALSE;
583 1 : osData.resize(osData.size() - rewindSize);
584 :
585 : // --------------------------------------------------------------------
586 : // Okay, now let's populate the heck out of osData...
587 : // --------------------------------------------------------------------
588 3 : for (i = 0; i < nFieldCount; i++)
589 : {
590 2 : int nEntryOffset = (i * nFieldEntryWidth) + _sizeFieldTag;
591 : int nFieldLength =
592 2 : DDFScanInt(osData.c_str() + nEntryOffset, _sizeFieldLength);
593 2 : if (nFieldLength < 0)
594 : {
595 0 : nFieldOffset = -1;
596 0 : return FALSE;
597 : }
598 :
599 2 : osEntry.resize(nFieldLength);
600 :
601 : // read an Entry:
602 2 : if (nFieldLength !=
603 2 : static_cast<int>(VSIFReadL(osEntry.data(), 1, nFieldLength,
604 2 : poModule->GetFP())))
605 : {
606 0 : CPLError(CE_Failure, CPLE_FileIO,
607 : "Data record is short on DDF file.");
608 0 : nFieldOffset = -1;
609 0 : return FALSE;
610 : }
611 :
612 : // move this temp buffer into more permanent storage:
613 2 : osData.append(osEntry.data(), nFieldLength);
614 : }
615 :
616 1 : if (nFieldOffset >= static_cast<int>(osData.size()))
617 : {
618 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
619 : "nFieldOffset < static_cast<int>(osData.size())");
620 0 : nFieldOffset = -1;
621 0 : return FALSE;
622 : }
623 :
624 : /* ----------------------------------------------------------------- */
625 : /* Allocate, and read field definitions. */
626 : /* ----------------------------------------------------------------- */
627 1 : apoFields.resize(nFieldCount);
628 :
629 1 : int nLastFieldPos = 0;
630 1 : int nLastFieldLength = 0;
631 3 : for (i = 0; i < nFieldCount; i++)
632 : {
633 : char szTag[128];
634 2 : int nEntryOffset = i * nFieldEntryWidth;
635 : int nFieldLength, nFieldPos;
636 :
637 : /* ------------------------------------------------------------- */
638 : /* Read the position information and tag. */
639 : /* ------------------------------------------------------------- */
640 2 : strncpy(szTag, osData.c_str() + nEntryOffset, _sizeFieldTag);
641 2 : szTag[_sizeFieldTag] = '\0';
642 :
643 2 : nEntryOffset += _sizeFieldTag;
644 : nFieldLength =
645 2 : DDFScanInt(osData.c_str() + nEntryOffset, _sizeFieldLength);
646 :
647 2 : nEntryOffset += _sizeFieldLength;
648 : nFieldPos =
649 2 : DDFScanInt(osData.c_str() + nEntryOffset, _sizeFieldPos);
650 :
651 : /* ------------------------------------------------------------- */
652 : /* Find the corresponding field in the module directory. */
653 : /* ------------------------------------------------------------- */
654 2 : DDFFieldDefn *poFieldDefn = poModule->FindFieldDefn(szTag);
655 :
656 2 : if (poFieldDefn == nullptr || nFieldLength < 0 || nFieldPos < 0)
657 : {
658 0 : CPLError(CE_Failure, CPLE_AppDefined,
659 : "Undefined field `%s' encountered in data record.",
660 : szTag);
661 0 : nFieldOffset = -1;
662 0 : return FALSE;
663 : }
664 :
665 4 : if (_fieldAreaStart + nFieldPos - nLeaderSize < 0 ||
666 2 : static_cast<int>(osData.size()) -
667 2 : (_fieldAreaStart + nFieldPos - nLeaderSize) <
668 : nFieldLength)
669 : {
670 0 : CPLError(CE_Failure, CPLE_AppDefined,
671 : "Not enough byte to initialize field `%s'.", szTag);
672 0 : nFieldOffset = -1;
673 0 : return FALSE;
674 : }
675 :
676 : // This check is not strictly needed for reading scenarios, but
677 : // in update scenarios (such as S57/S101), it is essential to avoid
678 : // issues when resizing fields.
679 2 : if (nFieldPos < nLastFieldPos + nLastFieldLength)
680 : {
681 0 : CPLError(CE_Failure, CPLE_AppDefined,
682 : "Field `%s' overlapping with previous one.", szTag);
683 0 : nFieldOffset = -1;
684 0 : return FALSE;
685 : }
686 :
687 : /* ------------------------------------------------------------- */
688 : /* Assign info the DDFField. */
689 : /* ------------------------------------------------------------- */
690 :
691 2 : apoFields[i] = std::make_unique<DDFField>();
692 2 : apoFields[i]->Initialize(poFieldDefn,
693 2 : osData.c_str() + _fieldAreaStart +
694 2 : nFieldPos - nLeaderSize,
695 : nFieldLength, true);
696 :
697 2 : nLastFieldPos = nFieldPos;
698 2 : nLastFieldLength = nFieldLength;
699 : }
700 :
701 1 : return TRUE;
702 : }
703 : }
704 :
705 : /************************************************************************/
706 : /* FindField() */
707 : /************************************************************************/
708 :
709 : /**
710 : * Find the named field within this record.
711 : *
712 : * @param pszName The name of the field to fetch. The comparison is
713 : * case insensitive.
714 : * @param iFieldIndex The instance of this field to fetch. Use zero (the
715 : * default) for the first instance.
716 : *
717 : * @return Pointer to the requested DDFField. This pointer is to an
718 : * internal object, and should not be freed. It remains valid until
719 : * the next record read.
720 : */
721 :
722 590082 : const DDFField *DDFRecord::FindField(const char *pszName, int iFieldIndex) const
723 :
724 : {
725 1692740 : for (const auto &poField : apoFields)
726 : {
727 1672570 : const DDFFieldDefn *poFieldDefn = poField->GetFieldDefn();
728 1672570 : if (poFieldDefn && EQUAL(poFieldDefn->GetName(), pszName))
729 : {
730 570926 : if (iFieldIndex == 0)
731 569915 : return poField.get();
732 : else
733 1011 : iFieldIndex--;
734 : }
735 : }
736 :
737 20167 : return nullptr;
738 : }
739 :
740 : /************************************************************************/
741 : /* GetField() */
742 : /************************************************************************/
743 :
744 : /**
745 : * Fetch field object based on index.
746 : *
747 : * @param i The index of the field to fetch. Between 0 and GetFieldCount()-1.
748 : *
749 : * @return A DDFField pointer, or NULL if the index is out of range.
750 : */
751 :
752 224222 : const DDFField *DDFRecord::GetField(int i) const
753 :
754 : {
755 224222 : if (i < 0 || static_cast<size_t>(i) >= apoFields.size())
756 0 : return nullptr;
757 : else
758 224222 : return apoFields[i].get();
759 : }
760 :
761 : /************************************************************************/
762 : /* FindSubfieldDefn() */
763 : /************************************************************************/
764 :
765 : /* static */ std::tuple<const DDFField *, const DDFSubfieldDefn *>
766 552520 : DDFRecord::FindSubfieldDefn(const DDFField *poField, const char *pszSubfield,
767 : bool bEmitError)
768 : {
769 552520 : if (poField->GetParts().empty())
770 : {
771 : /* -------------------------------------------------------------------- */
772 : /* Get the subfield definition */
773 : /* -------------------------------------------------------------------- */
774 : const DDFSubfieldDefn *poSFDefn =
775 533254 : poField->GetFieldDefn()->FindSubfieldDefn(pszSubfield);
776 533254 : if (poSFDefn == nullptr)
777 : {
778 88 : if (bEmitError)
779 : {
780 0 : CPLError(CE_Failure, CPLE_AppDefined,
781 : "Cannot find subfield %s of %s", pszSubfield,
782 : poField->GetFieldDefn()->GetName());
783 : }
784 88 : return {nullptr, nullptr};
785 : }
786 :
787 533166 : return {nullptr, poSFDefn};
788 : }
789 : else
790 : {
791 21066 : for (auto &poPart : poField->GetParts())
792 : {
793 : const DDFSubfieldDefn *poSFDefn =
794 21066 : poPart->GetFieldDefn()->FindSubfieldDefn(pszSubfield);
795 21066 : if (poSFDefn)
796 38532 : return {poPart.get(), poSFDefn};
797 : }
798 0 : if (bEmitError)
799 : {
800 0 : CPLError(CE_Failure, CPLE_AppDefined,
801 : "Cannot find subfield %s of %s", pszSubfield,
802 : poField->GetFieldDefn()->GetName());
803 : }
804 0 : return {nullptr, nullptr};
805 : }
806 : }
807 :
808 : /************************************************************************/
809 : /* FindSubfieldDefn() */
810 : /************************************************************************/
811 :
812 : std::tuple<const DDFField *, const DDFField *, const DDFSubfieldDefn *>
813 27753 : DDFRecord::FindSubfieldDefn(const char *pszField, int iFieldIndex,
814 : const char *pszSubfield, bool bEmitError) const
815 : {
816 : /* -------------------------------------------------------------------- */
817 : /* Fetch the field. If this fails, return zero. */
818 : /* -------------------------------------------------------------------- */
819 27753 : const DDFField *poField = FindField(pszField, iFieldIndex);
820 27753 : if (poField == nullptr)
821 : {
822 0 : if (bEmitError)
823 : {
824 0 : CPLError(CE_Failure, CPLE_AppDefined,
825 : "Cannot find field index %d of %s", iFieldIndex, pszField);
826 : }
827 0 : return {nullptr, nullptr, nullptr};
828 : }
829 :
830 27753 : auto [poPartField, poSFDefn] =
831 27753 : FindSubfieldDefn(poField, pszSubfield, bEmitError);
832 55506 : return {poSFDefn ? poField : nullptr, poPartField, poSFDefn};
833 : }
834 :
835 : /************************************************************************/
836 : /* GetIntSubfield() */
837 : /************************************************************************/
838 :
839 : /**
840 : * Fetch value of a subfield as an integer. This is a convenience
841 : * function for fetching a subfield of a field within this record.
842 : *
843 : * @param poField The field containing the subfield.
844 : * @param iSubfieldIndex The instance of this subfield within the record.
845 : * Use zero for the first instance.
846 : * @param pnSuccess Pointer to an int which will be set to TRUE if the fetch
847 : * succeeds, or FALSE if it fails. Use NULL if you don't want to check
848 : * success.
849 : * @return The value of the subfield, or zero if it failed for some reason.
850 : */
851 :
852 484875 : int DDFRecord::GetIntSubfield(const DDFField *poField, const char *pszSubfield,
853 : int iSubfieldIndex, int *pnSuccess) const
854 :
855 : {
856 484875 : int nDummyErr = FALSE;
857 :
858 484875 : if (pnSuccess == nullptr)
859 396038 : pnSuccess = &nDummyErr;
860 :
861 484875 : *pnSuccess = FALSE;
862 :
863 : /* -------------------------------------------------------------------- */
864 : /* Get the subfield definition */
865 : /* -------------------------------------------------------------------- */
866 484875 : auto [poPartField, poSFDefn] =
867 484875 : FindSubfieldDefn(poField, pszSubfield, false);
868 484875 : if (poSFDefn == nullptr)
869 34 : return 0;
870 484841 : if (poPartField)
871 8105 : poField = poPartField;
872 :
873 : /* -------------------------------------------------------------------- */
874 : /* Get a pointer to the data. */
875 : /* -------------------------------------------------------------------- */
876 : int nBytesRemaining;
877 :
878 : const char *l_pachData =
879 484841 : poField->GetSubfieldData(poSFDefn, &nBytesRemaining, iSubfieldIndex);
880 484841 : if (l_pachData == nullptr)
881 0 : return 0;
882 :
883 : /* -------------------------------------------------------------------- */
884 : /* Return the extracted value. */
885 : /* */
886 : /* Assume an error has occurred if no bytes are consumed. */
887 : /* -------------------------------------------------------------------- */
888 484841 : int nConsumedBytes = 0;
889 : int nResult =
890 484841 : poSFDefn->ExtractIntData(l_pachData, nBytesRemaining, &nConsumedBytes);
891 :
892 484841 : if (nConsumedBytes > 0)
893 484841 : *pnSuccess = TRUE;
894 :
895 484841 : return nResult;
896 : }
897 :
898 : /************************************************************************/
899 : /* GetIntSubfield() */
900 : /************************************************************************/
901 :
902 : /**
903 : * Fetch value of a subfield as an integer. This is a convenience
904 : * function for fetching a subfield of a field within this record.
905 : *
906 : * @param pszField The name of the field containing the subfield.
907 : * @param iFieldIndex The instance of this field within the record. Use
908 : * zero for the first instance of this field.
909 : * @param pszSubfield The name of the subfield within the selected field.
910 : * @param iSubfieldIndex The instance of this subfield within the record.
911 : * Use zero for the first instance.
912 : * @param pnSuccess Pointer to an int which will be set to TRUE if the fetch
913 : * succeeds, or FALSE if it fails. Use NULL if you don't want to check
914 : * success.
915 : * @return The value of the subfield, or zero if it failed for some reason.
916 : */
917 :
918 379871 : int DDFRecord::GetIntSubfield(const char *pszField, int iFieldIndex,
919 : const char *pszSubfield, int iSubfieldIndex,
920 : int *pnSuccess) const
921 :
922 : {
923 379871 : const DDFField *poField = FindField(pszField, iFieldIndex);
924 379871 : if (poField == nullptr)
925 : {
926 33 : if (pnSuccess)
927 0 : *pnSuccess = FALSE;
928 33 : return 0;
929 : }
930 :
931 379838 : return GetIntSubfield(poField, pszSubfield, iSubfieldIndex, pnSuccess);
932 : }
933 :
934 : /************************************************************************/
935 : /* GetFloatSubfield() */
936 : /************************************************************************/
937 :
938 : /**
939 : * Fetch value of a subfield as a float (double). This is a convenience
940 : * function for fetching a subfield of a field within this record.
941 : *
942 : * @param pszField The name of the field containing the subfield.
943 : * @param iFieldIndex The instance of this field within the record. Use
944 : * zero for the first instance of this field.
945 : * @param pszSubfield The name of the subfield within the selected field.
946 : * @param iSubfieldIndex The instance of this subfield within the record.
947 : * Use zero for the first instance.
948 : * @param pnSuccess Pointer to an int which will be set to TRUE if the fetch
949 : * succeeds, or FALSE if it fails. Use NULL if you don't want to check
950 : * success.
951 : * @return The value of the subfield, or zero if it failed for some reason.
952 : */
953 :
954 1908 : double DDFRecord::GetFloatSubfield(const char *pszField, int iFieldIndex,
955 : const char *pszSubfield, int iSubfieldIndex,
956 : int *pnSuccess) const
957 :
958 : {
959 1908 : int nDummyErr = FALSE;
960 :
961 1908 : if (pnSuccess == nullptr)
962 84 : pnSuccess = &nDummyErr;
963 :
964 1908 : *pnSuccess = FALSE;
965 :
966 : /* -------------------------------------------------------------------- */
967 : /* Fetch the field. If this fails, return zero. */
968 : /* -------------------------------------------------------------------- */
969 1908 : auto [poField, poPartField, poSFDefn] =
970 1908 : FindSubfieldDefn(pszField, iFieldIndex, pszSubfield, false);
971 1908 : if (poSFDefn == nullptr)
972 2 : return 0;
973 1906 : if (poPartField)
974 0 : poField = poPartField;
975 :
976 : /* -------------------------------------------------------------------- */
977 : /* Get a pointer to the data. */
978 : /* -------------------------------------------------------------------- */
979 : int nBytesRemaining;
980 :
981 : const char *l_pachData =
982 1906 : poField->GetSubfieldData(poSFDefn, &nBytesRemaining, iSubfieldIndex);
983 1906 : if (l_pachData == nullptr)
984 0 : return 0;
985 :
986 : /* -------------------------------------------------------------------- */
987 : /* Return the extracted value. */
988 : /* -------------------------------------------------------------------- */
989 1906 : int nConsumedBytes = 0;
990 1906 : double dfResult = poSFDefn->ExtractFloatData(l_pachData, nBytesRemaining,
991 : &nConsumedBytes);
992 :
993 1906 : if (nConsumedBytes > 0)
994 1906 : *pnSuccess = TRUE;
995 :
996 1906 : return dfResult;
997 : }
998 :
999 : /************************************************************************/
1000 : /* GetStringSubfield() */
1001 : /************************************************************************/
1002 :
1003 : /**
1004 : * Fetch value of a subfield as a string. This is a convenience
1005 : * function for fetching a subfield of a field within this record.
1006 : *
1007 : * @param poField The field containing the subfield.
1008 : * @param pszSubfield The name of the subfield within the selected field.
1009 : * @param iSubfieldIndex The instance of this subfield within the record.
1010 : * Use zero for the first instance.
1011 : * @param pnSuccess Pointer to an int which will be set to TRUE if the fetch
1012 : * succeeds, or FALSE if it fails. Use NULL if you don't want to check
1013 : * success.
1014 : * @return The value of the subfield, or NULL if it failed for some reason.
1015 : * The returned pointer is to internal data and should not be modified or
1016 : * freed by the application.
1017 : */
1018 :
1019 39892 : const char *DDFRecord::GetStringSubfield(const DDFField *poField,
1020 : const char *pszSubfield,
1021 : int iSubfieldIndex,
1022 : int *pnSuccess) const
1023 :
1024 : {
1025 39892 : int nDummyErr = FALSE;
1026 :
1027 39892 : if (pnSuccess == nullptr)
1028 34939 : pnSuccess = &nDummyErr;
1029 :
1030 39892 : *pnSuccess = FALSE;
1031 :
1032 : /* -------------------------------------------------------------------- */
1033 : /* Fetch the field. If this fails, return zero. */
1034 : /* -------------------------------------------------------------------- */
1035 39892 : auto [poPartField, poSFDefn] =
1036 39892 : FindSubfieldDefn(poField, pszSubfield, false);
1037 39892 : if (poSFDefn == nullptr)
1038 52 : return nullptr;
1039 39840 : if (poPartField)
1040 6879 : poField = poPartField;
1041 :
1042 : /* -------------------------------------------------------------------- */
1043 : /* Get a pointer to the data. */
1044 : /* -------------------------------------------------------------------- */
1045 : int nBytesRemaining;
1046 :
1047 : const char *l_pachData =
1048 39840 : poField->GetSubfieldData(poSFDefn, &nBytesRemaining, iSubfieldIndex);
1049 39840 : if (l_pachData == nullptr)
1050 0 : return nullptr;
1051 :
1052 : /* -------------------------------------------------------------------- */
1053 : /* Return the extracted value. */
1054 : /* -------------------------------------------------------------------- */
1055 39840 : *pnSuccess = TRUE;
1056 :
1057 39840 : return poSFDefn->ExtractStringData(l_pachData, nBytesRemaining, nullptr);
1058 : }
1059 :
1060 : /************************************************************************/
1061 : /* GetStringSubfield() */
1062 : /************************************************************************/
1063 :
1064 : /**
1065 : * Fetch value of a subfield as a string. This is a convenience
1066 : * function for fetching a subfield of a field within this record.
1067 : *
1068 : * @param pszField The name of the field containing the subfield.
1069 : * @param iFieldIndex The instance of this field within the record. Use
1070 : * zero for the first instance of this field.
1071 : * @param pszSubfield The name of the subfield within the selected field.
1072 : * @param iSubfieldIndex The instance of this subfield within the record.
1073 : * Use zero for the first instance.
1074 : * @param pnSuccess Pointer to an int which will be set to TRUE if the fetch
1075 : * succeeds, or FALSE if it fails. Use NULL if you don't want to check
1076 : * success.
1077 : * @return The value of the subfield, or NULL if it failed for some reason.
1078 : * The returned pointer is to internal data and should not be modified or
1079 : * freed by the application.
1080 : */
1081 :
1082 23544 : const char *DDFRecord::GetStringSubfield(const char *pszField, int iFieldIndex,
1083 : const char *pszSubfield,
1084 : int iSubfieldIndex,
1085 : int *pnSuccess) const
1086 :
1087 : {
1088 23544 : const DDFField *poField = FindField(pszField, iFieldIndex);
1089 23544 : if (poField == nullptr)
1090 : {
1091 0 : if (pnSuccess)
1092 0 : *pnSuccess = FALSE;
1093 0 : return nullptr;
1094 : }
1095 :
1096 23544 : return GetStringSubfield(poField, pszSubfield, iSubfieldIndex, pnSuccess);
1097 : }
1098 :
1099 : /************************************************************************/
1100 : /* Clone() */
1101 : /************************************************************************/
1102 :
1103 : /**
1104 : * Make a copy of a record.
1105 : *
1106 : * This method is used to make a copy of a record that will become (mostly)
1107 : * the properly of application.
1108 : *
1109 : * @return A new copy of the DDFRecord. Its lifetime must not extend the one
1110 : * of the DDFModule of the original record, unless TransferTo() is called.
1111 : */
1112 :
1113 29859 : std::unique_ptr<DDFRecord> DDFRecord::Clone() const
1114 :
1115 : {
1116 29859 : auto poNR = std::make_unique<DDFRecord>(poModule);
1117 :
1118 29859 : poNR->bReuseHeader = false;
1119 29859 : poNR->nFieldOffset = nFieldOffset;
1120 :
1121 29859 : poNR->osData = osData;
1122 :
1123 29859 : poNR->apoFields.resize(apoFields.size());
1124 145568 : for (size_t i = 0; i < apoFields.size(); i++)
1125 : {
1126 : int nOffset;
1127 :
1128 115709 : nOffset = static_cast<int>(apoFields[i]->GetData() - osData.c_str());
1129 115709 : poNR->apoFields[i] = std::make_unique<DDFField>();
1130 347127 : poNR->apoFields[i]->Initialize(apoFields[i]->GetFieldDefn(),
1131 115709 : poNR->osData.c_str() + nOffset,
1132 115709 : apoFields[i]->GetDataSize(), true);
1133 : }
1134 :
1135 29859 : return poNR;
1136 : }
1137 :
1138 : /************************************************************************/
1139 : /* TransferTo() */
1140 : /************************************************************************/
1141 :
1142 : /**
1143 : * Transfer this record to another module.
1144 : *
1145 : * All DDFFieldDefn
1146 : * references are transcribed onto the new module based on field names.
1147 : * If any fields don't have a similarly named field on the target module
1148 : * the operation will fail. No validation of field types and properties
1149 : * is done, but this operation is intended only to be used between
1150 : * modules with matching definitions of all affected fields.
1151 : *
1152 : * @param poTargetModule the module to which the record should be transferred
1153 : *
1154 : * @return true on success
1155 : */
1156 :
1157 68 : bool DDFRecord::TransferTo(DDFModule *poTargetModule)
1158 :
1159 : {
1160 : /* -------------------------------------------------------------------- */
1161 : /* Verify that all fields have a corresponding field definition */
1162 : /* on the target module. */
1163 : /* -------------------------------------------------------------------- */
1164 300 : for (const auto &poField : apoFields)
1165 : {
1166 233 : const DDFFieldDefn *poDefn = poField->GetFieldDefn();
1167 :
1168 233 : if (poTargetModule->FindFieldDefn(poDefn->GetName()) == nullptr)
1169 : {
1170 1 : CPLError(CE_Failure, CPLE_AppDefined,
1171 : "Cannot find field definition %s in target module",
1172 : poDefn->GetName());
1173 1 : return false;
1174 : }
1175 :
1176 : //TODO? check equality between source and target field definitions
1177 : }
1178 :
1179 : /* -------------------------------------------------------------------- */
1180 : /* Update all internal information to reference other module. */
1181 : /* -------------------------------------------------------------------- */
1182 298 : for (auto &poField : apoFields)
1183 : {
1184 : DDFFieldDefn *poDefn =
1185 231 : poTargetModule->FindFieldDefn(poField->GetFieldDefn()->GetName());
1186 :
1187 231 : poField->Initialize(poDefn, poField->GetData(), poField->GetDataSize(),
1188 : true);
1189 : }
1190 :
1191 67 : poModule = poTargetModule;
1192 :
1193 67 : return true;
1194 : }
1195 :
1196 : /************************************************************************/
1197 : /* DeleteField() */
1198 : /************************************************************************/
1199 :
1200 : /**
1201 : * Delete a field instance from a record.
1202 : *
1203 : * Remove a field from this record, cleaning up the data
1204 : * portion and repacking the fields list. We don't try to
1205 : * reallocate the data area of the record to be smaller.
1206 : *
1207 : * NOTE: This method doesn't actually remove the header
1208 : * information for this field from the record tag list yet.
1209 : * This should be added if the resulting record is even to be
1210 : * written back to disk!
1211 : *
1212 : * @param poTarget the field instance on this record to delete.
1213 : *
1214 : * @return TRUE on success, or FALSE on failure. Failure can occur if
1215 : * poTarget isn't really a field on this record.
1216 : */
1217 :
1218 51 : int DDFRecord::DeleteField(DDFField *poTarget)
1219 :
1220 : {
1221 : int iTarget;
1222 :
1223 : /* -------------------------------------------------------------------- */
1224 : /* Find which field we are to delete. */
1225 : /* -------------------------------------------------------------------- */
1226 165 : for (iTarget = 0; iTarget < GetFieldCount(); iTarget++)
1227 : {
1228 165 : if (apoFields[iTarget].get() == poTarget)
1229 51 : break;
1230 : }
1231 :
1232 51 : if (iTarget == GetFieldCount())
1233 0 : return FALSE;
1234 :
1235 : /* -------------------------------------------------------------------- */
1236 : /* Change the target fields data size to zero. This takes care */
1237 : /* of repacking the data array, and updating all the following */
1238 : /* field data pointers. */
1239 : /* -------------------------------------------------------------------- */
1240 51 : ResizeField(poTarget, 0);
1241 :
1242 : /* -------------------------------------------------------------------- */
1243 : /* remove the target field, moving down all the other fields */
1244 : /* one step in the field list. */
1245 : /* -------------------------------------------------------------------- */
1246 51 : apoFields.erase(apoFields.begin() + iTarget);
1247 :
1248 219 : for (auto &poField : apoFields)
1249 168 : poField->InitializeParts();
1250 :
1251 51 : return TRUE;
1252 : }
1253 :
1254 : /************************************************************************/
1255 : /* ResizeField() */
1256 : /************************************************************************/
1257 :
1258 : /**
1259 : * Alter field data size within record.
1260 : *
1261 : * This method will rearrange a DDFRecord altering the amount of space
1262 : * reserved for one of the existing fields. All following fields will
1263 : * be shifted accordingly. This includes updating the DDFField infos,
1264 : * and actually moving stuff within the data array after reallocating
1265 : * to the desired size.
1266 : *
1267 : * @param poField the field to alter.
1268 : * @param nNewDataSize the number of data bytes to be reserved for the field.
1269 : *
1270 : * @return TRUE on success or FALSE on failure.
1271 : */
1272 :
1273 11360 : int DDFRecord::ResizeField(DDFField *poField, int nNewDataSize)
1274 :
1275 : {
1276 : /* -------------------------------------------------------------------- */
1277 : /* Find which field we are to resize. */
1278 : /* -------------------------------------------------------------------- */
1279 : int iTarget;
1280 30661 : for (iTarget = 0; iTarget < GetFieldCount(); iTarget++)
1281 : {
1282 30661 : if (apoFields[iTarget].get() == poField)
1283 11360 : break;
1284 : }
1285 :
1286 11360 : if (iTarget == GetFieldCount())
1287 0 : return FALSE;
1288 :
1289 : /* -------------------------------------------------------------------- */
1290 : /* How much data needs to be shifted up or down after this field? */
1291 : /* -------------------------------------------------------------------- */
1292 11360 : const int nOldDataSize = poField->GetDataSize();
1293 : const int nBytesToMove =
1294 11360 : static_cast<int>(osData.size()) -
1295 11360 : static_cast<int>(poField->GetData() + nOldDataSize - osData.data());
1296 :
1297 : /* -------------------------------------------------------------------- */
1298 : /* Store field offsets */
1299 : /* -------------------------------------------------------------------- */
1300 11360 : std::vector<int> anOffsets;
1301 42148 : for (auto &poIterField : apoFields)
1302 : {
1303 30788 : anOffsets.push_back(
1304 30788 : static_cast<int>(poIterField->GetData() - osData.data()));
1305 : }
1306 :
1307 : /* -------------------------------------------------------------------- */
1308 : /* Reallocate the data buffer accordingly. */
1309 : /* -------------------------------------------------------------------- */
1310 : // Don't realloc things smaller ... we will cut off some data.
1311 11360 : const int nBytesToAdd = nNewDataSize - poField->GetDataSize();
1312 11360 : if (nBytesToAdd > 0)
1313 : {
1314 11183 : osData.resize(osData.size() + nBytesToAdd);
1315 :
1316 : /* ---------------------------------------------------------------- */
1317 : /* Update the target fields info. */
1318 : /* ---------------------------------------------------------------- */
1319 11183 : poField->Initialize(poField->GetFieldDefn(),
1320 11183 : osData.c_str() + anOffsets[iTarget], nNewDataSize,
1321 : false);
1322 : }
1323 :
1324 : /* -------------------------------------------------------------------- */
1325 : /* Shift the data beyond this field up or down as needed. */
1326 : /* -------------------------------------------------------------------- */
1327 11360 : if (nBytesToMove > 0)
1328 78 : memmove(const_cast<char *>(poField->GetData()) + nNewDataSize,
1329 78 : poField->GetData() + nOldDataSize, nBytesToMove);
1330 :
1331 : /* -------------------------------------------------------------------- */
1332 : /* Shift all following fields down, and update their data */
1333 : /* locations. */
1334 : /* -------------------------------------------------------------------- */
1335 11360 : if (nBytesToAdd < 0)
1336 : {
1337 69 : osData.resize(osData.size() - (-nBytesToAdd));
1338 :
1339 : /* ---------------------------------------------------------------- */
1340 : /* Update the target fields info. */
1341 : /* ---------------------------------------------------------------- */
1342 69 : poField->Initialize(poField->GetFieldDefn(),
1343 69 : osData.c_str() + anOffsets[iTarget], nNewDataSize,
1344 : false);
1345 : }
1346 :
1347 : /* -------------------------------------------------------------------- */
1348 : /* Update fields up to the resized one to point into newly */
1349 : /* allocated buffer. */
1350 : /* -------------------------------------------------------------------- */
1351 30661 : for (int i = 0; i < iTarget; i++)
1352 : {
1353 19301 : auto &poIterField = apoFields[i];
1354 38602 : poIterField->Initialize(poIterField->GetFieldDefn(),
1355 19301 : osData.c_str() + anOffsets[i],
1356 : poIterField->GetDataSize(), false);
1357 : }
1358 :
1359 : /* -------------------------------------------------------------------- */
1360 : /* Shift all following fields down, and update their data */
1361 : /* locations. */
1362 : /* -------------------------------------------------------------------- */
1363 11487 : for (int i = iTarget + 1; i < GetFieldCount(); i++)
1364 : {
1365 381 : apoFields[i]->Initialize(apoFields[i]->GetFieldDefn(),
1366 127 : osData.c_str() + anOffsets[i] + nBytesToAdd,
1367 127 : apoFields[i]->GetDataSize(), false);
1368 : }
1369 :
1370 11360 : return TRUE;
1371 : }
1372 :
1373 : /************************************************************************/
1374 : /* AddField() */
1375 : /************************************************************************/
1376 :
1377 : /**
1378 : * Add a new field to record.
1379 : *
1380 : * Add a new zero sized field to the record. The new field is always
1381 : * added at the end of the record.
1382 : *
1383 : * NOTE: This method doesn't currently update the header information for
1384 : * the record to include the field information for this field, so the
1385 : * resulting record image isn't suitable for writing to disk. However,
1386 : * everything else about the record state should be updated properly to
1387 : * reflect the new field.
1388 : *
1389 : * @param poDefn the definition of the field to be added.
1390 : *
1391 : * @return the field object on success, or NULL on failure.
1392 : */
1393 :
1394 4269 : DDFField *DDFRecord::AddField(const DDFFieldDefn *poDefn)
1395 :
1396 : {
1397 : /* -------------------------------------------------------------------- */
1398 : /* Reallocate the fields array larger by one, and initialize */
1399 : /* the new field. */
1400 : /* -------------------------------------------------------------------- */
1401 4269 : apoFields.resize(apoFields.size() + 1);
1402 4269 : apoFields.back() = std::make_unique<DDFField>();
1403 :
1404 : /* -------------------------------------------------------------------- */
1405 : /* Initialize the new field properly. */
1406 : /* -------------------------------------------------------------------- */
1407 4269 : if (apoFields.size() == 1)
1408 : {
1409 1355 : apoFields[0]->Initialize(poDefn, GetData(), 0, false);
1410 : }
1411 : else
1412 : {
1413 2914 : apoFields.back()->Initialize(
1414 : poDefn,
1415 2914 : apoFields[GetFieldCount() - 2]->GetData() +
1416 2914 : apoFields[GetFieldCount() - 2]->GetDataSize(),
1417 : 0, false);
1418 : }
1419 :
1420 : /* -------------------------------------------------------------------- */
1421 : /* Initialize field. */
1422 : /* -------------------------------------------------------------------- */
1423 4269 : CreateDefaultFieldInstance(apoFields[GetFieldCount() - 1].get(), 0);
1424 :
1425 4269 : return apoFields.back().get();
1426 : }
1427 :
1428 : /************************************************************************/
1429 : /* SetFieldRaw() */
1430 : /************************************************************************/
1431 :
1432 : /**
1433 : * Set the raw contents of a field instance.
1434 : *
1435 : * @param poField the field to set data within.
1436 : * @param iIndexWithinField The instance of this field to replace. Must
1437 : * be a value between 0 and GetRepeatCount(). If GetRepeatCount() is used, a
1438 : * new instance of the field is appended.
1439 : * @param pachRawData the raw data to replace this field instance with.
1440 : * @param nRawDataSize the number of bytes pointed to by pachRawData.
1441 : *
1442 : * @return TRUE on success or FALSE on failure.
1443 : */
1444 :
1445 7037 : int DDFRecord::SetFieldRaw(DDFField *poField, int iIndexWithinField,
1446 : const char *pachRawData, int nRawDataSize)
1447 :
1448 : {
1449 : int iTarget, nRepeatCount;
1450 :
1451 : /* -------------------------------------------------------------------- */
1452 : /* Find which field we are to update. */
1453 : /* -------------------------------------------------------------------- */
1454 19653 : for (iTarget = 0; iTarget < GetFieldCount(); iTarget++)
1455 : {
1456 19653 : if (apoFields[iTarget].get() == poField)
1457 7037 : break;
1458 : }
1459 :
1460 7037 : if (iTarget == GetFieldCount())
1461 0 : return FALSE;
1462 :
1463 7037 : nRepeatCount = poField->GetRepeatCount();
1464 :
1465 7037 : if (iIndexWithinField < 0 || iIndexWithinField > nRepeatCount)
1466 0 : return FALSE;
1467 :
1468 : /* -------------------------------------------------------------------- */
1469 : /* Are we adding an instance? This is easier and different */
1470 : /* than replacing an existing instance. */
1471 : /* -------------------------------------------------------------------- */
1472 9938 : if ((iIndexWithinField == nRepeatCount ||
1473 9019 : !poField->GetFieldDefn()->IsRepeating()) &&
1474 1982 : !(nRepeatCount == 0 && poField->GetDataSize() > 0))
1475 : {
1476 6423 : if (!poField->GetFieldDefn()->IsRepeating() && iIndexWithinField != 0)
1477 0 : return FALSE;
1478 :
1479 6423 : int nOldSize = poField->GetDataSize();
1480 6423 : if (nOldSize == 0)
1481 4269 : nOldSize++; // for added DDF_FIELD_TERMINATOR.
1482 :
1483 6423 : if (!ResizeField(poField, nOldSize + nRawDataSize))
1484 0 : return FALSE;
1485 :
1486 6423 : char *pachFieldData = const_cast<char *>(poField->GetData());
1487 6423 : memcpy(pachFieldData + nOldSize - 1, pachRawData, nRawDataSize);
1488 6423 : pachFieldData[nOldSize + nRawDataSize - 1] = DDF_FIELD_TERMINATOR;
1489 :
1490 24922 : for (auto &poIterField : apoFields)
1491 18499 : poIterField->InitializeParts();
1492 :
1493 6423 : return TRUE;
1494 : }
1495 :
1496 : /* -------------------------------------------------------------------- */
1497 : /* Get a pointer to the start of the existing data for this */
1498 : /* iteration of the field. */
1499 : /* -------------------------------------------------------------------- */
1500 614 : const char *pachWrkData = nullptr;
1501 614 : int nInstanceSize = 0;
1502 :
1503 : // We special case this to avoid a lot of warnings when initializing
1504 : // the field the first time.
1505 614 : if (poField->GetDataSize() == 0)
1506 : {
1507 0 : pachWrkData = poField->GetData();
1508 : }
1509 : else
1510 : {
1511 : pachWrkData =
1512 614 : poField->GetInstanceData(iIndexWithinField, &nInstanceSize);
1513 : }
1514 :
1515 : /* -------------------------------------------------------------------- */
1516 : /* Create new image of this whole field. */
1517 : /* -------------------------------------------------------------------- */
1518 614 : int nNewFieldSize = poField->GetDataSize() - nInstanceSize + nRawDataSize;
1519 :
1520 614 : std::string osNewImage;
1521 614 : osNewImage.resize(nNewFieldSize);
1522 :
1523 614 : int nPreBytes = static_cast<int>(pachWrkData - poField->GetData());
1524 614 : int nPostBytes = poField->GetDataSize() - nPreBytes - nInstanceSize;
1525 :
1526 614 : memcpy(osNewImage.data(), poField->GetData(), nPreBytes);
1527 1842 : memcpy(osNewImage.data() + nPreBytes + nRawDataSize,
1528 614 : poField->GetData() + nPreBytes + nInstanceSize, nPostBytes);
1529 614 : memcpy(osNewImage.data() + nPreBytes, pachRawData, nRawDataSize);
1530 :
1531 : /* -------------------------------------------------------------------- */
1532 : /* Resize the field to the desired new size. */
1533 : /* -------------------------------------------------------------------- */
1534 614 : ResizeField(poField, nNewFieldSize);
1535 :
1536 614 : memcpy(const_cast<char *>(poField->GetData()), osNewImage.data(),
1537 : nNewFieldSize);
1538 :
1539 1769 : for (auto &poIterField : apoFields)
1540 1155 : poIterField->InitializeParts();
1541 :
1542 614 : return TRUE;
1543 : }
1544 :
1545 : /************************************************************************/
1546 : /* SetFieldRaw() */
1547 : /************************************************************************/
1548 :
1549 : /**
1550 : * Set the raw contents of a field (all instances in case it is a repeated one)
1551 : *
1552 : * A DDF_FIELD_TERMINATOR will be automatically added at the end of the raw data
1553 : * if not already present.
1554 : *
1555 : * @param poField the field to set data within.
1556 : * @param pachRawData the raw data to replace this field with.
1557 : * @param nRawDataSize the number of bytes pointed to by pachRawData.
1558 : *
1559 : * @return TRUE on success or FALSE on failure.
1560 : */
1561 :
1562 116 : int DDFRecord::SetFieldRaw(DDFField *poField, const char *pachRawData,
1563 : int nRawDataSize)
1564 :
1565 : {
1566 116 : const bool bAddFieldTerminator =
1567 232 : (nRawDataSize == 0 ||
1568 116 : pachRawData[nRawDataSize - 1] != DDF_FIELD_TERMINATOR);
1569 :
1570 : /* -------------------------------------------------------------------- */
1571 : /* Resize the field to the desired new size. */
1572 : /* -------------------------------------------------------------------- */
1573 116 : if (!ResizeField(poField, nRawDataSize + (bAddFieldTerminator ? 1 : 0)))
1574 0 : return FALSE;
1575 :
1576 116 : memcpy(const_cast<char *>(poField->GetData()), pachRawData, nRawDataSize);
1577 116 : if (bAddFieldTerminator)
1578 0 : const_cast<char *>(poField->GetData())[nRawDataSize] =
1579 : DDF_FIELD_TERMINATOR;
1580 :
1581 507 : for (auto &poIterField : apoFields)
1582 391 : poIterField->InitializeParts();
1583 :
1584 116 : return TRUE;
1585 : }
1586 :
1587 : /************************************************************************/
1588 : /* UpdateFieldRaw() */
1589 : /************************************************************************/
1590 :
1591 4156 : int DDFRecord::UpdateFieldRaw(DDFField *poField, DDFField *poPartField,
1592 : int iIndexWithinField, int nStartOffset,
1593 : int nOldSize, const char *pachRawData,
1594 : int nRawDataSize)
1595 :
1596 : {
1597 : int iTarget;
1598 :
1599 : /* -------------------------------------------------------------------- */
1600 : /* Find which field we are to update. */
1601 : /* -------------------------------------------------------------------- */
1602 10524 : for (iTarget = 0; iTarget < GetFieldCount(); iTarget++)
1603 : {
1604 10524 : if (apoFields[iTarget].get() == poField)
1605 4156 : break;
1606 : }
1607 :
1608 4156 : if (iTarget == GetFieldCount())
1609 0 : return FALSE;
1610 :
1611 4156 : auto poLowLevelField = poPartField ? poPartField : poField;
1612 4156 : const int nRepeatCount = poLowLevelField->GetRepeatCount();
1613 :
1614 4156 : if (iIndexWithinField < 0 || iIndexWithinField >= nRepeatCount)
1615 0 : return FALSE;
1616 :
1617 : /* -------------------------------------------------------------------- */
1618 : /* Figure out how much pre and post data there is. */
1619 : /* -------------------------------------------------------------------- */
1620 : char *const pachWrkData =
1621 4156 : const_cast<char *>(poLowLevelField->GetInstanceData(iIndexWithinField));
1622 : const int nPreBytes =
1623 4156 : static_cast<int>(pachWrkData - poField->GetData() + nStartOffset);
1624 4156 : const int nPostBytes = poField->GetDataSize() - nPreBytes - nOldSize;
1625 :
1626 : /* -------------------------------------------------------------------- */
1627 : /* If we aren't changing the size, just copy over the existing */
1628 : /* data. */
1629 : /* -------------------------------------------------------------------- */
1630 4156 : if (nOldSize == nRawDataSize)
1631 : {
1632 0 : memcpy(pachWrkData + nStartOffset, pachRawData, nRawDataSize);
1633 0 : return TRUE;
1634 : }
1635 :
1636 : /* -------------------------------------------------------------------- */
1637 : /* If we are shrinking, move in the new data, and shuffle down */
1638 : /* the old before resizing. */
1639 : /* -------------------------------------------------------------------- */
1640 4156 : char *pabyFieldData = const_cast<char *>(poField->GetData());
1641 4156 : if (nRawDataSize < nOldSize)
1642 : {
1643 0 : memcpy(pabyFieldData + nPreBytes, pachRawData, nRawDataSize);
1644 0 : memmove(pabyFieldData + nPreBytes + nRawDataSize,
1645 0 : pabyFieldData + nPreBytes + nOldSize, nPostBytes);
1646 : }
1647 :
1648 : /* -------------------------------------------------------------------- */
1649 : /* Resize the whole buffer. */
1650 : /* -------------------------------------------------------------------- */
1651 4156 : if (!ResizeField(poField, poField->GetDataSize() - nOldSize + nRawDataSize))
1652 0 : return FALSE;
1653 :
1654 : /* -------------------------------------------------------------------- */
1655 : /* If we growing the buffer, shuffle up the post data, and */
1656 : /* move in our new values. */
1657 : /* -------------------------------------------------------------------- */
1658 4156 : pabyFieldData = const_cast<char *>(poField->GetData());
1659 4156 : if (nRawDataSize >= nOldSize)
1660 : {
1661 4156 : memmove(pabyFieldData + nPreBytes + nRawDataSize,
1662 4156 : pabyFieldData + nPreBytes + nOldSize, nPostBytes);
1663 4156 : memcpy(pabyFieldData + nPreBytes, pachRawData, nRawDataSize);
1664 : }
1665 :
1666 14680 : for (auto &poIterField : apoFields)
1667 10524 : poIterField->InitializeParts();
1668 :
1669 4156 : return TRUE;
1670 : }
1671 :
1672 : /************************************************************************/
1673 : /* ResetDirectory() */
1674 : /* */
1675 : /* Re-prepares the directory information for the record. */
1676 : /************************************************************************/
1677 :
1678 1355 : void DDFRecord::ResetDirectory()
1679 :
1680 : {
1681 : /* -------------------------------------------------------------------- */
1682 : /* Eventually we should try to optimize the size of offset and */
1683 : /* field length. */
1684 : /* -------------------------------------------------------------------- */
1685 :
1686 : /* -------------------------------------------------------------------- */
1687 : /* Compute how large the directory needs to be. */
1688 : /* -------------------------------------------------------------------- */
1689 : int nEntrySize, nDirSize;
1690 :
1691 1355 : nEntrySize = _sizeFieldPos + _sizeFieldLength + _sizeFieldTag;
1692 1355 : nDirSize = nEntrySize * GetFieldCount() + 1;
1693 :
1694 : /* -------------------------------------------------------------------- */
1695 : /* If the directory size is different than what is currently */
1696 : /* reserved for it, we must resize. */
1697 : /* -------------------------------------------------------------------- */
1698 1355 : if (nDirSize != nFieldOffset)
1699 : {
1700 : const int nNewDataSize =
1701 1355 : static_cast<int>(osData.size()) - nFieldOffset + nDirSize;
1702 2710 : std::string osNewData;
1703 1355 : osNewData.resize(nNewDataSize);
1704 1355 : memcpy(osNewData.data() + nDirSize, osData.c_str() + nFieldOffset,
1705 1355 : nNewDataSize - nDirSize);
1706 :
1707 2710 : std::vector<int> anOffsets;
1708 5589 : for (auto &poField : apoFields)
1709 : {
1710 4234 : anOffsets.push_back(static_cast<int>(
1711 4234 : poField->GetData() - osData.c_str() - nFieldOffset + nDirSize));
1712 : }
1713 :
1714 1355 : osData = std::move(osNewData);
1715 1355 : nFieldOffset = nDirSize;
1716 :
1717 5589 : for (size_t i = 0; i < apoFields.size(); ++i)
1718 : {
1719 4234 : auto &poField = apoFields[i];
1720 8468 : poField->Initialize(poField->GetFieldDefn(),
1721 4234 : osData.c_str() + anOffsets[i],
1722 : poField->GetDataSize(), true);
1723 : }
1724 : }
1725 :
1726 : /* -------------------------------------------------------------------- */
1727 : /* Now set each directory entry. */
1728 : /* -------------------------------------------------------------------- */
1729 1355 : int iField = 0;
1730 5589 : for (auto &poField : apoFields)
1731 : {
1732 4234 : const DDFFieldDefn *poDefn = poField->GetFieldDefn();
1733 : char szFormat[128];
1734 :
1735 4234 : snprintf(szFormat, sizeof(szFormat), "%%%ds%%0%dd%%0%dd", _sizeFieldTag,
1736 : _sizeFieldLength, _sizeFieldPos);
1737 :
1738 4234 : snprintf(osData.data() + nEntrySize * iField, nEntrySize + 1, szFormat,
1739 : poDefn->GetName(), poField->GetDataSize(),
1740 4234 : poField->GetData() - osData.data() - nFieldOffset);
1741 4234 : ++iField;
1742 : }
1743 :
1744 1355 : osData[nEntrySize * GetFieldCount()] = DDF_FIELD_TERMINATOR;
1745 1355 : }
1746 :
1747 : /************************************************************************/
1748 : /* CreateDefaultFieldInstance() */
1749 : /************************************************************************/
1750 :
1751 : /**
1752 : * Initialize default instance.
1753 : *
1754 : * This method is normally only used internally by the AddField() method
1755 : * to initialize the new field instance with default subfield values. It
1756 : * installs default data for one instance of the field in the record
1757 : * using the DDFFieldDefn::GetDefaultValue() method and
1758 : * DDFRecord::SetFieldRaw().
1759 : *
1760 : * @param poField the field within the record to be assign a default
1761 : * instance.
1762 : * @param iIndexWithinField the instance to set (may not have been tested with
1763 : * values other than 0).
1764 : *
1765 : * @return TRUE on success or FALSE on failure.
1766 : */
1767 :
1768 6423 : int DDFRecord::CreateDefaultFieldInstance(DDFField *poField,
1769 : int iIndexWithinField)
1770 :
1771 : {
1772 6423 : int nRawSize = 0;
1773 6423 : char *pachRawData = poField->GetFieldDefn()->GetDefaultValue(&nRawSize);
1774 6423 : if (pachRawData == nullptr)
1775 224 : return FALSE;
1776 :
1777 : const int nSuccess =
1778 6199 : SetFieldRaw(poField, iIndexWithinField, pachRawData, nRawSize);
1779 :
1780 6199 : CPLFree(pachRawData);
1781 :
1782 6199 : return nSuccess;
1783 : }
1784 :
1785 : /************************************************************************/
1786 : /* GetSubfieldDataForSetSubfield() */
1787 : /************************************************************************/
1788 :
1789 25845 : char *DDFRecord::GetSubfieldDataForSetSubfield(DDFField *poField,
1790 : DDFField *poPartField,
1791 : const DDFSubfieldDefn *poSFDefn,
1792 : int iSubfieldIndex,
1793 : int &nMaxBytes)
1794 : {
1795 25845 : nMaxBytes = 0;
1796 :
1797 25845 : char *pachSubfieldData = nullptr;
1798 :
1799 25845 : const auto poLowLevelField = poPartField ? poPartField : poField;
1800 26675 : if (poPartField && poLowLevelField->GetFieldDefn()->IsRepeating() &&
1801 830 : iSubfieldIndex == poLowLevelField->GetRepeatCount())
1802 : {
1803 491 : if (poPartField != poField->GetParts().back().get())
1804 : {
1805 0 : CPLError(CE_Failure, CPLE_AppDefined,
1806 : "Can only append new field values to last part of field");
1807 0 : return nullptr;
1808 : }
1809 :
1810 491 : int nRawSize = 0;
1811 : char *pachRawData =
1812 491 : poLowLevelField->GetFieldDefn()->GetDefaultValue(&nRawSize);
1813 491 : if (pachRawData == nullptr)
1814 0 : return nullptr;
1815 :
1816 491 : std::string osNewData(poField->GetData(), poField->GetDataSize());
1817 491 : if (!osNewData.empty() && osNewData.back() == DDF_FIELD_TERMINATOR)
1818 491 : osNewData.pop_back();
1819 491 : osNewData.append(pachRawData, nRawSize);
1820 491 : osNewData += static_cast<char>(DDF_FIELD_TERMINATOR);
1821 491 : CPLFree(pachRawData);
1822 :
1823 491 : if (!SetFieldRaw(poField, 0, osNewData.c_str(),
1824 491 : static_cast<int>(osNewData.size())))
1825 0 : return nullptr;
1826 :
1827 491 : pachSubfieldData = const_cast<char *>(poLowLevelField->GetSubfieldData(
1828 : poSFDefn, &nMaxBytes, iSubfieldIndex));
1829 491 : if (pachSubfieldData == nullptr)
1830 0 : return nullptr;
1831 : }
1832 : else
1833 : {
1834 25354 : pachSubfieldData = const_cast<char *>(poLowLevelField->GetSubfieldData(
1835 : poSFDefn, &nMaxBytes, iSubfieldIndex));
1836 25354 : if (pachSubfieldData == nullptr)
1837 0 : return nullptr;
1838 :
1839 : /* -------------------------------------------------------------------- */
1840 : /* Add new instance if we have run out of data. */
1841 : /* -------------------------------------------------------------------- */
1842 25354 : if (poPartField == nullptr &&
1843 21563 : (nMaxBytes == 0 ||
1844 21563 : (nMaxBytes == 1 && pachSubfieldData[0] == DDF_FIELD_TERMINATOR)))
1845 : {
1846 2154 : CreateDefaultFieldInstance(poField, iSubfieldIndex);
1847 :
1848 : // Refetch.
1849 : pachSubfieldData = const_cast<char *>(
1850 2154 : poField->GetSubfieldData(poSFDefn, &nMaxBytes, iSubfieldIndex));
1851 2154 : if (pachSubfieldData == nullptr)
1852 0 : return nullptr;
1853 : }
1854 : }
1855 :
1856 25845 : return pachSubfieldData;
1857 : }
1858 :
1859 : /************************************************************************/
1860 : /* SetStringSubfield() */
1861 : /************************************************************************/
1862 :
1863 : /**
1864 : * Set a string subfield in record.
1865 : *
1866 : * The value of a given subfield is replaced with a new string value
1867 : * formatted appropriately.
1868 : *
1869 : * @param pszField the field name to operate on.
1870 : * @param iFieldIndex the field index to operate on (zero based).
1871 : * @param pszSubfield the subfield name to operate on.
1872 : * @param iSubfieldIndex the subfield index to operate on (zero based).
1873 : * @param pszValue the new string to place in the subfield. This may be
1874 : * arbitrary binary bytes if nValueLength is specified.
1875 : * @param nValueLength the number of valid bytes in pszValue, may be -1 to
1876 : * internally fetch with strlen().
1877 : *
1878 : * @return TRUE if successful, and FALSE if not.
1879 : */
1880 :
1881 5253 : int DDFRecord::SetStringSubfield(const char *pszField, int iFieldIndex,
1882 : const char *pszSubfield, int iSubfieldIndex,
1883 : const char *pszValue, int nValueLength)
1884 :
1885 : {
1886 : /* -------------------------------------------------------------------- */
1887 : /* Get the subfield definition */
1888 : /* -------------------------------------------------------------------- */
1889 5253 : auto [poField, poPartField, poSFDefn] =
1890 5253 : FindSubfieldDefn(pszField, iFieldIndex, pszSubfield);
1891 5253 : if (!poSFDefn)
1892 : {
1893 0 : return FALSE;
1894 : }
1895 :
1896 : /* -------------------------------------------------------------------- */
1897 : /* How long will the formatted value be? */
1898 : /* -------------------------------------------------------------------- */
1899 : int nFormattedLen;
1900 :
1901 5253 : if (!poSFDefn->FormatStringValue(nullptr, 0, &nFormattedLen, pszValue,
1902 : nValueLength))
1903 0 : return FALSE;
1904 :
1905 : /* -------------------------------------------------------------------- */
1906 : /* Get a pointer to the data. */
1907 : /* -------------------------------------------------------------------- */
1908 5253 : int nMaxBytes = 0;
1909 5253 : char *pachSubfieldData = GetSubfieldDataForSetSubfield(
1910 : poField, poPartField, poSFDefn, iSubfieldIndex, nMaxBytes);
1911 5253 : if (!pachSubfieldData)
1912 0 : return FALSE;
1913 :
1914 : /* -------------------------------------------------------------------- */
1915 : /* If the new length matches the existing length, just overlay */
1916 : /* and return. */
1917 : /* -------------------------------------------------------------------- */
1918 : int nExistingLength;
1919 :
1920 5253 : poSFDefn->GetDataLength(pachSubfieldData, nMaxBytes, &nExistingLength);
1921 :
1922 5253 : if (nExistingLength == nFormattedLen)
1923 : {
1924 1097 : return poSFDefn->FormatStringValue(pachSubfieldData, nFormattedLen,
1925 1097 : nullptr, pszValue, nValueLength);
1926 : }
1927 :
1928 : /* -------------------------------------------------------------------- */
1929 : /* We will need to resize the raw data. */
1930 : /* -------------------------------------------------------------------- */
1931 4156 : const auto poLowLevelField = poPartField ? poPartField : poField;
1932 : const char *pachFieldInstData =
1933 4156 : poLowLevelField->GetInstanceData(iSubfieldIndex);
1934 :
1935 4156 : const int nStartOffset =
1936 4156 : static_cast<int>(pachSubfieldData - pachFieldInstData);
1937 :
1938 8312 : std::string osNewData;
1939 4156 : osNewData.resize(nFormattedLen);
1940 4156 : poSFDefn->FormatStringValue(osNewData.data(), nFormattedLen, nullptr,
1941 : pszValue, nValueLength);
1942 :
1943 4156 : return UpdateFieldRaw(poField, poPartField, iSubfieldIndex, nStartOffset,
1944 8312 : nExistingLength, osNewData.data(), nFormattedLen);
1945 : }
1946 :
1947 : /************************************************************************/
1948 : /* SetIntSubfield() */
1949 : /************************************************************************/
1950 :
1951 : /**
1952 : * Set an integer subfield in record.
1953 : *
1954 : * The value of a given subfield is replaced with a new integer value
1955 : * formatted appropriately.
1956 : *
1957 : * @param pszField the field name to operate on.
1958 : * @param iFieldIndex the field index to operate on (zero based).
1959 : * @param pszSubfield the subfield name to operate on.
1960 : * @param iSubfieldIndex the subfield index to operate on (zero based).
1961 : * @param nNewValue the new value to place in the subfield.
1962 : *
1963 : * @return TRUE if successful, and FALSE if not.
1964 : */
1965 :
1966 19972 : int DDFRecord::SetIntSubfield(const char *pszField, int iFieldIndex,
1967 : const char *pszSubfield, int iSubfieldIndex,
1968 : int nNewValue)
1969 :
1970 : {
1971 : /* -------------------------------------------------------------------- */
1972 : /* Get the subfield definition */
1973 : /* -------------------------------------------------------------------- */
1974 19972 : auto [poField, poPartField, poSFDefn] =
1975 19972 : FindSubfieldDefn(pszField, iFieldIndex, pszSubfield);
1976 19972 : if (!poSFDefn)
1977 : {
1978 0 : return FALSE;
1979 : }
1980 :
1981 : /* -------------------------------------------------------------------- */
1982 : /* How long will the formatted value be? */
1983 : /* -------------------------------------------------------------------- */
1984 : int nFormattedLen;
1985 :
1986 19972 : if (!poSFDefn->FormatIntValue(nullptr, 0, &nFormattedLen, nNewValue))
1987 0 : return FALSE;
1988 :
1989 : /* -------------------------------------------------------------------- */
1990 : /* Get a pointer to the data. */
1991 : /* -------------------------------------------------------------------- */
1992 19972 : int nMaxBytes = 0;
1993 19972 : char *pachSubfieldData = GetSubfieldDataForSetSubfield(
1994 : poField, poPartField, poSFDefn, iSubfieldIndex, nMaxBytes);
1995 19972 : if (!pachSubfieldData)
1996 0 : return FALSE;
1997 :
1998 : /* -------------------------------------------------------------------- */
1999 : /* If the new length matches the existing length, just overlay */
2000 : /* and return. */
2001 : /* -------------------------------------------------------------------- */
2002 : int nExistingLength;
2003 :
2004 19972 : poSFDefn->GetDataLength(pachSubfieldData, nMaxBytes, &nExistingLength);
2005 :
2006 19972 : if (nExistingLength == nFormattedLen)
2007 : {
2008 19972 : return poSFDefn->FormatIntValue(pachSubfieldData, nFormattedLen,
2009 19972 : nullptr, nNewValue);
2010 : }
2011 :
2012 : /* -------------------------------------------------------------------- */
2013 : /* We will need to resize the raw data. */
2014 : /* -------------------------------------------------------------------- */
2015 0 : const auto poLowLevelField = poPartField ? poPartField : poField;
2016 : const char *pachFieldInstData =
2017 0 : poLowLevelField->GetInstanceData(iSubfieldIndex);
2018 :
2019 0 : const int nStartOffset =
2020 0 : static_cast<int>(pachSubfieldData - pachFieldInstData);
2021 :
2022 0 : std::string osNewData;
2023 0 : osNewData.resize(nFormattedLen);
2024 0 : poSFDefn->FormatIntValue(osNewData.data(), nFormattedLen, nullptr,
2025 : nNewValue);
2026 :
2027 0 : return UpdateFieldRaw(poField, poPartField, iSubfieldIndex, nStartOffset,
2028 0 : nExistingLength, osNewData.data(), nFormattedLen);
2029 : }
2030 :
2031 : /************************************************************************/
2032 : /* SetFloatSubfield() */
2033 : /************************************************************************/
2034 :
2035 : /**
2036 : * Set a float subfield in record.
2037 : *
2038 : * The value of a given subfield is replaced with a new float value
2039 : * formatted appropriately.
2040 : *
2041 : * @param pszField the field name to operate on.
2042 : * @param iFieldIndex the field index to operate on (zero based).
2043 : * @param pszSubfield the subfield name to operate on.
2044 : * @param iSubfieldIndex the subfield index to operate on (zero based).
2045 : * @param dfNewValue the new value to place in the subfield.
2046 : *
2047 : * @return TRUE if successful, and FALSE if not.
2048 : */
2049 :
2050 620 : int DDFRecord::SetFloatSubfield(const char *pszField, int iFieldIndex,
2051 : const char *pszSubfield, int iSubfieldIndex,
2052 : double dfNewValue)
2053 :
2054 : {
2055 : /* -------------------------------------------------------------------- */
2056 : /* Get the subfield definition */
2057 : /* -------------------------------------------------------------------- */
2058 620 : auto [poField, poPartField, poSFDefn] =
2059 620 : FindSubfieldDefn(pszField, iFieldIndex, pszSubfield);
2060 620 : if (!poSFDefn)
2061 : {
2062 0 : return FALSE;
2063 : }
2064 :
2065 : /* -------------------------------------------------------------------- */
2066 : /* How long will the formatted value be? */
2067 : /* -------------------------------------------------------------------- */
2068 : int nFormattedLen;
2069 :
2070 620 : if (!poSFDefn->FormatFloatValue(nullptr, 0, &nFormattedLen, dfNewValue))
2071 0 : return FALSE;
2072 :
2073 : /* -------------------------------------------------------------------- */
2074 : /* Get a pointer to the data. */
2075 : /* -------------------------------------------------------------------- */
2076 620 : int nMaxBytes = 0;
2077 620 : char *pachSubfieldData = GetSubfieldDataForSetSubfield(
2078 : poField, poPartField, poSFDefn, iSubfieldIndex, nMaxBytes);
2079 620 : if (!pachSubfieldData)
2080 0 : return FALSE;
2081 :
2082 : /* -------------------------------------------------------------------- */
2083 : /* If the new length matches the existing length, just overlay */
2084 : /* and return. */
2085 : /* -------------------------------------------------------------------- */
2086 : int nExistingLength;
2087 :
2088 620 : poSFDefn->GetDataLength(pachSubfieldData, nMaxBytes, &nExistingLength);
2089 :
2090 620 : if (nExistingLength == nFormattedLen)
2091 : {
2092 620 : return poSFDefn->FormatFloatValue(pachSubfieldData, nFormattedLen,
2093 620 : nullptr, dfNewValue);
2094 : }
2095 :
2096 : /* -------------------------------------------------------------------- */
2097 : /* We will need to resize the raw data. */
2098 : /* -------------------------------------------------------------------- */
2099 0 : const auto poLowLevelField = poPartField ? poPartField : poField;
2100 : const char *pachFieldInstData =
2101 0 : poLowLevelField->GetInstanceData(iSubfieldIndex);
2102 :
2103 0 : const int nStartOffset =
2104 0 : static_cast<int>(pachSubfieldData - pachFieldInstData);
2105 :
2106 0 : std::string osNewData;
2107 0 : osNewData.resize(nFormattedLen);
2108 0 : poSFDefn->FormatFloatValue(osNewData.data(), nFormattedLen, nullptr,
2109 : dfNewValue);
2110 :
2111 0 : return UpdateFieldRaw(poField, poPartField, iSubfieldIndex, nStartOffset,
2112 0 : nExistingLength, osNewData.data(), nFormattedLen);
2113 : }
|