Flag an error if the FB gui is configured without the rawfb device. For #108015.
[gnash.git] / libcore / MovieFactory.cpp
blobd815d2df8388529fc489b832935cf6c68e4a8b78
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 // Free Software Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "MovieFactory.h"
22 #include <string>
23 #include <map>
24 #include <memory>
25 #include <algorithm>
27 #include "GnashEnums.h"
28 #include "GnashImage.h"
29 #include "IOChannel.h"
30 #include "utility.h"
31 #include "log.h"
32 #include "SWFMovieDefinition.h"
33 #include "BitmapMovieDefinition.h"
34 #include "RunResources.h"
35 #include "URL.h"
36 #include "StreamProvider.h"
37 #include "MovieLibrary.h"
38 #include "fontlib.h"
40 namespace gnash {
42 namespace {
43 /// Get type of file looking at first bytes
44 FileType getFileType(IOChannel& in);
46 boost::intrusive_ptr<SWFMovieDefinition> createSWFMovie(
47 std::auto_ptr<IOChannel> in, const std::string& url,
48 const RunResources& runResources, bool startLoaderThread);
50 boost::intrusive_ptr<BitmapMovieDefinition> createBitmapMovie(
51 std::auto_ptr<IOChannel> in, const std::string& url,
52 const RunResources& r, FileType type);
54 boost::intrusive_ptr<movie_definition> createNonLibraryMovie(
55 const URL& url, const RunResources& runResources,
56 const char* reset_url, bool startLoaderThread,
57 const std::string* postdata);
60 MovieLibrary MovieFactory::movieLibrary;
62 boost::intrusive_ptr<movie_definition>
63 MovieFactory::makeMovie(std::auto_ptr<IOChannel> in, const std::string& url,
64 const RunResources& runResources, bool startLoaderThread)
66 boost::intrusive_ptr<movie_definition> ret;
68 assert(in.get());
70 // see if it's a jpeg or an swf
71 FileType type = getFileType(*in);
73 switch (type) {
74 case GNASH_FILETYPE_JPEG:
75 case GNASH_FILETYPE_PNG:
76 case GNASH_FILETYPE_GIF:
78 if (!startLoaderThread) {
79 log_unimpl(_("Requested to keep from completely loading "
80 "a movie, but the movie in question is an "
81 "image, for which we don't yet have the "
82 "concept of a 'loading thread'"));
84 ret = createBitmapMovie(in, url, runResources, type);
85 break;
89 case GNASH_FILETYPE_SWF:
90 ret = createSWFMovie(in, url, runResources, startLoaderThread);
91 break;
93 case GNASH_FILETYPE_FLV:
94 log_unimpl(_("FLV can't be loaded directly as a movie"));
95 return ret;
97 default:
98 log_error(_("Unknown file type"));
99 break;
102 return ret;
105 // Try to load a movie from the given url, if we haven't
106 // loaded it already. Add it to our library on success, and
107 // return a pointer to it.
108 boost::intrusive_ptr<movie_definition>
109 MovieFactory::makeMovie(const URL& url, const RunResources& runResources,
110 const char* real_url, bool startLoaderThread,
111 const std::string* postdata)
113 boost::intrusive_ptr<movie_definition> mov;
115 // Use real_url as label for cache if available
116 const std::string& cache_label = real_url ? URL(real_url).str() : url.str();
118 // Is the movie already in the library? (don't check if we have post data!)
119 if (!postdata) {
120 if (movieLibrary.get(cache_label, &mov)) {
121 log_debug("Movie %s already in library", cache_label);
122 return mov;
126 // Try to open a file under the filename, but DO NOT start
127 // the loader thread now to avoid IMPORT tag loaders from
128 // calling createMovie() again and NOT finding
129 // the just-created movie.
130 mov = createNonLibraryMovie(url, runResources, real_url, false, postdata);
132 if (!mov) {
133 log_error(_("Couldn't load library movie '%s'"), url.str());
134 return mov;
137 // Movie is good, add to the library, but not if we used POST
138 if (!postdata) {
139 movieLibrary.add(cache_label, mov.get());
140 log_debug("Movie %s (SWF%d) added to library",
141 cache_label, mov->get_version());
143 else {
144 log_debug("Movie %s (SWF%d) NOT added to library (resulted from "
145 "a POST)", cache_label, mov->get_version());
148 /// Now complete the load if the movie is an SWF movie
150 /// This is a no-op except for SWF movies.
151 if (startLoaderThread) mov->completeLoad();
153 return mov;
156 void
157 MovieFactory::clear()
159 movieLibrary.clear();
162 namespace {
164 /// Get type of file looking at first bytes
165 FileType
166 getFileType(IOChannel& in)
168 in.seek(0);
170 char buf[3];
172 if (in.read(buf, 3) < 3) {
173 log_error(_("Can't read file header"));
174 in.seek(0);
175 return GNASH_FILETYPE_UNKNOWN;
178 // This is the magic number {0xff, 0xd8, 0xff} for JPEG format files
179 if (std::equal(buf, buf + 3, "\xff\xd8\xff")) {
180 in.seek(0);
181 return GNASH_FILETYPE_JPEG;
184 // This is the magic number for any PNG format file
185 // buf[3] == 'G' (we didn't read so far)
186 if (std::equal(buf, buf + 3, "\x89PN")) {
187 in.seek(0);
188 return GNASH_FILETYPE_PNG;
191 // This is the magic number for any GIF format file
192 if (std::equal(buf, buf + 3, "GIF")) {
193 in.seek(0);
194 return GNASH_FILETYPE_GIF;
197 // This is for SWF (FWS or CWS)
198 if (std::equal(buf, buf + 3, "FWS") || std::equal(buf, buf + 3, "CWS")) {
199 in.seek(0);
200 return GNASH_FILETYPE_SWF;
203 // Take one guess at what this is. (It's an FLV-format file).
204 if (std::equal(buf, buf + 3, "FLV")) {
205 return GNASH_FILETYPE_FLV;
208 // Check if it is an swf embedded in a player (.exe-file)
209 if (std::equal(buf, buf + 2, "MZ")) {
211 if (in.read(buf, 3) < 3) {
212 log_error(_("Can't read 3 bytes after an MZ (.exe) header"));
213 in.seek(0);
214 return GNASH_FILETYPE_UNKNOWN;
217 while ((buf[0]!='F' && buf[0]!='C') || buf[1]!='W' || buf[2]!='S') {
218 buf[0] = buf[1];
219 buf[1] = buf[2];
220 buf[2] = in.read_byte();
221 if (in.eof()) {
222 log_error(_("Could not find SWF inside an .exe file"));
223 in.seek(0);
224 return GNASH_FILETYPE_UNKNOWN;
227 in.seek(in.tell() - static_cast<std::streamoff>(3));
228 return GNASH_FILETYPE_SWF;
231 log_error(_("unknown file type, buffer is %c%c%c"), buf[0], buf[1], buf[2]);
232 return GNASH_FILETYPE_UNKNOWN;
235 // Create a SWFMovieDefinition from an SWF stream
236 // NOTE: this method assumes this *is* an SWF stream
237 boost::intrusive_ptr<SWFMovieDefinition>
238 createSWFMovie(std::auto_ptr<IOChannel> in, const std::string& url,
239 const RunResources& runResources, bool startLoaderThread)
242 boost::intrusive_ptr<SWFMovieDefinition> m = new SWFMovieDefinition(runResources);
244 const std::string& absURL = URL(url).str();
246 if (!m->readHeader(in, absURL)) return 0;
247 if (startLoaderThread && !m->completeLoad()) return 0;
249 return m;
252 // Create a movie_definition from an image format stream
253 // NOTE: this method assumes this *is* the format described in the
254 // FileType type
255 // TODO: The pp won't display PNGs for SWF7 or below.
256 boost::intrusive_ptr<BitmapMovieDefinition>
257 createBitmapMovie(std::auto_ptr<IOChannel> in, const std::string& url,
258 const RunResources& r, FileType type)
260 assert (in.get());
262 boost::intrusive_ptr<BitmapMovieDefinition> ret;
264 // readImageData takes a shared pointer because JPEG streams sometimes need
265 // to transfer ownership.
266 boost::shared_ptr<IOChannel> imageData(in.release());
268 try {
269 std::auto_ptr<image::GnashImage> im(
270 image::Input::readImageData(imageData, type));
272 if (!im.get()) {
273 log_error(_("Can't read image file from %s"), url);
274 return ret;
277 Renderer* renderer = r.renderer();
278 ret = new BitmapMovieDefinition(im, renderer, url);
279 return ret;
282 catch (const ParserException& e) {
283 log_error(_("Parsing error: %s"), e.what());
284 return ret;
289 boost::intrusive_ptr<movie_definition>
290 createNonLibraryMovie(const URL& url, const RunResources& runResources,
291 const char* reset_url, bool startLoaderThread,
292 const std::string* postdata)
295 boost::intrusive_ptr<movie_definition> ret;
297 std::auto_ptr<IOChannel> in;
299 const StreamProvider& streamProvider = runResources.streamProvider();
301 const RcInitFile& rcfile = RcInitFile::getDefaultInstance();
303 if (postdata) {
304 in = streamProvider.getStream(url, *postdata, rcfile.saveLoadedMedia());
306 else in = streamProvider.getStream(url, rcfile.saveLoadedMedia());
308 if (!in.get()) {
309 log_error(_("failed to open '%s'; can't create movie"), url);
310 return ret;
313 if (in->bad()) {
314 log_error(_("streamProvider opener can't open '%s'"), url);
315 return ret;
318 const std::string& movie_url = reset_url ? reset_url : url.str();
319 ret = MovieFactory::makeMovie(in, movie_url, runResources,
320 startLoaderThread);
322 return ret;
326 } // unnamed namespace
328 } // namespace gnash
330 // Local Variables:
331 // mode: C++
332 // indent-tabs-mode: t
333 // End: