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