1 : /******************************************************************************
2 : * $Id: ddfrecord.cpp 23598 2011-12-18 23:40:29Z 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 23598 2011-12-18 23:40:29Z rouault $");
34 :
35 : static const int nLeaderSize = 24;
36 :
37 : /************************************************************************/
38 : /* DDFRecord() */
39 : /************************************************************************/
40 :
41 48010 : DDFRecord::DDFRecord( DDFModule * poModuleIn )
42 :
43 : {
44 48010 : poModule = poModuleIn;
45 :
46 48010 : nReuseHeader = FALSE;
47 :
48 48010 : nFieldOffset = 0;
49 :
50 48010 : nDataSize = 0;
51 48010 : pachData = NULL;
52 :
53 48010 : nFieldCount = 0;
54 48010 : paoFields = NULL;
55 :
56 48010 : bIsClone = FALSE;
57 :
58 48010 : _sizeFieldTag = 4;
59 48010 : _sizeFieldPos = 0;
60 48010 : _sizeFieldLength = 0;
61 48010 : }
62 :
63 : /************************************************************************/
64 : /* ~DDFRecord() */
65 : /************************************************************************/
66 :
67 48010 : DDFRecord::~DDFRecord()
68 :
69 : {
70 48010 : Clear();
71 :
72 48010 : if( bIsClone )
73 47898 : poModule->RemoveCloneRecord( this );
74 48010 : }
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 49084 : 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 49084 : if( !nReuseHeader )
126 : {
127 48212 : 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 872 : poModule->GetFP() );
140 872 : if( nReadBytes != (size_t) (nDataSize - nFieldOffset)
141 : && nReadBytes == 0
142 : && VSIFEofL( poModule->GetFP() ) )
143 : {
144 14 : return FALSE;
145 : }
146 858 : 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 858 : 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 96254 : void DDFRecord::Clear()
225 :
226 : {
227 96254 : if( paoFields != NULL )
228 96054 : delete[] paoFields;
229 :
230 96254 : paoFields = NULL;
231 96254 : nFieldCount = 0;
232 :
233 96254 : if( pachData != NULL )
234 96054 : CPLFree( pachData );
235 :
236 96254 : pachData = NULL;
237 96254 : nDataSize = 0;
238 96254 : nReuseHeader = FALSE;
239 96254 : }
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 48212 : int DDFRecord::ReadHeader()
250 :
251 : {
252 : /* -------------------------------------------------------------------- */
253 : /* Clear any existing information. */
254 : /* -------------------------------------------------------------------- */
255 48212 : Clear();
256 :
257 : /* -------------------------------------------------------------------- */
258 : /* Read the 24 byte leader. */
259 : /* -------------------------------------------------------------------- */
260 : char achLeader[nLeaderSize];
261 : int nReadBytes;
262 :
263 48212 : nReadBytes = VSIFReadL(achLeader,1,nLeaderSize,poModule->GetFP());
264 48212 : if( nReadBytes == 0 && VSIFEofL( poModule->GetFP() ) )
265 : {
266 56 : return FALSE;
267 : }
268 48156 : 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 48156 : _recLength = DDFScanInt( achLeader+0, 5 );
283 48156 : _leaderIden = achLeader[6];
284 48156 : _fieldAreaStart = DDFScanInt(achLeader+12,5);
285 :
286 48156 : _sizeFieldLength = achLeader[20] - '0';
287 48156 : _sizeFieldPos = achLeader[21] - '0';
288 48156 : _sizeFieldTag = achLeader[23] - '0';
289 :
290 48156 : 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 48156 : if( _leaderIden == 'R' )
300 26 : nReuseHeader = TRUE;
301 :
302 48156 : nFieldOffset = _fieldAreaStart - nLeaderSize;
303 :
304 : /* -------------------------------------------------------------------- */
305 : /* Is there anything seemly screwy about this record? */
306 : /* -------------------------------------------------------------------- */
307 48156 : 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 48156 : if(_recLength != 0) {
323 : /* -------------------------------------------------------------------- */
324 : /* Read the remainder of the record. */
325 : /* -------------------------------------------------------------------- */
326 48156 : nDataSize = _recLength - nLeaderSize;
327 48156 : pachData = (char *) CPLMalloc(nDataSize);
328 :
329 48156 : 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 96314 : while( pachData[nDataSize-1] != DDF_FIELD_TERMINATOR
343 2 : && (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 48156 : nFieldEntryWidth = _sizeFieldLength + _sizeFieldPos + _sizeFieldTag;
367 48156 : nFieldCount = 0;
368 227590 : for( i = 0; i < nDataSize; i += nFieldEntryWidth )
369 : {
370 227590 : if( pachData[i] == DDF_FIELD_TERMINATOR )
371 48156 : break;
372 :
373 179434 : nFieldCount++;
374 : }
375 :
376 : /* -------------------------------------------------------------------- */
377 : /* Allocate, and read field definitions. */
378 : /* -------------------------------------------------------------------- */
379 48156 : paoFields = new DDFField[nFieldCount];
380 :
381 227590 : for( i = 0; i < nFieldCount; i++ )
382 : {
383 : char szTag[128];
384 179434 : int nEntryOffset = i*nFieldEntryWidth;
385 : int nFieldLength, nFieldPos;
386 :
387 : /* -------------------------------------------------------------------- */
388 : /* Read the position information and tag. */
389 : /* -------------------------------------------------------------------- */
390 179434 : strncpy( szTag, pachData+nEntryOffset, _sizeFieldTag );
391 179434 : szTag[_sizeFieldTag] = '\0';
392 :
393 179434 : nEntryOffset += _sizeFieldTag;
394 179434 : nFieldLength = DDFScanInt( pachData+nEntryOffset, _sizeFieldLength );
395 :
396 179434 : nEntryOffset += _sizeFieldLength;
397 179434 : nFieldPos = DDFScanInt( pachData+nEntryOffset, _sizeFieldPos );
398 :
399 : /* -------------------------------------------------------------------- */
400 : /* Find the corresponding field in the module directory. */
401 : /* -------------------------------------------------------------------- */
402 179434 : DDFFieldDefn *poFieldDefn = poModule->FindFieldDefn( szTag );
403 :
404 179434 : 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 179434 : 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 179434 : nFieldLength );
427 : }
428 :
429 48156 : 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 : return FALSE;
484 : }
485 :
486 : // move this temp buffer into more permanent storage:
487 0 : char *newBuf = (char*)CPLMalloc(nDataSize+nFieldEntryWidth);
488 0 : if(pachData!=NULL) {
489 0 : memcpy(newBuf, pachData, nDataSize);
490 0 : CPLFree(pachData);
491 : }
492 0 : memcpy(&newBuf[nDataSize], tmpBuf, nFieldEntryWidth);
493 0 : pachData = newBuf;
494 0 : nDataSize += nFieldEntryWidth;
495 :
496 0 : if(DDF_FIELD_TERMINATOR != tmpBuf[0]) {
497 0 : nFieldCount++;
498 : }
499 : }
500 0 : while(DDF_FIELD_TERMINATOR != tmpBuf[0]);
501 :
502 : // --------------------------------------------------------------------
503 : // Now, rewind a little. Only the TERMINATOR should have been read
504 : // --------------------------------------------------------------------
505 0 : int rewindSize = nFieldEntryWidth - 1;
506 0 : VSILFILE *fp = poModule->GetFP();
507 0 : vsi_l_offset pos = VSIFTellL(fp) - rewindSize;
508 0 : VSIFSeekL(fp, pos, SEEK_SET);
509 0 : nDataSize -= rewindSize;
510 :
511 : // --------------------------------------------------------------------
512 : // Okay, now let's populate the heck out of pachData...
513 : // --------------------------------------------------------------------
514 0 : for(i=0; i<nFieldCount; i++) {
515 0 : int nEntryOffset = (i*nFieldEntryWidth) + _sizeFieldTag;
516 : int nFieldLength = DDFScanInt(pachData + nEntryOffset,
517 0 : _sizeFieldLength);
518 0 : char *tmpBuf = (char*)CPLMalloc(nFieldLength);
519 :
520 : // read an Entry:
521 0 : if(nFieldLength !=
522 : (int) VSIFReadL(tmpBuf, 1, nFieldLength, poModule->GetFP())) {
523 : CPLError(CE_Failure, CPLE_FileIO,
524 0 : "Data record is short on DDF file.");
525 0 : return FALSE;
526 : }
527 :
528 : // move this temp buffer into more permanent storage:
529 0 : char *newBuf = (char*)CPLMalloc(nDataSize+nFieldLength);
530 0 : memcpy(newBuf, pachData, nDataSize);
531 0 : CPLFree(pachData);
532 0 : memcpy(&newBuf[nDataSize], tmpBuf, nFieldLength);
533 0 : CPLFree(tmpBuf);
534 0 : pachData = newBuf;
535 0 : nDataSize += nFieldLength;
536 : }
537 :
538 : /* ----------------------------------------------------------------- */
539 : /* Allocate, and read field definitions. */
540 : /* ----------------------------------------------------------------- */
541 0 : paoFields = new DDFField[nFieldCount];
542 :
543 0 : for( i = 0; i < nFieldCount; i++ )
544 : {
545 : char szTag[128];
546 0 : int nEntryOffset = i*nFieldEntryWidth;
547 : int nFieldLength, nFieldPos;
548 :
549 : /* ------------------------------------------------------------- */
550 : /* Read the position information and tag. */
551 : /* ------------------------------------------------------------- */
552 0 : strncpy( szTag, pachData+nEntryOffset, _sizeFieldTag );
553 0 : szTag[_sizeFieldTag] = '\0';
554 :
555 0 : nEntryOffset += _sizeFieldTag;
556 0 : nFieldLength = DDFScanInt( pachData+nEntryOffset, _sizeFieldLength );
557 :
558 0 : nEntryOffset += _sizeFieldLength;
559 0 : nFieldPos = DDFScanInt( pachData+nEntryOffset, _sizeFieldPos );
560 :
561 : /* ------------------------------------------------------------- */
562 : /* Find the corresponding field in the module directory. */
563 : /* ------------------------------------------------------------- */
564 0 : DDFFieldDefn *poFieldDefn = poModule->FindFieldDefn( szTag );
565 :
566 0 : if( poFieldDefn == NULL )
567 : {
568 : CPLError( CE_Failure, CPLE_AppDefined,
569 : "Undefined field `%s' encountered in data record.",
570 0 : szTag );
571 0 : return FALSE;
572 : }
573 :
574 0 : if (_fieldAreaStart + nFieldPos - nLeaderSize < 0 ||
575 : nDataSize - (_fieldAreaStart + nFieldPos - nLeaderSize) < nFieldLength)
576 : {
577 : CPLError( CE_Failure, CPLE_AppDefined,
578 : "Not enough byte to initialize field `%s'.",
579 0 : szTag );
580 0 : return FALSE;
581 : }
582 :
583 : /* ------------------------------------------------------------- */
584 : /* Assign info the DDFField. */
585 : /* ------------------------------------------------------------- */
586 :
587 : paoFields[i].Initialize( poFieldDefn,
588 : pachData + _fieldAreaStart
589 : + nFieldPos - nLeaderSize,
590 0 : nFieldLength );
591 : }
592 :
593 0 : return TRUE;
594 : }
595 : }
596 :
597 : /************************************************************************/
598 : /* FindField() */
599 : /************************************************************************/
600 :
601 : /**
602 : * Find the named field within this record.
603 : *
604 : * @param pszName The name of the field to fetch. The comparison is
605 : * case insensitive.
606 : * @param iFieldIndex The instance of this field to fetch. Use zero (the
607 : * default) for the first instance.
608 : *
609 : * @return Pointer to the requested DDFField. This pointer is to an
610 : * internal object, and should not be freed. It remains valid until
611 : * the next record read.
612 : */
613 :
614 100368 : DDFField * DDFRecord::FindField( const char * pszName, int iFieldIndex )
615 :
616 : {
617 202938 : for( int i = 0; i < nFieldCount; i++ )
618 : {
619 202838 : if( EQUAL(paoFields[i].GetFieldDefn()->GetName(),pszName) )
620 : {
621 100268 : if( iFieldIndex == 0 )
622 100268 : return paoFields + i;
623 : else
624 0 : iFieldIndex--;
625 : }
626 : }
627 :
628 100 : return NULL;
629 : }
630 :
631 : /************************************************************************/
632 : /* GetField() */
633 : /************************************************************************/
634 :
635 : /**
636 : * Fetch field object based on index.
637 : *
638 : * @param i The index of the field to fetch. Between 0 and GetFieldCount()-1.
639 : *
640 : * @return A DDFField pointer, or NULL if the index is out of range.
641 : */
642 :
643 50518 : DDFField *DDFRecord::GetField( int i )
644 :
645 : {
646 50518 : if( i < 0 || i >= nFieldCount )
647 0 : return NULL;
648 : else
649 50518 : return paoFields + i;
650 : }
651 :
652 : /************************************************************************/
653 : /* GetIntSubfield() */
654 : /************************************************************************/
655 :
656 : /**
657 : * Fetch value of a subfield as an integer. This is a convenience
658 : * function for fetching a subfield of a field within this record.
659 : *
660 : * @param pszField The name of the field containing the subfield.
661 : * @param iFieldIndex The instance of this field within the record. Use
662 : * zero for the first instance of this field.
663 : * @param pszSubfield The name of the subfield within the selected field.
664 : * @param iSubfieldIndex The instance of this subfield within the record.
665 : * Use zero for the first instance.
666 : * @param pnSuccess Pointer to an int which will be set to TRUE if the fetch
667 : * succeeds, or FALSE if it fails. Use NULL if you don't want to check
668 : * success.
669 : * @return The value of the subfield, or zero if it failed for some reason.
670 : */
671 :
672 97618 : int DDFRecord::GetIntSubfield( const char * pszField, int iFieldIndex,
673 : const char * pszSubfield, int iSubfieldIndex,
674 : int * pnSuccess )
675 :
676 : {
677 : DDFField *poField;
678 : int nDummyErr;
679 :
680 97618 : if( pnSuccess == NULL )
681 97618 : pnSuccess = &nDummyErr;
682 :
683 97618 : *pnSuccess = FALSE;
684 :
685 : /* -------------------------------------------------------------------- */
686 : /* Fetch the field. If this fails, return zero. */
687 : /* -------------------------------------------------------------------- */
688 97618 : poField = FindField( pszField, iFieldIndex );
689 97618 : if( poField == NULL )
690 0 : return 0;
691 :
692 : /* -------------------------------------------------------------------- */
693 : /* Get the subfield definition */
694 : /* -------------------------------------------------------------------- */
695 : DDFSubfieldDefn *poSFDefn;
696 :
697 97618 : poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn( pszSubfield );
698 97618 : if( poSFDefn == NULL )
699 0 : return 0;
700 :
701 : /* -------------------------------------------------------------------- */
702 : /* Get a pointer to the data. */
703 : /* -------------------------------------------------------------------- */
704 : int nBytesRemaining;
705 :
706 : const char *pachData = poField->GetSubfieldData(poSFDefn,
707 : &nBytesRemaining,
708 97618 : iSubfieldIndex);
709 :
710 : /* -------------------------------------------------------------------- */
711 : /* Return the extracted value. */
712 : /* */
713 : /* Assume an error has occured if no bytes are consumed. */
714 : /* -------------------------------------------------------------------- */
715 97618 : int nConsumedBytes = 0;
716 : int nResult = poSFDefn->ExtractIntData( pachData, nBytesRemaining,
717 97618 : &nConsumedBytes );
718 :
719 97618 : if( nConsumedBytes > 0 )
720 97618 : *pnSuccess = TRUE;
721 :
722 97618 : return nResult;
723 : }
724 :
725 : /************************************************************************/
726 : /* GetFloatSubfield() */
727 : /************************************************************************/
728 :
729 : /**
730 : * Fetch value of a subfield as a float (double). This is a convenience
731 : * function for fetching a subfield of a field within this record.
732 : *
733 : * @param pszField The name of the field containing the subfield.
734 : * @param iFieldIndex The instance of this field within the record. Use
735 : * zero for the first instance of this field.
736 : * @param pszSubfield The name of the subfield within the selected field.
737 : * @param iSubfieldIndex The instance of this subfield within the record.
738 : * Use zero for the first instance.
739 : * @param pnSuccess Pointer to an int which will be set to TRUE if the fetch
740 : * succeeds, or FALSE if it fails. Use NULL if you don't want to check
741 : * success.
742 : * @return The value of the subfield, or zero if it failed for some reason.
743 : */
744 :
745 38 : double DDFRecord::GetFloatSubfield( const char * pszField, int iFieldIndex,
746 : const char * pszSubfield, int iSubfieldIndex,
747 : int * pnSuccess )
748 :
749 : {
750 : DDFField *poField;
751 : int nDummyErr;
752 :
753 38 : if( pnSuccess == NULL )
754 38 : pnSuccess = &nDummyErr;
755 :
756 38 : *pnSuccess = FALSE;
757 :
758 : /* -------------------------------------------------------------------- */
759 : /* Fetch the field. If this fails, return zero. */
760 : /* -------------------------------------------------------------------- */
761 38 : poField = FindField( pszField, iFieldIndex );
762 38 : if( poField == NULL )
763 0 : return 0;
764 :
765 : /* -------------------------------------------------------------------- */
766 : /* Get the subfield definition */
767 : /* -------------------------------------------------------------------- */
768 : DDFSubfieldDefn *poSFDefn;
769 :
770 38 : poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn( pszSubfield );
771 38 : if( poSFDefn == NULL )
772 0 : return 0;
773 :
774 : /* -------------------------------------------------------------------- */
775 : /* Get a pointer to the data. */
776 : /* -------------------------------------------------------------------- */
777 : int nBytesRemaining;
778 :
779 : const char *pachData = poField->GetSubfieldData(poSFDefn,
780 : &nBytesRemaining,
781 38 : iSubfieldIndex);
782 :
783 : /* -------------------------------------------------------------------- */
784 : /* Return the extracted value. */
785 : /* -------------------------------------------------------------------- */
786 38 : int nConsumedBytes = 0;
787 : double dfResult = poSFDefn->ExtractFloatData( pachData, nBytesRemaining,
788 38 : &nConsumedBytes );
789 :
790 38 : if( nConsumedBytes > 0 )
791 38 : *pnSuccess = TRUE;
792 :
793 38 : return dfResult;
794 : }
795 :
796 : /************************************************************************/
797 : /* GetStringSubfield() */
798 : /************************************************************************/
799 :
800 : /**
801 : * Fetch value of a subfield as a string. This is a convenience
802 : * function for fetching a subfield of a field within this record.
803 : *
804 : * @param pszField The name of the field containing the subfield.
805 : * @param iFieldIndex The instance of this field within the record. Use
806 : * zero for the first instance of this field.
807 : * @param pszSubfield The name of the subfield within the selected field.
808 : * @param iSubfieldIndex The instance of this subfield within the record.
809 : * Use zero for the first instance.
810 : * @param pnSuccess Pointer to an int which will be set to TRUE if the fetch
811 : * succeeds, or FALSE if it fails. Use NULL if you don't want to check
812 : * success.
813 : * @return The value of the subfield, or NULL if it failed for some reason.
814 : * The returned pointer is to internal data and should not be modified or
815 : * freed by the application.
816 : */
817 :
818 : const char *
819 884 : DDFRecord::GetStringSubfield( const char * pszField, int iFieldIndex,
820 : const char * pszSubfield, int iSubfieldIndex,
821 : int * pnSuccess )
822 :
823 : {
824 : DDFField *poField;
825 : int nDummyErr;
826 :
827 884 : if( pnSuccess == NULL )
828 884 : pnSuccess = &nDummyErr;
829 :
830 884 : *pnSuccess = FALSE;
831 :
832 : /* -------------------------------------------------------------------- */
833 : /* Fetch the field. If this fails, return zero. */
834 : /* -------------------------------------------------------------------- */
835 884 : poField = FindField( pszField, iFieldIndex );
836 884 : if( poField == NULL )
837 0 : return NULL;
838 :
839 : /* -------------------------------------------------------------------- */
840 : /* Get the subfield definition */
841 : /* -------------------------------------------------------------------- */
842 : DDFSubfieldDefn *poSFDefn;
843 :
844 884 : poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn( pszSubfield );
845 884 : if( poSFDefn == NULL )
846 0 : return NULL;
847 :
848 : /* -------------------------------------------------------------------- */
849 : /* Get a pointer to the data. */
850 : /* -------------------------------------------------------------------- */
851 : int nBytesRemaining;
852 :
853 : const char *pachData = poField->GetSubfieldData(poSFDefn,
854 : &nBytesRemaining,
855 884 : iSubfieldIndex);
856 :
857 : /* -------------------------------------------------------------------- */
858 : /* Return the extracted value. */
859 : /* -------------------------------------------------------------------- */
860 884 : *pnSuccess = TRUE;
861 :
862 884 : return( poSFDefn->ExtractStringData( pachData, nBytesRemaining, NULL ) );
863 : }
864 :
865 : /************************************************************************/
866 : /* Clone() */
867 : /************************************************************************/
868 :
869 : /**
870 : * Make a copy of a record.
871 : *
872 : * This method is used to make a copy of a record that will become (mostly)
873 : * the properly of application. However, it is automatically destroyed if
874 : * the DDFModule it was created relative to is destroyed, as it's field
875 : * and subfield definitions relate to that DDFModule. However, it does
876 : * persist even when the record returned by DDFModule::ReadRecord() is
877 : * invalidated, such as when reading a new record. This allows an application
878 : * to cache whole DDFRecords.
879 : *
880 : * @return A new copy of the DDFRecord. This can be delete'd by the
881 : * application when no longer needed, otherwise it will be cleaned up when
882 : * the DDFModule it relates to is destroyed or closed.
883 : */
884 :
885 47898 : DDFRecord * DDFRecord::Clone()
886 :
887 : {
888 : DDFRecord *poNR;
889 :
890 47898 : poNR = new DDFRecord( poModule );
891 :
892 47898 : poNR->nReuseHeader = FALSE;
893 47898 : poNR->nFieldOffset = nFieldOffset;
894 :
895 47898 : poNR->nDataSize = nDataSize;
896 47898 : poNR->pachData = (char *) CPLMalloc(nDataSize);
897 47898 : memcpy( poNR->pachData, pachData, nDataSize );
898 :
899 47898 : poNR->nFieldCount = nFieldCount;
900 47898 : poNR->paoFields = new DDFField[nFieldCount];
901 225828 : for( int i = 0; i < nFieldCount; i++ )
902 : {
903 : int nOffset;
904 :
905 177930 : nOffset = (paoFields[i].GetData() - pachData);
906 : poNR->paoFields[i].Initialize( paoFields[i].GetFieldDefn(),
907 : poNR->pachData + nOffset,
908 177930 : paoFields[i].GetDataSize() );
909 : }
910 :
911 47898 : poNR->bIsClone = TRUE;
912 47898 : poModule->AddCloneRecord( poNR );
913 :
914 47898 : return poNR;
915 : }
916 :
917 : /************************************************************************/
918 : /* CloneOn() */
919 : /************************************************************************/
920 :
921 : /**
922 : * Recreate a record referencing another module.
923 : *
924 : * Works similarly to the DDFRecord::Clone() method, but creates the
925 : * new record with reference to a different DDFModule. All DDFFieldDefn
926 : * references are transcribed onto the new module based on field names.
927 : * If any fields don't have a similarly named field on the target module
928 : * the operation will fail. No validation of field types and properties
929 : * is done, but this operation is intended only to be used between
930 : * modules with matching definitions of all affected fields.
931 : *
932 : * The new record will be managed as a clone by the target module in
933 : * a manner similar to regular clones.
934 : *
935 : * @param poTargetModule the module on which the record copy should be
936 : * created.
937 : *
938 : * @return NULL on failure or a pointer to the cloned record.
939 : */
940 :
941 36 : DDFRecord *DDFRecord::CloneOn( DDFModule *poTargetModule )
942 :
943 : {
944 : /* -------------------------------------------------------------------- */
945 : /* Verify that all fields have a corresponding field definition */
946 : /* on the target module. */
947 : /* -------------------------------------------------------------------- */
948 : int i;
949 :
950 176 : for( i = 0; i < nFieldCount; i++ )
951 : {
952 140 : DDFFieldDefn *poDefn = paoFields[i].GetFieldDefn();
953 :
954 140 : if( poTargetModule->FindFieldDefn( poDefn->GetName() ) == NULL )
955 0 : return NULL;
956 : }
957 :
958 : /* -------------------------------------------------------------------- */
959 : /* Create a clone. */
960 : /* -------------------------------------------------------------------- */
961 : DDFRecord *poClone;
962 :
963 36 : poClone = Clone();
964 :
965 : /* -------------------------------------------------------------------- */
966 : /* Update all internal information to reference other module. */
967 : /* -------------------------------------------------------------------- */
968 176 : for( i = 0; i < nFieldCount; i++ )
969 : {
970 140 : DDFField *poField = poClone->paoFields+i;
971 : DDFFieldDefn *poDefn;
972 :
973 : poDefn = poTargetModule->FindFieldDefn(
974 140 : poField->GetFieldDefn()->GetName() );
975 :
976 : poField->Initialize( poDefn, poField->GetData(),
977 140 : poField->GetDataSize() );
978 : }
979 :
980 36 : poModule->RemoveCloneRecord( poClone );
981 36 : poClone->poModule = poTargetModule;
982 36 : poTargetModule->AddCloneRecord( poClone );
983 :
984 36 : return poClone;
985 : }
986 :
987 :
988 : /************************************************************************/
989 : /* DeleteField() */
990 : /************************************************************************/
991 :
992 : /**
993 : * Delete a field instance from a record.
994 : *
995 : * Remove a field from this record, cleaning up the data
996 : * portion and repacking the fields list. We don't try to
997 : * reallocate the data area of the record to be smaller.
998 : *
999 : * NOTE: This method doesn't actually remove the header
1000 : * information for this field from the record tag list yet.
1001 : * This should be added if the resulting record is even to be
1002 : * written back to disk!
1003 : *
1004 : * @param poTarget the field instance on this record to delete.
1005 : *
1006 : * @return TRUE on success, or FALSE on failure. Failure can occur if
1007 : * poTarget isn't really a field on this record.
1008 : */
1009 :
1010 0 : int DDFRecord::DeleteField( DDFField *poTarget )
1011 :
1012 : {
1013 : int iTarget, i;
1014 :
1015 : /* -------------------------------------------------------------------- */
1016 : /* Find which field we are to delete. */
1017 : /* -------------------------------------------------------------------- */
1018 0 : for( iTarget = 0; iTarget < nFieldCount; iTarget++ )
1019 : {
1020 0 : if( paoFields + iTarget == poTarget )
1021 0 : break;
1022 : }
1023 :
1024 0 : if( iTarget == nFieldCount )
1025 0 : return FALSE;
1026 :
1027 : /* -------------------------------------------------------------------- */
1028 : /* Change the target fields data size to zero. This takes care */
1029 : /* of repacking the data array, and updating all the following */
1030 : /* field data pointers. */
1031 : /* -------------------------------------------------------------------- */
1032 0 : ResizeField( poTarget, 0 );
1033 :
1034 : /* -------------------------------------------------------------------- */
1035 : /* remove the target field, moving down all the other fields */
1036 : /* one step in the field list. */
1037 : /* -------------------------------------------------------------------- */
1038 0 : for( i = iTarget; i < nFieldCount-1; i++ )
1039 : {
1040 0 : paoFields[i] = paoFields[i+1];
1041 : }
1042 :
1043 0 : nFieldCount--;
1044 :
1045 0 : return TRUE;
1046 : }
1047 :
1048 : /************************************************************************/
1049 : /* ResizeField() */
1050 : /************************************************************************/
1051 :
1052 : /**
1053 : * Alter field data size within record.
1054 : *
1055 : * This method will rearrange a DDFRecord altering the amount of space
1056 : * reserved for one of the existing fields. All following fields will
1057 : * be shifted accordingly. This includes updating the DDFField infos,
1058 : * and actually moving stuff within the data array after reallocating
1059 : * to the desired size.
1060 : *
1061 : * @param poField the field to alter.
1062 : * @param nNewDataSize the number of data bytes to be reserved for the field.
1063 : *
1064 : * @return TRUE on success or FALSE on failure.
1065 : */
1066 :
1067 16 : int DDFRecord::ResizeField( DDFField *poField, int nNewDataSize )
1068 :
1069 : {
1070 : int iTarget, i;
1071 : int nBytesToMove;
1072 :
1073 : /* -------------------------------------------------------------------- */
1074 : /* Find which field we are to resize. */
1075 : /* -------------------------------------------------------------------- */
1076 80 : for( iTarget = 0; iTarget < nFieldCount; iTarget++ )
1077 : {
1078 80 : if( paoFields + iTarget == poField )
1079 16 : break;
1080 : }
1081 :
1082 16 : if( iTarget == nFieldCount )
1083 : {
1084 0 : CPLAssert( FALSE );
1085 0 : return FALSE;
1086 : }
1087 :
1088 : /* -------------------------------------------------------------------- */
1089 : /* Reallocate the data buffer accordingly. */
1090 : /* -------------------------------------------------------------------- */
1091 16 : int nBytesToAdd = nNewDataSize - poField->GetDataSize();
1092 16 : const char *pachOldData = pachData;
1093 :
1094 : // Don't realloc things smaller ... we will cut off some data.
1095 16 : if( nBytesToAdd > 0 )
1096 0 : pachData = (char *) CPLRealloc(pachData, nDataSize + nBytesToAdd );
1097 :
1098 16 : nDataSize += nBytesToAdd;
1099 :
1100 : /* -------------------------------------------------------------------- */
1101 : /* How much data needs to be shifted up or down after this field? */
1102 : /* -------------------------------------------------------------------- */
1103 : nBytesToMove = nDataSize
1104 16 : - (poField->GetData()+poField->GetDataSize()-pachOldData+nBytesToAdd);
1105 :
1106 : /* -------------------------------------------------------------------- */
1107 : /* Update fields to point into newly allocated buffer. */
1108 : /* -------------------------------------------------------------------- */
1109 96 : for( i = 0; i < nFieldCount; i++ )
1110 : {
1111 : int nOffset;
1112 :
1113 80 : nOffset = paoFields[i].GetData() - pachOldData;
1114 : paoFields[i].Initialize( paoFields[i].GetFieldDefn(),
1115 : pachData + nOffset,
1116 80 : paoFields[i].GetDataSize() );
1117 : }
1118 :
1119 : /* -------------------------------------------------------------------- */
1120 : /* Shift the data beyond this field up or down as needed. */
1121 : /* -------------------------------------------------------------------- */
1122 16 : if( nBytesToMove > 0 )
1123 : memmove( (char *)poField->GetData()+poField->GetDataSize()+nBytesToAdd,
1124 : (char *)poField->GetData()+poField->GetDataSize(),
1125 0 : nBytesToMove );
1126 :
1127 : /* -------------------------------------------------------------------- */
1128 : /* Update the target fields info. */
1129 : /* -------------------------------------------------------------------- */
1130 : poField->Initialize( poField->GetFieldDefn(),
1131 : poField->GetData(),
1132 16 : poField->GetDataSize() + nBytesToAdd );
1133 :
1134 : /* -------------------------------------------------------------------- */
1135 : /* Shift all following fields down, and update their data */
1136 : /* locations. */
1137 : /* -------------------------------------------------------------------- */
1138 16 : if( nBytesToAdd < 0 )
1139 : {
1140 0 : for( i = iTarget+1; i < nFieldCount; i++ )
1141 : {
1142 : char *pszOldDataLocation;
1143 :
1144 0 : pszOldDataLocation = (char *) paoFields[i].GetData();
1145 :
1146 : paoFields[i].Initialize( paoFields[i].GetFieldDefn(),
1147 : pszOldDataLocation + nBytesToAdd,
1148 0 : paoFields[i].GetDataSize() );
1149 : }
1150 : }
1151 : else
1152 : {
1153 16 : for( i = nFieldCount-1; i > iTarget; i-- )
1154 : {
1155 : char *pszOldDataLocation;
1156 :
1157 0 : pszOldDataLocation = (char *) paoFields[i].GetData();
1158 :
1159 : paoFields[i].Initialize( paoFields[i].GetFieldDefn(),
1160 : pszOldDataLocation + nBytesToAdd,
1161 0 : paoFields[i].GetDataSize() );
1162 : }
1163 : }
1164 :
1165 16 : return TRUE;
1166 : }
1167 :
1168 : /************************************************************************/
1169 : /* AddField() */
1170 : /************************************************************************/
1171 :
1172 : /**
1173 : * Add a new field to record.
1174 : *
1175 : * Add a new zero sized field to the record. The new field is always
1176 : * added at the end of the record.
1177 : *
1178 : * NOTE: This method doesn't currently update the header information for
1179 : * the record to include the field information for this field, so the
1180 : * resulting record image isn't suitable for writing to disk. However,
1181 : * everything else about the record state should be updated properly to
1182 : * reflect the new field.
1183 : *
1184 : * @param poDefn the definition of the field to be added.
1185 : *
1186 : * @return the field object on success, or NULL on failure.
1187 : */
1188 :
1189 0 : DDFField *DDFRecord::AddField( DDFFieldDefn *poDefn )
1190 :
1191 : {
1192 : /* -------------------------------------------------------------------- */
1193 : /* Reallocate the fields array larger by one, and initialize */
1194 : /* the new field. */
1195 : /* -------------------------------------------------------------------- */
1196 : DDFField *paoNewFields;
1197 :
1198 0 : paoNewFields = new DDFField[nFieldCount+1];
1199 0 : if( nFieldCount > 0 )
1200 : {
1201 0 : memcpy( paoNewFields, paoFields, sizeof(DDFField) * nFieldCount );
1202 0 : delete[] paoFields;
1203 : }
1204 0 : paoFields = paoNewFields;
1205 0 : nFieldCount++;
1206 :
1207 : /* -------------------------------------------------------------------- */
1208 : /* Initialize the new field properly. */
1209 : /* -------------------------------------------------------------------- */
1210 0 : if( nFieldCount == 1 )
1211 : {
1212 0 : paoFields[0].Initialize( poDefn, GetData(), 0 );
1213 : }
1214 : else
1215 : {
1216 : paoFields[nFieldCount-1].Initialize(
1217 : poDefn,
1218 : paoFields[nFieldCount-2].GetData()
1219 : + paoFields[nFieldCount-2].GetDataSize(),
1220 0 : 0 );
1221 : }
1222 :
1223 : /* -------------------------------------------------------------------- */
1224 : /* Initialize field. */
1225 : /* -------------------------------------------------------------------- */
1226 0 : CreateDefaultFieldInstance( paoFields + nFieldCount-1, 0 );
1227 :
1228 0 : return paoFields + (nFieldCount - 1);
1229 : }
1230 :
1231 : /************************************************************************/
1232 : /* SetFieldRaw() */
1233 : /************************************************************************/
1234 :
1235 : /**
1236 : * Set the raw contents of a field instance.
1237 : *
1238 : * @param poField the field to set data within.
1239 : * @param iIndexWithinField The instance of this field to replace. Must
1240 : * be a value between 0 and GetRepeatCount(). If GetRepeatCount() is used, a
1241 : * new instance of the field is appeneded.
1242 : * @param pachRawData the raw data to replace this field instance with.
1243 : * @param nRawDataSize the number of bytes pointed to by pachRawData.
1244 : *
1245 : * @return TRUE on success or FALSE on failure.
1246 : */
1247 :
1248 : int
1249 16 : DDFRecord::SetFieldRaw( DDFField *poField, int iIndexWithinField,
1250 : const char *pachRawData, int nRawDataSize )
1251 :
1252 : {
1253 : int iTarget, nRepeatCount;
1254 :
1255 : /* -------------------------------------------------------------------- */
1256 : /* Find which field we are to update. */
1257 : /* -------------------------------------------------------------------- */
1258 80 : for( iTarget = 0; iTarget < nFieldCount; iTarget++ )
1259 : {
1260 80 : if( paoFields + iTarget == poField )
1261 16 : break;
1262 : }
1263 :
1264 16 : if( iTarget == nFieldCount )
1265 0 : return FALSE;
1266 :
1267 16 : nRepeatCount = poField->GetRepeatCount();
1268 :
1269 16 : if( iIndexWithinField < 0 || iIndexWithinField > nRepeatCount )
1270 0 : return FALSE;
1271 :
1272 : /* -------------------------------------------------------------------- */
1273 : /* Are we adding an instance? This is easier and different */
1274 : /* than replacing an existing instance. */
1275 : /* -------------------------------------------------------------------- */
1276 16 : if( iIndexWithinField == nRepeatCount
1277 : || !poField->GetFieldDefn()->IsRepeating() )
1278 : {
1279 : char *pachFieldData;
1280 : int nOldSize;
1281 :
1282 0 : if( !poField->GetFieldDefn()->IsRepeating() && iIndexWithinField != 0 )
1283 0 : return FALSE;
1284 :
1285 0 : nOldSize = poField->GetDataSize();
1286 0 : if( nOldSize == 0 )
1287 0 : nOldSize++; // for added DDF_FIELD_TERMINATOR.
1288 :
1289 0 : if( !ResizeField( poField, nOldSize + nRawDataSize ) )
1290 0 : return FALSE;
1291 :
1292 0 : pachFieldData = (char *) poField->GetData();
1293 : memcpy( pachFieldData + nOldSize - 1,
1294 0 : pachRawData, nRawDataSize );
1295 0 : pachFieldData[nOldSize+nRawDataSize-1] = DDF_FIELD_TERMINATOR;
1296 :
1297 0 : return TRUE;
1298 : }
1299 :
1300 : /* -------------------------------------------------------------------- */
1301 : /* Get a pointer to the start of the existing data for this */
1302 : /* iteration of the field. */
1303 : /* -------------------------------------------------------------------- */
1304 : const char *pachWrkData;
1305 : int nInstanceSize;
1306 :
1307 : // We special case this to avoid alot of warnings when initializing
1308 : // the field the first time.
1309 16 : if( poField->GetDataSize() == 0 )
1310 : {
1311 0 : pachWrkData = poField->GetData();
1312 0 : nInstanceSize = 0;
1313 : }
1314 : else
1315 : {
1316 : pachWrkData = poField->GetInstanceData( iIndexWithinField,
1317 16 : &nInstanceSize );
1318 : }
1319 :
1320 : /* -------------------------------------------------------------------- */
1321 : /* Create new image of this whole field. */
1322 : /* -------------------------------------------------------------------- */
1323 : char *pachNewImage;
1324 : int nPreBytes, nPostBytes, nNewFieldSize;
1325 :
1326 16 : nNewFieldSize = poField->GetDataSize() - nInstanceSize + nRawDataSize;
1327 :
1328 16 : pachNewImage = (char *) CPLMalloc(nNewFieldSize);
1329 :
1330 16 : nPreBytes = pachWrkData - poField->GetData();
1331 16 : nPostBytes = poField->GetDataSize() - nPreBytes - nInstanceSize;
1332 :
1333 16 : memcpy( pachNewImage, poField->GetData(), nPreBytes );
1334 : memcpy( pachNewImage + nPreBytes + nRawDataSize,
1335 : poField->GetData() + nPreBytes + nInstanceSize,
1336 16 : nPostBytes );
1337 16 : memcpy( pachNewImage + nPreBytes, pachRawData, nRawDataSize );
1338 :
1339 : /* -------------------------------------------------------------------- */
1340 : /* Resize the field to the desired new size. */
1341 : /* -------------------------------------------------------------------- */
1342 16 : ResizeField( poField, nNewFieldSize );
1343 :
1344 16 : memcpy( (void *) poField->GetData(), pachNewImage, nNewFieldSize );
1345 16 : CPLFree( pachNewImage );
1346 :
1347 16 : return TRUE;
1348 : }
1349 :
1350 : /************************************************************************/
1351 : /* UpdateFieldRaw() */
1352 : /************************************************************************/
1353 :
1354 : int
1355 0 : DDFRecord::UpdateFieldRaw( DDFField *poField, int iIndexWithinField,
1356 : int nStartOffset, int nOldSize,
1357 : const char *pachRawData, int nRawDataSize )
1358 :
1359 : {
1360 : int iTarget, nRepeatCount;
1361 :
1362 : /* -------------------------------------------------------------------- */
1363 : /* Find which field we are to update. */
1364 : /* -------------------------------------------------------------------- */
1365 0 : for( iTarget = 0; iTarget < nFieldCount; iTarget++ )
1366 : {
1367 0 : if( paoFields + iTarget == poField )
1368 0 : break;
1369 : }
1370 :
1371 0 : if( iTarget == nFieldCount )
1372 0 : return FALSE;
1373 :
1374 0 : nRepeatCount = poField->GetRepeatCount();
1375 :
1376 0 : if( iIndexWithinField < 0 || iIndexWithinField >= nRepeatCount )
1377 0 : return FALSE;
1378 :
1379 : /* -------------------------------------------------------------------- */
1380 : /* Figure out how much pre and post data there is. */
1381 : /* -------------------------------------------------------------------- */
1382 : char *pachWrkData;
1383 : int nInstanceSize, nPostBytes, nPreBytes;
1384 :
1385 : pachWrkData = (char *) poField->GetInstanceData( iIndexWithinField,
1386 0 : &nInstanceSize );
1387 0 : nPreBytes = pachWrkData - poField->GetData() + nStartOffset;
1388 0 : nPostBytes = poField->GetDataSize() - nPreBytes - nOldSize;
1389 :
1390 : /* -------------------------------------------------------------------- */
1391 : /* If we aren't changing the size, just copy over the existing */
1392 : /* data. */
1393 : /* -------------------------------------------------------------------- */
1394 0 : if( nOldSize == nRawDataSize )
1395 : {
1396 0 : memcpy( pachWrkData + nStartOffset, pachRawData, nRawDataSize );
1397 0 : return TRUE;
1398 : }
1399 :
1400 : /* -------------------------------------------------------------------- */
1401 : /* If we are shrinking, move in the new data, and shuffle down */
1402 : /* the old before resizing. */
1403 : /* -------------------------------------------------------------------- */
1404 0 : if( nRawDataSize < nOldSize )
1405 : {
1406 : memcpy( ((char*) poField->GetData()) + nPreBytes,
1407 0 : pachRawData, nRawDataSize );
1408 : memmove( ((char *) poField->GetData()) + nPreBytes + nRawDataSize,
1409 : ((char *) poField->GetData()) + nPreBytes + nOldSize,
1410 0 : nPostBytes );
1411 : }
1412 :
1413 : /* -------------------------------------------------------------------- */
1414 : /* Resize the whole buffer. */
1415 : /* -------------------------------------------------------------------- */
1416 0 : if( !ResizeField( poField,
1417 : poField->GetDataSize() - nOldSize + nRawDataSize ) )
1418 0 : return FALSE;
1419 :
1420 : /* -------------------------------------------------------------------- */
1421 : /* If we growing the buffer, shuffle up the post data, and */
1422 : /* move in our new values. */
1423 : /* -------------------------------------------------------------------- */
1424 0 : if( nRawDataSize >= nOldSize )
1425 : {
1426 : memmove( ((char *) poField->GetData()) + nPreBytes + nRawDataSize,
1427 : ((char *) poField->GetData()) + nPreBytes + nOldSize,
1428 0 : nPostBytes );
1429 : memcpy( ((char*) poField->GetData()) + nPreBytes,
1430 0 : pachRawData, nRawDataSize );
1431 : }
1432 :
1433 0 : return TRUE;
1434 : }
1435 :
1436 : /************************************************************************/
1437 : /* ResetDirectory() */
1438 : /* */
1439 : /* Re-prepares the directory information for the record. */
1440 : /************************************************************************/
1441 :
1442 0 : int DDFRecord::ResetDirectory()
1443 :
1444 : {
1445 : int iField;
1446 :
1447 : /* -------------------------------------------------------------------- */
1448 : /* Eventually we should try to optimize the size of offset and */
1449 : /* field length. For now we will use 5 for each which is */
1450 : /* pretty big. */
1451 : /* -------------------------------------------------------------------- */
1452 0 : _sizeFieldPos = 5;
1453 0 : _sizeFieldLength = 5;
1454 :
1455 : /* -------------------------------------------------------------------- */
1456 : /* Compute how large the directory needs to be. */
1457 : /* -------------------------------------------------------------------- */
1458 : int nEntrySize, nDirSize;
1459 :
1460 0 : nEntrySize = _sizeFieldPos + _sizeFieldLength + _sizeFieldTag;
1461 0 : nDirSize = nEntrySize * nFieldCount + 1;
1462 :
1463 : /* -------------------------------------------------------------------- */
1464 : /* If the directory size is different than what is currently */
1465 : /* reserved for it, we must resize. */
1466 : /* -------------------------------------------------------------------- */
1467 0 : if( nDirSize != nFieldOffset )
1468 : {
1469 : char *pachNewData;
1470 : int nNewDataSize;
1471 :
1472 0 : nNewDataSize = nDataSize - nFieldOffset + nDirSize;
1473 0 : pachNewData = (char *) CPLMalloc(nNewDataSize);
1474 : memcpy( pachNewData + nDirSize,
1475 : pachData + nFieldOffset,
1476 0 : nNewDataSize - nDirSize );
1477 :
1478 0 : for( iField = 0; iField < nFieldCount; iField++ )
1479 : {
1480 : int nOffset;
1481 0 : DDFField *poField = GetField( iField );
1482 :
1483 0 : nOffset = poField->GetData() - pachData - nFieldOffset + nDirSize;
1484 : poField->Initialize( poField->GetFieldDefn(),
1485 : pachNewData + nOffset,
1486 0 : poField->GetDataSize() );
1487 : }
1488 :
1489 0 : CPLFree( pachData );
1490 0 : pachData = pachNewData;
1491 0 : nDataSize = nNewDataSize;
1492 0 : nFieldOffset = nDirSize;
1493 : }
1494 :
1495 : /* -------------------------------------------------------------------- */
1496 : /* Now set each directory entry. */
1497 : /* -------------------------------------------------------------------- */
1498 0 : for( iField = 0; iField < nFieldCount; iField++ )
1499 : {
1500 0 : DDFField *poField = GetField( iField );
1501 0 : DDFFieldDefn *poDefn = poField->GetFieldDefn();
1502 : char szFormat[128];
1503 :
1504 : sprintf( szFormat, "%%%ds%%0%dd%%0%dd",
1505 0 : _sizeFieldTag, _sizeFieldLength, _sizeFieldPos );
1506 :
1507 : sprintf( pachData + nEntrySize * iField, szFormat,
1508 : poDefn->GetName(), poField->GetDataSize(),
1509 0 : poField->GetData() - pachData - nFieldOffset );
1510 : }
1511 :
1512 0 : pachData[nEntrySize * nFieldCount] = DDF_FIELD_TERMINATOR;
1513 :
1514 0 : return TRUE;
1515 : }
1516 :
1517 : /************************************************************************/
1518 : /* CreateDefaultFieldInstance() */
1519 : /************************************************************************/
1520 :
1521 : /**
1522 : * Initialize default instance.
1523 : *
1524 : * This method is normally only used internally by the AddField() method
1525 : * to initialize the new field instance with default subfield values. It
1526 : * installs default data for one instance of the field in the record
1527 : * using the DDFFieldDefn::GetDefaultValue() method and
1528 : * DDFRecord::SetFieldRaw().
1529 : *
1530 : * @param poField the field within the record to be assign a default
1531 : * instance.
1532 : * @param iIndexWithinField the instance to set (may not have been tested with
1533 : * values other than 0).
1534 : *
1535 : * @return TRUE on success or FALSE on failure.
1536 : */
1537 :
1538 0 : int DDFRecord::CreateDefaultFieldInstance( DDFField *poField,
1539 : int iIndexWithinField )
1540 :
1541 : {
1542 : int nRawSize, nSuccess;
1543 : char *pachRawData;
1544 :
1545 0 : pachRawData = poField->GetFieldDefn()->GetDefaultValue( &nRawSize );
1546 0 : if( pachRawData == NULL )
1547 0 : return FALSE;
1548 :
1549 0 : nSuccess = SetFieldRaw( poField, iIndexWithinField, pachRawData, nRawSize);
1550 :
1551 0 : CPLFree( pachRawData );
1552 :
1553 0 : return nSuccess;
1554 : }
1555 :
1556 : /************************************************************************/
1557 : /* SetStringSubfield() */
1558 : /************************************************************************/
1559 :
1560 : /**
1561 : * Set a string subfield in record.
1562 : *
1563 : * The value of a given subfield is replaced with a new string value
1564 : * formatted appropriately.
1565 : *
1566 : * @param pszField the field name to operate on.
1567 : * @param iFieldIndex the field index to operate on (zero based).
1568 : * @param pszSubfield the subfield name to operate on.
1569 : * @param iSubfieldIndex the subfield index to operate on (zero based).
1570 : * @param pszValue the new string to place in the subfield. This may be
1571 : * arbitrary binary bytes if nValueLength is specified.
1572 : * @param nValueLength the number of valid bytes in pszValue, may be -1 to
1573 : * internally fetch with strlen().
1574 : *
1575 : * @return TRUE if successful, and FALSE if not.
1576 : */
1577 :
1578 0 : int DDFRecord::SetStringSubfield( const char *pszField, int iFieldIndex,
1579 : const char *pszSubfield, int iSubfieldIndex,
1580 : const char *pszValue, int nValueLength )
1581 :
1582 : {
1583 : /* -------------------------------------------------------------------- */
1584 : /* Fetch the field. If this fails, return zero. */
1585 : /* -------------------------------------------------------------------- */
1586 : DDFField *poField;
1587 :
1588 0 : poField = FindField( pszField, iFieldIndex );
1589 0 : if( poField == NULL )
1590 0 : return FALSE;
1591 :
1592 : /* -------------------------------------------------------------------- */
1593 : /* Get the subfield definition */
1594 : /* -------------------------------------------------------------------- */
1595 : DDFSubfieldDefn *poSFDefn;
1596 :
1597 0 : poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn( pszSubfield );
1598 0 : if( poSFDefn == NULL )
1599 0 : return FALSE;
1600 :
1601 : /* -------------------------------------------------------------------- */
1602 : /* How long will the formatted value be? */
1603 : /* -------------------------------------------------------------------- */
1604 : int nFormattedLen;
1605 :
1606 0 : if( !poSFDefn->FormatStringValue( NULL, 0, &nFormattedLen, pszValue,
1607 : nValueLength ) )
1608 0 : return FALSE;
1609 :
1610 : /* -------------------------------------------------------------------- */
1611 : /* Get a pointer to the data. */
1612 : /* -------------------------------------------------------------------- */
1613 : int nMaxBytes;
1614 : char *pachSubfieldData = (char *)
1615 : poField->GetSubfieldData(poSFDefn, &nMaxBytes,
1616 0 : iSubfieldIndex);
1617 :
1618 : /* -------------------------------------------------------------------- */
1619 : /* Add new instance if we have run out of data. */
1620 : /* -------------------------------------------------------------------- */
1621 0 : if( nMaxBytes == 0
1622 0 : || (nMaxBytes == 1 && pachSubfieldData[0] == DDF_FIELD_TERMINATOR) )
1623 : {
1624 0 : CreateDefaultFieldInstance( poField, iSubfieldIndex );
1625 :
1626 : // Refetch.
1627 : pachSubfieldData = (char *)
1628 : poField->GetSubfieldData(poSFDefn, &nMaxBytes,
1629 0 : iSubfieldIndex);
1630 : }
1631 :
1632 : /* -------------------------------------------------------------------- */
1633 : /* If the new length matches the existing length, just overlay */
1634 : /* and return. */
1635 : /* -------------------------------------------------------------------- */
1636 : int nExistingLength;
1637 :
1638 0 : poSFDefn->GetDataLength( pachSubfieldData, nMaxBytes, &nExistingLength );
1639 :
1640 0 : if( nExistingLength == nFormattedLen )
1641 : {
1642 : return poSFDefn->FormatStringValue( pachSubfieldData, nFormattedLen,
1643 0 : NULL, pszValue, nValueLength );
1644 : }
1645 :
1646 : /* -------------------------------------------------------------------- */
1647 : /* We will need to resize the raw data. */
1648 : /* -------------------------------------------------------------------- */
1649 : const char *pachFieldInstData;
1650 : int nInstanceSize, nStartOffset, nSuccess;
1651 : char *pachNewData;
1652 :
1653 : pachFieldInstData = poField->GetInstanceData( iFieldIndex,
1654 0 : &nInstanceSize );
1655 :
1656 0 : nStartOffset = pachSubfieldData - pachFieldInstData;
1657 :
1658 0 : pachNewData = (char *) CPLMalloc(nFormattedLen);
1659 : poSFDefn->FormatStringValue( pachNewData, nFormattedLen, NULL,
1660 0 : pszValue, nValueLength );
1661 :
1662 : nSuccess = UpdateFieldRaw( poField, iFieldIndex,
1663 : nStartOffset, nExistingLength,
1664 0 : pachNewData, nFormattedLen );
1665 :
1666 0 : CPLFree( pachNewData );
1667 :
1668 0 : return nSuccess;
1669 : }
1670 :
1671 : /************************************************************************/
1672 : /* SetIntSubfield() */
1673 : /************************************************************************/
1674 :
1675 : /**
1676 : * Set an integer subfield in record.
1677 : *
1678 : * The value of a given subfield is replaced with a new integer value
1679 : * formatted appropriately.
1680 : *
1681 : * @param pszField the field name to operate on.
1682 : * @param iFieldIndex the field index to operate on (zero based).
1683 : * @param pszSubfield the subfield name to operate on.
1684 : * @param iSubfieldIndex the subfield index to operate on (zero based).
1685 : * @param nNewValue the new value to place in the subfield.
1686 : *
1687 : * @return TRUE if successful, and FALSE if not.
1688 : */
1689 :
1690 0 : int DDFRecord::SetIntSubfield( const char *pszField, int iFieldIndex,
1691 : const char *pszSubfield, int iSubfieldIndex,
1692 : int nNewValue )
1693 :
1694 : {
1695 : /* -------------------------------------------------------------------- */
1696 : /* Fetch the field. If this fails, return zero. */
1697 : /* -------------------------------------------------------------------- */
1698 : DDFField *poField;
1699 :
1700 0 : poField = FindField( pszField, iFieldIndex );
1701 0 : if( poField == NULL )
1702 0 : return FALSE;
1703 :
1704 : /* -------------------------------------------------------------------- */
1705 : /* Get the subfield definition */
1706 : /* -------------------------------------------------------------------- */
1707 : DDFSubfieldDefn *poSFDefn;
1708 :
1709 0 : poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn( pszSubfield );
1710 0 : if( poSFDefn == NULL )
1711 0 : return FALSE;
1712 :
1713 : /* -------------------------------------------------------------------- */
1714 : /* How long will the formatted value be? */
1715 : /* -------------------------------------------------------------------- */
1716 : int nFormattedLen;
1717 :
1718 0 : if( !poSFDefn->FormatIntValue( NULL, 0, &nFormattedLen, nNewValue ) )
1719 0 : return FALSE;
1720 :
1721 : /* -------------------------------------------------------------------- */
1722 : /* Get a pointer to the data. */
1723 : /* -------------------------------------------------------------------- */
1724 : int nMaxBytes;
1725 : char *pachSubfieldData = (char *)
1726 : poField->GetSubfieldData(poSFDefn, &nMaxBytes,
1727 0 : iSubfieldIndex);
1728 :
1729 : /* -------------------------------------------------------------------- */
1730 : /* Add new instance if we have run out of data. */
1731 : /* -------------------------------------------------------------------- */
1732 0 : if( nMaxBytes == 0
1733 0 : || (nMaxBytes == 1 && pachSubfieldData[0] == DDF_FIELD_TERMINATOR) )
1734 : {
1735 0 : CreateDefaultFieldInstance( poField, iSubfieldIndex );
1736 :
1737 : // Refetch.
1738 : pachSubfieldData = (char *)
1739 : poField->GetSubfieldData(poSFDefn, &nMaxBytes,
1740 0 : iSubfieldIndex);
1741 : }
1742 :
1743 : /* -------------------------------------------------------------------- */
1744 : /* If the new length matches the existing length, just overlay */
1745 : /* and return. */
1746 : /* -------------------------------------------------------------------- */
1747 : int nExistingLength;
1748 :
1749 0 : poSFDefn->GetDataLength( pachSubfieldData, nMaxBytes, &nExistingLength );
1750 :
1751 0 : if( nExistingLength == nFormattedLen )
1752 : {
1753 : return poSFDefn->FormatIntValue( pachSubfieldData, nFormattedLen,
1754 0 : NULL, nNewValue );
1755 : }
1756 :
1757 : /* -------------------------------------------------------------------- */
1758 : /* We will need to resize the raw data. */
1759 : /* -------------------------------------------------------------------- */
1760 : const char *pachFieldInstData;
1761 : int nInstanceSize, nStartOffset, nSuccess;
1762 : char *pachNewData;
1763 :
1764 : pachFieldInstData = poField->GetInstanceData( iFieldIndex,
1765 0 : &nInstanceSize );
1766 :
1767 0 : nStartOffset = pachSubfieldData - pachFieldInstData;
1768 :
1769 0 : pachNewData = (char *) CPLMalloc(nFormattedLen);
1770 : poSFDefn->FormatIntValue( pachNewData, nFormattedLen, NULL,
1771 0 : nNewValue );
1772 :
1773 : nSuccess = UpdateFieldRaw( poField, iFieldIndex,
1774 : nStartOffset, nExistingLength,
1775 0 : pachNewData, nFormattedLen );
1776 :
1777 0 : CPLFree( pachNewData );
1778 :
1779 0 : return nSuccess;
1780 : }
1781 :
1782 : /************************************************************************/
1783 : /* SetFloatSubfield() */
1784 : /************************************************************************/
1785 :
1786 : /**
1787 : * Set a float subfield in record.
1788 : *
1789 : * The value of a given subfield is replaced with a new float value
1790 : * formatted appropriately.
1791 : *
1792 : * @param pszField the field name to operate on.
1793 : * @param iFieldIndex the field index to operate on (zero based).
1794 : * @param pszSubfield the subfield name to operate on.
1795 : * @param iSubfieldIndex the subfield index to operate on (zero based).
1796 : * @param dfNewValue the new value to place in the subfield.
1797 : *
1798 : * @return TRUE if successful, and FALSE if not.
1799 : */
1800 :
1801 0 : int DDFRecord::SetFloatSubfield( const char *pszField, int iFieldIndex,
1802 : const char *pszSubfield, int iSubfieldIndex,
1803 : double dfNewValue )
1804 :
1805 : {
1806 : /* -------------------------------------------------------------------- */
1807 : /* Fetch the field. If this fails, return zero. */
1808 : /* -------------------------------------------------------------------- */
1809 : DDFField *poField;
1810 :
1811 0 : poField = FindField( pszField, iFieldIndex );
1812 0 : if( poField == NULL )
1813 0 : return FALSE;
1814 :
1815 : /* -------------------------------------------------------------------- */
1816 : /* Get the subfield definition */
1817 : /* -------------------------------------------------------------------- */
1818 : DDFSubfieldDefn *poSFDefn;
1819 :
1820 0 : poSFDefn = poField->GetFieldDefn()->FindSubfieldDefn( pszSubfield );
1821 0 : if( poSFDefn == NULL )
1822 0 : return FALSE;
1823 :
1824 : /* -------------------------------------------------------------------- */
1825 : /* How long will the formatted value be? */
1826 : /* -------------------------------------------------------------------- */
1827 : int nFormattedLen;
1828 :
1829 0 : if( !poSFDefn->FormatFloatValue( NULL, 0, &nFormattedLen, dfNewValue ) )
1830 0 : return FALSE;
1831 :
1832 : /* -------------------------------------------------------------------- */
1833 : /* Get a pointer to the data. */
1834 : /* -------------------------------------------------------------------- */
1835 : int nMaxBytes;
1836 : char *pachSubfieldData = (char *)
1837 : poField->GetSubfieldData(poSFDefn, &nMaxBytes,
1838 0 : iSubfieldIndex);
1839 :
1840 : /* -------------------------------------------------------------------- */
1841 : /* Add new instance if we have run out of data. */
1842 : /* -------------------------------------------------------------------- */
1843 0 : if( nMaxBytes == 0
1844 0 : || (nMaxBytes == 1 && pachSubfieldData[0] == DDF_FIELD_TERMINATOR) )
1845 : {
1846 0 : CreateDefaultFieldInstance( poField, iSubfieldIndex );
1847 :
1848 : // Refetch.
1849 : pachSubfieldData = (char *)
1850 : poField->GetSubfieldData(poSFDefn, &nMaxBytes,
1851 0 : iSubfieldIndex);
1852 : }
1853 :
1854 : /* -------------------------------------------------------------------- */
1855 : /* If the new length matches the existing length, just overlay */
1856 : /* and return. */
1857 : /* -------------------------------------------------------------------- */
1858 : int nExistingLength;
1859 :
1860 0 : poSFDefn->GetDataLength( pachSubfieldData, nMaxBytes, &nExistingLength );
1861 :
1862 0 : if( nExistingLength == nFormattedLen )
1863 : {
1864 : return poSFDefn->FormatFloatValue( pachSubfieldData, nFormattedLen,
1865 0 : NULL, dfNewValue );
1866 : }
1867 :
1868 : /* -------------------------------------------------------------------- */
1869 : /* We will need to resize the raw data. */
1870 : /* -------------------------------------------------------------------- */
1871 : const char *pachFieldInstData;
1872 : int nInstanceSize, nStartOffset, nSuccess;
1873 : char *pachNewData;
1874 :
1875 : pachFieldInstData = poField->GetInstanceData( iFieldIndex,
1876 0 : &nInstanceSize );
1877 :
1878 0 : nStartOffset = (int) (pachSubfieldData - pachFieldInstData);
1879 :
1880 0 : pachNewData = (char *) CPLMalloc(nFormattedLen);
1881 : poSFDefn->FormatFloatValue( pachNewData, nFormattedLen, NULL,
1882 0 : dfNewValue );
1883 :
1884 : nSuccess = UpdateFieldRaw( poField, iFieldIndex,
1885 : nStartOffset, nExistingLength,
1886 0 : pachNewData, nFormattedLen );
1887 :
1888 0 : CPLFree( pachNewData );
1889 :
1890 0 : return nSuccess;
1891 : }
|