xref: /onnv-gate/usr/src/cmd/audio/utilities/AudioFile.cc (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <stdlib.h>
30*0Sstevel@tonic-gate #include <stdio.h>
31*0Sstevel@tonic-gate #include <unistd.h>
32*0Sstevel@tonic-gate #include <errno.h>
33*0Sstevel@tonic-gate #include <malloc.h>
34*0Sstevel@tonic-gate #include <string.h>
35*0Sstevel@tonic-gate #include <fcntl.h>
36*0Sstevel@tonic-gate #include <sys/stat.h>
37*0Sstevel@tonic-gate #include <sys/types.h>
38*0Sstevel@tonic-gate #include <sys/mman.h>
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate #include <AudioFile.h>
41*0Sstevel@tonic-gate #include <AudioLib.h>
42*0Sstevel@tonic-gate #include <AudioDebug.h>
43*0Sstevel@tonic-gate #include <libaudio.h>
44*0Sstevel@tonic-gate #include <audio_hdr.h>
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate // XX64  This should go away when <sys/mman.h> gets fixed.
47*0Sstevel@tonic-gate extern "C" int madvise(caddr_t, size_t, int);
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate // class AudioFile methods
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate // Initialize temporary file params
53*0Sstevel@tonic-gate #define	TMPDIR		"/tmp"
54*0Sstevel@tonic-gate #define	TMPFILE		"/audiotoolXXXXXX"
55*0Sstevel@tonic-gate static char		*tmpdir = NULL;
56*0Sstevel@tonic-gate static const char	*tmpname = "(temporary file)";
57*0Sstevel@tonic-gate static const FileAccess	tmpmode = ReadWrite;
58*0Sstevel@tonic-gate static const VMAccess	defaccess = SequentialAccess;
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate // Initialize default access mode, used when a filename is supplied
61*0Sstevel@tonic-gate const FileAccess	AudioFile::defmode = ReadOnly;
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate // Default audio file path prefix environment variable
64*0Sstevel@tonic-gate const char *AudioFile::AUDIO_PATH = "AUDIOPATH";
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate // Constructor with no arguments opens a read/write temporary file
68*0Sstevel@tonic-gate AudioFile::
AudioFile()69*0Sstevel@tonic-gate AudioFile():
70*0Sstevel@tonic-gate 	AudioUnixfile(tmpname, tmpmode),
71*0Sstevel@tonic-gate 	hdrsize(0), seekpos(0), origlen(0.), mapaddr(0), maplen(0),
72*0Sstevel@tonic-gate 	vmaccess(defaccess)
73*0Sstevel@tonic-gate {
74*0Sstevel@tonic-gate }
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate // Constructor with pathname and optional mode arg
77*0Sstevel@tonic-gate AudioFile::
AudioFile(const char * path,const FileAccess acc)78*0Sstevel@tonic-gate AudioFile(
79*0Sstevel@tonic-gate 	const char		*path,		// filename
80*0Sstevel@tonic-gate 	const FileAccess	acc):		// access mode
81*0Sstevel@tonic-gate 	AudioUnixfile(path, acc),
82*0Sstevel@tonic-gate 	hdrsize(0), seekpos(0), origlen(0.), mapaddr(0), maplen(0),
83*0Sstevel@tonic-gate 	vmaccess(defaccess)
84*0Sstevel@tonic-gate {
85*0Sstevel@tonic-gate }
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate // Destructor must call the local Close() routine
88*0Sstevel@tonic-gate AudioFile::
~AudioFile()89*0Sstevel@tonic-gate ~AudioFile()
90*0Sstevel@tonic-gate {
91*0Sstevel@tonic-gate 	// If the file was open, close it
92*0Sstevel@tonic-gate 	if (opened())
93*0Sstevel@tonic-gate 		(void) Close();
94*0Sstevel@tonic-gate }
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate // Set a default temporary file directory
97*0Sstevel@tonic-gate AudioError AudioFile::
SetTempPath(const char * path)98*0Sstevel@tonic-gate SetTempPath(
99*0Sstevel@tonic-gate 	const char	*path)
100*0Sstevel@tonic-gate {
101*0Sstevel@tonic-gate 	struct stat	st;
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate 	// Verify intended path
104*0Sstevel@tonic-gate 	if ((stat(path, &st) < 0) ||
105*0Sstevel@tonic-gate 	    !S_ISDIR(st.st_mode) ||
106*0Sstevel@tonic-gate 	    (access(path, W_OK) < 0)) {
107*0Sstevel@tonic-gate 		errno = ENOTDIR;
108*0Sstevel@tonic-gate 		return (AUDIO_UNIXERROR);
109*0Sstevel@tonic-gate 	}
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 	if (tmpdir != NULL)
112*0Sstevel@tonic-gate 		(void) free(tmpdir);
113*0Sstevel@tonic-gate 	tmpdir = (char *)malloc(strlen(path) + 1);
114*0Sstevel@tonic-gate 	(void) strcpy(tmpdir, path);
115*0Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
116*0Sstevel@tonic-gate }
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate // Create a named file according to the current mode setting
120*0Sstevel@tonic-gate AudioError AudioFile::
createfile(const char * path)121*0Sstevel@tonic-gate createfile(
122*0Sstevel@tonic-gate 	const char	*path)			// pathname or 0
123*0Sstevel@tonic-gate {
124*0Sstevel@tonic-gate 	char		*tmpf;
125*0Sstevel@tonic-gate 	char		*tmpstr;
126*0Sstevel@tonic-gate 	int		openmode;
127*0Sstevel@tonic-gate 	int		desc;
128*0Sstevel@tonic-gate 	AudioError	err;
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 	// Convert the open mode to an int argument for open()
131*0Sstevel@tonic-gate 	openmode = GetAccess();
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate 	// Was the header properly set?
134*0Sstevel@tonic-gate 	if (!hdrset())
135*0Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_BADHDR));
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 	// Can't create if already opened or if mode or name not set
138*0Sstevel@tonic-gate 	if ((openmode == -1) || opened() || (strlen(path) == 0))
139*0Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_NOEFFECT));
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 	// If temporary file, create and unlink it.
142*0Sstevel@tonic-gate 	if (strcmp(path, tmpname) == 0) {
143*0Sstevel@tonic-gate 		// Construct the temporary file path
144*0Sstevel@tonic-gate 		tmpstr = (char *)malloc(1 + strlen(TMPFILE) +
145*0Sstevel@tonic-gate 		    strlen((tmpdir == NULL) ? TMPDIR : tmpdir));
146*0Sstevel@tonic-gate 		(void) sprintf(tmpstr, "%s%s",
147*0Sstevel@tonic-gate 		    (tmpdir == NULL) ? TMPDIR : tmpdir, TMPFILE);
148*0Sstevel@tonic-gate 		tmpf = mktemp(tmpstr);
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate 		// Open the temp file and unlink it
151*0Sstevel@tonic-gate 		err = createfile(tmpf);
152*0Sstevel@tonic-gate 		if ((err == AUDIO_SUCCESS) && (unlink(tmpf) < 0)) {
153*0Sstevel@tonic-gate 			(void) Close();
154*0Sstevel@tonic-gate 			err = RaiseError(AUDIO_UNIXERROR, Warning);
155*0Sstevel@tonic-gate 		}
156*0Sstevel@tonic-gate 		(void) free(tmpstr);
157*0Sstevel@tonic-gate 		return (err);
158*0Sstevel@tonic-gate 	}
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 	// Create the file
161*0Sstevel@tonic-gate 	desc = open(path, openmode | O_CREAT | O_TRUNC, 0666);
162*0Sstevel@tonic-gate 	if ((desc < 0) && (errno == EOVERFLOW)) {
163*0Sstevel@tonic-gate 		return (RaiseError(AUDIO_UNIXERROR, Fatal,
164*0Sstevel@tonic-gate 		    (char *)"Large File"));
165*0Sstevel@tonic-gate 	} else if (desc < 0) {
166*0Sstevel@tonic-gate 		return (RaiseError(AUDIO_UNIXERROR));
167*0Sstevel@tonic-gate 	}
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 	// Set the file descriptor (this marks the file open)
170*0Sstevel@tonic-gate 	setfd(desc);
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	// Write the file header with current (usually unknown) size
173*0Sstevel@tonic-gate 	err = encode_filehdr();
174*0Sstevel@tonic-gate 	if (err != AUDIO_SUCCESS) {
175*0Sstevel@tonic-gate 		setfd(-1);
176*0Sstevel@tonic-gate 		(void) close(desc);		// If error, remove file
177*0Sstevel@tonic-gate 		(void) unlink(path);
178*0Sstevel@tonic-gate 		return (err);
179*0Sstevel@tonic-gate 	}
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	// Save the length that got written, then set it to zero
182*0Sstevel@tonic-gate 	origlen = GetLength();
183*0Sstevel@tonic-gate 	setlength(0.);
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 	// Set the size of the file header
186*0Sstevel@tonic-gate 	hdrsize = lseek(desc, (off_t)0, SEEK_CUR);
187*0Sstevel@tonic-gate 	if (hdrsize < 0) {
188*0Sstevel@tonic-gate 		setfd(-1);
189*0Sstevel@tonic-gate 		(void) close(desc);		// If error, remove file
190*0Sstevel@tonic-gate 		(void) unlink(path);
191*0Sstevel@tonic-gate 		return (err);
192*0Sstevel@tonic-gate 	}
193*0Sstevel@tonic-gate 	seekpos = 0;
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
196*0Sstevel@tonic-gate }
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate // Create a file whose name is already set, according to the mode setting
199*0Sstevel@tonic-gate AudioError AudioFile::
Create()200*0Sstevel@tonic-gate Create()
201*0Sstevel@tonic-gate {
202*0Sstevel@tonic-gate 	return (createfile(GetName()));
203*0Sstevel@tonic-gate }
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate // Open a file whose name is set
206*0Sstevel@tonic-gate AudioError AudioFile::
Open()207*0Sstevel@tonic-gate Open()
208*0Sstevel@tonic-gate {
209*0Sstevel@tonic-gate 	return (OpenPath(NULL));
210*0Sstevel@tonic-gate }
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate // Open a file, using the specified path prefixes
213*0Sstevel@tonic-gate AudioError AudioFile::
OpenPath(const char * path)214*0Sstevel@tonic-gate OpenPath(
215*0Sstevel@tonic-gate 	const char	*path)
216*0Sstevel@tonic-gate {
217*0Sstevel@tonic-gate 	char		*filename;
218*0Sstevel@tonic-gate 	int		flen;
219*0Sstevel@tonic-gate 	char		*prefix;
220*0Sstevel@tonic-gate 	char		*str;
221*0Sstevel@tonic-gate 	char		*wrk;
222*0Sstevel@tonic-gate 	char		*pathname;
223*0Sstevel@tonic-gate 	int		openmode;
224*0Sstevel@tonic-gate 	AudioError	err;
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 	// Convert the open mode to an int argument for open()
227*0Sstevel@tonic-gate 	openmode = GetAccess();
228*0Sstevel@tonic-gate 	filename = GetName();
229*0Sstevel@tonic-gate 	flen = strlen(filename);
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 	// Can't open if already opened or if mode or name not set
232*0Sstevel@tonic-gate 	if ((openmode == -1) || opened() || (strlen(filename) == 0))
233*0Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_NOEFFECT));
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	// Search path:
236*0Sstevel@tonic-gate 	//	1) try name: if not found and not readonly:
237*0Sstevel@tonic-gate 	//		if Append mode, try creating it
238*0Sstevel@tonic-gate 	//	2) if name is a relative pathname, and 'path' is not NULL:
239*0Sstevel@tonic-gate 	//		try every path prefix in 'path'
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 	err = tryopen(filename, openmode);
242*0Sstevel@tonic-gate 	if (!err)
243*0Sstevel@tonic-gate 		return (AUDIO_SUCCESS);
244*0Sstevel@tonic-gate 	if (GetAccess().Writeable() || (filename[0] == '/')) {
245*0Sstevel@tonic-gate 		// If file is non-existent and Append mode, try creating it.
246*0Sstevel@tonic-gate 		if ((err == AUDIO_UNIXERROR) && (err.sys == ENOENT) &&
247*0Sstevel@tonic-gate 		    GetAccess().Append() && hdrset()) {
248*0Sstevel@tonic-gate 			return (Create());
249*0Sstevel@tonic-gate 		}
250*0Sstevel@tonic-gate 		return (RaiseError(err));
251*0Sstevel@tonic-gate 	}
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	// Try path as an environment variable name, else assume it is a path
254*0Sstevel@tonic-gate 	str = (path == NULL) ? NULL : getenv(path);
255*0Sstevel@tonic-gate 	if (str == NULL)
256*0Sstevel@tonic-gate 		str = (char *)path;
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	if (str != NULL) {
259*0Sstevel@tonic-gate 		// Make a copy of the path, to parse it
260*0Sstevel@tonic-gate 		wrk = new char[strlen(str) + 1];
261*0Sstevel@tonic-gate 		(void) strcpy(wrk, str);
262*0Sstevel@tonic-gate 		str = wrk;
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate 		// Try each component as a path prefix
265*0Sstevel@tonic-gate 		for (prefix = str;
266*0Sstevel@tonic-gate 		    (prefix != NULL) && (prefix[0] != '\0');
267*0Sstevel@tonic-gate 		    prefix = str) {
268*0Sstevel@tonic-gate 			str = strchr(str, ':');
269*0Sstevel@tonic-gate 			if (str != NULL)
270*0Sstevel@tonic-gate 				*str++ = '\0';
271*0Sstevel@tonic-gate 			pathname = new char[strlen(prefix) + flen + 2];
272*0Sstevel@tonic-gate 			(void) sprintf(pathname, "%s/%s", prefix, filename);
273*0Sstevel@tonic-gate 			err = tryopen(pathname, openmode);
274*0Sstevel@tonic-gate 			delete pathname;
275*0Sstevel@tonic-gate 			switch (err) {
276*0Sstevel@tonic-gate 			case AUDIO_SUCCESS:	// found the file
277*0Sstevel@tonic-gate 				delete wrk;
278*0Sstevel@tonic-gate 				return (RaiseError(err));
279*0Sstevel@tonic-gate 			// XXX - if file found but not audio, stop looking??
280*0Sstevel@tonic-gate 			}
281*0Sstevel@tonic-gate 		}
282*0Sstevel@tonic-gate 		delete wrk;
283*0Sstevel@tonic-gate 	}
284*0Sstevel@tonic-gate 	// Can't find file.  Return the original error condition.
285*0Sstevel@tonic-gate 	return (RaiseError(tryopen(filename, openmode)));
286*0Sstevel@tonic-gate }
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate // Attempt to open the given audio file
289*0Sstevel@tonic-gate AudioError AudioFile::
tryopen(const char * pathname,int openmode)290*0Sstevel@tonic-gate tryopen(
291*0Sstevel@tonic-gate 	const char	*pathname,
292*0Sstevel@tonic-gate 	int		openmode)
293*0Sstevel@tonic-gate {
294*0Sstevel@tonic-gate 	struct stat	st;
295*0Sstevel@tonic-gate 	int		desc;
296*0Sstevel@tonic-gate 	AudioError	err;
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	// If the name is changing, set the new one
299*0Sstevel@tonic-gate 	if (pathname != GetName())
300*0Sstevel@tonic-gate 		SetName(pathname);
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	// Does the file exist?
303*0Sstevel@tonic-gate 	if (stat(pathname, &st) < 0)
304*0Sstevel@tonic-gate 		return (AUDIO_UNIXERROR);
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	// If not a regular file, stop right there
307*0Sstevel@tonic-gate 	if (!S_ISREG(st.st_mode))
308*0Sstevel@tonic-gate 		return (AUDIO_ERR_BADFILEHDR);
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 	// Open the file and check that it's an audio file
311*0Sstevel@tonic-gate 	desc = open(GetName(), openmode);
312*0Sstevel@tonic-gate 	if ((desc < 0) && (errno == EOVERFLOW)) {
313*0Sstevel@tonic-gate 		return (RaiseError(AUDIO_UNIXERROR, Fatal,
314*0Sstevel@tonic-gate 		    (char *)"Large File"));
315*0Sstevel@tonic-gate 	} else if (desc < 0) {
316*0Sstevel@tonic-gate 		return (AUDIO_UNIXERROR);
317*0Sstevel@tonic-gate 	}
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate 	// Set the file descriptor (this marks the file open)
320*0Sstevel@tonic-gate 	setfd(desc);
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 	err = decode_filehdr();
323*0Sstevel@tonic-gate 	if (err != AUDIO_SUCCESS) {
324*0Sstevel@tonic-gate 		(void) close(desc);
325*0Sstevel@tonic-gate 		setfd(-1);
326*0Sstevel@tonic-gate 		return (err);
327*0Sstevel@tonic-gate 	}
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	// Save the length of the data and the size of the file header
330*0Sstevel@tonic-gate 	origlen = GetLength();
331*0Sstevel@tonic-gate 	hdrsize = (off_t)lseek(desc, (off_t)0, SEEK_CUR);
332*0Sstevel@tonic-gate 	if (hdrsize < 0) {
333*0Sstevel@tonic-gate 		(void) close(desc);
334*0Sstevel@tonic-gate 		setfd(-1);
335*0Sstevel@tonic-gate 		return (err);
336*0Sstevel@tonic-gate 	}
337*0Sstevel@tonic-gate 	seekpos = 0;
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 	// If this is ReadOnly file, mmap() it.  Don't worry if mmap() fails.
340*0Sstevel@tonic-gate 	if (!GetAccess().Writeable()) {
341*0Sstevel@tonic-gate 		maplen = st.st_size;
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 		/*
344*0Sstevel@tonic-gate 		 * Can't mmap LITTLE_ENDIAN as they are converted in
345*0Sstevel@tonic-gate 		 * place.
346*0Sstevel@tonic-gate 		 */
347*0Sstevel@tonic-gate 		if (localByteOrder() == BIG_ENDIAN) {
348*0Sstevel@tonic-gate 			if ((mapaddr = (caddr_t)mmap(0, (int)maplen, PROT_READ,
349*0Sstevel@tonic-gate 				MAP_SHARED, desc, 0)) != (caddr_t)-1) {
350*0Sstevel@tonic-gate 				// set default access method
351*0Sstevel@tonic-gate 				(void) madvise(mapaddr, (unsigned int)maplen,
352*0Sstevel@tonic-gate 				    (int)GetAccessType());
353*0Sstevel@tonic-gate 			} else {
354*0Sstevel@tonic-gate 				(void) RaiseError(AUDIO_UNIXERROR, Warning,
355*0Sstevel@tonic-gate 				    (char *)"Could not mmap() file");
356*0Sstevel@tonic-gate 				mapaddr = 0;
357*0Sstevel@tonic-gate 				maplen = 0;
358*0Sstevel@tonic-gate 			}
359*0Sstevel@tonic-gate 		} else {
360*0Sstevel@tonic-gate 			mapaddr = 0;
361*0Sstevel@tonic-gate 			maplen = 0;
362*0Sstevel@tonic-gate 		}
363*0Sstevel@tonic-gate 	}
364*0Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
365*0Sstevel@tonic-gate }
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate // set VM access hint for mmapped files
368*0Sstevel@tonic-gate AudioError AudioFile::
SetAccessType(VMAccess vmacc)369*0Sstevel@tonic-gate SetAccessType(VMAccess vmacc)
370*0Sstevel@tonic-gate {
371*0Sstevel@tonic-gate 	if (!opened()) {
372*0Sstevel@tonic-gate 		return (AUDIO_ERR_NOEFFECT);
373*0Sstevel@tonic-gate 	}
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	if (mapaddr == 0) {
376*0Sstevel@tonic-gate 		return (AUDIO_ERR_NOEFFECT);
377*0Sstevel@tonic-gate 	}
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 	(void) madvise(mapaddr, (unsigned int)maplen, (int)vmacc);
380*0Sstevel@tonic-gate 	vmaccess = vmacc;
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
383*0Sstevel@tonic-gate }
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate // Close the file
386*0Sstevel@tonic-gate AudioError AudioFile::
Close()387*0Sstevel@tonic-gate Close()
388*0Sstevel@tonic-gate {
389*0Sstevel@tonic-gate 	AudioError	err;
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 	if (!opened())
392*0Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_NOEFFECT, Warning));
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 	// Rewind the file and rewrite the header with the correct length
395*0Sstevel@tonic-gate 	if (GetAccess().Writeable() && (origlen != GetLength())) {
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate 		// sanity check
398*0Sstevel@tonic-gate 		if (GetHeader().Time_to_Bytes(GetLength()) !=
399*0Sstevel@tonic-gate 		    (lseek(getfd(), (off_t)0, SEEK_END) - hdrsize)) {
400*0Sstevel@tonic-gate 			PrintMsg(_MGET_(
401*0Sstevel@tonic-gate 			    "AudioFile:Close()...inconsistent length\n"),
402*0Sstevel@tonic-gate 			    Fatal);
403*0Sstevel@tonic-gate 		}
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 		// XXX - should be rewritten in C++
406*0Sstevel@tonic-gate 		err = (AudioError) audio_rewrite_filesize(getfd(), FILE_AU,
407*0Sstevel@tonic-gate 		    (uint_t)GetHeader().Time_to_Bytes(GetLength()), 0, 0);
408*0Sstevel@tonic-gate 	}
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 	// Call the generic file close routine
411*0Sstevel@tonic-gate 	err = AudioUnixfile::Close();
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 	if (mapaddr) {
414*0Sstevel@tonic-gate 		munmap(mapaddr, (int)maplen);
415*0Sstevel@tonic-gate 		mapaddr = 0;
416*0Sstevel@tonic-gate 		maplen = 0;
417*0Sstevel@tonic-gate 	}
418*0Sstevel@tonic-gate 
419*0Sstevel@tonic-gate 	// Init important values, in case the file is reopened
420*0Sstevel@tonic-gate 	hdrsize = 0;
421*0Sstevel@tonic-gate 	seekpos = 0;
422*0Sstevel@tonic-gate 	return (RaiseError(err));
423*0Sstevel@tonic-gate }
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate // Read data from underlying file into specified buffer.
426*0Sstevel@tonic-gate // No data format translation takes place.
427*0Sstevel@tonic-gate // The object's read position pointer is unaffected.
428*0Sstevel@tonic-gate AudioError AudioFile::
ReadData(void * buf,size_t & len,Double & pos)429*0Sstevel@tonic-gate ReadData(
430*0Sstevel@tonic-gate 	void*		buf,		// destination buffer address
431*0Sstevel@tonic-gate 	size_t&		len,		// buffer length (updated)
432*0Sstevel@tonic-gate 	Double&		pos)		// start position (updated)
433*0Sstevel@tonic-gate {
434*0Sstevel@tonic-gate 	off_t		offset;
435*0Sstevel@tonic-gate 	size_t		cnt;
436*0Sstevel@tonic-gate 	caddr_t		cp;
437*0Sstevel@tonic-gate 	AudioError	err;
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 	// If the file is not mapped, call parent ReadData() and return
440*0Sstevel@tonic-gate 	if (mapaddr == 0) {
441*0Sstevel@tonic-gate 		// Call the real routine
442*0Sstevel@tonic-gate 		err = AudioUnixfile::ReadData(buf, len, pos);
443*0Sstevel@tonic-gate 		// Update the cached seek pointer
444*0Sstevel@tonic-gate 		seekpos += len;
445*0Sstevel@tonic-gate 		return (err);
446*0Sstevel@tonic-gate 	}
447*0Sstevel@tonic-gate 
448*0Sstevel@tonic-gate 	// If the file is mmapped, do a memcpy() from the mapaddr
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 	// Save buffer size and zero transfer count
451*0Sstevel@tonic-gate 	cnt = (size_t)len;
452*0Sstevel@tonic-gate 	len = 0;
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	// Cannot read if file is not open
455*0Sstevel@tonic-gate 	if (!opened() || !GetAccess().Readable())
456*0Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_NOEFFECT));
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 	// Position must be valid
459*0Sstevel@tonic-gate 	if (Undefined(pos) || (pos < 0.) || ((int)cnt < 0))
460*0Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_BADARG));
461*0Sstevel@tonic-gate 
462*0Sstevel@tonic-gate 	// Make sure we don't read off the end of file
463*0Sstevel@tonic-gate 	offset = GetHeader().Time_to_Bytes(pos);
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	if ((offset + hdrsize) >= maplen) {
466*0Sstevel@tonic-gate 		// trying to read past EOF
467*0Sstevel@tonic-gate 		err = AUDIO_EOF;
468*0Sstevel@tonic-gate 		err.sys = AUDIO_COPY_INPUT_EOF;
469*0Sstevel@tonic-gate 		return (err);
470*0Sstevel@tonic-gate 	} else if ((offset + hdrsize + cnt) > maplen) {
471*0Sstevel@tonic-gate 		// re-adjust cnt so it reads up to the end of file
472*0Sstevel@tonic-gate 		cnt = (size_t)(maplen - (offset + hdrsize));
473*0Sstevel@tonic-gate 	}
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate 	// Zero-length reads are finished
476*0Sstevel@tonic-gate 	if (GetHeader().Bytes_to_Bytes(cnt) == 0) {
477*0Sstevel@tonic-gate 		err = AUDIO_SUCCESS;
478*0Sstevel@tonic-gate 		err.sys = AUDIO_COPY_ZERO_LIMIT;
479*0Sstevel@tonic-gate 		return (err);
480*0Sstevel@tonic-gate 	} else {
481*0Sstevel@tonic-gate 		cp = mapaddr + offset + hdrsize;
482*0Sstevel@tonic-gate 		memcpy((void*)buf, (void*)cp, cnt);
483*0Sstevel@tonic-gate 	}
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate 	// Return the updated byte count and position
486*0Sstevel@tonic-gate 	len = cnt;
487*0Sstevel@tonic-gate 	pos = GetHeader().Bytes_to_Time(offset + len);
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 	// Check to see if the endian is right. Note that special care
490*0Sstevel@tonic-gate 	// doesn't need to be taken because of the mmap, since the data
491*0Sstevel@tonic-gate 	// is copied into a separate buffer anyway.
492*0Sstevel@tonic-gate 	coerceEndian((unsigned char *)buf, len, localByteOrder());
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
495*0Sstevel@tonic-gate }
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate // Write data to underlying file from specified buffer.
498*0Sstevel@tonic-gate // No data format translation takes place.
499*0Sstevel@tonic-gate // The object's write position pointer is unaffected.
500*0Sstevel@tonic-gate AudioError AudioFile::
WriteData(void * buf,size_t & len,Double & pos)501*0Sstevel@tonic-gate WriteData(
502*0Sstevel@tonic-gate 	void*		buf, // source buffer address
503*0Sstevel@tonic-gate 	size_t&		len, // buffer length (updated)
504*0Sstevel@tonic-gate 	Double&		pos) // start position (updated)
505*0Sstevel@tonic-gate {
506*0Sstevel@tonic-gate 	AudioError	err;
507*0Sstevel@tonic-gate 
508*0Sstevel@tonic-gate 	// Call the real routine
509*0Sstevel@tonic-gate 	err = AudioUnixfile::WriteData(buf, len, pos);
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 	// Update the cached seek pointer
512*0Sstevel@tonic-gate 	seekpos += len;
513*0Sstevel@tonic-gate 	return (err);
514*0Sstevel@tonic-gate }
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate // Set the Unix file pointer to match a given file position.
517*0Sstevel@tonic-gate AudioError AudioFile::
seekread(Double pos,off_t & offset)518*0Sstevel@tonic-gate seekread(
519*0Sstevel@tonic-gate 	Double		pos,	// position to seek to
520*0Sstevel@tonic-gate 	off_t&		offset)	// returned byte offset
521*0Sstevel@tonic-gate {
522*0Sstevel@tonic-gate 	offset = GetHeader().Time_to_Bytes(pos);
523*0Sstevel@tonic-gate 	if (offset != seekpos) {
524*0Sstevel@tonic-gate 		if (lseek(getfd(), (off_t)(hdrsize + offset), SEEK_SET) < 0)
525*0Sstevel@tonic-gate 			return (RaiseError(AUDIO_UNIXERROR, Warning));
526*0Sstevel@tonic-gate 		seekpos = offset;
527*0Sstevel@tonic-gate 	}
528*0Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
529*0Sstevel@tonic-gate }
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate // Set the Unix file pointer to match a given file position.
532*0Sstevel@tonic-gate // If seek beyond end-of-file, NULL out intervening data.
533*0Sstevel@tonic-gate AudioError AudioFile::
seekwrite(Double pos,off_t & offset)534*0Sstevel@tonic-gate seekwrite(
535*0Sstevel@tonic-gate 	Double		pos,	// position to seek to
536*0Sstevel@tonic-gate 	off_t&		offset)	// returned byte offset
537*0Sstevel@tonic-gate {
538*0Sstevel@tonic-gate 	// If append-only, can't seek backwards into file
539*0Sstevel@tonic-gate 	if (GetAccess().Append() && (pos < GetLength()))
540*0Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_NOEFFECT, Warning));
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 	// If seek beyond eof, fill data
543*0Sstevel@tonic-gate 	if (pos > GetLength()) {
544*0Sstevel@tonic-gate 		seekwrite(GetLength(), offset);	// seek to eof
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 		// XXX - not implemented yet
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate 		return (AUDIO_SUCCESS);
549*0Sstevel@tonic-gate 	}
550*0Sstevel@tonic-gate 
551*0Sstevel@tonic-gate 	offset = GetHeader().Time_to_Bytes(pos);
552*0Sstevel@tonic-gate 	if (offset != seekpos) {
553*0Sstevel@tonic-gate 		if (lseek(getfd(), (off_t)(hdrsize + offset), SEEK_SET) < 0)
554*0Sstevel@tonic-gate 			return (RaiseError(AUDIO_UNIXERROR, Warning));
555*0Sstevel@tonic-gate 		seekpos = offset;
556*0Sstevel@tonic-gate 	}
557*0Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
558*0Sstevel@tonic-gate }
559*0Sstevel@tonic-gate 
560*0Sstevel@tonic-gate // Copy routine that handles mapped files
561*0Sstevel@tonic-gate AudioError AudioFile::
AsyncCopy(Audio * to,Double & frompos,Double & topos,Double & limit)562*0Sstevel@tonic-gate AsyncCopy(
563*0Sstevel@tonic-gate 	Audio*		to,			// audio object to copy to
564*0Sstevel@tonic-gate 	Double&		frompos,
565*0Sstevel@tonic-gate 	Double&		topos,
566*0Sstevel@tonic-gate 	Double&		limit)
567*0Sstevel@tonic-gate {
568*0Sstevel@tonic-gate 	caddr_t		bptr;
569*0Sstevel@tonic-gate 	size_t		offset;
570*0Sstevel@tonic-gate 	size_t		cnt;
571*0Sstevel@tonic-gate 	size_t		svlim;
572*0Sstevel@tonic-gate 	Double		svfrom;
573*0Sstevel@tonic-gate 	Double		svto;
574*0Sstevel@tonic-gate 	AudioHdr	tohdr;
575*0Sstevel@tonic-gate 	AudioError	err;
576*0Sstevel@tonic-gate 
577*0Sstevel@tonic-gate 	// If this is NOT mmapped, or the destination is an AudioBuffer,
578*0Sstevel@tonic-gate 	// use the default routine
579*0Sstevel@tonic-gate 	if ((mapaddr == 0) || to->isBuffer()) {
580*0Sstevel@tonic-gate 		return (Audio::AsyncCopy(to, frompos, topos, limit));
581*0Sstevel@tonic-gate 	}
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate 	tohdr = to->GetHeader();
584*0Sstevel@tonic-gate 	if (err = tohdr.Validate())
585*0Sstevel@tonic-gate 		return (err);
586*0Sstevel@tonic-gate 	if (limit < 0.)
587*0Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_BADARG));
588*0Sstevel@tonic-gate 	svlim = (size_t)tohdr.Time_to_Bytes(limit);
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate 	// Get maximum possible copy length
591*0Sstevel@tonic-gate 	svfrom = GetLength();
592*0Sstevel@tonic-gate 	if ((frompos >= svfrom) || ((cnt = (size_t)
593*0Sstevel@tonic-gate 	    GetHeader().Time_to_Bytes(svfrom - frompos)) == 0)) {
594*0Sstevel@tonic-gate 		limit = 0.;
595*0Sstevel@tonic-gate 		err = AUDIO_EOF;
596*0Sstevel@tonic-gate 		err.sys = AUDIO_COPY_INPUT_EOF;
597*0Sstevel@tonic-gate 		return (err);
598*0Sstevel@tonic-gate 	}
599*0Sstevel@tonic-gate 	if (!Undefined(limit) && (svlim < cnt))
600*0Sstevel@tonic-gate 		cnt = svlim;
601*0Sstevel@tonic-gate 
602*0Sstevel@tonic-gate 	limit = 0.;
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 	offset = (size_t)GetHeader().Time_to_Bytes(frompos);
605*0Sstevel@tonic-gate 	if ((offset + hdrsize) >= maplen) {
606*0Sstevel@tonic-gate 		// trying to read past EOF
607*0Sstevel@tonic-gate 		err = AUDIO_EOF;
608*0Sstevel@tonic-gate 		err.sys = AUDIO_COPY_INPUT_EOF;
609*0Sstevel@tonic-gate 		return (err);
610*0Sstevel@tonic-gate 	} else if ((offset + hdrsize + cnt) > maplen) {
611*0Sstevel@tonic-gate 		// re-adjust cnt so it reads up to the end of file
612*0Sstevel@tonic-gate 		cnt = (size_t)(maplen - (offset + hdrsize));
613*0Sstevel@tonic-gate 	}
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate 	// Zero-length reads are done
616*0Sstevel@tonic-gate 	if (GetHeader().Bytes_to_Bytes(cnt) == 0) {
617*0Sstevel@tonic-gate 		err = AUDIO_SUCCESS;
618*0Sstevel@tonic-gate 		err.sys = AUDIO_COPY_ZERO_LIMIT;
619*0Sstevel@tonic-gate 		return (err);
620*0Sstevel@tonic-gate 	}
621*0Sstevel@tonic-gate 
622*0Sstevel@tonic-gate 	// Write the data to the destination and update pointers/ctrs
623*0Sstevel@tonic-gate 	svfrom = frompos;
624*0Sstevel@tonic-gate 	svto = topos;
625*0Sstevel@tonic-gate 	svlim = cnt;
626*0Sstevel@tonic-gate 	bptr = mapaddr + hdrsize + offset;
627*0Sstevel@tonic-gate 	err = to->WriteData(bptr, cnt, topos);
628*0Sstevel@tonic-gate 	limit = topos - svto;
629*0Sstevel@tonic-gate 	frompos = svfrom + limit;
630*0Sstevel@tonic-gate 
631*0Sstevel@tonic-gate 	// Report short writes
632*0Sstevel@tonic-gate 	if (!err && (cnt < svlim))
633*0Sstevel@tonic-gate 		err.sys = AUDIO_COPY_SHORT_OUTPUT;
634*0Sstevel@tonic-gate 	return (err);
635*0Sstevel@tonic-gate }
636