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