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