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

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

KML: Addition of KML_Comment class to save and regurgitate KML comments.

File size: 14.6 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 KMLFileTagAttrib {{{1*/
232int KMLFileTagAttrib(KML_Object* kobj,
233 char* ktag){
234
235/* for the given tag buffer, read and store the attributes */
236
237 char* ktagi;
238 char* ktokn;
239 char* ktokv;
240 char quote[]={'\"','\0'};
241 int isolo=0;
242
243/* strtok modifies ktag, so work on copy */
244
245 ktagi=(char *) xmalloc((strlen(ktag)+1)*sizeof(char));
246 memcpy(ktagi,ktag,(strlen(ktag)+1)*sizeof(char));
247
248/* loop through tag to find all attributes */
249
250 /* return first non blank and move past subsequent blank */
251 ktokn=strtok(ktagi," ");
252// _printf_(true,"KMLFileTagAttrib -- initial token=\"%s\".\n",ktokn);
253
254 /* return next non " =?/>" and move past subsequent " =?/>" */
255 while (ktokn=strtok(NULL," =?/>")) {
256
257 /* return next non quote and move past subsequent quote */
258 ktokv=strtok(NULL,quote);
259// _printf_(true,"KMLFileTagAttrib -- attribute %s=\"%s\".\n",ktokn,ktokv);
260
261/* add the attribute to the dataset */
262
263 if (kobj)
264 kobj->AddAttrib(ktokn,ktokv);
265 }
266
267 xfree((void**)&ktagi);
268
269/* check for xml declaration, dtd declaration, or solo tag */
270
271 if ((!strncmp(&ktag[0],"<?" ,2) && !strncmp(&ktag[strlen(ktag)-2],"?>",2)) ||
272 (!strncmp(&ktag[0],"<!DOCTYPE",9) && !strncmp(&ktag[strlen(ktag)-1], ">",1)) ||
273 (!strncmp(&ktag[0],"<" ,1) && !strncmp(&ktag[strlen(ktag)-2],"/>",2)))
274 isolo=1;
275// _printf_(true,"KMLFileTagAttrib -- isolo=%d.\n",isolo);
276
277 return(isolo);
278}
279/*}}}*/
280
281/*FUNCTION KMLFileTokenParse {{{1*/
282int KMLFileTokenParse(int* pival,
283 char* ktag,
284 FILE* fid){
285
286 char* kstr;
287
288/* get next token and convert to appropriate format */
289
290 if (!(kstr=KMLFileToken(fid,
291 NULL,NULL)) ||
292 (kstr[0] == '<'))
293 _error_("KMLFileTokenParse -- Missing integer field for %s.\n",ktag);
294
295 sscanf(kstr,"%d",pival);
296 xfree((void**)&kstr);
297
298/* get additional token and compare to closing tag */
299
300 if (ktag)
301 if (!(kstr=KMLFileToken(fid,
302 NULL,NULL)) ||
303 (kstr[0] != '<') ||
304 (kstr[1] != '/') ||
305 (strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
306 _error_("KMLFileTokenParse -- Missing closing tag for %s.\n",ktag);
307 else
308 xfree((void**)&kstr);
309
310// _printf_(true,"KMLFileTokenParse -- %s=%d.\n",ktag,*pival);
311
312 return(0);
313}
314/*}}}*/
315
316/*FUNCTION KMLFileTokenParse {{{1*/
317int KMLFileTokenParse(bool* pbval,
318 char* ktag,
319 FILE* fid){
320
321 int ival;
322 char* kstr;
323
324/* get next token and convert to appropriate format */
325
326 if (!(kstr=KMLFileToken(fid,
327 NULL,NULL)) ||
328 (kstr[0] == '<'))
329 _error_("KMLFileTokenParse -- Missing bool field for %s.\n",ktag);
330
331 sscanf(kstr,"%d",&ival);
332 *pbval=(bool)ival;
333 xfree((void**)&kstr);
334
335/* get additional token and compare to closing tag */
336
337 if (ktag)
338 if (!(kstr=KMLFileToken(fid,
339 NULL,NULL)) ||
340 (kstr[0] != '<') ||
341 (kstr[1] != '/') ||
342 (strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
343 _error_("KMLFileTokenParse -- Missing closing tag for %s.\n",ktag);
344 else
345 xfree((void**)&kstr);
346
347// _printf_(true,"KMLFileTokenParse -- %s=%s.\n",ktag,(*pbval ? "true" : "false"));
348
349 return(0);
350}
351/*}}}*/
352
353/*FUNCTION KMLFileTokenParse {{{1*/
354char* KMLFileTokenParse(char* pstr,int *m,int maxlen,
355 char* ktag,
356 FILE* fid){
357
358 char* kstr;
359 char* pstro=NULL;
360
361/* get next token and allocate if necessary */
362
363 if (!(kstr=KMLFileToken(fid,
364 NULL,NULL)) ||
365 (kstr[0] == '<'))
366 _error_("KMLFileTokenParse -- Missing string field for %s.\n",ktag);
367
368 if (!pstr) {
369 if (maxlen)
370 pstr=(char *) xmalloc((maxlen +1)*sizeof(char));
371 else
372 pstr=(char *) xmalloc((strlen(kstr)+1)*sizeof(char));
373 pstro=pstr;
374 }
375
376 if (maxlen && (maxlen < strlen(kstr))) {
377 _printf_(true,"KMLFileTokenParse -- string field too short for %s.\n",ktag);
378 _printf_(true,"KMLFileTokenParse -- \"%s\" truncated to %d characters.\n",kstr,maxlen);
379 strncpy(pstr,kstr,maxlen);
380 }
381 else
382 memcpy(pstr,kstr,(strlen(kstr)+1)*sizeof(char));
383
384 xfree((void**)&kstr);
385
386 if (m)
387 *m=strlen(pstr);
388
389/* get additional token and compare to closing tag */
390
391 if (ktag)
392 if (!(kstr=KMLFileToken(fid,
393 NULL,NULL)) ||
394 (kstr[0] != '<') ||
395 (kstr[1] != '/') ||
396 (strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
397 _error_("KMLFileTokenParse -- Missing closing tag for %s.\n",ktag);
398 else
399 xfree((void**)&kstr);
400
401// _printf_(true,"KMLFileTokenParse -- %s=\"%s\".\n",ktag,pstr);
402
403 return(pstro);
404}
405/*}}}*/
406
407/*FUNCTION KMLFileTokenParse {{{1*/
408int KMLFileTokenParse(float* pfval,
409 char* ktag,
410 FILE* fid){
411
412 char* kstr;
413
414/* get next token and convert to appropriate format */
415
416 if (!(kstr=KMLFileToken(fid,
417 NULL,NULL)) ||
418 (kstr[0] == '<'))
419 _error_("KMLFileTokenParse -- Missing integer field for %s.\n",ktag);
420
421 sscanf(kstr,"%g",pfval);
422 xfree((void**)&kstr);
423
424/* get additional token and compare to closing tag */
425
426 if (ktag)
427 if (!(kstr=KMLFileToken(fid,
428 NULL,NULL)) ||
429 (kstr[0] != '<') ||
430 (kstr[1] != '/') ||
431 (strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
432 _error_("KMLFileTokenParse -- Missing closing tag for %s.\n",ktag);
433 else
434 xfree((void**)&kstr);
435
436// _printf_(true,"KMLFileTokenParse -- %s=%g.\n",ktag,*pfval);
437
438 return(0);
439}
440/*}}}*/
441
442/*FUNCTION KMLFileTokenParse {{{1*/
443int KMLFileTokenParse(double* pdval,
444 char* ktag,
445 FILE* fid){
446
447 char* kstr;
448
449/* get next token and convert to appropriate format */
450
451 if (!(kstr=KMLFileToken(fid,
452 NULL,NULL)) ||
453 (kstr[0] == '<'))
454 _error_("KMLFileTokenParse -- Missing integer field for %s.\n",ktag);
455
456 sscanf(kstr,"%lg",pdval);
457 xfree((void**)&kstr);
458
459/* get additional token and compare to closing tag */
460
461 if (ktag)
462 if (!(kstr=KMLFileToken(fid,
463 NULL,NULL)) ||
464 (kstr[0] != '<') ||
465 (kstr[1] != '/') ||
466 (strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
467 _error_("KMLFileTokenParse -- Missing closing tag for %s.\n",ktag);
468 else
469 xfree((void**)&kstr);
470
471// _printf_(true,"KMLFileTokenParse -- %s=%g.\n",ktag,*pdval);
472
473 return(0);
474}
475/*}}}*/
476
477/*FUNCTION KMLFileTokenParse {{{1*/
478int KMLFileTokenParse(double **pdval,int* m,int maxlen,
479 char* ktag,
480 FILE* fid){
481
482 int i=-1,j;
483 char* kstr;
484 char* ktok;
485 char delim[]={' ',',','\f','\n','\r','\t','\v','\0'};
486
487/* get next token and allocate if necessary */
488
489 if (!(kstr=KMLFileToken(fid,
490 NULL,NULL)) ||
491 (kstr[0] == '<'))
492 _error_("KMLFileTokenParse -- Missing double [m] field for %s.\n",ktag);
493
494 if (!*pdval)
495 if (maxlen)
496 *pdval=(double *) xmalloc(maxlen *sizeof(double));
497 else
498 *pdval=(double *) xmalloc(((strlen(kstr)+1)/2)*sizeof(double));
499
500/* loop through string to get all values */
501
502 ktok=strtok(kstr,delim);
503 while (ktok) {
504 i++;
505 if (maxlen && (maxlen < i+1))
506 _error_("KMLFileTokenParse -- Double [m] field too short for %s.\n",ktag);
507 sscanf(ktok,"%lg",&((*pdval)[i]));
508 ktok=strtok(NULL,delim);
509 }
510 xfree((void**)&kstr);
511
512 if (!maxlen)
513 *pdval=(double *) xrealloc(*pdval,(i+1)*sizeof(double));
514
515 if (m)
516 *m=i+1;
517
518/* get additional token and compare to closing tag */
519
520 if (ktag)
521 if (!(kstr=KMLFileToken(fid,
522 NULL,NULL)) ||
523 (kstr[0] != '<') ||
524 (kstr[1] != '/') ||
525 (strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
526 _error_("KMLFileTokenParse -- Missing closing tag for %s.\n",ktag);
527 else
528 xfree((void**)&kstr);
529
530// _printf_(true,"KMLFileTokenParse -- %s=...\n",ktag);
531// for (j=0; j<=i; j++)
532// _printf_(true," [%d]: %lg\n",j,(*pdval)[j]);
533
534 return(0);
535}
536/*}}}*/
537
538/*FUNCTION KMLFileTokenParse {{{1*/
539int KMLFileTokenParse(double (**pdval3)[3],int* m,int maxlen,
540 char* ktag,
541 FILE* fid){
542
543 int i=0,j=-1;
544 char* kstr;
545 char* ktok;
546 char delim[]={' ',',','\f','\n','\r','\t','\v','\0'};
547
548/* get next token and allocate if necessary */
549
550 if (!(kstr=KMLFileToken(fid,
551 NULL,NULL)) ||
552 (kstr[0] == '<'))
553 _error_("KMLFileTokenParse -- Missing double [m x 3] field for %s.\n",ktag);
554
555 if (!*pdval3)
556 if (maxlen)
557 *pdval3=(double (*)[3]) xmalloc((maxlen*3) *sizeof(double));
558 else
559 *pdval3=(double (*)[3]) xmalloc(((strlen(kstr)+1)/2)*sizeof(double));
560
561/* loop through string to get all values */
562
563 ktok=strtok(kstr,delim);
564 while (ktok) {
565 j++;
566 if (j == 3) {
567 i++;
568 j=0;
569 if (maxlen && (maxlen < i+1))
570 _error_("KMLFileTokenParse -- Double [m x 3] field too short for %s.\n",ktag);
571 }
572 sscanf(ktok,"%lg",&((*pdval3)[i][j]));
573 ktok=strtok(NULL,delim);
574 }
575 xfree((void**)&kstr);
576
577 if (!maxlen)
578 *pdval3=(double (*)[3]) xrealloc(*pdval3,((i+1)*3)*sizeof(double));
579
580 if (m)
581 *m=i+1;
582
583 if (j != 2)
584 _printf_(true,"KMLFileTokenParse -- Double [m x 3] field for %s does not have multiple of 3 values.\n",ktag);
585
586/* get additional token and compare to closing tag */
587
588 if (ktag)
589 if (!(kstr=KMLFileToken(fid,
590 NULL,NULL)) ||
591 (kstr[0] != '<') ||
592 (kstr[1] != '/') ||
593 (strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
594 _error_("KMLFileTokenParse -- Missing closing tag for %s.\n",ktag);
595 else
596 xfree((void**)&kstr);
597
598// _printf_(true,"KMLFileTokenParse -- %s=...\n",ktag);
599// for (j=0; j<=i; j++)
600// _printf_(true," [%d][0-2]: %lg,%lg,%lg\n",j,(*pdval3)[j][0],(*pdval3)[j][1],(*pdval3)[j][2]);
601
602 return(0);
603}
604/*}}}*/
605
606/*FUNCTION KMLFileTagSkip {{{1*/
607int KMLFileTagSkip(char* ktag,
608 FILE* fid){
609
610 char* kstr;
611
612/* note that tags of the same type can be nested inside each other, so for each
613 opening tag, must find corresponding closing tag */
614
615 _printf_(true,"KMLFileTagSkip -- input tag %s.\n",ktag);
616
617/* if next token is a closing tag, compare to input */
618
619 while (kstr=KMLFileToken(fid,
620 NULL,NULL)) {
621 if ((kstr[0] == '<') &&
622 (kstr[1] == '/') &&
623 (!strncmp(&(kstr[2]),&(ktag[1]),(strcspn(ktag," >")-1)/sizeof(char)))) {
624 _printf_(true,"KMLFileTagSkip -- closing tag %s.\n",kstr);
625 xfree((void**)&kstr);
626 return(0);
627 }
628
629/* if next token is an opening tag, call recursively */
630
631 else if ((kstr[0] == '<') &&
632 (kstr[1] != '/')) {
633 _printf_(true,"KMLFileTagSkip -- opening tag %s.\n",kstr);
634 KMLFileTagSkip(kstr,
635 fid);
636 }
637
638/* if next token is a closing tag, error out */
639
640 else if ((kstr[0] == '<') &&
641 (kstr[1] == '/')) {
642 _error_("KMLFileTagSkip -- Unexpected closing tag %s.\n",kstr);
643 }
644
645 xfree((void**)&kstr);
646 }
647
648 _error_("KMLFileTokenParse -- Corresponding closing tag for %s not found.\n",ktag);
649
650 return(0);
651}
652/*}}}*/
653
Note: See TracBrowser for help on using the repository browser.