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