1 /*
2 	Audio File Library
3 	Copyright (C) 2000-2001, Silicon Graphics, Inc.
4 
5 	This library is free software; you can redistribute it and/or
6 	modify it under the terms of the GNU Lesser General Public
7 	License as published by the Free Software Foundation; either
8 	version 2.1 of the License, or (at your option) any later version.
9 
10 	This library is distributed in the hope that it will be useful,
11 	but WITHOUT ANY WARRANTY; without even the implied warranty of
12 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 	Lesser General Public License for more details.
14 
15 	You should have received a copy of the GNU Lesser General Public
16 	License along with this library; if not, write to the
17 	Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 	Boston, MA  02110-1301  USA
19 */
20 
21 #include "config.h"
22 
23 #include <stdlib.h>
24 #include <assert.h>
25 #include <string.h>
26 
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30 
31 #include <audiofile.h>
32 
33 #include "File.h"
34 #include "FileHandle.h"
35 #include "Instrument.h"
36 #include "Marker.h"
37 #include "Setup.h"
38 #include "Track.h"
39 #include "afinternal.h"
40 #include "modules/Module.h"
41 #include "modules/ModuleState.h"
42 #include "units.h"
43 #include "util.h"
44 
45 static status _afOpenFile (int access, File *f, const char *filename,
46 	AFfilehandle *file, AFfilesetup filesetup);
47 
_af_identify(File * f,int * implemented)48 int _af_identify (File *f, int *implemented)
49 {
50 	if (!f->canSeek())
51 	{
52 		_af_error(AF_BAD_LSEEK, "Cannot seek in file");
53 		return AF_FILE_UNKNOWN;
54 	}
55 
56 	AFfileoffset curpos = f->tell();
57 
58 	for (int i=0; i<_AF_NUM_UNITS; i++)
59 	{
60 		if (_af_units[i].recognize &&
61 			_af_units[i].recognize(f))
62 		{
63 			if (implemented != NULL)
64 				*implemented = _af_units[i].implemented;
65 			f->seek(curpos, File::SeekFromBeginning);
66 			return _af_units[i].fileFormat;
67 		}
68 	}
69 
70 	f->seek(curpos, File::SeekFromBeginning);
71 
72 	if (implemented != NULL)
73 		*implemented = false;
74 
75 	return AF_FILE_UNKNOWN;
76 }
77 
afIdentifyFD(int fd)78 int afIdentifyFD (int fd)
79 {
80 	/*
81 		Duplicate the file descriptor since otherwise the
82 		original file descriptor would get closed when we close
83 		the virtual file below.
84 	*/
85 	fd = dup(fd);
86 	File *f = File::create(fd, File::ReadAccess);
87 
88 	int result = _af_identify(f, NULL);
89 
90 	delete f;
91 
92 	return result;
93 }
94 
afIdentifyNamedFD(int fd,const char * filename,int * implemented)95 int afIdentifyNamedFD (int fd, const char *filename, int *implemented)
96 {
97 	/*
98 		Duplicate the file descriptor since otherwise the
99 		original file descriptor would get closed when we close
100 		the virtual file below.
101 	*/
102 	fd = dup(fd);
103 
104 	File *f = File::create(fd, File::ReadAccess);
105 	if (!f)
106 	{
107 		_af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
108 		return AF_FILE_UNKNOWN;
109 	}
110 
111 	int result = _af_identify(f, implemented);
112 
113 	delete f;
114 
115 	return result;
116 }
117 
afOpenFD(int fd,const char * mode,AFfilesetup setup)118 AFfilehandle afOpenFD (int fd, const char *mode, AFfilesetup setup)
119 {
120 	if (!mode)
121 	{
122 		_af_error(AF_BAD_ACCMODE, "null access mode");
123 		return AF_NULL_FILEHANDLE;
124 	}
125 
126 	int access;
127 	if (mode[0] == 'r')
128 	{
129 		access = _AF_READ_ACCESS;
130 	}
131 	else if (mode[0] == 'w')
132 	{
133 		access = _AF_WRITE_ACCESS;
134 	}
135 	else
136 	{
137 		_af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
138 		return AF_NULL_FILEHANDLE;
139 	}
140 
141 	File *f = File::create(fd, access == _AF_READ_ACCESS ?
142 		File::ReadAccess : File::WriteAccess);
143 
144 	AFfilehandle filehandle = NULL;
145 	if (_afOpenFile(access, f, NULL, &filehandle, setup) != AF_SUCCEED)
146 	{
147 		delete f;
148 	}
149 
150 	return filehandle;
151 }
152 
afOpenNamedFD(int fd,const char * mode,AFfilesetup setup,const char * filename)153 AFfilehandle afOpenNamedFD (int fd, const char *mode, AFfilesetup setup,
154 	const char *filename)
155 {
156 	if (!mode)
157 	{
158 		_af_error(AF_BAD_ACCMODE, "null access mode");
159 		return AF_NULL_FILEHANDLE;
160 	}
161 
162 	int access;
163 	if (mode[0] == 'r')
164 		access = _AF_READ_ACCESS;
165 	else if (mode[0] == 'w')
166 		access = _AF_WRITE_ACCESS;
167 	else
168 	{
169 		_af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
170 		return AF_NULL_FILEHANDLE;
171 	}
172 
173 	File *f = File::create(fd, access == _AF_READ_ACCESS ?
174 		File::ReadAccess : File::WriteAccess);
175 
176 	AFfilehandle filehandle;
177 	if (_afOpenFile(access, f, filename, &filehandle, setup) != AF_SUCCEED)
178 	{
179 		delete f;
180 	}
181 
182 	return filehandle;
183 }
184 
afOpenFile(const char * filename,const char * mode,AFfilesetup setup)185 AFfilehandle afOpenFile (const char *filename, const char *mode, AFfilesetup setup)
186 {
187 	if (!mode)
188 	{
189 		_af_error(AF_BAD_ACCMODE, "null access mode");
190 		return AF_NULL_FILEHANDLE;
191 	}
192 
193 	int access;
194 	if (mode[0] == 'r')
195 	{
196 		access = _AF_READ_ACCESS;
197 	}
198 	else if (mode[0] == 'w')
199 	{
200 		access = _AF_WRITE_ACCESS;
201 	}
202 	else
203 	{
204 		_af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
205 		return AF_NULL_FILEHANDLE;
206 	}
207 
208 	File *f = File::open(filename,
209 		access == _AF_READ_ACCESS ? File::ReadAccess : File::WriteAccess);
210 	if (!f)
211 	{
212 		_af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
213 		return AF_NULL_FILEHANDLE;
214 	}
215 
216 	AFfilehandle filehandle;
217 	if (_afOpenFile(access, f, filename, &filehandle, setup) != AF_SUCCEED)
218 	{
219 		delete f;
220 	}
221 
222 	return filehandle;
223 }
224 
afOpenVirtualFile(AFvirtualfile * vf,const char * mode,AFfilesetup setup)225 AFfilehandle afOpenVirtualFile (AFvirtualfile *vf, const char *mode,
226 	AFfilesetup setup)
227 {
228 	if (!vf)
229 	{
230 		_af_error(AF_BAD_OPEN, "null virtual file");
231 		return AF_NULL_FILEHANDLE;
232 	}
233 
234 	if (!mode)
235 	{
236 		_af_error(AF_BAD_ACCMODE, "null access mode");
237 		return AF_NULL_FILEHANDLE;
238 	}
239 
240 	int access;
241 	if (mode[0] == 'r')
242 	{
243 		access = _AF_READ_ACCESS;
244 	}
245 	else if (mode[0] == 'w')
246 	{
247 		access = _AF_WRITE_ACCESS;
248 	}
249 	else
250 	{
251 		_af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
252 		return AF_NULL_FILEHANDLE;
253 	}
254 
255 	File *f = File::create(vf,
256 		access == _AF_READ_ACCESS ? File::ReadAccess : File::WriteAccess);
257 	if (!f)
258 	{
259 		_af_error(AF_BAD_OPEN, "could not open virtual file");
260 		return AF_NULL_FILEHANDLE;
261 	}
262 
263 	AFfilehandle filehandle;
264 	if (_afOpenFile(access, f, NULL, &filehandle, setup) != AF_SUCCEED)
265 	{
266 		delete f;
267 	}
268 
269 	return filehandle;
270 }
271 
_afOpenFile(int access,File * f,const char * filename,AFfilehandle * file,AFfilesetup filesetup)272 static status _afOpenFile (int access, File *f, const char *filename,
273 	AFfilehandle *file, AFfilesetup filesetup)
274 {
275 	int	fileFormat = AF_FILE_UNKNOWN;
276 	int	implemented = true;
277 
278 	int		userSampleFormat = 0;
279 	double		userSampleRate = 0.0;
280 	PCMInfo	userPCM = {0};
281 	bool		userFormatSet = false;
282 
283 	AFfilehandle	filehandle = AF_NULL_FILEHANDLE;
284 	AFfilesetup	completesetup = AF_NULL_FILESETUP;
285 
286 	*file = AF_NULL_FILEHANDLE;
287 
288 	if (access == _AF_WRITE_ACCESS || filesetup != AF_NULL_FILESETUP)
289 	{
290 		if (!_af_filesetup_ok(filesetup))
291 			return AF_FAIL;
292 
293 		fileFormat = filesetup->fileFormat;
294 		if (access == _AF_READ_ACCESS && fileFormat != AF_FILE_RAWDATA)
295 		{
296 			_af_error(AF_BAD_FILESETUP,
297 				"warning: opening file for read access: "
298 				"ignoring file setup with non-raw file format");
299 			filesetup = AF_NULL_FILESETUP;
300 			fileFormat = _af_identify(f, &implemented);
301 		}
302 	}
303 	else if (filesetup == AF_NULL_FILESETUP)
304 		fileFormat = _af_identify(f, &implemented);
305 
306 	if (fileFormat == AF_FILE_UNKNOWN)
307 	{
308 		if (filename != NULL)
309 			_af_error(AF_BAD_NOT_IMPLEMENTED,
310 				"'%s': unrecognized audio file format",
311 				filename);
312 		else
313 			_af_error(AF_BAD_NOT_IMPLEMENTED,
314 				"unrecognized audio file format");
315 		return AF_FAIL;
316 	}
317 
318 	const char *formatName = _af_units[fileFormat].name;
319 
320 	if (!implemented)
321 	{
322 		_af_error(AF_BAD_NOT_IMPLEMENTED,
323 			"%s format not currently supported", formatName);
324 	}
325 
326 	completesetup = NULL;
327 	if (filesetup != AF_NULL_FILESETUP)
328 	{
329 		userSampleFormat = filesetup->tracks[0].f.sampleFormat;
330 		userPCM = filesetup->tracks[0].f.pcm;
331 		userSampleRate = filesetup->tracks[0].f.sampleRate;
332 		userFormatSet = true;
333 		if ((completesetup = _af_units[fileFormat].completesetup(filesetup)) == NULL)
334 			return AF_FAIL;
335 	}
336 
337 	filehandle = _AFfilehandle::create(fileFormat);
338 	if (!filehandle)
339 	{
340 		if (completesetup)
341 			afFreeFileSetup(completesetup);
342 		return AF_FAIL;
343 	}
344 
345 	filehandle->m_fh = f;
346 	filehandle->m_access = access;
347 	filehandle->m_seekok = f->canSeek();
348 	if (filename != NULL)
349 		filehandle->m_fileName = strdup(filename);
350 	else
351 		filehandle->m_fileName = NULL;
352 	filehandle->m_fileFormat = fileFormat;
353 
354 	status result = access == _AF_READ_ACCESS ?
355 		filehandle->readInit(completesetup) :
356 		filehandle->writeInit(completesetup);
357 
358 	if (result != AF_SUCCEED)
359 	{
360 		delete filehandle;
361 		filehandle = AF_NULL_FILEHANDLE;
362 		if (completesetup)
363 			afFreeFileSetup(completesetup);
364 		return AF_FAIL;
365 	}
366 
367 	if (completesetup)
368 		afFreeFileSetup(completesetup);
369 
370 	/*
371 		Initialize virtual format.
372 	*/
373 	for (int t=0; t<filehandle->m_trackCount; t++)
374 	{
375 		Track *track = &filehandle->m_tracks[t];
376 
377 		track->v = track->f;
378 
379 		if (userFormatSet)
380 		{
381 			track->v.sampleFormat = userSampleFormat;
382 			track->v.pcm = userPCM;
383 			track->v.sampleRate = userSampleRate;
384 		}
385 
386 		track->v.compressionType = AF_COMPRESSION_NONE;
387 		track->v.compressionParams = NULL;
388 
389 #if WORDS_BIGENDIAN
390 		track->v.byteOrder = AF_BYTEORDER_BIGENDIAN;
391 #else
392 		track->v.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
393 #endif
394 
395 		track->ms = new ModuleState();
396 		if (track->ms->init(filehandle, track) == AF_FAIL)
397 		{
398 			delete filehandle;
399 			return AF_FAIL;
400 		}
401 	}
402 
403 	*file = filehandle;
404 
405 	return AF_SUCCEED;
406 }
407 
afSyncFile(AFfilehandle handle)408 int afSyncFile (AFfilehandle handle)
409 {
410 	if (!_af_filehandle_ok(handle))
411 		return -1;
412 
413 	if (handle->m_access == _AF_WRITE_ACCESS)
414 	{
415 		/* Finish writes on all tracks. */
416 		for (int trackno = 0; trackno < handle->m_trackCount; trackno++)
417 		{
418 			Track *track = &handle->m_tracks[trackno];
419 
420 			if (track->ms->isDirty() && track->ms->setup(handle, track) == AF_FAIL)
421 				return -1;
422 
423 			if (track->ms->sync(handle, track) != AF_SUCCEED)
424 				return -1;
425 		}
426 
427 		/* Update file headers. */
428 		if (handle->update() != AF_SUCCEED)
429 			return AF_FAIL;
430 	}
431 	else if (handle->m_access == _AF_READ_ACCESS)
432 	{
433 		/* Do nothing. */
434 	}
435 	else
436 	{
437 		_af_error(AF_BAD_ACCMODE, "unrecognized access mode %d",
438 			handle->m_access);
439 		return AF_FAIL;
440 	}
441 
442 	return AF_SUCCEED;
443 }
444 
afCloseFile(AFfilehandle file)445 int afCloseFile (AFfilehandle file)
446 {
447 	int	err;
448 
449 	if (!_af_filehandle_ok(file))
450 		return -1;
451 
452 	afSyncFile(file);
453 
454 	err = file->m_fh->close();
455 	if (err < 0)
456 		_af_error(AF_BAD_CLOSE, "close returned %d", err);
457 
458 	delete file->m_fh;
459 	delete file;
460 
461 	return 0;
462 }
463