Separate out STL binary tables so that writer can use them; start of writer.
[libsub.git] / src / stl_binary_writer.cc
1 /*
2     Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "stl_binary_writer.h"
21 #include "compose.hpp"
22 #include <list>
23 #include <cmath>
24 #include <fstream>
25 #include <iomanip>
26
27 using std::list;
28 using std::ofstream;
29 using std::string;
30 using std::setw;
31 using std::setfill;
32 using namespace sub;
33
34 static void
35 put_string (char* p, string s)
36 {
37         memcpy (p, s.c_str (), s.length ());
38 }
39
40 static void
41 put_string (char* p, unsigned int n, string s)
42 {
43         assert (s.length() <= n);
44         
45         memcpy (p, s.c_str (), s.length ());
46         memset (p + s.length(), ' ', n - s.length ());
47 }
48
49 static void
50 put_int (char* p, int v, unsigned int n)
51 {
52         std::stringstream s;
53         /* Be careful to ensure we get no thousands separators */
54         s.imbue (std::locale::classic ());
55         s << setw (n) << setfill ('0');
56         s << v;
57         assert (s.str().length() == n);
58         put_string (p, s.str ());
59 }
60
61 /** @param language ISO 3-character country code for the language of the subtitles */
62 void
63 sub::write_stl_binary (
64         list<Subtitle> subtitles,
65         float frames_per_second,
66         Language language,
67         string original_programme_title,
68         string original_episode_title,
69         string translated_programme_title,
70         string translated_episode_title,
71         string translator_name,
72         string translator_contact_details,
73         string creation_date,
74         string revision_date,
75         int revision_number,
76         string country_of_origin,
77         string publisher,
78         string editor_name,
79         string editor_contact_details,
80         boost::filesystem::path file_name
81         )
82 {
83         assert (original_programme_title.size() <= 32);
84         assert (original_episode_title.size() <= 32);
85         assert (translated_programme_title.size() <= 32);
86         assert (translated_episode_title.size() <= 32);
87         assert (translator_name.size() <= 32);
88         assert (translator_contact_details.size() <= 32);
89         assert (creation_date.size() == 6);
90         assert (revision_date.size() == 6);
91         assert (revision_number <= 99);
92         assert (country_of_origin.size() == 3);
93         assert (publisher.size() <= 32);
94         assert (editor_name.size() <= 32);
95         assert (editor_contact_details.size() <= 32);
96         
97         char* buffer = new char[1024];
98         ofstream output (file_name.string().c_str ());
99         STLBinaryTables tables;
100         
101         /* Code page: 850 */
102         put_string (buffer + 0, "850");
103         /* Disk format code */
104         put_string (buffer + 3, String::compose ("STL%1.01", rint (frames_per_second)));
105         /* Display standard code: open subtitling */
106         put_string (buffer + 11, "0");
107         /* Character code table: Latin (ISO 6937) */
108         put_string (buffer + 12, "00");
109         put_string (buffer + 14, tables.language_enum_to_file (language));
110         put_string (buffer + 16, 32, original_programme_title);
111         put_string (buffer + 48, 32, original_episode_title);
112         put_string (buffer + 80, 32, translated_programme_title);
113         put_string (buffer + 112, 32, translated_episode_title);
114         put_string (buffer + 144, 32, translator_name);
115         put_string (buffer + 176, 32, translator_contact_details);
116         /* Subtitle list reference code */
117         put_string (buffer + 208, "0000000000000000");
118         put_string (buffer + 224, creation_date);
119         put_string (buffer + 230, revision_date);
120         put_int (buffer + 236, revision_number, 2);
121         /* TTI blocks */
122         put_int (buffer + 238, subtitles.size (), 5);
123         /* Total number of subtitles */
124         put_int (buffer + 243, subtitles.size (), 5);
125         /* Total number of subtitle groups */
126         put_string (buffer + 248, "000");
127         /* Maximum number of displayable characters in any text row */
128         /* XXX */
129         put_string (buffer + 251, "99");
130         /* Maximum number of displayable rows */
131         /* XXX */
132         put_string (buffer + 253, "99");
133         /* Time code status */
134         put_string (buffer + 255, "1");
135         /* Start-of-programme time code */
136         put_string (buffer + 256, "00000000");
137         /* First-in-cue time code */
138         put_string (buffer + 264, "00000000");
139         /* Total number of disks */
140         put_string (buffer + 272, "1");
141         /* Disk sequence number */
142         put_string (buffer + 273, "1");
143         put_string (buffer + 274, 32, country_of_origin);
144         put_string (buffer + 277, 32, publisher);
145         put_string (buffer + 309, 32, editor_name);
146         put_string (buffer + 341, 32, editor_contact_details);
147
148         output.write (buffer, 1024);
149
150         delete[] buffer;
151 }