1 : /******************************************************************************
2 : * $Id: ddffielddefn.cpp 12706 2007-11-10 22:11:39Z rouault $
3 : *
4 : * Project: ISO 8211 Access
5 : * Purpose: Implements the DDFFieldDefn 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_string.h"
32 : #include <ctype.h>
33 :
34 : CPL_CVSID("$Id: ddffielddefn.cpp 12706 2007-11-10 22:11:39Z rouault $");
35 :
36 : #define CPLE_DiscardedFormat 1301
37 :
38 : /************************************************************************/
39 : /* DDFFieldDefn() */
40 : /************************************************************************/
41 :
42 425 : DDFFieldDefn::DDFFieldDefn()
43 :
44 : {
45 425 : poModule = NULL;
46 425 : pszTag = NULL;
47 425 : _fieldName = NULL;
48 425 : _arrayDescr = NULL;
49 425 : _formatControls = NULL;
50 425 : nSubfieldCount = 0;
51 425 : papoSubfields = NULL;
52 425 : bRepeatingSubfields = FALSE;
53 425 : nFixedWidth = 0;
54 425 : }
55 :
56 : /************************************************************************/
57 : /* ~DDFFieldDefn() */
58 : /************************************************************************/
59 :
60 425 : DDFFieldDefn::~DDFFieldDefn()
61 :
62 : {
63 : int i;
64 :
65 425 : CPLFree( pszTag );
66 425 : CPLFree( _fieldName );
67 425 : CPLFree( _arrayDescr );
68 425 : CPLFree( _formatControls );
69 :
70 2483 : for( i = 0; i < nSubfieldCount; i++ )
71 2058 : delete papoSubfields[i];
72 425 : CPLFree( papoSubfields );
73 425 : }
74 :
75 : /************************************************************************/
76 : /* AddSubfield() */
77 : /************************************************************************/
78 :
79 0 : void DDFFieldDefn::AddSubfield( const char *pszName,
80 : const char *pszFormat )
81 :
82 : {
83 0 : DDFSubfieldDefn *poSFDefn = new DDFSubfieldDefn;
84 :
85 0 : poSFDefn->SetName( pszName );
86 0 : poSFDefn->SetFormat( pszFormat );
87 0 : AddSubfield( poSFDefn );
88 0 : }
89 :
90 : /************************************************************************/
91 : /* AddSubfield() */
92 : /************************************************************************/
93 :
94 2058 : void DDFFieldDefn::AddSubfield( DDFSubfieldDefn *poNewSFDefn,
95 : int bDontAddToFormat )
96 :
97 : {
98 2058 : nSubfieldCount++;
99 : papoSubfields = (DDFSubfieldDefn ** )
100 2058 : CPLRealloc( papoSubfields, sizeof(void*) * nSubfieldCount );
101 2058 : papoSubfields[nSubfieldCount-1] = poNewSFDefn;
102 :
103 2058 : if( bDontAddToFormat )
104 2058 : return;
105 :
106 : /* -------------------------------------------------------------------- */
107 : /* Add this format to the format list. We don't bother */
108 : /* aggregating formats here. */
109 : /* -------------------------------------------------------------------- */
110 0 : if( _formatControls == NULL || strlen(_formatControls) == 0 )
111 : {
112 0 : CPLFree( _formatControls );
113 0 : _formatControls = CPLStrdup( "()" );
114 : }
115 :
116 0 : int nOldLen = strlen(_formatControls);
117 :
118 : char *pszNewFormatControls = (char *)
119 0 : CPLMalloc(nOldLen+3+strlen(poNewSFDefn->GetFormat()));
120 :
121 0 : strcpy( pszNewFormatControls, _formatControls );
122 0 : pszNewFormatControls[nOldLen-1] = '\0';
123 0 : if( pszNewFormatControls[nOldLen-2] != '(' )
124 0 : strcat( pszNewFormatControls, "," );
125 :
126 0 : strcat( pszNewFormatControls, poNewSFDefn->GetFormat() );
127 0 : strcat( pszNewFormatControls, ")" );
128 :
129 0 : CPLFree( _formatControls );
130 0 : _formatControls = pszNewFormatControls;
131 :
132 : /* -------------------------------------------------------------------- */
133 : /* Add the subfield name to the list. */
134 : /* -------------------------------------------------------------------- */
135 0 : if( _arrayDescr == NULL )
136 0 : _arrayDescr = CPLStrdup("");
137 :
138 : _arrayDescr = (char *)
139 : CPLRealloc(_arrayDescr,
140 0 : strlen(_arrayDescr)+strlen(poNewSFDefn->GetName())+2);
141 0 : if( strlen(_arrayDescr) > 0 )
142 0 : strcat( _arrayDescr, "!" );
143 0 : strcat( _arrayDescr, poNewSFDefn->GetName() );
144 : }
145 :
146 : /************************************************************************/
147 : /* Create() */
148 : /* */
149 : /* Initialize a new field defn from application input, instead */
150 : /* of from an existing file. */
151 : /************************************************************************/
152 :
153 0 : int DDFFieldDefn::Create( const char *pszTag, const char *pszFieldName,
154 : const char *pszDescription,
155 : DDF_data_struct_code eDataStructCode,
156 : DDF_data_type_code eDataTypeCode,
157 : const char *pszFormat )
158 :
159 : {
160 : CPLAssert( this->pszTag == NULL );
161 0 : poModule = NULL;
162 0 : this->pszTag = CPLStrdup( pszTag );
163 0 : _fieldName = CPLStrdup( pszFieldName );
164 0 : _arrayDescr = CPLStrdup( pszDescription );
165 0 : _formatControls = CPLStrdup( "" );
166 :
167 0 : _data_struct_code = eDataStructCode;
168 0 : _data_type_code = eDataTypeCode;
169 :
170 0 : if( pszFormat != NULL )
171 0 : _formatControls = CPLStrdup( pszFormat );
172 :
173 0 : if( pszDescription != NULL && *pszDescription == '*' )
174 0 : bRepeatingSubfields = TRUE;
175 :
176 0 : return TRUE;
177 : }
178 :
179 : /************************************************************************/
180 : /* GenerateDDREntry() */
181 : /************************************************************************/
182 :
183 0 : int DDFFieldDefn::GenerateDDREntry( char **ppachData,
184 : int *pnLength )
185 :
186 : {
187 : *pnLength = 9 + strlen(_fieldName) + 1
188 : + strlen(_arrayDescr) + 1
189 0 : + strlen(_formatControls) + 1;
190 :
191 0 : if( strlen(_formatControls) == 0 )
192 0 : *pnLength -= 1;
193 :
194 0 : if( ppachData == NULL )
195 0 : return TRUE;
196 :
197 0 : *ppachData = (char *) CPLMalloc( *pnLength+1 );
198 :
199 0 : if( _data_struct_code == dsc_elementary )
200 0 : (*ppachData)[0] = '0';
201 0 : else if( _data_struct_code == dsc_vector )
202 0 : (*ppachData)[0] = '1';
203 0 : else if( _data_struct_code == dsc_array )
204 0 : (*ppachData)[0] = '2';
205 0 : else if( _data_struct_code == dsc_concatenated )
206 0 : (*ppachData)[0] = '3';
207 :
208 0 : if( _data_type_code == dtc_char_string )
209 0 : (*ppachData)[1] = '0';
210 0 : else if( _data_type_code == dtc_implicit_point )
211 0 : (*ppachData)[1] = '1';
212 0 : else if( _data_type_code == dtc_explicit_point )
213 0 : (*ppachData)[1] = '2';
214 0 : else if( _data_type_code == dtc_explicit_point_scaled )
215 0 : (*ppachData)[1] = '3';
216 0 : else if( _data_type_code == dtc_char_bit_string )
217 0 : (*ppachData)[1] = '4';
218 0 : else if( _data_type_code == dtc_bit_string )
219 0 : (*ppachData)[1] = '5';
220 0 : else if( _data_type_code == dtc_mixed_data_type )
221 0 : (*ppachData)[1] = '6';
222 :
223 0 : (*ppachData)[2] = '0';
224 0 : (*ppachData)[3] = '0';
225 0 : (*ppachData)[4] = ';';
226 0 : (*ppachData)[5] = '&';
227 0 : (*ppachData)[6] = ' ';
228 0 : (*ppachData)[7] = ' ';
229 0 : (*ppachData)[8] = ' ';
230 : sprintf( *ppachData + 9, "%s%c%s",
231 0 : _fieldName, DDF_UNIT_TERMINATOR, _arrayDescr );
232 :
233 0 : if( strlen(_formatControls) > 0 )
234 : sprintf( *ppachData + strlen(*ppachData), "%c%s",
235 0 : DDF_UNIT_TERMINATOR, _formatControls );
236 0 : sprintf( *ppachData + strlen(*ppachData), "%c", DDF_FIELD_TERMINATOR );
237 :
238 0 : return TRUE;
239 : }
240 :
241 : /************************************************************************/
242 : /* Initialize() */
243 : /* */
244 : /* Initialize the field definition from the information in the */
245 : /* DDR record. This is called by DDFModule::Open(). */
246 : /************************************************************************/
247 :
248 425 : int DDFFieldDefn::Initialize( DDFModule * poModuleIn,
249 : const char * pszTagIn,
250 : int nFieldEntrySize,
251 : const char * pachFieldArea )
252 :
253 : {
254 425 : int iFDOffset = poModuleIn->GetFieldControlLength();
255 : int nCharsConsumed;
256 :
257 425 : poModule = poModuleIn;
258 :
259 425 : pszTag = CPLStrdup( pszTagIn );
260 :
261 : /* -------------------------------------------------------------------- */
262 : /* Set the data struct and type codes. */
263 : /* -------------------------------------------------------------------- */
264 425 : switch( pachFieldArea[0] )
265 : {
266 : case ' ': /* for ADRG, DIGEST USRP, DIGEST ASRP files */
267 : case '0':
268 88 : _data_struct_code = dsc_elementary;
269 88 : break;
270 :
271 : case '1':
272 259 : _data_struct_code = dsc_vector;
273 259 : break;
274 :
275 : case '2':
276 78 : _data_struct_code = dsc_array;
277 78 : break;
278 :
279 : case '3':
280 0 : _data_struct_code = dsc_concatenated;
281 0 : break;
282 :
283 : default:
284 : CPLError( CE_Failure, CPLE_AppDefined,
285 : "Unrecognised data_struct_code value %c.\n"
286 : "Field %s initialization incorrect.",
287 0 : pachFieldArea[0], pszTag );
288 0 : _data_struct_code = dsc_elementary;
289 : }
290 :
291 425 : switch( pachFieldArea[1] )
292 : {
293 : case ' ': /* for ADRG, DIGEST USRP, DIGEST ASRP files */
294 : case '0':
295 130 : _data_type_code = dtc_char_string;
296 130 : break;
297 :
298 : case '1':
299 79 : _data_type_code = dtc_implicit_point;
300 79 : break;
301 :
302 : case '2':
303 2 : _data_type_code = dtc_explicit_point;
304 2 : break;
305 :
306 : case '3':
307 0 : _data_type_code = dtc_explicit_point_scaled;
308 0 : break;
309 :
310 : case '4':
311 0 : _data_type_code = dtc_char_bit_string;
312 0 : break;
313 :
314 : case '5':
315 4 : _data_type_code = dtc_bit_string;
316 4 : break;
317 :
318 : case '6':
319 210 : _data_type_code = dtc_mixed_data_type;
320 210 : break;
321 :
322 : default:
323 : CPLError( CE_Failure, CPLE_AppDefined,
324 : "Unrecognised data_type_code value %c.\n"
325 : "Field %s initialization incorrect.",
326 0 : pachFieldArea[1], pszTag );
327 0 : _data_type_code = dtc_char_string;
328 : }
329 :
330 : /* -------------------------------------------------------------------- */
331 : /* Capture the field name, description (sub field names), and */
332 : /* format statements. */
333 : /* -------------------------------------------------------------------- */
334 :
335 : _fieldName =
336 : DDFFetchVariable( pachFieldArea + iFDOffset,
337 : nFieldEntrySize - iFDOffset,
338 : DDF_UNIT_TERMINATOR, DDF_FIELD_TERMINATOR,
339 425 : &nCharsConsumed );
340 425 : iFDOffset += nCharsConsumed;
341 :
342 : _arrayDescr =
343 : DDFFetchVariable( pachFieldArea + iFDOffset,
344 : nFieldEntrySize - iFDOffset,
345 : DDF_UNIT_TERMINATOR, DDF_FIELD_TERMINATOR,
346 425 : &nCharsConsumed );
347 425 : iFDOffset += nCharsConsumed;
348 :
349 : _formatControls =
350 : DDFFetchVariable( pachFieldArea + iFDOffset,
351 : nFieldEntrySize - iFDOffset,
352 : DDF_UNIT_TERMINATOR, DDF_FIELD_TERMINATOR,
353 425 : &nCharsConsumed );
354 :
355 : /* -------------------------------------------------------------------- */
356 : /* Parse the subfield info. */
357 : /* -------------------------------------------------------------------- */
358 425 : if( _data_struct_code != dsc_elementary )
359 : {
360 337 : if( !BuildSubfields() )
361 0 : return FALSE;
362 :
363 337 : if( !ApplyFormats() )
364 0 : return FALSE;
365 : }
366 :
367 425 : return TRUE;
368 : }
369 :
370 : /************************************************************************/
371 : /* Dump() */
372 : /************************************************************************/
373 :
374 : /**
375 : * Write out field definition info to debugging file.
376 : *
377 : * A variety of information about this field definition, and all it's
378 : * subfields is written to the give debugging file handle.
379 : *
380 : * @param fp The standard io file handle to write to. ie. stderr
381 : */
382 :
383 0 : void DDFFieldDefn::Dump( FILE * fp )
384 :
385 : {
386 0 : const char *pszValue = "";
387 :
388 0 : fprintf( fp, " DDFFieldDefn:\n" );
389 0 : fprintf( fp, " Tag = `%s'\n", pszTag );
390 0 : fprintf( fp, " _fieldName = `%s'\n", _fieldName );
391 0 : fprintf( fp, " _arrayDescr = `%s'\n", _arrayDescr );
392 0 : fprintf( fp, " _formatControls = `%s'\n", _formatControls );
393 :
394 0 : switch( _data_struct_code )
395 : {
396 : case dsc_elementary:
397 0 : pszValue = "elementary";
398 0 : break;
399 :
400 : case dsc_vector:
401 0 : pszValue = "vector";
402 0 : break;
403 :
404 : case dsc_array:
405 0 : pszValue = "array";
406 0 : break;
407 :
408 : case dsc_concatenated:
409 0 : pszValue = "concatenated";
410 0 : break;
411 :
412 : default:
413 : CPLAssert( FALSE );
414 0 : pszValue = "(unknown)";
415 : }
416 :
417 0 : fprintf( fp, " _data_struct_code = %s\n", pszValue );
418 :
419 0 : switch( _data_type_code )
420 : {
421 : case dtc_char_string:
422 0 : pszValue = "char_string";
423 0 : break;
424 :
425 : case dtc_implicit_point:
426 0 : pszValue = "implicit_point";
427 0 : break;
428 :
429 : case dtc_explicit_point:
430 0 : pszValue = "explicit_point";
431 0 : break;
432 :
433 : case dtc_explicit_point_scaled:
434 0 : pszValue = "explicit_point_scaled";
435 0 : break;
436 :
437 : case dtc_char_bit_string:
438 0 : pszValue = "char_bit_string";
439 0 : break;
440 :
441 : case dtc_bit_string:
442 0 : pszValue = "bit_string";
443 0 : break;
444 :
445 : case dtc_mixed_data_type:
446 0 : pszValue = "mixed_data_type";
447 0 : break;
448 :
449 : default:
450 : CPLAssert( FALSE );
451 0 : pszValue = "(unknown)";
452 : break;
453 : }
454 :
455 0 : fprintf( fp, " _data_type_code = %s\n", pszValue );
456 :
457 0 : for( int i = 0; i < nSubfieldCount; i++ )
458 0 : papoSubfields[i]->Dump( fp );
459 0 : }
460 :
461 : /************************************************************************/
462 : /* BuildSubfields() */
463 : /* */
464 : /* Based on the _arrayDescr build a set of subfields. */
465 : /************************************************************************/
466 :
467 337 : int DDFFieldDefn::BuildSubfields()
468 :
469 : {
470 : char **papszSubfieldNames;
471 337 : const char *pszSublist = _arrayDescr;
472 :
473 : /* -------------------------------------------------------------------- */
474 : /* It is valid to define a field with _arrayDesc */
475 : /* '*STPT!CTPT!ENPT*YCOO!XCOO' and formatControls '(2b24)'. */
476 : /* This basically indicates that there are 3 (YCOO,XCOO) */
477 : /* structures named STPT, CTPT and ENPT. But we can't handle */
478 : /* such a case gracefully here, so we just ignore the */
479 : /* "structure names" and treat such a thing as a repeating */
480 : /* YCOO/XCOO array. This occurs with the AR2D field of some */
481 : /* AML S-57 files for instance. */
482 : /* */
483 : /* We accomplish this by ignoring everything before the last */
484 : /* '*' in the subfield list. */
485 : /* -------------------------------------------------------------------- */
486 337 : if( strrchr(pszSublist, '*') != NULL )
487 79 : pszSublist = strrchr(pszSublist,'*');
488 :
489 : /* -------------------------------------------------------------------- */
490 : /* Strip off the repeating marker, when it occurs, but mark our */
491 : /* field as repeating. */
492 : /* -------------------------------------------------------------------- */
493 337 : if( pszSublist[0] == '*' )
494 : {
495 79 : bRepeatingSubfields = TRUE;
496 79 : pszSublist++;
497 : }
498 :
499 : /* -------------------------------------------------------------------- */
500 : /* split list of fields . */
501 : /* -------------------------------------------------------------------- */
502 : papszSubfieldNames = CSLTokenizeStringComplex( pszSublist, "!",
503 337 : FALSE, FALSE );
504 :
505 : /* -------------------------------------------------------------------- */
506 : /* minimally initialize the subfields. More will be done later. */
507 : /* -------------------------------------------------------------------- */
508 337 : int nSFCount = CSLCount( papszSubfieldNames );
509 4790 : for( int iSF = 0; iSF < nSFCount; iSF++ )
510 : {
511 2058 : DDFSubfieldDefn *poSFDefn = new DDFSubfieldDefn;
512 :
513 2058 : poSFDefn->SetName( papszSubfieldNames[iSF] );
514 2058 : AddSubfield( poSFDefn, TRUE );
515 : }
516 :
517 337 : CSLDestroy( papszSubfieldNames );
518 :
519 337 : return TRUE;
520 : }
521 :
522 : /************************************************************************/
523 : /* ExtractSubstring() */
524 : /* */
525 : /* Extract a substring terminated by a comma (or end of */
526 : /* string). Commas in brackets are ignored as terminated with */
527 : /* bracket nesting understood gracefully. If the returned */
528 : /* string would being and end with a bracket then strip off the */
529 : /* brackets. */
530 : /* */
531 : /* Given a string like "(A,3(B,C),D),X,Y)" return "A,3(B,C),D". */
532 : /* Give a string like "3A,2C" return "3A". */
533 : /************************************************************************/
534 :
535 599 : char *DDFFieldDefn::ExtractSubstring( const char * pszSrc )
536 :
537 : {
538 599 : int nBracket=0, i;
539 : char *pszReturn;
540 :
541 20210 : for( i = 0;
542 10628 : pszSrc[i] != '\0' && (nBracket > 0 || pszSrc[i] != ',');
543 : i++ )
544 : {
545 8983 : if( pszSrc[i] == '(' )
546 1831 : nBracket++;
547 7152 : else if( pszSrc[i] == ')' )
548 1831 : nBracket--;
549 : }
550 :
551 599 : if( pszSrc[0] == '(' )
552 : {
553 338 : pszReturn = CPLStrdup( pszSrc + 1 );
554 338 : pszReturn[i-2] = '\0';
555 : }
556 : else
557 : {
558 261 : pszReturn = CPLStrdup( pszSrc );
559 261 : pszReturn[i] = '\0';
560 : }
561 :
562 599 : return pszReturn;
563 : }
564 :
565 : /************************************************************************/
566 : /* ExpandFormat() */
567 : /************************************************************************/
568 :
569 936 : char *DDFFieldDefn::ExpandFormat( const char * pszSrc )
570 :
571 : {
572 936 : int nDestMax = 32;
573 936 : char *pszDest = (char *) CPLMalloc(nDestMax+1);
574 : int iSrc, iDst;
575 936 : int nRepeat = 0;
576 :
577 936 : iSrc = 0;
578 936 : iDst = 0;
579 936 : pszDest[0] = '\0';
580 :
581 9600 : while( pszSrc[iSrc] != '\0' )
582 : {
583 : /* This is presumably an extra level of brackets around some
584 : binary stuff related to rescaning which we don't care to do
585 : (see 6.4.3.3 of the standard. We just strip off the extra
586 : layer of brackets */
587 8066 : if( (iSrc == 0 || pszSrc[iSrc-1] == ',') && pszSrc[iSrc] == '(' )
588 : {
589 338 : char *pszContents = ExtractSubstring( pszSrc+iSrc );
590 338 : char *pszExpandedContents = ExpandFormat( pszContents );
591 :
592 338 : if( (int) (strlen(pszExpandedContents) + strlen(pszDest) + 1)
593 : > nDestMax )
594 : {
595 75 : nDestMax = 2 * (strlen(pszExpandedContents) + strlen(pszDest));
596 75 : pszDest = (char *) CPLRealloc(pszDest,nDestMax+1);
597 : }
598 :
599 338 : strcat( pszDest, pszExpandedContents );
600 338 : iDst = strlen(pszDest);
601 :
602 338 : iSrc = iSrc + strlen(pszContents) + 2;
603 :
604 338 : CPLFree( pszContents );
605 338 : CPLFree( pszExpandedContents );
606 : }
607 :
608 : /* this is a repeated subclause */
609 9394 : else if( (iSrc == 0 || pszSrc[iSrc-1] == ',')
610 1743 : && isdigit(pszSrc[iSrc]) )
611 : {
612 : const char *pszNext;
613 261 : nRepeat = atoi(pszSrc+iSrc);
614 :
615 : // skip over repeat count.
616 525 : for( pszNext = pszSrc+iSrc; isdigit(*pszNext); pszNext++ )
617 264 : iSrc++;
618 :
619 261 : char *pszContents = ExtractSubstring( pszNext );
620 261 : char *pszExpandedContents = ExpandFormat( pszContents );
621 :
622 1098 : for( int i = 0; i < nRepeat; i++ )
623 : {
624 837 : if( (int) (strlen(pszExpandedContents) + strlen(pszDest) + 1)
625 : > nDestMax )
626 : {
627 : nDestMax =
628 32 : 2 * (strlen(pszExpandedContents) + strlen(pszDest));
629 32 : pszDest = (char *) CPLRealloc(pszDest,nDestMax+1);
630 : }
631 :
632 837 : strcat( pszDest, pszExpandedContents );
633 837 : if( i < nRepeat-1 )
634 576 : strcat( pszDest, "," );
635 : }
636 :
637 261 : iDst = strlen(pszDest);
638 :
639 261 : if( pszNext[0] == '(' )
640 0 : iSrc = iSrc + strlen(pszContents) + 2;
641 : else
642 261 : iSrc = iSrc + strlen(pszContents);
643 :
644 261 : CPLFree( pszContents );
645 261 : CPLFree( pszExpandedContents );
646 : }
647 : else
648 : {
649 7129 : if( iDst+1 >= nDestMax )
650 : {
651 101 : nDestMax = 2 * iDst;
652 101 : pszDest = (char *) CPLRealloc(pszDest,nDestMax);
653 : }
654 :
655 7129 : pszDest[iDst++] = pszSrc[iSrc++];
656 7129 : pszDest[iDst] = '\0';
657 : }
658 : }
659 :
660 936 : return pszDest;
661 : }
662 :
663 : /************************************************************************/
664 : /* ApplyFormats() */
665 : /* */
666 : /* This method parses the format string partially, and then */
667 : /* applies a subfield format string to each subfield object. */
668 : /* It in turn does final parsing of the subfield formats. */
669 : /************************************************************************/
670 :
671 337 : int DDFFieldDefn::ApplyFormats()
672 :
673 : {
674 : char *pszFormatList;
675 : char **papszFormatItems;
676 :
677 : /* -------------------------------------------------------------------- */
678 : /* Verify that the format string is contained within brackets. */
679 : /* -------------------------------------------------------------------- */
680 1011 : if( strlen(_formatControls) < 2
681 337 : || _formatControls[0] != '('
682 337 : || _formatControls[strlen(_formatControls)-1] != ')' )
683 : {
684 : CPLError( CE_Warning, CPLE_DiscardedFormat,
685 : "Format controls for `%s' field missing brackets:%s",
686 0 : pszTag, _formatControls );
687 :
688 0 : return FALSE;
689 : }
690 :
691 : /* -------------------------------------------------------------------- */
692 : /* Duplicate the string, and strip off the brackets. */
693 : /* -------------------------------------------------------------------- */
694 :
695 337 : pszFormatList = ExpandFormat( _formatControls );
696 :
697 : /* -------------------------------------------------------------------- */
698 : /* Tokenize based on commas. */
699 : /* -------------------------------------------------------------------- */
700 : papszFormatItems =
701 337 : CSLTokenizeStringComplex(pszFormatList, ",", FALSE, FALSE );
702 :
703 337 : CPLFree( pszFormatList );
704 :
705 : /* -------------------------------------------------------------------- */
706 : /* Apply the format items to subfields. */
707 : /* -------------------------------------------------------------------- */
708 : int iFormatItem;
709 :
710 4790 : for( iFormatItem = 0;
711 2395 : papszFormatItems[iFormatItem] != NULL;
712 : iFormatItem++ )
713 : {
714 : const char *pszPastPrefix;
715 :
716 2058 : pszPastPrefix = papszFormatItems[iFormatItem];
717 4116 : while( *pszPastPrefix >= '0' && *pszPastPrefix <= '9' )
718 0 : pszPastPrefix++;
719 :
720 : ///////////////////////////////////////////////////////////////
721 : // Did we get too many formats for the subfields created
722 : // by names? This may be legal by the 8211 specification, but
723 : // isn't encountered in any formats we care about so we just
724 : // blow.
725 :
726 2058 : if( iFormatItem >= nSubfieldCount )
727 : {
728 : CPLError( CE_Warning, CPLE_DiscardedFormat,
729 : "Got more formats than subfields for field `%s'.",
730 0 : pszTag );
731 0 : break;
732 : }
733 :
734 2058 : if( !papoSubfields[iFormatItem]->SetFormat(pszPastPrefix) )
735 0 : return FALSE;
736 : }
737 :
738 : /* -------------------------------------------------------------------- */
739 : /* Verify that we got enough formats, cleanup and return. */
740 : /* -------------------------------------------------------------------- */
741 337 : CSLDestroy( papszFormatItems );
742 :
743 337 : if( iFormatItem < nSubfieldCount )
744 : {
745 : CPLError( CE_Warning, CPLE_DiscardedFormat,
746 : "Got less formats than subfields for field `%s'.",
747 0 : pszTag );
748 0 : return FALSE;
749 : }
750 :
751 : /* -------------------------------------------------------------------- */
752 : /* If all the fields are fixed width, then we are fixed width */
753 : /* too. This is important for repeating fields. */
754 : /* -------------------------------------------------------------------- */
755 337 : nFixedWidth = 0;
756 2156 : for( int i = 0; i < nSubfieldCount; i++ )
757 : {
758 1858 : if( papoSubfields[i]->GetWidth() == 0 )
759 : {
760 39 : nFixedWidth = 0;
761 39 : break;
762 : }
763 : else
764 1819 : nFixedWidth += papoSubfields[i]->GetWidth();
765 : }
766 :
767 337 : return TRUE;
768 : }
769 :
770 : /************************************************************************/
771 : /* FindSubfieldDefn() */
772 : /************************************************************************/
773 :
774 : /**
775 : * Find a subfield definition by it's mnemonic tag.
776 : *
777 : * @param pszMnemonic The name of the field.
778 : *
779 : * @return The subfield pointer, or NULL if there isn't any such subfield.
780 : */
781 :
782 :
783 1233 : DDFSubfieldDefn *DDFFieldDefn::FindSubfieldDefn( const char * pszMnemonic )
784 :
785 : {
786 4337 : for( int i = 0; i < nSubfieldCount; i++ )
787 : {
788 4337 : if( EQUAL(papoSubfields[i]->GetName(),pszMnemonic) )
789 1233 : return papoSubfields[i];
790 : }
791 :
792 0 : return NULL;
793 : }
794 :
795 : /************************************************************************/
796 : /* GetSubfield() */
797 : /* */
798 : /* Fetch a subfield by it's index. */
799 : /************************************************************************/
800 :
801 : /**
802 : * Fetch a subfield by index.
803 : *
804 : * @param i The index subfield index. (Between 0 and GetSubfieldCount()-1)
805 : *
806 : * @return The subfield pointer, or NULL if the index is out of range.
807 : */
808 :
809 34298 : DDFSubfieldDefn *DDFFieldDefn::GetSubfield( int i )
810 :
811 : {
812 34298 : if( i < 0 || i >= nSubfieldCount )
813 : {
814 : CPLAssert( FALSE );
815 0 : return NULL;
816 : }
817 :
818 34298 : return papoSubfields[i];
819 : }
820 :
821 : /************************************************************************/
822 : /* GetDefaultValue() */
823 : /************************************************************************/
824 :
825 : /**
826 : * Return default data for field instance.
827 : */
828 :
829 0 : char *DDFFieldDefn::GetDefaultValue( int *pnSize )
830 :
831 : {
832 : /* -------------------------------------------------------------------- */
833 : /* Loop once collecting the sum of the subfield lengths. */
834 : /* -------------------------------------------------------------------- */
835 : int iSubfield;
836 0 : int nTotalSize = 0;
837 :
838 0 : for( iSubfield = 0; iSubfield < nSubfieldCount; iSubfield++ )
839 : {
840 : int nSubfieldSize;
841 :
842 0 : if( !papoSubfields[iSubfield]->GetDefaultValue( NULL, 0,
843 : &nSubfieldSize ) )
844 0 : return NULL;
845 0 : nTotalSize += nSubfieldSize;
846 : }
847 :
848 : /* -------------------------------------------------------------------- */
849 : /* Allocate buffer. */
850 : /* -------------------------------------------------------------------- */
851 0 : char *pachData = (char *) CPLMalloc( nTotalSize );
852 :
853 0 : if( pnSize != NULL )
854 0 : *pnSize = nTotalSize;
855 :
856 : /* -------------------------------------------------------------------- */
857 : /* Loop again, collecting actual default values. */
858 : /* -------------------------------------------------------------------- */
859 0 : int nOffset = 0;
860 0 : for( iSubfield = 0; iSubfield < nSubfieldCount; iSubfield++ )
861 : {
862 : int nSubfieldSize;
863 :
864 0 : if( !papoSubfields[iSubfield]->GetDefaultValue(
865 : pachData + nOffset, nTotalSize - nOffset, &nSubfieldSize ) )
866 : {
867 : CPLAssert( FALSE );
868 0 : return NULL;
869 : }
870 :
871 0 : nOffset += nSubfieldSize;
872 : }
873 :
874 : CPLAssert( nOffset == nTotalSize );
875 :
876 0 : return pachData;
877 : }
|