Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. #include "fitz.h"
  2. #include "mupdf.h"
  3.  
  4. /*
  5.  * Check if an object is a stream or not.
  6.  */
  7. int
  8. pdf_is_stream(pdf_xref *xref, int num, int gen)
  9. {
  10.         fz_error error;
  11.  
  12.         if (num < 0 || num >= xref->len)
  13.                 return 0;
  14.  
  15.         error = pdf_cache_object(xref, num, gen);
  16.         if (error)
  17.         {
  18.                 fz_catch(error, "cannot load object, ignoring error");
  19.                 return 0;
  20.         }
  21.  
  22.         return xref->table[num].stm_ofs > 0;
  23. }
  24.  
  25. /*
  26.  * Scan stream dictionary for an explicit /Crypt filter
  27.  */
  28. static int
  29. pdf_stream_has_crypt(fz_obj *stm)
  30. {
  31.         fz_obj *filters;
  32.         fz_obj *obj;
  33.         int i;
  34.  
  35.         filters = fz_dict_getsa(stm, "Filter", "F");
  36.         if (filters)
  37.         {
  38.                 if (!strcmp(fz_to_name(filters), "Crypt"))
  39.                         return 1;
  40.                 if (fz_is_array(filters))
  41.                 {
  42.                         for (i = 0; i < fz_array_len(filters); i++)
  43.                         {
  44.                                 obj = fz_array_get(filters, i);
  45.                                 if (!strcmp(fz_to_name(obj), "Crypt"))
  46.                                         return 1;
  47.                         }
  48.                 }
  49.         }
  50.         return 0;
  51. }
  52.  
  53. /*
  54.  * Create a filter given a name and param dictionary.
  55.  */
  56. static fz_stream *
  57. build_filter(fz_stream *chain, pdf_xref * xref, fz_obj * f, fz_obj * p, int num, int gen)
  58. {
  59.         fz_error error;
  60.         char *s;
  61.  
  62.         s = fz_to_name(f);
  63.  
  64.         if (!strcmp(s, "ASCIIHexDecode") || !strcmp(s, "AHx"))
  65.                 return fz_open_ahxd(chain);
  66.  
  67.         else if (!strcmp(s, "ASCII85Decode") || !strcmp(s, "A85"))
  68.                 return fz_open_a85d(chain);
  69.  
  70.         else if (!strcmp(s, "CCITTFaxDecode") || !strcmp(s, "CCF"))
  71.                 return fz_open_faxd(chain, p);
  72.  
  73.         else if (!strcmp(s, "DCTDecode") || !strcmp(s, "DCT"))
  74.                 return fz_open_dctd(chain, p);
  75.  
  76.         else if (!strcmp(s, "RunLengthDecode") || !strcmp(s, "RL"))
  77.                 return fz_open_rld(chain);
  78.  
  79.         else if (!strcmp(s, "FlateDecode") || !strcmp(s, "Fl"))
  80.         {
  81.                 fz_obj *obj = fz_dict_gets(p, "Predictor");
  82.                 if (fz_to_int(obj) > 1)
  83.                         return fz_open_predict(fz_open_flated(chain), p);
  84.                 return fz_open_flated(chain);
  85.         }
  86.  
  87.         else if (!strcmp(s, "LZWDecode") || !strcmp(s, "LZW"))
  88.         {
  89.                 fz_obj *obj = fz_dict_gets(p, "Predictor");
  90.                 if (fz_to_int(obj) > 1)
  91.                         return fz_open_predict(fz_open_lzwd(chain, p), p);
  92.                 return fz_open_lzwd(chain, p);
  93.         }
  94.  
  95.         else if (!strcmp(s, "JBIG2Decode"))
  96.         {
  97.                 fz_obj *obj = fz_dict_gets(p, "JBIG2Globals");
  98.                 if (obj)
  99.                 {
  100.                         fz_buffer *globals;
  101.                         error = pdf_load_stream(&globals, xref, fz_to_num(obj), fz_to_gen(obj));
  102.                         if (error)
  103.                                 fz_catch(error, "cannot load jbig2 global segments");
  104.                         chain = fz_open_jbig2d(chain, globals);
  105.                         fz_drop_buffer(globals);
  106.                         return chain;
  107.                 }
  108.                 return fz_open_jbig2d(chain, NULL);
  109.         }
  110.  
  111.         else if (!strcmp(s, "JPXDecode"))
  112.                 return chain; /* JPX decoding is special cased in the image loading code */
  113.  
  114.         else if (!strcmp(s, "Crypt"))
  115.         {
  116.                 fz_obj *name;
  117.  
  118.                 if (!xref->crypt)
  119.                 {
  120.                         fz_warn("crypt filter in unencrypted document");
  121.                         return chain;
  122.                 }
  123.  
  124.                 name = fz_dict_gets(p, "Name");
  125.                 if (fz_is_name(name))
  126.                         return pdf_open_crypt_with_filter(chain, xref->crypt, fz_to_name(name), num, gen);
  127.  
  128.                 return chain;
  129.         }
  130.  
  131.         fz_warn("unknown filter name (%s)", s);
  132.         return chain;
  133. }
  134.  
  135. /*
  136.  * Build a chain of filters given filter names and param dicts.
  137.  * If head is given, start filter chain with it.
  138.  * Assume ownership of head.
  139.  */
  140. static fz_stream *
  141. build_filter_chain(fz_stream *chain, pdf_xref *xref, fz_obj *fs, fz_obj *ps, int num, int gen)
  142. {
  143.         fz_obj *f;
  144.         fz_obj *p;
  145.         int i;
  146.  
  147.         for (i = 0; i < fz_array_len(fs); i++)
  148.         {
  149.                 f = fz_array_get(fs, i);
  150.                 p = fz_array_get(ps, i);
  151.                 chain = build_filter(chain, xref, f, p, num, gen);
  152.         }
  153.  
  154.         return chain;
  155. }
  156.  
  157. /*
  158.  * Build a filter for reading raw stream data.
  159.  * This is a null filter to constrain reading to the
  160.  * stream length, followed by a decryption filter.
  161.  */
  162. static fz_stream *
  163. pdf_open_raw_filter(fz_stream *chain, pdf_xref *xref, fz_obj *stmobj, int num, int gen)
  164. {
  165.         int hascrypt;
  166.         int len;
  167.  
  168.         /* don't close chain when we close this filter */
  169.         fz_keep_stream(chain);
  170.  
  171.         len = fz_to_int(fz_dict_gets(stmobj, "Length"));
  172.         chain = fz_open_null(chain, len);
  173.  
  174.         hascrypt = pdf_stream_has_crypt(stmobj);
  175.         if (xref->crypt && !hascrypt)
  176.                 chain = pdf_open_crypt(chain, xref->crypt, num, gen);
  177.  
  178.         return chain;
  179. }
  180.  
  181. /*
  182.  * Construct a filter to decode a stream, constraining
  183.  * to stream length and decrypting.
  184.  */
  185. static fz_stream *
  186. pdf_open_filter(fz_stream *chain, pdf_xref *xref, fz_obj *stmobj, int num, int gen)
  187. {
  188.         fz_obj *filters;
  189.         fz_obj *params;
  190.  
  191.         filters = fz_dict_getsa(stmobj, "Filter", "F");
  192.         params = fz_dict_getsa(stmobj, "DecodeParms", "DP");
  193.  
  194.         chain = pdf_open_raw_filter(chain, xref, stmobj, num, gen);
  195.  
  196.         if (fz_is_name(filters))
  197.                 return build_filter(chain, xref, filters, params, num, gen);
  198.         if (fz_array_len(filters) > 0)
  199.                 return build_filter_chain(chain, xref, filters, params, num, gen);
  200.  
  201.         return chain;
  202. }
  203.  
  204. /*
  205.  * Construct a filter to decode a stream, without
  206.  * constraining to stream length, and without decryption.
  207.  */
  208. fz_stream *
  209. pdf_open_inline_stream(fz_stream *chain, pdf_xref *xref, fz_obj *stmobj, int length)
  210. {
  211.         fz_obj *filters;
  212.         fz_obj *params;
  213.  
  214.         filters = fz_dict_getsa(stmobj, "Filter", "F");
  215.         params = fz_dict_getsa(stmobj, "DecodeParms", "DP");
  216.  
  217.         /* don't close chain when we close this filter */
  218.         fz_keep_stream(chain);
  219.  
  220.         if (fz_is_name(filters))
  221.                 return build_filter(chain, xref, filters, params, 0, 0);
  222.         if (fz_array_len(filters) > 0)
  223.                 return build_filter_chain(chain, xref, filters, params, 0, 0);
  224.  
  225.         return fz_open_null(chain, length);
  226. }
  227.  
  228. /*
  229.  * Open a stream for reading the raw (compressed but decrypted) data.
  230.  * Using xref->file while this is open is a bad idea.
  231.  */
  232. fz_error
  233. pdf_open_raw_stream(fz_stream **stmp, pdf_xref *xref, int num, int gen)
  234. {
  235.         pdf_xref_entry *x;
  236.         fz_error error;
  237.  
  238.         if (num < 0 || num >= xref->len)
  239.                 return fz_throw("object id out of range (%d %d R)", num, gen);
  240.  
  241.         x = xref->table + num;
  242.  
  243.         error = pdf_cache_object(xref, num, gen);
  244.         if (error)
  245.                 return fz_rethrow(error, "cannot load stream object (%d %d R)", num, gen);
  246.  
  247.         if (x->stm_ofs)
  248.         {
  249.                 *stmp = pdf_open_raw_filter(xref->file, xref, x->obj, num, gen);
  250.                 fz_seek(xref->file, x->stm_ofs, 0);
  251.                 return fz_okay;
  252.         }
  253.  
  254.         return fz_throw("object is not a stream");
  255. }
  256.  
  257. /*
  258.  * Open a stream for reading uncompressed data.
  259.  * Put the opened file in xref->stream.
  260.  * Using xref->file while a stream is open is a Bad idea.
  261.  */
  262. fz_error
  263. pdf_open_stream(fz_stream **stmp, pdf_xref *xref, int num, int gen)
  264. {
  265.         pdf_xref_entry *x;
  266.         fz_error error;
  267.  
  268.         if (num < 0 || num >= xref->len)
  269.                 return fz_throw("object id out of range (%d %d R)", num, gen);
  270.  
  271.         x = xref->table + num;
  272.  
  273.         error = pdf_cache_object(xref, num, gen);
  274.         if (error)
  275.                 return fz_rethrow(error, "cannot load stream object (%d %d R)", num, gen);
  276.  
  277.         if (x->stm_ofs)
  278.         {
  279.                 *stmp = pdf_open_filter(xref->file, xref, x->obj, num, gen);
  280.                 fz_seek(xref->file, x->stm_ofs, 0);
  281.                 return fz_okay;
  282.         }
  283.  
  284.         return fz_throw("object is not a stream");
  285. }
  286.  
  287. fz_error
  288. pdf_open_stream_at(fz_stream **stmp, pdf_xref *xref, int num, int gen, fz_obj *dict, int stm_ofs)
  289. {
  290.         if (stm_ofs)
  291.         {
  292.                 *stmp = pdf_open_filter(xref->file, xref, dict, num, gen);
  293.                 fz_seek(xref->file, stm_ofs, 0);
  294.                 return fz_okay;
  295.         }
  296.         return fz_throw("object is not a stream");
  297. }
  298.  
  299. /*
  300.  * Load raw (compressed but decrypted) contents of a stream into buf.
  301.  */
  302. fz_error
  303. pdf_load_raw_stream(fz_buffer **bufp, pdf_xref *xref, int num, int gen)
  304. {
  305.         fz_error error;
  306.         fz_stream *stm;
  307.         fz_obj *dict;
  308.         int len;
  309.  
  310.         error = pdf_load_object(&dict, xref, num, gen);
  311.         if (error)
  312.                 return fz_rethrow(error, "cannot load stream dictionary (%d %d R)", num, gen);
  313.  
  314.         len = fz_to_int(fz_dict_gets(dict, "Length"));
  315.  
  316.         fz_drop_obj(dict);
  317.  
  318.         error = pdf_open_raw_stream(&stm, xref, num, gen);
  319.         if (error)
  320.                 return fz_rethrow(error, "cannot open raw stream (%d %d R)", num, gen);
  321.  
  322.         error = fz_read_all(bufp, stm, len);
  323.         if (error)
  324.         {
  325.                 fz_close(stm);
  326.                 return fz_rethrow(error, "cannot read raw stream (%d %d R)", num, gen);
  327.         }
  328.  
  329.         fz_close(stm);
  330.         return fz_okay;
  331. }
  332.  
  333. static int
  334. pdf_guess_filter_length(int len, char *filter)
  335. {
  336.         if (!strcmp(filter, "ASCIIHexDecode"))
  337.                 return len / 2;
  338.         if (!strcmp(filter, "ASCII85Decode"))
  339.                 return len * 4 / 5;
  340.         if (!strcmp(filter, "FlateDecode"))
  341.                 return len * 3;
  342.         if (!strcmp(filter, "RunLengthDecode"))
  343.                 return len * 3;
  344.         if (!strcmp(filter, "LZWDecode"))
  345.                 return len * 2;
  346.         return len;
  347. }
  348.  
  349. /*
  350.  * Load uncompressed contents of a stream into buf.
  351.  */
  352. fz_error
  353. pdf_load_stream(fz_buffer **bufp, pdf_xref *xref, int num, int gen)
  354. {
  355.         fz_error error;
  356.         fz_stream *stm;
  357.         fz_obj *dict, *obj;
  358.         int i, len;
  359.  
  360.         error = pdf_open_stream(&stm, xref, num, gen);
  361.         if (error)
  362.                 return fz_rethrow(error, "cannot open stream (%d %d R)", num, gen);
  363.  
  364.         error = pdf_load_object(&dict, xref, num, gen);
  365.         if (error)
  366.                 return fz_rethrow(error, "cannot load stream dictionary (%d %d R)", num, gen);
  367.  
  368.         len = fz_to_int(fz_dict_gets(dict, "Length"));
  369.         obj = fz_dict_gets(dict, "Filter");
  370.         len = pdf_guess_filter_length(len, fz_to_name(obj));
  371.         for (i = 0; i < fz_array_len(obj); i++)
  372.                 len = pdf_guess_filter_length(len, fz_to_name(fz_array_get(obj, i)));
  373.  
  374.         fz_drop_obj(dict);
  375.  
  376.         error = fz_read_all(bufp, stm, len);
  377.         if (error)
  378.         {
  379.                 fz_close(stm);
  380.                 return fz_rethrow(error, "cannot read raw stream (%d %d R)", num, gen);
  381.         }
  382.  
  383.         fz_close(stm);
  384.         return fz_okay;
  385. }
  386.