void crunch_backwards(struct membuf *inbuf, struct membuf *outbuf, struct crunch_options *options, /* IN */ struct crunch_info *info) /* OUT */ { static match_ctx ctx; encode_match_data emd; search_nodep snp; int outlen; int safety; int copy_used; if(options == NULL) { options = default_options; } outlen = membuf_memlen(outbuf); emd->out = NULL; optimal_init(emd); LOG(LOG_NORMAL, ("\nPhase 1: Instrumenting file" "\n-----------------------------\n")); LOG(LOG_NORMAL, (" Length of indata: %d bytes.\n", membuf_memlen(inbuf))); match_ctx_init(ctx, inbuf, options->max_len, options->max_offset, options->use_imprecise_rle); LOG(LOG_NORMAL, (" Instrumenting file, done.\n")); emd->out = NULL; optimal_init(emd); LOG(LOG_NORMAL, ("\nPhase 2: Calculating encoding" "\n-----------------------------\n")); snp = do_compress(ctx, emd, options->exported_encoding, options->max_passes, options->use_literal_sequences); LOG(LOG_NORMAL, (" Calculating encoding, done.\n")); LOG(LOG_NORMAL, ("\nPhase 3: Generating output file" "\n------------------------------\n")); LOG(LOG_NORMAL, (" Encoding: %s\n", optimal_encoding_export(emd))); safety = do_output(ctx, snp, emd, optimal_encode, outbuf, ©_used); LOG(LOG_NORMAL, (" Length of crunched data: %d bytes.\n", membuf_memlen(outbuf) - outlen)); optimal_free(emd); search_node_free(snp); match_ctx_free(ctx); if(info != NULL) { info->literal_sequences_used = copy_used; info->needed_safety_offset = safety; } }
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; } }
struct atom *new_incbin(const char *name, struct expr *skip, struct expr *len) { struct atom *atom; long length; i32 len32; i32 skip32; struct membuf *in; /* find out how long the file is */ in = get_named_buffer(s->named_buffer, name); length = membuf_memlen(in); skip32 = 0; if(skip != NULL) { skip32 = resolve_expr(skip); } if(skip32 < 0) { skip32 += length; } if(skip32 < 0 || skip32 > length) { LOG(LOG_ERROR, ("Can't read from offset %d in file \"%s\".\n", skip32, name)); exit(-1); } length -= skip32; len32 = 0; if(len != NULL) { len32 = resolve_expr(len); } if(len32 < 0) { len32 += length; } if(len32 < 0 || len32 > length) { LOG(LOG_ERROR, ("Can't read %d bytes from offset %d from file \"%s\".\n", len32, skip32, name)); exit(-1); } atom = chunkpool_malloc(s->atom_pool); atom->type = ATOM_TYPE_BUFFER; atom->u.buffer.name = name; atom->u.buffer.length = len32; atom->u.buffer.skip = skip32; if(len != NULL) { pc_add(len32); } return atom; }
struct expr *new_expr_inclen(const char *name) { long length; struct membuf *in; struct expr *expr; in = get_named_buffer(s->named_buffer, name); length = membuf_memlen(in); expr = new_expr_number((i32)length); return expr; }
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 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; } }
{ literal_sequences_used = 1; } if(info->needed_safety_offset > max_safety) { max_safety = info->needed_safety_offset; } } LOG(LOG_NORMAL, (" Literal sequences are %sused and", literal_sequences_used ? "" : "not ")); LOG(LOG_NORMAL, (" the largest safety offset is %d.\n", max_safety)); LOG(LOG_BRIEF, (" Writing %d bytes to \"%s\".\n", membuf_memlen(out), flags->outfile)); write_file(flags->outfile, out); membuf_free(out); membuf_free(in); } static void mem(const char *appl, int argc, char *argv[]) { char flags_arr[32]; int forward_mode = 0; int load_addr = -1; int prepend_load_addr = 1; int c; int infilec;
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); }
int assemble(struct membuf *source, struct membuf *dest) { struct vec guesses_history[1]; struct map guesses_storage[1]; int dest_pos; int result; dump_sym_table(LOG_DEBUG, s->initial_symbols); vec_init(guesses_history, sizeof(struct map)); s->guesses = NULL; dest_pos = membuf_memlen(dest); for(;;) { map_put_all(s->sym_table, s->initial_symbols); named_buffer_copy(s->named_buffer, s->initial_named_buffer); map_init(guesses_storage); if(s->guesses != NULL) { /* copy updated guesses from latest pass */ map_put_all(guesses_storage, s->guesses); } s->guesses = guesses_storage; result = assembleSinglePass(source, dest); if(result != 0) { /* the assemble pass failed */ break; } /* check if any guessed symbols was wrong and update them * to their actual value */ if(wasFinalPass()) { /* The assemble pass succeeded without any wrong guesses, * we're done */ break; } if(loopDetect(guesses_history)) { /* More passes would only get us into a loop */ LOG(LOG_VERBOSE, ("Aborting due to loop.\n")); result = -1; break; } LOG(LOG_VERBOSE, ("Trying another pass.\n")); /* allocate storage for the guesses in the history vector */ s->guesses = vec_push(guesses_history, s->guesses); parse_reset(); membuf_truncate(dest, dest_pos); } map_free(guesses_storage); vec_free(guesses_history, (cb_free*)map_free); s->guesses = NULL; return result; }
void dec_ctx_decrunch(struct dec_ctx ctx[1]) { int bits; int val; int i; int len; int offset; int src = 0; for(;;) { int literal = 0; bits = ctx->bits_read; if(get_bits(ctx, 1)) { /* literal */ len = 1; LOG(LOG_DEBUG, ("[%d] literal\n", membuf_memlen(ctx->outbuf))); literal = 1; goto literal; } val = get_gamma_code(ctx); if(val == 16) { /* done */ break; } if(val == 17) { len = get_bits(ctx, 16); literal = 1; LOG(LOG_DEBUG, ("[%d] literal copy len %d\n", membuf_memlen(ctx->outbuf), len)); goto literal; } len = get_cooked_code_phase2(ctx, val); i = (len > 3 ? 3 : len) - 1; val = ctx->t->table_off[i] + get_bits(ctx, ctx->t->table_bit[i]); offset = get_cooked_code_phase2(ctx, val); LOG(LOG_DEBUG, ("[%d] sequence offset = %d, len = %d\n", membuf_memlen(ctx->outbuf), offset, len)); src = membuf_memlen(ctx->outbuf) - offset; literal: do { if(literal) { val = get_byte(ctx); } else { val = get(ctx->outbuf)[src++]; } membuf_append_char(ctx->outbuf, val); } while (--len > 0); LOG(LOG_DEBUG, ("bits read for this iteration %d.\n", ctx->bits_read - bits)); } }