r602: Fix baver's code... don't insert timecode when show_tc is not set
[cinelerra_cv/mob.git] / cinelerra / filexml.C
blobcd2dd6dc94b600bd0d092628ebbdc90b6da8516c
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::serialize_and_append_text(char *text)
79 // We have to encode at least the '<' char
80 // We encode three things:
81 // '<' -> '&lt;' 
82 // '>' -> '&gt;'
83 // '&' -> '&amp;'
84         char leftb[] = "&lt;";
85         char rightb[] = "&gt;";
86         char amp[] = "&amp;";
87         char *replacement;
88         int len = strlen(text);
89         int lastpos = 0;
90         for (int i = 0; i < len; i++) 
91         {
92                 switch (text[i]) {
93                         case '<': replacement = leftb; break;
94                         case '>': replacement = rightb; break;
95                         case '&': replacement = amp; break;
96                         default: replacement = 0; break;
97                 }
98                 if (replacement)
99                 {
100                         if (i - lastpos > 0)
101                                 append_text(text + lastpos, i - lastpos);
102                         append_text(replacement, strlen(replacement));
103                         lastpos = i + 1;
104                 }
105         }
106         append_text(text + lastpos, len - lastpos);
107         return 0;
110 int FileXML::append_text(char *text, long len)
112         while(position + len > available)
113         {
114                 reallocate_string(available * 2);
115         }
117         for(int i = 0; i < len; i++, position++)
118         {
119                 string[position] = text[i];
120         }
121         return 0;
124 int FileXML::reallocate_string(long new_available)
126         if(!share_string)
127         {
128                 char *new_string = new char[new_available];
129                 for(int i = 0; i < position; i++) new_string[i] = string[i];
130                 available = new_available;
131                 delete [] string;
132                 string = new_string;
133         }
134         return 0;
137 char* FileXML::read_text()
139         long text_position = position;
140         int i;
142 // use < to mark end of text and start of tag
144 // find end of text
145         for(; position < length && string[position] != left_delimiter; position++)
146         {
147                 ;
148         }
150 // allocate enough space
151         if(output_length) delete [] output;
152         output_length = position - text_position;
153         output = new char[output_length + 1];
155 //printf("FileXML::read_text %d %c\n", text_position, string[text_position]);
156         for(i = 0; text_position < position; text_position++)
157         {
158 // filter out first newline
159                 if((i > 0 && i < output_length - 1) || string[text_position] != '\n') 
160                 {
161 // check if we have to do deserializing
162 // but try to be most backward compatible possible
163                         int character = string[text_position];
164                         if (string[text_position] == '&') 
165                         {
166                                 if (text_position + 3 < length)
167                                 {
168                                         if (string[text_position + 1] == 'l' && string[text_position + 2] == 't' && string[text_position + 3] == ';')
169                                         {
170                                                 character = '<';
171                                                 text_position += 3;
172                                         }               
173                                         if (string[text_position + 1] == 'g' && string[text_position + 2] == 't' && string[text_position + 3] == ';')
174                                         {
175                                                 character = '>';
176                                                 text_position += 3;
177                                         }               
178                                 }
179                                 if (text_position + 4 < length)
180                                 {
181                                         if (string[text_position + 1] == 'a' && string[text_position + 2] == 'm' && string[text_position + 3] == 'p' && string[text_position + 4] == ';')
182                                         {
183                                                 character = '&';
184                                                 text_position += 4;
185                                         }               
186                                 }
187                         }
188                         output[i] = character;
189                         i++;
190                 }
191         }
192         output[i] = 0;
194         return output;
197 int FileXML::read_tag()
199 // scan to next tag
200         while(position < length && string[position] != left_delimiter)
201         {
202                 position++;
203         }
204         tag.reset_tag();
205         if(position >= length) return 1;
206 //printf("FileXML::read_tag %s\n", &string[position]);
207         return tag.read_tag(string, position, length);
210 int FileXML::read_text_until(char *tag_end, char *output)
212 // read to next tag
213         int out_position = 0;
214         int test_position1, test_position2;
215         int result = 0;
216         
217         while(!result && position < length)
218         {
219                 while(position < length && string[position] != left_delimiter)
220                 {
221 //printf("FileXML::read_text_until 1 %c\n", string[position]);
222                         output[out_position++] = string[position++];
223                 }
224                 
225                 if(position < length && string[position] == left_delimiter)
226                 {
227 // tag reached
228 // test for tag_end
229                         result = 1;         // assume end
230                         
231                         for(test_position1 = 0, test_position2 = position + 1;   // skip < 
232                                 test_position2 < length &&
233                                 tag_end[test_position1] != 0 &&
234                                 result; 
235                                 test_position1++, test_position2++)
236                         {
237 // null result when first wrong character is reached
238 //printf("FileXML::read_text_until 2 %c\n", string[test_position2]);
239                                 if(tag_end[test_position1] != string[test_position2]) result = 0;
240                         }
242 // no end tag reached to copy <
243                         if(!result)
244                         {
245                                 output[out_position++] = string[position++];
246                         }
247                 }
248         }
249         output[out_position] = 0;
250 // if end tag is reached, position is left on the < of the end tag
251         return 0;
255 int FileXML::write_to_file(char *filename)
257         FILE *out;
258         strcpy(this->filename, filename);
259         if(out = fopen(filename, "wb"))
260         {
261                 fprintf(out, "<?xml version=\"1.0\"?>\n");
262 // Position may have been rewound after storing so we use a strlen
263                 if(!fwrite(string, strlen(string), 1, out) && strlen(string))
264                 {
265                         fprintf(stderr, "FileXML::write_to_file 1 \"%s\": %s\n",
266                                 filename,
267                                 strerror(errno));
268                         fclose(out);
269                         return 1;
270                 }
271                 else
272                 {
273                 }
274         }
275         else
276         {
277                 fprintf(stderr, "FileXML::write_to_file 2 \"%s\": %s\n",
278                         filename,
279                         strerror(errno));
280                 return 1;
281         }
282         fclose(out);
283         return 0;
286 int FileXML::write_to_file(FILE *file)
288         strcpy(filename, "");
289         fprintf(file, "<?xml version=\"1.0\"?>\n");
290 // Position may have been rewound after storing
291         if(fwrite(string, strlen(string), 1, file) || !strlen(string))
292         {
293                 return 0;
294         }
295         else
296         {
297                 fprintf(stderr, "FileXML::write_to_file \"%s\": %s\n",
298                         filename,
299                         strerror(errno));
300                 return 1;
301         }
302         return 0;
305 int FileXML::read_from_file(char *filename, int ignore_error)
307         FILE *in;
308         
309         strcpy(this->filename, filename);
310         if(in = fopen(filename, "rb"))
311         {
312                 fseek(in, 0, SEEK_END);
313                 length = ftell(in);
314                 fseek(in, 0, SEEK_SET);
315                 reallocate_string(length + 1);
316                 fread(string, length, 1, in);
317                 string[length] = 0;
318                 position = 0;
319         }
320         else
321         {
322                 if(!ignore_error) 
323                         fprintf(stderr, "FileXML::read_from_file \"%s\" %s\n",
324                                 filename,
325                                 strerror(errno));
326                 return 1;
327         }
328         fclose(in);
329         return 0;
332 int FileXML::read_from_string(char *string)
334         strcpy(this->filename, "");
335         reallocate_string(strlen(string) + 1);
336         strcpy(this->string, string);
337         length = strlen(string);
338         position = 0;
339         return 0;
342 int FileXML::set_shared_string(char *shared_string, long available)
344         strcpy(this->filename, "");
345         if(!share_string)
346         {
347                 delete [] string;
348                 share_string = 1;
349                 string = shared_string;
350                 this->available = available;
351                 length = available;
352                 position = 0;
353         }
354         return 0;
359 // ================================ XML tag
362 XMLTag::XMLTag()
364         total_properties = 0;
365         len = 0;
368 XMLTag::~XMLTag()
370         reset_tag();
373 int XMLTag::set_delimiters(char left_delimiter, char right_delimiter)
375         this->left_delimiter = left_delimiter;
376         this->right_delimiter = right_delimiter;
377         return 0;
380 int XMLTag::reset_tag()     // clear all structures
382         len = 0;
383         for(int i = 0; i < total_properties; i++) delete [] tag_properties[i];
384         for(int i = 0; i < total_properties; i++) delete [] tag_property_values[i];
385         total_properties = 0;
386         return 0;
389 int XMLTag::write_tag()
391         int i, j;
392         char *current_property, *current_value;
394 // opening bracket
395         string[len] = left_delimiter;        
396         len++;
397         
398 // title
399         for(i = 0; tag_title[i] != 0 && len < MAX_LENGTH; i++, len++) string[len] = tag_title[i];
401 // properties
402         for(i = 0; i < total_properties && len < MAX_LENGTH; i++)
403         {
404                 string[len++] = ' ';         // add a space before every property
405                 
406                 current_property = tag_properties[i];
408 // property title
409                 for(j = 0; current_property[j] != 0 && len < MAX_LENGTH; j++, len++)
410                 {
411                         string[len] = current_property[j];
412                 }
413                 
414                 if(len < MAX_LENGTH) string[len++] = '=';
415                 
416                 current_value = tag_property_values[i];
418 // property value
419                 if( len < MAX_LENGTH) string[len++] = '\"';
420 // write the value
421                 for(j = 0; current_value[j] != 0 && len < MAX_LENGTH; j++, len++)
422                 {
423                         string[len] = current_value[j];
424                 }
425                 if(len < MAX_LENGTH) string[len++] = '\"';
426         }     // next property
427         
428         if(len < MAX_LENGTH) string[len++] = right_delimiter;   // terminating bracket
429         return 0;
432 int XMLTag::read_tag(char *input, long &position, long length)
434         long tag_start;
435         int i, j, terminating_char;
437 // search for beginning of a tag
438         while(input[position] != left_delimiter && position < length) position++;
439         
440         if(position >= length) return 1;
441         
442 // find the start
443         while(position < length &&
444                 (input[position] == ' ' ||         // skip spaces
445                 input[position] == '\n' ||       // also skip new lines
446                 input[position] == left_delimiter))           // skip <
447                 position++;
449         if(position >= length) return 1;
450         
451         tag_start = position;
452         
453 // read title
454         for(i = 0; 
455                 i < MAX_TITLE && 
456                 position < length && 
457                 input[position] != '=' && 
458                 input[position] != ' ' &&       // space ends title
459                 input[position] != right_delimiter;
460                 position++, i++)
461         {
462                 tag_title[i] = input[position];
463         }
464         tag_title[i] = 0;
465         
466         if(position >= length) return 1;
467         
468         if(input[position] == '=')
469         {
470 // no title but first property
471                 tag_title[0] = 0;
472                 position = tag_start;       // rewind
473         }
475 // read properties
476         for(i = 0;
477                 i < MAX_PROPERTIES &&
478                 position < length &&
479                 input[position] != right_delimiter;
480                 i++)
481         {
482 // read a tag
483 // find the start
484                 while(position < length &&
485                         (input[position] == ' ' ||         // skip spaces
486                         input[position] == '\n' ||         // also skip new lines
487                         input[position] == left_delimiter))           // skip <
488                         position++;
490 // read the property description
491                 for(j = 0; 
492                         j < MAX_LENGTH &&
493                         position < length &&
494                         input[position] != right_delimiter &&
495                         input[position] != ' ' &&
496                         input[position] != '\n' &&      // also new line ends it
497                         input[position] != '=';
498                         j++, position++)
499                 {
500                         string[j] = input[position];
501                 }
502                 string[j] = 0;
505 // store the description in a property array
506                 tag_properties[total_properties] = new char[strlen(string) + 1];
507                 strcpy(tag_properties[total_properties], string);
509 // find the start of the value
510                 while(position < length &&
511                         (input[position] == ' ' ||         // skip spaces
512                         input[position] == '\n' ||         // also skip new lines
513                         input[position] == '='))           // skip =
514                         position++;
516 // find the terminating char
517                 if(position < length && input[position] == '\"')
518                 {
519                         terminating_char = '\"';     // use quotes to terminate
520                         if(position < length) position++;   // don't store the quote itself
521                 }
522                 else terminating_char = ' ';         // use space to terminate
524 // read until the terminating char
525                 for(j = 0;
526                         j < MAX_LENGTH &&
527                         position < length &&
528                         input[position] != right_delimiter &&
529                         input[position] != terminating_char;
530                         j++, position++)
531                 {
532                         string[j] = input[position];
533                 }
534                 string[j] = 0;
536 // store the value in a property array
537                 tag_property_values[total_properties] = new char[strlen(string) + 1];
538                 strcpy(tag_property_values[total_properties], string);
539                 
540 // advance property if one was just loaded
541                 if(tag_properties[total_properties][0] != 0) total_properties++;
543 // get the terminating char
544                 if(position < length && input[position] != right_delimiter) position++;
545         }
547 // skip the >
548         if(position < length && input[position] == right_delimiter) position++;
550         if(total_properties || tag_title[0]) return 0; else return 1;
551         return 0;
554 int XMLTag::title_is(char *title)
556         if(!strcasecmp(title, tag_title)) return 1;
557         else return 0;
560 char* XMLTag::get_title()
562         return tag_title;
565 int XMLTag::get_title(char *value)
567         if(tag_title[0] != 0) strcpy(value, tag_title);
568         return 0;
571 int XMLTag::test_property(char *property, char *value)
573         int i, result;
574         for(i = 0, result = 0; i < total_properties && !result; i++)
575         {
576                 if(!strcasecmp(tag_properties[i], property) && !strcasecmp(value, tag_property_values[i]))
577                 {
578                         return 1;
579                 }
580         }
581         return 0;
584 char* XMLTag::get_property(char *property, char *value)
586         int i, result;
587         for(i = 0, result = 0; i < total_properties && !result; i++)
588         {
589                 if(!strcasecmp(tag_properties[i], property))
590                 {
591                         strcpy(value, tag_property_values[i]);
592                         result = 1;
593                 }
594         }
595         return value;
598 char* XMLTag::get_property_text(int number)
600         if(number < total_properties) 
601                 return tag_properties[number];
602         else
603                 return "";
606 int XMLTag::get_property_int(int number)
608         if(number < total_properties) 
609                 return atol(tag_properties[number]);
610         else
611                 return 0;
614 float XMLTag::get_property_float(int number)
616         if(number < total_properties) 
617                 return atof(tag_properties[number]);
618         else
619                 return 0;
622 char* XMLTag::get_property(char *property)
624         int i, result;
625         for(i = 0, result = 0; i < total_properties && !result; i++)
626         {
627                 if(!strcasecmp(tag_properties[i], property))
628                 {
629                         return tag_property_values[i];
630                 }
631         }
632         return 0;
636 int32_t XMLTag::get_property(char *property, int32_t default_)
638         temp_string[0] = 0;
639         get_property(property, temp_string);
640         if(temp_string[0] == 0) 
641                 return default_;
642         else 
643                 return atol(temp_string);
646 int64_t XMLTag::get_property(char *property, int64_t default_)
648         int64_t result;
649         temp_string[0] = 0;
650         get_property(property, temp_string);
651         if(temp_string[0] == 0) 
652                 result = default_;
653         else 
654         {
655                 sscanf(temp_string, "%lld", &result);
656         }
657         return result;
659 // 
660 // int XMLTag::get_property(char *property, int default_)
661 // {
662 //      temp_string[0] = 0;
663 //      get_property(property, temp_string);
664 //      if(temp_string[0] == 0) return default_;
665 //      else return atol(temp_string);
666 // }
667 // 
668 float XMLTag::get_property(char *property, float default_)
670         temp_string[0] = 0;
671         get_property(property, temp_string);
672         if(temp_string[0] == 0) 
673                 return default_;
674         else 
675                 return atof(temp_string);
678 double XMLTag::get_property(char *property, double default_)
680         temp_string[0] = 0;
681         get_property(property, temp_string);
682         if(temp_string[0] == 0) 
683                 return default_;
684         else 
685                 return atof(temp_string);
688 int XMLTag::set_title(char *text)       // set the title field
690         strcpy(tag_title, text);
691         return 0;
694 int XMLTag::set_property(char *text, int32_t value)
696         sprintf(temp_string, "%ld", value);
697         set_property(text, temp_string);
698         return 0;
701 int XMLTag::set_property(char *text, int64_t value)
703         sprintf(temp_string, "%lld", value);
704         set_property(text, temp_string);
705         return 0;
708 // int XMLTag::set_property(char *text, int value)
709 // {
710 //      sprintf(temp_string, "%d", value);
711 //      set_property(text, temp_string);
712 //      return 0;
713 // }
715 int XMLTag::set_property(char *text, float value)
717         sprintf(temp_string, "%.6e", value);
718         set_property(text, temp_string);
719         return 0;
722 int XMLTag::set_property(char *text, double value)
724         sprintf(temp_string, "%.16e", value);
725         set_property(text, temp_string);
726         return 0;
729 int XMLTag::set_property(char *text, char *value)
731         tag_properties[total_properties] = new char[strlen(text) + 1];
732         strcpy(tag_properties[total_properties], text);
733         tag_property_values[total_properties] = new char[strlen(value) + 1];
734         strcpy(tag_property_values[total_properties], value);
735         total_properties++;
736         return 0;