#include <stdlib.h>
#include <stdio.h>
//
#include "proto.h"
#include "flash.h"
#include "bucket.h"

static int flash_read_rect(RECT *rect);
static int flash_read_matrix(MATRIX *matrix);
static int flash_read_gradient(GRADIENT *gradient, int format);
static int flash_read_rgba(U8 *r, U8 *g, U8 *b, U8 *a);
static int flash_read_shaperecord(U32 nfillbits, U32 nlinebits, int format, int *theend);
static int flash_read_linestylearray(int format);
static int flash_read_fillstylearray(int format);
static int flash_read_cxform(CXFORM *cxform);

static int read_actions(void);
static int read_shape(int format, int endptr);
static int read_place_object1(int endptr);
static int read_place_object2(int endptr);
static int read_remove_object(int format);
static int read_font_def1(int endptr);
static int read_text(int usealpha);
static int read_define_sound(void);
static int read_start_sound(void);
static int read_buttonsound(void);
static int read_button(int endptr);
static int read_define_jpeg(int format);

static int currentframe = 0;
static int endofdata;
static int infoflags;


int flash_read_header() {

  U8 id0, id1, id2, version;
  U16 framerate, framecount;
  RECT framesize;
  U32 filesize;

  if (read_ubyte(&id0))  return 1;
  if (read_ubyte(&id1))  return 1;
  if (read_ubyte(&id2))  return 1;
  if ((id0 != 'F') || (id1 != 'W') || (id2 != 'S')) {
    fprintf(stderr, "Not a flash-file - illegal signature ('%c%c%c') in header\n", id0, id1, id2);
    return 1;
  }

  if (read_ubyte(&version))  return 1;
  printf("FileVersion %d\n", version);

  if (read_uint(&filesize))  return 1;

  printf("FrameArea\n");
  if (flash_read_rect(&framesize))  return 1;
  printf("  {\n");
  printf("    width %d height %d\n", framesize.maxx, framesize.maxy);
  printf("  }\n");

  if (read_ushort(&framerate))  return 1;
  printf("FrameRate %d.%d // frames per second\n", framerate>>8, framerate &255);

  if (read_ushort(&framecount))  return 1;

  return 0;
}


