1 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2 /* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is [Open Source Virtual Machine.].
18 * The Initial Developer of the Original Code is
19 * Adobe System Incorporated.
20 * Portions created by the Initial Developer are Copyright (C) 2009
21 * the Initial Developer. All Rights Reserved.
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
45 // it's silly to write this again, but i'm being lazy.
52 SwfParser(ScriptBuffer swf
)
68 // skip frame rate and frame count
76 return readU8() | readU8()<<8;
79 return readU8() | readU8()<<8 | readU8()<<16 | readU8()<<24;
87 int readUBits(int n
) {
95 for (shift
= bitsLeft
- bitPos
; shift
> 0; shift
= bitsLeft
- bitPos
) {
96 result
|= bitBuf
<< shift
;
100 // consume part of buffer
101 result
|= bitBuf
>> -shift
;
103 bitBuf
&= 0xff >> (8 - bitPos
); // mask consumed bits
107 int readSBits(int n
) {
109 int num
= readUBits(n
);
111 return (num
<< shift
) >> shift
; // sign extend
115 while (readU8() != 0)
121 * isSwf() - return true if the swf magic # is present, ignoring version.
123 bool isSwf(ScriptBuffer swf
) {
124 if (swf
.getSize() < 4)
126 uint32_t magic
= swf
[0] | swf
[1]<<8 | swf
[2]<<16;
127 const uint32_t SWF
= 'S'<<16 | 'W'<<8 | 'F';
128 const uint32_t SWC
= 'S'<<16 | 'W'<<8 | 'C';
129 return magic
== SWF
|| magic
== SWC
;
132 static const int stagDoABC
= 72;
133 static const int stagDoABC2
= 82;
135 static void handleDoABC(int type
, SwfParser
&parser
, int taglen
,
136 Toplevel
* toplevel
, CodeContext
* codeContext
,
137 GCList
<PoolObject
>& deferred
)
139 AvmCore
*core
= toplevel
->core();
140 int tagstart
= parser
.pos
;
141 const int kDoAbcLazyInitializeFlag
= 1;
144 if (type
== stagDoABC2
)
146 // Flags (UI32) A 32-bit flags value, which may
147 // contain the following bits set: kDoAbcLazyInitializeFlag = 1: Indicates that
148 // the ABC block should not be executed immediately, but only parsed. A later
149 // finddef may cause its scripts to execute.
150 flags
= parser
.readU32();
156 // parse and execute the abc.
158 // allocate a new buffer and copy abc into it; the abc buffer will be referenced
159 // by PoolObject and can outlive the swf it came from. Using a ReadOnlyScriptBuffer
160 // avoids copying, but interior pointers to the swf data do not pin the swf in memory.
161 int abclen
= taglen
- (parser
.pos
- tagstart
);
162 ScriptBuffer
code(core
->newScriptBuffer(abclen
));
163 VMPI_memcpy(&code
[0], &parser
.swf
[parser
.pos
], abclen
);
165 // FIXME get api from the SWF
166 ApiVersion apiVersion
= core
->getApiVersionFromCallStack();
167 if (flags
& kDoAbcLazyInitializeFlag
) {
168 PoolObject
* pool
= core
->parseActionBlock(code
, 0, toplevel
, codeContext
->domainEnv()->domain(), NULL
, apiVersion
);
170 // defer: handleActionPool(pool/* result of parse */, domainEnv, toplevel, codeContext);
172 core
->handleActionBlock(code
, 0, toplevel
, NULL
, codeContext
, apiVersion
);
174 parser
.pos
+= abclen
;
178 * Execute a swf as follows:
180 * for each DoABC2 tag
181 * if lazy, parse it but don't run it: parseActionBlock()
183 * run it via handleActionBlock() just as if it were on the commandline
185 bool handleSwf(const char *filename
, ScriptBuffer swf
,
186 Toplevel
* toplevel
, CodeContext
* codeContext
,
189 bool has_abc
= false;
190 SwfParser
parser(swf
);
191 parser
.pos
= 4; // skip magic #
192 uint32_t swflen
= parser
.readU32();
193 AvmCore
*core
= toplevel
->core();
194 GCList
<PoolObject
> deferred(core
->gc
, kListInitialCapacity
);
196 // decompress the swf
198 ScriptBuffer
newswf(core
->newScriptBuffer(swflen
));
199 uLongf dlen
= swflen
;
200 int e
= uncompress((Bytef
*)&newswf
[0], &dlen
, (Bytef
*)&swf
[8], (uLongf
)swf
.getSize()-8);
203 core
->console
<< filename
<< ": error decompressing body: " << e
<< "\n";
207 parser
= SwfParser(newswf
);
210 if (swflen
!= swf
.getSize()) {
212 core
->console
<< filename
<<
213 ": incorrect size: " << (uint32_t)swf
.getSize() <<
214 " should be " << swflen
<< "\n";
218 uint32_t oldpos
= parser
.pos
;
219 while (parser
.pos
< swflen
) {
220 int tag
= parser
.readU16();
222 uint32_t taglen
= (tag
& 63);
224 taglen
= parser
.readU32();
225 if (type
== stagDoABC
|| type
== stagDoABC2
) {
228 handleDoABC(type
, parser
, taglen
, toplevel
, codeContext
, deferred
);
231 parser
.pos
+= taglen
;
232 if (parser
.pos
<= oldpos
) {
233 has_abc
= false; // broken file or broken parser, but either way we can't process it
239 for (int i
= 0, n
= deferred
.length(); i
< n
; i
++) {
240 core
->handleActionPool(deferred
[i
], toplevel
, codeContext
);