1 /*
2 * ALURE OpenAL utility library
3 * Copyright (c) 2009-2010 by Chris Robinson.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "config.h"
25
26 #include "main.h"
27
28 #include <string.h>
29 #include <assert.h>
30
31 #include <algorithm>
32 #include <vector>
33 #include <memory>
34 #include <string>
35 #include <istream>
36 #include <fstream>
37 #include <iostream>
38 #include <sstream>
39
40
GetList()41 const Decoder::ListType& Decoder::GetList()
42 { return AddList(); }
43
AddList(Decoder::FactoryType func,ALint prio)44 Decoder::ListType& Decoder::AddList(Decoder::FactoryType func, ALint prio)
45 {
46 static ListType FuncList;
47 if(func)
48 {
49 assert(SearchSecond(FuncList.begin(), FuncList.end(), func) == FuncList.end());
50 FuncList.insert(std::make_pair(prio, func));
51 }
52 return FuncList;
53 }
54
55
56 struct customStream : public alureStream {
57 void *usrFile;
58 ALenum format;
59 ALuint samplerate;
60 ALuint blockAlign;
61 MemDataInfo memInfo;
62
63 UserCallbacks cb;
64
IsValidcustomStream65 virtual bool IsValid()
66 { return usrFile != NULL; }
67
GetFormatcustomStream68 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
69 {
70 if(format == AL_NONE)
71 {
72 if(!cb.get_fmt || !cb.get_fmt(usrFile, &format, &samplerate, &blockAlign))
73 return false;
74
75 ALuint detected = DetectBlockAlignment(format);
76 if(detected && (blockAlign%detected) != 0)
77 blockAlign = 0;
78 }
79
80 *fmt = format;
81 *frequency = samplerate;
82 *blockalign = blockAlign;
83 return true;
84 }
85
GetDatacustomStream86 virtual ALuint GetData(ALubyte *data, ALuint bytes)
87 { return cb.decode(usrFile, data, bytes); }
88
RewindcustomStream89 virtual bool Rewind()
90 {
91 if(cb.rewind && cb.rewind(usrFile))
92 return true;
93 SetError("Rewind failed");
94 return false;
95 }
96
customStreamcustomStream97 customStream(const char *fname, const UserCallbacks &callbacks)
98 : alureStream(NULL), usrFile(NULL), format(AL_NONE), samplerate(0),
99 blockAlign(0), cb(callbacks)
100 { if(cb.open_file) usrFile = cb.open_file(fname); }
101
customStreamcustomStream102 customStream(const MemDataInfo &memData, const UserCallbacks &callbacks)
103 : alureStream(NULL), usrFile(NULL), format(AL_NONE), samplerate(0),
104 blockAlign(0), memInfo(memData), cb(callbacks)
105 { if(cb.open_mem) usrFile = cb.open_mem(memInfo.Data, memInfo.Length); }
106
customStreamcustomStream107 customStream(void *userdata, ALenum fmt, ALuint srate, const UserCallbacks &callbacks)
108 : alureStream(NULL), usrFile(userdata), format(fmt), samplerate(srate),
109 blockAlign(DetectBlockAlignment(format)), cb(callbacks)
110 { }
111
~customStreamcustomStream112 virtual ~customStream()
113 {
114 if(cb.close && usrFile)
115 cb.close(usrFile);
116 usrFile = NULL;
117 }
118 };
119
120
121 template <typename T>
get_stream_decoder(const T & fdata)122 static alureStream *get_stream_decoder(const T &fdata)
123 {
124 std::map<ALint,UserCallbacks>::iterator i = InstalledCallbacks.begin();
125 while(i != InstalledCallbacks.end() && i->first < 0)
126 {
127 std::auto_ptr<alureStream> stream(new customStream(fdata, i->second));
128 if(stream->IsValid()) return stream.release();
129 i++;
130 }
131
132 std::istream *file = new InStream(fdata);
133 if(!file->fail())
134 {
135 const Decoder::ListType Factories = Decoder::GetList();
136 Decoder::ListType::const_reverse_iterator factory = Factories.rbegin();
137 Decoder::ListType::const_reverse_iterator end = Factories.rend();
138 while(factory != end)
139 {
140 file->clear();
141 file->seekg(0, std::ios_base::beg);
142
143 std::auto_ptr<alureStream> stream(factory->second(file));
144 if(stream.get() != NULL) return stream.release();
145
146 factory++;
147 }
148
149 SetError("Unsupported type");
150 delete file;
151 }
152 else
153 {
154 SetError("Failed to open file");
155 delete file;
156 }
157
158 while(i != InstalledCallbacks.end())
159 {
160 std::auto_ptr<alureStream> stream(new customStream(fdata, i->second));
161 if(stream->IsValid()) return stream.release();
162 i++;
163 }
164
165 return NULL;
166 }
167
create_stream(const char * fname)168 alureStream *create_stream(const char *fname)
169 { return get_stream_decoder(fname); }
create_stream(const MemDataInfo & memData)170 alureStream *create_stream(const MemDataInfo &memData)
171 { return get_stream_decoder(memData); }
172
create_stream(ALvoid * userdata,ALenum format,ALuint rate,const UserCallbacks & cb)173 alureStream *create_stream(ALvoid *userdata, ALenum format, ALuint rate, const UserCallbacks &cb)
174 { return new customStream(userdata, format, rate, cb); }
175