1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 1993-2003 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
28*7c478bd9Sstevel@tonic-gate #include <stdio.h>
29*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
30*7c478bd9Sstevel@tonic-gate #include <string.h>
31*7c478bd9Sstevel@tonic-gate #include <unistd.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include <Audio.h>
38*7c478bd9Sstevel@tonic-gate #include <AudioFile.h>
39*7c478bd9Sstevel@tonic-gate #include <AudioPipe.h>
40*7c478bd9Sstevel@tonic-gate #include <AudioRawPipe.h>
41*7c478bd9Sstevel@tonic-gate #include <AudioLib.h>
42*7c478bd9Sstevel@tonic-gate #include <AudioHdr.h>
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate #include <libaudio.h>
45*7c478bd9Sstevel@tonic-gate #include <audio/au.h>
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate extern char *Stdin;
48*7c478bd9Sstevel@tonic-gate extern char *Stdout;
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate #include <convert.h>
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate // append contents of buffer to output audio stream.
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate AudioError
write_output(AudioBuffer * buf,AudioStream * ofp)55*7c478bd9Sstevel@tonic-gate write_output(AudioBuffer* buf, AudioStream* ofp)
56*7c478bd9Sstevel@tonic-gate {
57*7c478bd9Sstevel@tonic-gate 	unsigned char 	*cp;
58*7c478bd9Sstevel@tonic-gate 	size_t		len;
59*7c478bd9Sstevel@tonic-gate 	Double		pos;
60*7c478bd9Sstevel@tonic-gate 	AudioError	err;
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate 	pos = ofp->GetLength();
63*7c478bd9Sstevel@tonic-gate 	len = (size_t)buf->GetHeader().Time_to_Bytes(buf->GetLength());
64*7c478bd9Sstevel@tonic-gate 	cp = (unsigned char *)buf->GetAddress();
65*7c478bd9Sstevel@tonic-gate 	err = ofp->WriteData(cp, len, pos);
66*7c478bd9Sstevel@tonic-gate 	return (err);
67*7c478bd9Sstevel@tonic-gate }
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate // open input file and return ptr to AudioUnixFile object
70*7c478bd9Sstevel@tonic-gate // path is the path to the file (or set to Stdin if standard input).
71*7c478bd9Sstevel@tonic-gate // ihdr is the input header (only used for openning raw files)
72*7c478bd9Sstevel@tonic-gate // israw flags if it's a raw file. if fflag is set, ignore an
73*7c478bd9Sstevel@tonic-gate // any existing header on raw files. offset indicates where to
74*7c478bd9Sstevel@tonic-gate // start reading the file (raw files only ??).
open_input_file(const char * path,const AudioHdr ihdr,int israw,int fflag,off_t offset,format_type & fmt)75*7c478bd9Sstevel@tonic-gate AudioUnixfile *open_input_file(const char *path, const AudioHdr ihdr,
76*7c478bd9Sstevel@tonic-gate 				    int israw, int fflag, off_t offset,
77*7c478bd9Sstevel@tonic-gate 				    format_type& fmt)
78*7c478bd9Sstevel@tonic-gate {
79*7c478bd9Sstevel@tonic-gate 	AudioUnixfile*	ifp;
80*7c478bd9Sstevel@tonic-gate 	int		fd;
81*7c478bd9Sstevel@tonic-gate 	int		file_type; // ignore this ...
82*7c478bd9Sstevel@tonic-gate 	int		infosize; // ignore this ...
83*7c478bd9Sstevel@tonic-gate 	au_filehdr_t	fhdr;
84*7c478bd9Sstevel@tonic-gate 	Audio_hdr	ohdr;	// ignore this ...
85*7c478bd9Sstevel@tonic-gate 	unsigned int	hsize;
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate 	// need to let caller know what format this is. so far, only raw
88*7c478bd9Sstevel@tonic-gate 	// and sun are supported....
89*7c478bd9Sstevel@tonic-gate 	fmt = (israw ? F_RAW : F_SUN);
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate 	// no file
92*7c478bd9Sstevel@tonic-gate 	if (!path) {
93*7c478bd9Sstevel@tonic-gate 		// no file? shouldn't happen. bomb out.
94*7c478bd9Sstevel@tonic-gate 		Err(MGET("no input file specified\n"));
95*7c478bd9Sstevel@tonic-gate 		exit(1);
96*7c478bd9Sstevel@tonic-gate 	}
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate 	// deal with stdin
99*7c478bd9Sstevel@tonic-gate 	if (path == Stdin) {
100*7c478bd9Sstevel@tonic-gate 		if (isatty(fileno(stdin))) {
101*7c478bd9Sstevel@tonic-gate 			Err(MGET(
102*7c478bd9Sstevel@tonic-gate 			    "Stdin is a tty, please specify an input file\n"));
103*7c478bd9Sstevel@tonic-gate 			exit(1);
104*7c478bd9Sstevel@tonic-gate 		}
105*7c478bd9Sstevel@tonic-gate 		if (israw) {
106*7c478bd9Sstevel@tonic-gate 			// XXX - need to check if stdin has a file
107*7c478bd9Sstevel@tonic-gate 			// header and ignore it if fflag not set.
108*7c478bd9Sstevel@tonic-gate 			ifp = new AudioRawPipe(fileno(stdin),
109*7c478bd9Sstevel@tonic-gate 					    (FileAccess)ReadOnly, ihdr, path,
110*7c478bd9Sstevel@tonic-gate 					    offset);
111*7c478bd9Sstevel@tonic-gate 		} else {
112*7c478bd9Sstevel@tonic-gate 			ifp = new AudioPipe(fileno(stdin), (FileAccess)ReadOnly,
113*7c478bd9Sstevel@tonic-gate 					    path);
114*7c478bd9Sstevel@tonic-gate 		}
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 		if (!ifp) {
117*7c478bd9Sstevel@tonic-gate 			Err(MGET("can't open pipe to %s, skipping...\n"),
118*7c478bd9Sstevel@tonic-gate 			    Stdin);
119*7c478bd9Sstevel@tonic-gate 		}
120*7c478bd9Sstevel@tonic-gate 		return (ifp);
121*7c478bd9Sstevel@tonic-gate 	}
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 	// fall through for real files ...
124*7c478bd9Sstevel@tonic-gate 	if (israw) {
125*7c478bd9Sstevel@tonic-gate 		if ((fd = open(path, O_RDONLY)) < 0) {
126*7c478bd9Sstevel@tonic-gate 			Err(MGET("can't open %s, skipping...\n"), path);
127*7c478bd9Sstevel@tonic-gate 			perror(MGET("open"));
128*7c478bd9Sstevel@tonic-gate 			return (NULL);
129*7c478bd9Sstevel@tonic-gate 		}
130*7c478bd9Sstevel@tonic-gate 		if (!fflag) {
131*7c478bd9Sstevel@tonic-gate 			// check if file already has a hdr.
132*7c478bd9Sstevel@tonic-gate 			if (hsize = read(fd, (char *)&fhdr, sizeof (fhdr))
133*7c478bd9Sstevel@tonic-gate 			    < 0) {
134*7c478bd9Sstevel@tonic-gate 				perror("read");
135*7c478bd9Sstevel@tonic-gate 				exit(1);
136*7c478bd9Sstevel@tonic-gate 			}
137*7c478bd9Sstevel@tonic-gate 			if (lseek(fd, 0, 0) < 0) {  // reset
138*7c478bd9Sstevel@tonic-gate 				perror("lseek");
139*7c478bd9Sstevel@tonic-gate 				exit(1);
140*7c478bd9Sstevel@tonic-gate 			}
141*7c478bd9Sstevel@tonic-gate 			if (hsize != sizeof (fhdr)) {
142*7c478bd9Sstevel@tonic-gate 				// no hdr - file too small,
143*7c478bd9Sstevel@tonic-gate 				// assume data is ok (tho it
144*7c478bd9Sstevel@tonic-gate 				// probably won't be) ...
145*7c478bd9Sstevel@tonic-gate 				ifp = new AudioRawPipe(fd, (FileAccess)ReadOnly,
146*7c478bd9Sstevel@tonic-gate 							    ihdr, path, offset);
147*7c478bd9Sstevel@tonic-gate 			} else {
148*7c478bd9Sstevel@tonic-gate 				// Check the validity of the
149*7c478bd9Sstevel@tonic-gate 				// header and get the size of
150*7c478bd9Sstevel@tonic-gate 				// the info field
151*7c478bd9Sstevel@tonic-gate 				if (audio_decode_filehdr(fd,
152*7c478bd9Sstevel@tonic-gate 				    (unsigned char *)&fhdr, &file_type, &ohdr,
153*7c478bd9Sstevel@tonic-gate 				    &infosize) == AUDIO_SUCCESS) {
154*7c478bd9Sstevel@tonic-gate 					close(fd); // create AudioFile()
155*7c478bd9Sstevel@tonic-gate 					// issue a warning
156*7c478bd9Sstevel@tonic-gate 					Err(
157*7c478bd9Sstevel@tonic-gate 				MGET("%s has a file header, ignoring -i ...\n"),
158*7c478bd9Sstevel@tonic-gate 					    path);
159*7c478bd9Sstevel@tonic-gate 					fmt = F_SUN; // was raw ...
160*7c478bd9Sstevel@tonic-gate 					ifp = new AudioFile(path,
161*7c478bd9Sstevel@tonic-gate 						    (FileAccess)ReadOnly);
162*7c478bd9Sstevel@tonic-gate 				} else {
163*7c478bd9Sstevel@tonic-gate 					// no hdr, create AudioRawPipe.
164*7c478bd9Sstevel@tonic-gate 					ifp = new AudioRawPipe(fd,
165*7c478bd9Sstevel@tonic-gate 						    (FileAccess)ReadOnly, ihdr,
166*7c478bd9Sstevel@tonic-gate 						    path, offset);
167*7c478bd9Sstevel@tonic-gate 				}
168*7c478bd9Sstevel@tonic-gate 			}
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 		} else {	// force flag - don't even look for header
171*7c478bd9Sstevel@tonic-gate 			ifp = new AudioRawPipe(fd, (FileAccess)ReadOnly, ihdr,
172*7c478bd9Sstevel@tonic-gate 						    path, offset);
173*7c478bd9Sstevel@tonic-gate 		}
174*7c478bd9Sstevel@tonic-gate 	} else {
175*7c478bd9Sstevel@tonic-gate 		ifp = new AudioFile(path, (FileAccess)ReadOnly);
176*7c478bd9Sstevel@tonic-gate 	}
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 	if (!ifp) {
179*7c478bd9Sstevel@tonic-gate 		Err(MGET("can't open %s, skipping...\n"), path);
180*7c478bd9Sstevel@tonic-gate 	}
181*7c478bd9Sstevel@tonic-gate 	return (ifp);
182*7c478bd9Sstevel@tonic-gate }
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate // given a path, find the file it really points to (if it's a
185*7c478bd9Sstevel@tonic-gate // sym-link). return it's stat buf and real path.
186*7c478bd9Sstevel@tonic-gate void
get_realfile(char * & path,struct stat * st)187*7c478bd9Sstevel@tonic-gate get_realfile(char *&path, struct stat *st)
188*7c478bd9Sstevel@tonic-gate {
189*7c478bd9Sstevel@tonic-gate 	static char	tmpf[MAXPATHLEN]; // for reading sym-link
190*7c478bd9Sstevel@tonic-gate 	int		err;	// for stat err
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 	// first see if it's a sym-link and find real file
193*7c478bd9Sstevel@tonic-gate 	err = 0;
194*7c478bd9Sstevel@tonic-gate 	while (err == 0) {
195*7c478bd9Sstevel@tonic-gate 		if (err = lstat(path, st) < 0) {
196*7c478bd9Sstevel@tonic-gate 			perror("lstat");
197*7c478bd9Sstevel@tonic-gate 			exit(1);
198*7c478bd9Sstevel@tonic-gate 		}
199*7c478bd9Sstevel@tonic-gate 		if (!err && S_ISLNK(st->st_mode)) {
200*7c478bd9Sstevel@tonic-gate 			err = readlink(path, tmpf,
201*7c478bd9Sstevel@tonic-gate 					(sizeof (tmpf) - 1));
202*7c478bd9Sstevel@tonic-gate 			if (err > 0) {
203*7c478bd9Sstevel@tonic-gate 				tmpf[err] = '\0';
204*7c478bd9Sstevel@tonic-gate 				path = tmpf;
205*7c478bd9Sstevel@tonic-gate 				err = 0;
206*7c478bd9Sstevel@tonic-gate 			}
207*7c478bd9Sstevel@tonic-gate 		} else {
208*7c478bd9Sstevel@tonic-gate 			break;
209*7c478bd9Sstevel@tonic-gate 		}
210*7c478bd9Sstevel@tonic-gate 	}
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate }
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate // create output audio file. if no path is supplied, use stdout.
215*7c478bd9Sstevel@tonic-gate // returns a ptr to an AudioUnixFile object.
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate AudioUnixfile*
create_output_file(const char * path,const AudioHdr ohdr,format_type ofmt,const char * infoString)218*7c478bd9Sstevel@tonic-gate create_output_file(
219*7c478bd9Sstevel@tonic-gate 	const char *path,
220*7c478bd9Sstevel@tonic-gate 	const AudioHdr ohdr,
221*7c478bd9Sstevel@tonic-gate 	format_type ofmt,
222*7c478bd9Sstevel@tonic-gate 	const char *infoString)
223*7c478bd9Sstevel@tonic-gate {
224*7c478bd9Sstevel@tonic-gate 	AudioUnixfile*	ofp = 0;
225*7c478bd9Sstevel@tonic-gate 	AudioError	err;	// for error msgs
226*7c478bd9Sstevel@tonic-gate 	int		fd;
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 	if (!path) {
229*7c478bd9Sstevel@tonic-gate 		if (isatty(fileno(stdout))) {
230*7c478bd9Sstevel@tonic-gate 			Err(
231*7c478bd9Sstevel@tonic-gate 		    MGET("Stdout is a tty, please specify an output file\n"));
232*7c478bd9Sstevel@tonic-gate 			exit(1);
233*7c478bd9Sstevel@tonic-gate 		}
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 		path = Stdout;
236*7c478bd9Sstevel@tonic-gate 		if (ofmt == F_RAW) {
237*7c478bd9Sstevel@tonic-gate 			if (!(ofp = new AudioRawPipe(fileno(stdout),
238*7c478bd9Sstevel@tonic-gate 						    (FileAccess)WriteOnly, ohdr,
239*7c478bd9Sstevel@tonic-gate 						    path))) {
240*7c478bd9Sstevel@tonic-gate 				Err(
241*7c478bd9Sstevel@tonic-gate 			    MGET("can't create audio raw stdout pipe\n"));
242*7c478bd9Sstevel@tonic-gate 				exit(1);
243*7c478bd9Sstevel@tonic-gate 			}
244*7c478bd9Sstevel@tonic-gate 		} else if (ofmt == F_SUN) {
245*7c478bd9Sstevel@tonic-gate 			if (!(ofp = new AudioPipe(fileno(stdout),
246*7c478bd9Sstevel@tonic-gate 					    (FileAccess)WriteOnly, path))) {
247*7c478bd9Sstevel@tonic-gate 				Err(
248*7c478bd9Sstevel@tonic-gate 			    MGET("can't create audio pipe for stdout\n"));
249*7c478bd9Sstevel@tonic-gate 				exit(1);
250*7c478bd9Sstevel@tonic-gate 			}
251*7c478bd9Sstevel@tonic-gate 		} else {
252*7c478bd9Sstevel@tonic-gate 			// XXX - should never happen ...
253*7c478bd9Sstevel@tonic-gate 			Err(MGET("can't create output file, unknown format\n"));
254*7c478bd9Sstevel@tonic-gate 			exit(1);
255*7c478bd9Sstevel@tonic-gate 		}
256*7c478bd9Sstevel@tonic-gate 	} else {
257*7c478bd9Sstevel@tonic-gate 		if (ofmt == F_RAW) {
258*7c478bd9Sstevel@tonic-gate 			// first open file, then attach pipe to it
259*7c478bd9Sstevel@tonic-gate 			if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC,
260*7c478bd9Sstevel@tonic-gate 				    0666)) < 0) {
261*7c478bd9Sstevel@tonic-gate 				perror(MGET("open"));
262*7c478bd9Sstevel@tonic-gate 				Err(MGET("can't create output file %s\n"),
263*7c478bd9Sstevel@tonic-gate 				    path);
264*7c478bd9Sstevel@tonic-gate 				exit(1);
265*7c478bd9Sstevel@tonic-gate 			}
266*7c478bd9Sstevel@tonic-gate 			if (!(ofp = new AudioRawPipe(fd, (FileAccess)WriteOnly,
267*7c478bd9Sstevel@tonic-gate 						    ohdr, path))) {
268*7c478bd9Sstevel@tonic-gate 				Err(MGET("can't create raw audio pipe %s\n"),
269*7c478bd9Sstevel@tonic-gate 				    path);
270*7c478bd9Sstevel@tonic-gate 				exit(1);
271*7c478bd9Sstevel@tonic-gate 			}
272*7c478bd9Sstevel@tonic-gate 		} else if (ofmt == F_SUN) {
273*7c478bd9Sstevel@tonic-gate 			if (!(ofp = new AudioFile(path,
274*7c478bd9Sstevel@tonic-gate 						    (FileAccess)ReadWrite))) {
275*7c478bd9Sstevel@tonic-gate 				Err(MGET("can't create output file %s\n"),
276*7c478bd9Sstevel@tonic-gate 				    path);
277*7c478bd9Sstevel@tonic-gate 				exit(1);
278*7c478bd9Sstevel@tonic-gate 			}
279*7c478bd9Sstevel@tonic-gate 		} else {
280*7c478bd9Sstevel@tonic-gate 			// XXX - should never happen ...
281*7c478bd9Sstevel@tonic-gate 			Err(MGET("can't create output file, unknown format\n"));
282*7c478bd9Sstevel@tonic-gate 			exit(1);
283*7c478bd9Sstevel@tonic-gate 		}
284*7c478bd9Sstevel@tonic-gate 	}
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 	// set the info string.
287*7c478bd9Sstevel@tonic-gate 	ofp->SetInfostring(infoString, -1);
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 	// set the header and create the output audio object
290*7c478bd9Sstevel@tonic-gate 	if ((err = ofp->SetHeader(ohdr)) != AUDIO_SUCCESS) {
291*7c478bd9Sstevel@tonic-gate 		Err(MGET("can't set hdr on output file: %s\n"), err.msg());
292*7c478bd9Sstevel@tonic-gate 		exit(1);
293*7c478bd9Sstevel@tonic-gate 	}
294*7c478bd9Sstevel@tonic-gate 	if ((err = ofp->Create()) != AUDIO_SUCCESS) {
295*7c478bd9Sstevel@tonic-gate 		Err(MGET("can't create output file: %s\n"), err.msg());
296*7c478bd9Sstevel@tonic-gate 		exit(1);
297*7c478bd9Sstevel@tonic-gate 	}
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 	return (ofp);
300*7c478bd9Sstevel@tonic-gate }
301