1 /*
2  * Copyright (c) 2009-2014 Kuan-Chung Chiu <buganini@gmail.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
13  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
14  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 #include <bsdconv.h>
17 
18 #include "EXTERN.h"
19 #include "perl.h"
20 #include "XSUB.h"
21 
22 #include "ppport.h"
23 #include <errno.h>
24 #include <stdio.h>
25 #include <string.h>
26 
27 #ifndef WIN32
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #endif
32 
33 typedef struct bsdconv_instance * Bsdconv;
34 typedef FILE * Bsdconv_file;
35 
36 #define IBUFLEN 1024
37 #define TEMPLATE "bsdconv(\"%s\")"
38 
39 MODULE = bsdconv		PACKAGE = bsdconv
40 
41 BOOT:
42 {
43 	HV *m;
44 
45 	m = gv_stashpv("bsdconv", TRUE);
46 	newCONSTSUB(m, "FILTER", newSViv(FILTER));
47 	newCONSTSUB(m, "FROM", newSViv(FROM));
48 	newCONSTSUB(m, "INTER", newSViv(INTER));
49 	newCONSTSUB(m, "TO", newSViv(TO));
50 
51 	newCONSTSUB(m, "CTL_ATTACH_SCORE", newSViv(BSDCONV_CTL_ATTACH_SCORE));
52 	newCONSTSUB(m, "CTL_ATTACH_OUTPUT_FILE", newSViv(BSDCONV_CTL_ATTACH_OUTPUT_FILE));
53 	newCONSTSUB(m, "CTL_AMBIGUOUS_PAD", newSViv(BSDCONV_CTL_AMBIGUOUS_PAD));
54 }
55 
56 SV*
57 insert_phase(conversion, codecs, phase_type, ophasen)
58 	char* conversion
59 	char* codecs
60 	int phase_type
61 	int ophasen
62 	PREINIT:
63 		char *s;
64 	CODE:
65 		s=bsdconv_insert_phase(conversion, codecs, phase_type, ophasen);
66 		RETVAL=newSVpv(s, 0);
67 		bsdconv_free(s);
68 	OUTPUT:
69 		RETVAL
70 
71 SV*
72 insert_codec(conversion, codec, ophasen, ocodecn)
73 	char* conversion
74 	char* codec
75 	int ophasen
76 	int ocodecn
77 	PREINIT:
78 		char *s;
79 	CODE:
80 		s=bsdconv_insert_codec(conversion, codec, ophasen, ocodecn);
81 		RETVAL=newSVpv(s, 0);
82 		bsdconv_free(s);
83 	OUTPUT:
84 		RETVAL
85 
86 SV*
87 replace_phase(conversion, codecs, phase_type, ophasen)
88 	char* conversion
89 	char* codecs
90 	int phase_type
91 	int ophasen
92 	PREINIT:
93 		char *s;
94 	CODE:
95 		s=bsdconv_replace_phase(conversion, codecs, phase_type, ophasen);
96 		RETVAL=newSVpv(s, 0);
97 		bsdconv_free(s);
98 	OUTPUT:
99 		RETVAL
100 
101 SV*
102 replace_codec(conversion, codec, ophasen, ocodecn)
103 	char* conversion
104 	char* codec
105 	int ophasen
106 	int ocodecn
107 	PREINIT:
108 		char *s;
109 	CODE:
110 		s=bsdconv_replace_codec(conversion, codec, ophasen, ocodecn);
111 		RETVAL=newSVpv(s, 0);
112 		bsdconv_free(s);
113 	OUTPUT:
114 		RETVAL
115 
116 
117 SV*
118 error()
119 	PREINIT:
120 		char *s;
121 	CODE:
122 		s=bsdconv_error();
123 		RETVAL=newSVpv(s, 0);
124 		bsdconv_free(s);
125 	OUTPUT:
126 		RETVAL
127 
128 SV*
129 module_check(phase_type, codec)
130 	int phase_type
131 	char *codec
132 	CODE:
133 		if(bsdconv_module_check(phase_type, codec))
134 			XSRETURN_YES;
135 		XSRETURN_NO;
136 	OUTPUT:
137 		RETVAL
138 
139 SV*
140 codec_check(phase_type, codec)
141 	int phase_type
142 	char *codec
143 	CODE:
144 		if(bsdconv_module_check(phase_type, codec))
145 			XSRETURN_YES;
146 		XSRETURN_NO;
147 	OUTPUT:
148 		RETVAL
149 
150 AV*
151 modules_list(phase_type)
152 	int phase_type
153 	PREINIT:
154 		char **list;
155 		char **p;
156 	CODE:
157 		RETVAL=newAV();
158 		list=bsdconv_modules_list(phase_type);
159 		p=list;
160 		while(*p!=NULL){
161 			av_push(RETVAL, newSVpv(*p, 0));
162 			bsdconv_free(*p);
163 			p+=1;
164 		}
165 		bsdconv_free(list);
166 	OUTPUT:
167 		RETVAL
168 
169 AV*
170 codecs_list(phase_type)
171 	int phase_type
172 	PREINIT:
173 		char **list;
174 		char **p;
175 	CODE:
176 		RETVAL=newAV();
177 		list=bsdconv_modules_list(phase_type);
178 		p=list;
179 		while(*p!=NULL){
180 			av_push(RETVAL, newSVpv(*p, 0));
181 			bsdconv_free(*p);
182 			p+=1;
183 		}
184 		bsdconv_free(list);
185 	OUTPUT:
186 		RETVAL
187 
188 AV*
189 mktemp(template)
190 	char *template
191 	CODE:
192 		char *fn=strdup(template);
193 		int fd=bsdconv_mkstemp(fn);
194 		if(fd==-1)
195 			XSRETURN_UNDEF;
196 		FILE *fp=fdopen(fd, "wb+");
197 		SV *bsdconv_file=sv_newmortal();
198 		sv_setref_pv(bsdconv_file,"Bsdconv_file",(void *) fp);
199 		RETVAL=newAV();
200 		av_push(RETVAL, newSVsv(bsdconv_file));
201 		av_push(RETVAL, newSVpv(fn, 0));
202 	OUTPUT:
203 		RETVAL
204 
205 Bsdconv_file
206 fopen(filename, mode)
207 	char *filename
208 	char *mode
209 	CODE:
210 		RETVAL=fopen(filename, mode);
211 	OUTPUT:
212 		RETVAL
213 
214 Bsdconv
215 new(package, conversion)
216 	char *package
217 	char *conversion
218 	CODE:
219 		RETVAL=bsdconv_create(conversion);
220 	OUTPUT:
221 		RETVAL
222 
223 MODULE = bsdconv		PACKAGE = Bsdconv
224 
225 void
226 DESTROY(ins)
227 	Bsdconv ins
228 	CODE:
229 		bsdconv_destroy(ins);
230 
231 SV*
232 toString(ins)
233 	Bsdconv ins
234 	PREINIT:
235 		char *s;
236 		char *s2;
237 		int len;
238 	CODE:
239 		len=sizeof(TEMPLATE);
240 		s=bsdconv_pack(ins);
241 		len+=strlen(s);
242 		s2=malloc(len);
243 		sprintf(s2, TEMPLATE, s);
244 		bsdconv_free(s);
245 		RETVAL=newSVpv(s2, 0);
246 		free(s2);
247 	OUTPUT:
248 		RETVAL
249 
250 void
251 init(ins)
252 	Bsdconv ins
253 	CODE:
254 		bsdconv_init(ins);
255 
256 void
257 ctl(ins, ctl, res, num)
258 	Bsdconv ins
259 	int ctl
260 	SV* res
261 	int num
262 	CODE:
263 		void *ptr=NULL;
264 		if(sv_derived_from(res,"Bsdconv_file")){
265 			IV tmp = SvIV((SV*)SvRV(res));
266 			ptr=(void *)tmp;
267 		}
268 		bsdconv_ctl(ins, ctl, ptr, num);
269 
270 SV*
271 conv_chunk(ins, str)
272 	Bsdconv ins
273 	SV* str
274 	PREINIT:
275 		char *s;
276 		SSize_t l;
277 	CODE:
278 		s=SvPV(str, l);
279 
280 		ins->output_mode=BSDCONV_AUTOMALLOC;
281 		ins->input.data=s;
282 		ins->input.len=l;
283 		ins->input.flags=0;
284 		ins->input.next=NULL;
285 		bsdconv(ins);
286 
287 		RETVAL=newSVpvn(ins->output.data, (STRLEN)ins->output.len);
288 		bsdconv_free(ins->output.data);
289 	OUTPUT:
290 		RETVAL
291 
292 SV*
293 conv_chunk_last(ins, str)
294 	Bsdconv ins
295 	SV* str
296 	PREINIT:
297 		char *s;
298 		SSize_t l;
299 	CODE:
300 		s=SvPV(str, l);
301 
302 		ins->output_mode=BSDCONV_AUTOMALLOC;
303 		ins->input.data=s;
304 		ins->input.len=l;
305 		ins->input.flags=0;
306 		ins->input.next=NULL;
307 		ins->flush=1;
308 		bsdconv(ins);
309 
310 		RETVAL=newSVpvn(ins->output.data, (STRLEN)ins->output.len);
311 		bsdconv_free(ins->output.data);
312 	OUTPUT:
313 		RETVAL
314 
315 SV*
316 conv(ins, str)
317 	Bsdconv ins
318 	SV* str
319 	PREINIT:
320 		char *s;
321 		SSize_t l;
322 	CODE:
323 		s=SvPV(str, l);
324 
325 		bsdconv_init(ins);
326 		ins->output_mode=BSDCONV_AUTOMALLOC;
327 		ins->input.data=s;
328 		ins->input.len=l;
329 		ins->input.flags=0;
330 		ins->input.next=NULL;
331 		ins->flush=1;
332 		bsdconv(ins);
333 
334 		RETVAL=newSVpvn(ins->output.data, (STRLEN)ins->output.len);
335 		bsdconv_free(ins->output.data);
336 	OUTPUT:
337 		RETVAL
338 
339 SV*
340 conv_file(ins, f1, f2)
341 	Bsdconv ins
342 	SV* f1
343 	SV* f2
344 	PREINIT:
345 		char *s1, *s2;
346 		SSize_t l;
347 		FILE *inf, *otf;
348 		char *in;
349 		char *tmp;
350 		int fd;
351 	CODE:
352 		s1=SvPV(f1, l);
353 		s2=SvPV(f2, l);
354 		inf=fopen(s1,"r");
355 		if(!inf) XSRETURN_UNDEF;
356 		tmp=malloc(l+8);
357 		strcpy(tmp, s2);
358 		strcat(tmp, ".XXXXXX");
359 		if((fd=mkstemp(tmp))==-1){
360 			free(tmp);
361 			XSRETURN_UNDEF;
362 		}
363 		otf=fdopen(fd,"w");
364 		if(!otf){
365 			free(tmp);
366 			XSRETURN_UNDEF;
367 		}
368 #ifndef WIN32
369 		struct stat stat;
370 		fstat(fileno(inf), &stat);
371 		fchown(fileno(otf), stat.st_uid, stat.st_gid);
372 		fchmod(fileno(otf), stat.st_mode);
373 #endif
374 		bsdconv_init(ins);
375 		do{
376 			in=bsdconv_malloc(IBUFLEN);
377 			ins->input.data=in;
378 			ins->input.len=fread(in, 1, IBUFLEN, inf);
379 			ins->input.flags|=F_FREE;
380 			ins->input.next=NULL;
381 			if(ins->input.len==0){
382 				ins->flush=1;
383 			}
384 			ins->output_mode=BSDCONV_FILE;
385 			ins->output.data=otf;
386 			bsdconv(ins);
387 		}while(ins->flush==0);
388 
389 		fclose(inf);
390 		fclose(otf);
391 		unlink(s2);
392 		rename(tmp,s2);
393 		free(tmp);
394 		XSRETURN_YES;
395 	OUTPUT:
396 		RETVAL
397 
398 void
399 counter(ins, ...)
400 	Bsdconv ins
401 	PREINIT:
402 		char *key;
403 		HV *hash;
404 		struct bsdconv_counter_entry *p;
405 		bsdconv_counter_t *v;
406 	PPCODE:
407 		if(items > 1){
408 			key=(char *)SvPV_nolen(ST(1));
409 			v=bsdconv_counter(ins, key);
410 			PUSHs(sv_2mortal(newSViv(*v)));
411 		}else{
412 			hash=(HV *)sv_2mortal((SV *)newHV());
413 			p=ins->counter;
414 			while(p){
415 				hv_store(hash, p->key, strlen(p->key), newSVuv(p->val), 0);
416 				p=p->next;
417 			}
418 			EXTEND(SP, 1);
419 			PUSHs(newRV_noinc((SV *)hash));
420 		}
421 
422 void
counter_reset(ins,...)423 counter_reset(ins, ...)
424 	Bsdconv ins
425 	PREINIT:
426 		char *key;
427 	PPCODE:
428 		if(items > 1){
429 			key=(char *)SvPV_nolen(ST(1));
430 			bsdconv_counter_reset(ins, key);
431 		}else{
432 			bsdconv_counter_reset(ins, NULL);
433 		}
434 
435 MODULE = bsdconv		PACKAGE = Bsdconv_file
436 
437 void
438 DESTROY(fp)
439 	Bsdconv_file fp
440 	CODE:
441 		fclose(fp);
442