source: issm/trunk-jpl/src/c/objects/KML/KMLFileReadUtils.cpp@ 11319

Last change on this file since 11319 was 11319, checked in by jschierm, 13 years ago

KML: Implemented KML_Unknown class to digest and regurgitate unknown KML elements.

File size: 16.1 KB
Line 
1/*!\file KMLFileUtils.cpp
2 * \brief: utilities for kml file reading.
3 */
4
5/*Headers:*/
6/*{{{1*/
7#ifdef HAVE_CONFIG_H
8 #include <config.h>
9#else
10#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
11#endif
12
13#include <stdio.h>
14#include <string.h>
15#include "../objects.h"
16#include "../../shared/shared.h"
17#include "../../io/io.h"
18#include "../../Container/Container.h"
19#include "../../include/include.h"
20/*}}}*/
21
22/*FUNCTION KMLFileToken(FILE* fid,int* pncom=NULL,char*** ppcom=NULL) {{{1*/
23char* KMLFileToken(FILE* fid,
24 int* pncom=NULL,char*** ppcom=NULL){
25
26/* get the next token (tag or field) in the file */
27
28 bool inew=1,itag=0,ifield=0;
29 int c;
30 int ibuf=0,buflen=1024,bufblk=1024;
31 char *buffer=NULL,*bufferc=NULL;
32
33 buffer=(char *) xmalloc(buflen*sizeof(char));
34 buffer[0]='\0';
35
36/* read kml file character-by-character */
37
38// note that fgets includes newline
39// fgets(buffer,buflen,fid);
40
41 while ((c=getc(fid)) != EOF) {
42 /* ignore leading blanks */
43 if (inew && isspace(c))
44 continue;
45
46 /* distinguish between tag or field */
47 if (!itag && !ifield) {
48
49 /* distinguish between tag or comment */
50 if (c == '<') {
51 ungetc(c,fid);
52 if (!(bufferc=KMLFileTokenComment(fid))) {
53 c=getc(fid);
54 itag=1;
55 }
56 else {
57 if (pncom && ppcom) {
58 (*pncom)++;
59 *ppcom=(char **) xrealloc(*ppcom,*pncom*sizeof(char*));
60 (*ppcom)[*pncom-1]=bufferc;
61 }
62 else
63 xfree((void**)&bufferc);
64 inew=1;
65 continue;
66 }
67 }
68 else
69 ifield=1;
70 inew=0;
71 KMLFileTokenBuffer(&buffer,&ibuf,&buflen,
72 c,
73 bufblk);
74 }
75
76 /* accumulate tag, not including newlines */
77 else if (itag) {
78 if (c != '\n') {
79 inew=0;
80 KMLFileTokenBuffer(&buffer,&ibuf,&buflen,
81 c,
82 bufblk);
83 if (c == '>')
84 break;
85 }
86 else
87 inew=1;
88 }
89
90 /* accumulate field, including newlines */
91 else if (ifield) {
92 /* distinguish between another tag or comment */
93 if (c == '<') {
94 ungetc(c,fid);
95 if (!(bufferc=KMLFileTokenComment(fid)))
96 break;
97 else
98 if (pncom && ppcom) {
99 (*pncom)++;
100 *ppcom=(char **) xrealloc(*ppcom,*pncom*sizeof(char*));
101 (*ppcom)[*pncom-1]=bufferc;
102 }
103 else
104 xfree((void**)&bufferc);
105 }
106 else {
107 inew=0;
108 KMLFileTokenBuffer(&buffer,&ibuf,&buflen,
109 c,
110 bufblk);
111 if (c == '\n')
112 inew=1;
113 }
114 }
115
116 }
117
118/* remove trailing blanks or newline */
119
120 while (ibuf > 0)
121 if (isspace(buffer[ibuf-1]))
122 ibuf--;
123 else {
124 buffer[ibuf]='\0';
125 break;
126 }
127
128// if (itag)
129// _printf_(true,"tag buffer (length=%d):\n",ibuf);
130// else if (ifield)
131// _printf_(true,"field buffer (length=%d):\n",ibuf);
132// _printf_(true,"%s\n",buffer);
133
134 if (!ibuf)
135 xfree((void**)&buffer);
136
137 return(buffer);
138}
139/*}}}*/
140
141/*FUNCTION KMLFileTokenComment(FILE* fid) {{{1*/
142char* KMLFileTokenComment(FILE* fid){
143
144/* check for comment in the file and read it */
145
146 bool inew=1;
147 int i;
148 int c;
149 int ibuf=0,buflen=1024,bufblk=1024;
150 char* buffer=NULL;
151
152 buffer=(char *) xmalloc(buflen*sizeof(char));
153 buffer[0]='\0';
154
155/* read kml file character-by-character */
156
157 while ((c=getc(fid)) != EOF) {
158 /* ignore leading blanks */
159 if (inew && isspace(c))
160 continue;
161
162 inew=0;
163 KMLFileTokenBuffer(&buffer,&ibuf,&buflen,
164 c,
165 bufblk);
166
167 /* check for comment */
168 if (ibuf <= 4) {
169 if ((ibuf == 1 && buffer[0] != '<') ||
170 (ibuf == 2 && buffer[1] != '!') ||
171 (ibuf == 3 && buffer[2] != '-') ||
172 (ibuf == 4 && buffer[3] != '-')) {
173 for (i=ibuf-1; i>=0; i--)
174 ungetc(buffer[i],fid);
175 xfree((void**)&buffer);
176 return(buffer);
177 }
178 }
179
180 /* accumulate comment, including newlines */
181 else
182 if (buffer[ibuf-3]=='-' && buffer[ibuf-2]=='-' && buffer[ibuf-1]=='>')
183 break;
184 }
185
186/* remove trailing blanks or newline */
187
188 while (ibuf > 0)
189 if (isspace(buffer[ibuf-1]))
190 ibuf--;
191 else {
192 buffer[ibuf]='\0';
193 break;
194 }
195
196// _printf_(true,"comment buffer (length=%d):\n",ibuf);
197// _printf_(true,"%s\n",buffer);
198
199 if (!ibuf)
200 xfree((void**)&buffer);
201
202 return(buffer);
203}
204/*}}}*/
205
206/*FUNCTION KMLFileTokenBuffer {{{1*/
207void KMLFileTokenBuffer(char** pbuffer,int* pibuf,int* pbuflen,
208 int c,
209 int bufblk){
210
211/* add the specified character to the token buffer */
212
213 char* buffer=NULL;
214
215/* check buffer length and realloc if necessary */
216
217 if (*pibuf+2 > *pbuflen) {
218 *pbuflen+=bufblk;
219 *pbuffer=(char *) xrealloc(*pbuffer,*pbuflen*sizeof(char));
220 }
221
222/* add character and terminator */
223
224 (*pbuffer)[(*pibuf)++]=c;
225 (*pbuffer)[ *pibuf ]='\0';
226
227 return;
228}
229/*}}}*/
230
231/*FUNCTION KMLFileTagName {{{1*/
232char* KMLFileTagName(char* pname,
233 char* ktag){
234
235 return(KMLFileTagName(pname,NULL,0,
236 ktag));
237}
238/*}}}*/
239
240/*FUNCTION KMLFileTagName {{{1*/
241char* KMLFileTagName(char* pname,int *m,int maxlen,
242 char* ktag){
243
244/* for the given tag buffer, read and store the name */
245
246 char* ktagi;
247 char* ktokn;
248
249 if (strncmp(&ktag[0],"<" ,1) || strncmp(&ktag[strlen(ktag)-1],">",1))
250 _error_("KMLFileTagName -- Missing tag delimiters in %s.\n",ktag);
251
252/* strtok modifies ktag, so work on copy */
253
254 ktagi=(char *) xmalloc((strlen(ktag)+1)*sizeof(char));
255 memcpy(ktagi,ktag,(strlen(ktag)+1)*sizeof(char));
256
257/* skip opening delimeter and find subsequent blank or closing delimiter */
258
259 ktokn=strtok(ktagi,"< >");
260// _printf_(true,"KMLFileTagName -- initial token=\"%s\".\n",ktokn);
261
262 if (!pname) {
263 if (maxlen)
264 pname=(char *) xmalloc((maxlen +1)*sizeof(char));
265 else
266 pname=(char *) xmalloc((strlen(ktokn)+1)*sizeof(char));
267 }
268
269 if (maxlen && (maxlen < strlen(ktokn))) {
270 _printf_(true,"KMLFileTagName -- string field too short for %s.\n",ktag);
271 _printf_(true,"KMLFileTagName -- \"%s\" truncated to %d characters.\n",ktokn,maxlen);
272 strncpy(pname,ktokn,maxlen);
273 }
274 else
275 memcpy(pname,ktokn,(strlen(ktokn)+1)*sizeof(char));
276
277 xfree((void**)&ktagi);
278
279 if (m)
280 *m=strlen(pname);
281
282 return(pname);
283}
284/*}}}*/
285
286/*FUNCTION KMLFileTagAttrib {{{1*/
287int KMLFileTagAttrib(KML_Object* kobj,
288 char* ktag){
289
290/* for the given tag buffer, read and store the attributes */
291
292 char* ktagi;
293 char* ktokn;
294 char* ktokv;
295 char quote[]={'\"','\0'};
296 int isolo=0;
297
298/* strtok modifies ktag, so work on copy */
299
300 ktagi=(char *) xmalloc((strlen(ktag)+1)*sizeof(char));
301 memcpy(ktagi,ktag,(strlen(ktag)+1)*sizeof(char));
302
303/* loop through tag to find all attributes */
304
305 /* return first non blank and move past subsequent blank */
306 ktokn=strtok(ktagi," ");
307// _printf_(true,"KMLFileTagAttrib -- initial token=\"%s\".\n",ktokn);
308
309 /* return next non " =?/>" and move past subsequent " =?/>" */
310 while (ktokn=strtok(NULL," =?/>")) {
311
312 /* return next non quote and move past subsequent quote */
313 ktokv=strtok(NULL,quote);
314// _printf_(true,"KMLFileTagAttrib -- attribute %s=\"%s\".\n",ktokn,ktokv);
315
316/* add the attribute to the dataset */
317
318 if (kobj)
319 kobj->AddAttrib(ktokn,ktokv);
320 }
321
322 xfree((void**)&ktagi);
323
324/* check for xml declaration, dtd declaration, or solo tag */
325
326 if ((!strncmp(&ktag[0],"<?" ,2) && !strncmp(&ktag[strlen(ktag)-2],"?>",2)) ||
327 (!strncmp(&ktag[0],"<!DOCTYPE",9) && !strncmp(&ktag[strlen(ktag)-1], ">",1)) ||
328 (!strncmp(&ktag[0],"<" ,1) && !strncmp(&ktag[strlen(ktag)-2],"/>",2)))
329 isolo=1;
330// _printf_(true,"KMLFileTagAttrib -- isolo=%d.\n",isolo);
331
332 return(isolo);
333}
334/*}}}*/
335
336/*FUNCTION KMLFileTokenParse {{{1*/
337int KMLFileTokenParse(int* pival,
338 char* ktag,
339 FILE* fid){
340
341 char* kstr;
342
343/* get next token and convert to appropriate format */
344
345 if (!(kstr=KMLFileToken(fid,
346 NULL,NULL)) ||
347 (kstr[0] == '<'))
348 _error_("KMLFileTokenParse -- Missing integer field for %s.\n",ktag);
349
350 sscanf(kstr,"%d",pival);
351 xfree((void**)&kstr);
352
353/* get additional token and compare to closing tag */
354
355 if (ktag)
356 if (!(kstr=KMLFileToken(fid,
357 NULL,NULL)) ||
358 (kstr[0] != '<') ||
359 (kstr[1] != '/') ||
360 (strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
361 _error_("KMLFileTokenParse -- Missing closing tag for %s.\n",ktag);
362 else
363 xfree((void**)&kstr);
364
365// _printf_(true,"KMLFileTokenParse -- %s=%d.\n",ktag,*pival);
366
367 return(0);
368}
369/*}}}*/
370
371/*FUNCTION KMLFileTokenParse {{{1*/
372int KMLFileTokenParse(bool* pbval,
373 char* ktag,
374 FILE* fid){
375
376 int ival;
377 char* kstr;
378
379/* get next token and convert to appropriate format */
380
381 if (!(kstr=KMLFileToken(fid,
382 NULL,NULL)) ||
383 (kstr[0] == '<'))
384 _error_("KMLFileTokenParse -- Missing bool field for %s.\n",ktag);
385
386 sscanf(kstr,"%d",&ival);
387 *pbval=(bool)ival;
388 xfree((void**)&kstr);
389
390/* get additional token and compare to closing tag */
391
392 if (ktag)
393 if (!(kstr=KMLFileToken(fid,
394 NULL,NULL)) ||
395 (kstr[0] != '<') ||
396 (kstr[1] != '/') ||
397 (strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
398 _error_("KMLFileTokenParse -- Missing closing tag for %s.\n",ktag);
399 else
400 xfree((void**)&kstr);
401
402// _printf_(true,"KMLFileTokenParse -- %s=%s.\n",ktag,(*pbval ? "true" : "false"));
403
404 return(0);
405}
406/*}}}*/
407
408/*FUNCTION KMLFileTokenParse {{{1*/
409char* KMLFileTokenParse(char* pstr,
410 char* ktag,
411 FILE* fid){
412
413 return(KMLFileTokenParse(pstr,NULL,0,
414 ktag,
415 fid));
416}
417/*}}}*/
418
419/*FUNCTION KMLFileTokenParse {{{1*/
420char* KMLFileTokenParse(char* pstr,int *m,int maxlen,
421 char* ktag,
422 FILE* fid){
423
424 char* kstr;
425
426/* get next token and allocate if necessary */
427
428 if (!(kstr=KMLFileToken(fid,
429 NULL,NULL)) ||
430 (kstr[0] == '<'))
431 _error_("KMLFileTokenParse -- Missing string field for %s.\n",ktag);
432
433 if (!pstr) {
434 if (maxlen)
435 pstr=(char *) xmalloc((maxlen +1)*sizeof(char));
436 else
437 pstr=(char *) xmalloc((strlen(kstr)+1)*sizeof(char));
438 }
439
440 if (maxlen && (maxlen < strlen(kstr))) {
441 _printf_(true,"KMLFileTokenParse -- string field too short for %s.\n",ktag);
442 _printf_(true,"KMLFileTokenParse -- \"%s\" truncated to %d characters.\n",kstr,maxlen);
443 strncpy(pstr,kstr,maxlen);
444 }
445 else
446 memcpy(pstr,kstr,(strlen(kstr)+1)*sizeof(char));
447
448 xfree((void**)&kstr);
449
450 if (m)
451 *m=strlen(pstr);
452
453/* get additional token and compare to closing tag */
454
455 if (ktag)
456 if (!(kstr=KMLFileToken(fid,
457 NULL,NULL)) ||
458 (kstr[0] != '<') ||
459 (kstr[1] != '/') ||
460 (strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
461 _error_("KMLFileTokenParse -- Missing closing tag for %s.\n",ktag);
462 else
463 xfree((void**)&kstr);
464
465// _printf_(true,"KMLFileTokenParse -- %s=\"%s\".\n",ktag,pstr);
466
467 return(pstr);
468}
469/*}}}*/
470
471/*FUNCTION KMLFileTokenParse {{{1*/
472int KMLFileTokenParse(float* pfval,
473 char* ktag,
474 FILE* fid){
475
476 char* kstr;
477
478/* get next token and convert to appropriate format */
479
480 if (!(kstr=KMLFileToken(fid,
481 NULL,NULL)) ||
482 (kstr[0] == '<'))
483 _error_("KMLFileTokenParse -- Missing integer field for %s.\n",ktag);
484
485 sscanf(kstr,"%g",pfval);
486 xfree((void**)&kstr);
487
488/* get additional token and compare to closing tag */
489
490 if (ktag)
491 if (!(kstr=KMLFileToken(fid,
492 NULL,NULL)) ||
493 (kstr[0] != '<') ||
494 (kstr[1] != '/') ||
495 (strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
496 _error_("KMLFileTokenParse -- Missing closing tag for %s.\n",ktag);
497 else
498 xfree((void**)&kstr);
499
500// _printf_(true,"KMLFileTokenParse -- %s=%g.\n",ktag,*pfval);
501
502 return(0);
503}
504/*}}}*/
505
506/*FUNCTION KMLFileTokenParse {{{1*/
507int KMLFileTokenParse(double* pdval,
508 char* ktag,
509 FILE* fid){
510
511 char* kstr;
512
513/* get next token and convert to appropriate format */
514
515 if (!(kstr=KMLFileToken(fid,
516 NULL,NULL)) ||
517 (kstr[0] == '<'))
518 _error_("KMLFileTokenParse -- Missing integer field for %s.\n",ktag);
519
520 sscanf(kstr,"%lg",pdval);
521 xfree((void**)&kstr);
522
523/* get additional token and compare to closing tag */
524
525 if (ktag)
526 if (!(kstr=KMLFileToken(fid,
527 NULL,NULL)) ||
528 (kstr[0] != '<') ||
529 (kstr[1] != '/') ||
530 (strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
531 _error_("KMLFileTokenParse -- Missing closing tag for %s.\n",ktag);
532 else
533 xfree((void**)&kstr);
534
535// _printf_(true,"KMLFileTokenParse -- %s=%g.\n",ktag,*pdval);
536
537 return(0);
538}
539/*}}}*/
540
541/*FUNCTION KMLFileTokenParse {{{1*/
542int KMLFileTokenParse(double **pdval,int* m,int maxlen,
543 char* ktag,
544 FILE* fid){
545
546 int i=-1,j;
547 char* kstr;
548 char* ktok;
549 char delim[]={' ',',','\f','\n','\r','\t','\v','\0'};
550
551/* get next token and allocate if necessary */
552
553 if (!(kstr=KMLFileToken(fid,
554 NULL,NULL)) ||
555 (kstr[0] == '<'))
556 _error_("KMLFileTokenParse -- Missing double [m] field for %s.\n",ktag);
557
558 if (!*pdval)
559 if (maxlen)
560 *pdval=(double *) xmalloc(maxlen *sizeof(double));
561 else
562 *pdval=(double *) xmalloc(((strlen(kstr)+1)/2)*sizeof(double));
563
564/* loop through string to get all values */
565
566 ktok=strtok(kstr,delim);
567 while (ktok) {
568 i++;
569 if (maxlen && (maxlen < i+1))
570 _error_("KMLFileTokenParse -- Double [m] field too short for %s.\n",ktag);
571 sscanf(ktok,"%lg",&((*pdval)[i]));
572 ktok=strtok(NULL,delim);
573 }
574 xfree((void**)&kstr);
575
576 if (!maxlen)
577 *pdval=(double *) xrealloc(*pdval,(i+1)*sizeof(double));
578
579 if (m)
580 *m=i+1;
581
582/* get additional token and compare to closing tag */
583
584 if (ktag)
585 if (!(kstr=KMLFileToken(fid,
586 NULL,NULL)) ||
587 (kstr[0] != '<') ||
588 (kstr[1] != '/') ||
589 (strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
590 _error_("KMLFileTokenParse -- Missing closing tag for %s.\n",ktag);
591 else
592 xfree((void**)&kstr);
593
594// _printf_(true,"KMLFileTokenParse -- %s=...\n",ktag);
595// for (j=0; j<=i; j++)
596// _printf_(true," [%d]: %lg\n",j,(*pdval)[j]);
597
598 return(0);
599}
600/*}}}*/
601
602/*FUNCTION KMLFileTokenParse {{{1*/
603int KMLFileTokenParse(double (**pdval3)[3],int* m,int maxlen,
604 char* ktag,
605 FILE* fid){
606
607 int i=0,j=-1;
608 char* kstr;
609 char* ktok;
610 char delim[]={' ',',','\f','\n','\r','\t','\v','\0'};
611
612/* get next token and allocate if necessary */
613
614 if (!(kstr=KMLFileToken(fid,
615 NULL,NULL)) ||
616 (kstr[0] == '<'))
617 _error_("KMLFileTokenParse -- Missing double [m x 3] field for %s.\n",ktag);
618
619 if (!*pdval3)
620 if (maxlen)
621 *pdval3=(double (*)[3]) xmalloc((maxlen*3) *sizeof(double));
622 else
623 *pdval3=(double (*)[3]) xmalloc(((strlen(kstr)+1)/2)*sizeof(double));
624
625/* loop through string to get all values */
626
627 ktok=strtok(kstr,delim);
628 while (ktok) {
629 j++;
630 if (j == 3) {
631 i++;
632 j=0;
633 if (maxlen && (maxlen < i+1))
634 _error_("KMLFileTokenParse -- Double [m x 3] field too short for %s.\n",ktag);
635 }
636 sscanf(ktok,"%lg",&((*pdval3)[i][j]));
637 ktok=strtok(NULL,delim);
638 }
639 xfree((void**)&kstr);
640
641 if (!maxlen)
642 *pdval3=(double (*)[3]) xrealloc(*pdval3,((i+1)*3)*sizeof(double));
643
644 if (m)
645 *m=i+1;
646
647 if (j != 2)
648 _printf_(true,"KMLFileTokenParse -- Double [m x 3] field for %s does not have multiple of 3 values.\n",ktag);
649
650/* get additional token and compare to closing tag */
651
652 if (ktag)
653 if (!(kstr=KMLFileToken(fid,
654 NULL,NULL)) ||
655 (kstr[0] != '<') ||
656 (kstr[1] != '/') ||
657 (strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
658 _error_("KMLFileTokenParse -- Missing closing tag for %s.\n",ktag);
659 else
660 xfree((void**)&kstr);
661
662// _printf_(true,"KMLFileTokenParse -- %s=...\n",ktag);
663// for (j=0; j<=i; j++)
664// _printf_(true," [%d][0-2]: %lg,%lg,%lg\n",j,(*pdval3)[j][0],(*pdval3)[j][1],(*pdval3)[j][2]);
665
666 return(0);
667}
668/*}}}*/
669
670/*FUNCTION KMLFileTagSkip {{{1*/
671int KMLFileTagSkip(char* ktag,
672 FILE* fid){
673
674 char* kstr;
675
676/* note that tags of the same type can be nested inside each other, so for each
677 opening tag, must find corresponding closing tag */
678
679 _printf_(true,"KMLFileTagSkip -- input tag %s.\n",ktag);
680
681/* if next token is a closing tag, compare to input */
682
683 while (kstr=KMLFileToken(fid,
684 NULL,NULL)) {
685 if ((kstr[0] == '<') &&
686 (kstr[1] == '/') &&
687 (!strncmp(&(kstr[2]),&(ktag[1]),(strcspn(ktag," >")-1)/sizeof(char)))) {
688 _printf_(true,"KMLFileTagSkip -- closing tag %s.\n",kstr);
689 xfree((void**)&kstr);
690 return(0);
691 }
692
693/* if next token is an opening tag, call recursively */
694
695 else if ((kstr[0] == '<') &&
696 (kstr[1] != '/')) {
697 _printf_(true,"KMLFileTagSkip -- opening tag %s.\n",kstr);
698 KMLFileTagSkip(kstr,
699 fid);
700 }
701
702/* if next token is a closing tag, error out */
703
704 else if ((kstr[0] == '<') &&
705 (kstr[1] == '/')) {
706 _error_("KMLFileTagSkip -- Unexpected closing tag %s.\n",kstr);
707 }
708
709 xfree((void**)&kstr);
710 }
711
712 _error_("KMLFileTokenParse -- Corresponding closing tag for %s not found.\n",ktag);
713
714 return(0);
715}
716/*}}}*/
717
Note: See TracBrowser for help on using the repository browser.