Check return from std::string::find
[gnash.git] / libcore / MovieFactory.cpp
blob4d01fd1de903633ce46da387d0fd4ea28c5c9e22
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
3 // 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 "smart_ptr.h"
30 #include "IOChannel.h"
31 #include "utility.h"
32 #include "log.h"
33 #include "SWFMovieDefinition.h"
34 #include "BitmapMovieDefinition.h"
35 #include "RunResources.h"
36 #include "URL.h"
37 #include "StreamProvider.h"
38 #include "MovieLibrary.h"
39 #include "fontlib.h"
41 namespace gnash {
43 namespace {
44 /// Get type of file looking at first bytes
45 FileType getFileType(IOChannel& in);
47 boost::intrusive_ptr<SWFMovieDefinition> createSWFMovie(
48 std::auto_ptr<IOChannel> in, const std::string& url,
49 const RunResources& runResources, bool startLoaderThread);
51 boost::intrusive_ptr<BitmapMovieDefinition> createBitmapMovie(
52 std::auto_ptr<IOChannel> in, const std::string& url,
53 const RunResources& r, FileType type);
55 boost::intrusive_ptr<movie_definition> createNonLibraryMovie(
56 const URL& url, const RunResources& runResources,
57 const char* reset_url, bool startLoaderThread,
58 const std::string* postdata);
61 MovieLibrary MovieFactory::movieLibrary;
63 boost::intrusive_ptr<movie_definition>
64 MovieFactory::makeMovie(std::auto_ptr<IOChannel> in, const std::string& url,
65 const RunResources& runResources, bool startLoaderThread)
67 boost::intrusive_ptr<movie_definition> ret;
69 assert(in.get());
71 // see if it's a jpeg or an swf
72 FileType type = getFileType(*in);
74 switch (type) {
75 case GNASH_FILETYPE_JPEG:
76 case GNASH_FILETYPE_PNG:
77 case GNASH_FILETYPE_GIF:
79 if (!startLoaderThread) {
80 log_unimpl(_("Requested to keep from completely loading "
81 "a movie, but the movie in question is an "
82 "image, for which we don't yet have the "
83 "concept of a 'loading thread'"));
85 ret = createBitmapMovie(in, url, runResources, type);
86 break;
90 case GNASH_FILETYPE_SWF:
91 ret = createSWFMovie(in, url, runResources, startLoaderThread);
92 break;
94 case GNASH_FILETYPE_FLV:
95 log_unimpl(_("FLV can't be loaded directly as a movie"));
96 return ret;
98 default:
99 log_error(_("Unknown file type"));
100 break;
103 return ret;
106 // Try to load a movie from the given url, if we haven't
107 // loaded it already. Add it to our library on success, and
108 // return a pointer to it.
109 boost::intrusive_ptr<movie_definition>
110 MovieFactory::makeMovie(const URL& url, const RunResources& runResources,
111 const char* real_url, bool startLoaderThread,
112 const std::string* postdata)
114 boost::intrusive_ptr<movie_definition> mov;
116 // Use real_url as label for cache if available
117 const std::string& cache_label = real_url ? URL(real_url).str() : url.str();
119 // Is the movie already in the library? (don't check if we have post data!)
120 if (!postdata) {
121 if (movieLibrary.get(cache_label, &mov)) {
122 log_debug(_("Movie %s already in library"), cache_label);
123 return mov;
127 // Try to open a file under the filename, but DO NOT start
128 // the loader thread now to avoid IMPORT tag loaders from
129 // calling createMovie() again and NOT finding
130 // the just-created movie.
131 mov = createNonLibraryMovie(url, runResources, real_url, false, postdata);
133 if (!mov) {
134 log_error(_("Couldn't load library movie '%s'"), url.str());
135 return mov;
138 // Movie is good, add to the library, but not if we used POST
139 if (!postdata) {
140 movieLibrary.add(cache_label, mov.get());
141 log_debug(_("Movie %s (SWF%d) added to library"),
142 cache_label, mov->get_version());
144 else {
145 log_debug(_("Movie %s (SWF%d) NOT added to library (resulted from "
146 "a POST)"), cache_label, mov->get_version());
149 /// Now complete the load if the movie is an SWF movie
151 /// This is a no-op except for SWF movies.
152 if (startLoaderThread) mov->completeLoad();
154 return mov;
157 void
158 MovieFactory::clear()
160 movieLibrary.clear();
163 namespace {
165 /// Get type of file looking at first bytes
166 FileType
167 getFileType(IOChannel& in)
169 in.seek(0);
171 char buf[3];
173 if (in.read(buf, 3) < 3) {
174 log_error(_("Can't read file header"));
175 in.seek(0);
176 return GNASH_FILETYPE_UNKNOWN;
179 // This is the magic number {0xff, 0xd8, 0xff} for JPEG format files
180 if (std::equal(buf, buf + 3, "\xff\xd8\xff")) {
181 in.seek(0);
182 return GNASH_FILETYPE_JPEG;
185 // This is the magic number for any PNG format file
186 // buf[3] == 'G' (we didn't read so far)
187 if (std::equal(buf, buf + 3, "\x89PN")) {
188 in.seek(0);
189 return GNASH_FILETYPE_PNG;
192 // This is the magic number for any GIF format file
193 if (std::equal(buf, buf + 3, "GIF")) {
194 in.seek(0);
195 return GNASH_FILETYPE_GIF;
198 // This is for SWF (FWS or CWS)
199 if (std::equal(buf, buf + 3, "FWS") || std::equal(buf, buf + 3, "CWS")) {
200 in.seek(0);
201 return GNASH_FILETYPE_SWF;
204 // Take one guess at what this is. (It's an FLV-format file).
205 if (std::equal(buf, buf + 3, "FLV")) {
206 return GNASH_FILETYPE_FLV;
209 // Check if it is an swf embedded in a player (.exe-file)
210 if (std::equal(buf, buf + 2, "MZ")) {
212 if (in.read(buf, 3) < 3) {
213 log_error(_("Can't read 3 bytes after an MZ (.exe) header"));
214 in.seek(0);
215 return GNASH_FILETYPE_UNKNOWN;
218 while ((buf[0]!='F' && buf[0]!='C') || buf[1]!='W' || buf[2]!='S') {
219 buf[0] = buf[1];
220 buf[1] = buf[2];
221 buf[2] = in.read_byte();
222 if (in.eof()) {
223 log_error(_("Could not find SWF inside an exe file"));
224 in.seek(0);
225 return GNASH_FILETYPE_UNKNOWN;
228 in.seek(in.tell() - static_cast<std::streamoff>(3));
229 return GNASH_FILETYPE_SWF;
232 log_error("unknown file type, buf is %c%c%c", buf[0], buf[1], buf[2]);
233 return GNASH_FILETYPE_UNKNOWN;
236 // Create a SWFMovieDefinition from an SWF stream
237 // NOTE: this method assumes this *is* an SWF stream
238 boost::intrusive_ptr<SWFMovieDefinition>
239 createSWFMovie(std::auto_ptr<IOChannel> in, const std::string& url,
240 const RunResources& runResources, bool startLoaderThread)
243 boost::intrusive_ptr<SWFMovieDefinition> m = new SWFMovieDefinition(runResources);
245 const std::string& absURL = URL(url).str();
247 if (!m->readHeader(in, absURL)) return 0;
248 if (startLoaderThread && !m->completeLoad()) return 0;
250 return m;
253 // Create a movie_definition from an image format stream
254 // NOTE: this method assumes this *is* the format described in the
255 // FileType type
256 // TODO: The pp won't display PNGs for SWF7 or below.
257 boost::intrusive_ptr<BitmapMovieDefinition>
258 createBitmapMovie(std::auto_ptr<IOChannel> in, const std::string& url,
259 const RunResources& r, FileType type)
261 assert (in.get());
263 boost::intrusive_ptr<BitmapMovieDefinition> ret;
265 // readImageData takes a shared pointer because JPEG streams sometimes need
266 // to transfer ownership.
267 boost::shared_ptr<IOChannel> imageData(in.release());
269 try {
270 std::auto_ptr<image::GnashImage> im(
271 image::Input::readImageData(imageData, type));
273 if (!im.get()) {
274 log_error(_("Can't read image file from %s"), url);
275 return ret;
278 Renderer* renderer = r.renderer();
279 ret = new BitmapMovieDefinition(im, renderer, url);
280 return ret;
283 catch (const ParserException& e) {
284 log_error(_("Parsing error: %s"), e.what());
285 return ret;
290 boost::intrusive_ptr<movie_definition>
291 createNonLibraryMovie(const URL& url, const RunResources& runResources,
292 const char* reset_url, bool startLoaderThread,
293 const std::string* postdata)
296 boost::intrusive_ptr<movie_definition> ret;
298 std::auto_ptr<IOChannel> in;
300 const StreamProvider& streamProvider = runResources.streamProvider();
302 const RcInitFile& rcfile = RcInitFile::getDefaultInstance();
304 if (postdata) {
305 in = streamProvider.getStream(url, *postdata, rcfile.saveLoadedMedia());
307 else in = streamProvider.getStream(url, rcfile.saveLoadedMedia());
309 if (!in.get()) {
310 log_error(_("failed to open '%s'; can't create movie"), url);
311 return ret;
314 if (in->bad()) {
315 log_error(_("streamProvider opener can't open '%s'"), url);
316 return ret;
319 const std::string& movie_url = reset_url ? reset_url : url.str();
320 ret = MovieFactory::makeMovie(in, movie_url, runResources,
321 startLoaderThread);
323 return ret;
327 } // unnamed namespace
329 } // namespace gnash
331 // Local Variables:
332 // mode: C++
333 // indent-tabs-mode: t
334 // End: