1 /*
2  * avisubdump
3  *
4  * avi vobsub subtitle stream dumper (c) 2004 Tobias Diedrich
5  *
6  * The subtitles are dumped to stdout.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22 
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 
30 #define FCC(a,b,c,d)  (((a))|((b)<<8)|((c)<<16)|((d)<<24))
31 
32 #define FCC_RIFF FCC('R','I','F','F')
33 #define FCC_LIST FCC('L','I','S','T')
34 #define FCC_strh FCC('s','t','r','h')
35 #define FCC_txts FCC('t','x','t','s')
36 #define FCC_GAB2 FCC('G','A','B','2')
37 
38 #define GAB_LANGUAGE            0
39 #define GAB_ENTRY               1
40 #define GAB_LANGUAGE_UNICODE    2
41 #define GAB_ENTRY_UNICODE       3
42 #define GAB_RAWTEXTSUBTITLE     4
43 
getle16(FILE * f)44 static unsigned int getle16(FILE* f){
45 	unsigned int res;
46 
47 	res  = fgetc(f);
48 	res |= fgetc(f) << 8;
49 
50 	return res;
51 }
52 
getle(FILE * f)53 static unsigned int getle(FILE* f){
54 	unsigned int res;
55 
56 	res  = fgetc(f);
57 	res |= fgetc(f) << 8;
58 	res |= fgetc(f) << 16;
59 	res |= fgetc(f) << 24;
60 
61 	return res;
62 }
63 
skip(FILE * f,int len)64 static void skip(FILE *f, int len)
65 {
66 	if (f != stdin) {
67 		fseek(f,len,SEEK_CUR);
68 	} else {
69 		void *buf = malloc(len);
70 		fread(buf,len,1,f);
71 		free(buf);
72 	}
73 }
74 
stream_id(unsigned int id)75 static int stream_id(unsigned int id)
76 {
77 	char c1,c2;
78 	c1 = (char)(id & 0xff);
79 	c2 = (char)((id >> 8) & 0xff);
80 	if (c1 >= '0' && c1 <= '9' &&
81 	    c2 >= '0' && c2 <= '9') {
82 		c1 -= '0';
83 		c2 -= '0';
84 		return c1*10+c2;
85 	}
86 	return -1;
87 }
88 
dumpsub_gab2(FILE * f,int size)89 static int dumpsub_gab2(FILE *f, int size) {
90 	int ret = 0;
91 
92 	while (ret + 6 <= size) {
93 		unsigned int len, id;
94 		char *buf;
95 		int i;
96 
97 		id = getle16(f); ret += 2;
98 		len = getle(f); ret += 4;
99 		if (ret + len > size) break;
100 
101 		buf = malloc(len);
102 		ret += fread(buf, 1, len, f);
103 
104 		switch (id) {
105 		case GAB_LANGUAGE_UNICODE: /* FIXME: convert to utf-8; endianness */
106 			for (i=0; i<len; i++) buf[i] = buf[i*2];
107 		case GAB_LANGUAGE:
108 			fprintf(stderr, "LANGUAGE: %s\n", buf);
109 			break;
110 		case GAB_ENTRY_UNICODE: /* FIXME: convert to utf-8; endianness */
111 			for (i=0; i<len; i++) buf[i] = buf[i*2];
112 		case GAB_ENTRY:
113 			fprintf(stderr, "ENTRY: %s\n", buf);
114 			break;
115 		case GAB_RAWTEXTSUBTITLE:
116 			printf("%s", buf);
117 			break;
118 		default:
119 			fprintf(stderr, "Unknown type %d, len %d\n", id, len);
120 			break;
121 		}
122 		free(buf);
123 	}
124 
125 	return ret;
126 }
127 
dump(FILE * f)128 static void dump(FILE *f) {
129 	unsigned int id, len;
130 	int stream = 0;
131 	int substream = -2;
132 
133 	while (1) {
134 		id = getle(f);
135 		len = getle(f);
136 
137 		if(feof(f)) break;
138 
139 		if (id == FCC_RIFF ||
140 		    id == FCC_LIST) {
141 			getle(f);
142 			continue;
143 		} else if (id == FCC_strh) {
144 			id = getle(f); len -= 4;
145 			fprintf(stderr, "Stream %d is %c%c%c%c",
146 			       stream,
147 			       id,
148 			       id >> 8,
149 			       id >> 16,
150 			       id >> 24);
151 			if (id == FCC_txts) {
152 				substream = stream;
153 				fprintf(stderr, " (subtitle stream)");
154 			}
155 			fprintf(stderr, ".\n");
156 			stream++;
157 		} else if (stream_id(id) == substream) {
158 			unsigned int subid;
159 			subid = getle(f); len -= 4;
160 			if (subid != FCC_GAB2) {
161 				fprintf(stderr,
162 				        "Unknown subtitle chunk %c%c%c%c (%08x).\n",
163 				        id, id >> 8, id >> 16, id >> 24, subid);
164 			} else {
165 				skip(f,1); len -= 1;
166 				len -= dumpsub_gab2(f, len);
167 			}
168 		}
169 		len+=len&1;
170 		skip(f,len);
171 	}
172 }
173 
main(int argc,char * argv[])174 int main(int argc,char* argv[])
175 {
176 	FILE* f;
177 
178 	if (argc != 2) {
179 		fprintf(stderr, "Usage: %s <avi>\n", argv[0]);
180 		exit(1);
181 	}
182 
183 	if (strcmp(argv[argc-1], "-") == 0) {
184 		dump(stdin);
185 		return 0;
186 	}
187 
188 	f=fopen(argv[argc-1],"rb");
189 
190 	if (!f) {
191 		fprintf(stderr, "Could not open '%s': %s\n",
192 		        argv[argc-1], strerror(errno));
193 		exit(-errno);
194 	}
195 
196 	dump(f);
197 	fclose(f);
198 
199 	return 0;
200 }
201