+void code_write(TAG*tag, code_t*code, pool_t*pool, abc_file_t*file)
+{
+ code = code_start(code);
+ int pos = 0;
+ int length = 0;
+ code_t*c = code;
+ while(c) {
+ c->pos = pos;
+ pos += opcode_write(0, c, pool, file, 0);
+ c = c->next;
+ }
+ length = pos;
+ swf_SetU30(tag, pos);
+ int start = tag->len;
+ c = code;
+ pos = 0;
+ while(c) {
+ opcode_t*op = opcode_get(code->opcode);
+ if(op->flags&(OP_BRANCH|OP_JUMP)) {
+ int skip = 0;
+ }
+ pos += opcode_write(tag, c, pool, file, length);
+ c = c->next;
+ }
+ assert(tag->len - start == pos);
+}
+
+typedef struct {
+ int stackpos;
+ int scopepos;
+ code_t*code;
+ char flags;
+ char error;
+} stackpos_t;
+
+typedef struct {
+ stackpos_t*stack;
+ int num;
+ int maxlocal;
+ int maxstack;
+ int maxscope;
+ int flags;
+} currentstats_t;
+
+static int stack_minus(code_t*c)
+{
+ opcode_t*op = opcode_get(c->opcode);
+ if(op->stack_minus>0) {
+ fprintf(stderr, "Invalid opcode entry %02x %s\n", c->opcode, op->name);
+ }
+ int stack = op->stack_minus;
+ if(op->flags&OP_STACK_NS) {
+ multiname_t*m = (multiname_t*)c->data[0];
+ if(multiname_late_namespace(m))
+ stack--;
+ if(multiname_late_name(m))
+ stack--;
+ }
+ if(op->flags&OP_STACK_ARGS || op->flags&OP_STACK_ARGS2) {
+ assert(strchr(op->params, 'n'));
+ int nr = (ptroff_t)(op->params[0]=='n'?c->data[0]:c->data[1]);
+ stack-=nr;
+ if(op->flags&OP_STACK_ARGS2)
+ stack-=nr;
+ }
+ return stack;
+}
+static void handleregister(currentstats_t*stats, int reg)
+{
+ if(reg+1 > stats->maxlocal)
+ stats->maxlocal = reg+1;
+}
+
+#define FLAG_SEEN 1
+#define FLAG_ERROR 2
+
+static void dumpstack(currentstats_t*stats)
+{
+ int t;
+ for(t=0;t<stats->num;t++) {
+ code_t*c = stats->stack[t].code;
+ opcode_t*op = opcode_get(c->opcode);
+ printf("%05d) %c %d:%d %s", t, (stats->stack[t].flags&FLAG_SEEN)?'x':'|',
+ stats->stack[t].stackpos,
+ stats->stack[t].scopepos,
+ op->name);
+
+ if(op->flags&(OP_BRANCH|OP_JUMP)) {
+ if(c->branch)
+ printf(" ->%d\n", c->branch->pos);
+ else
+ printf(" 00000000\n");
+ }
+ if(op->params[0]=='2') {
+ printf(" %s", multiname_tostring(c->data[0]));
+ } else if(op->params[0]=='N') {
+ printf(" %s", namespace_tostring(c->data[0]));
+ }
+ printf("\n");
+ }
+}
+
+static char callcode(currentstats_t*stats, int pos, int stack, int scope)
+{
+ while(pos<stats->num) {
+ if(stats->stack[pos].flags&FLAG_SEEN) {
+ if(stats->stack[pos].stackpos != stack ||
+ stats->stack[pos].scopepos != scope) {
+ //dumpstack(stats);
+ stats->stack[pos].flags |= FLAG_ERROR;
+ fprintf(stderr, "Stack mismatch at pos %d\n", pos);
+ fprintf(stderr, "Should be: %d:%d, is: %d:%d\n", stack, scope,
+ stats->stack[pos].stackpos, stats->stack[pos].scopepos);
+
+ /* return error here if we do verification */
+ //return 0;
+ }
+ return 1;
+ }
+
+ stats->stack[pos].flags |= FLAG_SEEN;
+ stats->stack[pos].stackpos = stack;
+ stats->stack[pos].scopepos = scope;
+
+ code_t*c = stats->stack[pos].code;
+ opcode_t*op = opcode_get(c->opcode);
+
+ //printf("Walking %s at position %d, stack=%d, scope=%d\n", op->name, pos, stack, scope);
+
+ stack += stack_minus(c);
+
+ if(stack<0) {
+ stats->stack[pos].flags |= FLAG_ERROR;
+ fprintf(stderr, "error: stack underflow at %d (%s)\n", pos, op->name);
+
+ /* if we would do true verification (if we would be a vm), this is
+ where we would return the error
+ return 0;
+ */
+ }
+
+ stack += op->stack_plus;
+ scope += op->scope_stack_plus;
+
+ if(stack > stats->maxstack)
+ stats->maxstack = stack;
+ if(scope > stats->maxscope)
+ stats->maxscope = scope;
+
+ if(op->flags & OP_SET_DXNS)
+ stats->flags |= FLAGS_SET_DXNS;
+ if(op->flags & OP_NEED_ACTIVATION)
+ stats->flags |= FLAGS_ACTIVATION;
+
+ if(c->opcode == OPCODE_NEWCLASS) {
+ abc_class_t*cls = (abc_class_t*)(c->data[0]);
+ if(scope > cls->init_scope_depth)
+ cls->init_scope_depth = scope;
+ }
+ if(c->opcode == OPCODE_NEWFUNCTION) {
+ abc_method_t*m = (abc_method_t*)(c->data[0]);
+ if(m->body && scope > m->body->init_scope_depth)
+ m->body->init_scope_depth = scope;
+ }
+
+ if(op->flags & OP_REGISTER) {
+ char*p = op->params;
+ int pos = 0;
+ char ok=0;
+ while(*p) {
+ if(*p=='r') {
+ handleregister(stats, (ptroff_t)c->data[pos]);
+ ok = 1;
+ }
+ p++;
+ }
+ if(!ok) {
+ handleregister(stats, c->opcode&3);
+ }
+ }
+ if(op->flags&OP_RETURN) {
+ if(OP_RETURN==0x48/*returnvalue*/) {
+ if(stack!=1) {
+ stats->stack[pos].flags |= FLAG_ERROR;
+ fprintf(stderr, "return(value) with stackposition %d\n", stack);
+ }
+ } else if(OP_RETURN==0x47) {
+ if(stack!=0) {
+ stats->stack[pos].flags |= FLAG_ERROR;
+ fprintf(stderr, "return(void) with stackposition %d\n", stack);
+ }
+ }
+ }
+ if(op->flags & (OP_THROW|OP_RETURN))
+ return 1;
+ if(op->flags & OP_JUMP) {
+ if(!c->branch) {
+ stats->stack[pos].flags |= FLAG_ERROR;
+ fprintf(stderr, "Error: Invalid jump target in instruction %s at position %d.\n", op->name, pos);
+ return 0;
+ }
+ c = c->branch;
+ pos = c->pos;
+ continue;
+ }
+ if(op->flags & OP_BRANCH) {
+ if(!c->branch) {
+ stats->stack[pos].flags |= FLAG_ERROR;
+ fprintf(stderr, "Error: Invalid jump target in instruction %s at position %d\n", op->name, pos);
+ return 0;
+ }
+ int newpos = c->branch->pos;
+ if(!callcode(stats, newpos, stack, scope))
+ return 0;
+ }
+ if(op->flags & OP_LOOKUPSWITCH) {
+ lookupswitch_t*l = c->data[0];
+ if(!l->def) {
+ stats->stack[pos].flags |= FLAG_ERROR;
+ fprintf(stderr, "Error: Invalid jump target in instruction %s at position %d\n", op->name, pos);
+ return 0;
+ }
+ if(!callcode(stats, l->def->pos, stack, scope))
+ return 0;
+ code_list_t*t = l->targets;
+ while(t) {
+ if(!t->code) {
+ stats->stack[pos].flags |= FLAG_ERROR;
+ fprintf(stderr, "Error: Invalid jump target in instruction %s at position %d\n", op->name, pos);
+ return 0;
+ }
+ if(!callcode(stats, t->code->pos, stack, scope))
+ return 0;
+ t = t->next;
+ }
+ }
+
+ pos++;
+ if(pos<stats->num) {
+ assert(c->next == stats->stack[pos].code);
+ }
+ }
+ return 1;
+}
+
+static currentstats_t* code_get_stats(code_t*code, abc_exception_list_t*exceptions)
+{
+ code = code_start(code);
+ int num = 0;
+ code_t*c = code;
+ while(c) {
+ num++;
+ c = c->next;
+ }
+ currentstats_t* current = malloc(sizeof(currentstats_t));
+ current->stack = rfx_calloc(sizeof(stackpos_t)*num);
+ current->maxlocal = 0;
+ current->maxstack = 0;
+ current->maxscope = 0;
+ current->num = num;
+ current->flags = 0;
+
+//#define DEBUG_BYTES
+#ifdef DEBUG_BYTES
+ int t;
+ c = code;
+ for(t=0;t<num;t++) {
+ opcode_t*op = opcode_get(c->opcode);
+ if(op->flags & (OP_JUMP|OP_BRANCH)) {
+ printf("%05d) %s %08x\n", t, op->name, c->branch);
+ } else if(op->params[0]=='2') {
+ printf("%05d) %s %s\n", t, op->name, multiname_tostring(c->data[0]));
+ } else if(op->params[0]=='N') {
+ printf("%05d) %s %s\n", t, op->name, namespace_tostring(c->data[0]));
+ } else {
+ printf("%05d) %s\n", t, op->name);
+ }
+ c = c->next;
+ }
+ //printf("%05d) %02x\n", t, tag->data[start+t]);
+#endif
+
+ num = 0;
+ c = code;
+ while(c) {
+ //crosslink
+ current->stack[num].code = c;
+ c->pos = num;
+ num++;
+ c = c->next;
+ }
+
+ if(!callcode(current, 0, 0, 0)) {
+ free(current);
+ return 0;
+ }
+ abc_exception_list_t*e = exceptions;
+ while(e) {
+ if(e->abc_exception->target)
+ callcode(current, e->abc_exception->target->pos, 1, 0);
+ e = e->next;
+ }
+
+ return current;
+}
+
+void stats_free(currentstats_t*stats)
+{
+ if(stats) {
+ free(stats->stack);stats->stack=0;
+ free(stats);
+ }
+}
+
+int code_dump(code_t*c)
+{
+ code_t*cc = code_start(c);
+ while(cc) {
+ assert(!cc->next || cc->next->prev == cc);
+ cc = cc->next;
+ }
+
+ return code_dump2(c, 0, 0, "", stdout);
+}
+int code_dump2(code_t*c, abc_exception_list_t*exceptions, abc_file_t*file, char*prefix, FILE*fo)
+{
+ abc_exception_list_t*e = exceptions;
+ c = code_start(c);
+ currentstats_t*stats = code_get_stats(c, exceptions);
+
+ int pos = 0;