Hacking SWF – PlaceObject and the Ratio Field

According to the SWF10 specification, PlaceObject2

.. can both add a character to the display list, and modify the attributes of a character that is already on the display list.

The placed character is usually defined earlier in the SWF, and can be anything supported by SWF, e.g., Shape, MorphShape, Sprite, Text, EditText etc. It stays on the display list until it is explicitly removed by the RemoveObject tag. PlaceObject2 might also tell the Flash Player that the placed object is to be treated as a mask (and what depth range will be masked), and might give the character an instance name (if it is a Sprite).

Additionally, PlaceObject2 might carry an optional ratio parameter. According to the SWF10 specification, it

.. specifies a morph ratio for the character being added or modified. This field applies only to characters defined with DefineMorphShape, and controls how far the morph has progressed. A ratio of zero displays the character at the start of the morph. A ratio of 65535 displays the character at the end of the morph. For values between zero and 65535 Flash Player interpolates between the start and end shapes, and displays an in- between shape.

For Flash users, this is better known as a “Shape Tween”.

However, the statement that  “this field applies only to characters defined with DefineMorphShape” is incorrect. It also applies to Sprite characters (“MovieClips”).

The Flash Player uses the value of the Ratio field to determine whether or not to reset the playhead in the placed Sprite to frame 1, when jumping to arbitrary frames in the parent timeline.

To illustrate that, let’s create a simple Flash movie using the Flash IDE. We create a one-frame MovieClip (called “square”) containing a simple shape. We create another MovieClip (called “animatedSquare”), which contains “square”, animated by a motion tween over 20 frames. We place “animatedSquare” on the main timeline (one frame only). When the Flash Player executes the resulting SWF, we see “animatedSquare” looping over all its 20 frames, as we would expect.

Here are the guts of the resulting SWF (simplified). Nothing surprising in there:

Now, let’s make the main timeline 10 frames long (each frame containing “animatedSquare”). The behavior doesn’t change, “animatedSquare” still loops over all of its 20 frames as expected. Also, the SWF tags still don’t reveal anything surprising, 9 more ShowFrame tags were added:

Finally, let’s remove “animatedSquare” from frame 5, leaving it only on frames 1-4 and 6-10:

This is where things get interesting. The character at depth 1 (our “animatedSquare” Sprite) is removed after frame 4, frame 5 is displayed without any content, and then “animatedSquare” is placed back on depth 1. Only now, the PlaceObject2 tag carries a value (5) in the Ratio field. Now why is that?

If we let Flash Player execute this SWF, you will notice the following behavior:

  1. In frames 1-4, the first 4 frames of “animatedSquare” are displayed
  2. In frame 5, a blank frame is displayed
  3. In frames 6-10, the first 5 frames of “animatedSquare” are displayed
  4. The main timeline then loops and jumps back to frame 1, displaying the first frame of “animatedSquare” again. Back to 1. Etc.

If we would put a gotoAndPlay(6) action on frame 10 of the main timeline, “animatedSquare” would reset to frame 1 once, and then loop over all 20 frames infinitely.

So what happens here is that once the Flash Player encounters a PlaceObject tag that attempts to place a Sprite on a depth that was previously occupied by the same Sprite, it looks at the ratio fields of the current and previous PlaceObject tags. If both carry the same value, the child Sprite keeps on playing normally. If not, the child Sprite’s playhead is reset to frame 1.

There is a little more to it yet, so if you are interested in digging deeper you should take a look at the Gnash Wiki, which lists many cases.

Adobe iPhone Packager 2.0

The whole Flash community has been jumping for joy ever since Apple revised their controversial App Store License Agreement in early September this year. Apps created with Adobe’s “iPhone Packager” are not longer banned from the App Store, and Adobe started working on the product again.

Section 3.3.1 now merely forbids the use of private APIs.. tooling and language restrictions have been lifted, especially the part that prohibits “linking to documented APIs through an intermediary translation or compatibility layer or tool” – the iPhone Packager uses LLVM to cross-compile ActionScript to iPhone-native byte code, which is now allowed.

I didn’t hear many people commenting on Section 3.3.2 though, which i find weird. I think the real good news is this very section. Code interpreters are now explicitly allowed, given that “all scripts, code and interpreters are packaged in the Application and not downloaded”.

This means that Adobe could potentially shelve the existing, LLVM based iPhone Packager, and instead deploy a regular AIR runtime with a separate SWF. This would certainly make the publishing process a lot faster, as there is no cross-compilation step anymore – a standard SWF is published, which is then just packaged together with an iOS AIR runtime. I am uncertain which approach would perform better though: interpreted and JIT compiled via virtual machine, or LLVM translated native code.

Also feasible: a Flash Player engine that developers can plug in to their Cocoa apps, to mix UIKit and SWF. Best of both worlds.

Where do you think the iPhone Packager is heading?

Flash IDE Inspired Flex 4 Timeline Component

Here’s a little demo of a Flex 4 component i wrote that displays a Flash IDE-like timeline for any SWF you load into it. The timeline data is reconstructed by as3swf (i discuss how that works in a previous blog post, SWF Timeline Reconstruction with as3swf). The timeline is not interactive in this demo, and only the root timeline is shown.

