Minor refactoring, related to lzah
[deark.git] / src / deark-user.c
blobcdf7e4956871795af1cfdca204345c441f97c7c5
1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // deark-user.c
6 //
7 // Functions in this file can be called by deark-cmd.c, but should not be called
8 // by anything in the library or modules (use deark-util.c instead).
10 #define DE_NOT_IN_MODULE
11 #include "deark-config.h"
12 #include "deark-private.h"
13 #include "deark-user.h"
15 #define DE_DEFAULT_MAX_FILE_SIZE 0x280000000LL // 10GiB
16 #define DE_DEFAULT_MAX_TOTAL_OUTPUT_SIZE 0x3c0000000LL // 15GiB
17 #define DE_DEFAULT_MAX_IMAGE_DIMENSION 10000
18 #define DE_DEFAULT_MAX_OUTPUT_FILES 1000 // Limit for direct output (not ZIP)
19 #define DE_MAX_OUTPUT_FILES_HARD_LIMIT 250000
21 // Returns the best module to use, by looking at the file contents, etc.
22 static struct deark_module_info *detect_module_for_file(deark *c, int *errflag)
24 int i;
25 int result;
26 int orig_errcount;
27 struct deark_module_info *best_module = NULL;
29 *errflag = 0;
30 if(!c->detection_data) {
31 c->detection_data = de_malloc(c, sizeof(struct de_detection_data_struct));
34 // This value is made available to modules' identification functions, so
35 // that they can potentially skip expensive tests that cannot possibly return
36 // a high enough confidence.
37 c->detection_data->best_confidence_so_far = 0;
39 orig_errcount = c->error_count;
40 for(i=0; i<c->num_modules; i++) {
41 if(c->module_info[i].identify_fn==NULL) continue;
43 // If autodetect is disabled for this module, and its autodetect routine
44 // doesn't do anything that may be needed by other modules, don't bother
45 // to run this module's autodetection.
46 if((c->module_info[i].flags & DE_MODFLAG_DISABLEDETECT) &&
47 !(c->module_info[i].flags & DE_MODFLAG_SHAREDDETECTION))
49 continue;
52 result = c->module_info[i].identify_fn(c);
54 if(c->error_count > orig_errcount) {
55 // Detection routines don't normally produce errors. If one does,
56 // it's probably an internal error, or other serious problem.
57 *errflag = 1;
58 return NULL;
61 if(c->module_info[i].flags & DE_MODFLAG_DISABLEDETECT) {
62 // Ignore results of autodetection.
63 continue;
66 if(result <= c->detection_data->best_confidence_so_far) continue;
68 // This is the best result so far.
69 c->detection_data->best_confidence_so_far = result;
70 best_module = &c->module_info[i];
71 if(c->detection_data->best_confidence_so_far>=100) break;
74 return best_module;
77 struct sort_data_struct {
78 deark *c;
79 int module_index;
82 static int module_compare_fn(const void *a, const void *b)
84 struct sort_data_struct *m1, *m2;
85 deark *c;
87 m1 = (struct sort_data_struct *)a;
88 m2 = (struct sort_data_struct *)b;
89 c = m1->c;
90 return de_strcasecmp(c->module_info[m1->module_index].id,
91 c->module_info[m2->module_index].id);
94 void de_print_module_list(deark *c)
96 int i, k;
97 struct sort_data_struct *sort_data = NULL;
99 de_register_modules(c);
101 // An index to the modules. Will be sorted by name.
102 sort_data = de_mallocarray(c, c->num_modules, sizeof(struct sort_data_struct));
104 for(k=0; k<c->num_modules; k++) {
105 sort_data[k].c = c;
106 sort_data[k].module_index = k;
109 qsort((void*)sort_data, (size_t)c->num_modules, sizeof(struct sort_data_struct),
110 module_compare_fn);
112 for(k=0; k<c->num_modules; k++) {
113 const char *desc;
114 i = sort_data[k].module_index;
115 if(!c->module_info[i].id) continue;
116 if(c->extract_level<2) {
117 if(c->module_info[i].flags & DE_MODFLAG_HIDDEN) continue;
118 if(c->module_info[i].flags & DE_MODFLAG_NONWORKING) continue;
120 desc = c->module_info[i].desc ? c->module_info[i].desc : "-";
121 de_printf(c, DE_MSGTYPE_MESSAGE, "%-14s %s\n", c->module_info[i].id, desc);
124 de_free(c, sort_data);
127 static void do_modhelp_internal(deark *c, struct deark_module_info *module_to_use)
129 int k;
131 if(!module_to_use) goto done;
132 de_msg(c, "Module: %s", module_to_use->id);
134 for(k=0; k<DE_MAX_MODULE_ALIASES; k++) {
135 if(module_to_use->id_alias[k]) {
136 de_msg(c, "Alias: %s", module_to_use->id_alias[k]);
138 else {
139 break;
143 if(module_to_use->desc) {
144 de_msg(c, "Description: %s", module_to_use->desc);
146 if(module_to_use->desc2) {
147 de_msg(c, "Other notes: %s", module_to_use->desc2);
150 if(!module_to_use->help_fn) {
151 de_msg(c, "No help available for module \"%s\"", module_to_use->id);
152 goto done;
155 de_msg(c, "Help for module \"%s\":", module_to_use->id);
156 module_to_use->help_fn(c);
158 done:
162 static void do_modhelp(deark *c)
164 struct deark_module_info *module_to_use = NULL;
166 de_register_modules(c);
167 module_to_use = de_get_module_by_id(c, c->input_format_req);
168 if(!module_to_use) {
169 de_err(c, "Unknown module \"%s\"", c->input_format_req);
170 goto done;
173 if(de_strcmp(c->input_format_req, module_to_use->id)) {
174 de_msg(c, "\"%s\" is an alias for module \"%s\"",
175 c->input_format_req, module_to_use->id);
178 do_modhelp_internal(c, module_to_use);
180 done:
184 void de_register_modules(deark *c)
186 // The real register_modules function (de_register_modules_internal) is
187 // only called indirectly, to help simplify dependencies.
188 if(!c->module_register_fn) {
189 de_internal_err_fatal(c, "module_register_fn not set");
190 return;
192 c->module_register_fn(c);
195 static void open_extrlist(deark *c)
197 unsigned int flags = 0;
199 if(c->extrlist_dbuf || !c->extrlist_filename) return;
201 if(de_get_ext_option(c, "extrlist:append")) {
202 flags |= 0x1;
205 c->extrlist_dbuf = dbuf_create_unmanaged_file(c, c->extrlist_filename,
206 DE_OVERWRITEMODE_STANDARD, flags);
209 // Returns 0 on "serious" error; e.g. input file not found.
210 int de_run(deark *c)
212 dbuf *orig_ifile = NULL;
213 dbuf *subfile = NULL;
214 i64 subfile_size;
215 struct deark_module_info *module_to_use = NULL;
216 int module_was_autodetected = 0;
217 int moddisp;
218 int subdirs_opt;
219 int keepdirentries_opt;
220 de_module_params *mparams = NULL;
221 de_ucstring *friendly_infn = NULL;
223 if(c->modhelp_req && c->input_format_req) {
224 do_modhelp(c);
225 goto done;
228 if(c->extrlist_filename) {
229 open_extrlist(c);
230 if(c->serious_error_flag) goto done;
233 friendly_infn = ucstring_create(c);
235 if(c->input_style==DE_INPUTSTYLE_STDIN) {
236 ucstring_append_sz(friendly_infn, "[stdin]", DE_ENCODING_LATIN1);
238 else {
239 if(!c->input_filename) {
240 de_internal_err_nonfatal(c, "Input file not set");
241 c->serious_error_flag = 1;
242 goto done;
244 ucstring_append_sz(friendly_infn, c->input_filename, DE_ENCODING_UTF8);
247 de_register_modules(c);
249 if(c->input_format_req) {
250 module_to_use = de_get_module_by_id(c, c->input_format_req);
251 if(!module_to_use) {
252 de_err(c, "Unknown module \"%s\"", c->input_format_req);
253 c->serious_error_flag = 1;
254 goto done;
258 if(c->slice_size_req_valid) {
259 de_dbg(c, "Input file: %s[%d,%d]", ucstring_getpsz_d(friendly_infn),
260 (int)c->slice_start_req, (int)c->slice_size_req);
262 else if(c->slice_start_req) {
263 de_dbg(c, "Input file: %s[%d]", ucstring_getpsz_d(friendly_infn),
264 (int)c->slice_start_req);
266 else {
267 de_dbg(c, "Input file: %s", ucstring_getpsz_d(friendly_infn));
270 if(c->input_style==DE_INPUTSTYLE_STDIN) {
271 orig_ifile = dbuf_open_input_stdin(c);
273 else {
274 orig_ifile = dbuf_open_input_file(c, c->input_filename);
276 if(orig_ifile && orig_ifile->btype==DBUF_TYPE_FIFO) {
277 // Only now do we know that the input "file" is a named pipe.
278 // Set a flag to remember that the input filename does not
279 // reflect the file format.
280 c->suppress_detection_by_filename = 1;
283 if(!orig_ifile) {
284 goto done;
287 c->infile = orig_ifile;
289 // If we are only supposed to look at a segment of the original file,
290 // do that by creating a child dbuf, using dbuf_open_input_subfile().
291 if(c->slice_start_req>0 || c->slice_size_req_valid) {
292 if(c->slice_size_req_valid)
293 subfile_size = c->slice_size_req;
294 else
295 subfile_size = c->infile->len - c->slice_start_req;
296 subfile = dbuf_open_input_subfile(c->infile, c->slice_start_req, subfile_size);
297 c->infile = subfile;
300 if(!module_to_use) {
301 int errflag;
303 module_to_use = detect_module_for_file(c, &errflag);
304 if(errflag) goto done;
305 module_was_autodetected = 1;
308 if(!module_to_use) {
309 if(c->infile->len==0)
310 de_err(c, "Unknown or unsupported file format (empty file)");
311 else
312 de_err(c, "Unknown or unsupported file format");
313 goto done;
316 if(c->modhelp_req && module_was_autodetected &&
317 module_to_use->unique_id!=1) // id 1 == "unsupported"
319 do_modhelp_internal(c, module_to_use);
320 goto done;
323 de_info(c, "Module: %s", module_to_use->id);
325 if(module_was_autodetected && (module_to_use->flags&DE_MODFLAG_SECURITYWARNING)) {
326 de_err(c, "The %s module has not been audited for security. There is a "
327 "greater than average chance that it is unsafe to use with untrusted "
328 "input files. Use \"-m %s\" to confirm that you want to use it.",
329 module_to_use->id, module_to_use->id);
330 c->serious_error_flag = 1;
331 goto done;
334 if(module_to_use->flags&DE_MODFLAG_NONWORKING) {
335 de_warn(c, "The %s module is considered to be incomplete, and may "
336 "not work properly. Caveat emptor.",
337 module_to_use->id);
340 if(c->identify_only) {
341 // Stop here, unless we're using the "unsupported" module.
342 if(module_to_use->unique_id!=1) {
343 goto done;
347 de_dbg2(c, "file size: %" I64_FMT "", c->infile->len);
349 if(c->output_style==DE_OUTPUTSTYLE_ARCHIVE) {
350 subdirs_opt = de_get_ext_option_bool(c, "archive:subdirs", -1);
351 if(subdirs_opt<0) {
352 // By default, for archive output, enable subdirs unless -o was used.
353 if(!c->base_output_filename) {
354 c->allow_subdirs = 1;
357 else {
358 c->allow_subdirs = subdirs_opt?1:0;
362 keepdirentries_opt = de_get_ext_option_bool(c, "keepdirentries", -1);
363 if(keepdirentries_opt<0) {
364 // By default, only keep dir entries if there is some way that
365 // files can be present in such a subdir.
366 c->keep_dir_entries = (u8)(
367 (c->output_style==DE_OUTPUTSTYLE_ARCHIVE) &&
368 c->allow_subdirs &&
369 (!c->base_output_filename));
371 else {
372 c->keep_dir_entries = keepdirentries_opt?1:0;
375 if(c->output_style==DE_OUTPUTSTYLE_ARCHIVE) {
376 const char *s_opt;
378 s_opt = de_get_ext_option(c, "archive:timestamp");
379 if(s_opt) {
380 c->reproducible_output = 1;
381 de_unix_time_to_timestamp(de_atoi64(s_opt), &c->reproducible_timestamp, 0x1);
382 if(!c->reproducible_timestamp.is_valid) {
383 // Timestamp out of range? Note: Supported range is
384 // -11644473599 ( 1601-01-01 00:00:01) through
385 // 910692730085 (30828-09-14 02:48:05)
386 c->reproducible_output = 0;
389 else {
390 if(de_get_ext_option(c, "archive:repro")) {
391 c->reproducible_output = 1;
396 if(c->output_style==DE_OUTPUTSTYLE_DIRECT &&
397 c->max_output_files > DE_DEFAULT_MAX_OUTPUT_FILES &&
398 !c->list_mode && !c->user_set_max_output_files)
400 c->max_output_files = DE_DEFAULT_MAX_OUTPUT_FILES;
403 // If we're writing to a zip file, we normally defer creating that zip file
404 // until we find a file to extract, so that we never create a zip file with
405 // no member files.
406 // But if the zip "file" is going to stdout, we'll make sure we produce zip
407 // output, even if it has no member files.
408 if(c->output_style==DE_OUTPUTSTYLE_ARCHIVE && c->archive_to_stdout) {
409 if(!de_archive_initialize(c)) {
410 goto done;
414 if(c->list_mode) {
415 if(de_get_ext_option_bool(c, "list:fileid", 0)) {
416 c->list_mode_include_file_id = 1;
420 if(c->modcodes_req) {
421 if(!mparams)
422 mparams = de_malloc(c, sizeof(de_module_params));
423 // This is a hack, mainly for developer use. It lets the user set the
424 // "module codes" string from the command line, so that some modules
425 // can be run in special modes. For example, you can run the psd module
426 // in its "tagged blocks" mode. (If that turns out to be useful, though,
427 // it would be better to make it available via an "-opt" option, or
428 // even a new module.)
429 mparams->in_params.codes = c->modcodes_req;
432 if(module_was_autodetected)
433 moddisp = DE_MODDISP_AUTODETECT;
434 else
435 moddisp = DE_MODDISP_EXPLICIT;
437 if(!de_run_module(c, module_to_use, mparams, moddisp)) {
438 goto done;
441 // The DE_MODFLAG_NOEXTRACT flag means the module is not expected to extract
442 // any files.
443 if(c->num_files_extracted==0 && c->error_count==0 &&
444 !(module_to_use->flags&DE_MODFLAG_NOEXTRACT))
446 de_info(c, "No files found to extract!");
449 done:
450 if(c->extrlist_dbuf) { dbuf_close(c->extrlist_dbuf); c->extrlist_dbuf=NULL; }
451 ucstring_destroy(friendly_infn);
452 if(subfile) dbuf_close(subfile);
453 if(orig_ifile) dbuf_close(orig_ifile);
454 de_free(c, mparams);
455 return c->serious_error_flag ? 0 : 1;
458 deark *de_create_internal(void)
460 deark *c;
461 c = de_malloc(NULL,sizeof(deark));
462 c->show_infomessages = 1;
463 c->show_warnings = 1;
464 c->write_bom = 1;
465 c->write_density = 1;
466 c->filenames_from_file = 1;
467 c->preserve_file_times = 1;
468 c->preserve_file_times_archives = 1;
469 c->preserve_file_times_internal = 1;
470 c->max_output_files = DE_MAX_OUTPUT_FILES_HARD_LIMIT;
471 c->max_image_dimension = DE_DEFAULT_MAX_IMAGE_DIMENSION;
472 c->max_output_file_size = DE_DEFAULT_MAX_FILE_SIZE;
473 c->max_total_output_size = DE_DEFAULT_MAX_TOTAL_OUTPUT_SIZE;
474 c->current_time.is_valid = 0;
475 c->can_decode_fltpt = -1; // = unknown
476 c->host_is_le = -1; // = unknown
477 c->input_encoding = DE_ENCODING_UNKNOWN;
478 return c;
481 void de_destroy(deark *c)
483 i64 i;
485 if(!c) return;
486 if(c->zip_data) { de_zip_close_file(c); }
487 if(c->tar_data) { de_tar_close_file(c); }
488 if(c->extrlist_dbuf) { dbuf_close(c->extrlist_dbuf); }
489 for(i=0; i<c->num_ext_options; i++) {
490 de_free(c, c->ext_option[i].name);
491 de_free(c, c->ext_option[i].val);
493 if(c->base_output_filename) { de_free(c, c->base_output_filename); }
494 if(c->special_1st_filename) { de_free(c, c->special_1st_filename); }
495 if(c->output_archive_filename) { de_free(c, c->output_archive_filename); }
496 if(c->extrlist_filename) { de_free(c, c->extrlist_filename); }
497 if(c->detection_data) { de_free(c, c->detection_data); }
498 de_free(c, c->module_info);
499 de_free(NULL,c);
502 void de_set_userdata(deark *c, void *x)
504 c->userdata = x;
507 void *de_get_userdata(deark *c)
509 return c->userdata;
512 void de_set_messages_callback(deark *c, de_msgfn_type fn)
514 c->msgfn = fn;
517 void de_set_special_messages_callback(deark *c, de_specialmsgfn_type fn)
519 c->specialmsgfn = fn;
522 void de_set_fatalerror_callback(deark *c, de_fatalerrorfn_type fn)
524 c->fatalerrorfn = fn;
527 static int is_pathsep(i32 ch)
529 if(ch=='/') return 1;
530 #ifdef DE_WINDOWS
531 if(ch=='\\') return 1;
532 #endif
533 return 0;
536 #ifdef DE_WINDOWS
537 #define DE_PATHSEP '\\'
538 #else
539 #define DE_PATHSEP '/'
540 #endif
542 static const char *get_basename_ptr(const char *fn)
544 size_t i;
545 const char *basenameptr = fn;
547 for(i=0; fn[i]; i++) {
548 if(is_pathsep(fn[i])) {
549 basenameptr = &fn[i+1];
552 return basenameptr;
555 static i32 ucstring_char_at(de_ucstring *s, i64 pos)
557 if(!s) return 0;
558 if(pos>=0 && pos<s->len) return s->str[pos];
559 return 0;
562 #ifdef DE_WINDOWS
563 static void backslashes_to_slashes(de_ucstring *s)
565 i64 i;
567 for(i=0; i<s->len; i++) {
568 if(s->str[i]=='\\') {
569 s->str[i] = '/';
573 #endif
575 // Construct a basename for output files, or a filename for archives.
576 // flags:
577 // 0x1 = use base filename only
578 // 0x2 = remove path separators
579 // 0x4 = this is an "internal" filename for a zip/tar archive
580 // Returns an allocated string, which the caller must eventually free.
581 // Returns NULL if it can't make a decent filename.
582 static char *make_output_filename(deark *c, const char *dirname, const char *fn,
583 const char *suffix, unsigned int flags)
585 char *newfn = NULL;
586 const char *fn_part;
587 size_t newfn_alloc;
588 de_ucstring *tmps = NULL;
589 i64 fnpartpos;
591 tmps = ucstring_create(c);
593 if(dirname && dirname[0]) {
594 ucstring_append_sz(tmps, dirname, DE_ENCODING_UTF8);
595 if(!is_pathsep(ucstring_char_at(tmps, tmps->len-1))) {
596 ucstring_append_char(tmps, DE_PATHSEP);
600 fnpartpos = tmps->len;
602 if(flags & 0x1) {
603 // Use base filename only
604 fn_part = get_basename_ptr(fn);
606 else {
607 fn_part = fn;
609 if(fn_part) {
610 ucstring_append_sz(tmps, fn_part, DE_ENCODING_UTF8);
613 if(tmps->len <= fnpartpos) {
614 // Disallow empty filename
615 ucstring_append_sz(tmps, "_", DE_ENCODING_LATIN1);
618 if(suffix) {
619 ucstring_append_sz(tmps, suffix, DE_ENCODING_UTF8);
622 if(flags & 0x2) {
623 // Remove path separators; sanitize
624 i64 i;
626 for(i=fnpartpos; i<tmps->len; i++) {
627 if(is_pathsep(tmps->str[i])) {
628 tmps->str[i] = '_';
631 if(i==fnpartpos && tmps->str[i]=='.') {
632 tmps->str[i] = '_';
637 #ifdef DE_WINDOWS
638 if(flags & 0x4) {
639 // When a filename-like option is supplied on the command line, there are
640 // cases where we can't be agnostic about which characters are path
641 // separators. One of them is when that name is written to an archive
642 // (zip/tar) file.
643 // Our rule is that, for Windows builds, both "\" and "/" are path
644 // separators. For Unix builds, only "/" is, and "\" will be treated as
645 // an ordinary filename character, if allowed by the archive format.
646 // This difference in behavior on different platforms is unfortunate, but
647 // I think it's the least bad thing to do.
648 backslashes_to_slashes(tmps);
650 #endif
652 // Don't allow empty filename
653 if(tmps->len<1) goto done;
655 newfn_alloc = (size_t)ucstring_count_utf8_bytes(tmps) + 1;
656 newfn = de_malloc(c, newfn_alloc);
657 ucstring_to_sz(tmps, newfn, newfn_alloc, 0, DE_ENCODING_UTF8);
659 done:
660 ucstring_destroy(tmps);
661 return newfn;
664 // Must call de_set_output_style() before this, if at all.
665 // flags:
666 // 0x1 = use base filename only
667 // 0x2 = remove path separators
668 void de_set_output_filename_pattern(deark *c, const char *dirname, const char *fn,
669 unsigned int flags)
671 if(c->base_output_filename) de_free(c, c->base_output_filename);
672 c->base_output_filename = NULL;
673 if(!fn && !dirname) return;
674 if(!fn) fn = "output";
675 if(c->output_style==DE_OUTPUTSTYLE_ARCHIVE) {
676 flags |= 0x4;
678 c->base_output_filename = make_output_filename(c, dirname, fn, NULL, flags);
681 // Use exactly fn for the first output file (no ".000.")
682 // Must call de_set_output_style() before this, if at all.
683 void de_set_output_special_1st_filename(deark *c, const char *dirname, const char *fn)
685 if(c->special_1st_filename) {
686 de_free(c, c->special_1st_filename);
687 c->special_1st_filename = NULL;
689 if(fn) {
690 UI flags = 0;
692 if(c->output_style==DE_OUTPUTSTYLE_ARCHIVE) {
693 flags |= 0x4;
696 c->special_1st_filename = make_output_filename(c, dirname, fn, NULL, flags);
700 // If flags&0x10, configure the archive file to be written to stdout.
701 // 0x20 = Append ".zip"/".tar" (must have already called de_set_output_style())
702 // 0x1 = use base filename only
703 // 0x2 = remove path separators
704 void de_set_output_archive_filename(deark *c, const char *dname, const char *fn,
705 unsigned int flags)
707 const char *suffix = NULL;
708 if(c->output_archive_filename) de_free(c, c->output_archive_filename);
710 if(flags&0x10) {
711 c->archive_to_stdout = 1;
712 return;
715 if((flags & 0x20) && c->output_style==DE_OUTPUTSTYLE_ARCHIVE) {
716 if(c->archive_fmt==DE_ARCHIVEFMT_ZIP) {
717 suffix = ".zip";
719 else if(c->archive_fmt==DE_ARCHIVEFMT_TAR) {
720 suffix = ".tar";
722 else {
723 suffix = ".err";
727 c->output_archive_filename = make_output_filename(c, dname, fn, suffix, flags);
730 void de_set_extrlist_filename(deark *c, const char *fn)
732 if(c->extrlist_filename) de_free(c, c->extrlist_filename);
733 c->extrlist_filename = NULL;
734 if(fn) {
735 c->extrlist_filename = de_strdup(c, fn);
739 void de_set_std_option_int(deark *c, enum de_stdoptions_enum o, int x)
741 switch(o) {
742 case DE_STDOPT_DEBUG_LEVEL:
743 c->debug_level = x;
744 break;
745 case DE_STDOPT_EXTRACT_POLICY:
746 c->extract_policy = x;
747 break;
748 case DE_STDOPT_EXTRACT_LEVEL:
749 c->extract_level = x;
750 break;
751 case DE_STDOPT_LISTMODE:
752 c->list_mode = x?1:0;
753 break;
754 case DE_STDOPT_WANT_MODHELP:
755 c->modhelp_req = x?1:0;
756 break;
757 case DE_STDOPT_ID_MODE:
758 c->identify_only = x?1:0;
759 break;
760 case DE_STDOPT_WARNINGS:
761 c->show_warnings = x;
762 break;
763 case DE_STDOPT_INFOMESSAGES:
764 c->show_infomessages = x;
765 break;
766 case DE_STDOPT_WRITE_BOM:
767 c->write_bom = (u8)x;
768 break;
769 case DE_STDOPT_WRITE_DENSITY:
770 c->write_density = (u8)x;
771 break;
772 case DE_STDOPT_ASCII_HTML:
773 c->ascii_html = (u8)x;
774 break;
775 case DE_STDOPT_FILENAMES_FROM_FILE:
776 c->filenames_from_file = (u8)x;
777 break;
778 case DE_STDOPT_OVERWRITE_MODE:
779 c->overwrite_mode = x;
780 break;
781 case DE_STDOPT_PADPIX:
782 c->padpix = (u8)x;
783 break;
784 default:
785 de_internal_err_fatal(c, "set_std_option");
789 void de_set_input_style(deark *c, int x)
791 c->input_style = x;
794 void de_set_input_filename(deark *c, const char *fn)
796 c->input_filename = fn;
799 int de_set_input_encoding(deark *c, const char *encname, int reserved)
801 de_encoding enc;
803 enc = de_encoding_name_to_code(encname);
804 if(enc==DE_ENCODING_UNKNOWN) {
805 return 0;
807 c->input_encoding = enc;
808 return 1;
811 // A hint as to the timezone of local-time timestamps in input files.
812 // In hours east of UTC.
813 void de_set_input_timezone(deark *c, i64 tzoffs_seconds)
815 c->input_tz_offs_seconds = tzoffs_seconds;
818 void de_set_input_file_slice_start(deark *c, i64 n)
820 c->slice_start_req = n;
823 void de_set_input_file_slice_size(deark *c, i64 n)
825 c->slice_size_req = n;
826 c->slice_size_req_valid = 1;
829 void de_set_output_style(deark *c, int x, int subtype)
831 c->output_style = x;
832 if(c->output_style==DE_OUTPUTSTYLE_ARCHIVE) {
833 c->archive_fmt = subtype;
835 else {
836 c->archive_fmt = 0;
840 void de_set_dprefix(deark *c, const char *s)
842 c->dprefix = s;
845 void de_set_first_output_file(deark *c, int x)
847 c->first_output_file = x;
850 void de_set_max_output_files(deark *c, i64 n)
852 if(n>DE_MAX_OUTPUT_FILES_HARD_LIMIT) {
853 c->max_output_files = DE_MAX_OUTPUT_FILES_HARD_LIMIT;
855 else if(n<0) {
856 c->max_output_files = 0;
858 else {
859 c->max_output_files = (int)n;
861 c->user_set_max_output_files = 1;
864 void de_set_max_output_file_size(deark *c, i64 n)
866 if(n<0) n=0;
867 c->max_output_file_size = n;
868 if(c->max_total_output_size < n) {
869 c->max_total_output_size = n;
873 void de_set_max_total_output_size(deark *c, i64 n)
875 if(n<0) n=0;
876 c->max_total_output_size = n;
879 void de_set_max_image_dimension(deark *c, i64 n)
881 if(n<0) n=0;
882 else if (n>0x7fffffff) n=0x7fffffff;
883 c->max_image_dimension = n;
886 void de_set_preserve_file_times(deark *c, int setting, int x)
888 if(setting==0) {
889 // For files written directly to the filesystem.
890 c->preserve_file_times = x?1:0;
892 else if(setting==1) {
893 // For member files written to .zip/.tar files.
894 // I can't think of a good reason why a user would want to disable
895 // this, but it's allowed for consistency, and it doesn't hurt
896 // anything.
897 c->preserve_file_times_archives = x?1:0;
899 else if(setting==2) {
900 // For the tIME chunk in PNG files we generate, and other internal timestamps.
901 // (Not currently used.)
902 // TODO: I'm undecided about whether this should be a user option, or
903 // just always be on.
904 // TODO: If we allow this setting to be turned off, it would be
905 // consistent to rename it, and use it for all "converted" formats,
906 // including e.g. the "Date" header item in ANSI Art files converted
907 // to HTML.
908 c->preserve_file_times_internal = x?1:0;
912 void de_set_ext_option(deark *c, const char *name, const char *val)
914 int n;
916 n = c->num_ext_options;
917 if(n>=DE_MAX_EXT_OPTIONS) return;
918 if(!name || !val) return;
920 c->ext_option[n].name = de_strdup(c, name);
921 c->ext_option[n].val = de_strdup(c, val);
922 c->num_ext_options++;
925 void de_set_input_format(deark *c, const char *fmtname)
927 c->input_format_req = fmtname;
930 void de_set_module_init_codes(deark *c, const char *codes)
932 c->modcodes_req = codes;
935 // invert=0: Disable the mods in the list
936 // invert=1: Disable all mods not in the list
937 void de_set_disable_mods(deark *c, const char *s, int invert)
939 if(invert==0) {
940 c->disablemods_string = s;
942 else {
943 c->onlymods_string = s;
947 // invert=0: Disable autodetection of the mods in the list
948 // invert=1: Disable autodetection of all mods not in the list
949 void de_set_disable_moddetect(deark *c, const char *s, int invert)
951 if(invert==0) {
952 c->nodetectmods_string = s;
954 else {
955 c->onlydetectmods_string = s;