2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
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.
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"
27 #include "GnashEnums.h"
28 #include "GnashImage.h"
29 #include "smart_ptr.h"
30 #include "IOChannel.h"
33 #include "SWFMovieDefinition.h"
34 #include "BitmapMovieDefinition.h"
35 #include "RunResources.h"
37 #include "StreamProvider.h"
38 #include "MovieLibrary.h"
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
;
71 // see if it's a jpeg or an swf
72 FileType type
= getFileType(*in
);
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
);
90 case GNASH_FILETYPE_SWF
:
91 ret
= createSWFMovie(in
, url
, runResources
, startLoaderThread
);
94 case GNASH_FILETYPE_FLV
:
95 log_unimpl(_("FLV can't be loaded directly as a movie"));
99 log_error(_("Unknown file type"));
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!)
121 if (movieLibrary
.get(cache_label
, &mov
)) {
122 log_debug(_("Movie %s already in library"), cache_label
);
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
);
134 log_error(_("Couldn't load library movie '%s'"), url
.str());
138 // Movie is good, add to the library, but not if we used POST
140 movieLibrary
.add(cache_label
, mov
.get());
141 log_debug(_("Movie %s (SWF%d) added to library"),
142 cache_label
, mov
->get_version());
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();
158 MovieFactory::clear()
160 movieLibrary
.clear();
165 /// Get type of file looking at first bytes
167 getFileType(IOChannel
& in
)
173 if (in
.read(buf
, 3) < 3) {
174 log_error(_("Can't read file header"));
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")) {
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")) {
189 return GNASH_FILETYPE_PNG
;
192 // This is the magic number for any GIF format file
193 if (std::equal(buf
, buf
+ 3, "GIF")) {
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")) {
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"));
215 return GNASH_FILETYPE_UNKNOWN
;
218 while ((buf
[0]!='F' && buf
[0]!='C') || buf
[1]!='W' || buf
[2]!='S') {
221 buf
[2] = in
.read_byte();
223 log_error(_("Could not find SWF inside an exe file"));
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;
253 // Create a movie_definition from an image format stream
254 // NOTE: this method assumes this *is* the format described in the
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
)
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());
270 std::auto_ptr
<image::GnashImage
> im(
271 image::Input::readImageData(imageData
, type
));
274 log_error(_("Can't read image file from %s"), url
);
278 Renderer
* renderer
= r
.renderer();
279 ret
= new BitmapMovieDefinition(im
, renderer
, url
);
283 catch (const ParserException
& e
) {
284 log_error(_("Parsing error: %s"), e
.what());
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();
305 in
= streamProvider
.getStream(url
, *postdata
, rcfile
.saveLoadedMedia());
307 else in
= streamProvider
.getStream(url
, rcfile
.saveLoadedMedia());
310 log_error(_("failed to open '%s'; can't create movie"), url
);
315 log_error(_("streamProvider opener can't open '%s'"), url
);
319 const std::string
& movie_url
= reset_url
? reset_url
: url
.str();
320 ret
= MovieFactory::makeMovie(in
, movie_url
, runResources
,
327 } // unnamed namespace
333 // indent-tabs-mode: t