int flash_read_object(int info) {

  U32 tag, length;
  U16 combined;
  U8 dummy;

  infoflags = info;

  if (read_ushort(&combined))    return 1;
  tag = combined >>6;
  length = combined & 0x3f;
  if (length == 0x3f)
    if (read_uint(&length))      return 1;

  endofdata = read_position() + length;

  printf("// offset %d (0x%x), length %d\n", read_position(), read_position(), length);
  switch (tag) {
  case stagEnd:
    printf("End { }\n");
    break;
  case stagShowFrame:
    printf("ShowFrame { } // frame #%d\n", currentframe++);
    break;
  case stagSetBackgroundColor:
    {
      U8 r, g, b;
      if (flash_read_rgba(&r, &g, &b, NULL))  return 1;
      printf("BackgroundColour %02x%02x%02x // RGB\n", b, g, r);
    }
    break;
  case stagDoAction:
    printf("DoAction {\n");
    if (infoflags & TAG_BODY)
      if (read_actions())  return 1;
    printf("}\n");
    break;
  case stagProtect:
    printf("Protect { }\n");
    break;
  case stagFrameLabel:
    printf("FrameLabel {\n  ");
    if (infoflags & TAG_BODY) {
      char chr;
      do {
        if (read_ubyte((U8 *)&chr))     return 1;
        if (chr)  printf("%c", chr);
      } while (chr);
    }
    printf("\n}\n");
    break;

  case stagPlaceObject:
    printf("PlaceObject {\n");
    if (infoflags & TAG_BODY)
      if (read_place_object1(endofdata))  return 1;
    printf("}\n");
    break;
  case stagPlaceObject2:
    printf("PlaceObject {\n");
    if (infoflags & TAG_BODY)
      if (read_place_object2(endofdata))  return 1;
    printf("}\n");
    break;
  case stagRemoveObject:
    printf("RemoveObject {\n");
    if (infoflags & TAG_BODY)
      if (read_remove_object(1))          return 1;
    printf("}\n");
    break;
  case stagRemoveObject2:
    printf("RemoveObject {\n");
    if (infoflags &TAG_BODY)
      if (read_remove_object(2))          return 1;
    printf("}\n");
    break;

  case stagDefineShape:
  case stagDefineShape2:
  case stagDefineShape3:
    printf("DefineShape {\n");
    if (infoflags & TAG_BODY) {
      if (tag == stagDefineShape3) {
        if (read_shape(3, endofdata))      return 1;
      } else {
        if (read_shape(2, endofdata))      return 1;
      }
    }
    printf("}\n");
    break;

  case stagFreeCharacter:
    printf("FreeCharacter { }\n");
    break;
  case stagDefineButton:
    printf("DefineButton {\n");
    if (infoflags & TAG_BODY) {
      if (read_button(endofdata))         return 1;
    }
    printf("}\n");
    break;
  case stagDefineFont:
    printf("DefineFont {\n");
    if (infoflags & TAG_BODY)
      if (read_font_def1(endofdata))      return 1;
    printf("}\n");
    break;
  case stagDefineFont2:
    printf("DefineFont2 { }\n");
    break;
  case stagDefineText:
  case stagDefineText2:
    printf("DefineText {\n");
    if (infoflags & TAG_BODY) {
      if (tag == stagDefineText) {
        if (read_text(0))                   return 1;
      } else {
        if (read_text(1))                   return 1;
      }
    }
    printf("}\n");
    break;
  case stagDefineFontInfo:
    printf("DefineFontInfo { }\n");
    break;

  case stagDefineSound:
    printf("DefineSound {\n");
    if (infoflags & TAG_BODY)
      read_define_sound();
    printf("}\n");
    break;
  case stagStartSound:
    printf("StartSound {\n");
    if (infoflags & TAG_BODY)
      read_start_sound();
    printf("}\n");
    break;
  case stagDefineButtonSound:
    printf("ButtonSound {\n");
    if (infoflags & TAG_BODY)
      read_buttonsound();
    printf("}\n");
    break;
  case stagSoundStreamHead:
    printf("SoundStreamHead { }\n");
    break;
  case stagSoundStreamBlock:
    printf("SoundStreamBlock { }\n");
    break;
  case stagSoundStreamHead2:
    printf("SoundStreamHead2 { }\n");
    break;

  case stagDefineBitsLossless:
    printf("DefineBitsLossless { }\n");
    break;
  case stagDefineBitsJPEG2:
    printf("JPEG {\n");
    if (infoflags & TAG_BODY)
      read_define_jpeg(2);
    printf("           }\n");
    break;
  case stagDefineBitsJPEG3:
    printf("JPEG {\n");
    if (infoflags & TAG_BODY)
      read_define_jpeg(3);
    printf("           }\n");
    break;
  case stagDefineBitsLossless2:
    printf("DefineBitsLossless2 { }\n");
    break;
  case stagJPEGTables:
    printf("JPEGTables { }\n");
    break;
  case stagDefineBits:
    printf("DefineBits { }\n");
    break;
  case stagDefineButtonCxform:
    printf("DefineButtonCxform { }\n");
    break;
  case stagDefineButton2:
    printf("DefineButton2 { }\n");
    break;
  case stagDefineSprite:
    printf("DefineSprite { }\n");
    break;
  case stagNameCharacter:
    printf("NameCharacter { }\n");
    break;
  case stagDefineMorphShape:
    printf("DefineMorphShape { }\n");
    break;
  default:
    printf("Unknown tag : %d (%02x)\n", tag, tag);
    break;
  }

  while (read_position() < endofdata)
    if (read_ubyte(&dummy))      return 1;

  return 0;
}

// -------------------------------------------------------------------------

static int read_unknown_action(U8 action, U16 length, U16 *bytesread) {

  if (action & 0x80) {
    printf("  unknown 0x%02x ", action);
    while (*bytesread < length) {
      U8 arg;
      if (read_ubyte(&arg))           return 1;
      printf("%02x ", arg);
      *bytesread += 1;
    }
    printf("\n");
  } else
    printf("  unknown 0x%02x\n", action);

  return 0;
}

