static void do_on_dbuf_size_exceeded(dbuf *f) { de_err(f->c, "Maximum %s size of %"I64_FMT" bytes exceeded", (f->btype==DBUF_TYPE_MEMBUF)?"membuf":"output file", f->max_len_hard); de_fatalerror(f->c); }
// Allowed only for membufs, and unmanaged output files. // For unmanaged output files, must be used with care, and should not be // mixed with dbuf_write(). void dbuf_write_at(dbuf *f, i64 pos, const u8 *m, i64 len) { if(len<1 || pos<0) return; if(pos + len > f->max_len_hard) { do_on_dbuf_size_exceeded(f); } if(f->btype==DBUF_TYPE_MEMBUF) { i64 amt_overwrite, amt_newzeroes, amt_append; if(pos+len <= f->len) { // entirely within the current file amt_overwrite = len; amt_newzeroes = 0; amt_append = 0; } else if(pos >= f->len) { // starts after the end of the current file amt_overwrite = 0; amt_newzeroes = pos - f->len; amt_append = len; } else { // overlaps the end of the current file amt_overwrite = f->len - pos; amt_newzeroes = 0; amt_append = len - amt_overwrite; } if(amt_overwrite>0) { de_memcpy(&f->membuf_buf[pos], m, (size_t)amt_overwrite); } if(amt_newzeroes>0) { dbuf_write_zeroes(f, amt_newzeroes); } if(amt_append>0) { membuf_append(f, &m[amt_overwrite], amt_append); } } else if(f->btype==DBUF_TYPE_OFILE && !f->is_managed) { i64 curpos = de_ftell(f->fp); if(pos != curpos) { de_fseek(f->fp, pos, SEEK_SET); } fwrite(m, 1, (size_t)len, f->fp); if(pos+len > f->len) { f->len = pos+len; } } else if(f->btype==DBUF_TYPE_NULL) { ; } else { de_err(f->c, "internal: Attempt to seek on non-seekable stream"); de_fatalerror(f->c); } }
void dbuf_write(dbuf *f, const u8 *m, i64 len) { if(f->len + len > f->max_len_hard) { do_on_dbuf_size_exceeded(f); } if(f->writecallback_fn) { f->writecallback_fn(f, m, len); } if(f->btype==DBUF_TYPE_NULL) { f->len += len; return; } else if(f->btype==DBUF_TYPE_OFILE || f->btype==DBUF_TYPE_STDOUT) { if(!f->fp) return; if(f->c->debug_level>=3) { de_dbg3(f->c, "writing %d bytes to %s", (int)len, f->name); } fwrite(m, 1, (size_t)len, f->fp); f->len += len; return; } else if(f->btype==DBUF_TYPE_MEMBUF) { if(f->c->debug_level>=3 && f->name) { de_dbg3(f->c, "appending %d bytes to membuf %s", (int)len, f->name); } membuf_append(f, m, len); return; } else if(f->btype==DBUF_TYPE_ODBUF) { dbuf_write(f->parent_dbuf, m, len); f->len += len; return; } de_err(f->c, "Internal: Invalid output file type (%d)", f->btype); de_fatalerror(f->c); }
void de_run(deark *c) { dbuf *orig_ifile = NULL; dbuf *subfile = NULL; de_int64 subfile_size; struct deark_module_info *module_to_use = NULL; const char *friendly_infn; if(c->modhelp_req && c->input_format_req) { do_modhelp(c); goto done; } if(c->input_style==DE_INPUTSTYLE_STDIN) { friendly_infn = "[stdin]"; } else { friendly_infn = c->input_filename; } if(!friendly_infn) { de_err(c, "Input file not set\n"); de_fatalerror(c); return; } de_register_modules(c); if(c->input_format_req) { module_to_use = de_get_module_by_id(c, c->input_format_req); if(!module_to_use) { de_err(c, "Unknown module \"%s\"\n", c->input_format_req); goto done; } } if(c->slice_size_req_valid) { de_dbg(c, "Input file: %s[%d,%d]\n", friendly_infn, (int)c->slice_start_req, (int)c->slice_size_req); } else if(c->slice_start_req) { de_dbg(c, "Input file: %s[%d]\n", friendly_infn, (int)c->slice_start_req); } else { de_dbg(c, "Input file: %s\n", friendly_infn); } if(c->input_style==DE_INPUTSTYLE_STDIN) { orig_ifile = dbuf_open_input_stdin(c, c->input_filename); } else { orig_ifile = dbuf_open_input_file(c, c->input_filename); } if(!orig_ifile) { goto done; } c->infile = orig_ifile; // If we are only supposed to look at a segment of the original file, // do that by creating a child dbuf, using dbuf_open_input_subfile(). if(c->slice_start_req>0 || c->slice_size_req_valid) { if(c->slice_size_req_valid) subfile_size = c->slice_size_req; else subfile_size = dbuf_get_length(c->infile) - c->slice_start_req; subfile = dbuf_open_input_subfile(c->infile, c->slice_start_req, subfile_size); c->infile = subfile; } if(!module_to_use) { module_to_use = detect_module_for_file(c); } if(!module_to_use) { if(c->infile->len==0) de_err(c, "Unknown or unsupported file format (empty file)\n"); else de_err(c, "Unknown or unsupported file format\n"); goto done; } de_msg(c, "Module: %s\n", module_to_use->id); if(module_to_use->flags&DE_MODFLAG_NONWORKING) { de_warn(c, "The %s module is considered to be incomplete, and may " "not work properly. Caveat emptor.\n", module_to_use->id); } de_dbg2(c, "file size: %" INT64_FMT "\n", c->infile->len); if(!de_run_module(c, module_to_use, NULL)) { goto done; } // The DE_MODFLAG_NOEXTRACT flag means the module is not expected to extract // any files. if(c->num_files_extracted==0 && c->error_count==0 && !(module_to_use->flags&DE_MODFLAG_NOEXTRACT)) { de_msg(c, "No files found to extract!\n"); } done: if(subfile) dbuf_close(subfile); if(orig_ifile) dbuf_close(orig_ifile); }
void de_font_bitmap_font_to_image(deark *c, struct de_bitmap_font *font1, de_finfo *fi, unsigned int createflags) { struct font_render_ctx *fctx = NULL; i64 i, j, k; de_bitmap *img = NULL; i64 xpos, ypos; i64 img_leftmargin, img_topmargin; i64 img_rightmargin, img_bottommargin; i64 img_vpixelsperchar; i64 img_width, img_height; i64 num_table_rows_to_display; i64 num_table_rows_total; i64 last_valid_row; struct de_bitmap_font *dfont = NULL; i64 chars_per_row = 32; const char *s; struct row_info_struct *row_info = NULL; struct col_info_struct *col_info = NULL; int unicode_req = 0; i64 label_stride; i64 rownum, colnum; i64 curpos; unsigned int dnflags; fctx = de_malloc(c, sizeof(struct font_render_ctx)); fctx->font = font1; if(fctx->font->num_chars<1) goto done; if(fctx->font->num_chars>17*65536) goto done; if(fctx->font->nominal_width>512 || fctx->font->nominal_height>512) { de_err(c, "Font size too big (%d"DE_CHAR_TIMES"%d). Not supported.", (int)fctx->font->nominal_width, (int)fctx->font->nominal_height); goto done; } // -1 = "no preference" unicode_req = de_get_ext_option_bool(c, "font:tounicode", -1); if(unicode_req==0 && (fctx->font->has_nonunicode_codepoints || !fctx->font->has_unicode_codepoints)) { ; // Render as nonunicode. } else if(fctx->font->has_unicode_codepoints && (unicode_req>0 || fctx->font->prefer_unicode || !fctx->font->has_nonunicode_codepoints)) { fctx->render_as_unicode = 1; } s = de_get_ext_option(c, "font:charsperrow"); if(s) { chars_per_row = de_atoi64(s); if(chars_per_row<1) chars_per_row=1; } dfont = make_digit_font(c); fctx->codepoint_tmp = de_mallocarray(c, fctx->font->num_chars, sizeof(i32)); fixup_codepoints(c, fctx); get_min_max_codepoint(fctx); if(fctx->num_valid_chars<1) goto done; num_table_rows_total = fctx->max_codepoint/chars_per_row+1; // TODO: Clean up these margin calculations, and make it more general. if(fctx->render_as_unicode) { img_leftmargin = dfont->nominal_width * 5 + 6; } else { if(fctx->max_codepoint >= 1000) img_leftmargin = dfont->nominal_width * 5 + 6; else img_leftmargin = dfont->nominal_width * 3 + 6; } img_topmargin = dfont->nominal_height + 6; img_rightmargin = 1; img_bottommargin = 1; // Scan the characters, and record relevant information. row_info = de_mallocarray(c, num_table_rows_total, sizeof(struct row_info_struct)); col_info = de_mallocarray(c, chars_per_row, sizeof(struct col_info_struct)); for(i=0; i<chars_per_row; i++) { #define MIN_CHAR_CELL_WIDTH 5 col_info[i].display_width = MIN_CHAR_CELL_WIDTH; } for(k=0; k<fctx->font->num_chars; k++) { i64 char_display_width; if(fctx->codepoint_tmp[k] == DE_CODEPOINT_INVALID) continue; if(!is_valid_char(&fctx->font->char_array[k])) continue; rownum = fctx->codepoint_tmp[k] / chars_per_row; colnum = fctx->codepoint_tmp[k] % chars_per_row; if(rownum<0 || rownum>=num_table_rows_total) { de_err(c, "internal: bad rownum"); de_fatalerror(c); } // Remember that there is at least one valid character in this character's row. row_info[rownum].is_visible = 1; // Track the maximum width of any character in this character's column. char_display_width = (i64)(fctx->font->char_array[k].width + (int)fctx->font->char_array[k].extraspace_l + (int)fctx->font->char_array[k].extraspace_r); if(char_display_width > col_info[colnum].display_width) { col_info[colnum].display_width = char_display_width; } } img_vpixelsperchar = fctx->font->nominal_height + 1; // Figure out how many rows are used, and where to draw them. num_table_rows_to_display = 0; last_valid_row = -1; curpos = img_topmargin; for(j=0; j<num_table_rows_total; j++) { if(!row_info[j].is_visible) continue; // If we skipped one or more rows, leave some extra vertical space. if(num_table_rows_to_display>0 && !row_info[j-1].is_visible) curpos+=3; last_valid_row = j; row_info[j].display_pos = curpos; curpos += img_vpixelsperchar; num_table_rows_to_display++; } if(num_table_rows_to_display<1) goto done; // Figure out the positions of the columns. curpos = img_leftmargin; for(i=0; i<chars_per_row; i++) { col_info[i].display_pos = curpos; curpos += col_info[i].display_width + 1; } img_width = col_info[chars_per_row-1].display_pos + col_info[chars_per_row-1].display_width + img_rightmargin; img_height = row_info[last_valid_row].display_pos + img_vpixelsperchar -1 + img_bottommargin; img = de_bitmap_create(c, img_width, img_height, 1); // Clear the image for(j=0; j<img->height; j++) { for(i=0; i<img->width; i++) { de_bitmap_setpixel_gray(img, i, j, 128); } } // Draw/clear the cell backgrounds for(j=0; j<num_table_rows_total; j++) { if(!row_info[j].is_visible) continue; ypos = row_info[j].display_pos; for(i=0; i<chars_per_row; i++) { i64 ii, jj; xpos = col_info[i].display_pos; for(jj=0; jj<img_vpixelsperchar-1; jj++) { for(ii=0; ii<col_info[i].display_width; ii++) { de_bitmap_setpixel_gray(img, xpos+ii, ypos+jj, (ii/2+jj/2)%2 ? 176 : 192); } } } } // Draw the labels in the top margin. // TODO: Better label spacing logic. if(fctx->font->nominal_width <= 12) label_stride = 2; else label_stride = 1; for(i=0; i<chars_per_row; i++) { if(i%label_stride != 0) continue; xpos = col_info[i].display_pos + col_info[i].display_width/2; ypos = img_topmargin - 3; dnflags = DNFLAG_HCENTER; if(fctx->render_as_unicode) dnflags |= DNFLAG_HEX; draw_number(c, img, dfont, i, xpos, ypos, dnflags); } // Draw the labels in the left margin. for(j=0; j<num_table_rows_total; j++) { if(!row_info[j].is_visible) continue; xpos = img_leftmargin - 3; ypos = row_info[j].display_pos + (img_vpixelsperchar + dfont->nominal_height + 1)/2; dnflags = 0; if(fctx->render_as_unicode) dnflags |= DNFLAG_HEX | DNFLAG_LEADING_ZEROES; draw_number(c, img, dfont, j*chars_per_row, xpos, ypos, dnflags); } // Render the glyphs. for(k=0; k<fctx->font->num_chars; k++) { if(fctx->codepoint_tmp[k] == DE_CODEPOINT_INVALID) continue; if(!is_valid_char(&fctx->font->char_array[k])) continue; rownum = fctx->codepoint_tmp[k] / chars_per_row; colnum = fctx->codepoint_tmp[k] % chars_per_row; if(rownum<0 || rownum>=num_table_rows_total) { de_err(c, "internal: bad rownum"); de_fatalerror(c); } xpos = col_info[colnum].display_pos; ypos = row_info[rownum].display_pos; de_font_paint_character_idx(c, img, fctx->font, k, xpos, ypos, DE_STOCKCOLOR_BLACK, DE_STOCKCOLOR_WHITE, 0); } de_bitmap_write_to_file_finfo(img, fi, createflags); done: if(dfont) { de_free(c, dfont->char_array); de_destroy_bitmap_font(c, dfont); } de_bitmap_destroy(img); de_free(c, row_info); de_free(c, col_info); if(fctx) { de_free(c, fctx->codepoint_tmp); de_free(c, fctx); } }
// Read len bytes, starting at file position pos, into buf. // Unread bytes will be set to 0. void dbuf_read(dbuf *f, u8 *buf, i64 pos, i64 len) { i64 bytes_read = 0; i64 bytes_to_read; deark *c; c = f->c; bytes_to_read = len; if(pos >= f->len) { bytes_to_read = 0; } else if(pos + bytes_to_read > f->len) { bytes_to_read = f->len - pos; } if(bytes_to_read<1) { goto done_read; } if(!f->cache && f->cache_policy==DE_CACHE_POLICY_ENABLED) { populate_cache(f); } // If the data we need is all cached, get it from cache. if(f->cache && pos >= f->cache_start_pos && pos + bytes_to_read <= f->cache_start_pos + f->cache_bytes_used) { de_memcpy(buf, &f->cache[pos - f->cache_start_pos], (size_t)bytes_to_read); bytes_read = bytes_to_read; goto done_read; } switch(f->btype) { case DBUF_TYPE_IFILE: if(!f->fp) { de_err(c, "Internal: File not open"); de_fatalerror(c); return; } // For performance reasons, don't call fseek if we're already at the // right position. if(!f->file_pos_known || f->file_pos!=pos) { de_fseek(f->fp, pos, SEEK_SET); } bytes_read = fread(buf, 1, (size_t)bytes_to_read, f->fp); f->file_pos = pos + bytes_read; f->file_pos_known = 1; break; case DBUF_TYPE_IDBUF: // Recursive call to the parent dbuf. dbuf_read(f->parent_dbuf, buf, f->offset_into_parent_dbuf+pos, bytes_to_read); // The parent dbuf always writes 'bytes_to_read' bytes. bytes_read = bytes_to_read; break; case DBUF_TYPE_MEMBUF: de_memcpy(buf, &f->membuf_buf[pos], (size_t)bytes_to_read); bytes_read = bytes_to_read; break; default: de_err(c, "Internal: getbytes from this I/O type not implemented"); de_fatalerror(c); return; } done_read: // Zero out any requested bytes that were not read. if(bytes_read < len) { de_zeromem(buf+bytes_read, (size_t)(len - bytes_read)); } }