/** Copy a single line from a data buffer. * If the output buffer cannot hold the whole line, or if there is no * EOL in the buffer, return 0. * @param[in,out] dyn Data buffer to copy from. * @param[out] buf Buffer to copy to. * @param[in] length Maximum number of bytes to copy. * @return Number of bytes copied to \a buf. */ unsigned int dbuf_getmsg(struct DBuf *dyn, char *buf, unsigned int length) { struct DBufBuffer *db; char *start; char *end; unsigned int count; unsigned int copied = 0; assert(0 != dyn); assert(0 != buf); if (0 == dbuf_flush(dyn)) return 0; assert(0 != dyn->head); db = dyn->head; start = db->start; assert(start < db->end); if (length > dyn->length) length = dyn->length; /* * might as well copy it while we're here */ while (length > 0) { end = IRCD_MIN(db->end, (start + length)); while (start < end && !IsEol(*start)) *buf++ = *start++; count = start - db->start; if (start < end) { *buf = '\0'; copied += count; dbuf_delete(dyn, copied); dbuf_flush(dyn); return copied; } if (0 == (db = db->next)) break; copied += count; length -= count; start = db->start; } return 0; }
dbuf *dbuf_create_output_file(deark *c, const char *ext, de_finfo *fi, unsigned int createflags) { char nbuf[500]; char msgbuf[200]; dbuf *f; const char *basefn; int file_index; u8 is_directory = 0; char *name_from_finfo = NULL; i64 name_from_finfo_len = 0; if(ext && fi && fi->original_filename_flag) { de_dbg(c, "[internal warning: Incorrect use of create_output_file]"); } f = de_malloc(c, sizeof(dbuf)); f->c = c; f->max_len_hard = c->max_output_file_size; f->is_managed = 1; if(fi && fi->is_directory) { is_directory = 1; } if(is_directory && !c->keep_dir_entries) { de_dbg(c, "skipping 'directory' file"); f->btype = DBUF_TYPE_NULL; goto done; } if(c->extract_policy==DE_EXTRACTPOLICY_MAINONLY) { if(createflags&DE_CREATEFLAG_IS_AUX) { de_dbg(c, "skipping 'auxiliary' file"); f->btype = DBUF_TYPE_NULL; goto done; } } else if(c->extract_policy==DE_EXTRACTPOLICY_AUXONLY) { if(!(createflags&DE_CREATEFLAG_IS_AUX)) { de_dbg(c, "skipping 'main' file"); f->btype = DBUF_TYPE_NULL; goto done; } } file_index = c->file_count; c->file_count++; basefn = c->base_output_filename ? c->base_output_filename : "output"; if(fi && ucstring_isnonempty(fi->file_name_internal)) { name_from_finfo_len = 1 + ucstring_count_utf8_bytes(fi->file_name_internal); name_from_finfo = de_malloc(c, name_from_finfo_len); ucstring_to_sz(fi->file_name_internal, name_from_finfo, (size_t)name_from_finfo_len, 0, DE_ENCODING_UTF8); } if(c->output_style==DE_OUTPUTSTYLE_ARCHIVE && !c->base_output_filename && fi && fi->is_directory && (fi->is_root_dir || (fi->detect_root_dot_dir && fi->orig_name_was_dot))) { de_strlcpy(nbuf, ".", sizeof(nbuf)); } else if(c->output_style==DE_OUTPUTSTYLE_ARCHIVE && !c->base_output_filename && fi && fi->original_filename_flag && name_from_finfo) { // TODO: This is a "temporary" hack to allow us to, when both reading from // and writing to an archive format, use some semblance of the correct // filename (instead of "output.xxx.yyy"). // There are some things that we don't handle optimally, such as // subdirectories. // A major redesign of the file naming logic would be good. de_strlcpy(nbuf, name_from_finfo, sizeof(nbuf)); } else { char fn_suffix[256]; if(ext && name_from_finfo) { de_snprintf(fn_suffix, sizeof(fn_suffix), "%s.%s", name_from_finfo, ext); } else if(ext) { de_strlcpy(fn_suffix, ext, sizeof(fn_suffix)); } else if(is_directory && name_from_finfo) { de_snprintf(fn_suffix, sizeof(fn_suffix), "%s.dir", name_from_finfo); } else if(name_from_finfo) { de_strlcpy(fn_suffix, name_from_finfo, sizeof(fn_suffix)); } else if(is_directory) { de_strlcpy(fn_suffix, "dir", sizeof(fn_suffix)); } else { de_strlcpy(fn_suffix, "bin", sizeof(fn_suffix)); } de_snprintf(nbuf, sizeof(nbuf), "%s.%03d.%s", basefn, file_index, fn_suffix); } f->name = de_strdup(c, nbuf); if(fi) { // The finfo object passed to us at file creation is not required to // remain valid, so make a copy of anything in it that we might need // later. f->fi_copy = de_finfo_create(c); finfo_shallow_copy(c, fi, f->fi_copy); // Here's where we respect the -intz option, by using it to convert to // UTC in some cases. if(f->fi_copy->mod_time.is_valid && f->fi_copy->mod_time.tzcode==DE_TZCODE_LOCAL && c->input_tz_offs_seconds!=0) { de_timestamp_cvt_to_utc(&f->fi_copy->mod_time, -c->input_tz_offs_seconds); } if(f->fi_copy->image_mod_time.is_valid && f->fi_copy->image_mod_time.tzcode==DE_TZCODE_LOCAL && c->input_tz_offs_seconds!=0) { de_timestamp_cvt_to_utc(&f->fi_copy->image_mod_time, -c->input_tz_offs_seconds); } } if(file_index < c->first_output_file) { f->btype = DBUF_TYPE_NULL; goto done; } if(c->max_output_files>=0 && file_index >= c->first_output_file + c->max_output_files) { f->btype = DBUF_TYPE_NULL; goto done; } c->num_files_extracted++; if(c->extrlist_dbuf) { dbuf_printf(c->extrlist_dbuf, "%s\n", f->name); dbuf_flush(c->extrlist_dbuf); } if(c->list_mode) { f->btype = DBUF_TYPE_NULL; if(c->list_mode_include_file_id) { de_msg(c, "%d:%s", file_index, f->name); } else { de_msg(c, "%s", f->name); } goto done; } if(c->output_style==DE_OUTPUTSTYLE_ARCHIVE && c->archive_fmt==DE_ARCHIVEFMT_TAR) { de_info(c, "Adding %s to TAR file", f->name); f->btype = DBUF_TYPE_ODBUF; // A dummy max_len_hard value. The parent will do the checking. f->max_len_hard = DE_DUMMY_MAX_FILE_SIZE; f->writing_to_tar_archive = 1; de_tar_start_member_file(c, f); } else if(c->output_style==DE_OUTPUTSTYLE_ARCHIVE) { // ZIP i64 initial_alloc; de_info(c, "Adding %s to ZIP file", f->name); f->btype = DBUF_TYPE_MEMBUF; f->max_len_hard = DE_MAX_MEMBUF_SIZE; if(is_directory) { // A directory entry is not expected to have any data associated // with it (besides the files it contains). initial_alloc = 16; } else { initial_alloc = 65536; } f->membuf_buf = de_malloc(c, initial_alloc); f->membuf_alloc = initial_alloc; f->write_memfile_to_zip_archive = 1; } else if(c->output_style==DE_OUTPUTSTYLE_STDOUT) { de_info(c, "Writing %s to [stdout]", f->name); f->btype = DBUF_TYPE_STDOUT; // TODO: Should we increase f->max_len_hard? f->fp = stdout; } else { de_info(c, "Writing %s", f->name); f->btype = DBUF_TYPE_OFILE; f->fp = de_fopen_for_write(c, f->name, msgbuf, sizeof(msgbuf), c->overwrite_mode, 0); if(!f->fp) { de_err(c, "Failed to write %s: %s", f->name, msgbuf); f->btype = DBUF_TYPE_NULL; } } done: de_free(c, name_from_finfo); return f; }