void membuf_printf(struct membuf *sb, const char *format, ...) { int pos; int printed; va_list args; pos = sb->len; va_start(args, format); printed = vsnprintf((char*)membuf_get(sb) + pos, sb->size - pos, format, args); va_end(args); if (printed >= sb->size - pos) { va_list args2; membuf_atleast(sb, pos + printed + 1); va_start(args2, format); printed = vsnprintf((char*)membuf_get(sb) + pos, sb->size - pos, format, args2); va_end(args2); } sb->len += printed; }
void decrunch_backwards(int level, struct membuf *inbuf, struct membuf *outbuf) { int outpos; reverse_buffer(membuf_get(inbuf), membuf_memlen(inbuf)); outpos = membuf_memlen(outbuf); decrunch(level, inbuf, outbuf); reverse_buffer(membuf_get(inbuf), membuf_memlen(inbuf)); reverse_buffer((char*)membuf_get(outbuf) + outpos, membuf_memlen(outbuf) - outpos); }
void crunch(struct membuf *inbuf, struct membuf *outbuf, struct crunch_options *options, /* IN */ struct crunch_info *info) /* OUT */ { int outpos; reverse_buffer(membuf_get(inbuf), membuf_memlen(inbuf)); outpos = membuf_memlen(outbuf); crunch_backwards(inbuf, outbuf, options, info); reverse_buffer(membuf_get(inbuf), membuf_memlen(inbuf)); reverse_buffer((char*)membuf_get(outbuf) + outpos, membuf_memlen(outbuf) - outpos); }
struct expr *new_expr_incword(const char *name, struct expr *skip) { i32 word; i32 offset; long length; struct membuf *in; struct expr *expr; unsigned char *p; offset = resolve_expr(skip); in = get_named_buffer(s->named_buffer, name); length = membuf_memlen(in); if(offset < 0) { offset += length; } if(offset < 0 || offset > length - 2) { LOG(LOG_ERROR, ("Can't read word from offset %d in file \"%s\".\n", offset, name)); exit(-1); } p = membuf_get(in); p += offset; word = *p++; word |= *p++ << 8; expr = new_expr_number(word); return expr; }
unsigned int write_track_block(TZX_FILE *pTZXfile, struct membuf tracks[], int first_track, int last_track) { char blockbuf[MAX_BLOCK_SIZE]; int track; int track_count = last_track - first_track + 1; int block_ptr = (track_count+1) * 2; // space for pointer table at start plus 0x0000 terminator int block_tbl_ptr = 0; printf("writing tracks %d-%d\n", first_track, last_track); memset(blockbuf, 0, MAX_BLOCK_SIZE); for (track = first_track; track <= last_track; track++) { int track_len = membuf_memlen(&tracks[track]); if (track_len > 0) // skip null tracks { memcpy(blockbuf+block_ptr, membuf_get(&tracks[track]), track_len); blockbuf[block_tbl_ptr++] = block_ptr & 0xff; blockbuf[block_tbl_ptr++] = block_ptr >> 8; membuf_free(&tracks[track]); block_ptr += track_len; } }
void write_file(const char *name, struct membuf *buf) { FILE *out; out = fopen(name, "wb"); if(out == NULL) { LOG(LOG_ERROR, ("Can't open file \"%s\" for output.\n", name)); exit(-1); } fwrite(membuf_get(buf), 1, membuf_memlen(buf), out); fclose(out); }
char * dec_ctx_init(struct dec_ctx *ctx, struct membuf *inbuf, struct membuf *outbuf) { char *encoding; ctx->bits_read = 0; ctx->inbuf = membuf_get(inbuf); ctx->inend = membuf_memlen(inbuf); ctx->inpos = 0; ctx->outbuf = outbuf; /* init bitbuf */ ctx->bitbuf = get_byte(ctx); /* init tables */ table_init(ctx, ctx->t); encoding = table_dump(ctx->t); return encoding; }
static int do_load(char *file_name, struct membuf *mem) { struct load_info info[1]; unsigned char *p; membuf_clear(mem); membuf_append(mem, NULL, 65536); p = membuf_get(mem); info->basic_txt_start = -1; load_located(file_name, p, info); /* move memory to beginning of buffer */ membuf_truncate(mem, info->end); membuf_trim(mem, info->start); LOG(LOG_NORMAL, (" Crunching from $%04X to $%04X.", info->start, info->end)); return info->start; }
static void level(const char *appl, int argc, char *argv[]) { char flags_arr[32]; int forward_mode = 0; int literal_sequences_used = 0; int max_safety = 0; int c; int infilec; char **infilev; struct crunch_options options[1] = { CRUNCH_OPTIONS_DEFAULT }; struct common_flags flags[1] = {{NULL, DEFAULT_OUTFILE}}; struct membuf in[1]; struct membuf out[1]; flags->options = options; LOG(LOG_DUMP, ("flagind %d\n", flagind)); sprintf(flags_arr, "f%s", CRUNCH_FLAGS); while ((c = getflag(argc, argv, flags_arr)) != -1) { LOG(LOG_DUMP, (" flagind %d flagopt '%c'\n", flagind, c)); switch (c) { case 'f': forward_mode = 1; break; default: handle_crunch_flags(c, flagarg, print_level_usage, appl, flags); } } membuf_init(in); membuf_init(out); infilev = argv + flagind; infilec = argc - flagind; if (infilec == 0) { LOG(LOG_ERROR, ("Error: no input files to process.\n")); print_level_usage(appl, LOG_NORMAL, DEFAULT_OUTFILE); exit(1); } /* append the files instead of merging them */ for(c = 0; c < infilec; ++c) { struct crunch_info info[1]; int in_load; int in_len; int out_pos; out_pos = membuf_memlen(out); in_load = do_load(infilev[c], in); in_len = membuf_memlen(in); if(forward_mode) { /* append the starting address of decrunching */ membuf_append_char(out, in_load >> 8); membuf_append_char(out, in_load & 255); crunch(in, out, options, info); } else { crunch_backwards(in, out, options, info); /* append the starting address of decrunching */ membuf_append_char(out, (in_load + in_len) & 255); membuf_append_char(out, (in_load + in_len) >> 8); /* reverse the just appended segment of the out buffer */ reverse_buffer((char*)membuf_get(out) + out_pos, membuf_memlen(out) - out_pos); } if(info->literal_sequences_used) { literal_sequences_used = 1; } if(info->needed_safety_offset > max_safety) { max_safety = info->needed_safety_offset; } }
static int do_loads(int filec, char *filev[], struct membuf *mem, int basic_txt_start, int sys_token, int *basic_var_startp, int *runp, int trim_sys) { int run = -1; int min_start = 65537; int max_end = -1; int basic_code = 0; int i; unsigned char *p; struct load_info info[1]; membuf_clear(mem); membuf_append(mem, NULL, 65536); p = membuf_get(mem); for (i = 0; i < filec; ++i) { info->basic_txt_start = basic_txt_start; load_located(filev[i], p, info); run = info->run; if(run != -1 && runp != NULL) { LOG(LOG_DEBUG, ("Propagating found run address $%04X.\n", info->run)); *runp = info->run; } /* do we expect any basic file? */ if(basic_txt_start >= 0) { if(info->basic_var_start >= 0) { basic_code = 1; if(basic_var_startp != NULL) { *basic_var_startp = info->basic_var_start; } if(runp != NULL && run == -1) { /* only if we didn't get run address from load_located * (run is not -1 if we did) */ int stub_len; run = find_sys(p + basic_txt_start, sys_token, &stub_len); *runp = run; if (trim_sys && basic_txt_start == info->start && min_start >= info->start) { if (run >= info->start && run < info->start + stub_len) { /* the run address points into the sys stub, trim up to it but no further */ info->start = run; } else { /* trim the sys stub*/ info->start += stub_len; } } } } } if (info->start < min_start) { min_start = info->start; } if (info->end > max_end) { max_end = info->end; } } if(basic_txt_start >= 0 && !basic_code && run == -1) { /* no program loaded to the basic start */ LOG(LOG_ERROR, ("\nError: nothing loaded at the start of basic " "text address ($%04X).\n", basic_txt_start)); exit(1); } /* if we have a basic code loaded and we are doing a proper basic start * (the caller don't expect a sys address so runp is NULL */ if(basic_code && runp == NULL) { int valuepos = basic_txt_start - 1; /* the byte immediatley preceeding the basic start must be 0 * for basic to function properly. */ if(min_start > valuepos) { /* It not covered by the files to crunch. Since the * default fill value is 0 we don't need to set it but we * need to include that location in the crunch as well. */ min_start = valuepos; } else { int value = p[valuepos]; /* it has been covered by at least one file. Let's check * if it is zero. */ if(value != 0) { /* Hm, its not, danger Will Robinson! */ LOG(LOG_WARNING, ("Warning, basic will probably not work since the value of" " the location \npreceeding the basic start ($%04X)" " is not 0 but %d.\n", valuepos, value)); } } } /* move memory to beginning of buffer */ membuf_truncate(mem, max_end); membuf_trim(mem, min_start); return min_start; }
void match_ctx_init(match_ctx ctx, /* IN/OUT */ struct membuf *inbuf, /* IN */ int max_offset) { struct match_node *np; struct progress prog[1]; int buf_len = membuf_memlen(inbuf); const unsigned char *buf = membuf_get(inbuf); int c, i; int val; ctx->info = calloc(buf_len + 1, sizeof(*ctx->info)); ctx->rle = calloc(buf_len + 1, sizeof(*ctx->rle)); ctx->rle_r = calloc(buf_len + 1, sizeof(*ctx->rle_r)); chunkpool_init(ctx->m_pool, sizeof(match)); ctx->max_offset = max_offset; ctx->buf = buf; ctx->len = buf_len; val = buf[0]; for (i = 1; i < buf_len; ++i) { if (buf[i] == val) { int len = ctx->rle[i - 1] + 1; if(len > 65535) { len = 0; } ctx->rle[i] = len; } else { ctx->rle[i] = 0; } val = buf[i]; } for (i = buf_len - 2; i >= 0; --i) { if (ctx->rle[i] < ctx->rle[i + 1]) { ctx->rle_r[i] = ctx->rle_r[i + 1] + 1; } else { ctx->rle_r[i] = 0; } } /* add extra nodes to rle sequences */ for(c = 0; c < 256; ++c) { static char rle_map[65536]; struct match_node *prev_np; unsigned short int rle_len; /* for each possible rle char */ memset(rle_map, 0, sizeof(rle_map)); prev_np = NULL; for (i = 0; i < buf_len; ++i) { /* must be the correct char */ if(buf[i] != c) { continue; } rle_len = ctx->rle[i]; if(!rle_map[rle_len] && ctx->rle_r[i] > 16) { /* no previous lengths and not our primary length*/ continue; } np = chunkpool_malloc(ctx->m_pool); np->index = i; np->next = NULL; rle_map[rle_len] = 1; LOG(LOG_DUMP, ("0) c = %d, added np idx %d -> %d\n", c, i, 0)); /* if we have a previous entry, let's chain it together */ if(prev_np != NULL) { LOG(LOG_DUMP, ("1) c = %d, pointed np idx %d -> %d\n", c, prev_np->index, i)); prev_np->next = np; } ctx->info[i]->single = np; prev_np = np; } memset(rle_map, 0, sizeof(rle_map)); prev_np = NULL; for (i = buf_len - 1; i >= 0; --i) { /* must be the correct char */ if(buf[i] != c) { continue; } rle_len = ctx->rle_r[i]; np = ctx->info[i]->single; if(np == NULL) { if(rle_map[rle_len] && prev_np != NULL && rle_len > 0) { np = chunkpool_malloc(ctx->m_pool); np->index = i; np->next = prev_np; ctx->info[i]->single = np; LOG(LOG_DEBUG, ("2) c = %d, added np idx %d -> %d\n", c, i, prev_np->index)); } } else { prev_np = np; } if(ctx->rle_r[i] > 0) { continue; } rle_len = ctx->rle[i] + 1; rle_map[rle_len] = 1; } } progress_init(prog, "building.directed.acyclic.graph.", buf_len - 1, 0); for (i = buf_len - 1; i >= 0; --i) { const_matchp matches; /* let's populate the cache */ matches = matches_calc(ctx, i); /* add to cache */ ctx->info[i]->cache = matches; progress_bump(prog, i); } LOG(LOG_NORMAL, ("\n")); progress_free(prog); }
void output_atoms(struct membuf *out, struct vec *atoms) { struct vec_iterator i[1]; struct vec_iterator i2[1]; struct atom **atomp; struct atom *atom; struct expr **exprp; struct expr *expr; struct membuf *in; const char *p; i32 value; i32 value2; dump_sym_table(LOG_DEBUG, s->sym_table); vec_get_iterator(atoms, i); while((atomp = vec_iterator_next(i)) != NULL) { atom = *atomp; LOG(LOG_DEBUG, ("yadda\n")); switch(atom->type) { case ATOM_TYPE_OP_ARG_NONE: LOG(LOG_DEBUG, ("output: $%02X\n", atom->u.op.code)); membuf_append_char(out, atom->u.op.code); break; case ATOM_TYPE_OP_ARG_U8: /* op with argument */ value = resolve_expr(atom->u.op.arg); if(!is_valid_u8(value)) { LOG(LOG_ERROR, ("value %d out of range for op $%02X @%p\n", value, atom->u.op.code, (void*)atom)); exit(1); } LOG(LOG_DEBUG, ("output: $%02X $%02X\n", atom->u.op.code, value & 255)); membuf_append_char(out, atom->u.op.code); membuf_append_char(out, value); break; case ATOM_TYPE_OP_ARG_I8: /* op with argument */ value = resolve_expr(atom->u.op.arg); if(!is_valid_i8(value)) { LOG(LOG_ERROR, ("value %d out of range for op $%02X @%p\n", value, atom->u.op.code, (void*)atom)); exit(1); } LOG(LOG_DEBUG, ("output: $%02X $%02X\n", atom->u.op.code, value & 255)); membuf_append_char(out, atom->u.op.code); membuf_append_char(out, value); break; case ATOM_TYPE_OP_ARG_UI8: /* op with argument */ value = resolve_expr(atom->u.op.arg); if(!is_valid_ui8(value)) { LOG(LOG_ERROR, ("value %d out of range for op $%02X @%p\n", value, atom->u.op.code, (void*)atom)); exit(1); } LOG(LOG_DEBUG, ("output: $%02X $%02X\n", atom->u.op.code, value & 255)); membuf_append_char(out, atom->u.op.code); membuf_append_char(out, value); break; case ATOM_TYPE_OP_ARG_U16: /* op with argument */ value = resolve_expr(atom->u.op.arg); if(!is_valid_u16(value)) { LOG(LOG_ERROR, ("value %d out of range for op $%02X @%p\n", value, atom->u.op.code, (void*)atom)); exit(1); } value2 = value / 256; value = value % 256; LOG(LOG_DEBUG, ("output: $%02X $%02X $%02X\n", atom->u.op.code, value, value2)); membuf_append_char(out, atom->u.op.code); membuf_append_char(out, value); membuf_append_char(out, value2); break; case ATOM_TYPE_RES: /* reserve memory statement */ value = resolve_expr(atom->u.res.length); if(!is_valid_u16(value)) { LOG(LOG_ERROR, ("length %d for .res(length, value) " "is out of range\n", value)); exit(1); } value2 = resolve_expr(atom->u.res.value); if(!is_valid_ui8(value2)) { LOG(LOG_ERROR, ("value %d for .res(length, value) " "is out of range\n", value)); exit(1); } LOG(LOG_DEBUG, ("output: .RES %d, %d\n", value, value2)); while(--value >= 0) { membuf_append_char(out, value2); } break; case ATOM_TYPE_BUFFER: /* include binary file statement */ value = atom->u.buffer.skip; if(!is_valid_u16(value)) { LOG(LOG_ERROR, ("value %d for .res(length, value) " "is out of range\n", value)); exit(1); } value2 = atom->u.buffer.length; if(!is_valid_u16(value2)) { LOG(LOG_ERROR, ("length %d for .incbin(name, skip, length) " "is out of range\n", value2)); exit(1); } LOG(LOG_DEBUG, ("output: .INCBIN \"%s\", %d, %d\n", atom->u.buffer.name, value, value2)); in = get_named_buffer(s->named_buffer, atom->u.buffer.name); p = membuf_get(in); p += value; while(--value2 >= 0) { membuf_append_char(out, *p++); } break; case ATOM_TYPE_WORD_EXPRS: vec_get_iterator(atom->u.exprs, i2); while((exprp = vec_iterator_next(i2)) != NULL) { expr = *exprp; value = resolve_expr(expr); if(!is_valid_ui16(value)) { LOG(LOG_ERROR, ("value %d for .word(value, ...) " "is out of range\n", value)); } value2 = value / 256; value = value % 256; membuf_append_char(out, value); membuf_append_char(out, value2); } LOG(LOG_DEBUG, ("output: %d words\n", vec_count(atom->u.exprs))); break; case ATOM_TYPE_BYTE_EXPRS: vec_get_iterator(atom->u.exprs, i2); while((exprp = vec_iterator_next(i2)) != NULL) { expr = *exprp; value = resolve_expr(expr); if(!is_valid_ui8(value)) { LOG(LOG_ERROR, ("value %d for .byte(value, ...) " "is out of range\n", value)); } membuf_append_char(out, value); } LOG(LOG_DEBUG, ("output: %d bytes\n", vec_count(atom->u.exprs))); break; default: LOG(LOG_ERROR, ("invalid atom_type %d @%p\n", atom->type, (void*)atom)); exit(1); } } }
char *get(struct membuf *buf) { return membuf_get(buf); }