1 /*******************************************************************************
2  lqt_codecfile.c
3 
4  libquicktime - A library for reading and writing quicktime/avi/mp4 files.
5  http://libquicktime.sourceforge.net
6 
7  Copyright (C) 2002 Heroine Virtual Ltd.
8  Copyright (C) 2002-2011 Members of the libquicktime project.
9 
10  Modified by Napoleon E. Cornejo
11  May 4, 2007, San Salvador, El Salvador
12  - Validated user home directory in create_filename()
13 
14  This library is free software; you can redistribute it and/or modify it under
15  the terms of the GNU Lesser General Public License as published by the Free
16  Software Foundation; either version 2.1 of the License, or (at your option)
17  any later version.
18 
19  This library is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
21  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
22  details.
23 
24  You should have received a copy of the GNU Lesser General Public License along
25  with this library; if not, write to the Free Software Foundation, Inc., 51
26  Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 *******************************************************************************/
28 
29 /*
30  *   Codec file handling
31  */
32 
33 #include "lqt_private.h"
34 #include "lqt_codecinfo_private.h"
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <limits.h>
40 
41 #define LOG_DOMAIN "codecfile"
42 
43 /*
44  *  The keywords are defined globaly, so they are automatically
45  *  the same in reading and writing functions
46  */
47 
48 static const char * begin_codec_key     = "BeginCodec: ";
49 static const char * end_codec_key       = "EndCodec";
50 
51 /*
52  *  Start string for parameter definition:
53  *  These 2 strings (for en- and decoding MUST have the same length)
54  */
55 
56 static const char * begin_parameter_e_key = "BeginParameterE: ";
57 static const char * begin_parameter_d_key = "BeginParameterD: ";
58 
59 static const char * end_parameter_key   = "EndParameter";
60 
61 static const char * long_name_key       = "LongName: ";
62 static const char * description_key     = "Description: ";
63 
64 static const char * type_key            = "Type: ";
65 
66 /* Types for codecs */
67 
68 static const char * type_audio          = "Audio";
69 static const char * type_video          = "Video";
70 
71 
72 /* Codec direction */
73 
74 static const char * direction_key       = "Direction: ";
75 static const char * direction_encode    = "Encode";
76 static const char * direction_decode    = "Decode";
77 static const char * direction_both      = "Both";
78 
79 static const char * num_fourccs_key     = "NumFourccs: ";
80 static const char * fourccs_key         = "Fourccs: ";
81 
82 static const char * num_wav_ids_key     = "NumWavIds: ";
83 static const char * wav_ids_key         = "WavIds: ";
84 
85 static const char * compatibility_key   = "Compatibility: ";
86 static const char * compression_id_key  = "CompressionID: ";
87 
88 /* Module filename and module index */
89 
90 static const char * module_filename_key  = "ModuleFilename: ";
91 static const char * module_index_key     = "ModuleIndex: ";
92 static const char * module_file_time_key = "FileTime: ";
93 
94 static const char * gettext_domain_key  = "GettextDomain";
95 static const char * gettext_directory_key  = "GettextDirectory";
96 
97 
98 /* Types for parameters */
99 
100 static const char * type_int            = "Integer";
101 static const char * type_float          = "Float";
102 static const char * type_string         = "String";
103 static const char * type_stringlist     = "Stringlist";
104 static const char * type_section        = "Section";
105 
106 static const char * help_string_key     = "HelpString: ";
107 static const char * num_digits_key      = "NumDigits";
108 
109 
110 static const char * num_encoding_parameters_key  = "NumEncodingParameters: ";
111 static const char * num_decoding_parameters_key  = "NumDecodingParameters: ";
112 
113 static const char * value_key           = "Value: ";
114 static const char * min_value_key       = "ValueMin: ";
115 static const char * max_value_key       = "ValueMax: ";
116 
117 static const char * real_name_key       = "RealName: ";
118 
119 static const char * num_options_key     = "NumOptions: ";
120 static const char * option_key          = "Options: ";
121 static const char * label_key           = "OptionLabels: ";
122 
123  /* Encoding colormodels */
124 
125 static const char *
126 num_encoding_colormodels_key = "NumEncodingColormodels: ";
127 
128 static const char *
129 encoding_colormodel_key =      "EncodingColormodel: ";
130 
131 static const char *
132 num_image_sizes_key = "NumImageSizes: ";
133 
134 static const char *
135 image_size_key =      "ImageSize: ";
136 
137 /* Codec order */
138 
139 static const char * audio_order_key = "AudioOrder: ";
140 static const char * video_order_key = "VideoOrder: ";
141 
142 #define READ_BUFFER_SIZE 2048
143 
144 #define CHECK_KEYWORD(key) (!strncmp(line, key, strlen(key)))
145 
create_filename()146 static char * create_filename()
147   {
148   char * filename_buffer;
149   /* Obtain the home directory */
150 
151   char * fdir;
152 
153   /* First look for a system-wide codec file if available.  If not
154      look into users home */
155 
156   fdir = getenv("LQT_CODEC_FILE");
157   if (fdir == NULL ) {
158 
159     lqt_log(NULL, LQT_LOG_DEBUG, LOG_DOMAIN,
160                     "no system-wide codec file. Looking in user's home.");
161 
162     fdir = getenv("HOME");
163     if(!fdir)
164       return NULL;
165     filename_buffer = malloc(strlen(fdir) + 22);
166     strcpy(filename_buffer, fdir);
167     strcat(filename_buffer, "/.libquicktime_codecs");
168 
169   } else
170      {
171      filename_buffer = malloc(strlen(fdir) + 1);
172      strcpy(filename_buffer, fdir);
173      }
174   return filename_buffer;
175 
176 }
177 
__lqt_strdup(const char * string)178 static char * __lqt_strdup(const char * string)
179   {
180   char * ret = malloc(strlen(string)+1);
181   strcpy(ret, string);
182   return ret;
183   }
184 
read_parameter_value(char * pos,lqt_parameter_value_t * ret,lqt_parameter_type_t type)185 static void read_parameter_value(char * pos,
186                                  lqt_parameter_value_t * ret,
187                                  lqt_parameter_type_t type)
188   {
189   switch(type)
190     {
191     case LQT_PARAMETER_INT:
192       ret->val_int = atoi(pos);
193       break;
194     case LQT_PARAMETER_FLOAT:
195       ret->val_float = strtod(pos, (char**)0);
196       break;
197     case LQT_PARAMETER_STRING:
198     case LQT_PARAMETER_STRINGLIST:
199       ret->val_string = __lqt_strdup(pos);
200       break;
201     case LQT_PARAMETER_SECTION:
202       break;
203     }
204   }
205 
convert_help_string(char * str)206 static char * convert_help_string(char * str)
207   {
208   char * ret;
209   char * src_pos, *dst_pos;
210 
211   ret = malloc(strlen(str)+1);
212 
213   src_pos = str;
214   dst_pos = ret;
215 
216   while(*src_pos != '\0')
217     {
218     if((src_pos[0] == '\\') && (src_pos[1] == 'n'))
219       {
220       *dst_pos = '\n';
221       src_pos += 2;
222       dst_pos++;
223       }
224     else
225       {
226       *dst_pos = *src_pos;
227       src_pos++;
228       dst_pos++;
229       }
230     }
231   *dst_pos = '\0';
232   free(str);
233   return ret;
234   }
235 
read_parameter_info(FILE * input,lqt_parameter_info_t * info,char * line)236 static void read_parameter_info(FILE * input,
237                                 lqt_parameter_info_t * info,
238                                 char * line)
239   {
240   char * pos;
241   int options_read = 0;
242   int labels_read = 0;
243 
244   /* First, get the name */
245 
246   pos = line + strlen(begin_parameter_e_key);
247   info->name = __lqt_strdup(pos);
248 
249   while(1)
250     {
251     fgets(line, READ_BUFFER_SIZE-1, input);
252     if(feof(input))
253       break;
254     pos = strchr(line, '\n');
255     if(pos)
256       *pos = '\0';
257 
258     /* Now, go through the syntax */
259 
260     if(CHECK_KEYWORD(type_key))
261       {
262       pos = line + strlen(type_key);
263 
264       if(!strcmp(pos, type_int))
265         {
266         info->type = LQT_PARAMETER_INT;
267 
268         /*
269          *  We set them here for the case, they are not set after
270          *  (which can happen for min and max)
271          */
272 
273         info->val_default.val_int = 0;
274         info->val_min.val_int = 0;
275         info->val_max.val_int = 0;
276         }
277       if(!strcmp(pos, type_float))
278         {
279         info->type = LQT_PARAMETER_FLOAT;
280 
281         /*
282          *  We set them here for the case, they are not set after
283          *  (which can happen for min and max)
284          */
285 
286         info->val_default.val_float = 0;
287         info->val_min.val_float = 0;
288         info->val_max.val_float = 0;
289         info->num_digits = 1;
290         }
291 
292       /*
293        *  Important: type_stringlist must be checked
294        *  BEFORE type_string
295        */
296 
297       else if(!strcmp(pos, type_stringlist))
298         {
299         info->type = LQT_PARAMETER_STRINGLIST;
300         info->val_default.val_string = (char*)0;
301         }
302       else if(!strcmp(pos, type_string))
303         {
304         info->type = LQT_PARAMETER_STRING;
305         info->val_default.val_string = (char*)0;
306         }
307       else if(!strcmp(pos, type_section))
308         {
309         info->type = LQT_PARAMETER_SECTION;
310         info->val_default.val_string = (char*)0;
311         }
312       }
313     else if(CHECK_KEYWORD(real_name_key))
314       {
315       pos = line + strlen(real_name_key);
316       info->real_name = __lqt_strdup(pos);
317       }
318 
319     else if(CHECK_KEYWORD(value_key))
320       {
321       pos = line + strlen(value_key);
322       read_parameter_value(pos, &info->val_default, info->type);
323       }
324 
325     else if(CHECK_KEYWORD(min_value_key))
326       {
327       pos = line + strlen(min_value_key);
328       if(info->type == LQT_PARAMETER_INT)
329         info->val_min.val_int = atoi(pos);
330       else if(info->type == LQT_PARAMETER_FLOAT)
331         info->val_min.val_float = strtod(pos, (char**)0);
332       }
333 
334     else if(CHECK_KEYWORD(max_value_key))
335       {
336       pos = line + strlen(max_value_key);
337       if(info->type == LQT_PARAMETER_INT)
338         info->val_max.val_int = atoi(pos);
339       else if(info->type == LQT_PARAMETER_FLOAT)
340         info->val_max.val_float = strtod(pos, (char**)0);
341       }
342     else if(CHECK_KEYWORD(num_options_key))
343       {
344       pos = line + strlen(num_options_key);
345       info->num_stringlist_options = atoi(pos);
346       info->stringlist_options = calloc(info->num_stringlist_options,
347                                         sizeof(char*));
348       info->stringlist_labels = calloc(info->num_stringlist_options,
349                                        sizeof(char*));
350       }
351     else if(CHECK_KEYWORD(option_key))
352       {
353       pos = line + strlen(option_key);
354       info->stringlist_options[options_read] = __lqt_strdup(pos);
355       options_read++;
356       }
357     else if(CHECK_KEYWORD(label_key))
358       {
359       pos = line + strlen(label_key);
360       info->stringlist_labels[labels_read] = __lqt_strdup(pos);
361       labels_read++;
362       }
363     else if(CHECK_KEYWORD(help_string_key))
364       {
365       pos = line + strlen(help_string_key);
366       info->help_string = __lqt_strdup(pos);
367       info->help_string = convert_help_string(info->help_string);
368       }
369     else if(CHECK_KEYWORD(num_digits_key))
370       {
371       pos = line + strlen(num_digits_key);
372       info->num_digits = atoi(pos);
373       }
374     else if(CHECK_KEYWORD(end_parameter_key))
375       break;
376     }
377   }
378 
read_codec_info(FILE * input,lqt_codec_info_t * codec,char * line)379 static void read_codec_info(FILE * input, lqt_codec_info_t * codec,
380                             char * line)
381   {
382   char * pos, *rest;
383   int i;
384 
385   int encoding_parameters_read = 0;
386   int decoding_parameters_read = 0;
387   int encoding_colormodels_read = 0;
388   int image_sizes_read = 0;
389 
390   uint32_t tmp_fourcc;
391 
392   /* First, get the name */
393 
394   pos = line + strlen(begin_codec_key);
395   codec->name = __lqt_strdup(pos);
396 
397   while(1)
398     {
399     fgets(line, READ_BUFFER_SIZE-1, input);
400     if(feof(input))
401       break;
402     pos = strchr(line, '\n');
403     if(pos)
404       *pos = '\0';
405 
406     /* Long name */
407 
408     if(CHECK_KEYWORD(long_name_key))
409       {
410       pos = line + strlen(long_name_key);
411       codec->long_name = __lqt_strdup(pos);
412       }
413 
414     /* Description */
415 
416     else if(CHECK_KEYWORD(description_key))
417       {
418       pos = line + strlen(description_key);
419       codec->description = __lqt_strdup(pos);
420       }
421 
422     /* Type */
423 
424     else if(CHECK_KEYWORD(type_key))
425       {
426       pos = line + strlen(type_key);
427       if(!strcmp(pos, type_audio))
428         codec->type = LQT_CODEC_AUDIO;
429       else if(!strcmp(pos, type_video))
430         codec->type = LQT_CODEC_VIDEO;
431       }
432 
433     /* Compression ID */
434 
435     else if(CHECK_KEYWORD(compression_id_key))
436       {
437       pos = line + strlen(compression_id_key);
438       codec->compression_id =
439         lqt_compression_id_from_string(pos);
440       }
441 
442     /* Direction */
443 
444     else if(CHECK_KEYWORD(direction_key))
445       {
446       pos = line + strlen(direction_key);
447       if(!strcmp(pos, direction_encode))
448         codec->direction = LQT_DIRECTION_ENCODE;
449       else if(!strcmp(pos, direction_decode))
450         codec->direction = LQT_DIRECTION_DECODE;
451       else if(!strcmp(pos, direction_both))
452         codec->direction = LQT_DIRECTION_BOTH;
453       }
454 
455     /* Compatibility flags */
456     else if(CHECK_KEYWORD(compatibility_key))
457       {
458       pos = line + strlen(compatibility_key);
459       codec->compatibility_flags = strtoul(pos, (char**)0, 16);
460       }
461 
462     /* Module filename */
463 
464     else if(CHECK_KEYWORD(module_filename_key))
465       {
466       pos = line + strlen(module_filename_key);
467       codec->module_filename = __lqt_strdup(pos);
468       }
469 
470     /* Gettext domain */
471 
472     else if(CHECK_KEYWORD(gettext_domain_key))
473       {
474       pos = line + strlen(gettext_domain_key);
475       codec->gettext_domain = __lqt_strdup(pos);
476       }
477 
478     /* Gettext directory */
479 
480     else if(CHECK_KEYWORD(gettext_directory_key))
481       {
482       pos = line + strlen(gettext_directory_key);
483       codec->gettext_directory = __lqt_strdup(pos);
484       }
485 
486     /* Module Index */
487 
488     else if(CHECK_KEYWORD(module_index_key))
489       {
490       pos = line + strlen(module_index_key);
491       codec->module_index = atoi(pos);
492       }
493 
494     /* File modification time */
495 
496     else if(CHECK_KEYWORD(module_file_time_key))
497       {
498       pos = line + strlen(module_file_time_key);
499       codec->file_time = strtoul(pos, (char**)0, 10);
500       }
501 
502     /* Number of Fourccs */
503 
504     else if(CHECK_KEYWORD(num_fourccs_key))
505       {
506       pos = line + strlen(num_fourccs_key);
507       codec->num_fourccs = atoi(pos);
508 
509       /* We allocate memory here */
510       if(codec->num_fourccs)
511         {
512         codec->fourccs = malloc(codec->num_fourccs * sizeof(char*));
513         for(i = 0; i < codec->num_fourccs; i++)
514           codec->fourccs[i] = malloc(5 * sizeof(char));
515         }
516       }
517 
518     /* Fourccs */
519 
520     else if(CHECK_KEYWORD(fourccs_key))
521       {
522       pos = line + strlen(fourccs_key);
523       for(i = 0; i < codec->num_fourccs; i++)
524         {
525         tmp_fourcc = strtoul(pos, &rest, 16);
526         LQT_FOURCC_2_STRING(codec->fourccs[i], tmp_fourcc);
527         if(rest == pos)
528           break;
529         pos = rest;
530         }
531       }
532 
533     /* Number of wav ids */
534 
535     else if(CHECK_KEYWORD(num_wav_ids_key))
536       {
537       pos = line + strlen(num_wav_ids_key);
538       codec->num_wav_ids = atoi(pos);
539 
540       /* We allocate memory here */
541 
542       codec->wav_ids = malloc(codec->num_wav_ids * sizeof(int));
543       }
544 
545     /* Wav ids */
546 
547     else if(CHECK_KEYWORD(wav_ids_key))
548       {
549       pos = line + strlen(wav_ids_key);
550       for(i = 0; i < codec->num_wav_ids; i++)
551         {
552         codec->wav_ids[i] = strtoul(pos, &rest, 16);
553         pos = rest;
554         }
555       }
556 
557     /* Number of encoding colormodels */
558 
559     else if(CHECK_KEYWORD(num_encoding_colormodels_key))
560       {
561       pos = line + strlen(num_encoding_colormodels_key);
562       codec->num_encoding_colormodels = atoi(pos);
563       if(codec->num_encoding_colormodels)
564         {
565         codec->encoding_colormodels =
566           malloc((codec->num_encoding_colormodels+1) *
567                  sizeof(*codec->encoding_colormodels));
568         /* terminate */
569         codec->encoding_colormodels[codec->num_encoding_colormodels] =
570           LQT_COLORMODEL_NONE;
571         }
572       else
573         codec->encoding_colormodels = (int*)0;
574       }
575 
576     /* Encoding colormodels */
577 
578     else if(CHECK_KEYWORD(encoding_colormodel_key))
579       {
580       pos = line + strlen(encoding_colormodel_key);
581       codec->encoding_colormodels[encoding_colormodels_read] =
582         lqt_string_to_colormodel(pos);
583       encoding_colormodels_read++;
584       }
585 
586     /* Number of image sizes */
587 
588     else if(CHECK_KEYWORD(num_image_sizes_key))
589       {
590       pos = line + strlen(num_image_sizes_key);
591       codec->num_image_sizes = atoi(pos);
592       if(codec->num_image_sizes)
593         codec->image_sizes =
594           malloc(codec->num_image_sizes *
595                  sizeof(*codec->image_sizes));
596       else
597         codec->image_sizes = NULL;
598       }
599 
600     /* Image size */
601 
602     else if(CHECK_KEYWORD(image_size_key))
603       {
604       pos = line + strlen(image_size_key);
605 
606       sscanf(pos, "%d %d", &codec->image_sizes[image_sizes_read].width,
607              &codec->image_sizes[image_sizes_read].height);
608       image_sizes_read++;
609       }
610 
611     /* Number of parameters */
612 
613     else if(CHECK_KEYWORD(num_encoding_parameters_key))
614       {
615       pos = line + strlen(num_encoding_parameters_key);
616       codec->num_encoding_parameters = atoi(pos);
617       if(codec->num_encoding_parameters)
618         codec->encoding_parameters =
619           calloc(codec->num_encoding_parameters,
620                  sizeof(lqt_parameter_info_t));
621       else
622         codec->encoding_parameters =
623           (lqt_parameter_info_t*)0;
624       }
625     else if(CHECK_KEYWORD(num_decoding_parameters_key))
626       {
627       pos = line + strlen(num_decoding_parameters_key);
628       codec->num_decoding_parameters = atoi(pos);
629       if(codec->num_decoding_parameters)
630         codec->decoding_parameters =
631           calloc(codec->num_decoding_parameters,
632                  sizeof(lqt_parameter_info_t));
633       else
634         codec->decoding_parameters =
635           (lqt_parameter_info_t*)0;
636 
637       }
638 
639     /* Read parameters */
640 
641     else if(CHECK_KEYWORD(begin_parameter_e_key))
642       {
643       read_parameter_info(input,
644                           &codec->encoding_parameters[encoding_parameters_read],
645                           line);
646       encoding_parameters_read++;
647       }
648 
649     else if(CHECK_KEYWORD(begin_parameter_d_key))
650       {
651       read_parameter_info(input,
652                      &codec->decoding_parameters[decoding_parameters_read],
653                      line);
654       decoding_parameters_read++;
655       }
656     else if(CHECK_KEYWORD(end_codec_key))
657       break;
658     }
659 
660   }
661 
662 
lqt_registry_read(char ** audio_order,char ** video_order)663 lqt_codec_info_t * lqt_registry_read(char ** audio_order, char ** video_order)
664   {
665   FILE * input;
666   char * line;
667   char * pos = (char*)0;
668   char * filename_buffer = create_filename();
669   lqt_codec_info_t * ret =     (lqt_codec_info_t *)0;
670   lqt_codec_info_t * ret_end = (lqt_codec_info_t *)0;
671 
672   if(!filename_buffer || (*filename_buffer == '\0'))
673     return NULL;
674 
675   input = fopen(filename_buffer, "r");
676 
677   if(!input)
678     {
679     free(filename_buffer);
680     return (lqt_codec_info_t*)0;
681     }
682 
683   line = malloc(READ_BUFFER_SIZE);
684 
685   while(1)
686     {
687     fgets(line, READ_BUFFER_SIZE-1, input);
688     if(feof(input))
689       break;
690     pos = strchr(line, '\n');
691     if(pos)
692       *pos = '\0';
693 
694     pos = line;
695 
696     /* Skip comment lines */
697 
698     if(*pos == '#')
699       continue;
700 
701     else if(CHECK_KEYWORD(audio_order_key))
702       {
703       if(audio_order)
704         {
705         pos += strlen(audio_order_key);
706         *audio_order = __lqt_strdup(pos);
707         }
708       continue;
709       }
710     else if(CHECK_KEYWORD(video_order_key))
711       {
712       if(video_order)
713         {
714         pos += strlen(video_order_key);
715         *video_order = __lqt_strdup(pos);
716         }
717       continue;
718       }
719 
720     else if(CHECK_KEYWORD(begin_codec_key))
721       {
722       if(!ret_end)
723         {
724         ret = calloc(1, sizeof(lqt_codec_info_t));
725         ret_end = ret;
726         }
727       else
728         {
729         ret_end->next = calloc(1, sizeof(lqt_codec_info_t));
730         ret_end = ret_end->next;
731         }
732       read_codec_info(input, ret_end, pos);
733 
734       ret_end->next = (lqt_codec_info_t*)0;
735       }
736     }
737 
738 
739   fclose(input);
740   free(filename_buffer);
741   free(line);
742   return ret;
743   }
744 
write_help_string(FILE * output,char * help_string)745 static void write_help_string(FILE * output, char * help_string)
746   {
747   int i, imax;
748   fprintf(output, "%s", help_string_key);
749 
750   imax = strlen(help_string);
751   for(i = 0; i < imax; i++)
752     {
753     if(help_string[i] == '\n')
754       fprintf(output, "\\n");
755     else
756       fprintf(output, "%c", help_string[i]);
757     }
758   fprintf(output, "\n");
759   }
760 
write_parameter_info(FILE * output,const lqt_parameter_info_t * info,int encode)761 static void write_parameter_info(FILE * output,
762                                  const lqt_parameter_info_t * info,
763                                  int encode)
764   {
765   const char * tmp = (const char*)0;
766   int i;
767 
768   fprintf(output, "%s%s\n",
769           (encode ? begin_parameter_e_key : begin_parameter_d_key),
770           info->name);
771   fprintf(output, "%s%s\n", real_name_key, info->real_name);
772   switch(info->type)
773     {
774     case LQT_PARAMETER_INT:
775       tmp = type_int;
776       break;
777     case LQT_PARAMETER_FLOAT:
778       tmp = type_float;
779       break;
780     case LQT_PARAMETER_STRING:
781       tmp = type_string;
782       break;
783     case LQT_PARAMETER_STRINGLIST:
784       tmp = type_stringlist;
785       break;
786     case LQT_PARAMETER_SECTION:
787       tmp = type_section;
788       break;
789     }
790 
791   fprintf(output, "%s%s\n", type_key, tmp);
792 
793   /*
794    *   Print the value
795    */
796 
797   switch(info->type)
798     {
799     case LQT_PARAMETER_INT:
800       fprintf(output, "%s%d\n", value_key, info->val_default.val_int);
801 
802       if(info->val_min.val_int < info->val_max.val_int)
803         {
804         fprintf(output, "%s%d\n", min_value_key, info->val_min.val_int);
805         fprintf(output, "%s%d\n", max_value_key, info->val_max.val_int);
806         }
807 
808       break;
809     case LQT_PARAMETER_FLOAT:
810       fprintf(output, "%s%f\n", value_key, info->val_default.val_float);
811 
812       if(info->val_min.val_float < info->val_max.val_float)
813         {
814         fprintf(output, "%s%f\n", min_value_key, info->val_min.val_float);
815         fprintf(output, "%s%f\n", max_value_key, info->val_max.val_float);
816         }
817       fprintf(output, "%s%d\n", num_digits_key, info->num_digits);
818       break;
819     case LQT_PARAMETER_STRING:
820       fprintf(output, "%s%s\n", value_key, info->val_default.val_string);
821       break;
822     case LQT_PARAMETER_STRINGLIST:
823       fprintf(output, "%s%s\n", value_key, info->val_default.val_string);
824 
825       /*
826        *  Print options
827        */
828       fprintf(output, "%s%d\n", num_options_key, info->num_stringlist_options);
829 
830       for(i = 0; i < info->num_stringlist_options; i++)
831         fprintf(output, "%s%s\n", option_key, info->stringlist_options[i]);
832       for(i = 0; i < info->num_stringlist_options; i++)
833         fprintf(output, "%s%s\n", label_key, info->stringlist_labels[i]);
834       break;
835     case LQT_PARAMETER_SECTION:
836       break;
837     }
838 
839   if(info->help_string)
840     {
841     write_help_string(output, info->help_string);
842     }
843 
844   fprintf(output, "%s\n", end_parameter_key);
845 
846   }
847 
848 /*
849  *  Write codec info, return FALSE on error
850  */
851 
write_codec_info(const lqt_codec_info_t * info,FILE * output)852 static int write_codec_info(const lqt_codec_info_t * info, FILE * output)
853   {
854   const char * tmp;
855 
856   int i;
857 
858   fprintf(output, "%s%s\n", begin_codec_key, info->name);
859   fprintf(output, "%s%s\n", long_name_key, info->long_name);
860 
861   fprintf(output, "%s%s\n", description_key, info->description);
862 
863   tmp = NULL;
864 
865   switch(info->type)
866     {
867     case LQT_CODEC_AUDIO:
868       tmp = type_audio;
869       break;
870     case LQT_CODEC_VIDEO:
871       tmp = type_video;
872       break;
873     }
874 
875   if(tmp)
876     fprintf(output, "%s%s\n", type_key, tmp);
877 
878   if(info->compression_id != LQT_COMPRESSION_NONE)
879     {
880     fprintf(output, "%s%s\n", compression_id_key,
881             lqt_compression_id_to_string(info->compression_id));
882     }
883 
884   switch(info->direction)
885     {
886     case LQT_DIRECTION_DECODE:
887       tmp = direction_decode;
888       break;
889     case LQT_DIRECTION_ENCODE:
890       tmp = direction_encode;
891       break;
892     case LQT_DIRECTION_BOTH:
893       tmp = direction_both;
894       break;
895     }
896 
897   if(tmp)
898     fprintf(output, "%s%s\n", direction_key, tmp);
899 
900   fprintf(output, "%s%08x\n", compatibility_key, info->compatibility_flags);
901 
902 
903   if(info->num_fourccs)
904     {
905     fprintf(output, "%s%d\n", num_fourccs_key, info->num_fourccs);
906 
907     fprintf(output, "%s", fourccs_key);
908 
909     for(i = 0; i < info->num_fourccs; i++)
910       fprintf(output, "0x%08X ", LQT_STRING_2_FOURCC(info->fourccs[i]));
911     fprintf(output, "\n");
912     }
913 
914   if(info->num_wav_ids)
915     {
916     fprintf(output, "%s%d\n", num_wav_ids_key, info->num_wav_ids);
917     fprintf(output, "%s", wav_ids_key);
918     for(i = 0; i < info->num_wav_ids; i++)
919       fprintf(output, "0x%02X ", info->wav_ids[i]);
920     fprintf(output, "\n");
921     }
922 
923   fprintf(output, "%s%d\n", num_encoding_parameters_key,
924           info->num_encoding_parameters);
925 
926   for(i = 0; i < info->num_encoding_parameters; i++)
927     {
928     write_parameter_info(output, &info->encoding_parameters[i], 1);
929     }
930 
931   fprintf(output, "%s%d\n", num_decoding_parameters_key,
932           info->num_decoding_parameters);
933 
934   for(i = 0; i < info->num_decoding_parameters; i++)
935     {
936     write_parameter_info(output, &info->decoding_parameters[i], 0);
937     }
938 
939   if((info->type == LQT_CODEC_VIDEO) &&
940      (info->direction != LQT_DIRECTION_DECODE))
941     {
942     fprintf(output, "%s%d\n", num_encoding_colormodels_key,
943             info->num_encoding_colormodels);
944 
945     for(i = 0; i < info->num_encoding_colormodels; i++)
946       {
947       fprintf(output, "%s%s\n", encoding_colormodel_key,
948               lqt_colormodel_to_string(info->encoding_colormodels[i]));
949       }
950     }
951 
952   if((info->type == LQT_CODEC_VIDEO) &&
953      (info->direction != LQT_DIRECTION_DECODE))
954     {
955     fprintf(output, "%s%d\n", num_image_sizes_key,
956             info->num_image_sizes);
957     for(i = 0; i < info->num_image_sizes; i++)
958       {
959       fprintf(output, "%s%d %d\n", image_size_key,
960               info->image_sizes[i].width, info->image_sizes[i].height);
961       }
962     }
963 
964   /* Module filename and index */
965   fprintf(output, "%s%s\n", module_filename_key, info->module_filename);
966   fprintf(output, "%s%d\n", module_index_key, info->module_index);
967   fprintf(output, "%s%u\n", module_file_time_key, info->file_time);
968 
969   if(info->gettext_domain)
970     fprintf(output, "%s%s\n", gettext_domain_key, info->gettext_domain);
971   if(info->gettext_directory)
972     fprintf(output, "%s%s\n", gettext_directory_key, info->gettext_directory);
973 
974   if(fprintf(output, "%s\n", end_codec_key) < 0)
975     return 0;
976   return 1;
977   }
978 
lqt_registry_write()979 void lqt_registry_write()
980   {
981   int i;
982   FILE * output;
983   char * filename_buffer = create_filename();
984   lqt_codec_info_t * codec_info;
985 
986   lqt_registry_lock();
987 
988   if(!filename_buffer || (*filename_buffer == '\0'))
989     {
990     lqt_log(NULL, LQT_LOG_ERROR, LOG_DOMAIN, "Codec registry filename could not be generated");
991     return;
992     }
993 
994   output = fopen(filename_buffer, "w");
995 
996   if(!output)
997     {
998     lqt_registry_unlock();
999     free(filename_buffer);
1000     return;
1001     }
1002 
1003   /*
1004    *  Write initial comment
1005    */
1006 
1007   fprintf(output, "# This is the codec database file for libquicktime\n\
1008 # It is automatically generated and should not be edited.\n\
1009 # If you changed it and your libquicktime program doesn't work\n\
1010 # anymore, delete it, and you will get a new one\n");
1011 
1012   /* Write the sort strings */
1013 
1014   if(lqt_num_audio_codecs)
1015     {
1016     codec_info = lqt_audio_codecs;
1017 
1018     fprintf(output, "%s", audio_order_key);
1019     for(i = 0; i < lqt_num_audio_codecs; i++)
1020       {
1021       fprintf(output, "%s", codec_info->name);
1022       if(i == lqt_num_audio_codecs - 1)
1023         fprintf(output, "\n");
1024       else
1025         fprintf(output, ",");
1026       codec_info = codec_info->next;
1027       }
1028     }
1029 
1030   if(lqt_num_video_codecs)
1031     {
1032     codec_info = lqt_video_codecs;
1033     fprintf(output, "%s", video_order_key);
1034     for(i = 0; i < lqt_num_video_codecs; i++)
1035       {
1036       fprintf(output, "%s", codec_info->name);
1037       if(i == lqt_num_video_codecs - 1)
1038         fprintf(output, "\n");
1039       else
1040         fprintf(output, ",");
1041       codec_info = codec_info->next;
1042       }
1043     }
1044 
1045   codec_info = lqt_audio_codecs;
1046 
1047   for(i = 0; i < lqt_num_audio_codecs; i++)
1048     {
1049     if(!write_codec_info(codec_info, output))
1050       goto fail;
1051     codec_info = codec_info->next;
1052     }
1053 
1054   codec_info = lqt_video_codecs;
1055   for(i = 0; i < lqt_num_video_codecs; i++)
1056     {
1057     if(!write_codec_info(codec_info, output))
1058       goto fail;
1059     codec_info = codec_info->next;
1060     }
1061   fclose(output);
1062   lqt_registry_unlock();
1063   free(filename_buffer);
1064   return;
1065 fail:
1066   fclose(output);
1067   lqt_registry_unlock();
1068   free(filename_buffer);
1069   lqt_log(NULL, LQT_LOG_INFO, LOG_DOMAIN,
1070           "%s could not be written, deleting imcomplete file", filename_buffer);
1071   remove(filename_buffer);
1072   }
1073