int read_actions() {

  U8 action;
  U16 length;

  printf("// Flash4 actions are marked with [Flash4]\n");
  printf("// the fileoffset of each action is displayed at the end of the line\n");
  do {
    U16 bytesread;
    S32 fileposition = read_position();
        printf("2");

    if (read_ubyte(&action))            return 1;

    if (action & 0x80) {
      if (read_ushort(&length))         return 1;
      bytesread = 0;
    } else {
      length = 1;
      bytesread = 1;
    }

    switch (action) {
    case 0x81:                // goto frame
      {
        U16 frame;
        if (read_ushort(&frame))        return 1;
        bytesread = 2;
        printf("  gotoframe %d // %d\n", frame, fileposition);
      }
      break;
    case 0x83:                // get URL
      {
        char url[2048], window[256];
        int i;
        U8 chr;

        i = 0;
        do {
          if (read_ubyte(&chr))  return 1;
          bytesread++;
          if (i < 2047)  url[i++] = chr;
        } while (chr);
        url[2047] = '\0';

        i = 0;
        do {
          if (read_ubyte(&chr))  return 1;
          bytesread++;
          if (i < 255)  window[i++] = chr;
        } while (chr);
        window[255] = '\0';

        printf("  geturl {      // %d\n", fileposition);
        printf("           url \"%s\"\n", (char *)url);
        printf("           target \"%s\"\n         } \n", (char *)window);
      }
      break;
    case 0x04:
      printf("  nextframe     // %d\n", fileposition);
      break;
    case 0x05:
      printf("  previousframe // %d\n", fileposition);
      break;
    case 0x06:
      printf("  startplaying  // %d\n", fileposition);
      break;
    case 0x07:
      printf("  stopplaying   // %d\n", fileposition);
      break;
    case 0x08:
      printf("  togglequality // %d\n", fileposition);
      break;
    case 0x09:
      printf("  stopsounds    // %d\n", fileposition);
      break;
    case 0x8a:                // wait for frame
      {
        U16 frame;
        U8 skip;
        if (read_ushort(&frame))        return 1;
        if (read_ubyte(&skip))          return 1;
        bytesread = 3;
        printf("  waitforframe { frame %d   skip %d } // %d\n", frame, skip, fileposition);
      }
      break;
    case 0x8b:                // set action target
      if (length < 256) {
        char target[256];
        while (bytesread < length) {
          if (read_ubyte((U8 *)target+bytesread))     return 1;
          if ((target[bytesread] < ' ') ||
              (target[bytesread] >= 127))   target[bytesread] = ' ';
          bytesread++;
        }
        target[bytesread] = '\0';
        printf("  setactiontarget %s", target);
      } else
        printf("  setactiontarget ??");
      printf(" // %d\n", fileposition);
      break;
    case 0x8c:
      printf("  gotolabel     // %d\n", fileposition);
      break;
    case 0x96:
      {
        U8 type;
        printf("  push ");
        if (read_ubyte(&type))          return 1;
        bytesread++;
        if (type == 0) {
          if (length-1 < 256) {
            char val[256];
            U32 i;
            for (i = 0; bytesread < length; i++) {
              if (read_ubyte((U8 *)val+i))  return 1;
              bytesread++;
              if ((val[i] < ' ') || (val[i] >= 127))   val[i] = ' ';
            }
            val[i-1] = '\0';
            printf("\"%s\"", val);
          } else
            printf("??");
        } else if (type == 1) {
          while (bytesread < length) {
            U8 val;
            if (read_ubyte(&val))  return 1;
            printf("%02x", val);
            bytesread++;
          }
        } else
          printf("<unknown type %d>", type);
        printf("        // %d %d [Flash4]\n", fileposition, length);
      }
      break;
    case 0x21:
      printf("  strcat        // %d [Flash4]\n", fileposition);
      break;
    case 0x29:
      printf("  strless       // %d [Flash4]\n", fileposition);
      break;
    case 0x32:
      printf("  ctoa          // %d [Flash4]\n", fileposition);
      break;
    case 0x33:
      printf("  atoc          // %d [Flash4]\n", fileposition);
      break;
    case 0x0a:
      printf("  add           // %d [Flash4]\n", fileposition);
      break;
    case 0x0b:
      printf("  sub           // %d [Flash4]\n", fileposition);
      break;
    case 0x0c:
      printf("  mul           // %d [Flash4]\n", fileposition);
      break;
    case 0x0d:
      printf("  div           // %d [Flash4]\n", fileposition);
      break;
    case 0x0e:
      printf("  eq            // %d [Flash4]\n", fileposition);
      break;
    case 0x0f:
      printf("  less          // %d [Flash4]\n", fileposition);
      break;
    case 0x10:
      printf("  and           // %d [Flash4]\n", fileposition);
      break;
    case 0x11:
      printf("  or            // %d [Flash4]\n", fileposition);
      break;
    case 0x12:
      printf("  not           // %d [Flash4]\n", fileposition);
      break;
    case 0x18:
      printf("  atoi          // %d [Flash4]\n", fileposition);
      break;
    case 0x30:
      printf("  rnd           // %d [Flash4]\n", fileposition);
      break;
    case 0x22:
      printf("  getprop       // %d [Flash4]\n", fileposition);
      break;
    case 0x23:
      printf("  setprop       // %d [Flash4]\n", fileposition);
      break;
    case 0x1c:
    case 0x9e:
    case 0x1d:
      printf("  ??            // %d [Flash5]\n", fileposition);
      break;
    case 0x99:
    case 0x9d:
      if (length != 2) {
        fprintf(stderr, "Bad length in action\n");
        return 1;
      } else {
        S16 offset;
        if (read_short(&offset))        return 1;
        bytesread += 2;
        if (action == 0x9d)
          printf("  jumptoif");
        else
          printf("  jumpto");
        printf(" %d        // %d [Flash4]\n", 3+length+offset+fileposition, fileposition);
      }
      break;
    case 0x00:
      // end of action list
      break;
    default:
      if (read_unknown_action(action, length, &bytesread))   return 1;
      break;
    }
    if (action) {
      while (bytesread < length) {
        printf("1");
        if (read_ubyte(&action))        return 1;
        bytesread++;
      }

      if (bytesread > length) {
        printf("// error when parsing actiontype %02x\n", action);
        return 1;
      }
    }
  } while (action);

  return 0;
}



