+static int opcode_write(TAG*tag, code_t*c, pool_t*pool, abc_file_t*file, int length)
+{
+ opcode_t*op = opcode_get(c->opcode);
+ char*p = op->params;
+ int pos = 0;
+ int len = 0;
+
+ if(tag)
+ swf_SetU8(tag, c->opcode);
+ len++;
+
+ if(op->flags & OP_INTERNAL) {
+ if(c->opcode == OPCODE___BREAK__ ||
+ c->opcode == OPCODE___CONTINUE__) {
+ fprintf(stderr, "Unresolved %s\n", op->name);
+ } else {
+ fprintf(stderr, "Error: writing undefined internal opcode %s\n", op->name);
+ }
+ }
+
+ while(*p) {
+ void*data = c->data[pos++];
+ assert(pos<=2);
+ if(*p == 'n') { // number
+ len += swf_SetU30(tag, (ptroff_t)data);
+ } else if(*p == '2') { //multiname
+ multiname_t*m = (multiname_t*)data;
+ len += swf_SetU30(tag, pool_register_multiname(pool, m));
+ } else if(*p == 'm') { //method
+ abc_method_t*m = (abc_method_t*)data;
+ len += swf_SetU30(tag, m->index);
+ } else if(*p == 'c') { //classinfo
+ abc_class_t*cls = (abc_class_t*)data;
+ len += swf_SetU30(tag, cls->index);
+ } else if(*p == 'i') { //methodbody
+ abc_method_body_t*m = (abc_method_body_t*)data;
+ len += swf_SetU30(tag, m->index);
+ } else if(*p == 'I') { // int
+ len += swf_SetU30(tag, pool_register_int(pool, (ptroff_t)data));
+ } else if(*p == 'U') { // uint
+ len += swf_SetU30(tag, pool_register_uint(pool, (ptroff_t)data));
+ } else if(*p == 'f') { // float
+ len += swf_SetU30(tag, pool_register_float(pool, *(double*)data));
+ } else if(*p == 'u') { // integer
+ len += swf_SetU30(tag, (ptroff_t)data);
+ } else if(*p == 'r') { // integer
+ len += swf_SetU30(tag, (ptroff_t)data);
+ } else if(*p == 'b') { // byte
+ if(tag)
+ swf_SetU8(tag, (ptroff_t)data);
+ len++;
+ } else if(*p == 'j') { // jump
+ int skip = length-c->pos-4;
+ if(c->branch)
+ skip = (c->branch->pos) - c->pos - 4;
+ len += swf_SetS24(tag, skip);
+ } else if(*p == 's') { // string
+ int index = pool_register_string2(pool, (string_t*)data);
+ len += swf_SetU30(tag, index);
+ } else if(*p == 'D') { // debug statement
+ if(tag)
+ swf_SetU8(tag, 1);
+ len++;
+ len+=swf_SetU30(tag, pool_register_string(pool,c->data[0]));
+ if(tag)
+ swf_SetU8(tag, (ptroff_t)c->data[1]);
+ len++;
+ len+=swf_SetU30(tag, 0);
+ } else if(*p == 'S') { // switch statement
+ lookupswitch_t*l = (lookupswitch_t*)data;
+ int offset = 0;
+ len+=swf_SetS24(tag, l->def->pos-c->pos+offset); //default
+ code_list_t*t = l->targets;
+ if(list_length(t)) {
+ len+=swf_SetU30(tag, list_length(t)-1); //nr-1
+ code_list_t*t = l->targets;
+ while(t) {
+ len+=swf_SetS24(tag, t->code->pos - c->pos+offset);
+ t = t->next;
+ }
+ } else {
+ len+=swf_SetU30(tag, 0); //nr-1
+ len+=swf_SetS24(tag, l->def->pos-c->pos+offset);
+ }
+ } else {
+ printf("Can't parse opcode param type \"%c\"\n", *p);
+ }
+ p++;
+ }
+ return len;
+}
+
+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("%5d) %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]));
+ }
+ 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)