r665: Merged the official release 2.0.
[cinelerra_cv.git] / cinelerra / filexml.C
blobfe639c5289a3ff711c7981cb0be048591573e52c
1 #include <ctype.h>
2 #include <errno.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
7 #include "filexml.h"
12 // Precision in base 10
13 // for float is 6 significant figures
14 // for double is 16 significant figures
18 FileXML::FileXML(char left_delimiter, char right_delimiter)
20         tag.set_delimiters(left_delimiter, right_delimiter);
21         this->left_delimiter = left_delimiter;
22         this->right_delimiter = right_delimiter;
23         available = 64;
24         string = new char[available];
25         string[0] = 0;
26         position = length = 0;
27         output_length = 0;
28         share_string = 0;
31 FileXML::~FileXML()
33         if(!share_string) delete [] string;
34         if(output_length) delete [] output;
37 void FileXML::dump()
39         printf("FileXML::dump:\n%s\n", string);
42 int FileXML::terminate_string()
44         append_text("", 1);
45         return 0;
48 int FileXML::rewind()
50         terminate_string();
51         length = strlen(string);
52         position = 0;
53         return 0;
57 int FileXML::append_newline()
59         append_text("\n", 1);
60         return 0;
63 int FileXML::append_tag()
65         tag.write_tag();
66         append_text(tag.string, tag.len);
67         tag.reset_tag();
68         return 0;
71 int FileXML::append_text(char *text)
73         append_text(text, strlen(text));
74         return 0;
77 int FileXML::append_text(char *text, long len)
79         while(position + len > available)
80         {
81                 reallocate_string(available * 2);
82         }
84         for(int i = 0; i < len; i++, position++)
85         {
86                 string[position] = text[i];
87         }
88         return 0;
91 int FileXML::encode_text(char *text)
93 // We have to encode at least the '<' char
94 // We encode three things:
95 // '<' -> '&lt;' 
96 // '>' -> '&gt;'
97 // '&' -> '&amp;'
98         char leftb[] = "&lt;";
99         char rightb[] = "&gt;";
100         char amp[] = "&amp;";
101         char *replacement;
102         int len = strlen(text);
103         int lastpos = 0;
104         for (int i = 0; i < len; i++) 
105         {
106                 switch (text[i]) {
107                         case '<': replacement = leftb; break;
108                         case '>': replacement = rightb; break;
109                         case '&': replacement = amp; break;
110                         default: replacement = 0; break;
111                 }
112                 if (replacement)
113                 {
114                         if (i - lastpos > 0)
115                                 append_text(text + lastpos, i - lastpos);
116                         append_text(replacement, strlen(replacement));
117                         lastpos = i + 1;
118                 }
119         }
120         append_text(text + lastpos, len - lastpos);
121         return 0;
126 int FileXML::reallocate_string(long new_available)
128         if(!share_string)
129         {
130                 char *new_string = new char[new_available];
131                 for(int i = 0; i < position; i++) new_string[i] = string[i];
132                 available = new_available;
133                 delete [] string;
134                 string = new_string;
135         }
136         return 0;
139 char* FileXML::read_text()
141         long text_position = position;
142         int i;
144 // use < to mark end of text and start of tag
146 // find end of text
147         for(; position < length && string[position] != left_delimiter; position++)
148         {
149                 ;
150         }
152 // allocate enough space
153         if(output_length) delete [] output;
154         output_length = position - text_position;
155         output = new char[output_length + 1];
157 //printf("FileXML::read_text %d %c\n", text_position, string[text_position]);
158         for(i = 0; text_position < position; text_position++)
159         {
160 // filter out first newline
161                 if((i > 0 && i < output_length - 1) || string[text_position] != '\n') 
162                 {
163 // check if we have to decode special characters
164 // but try to be most backward compatible possible
165                         int character = string[text_position];
166                         if (string[text_position] == '&')
167                         {
168                                 if (text_position + 3 < length)
169                                 {
170                                         if (string[text_position + 1] == 'l' && string[text_position + 2] == 't' && string[text_position + 3] == ';')
171                                         {
172                                                 character = '<';
173                                                 text_position += 3;
174                                         }               
175                                         if (string[text_position + 1] == 'g' && string[text_position + 2] == 't' && string[text_position + 3] == ';')
176                                         {
177                                                 character = '>';
178                                                 text_position += 3;
179                                         }               
180                                 }
181                                 if (text_position + 4 < length)
182                                 {
183                                         if (string[text_position + 1] == 'a' && string[text_position + 2] == 'm' && string[text_position + 3] == 'p' && string[text_position + 4] == ';')
184                                         {
185                                                 character = '&';
186                                                 text_position += 4;
187                                         }               
188                                 }
189                         }
190                         output[i] = character;
191                         i++;
192                 }
193         }
194         output[i] = 0;
196         return output;
199 int FileXML::read_tag()
201 // scan to next tag
202         while(position < length && string[position] != left_delimiter)
203         {
204                 position++;
205         }
206         tag.reset_tag();
207         if(position >= length) return 1;
208 //printf("FileXML::read_tag %s\n", &string[position]);
209         return tag.read_tag(string, position, length);
212 int FileXML::read_text_until(char *tag_end, char *output, int max_len)
214 // read to next tag
215         int out_position = 0;
216         int test_position1, test_position2;
217         int result = 0;
218         
219         while(!result && position < length && out_position < max_len - 1)
220         {
221                 while(position < length && string[position] != left_delimiter)
222                 {
223 //printf("FileXML::read_text_until 1 %c\n", string[position]);
224                         output[out_position++] = string[position++];
225                 }
226                 
227                 if(position < length && string[position] == left_delimiter)
228                 {
229 // tag reached
230 // test for tag_end
231                         result = 1;         // assume end
232                         
233                         for(test_position1 = 0, test_position2 = position + 1;   // skip < 
234                                 test_position2 < length &&
235                                 tag_end[test_position1] != 0 &&
236                                 result; 
237                                 test_position1++, test_position2++)
238                         {
239 // null result when first wrong character is reached
240 //printf("FileXML::read_text_until 2 %c\n", string[test_position2]);
241                                 if(tag_end[test_position1] != string[test_position2]) result = 0;
242                         }
244 // no end tag reached to copy <
245                         if(!result)
246                         {
247                                 output[out_position++] = string[position++];
248                         }
249                 }
250         }
251         output[out_position] = 0;
252 // if end tag is reached, position is left on the < of the end tag
253         return 0;
257 int FileXML::write_to_file(char *filename)
259         FILE *out;
260         strcpy(this->filename, filename);
261         if(out = fopen(filename, "wb"))
262         {
263                 fprintf(out, "<?xml version=\"1.0\"?>\n");
264 // Position may have been rewound after storing so we use a strlen
265                 if(!fwrite(string, strlen(string), 1, out) && strlen(string))
266                 {
267                         fprintf(stderr, "FileXML::write_to_file 1 \"%s\": %s\n",
268                                 filename,
269                                 strerror(errno));
270                         fclose(out);
271                         return 1;
272                 }
273                 else
274                 {
275                 }
276         }
277         else
278         {
279                 fprintf(stderr, "FileXML::write_to_file 2 \"%s\": %s\n",
280                         filename,
281                         strerror(errno));
282                 return 1;
283         }
284         fclose(out);
285         return 0;
288 int FileXML::write_to_file(FILE *file)
290         strcpy(filename, "");
291         fprintf(file, "<?xml version=\"1.0\"?>\n");
292 // Position may have been rewound after storing
293         if(fwrite(string, strlen(string), 1, file) || !strlen(string))
294         {
295                 return 0;
296         }
297         else
298         {
299                 fprintf(stderr, "FileXML::write_to_file \"%s\": %s\n",
300                         filename,
301                         strerror(errno));
302                 return 1;
303         }
304         return 0;
307 int FileXML::read_from_file(char *filename, int ignore_error)
309         FILE *in;
310         
311         strcpy(this->filename, filename);
312         if(in = fopen(filename, "rb"))
313         {
314                 fseek(in, 0, SEEK_END);
315                 length = ftell(in);
316                 fseek(in, 0, SEEK_SET);
317                 reallocate_string(length + 1);
318                 fread(string, length, 1, in);
319                 string[length] = 0;
320                 position = 0;
321         }
322         else
323         {
324                 if(!ignore_error) 
325                         fprintf(stderr, "FileXML::read_from_file \"%s\" %s\n",
326                                 filename,
327                                 strerror(errno));
328                 return 1;
329         }
330         fclose(in);
331         return 0;
334 int FileXML::read_from_string(char *string)
336         strcpy(this->filename, "");
337         reallocate_string(strlen(string) + 1);
338         strcpy(this->string, string);
339         length = strlen(string);
340         position = 0;
341         return 0;
344 int FileXML::set_shared_string(char *shared_string, long available)
346         strcpy(this->filename, "");
347         if(!share_string)
348         {
349                 delete [] string;
350                 share_string = 1;
351                 string = shared_string;
352                 this->available = available;
353                 length = available;
354                 position = 0;
355         }
356         return 0;
361 // ================================ XML tag
364 XMLTag::XMLTag()
366         total_properties = 0;
367         len = 0;
370 XMLTag::~XMLTag()
372         reset_tag();
375 int XMLTag::set_delimiters(char left_delimiter, char right_delimiter)
377         this->left_delimiter = left_delimiter;
378         this->right_delimiter = right_delimiter;
379         return 0;
382 int XMLTag::reset_tag()     // clear all structures
384         len = 0;
385         for(int i = 0; i < total_properties; i++) delete [] tag_properties[i];
386         for(int i = 0; i < total_properties; i++) delete [] tag_property_values[i];
387         total_properties = 0;
388         return 0;
391 int XMLTag::write_tag()
393         int i, j;
394         char *current_property, *current_value;
396 // opening bracket
397         string[len] = left_delimiter;        
398         len++;
399         
400 // title
401         for(i = 0; tag_title[i] != 0 && len < MAX_LENGTH; i++, len++) string[len] = tag_title[i];
403 // properties
404         for(i = 0; i < total_properties && len < MAX_LENGTH; i++)
405         {
406                 string[len++] = ' ';         // add a space before every property
407                 
408                 current_property = tag_properties[i];
410 // property title
411                 for(j = 0; current_property[j] != 0 && len < MAX_LENGTH; j++, len++)
412                 {
413                         string[len] = current_property[j];
414                 }
415                 
416                 if(len < MAX_LENGTH) string[len++] = '=';
417                 
418                 current_value = tag_property_values[i];
420 // property value
421                 if( len < MAX_LENGTH) string[len++] = '\"';
422 // write the value
423                 for(j = 0; current_value[j] != 0 && len < MAX_LENGTH; j++, len++)
424                 {
425                         string[len] = current_value[j];
426                 }
427                 if(len < MAX_LENGTH) string[len++] = '\"';
428         }     // next property
429         
430         if(len < MAX_LENGTH) string[len++] = right_delimiter;   // terminating bracket
431         return 0;
434 int XMLTag::read_tag(char *input, long &position, long length)
436         long tag_start;
437         int i, j, terminating_char;
439 // search for beginning of a tag
440         while(input[position] != left_delimiter && position < length) position++;
441         
442         if(position >= length) return 1;
443         
444 // find the start
445         while(position < length &&
446                 (input[position] == ' ' ||         // skip spaces
447                 input[position] == '\n' ||       // also skip new lines
448                 input[position] == left_delimiter))           // skip <
449                 position++;
451         if(position >= length) return 1;
452         
453         tag_start = position;
454         
455 // read title
456         for(i = 0; 
457                 i < MAX_TITLE && 
458                 position < length && 
459                 input[position] != '=' && 
460                 input[position] != ' ' &&       // space ends title
461                 input[position] != right_delimiter;
462                 position++, i++)
463         {
464                 tag_title[i] = input[position];
465         }
466         tag_title[i] = 0;
467         
468         if(position >= length) return 1;
469         
470         if(input[position] == '=')
471         {
472 // no title but first property
473                 tag_title[0] = 0;
474                 position = tag_start;       // rewind
475         }
477 // read properties
478         for(i = 0;
479                 i < MAX_PROPERTIES &&
480                 position < length &&
481                 input[position] != right_delimiter;
482                 i++)
483         {
484 // read a tag
485 // find the start
486                 while(position < length &&
487                         (input[position] == ' ' ||         // skip spaces
488                         input[position] == '\n' ||         // also skip new lines
489                         input[position] == left_delimiter))           // skip <
490                         position++;
492 // read the property description
493                 for(j = 0; 
494                         j < MAX_LENGTH &&
495                         position < length &&
496                         input[position] != right_delimiter &&
497                         input[position] != ' ' &&
498                         input[position] != '\n' &&      // also new line ends it
499                         input[position] != '=';
500                         j++, position++)
501                 {
502                         string[j] = input[position];
503                 }
504                 string[j] = 0;
507 // store the description in a property array
508                 tag_properties[total_properties] = new char[strlen(string) + 1];
509                 strcpy(tag_properties[total_properties], string);
511 // find the start of the value
512                 while(position < length &&
513                         (input[position] == ' ' ||         // skip spaces
514                         input[position] == '\n' ||         // also skip new lines
515                         input[position] == '='))           // skip =
516                         position++;
518 // find the terminating char
519                 if(position < length && input[position] == '\"')
520                 {
521                         terminating_char = '\"';     // use quotes to terminate
522                         if(position < length) position++;   // don't store the quote itself
523                 }
524                 else terminating_char = ' ';         // use space to terminate
526 // read until the terminating char
527                 for(j = 0;
528                         j < MAX_LENGTH &&
529                         position < length &&
530                         input[position] != right_delimiter &&
531                         input[position] != terminating_char;
532                         j++, position++)
533                 {
534                         string[j] = input[position];
535                 }
536                 string[j] = 0;
538 // store the value in a property array
539                 tag_property_values[total_properties] = new char[strlen(string) + 1];
540                 strcpy(tag_property_values[total_properties], string);
541                 
542 // advance property if one was just loaded
543                 if(tag_properties[total_properties][0] != 0) total_properties++;
545 // get the terminating char
546                 if(position < length && input[position] != right_delimiter) position++;
547         }
549 // skip the >
550         if(position < length && input[position] == right_delimiter) position++;
552         if(total_properties || tag_title[0]) return 0; else return 1;
553         return 0;
556 int XMLTag::title_is(char *title)
558         if(!strcasecmp(title, tag_title)) return 1;
559         else return 0;
562 char* XMLTag::get_title()
564         return tag_title;
567 int XMLTag::get_title(char *value)
569         if(tag_title[0] != 0) strcpy(value, tag_title);
570         return 0;
573 int XMLTag::test_property(char *property, char *value)
575         int i, result;
576         for(i = 0, result = 0; i < total_properties && !result; i++)
577         {
578                 if(!strcasecmp(tag_properties[i], property) && !strcasecmp(value, tag_property_values[i]))
579                 {
580                         return 1;
581                 }
582         }
583         return 0;
586 char* XMLTag::get_property(char *property, char *value)
588         int i, result;
589         for(i = 0, result = 0; i < total_properties && !result; i++)
590         {
591                 if(!strcasecmp(tag_properties[i], property))
592                 {
593                         strcpy(value, tag_property_values[i]);
594                         result = 1;
595                 }
596         }
597         return value;
600 char* XMLTag::get_property_text(int number)
602         if(number < total_properties) 
603                 return tag_properties[number];
604         else
605                 return "";
608 int XMLTag::get_property_int(int number)
610         if(number < total_properties) 
611                 return atol(tag_properties[number]);
612         else
613                 return 0;
616 float XMLTag::get_property_float(int number)
618         if(number < total_properties) 
619                 return atof(tag_properties[number]);
620         else
621                 return 0;
624 char* XMLTag::get_property(char *property)
626         int i, result;
627         for(i = 0, result = 0; i < total_properties && !result; i++)
628         {
629                 if(!strcasecmp(tag_properties[i], property))
630                 {
631                         return tag_property_values[i];
632                 }
633         }
634         return 0;
638 int32_t XMLTag::get_property(char *property, int32_t default_)
640         temp_string[0] = 0;
641         get_property(property, temp_string);
642         if(temp_string[0] == 0) 
643                 return default_;
644         else 
645                 return atol(temp_string);
648 int64_t XMLTag::get_property(char *property, int64_t default_)
650         int64_t result;
651         temp_string[0] = 0;
652         get_property(property, temp_string);
653         if(temp_string[0] == 0) 
654                 result = default_;
655         else 
656         {
657                 sscanf(temp_string, "%lld", &result);
658         }
659         return result;
661 // 
662 // int XMLTag::get_property(char *property, int default_)
663 // {
664 //      temp_string[0] = 0;
665 //      get_property(property, temp_string);
666 //      if(temp_string[0] == 0) return default_;
667 //      else return atol(temp_string);
668 // }
669 // 
670 float XMLTag::get_property(char *property, float default_)
672         temp_string[0] = 0;
673         get_property(property, temp_string);
674         if(temp_string[0] == 0) 
675                 return default_;
676         else 
677                 return atof(temp_string);
680 double XMLTag::get_property(char *property, double default_)
682         temp_string[0] = 0;
683         get_property(property, temp_string);
684         if(temp_string[0] == 0) 
685                 return default_;
686         else 
687                 return atof(temp_string);
690 int XMLTag::set_title(char *text)       // set the title field
692         strcpy(tag_title, text);
693         return 0;
696 int XMLTag::set_property(char *text, int32_t value)
698         sprintf(temp_string, "%ld", value);
699         set_property(text, temp_string);
700         return 0;
703 int XMLTag::set_property(char *text, int64_t value)
705         sprintf(temp_string, "%lld", value);
706         set_property(text, temp_string);
707         return 0;
710 // int XMLTag::set_property(char *text, int value)
711 // {
712 //      sprintf(temp_string, "%d", value);
713 //      set_property(text, temp_string);
714 //      return 0;
715 // }
717 int XMLTag::set_property(char *text, float value)
719         sprintf(temp_string, "%.6e", value);
720         set_property(text, temp_string);
721         return 0;
724 int XMLTag::set_property(char *text, double value)
726         sprintf(temp_string, "%.16e", value);
727         set_property(text, temp_string);
728         return 0;
731 int XMLTag::set_property(char *text, char *value)
733         tag_properties[total_properties] = new char[strlen(text) + 1];
734         strcpy(tag_properties[total_properties], text);
735         tag_property_values[total_properties] = new char[strlen(value) + 1];
736         strcpy(tag_property_values[total_properties], value);
737         total_properties++;
738         return 0;