1 /*
2     Copyright (C) 2018, Rocky Bernstein <rocky@gnu.org>
3     Copyright (C) 2000, 2004-2005 Herbert Valerio Riedel <hvr@gnu.org>
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <math.h>
29 
30 #define _VCD_INFO_PRIVATE_H
31 /* We don't want to pull in cdio's config */
32 #define __CDIO_CONFIG_H__
33 #include <cdio/cdio.h>
34 #include <cdio/util.h>
35 #include <cdio/iso9660.h>
36 
37 /* public headers */
38 #include <libvcd/types.h>
39 #include <libvcd/info.h>
40 
41 #include <libvcd/files.h>
42 #include <libvcd/sector.h>
43 #include <libvcd/logging.h>
44 
45 /* Private headers */
46 #include "assert.h"
47 #include "dict.h"
48 #include "directory.h"
49 #include "obj.h"
50 #include "pbc.h"
51 #include "salloc.h"
52 #include "util.h"
53 #include "vcd.h"
54 
55 static const char zero[CDIO_CD_FRAMESIZE_RAW] = { 0, };
56 
57 #define DEFAULT_ISO_PREPARER_ID       "GNU VCDImager " VERSION " " HOST_ARCH
58 
sequence_free(mpeg_sequence_t * data)59 static void sequence_free(mpeg_sequence_t *data)
60 {
61   if (data != NULL) free(data);
62 }
63 
dict_free(struct _dict_t * data)64 static void dict_free(struct _dict_t *data)
65 {
66   if (data != NULL) free(data);
67 }
68 
cue_data_free(vcd_cue_t * data)69 static void cue_data_free(vcd_cue_t *data)
70 {
71   if (data != NULL) free(data);
72 }
73 
74 
75 /* exported private functions
76  */
77 
78 mpeg_sequence_t *
_vcd_obj_get_sequence_by_id(VcdObj_t * p_obj,const char sequence_id[])79 _vcd_obj_get_sequence_by_id (VcdObj_t *p_obj, const char sequence_id[])
80 {
81   CdioListNode_t *node;
82 
83   vcd_assert (sequence_id != NULL);
84   vcd_assert (p_obj != NULL);
85 
86   _CDIO_LIST_FOREACH (node, p_obj->mpeg_sequence_list)
87     {
88       mpeg_sequence_t *_sequence = _cdio_list_node_data (node);
89 
90       if (_sequence->id && !strcmp (sequence_id, _sequence->id))
91         return _sequence;
92     }
93 
94   return NULL;
95 }
96 
97 mpeg_sequence_t *
_vcd_obj_get_sequence_by_entry_id(VcdObj_t * p_obj,const char entry_id[])98 _vcd_obj_get_sequence_by_entry_id (VcdObj_t *p_obj, const char entry_id[])
99 {
100   CdioListNode_t *node;
101 
102   vcd_assert (entry_id != NULL);
103   vcd_assert (p_obj != NULL);
104 
105   _CDIO_LIST_FOREACH (node, p_obj->mpeg_sequence_list)
106     {
107       mpeg_sequence_t *_sequence = _cdio_list_node_data (node);
108       CdioListNode_t *node2;
109 
110       /* default entry point */
111       if (_sequence->default_entry_id
112           && !strcmp (entry_id, _sequence->default_entry_id))
113         return _sequence;
114 
115       /* additional entry points */
116       _CDIO_LIST_FOREACH (node2, _sequence->entry_list)
117 	{
118 	  entry_t *_entry = _cdio_list_node_data (node2);
119 
120 	  if (_entry->id
121               && !strcmp (entry_id, _entry->id))
122 	    return _sequence;
123 	}
124     }
125 
126   /* not found */
127 
128   return NULL;
129 }
130 
131 mpeg_segment_t *
_vcd_obj_get_segment_by_id(VcdObj_t * p_obj,const char segment_id[])132 _vcd_obj_get_segment_by_id (VcdObj_t *p_obj, const char segment_id[])
133 {
134   CdioListNode_t *node;
135 
136   vcd_assert (segment_id != NULL);
137   vcd_assert (p_obj != NULL);
138 
139   _CDIO_LIST_FOREACH (node, p_obj->mpeg_segment_list)
140     {
141       mpeg_segment_t *_segment = _cdio_list_node_data (node);
142 
143       if (_segment->id && !strcmp (segment_id, _segment->id))
144         return _segment;
145     }
146 
147   return NULL;
148 }
149 
150 bool
_vcd_obj_has_cap_p(const VcdObj_t * p_obj,enum vcd_capability_t capability)151 _vcd_obj_has_cap_p (const VcdObj_t *p_obj, enum vcd_capability_t capability)
152 {
153   switch (capability)
154     {
155     case _CAP_VALID:
156       switch (p_obj->type)
157         {
158         case VCD_TYPE_VCD:
159         case VCD_TYPE_VCD11:
160         case VCD_TYPE_VCD2:
161         case VCD_TYPE_SVCD:
162         case VCD_TYPE_HQVCD:
163           return true;
164           break;
165 
166         case VCD_TYPE_INVALID:
167           return false;
168           break;
169         }
170       break;
171 
172     case _CAP_MPEG2:
173       switch (p_obj->type)
174         {
175         case VCD_TYPE_VCD:
176         case VCD_TYPE_VCD11:
177         case VCD_TYPE_VCD2:
178         case VCD_TYPE_INVALID:
179           return false;
180           break;
181 
182         case VCD_TYPE_SVCD:
183         case VCD_TYPE_HQVCD:
184           return true;
185           break;
186         }
187       break;
188 
189     case _CAP_PBC:
190       switch (p_obj->type)
191         {
192         case VCD_TYPE_VCD:
193         case VCD_TYPE_VCD11:
194         case VCD_TYPE_INVALID:
195           return false;
196           break;
197 
198         case VCD_TYPE_VCD2:
199         case VCD_TYPE_SVCD:
200         case VCD_TYPE_HQVCD:
201           return true;
202           break;
203         }
204       break;
205 
206     case _CAP_PBC_X:
207       switch (p_obj->type)
208         {
209         case VCD_TYPE_VCD:
210         case VCD_TYPE_VCD11:
211         case VCD_TYPE_INVALID:
212         case VCD_TYPE_SVCD:
213         case VCD_TYPE_HQVCD:
214           return false;
215           break;
216 
217         case VCD_TYPE_VCD2:
218           return true;
219           break;
220         }
221       break;
222 
223     case _CAP_4C_SVCD:
224       switch (p_obj->type)
225         {
226         case VCD_TYPE_VCD:
227         case VCD_TYPE_VCD11:
228         case VCD_TYPE_INVALID:
229         case VCD_TYPE_VCD2:
230           return false;
231           break;
232 
233         case VCD_TYPE_SVCD:
234         case VCD_TYPE_HQVCD:
235           return true;
236           break;
237         }
238       break;
239 
240     case _CAP_PAL_BITS:
241       return _vcd_obj_has_cap_p (p_obj, _CAP_PBC); /* for now */
242       break;
243 
244     case _CAP_MPEG1:
245       return !_vcd_obj_has_cap_p (p_obj, _CAP_MPEG2); /* for now */
246       break;
247 
248     case _CAP_TRACK_MARGINS:
249       return !_vcd_obj_has_cap_p (p_obj, _CAP_MPEG2); /* for now */
250       break;
251     }
252 
253   vcd_assert_not_reached ();
254   return false;
255 }
256 
257 /*
258  * public methods
259  */
260 
261 VcdObj_t *
vcd_obj_new(vcd_type_t vcd_type)262 vcd_obj_new (vcd_type_t vcd_type)
263 {
264   VcdObj_t *p_new_obj = NULL;
265   static bool _first = true;
266 
267   if (_first)
268     {
269 #if defined(_DEVELOPMENT_)
270       vcd_warn ("initializing libvcd %s [%s]", VERSION, HOST_ARCH);
271       vcd_warn (" ");
272       vcd_warn (" this is the Beta development branch!");
273       vcd_warn (" use only if you know what you are doing");
274       vcd_warn (" see http://www.hvrlab.org/~hvr/vcdimager/ for more information");
275       vcd_warn (" ");
276 #else
277       vcd_debug ("initializing libvcd %s [%s]", VERSION, HOST_ARCH);
278 #endif
279       _first = false;
280     }
281 
282   p_new_obj = calloc(1, sizeof (VcdObj_t));
283   p_new_obj->type = vcd_type;
284 
285   if (!_vcd_obj_has_cap_p (p_new_obj, _CAP_VALID))
286     {
287       vcd_error ("VCD type not supported");
288       free (p_new_obj);
289       return NULL;
290     }
291 
292   if (vcd_type == VCD_TYPE_VCD)
293     vcd_warn ("VCD 1.0 support is experimental -- user feedback needed!");
294 
295   p_new_obj->iso_volume_label = strdup ("");
296   p_new_obj->iso_publisher_id = strdup ("");
297   p_new_obj->iso_application_id = strdup ("");
298   p_new_obj->iso_preparer_id = _vcd_strdup_upper (DEFAULT_ISO_PREPARER_ID);
299   p_new_obj->info_album_id = strdup ("");
300   p_new_obj->info_volume_count = 1;
301   p_new_obj->info_volume_number = 1;
302 
303   p_new_obj->custom_file_list = _cdio_list_new ();
304   p_new_obj->custom_dir_list = _cdio_list_new ();
305 
306 
307   p_new_obj->mpeg_sequence_list = _cdio_list_new ();
308 
309   p_new_obj->mpeg_segment_list = _cdio_list_new ();
310 
311   p_new_obj->pbc_list = _cdio_list_new ();
312 
313   /* gap's defined by IEC-10149 / ECMA-130 */
314 
315   /* pre-gap's for tracks but the first one */
316   p_new_obj->track_pregap = CDIO_PREGAP_SECTORS;
317   /* post-gap after last track */
318   p_new_obj->leadout_pregap = CDIO_POSTGAP_SECTORS;
319 
320   if (_vcd_obj_has_cap_p (p_new_obj, _CAP_TRACK_MARGINS))
321     {
322       p_new_obj->track_front_margin = 30;
323       p_new_obj->track_rear_margin  = 45;
324     }
325   else
326     {
327       p_new_obj->track_front_margin = 0;
328       p_new_obj->track_rear_margin  = 0;
329     }
330 
331   return p_new_obj;
332 }
333 
334 int
vcd_obj_remove_item(VcdObj_t * p_vcdobj,const char id[])335 vcd_obj_remove_item (VcdObj_t *p_vcdobj, const char id[])
336 {
337   vcd_warn ("vcd_obj_remove_item('%s') not implemented yet!", id);
338 
339   return -1;
340 }
341 
342 static void
_vcd_obj_remove_mpeg_track(VcdObj_t * p_vcdobj,int track_id)343 _vcd_obj_remove_mpeg_track (VcdObj_t *p_vcdobj, int track_id)
344 {
345   int length;
346   mpeg_sequence_t *track = NULL;
347   CdioListNode_t *node = NULL;
348 
349   vcd_assert (track_id >= 0);
350 
351   node = _vcd_list_at (p_vcdobj->mpeg_sequence_list, track_id);
352 
353   vcd_assert (node != NULL);
354 
355   track = (mpeg_sequence_t *) _cdio_list_node_data (node);
356 
357   vcd_mpeg_source_destroy (track->source, true);
358 
359   length = track->info ? track->info->packets : 0;
360   length += p_vcdobj->track_pregap + p_vcdobj->track_front_margin
361     + 0 + p_vcdobj->track_rear_margin;
362 
363   /* fixup offsets */
364   {
365     CdioListNode_t *node2 = node;
366     while ((node2 = _cdio_list_node_next (node2)) != NULL)
367       ((mpeg_sequence_t *) _cdio_list_node_data (node))->relative_start_extent
368         -= length;
369   }
370 
371   p_vcdobj->relative_end_extent -= length;
372 
373   /* shift up */
374   _cdio_list_node_free (node, true, NULL);
375 }
376 
377 int
vcd_obj_append_segment_play_item(VcdObj_t * p_vcdobj,VcdMpegSource_t * p_mpeg_source,const char item_id[])378 vcd_obj_append_segment_play_item (VcdObj_t *p_vcdobj,
379                                   VcdMpegSource_t *p_mpeg_source,
380                                   const char item_id[])
381 {
382   mpeg_segment_t *segment = NULL;
383 
384   vcd_assert (p_vcdobj != NULL);
385   vcd_assert (p_mpeg_source != NULL);
386 
387   if (!_vcd_obj_has_cap_p (p_vcdobj, _CAP_PBC))
388     {
389       vcd_error ("segment play items not supported for this vcd type");
390       return -1;
391     }
392 
393   if (!item_id)
394     {
395       vcd_error ("no id given for segment play item");
396       return -1;
397     }
398 
399   if (_vcd_pbc_lookup (p_vcdobj, item_id))
400     {
401       vcd_error ("item id (%s) exists already", item_id);
402       return -1;
403     }
404 
405   vcd_info ("scanning mpeg segment item #%d for scanpoints...",
406             _cdio_list_length (p_vcdobj->mpeg_segment_list));
407 
408   vcd_mpeg_source_scan (p_mpeg_source, !p_vcdobj->relaxed_aps,
409                         p_vcdobj->update_scan_offsets, NULL, NULL);
410 
411   if (vcd_mpeg_source_get_info (p_mpeg_source)->packets == 0)
412     {
413       vcd_error ("mpeg is empty?");
414       return -1;
415     }
416 
417   /* create list node */
418 
419   segment = calloc(1, sizeof (mpeg_sequence_t));
420 
421   segment->source = p_mpeg_source;
422 
423   segment->id = strdup (item_id);
424 
425   segment->info = vcd_mpeg_source_get_info (p_mpeg_source);
426   segment->segment_count = _vcd_len2blocks (segment->info->packets, 150);
427 
428   segment->pause_list = _cdio_list_new ();
429 
430   vcd_debug ("SPI length is %d sector(s), allocated %d segment(s)",
431              segment->info->packets,
432              segment->segment_count);
433 
434   _cdio_list_append (p_vcdobj->mpeg_segment_list, segment);
435 
436   return 0;
437 }
438 
439 int
vcd_obj_append_sequence_play_item(VcdObj_t * p_vcdobj,VcdMpegSource_t * p_mpeg_source,const char item_id[],const char default_entry_id[])440 vcd_obj_append_sequence_play_item (VcdObj_t *p_vcdobj,
441                                    VcdMpegSource_t *p_mpeg_source,
442                                    const char item_id[],
443                                    const char default_entry_id[])
444 {
445   unsigned length;
446   mpeg_sequence_t *sequence = NULL;
447   int track_no = _cdio_list_length (p_vcdobj->mpeg_sequence_list);
448 
449   vcd_assert (p_vcdobj != NULL);
450   vcd_assert (p_mpeg_source != NULL);
451 
452   if (item_id && _vcd_pbc_lookup (p_vcdobj, item_id))
453     {
454       vcd_error ("item id (%s) exist already", item_id);
455       return -1;
456     }
457 
458   if (default_entry_id && _vcd_pbc_lookup (p_vcdobj, default_entry_id))
459     {
460       vcd_error ("default entry id (%s) exist already", default_entry_id);
461       return -1;
462     }
463 
464   if (default_entry_id && item_id && !strcmp (item_id, default_entry_id))
465     {
466       vcd_error ("default entry id == item id (%s)", item_id);
467       return -1;
468     }
469 
470   vcd_info ("scanning mpeg sequence item #%d for scanpoints...", track_no);
471   vcd_mpeg_source_scan (p_mpeg_source, !p_vcdobj->relaxed_aps,
472                         p_vcdobj->update_scan_offsets, NULL, NULL);
473 
474   sequence = calloc(1, sizeof (mpeg_sequence_t));
475 
476   sequence->source = p_mpeg_source;
477 
478   if (item_id)
479     sequence->id = strdup (item_id);
480 
481   if (default_entry_id)
482     sequence->default_entry_id = strdup (default_entry_id);
483 
484   sequence->info = vcd_mpeg_source_get_info (p_mpeg_source);
485   length = sequence->info->packets;
486 
487   sequence->entry_list = _cdio_list_new ();
488   sequence->pause_list = _cdio_list_new ();
489 
490   p_vcdobj->relative_end_extent += p_vcdobj->track_pregap;
491   sequence->relative_start_extent = p_vcdobj->relative_end_extent;
492 
493   p_vcdobj->relative_end_extent += p_vcdobj->track_front_margin + length
494     + p_vcdobj->track_rear_margin;
495 
496   /* sanity checks */
497 
498   if (length < 75)
499     vcd_warn ("mpeg stream shorter than 75 sectors");
500 
501   if (!_vcd_obj_has_cap_p (p_vcdobj, _CAP_PAL_BITS)
502       && vcd_mpeg_get_norm (&sequence->info->shdr[0]) != MPEG_NORM_FILM
503       && vcd_mpeg_get_norm (&sequence->info->shdr[0]) != MPEG_NORM_NTSC)
504     vcd_warn ("VCD 1.x should contain only NTSC/FILM video (may work with PAL nevertheless)");
505 
506   if (!_vcd_obj_has_cap_p (p_vcdobj, _CAP_MPEG1)
507       && sequence->info->version == MPEG_VERS_MPEG1)
508     vcd_warn ("this VCD type should not contain MPEG1 streams");
509 
510   if (!_vcd_obj_has_cap_p (p_vcdobj, _CAP_MPEG2)
511       && sequence->info->version == MPEG_VERS_MPEG2)
512     vcd_warn ("this VCD type should not contain MPEG2 streams");
513 
514   if (!sequence->info->shdr[0].seen
515       || sequence->info->shdr[1].seen
516       || sequence->info->shdr[2].seen)
517     vcd_warn ("sequence items should contain a motion video stream!");
518 
519   {
520     int i;
521 
522     for (i = 0; i < 3; i++)
523       {
524         if (sequence->info->ahdr[i].seen)
525           {
526             if (i && !_vcd_obj_has_cap_p (p_vcdobj, _CAP_MPEG2))
527               vcd_warn ("audio stream #%d not supported by this VCD type", i);
528 
529             if (sequence->info->ahdr[i].sampfreq != 44100)
530               vcd_warn ("audio stream #%d has sampling frequency %d Hz (should be 44100 Hz)",
531                         i, sequence->info->ahdr[i].sampfreq);
532 
533             if (sequence->info->ahdr[i].layer != 2)
534               vcd_warn ("audio stream #%d is not layer II", i);
535 
536             if (_vcd_obj_has_cap_p (p_vcdobj, _CAP_MPEG1)
537                 && sequence->info->ahdr[i].bitrate != 224*1024)
538               vcd_warn ("audio stream #%d has bitrate %d kbps (should be 224 kbps for this vcd type)",
539                         i, sequence->info->ahdr[i].bitrate);
540           }
541         else if (!i && !_vcd_obj_has_cap_p (p_vcdobj, _CAP_MPEG2))
542           {
543             vcd_warn ("this VCD type requires an audio stream to be present");
544           }
545       }
546   }
547 
548   /* vcd_debug ("track# %d's detected playing time: %.2f seconds",  */
549   /*            track_no, sequence->info->playing_time); */
550 
551   _cdio_list_append (p_vcdobj->mpeg_sequence_list, sequence);
552 
553   return track_no;
554 }
555 
556 static int
_pause_cmp(pause_t * ent1,pause_t * ent2)557 _pause_cmp (pause_t *ent1, pause_t *ent2)
558 {
559   if (ent1->time < ent2->time)
560     return -1;
561 
562   if (ent1->time > ent2->time)
563     return 1;
564 
565   return 0;
566 }
567 
568 int
vcd_obj_add_sequence_pause(VcdObj_t * obj,const char sequence_id[],double pause_time,const char pause_id[])569 vcd_obj_add_sequence_pause (VcdObj_t *obj, const char sequence_id[],
570                             double pause_time, const char pause_id[])
571 {
572   mpeg_sequence_t *p_sequence;
573 
574   vcd_assert (obj != NULL);
575 
576   if (sequence_id)
577     p_sequence = _vcd_obj_get_sequence_by_id (obj, sequence_id);
578   else
579     p_sequence =
580       _cdio_list_node_data (_cdio_list_end (obj->mpeg_sequence_list));
581 
582   if (!p_sequence)
583     {
584       vcd_error ("sequence id `%s' not found", sequence_id);
585       return -1;
586     }
587 
588   if (pause_id)
589     vcd_warn ("pause id ignored...");
590 
591   {
592     pause_t *_pause = calloc(1, sizeof (pause_t));
593 
594     if (pause_id)
595       _pause->id = strdup (pause_id);
596     _pause->time = pause_time;
597 
598     _cdio_list_append (p_sequence->pause_list, _pause);
599   }
600 
601   _vcd_list_sort (p_sequence->pause_list,
602                   (_cdio_list_cmp_func_t) _pause_cmp);
603 
604   vcd_debug ("added autopause point at %f", pause_time);
605 
606   return 0;
607 }
608 
609 int
vcd_obj_add_segment_pause(VcdObj_t * p_obj,const char segment_id[],double pause_time,const char pause_id[])610 vcd_obj_add_segment_pause (VcdObj_t *p_obj, const char segment_id[],
611                             double pause_time, const char pause_id[])
612 {
613   mpeg_segment_t *_segment;
614 
615   vcd_assert (p_obj != NULL);
616 
617   if (segment_id)
618     _segment = _vcd_obj_get_segment_by_id (p_obj, segment_id);
619   else
620     _segment = _cdio_list_node_data (_cdio_list_end (p_obj->mpeg_segment_list));
621 
622   if (!_segment)
623     {
624       vcd_error ("segment id `%s' not found", segment_id);
625       return -1;
626     }
627 
628   if (pause_id)
629     vcd_warn ("pause id ignored...");
630 
631   {
632     pause_t *_pause = calloc(1, sizeof (pause_t));
633 
634     if (pause_id)
635       _pause->id = strdup (pause_id);
636     _pause->time = pause_time;
637 
638     _cdio_list_append (_segment->pause_list, _pause);
639   }
640 
641   _vcd_list_sort (_segment->pause_list,
642                   (_cdio_list_cmp_func_t) _pause_cmp);
643 
644   vcd_debug ("added autopause point at %f", pause_time);
645 
646   return 0;
647 }
648 
649 static int
_entry_cmp(entry_t * p_ent1,entry_t * p_ent2)650 _entry_cmp (entry_t *p_ent1, entry_t *p_ent2)
651 {
652   if (p_ent1->time < p_ent2->time)
653     return -1;
654 
655   if (p_ent1->time > p_ent2->time)
656     return 1;
657 
658   return 0;
659 }
660 
661 int
vcd_obj_add_sequence_entry(VcdObj_t * p_obj,const char sequence_id[],double entry_time,const char entry_id[])662 vcd_obj_add_sequence_entry (VcdObj_t *p_obj, const char sequence_id[],
663                             double entry_time, const char entry_id[])
664 {
665   mpeg_sequence_t *p_sequence;
666 
667   vcd_assert (p_obj != NULL);
668 
669   if (sequence_id)
670     p_sequence = _vcd_obj_get_sequence_by_id (p_obj, sequence_id);
671   else
672     p_sequence =
673       _cdio_list_node_data (_cdio_list_end (p_obj->mpeg_sequence_list));
674 
675   if (!p_sequence)
676     {
677       vcd_error ("sequence id `%s' not found", sequence_id);
678       return -1;
679     }
680 
681   if (_cdio_list_length (p_sequence->entry_list) >= MAX_SEQ_ENTRIES)
682     {
683       vcd_error ("only %d entries per sequence allowed!", MAX_SEQ_ENTRIES);
684       return -1;
685     }
686 
687   if (entry_id && _vcd_pbc_lookup (p_obj, entry_id))
688     {
689       vcd_error ("item id (%s) exists already", entry_id);
690       return -1;
691     }
692 
693   {
694     entry_t *_entry = calloc(1, sizeof (entry_t));
695 
696     if (entry_id)
697       _entry->id = strdup (entry_id);
698     _entry->time = entry_time;
699 
700     _cdio_list_append (p_sequence->entry_list, _entry);
701   }
702 
703   _vcd_list_sort (p_sequence->entry_list,
704                   (_cdio_list_cmp_func_t) _entry_cmp);
705 
706   return 0;
707 }
708 
709 void
vcd_obj_destroy(VcdObj_t * p_obj)710 vcd_obj_destroy (VcdObj_t *p_obj)
711 {
712   CdioListNode_t *p_node;
713 
714   vcd_assert (p_obj != NULL);
715   vcd_assert (!p_obj->in_output);
716 
717   free (p_obj->iso_volume_label);
718   free (p_obj->iso_application_id);
719 
720   _CDIO_LIST_FOREACH (p_node, p_obj->custom_file_list)
721     {
722       custom_file_t *p = _cdio_list_node_data (p_node);
723 
724       free (p->iso_pathname);
725     }
726 
727   _cdio_list_free (p_obj->custom_file_list, true, NULL);
728 
729   _cdio_list_free (p_obj->custom_dir_list, true, NULL);
730 
731   while (_cdio_list_length (p_obj->mpeg_sequence_list))
732     _vcd_obj_remove_mpeg_track (p_obj, 0);
733   _cdio_list_free (p_obj->mpeg_sequence_list, true, (CdioDataFree_t) &sequence_free);
734 
735   free (p_obj);
736 }
737 
738 int
vcd_obj_set_param_uint(VcdObj_t * p_obj,vcd_parm_t param,unsigned arg)739 vcd_obj_set_param_uint (VcdObj_t *p_obj, vcd_parm_t param, unsigned arg)
740 {
741   vcd_assert (p_obj != NULL);
742 
743   switch (param)
744     {
745     case VCD_PARM_VOLUME_COUNT:
746       p_obj->info_volume_count = arg;
747       if (!IN (p_obj->info_volume_count, 1, 65535))
748         {
749           p_obj->info_volume_count =
750             CLAMP (p_obj->info_volume_count, 1, 65535);
751           vcd_warn ("volume count out of range, clamping to range");
752         }
753       vcd_debug ("changed volume count to %u", p_obj->info_volume_count);
754       break;
755 
756     case VCD_PARM_VOLUME_NUMBER:
757       p_obj->info_volume_number = arg;
758       if (!IN (p_obj->info_volume_number, 0, 65534))
759         {
760           p_obj->info_volume_number =
761             CLAMP (p_obj->info_volume_number, 0, 65534);
762           vcd_warn ("volume number out of range, clamping to range");
763         }
764       vcd_debug ("changed volume number to %u", p_obj->info_volume_number);
765       break;
766 
767     case VCD_PARM_RESTRICTION:
768       p_obj->info_restriction = arg;
769       if (!IN (p_obj->info_restriction, 0, 3))
770         {
771           p_obj->info_restriction = CLAMP (p_obj->info_restriction, 0, 65534);
772           vcd_warn ("restriction out of range, clamping to range");
773         }
774       vcd_debug ("changed restriction number to %u", p_obj->info_restriction);
775       break;
776 
777     case VCD_PARM_LEADOUT_PREGAP:
778       p_obj->leadout_pregap = arg;
779       if (!IN (p_obj->leadout_pregap, 0, 300))
780         {
781           p_obj->leadout_pregap = CLAMP (p_obj->leadout_pregap, 0, 300);
782           vcd_warn ("ledout pregap out of range, clamping to allowed range");
783         }
784       if (p_obj->leadout_pregap < CDIO_PREGAP_SECTORS)
785         vcd_warn ("track leadout pregap set below %d sectors; "
786                   "created (S)VCD may be non-working",
787                   CDIO_PREGAP_SECTORS);
788 
789       vcd_debug ("changed leadout pregap to %u", p_obj->leadout_pregap);
790       break;
791 
792     case VCD_PARM_TRACK_PREGAP:
793       p_obj->track_pregap = arg;
794       if (!IN (p_obj->track_pregap, 1, 300))
795         {
796           p_obj->track_pregap = CLAMP (p_obj->track_pregap, 1, 300);
797           vcd_warn ("track pregap out of range, clamping to allowed range");
798         }
799       if (p_obj->track_pregap < CDIO_PREGAP_SECTORS)
800         vcd_warn ("track pre gap set below %d sectors; "
801                   "created (S)VCD may be non-working",
802                   CDIO_PREGAP_SECTORS);
803       vcd_debug ("changed track pregap to %u", p_obj->track_pregap);
804       break;
805 
806     case VCD_PARM_TRACK_FRONT_MARGIN:
807       p_obj->track_front_margin = arg;
808       if (!IN (p_obj->track_front_margin, 0, CDIO_PREGAP_SECTORS))
809         {
810           p_obj->track_front_margin = CLAMP (p_obj->track_front_margin, 0,
811                                            CDIO_PREGAP_SECTORS);
812           vcd_warn ("front margin out of range, clamping to allowed range");
813         }
814       if (_vcd_obj_has_cap_p (p_obj, _CAP_TRACK_MARGINS)
815           && p_obj->track_front_margin < 15)
816         vcd_warn ("front margin set smaller than recommended (%d < 15 sectors) for disc type used",
817                   p_obj->track_front_margin);
818 
819       vcd_debug ("changed front margin to %u", p_obj->track_front_margin);
820       break;
821 
822     case VCD_PARM_TRACK_REAR_MARGIN:
823       p_obj->track_rear_margin = arg;
824       if (!IN (p_obj->track_rear_margin, 0, CDIO_POSTGAP_SECTORS))
825         {
826           p_obj->track_rear_margin = CLAMP (p_obj->track_rear_margin, 0,
827                                             CDIO_POSTGAP_SECTORS);
828           vcd_warn ("rear margin out of range, clamping to allowed range");
829         }
830       if (_vcd_obj_has_cap_p (p_obj, _CAP_TRACK_MARGINS)
831           && p_obj->track_rear_margin < 15)
832         vcd_warn ("rear margin set smaller than recommended (%d < 15 sectors) for disc type used",
833                  p_obj->track_rear_margin);
834       vcd_debug ("changed rear margin to %u", p_obj->track_rear_margin);
835       break;
836 
837     default:
838       vcd_assert_not_reached ();
839       break;
840     }
841 
842   return 0;
843 }
844 
845 int
vcd_obj_set_param_str(VcdObj_t * p_obj,vcd_parm_t param,const char * arg)846 vcd_obj_set_param_str (VcdObj_t *p_obj, vcd_parm_t param, const char *arg)
847 {
848   vcd_assert (p_obj != NULL);
849   vcd_assert (arg != NULL);
850 
851   switch (param)
852     {
853     case VCD_PARM_VOLUME_ID:
854       free (p_obj->iso_volume_label);
855       p_obj->iso_volume_label = strdup (arg);
856       if (strlen (p_obj->iso_volume_label) > ISO_MAX_VOLUME_ID)
857         {
858           p_obj->iso_volume_label[ISO_MAX_VOLUME_ID] = '\0';
859           vcd_warn ("Volume label too long, will be truncated");
860         }
861       vcd_debug ("changed volume label to `%s'", p_obj->iso_volume_label);
862       break;
863 
864     case VCD_PARM_PUBLISHER_ID:
865       free (p_obj->iso_publisher_id);
866       p_obj->iso_publisher_id = strdup (arg);
867       if (strlen (p_obj->iso_publisher_id) > ISO_MAX_PUBLISHER_ID)
868         {
869           p_obj->iso_publisher_id[ISO_MAX_PUBLISHER_ID] = '\0';
870           vcd_warn ("Publisher ID too long, will be truncated");
871         }
872       vcd_debug ("changed publisher id to `%s'", p_obj->iso_publisher_id);
873       break;
874 
875     case VCD_PARM_PREPARER_ID:
876       free (p_obj->iso_preparer_id);
877       p_obj->iso_preparer_id = strdup (arg);
878       if (strlen (p_obj->iso_preparer_id) > ISO_MAX_PREPARER_ID)
879         {
880           p_obj->iso_preparer_id[ISO_MAX_PREPARER_ID] = '\0';
881           vcd_warn ("Preparer ID too long, will be truncated");
882         }
883       vcd_debug ("changed preparer id to `%s'", p_obj->iso_preparer_id);
884       break;
885 
886     case VCD_PARM_APPLICATION_ID:
887       free (p_obj->iso_application_id);
888       p_obj->iso_application_id = strdup (arg);
889       if (strlen (p_obj->iso_application_id) > ISO_MAX_APPLICATION_ID)
890         {
891           p_obj->iso_application_id[ISO_MAX_APPLICATION_ID] = '\0';
892           vcd_warn ("Application ID too long, will be truncated");
893         }
894       vcd_debug ("changed application id to `%s'", p_obj->iso_application_id);
895       break;
896 
897     case VCD_PARM_ALBUM_ID:
898       free (p_obj->info_album_id);
899       p_obj->info_album_id = strdup (arg);
900       if (strlen (p_obj->info_album_id) > 16)
901         {
902           p_obj->info_album_id[16] = '\0';
903           vcd_warn ("Album ID too long, will be truncated");
904         }
905       vcd_debug ("changed album id to `%s'", p_obj->info_album_id);
906       break;
907 
908     default:
909       vcd_assert_not_reached ();
910       break;
911     }
912 
913   return 0;
914 }
915 
916 int
vcd_obj_set_param_bool(VcdObj_t * p_obj,vcd_parm_t param,bool arg)917 vcd_obj_set_param_bool (VcdObj_t *p_obj, vcd_parm_t param, bool arg)
918 {
919   vcd_assert (p_obj != NULL);
920 
921   switch (param)
922     {
923     case VCD_PARM_RELAXED_APS:
924       p_obj->relaxed_aps = arg ? true : false;
925       vcd_debug ("changing 'relaxed aps' to %d", p_obj->relaxed_aps);
926       break;
927 
928     case VCD_PARM_NEXT_VOL_LID2:
929       p_obj->info_use_lid2 = arg ? true : false;
930       vcd_debug ("changing 'next volume use lid 2' to %d",
931                  p_obj->info_use_lid2);
932       break;
933 
934     case VCD_PARM_NEXT_VOL_SEQ2:
935       p_obj->info_use_seq2 = arg ? true : false;
936       vcd_debug ("changing 'next volume use sequence 2' to %d",
937                  p_obj->info_use_seq2);
938       break;
939 
940     case VCD_PARM_SVCD_VCD3_MPEGAV:
941       if (p_obj->type == VCD_TYPE_SVCD)
942         {
943           if ((p_obj->svcd_vcd3_mpegav = arg ? true : false))
944             vcd_warn ("!! enabling deprecated VCD3.0 MPEGAV folder --"
945                       " SVCD will not be IEC62107 compliant !!");
946         }
947       else
948         vcd_error ("parameter not applicable for vcd type");
949       break;
950 
951     case VCD_PARM_SVCD_VCD3_ENTRYSVD:
952       if (p_obj->type == VCD_TYPE_SVCD)
953         {
954           if ((p_obj->svcd_vcd3_entrysvd = arg ? true : false))
955             vcd_warn ("!! enabling deprecated VCD3.0 ENTRYSVD signature --"
956                       " SVCD will not be IEC62107 compliant !!");
957         }
958       else
959         vcd_error ("parameter not applicable for vcd type");
960       break;
961 
962     case VCD_PARM_SVCD_VCD3_TRACKSVD:
963       if (p_obj->type == VCD_TYPE_SVCD)
964         {
965           if ((p_obj->svcd_vcd3_tracksvd = arg ? true : false))
966             vcd_warn ("!! enabling deprecated VCD3.0 TRACK.SVD format --"
967                       " SVCD will not be IEC62107 compliant !!");
968         }
969       else
970         vcd_error ("parameter not applicable for vcd type");
971       break;
972 
973     case VCD_PARM_UPDATE_SCAN_OFFSETS:
974       if (_vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD))
975         {
976           p_obj->update_scan_offsets = arg ? true : false;
977           vcd_debug ("changing 'update scan offsets' to %d",
978                      p_obj->update_scan_offsets);
979         }
980       else
981         vcd_error ("parameter not applicable for vcd type");
982       break;
983 
984     case VCD_PARM_LEADOUT_PAUSE:
985       vcd_warn ("use of 'leadout pause' is deprecated and may be removed in later releases;"
986                 " use 'leadout pregap' instead");
987       vcd_obj_set_param_uint (p_obj, VCD_PARM_LEADOUT_PREGAP,
988                               (arg ? CDIO_PREGAP_SECTORS : 0));
989       break;
990 
991     default:
992       vcd_assert_not_reached ();
993       break;
994     }
995 
996   return 0;
997 }
998 
999 int
vcd_obj_add_dir(VcdObj_t * p_obj,const char iso_pathname[])1000 vcd_obj_add_dir (VcdObj_t *p_obj, const char iso_pathname[])
1001 {
1002   char *_iso_pathname;
1003 
1004   vcd_assert (p_obj != NULL);
1005   vcd_assert (iso_pathname != NULL);
1006 
1007   _iso_pathname = _vcd_strdup_upper (iso_pathname);
1008 
1009   if (!iso9660_dirname_valid_p (_iso_pathname))
1010     {
1011       vcd_error("pathname `%s' is not a valid iso pathname",
1012                 _iso_pathname);
1013       free (_iso_pathname);
1014       return 1;
1015     }
1016 
1017   _cdio_list_append (p_obj->custom_dir_list, _iso_pathname);
1018 
1019   _vcd_list_sort (p_obj->custom_dir_list,
1020                   (_cdio_list_cmp_func_t) strcmp);
1021 
1022   return 0;
1023 }
1024 
1025 int
vcd_obj_add_file(VcdObj_t * p_obj,const char iso_pathname[],VcdDataSource_t * file,bool raw_flag)1026 vcd_obj_add_file (VcdObj_t *p_obj, const char iso_pathname[],
1027                   VcdDataSource_t *file, bool raw_flag)
1028 {
1029   uint32_t size = 0, sectors = 0;
1030 
1031   vcd_assert (p_obj != NULL);
1032   vcd_assert (file != NULL);
1033   vcd_assert (iso_pathname != NULL);
1034   vcd_assert (strlen (iso_pathname) > 0);
1035   vcd_assert (file != NULL);
1036 
1037   size = vcd_data_source_stat (file);
1038 
1039   /* close file to save file descriptors */
1040   vcd_data_source_close (file);
1041 
1042   if (raw_flag)
1043     {
1044       if (!size)
1045         {
1046           vcd_error("raw mode2 file must not be empty\n");
1047           return 1;
1048         }
1049 
1050       sectors = size / M2RAW_SECTOR_SIZE;
1051 
1052       if (size % M2RAW_SECTOR_SIZE)
1053         {
1054           vcd_error("raw mode2 file must have size multiple of %d \n",
1055                     M2RAW_SECTOR_SIZE);
1056           return 1;
1057         }
1058     }
1059   else
1060     sectors = _vcd_len2blocks (size, CDIO_CD_FRAMESIZE);
1061 
1062   {
1063     custom_file_t *p;
1064     char *_iso_pathname = _vcd_strdup_upper (iso_pathname);
1065 
1066     if (!iso9660_pathname_valid_p (_iso_pathname))
1067       {
1068         vcd_error("pathname `%s' is not a valid iso pathname",
1069                   _iso_pathname);
1070         free (_iso_pathname);
1071         return 1;
1072       }
1073 
1074     p = calloc(1, sizeof (custom_file_t));
1075 
1076     p->file = file;
1077     p->iso_pathname = _iso_pathname;
1078     p->raw_flag = raw_flag;
1079 
1080     p->size = size;
1081     p->start_extent = 0;
1082     p->sectors = sectors;
1083 
1084     _cdio_list_append (p_obj->custom_file_list, p);
1085   }
1086 
1087   return 0;
1088 }
1089 
1090 static void
_finalize_vcd_iso_track_allocation(VcdObj_t * p_obj)1091 _finalize_vcd_iso_track_allocation (VcdObj_t *p_obj)
1092 {
1093   int n;
1094   CdioListNode_t *p_node;
1095 
1096   _dict_clean (p_obj);
1097 
1098   /* pre-alloc 16 blocks of ISO9660 required silence */
1099   if (_vcd_salloc (p_obj->iso_bitmap, 0, 16) == SECTOR_NIL)
1100     vcd_assert_not_reached ();
1101 
1102   /* keep karaoke sectors blank -- well... guess I'm too paranoid :) */
1103   if (_vcd_salloc (p_obj->iso_bitmap, 75, 75) == SECTOR_NIL)
1104     vcd_assert_not_reached ();
1105 
1106   /* pre-alloc descriptors, PVD */
1107   _dict_insert (p_obj, "pvd", ISO_PVD_SECTOR, 1, SM_EOR);         /* EOR */
1108   /* EVD */
1109   _dict_insert (p_obj, "evd", ISO_EVD_SECTOR, 1, SM_EOR|SM_EOF);  /* EOR+EOF */
1110 
1111   /* reserve for iso directory */
1112   _vcd_salloc (p_obj->iso_bitmap, 18, 75-18);
1113 
1114   /* VCD information area */
1115 
1116   _dict_insert (p_obj, "info", INFO_VCD_SECTOR, 1, SM_EOF);       /* INFO.VCD */           /* EOF */
1117   _dict_insert (p_obj, "entries", ENTRIES_VCD_SECTOR, 1, SM_EOF); /* ENTRIES.VCD */        /* EOF */
1118 
1119   /* PBC */
1120 
1121   if (_vcd_pbc_available (p_obj))
1122     {
1123       _dict_insert (p_obj, "lot", LOT_VCD_SECTOR, LOT_VCD_SIZE, SM_EOF); /* LOT.VCD */            /* EOF */
1124       _dict_insert (p_obj, "psd", PSD_VCD_SECTOR,
1125                     _vcd_len2blocks (get_psd_size (p_obj, false), ISO_BLOCKSIZE), SM_EOF); /* PSD.VCD */ /* EOF */
1126     }
1127 
1128   if (_vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD))
1129     {
1130       _dict_insert (p_obj, "tracks", SECTOR_NIL, 1, SM_EOF);   /* TRACKS.SVD */
1131       _dict_insert (p_obj, "search", SECTOR_NIL,
1132                     _vcd_len2blocks (get_search_dat_size (p_obj), ISO_BLOCKSIZE), SM_EOF); /* SEARCH.DAT */
1133 
1134       vcd_assert (_dict_get_bykey (p_obj, "tracks")->sector > INFO_VCD_SECTOR);
1135       vcd_assert (_dict_get_bykey (p_obj, "search")->sector > INFO_VCD_SECTOR);
1136     }
1137 
1138   /* done with primary information area */
1139 
1140   p_obj->mpeg_segment_start_extent =
1141     _vcd_len2blocks (_vcd_salloc_get_highest (p_obj->iso_bitmap) + 1, 75) * 75;
1142 
1143   /* salloc up to end of vcd sector */
1144   for(n = 0;n < p_obj->mpeg_segment_start_extent;n++)
1145     _vcd_salloc (p_obj->iso_bitmap, n, 1);
1146 
1147   vcd_assert (_vcd_salloc_get_highest (p_obj->iso_bitmap) + 1 == p_obj->mpeg_segment_start_extent);
1148 
1149   /* insert segments */
1150 
1151   _CDIO_LIST_FOREACH (p_node, p_obj->mpeg_segment_list)
1152     {
1153       mpeg_segment_t *_segment = _cdio_list_node_data (p_node);
1154 
1155       _segment->start_extent =
1156         _vcd_salloc (p_obj->iso_bitmap, SECTOR_NIL,
1157                      _segment->segment_count * VCDINFO_SEGMENT_SECTOR_SIZE);
1158 
1159       vcd_assert (_segment->start_extent % 75 == 0);
1160       vcd_assert (_vcd_salloc_get_highest (p_obj->iso_bitmap) + 1
1161                   == _segment->start_extent
1162                   + _segment->segment_count * VCDINFO_SEGMENT_SECTOR_SIZE);
1163     }
1164 
1165   p_obj->ext_file_start_extent = _vcd_salloc_get_highest (p_obj->iso_bitmap) + 1;
1166 
1167   vcd_assert (p_obj->ext_file_start_extent % 75 == 0);
1168 
1169   /* go on with EXT area */
1170 
1171   if (_vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD))
1172     {
1173       _dict_insert (p_obj, "scandata", SECTOR_NIL,
1174                     _vcd_len2blocks (get_scandata_dat_size (p_obj),
1175                                      ISO_BLOCKSIZE),
1176                     SM_EOF);
1177     }
1178 
1179   if (_vcd_obj_has_cap_p (p_obj, _CAP_PBC_X)
1180       &&_vcd_pbc_available (p_obj))
1181     {
1182       _dict_insert (p_obj, "lot_x", SECTOR_NIL, LOT_VCD_SIZE, SM_EOF);
1183 
1184       _dict_insert (p_obj, "psd_x", SECTOR_NIL,
1185                     _vcd_len2blocks (get_psd_size (p_obj, true),
1186                                      ISO_BLOCKSIZE), SM_EOF);
1187     }
1188 
1189 
1190   p_obj->custom_file_start_extent =
1191     _vcd_salloc_get_highest (p_obj->iso_bitmap) + 1;
1192 
1193   /* now for the custom files */
1194 
1195   _CDIO_LIST_FOREACH (p_node, p_obj->custom_file_list)
1196     {
1197       custom_file_t *p = _cdio_list_node_data (p_node);
1198 
1199       if (p->sectors)
1200         {
1201           p->start_extent =
1202             _vcd_salloc(p_obj->iso_bitmap, SECTOR_NIL, p->sectors);
1203           vcd_assert (p->start_extent != SECTOR_NIL);
1204         }
1205       else /* zero sized files -- set dummy extent */
1206         p->start_extent = p_obj->custom_file_start_extent;
1207     }
1208 
1209   /* calculate iso size -- after this point no sector shall be
1210      allocated anymore */
1211 
1212   p_obj->iso_size =
1213     MAX (MIN_ISO_SIZE, _vcd_salloc_get_highest (p_obj->iso_bitmap) + 1);
1214 
1215   vcd_debug ("iso9660: highest alloced sector is %lu (using %d as isosize)",
1216              (unsigned long int) _vcd_salloc_get_highest (p_obj->iso_bitmap),
1217              p_obj->iso_size);
1218 
1219   /* after this point the ISO9660's size is frozen */
1220 }
1221 
1222 static void
_finalize_vcd_iso_track_filesystem(VcdObj_t * p_obj)1223 _finalize_vcd_iso_track_filesystem (VcdObj_t *p_obj)
1224 {
1225   int n;
1226   CdioListNode_t *p_node;
1227 
1228   /* create filesystem entries */
1229 
1230   switch (p_obj->type) {
1231   case VCD_TYPE_VCD:
1232   case VCD_TYPE_VCD11:
1233   case VCD_TYPE_VCD2:
1234     /* add only necessary directories! */
1235     /* _vcd_directory_mkdir (p_obj->dir, "CDDA"); */
1236     /* _vcd_directory_mkdir (p_obj->dir, "CDI"); */
1237     _vcd_directory_mkdir (p_obj->dir, "EXT");
1238     /* _vcd_directory_mkdir (p_obj->dir, "KARAOKE"); */
1239     _vcd_directory_mkdir (p_obj->dir, "MPEGAV");
1240     _vcd_directory_mkdir (p_obj->dir, "VCD");
1241 
1242     /* add segment dir only when there are actually segment play items */
1243     if (_cdio_list_length (p_obj->mpeg_segment_list))
1244       _vcd_directory_mkdir (p_obj->dir, "SEGMENT");
1245 
1246     _vcd_directory_mkfile (p_obj->dir, "VCD/ENTRIES.VCD",
1247                            _dict_get_bykey (p_obj, "entries")->sector,
1248                            ISO_BLOCKSIZE, false, 0);
1249     _vcd_directory_mkfile (p_obj->dir, "VCD/INFO.VCD",
1250                            _dict_get_bykey (p_obj, "info")->sector,
1251                            ISO_BLOCKSIZE, false, 0);
1252 
1253     /* only for vcd2.0 */
1254     if (_vcd_pbc_available (p_obj))
1255       {
1256         _vcd_directory_mkfile (p_obj->dir, "VCD/LOT.VCD",
1257                                _dict_get_bykey (p_obj, "lot")->sector,
1258                                ISO_BLOCKSIZE*LOT_VCD_SIZE, false, 0);
1259         _vcd_directory_mkfile (p_obj->dir, "VCD/PSD.VCD",
1260                                _dict_get_bykey (p_obj, "psd")->sector,
1261                                get_psd_size (p_obj, false), false, 0);
1262       }
1263     break;
1264 
1265   case VCD_TYPE_SVCD:
1266   case VCD_TYPE_HQVCD:
1267     _vcd_directory_mkdir (p_obj->dir, "EXT");
1268 
1269     if (!p_obj->svcd_vcd3_mpegav)
1270       _vcd_directory_mkdir (p_obj->dir, "MPEG2");
1271     else
1272       {
1273         vcd_warn ("adding MPEGAV dir for *DEPRECATED* SVCD VCD30 mode");
1274         _vcd_directory_mkdir (p_obj->dir, "MPEGAV");
1275       }
1276 
1277     /* add segment dir only when there are actually segment play items */
1278     if (_cdio_list_length (p_obj->mpeg_segment_list))
1279       _vcd_directory_mkdir (p_obj->dir, "SEGMENT");
1280 
1281     _vcd_directory_mkdir (p_obj->dir, "SVCD");
1282 
1283     _vcd_directory_mkfile (p_obj->dir, "SVCD/ENTRIES.SVD",
1284                            _dict_get_bykey (p_obj, "entries")->sector,
1285                            ISO_BLOCKSIZE, false, 0);
1286     _vcd_directory_mkfile (p_obj->dir, "SVCD/INFO.SVD",
1287                            _dict_get_bykey (p_obj, "info")->sector,
1288                            ISO_BLOCKSIZE, false, 0);
1289 
1290     if (_vcd_pbc_available (p_obj))
1291       {
1292         _vcd_directory_mkfile (p_obj->dir, "SVCD/LOT.SVD",
1293                                _dict_get_bykey (p_obj, "lot")->sector,
1294                                ISO_BLOCKSIZE*LOT_VCD_SIZE, false, 0);
1295         _vcd_directory_mkfile (p_obj->dir, "SVCD/PSD.SVD",
1296                                _dict_get_bykey (p_obj, "psd")->sector,
1297                                get_psd_size (p_obj, false), false, 0);
1298       }
1299 
1300     _vcd_directory_mkfile (p_obj->dir, "SVCD/SEARCH.DAT",
1301                            _dict_get_bykey (p_obj, "search")->sector,
1302                            get_search_dat_size (p_obj), false, 0);
1303     _vcd_directory_mkfile (p_obj->dir, "SVCD/TRACKS.SVD",
1304                            _dict_get_bykey (p_obj, "tracks")->sector,
1305                            ISO_BLOCKSIZE, false, 0);
1306     break;
1307 
1308   default:
1309     vcd_assert_not_reached ();
1310     break;
1311   }
1312 
1313   /* SEGMENTS */
1314 
1315   n = 1;
1316   _CDIO_LIST_FOREACH (p_node, p_obj->mpeg_segment_list)
1317     {
1318       mpeg_segment_t *segment = _cdio_list_node_data (p_node);
1319       char segment_pathname[128] = { 0, };
1320       const char *fmt = NULL;
1321       uint8_t fnum = 0;
1322 
1323       switch (p_obj->type)
1324         {
1325         case VCD_TYPE_VCD2:
1326           fmt = "SEGMENT/ITEM%4.4d.DAT";
1327           fnum = 1;
1328           break;
1329         case VCD_TYPE_SVCD:
1330         case VCD_TYPE_HQVCD:
1331           fmt = "SEGMENT/ITEM%4.4d.MPG";
1332           fnum = 0;
1333           break;
1334         default:
1335           vcd_assert_not_reached ();
1336         }
1337 
1338       snprintf (segment_pathname, sizeof (segment_pathname), fmt, n);
1339 
1340       _vcd_directory_mkfile (p_obj->dir, segment_pathname,
1341                              segment->start_extent,
1342                              segment->info->packets * ISO_BLOCKSIZE,
1343                              true, fnum);
1344 
1345       vcd_assert (n <= MAX_SEGMENTS);
1346 
1347       n += segment->segment_count;
1348     }
1349 
1350   /* EXT files */
1351 
1352   if (_vcd_obj_has_cap_p (p_obj, _CAP_PBC_X)
1353       &&_vcd_pbc_available (p_obj))
1354     {
1355       /* psd_x -- extended PSD */
1356       _vcd_directory_mkfile (p_obj->dir, "EXT/PSD_X.VCD",
1357                              _dict_get_bykey (p_obj, "psd_x")->sector,
1358                              get_psd_size (p_obj, true), false, 1);
1359 
1360       /* lot_x -- extended LOT */
1361       _vcd_directory_mkfile (p_obj->dir, "EXT/LOT_X.VCD",
1362                              _dict_get_bykey (p_obj, "lot_x")->sector,
1363                              ISO_BLOCKSIZE*LOT_VCD_SIZE, false, 1);
1364 
1365       vcd_assert (p_obj->type == VCD_TYPE_VCD2);
1366     }
1367 
1368   if (_vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD))
1369     {
1370       /* scandata.dat -- scanpoints */
1371       _vcd_directory_mkfile (p_obj->dir, "EXT/SCANDATA.DAT",
1372                              _dict_get_bykey (p_obj, "scandata")->sector,
1373                              get_scandata_dat_size (p_obj), false, 0);
1374     }
1375 
1376   /* custom files/dirs */
1377   _CDIO_LIST_FOREACH (p_node, p_obj->custom_dir_list)
1378     {
1379       char *p = _cdio_list_node_data (p_node);
1380       _vcd_directory_mkdir (p_obj->dir, p);
1381     }
1382 
1383   _CDIO_LIST_FOREACH (p_node, p_obj->custom_file_list)
1384     {
1385       custom_file_t *p = _cdio_list_node_data (p_node);
1386 
1387       _vcd_directory_mkfile (p_obj->dir, p->iso_pathname, p->start_extent,
1388                              (p->raw_flag
1389                               ? (ISO_BLOCKSIZE * (p->size / M2RAW_SECTOR_SIZE))
1390                               : p->size),
1391                              p->raw_flag, 1);
1392     }
1393 
1394 
1395   n = 0;
1396   _CDIO_LIST_FOREACH (p_node, p_obj->mpeg_sequence_list)
1397     {
1398       char avseq_pathname[128] = { 0, };
1399       const char *fmt = NULL;
1400       mpeg_sequence_t *p_sequence = _cdio_list_node_data (p_node);
1401       uint32_t extent = p_sequence->relative_start_extent;
1402       uint8_t file_num = 0;
1403 
1404       extent += p_obj->iso_size;
1405 
1406       switch (p_obj->type)
1407         {
1408         case VCD_TYPE_VCD:
1409           fmt = "MPEGAV/MUSIC%2.2d.DAT";
1410           file_num = n + 1;
1411           break;
1412 
1413         case VCD_TYPE_VCD11:
1414         case VCD_TYPE_VCD2:
1415           fmt = "MPEGAV/AVSEQ%2.2d.DAT";
1416           file_num = n + 1;
1417           break;
1418         case VCD_TYPE_SVCD:
1419         case VCD_TYPE_HQVCD:
1420           fmt = "MPEG2/AVSEQ%2.2d.MPG";
1421           file_num = 0;
1422 
1423           /* if vcd3 compat mode, override */
1424           if (p_obj->svcd_vcd3_mpegav)
1425             {
1426               fmt = "MPEGAV/AVSEQ%2.2d.MPG";
1427               file_num = n + 1;
1428             }
1429 
1430           break;
1431         default:
1432           vcd_assert_not_reached ();
1433         }
1434 
1435       vcd_assert (n < 98);
1436 
1437       snprintf (avseq_pathname, sizeof (avseq_pathname), fmt, n + 1);
1438 
1439       /* file entry contains front margin, mpeg stream and rear margin */
1440       _vcd_directory_mkfile (p_obj->dir, avseq_pathname, extent,
1441                              (p_obj->track_front_margin
1442                               + p_sequence->info->packets
1443                               + p_obj->track_rear_margin) * ISO_BLOCKSIZE,
1444                              true, file_num);
1445 
1446       n++;
1447     }
1448 
1449   /* register isofs dir structures */
1450   {
1451     uint32_t dirs_size = _vcd_directory_get_size (p_obj->dir);
1452 
1453     /* be sure to stay out of information areas */
1454 
1455     switch (p_obj->type)
1456       {
1457       case VCD_TYPE_VCD:
1458       case VCD_TYPE_VCD11:
1459       case VCD_TYPE_VCD2:
1460         /* karaoke area starts at 03:00 */
1461         if (16 + 2 + dirs_size + 2 >= 75)
1462           vcd_error ("directory section to big for a VCD");
1463         break;
1464 
1465       case VCD_TYPE_SVCD:
1466       case VCD_TYPE_HQVCD:
1467         /* since no karaoke exists the next fixed area starts at 04:00 */
1468         if (16 + 2 + dirs_size + 2 >= 150)
1469           vcd_error ("directory section to big for a SVCD");
1470         break;
1471       default:
1472         vcd_assert_not_reached ();
1473       }
1474 
1475     /* un-alloc small area */
1476 
1477     _vcd_salloc_free (p_obj->iso_bitmap, 18, dirs_size + 2);
1478 
1479     /* alloc it again! */
1480 
1481     _dict_insert (p_obj, "dir", 18, dirs_size, SM_EOR|SM_EOF);
1482     _dict_insert (p_obj, "ptl", 18 + dirs_size, 1, SM_EOR|SM_EOF);
1483     _dict_insert (p_obj, "ptm", 18 + dirs_size + 1, 1, SM_EOR|SM_EOF);
1484   }
1485 }
1486 
1487 static void
_finalize_vcd_iso_track(VcdObj_t * p_obj)1488 _finalize_vcd_iso_track (VcdObj_t *p_obj)
1489 {
1490   _vcd_pbc_finalize (p_obj);
1491   _finalize_vcd_iso_track_allocation (p_obj);
1492   _finalize_vcd_iso_track_filesystem (p_obj);
1493 }
1494 
1495 static int
_callback_wrapper(VcdObj_t * p_obj,int force)1496 _callback_wrapper (VcdObj_t *p_obj, int force)
1497 {
1498   const int cb_frequency = 75;
1499 
1500   if (p_obj->last_cb_call + cb_frequency > p_obj->sectors_written && !force)
1501     return 0;
1502 
1503   p_obj->last_cb_call = p_obj->sectors_written;
1504 
1505   if (p_obj->progress_callback) {
1506     progress_info_t _pi;
1507 
1508     _pi.sectors_written = p_obj->sectors_written;
1509     _pi.total_sectors = p_obj->relative_end_extent + p_obj->iso_size;
1510     _pi.in_track = p_obj->in_track;
1511     _pi.total_tracks = _cdio_list_length (p_obj->mpeg_sequence_list) + 1;
1512 
1513     return p_obj->progress_callback (&_pi, p_obj->callback_user_data);
1514   }
1515   else
1516     return 0;
1517 }
1518 
1519 static int
_write_m2_image_sector(VcdObj_t * obj,const void * data,uint32_t extent,uint8_t fnum,uint8_t cnum,uint8_t sm,uint8_t ci)1520 _write_m2_image_sector (VcdObj_t *obj, const void *data, uint32_t extent,
1521                         uint8_t fnum, uint8_t cnum, uint8_t sm, uint8_t ci)
1522 {
1523   char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
1524 
1525   vcd_assert (extent == obj->sectors_written);
1526 
1527   _vcd_make_mode2(buf, data, extent, fnum, cnum, sm, ci);
1528 
1529   vcd_image_sink_write (obj->image_sink, buf, extent);
1530 
1531   obj->sectors_written++;
1532 
1533   return _callback_wrapper (obj, false);
1534 }
1535 
1536 static int
_write_m2_raw_image_sector(VcdObj_t * obj,const void * data,uint32_t extent)1537 _write_m2_raw_image_sector (VcdObj_t *obj, const void *data, uint32_t extent)
1538 {
1539   char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
1540 
1541   vcd_assert (extent == obj->sectors_written);
1542 
1543   _vcd_make_raw_mode2(buf, data, extent);
1544 
1545   vcd_image_sink_write (obj->image_sink, buf, extent);
1546 
1547   obj->sectors_written++;
1548 
1549   return _callback_wrapper (obj, false);
1550 }
1551 
1552 static void
_write_source_mode2_raw(VcdObj_t * obj,VcdDataSource_t * source,uint32_t extent)1553 _write_source_mode2_raw (VcdObj_t *obj, VcdDataSource_t *source,
1554                          uint32_t extent)
1555 {
1556   int n;
1557   uint32_t sectors;
1558 
1559   sectors = vcd_data_source_stat (source) / M2RAW_SECTOR_SIZE;
1560 
1561   vcd_data_source_seek (source, 0);
1562 
1563   for (n = 0;n < sectors;n++) {
1564     char buf[M2RAW_SECTOR_SIZE] = { 0, };
1565 
1566     vcd_data_source_read (source, buf, M2RAW_SECTOR_SIZE, 1);
1567 
1568     if (_write_m2_raw_image_sector (obj, buf, extent+n))
1569       break;
1570   }
1571 
1572   vcd_data_source_close (source);
1573 }
1574 
1575 static void
_write_source_mode2_form1(VcdObj_t * obj,VcdDataSource_t * source,uint32_t extent)1576 _write_source_mode2_form1 (VcdObj_t *obj, VcdDataSource_t *source,
1577                            uint32_t extent)
1578 {
1579   int n;
1580   uint32_t sectors, size, last_block_size;
1581 
1582   size = vcd_data_source_stat (source);
1583 
1584   sectors = _vcd_len2blocks (size, CDIO_CD_FRAMESIZE);
1585 
1586   last_block_size = size % CDIO_CD_FRAMESIZE;
1587   if (!last_block_size)
1588     last_block_size = CDIO_CD_FRAMESIZE;
1589 
1590   vcd_data_source_seek (source, 0);
1591 
1592   for (n = 0;n < sectors;n++) {
1593     char buf[CDIO_CD_FRAMESIZE] = { 0, };
1594 
1595     vcd_data_source_read (source, buf,
1596                           ((n + 1 == sectors)
1597                            ? last_block_size
1598                            : CDIO_CD_FRAMESIZE), 1);
1599 
1600     if (_write_m2_image_sector (obj, buf, extent+n, 1, 0,
1601                                 ((n+1 < sectors)
1602                                  ? SM_DATA
1603                                  : SM_DATA |SM_EOF),
1604                                 0))
1605       break;
1606   }
1607 
1608   vcd_data_source_close (source);
1609 }
1610 
1611 static int
_write_sequence(VcdObj_t * p_obj,int track_idx)1612 _write_sequence (VcdObj_t *p_obj, int track_idx)
1613 {
1614   mpeg_sequence_t *track =
1615     _cdio_list_node_data (_vcd_list_at (p_obj->mpeg_sequence_list, track_idx));
1616   CdioListNode_t *pause_node;
1617   int n, lastsect = p_obj->sectors_written;
1618   char buf[2324];
1619   struct {
1620     int audio;
1621     int video;
1622     int zero;
1623     int ogt;
1624     int unknown;
1625   } mpeg_packets = {0, };
1626 
1627 
1628   {
1629     char *norm_str = NULL;
1630     const struct vcd_mpeg_stream_vid_info *_info = &track->info->shdr[0];
1631 
1632     switch (vcd_mpeg_get_norm (_info)) {
1633     case MPEG_NORM_PAL:
1634       norm_str = strdup ("PAL SIF (352x288/25fps)");
1635       break;
1636     case MPEG_NORM_NTSC:
1637       norm_str = strdup ("NTSC SIF (352x240/29.97fps)");
1638       break;
1639     case MPEG_NORM_FILM:
1640       norm_str = strdup ("FILM SIF (352x240/24fps)");
1641       break;
1642     case MPEG_NORM_PAL_S:
1643       norm_str = strdup ("PAL 2/3 D1 (480x576/25fps)");
1644       break;
1645     case MPEG_NORM_NTSC_S:
1646       norm_str = strdup ("NTSC 2/3 D1 (480x480/29.97fps)");
1647       break;
1648 
1649     case MPEG_NORM_OTHER:
1650       {
1651         char buf[1024] = { 0, };
1652         switch (_info->vsize)
1653           {
1654           case 480:
1655           case 240:
1656             snprintf (buf, sizeof (buf), "NTSC UNKNOWN (%dx%d/%2.2ffps)",
1657                       _info->hsize, _info->vsize, _info->frate);
1658             break;
1659           case 288:
1660           case 576:
1661             snprintf (buf, sizeof (buf), "PAL UNKNOWN (%dx%d/%2.2ffps)",
1662                       _info->hsize, _info->vsize, _info->frate);
1663             break;
1664           default:
1665             snprintf (buf, sizeof (buf), "UNKNOWN (%dx%d/%2.2ffps)",
1666                       _info->hsize, _info->vsize, _info->frate);
1667             break;
1668           }
1669         norm_str = strdup (buf);
1670       }
1671       break;
1672     }
1673 
1674     {
1675       char buf[1024] = { 0, }, buf2[1024] = { 0, };
1676       int i;
1677       int i_buf2 = 0;
1678 
1679       for (i = 0; i < 3; i++)
1680         if (track->info->ahdr[i].seen)
1681           {
1682             const char *_mode_str[] = {
1683               0,
1684               "stereo",
1685               "jstereo",
1686               "dual",
1687               "single",
1688               0
1689             };
1690 
1691             int i_buf = snprintf (buf, sizeof (buf),
1692                                   "audio[%d]: l%d/%2.1fkHz/%dkbps/%s ",
1693                                   i,
1694                                   track->info->ahdr[i].layer,
1695                                   track->info->ahdr[i].sampfreq / 1000.0,
1696                                   track->info->ahdr[i].bitrate / 1024,
1697                                   _mode_str[track->info->ahdr[i].mode]);
1698 
1699             strncat (buf2, buf, sizeof(buf2)-strlen(buf2)-i_buf2-1);
1700             i_buf2 += i_buf;
1701           }
1702 
1703       vcd_info ("writing track %d, %s, %s, %s...", track_idx + 2,
1704                 (track->info->version == MPEG_VERS_MPEG1 ? "MPEG1" : "MPEG2"),
1705                 norm_str, buf2);
1706     }
1707 
1708     free (norm_str);
1709   }
1710 
1711   for (n = 0; n < p_obj->track_pregap; n++)
1712     _write_m2_image_sector (p_obj, zero, lastsect++, 0, 0, SM_FORM2, 0);
1713 
1714   for (n = 0; n < p_obj->track_front_margin;n++)
1715     _write_m2_image_sector (p_obj, zero, lastsect++, track_idx + 1,
1716                             0, SM_FORM2|SM_REALT, 0);
1717 
1718   pause_node = _cdio_list_begin (track->pause_list);
1719 
1720   for (n = 0; n < track->info->packets; n++) {
1721     int ci = 0, sm = 0, cnum = 0, fnum = 0;
1722     struct vcd_mpeg_packet_info pkt_flags;
1723     bool set_trigger = false;
1724 
1725     vcd_mpeg_source_get_packet (track->source, n, buf, &pkt_flags,
1726                                 p_obj->update_scan_offsets);
1727 
1728     while (pause_node)
1729       {
1730         pause_t *_pause = _cdio_list_node_data (pause_node);
1731 
1732         if (!pkt_flags.has_pts)
1733           break; /* no pts */
1734 
1735         if (pkt_flags.pts < _pause->time)
1736           break; /* our time has not come yet */
1737 
1738         /* seems it's time to trigger! */
1739         set_trigger = true;
1740 
1741         vcd_debug ("setting auto pause trigger for time %f (pts %f) @%d",
1742                    _pause->time, pkt_flags.pts, n);
1743 
1744         pause_node = _cdio_list_node_next (pause_node);
1745       }
1746 
1747     switch (vcd_mpeg_packet_get_type (&pkt_flags))
1748       {
1749     case PKT_TYPE_VIDEO:
1750       mpeg_packets.video++;
1751       sm = SM_FORM2|SM_REALT|SM_VIDEO;
1752       ci = CI_VIDEO;
1753       cnum = CN_VIDEO;
1754       break;
1755 
1756     case PKT_TYPE_OGT:
1757       mpeg_packets.ogt++;
1758       sm = SM_FORM2|SM_REALT|SM_VIDEO;
1759       ci = CI_OGT;
1760       cnum = CN_OGT;
1761       break;
1762 
1763     case PKT_TYPE_AUDIO:
1764       mpeg_packets.audio++;
1765       sm = SM_FORM2|SM_REALT|SM_AUDIO;
1766       ci = CI_AUDIO;
1767       cnum = CN_AUDIO;
1768       if (pkt_flags.audio[1] || pkt_flags.audio[2])
1769         {
1770           ci = CI_AUDIO2;
1771           cnum = CN_AUDIO2;
1772         }
1773       break;
1774 
1775 
1776     case PKT_TYPE_ZERO:
1777       mpeg_packets.zero++;
1778       mpeg_packets.unknown--;
1779     case PKT_TYPE_EMPTY:
1780       mpeg_packets.unknown++;
1781       sm = SM_FORM2|SM_REALT;
1782       ci = CI_EMPTY;
1783       cnum = CN_EMPTY;
1784       break;
1785 
1786     case PKT_TYPE_INVALID:
1787       vcd_error ("invalid mpeg packet found at packet# %d"
1788                  " -- please fix this mpeg file!", n);
1789       vcd_mpeg_source_close (track->source);
1790       return 1;
1791       break;
1792 
1793     default:
1794       vcd_assert_not_reached ();
1795     }
1796 
1797     if (n == track->info->packets - 1)
1798       {
1799         sm |= SM_EOR;
1800         if (!p_obj->track_rear_margin) /* if no rear margin... */
1801           sm |= SM_EOF;
1802       }
1803 
1804     if (set_trigger)
1805       sm |= SM_TRIG;
1806 
1807     fnum = track_idx + 1;
1808 
1809     if (_vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD)
1810         && !p_obj->svcd_vcd3_mpegav) /* IEC62107 SVCDs have a
1811                                         simplified subheader */
1812       {
1813         fnum = 1;
1814         ci = CI_MPEG2;
1815       }
1816 
1817     if (_write_m2_image_sector (p_obj, buf, lastsect++, fnum, cnum, sm, ci))
1818       break;
1819   }
1820 
1821   vcd_mpeg_source_close (track->source);
1822 
1823   for (n = 0; n < p_obj->track_rear_margin; n++)
1824     {
1825       const uint8_t ci = 0, cnum = 0;
1826       uint8_t fnum = track_idx + 1;
1827       uint8_t sm = SM_FORM2 | SM_REALT;
1828 
1829       if (n + 1 == p_obj->track_rear_margin)
1830         sm |= SM_EOF;
1831 
1832       _write_m2_image_sector (p_obj, zero, lastsect++, fnum, cnum, sm, ci);
1833     }
1834 
1835   vcd_debug ("MPEG packet statistics: %d video, %d audio, %d zero, %d ogt, %d unknown",
1836              mpeg_packets.video, mpeg_packets.audio, mpeg_packets.zero, mpeg_packets.ogt,
1837              mpeg_packets.unknown);
1838 
1839   return 0;
1840 }
1841 
1842 static int
_write_segment(VcdObj_t * p_obj,mpeg_segment_t * p_segment)1843 _write_segment (VcdObj_t *p_obj, mpeg_segment_t *p_segment)
1844 {
1845   CdioListNode_t *pause_node;
1846   unsigned int packet_no;
1847   int n = p_obj->sectors_written;
1848 
1849   vcd_assert (p_segment->start_extent == n);
1850 
1851   pause_node = _cdio_list_begin (p_segment->pause_list);
1852 
1853   for (packet_no = 0;
1854        packet_no < (p_segment->segment_count * VCDINFO_SEGMENT_SECTOR_SIZE);
1855        packet_no++)
1856     {
1857       uint8_t buf[M2F2_SECTOR_SIZE] = { 0, };
1858       uint8_t fn, cn, sm, ci;
1859 
1860       if (packet_no < p_segment->info->packets)
1861         {
1862           struct vcd_mpeg_packet_info pkt_flags;
1863           bool set_trigger = false;
1864           bool _need_eor = false;
1865 
1866           vcd_mpeg_source_get_packet (p_segment->source, packet_no,
1867                                       buf, &pkt_flags,
1868                                       p_obj->update_scan_offsets);
1869 
1870           fn = 1;
1871           cn = CN_EMPTY;
1872           sm = SM_FORM2 | SM_REALT;
1873           ci = CI_EMPTY;
1874 
1875           while (pause_node)
1876             {
1877               pause_t *_pause = _cdio_list_node_data (pause_node);
1878 
1879               if (!pkt_flags.has_pts)
1880                 break; /* no pts */
1881 
1882               if (pkt_flags.pts < _pause->time)
1883                 break; /* our time has not come yet */
1884 
1885               /* seems it's time to trigger! */
1886               set_trigger = true;
1887 
1888               vcd_debug ("setting auto pause trigger for time %f (pts %f) @%d",
1889                          _pause->time, pkt_flags.pts, n);
1890 
1891               pause_node = _cdio_list_node_next (pause_node);
1892             }
1893 
1894           switch (vcd_mpeg_packet_get_type (&pkt_flags))
1895             {
1896             case PKT_TYPE_VIDEO:
1897               sm = SM_FORM2 | SM_REALT | SM_VIDEO;
1898 
1899               ci = CI_VIDEO;
1900               cn = CN_VIDEO;
1901 
1902               if (pkt_flags.video[1])
1903                 ci = CI_STILL, cn = CN_STILL;
1904               else if (pkt_flags.video[2])
1905                 ci = CI_STILL2, cn = CN_STILL2;
1906 
1907               if (pkt_flags.video[1] || pkt_flags.video[2])
1908                 { /* search for endcode -- hack */
1909                   int idx;
1910 
1911                   for (idx = 0; idx <= 2320; idx++)
1912                     if (buf[idx] == 0x00
1913                         && buf[idx + 1] == 0x00
1914                         && buf[idx + 2] == 0x01
1915                         && buf[idx + 3] == 0xb7)
1916                       {
1917                         _need_eor = true;
1918                         break;
1919                       }
1920                 }
1921               break;
1922 
1923             case PKT_TYPE_AUDIO:
1924               sm = SM_FORM2 | SM_REALT | SM_AUDIO;
1925 
1926               ci = CI_AUDIO;
1927               cn = CN_AUDIO;
1928               break;
1929 
1930             case PKT_TYPE_EMPTY:
1931               ci = CI_EMPTY;
1932               cn = CN_EMPTY;
1933               break;
1934 
1935             default:
1936               /* fixme -- check.... */
1937               break;
1938             }
1939 
1940           if (_vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD))
1941             {
1942               cn = 1;
1943               sm = SM_FORM2 | SM_REALT | SM_VIDEO;
1944               ci = CI_MPEG2;
1945             }
1946 
1947           if (packet_no + 1 == p_segment->info->packets)
1948             sm |= SM_EOF;
1949 
1950           if (set_trigger)
1951             sm |= SM_TRIG;
1952 
1953           if (_need_eor)
1954             {
1955               vcd_debug ("setting EOR for SeqEnd at packet# %d ('%s')",
1956                          packet_no, p_segment->id);
1957               sm |= SM_EOR;
1958             }
1959         }
1960       else
1961         {
1962           fn = 1;
1963           cn = CN_EMPTY;
1964           sm = SM_FORM2 | SM_REALT;
1965           ci = CI_EMPTY;
1966 
1967           if (_vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD))
1968             {
1969               fn = 0;
1970               sm = SM_FORM2;
1971             }
1972 
1973         }
1974 
1975       _write_m2_image_sector (p_obj, buf, n, fn, cn, sm, ci);
1976 
1977       n++;
1978     }
1979 
1980   vcd_mpeg_source_close (p_segment->source);
1981 
1982   return 0;
1983 }
1984 
1985 static uint32_t
_get_closest_aps(const struct vcd_mpeg_stream_info * _mpeg_info,double t,struct aps_data * _best_aps)1986 _get_closest_aps (const struct vcd_mpeg_stream_info *_mpeg_info, double t,
1987                   struct aps_data *_best_aps)
1988 {
1989   CdioListNode_t *p_node;
1990   struct aps_data best_aps;
1991   bool first = true;
1992 
1993   best_aps.packet_no = 0xFFFF; /* A number which will be caught as an error*/
1994   best_aps.timestamp = -1;     /* A number which will be caught as an error*/
1995   vcd_assert (_mpeg_info != NULL);
1996   vcd_assert (_mpeg_info->shdr[0].aps_list != NULL);
1997 
1998   _CDIO_LIST_FOREACH (p_node, _mpeg_info->shdr[0].aps_list)
1999     {
2000       struct aps_data *_aps = _cdio_list_node_data (p_node);
2001 
2002       if (first)
2003         {
2004           best_aps = *_aps;
2005           first = false;
2006         }
2007       else if (fabs (_aps->timestamp - t) < fabs (best_aps.timestamp - t))
2008         best_aps = *_aps;
2009       else
2010         break;
2011     }
2012 
2013   if (_best_aps)
2014     *_best_aps = best_aps;
2015 
2016   return best_aps.packet_no;
2017 }
2018 
2019 static void
_update_entry_points(VcdObj_t * p_obj)2020 _update_entry_points (VcdObj_t *p_obj)
2021 {
2022   CdioListNode_t *sequence_node;
2023 
2024   _CDIO_LIST_FOREACH (sequence_node, p_obj->mpeg_sequence_list)
2025     {
2026       mpeg_sequence_t *_sequence = _cdio_list_node_data (sequence_node);
2027       CdioListNode_t *entry_node;
2028       unsigned int last_packet_no = 0;
2029 
2030       _CDIO_LIST_FOREACH (entry_node, _sequence->entry_list)
2031         {
2032           entry_t *_entry = _cdio_list_node_data (entry_node);
2033 
2034           _get_closest_aps (_sequence->info, _entry->time, &_entry->aps);
2035 
2036           vcd_log ((fabs (_entry->aps.timestamp - _entry->time) > 1
2037                     ? VCD_LOG_WARN
2038                     : VCD_LOG_DEBUG),
2039                    "requested entry point (id=%s) at %f, "
2040                    "closest possible entry point at %f",
2041                    _entry->id, _entry->time, _entry->aps.timestamp);
2042 
2043           if (last_packet_no == _entry->aps.packet_no)
2044             vcd_warn ("entry point '%s' falls into same sector as previous one!",
2045                       _entry->id);
2046 
2047           last_packet_no = _entry->aps.packet_no;
2048         }
2049     }
2050 }
2051 
2052 static int
_write_vcd_iso_track(VcdObj_t * p_obj,const time_t * p_create_time)2053 _write_vcd_iso_track (VcdObj_t *p_obj, const time_t *p_create_time)
2054 {
2055   CdioListNode_t *node;
2056   int n;
2057 
2058   /* generate dir sectors */
2059 
2060   _vcd_directory_dump_entries (p_obj->dir,
2061                                _dict_get_bykey (p_obj, "dir")->buf,
2062                                _dict_get_bykey (p_obj, "dir")->sector);
2063 
2064   _vcd_directory_dump_pathtables (p_obj->dir,
2065                                   _dict_get_bykey (p_obj, "ptl")->buf,
2066                                   _dict_get_bykey (p_obj, "ptm")->buf);
2067 
2068   /* generate PVD and EVD at last... */
2069   iso9660_set_pvd (_dict_get_bykey (p_obj, "pvd")->buf,
2070                    p_obj->iso_volume_label,
2071                    p_obj->iso_publisher_id,
2072                    p_obj->iso_preparer_id,
2073                    p_obj->iso_application_id,
2074                    p_obj->iso_size,
2075                    _dict_get_bykey (p_obj, "dir")->buf,
2076                    _dict_get_bykey (p_obj, "ptl")->sector,
2077                    _dict_get_bykey (p_obj, "ptm")->sector,
2078                    iso9660_pathtable_get_size (_dict_get_bykey (p_obj, "ptm")->buf),
2079                    p_create_time
2080 );
2081 
2082   iso9660_set_evd (_dict_get_bykey (p_obj, "evd")->buf);
2083 
2084   /* fill VCD relevant files with data */
2085 
2086   set_info_vcd (p_obj, _dict_get_bykey (p_obj, "info")->buf);
2087   set_entries_vcd (p_obj, _dict_get_bykey (p_obj, "entries")->buf);
2088 
2089   if (_vcd_pbc_available (p_obj))
2090     {
2091       if (_vcd_obj_has_cap_p (p_obj, _CAP_PBC_X))
2092         {
2093           set_lot_vcd (p_obj, _dict_get_bykey (p_obj, "lot_x")->buf, true);
2094           set_psd_vcd (p_obj, _dict_get_bykey (p_obj, "psd_x")->buf, true);
2095         }
2096 
2097       _vcd_pbc_check_unreferenced (p_obj);
2098 
2099       set_lot_vcd (p_obj, _dict_get_bykey (p_obj, "lot")->buf, false);
2100       set_psd_vcd (p_obj, _dict_get_bykey (p_obj, "psd")->buf, false);
2101     }
2102 
2103   if (_vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD))
2104     {
2105       set_tracks_svd (p_obj, _dict_get_bykey (p_obj, "tracks")->buf);
2106       set_search_dat (p_obj, _dict_get_bykey (p_obj, "search")->buf);
2107       set_scandata_dat (p_obj, _dict_get_bykey (p_obj, "scandata")->buf);
2108     }
2109 
2110   /* start actually writing stuff */
2111 
2112   vcd_info ("writing track 1 (ISO9660)...");
2113 
2114   /* 00:02:00 -> 00:04:74 */
2115   for (n = 0; n < p_obj->mpeg_segment_start_extent; n++)
2116     {
2117       const void *content = NULL;
2118       uint8_t flags = SM_DATA;
2119 
2120       content = _dict_get_sector (p_obj, n);
2121       flags |= _dict_get_sector_flags (p_obj, n);
2122 
2123       if (content == NULL)
2124         content = zero;
2125 
2126       _write_m2_image_sector (p_obj, content, n, 0, 0, flags, 0);
2127     }
2128 
2129   /* SEGMENTS */
2130 
2131   vcd_assert (n == p_obj->mpeg_segment_start_extent);
2132 
2133   _CDIO_LIST_FOREACH (node, p_obj->mpeg_segment_list)
2134     {
2135       mpeg_segment_t *p_segment = _cdio_list_node_data (node);
2136 
2137       _write_segment (p_obj, p_segment);
2138     }
2139 
2140   n = p_obj->sectors_written;
2141 
2142   /* EXT stuff */
2143 
2144   vcd_assert (n == p_obj->ext_file_start_extent);
2145 
2146   for (;n < p_obj->custom_file_start_extent; n++)
2147     {
2148       const void *content = NULL;
2149       uint8_t flags = SM_DATA;
2150       uint8_t fileno = _vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD) ? 0 : 1;
2151 
2152       content = _dict_get_sector (p_obj, n);
2153       flags |= _dict_get_sector_flags (p_obj, n);
2154 
2155       if (content == NULL)
2156         {
2157           vcd_debug ("unexpected empty EXT sector");
2158           content = zero;
2159         }
2160 
2161       _write_m2_image_sector (p_obj, content, n, fileno, 0, flags, 0);
2162     }
2163 
2164   /* write custom files */
2165 
2166   vcd_assert (n == p_obj->custom_file_start_extent);
2167 
2168   _CDIO_LIST_FOREACH (node, p_obj->custom_file_list)
2169     {
2170       custom_file_t *p = _cdio_list_node_data (node);
2171 
2172       vcd_info ("writing file `%s' (%lu bytes%s)",
2173                 p->iso_pathname, (unsigned long) p->size,
2174                 p->raw_flag ? ", raw sectors file": "");
2175       if (p->raw_flag)
2176         _write_source_mode2_raw (p_obj, p->file, p->start_extent);
2177       else
2178         _write_source_mode2_form1 (p_obj, p->file, p->start_extent);
2179     }
2180 
2181   /* blank unalloced tracks */
2182   while ((n = _vcd_salloc (p_obj->iso_bitmap, SECTOR_NIL, 1)) < p_obj->iso_size)
2183     _write_m2_image_sector (p_obj, zero, n, 0, 0, SM_DATA, 0);
2184 
2185   return 0;
2186 }
2187 
2188 
2189 long
vcd_obj_get_image_size(VcdObj_t * p_obj)2190 vcd_obj_get_image_size (VcdObj_t *p_obj)
2191 {
2192   long size_sectors = -1;
2193 
2194   vcd_assert (!p_obj->in_output);
2195 
2196   if (_cdio_list_length (p_obj->mpeg_sequence_list) > 0)
2197     {
2198       /* fixme -- make this efficient */
2199       size_sectors = vcd_obj_begin_output (p_obj);
2200       vcd_obj_end_output (p_obj);
2201     }
2202 
2203   return size_sectors;
2204 }
2205 
2206 long
vcd_obj_begin_output(VcdObj_t * p_obj)2207 vcd_obj_begin_output (VcdObj_t *p_obj)
2208 {
2209   uint32_t image_size;
2210 
2211   vcd_assert (p_obj != NULL);
2212   vcd_assert (_cdio_list_length (p_obj->mpeg_sequence_list) > 0);
2213 
2214   vcd_assert (!p_obj->in_output);
2215   p_obj->in_output = true;
2216 
2217   p_obj->in_track = 1;
2218   p_obj->sectors_written = 0;
2219 
2220   p_obj->iso_bitmap = _vcd_salloc_new ();
2221 
2222   p_obj->dir = _vcd_directory_new ();
2223 
2224   p_obj->buffer_dict_list = _cdio_list_new ();
2225 
2226   _finalize_vcd_iso_track (p_obj);
2227 
2228   _update_entry_points (p_obj);
2229 
2230   image_size = p_obj->relative_end_extent + p_obj->iso_size;
2231 
2232   image_size += p_obj->leadout_pregap;
2233 
2234   if (image_size > CDIO_CD_MAX_SECTORS)
2235     vcd_error ("image too big (%d sectors > %d sectors)",
2236                (unsigned) image_size, (unsigned) CDIO_CD_MAX_SECTORS);
2237 
2238   {
2239     char *_tmp = cdio_lba_to_msf_str (image_size);
2240 
2241     if (image_size > CDIO_CD_74MIN_SECTORS)
2242       vcd_warn ("generated image (%d sectors [%s]) may not fit "
2243                 "on 74min CDRs (%d sectors)",
2244                 (unsigned) image_size, _tmp, (unsigned) CDIO_CD_74MIN_SECTORS);
2245 
2246     free (_tmp);
2247   }
2248 
2249   return image_size;
2250 }
2251 
2252 void
vcd_obj_end_output(VcdObj_t * p_obj)2253 vcd_obj_end_output (VcdObj_t *p_obj)
2254 {
2255   vcd_assert (p_obj != NULL);
2256 
2257   vcd_assert (p_obj->in_output);
2258   p_obj->in_output = false;
2259 
2260   _vcd_directory_destroy (p_obj->dir);
2261   _vcd_salloc_destroy (p_obj->iso_bitmap);
2262 
2263   _dict_clean (p_obj);
2264   _cdio_list_free (p_obj->buffer_dict_list, true, (CdioDataFree_t) &dict_free);
2265 }
2266 
2267 int
vcd_obj_append_pbc_node(VcdObj_t * p_obj,struct _pbc_t * p_pbc)2268 vcd_obj_append_pbc_node (VcdObj_t *p_obj, struct _pbc_t *p_pbc)
2269 {
2270   vcd_assert (p_obj != NULL);
2271   vcd_assert (p_pbc != NULL);
2272 
2273   if (!_vcd_obj_has_cap_p (p_obj, _CAP_PBC))
2274     {
2275       vcd_error ("PBC not supported for current VCD type");
2276       return -1;
2277     }
2278 
2279   if (p_pbc->item_id && _vcd_pbc_lookup (p_obj, p_pbc->item_id))
2280     {
2281       vcd_error ("item id (%s) exists already", p_pbc->item_id);
2282       return -1;
2283     }
2284 
2285   _cdio_list_append (p_obj->pbc_list, p_pbc);
2286 
2287   return 0;
2288 }
2289 
2290 int
vcd_obj_write_image(VcdObj_t * p_obj,VcdImageSink_t * p_image_sink,progress_callback_t callback,void * user_data,const time_t * p_create_time)2291 vcd_obj_write_image (VcdObj_t *p_obj, VcdImageSink_t *p_image_sink,
2292                      progress_callback_t callback, void *user_data,
2293                      const time_t *p_create_time)
2294 {
2295   CdioListNode_t *node;
2296 
2297   vcd_assert (p_obj != NULL);
2298   vcd_assert (p_obj->in_output);
2299 
2300   if (!p_image_sink)
2301     return -1;
2302 
2303   /* start with meta info */
2304 
2305   {
2306     CdioList_t *p_cue_list;
2307     vcd_cue_t *p_cue;
2308 
2309     p_cue_list = _cdio_list_new ();
2310 
2311     _cdio_list_append (p_cue_list, (p_cue = calloc(1, sizeof (vcd_cue_t))));
2312 
2313     p_cue->lsn = 0;
2314     p_cue->type = VCD_CUE_TRACK_START;
2315 
2316     _CDIO_LIST_FOREACH (node, p_obj->mpeg_sequence_list)
2317       {
2318         mpeg_sequence_t *p_track = _cdio_list_node_data (node);
2319         CdioListNode_t *p_entry_node;
2320 
2321         _cdio_list_append (p_cue_list,
2322                            (p_cue = calloc(1, sizeof (vcd_cue_t))));
2323 
2324         p_cue->lsn = p_track->relative_start_extent + p_obj->iso_size;
2325         p_cue->lsn -= p_obj->track_pregap;
2326         p_cue->type = VCD_CUE_PREGAP_START;
2327 
2328         _cdio_list_append (p_cue_list,
2329                            (p_cue = calloc(1, sizeof (vcd_cue_t))));
2330 
2331         p_cue->lsn = p_track->relative_start_extent + p_obj->iso_size;
2332         p_cue->type = VCD_CUE_TRACK_START;
2333 
2334         _CDIO_LIST_FOREACH (p_entry_node, p_track->entry_list)
2335           {
2336             entry_t *_entry = _cdio_list_node_data (p_entry_node);
2337 
2338             _cdio_list_append (p_cue_list,
2339                                (p_cue = calloc(1, sizeof (vcd_cue_t))));
2340 
2341             p_cue->lsn = p_obj->iso_size;
2342             p_cue->lsn += p_track->relative_start_extent;
2343             p_cue->lsn += p_obj->track_front_margin;
2344             p_cue->lsn += _entry->aps.packet_no;
2345 
2346             p_cue->type = VCD_CUE_SUBINDEX;
2347           }
2348       }
2349 
2350     /* add last one... */
2351 
2352     _cdio_list_append (p_cue_list, (p_cue = calloc(1, sizeof (vcd_cue_t))));
2353 
2354     p_cue->lsn = p_obj->relative_end_extent + p_obj->iso_size;
2355 
2356     p_cue->lsn += p_obj->leadout_pregap;
2357 
2358     p_cue->type = VCD_CUE_END;
2359 
2360     /* send it to image object */
2361 
2362     vcd_image_sink_set_cuesheet (p_image_sink, p_cue_list);
2363 
2364     _cdio_list_free (p_cue_list, true, (CdioDataFree_t) &cue_data_free);
2365   }
2366 
2367   /* and now for the pay load */
2368 
2369   {
2370     unsigned int track;
2371 
2372     vcd_assert (p_obj != NULL);
2373     vcd_assert (p_obj->sectors_written == 0);
2374 
2375     vcd_assert (p_obj->in_output);
2376 
2377     p_obj->progress_callback = callback;
2378     p_obj->callback_user_data = user_data;
2379     p_obj->image_sink = p_image_sink;
2380 
2381     if (_callback_wrapper (p_obj, true))
2382       return 1;
2383 
2384     if (_write_vcd_iso_track (p_obj, p_create_time))
2385       return 1;
2386 
2387     if (p_obj->update_scan_offsets)
2388       vcd_info ("'update scan offsets' option enabled for "
2389                 "the following tracks!");
2390 
2391     for (track = 0;
2392          track < _cdio_list_length (p_obj->mpeg_sequence_list);
2393          track++)
2394       {
2395         p_obj->in_track++;
2396 
2397         if (_callback_wrapper (p_obj, true))
2398           return 1;
2399 
2400         if (_write_sequence (p_obj, track))
2401           return 1;
2402       }
2403 
2404     if (p_obj->leadout_pregap)
2405       {
2406         int n, lastsect = p_obj->sectors_written;
2407 
2408         vcd_debug ("writting post-gap ('leadout pregap')...");
2409 
2410         for (n = 0; n < p_obj->leadout_pregap; n++)
2411           _write_m2_image_sector (p_obj, zero, lastsect++, 0, 0, SM_FORM2, 0);
2412       }
2413 
2414     if (_callback_wrapper (p_obj, true))
2415       return 1;
2416 
2417     p_obj->image_sink = NULL;
2418 
2419     vcd_image_sink_destroy (p_image_sink);
2420 
2421     return 0; /* ok */
2422   }
2423 }
2424 
2425 const char *
vcd_version_string(bool full_text)2426 vcd_version_string (bool full_text)
2427 {
2428   if (!full_text)
2429     return ("GNU VCDImager " VERSION " [" HOST_ARCH "]");
2430 
2431   return ("%s (GNU VCDImager) " VERSION "\n"
2432           "Written by Herbert Valerio Riedel and Rocky Bernstein.\n"
2433           "\n"
2434           "http://www.gnu.org/software/vcdimager/\n"
2435           "\n"
2436           "Copyright (C) 2000-2003 Herbert Valerio Riedel <hvr@gnu.org>\n"
2437 	  "                   2003 Rocky Bernstein <rocky@gnu.org>\n"
2438           "\n"
2439           "This is free software; see the source for copying conditions.  There is NO\n"
2440           "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
2441 }
2442 
2443 
2444 /*
2445  * Local variables:
2446  *  c-file-style: "gnu"
2447  *  tab-width: 8
2448  *  indent-tabs-mode: nil
2449  * End:
2450  */
2451