2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 // Free Software Foundation, Inc
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 "IOChannel.h"
32 #include "SWFMovieDefinition.h"
33 #include "BitmapMovieDefinition.h"
34 #include "RunResources.h"
36 #include "StreamProvider.h"
37 #include "MovieLibrary.h"
43 /// Get type of file looking at first bytes
44 FileType
getFileType(IOChannel
& in
);
46 boost::intrusive_ptr
<SWFMovieDefinition
> createSWFMovie(
47 std::unique_ptr
<IOChannel
> in
, const std::string
& url
,
48 const RunResources
& runResources
, bool startLoaderThread
);
50 boost::intrusive_ptr
<BitmapMovieDefinition
> createBitmapMovie(
51 std::unique_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::unique_ptr
<IOChannel
> in
, const std::string
& url
,
64 const RunResources
& runResources
, bool startLoaderThread
)
66 boost::intrusive_ptr
<movie_definition
> ret
;
70 // see if it's a jpeg or an swf
71 FileType type
= getFileType(*in
);
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(std::move(in
), url
, runResources
, type
);
89 case GNASH_FILETYPE_SWF
:
90 ret
= createSWFMovie(std::move(in
), url
, runResources
, startLoaderThread
);
93 case GNASH_FILETYPE_FLV
:
94 log_unimpl(_("FLV can't be loaded directly as a movie"));
98 log_error(_("Unknown file type"));
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!)
120 if (movieLibrary
.get(cache_label
, &mov
)) {
121 log_debug("Movie %s already in library", cache_label
);
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
);
133 log_error(_("Couldn't load library movie '%s'"), url
.str());
137 // Movie is good, add to the library, but not if we used POST
139 movieLibrary
.add(cache_label
, mov
.get());
140 log_debug("Movie %s (SWF%d) added to library",
141 cache_label
, mov
->get_version());
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();
157 MovieFactory::clear()
159 movieLibrary
.clear();
164 /// Get type of file looking at first bytes
166 getFileType(IOChannel
& in
)
172 if (in
.read(buf
, 3) < 3) {
173 log_error(_("Can't read file header"));
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")) {
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")) {
188 return GNASH_FILETYPE_PNG
;
191 // This is the magic number for any GIF format file
192 if (std::equal(buf
, buf
+ 3, "GIF")) {
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")) {
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"));
214 return GNASH_FILETYPE_UNKNOWN
;
217 while ((buf
[0]!='F' && buf
[0]!='C') || buf
[1]!='W' || buf
[2]!='S') {
220 buf
[2] = in
.read_byte();
222 log_error(_("Could not find SWF inside an .exe file"));
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::unique_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(std::move(in
), absURL
)) return nullptr;
247 if (startLoaderThread
&& !m
->completeLoad()) return nullptr;
252 // Create a movie_definition from an image format stream
253 // NOTE: this method assumes this *is* the format described in the
255 // TODO: The pp won't display PNGs for SWF7 or below.
256 boost::intrusive_ptr
<BitmapMovieDefinition
>
257 createBitmapMovie(std::unique_ptr
<IOChannel
> in
, const std::string
& url
,
258 const RunResources
& r
, FileType type
)
262 boost::intrusive_ptr
<BitmapMovieDefinition
> ret
;
264 // readImageData takes a shared pointer because JPEG streams sometimes need
265 // to transfer ownership.
266 std::unique_ptr
<IOChannel
> imageData(in
.release());
269 std::unique_ptr
<image::GnashImage
> im(
270 std::move(image::Input::readImageData(std::move(imageData
), type
)));
273 log_error(_("Can't read image file from %s"), url
);
277 Renderer
* renderer
= r
.renderer();
278 ret
= new BitmapMovieDefinition(std::move(im
), renderer
, url
);
282 catch (const ParserException
& e
) {
283 log_error(_("Parsing error: %s"), e
.what());
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::unique_ptr
<IOChannel
> in
;
299 const StreamProvider
& streamProvider
= runResources
.streamProvider();
301 const RcInitFile
& rcfile
= RcInitFile::getDefaultInstance();
304 in
= streamProvider
.getStream(url
, *postdata
, rcfile
.saveLoadedMedia());
306 else in
= streamProvider
.getStream(url
, rcfile
.saveLoadedMedia());
309 log_error(_("failed to open '%s'; can't create movie"), url
);
314 log_error(_("streamProvider opener can't open '%s'"), url
);
318 const std::string
& movie_url
= reset_url
? reset_url
: url
.str();
319 ret
= MovieFactory::makeMovie(std::move(in
), movie_url
, runResources
,
326 } // unnamed namespace
332 // indent-tabs-mode: t