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