int read_button(int endptr) {

  U16 id;
  U8 buttonflags;

  if (read_ushort(&id))                 return 1;
  printf("  id %d\n", id);

  do {
    MATRIX matrix;

    if (read_ubyte(&buttonflags))       return 1;
    if (buttonflags & 0x0f) {
       U16 id, depth;
       if (read_ushort(&id))            return 1;
       if (read_ushort(&depth))         return 1;
       printf("  ");
       if (buttonflags & 0x01) {
         printf("up");
         if (buttonflags & 0x0e)  printf(":");
       }
       if (buttonflags & 0x02) {
         printf("over");
         if (buttonflags & 0x0c)  printf(":");
       }
       if (buttonflags & 0x04) {
         printf("down");
         if (buttonflags & 0x08)  printf(":");
       }
       if (buttonflags & 0x08)  printf("activearea");
       printf(" { id %d  depth %d\n", id, depth);
       flash_read_matrix(&matrix);
//       if (read_position() < endptr)
//         if (flash_read_cxform(&cxform))  return 1;
       printf(" }\n");
    }
  } while (buttonflags);

  read_actions();

  return 0;
}


int read_shape(int format, int endptr) {

  RECT rect;
  U32 nfillbits, nlinebits;
  U16 id;
  int theend;

  if (read_ushort(&id))                 return 1;
  printf("  id %d\n", id);

  if (flash_read_rect(&rect))           return 1;
  printf("  bbox {\n");
  printf("    %d %d %d %d\n", rect.minx, rect.miny, rect.maxx, rect.maxy);
  printf("  }\n");

  if (flash_read_fillstylearray(format))    return 1;
  if (flash_read_linestylearray(format))    return 1;

  // read shape-records
  if (read_ubits(4, &nfillbits))        return 1;
  if (read_ubits(4, &nlinebits))        return 1;
  do {
    if (flash_read_shaperecord(nfillbits, nlinebits, format, &theend))  return 1;
  } while (!theend);

  return 0;
}



int read_place_object1(int endptr) {

  U16 id, depth;
  MATRIX matrix;
  CXFORM cxform;

  if (read_ushort(&id))                 return 1;
  if (read_ushort(&depth))              return 1;
  printf("  id %d\n", id);
  printf("  depth %d\n", depth);
  if (flash_read_matrix(&matrix))       return 1;
  if (read_position() < endptr)
    if (flash_read_cxform(&cxform))     return 1;

  return 0;
}



int read_place_object2(int endptr) {

  U8 flags;
  U16 depth;

  if (read_ubyte(&flags))               return 1;

  if (read_ushort(&depth))              return 1;
  printf("  depth %d\n", depth);

  if (flags & 0x01) {         // move
  }
  if (flags & 0x02) {         // has character
    U16 id;
    if (read_ushort(&id))               return 1;
    printf("  id %d\n", id);
  }

  if (flags & 0x04) {         // has matrix
    MATRIX matrix;
    if (flash_read_matrix(&matrix))     return 1;
  }

  if (flags & 0x08) {         // has cxform
    CXFORM cxform;
    if (flash_read_cxform(&cxform))     return 1;
  }

  if (flags & 0x10) {         // has ratio
    U16 ratio;
    if (read_ushort(&ratio))            return 1;
    printf("  ratio %d\n", ratio);
  }

  if (flags & 0x20) {         // has name
    char chr;

    printf("  name \"");
    do {
      if (read_ubyte((U8 *)&chr))       return 1;
      if (chr)
        printf("%c", chr);
    } while (chr);
    printf("\"\n");
  }

  if (flags & 0x40) {         //has clip
    U16 clip;
    if (read_ushort(&clip))             return 1;
    printf("  clip %d\n", clip);
  }

  return 0;
}


