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