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