int read_remove_object(int format) {

  U16 id, depth;

  if (format == 1) {
    if (read_ushort(&id))               return 1;
    printf("    id %d\n", id);
  }
  if (read_ushort(&depth))              return 1;
  printf("    depth %d\n", depth);

  return 0;
}


int read_text(int usealpha) {

  U16 id;
  RECT rect;
  MATRIX matrix;
  U8 gbits, abits;
  int endofrecords;

  if (read_ushort(&id))                 return 1;
  printf("  id %d\n", id);

  if (flash_read_rect(&rect))           return 1;
  printf("  bbox {\n");
  printf("    %d %d %d %d\n", rect.minx, rect.miny, rect.maxx, rect.maxy);
  printf("  }\n");

  if (flash_read_matrix(&matrix))       return 1;

  if (read_ubyte(&gbits))               return 1;
  if (read_ubyte(&abits))               return 1;

  endofrecords = 0;
  do {
    U8 flags, glyphs;
    int i;

    if (read_ubyte(&flags))            return 1;
    if (flags == 0)
      endofrecords = 1, glyphs = 0;
    else if (flags & 128) {
      printf("  style {\n");
      if (flags &8) {
        U16 fontid;
        if (read_ushort(&fontid))       return 1;
        printf("    font %d\n", fontid);
      }
      if (flags &4) {
        U8 r, g, b, a;
        if (read_ubyte(&r))             return 1;
        if (read_ubyte(&g))             return 1;
        if (read_ubyte(&b))             return 1;
        if (usealpha) {
          if (read_ubyte(&a))           return 1;
          printf("    colour %02x%02x%02x%02x\n", a, b, g, r);
        } else
          printf("    colour %02x%02x%02x\n", b, g, r);
      }
      if (flags &3) {
        S16 x, y;
        x = y = 0;
        if (flags &1)
          if (read_short(&x))           return 1;
        if (flags &2)
          if (read_short(&y))           return 1;
        printf("    move { %d %d }\n", x, y);
      }
      if (flags &8) {
        U16 size;
        if (read_ushort(&size))        return 1;
        printf("    size %d\n", size);
      }
      printf("  }\n");
      if (read_ubyte(&glyphs))          return 1;

    } else
      glyphs = flags;

    if (glyphs) {
      printf("  text {\n");
      for (i = 0; i < glyphs; i++) {
        U32 glyph;
        S32 advance;
        if (read_ubits(gbits, &glyph))  return 1;
        if (read_bits(abits, &advance)) return 1;
        printf("    %d %d\n", glyph, advance);
      }
      printf("  }\n");
    }
  } while (!endofrecords);

  return 0;
}


int read_font_def1(int endptr) {

  U16 id, *offsets, glyphs;
  int i, theend;

  if (read_ushort(&id))                 return 1;
  printf("  id %d\n", id);

  if (read_ushort(&glyphs))             return 1;
  glyphs /= 2;

  printf("// %d glyphs\n", glyphs);

  offsets = malloc(2*glyphs+2);
  if (!offsets)                         return 1;
  offsets[0] = 0;
  for (i = 1; i < glyphs; i++) {
    if (read_ushort(offsets+i))         return 1;
    offsets[i] -= 2*glyphs;
  }

  offsets[glyphs] = endptr - (read_position() -2*glyphs);

  for (i = 0; i < glyphs; i++) {
    int endofglyphs, nfillbits, nlinebits;

    printf("  glyph { index %d\n", i);

    endofglyphs = read_position() + offsets[i+1];
    // read shape-records
    if (read_ubits(4, (U32 *)&nfillbits))  return 1;
    if (read_ubits(4, (U32 *)&nlinebits))  return 1;
    do {
      if (flash_read_shaperecord(nfillbits, nlinebits, 1, &theend))  return 1;
    } while (!theend);
    align_bucket();
    printf("  }\n");
  }

  return 0;
}


int read_define_jpeg(int format) {

  U16 id;

  if (read_ushort(&id))                 return 1;
  printf("  id %d\n", id);

  return 0;
}


