1 // Copyright (C) 1999-2005 Open Source Telecom Corporation.
2 // Copyright (C) 2006-2014 David Sugar, Tycho Softworks.
3 // Copyright (C) 2015 Cherokees of Idaho.
4 //
5 // This file is part of GNU ccAudio2.
6 //
7 // GNU ccAudio2 is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Lesser General Public License as published
9 // by the Free Software Foundation, either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // GNU ccAudio2 is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Lesser General Public License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public License
18 // along with GNU ccAudio2. If not, see <http://www.gnu.org/licenses/>.
19
20 #include <ucommon/ucommon.h>
21 #include <ccaudio2-config.h>
22 #include <ucommon/export.h>
23 #include <ccaudio2.h>
24
25 #ifdef _MSWINDOWS_
26 #define FD(x) ((HANDLE)(x.handle))
27 #define SETFD(x,y) (x.handle = (void *)(y))
28 #ifndef INVALID_SET_FILE_POINTER
29 #define INVALID_SET_FILE_POINTER ((DWORD)(-1))
30 #endif
31 #else
32 #include <fcntl.h>
33 #include <unistd.h>
34 #endif
35
36 namespace ucommon {
37
afCreate(const char * name,bool exclusive)38 bool AudioFile::afCreate(const char *name, bool exclusive)
39 {
40 AudioFile::close();
41 mode = modeWrite;
42 #ifdef _MSWINDOWS_
43 if(exclusive)
44 SETFD(file, CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
45 NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL));
46 else
47 SETFD(file, CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
48 NULL, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
49 #else
50 // JRS: do not use creat() here. It uses O_RDONLY by default
51 // which prevents us from reading the wave header later on when
52 // setting the length during AudioFile::Close().
53 if(exclusive)
54 file.fd = ::open(name, O_CREAT | O_EXCL | O_RDWR, 0660);
55 else
56 file.fd = ::open(name, O_CREAT | O_TRUNC | O_RDWR, 0660);
57 #endif
58 return is_open();
59 }
60
afOpen(const char * name,Mode m)61 bool AudioFile::afOpen(const char *name, Mode m)
62 {
63 AudioFile::close();
64 mode = m;
65 #ifdef _MSWINDOWS_
66 switch(m) {
67 case modeWrite:
68 case modeCache:
69 SETFD(file, CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
70 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
71 if(is_open())
72 break;
73 case modeInfo:
74 case modeRead:
75 case modeFeed:
76 case modeReadAny:
77 case modeReadOne:
78 SETFD(file, CreateFile(name,GENERIC_READ, 0,
79 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
80 default:
81 break;
82 }
83 #else
84 switch(m) {
85 case modeWrite:
86 case modeCache:
87 file.fd = ::open(name, O_RDWR);
88 if(file.fd > -1)
89 break;
90 case modeInfo:
91 case modeRead:
92 case modeFeed:
93 case modeReadAny:
94 case modeReadOne:
95 file.fd = ::open(name, O_RDONLY);
96 default:
97 break;
98 }
99 #endif
100 return is_open();
101 }
afWrite(unsigned char * data,unsigned len)102 int AudioFile::afWrite(unsigned char *data, unsigned len)
103 {
104 #ifdef _MSWINDOWS_
105 DWORD count;
106
107 if(!WriteFile(FD(file), data, (DWORD)len, &count, NULL))
108 return -1;
109 return count;
110 #else
111 return ::write(file.fd, data, len);
112 #endif
113 }
114
afRead(unsigned char * data,unsigned len)115 int AudioFile::afRead(unsigned char *data, unsigned len)
116 {
117 #ifdef _MSWINDOWS_
118 DWORD count;
119
120 if(!ReadFile(FD(file), data, (DWORD)len, &count, NULL))
121 return -1;
122 return count;
123 #else
124 return ::read(file.fd, data, len);
125 #endif
126 }
127
afPeek(unsigned char * data,unsigned len)128 bool AudioFile::afPeek(unsigned char *data, unsigned len)
129 {
130 if(afRead(data, len) != (int)len)
131 return false;
132 return true;
133 }
134
afSeek(unsigned long pos)135 bool AudioFile::afSeek(unsigned long pos)
136 {
137 #ifdef _MSWINDOWS_
138 if(SetFilePointer(FD(file), pos, NULL, FILE_BEGIN) != INVALID_SET_FILE_POINTER)
139 #else
140 if(::lseek(file.fd, pos, SEEK_SET) != -1)
141 #endif
142 return true;
143 else
144 return false;
145 }
146
is_open(void) const147 bool AudioFile::is_open(void) const
148 {
149 #ifdef _MSWINDOWS_
150 if(FD(file) == INVALID_HANDLE_VALUE)
151 return false;
152 #else
153 if(file.fd < 0)
154 return false;
155 #endif
156 return true;
157 }
158
afClose(void)159 void AudioFile::afClose(void)
160 {
161 unsigned long size = ~0;
162 #ifdef _MSWINDOWS_
163 if(FD(file) != INVALID_HANDLE_VALUE) {
164 size = getPosition();
165 CloseHandle(FD(file));
166 if(size < minimum && pathname && mode == modeWrite)
167 DeleteFile(pathname);
168 }
169 SETFD(file, INVALID_HANDLE_VALUE);
170 #else
171 if(file.fd > -1) {
172 size = getPosition();
173 if(size < minimum && pathname && mode == modeWrite)
174 ::remove(pathname);
175 ::close(file.fd);
176 }
177 file.fd = -1;
178 #endif
179 }
180
initialize(void)181 void AudioFile::initialize(void)
182 {
183 minimum = 0;
184 pathname = NULL;
185 info.annotation = NULL;
186 header = 0l;
187 iolimit = 0l;
188 mode = modeInfo;
189 #ifdef _MSWINDOWS_
190 SETFD(file, INVALID_HANDLE_VALUE);
191 #else
192 file.fd = -1;
193 #endif
194 }
195
setPosition(unsigned long samples)196 Audio::Error AudioFile::setPosition(unsigned long samples)
197 {
198 long pos;
199 long eof;
200
201 if(!is_open())
202 return errNotOpened;
203
204 #ifdef _MSWINDOWS_
205 eof = SetFilePointer(FD(file), 0l, NULL, FILE_END);
206 #else
207 eof = ::lseek(file.fd, 0l, SEEK_END);
208 #endif
209 if(samples == (unsigned long)~0l)
210 return errSuccess;
211
212 pos = (long)(header + toBytes(info, samples));
213 if(pos > eof) {
214 pos = eof;
215 return errSuccess;
216 }
217
218 #ifdef _MSWINDOWS_
219 SetFilePointer(FD(file), pos, NULL, FILE_BEGIN);
220 #else
221 ::lseek(file.fd, pos, SEEK_SET);
222 #endif
223 return errSuccess;
224 }
225
getAbsolutePosition(void)226 unsigned long AudioFile::getAbsolutePosition(void)
227 {
228 unsigned long pos;
229 if(!is_open())
230 return 0;
231
232 #ifdef _MSWINDOWS_
233 pos = SetFilePointer(FD(file), 0l, NULL, FILE_CURRENT);
234 if(pos == INVALID_SET_FILE_POINTER) {
235 #else
236 pos = ::lseek(file.fd, 0l, SEEK_CUR);
237 if(pos == (unsigned long)-1l) {
238 #endif
239 close();
240 return 0;
241 }
242 return pos;
243 }
244
245 unsigned long AudioFile::getPosition(void)
246 {
247 unsigned long pos;
248 if(!is_open())
249 return 0;
250
251 #ifdef _MSWINDOWS_
252 pos = SetFilePointer(FD(file), 0l, NULL, FILE_CURRENT);
253 if(pos == INVALID_SET_FILE_POINTER) {
254 #else
255 pos = getAbsolutePosition();
256 if(pos == (unsigned long)-1l) {
257 #endif
258 close();
259 return 0;
260 }
261 pos = toSamples(info, pos - header);
262 return pos;
263 }
264
265 } // namespace ucommon
266