Continue reading

My Silly Gist Collection

I’ve been quite busy lately on both client and personal projects (can’t talk about the former, other than it being a big ass Flex 4 enterprise application i’ve been working on for the fine folks at Powerflasher; and it’s too early to talk about the latter.. stay tuned).

In the last few weeks i silently released random little experiments on Gist – mostly fallout from personal projects of mine. Nothing super impressive, all pretty rough, but i thought some of you might be interested.

Continue reading

SWF Timeline Reconstruction with as3swf

In case you havent heard of it yet, as3swf is an ActionScript 3 library to parse and publish SWF files. It does that rather well by now, providing full roundtrip publishing, plus some neat extra features like shape export to AS3 Drawing API, AS3 GraphicsObjects, FXG, and Objective-C.

Whenever i find some free time i’m working on adding new, useful features. One feature of as3swf, that i haven’t talked about much yet but is implemented for quite a while already, is the reconstruction of timelines as you know them from Adobe’s Flash IDEs.

In the first place, timelines in as3swf help you to export and render layered animations. Having a long list of parsed SWF tags won’t help much if you want to export or render frame X, as the Flash Player would display it.

Continue reading

The Grand SWF Archive

What if somebody would write a spider (which respects common conventions like robots.txt etc) that searches for and archives publicly available SWF files, and a service that makes graphical assets found in those SWFs (vector shapes, bitmap images, videos, fonts, etc) available for public browsing, similar to what the Internet Archive’s Wayback Machine does?

As SWF, at least according to Adobe, is an open format, this would be both technically and legally feasible, wouldn’t it? From a legal perspective, what line would need to be drawn where, and why exactly?

Posted in SWF

SWFtrospection

Open Flash CS4, create new AS3 FLA, add as3swf.swc and paste this on frame 1:

import com.codeazur.as3swf.SWF;
var swf:SWF = new SWF(root.loaderInfo.bytes);
trace(swf);

Trace output:

[SWF]
  Header:
    Version: 10
    FileLength: 149405
    FileLengthCompressed: 149405
    FrameSize: (550,400)
    FrameRate: 24
    FrameCount: 1
  Tags:
    [69:FileAttributes] AS3: true, HasMetadata: false, 
      UseDirectBlit: false, UseGPU: false, UseNetwork: false
    [09:SetBackgroundColor] Color: #FFFFFF
    [86:DefineSceneAndFrameLabelData] 
      Scenes:
        [0] Frame: 0, Name: Scene 1
    [82:DoABC] Lazy: true, Length: 149219
    [76:SymbolClass] 
      Symbols:
        [0] TagID: 0, Name: Untitled_fla.MainTimeline
    [01:ShowFrame] 
    [00:End]

Excercise: Draw something on stage, and run the code again.

Want more? Drop by my session Hacking SWF at FITC Amsterdam (Feb 22th, 16:00).

[Edit] Jim Cheng deserves credits. He was the one who whispered “root.loaderInfo.bytes” into my virtual ear on IM.

Undocumented SWF Tags written by MXMLC

While testing my AS3 SWF library as3swf yesterday, i found that MXMLC (the compiler that comes with the Flex SDKs)  writes undocumented SWF tags to the SWFs it produces.

I was able to identify two so far:

ProductInfo (Tag ID 41)

The ProductInfo tag contains infos about the tool used to generate the SWF, as well as the date and time the SWF was compiled. It also contains info about the “Edition” of the software used (see below), and although this seems to be always set to “None” in Flex Builder 3 and Flash Builder 4, it potentially could become a privacy issue, especially being an undocumented feature (you better know about this tag just in case you accidentally publish commercial work with your non commercial Flash Builder license).

  • ProductID (UI32)
    0: Unknown
    1: Macromedia Flex for J2EE
    2: Macromedia Flex for .NET
    3: Adobe Flex
  • Edition (UI32)
    0: Developer Edition
    1: Full Commercial Edition
    2: Non Commercial Edition
    3: Educational Edition
    4: Not For Resale (NFR) Edition
    5: Trial Edition
    6: None
  • MajorVersion (UI8)
  • MinorVersion (UI8)
  • BuildLow (UI32)
  • BuildHigh (UI32)
  • CompilationDate (UI64)
    Milliseconds since 1.1.1970

Examples:

Flex 4.0 – [41:ProductInfo] ProductID: 3, Edition: 6, Version: 4.0.0.7791, CompileDate: Fri Aug 21 05:18:21 GMT-0300 2009

Flex 3.2 – [41:ProductInfo] ProductID: 3, Edition: 6, Version: 3.2.0.3958, CompileDate: Fri Aug 21 05:23:22 GMT-0300 2009

DebugID (Tag ID 63)

This tag is written to SWFs that are enabled for debugging. It contains a 16 byte UUID.

  • UUID (UI8[16])

Example:

[63:DebugID] UUID: b8f36d6a-c735-a340-daa7-44730af92505

Reference

Flex SDK:

Community: