Fix for coverity #29360
[supertux.git] / src / audio / sound_file.cpp
1 //  SuperTux
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 //
4 //  This program is free software: you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation, either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 /** Used SDL_mixer and glest source as reference */
18
19 #include "audio/sound_file.hpp"
20
21 #include <config.h>
22
23 #include <stdint.h>
24 #include <sstream>
25 #include <physfs.h>
26
27 #include "audio/sound_error.hpp"
28 #include "audio/ogg_sound_file.hpp"
29 #include "audio/wav_sound_file.hpp"
30 #include "lisp/parser.hpp"
31 #include "util/reader.hpp"
32 #include "util/file_system.hpp"
33 #include "util/log.hpp"
34
35 std::unique_ptr<SoundFile> load_music_file(const std::string& filename)
36 {
37   lisp::Parser parser(false);
38   const lisp::Lisp* root = parser.parse(filename);
39   const lisp::Lisp* music = root->get_lisp("supertux-music");
40   if(music == NULL)
41     throw SoundError("file is not a supertux-music file.");
42
43   std::string raw_music_file;
44   float loop_begin = 0;
45   float loop_at    = -1;
46
47   music->get("file", raw_music_file);
48   music->get("loop-begin", loop_begin);
49   music->get("loop-at", loop_at);
50
51   if(loop_begin < 0) {
52     throw SoundError("can't loop from negative value");
53   }
54
55   std::string basedir = FileSystem::dirname(filename);
56   raw_music_file = FileSystem::normalize(basedir + raw_music_file);
57
58   PHYSFS_file* file = PHYSFS_openRead(raw_music_file.c_str());
59   if(!file) {
60     std::stringstream msg;
61     msg << "Couldn't open '" << raw_music_file << "': " << PHYSFS_getLastError();
62     throw SoundError(msg.str());
63   }
64
65   return std::unique_ptr<SoundFile>(new OggSoundFile(file, loop_begin, loop_at));
66 }
67
68 std::unique_ptr<SoundFile> load_sound_file(const std::string& filename)
69 {
70   if(filename.length() > 6
71      && filename.compare(filename.length()-6, 6, ".music") == 0) {
72     return load_music_file(filename);
73   }
74
75   PHYSFS_file* file = PHYSFS_openRead(filename.c_str());
76   if(!file) {
77     std::stringstream msg;
78     msg << "Couldn't open '" << filename << "': " << PHYSFS_getLastError() << ", using dummy sound file.";
79     throw SoundError(msg.str());
80   }
81
82   try {
83     char magic[4];
84     if(PHYSFS_read(file, magic, sizeof(magic), 1) != 1)
85       throw SoundError("Couldn't read magic, file too short");
86     if (PHYSFS_seek(file, 0) == 0) {
87       std::stringstream msg;
88       msg << "Couldn't seek through sound file: " << PHYSFS_getLastError();
89       throw SoundError(msg.str());
90     }
91
92     if(strncmp(magic, "RIFF", 4) == 0)
93       return std::unique_ptr<SoundFile>(new WavSoundFile(file));
94     else if(strncmp(magic, "OggS", 4) == 0)
95       return std::unique_ptr<SoundFile>(new OggSoundFile(file, 0, -1));
96     else
97       throw SoundError("Unknown file format");
98   } catch(std::exception& e) {
99     std::stringstream msg;
100     msg << "Couldn't read '" << filename << "': " << e.what();
101     throw SoundError(msg.str());
102   }
103 }
104
105 /* EOF */