int read_buttonsound() {

  U16 id;
  U8 tr;

  if (read_ushort(&id))                 return 1;
  printf("  buttonid %d\n", id);
  for (tr = 0; tr < 4; tr++) {
    U16 sndid;

    if (read_ushort(&sndid))            return 1;
    if (sndid) {
      U16 loops;
      U32 inp, outp;
      U8 flags;

      loops = 1;
      inp = outp = -1;

      if (read_ubyte(&flags))           return 1;
      if (flags &1)           // has in-point
        if (read_uint(&inp))            return 1;
      if (flags &2)           // has out-point
        if (read_uint(&outp))           return 1;
      if (flags &4)           // has loops
        if (read_ushort(&loops))        return 1;
      if (flags &8) {         // has envelope
        U8 n;
        if (read_ubyte(&n))             return 1;
        while (n) {
          U32 t0;
          U16 t1;
          if (read_uint(&t0))           return 1;
          if (read_ushort(&t1))         return 1;
          if (read_ushort(&t1))         return 1;
          n--;
        }
      }
      switch (tr) {
      case 0:
        printf("  leave");
        break;
      case 1:
        printf("  enter");
        break;
      case 2:
        printf("  down");
        break;
      case 3:
        printf("  up");
        break;
      }
      if ((flags>>4) == 0x2)   loops = 0;
      printf(" { %d %d }\n", sndid, loops);
    }
  }

  return 0;
}


int read_start_sound() {

  U16 id;
  U8 flags;

  if (read_ushort(&id))                 return 1;
  printf("  id %d\n", id);

  if (read_ubyte(&flags))               return 1;
  if (flags &1) {
    U32 ip;
    if (read_uint(&ip))                 return 1;
    printf("  // inpoint %d\n", ip);
  }
  if (flags &2) {
    U32 op;
    if (read_uint(&op))                 return 1;
    printf("  // inpoint %d\n", op);
  }
  if ((flags>>4) == 0x02) {
    printf("  loops 0\n");

  } else if (flags &4) {
    U16 loops;
    if (read_ushort(&loops))                 return 1;
    printf("  loops %d\n", loops);
  }

  return 0;
}


int read_define_sound() {

  U8 flags;
  U16 id;
  U32 samples;

  if (read_ushort(&id))                 return 1;
  printf("  id %d\n", id);

  if (read_ubyte(&flags))               return 1;
  if (read_uint(&samples))              return 1;

  printf("  samples %d\n", samples);
  printf("  channels %d\n", (flags &1)+1);
  switch ((flags>>2) &3) {
  case 0:  printf("  freq 5\n");  break;
  case 1:  printf("  freq 11\n");  break;
  case 2:  printf("  freq 22\n");  break;
  case 3:  printf("  freq 44\n");  break;
  }
  switch ((flags>>4) &15) {
  case 0:
    if (flags &2)
      printf("  format \"LIN16\"\n");
    else
      printf("  format \"LIN8\"\n");
    break;
  case 1:
    {
      U32 adpcmbits;
      if (read_ubits(2, &adpcmbits))     return 1;
      printf("  format \"ADPCM%d\"\n", adpcmbits+2);
    }
    break;
  case 2:
    printf("  format \"MP3\"\n");
    break;
  default:
    fprintf(stderr, "Undefined audio-format\n");
    return 1;
    break;
  }

  return 0;
}

// -------------------------------------------------------------------------

int flash_read_cxform(CXFORM *cxform) {

  U32 mul, add, bits;

  cxform->rmul = cxform->gmul = cxform->bmul = cxform->amul = 255;
  cxform->radd = cxform->gadd = cxform->badd = cxform->aadd = 0;

  align_bucket();

  if (read_ubits(1, &add))                        return 1;
  if (read_ubits(1, &mul))                        return 1;
  if (read_ubits(4, &bits))                       return 1;
  if (mul) {
    if (read_ubits(bits, (U32 *)&cxform->rmul))   return 1;
    if (read_ubits(bits, (U32 *)&cxform->gmul))   return 1;
    if (read_ubits(bits, (U32 *)&cxform->bmul))   return 1;
    if (read_ubits(bits, (U32 *)&cxform->amul))   return 1;
  }
  if (add) {
    if (read_bits(bits, (S32 *)&cxform->radd))    return 1;
    if (read_bits(bits, (S32 *)&cxform->gadd))    return 1;
    if (read_bits(bits, (S32 *)&cxform->badd))    return 1;
    if (read_bits(bits, (S32 *)&cxform->aadd))    return 1;
  }

  printf("    cxform {\n");
  printf("      %d %d %d %d // rgba multiply\n",
             cxform->rmul, cxform->gmul, cxform->bmul, cxform->amul);
  printf("      %d %d %d %d // rgba add\n",
             cxform->radd, cxform->gadd, cxform->badd, cxform->aadd);
  printf("    }\n");

  return 0;
}


