diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /graphics/sam2p/sam2p_main.cpp |
Initial commit
Diffstat (limited to 'graphics/sam2p/sam2p_main.cpp')
-rw-r--r-- | graphics/sam2p/sam2p_main.cpp | 1118 |
1 files changed, 1118 insertions, 0 deletions
diff --git a/graphics/sam2p/sam2p_main.cpp b/graphics/sam2p/sam2p_main.cpp new file mode 100644 index 0000000000..5b39a6c19a --- /dev/null +++ b/graphics/sam2p/sam2p_main.cpp @@ -0,0 +1,1118 @@ +/* sam2p_main.cpp + * by pts@fazekas.hu at Fri Mar 15 16:11:03 CET 2002 + */ + +#include "gensi.hpp" +#include "gensio.hpp" +#include "image.hpp" +#include "error.hpp" +#include "encoder.hpp" +#include "minips.hpp" +#include "rule.hpp" +#include "main.hpp" +#include "in_jai.hpp" + +#ifndef SAM2P_VERSION +#include "sam2p_version.h" +#endif + +/* Sat Jul 6 16:39:19 CEST 2002 + * empirical checkerg++ helper routines for gcc version 2.95.2 20000220 (Debian GNU/Linux) + * see c_lgcc.cpp for more + */ +#if !defined(OBJDEP) && defined(__CHECKER__) && !HAVE_PTS_C_LGCC_CPP_REQUIRED +# include "c_lgcc.cpp" +#endif + +#if 0 /*#ifdef __CHECKER__*/ +#include <stdlib.h> +void* __builtin_vec_new(unsigned len){ return malloc(len); } +void __builtin_vec_delete(void *p) { free(p); } +void* __builtin_new(unsigned len){ return malloc(len); } +void __builtin_delete(void *p) { free(p); } +void __rtti_user() { abort(); } +void __rtti_si() { abort(); } +void terminate() { abort(); } +extern "C" void __pure_virtual(); +void __pure_virtual() { abort(); } +#endif + +#if OBJDEP +# warning PROVIDES: sam2p_main +# warning REQUIRES: gensi.o +# warning REQUIRES: gensio.o +# warning REQUIRES: image.o +# warning REQUIRES: error.o +# warning REQUIRES: encoder.o +# warning REQUIRES: minips.o +# warning REQUIRES: rule.o +#endif + +#include <stdio.h> +#include <string.h> /* memset() */ + +#if OBJDEP +# warning REQUIRES: in_tiff.o +# warning REQUIRES: in_jpeg.o +# warning REQUIRES: in_png.o +# warning REQUIRES: in_jai.o +# warning REQUIRES: in_pcx.o +# warning REQUIRES: in_xpm.o +# warning REQUIRES: in_lbm.o +# warning REQUIRES: in_gif.o +# warning REQUIRES: in_bmp.o +# warning REQUIRES: in_pnm.o +# warning REQUIRES: in_tga.o +/*# warning REQUIRES: in_pdf.o Dat: no more, integrated to in_ps.o */ +# warning REQUIRES: in_ps.o +#endif +extern Image::Loader in_tiff_loader; +extern Image::Loader in_jpeg_loader; +extern Image::Loader in_png_loader; +extern Image::Loader in_jai_loader; +extern Image::Loader in_pcx_loader; +extern Image::Loader in_xpm_loader; +extern Image::Loader in_lbm_loader; +extern Image::Loader in_gif_loader; +extern Image::Loader in_bmp_loader; +extern Image::Loader in_pnm_loader; +extern Image::Loader in_tga_loader; +extern Image::Loader in_pdf_loader; +extern Image::Loader in_ps_loader; +void init_loader() { + static bool had_init_loader=false; + if (had_init_loader) return; + Image::register0(&in_tga_loader); /* checker not sure; install early */ + Image::register0(&in_pcx_loader); + Image::register0(&in_xpm_loader); + Image::register0(&in_lbm_loader); + Image::register0(&in_gif_loader); + Image::register0(&in_bmp_loader); + Image::register0(&in_pnm_loader); + Image::register0(&in_tiff_loader); + Image::register0(&in_jpeg_loader); + Image::register0(&in_png_loader); + Image::register0(&in_jai_loader); + Image::register0(&in_pdf_loader); + Image::register0(&in_ps_loader); + had_init_loader=true; +} + +#if OBJDEP +# warning REQUIRES: appliers.o +#endif +extern Rule::Applier out_pnm_applier; +extern Rule::Applier out_jpeg_applier; +extern Rule::Applier out_jpegjai_applier; +extern Rule::Applier out_tiffjai_applier; +extern Rule::Applier out_tiff_applier; +extern Rule::Applier out_png_applier; +extern Rule::Applier out_bmp_applier; +extern Rule::Applier out_gif89a_applier; +extern Rule::Applier out_xpm_applier; +extern Rule::Applier out_l1c_applier; +// extern Rule::Applier out_l1op_applier; +extern Rule::Applier out_l1tr_applier; +extern Rule::Applier out_l23_applier; +// extern Rule::Applier out_l1fa85g_applier; +extern Rule::Applier out_l2jbin_applier; +// extern Rule::Applier out_p0jbin_applier; +extern Rule::Applier out_empty_applier; +extern Rule::Applier out_meta_applier; +extern Rule::Applier out_xwd_applier; +extern Rule::Applier out_x11_applier; +void init_applier() { + static bool had_init_applier=false; + if (had_init_applier) return; + // Rule::register0(&out_l1op_applier); + Rule::register0(&out_l1tr_applier); + // Rule::register0(&out_l1fa85g_applier); + Rule::register0(&out_l2jbin_applier); + // Rule::register0(&out_p0jbin_applier); + Rule::register0(&out_l23_applier); + Rule::register0(&out_l1c_applier); + Rule::register0(&out_xpm_applier); + Rule::register0(&out_gif89a_applier); + Rule::register0(&out_pnm_applier); + Rule::register0(&out_jpeg_applier); + Rule::register0(&out_jpegjai_applier); + Rule::register0(&out_tiffjai_applier); + Rule::register0(&out_tiff_applier); + Rule::register0(&out_png_applier); + Rule::register0(&out_bmp_applier); + Rule::register0(&out_empty_applier); + Rule::register0(&out_meta_applier); + Rule::register0(&out_xwd_applier); + Rule::register0(&out_x11_applier); + had_init_applier=true; +} + +static char bts_ttt[] = +#include "bts2.tth" +; + +/* --- One-liner mode */ + +/** Dat: mod 16 does matter: expected # args etc. */ +static const unsigned + OPT_unknown=0, + OPT_SampleFormat=0x02, + OPT_LoadHints=0x12, + OPT_Compression=0x22, + OPT_TransferEncoding=0x32, + OPT_TransferEncodingF=0x42, + // OPT_Asis=0x50, + OPT_PSL1=0x60, + OPT_PSLC=0x70, + OPT_PSL2=0x80, + OPT_PSL3=0x90, + OPT_PS=0xA1, + OPT_PDF=0xB1, + OPT_DisplayJobFile=0xC1, + OPT_Hints=0xD2, + // OPT_InputFile=0xE2, + OPT_OutputFile=0xF2, + OPT_Scale=0x101, + OPT_Margins=0x112, + OPT_Transparent=0x122, + OPT_TmpRemove=0x132; + +/** @param s an option (lower/upper case intact), without leading `-'s + * @param slen length of option + * @return 0 if invalid/unsupported/unknown option + * | 16*(k+1)+0 if the option never accepts parameters + * | 16*(k+2)+1 if the option may or may not have a parameter + * | 16*(k+3)+2 if the option must have a parameter + */ +static unsigned sam2p_optval(char const* s, slen_t slen) { + if (slen==1) { + switch (s[0]) { + case 's': return OPT_SampleFormat; + case 'l': return OPT_LoadHints; + case 'h': return OPT_Hints; + case 't': return OPT_TransferEncoding; + case 'f': return OPT_TransferEncodingF; + case 'c': return OPT_Compression; + // case 'a': return OPT_Asis; /* disabled, automatic! */ + case '1': return OPT_PSL1; + case '2': return OPT_PSL2; + case '3': return OPT_PSL3; + case 'j': return OPT_DisplayJobFile; + case 'o': case 'O': return OPT_OutputFile; + case 'e': return OPT_Scale; + case 'm': return OPT_Margins; + } + } else { + slen_t len=slen; /* strlen(s); */ + if (len>=32) return OPT_unknown; + char buf[32]; + GenBuffer::tolower_memcpy(buf, s, len); + buf[len]='\0'; + /* printf("buf=(%s)\n", buf); */ + if (0==strcmp(buf, "sampleformat")) return OPT_SampleFormat; + if (0==strcmp(buf, "loadhints")) return OPT_LoadHints; + if (0==strcmp(buf, "tmpremove")) return OPT_TmpRemove; + if (0==strcmp(buf, "transparent")) return OPT_Transparent; + if (0==strcmp(buf, "hints")) return OPT_Hints; + if (0==strcmp(buf, "ps") + || 0==strcmp(buf, "eps")) return OPT_PS; + if (0==strcmp(buf, "pdf")) return OPT_PDF; + if (0==strcmp(buf, "1c")) return OPT_PSLC; + if (0==strcmp(buf, "scale")) return OPT_Scale; + if (0==strcmp(buf, "hints")) return OPT_Margins; + } + return OPT_unknown; +} + +static void displayJob(GenBuffer::Writable &sout, SimBuffer::Flat const& jobss) { + fflush(stdout); fflush(stderr); + #if 0 + puts("\n\n% begin sam2p job dump"); + fwrite(stdout, 1, jobss.getLength(), jobss); + puts("% end sam2p job dump\n"); + #else + /* vvv Dat: sout conflicts /OutputFile(-), but it is OK here */ + sout << "\n% begin sam2p job dump\n" + << jobss + << "%)%)%)% end sam2p job dump\n\n"; + #endif + fflush(stdout); fflush(stderr); +} + +static inline char const *protect_null(char const *s) { + return s==(char const*)NULLP ? "//" : s; +} + +/** @return the value for the parameter if matches key or the first letter of + * key; or NULLP if no match. + * @param key lower case + */ +static char const*one_pabbr(char const*param, char const *key) { + return GenBuffer::nocase_strbegins(param, key) ? param+strlen(key) + : (param[0]==key[0] || param[0]==key[0]+'A'-'a') && param[1]==':' ? param+2 + : (char const*)NULLP; +} + +#if 0 /* cannot set badp... */ +static inline void one_setdimen2(char const*&Dimen1, char const*&Dimen2, char const*p2) { + if (MiniPS::Real::isDimen(p2)) Dimen1=Dimen2=p2; + else Error::sev(Error::ERROR_CONT) << "one_liner: dimen expected" /*<< (SimBuffer::B().appendDumpC(p2, true))*/ << (Error*)0; +} +#endif +#if 0 +#define one_setdimen2(Dimen1,Dimen2,p2) do { \ + if (MiniPS::Real::isDimen(p2)) Dimen1=Dimen2=p2; \ + else { badmsg="one_liner: dimen expected: "; goto bad_label; } \ +} while(0) +#endif + +static Filter::UngetFILED *ufd; +static bool do_DisplayJobFile; +static bool buildProfile_quiet=false; +/** Creates an in-memory job file according to the command-line options. + * @param a argv+1 + * @param job initially an empty string. On error, this function leaves it + * as-is, but on success, a valid job file is appened. + * @return true on syntax error + */ +static bool one_liner(SimBuffer::B &jobss, char const *const* a) { + /* Tue Jul 2 21:27:15 CEST 2002 */ + char const *p, *pend; + bool no_option_term=true; + bool badp=false; + bool no_selector=true; + char const *badmsg; + // SimBuffer::B Profile /* MiniPS code */ + SimBuffer::B Hints; /* MiniPS code */ + /* ^^^ Imp: separate hint for each -c arg?? */ + SimBuffer::B LoadHints; + bool TmpRemove_p=true; + Rule::Cache::pr_t Predictor=Rule::Cache::PR_None; /* Imp: separate for each Compression */ + Rule::Cache::ff_t FileFormat=Rule::Cache::FF_default; + Rule::Cache::te_t TransferEncoding=Rule::Cache::TE_default; + do_DisplayJobFile=false; + bool do_stop_SampleFormat=false; + char const *Transparent=(char const*)NULLP; /* change 1 color to transparent unless NULL */ + char const *OutputFile=(char const*)NULLP, *InputFile=(char const*)NULLP; + // SimBuffer::B tmp; + char const *TopMargin=(char const*)NULLP, *BottomMargin=(char const*)NULLP, + *LeftMargin=(char const*)NULLP, *RightMargin=(char const*)NULLP, + *LowerMargin=(char const*)NULLP, *ImageDPI=(char const*)NULLP; + bool negLowerMargin=false; + Rule::CacheHints::sc_t Scale=Rule::CacheHints::SC_default; + #define APPEND_sf(val) do { if (sfx[val]==0) { sfx[val]=1; sft[sflen++]=val; } } while (0) + Image::sf_t sft[Image::SF_max+1]; char sfx[Image::SF_max+1]; memset(sfx, 0, sizeof(sfx)); unsigned sflen=0; + #define APPEND_co(val) do { if (cox[val]==0) { cox[val]=1; cot[colen++]=val; } } while (0) + Rule::Cache::co_t cot[Rule::Cache::CO_max+1]; char cox[Image::SF_max+1]; memset(cox, 0, sizeof(cox)); unsigned colen=0; + /* ^^^ BUGFIX at 2002.12.02 */ + + /** OPT_* value of current option */ + unsigned opt; + /** Parameter for current option. May be NULL. */ + char const *param=""; /* pacify VC6.0 */ + char const *p2; + slen_t paramlen; + SimBuffer::B tmpnam; /* any dir -- keep on stack frame */ + + buildProfile_quiet=true; + + for (; (p=*a)!=(char const*)NULLP; a++) { + if (p[0]=='-' && p[1]=='\0') { /* `-': Filename: STDIN or STDOUT */ + #if 1 + goto normal_label; + #else + Error::sev(Error::ERROR_CONT) << "one_liner: `-' (stdin|stdout) not allowed as filename" << (Error*)0; + badp=true; + continue; + #endif + } else if (p[0]=='-' && p[1]=='-' && p[2]=='\0') { /* `--': No more options */ + if (a[1]==(char const*)NULLP && InputFile!=(char const*)NULLP) { /* `--' is last argument */ + p=InputFile; /* OutputFile:=InputFile */ + goto normal_label; + } + no_option_term=false; + } else if (p[0]=='-' && no_option_term) { /* an option */ + while (*p=='-') p++; /* short options (-p) and long options (--pdf) are equivalent */ + pend=p; while (*pend!='\0' && *pend!=':' && *pend!='=') pend++; + SimBuffer::Static optss(p, pend-p); + if (0==(opt=sam2p_optval(p, pend-p))) { + badmsg="one_liner: unknown option: "; + bad_label: + Error::sev(Error::ERROR_CONT) << badmsg << (SimBuffer::B().appendDumpC(optss, true)) << (Error*)0; + badp=true; + continue; + } + if ((opt&15)==0) { /* no parameters */ + if (*pend!='\0') { badmsg="one_liner: don't give param to option: "; goto bad_label; } + param=(char const*)NULLP; + } else if ((opt&15)==1) { /* an optional parameter */ + if (*pend!='\0') { + param=pend+1; while (*pend==*param) param++; + } else param=(char const*)NULLP; + } else if ((opt&15)==2) { /* a mandatory parameter */ + if (*pend!='\0') { + param=pend+1; while (*pend==*param) param++; + } else if ((param=*++a)==(char const*)NULLP) { badmsg="one_liner: missing param for option: "; goto bad_label; } + } else assert(0); + paramlen=param==(char const*)NULLP ? 0 : strlen(param); + + /* Dat: now opt, paramlen and param are correct */ + switch (opt) { + case OPT_LoadHints: LoadHints << ',' << param; break; + case OPT_TmpRemove: TmpRemove_p=GenBuffer::parseBool(param, paramlen); break; + case OPT_Transparent: Transparent=param; break; /* Imp: is this good memory management */ + case OPT_Hints: Hints << '\n' << param; break; + case OPT_PSL1: FileFormat=Rule::Cache::FF_PSL1; break; + case OPT_PSLC: FileFormat=Rule::Cache::FF_PSLC; break; + case OPT_PSL2: FileFormat=Rule::Cache::FF_PSL2; break; + case OPT_PSL3: FileFormat=Rule::Cache::FF_PSL3; break; + case OPT_DisplayJobFile: + // fprintf(stderr, "param=(%s)\n", param); + if (paramlen==0 || 0==GenBuffer::nocase_strcmp(param, "job")) do_DisplayJobFile=true; + else if (0==GenBuffer::nocase_strcmp(param, "warn")) buildProfile_quiet=false; + else if (GenBuffer::nocase_strbegins(param, "warn:")) buildProfile_quiet=!GenBuffer::parseBool(param+5, paramlen-5); + else if (0==GenBuffer::nocase_strcmp(param, "quiet")) { buildProfile_quiet=true; Error::setTopPrinted(Error::ERROR_CONT); } /* Dat: hide warnings, info etc. */ /* at Fri Aug 26 07:54:00 CEST 2005 */ + else if (GenBuffer::nocase_strbegins(param, "job:")) do_DisplayJobFile=GenBuffer::parseBool(param+4, paramlen-4); + else do_DisplayJobFile=GenBuffer::parseBool(param, paramlen); /* Imp: better error report */ + break; + case OPT_Margins: + /* Dat:abbreviation letters are distinct: [ahxvylrtubd] */ + if (0!=(p2=one_pabbr(param,"all:"))) { all5: + if (MiniPS::Real::isDimen(p2)) LeftMargin=RightMargin=TopMargin=BottomMargin=LowerMargin=p2; + else { err_dimexp: badmsg="one_liner: dimen expected: "; goto bad_label; } + } + else if (0!=(p2=one_pabbr(param,"horiz:")) + || 0!=(p2=one_pabbr(param,"x:"))) { if (MiniPS::Real::isDimen(p2)) LeftMargin=RightMargin=p2; else goto err_dimexp; } + else if (0!=(p2=one_pabbr(param,"vert:")) + || 0!=(p2=one_pabbr(param,"y:"))) { if (MiniPS::Real::isDimen(p2)) TopMargin=BottomMargin=LowerMargin=p2; else goto err_dimexp; } + else if (0!=(p2=one_pabbr(param,"left:"))) { if (MiniPS::Real::isDimen(p2)) LeftMargin=p2; else goto err_dimexp; } + else if (0!=(p2=one_pabbr(param,"right:"))) { if (MiniPS::Real::isDimen(p2)) RightMargin=p2; else goto err_dimexp; } + else if (0!=(p2=one_pabbr(param,"dpi:"))) { if (MiniPS::Real::isDimen(p2)) ImageDPI=p2; else goto err_dimexp; } + else if (0!=(p2=one_pabbr(param,"top:")) + || 0!=(p2=one_pabbr(param,"up:"))) { if (MiniPS::Real::isDimen(p2)) TopMargin=p2; else goto err_dimexp; } + else if (0!=(p2=one_pabbr(param,"bottom:")) + || 0!=(p2=one_pabbr(param,"down:"))) { if (MiniPS::Real::isDimen(p2)) BottomMargin=LowerMargin=p2; else goto err_dimexp; } + else if (0!=(p2=one_pabbr(param,"raise:"))) { if (MiniPS::Real::isDimen(p2)) LowerMargin=p2; else goto err_dimexp; } + else if (0!=(p2=one_pabbr(param,"lower:"))) { negLowerMargin=true; if (MiniPS::Real::isDimen(p2)) LowerMargin=p2; else goto err_dimexp; } + else { p2=param; goto all5; } + break; + case OPT_Scale: + if (paramlen==0 || 0==GenBuffer::nocase_strcmp(param, "scale")) Scale=Rule::CacheHints::SC_OK; + else if (0==GenBuffer::nocase_strcmp(param, "none")) Scale=Rule::CacheHints::SC_None; + else if (0==GenBuffer::nocase_strcmp(param, "rot")) Scale=Rule::CacheHints::SC_RotateOK; + else if (0==GenBuffer::nocase_strcmp(param, "rotate")) Scale=Rule::CacheHints::SC_RotateOK; + else Scale=(Rule::CacheHints::sc_t)(GenBuffer::parseBool(param, paramlen) ? 0+Rule::CacheHints::SC_OK : 0+Rule::CacheHints::SC_None); + /* ^^^ Imp: better error report */ + /* ^^^ +0: pacify g++-3.1 */ + break; + case OPT_TransferEncoding: + if (0==GenBuffer::nocase_strcmp(param, "bin")) TransferEncoding=Rule::Cache::TE_Binary; + else if (0==GenBuffer::nocase_strcmp(param, "hex")) TransferEncoding=Rule::Cache::TE_Hex; + else if (0==GenBuffer::nocase_strcmp(param, "a85")) TransferEncoding=Rule::Cache::TE_A85; + else if (0==GenBuffer::nocase_strcmp(param, "ascii"))TransferEncoding=Rule::Cache::TE_ASCII; + else if (0==GenBuffer::nocase_strcmp(param, "lsb1")) TransferEncoding=Rule::Cache::TE_LSBfirst; + else if (0==GenBuffer::nocase_strcmp(param, "msb1")) TransferEncoding=Rule::Cache::TE_MSBfirst; + else { inv_par: badmsg="one_liner: invalid param for option: "; goto bad_label; } + break; + case OPT_TransferEncodingF: + if (0==GenBuffer::nocase_strcmp(param, "lsb2msb")) TransferEncoding=Rule::Cache::TE_LSBfirst; + else if (0==GenBuffer::nocase_strcmp(param, "msb2lsb")) TransferEncoding=Rule::Cache::TE_MSBfirst; + else goto inv_par; + break; + case OPT_PS: + if (param==(char const*)NULLP || param[0]=='\0') FileFormat=Rule::Cache::FF_eps; + else if (0==GenBuffer::nocase_strcmp(param, "1")) FileFormat=Rule::Cache::FF_PSL1; + else if (0==GenBuffer::nocase_strcmp(param, "1c") + || 0==GenBuffer::nocase_strcmp(param, "c")) FileFormat=Rule::Cache::FF_PSLC; + else if (0==GenBuffer::nocase_strcmp(param, "2")) FileFormat=Rule::Cache::FF_PSL2; + else if (0==GenBuffer::nocase_strcmp(param, "3")) FileFormat=Rule::Cache::FF_PSL3; + else goto inv_par; + break; + case OPT_PDF: + if (param==(char const*)NULLP || param[0]=='\0') FileFormat=Rule::Cache::FF_pdfb; + else if (0==GenBuffer::nocase_strcmp(param, "b")) FileFormat=Rule::Cache::FF_pdfb; /* BI */ + else if (0==GenBuffer::nocase_strcmp(param, "x")) FileFormat=Rule::Cache::FF_pdf; /* XObject */ + else if (0==GenBuffer::nocase_strcmp(param, "b0")) FileFormat=Rule::Cache::FF_PDFB10; + else if (0==GenBuffer::nocase_strcmp(param, "b2")) FileFormat=Rule::Cache::FF_PDFB12; + else if (0==GenBuffer::nocase_strcmp(param, "0")) FileFormat=Rule::Cache::FF_PDF10; + else if (0==GenBuffer::nocase_strcmp(param, "2")) FileFormat=Rule::Cache::FF_PDF12; + else goto inv_par; + break; + case OPT_SampleFormat: + pend=param; + while (*pend!='\0') { + while (*pend==':') pend++; + if (do_stop_SampleFormat) goto inv_par; /* already stopped */ + p=pend; while (*pend!='\0' && *pend!=':') pend++; + paramlen=pend-p; + if (4==paramlen && 0==memcmp(p,"stop",4)) { do_stop_SampleFormat=true; buildProfile_quiet=false; break; } + if (5==paramlen && 0==memcmp(p,"stopq",5)) { do_stop_SampleFormat=true; break; } + if (2==paramlen && 0==memcmp(p,"tr",2)) { + APPEND_sf(Image::SF_Transparent); + APPEND_sf(Image::SF_Opaque); + APPEND_sf(Image::SF_Mask); + APPEND_sf(Image::SF_Transparent2); + APPEND_sf(Image::SF_Transparent4); + APPEND_sf(Image::SF_Transparent8); + } else { + Image::sf_t sf=Rule::Cache::parseSampleFormat(p, paramlen); + if (sf==Image::SF_max) goto inv_par; + APPEND_sf(sf); + } + } + break; + case OPT_Compression: + assert(param!=(char const*)NULLP); + if (0==GenBuffer::nocase_strcmp(param, "none")) APPEND_co(Rule::Cache::CO_None); + else if (0==GenBuffer::nocase_strcmp(param, "lzw")) APPEND_co(Rule::Cache::CO_LZW); + else if (0==GenBuffer::nocase_strcmp(param, "zip")) APPEND_co(Rule::Cache::CO_ZIP); + else if (0==GenBuffer::nocase_strcmp(param, "rle") + || 0==GenBuffer::nocase_strcmp(param, "packbits")) APPEND_co(Rule::Cache::CO_RLE); + else if (0==GenBuffer::nocase_strcmp(param, "dct")) { APPEND_co(Rule::Cache::CO_DCT); Hints << "\n/DCT<<>>"; } + else if (0==GenBuffer::nocase_strcmp(param, "jpg") + || 0==GenBuffer::nocase_strcmp(param, "jpeg")) { APPEND_co(Rule::Cache::CO_JAI); APPEND_co(Rule::Cache::CO_IJG); } + else if (0==GenBuffer::nocase_strcmp(param, "ijg")) APPEND_co(Rule::Cache::CO_IJG); + else if (0==GenBuffer::nocase_strcmp(param, "g4")) { APPEND_co(Rule::Cache::CO_Fax); Hints << "\n/K -1"; } + else if (0==GenBuffer::nocase_strcmp(param, "g3") + || 0==GenBuffer::nocase_strcmp(param, "fax") + || 0==GenBuffer::nocase_strcmp(param, "g3:1d"))APPEND_co(Rule::Cache::CO_Fax); + else if (0==GenBuffer::nocase_strcmp(param, "g3:2d")){ APPEND_co(Rule::Cache::CO_Fax); Hints << "\n/K -2"; } + else if (0==GenBuffer::nocase_strcmp(param, "jai")) APPEND_co(Rule::Cache::CO_JAI); + else if (GenBuffer::nocase_strbegins(param, "lzw:")) { + SimBuffer::Static s(param+4); + unsigned long i; /* toInteger() is quickest on long */ + if (s.toInteger(i)) goto inv_par; + APPEND_co(Rule::Cache::CO_LZW); Predictor=(Rule::Cache::pr_t)i; + } else if (GenBuffer::nocase_strbegins(param, "rle:")) { + SimBuffer::Static s(param+4); + unsigned long i; /* toInteger() is quickest on long */ + if (s.toInteger(i)) goto inv_par; + APPEND_co(Rule::Cache::CO_RLE); Hints << "\n/RecordSize " << i; + } else if (GenBuffer::nocase_strbegins(param, "packbits:")) { + SimBuffer::Static s(param+9); + unsigned long i; /* toInteger() is quickest on long */ + if (s.toInteger(i)) goto inv_par; + APPEND_co(Rule::Cache::CO_RLE); Hints << "\n/RecordSize " << i; + } else if (GenBuffer::nocase_strbegins(param, "fax:")) { + SimBuffer::Static s(param+4); + long i; /* toInteger() is quickest on long */ + if (s.toInteger(i)) goto inv_par; + APPEND_co(Rule::Cache::CO_Fax); Hints << "\n/K " << i; + } else if (GenBuffer::nocase_strbegins(param, "dct:")) { + APPEND_co(Rule::Cache::CO_DCT); Hints << "\n/DCT<< " << (param+4) << " >>"; + } else if (GenBuffer::nocase_strbegins(param, "ijg:")) { + SimBuffer::Static s(param+4); + unsigned long i; /* toInteger() is quickest on long */ + if (s.toInteger(i)) goto inv_par; + APPEND_co(Rule::Cache::CO_IJG); Hints << "\n/Quality " << i; + } else if (GenBuffer::nocase_strbegins(param, "jpeg:")) { + SimBuffer::Static s(param+5); + unsigned long i; /* toInteger() is quickest on long */ + if (s.toInteger(i)) goto inv_par; + APPEND_co(Rule::Cache::CO_JAI); + APPEND_co(Rule::Cache::CO_IJG); Hints << "\n/Quality " << i; + } else if (GenBuffer::nocase_strbegins(param, "zip:")) { + pend=param+4; while (*pend!='\0' && *pend!=':') pend++; + SimBuffer::Static s(param+4, pend-param-4); + unsigned long i; /* toInteger() is quickest on long */ + if (s.toInteger(i)) goto inv_par; + APPEND_co(Rule::Cache::CO_ZIP); Predictor=(Rule::Cache::pr_t)i; + if (*pend==':') { + pend++; while (*pend==':') pend++; + SimBuffer::Static s(pend); + if (s.toInteger(i)) goto inv_par; + // Error::sev(Error::FATAL) << "SUXX)" << s << ',' << i << '.' << (Error*)0; + APPEND_co(Rule::Cache::CO_ZIP); Hints << "\n/Effort " << i; + // Error::sev(Error::FATAL) << "SUXX(" << s << ',' << Hints << '.' << (Error*)0; + } + } else goto inv_par; + break; + default: assert(0); + } + } else { /* a selector or a normal argument */ + if (!(no_selector && no_option_term)) goto normal_label; + pend=p; while (*pend!='\0' && *pend!=':') pend++; + if (pend-p>=2 && *pend==':') { /* an ImageMagick-style FileFormat selector */ + if (GenBuffer::nocase_strbegins(p, "PSL2:") + || GenBuffer::nocase_strbegins(p, "EPS2:")) FileFormat=Rule::Cache::FF_PSL2; + else if (GenBuffer::nocase_strbegins(p, "EPS:")) FileFormat=Rule::Cache::FF_eps; + else if (GenBuffer::nocase_strbegins(p, "PS2:")) { FileFormat=Rule::Cache::FF_PSL2; if (Scale==Rule::CacheHints::SC_default) Scale=Rule::CacheHints::SC_RotateOK; } + else if (GenBuffer::nocase_strbegins(p, "PS:")) { FileFormat=Rule::Cache::FF_eps; if (Scale==Rule::CacheHints::SC_default) Scale=Rule::CacheHints::SC_RotateOK; } + else if (GenBuffer::nocase_strbegins(p, "PSL1:")) FileFormat=Rule::Cache::FF_PSL1; + else if (GenBuffer::nocase_strbegins(p, "PSLC:")) FileFormat=Rule::Cache::FF_PSLC; + else if (GenBuffer::nocase_strbegins(p, "PSL3:")) FileFormat=Rule::Cache::FF_PSL3; + else if (GenBuffer::nocase_strbegins(p, "PDF:") + || GenBuffer::nocase_strbegins(p, "PDF:")) FileFormat=Rule::Cache::FF_pdfb; + else if (GenBuffer::nocase_strbegins(p, "PDFX:")) FileFormat=Rule::Cache::FF_pdf; + else if (GenBuffer::nocase_strbegins(p, "PDFB1.0:")) FileFormat=Rule::Cache::FF_PDFB10; + else if (GenBuffer::nocase_strbegins(p, "PDFB1.2:")) FileFormat=Rule::Cache::FF_PDFB12; + else if (GenBuffer::nocase_strbegins(p, "PDF1.0:")) FileFormat=Rule::Cache::FF_PDF10; + else if (GenBuffer::nocase_strbegins(p, "PDF1.2:")) FileFormat=Rule::Cache::FF_PDF12; + else if (GenBuffer::nocase_strbegins(p, "GIF89a:") + || GenBuffer::nocase_strbegins(p, "GIF:")) FileFormat=Rule::Cache::FF_GIF89a; + /* vvv do_stop_SampleFormat BUGFIX at Thu Nov 21 23:44:20 CET 2002 */ + else if (GenBuffer::nocase_strbegins(p, "PNM:")) { FileFormat=Rule::Cache::FF_PNM; APPEND_sf(Image::SF_Gray1); APPEND_sf(Image::SF_Gray8); APPEND_sf(Image::SF_Rgb8); APPEND_sf(Image::SF_Transparent8); do_stop_SampleFormat=true; } + else if (GenBuffer::nocase_strbegins(p, "PBM:")) { FileFormat=Rule::Cache::FF_PNM; APPEND_sf(Image::SF_Gray1); do_stop_SampleFormat=true; } + else if (GenBuffer::nocase_strbegins(p, "PGM:")) { FileFormat=Rule::Cache::FF_PNM; APPEND_sf(Image::SF_Gray8); do_stop_SampleFormat=true; } + else if (GenBuffer::nocase_strbegins(p, "PPM:")) { FileFormat=Rule::Cache::FF_PNM; APPEND_sf(Image::SF_Rgb8); do_stop_SampleFormat=true; } + else if (GenBuffer::nocase_strbegins(p, "PAM:")) FileFormat=Rule::Cache::FF_PAM; + else if (GenBuffer::nocase_strbegins(p, "PIP:")) FileFormat=Rule::Cache::FF_PIP; + else if (GenBuffer::nocase_strbegins(p, "Empty:"))FileFormat=Rule::Cache::FF_Empty; + else if (GenBuffer::nocase_strbegins(p, "Meta:")) FileFormat=Rule::Cache::FF_Meta; + else if (GenBuffer::nocase_strbegins(p, "JPEG:") + || GenBuffer::nocase_strbegins(p, "JPG:")) FileFormat=Rule::Cache::FF_JPEG; + else if (GenBuffer::nocase_strbegins(p, "TIFF:") + || GenBuffer::nocase_strbegins(p, "TIF:")) FileFormat=Rule::Cache::FF_TIFF; + else if (GenBuffer::nocase_strbegins(p, "PNG:")) FileFormat=Rule::Cache::FF_PNG; + else if (GenBuffer::nocase_strbegins(p, "XPM:")) FileFormat=Rule::Cache::FF_XPM; + else if (GenBuffer::nocase_strbegins(p, "BMP:") + || GenBuffer::nocase_strbegins(p, "RLE:")) { FileFormat=Rule::Cache::FF_BMP; /*APPEND_co(Rule::Cache::CO_RLE);*/ } + else if (GenBuffer::nocase_strbegins(p, "XWD:")) FileFormat=Rule::Cache::FF_XWD; + else if (GenBuffer::nocase_strbegins(p, "X11:")) FileFormat=Rule::Cache::FF_X11; + else { + Error::sev(Error::ERROR_CONT) << "one_liner: invalid FileFormat selector: " << (SimBuffer::B().appendDumpC(SimBuffer::Static(p, pend-p), true)) << (Error*)0; + badp=true; + continue; + } + no_selector=false; + while (*pend==':') pend++; + if (*pend=='\0') continue; /* this arg is just a selector */ + /* normal argument is coming */ + p=pend; + } + normal_label: + if (InputFile==(char const*)NULLP) { + InputFile=p; /* set it even on error */ + /* vvv since Sat Apr 19 13:37:57 CEST 2003: + * Possibly unseekable STDIN is handled by Filter::UngetFILED + */ + #if 0 + if (p[0]=='-' && p[1]=='\0') { /* Filename: STDIN */ + Files::set_binary_mode(0, true); + if (0!=fseek(stdin, 0L, 0)) { unseekable: + #if 0 + Error::sev(Error::ERROR_CONT) << "one_liner: `-' (stdin) not allowed as InputFile (stdin unseekable)" << (Error*)0; + badp=true; continue; + #endif + FILE *f=Files::open_tmpnam(tmpnam); + if (!f) { Error::sev(Error::ERROR_CONT) << "one_liner: cannot open" << " temporary file for `-' (stdin)" << (Error*)0; badp=true; continue; } + tmpnam.term0(); + Files::tmpRemoveCleanup(InputFile=tmpnam()); + char *buf=new char[4096]; + unsigned got; + while ( + (0<(got=fread(buf, 1, sizeof(buf), stdin))) + && got==fwrite(buf, 1, sizeof(buf), f)) {} + delete [] buf; + if (ferror(f) || 0!=fclose(f) || ferror(stdin)) + { Error::sev(Error::ERROR_CONT) << "one_liner: cannot write" << " temporary file for `-' (stdin)" << (Error*)0; badp=true; continue; } + // fprintf(stderr, "if=(%s)\n", InputFile); + continue; + /* Imp: report `-' as filename on errors etc. */ + } + int c=MACRO_GETC(stdin); + if (0!=fseek(stdin, 0L, 0)) { if (c>=0) ungetc(c, stdin); goto unseekable; } /* active test */ + /* ungetc() is not necessary because of fseek() */ + } + #endif + } else if (OutputFile==(char const*)NULLP) { /* Filename: STDOUT */ + Files::set_binary_mode(1, true); + OutputFile=p; + if (FileFormat==Rule::Cache::FF_default) { /* OutputFile; determine FileFormat from extension */ + pend=p+strlen(p); + while (pend!=p && *pend!='.') pend--; + /* ^^^ Dat: extra care later for /a/b.c/d */ + if (pend!=p) { /* have extension */ + assert(*pend=='.'); pend++; + if (0==GenBuffer::nocase_strcmp(pend, "eps") + || 0==GenBuffer::nocase_strcmp(pend, "epsi") + || 0==GenBuffer::nocase_strcmp(pend, "epsf")) FileFormat=Rule::Cache::FF_eps; + else if (0==GenBuffer::nocase_strcmp(pend, "ps")) { FileFormat=Rule::Cache::FF_eps; if (Scale==Rule::CacheHints::SC_default) Scale=Rule::CacheHints::SC_RotateOK; } + else if (0==GenBuffer::nocase_strcmp(pend, "pdf")) FileFormat=Rule::Cache::FF_pdfb; + else if (0==GenBuffer::nocase_strcmp(pend, "gif")) FileFormat=Rule::Cache::FF_GIF89a; + else if (0==GenBuffer::nocase_strcmp(pend, "pnm")) { FileFormat=Rule::Cache::FF_PNM; APPEND_sf(Image::SF_Gray1); APPEND_sf(Image::SF_Gray8); APPEND_sf(Image::SF_Rgb8); APPEND_sf(Image::SF_Transparent8); do_stop_SampleFormat=true; } + else if (0==GenBuffer::nocase_strcmp(pend, "pbm")) { FileFormat=Rule::Cache::FF_PNM; APPEND_sf(Image::SF_Gray1); do_stop_SampleFormat=true; } + else if (0==GenBuffer::nocase_strcmp(pend, "pgm")) { FileFormat=Rule::Cache::FF_PNM; APPEND_sf(Image::SF_Gray8); do_stop_SampleFormat=true; } + else if (0==GenBuffer::nocase_strcmp(pend, "ppm")) { FileFormat=Rule::Cache::FF_PNM; APPEND_sf(Image::SF_Rgb8); do_stop_SampleFormat=true; } + else if (0==GenBuffer::nocase_strcmp(pend, "pam")) FileFormat=Rule::Cache::FF_PAM; + else if (0==GenBuffer::nocase_strcmp(pend, "pip")) FileFormat=Rule::Cache::FF_PIP; + else if (0==GenBuffer::nocase_strcmp(pend, "empty"))FileFormat=Rule::Cache::FF_Empty; + else if (0==GenBuffer::nocase_strcmp(pend, "meta")) FileFormat=Rule::Cache::FF_Meta; + else if (0==GenBuffer::nocase_strcmp(pend, "jpeg") + || 0==GenBuffer::nocase_strcmp(pend, "jpg")) FileFormat=Rule::Cache::FF_JPEG; + else if (0==GenBuffer::nocase_strcmp(pend, "tiff") + || 0==GenBuffer::nocase_strcmp(pend, "tif")) FileFormat=Rule::Cache::FF_TIFF; + else if (0==GenBuffer::nocase_strcmp(pend, "png")) FileFormat=Rule::Cache::FF_PNG; + else if (0==GenBuffer::nocase_strcmp(pend, "xpm")) FileFormat=Rule::Cache::FF_XPM; + else if (0==GenBuffer::nocase_strcmp(pend, "bmp") + || 0==GenBuffer::nocase_strcmp(pend, "rle")) { FileFormat=Rule::Cache::FF_BMP; /*APPEND_co(Rule::Cache::CO_RLE);*/ } + else if (0==GenBuffer::nocase_strcmp(pend, "xwd")) FileFormat=Rule::Cache::FF_XWD; + // else if (0==GenBuffer::nocase_strcmp(pend, "x11")) FileFormat=Rule::Cache::FF_X11; + /* ^^^ .x11 extension is useless */ + } + } + } else { + Error::sev(Error::ERROR_CONT) << "one_liner: got too many (>2) filenames" << (Error*)0; + badp=true; + continue; + } + } /* IF */ + } /* NEXT */ + + if (InputFile==(char const*)NULLP) { + Error::sev(Error::ERROR_CONT) << "one_liner: InputFile unspecified" << (Error*)0; + badp=true; + } + if (OutputFile==(char const*)NULLP) { + Error::sev(Error::ERROR_CONT) << "one_liner: OutputFile unspecified" << (Error*)0; + badp=true; + } + if (FileFormat==Rule::Cache::FF_default) { + Error::sev(Error::ERROR_CONT) << "one_liner: FileFormat unspecified" << (Error*)0; + badp=true; + } + if (badp) return true; + + int prcc = (colen==0) ? 2 : 1; + if (colen==0) { /* apply default if Compression is unspecified */ + // Error::sev(Error::FATAL) << "FileFormat=" << (unsigned)FileFormat << (Error*)0; + switch (FileFormat) { + case Rule::Cache::FF_TIFF: + case Rule::Cache::FF_eps: case Rule::Cache::FF_PSL2: + case Rule::Cache::FF_PDFB10: case Rule::Cache::FF_PDF10: + APPEND_co(Rule::Cache::CO_JAI); + #if HAVE_LZW + APPEND_co(Rule::Cache::CO_LZW); + #endif + APPEND_co(Rule::Cache::CO_RLE); + APPEND_co(Rule::Cache::CO_None); break; + case Rule::Cache::FF_BMP: + case Rule::Cache::FF_PSL1: case Rule::Cache::FF_PSLC: + /* assert(0); */ + APPEND_co(Rule::Cache::CO_RLE); + APPEND_co(Rule::Cache::CO_None); break; + case Rule::Cache::FF_PSL3: + case Rule::Cache::FF_pdfb: /* BUGFIX at Sun Sep 22 14:57:03 CEST 2002 */ + case Rule::Cache::FF_pdf: + case Rule::Cache::FF_PDFB12: case Rule::Cache::FF_PDF12: + APPEND_co(Rule::Cache::CO_JAI); + APPEND_co(Rule::Cache::CO_ZIP); + APPEND_co(Rule::Cache::CO_None); break; + case Rule::Cache::FF_GIF89a: + APPEND_co(Rule::Cache::CO_LZW); /* _not_ /LZWEncode filter */ + APPEND_co(Rule::Cache::CO_None); break; + case Rule::Cache::FF_JPEG: + APPEND_co(Rule::Cache::CO_JAI); + APPEND_co(Rule::Cache::CO_IJG); break; + case Rule::Cache::FF_PNG: + APPEND_co(Rule::Cache::CO_ZIP); break; + default: + APPEND_co(Rule::Cache::CO_None); break; + /* for others FileFormats: CO_None, but that is _not_ appended anyway */ + } + } else { + if ((int)Predictor == 55 || (int)Predictor == 45) { + Error::sev(Error::WARNING) << "predictor: /Predictor " << (int)Predictor + << " is inefficient; use /Predictor 15 instead" << (Error*)0; + } + } + /* Dat: don't append /Compression/None if the user has specified `-c'. The + * user can append `-c none' manually. + */ + + if (Scale==Rule::CacheHints::SC_default) Scale=Rule::CacheHints::SC_None; + if (TransferEncoding==Rule::Cache::TE_default) { /* apply default if TransferEncoding is unspecified */ + switch (FileFormat) { + case Rule::Cache::FF_PSL1: case Rule::Cache::FF_PSLC: + TransferEncoding=(Rule::Cache::te_t)(cox[Rule::Cache::CO_ZIP]!=0 || + cox[Rule::Cache::CO_LZW]!=0 ? 0+Rule::Cache::TE_A85 : 0+Rule::Cache::TE_Hex); break; + /* ^^^ Dat: /Hex is default for /RLE */ + case Rule::Cache::FF_eps: case Rule::Cache::FF_PSL2: + case Rule::Cache::FF_PSL3: + TransferEncoding=Rule::Cache::TE_A85; break; + #if 0 /* useless bugfix */ + case Rule::Cache::FF_XPM: /* BUGFIX at Thu Jul 11 21:53:56 CEST 2002 */ + // assert(0); + TransferEncoding=Rule::Cache::TE_ASCII; break; + #endif + default: + TransferEncoding=Rule::Cache::TE_Binary; break; + } + } + + unsigned coc=colen; + + /* Smart verify whether /Compression/JAI is requested. If so, and the input + * file is JPEG, then load it as-is. Our heuristic is that if the user + * allowed /Compression/JAI among others, and the input file is a baseline + * JPEG, then /Compression/JAI will be the best (and only) compression + * method. + */ + bool jaip=cox[Rule::Cache::CO_JAI]!=0; + if (jaip) { + if (ufd==NULLP) ufd=new Filter::UngetFILED(InputFile, stdin, + Filter::UngetFILED::CM_closep|Filter::UngetFILED::CM_keep_stdinp); + /* vvv Imp: no error handling */ + if (1!=jai_is_baseline_jpeg(ufd)) { jaip=false; coc--; cox[Rule::Cache::CO_JAI]=0; } + ufd->seek(0); +#if 0 + assert(ufd->vi_getcc()==255); + assert(ufd->vi_getcc()==0xd8); + assert(ufd->vi_getcc()==255+0); + assert(0); +#endif + } + + if (jaip) { /* Dat: might have changed to false */ + APPEND_sf(Image::SF_Asis); + LoadHints << ",jpeg-asis,"; + cot[0]=Rule::Cache::CO_JAI; colen=1; /* disable all other compression */ + } else if (coc==1 && cox[Rule::Cache::CO_Fax]!=0) { + APPEND_sf(Image::SF_Opaque); + APPEND_sf(Image::SF_Transparent); + APPEND_sf(Image::SF_Gray1); + APPEND_sf(Image::SF_Indexed1); + APPEND_sf(Image::SF_Mask); + } else if (coc==1 && (cox[Rule::Cache::CO_DCT]!=0 || cox[Rule::Cache::CO_IJG]!=0)) { + APPEND_sf(Image::SF_Opaque); + APPEND_sf(Image::SF_Transparent); + APPEND_sf(Image::SF_Gray8); + APPEND_sf(Image::SF_Rgb8); + } else if (!do_stop_SampleFormat) { + /* JAI compression is automatically disabled since jaip==false */ + /* Guess SampleFormat automatically. The order is significant, so most + * warnings emitted by Image::SampledInfo::setSampleFormat() are avoided. + */ + APPEND_sf(Image::SF_Opaque); + APPEND_sf(Image::SF_Transparent); + APPEND_sf(Image::SF_Gray1); + APPEND_sf(Image::SF_Indexed1); + APPEND_sf(Image::SF_Mask); + APPEND_sf(Image::SF_Gray2); + APPEND_sf(Image::SF_Indexed2); + APPEND_sf(Image::SF_Rgb1); + APPEND_sf(Image::SF_Gray4); + APPEND_sf(Image::SF_Indexed4); + APPEND_sf(Image::SF_Rgb2); + APPEND_sf(Image::SF_Gray8); + APPEND_sf(Image::SF_Indexed8); + APPEND_sf(Image::SF_Rgb4); + APPEND_sf(Image::SF_Rgb8); + APPEND_sf(Image::SF_Transparent2); /* transparents are put last because of expensive color separation */ + APPEND_sf(Image::SF_Transparent4); + APPEND_sf(Image::SF_Transparent8); + } + + /* Append more Hints */ + if (Scale!=Rule::CacheHints::SC_None) Hints << "\n/Scale /" << protect_null(Rule::CacheHints::dumpScale(Scale)); + if ((char const*)NULLP!=ImageDPI) Hints << "\n/ImageDPI " << ImageDPI; + if ((char const*)NULLP!=LeftMargin) Hints << "\n/LeftMargin " << LeftMargin; + if ((char const*)NULLP!=RightMargin) Hints << "\n/RightMargin " << RightMargin; + if ((char const*)NULLP!=TopMargin) Hints << "\n/TopMargin " << TopMargin; + if ((char const*)NULLP!=BottomMargin) Hints << "\n/BottomMargin " << BottomMargin; + if ((char const*)NULLP!=LowerMargin) { + Hints << "\n/LowerMargin "; + if (negLowerMargin) { + if (LowerMargin[0]=='-') Hints << (LowerMargin+1); + else Hints << '-' << LowerMargin; + } else Hints << LowerMargin; + } + + /* Emit job file */ + jobss << "<<%sam2p in-memory job file, autogenerated by " << Error::banner0 + << "\n/InputFile "; + jobss.appendDumpPS(SimBuffer::Static(InputFile), true); + jobss << "\n/OutputFile "; + jobss.appendDumpPS(SimBuffer::Static(OutputFile), true); + jobss << "\n/LoadHints "; + jobss.appendDumpPS(LoadHints, true); + jobss << "\n/TmpRemove " << (TmpRemove_p ? "true" : "false"); + jobss << "\n/Profile[\n"; + + unsigned coi, sfi; + slen_t orc=0; + int prc; + bool is_predictor_recommended; + for (sfi=0;sfi<sflen;sfi++) { for (coi=0;coi<colen;coi++) { + // for (coi=0;coi<colen;coi++) for (sfi=0;sfi<sflen;sfi++) + Rule::Cache::co_t co=cot[coi]; + Image::sf_t sf=sft[sfi]; + if (co==Rule::Cache::CO_JAI) { + if (!jaip || sf!=Image::SF_Asis) continue; + } + for (prc=prcc; prc>0; --prc) { + /* Add an extra predictor only for LZW or ZIP, appropriate SampleFormat + * and if the `-c' command line option was not specified. + * So if the user specifies `-c zip', he won't get a predictor by + * default; but if he specifies no `-c', he might get a `-c:zip:15'. + * To get the smallest file size, he should specify `-c zip:15:9'. + * + * The value we assign to is_predictor_recommended comes from the + * do_filter = ... assignment in png_write_IHDR() in pngwutil.c of + * libpng-1.2.15 . + */ + is_predictor_recommended = ( + sf==Image::SF_Gray8 || sf==Image::SF_Rgb8); + if (prc>1 && ((co!=Rule::Cache::CO_LZW && co!=Rule::Cache::CO_ZIP) || + !is_predictor_recommended)) continue; + jobss << "<<% OutputRule #" << orc++ + << "\n /FileFormat /" << protect_null(Rule::Cache::dumpFileFormat(FileFormat, co)) + << "\n /TransferEncoding /" << protect_null(Rule::Cache::dumpTransferEncoding(TransferEncoding)) + << "\n /SampleFormat /" << protect_null(Rule::Cache::dumpSampleFormat(sf)) + << "\n /Compression /" << protect_null(Rule::Cache::dumpCompression (co)) + << "\n /Predictor " << (int)(co==Rule::Cache::CO_LZW || co==Rule::Cache::CO_ZIP ? + /* If no compression (or predictor) specified, try predictor 15, then 1; otherwise try the specified predictor */ + /* +0 down there to avoid linking problems with g++ on Mac OS X 10.5.6 */ + (prc>1 ? Rule::Cache::PR_PNGAuto+0 : Predictor != Rule::Cache::PR_PNGAutoMaybe ? Predictor : is_predictor_recommended ? Rule::Cache::PR_PNGAuto+0 : Rule::Cache::PR_None+0) : Rule::Cache::PR_None+0) + << "\n /Hints << " << Hints << " >>"; + // jobss << " /Transparent (\377\377\377)\n"; + if (Transparent!=NULL) { + jobss << "\n /Transparent "; + jobss.appendDumpPS(SimBuffer::Static(Transparent), true); + } + jobss << "\n>>\n"; + } + } + } + jobss << "]>>% __EOF__\n"; + + /* Common keys not emited here: + * /TmpRemove true /Templates pop + * /ColorTransform pop + * /EncoderColumns 0 /EncoderBPL 0 /EncoderRows 0 /EncoderColors 0 + * /PredictorColumns 0 /PredictorBPC 0 /PredictorColors 0 + * /Transparent null + * /WarningOK true + * /Comment pop + * /Title pop + * /Subject pop + * /Author pop + * /Creator pop + * /Producer pop + * /Created pop + * /Produced pop + */ + return false; + #undef APPEND_sf + #undef APPEND_co +} /* one_liner() */ + +static bool option_eq(char const *arg, char const*option) { + if (option[0]=='-') { option++; while (arg[0]=='-') arg++; } + return 0==GenBuffer::nocase_strcmp(arg, option); +} + +void init_sam2p_engine(char const*argv0) { + Error::long_argv0=argv0==(char const*)NULLP ? "sam2p" : argv0; + Error::argv0=Files::only_fext(Error::long_argv0); + Error::tmpargv0="_sam2p_"; + Error::banner0="sam2p " SAM2P_VERSION; +} + +/* --- */ + +/* Never returns. */ +int run_sam2p_engine(Files::FILEW &sout, Files::FILEW &serr, char const*const*argv1, bool helpp) { + class SerrResetter { + public: + SerrResetter(GenBuffer::Writable *old_serr_): old_serr(old_serr_) {} + ~SerrResetter() { Error::serr = old_serr; } + private: + GenBuffer::Writable *old_serr; + } serr_resetter(Error::serr); + Error::serr=&serr; + + /* --- Parse arguments, generate/read .job file */ + + MiniPS::VALUE job=MiniPS::Qundef; + Filter::FlatD bts(bts_ttt); + ufd=(Filter::UngetFILED*)NULLP; + if (!helpp && argv1[0]!=(char const*)NULLP && argv1[1]==(char const*)NULLP) { + /* A single argument: must be the name of the .job file */ + MiniPS::Parser p(argv1[0]); + p.addSpecRun("%bts", &bts); /* bts: Built-in TemplateS, the bts.ttt file in the sources */ + job=p.parse1(); + if (p.parse1(p.EOF_ALLOWED)!=MiniPS::Qundef) + Error::sev(Error::EERROR) << "job: the .job file should contain a single job" << (Error*)0; + /* ^^^ Dat: the result of the second p.parse1() doesn't get delete0(...)d */ + } else if (helpp || argv1[0]==(char const*)NULLP) { help: /* help message */ + sout << "Usage: " << Error::long_argv0 << " <filename.job>\n" << + " " << Error::long_argv0 << " [options] <in.img> [OutputFormat:] <out.img>\n" << + "Example: " << Error::long_argv0 << " test.gif EPS: test.eps\n"; + if (helpp) Error::cexit(Error::runCleanups(0)); + Error::sev(Error::EERROR) << "Incorrect command line" << (Error*)0; + } else { /* one_liner */ + SimBuffer::B jobss; + if (one_liner(jobss, argv1)) goto help; + if (do_DisplayJobFile) displayJob(sout, jobss); + Filter::FlatD jobr(jobss(), jobss.getLength()); + MiniPS::Parser p(&jobr); + p.addSpecRun("%bts", &bts); /* bts: Built-in TemplateS, the bts.ttt file in the sources */ + if (MiniPS::Qerror==(job=p.parse1(p.EOF_ILLEGAL, Error::ERROR_CONT)) + || p.parse1(p.EOF_ALLOWED)!=MiniPS::Qundef + ) { + displayJob(sout, jobss); + Error::sev(Error::EERROR) << "job: in-memory .job file corrupt (bug?" "?)" << (Error*)0; + /* ^^^ Dat: the result of the second p.parse1() doesn't get delete0(...)d */ + } + } + Files::doSignalCleanup(); + + /* --- Pre-parse .job file */ + + /* Dat: memory storage for the MiniPS objects in the .job file are + * allocated by p.parse1() and freed by MiniPS::delete0(job). Other + * structures throughout this program hold pointers to inside `job', + * but storage is not copied. + */ + + MiniPS::String *InputFile, *OutputFile, *LoadHints; + MiniPS::Array *Profile; + MiniPS::VALUE TmpRemove; + MiniPS::scanf_dict(job, /*show_warnings:*/true, + "InputFile", MiniPS::T_STRING, MiniPS::Qundef, &InputFile, + "OutputFile", MiniPS::T_STRING, MiniPS::Qundef, &OutputFile, + "LoadHints", MiniPS::T_STRING, MiniPS::Qnull, &LoadHints, + "Templates", MiniPS::T_DICT, MiniPS::Qnull, &Rule::Templates, + "Profile", MiniPS::T_ARRAY, MiniPS::Qundef, &Profile, + "TmpRemove", MiniPS::T_BOOLEAN,MiniPS::Qtrue, &TmpRemove, /* remove temporary files upon exit? */ + NULLP + ); + // MiniPS::dump(sout, job, 1); + Files::tmpRemove=TmpRemove==MiniPS::Qtrue; + if (MiniPS::Qnull==(MiniPS::VALUE)Rule::Templates) { + Filter::FlatD flatd("<< (%bts) run >>"); + MiniPS::Parser p(&flatd); + p.addSpecRun("%bts", &bts); + Rule::Templates=(MiniPS::Dict*)p.parse1(); + MiniPS::RDICT(job)->put("/Templates", (MiniPS::VALUE)Rule::Templates); /* Takes ownership, deletes the previous value. */ + } + + /* --- Preprocess Appliers */ + + Rule::OutputRule *rule_list=Rule::buildProfile((MiniPS::VALUE)Profile, buildProfile_quiet); + + /* --- Read/open other files */ + + if ((MiniPS::VALUE)LoadHints==MiniPS::Qnull) { /* smart default */ + /* This isn't reached by default (sam2p t.png t.pdf), becuase `job' + * already contains /LoadHints (). + */ + + if (!rule_list[0].isEOL() && rule_list[0].cache.Compression==Rule::Cache::CO_JAI) { + LoadHints=new MiniPS::String("jpeg-asis",4); /* used by in_jai.cpp and in_jpeg.cpp; even TIFF/JPEG */ + } else { + LoadHints=new MiniPS::String("",0); + } + MiniPS::RDICT(job)->put("/LoadHints", (MiniPS::VALUE)LoadHints); /* Takes ownership, deletes the previous value. */ + } + + /* vvv may raise tons of error messages */ + // InputFile->term0(); /* always term0() for MiniPS::String */ + if (ufd==NULLP) ufd=new Filter::UngetFILED(InputFile->begin_(), stdin, + Filter::UngetFILED::CM_closep|Filter::UngetFILED::CM_keep_stdinp); + // fprintf(stderr, "ufd=%p\n", ufd); + Image::SampledInfo info(Image::load( + #if 0 + InputFile->begin_(), /* knows about stdin `-' */ + SimBuffer::B(",",1, LoadHints->begin_(),LoadHints->getLength(), ",",1 ).term0() /* three-way concatentation */ + #else + (Image::Loader::UFD*)ufd, + SimBuffer::B(",",1, LoadHints->begin_(),LoadHints->getLength(), ",",1 ).term0(), /* three-way concatentation */ + /*format:*/(char const*)NULLP + #endif + )); + Error::sev(Error::NOTICE) << "job: read InputFile: " << + FNQ2STDOK(InputFile->begin_(),InputFile->getLength()) << (Error*)0; + delete ufd; + // assert(0); + + bool overwrite=false; + if (0==strcmp(InputFile->begin_(), OutputFile->begin_()) && 0!=strcmp("-", InputFile->begin_())) { + // Error::sev(Error::WARNING) << "job: InputFile == OutputFile" << (Error*)0; + OutputFile->replace(OutputFile->begin_(), OutputFile->getLength(), ".s2new", 6); + overwrite=true; + } + FILE *of=stdout; + if (OutputFile->getLength()!=1 || OutputFile->begin_()[0]!='-') { + if ((of=fopen(OutputFile->begin_(), "wb"))==(FILE*)NULLP) { + Error::sev(Error::EERROR) << "job: cannot rewrite OutputFile: " << FNQ2STDOK(OutputFile->begin_(),OutputFile->getLength()) << (Error*)0; + } + /*if (!overwrite)*/ + Files::tmpRemoveCleanup(OutputFile->begin_(), &of); + } else Files::set_binary_mode(1, true); + + /* --- Find and apply best applier */ + + Files::FILEW wf(of); + Rule::applyProfile(wf, rule_list, &info); + + /* --- Done, flush files and clean up. */ + + fflush(of); + if (ferror(of)) { + /* FILE *backup=of; of=(FILE*)NULLP; fclose(backup); */ + Error::sev(Error::EERROR) << "job: error writing OutputFile: " << FNQ2STDOK(OutputFile->begin_(),OutputFile->getLength()) << (Error*)0; + } + if (of!=stdout) { /* Don't interfere with tmpRemoveCleanup() */ + FILE *backup=of; of=(FILE*)NULLP; fclose(backup); + } + if (overwrite) { + if (0!=rename(OutputFile->begin_(), InputFile->begin_())) { + // remove(OutputFile->begin_()); /* tmpRemoveCleanup() does it */ + Error::sev(Error::EERROR) << "job: error renaming, InputFile left intact" << (Error*)0; + } + } + Error::sev(Error::NOTICE) << "job: written OutputFile: " << FNQ2STDOK(OutputFile->begin_(),OutputFile->getLength()) << (Error*)0; + + /* Freeing memory may cause segfaults because of possibly + * bad code design :-(. Luckily we have already saved the output file. + */ + Rule::deleteProfile(rule_list); + MiniPS::delete0(job); /* frees OutputFile etc. */ + + bool successp = Error::getTopPrinted()+0<=Error::NOTICE+0; + int exitCode = Error::runCleanups(0); + fflush(stdout); fflush(stderr); + if (successp && exitCode == 0) + fputs("Success.\n", stderr); + /* Don't do Error::cexit(exitCode);, it won't run destructors of + * stack-allocated objects, and valgrind will complain about leaking memory. + */ + return exitCode; +} + +/** main: process entry point for the sam2p utility. */ +int main(int, char const*const* argv) { + Files::FILEW sout(stdout); + Files::FILEW serr(stderr); + /* --- Initialize */ + + bool helpp=argv[0]==(char const*)NULLP || (argv[0]!=(char const*)NULLP && argv[1]!=(char const*)NULLP && argv[2]==(char const*)NULLP && ( + option_eq(argv[1], "-help") || + option_eq(argv[1], "-h") || + option_eq(argv[1], "-?") || + option_eq(argv[1], "/h") || + option_eq(argv[1], "/?"))); + bool versionp=argv[0]!=(char const*)NULLP && argv[1]!=(char const*)NULLP && argv[2]==(char const*)NULLP && ( + option_eq(argv[1], "-version") || + option_eq(argv[1], "-v")); + bool quietp=argv[0]!=(char const*)NULLP && argv[1]!=(char const*)NULLP && + option_eq(argv[1], "-j:quiet"); + init_sam2p_engine(argv[0]); + + if (versionp) { + sout << "This is " << Error::banner0 << ".\n"; + return 0; + } + + /* Don't print diagnostics to stdout, becuse it might be the OutputFile */ + if (!quietp) { serr << "This is " << Error::banner0 << ".\n"; } + init_loader(); + if (!quietp) { serr << "Available Loaders:"; Image::printLoaders(serr); serr << ".\n"; } + init_applier(); + if (!quietp) { serr << "Available Appliers:"; Rule::printAppliers(serr); serr << ".\n"; } + + return run_sam2p_engine( + sout, serr, argv+(argv[0]!=(char const*)NULLP), helpp); +} |