Friday, 13 July 2012

Getting Data From Flash Files with Transform SWF (Part 1)

The mission that I chose to accept was to get the above statistics from a .swf file. The coloured blocks represent percentage of the total i.e. the blue block in shots is 33% of max length because that team had 1/3 of all shots. As the title gives away, I will be using Transform SWF from Flagstone Software - this seemed like the best option from what I found by searching Google/Stack Overflow.

Transform SWF provides a small cookbook of examples using the software. The most relevant of these seemed to be find the number of frames in a movie. The example calls a movie's getObjects() method and checks for instances of Showframe. I modified this to call getClass() on each object and place the Class in a Set. Then I printed this out so that I could see which classes I needed to learn about.

private static void printDifferentTypesOfClasses(final List<movietag> objects) {

  Set<Class> classes = new HashSet<>();
  for(MovieTag movieTag : objects){
  for (Class c: classes){

This provides the following output:

class com.flagstone.transform.DoABC
class com.flagstone.transform.MovieAttributes
class com.flagstone.transform.text.TextSettings
class com.flagstone.transform.MovieMetaData
class com.flagstone.transform.shape.DefineShape
class com.flagstone.transform.shape.DefineShape4
class com.flagstone.transform.Background
class com.flagstone.transform.text.DefineTextField
class com.flagstone.transform.font.FontAlignment
class com.flagstone.transform.MovieHeader
class com.flagstone.transform.SymbolClass
class com.flagstone.transform.ScenesAndLabels
class com.flagstone.transform.button.DefineButton2
class com.flagstone.transform.font.FontName
class com.flagstone.transform.ShowFrame
class com.flagstone.transform.font.DefineFont3
class com.flagstone.transform.movieclip.DefineMovieClip
class com.flagstone.transform.Place2
class com.flagstone.transform.shape.DefineMorphShape

The one that grabs my attention is DefineTextField, the eight-one down. Using Shift+F2 to open the Javadoc, the most obvious method to check is getInitialText(). The returned String contains HTML so we will need to clean that up and every time we come across a word we want to go to a new line.

private static void printDefineTextFields(final List<MovieTag> objects) {
 for(MovieTag object : objects){
  if (object instanceof DefineTextField) {
                DefineTextField d = (DefineTextField) object;
                String initialText = removeHtmlTags(d.getInitialText());
                if (Character.isDigit(initialText.charAt(0))){
                      System.out.print(initialText + " ");
                } else {
                      System.out.print("\n" + initialText + " "); 

And this provides us with the following output (with non-interesting data removed).
0 0
Shots (SH) 1 1 1 1 1 1 2 1 2 0 0
Shots (on target) 1 1 0 0
Shots (off target) 1 0 0
Shots (woodwork) 1 1 1 1 1 0 0
Shots (blocked) 1 0 1 0 0 0
Attacks (AT) 1 1 1 1 2 2 2 2 2 2 3 2 3 2 3 3 3 2 4 2 4 0 0
Dangerous Attacks 0 0 1 1 1 1 1 1 1 1 1 1

The first thing to notice is the pair of goose eggs at the end of each line except the last. This is probably the starting value for each statistic. The second thing is that Shots (SH), Attacks (AT), and Dangerous Attacks all have the correct values at the end of it's adjusted line i.e. any pair of zeros at the end of a line is moved to the following line. The other four values all involve a zero statistic. Solving the values for these statistics will be the next challenge.

Part 2 can be found here.

Arrow Key Nav