int flash_read_linestylearray(int format) {

  int num, i;

  // read line styles
  num = 0;
  if (read_ubyte((U8 *)&num))           return 1;
  if ( ((format == 2) || (format == 3)) && (num == 255))
    if (read_ushort((U16 *)&num))       return 1;

  printf("  // %d linestyles\n", num);
  for (i = 0; i < num; i++) {
    U16 width;
    U8 r, g, b, a;
    printf("  linestyle {     // linestyle #%d\n", i+1);
    if (read_ushort(&width))            return 1;
    if (format == 3) {
      if (flash_read_rgba(&r, &g, &b, &a))   return 1;
      printf("    %d %02x%02x%02x%02x  // width RGBA\n", width, a, b, g, r);
    } else {
      if (flash_read_rgba(&r, &g, &b, NULL))   return 1;
      printf("    %d %02x%02x%02x     // width RGB\n", width, b, g, r);
    }
    printf("  }\n");
  }

  return 0;
}


int flash_read_fillstylearray(int format) {

  int i;
  U16 num;

  num = 0;
  if (read_ubyte((U8 *)&num))           return 1;
  if ( ((format == 2) || (format == 3)) && (num == 255))
    if (read_ushort(&num))              return 1;

  printf("  // %d fillstyles\n", num);
  for (i = 0; i < num; i++) {
    U8 type;
    if (read_ubyte(&type))  return 1;
    printf("  fillstyle {     // fillstyle #%d \n", i+1);
    switch (type) {
    case 0x00:                // solid
      {
        U8 r, g, b, a;
        if (format == 3)
          flash_read_rgba(&r, &g, &b, &a);
        else
          flash_read_rgba(&r, &g, &b, NULL);
        if (format == 3)
          printf("    solid %02x%02x%02x%02x // RGBA\n", a, b, g, r);
        else
          printf("    solid %02x%02x%02x // RGB\n", b, g, r);
      }
      break;
    case 0x10:                // linear gradient
    case 0x12:                // radial gradient
      {
        MATRIX matrix;
        GRADIENT gradient;
        if (type == 0x10)
          printf("    linear {\n");
        else
          printf("    radial {\n");
        if (flash_read_matrix(&matrix))              return 1;
        if (flash_read_gradient(&gradient, format))  return 1;
        printf("    }\n");
      }
      break;
    case 0x40:                // tiled bitmap
    case 0x41:                // clipped bitmap
      {
        U16 id;
        MATRIX matrix;
        if (read_ushort(&id))              return 1;
        if (type == 0x40)
          printf("    tiled { id %d\n", id);
        else
          printf("    clipped { id %d\n", id);
        if (flash_read_matrix(&matrix))    return 1;
        printf("    }\n");
      }
      break;
    default:
      fprintf(stderr, "Unknown fillstyle (%d)\n", type);
      return 1;
      break;
    }
    printf("  }\n");
  }

  return 0;
}


int flash_read_shaperecord(U32 nfillbits, U32 nlinebits, int format, int *theend) {

  U32 edge;

  *theend = 0;

  while (1) {
    if (read_ubits(1, &edge))             return 1;
    if (!edge) {            // non-edge
      U32 flags;

      if (read_ubits(5, &flags))          return 1;
      if (flags == 0) {
        *theend = 1;
        return 0;
      }

      if (flags & 0x01) {
        S32 x, y;
        U32 bits;
        if (read_ubits(5, &bits))   return 1;
        if (read_bits(bits, &x))    return 1;
        if (read_bits(bits, &y))    return 1;
        printf("    moveto { %d %d }\n", x, y);
      }
      if (flags & 0x02) {
        U32 style;

        if (read_ubits(nfillbits, &style)) return 1;
        printf("    selectfillstyle0 %d\n", style);
      }
      if (flags & 0x04) {
        U32 style;

        if (read_ubits(nfillbits, &style)) return 1;
        printf("    selectfillstyle1 %d\n", style);
      }
      if (flags & 0x08) {
        U32 style;

        if (read_ubits(nlinebits, &style)) return 1;
        printf("    selectlinestyle %d\n", style);
      }
      if (flags & 0x10) {
        U32 fillbits, linebits;
        printf("// new fill/line styles defined within shape\n");
        if (flash_read_fillstylearray(format)) return 1;
        if (flash_read_linestylearray(format)) return 1;
        if (read_ubits(4, &fillbits))             return 1;
        if (read_ubits(4, &linebits))             return 1;

      }

    } else {                    // edge
      U32 straight;

      if (read_ubits(1, &straight))       return 1;
      if (straight) {
        U32 bits, line;
        S32 x, y;

        if (read_ubits(4, &bits))         return 1;
        bits += 2;
        x = y = 0;
        if (read_ubits(1, &line))         return 1;
        if (line) {
          if (read_bits(bits, &x))        return 1;
          if (read_bits(bits, &y))        return 1;
        } else {
          if (read_ubits(1, &line))       return 1;
          if (line) {
            if (read_bits(bits, &y))      return 1;
          } else {
            if (read_bits(bits, &x))      return 1;
          }
        }
        printf("    lineby { %d %d }\n", x, y);

      } else {
        U32 bits;
        S32 xc, yc, xa, ya;

        if (read_ubits(4, &bits))         return 1;
        bits += 2;
        if (read_bits(bits, &xc))         return 1;
        if (read_bits(bits, &yc))         return 1;
        if (read_bits(bits, &xa))         return 1;
        if (read_bits(bits, &ya))         return 1;
        printf("    curveby {\n");
        printf("      %d %d %d %d\n", xc, yc, xa, ya);
        printf("    }\n");
      }
    }
  }

  return 1;
}


