summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am13
-rw-r--r--src/Makefile.in383
-rw-r--r--src/args.h63
-rw-r--r--src/bitio.c187
-rw-r--r--src/bitio.h51
-rw-r--r--src/combine.c398
-rw-r--r--src/combine.h14
-rw-r--r--src/flash.c528
-rw-r--r--src/flash.h196
-rw-r--r--src/reloc.c285
-rw-r--r--src/reloc.h14
-rw-r--r--src/settings.h26
-rw-r--r--src/swfcombine.183
-rw-r--r--src/swfcombine.c431
-rw-r--r--src/swfdump.123
-rw-r--r--src/swfdump.c109
-rw-r--r--src/swfstrings.124
-rw-r--r--src/swfstrings.c54
-rw-r--r--src/types.h33
19 files changed, 2915 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 00000000..6b50cee5
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,13 @@
+## Process this file with automake to produce Makefile.in
+bin_PROGRAMS = swfcombine swfstrings swfdump
+swfdump_SOURCES = swfdump.c
+swfcombine_SOURCES = bitio.c bitio.h reloc.c reloc.h combine.c combine.h flash.c flash.h swfcombine.c types.h
+swfstrings_SOURCES = swfstrings.c
+swfdump_LINK = $(CCLD) ../lib/rfxswf.o -o $@
+swfcombine_LINK = $(CCLD) ../lib/log.o -o $@
+swfstrings_LINK = $(CCLD) ../lib/log.o ../lib/rfxswf.o -o $@
+##LIBS =
+##swfcombine_LIBS =
+##swfstrings_LIBS = -ljpeg
+man_MANS = swfcombine.1 swfstrings.1 swfdump.1
+
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 00000000..d87977be
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,383 @@
+# Makefile.in generated automatically by automake 1.4-p4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+AWK = @AWK@
+CC = @CC@
+CPP = @CPP@
+CXX = @CXX@
+EXEEXT = @EXEEXT@
+HAVE_UNISTD_H = @HAVE_UNISTD_H@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+
+bin_PROGRAMS = swfcombine swfstrings swfdump
+swfdump_SOURCES = swfdump.c
+swfcombine_SOURCES = bitio.c bitio.h reloc.c reloc.h combine.c combine.h flash.c flash.h swfcombine.c types.h
+swfstrings_SOURCES = swfstrings.c
+swfdump_LINK = $(CCLD) ../lib/rfxswf.o -o $@
+swfcombine_LINK = $(CCLD) ../lib/log.o -o $@
+swfstrings_LINK = $(CCLD) ../lib/log.o ../lib/rfxswf.o -o $@
+man_MANS = swfcombine.1 swfstrings.1 swfdump.1
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+bin_PROGRAMS = swfcombine$(EXEEXT) swfstrings$(EXEEXT) swfdump$(EXEEXT)
+PROGRAMS = $(bin_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+swfcombine_OBJECTS = bitio.o reloc.o combine.o flash.o swfcombine.o
+swfcombine_LDADD = $(LDADD)
+swfcombine_DEPENDENCIES =
+swfcombine_LDFLAGS =
+swfstrings_OBJECTS = swfstrings.o
+swfstrings_LDADD = $(LDADD)
+swfstrings_DEPENDENCIES =
+swfstrings_LDFLAGS =
+swfdump_OBJECTS = swfdump.o
+swfdump_LDADD = $(LDADD)
+swfdump_DEPENDENCIES =
+swfdump_LDFLAGS =
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+man1dir = $(mandir)/man1
+MANS = $(man_MANS)
+
+NROFF = nroff
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+DEP_FILES = .deps/bitio.P .deps/combine.P .deps/flash.P .deps/reloc.P \
+.deps/swfcombine.P .deps/swfdump.P .deps/swfstrings.P
+SOURCES = $(swfcombine_SOURCES) $(swfstrings_SOURCES) $(swfdump_SOURCES)
+OBJECTS = $(swfcombine_OBJECTS) $(swfstrings_OBJECTS) $(swfdump_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(bindir)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ if test -f $$p; then \
+ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ list='$(bin_PROGRAMS)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ done
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+swfcombine$(EXEEXT): $(swfcombine_OBJECTS) $(swfcombine_DEPENDENCIES)
+ @rm -f swfcombine$(EXEEXT)
+ $(swfcombine_LINK) $(swfcombine_LDFLAGS) $(swfcombine_OBJECTS) $(swfcombine_LDADD) $(LIBS)
+
+swfstrings$(EXEEXT): $(swfstrings_OBJECTS) $(swfstrings_DEPENDENCIES)
+ @rm -f swfstrings$(EXEEXT)
+ $(swfstrings_LINK) $(swfstrings_LDFLAGS) $(swfstrings_OBJECTS) $(swfstrings_LDADD) $(LIBS)
+
+swfdump$(EXEEXT): $(swfdump_OBJECTS) $(swfdump_DEPENDENCIES)
+ @rm -f swfdump$(EXEEXT)
+ $(swfdump_LINK) $(swfdump_LDFLAGS) $(swfdump_OBJECTS) $(swfdump_LDADD) $(LIBS)
+
+install-man1:
+ $(mkinstalldirs) $(DESTDIR)$(man1dir)
+ @list='$(man1_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \
+ $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \
+ done
+
+uninstall-man1:
+ @list='$(man1_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \
+ rm -f $(DESTDIR)$(man1dir)/$$inst; \
+ done
+install-man: $(MANS)
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) install-man1
+uninstall-man:
+ @$(NORMAL_UNINSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) uninstall-man1
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = src
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu src/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am: install-binPROGRAMS
+install-exec: install-exec-am
+
+install-data-am: install-man
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-binPROGRAMS uninstall-man
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS) $(MANS)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(mandir)/man1
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \
+ mostlyclean-tags mostlyclean-depend mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-binPROGRAMS clean-compile clean-tags clean-depend \
+ clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-binPROGRAMS distclean-compile distclean-tags \
+ distclean-depend distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-binPROGRAMS \
+ maintainer-clean-compile maintainer-clean-tags \
+ maintainer-clean-depend maintainer-clean-generic \
+ distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
+maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile install-man1 uninstall-man1 install-man \
+uninstall-man tags mostlyclean-tags distclean-tags clean-tags \
+maintainer-clean-tags distdir mostlyclean-depend distclean-depend \
+clean-depend maintainer-clean-depend info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/args.h b/src/args.h
new file mode 100644
index 00000000..a5699df4
--- /dev/null
+++ b/src/args.h
@@ -0,0 +1,63 @@
+/* args.h
+ Routines to simplify argument handling
+
+ Part of the swftools package.
+
+ Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
+
+ This file is distributed under the GPL, see file COPYING for details */
+
+#ifndef __args_h__
+#define __args_h__
+
+extern int args_callback_option(char*,char*);
+extern int args_callback_longoption(char*,char*);
+extern int args_callback_command(char*,char*);
+extern void args_callback_usage(char*name);
+
+int argn;
+char**argv;
+
+void processargs(int argn2,char**argv2)
+{
+ int t;
+ if(argn2==1)
+ {
+ args_callback_usage(argv2[0]);
+ exit(1);
+ }
+ for(t=1;t<argn2;t++)
+ {
+ char*next;
+ if(t<argn2-1) next=argv2[t+1];
+ else next=0;
+
+ if(argv2[t][0]=='-')
+ {
+ if(argv2[t][1]=='-')
+ {
+ if(!strcmp(&argv2[t][2],"help"))
+ {
+ args_callback_usage(argv2[0]);
+ exit(1);
+ }
+ t+=args_callback_longoption(&argv2[t][2],next);
+ }
+ else
+ {
+ if(strchr("?h",argv2[t][1]))
+ {
+ args_callback_usage(argv2[0]);
+ exit(1);
+ }
+ t+=args_callback_option(&argv2[t][1],next);
+ }
+ }
+ else
+ {
+ t+=args_callback_command(argv2[t],next);
+ }
+ }
+}
+
+#endif //__args_h__
diff --git a/src/bitio.c b/src/bitio.c
new file mode 100644
index 00000000..871fb804
--- /dev/null
+++ b/src/bitio.c
@@ -0,0 +1,187 @@
+/* bitio.c
+ Various routines for reading and writing bit- and bytewise, from and to memory.
+
+ Part of the swftools package.
+
+ Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
+
+ This file is distributed under the GPL, see file COPYING for details */
+
+#include "bitio.h"
+
+static uchar*data;
+static int datalength;
+static int datapos;
+
+void resetbits();
+
+void reader_init(uchar*newdata, int newlength)
+{
+ data = newdata;
+ datalength = newlength;
+ datapos = 0;
+ resetbits();
+}
+void skip(int length)
+{
+ datapos += length;
+}
+static u8 bitpos=8,mybyte;
+static u8 bitmem=0;
+void resetbits()
+{
+ bitpos=8;
+}
+
+void input1(void*target)
+{
+ *(uchar*)target = *(uchar*)&data[datapos];
+ datapos ++;
+}
+void input2(void*target)
+{
+ *(unsigned short int*)target = *(unsigned short int*)&data[datapos];
+ datapos += 2;
+}
+void input4(void*target)
+{
+ *(unsigned int*)target = *(unsigned int*)&data[datapos];
+ datapos += 4;
+}
+uchar*getinputpos()
+{
+ return &data[datapos];
+}
+int getinputlength()
+{
+ return datalength;
+}
+void setinputpos(uchar*pos)
+{
+ datapos = pos-data;
+}
+
+u32 readbit()
+{
+ if(bitpos==8)
+ {
+ bitpos=0;
+ input1(&mybyte);
+ }
+ return (mybyte>>(7-bitpos++))&1;
+}
+void readbits(u32*val,int num)
+{
+ int t;
+ *val=0;
+ for(t=0;t<num;t++)
+ {
+ *val<<=1;
+ *val|=readbit();
+ }
+}
+
+void readsbits(s32*val,int num)
+{
+ u32 x;
+ readbits(&x, num);
+ if((x>>(num-1))&1)
+ {
+ x|=(0xffffffff<<num);
+ }
+ *(s32*)val=x;
+}
+
+u32 getbits(int num)
+{
+ u32 x;
+ readbits(&x,num);
+ return x;
+}
+
+s32 getsbits(int num)
+{
+ s32 x;
+ readsbits(&x,num);
+ return x;
+}
+
+u16 readu8()
+{
+ u8 a;
+ input1(&a);
+ return a;
+}
+
+u16 readu16()
+{
+ u8 a,b;
+ // I'm not using input2(&a) here because our input is
+ // little endian.
+ input1(&a);
+ input1(&b);
+ return ((u16)b)*256+a;
+}
+
+void writer_init(struct writer_t*w, u8*data, int maxlength)
+{
+ w->data = data;
+ w->maxlength = maxlength;
+ w->pos = 0;
+ w->bitpos = 0;
+ w->mybyte = 0;
+}
+
+void writer_write(struct writer_t*w, void*data, int length)
+{
+ memcpy(&w->data[w->pos], data, length);
+ w->pos += length;
+}
+
+void writer_writeu8(struct writer_t*w, u8 value)
+{
+ writer_resetbits(w);
+ writer_write(w, &value, 1);
+}
+
+void writer_writeu16(struct writer_t*w, u16 value)
+{
+ writer_resetbits(w);
+ writer_write(w, &value, 2);
+}
+
+void* writer_getpos(struct writer_t*w)
+{
+ return &w->data[w->pos];
+}
+
+void writer_resetbits(struct writer_t*w)
+{
+ if(w->bitpos)
+ writer_write(w, &w->mybyte, 1);
+ w->bitpos = 0;
+ w->mybyte = 0;
+}
+
+void writer_writebit(struct writer_t*w, int bit)
+{
+ if(w->bitpos==8)
+ {
+ writer_write(w, &w->mybyte, 1);
+ w->bitpos = 0;
+ w->mybyte = 0;
+ }
+ if(bit&1)
+ w->mybyte |= 1 << (7 - w->bitpos);
+ w->bitpos ++;
+}
+
+void writer_writebits(struct writer_t*w, u32 data, int bits)
+{
+ int t;
+ for(t=0;t<bits;t++)
+ {
+ writer_writebit(w, (data >> (bits-t-1))&1);
+ }
+}
+
diff --git a/src/bitio.h b/src/bitio.h
new file mode 100644
index 00000000..c9ec2383
--- /dev/null
+++ b/src/bitio.h
@@ -0,0 +1,51 @@
+/* bitio.h
+ Header file for bitio.c.
+
+ Part of the swftools package.
+
+ Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
+
+ This file is distributed under the GPL, see file COPYING for details */
+
+#ifndef __bitio_h__
+#define __bitio_h__
+
+#include "types.h"
+
+void resetbits();
+void reader_init(uchar*newdata, int newlength);
+void skip(int length);
+void input1(void*target);
+void input2(void*target);
+void input4(void*target);
+
+uchar*getinputpos();
+int getinputlength();
+void setinputpos(uchar*pos);
+
+u32 readbit();
+void readbits(u32*val,int num);
+void readsbits(s32*val,int num);
+u32 getbits(int num);
+s32 getsbits(int num);
+u16 readu8();
+u16 readu16();
+
+struct writer_t {
+ u8* data;
+ int maxlength;
+ int pos;
+ int bitpos;
+ u8 mybyte;
+};
+
+void writer_init(struct writer_t*w, u8*data, int maxlength);
+void writer_write(struct writer_t*w, void*data, int length);
+void* writer_getpos(struct writer_t*w);
+void writer_writebit(struct writer_t*w, int bit);
+void writer_writebits(struct writer_t*w, u32 data, int bits);
+void writer_writeu8(struct writer_t*w, u8 value);
+void writer_writeu16(struct writer_t*w, u16 value);
+void writer_resetbits(struct writer_t*w);
+
+#endif //__bitio_h__
diff --git a/src/combine.c b/src/combine.c
new file mode 100644
index 00000000..a6120066
--- /dev/null
+++ b/src/combine.c
@@ -0,0 +1,398 @@
+/* combine.c
+ Implements combine(), which merges two swfs in memory.
+
+ Part of the swftools package.
+
+ Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
+
+ This file is distributed under the GPL, see file COPYING for details */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include "../lib/log.h"
+#include "./flash.h"
+#include "./reloc.h"
+#include "./settings.h"
+
+// TODO:
+// * readers should be object-oriented
+
+static char* tag_placeobject2_name (struct swf_tag* tag)
+{
+ struct PlaceObject2 plo2;
+ placeobject2_init (&plo2, tag);
+ return plo2.name;
+}
+
+static u16 tag_placeobject2_character (struct swf_tag* tag)
+{
+ struct PlaceObject2 plo2;
+ placeobject2_init (&plo2, tag);
+ return plo2.id;
+}
+
+static struct swffile master;
+static struct swffile slave;
+
+static int masterids[65536];
+
+static int get_free_id()
+{
+ int t;
+ for (t=1;t<65536;t++)
+ {
+ if(masterids[t] == -1)
+ {
+ masterids[t] = 1;
+ return t;
+ }
+ }
+ return -1;
+}
+
+void changedepth(struct swf_tag*tag, int add)
+{
+ if(tag->id == TAGID_PLACEOBJECT)
+ (*(u16*)&tag->data[2]) += add;
+ if(tag->id == TAGID_PLACEOBJECT2)
+ (*(u16*)&tag->data[1]) += add;
+ if(tag->id == TAGID_REMOVEOBJECT)
+ (*(u16*)&tag->data[2]) += add;
+ if(tag->id == TAGID_REMOVEOBJECT2)
+ (*(u16*)&tag->data[0]) += add;
+}
+
+/* applies the config move and scale parameters to
+ * a matrix. (If settings would provide a rotation,
+ * this would be a matrix concatenation/multiplication
+ * routine. In this case, it's just element-wise multiplication.
+ */
+void matrix_adjust(struct MATRIX*m)
+{
+ if(config.scalex != 1 || config.scaley != 1)
+ {
+ if(!m->hasscale) {
+ m->hasscale = 1;
+ m->a[0][0] = config.scalex;
+ m->a[1][1] = config.scaley;
+ } else {
+ m->a[0][0] *= config.scalex;
+ m->a[1][1] *= config.scaley;
+ }
+ if(m->hasrotate) {
+ m->a[0][1] *= config.scalex;
+ m->a[1][0] *= config.scaley;
+ }
+ m->b[0] *= config.scalex;
+ m->b[1] *= config.scaley;
+ }
+/* printf("hasscale: %d\n",m->hasscale);
+ printf("hasrotate: %d\n", m->hasrotate);
+ printf("move: %d %d\n", m->b[0],m->b[1]);
+ printf("rot: %f %f\n",m->a[0][0],m->a[0][1]);
+ printf(" %f %f\n",m->a[1][0],m->a[1][1]);*/
+ m->b[0] += config.movex;
+ m->b[1] += config.movey;
+}
+
+void write_changepos(struct swf_tag*tag, struct writer_t*w)
+{
+ if(config.movex || config.movey || config.scalex != 1 || config.scaley != 1)
+ {
+ switch(tag->id)
+ {
+ case TAGID_PLACEOBJECT: {
+ struct PlaceObject p;
+ placeobject_init(&p, tag);
+ matrix_adjust(&p.matrix);
+ placeobject_write(&p, w);
+ break;
+ }
+ case TAGID_PLACEOBJECT2: {
+ struct PlaceObject2 p;
+ placeobject2_init(&p, tag);
+ if(!p.hasmatrix) {
+ p.hasmatrix = 1;
+ MATRIX_init(&p.matrix);
+ }
+ matrix_adjust(&p.matrix);
+ placeobject2_write(&p, w);
+ break;
+ }
+ default:
+ writer_write(w, tag->fulldata, tag->fulllength);
+ }
+ }
+ else
+ {
+ writer_write(w, tag->fulldata, tag->fulllength);
+ }
+}
+
+uchar * combine(uchar*masterdata, int masterlength, char*slavename, uchar*slavedata, int slavelength, int*newlength)
+{
+ char master_flash = 0;
+ char slave_flash = 0;
+
+ logf("<debug> move x (%d)", config.movex);
+ logf("<debug> move y (%d)", config.movey);
+ logf("<debug> scale x (%d)", config.scalex);
+ logf("<debug> scale y (%d)", config.scaley);
+
+ memset(masterids, -1, sizeof(masterids));
+
+ if(masterlength < 3)
+ {
+ logf("<fatal> the master file is too small (%d bytes)", masterlength);
+ return 0;
+ }
+ if(slavelength < 3)
+ {
+ logf("<fatal> the slave file is too small (%d bytes)", slavelength);
+ return 0;
+ }
+ if(masterdata[2] == 'S' &&
+ masterdata[1] == 'W' &&
+ masterdata[0] == 'F')
+ {
+ logf("<notice> the master file is flash (swf) format\n");
+ master_flash = 1;
+ }
+ if(slavedata[2] == 'S' &&
+ slavedata[1] == 'W' &&
+ slavedata[0] == 'F')
+ {
+ logf("<notice> the slave file is flash (swf) format\n");
+ slave_flash = 1;
+ }
+
+ if(master_flash && slave_flash)
+ {
+ int length;
+ int pos=0;
+ u16 tmp;
+ u32 tmp32;
+ u32*tagidpos;
+ u8*startpos;
+ u32*headlength;
+ uchar*newdata;
+ int spriteid = -1;
+ int replaceddefine = -1;
+ struct writer_t w;
+
+ read_swf(&master, masterdata, masterlength);
+
+ length = masterlength + slavelength*2 + 128; // this is a guess, but a good guess.
+ newdata = malloc(length);
+ writer_init(&w, newdata, length);
+
+ if(!newdata) {
+ logf("<fatal> Couldn't allocate %d bytes of memory", length);
+ return 0;
+ }
+
+ // set the idtab
+ pos = 0;
+ do {
+ int tag = master.tags[pos].id;
+ if(is_defining_tag(tag)) {
+ int defineid = getidfromtag(&master.tags[pos]);
+ logf("<debug> tagid %02x defines object %d", tag, defineid);
+ masterids[defineid] = 1;
+ } else if(tag == TAGID_PLACEOBJECT2) {
+ char * name = tag_placeobject2_name(&master.tags[pos]);
+ int id = tag_placeobject2_character(&master.tags[pos]);
+
+ if(name)
+ logf("<verbose> tagid %02x places object %d named \"%s\"", tag, id, name);
+ else
+ logf("<verbose> tagid %02x places object %d (no name)", tag, id);
+
+ if (name && !strcmp(name,slavename)) {
+ if(id>=0) {
+ spriteid = id;
+ logf("<notice> Slave file attached to object %d.", id);
+ }
+ }
+ }
+ }
+ while(master.tags[pos++].id != 0);
+
+ swf_relocate (slavedata, slavelength, masterids);
+
+ read_swf(&slave, slavedata, slavelength);
+
+ // write header
+
+ writer_write(&w, "FWS",3);
+ headlength = (u32*)(writer_getpos(&w) + 1);
+ writer_write(&w, master.header.headerdata, master.header.headerlength);
+
+ // write sprite(1)
+
+ pos = 0;
+ while(slave.tags[pos].id != 0) {
+ struct swf_tag * tag = &slave.tags[pos];
+ if(!is_sprite_tag(tag->id)) {
+ logf("<debug> processing sprite tag %02x", slave.tags[pos].id);
+ if(is_defining_tag(tag->id))
+ {
+ logf("<debug> [sprite defs] write tag %02x (%d bytes in body)",
+ tag->id, tag->length);
+ writer_write(&w, tag->fulldata, tag->fulllength);
+ }
+ else
+ {
+ switch(tag->id)
+ {case TAGID_DEFINEFONTINFO:
+ {
+ /* define font info is not a defining tag, in that
+ * it doesn't define a new id, but rather extends
+ * an existing one. It also isn't a sprite tag.
+ * Anyway we can't throw it out, so we just pass it
+ * through.
+ */
+ break;
+ }
+ case TAGID_EXPORTASSETS:
+ logf("<debug> deliberately ignoring EXPORTASSETS tag");
+ break;
+ case TAGID_ENABLEDEBUGGER:
+ logf("<debug> deliberately ignoring ENABLEDEBUGGER tag");
+ break;
+ case TAGID_BACKGROUNDCOLOR:
+ logf("<debug> deliberately ignoring BACKGROUNDCOLOR tag");
+ break;
+ case 40:
+ case 49:
+ case 51:
+ logf("<notice> found tag %d. This is a Generator template, isn't it?", slave.tags[pos].id);
+ break;
+ default:
+ logf("<notice> funny tag: %d is neither defining nor sprite", slave.tags[pos].id);
+ }
+ }
+ }
+ pos++;
+ }
+
+ // write master (1)
+ pos = 0;
+ do {
+ if(is_defining_tag(master.tags[pos].id))
+ {
+ logf("<debug> [master] write tag %02x (%d bytes in body)",
+ master.tags[pos].id, master.tags[pos].length);
+ if( getidfromtag(&master.tags[pos]) == spriteid)
+ {
+ if(config.overlay)
+ {
+ *(u16*)master.tags[pos].data = replaceddefine = get_free_id();
+ writer_write(&w, master.tags[pos].fulldata, master.tags[pos].fulllength);
+ } else {
+ /* don't write this tag */
+ logf("<verbose> replacing tag %d id %d with sprite", master.tags[pos].id
+ ,spriteid);
+ }
+ } else {
+ writer_write(&w, master.tags[pos].fulldata, master.tags[pos].fulllength);
+ }
+ }
+ }
+ while(master.tags[pos++].id != 0);
+
+ // write slave(2) (header)
+ tmp = 0x3f + (TAGID_DEFINESPRITE << 6);
+ writer_write(&w, &tmp, 2);
+ tagidpos = (u32*)writer_getpos(&w);
+ writer_write(&w, &tmp32, 4);
+
+ startpos = (u8*)writer_getpos(&w);
+
+ if (spriteid<0)
+ {
+ logf("<warning> Didn't find anything named %s in file. No substitutions will occur.", slavename);
+ spriteid = get_free_id();
+ }
+
+ logf ("<notice> sprite id is %d", spriteid);
+ tmp = spriteid;
+ writer_write(&w, &tmp, 2);
+ tmp = slave.header.count;
+ writer_write(&w, &tmp, 2);
+
+
+ // write slave(2) (body)
+ pos = 0;
+ tmp = slave.header.count;
+ logf("<debug> %d frames to go",tmp);
+
+ if(config.clip) {
+ tmp = 7 + (TAGID_PLACEOBJECT2 << 6);
+ writer_write(&w, &tmp, 2);
+ tmp = 2+64; //flags: character + clipaction
+ writer_write(&w, &tmp, 1);
+ tmp = 0; //depth
+ writer_write(&w, &tmp,2);
+ tmp = replaceddefine; //id
+ writer_write(&w, &tmp,2);
+ tmp = 65535; //clipdepth
+ writer_write(&w, &tmp,2);
+ }
+
+ if(config.overlay) {
+ tmp = 5 + (TAGID_PLACEOBJECT2 << 6);
+ writer_write(&w, &tmp, 2);
+ tmp = 2; //flags: character
+ writer_write(&w, &tmp, 1);
+ tmp = 0; //depth
+ writer_write(&w, &tmp,2);
+ tmp = replaceddefine; //id
+ writer_write(&w, &tmp,2);
+ }
+
+ do {
+ struct swf_tag * tag = &slave.tags[pos];
+ if (is_sprite_tag(tag->id)) {
+
+ changedepth(tag, +1);
+ logf("<debug> [sprite main] write tag %02x (%d bytes in body)",
+ slave.tags[pos].id, slave.tags[pos].length);
+ write_changepos(tag, &w);
+
+ if(tag->id == TAGID_SHOWFRAME)
+ {
+ tmp--;
+ logf("<debug> %d frames to go",tmp);
+ }
+ }
+ }
+ while(slave.tags[pos++].id != TAGID_END);
+
+ *tagidpos = (u8*)writer_getpos(&w) - startpos; // set length of sprite (in header)
+ logf("<verbose> sprite length is %d",*tagidpos);
+
+ // write master (2)
+ pos = 0;
+ do {
+ if(!is_defining_tag(master.tags[pos].id))
+ {
+ logf("<debug> [master] write tag %02x (%d bytes in body)",
+ master.tags[pos].id, master.tags[pos].length);
+ writer_write(&w, master.tags[pos].fulldata, master.tags[pos].fulllength);
+ }
+ }
+ while(master.tags[pos++].id != 0);
+
+ tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length
+ *newlength = tmp32;
+ *headlength = tmp32; // set the header to the correct length
+
+ return newdata; //length
+ }
+
+ *newlength = 0;
+ return 0;
+}
diff --git a/src/combine.h b/src/combine.h
new file mode 100644
index 00000000..d522771d
--- /dev/null
+++ b/src/combine.h
@@ -0,0 +1,14 @@
+/* combine.h
+ Header file for combine.c
+
+ Part of the swftools package.
+
+ Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
+
+ This file is distributed under the GPL, see file COPYING for details */
+
+#ifndef __combine_h__
+#define __combine_h__
+unsigned char * combine(unsigned char*masterdata, int masterlength,
+ char*slavename, unsigned char*slavedata, int slavelength, int*newlength);
+#endif //__combine_h__
diff --git a/src/flash.c b/src/flash.c
new file mode 100644
index 00000000..fff82843
--- /dev/null
+++ b/src/flash.c
@@ -0,0 +1,528 @@
+/* flash.c
+ Various routines for reading and writing swf files and tags.
+
+ Part of the swftools package.
+
+ Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
+
+ This file is distributed under the GPL, see file COPYING for details */
+
+#include "flash.h"
+#include "bitio.h"
+
+void swf_init(uchar*newdata, int newlength)
+{
+ reader_init (&newdata[3], newlength - 3);
+}
+
+struct flash_header swf_read_header()
+{
+ struct flash_header head;
+ u16 rate;
+ u16 count;
+ char version;
+ int length;
+ u8* oldpos = getinputpos();
+
+ input1(&version);
+ head.version = version;
+ input4(&length);
+ head.length = length;
+
+ resetbits();
+ head.boundingBox = readRECT();
+ input2(&rate);
+ head.rate = rate;
+ input2(&count);
+ head.count = count;
+
+ head.headerlength = getinputpos() - oldpos;
+ head.headerdata = oldpos;
+
+ return head;
+}
+
+struct RGB readRGB()
+{
+ struct RGB rgb;
+ input1(&rgb.r);
+ input1(&rgb.g);
+ input1(&rgb.b);
+ return rgb;
+}
+
+struct RGBA readRGBA()
+{
+ struct RGBA rgba;
+ input1(&rgba.r);
+ input1(&rgba.g);
+ input1(&rgba.b);
+ input1(&rgba.a);
+ return rgba;
+}
+
+struct GRADIENT readGRADIENT(int shape)
+{
+ struct GRADIENT gradient;
+ int t;
+ gradient.num = readu8();
+ for(t=0;t<gradient.num;t++)
+ {
+ gradient.ratios[t] = readu8();
+ if(shape>=3)
+ gradient.rgb[t] = readRGB();
+ else
+ gradient.rgba[t] = readRGBA();
+ }
+}
+
+struct RECT readRECT()
+{
+ u32 a;
+ struct RECT r;
+ s32 b;
+ readbits(&a,5);
+ readsbits(&b,a);
+ r.x1=b;
+ readsbits(&b,a);
+ r.x2=b;
+ readsbits(&b,a);
+ r.y1=b;
+ readsbits(&b,a);
+ r.y2=b;
+ return r;
+}
+
+
+void writeRECT(u8**pos, struct RECT*r)
+{
+ struct writer_t w;
+ int t=0;
+ writer_init(&w, *pos, 256);
+ writer_writebits(&w, 31, 5); //FIXME:count
+ writer_writebits(&w, r->x1, 31);
+ writer_writebits(&w, r->x2, 31);
+ writer_writebits(&w, r->y1, 31);
+ writer_writebits(&w, r->y2, 31);
+ writer_resetbits(&w);
+ *pos = writer_getpos(&w);
+}
+
+struct CXFORM readCXFORM()
+{
+ struct CXFORM c;
+ int bits;
+ c.hasadd=readbit();
+ c.hasmult=readbit();
+ bits=getbits(4);
+ c.alpha = 0;
+
+ if (c.hasmult)
+ {
+ c.rmult=getsbits(bits)/65536.0;
+ c.gmult=getsbits(bits)/65536.0;
+ c.bmult=getsbits(bits)/65536.0;
+ if(c.alpha)
+ c.amult=getsbits(bits)/65536.0;
+ }
+ if (c.hasadd)
+ {
+ c.radd=getsbits(bits)/65536.0;
+ c.gadd=getsbits(bits)/65536.0;
+ c.badd=getsbits(bits)/65536.0;
+ if(c.alpha)
+ c.aadd=getsbits(bits)/65536.0;
+ }
+ return c;
+}
+
+void CXFORM_write(struct CXFORM *obj, struct writer_t*w)
+{
+ int bits = 15;
+ writer_writebit(w,obj->hasadd);
+ writer_writebit(w,obj->hasmult);
+ writer_writebits(w, bits, 4);
+ if (obj->hasmult)
+ {
+ writer_writebits(w, obj->rmult, bits);
+ writer_writebits(w, obj->gmult, bits);
+ writer_writebits(w, obj->bmult, bits);
+ if(obj->alpha)
+ writer_writebits(w, obj->amult, 4);
+ }
+ if (obj->hasadd)
+ {
+ writer_writebits(w, obj->radd, bits);
+ writer_writebits(w, obj->gadd, bits);
+ writer_writebits(w, obj->badd, bits);
+ if(obj->alpha)
+ writer_writebits(w, obj->aadd, 4);
+ }
+}
+
+unsigned char* readSTRING()
+{
+ unsigned char*now = getinputpos();
+ char a;
+ do
+ {
+ input1(&a);
+ }
+ while(a);
+ return now;
+}
+void MATRIX_init(struct MATRIX*m)
+{
+ m->hasrotate = 0;
+ m->hasscale = 0;
+ m->b[0] = 0;
+ m->b[1] = 0;
+ m->a[0][0] = 1;
+ m->a[1][1] = 1;
+ m->a[1][0] = 0;
+ m->a[0][1] = 0;
+}
+struct MATRIX readMATRIX()
+{
+ struct MATRIX m;
+ u8 hasrotate;
+ u8 translatebits;
+ u32 translatex;
+ u32 translatey;
+
+ m.a[0][0] = m.a[1][1] = 1;
+ m.a[0][1] = m.a[1][0] = 0;
+ m.hasscale=readbit();
+ if(m.hasscale)
+ {
+ u8 scalebits=getbits(5);
+ s32 scalex=getsbits(scalebits);
+ s32 scaley=getsbits(scalebits);
+ m.a[0][0]=scalex/65536.0;
+ m.a[1][1]=scaley/65536.0;
+ }
+ m.hasrotate=readbit();
+ if(m.hasrotate)
+ {
+ u8 rotbits=getbits(5);
+ s32 rotateskew0=getsbits(rotbits);
+ s32 rotateskew1=getsbits(rotbits);
+ m.a[0][1]=rotateskew0/65536.0;
+ m.a[1][0]=rotateskew1/65536.0;
+ }
+
+ translatebits=getbits(5);
+ translatex=getsbits(translatebits);
+ translatey=getsbits(translatebits);
+ m.b[0]=translatex;
+ m.b[1]=translatey;
+
+ return m;
+}
+
+void MATRIX_write(struct MATRIX * m , struct writer_t*w)
+{
+ writer_writebit (w, m->hasscale);
+ if(m->hasscale)
+ {
+ int bits = 31;
+ writer_writebits(w, bits, 5);
+ writer_writebits(w, (u32)(m->a[0][0]*65536.0), bits);
+ writer_writebits(w, (u32)(m->a[1][1]*65536.0), bits);
+ }
+ writer_writebit (w, m->hasrotate);
+ if(m->hasrotate)
+ {
+ int bits = 31;
+ writer_writebits(w, bits, 5);
+ writer_writebits(w, (u32)(m->a[0][1]*65536.0), bits);
+ writer_writebits(w, (u32)(m->a[1][0]*65536.0), bits);
+ }
+
+ //translate
+ {
+ int bits = 31;
+ writer_writebits(w, bits, 5);
+ writer_writebits(w, (u32)(m->b[0]), bits);
+ writer_writebits(w, (u32)(m->b[1]), bits);
+ }
+}
+
+
+int swf_read_tag(struct swf_tag* swftag)
+{
+ u8*pos2,*pos = getinputpos();
+ u16 tag;
+ u32 taglength;
+ u32 tagid;
+ int t;
+
+ input2(&tag);
+
+ taglength = tag & 0x3f;
+ if (taglength == 0x3f)
+ {
+ input4(&taglength);
+ }
+
+ swftag->id=tag>>6;
+ swftag->length = taglength;
+ swftag->data = getinputpos();
+ skip(taglength);
+ pos2 = getinputpos();
+ swftag->fulllength = pos2 - pos;
+ swftag->fulldata = pos;
+ return 1;
+}
+
+int swf_count_tags()
+{
+ u8*pos = getinputpos();
+ int t=0;
+ struct swf_tag tag;
+
+ while(1)
+ {
+ swf_read_tag(&tag);
+ t++;
+ if (tag.id == 0)
+ break;
+ }
+
+ setinputpos(pos);
+ return t;
+}
+
+void placeobject_init (struct PlaceObject*obj, struct swf_tag*tag)
+{
+ reader_init (tag->data, tag->length);
+ obj -> id = readu16();
+ obj -> depth = readu16();
+ obj -> matrix = readMATRIX();
+ obj -> hascxform = (getinputpos() < &tag->data[tag->length]);
+ if(obj -> hascxform)
+ obj -> cxform = readCXFORM();
+}
+
+void placeobject_write (struct PlaceObject*obj, struct writer_t*w)
+{
+ u16 taghead = 0x3f | TAGID_PLACEOBJECT<<6;
+ u8*pos;
+ u8*lenpos;
+ writer_resetbits(w);
+ writer_write(w, &taghead, 2);
+ lenpos = writer_getpos(w);
+
+ writer_write(w, &taghead, 2);
+ writer_write(w, &taghead, 2);
+
+ pos = writer_getpos(w);
+
+ writer_write(w, &obj->id, 2);
+ writer_write(w, &obj->depth, 2);
+ MATRIX_write(&obj->matrix, w);
+
+ if(obj->hascxform)
+ {
+ CXFORM_write(&obj->cxform, w);
+ }
+ writer_resetbits(w);
+
+ *(u32*)lenpos = (u8*)writer_getpos(w) - pos;
+}
+
+void placeobject2_init (struct PlaceObject2*obj,struct swf_tag*tag)
+{
+ u8 b;
+ reader_init (tag->data, tag->length);
+ b=readu8();
+ obj->reserved= (b>>7)&1;
+ obj->hasclipactions= (b>>6)&1;
+ obj->hasname= (b>>5)&1;
+ obj->hasratio= (b>>4)&1;
+ obj->hascolortransform=(b>>3)&1;
+ obj->hasmatrix= (b>>2)&1;
+ obj->hascharacter= (b>>1)&1;
+ obj->hasmove= (b>>0)&1;
+
+ obj->depth = readu16();
+ obj->id = -1;
+ if(obj->hascharacter) {
+ obj->id = readu16();
+ }
+ if(obj->hasmatrix) {
+ obj->matrix = readMATRIX();
+ }
+ if(obj->hascolortransform) {
+ obj->cxform = readCXFORM();
+ }
+ if(obj->hasratio) {
+ obj->ratio=readu16();
+ }
+ obj->name = 0;
+ if(obj->hasname) {
+ obj->name=readSTRING();
+ }
+ if(obj->hasclipactions) {
+ obj->clipactions=readu16();
+ }
+}
+
+void placeobject2_write (struct PlaceObject2*obj, struct writer_t*w)
+{
+ u8 flags = obj->reserved<<7 | obj->hasclipactions<<6 | obj->hasname<<5 | obj->hasratio<<4 |
+ obj->hascolortransform<<3 | obj->hasmatrix<<2 | obj->hascharacter<<1 | obj->hasmove;
+ u16 taghead = 0x3f | TAGID_PLACEOBJECT2<<6;
+ u8*pos;
+ u8*lenpos;
+ writer_resetbits(w);
+ writer_write(w, &taghead, 2);
+ lenpos = writer_getpos(w);
+ writer_write(w, &taghead, 2);
+ writer_write(w, &taghead, 2);
+
+ pos = writer_getpos(w);
+
+ writer_writeu8(w, flags);
+ writer_writeu16(w, obj->depth);
+ if(obj->hascharacter)
+ writer_writeu16(w, obj->id);
+ if(obj->hasmatrix)
+ MATRIX_write(&obj->matrix, w);
+ if(obj->hascolortransform)
+ CXFORM_write(&obj->cxform, w);
+ if(obj->hasratio)
+ writer_writeu16(w, obj->ratio);
+ writer_resetbits(w);
+ if(obj->hasname)
+ writer_write(w, obj->name, strlen(obj->name) + 1);
+ if(obj->hasclipactions)
+ writer_writeu16(w, obj->clipactions);
+ writer_resetbits(w);
+ *(u32*)lenpos = (u8*)writer_getpos(w) - pos;
+}
+
+void read_swf(struct swffile*swf, uchar*data, int length)
+{
+ int pos;
+ struct flash_header head;
+ int tagnum;
+ swf_init(data, length);
+ head = swf_read_header(data);
+ logf("<debug> [HEADER] the version is %d", head.version);
+ logf("<debug> [HEADER] the length is %d", head.length);
+ logf("<debug> [HEADER] the boundingBox is %d:%d:%d:%d",
+ head.boundingBox.x1,head.boundingBox.y1,
+ head.boundingBox.x2,head.boundingBox.y2);
+ logf("<debug> [HEADER] the rate (frames/second) is %d", head.rate);
+ logf("<debug> [HEADER] the count (frame number) is %d", head.count);
+
+ tagnum = swf_count_tags();
+ swf->tags = (struct swf_tag*)malloc(sizeof(struct swf_tag)*tagnum);
+
+ logf("<debug> [HEADER] the file consists of %d tags", tagnum);
+
+ pos = 0;
+ while(1)
+ {
+ struct swf_tag tag;
+ swf_read_tag(&tag);
+ logf("<debug> read tag %02x (%d bytes)", tag.id, tag.length);
+ swf->tags[pos] = tag;
+ pos++;
+ if(tag.id == TAGID_END)
+ break;
+ }
+ swf->tagnum = tagnum;
+ swf->header = head;
+}
+
+int definingtagids[] =
+{TAGID_DEFINESHAPE,
+ TAGID_DEFINESHAPE2,
+ TAGID_DEFINESHAPE3,
+ TAGID_DEFINEMORPHSHAPE,
+ TAGID_DEFINEFONT,
+ TAGID_DEFINEFONT2,
+ TAGID_DEFINETEXT,
+ TAGID_DEFINETEXT2,
+ TAGID_DEFINEEDITTEXT,
+ TAGID_DEFINEBITS,
+ TAGID_DEFINEBITSJPEG2,
+ TAGID_DEFINEBITSJPEG3,
+ TAGID_DEFINEBITSLOSSLESS,
+ TAGID_DEFINEBITSLOSSLESS2,
+ TAGID_DEFINEMOVIE,
+ TAGID_DEFINESPRITE,
+ TAGID_DEFINEBUTTON,
+ TAGID_DEFINEBUTTON2,
+ TAGID_DEFINESOUND,
+ -1
+};
+
+// tags which may be used inside a sprite definition
+int spritetagids[] =
+{TAGID_SHOWFRAME,
+ TAGID_PLACEOBJECT,
+ TAGID_PLACEOBJECT2,
+ TAGID_REMOVEOBJECT,
+ TAGID_REMOVEOBJECT2, //?
+ TAGID_DOACTION,
+ TAGID_STARTSOUND,
+ TAGID_FRAMELABEL,
+ TAGID_SOUNDSTREAMHEAD,
+ TAGID_SOUNDSTREAMHEAD2,
+ TAGID_SOUNDSTREAMBLOCK,
+ TAGID_END,
+ -1
+};
+
+int getidfromtag(struct swf_tag* tag)
+{
+ // todo: check for more than one id
+ return *(u16*)tag->data;
+}
+
+void setidintag(struct swf_tag* tag, int id)
+{
+ *(u16*)tag->data = id;
+}
+
+char is_sprite_tag (int id)
+{
+
+ int t=0;
+ while(spritetagids[t]>=0)
+ {
+ if(spritetagids[t] == id)
+ return 1;
+ t++;
+ }
+ return 0;
+}
+
+char is_defining_tag (int id)
+{
+
+ int t=0;
+ while(definingtagids[t]>=0)
+ {
+ if(definingtagids[t] == id)
+ return 1;
+ t++;
+ }
+ return 0;
+}
+
+struct swf_tag* duptag(struct swf_tag*tag)
+{
+ struct swf_tag* newtag = (struct swf_tag*)malloc(sizeof(struct swf_tag));
+ newtag->id = tag->id;
+ newtag->fulldata = (u8*)malloc(tag->fulllength);
+ newtag->fulllength = tag->fulllength;
+ newtag->data = newtag->fulldata + (tag->data - tag->fulldata);
+ newtag->length = tag->length;
+ memcpy(newtag->fulldata, tag->fulldata, tag->fulllength);
+ return newtag;
+}
+
diff --git a/src/flash.h b/src/flash.h
new file mode 100644
index 00000000..255aeff5
--- /dev/null
+++ b/src/flash.h
@@ -0,0 +1,196 @@
+/* flash.h
+ Header file for flash.c
+
+ Part of the swftools package.
+
+ Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
+
+ This file is distributed under the GPL, see file COPYING for details */
+
+#ifndef __flash_h__
+#define __flash_h__
+
+#include "types.h"
+
+#define TAGID_END 0
+#define TAGID_SHOWFRAME 1
+#define TAGID_DEFINESHAPE 2
+#define TAGID_PLACEOBJECT 4
+#define TAGID_REMOVEOBJECT 5
+#define TAGID_DEFINEBITS 6
+#define TAGID_DEFINEBUTTON 7
+#define TAGID_JPEGTABLES 8
+#define TAGID_BACKGROUNDCOLOR 9
+#define TAGID_DEFINEFONT 10
+#define TAGID_DEFINETEXT 11
+#define TAGID_DOACTION 12
+#define TAGID_DEFINEFONTINFO 13
+#define TAGID_DEFINESOUND 14
+#define TAGID_STARTSOUND 15
+#define TAGID_SOUNDSTREAMHEAD 18
+#define TAGID_SOUNDSTREAMHEAD2 18
+#define TAGID_SOUNDSTREAMBLOCK 19
+#define TAGID_DEFINEBITSLOSSLESS 20
+#define TAGID_DEFINEBITSJPEG2 21
+#define TAGID_DEFINESHAPE2 22
+#define TAGID_PROTECT 24
+#define TAGID_PLACEOBJECT2 26
+#define TAGID_REMOVEOBJECT2 28
+#define TAGID_DEFINESHAPE3 32
+#define TAGID_DEFINETEXT2 33
+#define TAGID_DEFINEBUTTON2 34
+#define TAGID_DEFINEBITSJPEG3 35
+#define TAGID_DEFINEBITSLOSSLESS2 36
+#define TAGID_DEFINEEDITTEXT 37
+#define TAGID_DEFINEMOVIE 38
+#define TAGID_DEFINESPRITE 39
+#define TAGID_FRAMELABEL 43
+#define TAGID_DEFINEMORPHSHAPE 46
+#define TAGID_DEFINEFONT2 48
+#define TAGID_EXPORTASSETS 56
+#define TAGID_IMPORTASSETS 57
+#define TAGID_ENABLEDEBUGGER 58
+
+#include "bitio.h"
+
+struct swf_tag;
+struct RECT;
+struct RGB;
+struct MATRIX;
+struct CXFORM;
+struct CLIPACTIONS;
+
+struct swf_tag
+{
+ u8 id;
+ u32 length;
+ u8*data;
+ u32 fulllength; // includes id
+ u8*fulldata; // likewise
+};
+
+struct RGB
+{
+ byte r,g,b;
+};
+
+struct RGBA
+{
+ byte r,g,b,a;
+};
+
+struct RECT
+{
+ int x1, y1, x2, y2;
+};
+
+struct MATRIX
+{
+ u8 hasscale;
+ u8 hasrotate;
+ float a[2][2];
+ int b[2];
+};
+
+struct CXFORM
+{
+ u8 hasadd;
+ u8 hasmult;
+ float rmult, gmult, bmult, amult;
+ float radd, gadd, badd, aadd;
+ u8 alpha;
+};
+
+struct GRADIENT
+{
+ int num;
+ u8 ratios[8];
+ struct RGB rgb[8];
+ struct RGBA rgba[8];
+};
+
+struct RECT readRECT();
+struct RGB readRGB();
+struct MATRIX readMATRIX();
+unsigned char* readSTRING();
+struct CXFORM readCXFORM();
+struct CLIPACTIONS readCLIPACTIONS();
+
+void writeRECT(u8**pos, struct RECT*r);
+
+void swf_init(uchar*newdata, int newlength);
+struct flash_header
+{
+ int version;
+ u32 length;
+ struct RECT boundingBox;
+ u16 rate;
+ u16 count;
+
+ u8*headerdata;
+ int headerlength;
+};
+
+struct swffile
+{
+ struct flash_header header;
+ int tagnum;
+ struct swf_tag* tags;
+};
+
+struct flash_header swf_read_header();
+struct RGB readRGB();
+struct RGBA readRGBA();
+struct GRADIENT readGRADIENT(int shape);
+struct RECT readRECT();
+struct CXFORM readCXFORM();
+struct MATRIX readMATRIX();
+unsigned char* readSTRING();
+int swf_read_tag(struct swf_tag* swftag);
+int swf_count_tags();
+
+
+struct PlaceObject
+{
+ u16 id;
+ u16 depth;
+ struct MATRIX matrix;
+ struct CXFORM cxform;
+ u8 hascxform;
+};
+
+struct PlaceObject2
+{
+ u8 reserved;
+ u8 hasclipactions;
+ u8 hasname;
+ u8 hasratio;
+ u8 hascolortransform;
+ u8 hasmatrix;
+ u8 hascharacter;
+ u8 hasmove;
+
+ u16 depth;
+ int id;
+ struct MATRIX matrix;
+ struct CXFORM cxform;
+ u16 ratio;
+ char * name;
+ u16 clipactions;
+};
+
+
+void placeobject_init (struct PlaceObject*obj, struct swf_tag*tag);
+void placeobject_write (struct PlaceObject*obj, struct writer_t*w);
+
+void placeobject2_init (struct PlaceObject2*obj, struct swf_tag*tag);
+
+void read_swf(struct swffile*swf, uchar*data, int length);
+
+int getidfromtag(struct swf_tag* tag);
+void setidintag(struct swf_tag* tag, int id);
+char is_sprite_tag (int id);
+char is_defining_tag (int id);
+struct swf_tag* duptag(struct swf_tag*tag);
+
+#endif //__flash_h__
diff --git a/src/reloc.c b/src/reloc.c
new file mode 100644
index 00000000..2f82afa5
--- /dev/null
+++ b/src/reloc.c
@@ -0,0 +1,285 @@
+/* reloc.h
+ Implements swf_relocate(), which changes the id range of a swf file in
+ memory.
+
+ Part of the swftools package.
+
+ Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
+
+ This file is distributed under the GPL, see file COPYING for details */
+
+#include "flash.h"
+
+static struct swffile file;
+
+int slaveids[65536];
+
+
+void map_ids_mem(u8*mem, int length);
+static struct swf_tag* map_ids(struct swf_tag*tag)
+{
+ map_ids_mem(tag->fulldata, tag->fulllength);
+ return tag;
+}
+
+void maponeid(void*idpos)
+{
+ u16*idptr = (u16*)idpos;
+ if(slaveids[*idptr]<0) {
+ logf("<error> Trying to map id never encountered before: id=%d", *idptr);
+ return ;
+ }
+ logf("<debug> mapping %d to %d", *idptr, slaveids[*idptr]);
+ *idptr = slaveids[*idptr];
+}
+
+
+// take a memory region which contains a tag, and
+// map the ids inside this tag to new values
+void map_ids_mem(u8*mem, int length)
+{
+ int num=1;
+ struct swf_tag newtag_instance;
+ struct swf_tag*newtag = &newtag_instance;
+ reader_init (mem, length);
+ swf_read_tag(newtag);
+
+ switch(newtag->id)
+ {
+ case TAGID_PLACEOBJECT:
+ maponeid(&newtag->data[0]);
+ break;
+ case TAGID_PLACEOBJECT2:
+ // only if placeflaghascharacter
+ if(!(newtag->data[0]&2))
+ break;
+ maponeid(&newtag->data[3]);
+ break;
+ case TAGID_REMOVEOBJECT:
+ maponeid(&newtag->data[0]);
+ break;
+ case TAGID_STARTSOUND:
+ maponeid(&newtag->data[0]);
+ break;
+ case TAGID_DEFINESPRITE: {
+ u8*mem = &newtag->data[4];
+ int len = newtag->length-4;
+
+ while(1) {
+ u8*fmem = mem;
+ int flen = len;
+ struct swf_tag sprtag;
+
+ reader_init (mem, len);
+ swf_read_tag (&sprtag);
+
+ mem = getinputpos();
+ len = getinputlength();
+
+ if(sprtag.id == TAGID_END)
+ break;
+
+ map_ids_mem (fmem,flen);
+ }
+ }
+ break;
+ case TAGID_DEFINEBUTTON2: // has some font ids in the button records
+ num++;
+ //fallthrough
+ case TAGID_DEFINEBUTTON:
+ reader_init (newtag->data, newtag->length);
+ readu16(); //button id
+ if(num>1)
+ {
+ readu8(); //flag
+ readu16(); //offset
+ }
+ while(1)
+ {
+ u16 charid;
+ if(!readu8()) //flags
+ break;
+ charid = *(u16*)getinputpos();
+ maponeid(getinputpos());
+ readu16(); //char
+ readu16(); //layer
+ readMATRIX();
+ readCXFORM();
+ }
+ // ...
+ break;
+ case TAGID_DEFINEEDITTEXT: {
+ u8 flags1,flags2;
+ reader_init (newtag->data, newtag->length);
+ readu16(); //id
+ readRECT(); //bounding box
+ resetbits();
+ flags1 = readu8();
+ flags2 = readu8();
+ if(flags1 & 128)
+ maponeid(getinputpos());
+ }
+ break;
+ case TAGID_DEFINETEXT2:
+ num ++;
+ case TAGID_DEFINETEXT: {
+ int glyphbits, advancebits;
+ reader_init (newtag->data, newtag->length);
+ readu16(); //id
+ readRECT(); //bounding box
+ readMATRIX(); //matrix
+ resetbits();
+ glyphbits = readu8(); //glyphbits
+ advancebits = readu8(); //advancebits
+ while(1) {
+ u16 flags = getbits(8);
+ printf("define text flags: %02x\n", flags);
+ if(!flags) break;
+ if(flags & 128) // text style record
+ {
+ if(flags & 8) { // hasfont
+ maponeid(getinputpos());
+ resetbits();
+ readu16();
+ }
+ if(flags & 4) { // hascolor
+ if(num==1) readRGB();
+ else readRGBA();
+ }
+ if(flags & 2) { //has x offset
+ resetbits();
+ readu16();
+ }
+ if(flags & 1) { //has y offset
+ resetbits();
+ readu16();
+ }
+ if(flags & 8) { //has height
+ resetbits();
+ readu16();
+ }
+ } else { // glyph record
+ getbits(glyphbits);
+ getbits(advancebits);
+ break;
+ }
+ }
+ break;
+ }
+ case TAGID_DEFINEFONTINFO:
+ maponeid(&newtag->data[0]);
+ break;
+
+ case TAGID_DEFINESHAPE3: // these thingies might have bitmap ids in their fillstyles
+ num++; //fallthrough
+ case TAGID_DEFINESHAPE2:
+ num++; //fallthrough
+ case TAGID_DEFINESHAPE: {
+ u16 count;
+ int t;
+ struct RECT r;
+ reader_init (newtag->data, newtag->length);
+ readu16(); // id;
+ r = readRECT(); // bounds
+// printf("%d shape bounds: %d %d %d %d\n",newtag->id,r.x1,r.y1,r.x2,r.y2);
+ resetbits();
+ count = readu8();
+ if(count == 0xff && num>1)
+ count = readu16();
+// printf("%d fillstyles\n", count);
+ for(t=0;t<count;t++)
+ {
+ int type;
+ u8*pos;
+ pos=getinputpos();
+// printf("%02x %02x %02x %02x %02x %02x %02x %02x\n",
+// pos[0],pos[1],pos[2],pos[3],pos[4],pos[5],pos[6],pos[7]);
+ type = readu8(); //type
+// printf("fillstyle %d is type 0x%02x\n", t, type);
+ if(type == 0) {
+ if(num == 3)
+ readRGBA();
+ else
+ readRGB();
+ }
+ if(type == 0x10 || type == 0x12)
+ {
+ readMATRIX();
+ resetbits();
+ readGRADIENT(num);
+ }
+ if(type == 0x40 || type == 0x41)
+ {
+ resetbits();
+ // we made it.
+ if(*(u16*)getinputpos() != 65535)
+ maponeid(getinputpos());
+
+ readu16();
+ readMATRIX();
+ }
+ //...
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static int*bitmap;
+
+static int get_free_id()
+{
+ int t;
+ for (t=1;t<65536;t++)
+ {
+ if(bitmap[t] == -1)
+ {
+ bitmap[t] = 1;
+ return t;
+ }
+ }
+ return -1;
+}
+
+void swf_relocate (u8*data, int length, int*_bitmap)
+{
+ int pos;
+ bitmap = _bitmap;
+ read_swf(&file, data, length);
+ memset(slaveids, -1, sizeof(slaveids));
+
+ pos = 0;
+ while(file.tags[pos].id != 0) {
+ struct swf_tag*tag = &file.tags[pos];
+
+ map_ids(&file.tags[pos]);
+
+ if(is_defining_tag(tag->id))
+ {
+ int newid;
+ int id;
+
+ id = getidfromtag(tag); //own id
+
+ if(bitmap[id] < 0) { //free
+ newid = id;
+ }
+ else {
+ newid = get_free_id(id);
+ }
+ bitmap[newid] = 1;
+ slaveids[id] = newid;
+
+ logf("<debug> sprite id %d mapped to %d",id, newid);
+
+ setidintag(tag, newid);
+
+ logf("<debug> [sprite defs] write tag %02x (%d bytes in body)",
+ tag->id, tag->length);
+ }
+ pos++;
+ }
+}
+
diff --git a/src/reloc.h b/src/reloc.h
new file mode 100644
index 00000000..8624c440
--- /dev/null
+++ b/src/reloc.h
@@ -0,0 +1,14 @@
+/* reloc.h
+ Header file for reloc.c
+
+ Part of the swftools package.
+
+ Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
+
+ This file is distributed under the GPL, see file COPYING for details */
+
+#ifndef __swf_reallocate__
+#define __swf_reallocate__
+void swf_relocate (u8*data, int length, int*bitmap);
+#endif // __swf_reallocate__
+
diff --git a/src/settings.h b/src/settings.h
new file mode 100644
index 00000000..da73a716
--- /dev/null
+++ b/src/settings.h
@@ -0,0 +1,26 @@
+/* args.h
+ Settings for swfcombine. This is deliberately not named "config.h" to
+ avoid conflicts with GNU autoconf.
+
+ Part of the swftools package.
+
+ Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
+
+ This file is distributed under the GPL, see file COPYING for details */
+
+#ifndef __config_h__
+#define __config_h__
+struct config_t
+{
+ char overlay;
+ char alloctest;
+ char clip;
+ char stack;
+ int loglevel;
+ int movex;
+ int movey;
+ float scalex;
+ float scaley;
+};
+extern struct config_t config;
+#endif
diff --git a/src/swfcombine.1 b/src/swfcombine.1
new file mode 100644
index 00000000..d1e484e2
--- /dev/null
+++ b/src/swfcombine.1
@@ -0,0 +1,83 @@
+.TH swfcombine "1" "October 2001" "swfcombine" "swftools"
+.SH NAME
+swfcombine - a tool for combining swf (flash) files
+.SH Synopsis
+.B swfcombine
+[\fIoptions\fR] [\fImasterfile.swf\fR] [\fIslavename1=\fR][\fIslavefile1.swf\fR] ... [\fIslavenameN=\fR][\fIslavefileN.swf\fR]
+.SH DESCRIPTION
+Take two or more SWF files, and combine them into a new SWF. SWFs can either
+be stacked (no masterfile is present) or inserted (into the masterfile).
+.PP
+SWF files are animation files which can be displayed in Web Browsers using
+the Flash Plugin.
+.LP
+For template mechanisms, it's often convenient to separate the processes
+of generating small animation fragments, and merging them all into a big
+movie. swfcombine can be used to perform the latter.
+.SH OPTIONS
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+Print short help message and exit
+.\".TP
+.\" \fB\-\-version\fR
+.\" Print version info and exit
+.TP
+\fB\-o\fR, \fB\-\-output\fR \fIfilename\fR
+Explicitly specify output file. (otherwise, output.swf will be used)
+.TP
+\fB\-l\fR, \fB\-\-overlay\fR
+Don't remove any master objects, only overlay new objects.
+.TP
+\fB\-c\fR, \fB\-\-clip\fR
+Clip the slave objects by the corresponding master objects.
+.TP
+\fB\-v\fR, \fB\-\-verbose\fR
+Be verbose. Use more than one -v for greater effect.
+.TP
+\fB\-t\fR, \fB\-\-stack\fR
+Don't assume the first file is a master file. Instead, store each
+file in a seperate frame.
+.TP
+\fB\-x\fR, \fB\-\-xpos\fR \fIxpos\fR
+(move x) Adjust position of slave by xpos twips (1/20 pixel).
+.TP
+\fB\-y\fR, \fB\-\-ypos\fR \fIypos\fR
+(move y) Adjust position of slave by ypos twips (1/20 pixel).
+.TP
+\fB\-s\fR, \fB\-\-scale\fR \fIscale\fR
+(scale) Adjust size of slave by scale%
+.PP
+.SH Combining two or more .swf files using a master file
+Of the flash files to be combined, all except one will be packed into a sprite
+structure (Movieclip) which will then be inserted into the master .swf file.
+This means that, in terms of trees, when combining several flash files,
+one will form the root of the tree, while the others will be
+appended to the root as a subnode.
+The user has to specify which of the files will become the root
+of the tree ("master") and which will be the appended nodes ("slaves").
+The slave files must all have a name, which is then used to determine
+their exact position inside the master file.
+The slave files will then be converted into sprites, inserted into the
+master file, and all PlaceObject tags in the master file which match the
+name of the slave file will be updated to correctly display the slave sprite.
+.SH Combining (stacking) one or more .swf files without a master
+The flash files will be inserted in seperate frames. They will still be
+packed into Movieclips, therefore the outputfile will have exactly as many
+frames as there were inputfiles. Also, the files don't need to have names.
+If you want to access the Movieclips, their names are frameXX, where XX is
+the decimal number of the file, starting by zero (00).
+
+.SH EXAMPLES
+
+Create two flash movies. Insert some rectangle into one of them, and give
+it a name. (E.g. "foo") Now call
+
+swfcombine -o combined.swf master.swf foo:slave.swf
+
+As a result, the slave movie should be visible inside the master movie
+at the position where the rectangle used to be.
+
+.SH AUTHOR
+
+Matthias Kramm <kramm@quiss.org>
+
diff --git a/src/swfcombine.c b/src/swfcombine.c
new file mode 100644
index 00000000..77597b66
--- /dev/null
+++ b/src/swfcombine.c
@@ -0,0 +1,431 @@
+/* swfcombine.c
+ main routine for swfcombine(1), which is a tool for merging .swf-files.
+
+ Part of the swftools package.
+
+ Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
+
+ This file is distributed under the GPL, see file COPYING for details */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "args.h"
+#include "combine.h"
+#include "settings.h"
+#include "types.h"
+#include "flash.h"
+
+char * master_filename = 0;
+char * master_name = 0;
+char * slave_filename[128];
+char * slave_name[128];
+int slave_movex[128];
+int slave_movey[128];
+float slave_scalex[128];
+float slave_scaley[128];
+int numslaves = 0;
+
+char * outputname = "output.swf";
+
+int args_callback_option(char*name,char*val) {
+ if(!strcmp(name,"c"))
+ {
+ config.clip = 1;
+ return 0;
+ }
+ else if(!strcmp(name,"l"))
+ {
+ config.overlay = 1;
+ return 0;
+ }
+ else if (!strcmp(name, "o"))
+ {
+ outputname = val;
+ return 1;
+ }
+ else if (!strcmp(name, "v"))
+ {
+ config.loglevel ++;
+ return 0;
+ }
+ else if (!strcmp(name, "a"))
+ {
+ config.alloctest = 1;
+ return 0;
+ }
+ else if (!strcmp(name, "x"))
+ {
+ config.movex = atoi(val);
+ return 1;
+ }
+ else if (!strcmp(name, "y"))
+ {
+ config.movey = atoi(val);
+ return 1;
+ }
+ else if (!strcmp(name, "s"))
+ {
+ config.scalex = config.scaley = atoi(val)/100.0;
+ return 1;
+ }
+ else if (!strcmp(name, "t"))
+ {
+ if(master_filename) {
+ fprintf(stderr, "error with arguments. Try --help.\n");
+ exit(1);
+ }
+ config.stack = 1;
+ master_filename = "__none__";
+ return 0;
+ }
+ else if (!strcmp(name, "V"))
+ {
+ printf("swfcombine - part of swftools 0.0.1\n");
+ exit(0);
+ }
+ else
+ {
+ fprintf(stderr, "Unknown option: -%s\n", name);
+ exit(1);
+ }
+}
+
+struct options_t
+{
+ char*shortoption;
+ char*longoption;
+} options[] =
+{{"o","output"},
+ {"s","scale"},
+ {"x","xpos"},
+ {"y","ypos"},
+ {"l","overlay"},
+ {"v","verbose"},
+ {"V","version"},
+ {"c","clip"},
+};
+
+int args_callback_longoption(char*name,char*val) {
+ int t;
+ for(t=0;t<sizeof(options)/sizeof(struct options_t);t++)
+ if(!strcmp(options[t].longoption, name))
+ return args_callback_option(options[t].shortoption,val);
+ fprintf(stderr, "Unknown option: --%s\n", name);
+ exit(1);
+}
+
+int args_callback_command(char*name, char*val) {
+ char*myname = strdup(name);
+ char*filename;
+ filename = strchr(myname, '=');
+ if(filename) {
+ *filename = 0;
+ filename++;
+ } else {
+ // argument has no explicit name field. guess one from the file name
+ char*path = strrchr(myname, '/');
+ char*ext = strrchr(myname, '.');
+ if(!path) path = myname;
+ else path ++;
+ if(ext) *ext = 0;
+ myname = path;
+ filename = name;
+ }
+
+ if(!master_filename) {
+
+ master_filename = filename;
+ master_name = myname;
+ } else {
+ logf("<verbose> slave entity %s (named \"%s\")\n", filename, myname);
+
+ slave_filename[numslaves] = filename;
+ slave_name[numslaves] = myname;
+ slave_movex[numslaves] = config.movex;
+ slave_movey[numslaves] = config.movey;
+ slave_scalex[numslaves] = config.scalex;
+ slave_scaley[numslaves] = config.scaley;
+ config.movex = config.movey = 0;
+ config.scalex = config.scaley = 1.0;
+ numslaves ++;
+ }
+ return 0;
+}
+
+void args_callback_usage(char*name)
+{
+ printf("Usage: %s [-l] [-o outputfile] [name=]masterfile [-x xpos] [-y ypos] [-s scale] [name1=]slavefile1 .. [-x xpos] [-y ypos] [-s scale] [nameN=]slavefileN\n", name);
+ printf("\n");
+ printf("-o outputfile explicitly specify output file. (otherwise, output.swf will be used)\n");
+ printf("-l (overlay) Don't remove any master objects, only overlay new objects\n");
+ printf("-c (clip) Clip the slave objects by the corresponding master objects\n");
+ printf("-v (verbose) Use more than one -v for greater effect \n");
+ printf("-x xpos (move x) Adjust position of slave by xpos twips (1/20 pixel)\n");
+ printf("-y ypos (move y) Adjust position of slave by ypos twips (1/20 pixel)\n");
+ printf("-s scale (scale) Adjust size of slave by scale%\n");
+ printf("\n");
+}
+
+/* read a whole file in memory */
+char* fi_slurp(FILE*fi, unsigned int * setlength)
+{
+ char * mem;
+ long long int length; //;)
+ long long int pos = 0;
+ fseek(fi,0,SEEK_END);
+ length = ftell(fi);
+ fseek(fi,0,SEEK_SET);
+ if(!length)
+ return 0;
+ mem = malloc(length);
+ if(!mem)
+ return 0;
+ while(!feof(fi))
+ {
+ pos += fread(&mem[pos], 1, 65536, fi);
+ }
+ if (setlength)
+ *setlength = length;
+ return mem;
+}
+
+void fi_dump(FILE*fi, void*_mem, int length)
+{
+ char*mem = (char*)_mem;
+ int pos = 0;
+ while(pos < length)
+ {
+ int size = 65536;
+ if (size > (length - pos))
+ size = (length - pos);
+ pos += fwrite(&mem[pos], 1, size, fi);
+ }
+}
+
+void makestackmaster(u8**masterdata, int*masterlength)
+{
+ u8 head[] = {'F','W','S'};
+ u8 *pos;
+ u32 * fixpos;
+ int t;
+ struct RECT box;
+ int strlength = 0;
+ int fileversion = 1;
+
+ logf("<error> stacking doesn't work yet. Prepare for problems.");
+
+ /* scan all slaves for bounding box */
+ for(t=0;t<numslaves;t++)
+ {
+ FILE*fi=fopen(slave_filename[t],"rb");
+ u8 data[256];
+ int ret;
+ struct flash_header head;
+ strlength += strlen(slave_name[t]) + 9;
+ if(!fi) {
+ logf("<fatal> Couldn't open %s.", slave_filename[t]);
+ exit(1);
+ }
+ ret = fread(data,1,256,fi);
+ if(ret < 13) {
+ logf("<fatal> File %s is to small (%d bytes)", slave_filename[t], ret);
+ exit(1);
+ }
+ swf_init(data,256);
+ head = swf_read_header();
+ logf("<verbose> File %s has bounding box %d:%d:%d:%d\n",
+ slave_filename[t],
+ head.boundingBox.x1, head.boundingBox.y1,
+ head.boundingBox.x2, head.boundingBox.y2);
+ if(head.version > fileversion)
+ fileversion = head.version;
+ if(!t)
+ box = head.boundingBox;
+ else {
+ if(head.boundingBox.x1 < box.x1)
+ box.x1 = head.boundingBox.x1;
+ if(head.boundingBox.y1 < box.y1)
+ box.y1 = head.boundingBox.y1;
+ if(head.boundingBox.x2 > box.x2)
+ box.x2 = head.boundingBox.x2;
+ if(head.boundingBox.y2 > box.y2)
+ box.y2 = head.boundingBox.y2;
+ }
+ logf("<verbose> New master bounding box is %d:%d:%d:%d\n",
+ box.x1, box.y1,
+ box.x2, box.y2);
+ fclose(fi);
+ }
+
+ /* we don't have a master, so we create one ourselves. */
+ /* (please notice the philosophical content) */
+ *masterlength = (numslaves + 1) * 32 + strlength;
+ *masterdata = (u8*)malloc(*masterlength);
+ pos = *masterdata;
+ memcpy(pos, head, sizeof(head));
+ pos += sizeof(head);
+ *pos++ = fileversion;
+ fixpos = (u32*)pos;
+ *(u32*)pos = 0x12345678; // to be overwritten
+ pos += 4;
+ writeRECT(&pos, &box);
+ *(u16*)pos = 0x2000; // framerate
+ pos += 2;
+ *(u16*)pos = numslaves;
+ pos += 2;
+ for(t=0;t<numslaves;t++)
+ {
+ char buf[128];
+ int namelen;
+
+ if(1) {
+ sprintf(buf, "Frame%02d", t);
+ slave_name[t] = strdup(buf);
+ }
+ namelen = strlen(slave_name[t]);
+
+ *(u16*)&pos[0] = (u16)(TAGID_DEFINESPRITE<<6) + 6;
+ *(u16*)&pos[2] = t+1; //ID
+ *(u16*)&pos[4] = 0; // Frames
+ *(u16*)&pos[6] = 0; // TAG1
+ *(u16*)&pos[8] = (u16)(TAGID_PLACEOBJECT2<<6) + 6 + namelen;
+ *(u16*)&pos[10]= 34; //flags: id+name
+ *(u16*)&pos[11]= 1; // depth
+ *(u16*)&pos[13]= t+1; // id
+ sprintf(&pos[15],slave_name[t]);
+ pos += 15 + namelen + 1;
+ *(u16*)&pos[0]= (u16)(TAGID_SHOWFRAME<<6) + 0;
+ pos += 2;
+ if(t!=numslaves-1)
+ {
+ *(u16*)&pos[0]= (u16)(TAGID_REMOVEOBJECT2<<6) + 2;
+ *(u16*)&pos[2]= 1; // depth;
+ pos += 4;
+ }
+ }
+ *(u16*)pos = TAGID_END<<6 + 0;
+ *masterlength = pos - *masterdata;
+ *fixpos = *masterlength;
+}
+
+struct config_t config;
+int main(int argn, char *argv[])
+{
+ FILE*fi;
+ u8*masterdata;
+ unsigned int masterlength;
+ u8*slavedata;
+ unsigned int slavelength;
+ u8*newdata;
+ unsigned int newlength;
+ int t;
+
+ config.overlay = 0;
+ config.alloctest = 0;
+ config.clip = 0;
+ config.loglevel = 2;
+ config.movex = 0;
+ config.movey = 0;
+ config.scalex = 1.0;
+ config.scaley = 1.0;
+ config.stack = 0;
+
+ processargs(argn, argv);
+ initLog(0,-1,0,0,-1,config.loglevel);
+
+ if(config.stack) {
+
+ if(config.overlay) {
+ logf("<error> Can't combine -l and -t");
+ exit(1);
+ }
+ if(config.clip) {
+ logf("<error> Can't combine -c and -t");
+ exit(1);
+ }
+ logf("<verbose> (stacking) %d files found\n", numslaves);
+
+ makestackmaster(&masterdata,&masterlength);
+
+ logf("<verbose> Generated %d bytes of master data", masterlength);
+ }
+ else {
+ logf("<verbose> master entity %s (named \"%s\")\n", master_filename, master_name);
+ fi = fopen(master_filename, "rb");
+ if(!fi) {
+ fprintf(stderr, "Failed to open %s\n", master_filename);
+ return 1;
+ }
+ masterdata = fi_slurp(fi, &masterlength);
+ if(!masterdata) {
+ fprintf(stderr, "Failed to read from %s\n", master_filename);
+ return 1;
+ }
+ logf("<debug> Read %d bytes from masterfile\n", masterlength);
+ fclose(fi);
+ }
+
+ for(t=0;t<numslaves;t++)
+ logf("<verbose> slave entity(%d) %s (named \"%s\")\n", t+1, slave_filename[t], slave_name[t]);
+
+ if (config.alloctest)
+ {
+ int*bitmap = malloc(sizeof(int)*65536);
+ memset(bitmap, -1, 65536*sizeof(int));
+ memset(bitmap, 1, 101*sizeof(int));
+ swf_relocate(masterdata, masterlength, bitmap);
+ newdata = masterdata;
+ newlength = masterlength;
+ free(bitmap);
+ }
+ else
+ {
+ if (!numslaves)
+ {
+ logf("<error> You must have at least one slave entity.");
+ return 0;
+ }
+ for(t = 0; t < numslaves; t++)
+ {
+ config.movex = slave_movex[t];
+ config.movey = slave_movey[t];
+ config.scalex = slave_scalex[t];
+ config.scaley = slave_scaley[t];
+
+ logf("<notice> Combine [%s]%s and [%s]%s", master_name, master_filename,
+ slave_name[t], slave_filename[t]);
+ fi = fopen(slave_filename[t], "rb");
+ if(!fi) {
+ fprintf(stderr, "Failed to open %s\n", slave_filename[t]);
+ return 1;
+ }
+ slavedata = fi_slurp(fi, &slavelength);
+ if(!slavedata) {
+ fprintf(stderr, "Failed to read from %s\n", slave_filename[t]);
+ return 1;
+ }
+ logf("<debug> Read %d bytes from slavefile\n", slavelength);
+ fclose(fi);
+
+ newdata = combine(masterdata, masterlength, slave_name[t], slavedata, slavelength, &newlength);
+ if(!newdata) {
+ logf("<fatal> Aborting.");
+ return 1;
+ }
+
+ free(masterdata);
+ masterdata = newdata;
+ masterlength = newlength;
+ }
+ }
+
+ logf("<debug> New File is %d bytes \n", newlength);
+ if(newdata && newlength) {
+ FILE*fi = fopen(outputname, "wb");
+ fi_dump(fi, newdata, newlength);
+ fclose(fi);
+ }
+ return 0;
+}
+
diff --git a/src/swfdump.1 b/src/swfdump.1
new file mode 100644
index 00000000..0918cb16
--- /dev/null
+++ b/src/swfdump.1
@@ -0,0 +1,23 @@
+.TH swfdump "1" "October 2001" "swfdump" "swftools"
+.SH NAME
+swfdump - a tool for displaying information about flash files
+.SH Synopsis
+.B swfdump
+[\fIoptions\fR] [\fIfile.swf\fR]
+.SH DESCRIPTION
+swfdump shows ids, names and depths of objects defined in the SWF file.
+.PP
+SWF files are animation files which can be displayed in Web Browsers using
+the Flash Plugin.
+.SH OPTIONS
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+Print short help message and exit
+.\".TP
+.\" \fB\-\-version\fR
+.\" Print version info and exit
+
+.SH AUTHOR
+
+Matthias Kramm <kramm@quiss.org>
+
diff --git a/src/swfdump.c b/src/swfdump.c
new file mode 100644
index 00000000..fc9fda1b
--- /dev/null
+++ b/src/swfdump.c
@@ -0,0 +1,109 @@
+/* swfdump.c
+ Shows the structure of a swf file
+
+ Part of the swftools package.
+
+ Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
+
+ This file is distributed under the GPL, see file COPYING for details */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include "../lib/rfxswf.h"
+#include "args.h"
+
+char * filename = 0;
+
+/* idtab stores the ids which are defined in the file. This allows us
+ to detect errors in the file. (i.e. ids which are defined more than
+ once */
+char idtab[65536];
+
+int args_callback_option(char*name,char*val)
+{
+}
+int args_callback_longoption(char*name,char*val)
+{
+}
+void args_callback_usage(char*name)
+{
+ printf("Usage: %s file.swf\n", name);
+ printf("\n");
+}
+int args_callback_command(char*name,char*val)
+{
+ if(filename) {
+ fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
+ filename, name);
+ }
+ filename = name;
+ return 0;
+}
+
+int main (int argc,char ** argv)
+{
+ SWF swf;
+ TAG*tag;
+ int f;
+ char prefix[128];
+ prefix[0] = 0;
+ memset(idtab,0,65536);
+
+ processargs(argc, argv);
+
+ f = open(filename,O_RDONLY);
+
+ if (f<0)
+ {
+ perror("Couldn't open file: ");
+ exit(1);
+ }
+ if FAILED(ReadSWF(f,&swf))
+ {
+ fprintf(stderr,"%s is not a valid SWF file or contains errors.\n",filename);
+ close(f);
+ exit(1);
+ }
+ close(f);
+
+ tag = swf.FirstTag;
+
+ while(tag) {
+ printf("[%02x] %s%s", tag->id, prefix, getTagName(tag));
+ if(isDefiningTag(tag)) {
+ U16 id = GetDefineID(tag);
+ printf(" defines id %04x", id);
+ if(idtab[id])
+ fprintf(stderr, "Error: Id %04x is defined more than once.\n", id);
+ idtab[id] = 1;
+ }
+ else if(tag->id == ST_PLACEOBJECT ||
+ tag->id == ST_PLACEOBJECT2) {
+ printf(" places id %04x at depth %04x", GetPlaceID(tag), GetDepth(tag));
+ if(GetName(tag))
+ printf(" name \"%s\"",GetName(tag));
+ }
+ else if(tag->id == ST_REMOVEOBJECT) {
+ printf(" removes id %04x from depth %04x", GetPlaceID(tag), GetDepth(tag));
+ }
+ else if(tag->id == ST_REMOVEOBJECT2) {
+ printf(" removes object from depth %04x", GetDepth(tag));
+ }
+
+ printf("\n");
+
+ if(tag->id == ST_DEFINESPRITE)
+ {
+ sprintf(prefix, " ");
+ }
+ if(tag->id == ST_END)
+ {
+ sprintf(prefix, "");
+ }
+ tag = tag->next;
+ }
+
+ FreeTags(&swf);
+ return 0;
+}
+
diff --git a/src/swfstrings.1 b/src/swfstrings.1
new file mode 100644
index 00000000..0ab12a7b
--- /dev/null
+++ b/src/swfstrings.1
@@ -0,0 +1,24 @@
+.TH swfstrings "1" "October 2001" "swfstrings" "swftools"
+.SH NAME
+swfstrings - a tool for extracting text out of swf files.
+.SH Synopsis
+.B swfstrings
+[\fIoptions\fR] [\fIfile.swf\fR]
+.SH DESCRIPTION
+swfstrings extracts text out of DEFINETEXT tags of the .swf file. It also
+displays the fonts being used.
+.PP
+SWF files are animation files which can be displayed in Web Browsers using
+the Flash Plugin.
+.SH OPTIONS
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+Print short help message and exit
+.\".TP
+.\" \fB\-\-version\fR
+.\" Print version info and exit
+
+.SH AUTHOR
+
+Rainer Böhme <rfxswf@reflex-studio.de>
+
diff --git a/src/swfstrings.c b/src/swfstrings.c
new file mode 100644
index 00000000..2bf1d9a8
--- /dev/null
+++ b/src/swfstrings.c
@@ -0,0 +1,54 @@
+/* swfstrings.c
+ Scans a swf file for strings
+
+ Part of the swftools package.
+
+ Copyright (c) 2000,2001 Rainer Böhme <rfxswf@reflex-studio.de>
+
+ This file is distributed under the GPL, see file COPYING for details */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include "../lib/rfxswf.h"
+
+SWF swf;
+
+void fontcallback(U16 id,U8 * name)
+{ LPSWFFONT font;
+ LPTAG t;
+
+ FontExtract(&swf,id,&font);
+ printf("#< %s %s %s>\n",name,FontIsBold(font)?"bold":"",FontIsItalic(font)?"italic":"");
+
+ t = swf.FirstTag;
+
+ while (t)
+ { TextPrintDefineText(t,font);
+ t = NextTag(t);
+ }
+
+ FontFree(font);
+}
+
+int main (int argc,char ** argv)
+{ int f;
+
+ if (argc>1)
+ { f = open(argv[1],O_RDONLY);
+ if (f>=0)
+ { if FAILED(ReadSWF(f,&swf))
+ { fprintf(stderr,"%s is not a valid SWF file or contains errors.\n",argv[1]);
+ close(f);
+ }
+ else
+ { close(f);
+ FontEnumerate(&swf,&fontcallback);
+ FreeTags(&swf);
+ }
+ } else fprintf(stderr,"File not found: %s\n",argv[1]);
+ }
+ else fprintf(stderr,"\nreflex SWF Text Scan Utility\n(w) 2000 by Rainer Boehme <rb@reflex-studio.de>\n\nUsage: %s filename.swf\n", argv[0]);
+
+ return 0;
+}
+
diff --git a/src/types.h b/src/types.h
new file mode 100644
index 00000000..a5b540d7
--- /dev/null
+++ b/src/types.h
@@ -0,0 +1,33 @@
+/* types.h
+ Some typedefs to make life simpler. If this file causes you problems, you might
+ try to remove all #include "types.h" and live with what configure does define.
+
+ Part of the swftools package.
+
+ Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
+
+ This file is distributed under the GPL, see file COPYING for details */
+
+#ifndef __types_h__
+#define __types_h__
+typedef long unsigned w32;
+typedef short unsigned w16;
+typedef unsigned char u8;
+typedef signed char s8;
+typedef short unsigned u16;
+typedef short signed s16;
+typedef long unsigned u32;
+typedef long signed s32;
+typedef long long unsigned u64;
+typedef long long signed s64;
+typedef unsigned char byte;
+typedef unsigned char uchar;
+typedef signed char sbyte;
+typedef unsigned short int word;
+typedef signed short int sword;
+typedef unsigned long int dword;
+typedef signed long int sdword;
+typedef signed short int integer;
+typedef signed long int longint;
+typedef long double extended;
+#endif // __types_h__