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