int flash_read_rect(RECT *rect) {

  U32 nbits;

  if (read_ubits(5, &nbits))              return 1;
  if (read_bits(nbits, &rect->minx))      return 1;
  if (read_bits(nbits, &rect->maxx))      return 1;
  if (read_bits(nbits, &rect->miny))      return 1;
  if (read_bits(nbits, &rect->maxy))      return 1;
  return 0;
}


int flash_read_matrix(MATRIX *matrix) {

  U32 ok, bits;

  align_bucket();

  matrix->scalex = matrix->scaley = 65536;
  matrix->rotate0 = matrix->rotate1 = 0;
  matrix->tx = matrix->ty = 0;

  if (read_ubits(1, &ok))                   return 1;
  if (ok) {
    if (read_ubits(5, &bits))               return 1;
    if (read_bits(bits, &matrix->scalex))   return 1;
    if (read_bits(bits, &matrix->scaley))   return 1;
  }

  if (read_ubits(1, &ok))                   return 1;
  if (ok) {
    if (read_ubits(5, &bits))               return 1;
    if (read_bits(bits, &matrix->rotate0))  return 1;
    if (read_bits(bits, &matrix->rotate1))  return 1;
  }

  if (read_ubits(5, &bits))                return 1;
  if (read_bits(bits, &matrix->tx))        return 1;
  if (read_bits(bits, &matrix->ty))        return 1;

  if (matrix->scalex  == 65536 && matrix->scaley  == 65536 &&
      matrix->rotate0 == 0     && matrix->rotate0 == 0     &&
      matrix->tx      == 0     && matrix->ty      == 0)
    printf("  matrix { 65536 }\n");
  else {
    printf("  matrix {\n");
    printf("    %d %d // scale\n", matrix->scalex, matrix->scaley);
    printf("    %d %d // rotate\n", matrix->rotate0, matrix->rotate1);
    printf("    %d %d // translate\n", matrix->tx, matrix->ty);
    printf("  }\n");
  }
  return 0;
}


int flash_read_gradient(GRADIENT *gradient, int format) {

  U8 num, ratio[8];
  U8 r[8], g[8], b[8], a[8];
  int i;

  if (read_ubyte(&num))        return 1;
  if ((num < 1) || (num > 8))  return 1;

  printf("  gradient {\n");

  for (i = 0; i < num; i++) {
    if (read_ubyte(ratio+i))                      return 1;
    if (format == 3) {
      if (flash_read_rgba(r+i, g+i, b+i, a+i))    return 1;
      printf("    %d %02x%02x%02x%02x // ratio RGBA\n", ratio[i], a[i], b[i], g[i], r[i]);
    } else {
      if (flash_read_rgba(r+i, g+i, b+i, NULL))      return 1;
      printf("    %d %02x%02x%02x     // ratio RGB\n", ratio[i], b[i], g[i], r[i]);
    }
  }
  printf("  }\n");

  return 0;
}


int flash_read_rgba(U8 *r, U8 *g, U8 *b, U8 *a) {

  if (read_ubyte(r))  return 1;
  if (read_ubyte(g))  return 1;
  if (read_ubyte(b))  return 1;
  if (a)
    if (read_ubyte(a))  return 1;

  return 0;
}
