texlive[67196] Build/source/libs/pplib: fixes decryption failure on

commits+lscarso at tug.org commits+lscarso at tug.org
Tue May 23 19:09:02 CEST 2023


Revision: 67196
          http://tug.org/svn/texlive?view=revision&revision=67196
Author:   lscarso
Date:     2023-05-23 19:09:02 +0200 (Tue, 23 May 2023)
Log Message:
-----------
fixes decryption failure on unreadable perms (Pawe{U+0142} Jackowski)

Modified Paths:
--------------
    trunk/Build/source/libs/pplib/ChangeLog
    trunk/Build/source/libs/pplib/pplib-src/doc/_build/doctrees/environment.pickle
    trunk/Build/source/libs/pplib/pplib-src/doc/_build/doctrees/ppapi-1.x.doctree
    trunk/Build/source/libs/pplib/pplib-src/doc/_build/doctrees/ppapi-2.x.doctree
    trunk/Build/source/libs/pplib/pplib-src/doc/_build/doctrees/ppcode.doctree
    trunk/Build/source/libs/pplib/pplib-src/doc/_build/doctrees/pplib.doctree
    trunk/Build/source/libs/pplib/pplib-src/doc/_build/doctrees/ppnew.doctree
    trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppapi-2.x.rst.txt
    trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppcode.rst.txt
    trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/genindex.html
    trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/ppapi-1.x.html
    trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/ppapi-2.x.html
    trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/ppcode.html
    trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/pplib.html
    trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/ppnew.html
    trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/search.html
    trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/searchindex.js
    trunk/Build/source/libs/pplib/pplib-src/doc/make.bat
    trunk/Build/source/libs/pplib/pplib-src/doc/ppapi-2.x.rst
    trunk/Build/source/libs/pplib/pplib-src/doc/ppcode.rst
    trunk/Build/source/libs/pplib/pplib-src/src/Makefile.vc
    trunk/Build/source/libs/pplib/pplib-src/src/ppapi.h
    trunk/Build/source/libs/pplib/pplib-src/src/ppcrypt.c
    trunk/Build/source/libs/pplib/pplib-src/src/ppcrypt.h
    trunk/Build/source/libs/pplib/pplib-src/src/pptest2.c

Modified: trunk/Build/source/libs/pplib/ChangeLog
===================================================================
--- trunk/Build/source/libs/pplib/ChangeLog	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/ChangeLog	2023-05-23 17:09:02 UTC (rev 67196)
@@ -1,2 +1,6 @@
+2023-05-23 Luigi Scarso luigi.scarso at gmail.com
+	* sync with the upstrem repo.:
+          fixes decryption failure on unreadable perms (Paweł Jackowski)
+
 2020-04-18 Luigi Scarso luigi.scarso at gmail.com
 	* Moved luatexdir/luapplib under libs/pplib.
\ No newline at end of file

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/_build/doctrees/environment.pickle
===================================================================
(Binary files differ)

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/_build/doctrees/ppapi-1.x.doctree
===================================================================
(Binary files differ)

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/_build/doctrees/ppapi-2.x.doctree
===================================================================
(Binary files differ)

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/_build/doctrees/ppcode.doctree
===================================================================
(Binary files differ)

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/_build/doctrees/pplib.doctree
===================================================================
(Binary files differ)

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/_build/doctrees/ppnew.doctree
===================================================================
(Binary files differ)

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppapi-2.x.rst.txt
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppapi-2.x.rst.txt	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppapi-2.x.rst.txt	2023-05-23 17:09:02 UTC (rev 67196)
@@ -677,15 +677,14 @@
 for a password), but some features (eg. printing) may restricted by the application.
 
 When ``pplib`` detects encryption, it follows Acrobat approach and first tries an empty password. If it succeeds, ``pplib`` proceeeds normally, providing
-an access to decrypted strings and streams, as if they weren't ciphered. If the document is protected with non-empty password, ``pplib`` gives
-a way to provide a password and proceed. Until you provide a password, ``ppdoc`` object returned by ``ppdoc_load()`` function has all object wntries
-set to ``null``.
+an access to decrypted strings and streams, as if they weren't ciphered. If the document is protected with non-empty password, you have to call
+``ppdoc_crypt_pass()``. Until you provide a password, ``ppdoc`` object returned by ``ppdoc_load()`` function has all object entries set to ``null``.
 
-After loading a document you should check encryption status with::
+Once the document is loaded, encryption status can be checked with::
 
   ppcrypt_status ppdoc_crypt_status (ppdoc *pdf);
 
-``ppcrypt_status`` (integer) may have the following values:
+``ppcrypt_status`` (enum) may have the following values:
 
   ``PPCRYPT_NONE`` - no encryption, go ahead
   ``PPCRYPT_DONE`` - encryption present but password succeeded, go ahead
@@ -697,11 +696,13 @@
   ppcrypt_status ppdoc_crypt_pass (ppdoc *pdf, const void *userpass, size_t userpasslength,
                                                const void *ownerpass, size_t ownerpasslength);
 
-Well, yes, there are actually two passwords in encrypted documents. Relation between them is obscure to me, but enough
-to know that having one of them is enough to decrypt the document. If you know the password, you probably mean
-``userpass``, in which case you should put ``NULL`` as ``ownerpass``. The function returns ``PPCRYPT_DONE`` if the password
-succeeds and the previous status otherwise. Your custom loader function may look like that::
+Providing one of two is enough to decrypt the document.
+It is ok to use the same password for owner and user -- ``pplib`` will try both.
 
+The function returns ``PPCRYPT_DONE`` if the password succeeds and the previous crypt status otherwise.
+
+Your custom loader function may look like that::
+
   ppdoc *pdf;
   pdf = ppdoc_load("file.pdf");
   if (pdf == NULL)
@@ -712,8 +713,7 @@
     case PPCRYPT_DONE:
       return pdf;
     case PPCRYPT_PASS:
-      if (ppdoc_crypt_pass(pdf, "dummy", 5, NULL, 0) == PPCRYPT_DONE ||
-          ppdoc_crypt_pass(pdf, NULL, 0, "dummy", 5) == PPCRYPT_DONE)
+      if (ppdoc_crypt_pass(pdf, "dummy", 5, "dummy", 5) == PPCRYPT_DONE)
         return pdf;
       printf("sorry, password needed\n");
       ppdoc_free(pdf);
@@ -724,7 +724,7 @@
       return NULL;
   }
 
-[If you get ``PPCRYPT_FAIL`` it might mean *I failed*, so treat as a bug.]
+See ``pplib`` tests suite for a complete code.
 
 If you'd like to know what permissions are given/restricted to encrypted document::
 
@@ -751,6 +751,15 @@
 
 Encryption is independent from compression, don't confuse with ``ppstream_compressed()``
 
+.. caution::
+   Starting from ``pplib v2.10`` all passwords should be passed as ``UTF-8``.
+   Earlier PDF encryption algorithms (/V 1..4, PDF 1.7) were based on ``PdfDocEncoding``.
+   Newer algorithms (/V 5, PDF 1.8-2.0) expect Unicode encoded as ``UTF-8``.
+   ``pplib`` API now expects ``UTF-8`` and if opening documents with older encryption methods,
+   it tries to make a conversion to 8-bit encoding. In earlier versions ``pplib`` didn't
+   make any password preprocessing, treating them as raw byte arrays.
+   So in case of passwords with fancy characters, it may behave differently.
+
 Pages
 -----
 

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppcode.rst.txt
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppcode.rst.txt	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppcode.rst.txt	2023-05-23 17:09:02 UTC (rev 67196)
@@ -95,7 +95,7 @@
 uint8_t instead of ppbyte in internals; ppbyte intent is "the most natural 8-bit integer", so it is 'char',
 but internally we almost always need uint8_t (char may be signed or not..)
 
-TODO
-====
-- external streams (egzotic)
-
+v2.10
+-----
+Rework on encryption; algorithms /V5 /R6.
+Passwords passed to ppdoc_crypt_pass() should be UTF-8 (backward incompatible).

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/genindex.html
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/genindex.html	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/genindex.html	2023-05-23 17:09:02 UTC (rev 67196)
@@ -79,7 +79,7 @@
     </div>
     <div class="footer" role="contentinfo">
         © Copyright 2019, p.jackowski at gust.org.pl.
-      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.5.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.6.
     </div>
   </body>
 </html>
\ No newline at end of file

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/ppapi-1.x.html
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/ppapi-1.x.html	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/ppapi-1.x.html	2023-05-23 17:09:02 UTC (rev 67196)
@@ -1024,7 +1024,7 @@
     </div>
     <div class="footer" role="contentinfo">
         © Copyright 2019, p.jackowski at gust.org.pl.
-      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.5.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.6.
     </div>
   </body>
 </html>
\ No newline at end of file

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/ppapi-2.x.html
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/ppapi-2.x.html	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/ppapi-2.x.html	2023-05-23 17:09:02 UTC (rev 67196)
@@ -752,14 +752,13 @@
 It is a common practise to <em>protect</em> documents with an empty password. Such documents remain readable in Acrobat (just opens them without prompting
 for a password), but some features (eg. printing) may restricted by the application.</p>
 <p>When <code class="docutils literal notranslate"><span class="pre">pplib</span></code> detects encryption, it follows Acrobat approach and first tries an empty password. If it succeeds, <code class="docutils literal notranslate"><span class="pre">pplib</span></code> proceeeds normally, providing
-an access to decrypted strings and streams, as if they weren’t ciphered. If the document is protected with non-empty password, <code class="docutils literal notranslate"><span class="pre">pplib</span></code> gives
-a way to provide a password and proceed. Until you provide a password, <code class="docutils literal notranslate"><span class="pre">ppdoc</span></code> object returned by <code class="docutils literal notranslate"><span class="pre">ppdoc_load()</span></code> function has all object wntries
-set to <code class="docutils literal notranslate"><span class="pre">null</span></code>.</p>
-<p>After loading a document you should check encryption status with:</p>
+an access to decrypted strings and streams, as if they weren’t ciphered. If the document is protected with non-empty password, you have to call
+<code class="docutils literal notranslate"><span class="pre">ppdoc_crypt_pass()</span></code>. Until you provide a password, <code class="docutils literal notranslate"><span class="pre">ppdoc</span></code> object returned by <code class="docutils literal notranslate"><span class="pre">ppdoc_load()</span></code> function has all object entries set to <code class="docutils literal notranslate"><span class="pre">null</span></code>.</p>
+<p>Once the document is loaded, encryption status can be checked with:</p>
 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">ppcrypt_status</span> <span class="n">ppdoc_crypt_status</span> <span class="p">(</span><span class="n">ppdoc</span> <span class="o">*</span><span class="n">pdf</span><span class="p">);</span>
 </pre></div>
 </div>
-<p><code class="docutils literal notranslate"><span class="pre">ppcrypt_status</span></code> (integer) may have the following values:</p>
+<p><code class="docutils literal notranslate"><span class="pre">ppcrypt_status</span></code> (enum) may have the following values:</p>
 <blockquote>
 <div><code class="docutils literal notranslate"><span class="pre">PPCRYPT_NONE</span></code> - no encryption, go ahead
 <code class="docutils literal notranslate"><span class="pre">PPCRYPT_DONE</span></code> - encryption present but password succeeded, go ahead
@@ -770,10 +769,10 @@
                                              <span class="n">const</span> <span class="n">void</span> <span class="o">*</span><span class="n">ownerpass</span><span class="p">,</span> <span class="n">size_t</span> <span class="n">ownerpasslength</span><span class="p">);</span>
 </pre></div>
 </div>
-<p>Well, yes, there are actually two passwords in encrypted documents. Relation between them is obscure to me, but enough
-to know that having one of them is enough to decrypt the document. If you know the password, you probably mean
-<code class="docutils literal notranslate"><span class="pre">userpass</span></code>, in which case you should put <code class="docutils literal notranslate"><span class="pre">NULL</span></code> as <code class="docutils literal notranslate"><span class="pre">ownerpass</span></code>. The function returns <code class="docutils literal notranslate"><span class="pre">PPCRYPT_DONE</span></code> if the password
-succeeds and the previous status otherwise. Your custom loader function may look like that:</p>
+<p>Providing one of two is enough to decrypt the document.
+It is ok to use the same password for owner and user – <code class="docutils literal notranslate"><span class="pre">pplib</span></code> will try both.</p>
+<p>The function returns <code class="docutils literal notranslate"><span class="pre">PPCRYPT_DONE</span></code> if the password succeeds and the previous crypt status otherwise.</p>
+<p>Your custom loader function may look like that:</p>
 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">ppdoc</span> <span class="o">*</span><span class="n">pdf</span><span class="p">;</span>
 <span class="n">pdf</span> <span class="o">=</span> <span class="n">ppdoc_load</span><span class="p">(</span><span class="s2">"file.pdf"</span><span class="p">);</span>
 <span class="k">if</span> <span class="p">(</span><span class="n">pdf</span> <span class="o">==</span> <span class="n">NULL</span><span class="p">)</span>
@@ -784,8 +783,7 @@
   <span class="n">case</span> <span class="n">PPCRYPT_DONE</span><span class="p">:</span>
     <span class="k">return</span> <span class="n">pdf</span><span class="p">;</span>
   <span class="n">case</span> <span class="n">PPCRYPT_PASS</span><span class="p">:</span>
-    <span class="k">if</span> <span class="p">(</span><span class="n">ppdoc_crypt_pass</span><span class="p">(</span><span class="n">pdf</span><span class="p">,</span> <span class="s2">"dummy"</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="n">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">==</span> <span class="n">PPCRYPT_DONE</span> <span class="o">||</span>
-        <span class="n">ppdoc_crypt_pass</span><span class="p">(</span><span class="n">pdf</span><span class="p">,</span> <span class="n">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s2">"dummy"</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span> <span class="o">==</span> <span class="n">PPCRYPT_DONE</span><span class="p">)</span>
+    <span class="k">if</span> <span class="p">(</span><span class="n">ppdoc_crypt_pass</span><span class="p">(</span><span class="n">pdf</span><span class="p">,</span> <span class="s2">"dummy"</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="s2">"dummy"</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span> <span class="o">==</span> <span class="n">PPCRYPT_DONE</span><span class="p">)</span>
       <span class="k">return</span> <span class="n">pdf</span><span class="p">;</span>
     <span class="n">printf</span><span class="p">(</span><span class="s2">"sorry, password needed</span><span class="se">\n</span><span class="s2">"</span><span class="p">);</span>
     <span class="n">ppdoc_free</span><span class="p">(</span><span class="n">pdf</span><span class="p">);</span>
@@ -797,7 +795,7 @@
 <span class="p">}</span>
 </pre></div>
 </div>
-<p>[If you get <code class="docutils literal notranslate"><span class="pre">PPCRYPT_FAIL</span></code> it might mean <em>I failed</em>, so treat as a bug.]</p>
+<p>See <code class="docutils literal notranslate"><span class="pre">pplib</span></code> tests suite for a complete code.</p>
 <p>If you’d like to know what permissions are given/restricted to encrypted document:</p>
 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">ppint</span> <span class="n">ppdoc_permissions</span> <span class="p">(</span><span class="n">ppdoc</span> <span class="o">*</span><span class="n">pdf</span><span class="p">);</span>
 </pre></div>
@@ -821,7 +819,17 @@
 </pre></div>
 </div>
 <p>Encryption is independent from compression, don’t confuse with <code class="docutils literal notranslate"><span class="pre">ppstream_compressed()</span></code></p>
+<div class="admonition caution">
+<p class="first admonition-title">Caution</p>
+<p class="last">Starting from <code class="docutils literal notranslate"><span class="pre">pplib</span> <span class="pre">v2.10</span></code> all passwords should be passed as <code class="docutils literal notranslate"><span class="pre">UTF-8</span></code>.
+Earlier PDF encryption algorithms (/V 1..4, PDF 1.7) were based on <code class="docutils literal notranslate"><span class="pre">PdfDocEncoding</span></code>.
+Newer algorithms (/V 5, PDF 1.8-2.0) expect Unicode encoded as <code class="docutils literal notranslate"><span class="pre">UTF-8</span></code>.
+<code class="docutils literal notranslate"><span class="pre">pplib</span></code> API now expects <code class="docutils literal notranslate"><span class="pre">UTF-8</span></code> and if opening documents with older encryption methods,
+it tries to make a conversion to 8-bit encoding. In earlier versions <code class="docutils literal notranslate"><span class="pre">pplib</span></code> didn’t
+make any password preprocessing, treating them as raw byte arrays.
+So in case of passwords with fancy characters, it may behave differently.</p>
 </div>
+</div>
 <div class="section" id="pages">
 <h2>Pages<a class="headerlink" href="#pages" title="Permalink to this headline">¶</a></h2>
 <p>Several helpers to deal with pages. To get the number of pages:</p>
@@ -1025,7 +1033,7 @@
     </div>
     <div class="footer" role="contentinfo">
         © Copyright 2019, p.jackowski at gust.org.pl.
-      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.5.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.6.
     </div>
   </body>
 </html>
\ No newline at end of file

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/ppcode.html
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/ppcode.html	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/ppcode.html	2023-05-23 17:09:02 UTC (rev 67196)
@@ -63,9 +63,9 @@
 <li><a class="reference internal" href="#v2-03">v2.03</a></li>
 <li><a class="reference internal" href="#v2-04">v2.04</a></li>
 <li><a class="reference internal" href="#v2-05">v2.05</a></li>
+<li><a class="reference internal" href="#v2-10">v2.10</a></li>
 </ul>
 </li>
-<li><a class="reference internal" href="#todo">TODO</a></li>
 </ul>
 
   <h4>Previous topic</h4>
@@ -212,143 +212,175 @@
 <div class="section" id="example-2">
 <h2>Example 2<a class="headerlink" href="#example-2" title="Permalink to this headline">¶</a></h2>
 <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>
-<span class="c1">#include <stdio.h></span>
-<span class="c1">#include <assert.h></span>
-<span class="c1">#include "ppapi.h"</span>
+#include <stdio.h>
+#include <assert.h>
+#include "ppapi.h"
 
-<span class="o">/*</span>
-<span class="n">static</span> <span class="n">const</span> <span class="n">char</span> <span class="o">*</span> <span class="n">get_file_name</span> <span class="p">(</span><span class="n">const</span> <span class="n">char</span> <span class="o">*</span><span class="n">path</span><span class="p">)</span>
-<span class="p">{</span>
-  <span class="n">const</span> <span class="n">char</span> <span class="o">*</span><span class="n">fn</span><span class="p">,</span> <span class="o">*</span><span class="n">p</span><span class="p">;</span>
-  <span class="k">for</span> <span class="p">(</span><span class="n">fn</span> <span class="o">=</span> <span class="n">p</span> <span class="o">=</span> <span class="n">path</span><span class="p">;</span> <span class="o">*</span><span class="n">p</span> <span class="o">!=</span> <span class="s1">'</span><span class="se">\0</span><span class="s1">'</span><span class="p">;</span> <span class="o">++</span><span class="n">p</span><span class="p">)</span>
-    <span class="k">if</span> <span class="p">(</span><span class="o">*</span><span class="n">p</span> <span class="o">==</span> <span class="s1">'</span><span class="se">\\</span><span class="s1">'</span> <span class="o">||</span> <span class="o">*</span><span class="n">p</span> <span class="o">==</span> <span class="s1">'/'</span><span class="p">)</span>
-      <span class="n">fn</span> <span class="o">=</span> <span class="n">p</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
-  <span class="k">return</span> <span class="n">fn</span><span class="p">;</span>
-<span class="p">}</span>
-<span class="o">*/</span>
+/*
+static const char * get_file_name (const char *path)
+{
+  const char *fn, *p;
+  for (fn = p = path; *p != '\0'; ++p)
+    if (*p == '\\' || *p == '/')
+      fn = p + 1;
+  return fn;
+}
+*/
 
-<span class="n">static</span> <span class="n">void</span> <span class="n">box_info</span> <span class="p">(</span><span class="n">ppdict</span> <span class="o">*</span><span class="n">pagedict</span><span class="p">,</span> <span class="n">FILE</span> <span class="o">*</span><span class="n">fh</span><span class="p">)</span>
-<span class="p">{</span>
-  <span class="n">const</span> <span class="n">char</span> <span class="o">*</span><span class="n">boxes</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"MediaBox"</span><span class="p">,</span> <span class="s2">"CropBox"</span><span class="p">,</span> <span class="s2">"BleedBox"</span><span class="p">,</span> <span class="s2">"TrimBox"</span><span class="p">,</span> <span class="s2">"ArtBox"</span><span class="p">};</span>
-  <span class="n">pprect</span> <span class="n">rect</span><span class="p">;</span>
-  <span class="n">size_t</span> <span class="n">i</span><span class="p">;</span>
-  <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">sizeof</span><span class="p">(</span><span class="n">boxes</span><span class="p">)</span> <span class="o">/</span> <span class="n">sizeof</span><span class="p">(</span><span class="n">const</span> <span class="n">char</span> <span class="o">*</span><span class="p">);</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span>
-    <span class="k">if</span> <span class="p">(</span><span class="n">ppdict_get_box</span><span class="p">(</span><span class="n">pagedict</span><span class="p">,</span> <span class="n">boxes</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="o">&</span><span class="n">rect</span><span class="p">))</span>
-      <span class="n">fprintf</span><span class="p">(</span><span class="n">fh</span><span class="p">,</span> <span class="s2">"</span><span class="si">%%%%</span><span class="s2"> </span><span class="si">%s</span><span class="s2"> [</span><span class="si">%f</span><span class="s2"> </span><span class="si">%f</span><span class="s2"> </span><span class="si">%f</span><span class="s2"> </span><span class="si">%f</span><span class="s2">]</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="n">boxes</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">rect</span><span class="o">.</span><span class="n">lx</span><span class="p">,</span> <span class="n">rect</span><span class="o">.</span><span class="n">ly</span><span class="p">,</span> <span class="n">rect</span><span class="o">.</span><span class="n">rx</span><span class="p">,</span> <span class="n">rect</span><span class="o">.</span><span class="n">ry</span><span class="p">);</span>
-<span class="p">}</span>
+static void box_info (ppdict *pagedict, FILE *fh)
+{
+  const char *boxes[] = {"MediaBox", "CropBox", "BleedBox", "TrimBox", "ArtBox"};
+  pprect rect;
+  size_t i;
+  for (i = 0; i < sizeof(boxes) / sizeof(const char *); ++i)
+    if (ppdict_get_box(pagedict, boxes[i], &rect))
+      fprintf(fh, "%%%% %s [%f %f %f %f]\n", boxes[i], rect.lx, rect.ly, rect.rx, rect.ry);
+}
 
-<span class="n">static</span> <span class="nb">int</span> <span class="n">usage</span> <span class="p">(</span><span class="n">const</span> <span class="n">char</span> <span class="o">*</span><span class="n">argv0</span><span class="p">)</span>
-<span class="p">{</span>
-  <span class="n">printf</span><span class="p">(</span><span class="s2">"pplib "</span> <span class="n">pplib_version</span> <span class="s2">", "</span> <span class="n">pplib_author</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">);</span>
-  <span class="n">printf</span><span class="p">(</span><span class="s2">"usage: </span><span class="si">%s</span><span class="s2"> file1.pdf file2.pdf ...</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="n">argv0</span><span class="p">);</span>
-  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
-<span class="p">}</span>
+static int usage (const char *argv0)
+{
+  printf("pplib " pplib_version ", " pplib_author "\n");
+  printf("usage: %s file1.pdf file2.pdf ...\n", argv0);
+  printf("       %s file.pdf -u userpassword\n", argv0);
+  printf("       %s file.pdf -o ownerpassword\n", argv0);
+  printf("       %s file.pdf -p bothpasswords\n", argv0);
+  return 0;
+}
 
-<span class="n">static</span> <span class="n">void</span> <span class="n">log_callback</span> <span class="p">(</span><span class="n">const</span> <span class="n">char</span> <span class="o">*</span><span class="n">message</span><span class="p">,</span> <span class="n">void</span> <span class="o">*</span><span class="n">alien</span><span class="p">)</span>
-<span class="p">{</span>
-  <span class="n">fprintf</span><span class="p">((</span><span class="n">FILE</span> <span class="o">*</span><span class="p">)</span><span class="n">alien</span><span class="p">,</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">ooops: </span><span class="si">%s</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="n">message</span><span class="p">);</span>
-<span class="p">}</span>
+static void log_callback (const char *message, void *alien)
+{
+  fprintf((FILE *)alien, "\nooops: %s\n", message);
+}
 
-<span class="nb">int</span> <span class="n">main</span> <span class="p">(</span><span class="nb">int</span> <span class="n">argc</span><span class="p">,</span> <span class="n">const</span> <span class="n">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span>
-<span class="p">{</span>
-  <span class="n">const</span> <span class="n">char</span> <span class="o">*</span><span class="n">filepath</span><span class="p">;</span>
-  <span class="nb">int</span> <span class="n">a</span><span class="p">;</span>
-  <span class="n">ppdoc</span> <span class="o">*</span><span class="n">pdf</span><span class="p">;</span>
-  <span class="n">ppref</span> <span class="o">*</span><span class="n">pageref</span><span class="p">;</span>
-  <span class="n">ppdict</span> <span class="o">*</span><span class="n">pagedict</span><span class="p">;</span>
-  <span class="nb">int</span> <span class="n">pageno</span><span class="p">;</span>
-  <span class="n">char</span> <span class="n">outname</span><span class="p">[</span><span class="mi">1024</span><span class="p">];</span>
-  <span class="n">FILE</span> <span class="o">*</span><span class="n">fh</span><span class="p">;</span>
-  <span class="n">ppstream</span> <span class="o">*</span><span class="n">stream</span><span class="p">;</span>
-  <span class="n">uint8_t</span> <span class="o">*</span><span class="n">data</span><span class="p">;</span>
-  <span class="n">size_t</span> <span class="n">size</span><span class="p">;</span>
-  <span class="n">ppcontext</span> <span class="o">*</span><span class="n">context</span><span class="p">;</span>
-  <span class="n">ppobj</span> <span class="o">*</span><span class="n">obj</span><span class="p">;</span>
-  <span class="n">ppname</span> <span class="o">*</span><span class="n">op</span><span class="p">;</span>
-  <span class="n">size_t</span> <span class="n">operators</span><span class="p">;</span>
+static const char * get_next_argument (const char *opt, int *a, int argc, const char **argv)
+{
+  const char *next;
+  if ((*a) + 2 < argc)
+  {
+    next = argv[*a + 1];
+    if (strcmp(next, opt) == 0)
+    {
+      *a += 2;
+      return argv[*a];
+    }
+  }
+  return NULL;
+}
 
-  <span class="k">if</span> <span class="p">(</span><span class="n">argc</span> <span class="o"><</span> <span class="mi">2</span><span class="p">)</span>
-    <span class="k">return</span> <span class="n">usage</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
-  <span class="n">ppstream_init_buffers</span><span class="p">();</span>
-  <span class="n">pplog_callback</span><span class="p">(</span><span class="n">log_callback</span><span class="p">,</span> <span class="n">stderr</span><span class="p">);</span>
-  <span class="n">context</span> <span class="o">=</span> <span class="n">ppcontext_new</span><span class="p">();</span>
-  <span class="k">for</span> <span class="p">(</span><span class="n">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">a</span> <span class="o"><</span> <span class="n">argc</span><span class="p">;</span> <span class="o">++</span><span class="n">a</span><span class="p">)</span>
-  <span class="p">{</span>
-    <span class="n">filepath</span> <span class="o">=</span> <span class="n">argv</span><span class="p">[</span><span class="n">a</span><span class="p">];</span>
-    <span class="n">printf</span><span class="p">(</span><span class="s2">"loading </span><span class="si">%s</span><span class="s2">... "</span><span class="p">,</span> <span class="n">filepath</span><span class="p">);</span>
-    <span class="n">pdf</span> <span class="o">=</span> <span class="n">ppdoc_load</span><span class="p">(</span><span class="n">filepath</span><span class="p">);</span>
-    <span class="k">if</span> <span class="p">(</span><span class="n">pdf</span> <span class="o">==</span> <span class="n">NULL</span><span class="p">)</span>
-    <span class="p">{</span>
-      <span class="n">printf</span><span class="p">(</span><span class="s2">"failed</span><span class="se">\n</span><span class="s2">"</span><span class="p">);</span>
-      <span class="k">continue</span><span class="p">;</span>
-    <span class="p">}</span>
-    <span class="n">printf</span><span class="p">(</span><span class="s2">"done.</span><span class="se">\n</span><span class="s2">"</span><span class="p">);</span>
-    <span class="n">switch</span> <span class="p">(</span><span class="n">ppdoc_crypt_status</span><span class="p">(</span><span class="n">pdf</span><span class="p">))</span>
-    <span class="p">{</span>
-      <span class="n">case</span> <span class="n">PPCRYPT_NONE</span><span class="p">:</span>
-      <span class="n">case</span> <span class="n">PPCRYPT_DONE</span><span class="p">:</span>
-        <span class="k">break</span><span class="p">;</span>
-      <span class="n">case</span> <span class="n">PPCRYPT_PASS</span><span class="p">:</span>
-        <span class="k">if</span> <span class="p">(</span><span class="n">ppdoc_crypt_pass</span><span class="p">(</span><span class="n">pdf</span><span class="p">,</span> <span class="s2">"dummy"</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="n">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">==</span> <span class="n">PPCRYPT_DONE</span> <span class="o">||</span> <span class="n">ppdoc_crypt_pass</span><span class="p">(</span><span class="n">pdf</span><span class="p">,</span> <span class="n">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s2">"dummy"</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span> <span class="o">==</span> <span class="n">PPCRYPT_DONE</span><span class="p">)</span>
-          <span class="k">break</span><span class="p">;</span>
-        <span class="n">printf</span><span class="p">(</span><span class="s2">"sorry, password needed</span><span class="se">\n</span><span class="s2">"</span><span class="p">);</span>
-        <span class="n">ppdoc_free</span><span class="p">(</span><span class="n">pdf</span><span class="p">);</span>
-        <span class="k">continue</span><span class="p">;</span>
-      <span class="n">case</span> <span class="n">PPCRYPT_FAIL</span><span class="p">:</span>
-        <span class="n">printf</span><span class="p">(</span><span class="s2">"sorry, encryption failed</span><span class="se">\n</span><span class="s2">"</span><span class="p">);</span>
-        <span class="n">ppdoc_free</span><span class="p">(</span><span class="n">pdf</span><span class="p">);</span>
-        <span class="k">continue</span><span class="p">;</span>
-    <span class="p">}</span>
-    <span class="n">sprintf</span><span class="p">(</span><span class="n">outname</span><span class="p">,</span> <span class="s2">"</span><span class="si">%s</span><span class="s2">.out"</span><span class="p">,</span> <span class="n">filepath</span><span class="p">);</span>
-    <span class="n">fh</span> <span class="o">=</span> <span class="n">fopen</span><span class="p">(</span><span class="n">outname</span><span class="p">,</span> <span class="s2">"wb"</span><span class="p">);</span>
-    <span class="k">if</span> <span class="p">(</span><span class="n">fh</span> <span class="o">==</span> <span class="n">NULL</span><span class="p">)</span>
-    <span class="p">{</span>
-      <span class="n">printf</span><span class="p">(</span><span class="s2">"can't open </span><span class="si">%s</span><span class="s2"> for writing</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="n">outname</span><span class="p">);</span>
-      <span class="k">continue</span><span class="p">;</span>
-    <span class="p">}</span>
-    <span class="k">for</span> <span class="p">(</span><span class="n">pageref</span> <span class="o">=</span> <span class="n">ppdoc_first_page</span><span class="p">(</span><span class="n">pdf</span><span class="p">),</span> <span class="n">pageno</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
-         <span class="n">pageref</span> <span class="o">!=</span> <span class="n">NULL</span><span class="p">;</span>
-         <span class="n">pageref</span> <span class="o">=</span> <span class="n">ppdoc_next_page</span><span class="p">(</span><span class="n">pdf</span><span class="p">),</span> <span class="o">++</span><span class="n">pageno</span><span class="p">)</span>
-    <span class="p">{</span>
-      <span class="n">pagedict</span> <span class="o">=</span> <span class="n">pageref</span><span class="o">-></span><span class="nb">object</span><span class="o">.</span><span class="n">dict</span><span class="p">;</span>
-      <span class="o">/*</span> <span class="n">decompress</span> <span class="n">contents</span> <span class="n">data</span> <span class="o">*/</span>
-      <span class="n">fprintf</span><span class="p">(</span><span class="n">fh</span><span class="p">,</span> <span class="s2">"</span><span class="si">%%%%</span><span class="s2"> PAGE </span><span class="si">%d</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="n">pageno</span><span class="p">);</span>
-      <span class="n">box_info</span><span class="p">(</span><span class="n">pagedict</span><span class="p">,</span> <span class="n">fh</span><span class="p">);</span>
-      <span class="k">for</span> <span class="p">(</span><span class="n">stream</span> <span class="o">=</span> <span class="n">ppcontents_first</span><span class="p">(</span><span class="n">pagedict</span><span class="p">);</span>
-           <span class="n">stream</span> <span class="o">!=</span> <span class="n">NULL</span><span class="p">;</span>
-           <span class="n">stream</span> <span class="o">=</span> <span class="n">ppcontents_next</span><span class="p">(</span><span class="n">pagedict</span><span class="p">,</span> <span class="n">stream</span><span class="p">))</span>
-      <span class="p">{</span>
-        <span class="k">for</span> <span class="p">(</span><span class="n">data</span> <span class="o">=</span> <span class="n">ppstream_first</span><span class="p">(</span><span class="n">stream</span><span class="p">,</span> <span class="o">&</span><span class="n">size</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
-             <span class="n">data</span> <span class="o">!=</span> <span class="n">NULL</span><span class="p">;</span>
-             <span class="n">data</span> <span class="o">=</span> <span class="n">ppstream_next</span><span class="p">(</span><span class="n">stream</span><span class="p">,</span> <span class="o">&</span><span class="n">size</span><span class="p">))</span>
-          <span class="n">fwrite</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">fh</span><span class="p">);</span>
-        <span class="n">ppstream_done</span><span class="p">(</span><span class="n">stream</span><span class="p">);</span>
-      <span class="p">}</span>
-      <span class="o">/*</span> <span class="n">now</span> <span class="n">parse</span> <span class="n">contents</span> <span class="o">*/</span>
-      <span class="k">for</span> <span class="p">(</span><span class="n">stream</span> <span class="o">=</span> <span class="n">ppcontents_first</span><span class="p">(</span><span class="n">pagedict</span><span class="p">);</span>
-           <span class="n">stream</span> <span class="o">!=</span> <span class="n">NULL</span><span class="p">;</span>
-           <span class="n">stream</span> <span class="o">=</span> <span class="n">ppcontents_next</span><span class="p">(</span><span class="n">pagedict</span><span class="p">,</span> <span class="n">stream</span><span class="p">))</span>
-      <span class="p">{</span>
-        <span class="n">operators</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
-        <span class="k">for</span> <span class="p">(</span><span class="n">obj</span> <span class="o">=</span> <span class="n">ppcontents_first_op</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">stream</span><span class="p">,</span> <span class="o">&</span><span class="n">size</span><span class="p">,</span> <span class="o">&</span><span class="n">op</span><span class="p">);</span>
-             <span class="n">obj</span> <span class="o">!=</span> <span class="n">NULL</span><span class="p">;</span>
-             <span class="n">obj</span> <span class="o">=</span> <span class="n">ppcontents_next_op</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">stream</span><span class="p">,</span> <span class="o">&</span><span class="n">size</span><span class="p">,</span> <span class="o">&</span><span class="n">op</span><span class="p">))</span>
-          <span class="o">++</span><span class="n">operators</span><span class="p">;</span>
-        <span class="n">fprintf</span><span class="p">(</span><span class="n">fh</span><span class="p">,</span> <span class="s2">"</span><span class="si">%%%%</span><span class="s2"> OPERATORS count </span><span class="si">%lu</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="p">(</span><span class="n">unsigned</span> <span class="n">long</span><span class="p">)</span><span class="n">operators</span><span class="p">);</span>
-        <span class="n">ppstream_done</span><span class="p">(</span><span class="n">stream</span><span class="p">);</span>
-        <span class="o">//</span><span class="n">obj</span> <span class="o">=</span> <span class="n">ppcontents_parse</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">stream</span><span class="p">,</span> <span class="o">&</span><span class="n">size</span><span class="p">);</span>
-        <span class="o">//</span><span class="n">fprintf</span><span class="p">(</span><span class="n">fh</span><span class="p">,</span> <span class="s2">"</span><span class="si">%%%%</span><span class="s2"> items count </span><span class="si">%lu</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="p">(</span><span class="n">unsigned</span> <span class="n">long</span><span class="p">)</span><span class="n">size</span><span class="p">);</span>
-        <span class="n">fprintf</span><span class="p">(</span><span class="n">fh</span><span class="p">,</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">);</span>
-      <span class="p">}</span>
-      <span class="n">ppcontext_done</span><span class="p">(</span><span class="n">context</span><span class="p">);</span>
-    <span class="p">}</span>
-    <span class="n">fclose</span><span class="p">(</span><span class="n">fh</span><span class="p">);</span>
-    <span class="n">ppdoc_free</span><span class="p">(</span><span class="n">pdf</span><span class="p">);</span>
-  <span class="p">}</span>
-  <span class="n">ppcontext_free</span><span class="p">(</span><span class="n">context</span><span class="p">);</span>
-  <span class="n">ppstream_free_buffers</span><span class="p">();</span>
-  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
-<span class="p">}</span>
+int main (int argc, const char **argv)
+{
+  const char *filepath, *password;
+  int a;
+  ppdoc *pdf;
+  ppcrypt_status cryptstatus;
+  ppref *pageref;
+  ppdict *pagedict;
+  int pageno;
+  char outname[1024];
+  FILE *fh;
+  ppstream *stream;
+  uint8_t *data;
+  size_t size;
+  ppcontext *context;
+  ppobj *obj;
+  ppname *op;
+  size_t operators;
+
+  if (argc < 2)
+    return usage(argv[0]);
+  ppstream_init_buffers();
+  pplog_callback(log_callback, stderr);
+  context = ppcontext_new();
+  for (a = 1; a < argc; ++a)
+  {
+    /* load */
+    filepath = argv[a];
+    printf("loading %s... ", filepath);
+    pdf = ppdoc_load(filepath);
+    if (pdf == NULL)
+    {
+      printf("failed\n");
+      continue;
+    }
+    printf("done\n");
+
+    /* decrypt */
+    if ((password = get_next_argument("-u", &a, argc, argv)) != NULL)
+      cryptstatus = ppdoc_crypt_pass(pdf, password, strlen(password), NULL, 0);
+    else if ((password = get_next_argument("-o", &a, argc, argv)) != NULL)
+      cryptstatus = ppdoc_crypt_pass(pdf, NULL, 0, password, strlen(password));
+    else if ((password = get_next_argument("-p", &a, argc, argv)) != NULL)
+      cryptstatus = ppdoc_crypt_pass(pdf, password, strlen(password), password, strlen(password));
+    else
+      cryptstatus = ppdoc_crypt_status(pdf);
+    switch (cryptstatus)
+    {
+      case PPCRYPT_NONE:
+        break;
+      case PPCRYPT_DONE:
+        printf("opened with password '%s'\n", password != NULL ? password : "");
+        break;
+      case PPCRYPT_PASS:
+        printf("invalid password\n");
+        ppdoc_free(pdf);
+        continue;
+      case PPCRYPT_FAIL:
+        printf("invalid encryption\n");
+        ppdoc_free(pdf);
+        continue;
+    }
+
+    /* process */
+    sprintf(outname, "%s.out", filepath);
+    fh = fopen(outname, "wb");
+    if (fh == NULL)
+    {
+      printf("can't open %s for writing\n", outname);
+      continue;
+    }
+    for (pageref = ppdoc_first_page(pdf), pageno = 1;
+         pageref != NULL;
+         pageref = ppdoc_next_page(pdf), ++pageno)
+    {
+      pagedict = pageref->object.dict;
+      /* decompress contents data */
+      fprintf(fh, "%%%% PAGE %d\n", pageno);
+      box_info(pagedict, fh);
+      for (stream = ppcontents_first(pagedict);
+           stream != NULL;
+           stream = ppcontents_next(pagedict, stream))
+      {
+        for (data = ppstream_first(stream, &size, 1);
+             data != NULL;
+             data = ppstream_next(stream, &size))
+          fwrite(data, size, 1, fh);
+        ppstream_done(stream);
+      }
+      /* now parse contents */
+      for (stream = ppcontents_first(pagedict);
+           stream != NULL;
+           stream = ppcontents_next(pagedict, stream))
+      {
+        operators = 0;
+        for (obj = ppcontents_first_op(context, stream, &size, &op);
+             obj != NULL;
+             obj = ppcontents_next_op(context, stream, &size, &op))
+          ++operators;
+        fprintf(fh, "%%%% OPERATORS count %lu\n", (unsigned long)operators);
+        ppstream_done(stream);
+        //obj = ppcontents_parse(context, stream, &size);
+        //fprintf(fh, "%%%% items count %lu\n", (unsigned long)size);
+        fprintf(fh, "\n");
+      }
+      ppcontext_done(context);
+    }
+    fclose(fh);
+    ppdoc_free(pdf);
+  }
+  ppcontext_free(context);
+  ppstream_free_buffers();
+  return 0;
+}
 </pre></div>
 </div>
 </div>
@@ -492,7 +524,7 @@
 
 <span class="c1">#include "ppconf.h"</span>
 
-<span class="c1">#define pplib_version "v2.05 less toxic i hope"</span>
+<span class="c1">#define pplib_version "v2.1"</span>
 <span class="c1">#define pplib_author "p.jackowski at gust.org.pl"</span>
 
 <span class="o">/*</span> <span class="n">types</span> <span class="o">*/</span>
@@ -962,12 +994,11 @@
 <p>uint8_t instead of ppbyte in internals; ppbyte intent is “the most natural 8-bit integer”, so it is ‘char’,
 but internally we almost always need uint8_t (char may be signed or not..)</p>
 </div>
+<div class="section" id="v2-10">
+<h2>v2.10<a class="headerlink" href="#v2-10" title="Permalink to this headline">¶</a></h2>
+<p>Rework on encryption; algorithms /V5 /R6.
+Passwords passed to ppdoc_crypt_pass() should be UTF-8 (backward incompatible).</p>
 </div>
-<div class="section" id="todo">
-<h1>TODO<a class="headerlink" href="#todo" title="Permalink to this headline">¶</a></h1>
-<ul class="simple">
-<li>external streams (egzotic)</li>
-</ul>
 </div>
 
 
@@ -990,7 +1021,7 @@
     </div>
     <div class="footer" role="contentinfo">
         © Copyright 2019, p.jackowski at gust.org.pl.
-      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.5.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.6.
     </div>
   </body>
 </html>
\ No newline at end of file

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/pplib.html
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/pplib.html	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/pplib.html	2023-05-23 17:09:02 UTC (rev 67196)
@@ -143,9 +143,9 @@
 <li class="toctree-l2"><a class="reference internal" href="ppcode.html#v2-03">v2.03</a></li>
 <li class="toctree-l2"><a class="reference internal" href="ppcode.html#v2-04">v2.04</a></li>
 <li class="toctree-l2"><a class="reference internal" href="ppcode.html#v2-05">v2.05</a></li>
+<li class="toctree-l2"><a class="reference internal" href="ppcode.html#v2-10">v2.10</a></li>
 </ul>
 </li>
-<li class="toctree-l1"><a class="reference internal" href="ppcode.html#todo">TODO</a></li>
 </ul>
 </div>
 </div>
@@ -170,7 +170,7 @@
     </div>
     <div class="footer" role="contentinfo">
         © Copyright 2019, p.jackowski at gust.org.pl.
-      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.5.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.6.
     </div>
   </body>
 </html>
\ No newline at end of file

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/ppnew.html
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/ppnew.html	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/ppnew.html	2023-05-23 17:09:02 UTC (rev 67196)
@@ -203,7 +203,7 @@
     </div>
     <div class="footer" role="contentinfo">
         © Copyright 2019, p.jackowski at gust.org.pl.
-      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.5.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.6.
     </div>
   </body>
 </html>
\ No newline at end of file

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/search.html
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/search.html	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/search.html	2023-05-23 17:09:02 UTC (rev 67196)
@@ -91,7 +91,7 @@
     </div>
     <div class="footer" role="contentinfo">
         © Copyright 2019, p.jackowski at gust.org.pl.
-      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.5.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.6.
     </div>
   </body>
 </html>
\ No newline at end of file

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/searchindex.js
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/searchindex.js	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/doc/_build/html/searchindex.js	2023-05-23 17:09:02 UTC (rev 67196)
@@ -1 +1 @@
-Search.setIndex({docnames:["ppapi-1.x","ppapi-2.x","ppcode","pplib","ppnew"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,sphinx:54},filenames:["ppapi-1.x.rst","ppapi-2.x.rst","ppcode.rst","pplib.rst","ppnew.rst"],objects:{},objnames:{},objtypes:{},terms:{"1mb":[0,1],"2fkb":2,"2fmb":2,"64kb":[0,1],"boolean":[0,1],"break":[0,1,2],"byte":[0,1,2,4],"case":[0,1,2,4],"char":[0,1,2,4],"const":[0,1,2,4],"default":[0,1,2],"enum":[0,1,2],"final":[0,1],"function":[0,1,2,4],"int":[0,1,2,4],"long":[0,1,2,4],"new":[0,1],"null":[0,1,2,4],"return":[0,1,2,4],"short":[0,1],"static":2,"switch":[0,1,2,4],"void":[0,1,2],"while":[0,1,4],And:[0,1,3],But:[0,1],For:[0,1],NOT:2,One:[0,1],Such:[0,1],The:[0,1,4],Then:[0,1],There:[0,1,4],Use:[0,1],Using:4,about:[0,1,2,4],abov:[0,1],absolutelli:[0,1],accept:[0,1,4],access:[0,1,2],accessor:[0,1],accord:[0,1],acrobat:[0,1,2],actual:[0,1,4],added:2,addit:[0,1],address:4,adjust:2,after:[0,1,2],again:[0,1,2],ahead:[0,1],alfterego:4,alia:[0,1,4],alias:[1,4],alien:[0,1,2],align:[2,4],aliv:[0,1],all:[0,1,4],alloc:[0,1,2,3],allow:[0,1],almost:[2,4],alreadi:[0,1],also:[0,1],alter:[0,1],alterego:[1,2,4],alwai:[0,1,2],among:[0,1],ani:[0,1,2],annoi:[0,1],anoth:[0,1,4],anyhow:[0,1],anymor:[0,1],anyth:[0,1],api:[2,3,4],app:0,appear:[0,1],appli:[0,1],applic:[0,1],approach:[0,1],approx:[0,1],arbitrari:[0,1],aren:[0,1],argc:2,argument:[0,1,4],argv0:2,argv:2,arm:2,arm_compli:4,arrai:[2,3,4],artbox:2,ascii85decod:[0,1],ascii:[0,1],asciihexdecod:[0,1],ask:[0,1],assert:2,associ:[0,1],assum:[0,1],assumpt:4,attempt:2,auxilari:[0,1],avail:[0,1],avoid:[0,1,4],awar:[0,1],base16:[0,1],base85:[0,1],basic:[0,1],bbox:[0,1],becaus:[0,1],been:[0,1,4],befor:[0,1,2],beings:[0,1],belong:[0,1],below:[0,1,4],besid:[0,1],best:4,better:[0,1,4],between:[0,1,4],beyond:[0,1],binari:[0,1],bit:[0,1,2,4],bleedbox:2,bodi:[0,1],boject:[0,1],bom:[0,1],both:[0,1,4],bo!
 ther:[0,1],bound:[0,1],box:[2,3],box_info:2,buffer:[0,1,2],bug:[0,1],build:0,bunch:[0,1],call:[0,1,4],callback:[0,1],can:[0,1,2,4],care:[0,1],cast:[0,1],catalog:[0,1],caus:4,ccitt:[0,1],ccittfaxdecod:[0,1],chang:3,charact:[0,1,2],check:[0,1,4],check_stream_chunk:2,choic:4,chunk:[0,1,2,4],cipher:[0,1],cleanup:3,clear:0,close:[0,1],closefil:[1,2],code:[0,1,4],coercion:[0,1],come:[0,1],common:[0,1,4],compar:[0,1],comparison:[0,1],compil:4,complet:[0,1],completelli:[0,1],compound:[0,1],compress:[0,1,2],conceptu:[0,1],condit:[0,1],confus:[0,1],consequ:4,consid:0,constant:[0,1],construct:[0,1],contain:[0,1],content:[2,3],context:[0,1,2],continu:2,conveni:[0,1],convert:[0,1],copi:[0,1,2],correspond:[0,1],cost:[0,1,4],could:[0,1,4],count:[0,1,2],counterpart:[0,1,4],covert:[0,1],crap:2,creat:[0,1,2],creator:2,cropbox:2,cross:[0,1],crypt:[0,1,2],crypt_info:2,cryptkei:2,cstr:0,cstring:0,current:[0,1],custom:[0,1],data1:[0,1],data2:[0,1],data3:[0,1],data:[0,1,2,4],dct:[0,1],dctdecod:[0,1],deal:[0,1],declar:[0,1],decod:[0,1,2,4],decodeparm:[0,1,2],decompress:[0,1,2],decrypt:[0,1],dedic:[0,1],dedict:[0,1],deep:2,defin:[0,1,2,4],delim:[0,1],demand:[0,1],depend:[0,1,4],derefer:[0,1],dereferenc:2,describ:[0,1],descript:[0,1],design:[0,1],destroi:[0,1],detail:4,detect:[0,1],determin:[0,1],dict:[2,3,4],differ:[0,1,4],digit:[0,1,2],direct:[0,1],directli:[0,1],dirti:4,distinct:4,distinguish:[0,1],distingush:[0,1],doc:[1,2],document:[0,1],doe:[0,1],doesn:[0,1,4],don:[0,1,4],done:[0,1,2,4],doubl:[0,1,2,4],due:[0,1],dummi:[0,1,2],each:[0,1,4],eat:[0,1],effect:[0,1,2],ego:[0,1],egzot:2,element:[0,1],elementari:[0,1],els:2,empti:[0,1,2],encod:[0,1,2,4],encrypt:[2,3],end:[0,1],endif:2,enough:[0,1,4],ensur:[0,1],entir:[0,1],entri:[0,1],equiv:[0,1],error:3,escap:[0,1,2],even:[0,1],everi:[0,1],exactli:[0,1],exampl:[0,1,3],except:[0,1],execut:[0,1],expect:[0,1],explain:[0,1],explicit:[0,1,4],expos:[0,1],extend:[0,2],extens:0,extern:2,extra:[0,1,4],fail:[0,1,2],failur:[0,1],far:[0,1,4],fast:0,fault:0,fclose:[1,2],featur:[0,1,4],fetch:[0,1],fie!
 ld:[0,1,2],file1:2,file2:2,file:[0,1,2,4],filenam:[0,1,2],filepath:2,files:2,filespec:2,fill:[0,1,2],filter:[2,3],filternam:[0,1,2],filtertyp:[0,1,2],find:[0,1],finder:2,first:[0,1,2],fix:2,flag:[0,1,2,4],flate:[0,1],flatedecod:[0,1],fly:[0,1],folk:2,follow:[0,1],fopen:2,forbidden:0,form:[0,1,2,4],found:[0,1],fprintf:[0,1,2],free:[0,1,2],freed:[0,1],from:[0,1,2,4],futur:[0,1],fwrite:2,gener:[2,4],genuin:[0,1],get:[0,1],get_file_nam:2,getter:[0,1],give:[0,1],given:[0,1],gobbl:2,goe:[0,1],going:[0,1],grant:[0,1],grow:[0,1],guess:[0,1,4],gust:2,han:2,handl:[2,3],handler:[0,1],happen:[0,1,2],has:[0,1,4],hash:[0,1],have:[0,1,4],haven:[0,1],header:[0,1],heap:[0,1,2,4],helper:[0,1,4],here:[0,1],hex:[0,1],hidden:4,hide:0,hope:2,hopefulli:4,host:[0,1],how:[0,1],howev:0,hundr:0,idea:4,ident:[0,1,4],identifi:[0,1],iff:[0,1],ifndef:2,imag:[0,1,2],imagedict:[0,1],implement:[0,1,4],includ:[0,1,2],incomplet:[0,1],incorrect:2,increment:[0,1,2],independ:[0,1,4],index:[0,1,2],indic:[0,1],indirect:[0,1],inevit:4,info:[0,1,2],inform:[0,1,4],initi:[0,1],inlin:[0,1,2],input:2,instead:[0,1,2],insuffici:[0,1],int64_t:[0,1,2,4],int8_t:2,integ:[0,1,2,4],integr:2,intend:[0,1],intent:[0,1,2],interfac:[0,1],intern:[0,1,2],introduc:[0,1],invalid:[0,1,2],iof_copy_file_data:2,iof_discard:2,iof_heap:2,issu:4,item:[0,1,2],iter:[0,1,2],its:[0,1,2],itself:[0,1],jackowski:2,jbig2:[0,1],jbig2decod:[0,1],jbig:[0,1],jpeg:[0,1],jpegsiz:[0,1],jpegstream:[0,1],jpx:[0,1],jpxdecod:[0,1],jump:[0,1],just:[0,1,4],keep:[0,1,4],kei:[0,1,2,4],kep:[0,1],kept:[0,1],keyval:[0,1],keyword:2,kid:2,kind:[0,1],know:[0,1],known:[0,1],larg:[0,1],last:[0,1,2],later:[0,1],lead:[0,1],length:[0,1,2],less:[0,1,2,4],letter:[0,1],librari:[0,1,4],like:[0,1,4],limit:4,linear:[0,1],list:[0,1],liter:[0,1,4],load:[0,1,2],loader:[0,1,2],log:[0,1],log_callback:2,logger:[0,1,2],longer:[0,1,2,4],look:[0,1],lookup:[0,2],loop:[0,1],lot:4,luatex:2,luigi:2,lzw:[0,1],lzwdecod:[0,1],machin:[0,1,2,4],macro:[0,1,2,4],made:4,magic:[0,1],mai:[0,1,2],main:[0,1,2],maintain:4,major:[0,1],make:[0,1,4]!
 ,malloc:[0,1,2],mani:4,map:[0,1],mark:[0,1],match:[0,1],matrix:[0,1,2],matter:[0,1],md5:2,mean:[0,1],mechan:4,mediabox:[0,1,2],mem:2,member:[0,1,4],memcmp:[0,1,2],memori:[0,1,2,4],memus:2,memwast:2,mention:[0,1],messag:[0,1,2],might:[0,1,2],mind:[0,1],minor:[0,1,2],moment:[0,1],more:[0,1,2,4],most:[0,1,2,4],move:4,much:4,must:[0,1],name:[2,3],natur:2,necessari:[0,1],need:[0,1,2,4],never:4,newest:[0,1],next:[0,1,2],node:[0,1],non:[0,1],none:2,nonempti:2,nooop:[0,1,2],normal:[0,1],note:[0,1,2,4],noth:[0,1],now:[0,1,2,4],number:[0,1,2],numer:[0,1],obj:[0,1,2],object:[2,3,4],obligatori:[0,1],obscur:[0,1],octal:2,offset:[0,1,2],often:[0,1],older:[0,1],omit:[0,1],onc:[0,1,4],one:[0,1],onli:[0,1,2,4],open:[0,1,2],openbsd:[],oper:[0,1,2],operand:[0,1],operato:[0,1],oprat:[0,1],option:[0,1],org:2,origin:[0,1],other:[0,1,2,4],otherwis:[0,1],out:[0,1,2,4],outnam:2,output:[0,1],over:[0,1],own:[0,1,2],owner:[0,1],ownerpass:[0,1,2],ownerpasslength:[0,1,2],page:[2,3],pagecount:2,pagedict:[0,1,2],pageno:[0,1,2],pageref:2,paid:1,pair:[0,1],parallel:[0,1],param:[0,1,2],paramet:[0,1],parent:[0,1],pars:[0,1,2],parser:[0,1,2],part:[0,1,4],password:[0,1,2],path:2,pcontext:[0,1],pdf:[2,3,4],perfectli:0,perform:[0,1],permiss:[0,1,2],piec:[0,1],pkei:[0,1,2,4],place:4,plain:[0,1,2,4],platform:4,plu:2,pname:[0,1,2,4],point:[0,1],pointer:[0,1,2,4],pool:[0,1,4],portabl:2,possibl:[0,1],postscript:[0,1,2],pp_api_h:2,ppapi:[0,1,3,4],pparrai:[0,1,2,4],pparray_at:[0,1,2],pparray_first:[0,1,2],pparray_get:[0,1,2],pparray_get_:[0,1],pparray_get_arrai:[0,1,2],pparray_get_bool:[0,1,2],pparray_get_dict:[0,1,2],pparray_get_int:[0,1,2],pparray_get_nam:[0,1,2],pparray_get_num:[0,1,2],pparray_get_obj:[0,1,2],pparray_get_ref:[0,1,2],pparray_get_str:[0,1,2],pparray_get_stream:[0,1,2],pparray_get_uint:[0,1,2],pparray_next:[0,1,2],pparray_rget_:[0,1],pparray_rget_arrai:2,pparray_rget_bool:2,pparray_rget_dict:2,pparray_rget_int:2,pparray_rget_nam:2,pparray_rget_num:2,pparray_rget_obj:2,pparray_rget_ref:2,pparray_rget_str:2,pparray_rget_stream:[0,1,2],pparray_!
 rget_uint:2,pparray_s:[0,1,2],pparray_to_matrix:[0,1,2],pparray_to_rect:[0,1,2],ppbool:[0,1,2],ppbyte:[1,2,4],ppconf:2,ppcontents_first:[0,1,2],ppcontents_first_op:[0,1,2],ppcontents_next:[0,1,2],ppcontents_next_op:[0,1,2],ppcontents_pars:[0,1,2],ppcontext:[0,1,2],ppcontext_don:[0,1,2],ppcontext_fre:[0,1,2],ppcontext_new:[0,1,2],ppcrypt_don:[0,1,2],ppcrypt_fail:[0,1,2],ppcrypt_non:[0,1,2],ppcrypt_pass:[0,1,2],ppcrypt_statu:[0,1,2],ppdef:2,ppdic_rget_dict:[0,1],ppdict:[0,1,2],ppdict_at:[0,1,2],ppdict_first:[0,1,2,4],ppdict_get:4,ppdict_get_:[0,1,4],ppdict_get_arrai:[0,1,2],ppdict_get_bool:[0,1,2],ppdict_get_box:[0,1,2],ppdict_get_dict:[0,1,2],ppdict_get_int:[0,1,2],ppdict_get_matrix:[0,1,2],ppdict_get_nam:[0,1,2],ppdict_get_num:[0,1,2],ppdict_get_obj:[0,1,2],ppdict_get_rect:[0,1,2],ppdict_get_ref:[0,1,2],ppdict_get_someth:4,ppdict_get_str:[0,1,2],ppdict_get_stream:[0,1,2],ppdict_get_uint:[0,1,2],ppdict_kei:[0,1,2],ppdict_next:[0,1,2,4],ppdict_rget_:[0,1],ppdict_rget_arrai:2,ppdict_rget_bool:2,ppdict_rget_dict:[0,1,2],ppdict_rget_int:2,ppdict_rget_nam:2,ppdict_rget_num:2,ppdict_rget_obj:2,ppdict_rget_ref:2,ppdict_rget_str:2,ppdict_rget_stream:[0,1,2],ppdict_rget_uint:2,ppdict_siz:[0,1,2],ppdoc:[0,1,2],ppdoc_allow_annot:[0,1,2],ppdoc_allow_assembl:[0,1,2],ppdoc_allow_copi:[0,1,2],ppdoc_allow_extract:[0,1,2],ppdoc_allow_modifi:[0,1,2],ppdoc_allow_print:[0,1,2],ppdoc_allow_print_hir:[0,1,2],ppdoc_catalog:[0,1,2],ppdoc_crypt_pass:[0,1,2],ppdoc_crypt_statu:[0,1,2],ppdoc_fil:2,ppdoc_file_s:[0,1,2],ppdoc_filehandl:[1,2],ppdoc_first_pag:[0,1,2],ppdoc_fre:[0,1,2],ppdoc_info:[0,1,2],ppdoc_load:[0,1,2],ppdoc_mem:[0,1,2],ppdoc_memori:[0,1,2],ppdoc_next_pag:[0,1,2],ppdoc_object:[0,1,2],ppdoc_pag:[0,1,2],ppdoc_page_count:[0,1,2],ppdoc_permiss:[0,1,2],ppdoc_trail:[0,1,2],ppdoc_version_numb:[0,1,2],ppdoc_version_str:[0,1,2],ppdoc_xref:[0,1,2],ppint:[0,1,2],pplib:[2,4],pplib_author:2,pplib_vers:2,pplog_callback:[0,1,2],pplog_prefix:[0,1,2],pplogger_callback:[0,1,2],ppmatrix:[0,1,2],ppname:[0,1,2,4],ppname_data:[1,2,4],ppname_decod!
 :[0,1,2,4],ppname_decoded_data:[1,2,4],ppname_encod:[0,1,2,4],ppname_encoded_data:[1,2,4],ppname_eq:[0,1,2],ppname_exec:[0,1,2],ppname_i:[0,1,2],ppname_s:[0,1,2,4],ppnone:[0,1,2],ppnull:[0,1,2],ppnum:[0,1,2],ppobj:[0,1,2],ppobj_get_:[0,1],ppobj_get_arrai:[0,1,2],ppobj_get_bool:[0,1,2],ppobj_get_bool_valu:2,ppobj_get_dict:[0,1,2],ppobj_get_int:[0,1,2],ppobj_get_int_valu:2,ppobj_get_nam:[0,1,2],ppobj_get_nul:[0,1,2],ppobj_get_num:[0,1,2],ppobj_get_num_valu:2,ppobj_get_ref:[0,1,2],ppobj_get_str:[0,1,2],ppobj_get_stream:[0,1,2],ppobj_get_uint:[0,1,2],ppobj_kind:2,ppobj_rget_:[0,1],ppobj_rget_arrai:2,ppobj_rget_bool:2,ppobj_rget_dict:[0,1,2],ppobj_rget_int:2,ppobj_rget_nam:2,ppobj_rget_nul:2,ppobj_rget_num:2,ppobj_rget_obj:[0,1,2],ppobj_rget_ref:2,ppobj_rget_str:2,ppobj_rget_stream:2,ppobj_rget_uint:2,ppobjtp:[0,1,2],pprect:[0,1,2],ppref:[0,1,2],ppref_obj:[0,1,2],ppstream:[0,1,2],ppstream_al:[0,1,2],ppstream_base16:[0,1,2],ppstream_base85:[0,1,2],ppstream_ccitt:[0,1,2],ppstream_compress:[0,1,2],ppstream_crypt:[0,1,2],ppstream_dct:[0,1,2],ppstream_dict:[0,1,2],ppstream_don:[0,1,2],ppstream_encrypt:[0,1,2],ppstream_encrypted_a:2,ppstream_encrypted_own:[0,1,2],ppstream_encrypted_rc4:2,ppstream_filt:[0,1,2],ppstream_filter_info:[0,1,2],ppstream_filter_nam:[0,1,2],ppstream_filter_typ:[0,1,2],ppstream_first:[0,1,2],ppstream_flat:[0,1,2],ppstream_free_buff:[0,1,2],ppstream_imag:[0,1,2],ppstream_init_buff:[0,1,2],ppstream_jbig2:[0,1,2],ppstream_jpx:[0,1,2],ppstream_lzw:[0,1,2],ppstream_next:[0,1,2],ppstream_not_support:2,ppstream_runlength:[0,1,2],ppstreamtp:[0,1,2],ppstring:[0,1,2,4],ppstring_base16:[0,1,2],ppstring_base85:[0,1,2],ppstring_data:[1,2,4],ppstring_decod:[0,1,2,4],ppstring_decoded_data:[1,2,4],ppstring_encod:[0,1,2,4],ppstring_encoded_data:[1,2,4],ppstring_exec:2,ppstring_hex:[0,1,2],ppstring_intern:2,ppstring_plain:[0,1,2],ppstring_siz:[0,1,2,4],ppstring_typ:[0,1,2],ppstring_utf16b:[0,1,2],ppstring_utf16l:[0,1,2],ppstring_utf:[0,1,2],pptest3:2,ppuint:[0,1,2],ppxref:[0,1,2],ppxref_catalog:2,ppxref_find:[0,1,2],!
 ppxref_info:2,ppxref_pag:2,ppxref_prev:[0,1,2],ppxref_trail:2,ppxsec:2,practis:[0,1],preceed:[0,1],precis:[0,1],predictor:2,prefer:[0,1,4],prefix:[0,1,2],present:[0,1],preserv:[0,1],pretend:0,pretti:[0,1,4],previou:[0,1],print:[0,1,2],print_info:2,print_result_filt:2,print_stream_info:2,printabl:[0,1],printf:[0,1,2],privat:4,probabl:[0,1],proce:[0,1],procee:[0,1],process:[0,1],produc:[0,1,2],prompt:[0,1],proper:[0,1,2],properli:4,properti:[0,1,2],protect:[0,1,2],provid:[0,1,4],psize:[0,1,2],pune:2,put:[0,1],queri:[0,1],quit:[0,1],rather:[0,1],raw:[0,1,2],read:[0,1],readabl:[0,1],reader:[0,1],readi:[0,1],real:[0,1],realli:[0,1],reason:[0,1],reclaim:[0,1,2],reconstruct:[0,1],rect:[0,1,2],rectangl:[0,1],redirect:[0,1],ref:[2,3],refer:[0,1,2],referenc:[0,1],refnum:2,refnumb:[0,1,2],relat:[0,1,4],releas:[0,1,2],relev:[0,1],reli:1,remain:[0,1],remov:4,replac:[0,1],repres:[0,1,4],request:2,resid:1,resolv:[0,1,2],resourc:[0,1],restor:[0,1],restrict:[0,1],result:[0,1],reus:[0,1],revers:[0,1],revis:[2,4],revolut:4,rework:2,rewrit:[0,1],root:[0,1],roughli:[0,1],runlength:[0,1],runlengthdecod:[0,1],sai:[0,1],same:[0,1],saniti:[0,1,2],scheme:[0,1],search:[0,1],second:[0,1],sect:2,secur:[0,1,2],see:[0,1],seem:4,segfault:[],segment:0,self:4,sens:0,separ:[0,1],serv:4,set:[0,1],sever:[0,1],sha2:2,should:[0,1,2],shouldn:[0,1,2],show:[0,1],sign:[0,1,2],signed:4,simpl:[0,1],simpli:[0,1],sinc:[0,1,4],singl:[0,1,4],size:[0,1,2,4],size_t:[0,1,2,4],sizenum:2,sizeof:[0,1,2],skip:2,small:[0,1],smarter:[0,1],some:[0,1,2,4],some_output:[0,1],someth:[0,1],somewher:[0,1],soon:0,sorri:[0,1,2],sourc:[0,1,2],space:[0,1],spec:[0,1],special:[0,1],specif:[0,1],sprintf:2,stack:[0,1],standalon:[0,1],start:[0,1],state:[0,1],statu:[0,1],stddef:2,stderr:[0,1,2],stdint:2,stdio:2,stdout:[0,1],still:[0,1,4],stock:4,stop:[0,1],storag:4,store:[0,1,4],stream:[2,3],string:[2,3],strip:[0,1],strlen:[0,1],struct:[0,1,2,4],structur:[0,1,4],style:0,suboptim:[0,1],subsequ:[0,1],succe:[0,1],succeed:[0,1],suffer:[0,1],suit:[0,1,4],sum:[0,1,2],support:[0,1],surround:[!
 0,1],sync:4,syntax:[0,1],tab:[0,1,2],tabl:[0,1],take:[0,1,4],taken:2,target:[0,1],tech:2,tell:[0,1],templat:[0,1,2],termin:[0,1],termini:0,test:2,text:[0,1],than:[0,1],thank:2,thei:[0,1,4],them:[0,1],thi:[0,1,2,4],think:[0,1],those:[0,1],though:0,through:[0,1],tiff:2,todo:3,tollbox:4,top:[0,1],toxic:2,trailer:[0,1],transform:[2,3],treat:[0,1],tree:[0,1],tri:[0,1],trick:4,trickeri:[0,1,4],trimbox:2,triplet:[0,1],trivial:4,two:[0,1,4],type:[2,3,4],typedef:[0,1,2],typic:[0,1],uint8_t:[0,1,2,4],unalign:4,uncompress:2,unconst:[0,1],undocu:[0,1],unescap:[0,1],unicod:[0,1],unif:4,union:[0,1,2],unless:[0,1],unnecesari:[0,1],unnecessari:[0,1],unread:[0,1],unsign:[0,1,2,4],unsupport:[0,1],until:[0,1],unus:4,updat:[0,1,2],usabl:4,usag:[0,1,2],use:[0,1,4],use_buffers_pool:2,used:[0,1,4],useless:[0,1],userpass:[0,1,2],userpasslength:[0,1,2],uses:[0,1,4],using:[0,1],usual:[0,1],utf16:[0,1],utf16b:[0,1],utf16l:[0,1],util:[0,1,2,4],utiliof:2,utilmem:4,utilmemallc:4,val:[0,1],valid:[0,1],valu:[0,1],variabl:[0,1],variant:4,verbos:[0,1],verifi:[0,1],version:[0,1,2,4],via:[0,1,4],wai:[0,1],want:[0,1,4],warn:[2,4],wast:[0,1,2],watch:4,well:[0,1,4],were:4,weren:[0,1,2],what:[0,1],whatev:[0,1],when:[0,1,2],whenev:[0,1,4],which:[0,1,4],window:4,without:[0,1],wntri:[0,1],won:[0,1],word:[0,1,2,4],work:4,would:[0,1],write:2,wrong:[0,1,4],xref:[2,3],xsec:2,yes:[0,1],yet:4,you:[0,1],your:[0,1],your_callback:[0,1],yourself:[0,1],zero:[0,1]},titles:["<code class=\"docutils literal notranslate\"><span class=\"pre\">pplib</span></code> 1.x","<code class=\"docutils literal notranslate\"><span class=\"pre\">pplib</span></code> 2.x","Examples","pplib","1.x vs 2.x"],titleterms:{And:4,alloc:4,api:[0,1],arrai:[0,1],box:[0,1],chang:2,cleanup:4,content:[0,1],dict:[0,1],encrypt:[0,1],error:[0,1],exampl:2,filter:[0,1],handl:[0,1],name:[0,1,4],object:[0,1],page:[0,1],pdf:[0,1],ppapi:2,pplib:[0,1,3],ref:[0,1],stream:[0,1],string:[0,1,4],todo:2,transform:[0,1],type:[0,1],xref:[0,1]}})
\ No newline at end of file
+Search.setIndex({docnames:["ppapi-1.x","ppapi-2.x","ppcode","pplib","ppnew"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,sphinx:54},filenames:["ppapi-1.x.rst","ppapi-2.x.rst","ppcode.rst","pplib.rst","ppnew.rst"],objects:{},objnames:{},objtypes:{},terms:{"1mb":[0,1],"2fkb":2,"2fmb":2,"64kb":[0,1],"boolean":[0,1],"break":[0,1,2],"byte":[0,1,2,4],"case":[0,1,2,4],"char":[0,1,2,4],"const":[0,1,2,4],"default":[0,1,2],"enum":[0,1,2],"final":[0,1],"function":[0,1,2,4],"int":[0,1,2,4],"long":[0,1,2,4],"new":[0,1],"null":[0,1,2,4],"return":[0,1,2,4],"short":[0,1],"static":2,"switch":[0,1,2,4],"try":1,"void":[0,1,2],"while":[0,1,4],And:[0,1,3],But:[0,1],For:[0,1],NOT:2,One:[0,1],Such:[0,1],The:[0,1,4],Then:[0,1],There:[0,1,4],Use:[0,1],Using:4,about:[0,1,2,4],abov:[0,1],absolutelli:[0,1],accept:[0,1,4],access:[0,1,2],accessor:[0,1],accord:[0,1],acrobat:[0,1,2],actual:[0,1,4],added:2,addit:[0,1],address:4,adjust:2,after:[0,1,2],again:[0,1,2],ahead:[0,1],alfterego:4,algorithm:[1,2],alia:[0,1,4],alias:[1,4],alien:[0,1,2],align:[2,4],aliv:[0,1],all:[0,1,4],alloc:[0,1,2,3],allow:[0,1],almost:[2,4],alreadi:[0,1],also:[0,1],alter:[0,1],alterego:[1,2,4],alwai:[0,1,2],among:[0,1],ani:[0,1,2],annoi:[0,1],anoth:[0,1,4],anyhow:[0,1],anymor:[0,1],anyth:[0,1],api:[2,3,4],app:0,appear:[0,1],appli:[0,1],applic:[0,1],approach:[0,1],approx:[0,1],arbitrari:[0,1],aren:[0,1],argc:2,argument:[0,1,4],argv0:2,argv:2,arm:2,arm_compli:4,arrai:[2,3,4],artbox:2,ascii85decod:[0,1],ascii:[0,1],asciihexdecod:[0,1],ask:[0,1],assert:2,associ:[0,1],assum:[0,1],assumpt:4,attempt:2,auxilari:[0,1],avail:[0,1],avoid:[0,1,4],awar:[0,1],backward:2,base16:[0,1],base85:[0,1],base:1,basic:[0,1],bbox:[0,1],becaus:[0,1],been:[0,1,4],befor:[0,1,2],behav:1,beings:[0,1],belong:[0,1],below:[0,1,4],besid:[0,1],best:4,better:[0,1,4],between:[0,1,4],beyond:[0,1],binari:[0,1],bit:[0,1,2,4],bleedbox:2!
 ,bodi:[0,1],boject:[0,1],bom:[0,1],both:[0,1,4],bother:[0,1],bothpassword:2,bound:[0,1],box:[2,3],box_info:2,buffer:[0,1,2],bug:0,build:0,bunch:[0,1],call:[0,1,4],callback:[0,1],can:[0,1,2,4],care:[0,1],cast:[0,1],catalog:[0,1],caus:4,ccitt:[0,1],ccittfaxdecod:[0,1],chang:3,charact:[0,1,2],check:[0,1,4],check_stream_chunk:2,choic:4,chunk:[0,1,2,4],cipher:[0,1],cleanup:3,clear:0,close:[0,1],closefil:[1,2],code:[0,1,4],coercion:[0,1],come:[0,1],common:[0,1,4],compar:[0,1],comparison:[0,1],compil:4,complet:[0,1],completelli:[0,1],compound:[0,1],compress:[0,1,2],conceptu:[0,1],condit:[0,1],confus:[0,1],consequ:4,consid:0,constant:[0,1],construct:[0,1],contain:[0,1],content:[2,3],context:[0,1,2],continu:2,conveni:[0,1],convers:1,convert:[0,1],copi:[0,1,2],correspond:[0,1],cost:[0,1,4],could:[0,1,4],count:[0,1,2],counterpart:[0,1,4],covert:[0,1],crap:2,creat:[0,1,2],creator:2,cropbox:2,cross:[0,1],crypt:[0,1,2],crypt_info:2,cryptkei:2,cryptstatu:2,cstr:0,cstring:0,current:[0,1],custom:[0,1],data1:[0,1],data2:[0,1],data3:[0,1],data:[0,1,2,4],dct:[0,1],dctdecod:[0,1],deal:[0,1],declar:[0,1],decod:[0,1,2,4],decodeparm:[0,1,2],decompress:[0,1,2],decrypt:[0,1,2],dedic:[0,1],dedict:[0,1],deep:2,defin:[0,1,2,4],delim:[0,1],demand:[0,1],depend:[0,1,4],derefer:[0,1],dereferenc:2,describ:[0,1],descript:[0,1],design:[0,1],destroi:[0,1],detail:4,detect:[0,1],determin:[0,1],dict:[2,3,4],didn:1,differ:[0,1,4],digit:[0,1,2],direct:[0,1],directli:[0,1],dirti:4,distinct:4,distinguish:[0,1],distingush:[0,1],doc:[1,2],document:[0,1],doe:[0,1],doesn:[0,1,4],don:[0,1,4],done:[0,1,2,4],doubl:[0,1,2,4],due:[0,1],dummi:[0,1],each:[0,1,4],earlier:1,eat:[0,1],effect:[0,1,2],ego:[0,1],egzot:[],element:[0,1],elementari:[0,1],els:2,empti:[0,1,2],encod:[0,1,2,4],encrypt:[2,3],end:[0,1],endif:2,enough:[0,1,4],ensur:[0,1],entir:[0,1],entri:[0,1],equiv:[0,1],error:3,escap:[0,1,2],even:[0,1],everi:[0,1],exactli:[0,1],exampl:[0,1,3],except:[0,1],execut:[0,1],expect:[0,1],explain:[0,1],explicit:[0,1,4],expos:[0,1],extend:[0,2],extens:0,extern:2,extra:[0!
 ,1,4],fail:[0,1,2],failur:[0,1],fanci:1,far:[0,1,4],fast:0,fault:0,fclose:[1,2],featur:[0,1,4],fetch:[0,1],field:[0,1,2],file1:2,file2:2,file:[0,1,2,4],filenam:[0,1,2],filepath:2,files:2,filespec:2,fill:[0,1,2],filter:[2,3],filternam:[0,1,2],filtertyp:[0,1,2],find:[0,1],finder:2,first:[0,1,2],fix:2,flag:[0,1,2,4],flate:[0,1],flatedecod:[0,1],fly:[0,1],folk:2,follow:[0,1],fopen:2,forbidden:0,form:[0,1,2,4],found:[0,1],fprintf:[0,1,2],free:[0,1,2],freed:[0,1],from:[0,1,2,4],futur:[0,1],fwrite:2,gener:[2,4],genuin:[0,1],get:[0,1],get_file_nam:2,get_next_argu:2,getter:[0,1],give:[0,1],given:[0,1],gobbl:2,goe:[0,1],going:[0,1],grant:[0,1],grow:[0,1],guess:[0,1,4],gust:2,han:2,handl:[2,3],handler:[0,1],happen:[0,1,2],has:[0,1,4],hash:[0,1],have:[0,1,4],haven:[0,1],header:[0,1],heap:[0,1,2,4],helper:[0,1,4],here:[0,1],hex:[0,1],hidden:4,hide:0,hope:[],hopefulli:4,host:[0,1],how:[0,1],howev:0,hundr:0,idea:4,ident:[0,1,4],identifi:[0,1],iff:[0,1],ifndef:2,imag:[0,1,2],imagedict:[0,1],implement:[0,1,4],includ:[0,1,2],incompat:2,incomplet:[0,1],incorrect:2,increment:[0,1,2],independ:[0,1,4],index:[0,1,2],indic:[0,1],indirect:[0,1],inevit:4,info:[0,1,2],inform:[0,1,4],initi:[0,1],inlin:[0,1,2],input:2,instead:[0,1,2],insuffici:[0,1],int64_t:[0,1,2,4],int8_t:2,integ:[0,1,2,4],integr:2,intend:[0,1],intent:[0,1,2],interfac:[0,1],intern:[0,1,2],introduc:[0,1],invalid:[0,1,2],iof_copy_file_data:2,iof_discard:2,iof_heap:2,issu:4,item:[0,1,2],iter:[0,1,2],its:[0,1,2],itself:[0,1],jackowski:2,jbig2:[0,1],jbig2decod:[0,1],jbig:[0,1],jpeg:[0,1],jpegsiz:[0,1],jpegstream:[0,1],jpx:[0,1],jpxdecod:[0,1],jump:[0,1],just:[0,1,4],keep:[0,1,4],kei:[0,1,2,4],kep:[0,1],kept:[0,1],keyval:[0,1],keyword:2,kid:2,kind:[0,1],know:[0,1],known:[0,1],larg:[0,1],last:[0,1,2],later:[0,1],lead:[0,1],length:[0,1,2],less:[0,1,4],letter:[0,1],librari:[0,1,4],like:[0,1,4],limit:4,linear:[0,1],list:[0,1],liter:[0,1,4],load:[0,1,2],loader:[0,1,2],log:[0,1],log_callback:2,logger:[0,1,2],longer:[0,1,2,4],look:[0,1],lookup:[0,2],loop:[0,1],lot:4,luatex:2,luigi:2,l!
 zw:[0,1],lzwdecod:[0,1],machin:[0,1,2,4],macro:[0,1,2,4],made:4,magic:[0,1],mai:[0,1,2],main:[0,1,2],maintain:4,major:[0,1],make:[0,1,4],malloc:[0,1,2],mani:4,map:[0,1],mark:[0,1],match:[0,1],matrix:[0,1,2],matter:[0,1],md5:2,mean:[0,1],mechan:4,mediabox:[0,1,2],mem:2,member:[0,1,4],memcmp:[0,1,2],memori:[0,1,2,4],memus:2,memwast:2,mention:[0,1],messag:[0,1,2],method:1,might:[0,1,2],mind:[0,1],minor:[0,1,2],moment:[0,1],more:[0,1,2,4],most:[0,1,2,4],move:4,much:4,must:[0,1],name:[2,3],natur:2,necessari:[0,1],need:[0,1,2,4],never:4,newer:1,newest:[0,1],next:[0,1,2],node:[0,1],non:[0,1],none:2,nonempti:2,nooop:[0,1,2],normal:[0,1],note:[0,1,2,4],noth:[0,1],now:[0,1,2,4],number:[0,1,2],numer:[0,1],obj:[0,1,2],object:[2,3,4],obligatori:[0,1],obscur:0,octal:2,offset:[0,1,2],often:[0,1],older:[0,1],omit:[0,1],onc:[0,1,4],one:[0,1],onli:[0,1,2,4],open:[0,1,2],openbsd:[],oper:[0,1,2],operand:[0,1],operato:[0,1],oprat:[0,1],opt:2,option:[0,1],org:2,origin:[0,1],other:[0,1,2,4],otherwis:[0,1],out:[0,1,2,4],outnam:2,output:[0,1],over:[0,1],own:[0,1,2],owner:[0,1],ownerpass:[0,1,2],ownerpasslength:[0,1,2],ownerpassword:2,page:[2,3],pagecount:2,pagedict:[0,1,2],pageno:[0,1,2],pageref:2,paid:1,pair:[0,1],parallel:[0,1],param:[0,1,2],paramet:[0,1],parent:[0,1],pars:[0,1,2],parser:[0,1,2],part:[0,1,4],pass:[1,2],password:[0,1,2],path:2,pcontext:[0,1],pdf:[2,3,4],pdfdocencod:1,perfectli:0,perform:[0,1],permiss:[0,1,2],piec:[0,1],pkei:[0,1,2,4],place:4,plain:[0,1,2,4],platform:4,plu:2,pname:[0,1,2,4],point:[0,1],pointer:[0,1,2,4],pool:[0,1,4],portabl:2,possibl:[0,1],postscript:[0,1,2],pp_api_h:2,ppapi:[0,1,3,4],pparrai:[0,1,2,4],pparray_at:[0,1,2],pparray_first:[0,1,2],pparray_get:[0,1,2],pparray_get_:[0,1],pparray_get_arrai:[0,1,2],pparray_get_bool:[0,1,2],pparray_get_dict:[0,1,2],pparray_get_int:[0,1,2],pparray_get_nam:[0,1,2],pparray_get_num:[0,1,2],pparray_get_obj:[0,1,2],pparray_get_ref:[0,1,2],pparray_get_str:[0,1,2],pparray_get_stream:[0,1,2],pparray_get_uint:[0,1,2],pparray_next:[0,1,2],pparray_rget_:[0,1],pparray_rget_ar!
 rai:2,pparray_rget_bool:2,pparray_rget_dict:2,pparray_rget_int:2,pparray_rget_nam:2,pparray_rget_num:2,pparray_rget_obj:2,pparray_rget_ref:2,pparray_rget_str:2,pparray_rget_stream:[0,1,2],pparray_rget_uint:2,pparray_s:[0,1,2],pparray_to_matrix:[0,1,2],pparray_to_rect:[0,1,2],ppbool:[0,1,2],ppbyte:[1,2,4],ppconf:2,ppcontents_first:[0,1,2],ppcontents_first_op:[0,1,2],ppcontents_next:[0,1,2],ppcontents_next_op:[0,1,2],ppcontents_pars:[0,1,2],ppcontext:[0,1,2],ppcontext_don:[0,1,2],ppcontext_fre:[0,1,2],ppcontext_new:[0,1,2],ppcrypt_don:[0,1,2],ppcrypt_fail:[0,1,2],ppcrypt_non:[0,1,2],ppcrypt_pass:[0,1,2],ppcrypt_statu:[0,1,2],ppdef:2,ppdic_rget_dict:[0,1],ppdict:[0,1,2],ppdict_at:[0,1,2],ppdict_first:[0,1,2,4],ppdict_get:4,ppdict_get_:[0,1,4],ppdict_get_arrai:[0,1,2],ppdict_get_bool:[0,1,2],ppdict_get_box:[0,1,2],ppdict_get_dict:[0,1,2],ppdict_get_int:[0,1,2],ppdict_get_matrix:[0,1,2],ppdict_get_nam:[0,1,2],ppdict_get_num:[0,1,2],ppdict_get_obj:[0,1,2],ppdict_get_rect:[0,1,2],ppdict_get_ref:[0,1,2],ppdict_get_someth:4,ppdict_get_str:[0,1,2],ppdict_get_stream:[0,1,2],ppdict_get_uint:[0,1,2],ppdict_kei:[0,1,2],ppdict_next:[0,1,2,4],ppdict_rget_:[0,1],ppdict_rget_arrai:2,ppdict_rget_bool:2,ppdict_rget_dict:[0,1,2],ppdict_rget_int:2,ppdict_rget_nam:2,ppdict_rget_num:2,ppdict_rget_obj:2,ppdict_rget_ref:2,ppdict_rget_str:2,ppdict_rget_stream:[0,1,2],ppdict_rget_uint:2,ppdict_siz:[0,1,2],ppdoc:[0,1,2],ppdoc_allow_annot:[0,1,2],ppdoc_allow_assembl:[0,1,2],ppdoc_allow_copi:[0,1,2],ppdoc_allow_extract:[0,1,2],ppdoc_allow_modifi:[0,1,2],ppdoc_allow_print:[0,1,2],ppdoc_allow_print_hir:[0,1,2],ppdoc_catalog:[0,1,2],ppdoc_crypt_pass:[0,1,2],ppdoc_crypt_statu:[0,1,2],ppdoc_fil:2,ppdoc_file_s:[0,1,2],ppdoc_filehandl:[1,2],ppdoc_first_pag:[0,1,2],ppdoc_fre:[0,1,2],ppdoc_info:[0,1,2],ppdoc_load:[0,1,2],ppdoc_mem:[0,1,2],ppdoc_memori:[0,1,2],ppdoc_next_pag:[0,1,2],ppdoc_object:[0,1,2],ppdoc_pag:[0,1,2],ppdoc_page_count:[0,1,2],ppdoc_permiss:[0,1,2],ppdoc_trail:[0,1,2],ppdoc_version_numb:[0,1,2],ppdoc_version_str:[0,1,2],ppdoc_xref:[0!
 ,1,2],ppint:[0,1,2],pplib:[2,4],pplib_author:2,pplib_vers:2,pplog_callback:[0,1,2],pplog_prefix:[0,1,2],pplogger_callback:[0,1,2],ppmatrix:[0,1,2],ppname:[0,1,2,4],ppname_data:[1,2,4],ppname_decod:[0,1,2,4],ppname_decoded_data:[1,2,4],ppname_encod:[0,1,2,4],ppname_encoded_data:[1,2,4],ppname_eq:[0,1,2],ppname_exec:[0,1,2],ppname_i:[0,1,2],ppname_s:[0,1,2,4],ppnone:[0,1,2],ppnull:[0,1,2],ppnum:[0,1,2],ppobj:[0,1,2],ppobj_get_:[0,1],ppobj_get_arrai:[0,1,2],ppobj_get_bool:[0,1,2],ppobj_get_bool_valu:2,ppobj_get_dict:[0,1,2],ppobj_get_int:[0,1,2],ppobj_get_int_valu:2,ppobj_get_nam:[0,1,2],ppobj_get_nul:[0,1,2],ppobj_get_num:[0,1,2],ppobj_get_num_valu:2,ppobj_get_ref:[0,1,2],ppobj_get_str:[0,1,2],ppobj_get_stream:[0,1,2],ppobj_get_uint:[0,1,2],ppobj_kind:2,ppobj_rget_:[0,1],ppobj_rget_arrai:2,ppobj_rget_bool:2,ppobj_rget_dict:[0,1,2],ppobj_rget_int:2,ppobj_rget_nam:2,ppobj_rget_nul:2,ppobj_rget_num:2,ppobj_rget_obj:[0,1,2],ppobj_rget_ref:2,ppobj_rget_str:2,ppobj_rget_stream:2,ppobj_rget_uint:2,ppobjtp:[0,1,2],pprect:[0,1,2],ppref:[0,1,2],ppref_obj:[0,1,2],ppstream:[0,1,2],ppstream_al:[0,1,2],ppstream_base16:[0,1,2],ppstream_base85:[0,1,2],ppstream_ccitt:[0,1,2],ppstream_compress:[0,1,2],ppstream_crypt:[0,1,2],ppstream_dct:[0,1,2],ppstream_dict:[0,1,2],ppstream_don:[0,1,2],ppstream_encrypt:[0,1,2],ppstream_encrypted_a:2,ppstream_encrypted_own:[0,1,2],ppstream_encrypted_rc4:2,ppstream_filt:[0,1,2],ppstream_filter_info:[0,1,2],ppstream_filter_nam:[0,1,2],ppstream_filter_typ:[0,1,2],ppstream_first:[0,1,2],ppstream_flat:[0,1,2],ppstream_free_buff:[0,1,2],ppstream_imag:[0,1,2],ppstream_init_buff:[0,1,2],ppstream_jbig2:[0,1,2],ppstream_jpx:[0,1,2],ppstream_lzw:[0,1,2],ppstream_next:[0,1,2],ppstream_not_support:2,ppstream_runlength:[0,1,2],ppstreamtp:[0,1,2],ppstring:[0,1,2,4],ppstring_base16:[0,1,2],ppstring_base85:[0,1,2],ppstring_data:[1,2,4],ppstring_decod:[0,1,2,4],ppstring_decoded_data:[1,2,4],ppstring_encod:[0,1,2,4],ppstring_encoded_data:[1,2,4],ppstring_exec:2,ppstring_hex:[0,1,2],ppstring_intern:2,ppstring_plain:[0!
 ,1,2],ppstring_siz:[0,1,2,4],ppstring_typ:[0,1,2],ppstring_utf16b:[0,1,2],ppstring_utf16l:[0,1,2],ppstring_utf:[0,1,2],pptest3:2,ppuint:[0,1,2],ppxref:[0,1,2],ppxref_catalog:2,ppxref_find:[0,1,2],ppxref_info:2,ppxref_pag:2,ppxref_prev:[0,1,2],ppxref_trail:2,ppxsec:2,practis:[0,1],preceed:[0,1],precis:[0,1],predictor:2,prefer:[0,1,4],prefix:[0,1,2],preprocess:1,present:[0,1],preserv:[0,1],pretend:0,pretti:[0,1,4],previou:[0,1],print:[0,1,2],print_info:2,print_result_filt:2,print_stream_info:2,printabl:[0,1],printf:[0,1,2],privat:4,probabl:[0,1],proce:0,procee:[0,1],process:[0,1,2],produc:[0,1,2],prompt:[0,1],proper:[0,1,2],properli:4,properti:[0,1,2],protect:[0,1,2],provid:[0,1,4],psize:[0,1,2],pune:2,put:0,queri:[0,1],quit:[0,1],rather:[0,1],raw:[0,1,2],read:[0,1],readabl:[0,1],reader:[0,1],readi:[0,1],real:[0,1],realli:[0,1],reason:[0,1],reclaim:[0,1,2],reconstruct:[0,1],rect:[0,1,2],rectangl:[0,1],redirect:[0,1],ref:[2,3],refer:[0,1,2],referenc:[0,1],refnum:2,refnumb:[0,1,2],relat:[0,1,4],releas:[0,1,2],relev:[0,1],reli:1,remain:[0,1],remov:4,replac:[0,1],repres:[0,1,4],request:2,resid:1,resolv:[0,1,2],resourc:[0,1],restor:[0,1],restrict:[0,1],result:[0,1],reus:[0,1],revers:[0,1],revis:[2,4],revolut:4,rework:2,rewrit:[0,1],root:[0,1],roughli:[0,1],runlength:[0,1],runlengthdecod:[0,1],sai:[0,1],same:[0,1],saniti:[0,1,2],scheme:[0,1],search:[0,1],second:[0,1],sect:2,secur:[0,1,2],see:[0,1],seem:4,segfault:[],segment:0,self:4,sens:0,separ:[0,1],serv:4,set:[0,1],sever:[0,1],sha2:2,should:[0,1,2],shouldn:[0,1,2],show:[0,1],sign:[0,1,2],signed:4,simpl:[0,1],simpli:[0,1],sinc:[0,1,4],singl:[0,1,4],size:[0,1,2,4],size_t:[0,1,2,4],sizenum:2,sizeof:[0,1,2],skip:2,small:[0,1],smarter:[0,1],some:[0,1,2,4],some_output:[0,1],someth:[0,1],somewher:[0,1],soon:0,sorri:[0,1],sourc:[0,1,2],space:[0,1],spec:[0,1],special:[0,1],specif:[0,1],sprintf:2,stack:[0,1],standalon:[0,1],start:[0,1],state:[0,1],statu:[0,1],stddef:2,stderr:[0,1,2],stdint:2,stdio:2,stdout:[0,1],still:[0,1,4],stock:4,stop:[0,1],storag:4,store:[0,1,4],strcmp:2,!
 stream:[2,3],string:[2,3],strip:[0,1],strlen:[0,1,2],struct:[0,1,2,4],structur:[0,1,4],style:0,suboptim:[0,1],subsequ:[0,1],succe:[0,1],succeed:[0,1],suffer:[0,1],suit:[0,1,4],sum:[0,1,2],support:[0,1],surround:[0,1],sync:4,syntax:[0,1],tab:[0,1,2],tabl:[0,1],take:[0,1,4],taken:2,target:[0,1],tech:2,tell:[0,1],templat:[0,1,2],termin:[0,1],termini:0,test:[1,2],text:[0,1],than:[0,1],thank:2,thei:[0,1,4],them:[0,1],thi:[0,1,2,4],think:[0,1],those:[0,1],though:0,through:[0,1],tiff:2,todo:[],tollbox:4,top:[0,1],toxic:[],trailer:[0,1],transform:[2,3],treat:[0,1],tree:[0,1],tri:[0,1],trick:4,trickeri:[0,1,4],trimbox:2,triplet:[0,1],trivial:4,two:[0,1,4],type:[2,3,4],typedef:[0,1,2],typic:[0,1],uint8_t:[0,1,2,4],unalign:4,uncompress:2,unconst:[0,1],undocu:[0,1],unescap:[0,1],unicod:[0,1],unif:4,union:[0,1,2],unless:[0,1],unnecesari:[0,1],unnecessari:[0,1],unread:[0,1],unsign:[0,1,2,4],unsupport:[0,1],until:[0,1],unus:4,updat:[0,1,2],usabl:4,usag:[0,1,2],use:[0,1,4],use_buffers_pool:2,used:[0,1,4],useless:[0,1],user:1,userpass:[0,1,2],userpasslength:[0,1,2],userpassword:2,uses:[0,1,4],using:[0,1],usual:[0,1],utf16:[0,1],utf16b:[0,1],utf16l:[0,1],utf:[1,2],util:[0,1,2,4],utiliof:2,utilmem:4,utilmemallc:4,val:[0,1],valid:[0,1],valu:[0,1],variabl:[0,1],variant:4,verbos:[0,1],verifi:[0,1],version:[0,1,2,4],via:[0,1,4],wai:0,want:[0,1,4],warn:[2,4],wast:[0,1,2],watch:4,well:[0,1,4],were:[1,4],weren:[0,1,2],what:[0,1],whatev:[0,1],when:[0,1,2],whenev:[0,1,4],which:[0,1,4],window:4,without:[0,1],wntri:0,won:[0,1],word:[0,1,2,4],work:4,would:[0,1],write:2,wrong:[0,1,4],xref:[2,3],xsec:2,yes:0,yet:4,you:[0,1],your:[0,1],your_callback:[0,1],yourself:[0,1],zero:[0,1]},titles:["<code class=\"docutils literal notranslate\"><span class=\"pre\">pplib</span></code> 1.x","<code class=\"docutils literal notranslate\"><span class=\"pre\">pplib</span></code> 2.x","Examples","pplib","1.x vs 2.x"],titleterms:{And:4,alloc:4,api:[0,1],arrai:[0,1],box:[0,1],chang:2,cleanup:4,content:[0,1],dict:[0,1],encrypt:[0,1],error:[0,1],exampl:2,filter:[0,1!
 ],handl:[0,1],name:[0,1,4],object:[0,1],page:[0,1],pdf:[0,1],ppapi:2,pplib:[0,1,3],ref:[0,1],stream:[0,1],string:[0,1,4],todo:[],transform:[0,1],type:[0,1],xref:[0,1]}})
\ No newline at end of file

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/make.bat
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/doc/make.bat	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/doc/make.bat	2023-05-23 17:09:02 UTC (rev 67196)
@@ -1,5 +1,7 @@
 @ECHO OFF
 
+::set PATH=Q:\<wherepythonlives>\Scripts;%PATH%
+
 pushd %~dp0
 
 REM Command file for Sphinx documentation

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/ppapi-2.x.rst
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/doc/ppapi-2.x.rst	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/doc/ppapi-2.x.rst	2023-05-23 17:09:02 UTC (rev 67196)
@@ -677,15 +677,14 @@
 for a password), but some features (eg. printing) may restricted by the application.
 
 When ``pplib`` detects encryption, it follows Acrobat approach and first tries an empty password. If it succeeds, ``pplib`` proceeeds normally, providing
-an access to decrypted strings and streams, as if they weren't ciphered. If the document is protected with non-empty password, ``pplib`` gives
-a way to provide a password and proceed. Until you provide a password, ``ppdoc`` object returned by ``ppdoc_load()`` function has all object wntries
-set to ``null``.
+an access to decrypted strings and streams, as if they weren't ciphered. If the document is protected with non-empty password, you have to call
+``ppdoc_crypt_pass()``. Until you provide a password, ``ppdoc`` object returned by ``ppdoc_load()`` function has all object entries set to ``null``.
 
-After loading a document you should check encryption status with::
+Once the document is loaded, encryption status can be checked with::
 
   ppcrypt_status ppdoc_crypt_status (ppdoc *pdf);
 
-``ppcrypt_status`` (integer) may have the following values:
+``ppcrypt_status`` (enum) may have the following values:
 
   ``PPCRYPT_NONE`` - no encryption, go ahead
   ``PPCRYPT_DONE`` - encryption present but password succeeded, go ahead
@@ -697,11 +696,13 @@
   ppcrypt_status ppdoc_crypt_pass (ppdoc *pdf, const void *userpass, size_t userpasslength,
                                                const void *ownerpass, size_t ownerpasslength);
 
-Well, yes, there are actually two passwords in encrypted documents. Relation between them is obscure to me, but enough
-to know that having one of them is enough to decrypt the document. If you know the password, you probably mean
-``userpass``, in which case you should put ``NULL`` as ``ownerpass``. The function returns ``PPCRYPT_DONE`` if the password
-succeeds and the previous status otherwise. Your custom loader function may look like that::
+Providing one of two is enough to decrypt the document.
+It is ok to use the same password for owner and user -- ``pplib`` will try both.
 
+The function returns ``PPCRYPT_DONE`` if the password succeeds and the previous crypt status otherwise.
+
+Your custom loader function may look like that::
+
   ppdoc *pdf;
   pdf = ppdoc_load("file.pdf");
   if (pdf == NULL)
@@ -712,8 +713,7 @@
     case PPCRYPT_DONE:
       return pdf;
     case PPCRYPT_PASS:
-      if (ppdoc_crypt_pass(pdf, "dummy", 5, NULL, 0) == PPCRYPT_DONE ||
-          ppdoc_crypt_pass(pdf, NULL, 0, "dummy", 5) == PPCRYPT_DONE)
+      if (ppdoc_crypt_pass(pdf, "dummy", 5, "dummy", 5) == PPCRYPT_DONE)
         return pdf;
       printf("sorry, password needed\n");
       ppdoc_free(pdf);
@@ -724,7 +724,7 @@
       return NULL;
   }
 
-[If you get ``PPCRYPT_FAIL`` it might mean *I failed*, so treat as a bug.]
+See ``pplib`` tests suite for a complete code.
 
 If you'd like to know what permissions are given/restricted to encrypted document::
 
@@ -751,6 +751,15 @@
 
 Encryption is independent from compression, don't confuse with ``ppstream_compressed()``
 
+.. caution::
+   Starting from ``pplib v2.10`` all passwords should be passed as ``UTF-8``.
+   Earlier PDF encryption algorithms (/V 1..4, PDF 1.7) were based on ``PdfDocEncoding``.
+   Newer algorithms (/V 5, PDF 1.8-2.0) expect Unicode encoded as ``UTF-8``.
+   ``pplib`` API now expects ``UTF-8`` and if opening documents with older encryption methods,
+   it tries to make a conversion to 8-bit encoding. In earlier versions ``pplib`` didn't
+   make any password preprocessing, treating them as raw byte arrays.
+   So in case of passwords with fancy characters, it may behave differently.
+
 Pages
 -----
 

Modified: trunk/Build/source/libs/pplib/pplib-src/doc/ppcode.rst
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/doc/ppcode.rst	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/doc/ppcode.rst	2023-05-23 17:09:02 UTC (rev 67196)
@@ -95,7 +95,7 @@
 uint8_t instead of ppbyte in internals; ppbyte intent is "the most natural 8-bit integer", so it is 'char',
 but internally we almost always need uint8_t (char may be signed or not..)
 
-TODO
-====
-- external streams (egzotic)
-
+v2.10
+-----
+Rework on encryption; algorithms /V5 /R6.
+Passwords passed to ppdoc_crypt_pass() should be UTF-8 (backward incompatible).

Modified: trunk/Build/source/libs/pplib/pplib-src/src/Makefile.vc
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/src/Makefile.vc	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/src/Makefile.vc	2023-05-23 17:09:02 UTC (rev 67196)
@@ -19,9 +19,10 @@
 # 4710: no inlined
 # 4711: inline expansion
 # 4706: assignment in conditionals
+# 4061: switch(enum) case label missing, even if default is there
 
 #WFLAGS= /W3 /D_CRT_SECURE_NO_DEPRECATE
-WFLAGS= /Wall /D_CRT_SECURE_NO_DEPRECATE /wd5045 /wd4820 /wd4456 /wd4457 /wd4668 /wd4244 /wd4127 /wd4131 /wd4464 /wd4201 /wd4710 /wd4711
+WFLAGS= /Wall /D_CRT_SECURE_NO_DEPRECATE /wd5045 /wd4820 /wd4456 /wd4457 /wd4668 /wd4244 /wd4127 /wd4131 /wd4464 /wd4201 /wd4710 /wd4711 /wd4061
 CFLAGS= $(WFLAGS) /O2
 
 #LFLAGS = /NODEFAULTLIB:LIBCMT # produces binary dependent from redistributable

Modified: trunk/Build/source/libs/pplib/pplib-src/src/ppapi.h
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/src/ppapi.h	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/src/ppapi.h	2023-05-23 17:09:02 UTC (rev 67196)
@@ -8,7 +8,7 @@
 
 #include "ppconf.h"
 
-#define pplib_version "v2.05 less toxic i hope"
+#define pplib_version "v2.2"
 #define pplib_author "p.jackowski at gust.org.pl"
 
 /* types */

Modified: trunk/Build/source/libs/pplib/pplib-src/src/ppcrypt.c
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/src/ppcrypt.c	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/src/ppcrypt.c	2023-05-23 17:09:02 UTC (rev 67196)
@@ -44,30 +44,156 @@
   return 1;
 }
 
-static const uint8_t padding_string[] = {
+/* V1..4 algorithms */
+
+/* V1..4 unicode do PdfDocEncoding */
+
+typedef struct {
+  uint32_t unicode;
+  uint32_t code;
+  uint32_t count;
+} map_range_t;
+
+static const map_range_t unicode_to_pdf_doc_encoding_map[] = {
+  { 32, 32, 95 },
+  { 161, 161, 12 },
+  { 174, 174, 82 },
+  { 305, 154, 1 },
+  { 321, 149, 1 },
+  { 322, 155, 1 },
+  { 338, 150, 1 },
+  { 339, 156, 1 },
+  { 352, 151, 1 },
+  { 353, 157, 1 },
+  { 376, 152, 1 },
+  { 381, 153, 1 },
+  { 382, 158, 1 },
+  { 402, 134, 1 },
+  { 710, 26, 1 },
+  { 711, 25, 1 },
+  { 728, 24, 1 },
+  { 729, 27, 1 },
+  { 730, 30, 1 },
+  { 731, 29, 1 },
+  { 732, 31, 1 },
+  { 733, 28, 1 },
+  { 8211, 133, 1 },
+  { 8212, 132, 1 },
+  { 8216, 143, 3 },
+  { 8220, 141, 2 },
+  { 8222, 140, 1 },
+  { 8224, 129, 2 },
+  { 8226, 128, 1 },
+  { 8230, 131, 1 },
+  { 8240, 139, 1 },
+  { 8249, 136, 2 },
+  { 8260, 135, 1 },
+  { 8364, 160, 1 },
+  { 8482, 146, 1 },
+  { 8722, 138, 1 },
+  { 64257, 147, 2 }
+};
+
+#define unicode_to_pdf_doc_encoding_entries (sizeof(unicode_to_pdf_doc_encoding_map) / sizeof(map_range_t))
+
+static int unicode_to_pdf_doc_encoding (uint32_t unicode, uint8_t *pcode)
+{
+  const map_range_t *left, *right, *mid;
+
+  left = &unicode_to_pdf_doc_encoding_map[0];
+  right = &unicode_to_pdf_doc_encoding_map[unicode_to_pdf_doc_encoding_entries - 1];
+  for ( ; left <= right; )
+  {
+    mid = left + ((right - left) / 2);
+    if (unicode > mid->unicode + mid->count - 1)
+      left = mid + 1;
+    else if (unicode < mid->unicode)
+      right = mid - 1;
+    else
+    {
+      *pcode = (uint8_t)(mid->code + (unicode - mid->unicode));
+      return 1;
+    }
+  }
+  return 0;
+}
+
+#define utf8_unicode2(p) (((p[0]&31)<<6)|(p[1]&63))
+#define utf8_unicode3(p) (((p[0]&15)<<12)|((p[1]&63)<<6)|(p[2]&63))
+#define utf8_unicode4(p) (((p[0]&7)<<18)|((p[1]&63)<<12)|((p[2]&63)<<6)|(p[3]&63))
+
+#define utf8_get1(p, e, unicode) ((unicode = p[0]), p + 1)
+#define utf8_get2(p, e, unicode) (p + 1 < e ? ((unicode = utf8_unicode2(p)), p + 2) : NULL)
+#define utf8_get3(p, e, unicode) (p + 2 < e ? ((unicode = utf8_unicode3(p)), p + 3) : NULL)
+#define utf8_get4(p, e, unicode) (p + 4 < e ? ((unicode = utf8_unicode3(p)), p + 4) : NULL)
+
+#define utf8_get(p, e, unicode) \
+  (p[0] < 0x80 ? utf8_get1(p, e, unicode) : \
+   p[0] < 0xC0 ? NULL : \
+   p[0] < 0xE0 ? utf8_get2(p, e, unicode) : \
+   p[0] < 0xF0 ? utf8_get3(p, e, unicode) : utf8_get4(p, e, unicode))
+
+static int ppcrypt_password_encoding (uint8_t *password, size_t *passwordlength)
+{
+  uint8_t *p, newpassword[PPCRYPT_MAX_PASSWORD], *n;
+  const uint8_t *e;
+  uint32_t unicode = 0;
+
+  for (n = &newpassword[0], p = &password[0], e = p + *passwordlength; p < e; ++n)
+  {
+    p = utf8_get(p, e, unicode);
+    if (p == NULL)
+      return 0;
+    if (unicode_to_pdf_doc_encoding(unicode, n) == 0)
+      return 0;
+  }
+  *passwordlength = n - &newpassword[0];
+  memcpy(password, newpassword, *passwordlength);
+  return 1;
+}
+
+/* setup passwords */
+
+static const uint8_t password_padding[] = {
   0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
   0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A
 };
 
-static void ppcrypt_set_userpass (ppcrypt *crypt, const void *userpass, size_t userpasslength)
+static void ppcrypt_set_user_password (ppcrypt *crypt, const void *userpass, size_t userpasslength)
 {
-  crypt->userpasslength = userpasslength > 32 ? 32 : userpasslength;
+  crypt->userpasslength = userpasslength > PPCRYPT_MAX_PASSWORD ? PPCRYPT_MAX_PASSWORD : userpasslength;
   memcpy(crypt->userpass, userpass, crypt->userpasslength);
-  memcpy(crypt->userpass + crypt->userpasslength, padding_string, 32 - crypt->userpasslength);
+  if (crypt->algorithm_variant < 5)
+  {
+    if (ppcrypt_password_encoding(crypt->userpass, &crypt->userpasslength) == 0)
+      return;
+    if (crypt->userpasslength > 32)
+      crypt->userpasslength = 32;
+    else if (crypt->userpasslength < 32)
+      memcpy(&crypt->userpass[crypt->userpasslength], password_padding, 32 - crypt->userpasslength);
+  }
   crypt->flags |= PPCRYPT_USER_PASSWORD;
 }
 
-static void ppcrypt_set_ownerpass (ppcrypt *crypt, const void *ownerpass, size_t ownerpasslength)
+static void ppcrypt_set_owner_password (ppcrypt *crypt, const void *ownerpass, size_t ownerpasslength)
 {
-  crypt->ownerpasslength = ownerpasslength > 32 ? 32 : ownerpasslength;
+  crypt->ownerpasslength = ownerpasslength > PPCRYPT_MAX_PASSWORD ? PPCRYPT_MAX_PASSWORD : ownerpasslength;
   memcpy(crypt->ownerpass, ownerpass, crypt->ownerpasslength);
-  memcpy(crypt->ownerpass + crypt->ownerpasslength, padding_string, 32 - crypt->ownerpasslength);
+  if (crypt->algorithm_variant < 5)
+  {
+    if (ppcrypt_password_encoding(crypt->ownerpass, &crypt->ownerpasslength) == 0)
+      return;
+    if (crypt->ownerpasslength > 32)
+      crypt->ownerpasslength = 32;
+    else if (crypt->ownerpasslength < 32)
+      memcpy(&crypt->ownerpass[crypt->ownerpasslength], password_padding, 32 - crypt->ownerpasslength);
+  }
   crypt->flags |= PPCRYPT_OWNER_PASSWORD;
 }
 
-/* retrieving user password from owner password and owner key (variant < 5) */
+/* V1..4 retrieving user password from owner password and owner key (variant < 5) */
 
-static void ppcrypt_retrieve_userpass (ppcrypt *crypt, const void *ownerkey, size_t ownerkeysize)
+static void ppcrypt_user_password_from_owner_key (ppcrypt *crypt, const void *ownerkey, size_t ownerkeysize)
 {
   uint8_t temp[16], rc4key[32], rc4key2[32];
   uint8_t i;
@@ -97,14 +223,14 @@
   }
   //crypt->userpasslength = 32;
   for (crypt->userpasslength = 0; crypt->userpasslength < 32; ++crypt->userpasslength)
-    if (memcmp(&crypt->userpass[crypt->userpasslength], padding_string, 32 - crypt->userpasslength) == 0)
+    if (memcmp(&crypt->userpass[crypt->userpasslength], password_padding, 32 - crypt->userpasslength) == 0)
       break;
   crypt->flags |= PPCRYPT_USER_PASSWORD;
 }
 
-/* generating file key; pdf spec p. 125 */
+/* V1..4 generating file key; pdf spec p. 125 */
 
-static void ppcrypt_filekey (ppcrypt *crypt, const void *ownerkey, size_t ownerkeysize, const void *id, size_t idsize)
+static void ppcrypt_compute_file_key (ppcrypt *crypt, const void *ownerkey, size_t ownerkeysize, const void *id, size_t idsize)
 {
   uint32_t p;
   uint8_t permissions[4], temp[16];
@@ -134,9 +260,9 @@
   }
 }
 
-/* generating userkey for comparison with /U; requires a general file key and id; pdf spec page 126-127 */
+/* V1..4 generating userkey for comparison with /U; requires a general file key and id; pdf spec page 126-127 */
 
-static void ppcrypt_userkey (ppcrypt *crypt, const void *id, size_t idsize, uint8_t *password_hash)
+static void ppcrypt_compute_user_key (ppcrypt *crypt, const void *id, size_t idsize, uint8_t password_hash[32])
 {
   uint8_t rc4key2[32];
   uint8_t i;
@@ -144,13 +270,13 @@
 
   if (crypt->algorithm_revision <= 2)
   {
-    rc4_encode_data(padding_string, 32, password_hash, crypt->filekey, crypt->filekeylength);
+    rc4_encode_data(password_padding, 32, password_hash, crypt->filekey, crypt->filekeylength);
   }
   else
   {
     md5_state md5;
     md5_digest_init(&md5);
-    md5_digest_add(&md5, padding_string, 32);
+    md5_digest_add(&md5, password_padding, 32);
     md5_digest_add(&md5, id, idsize);
     md5_digest_get(&md5, password_hash, MD5_BYTES);
     rc4_encode_data(password_hash, 16, password_hash, crypt->filekey, crypt->filekeylength);
@@ -165,25 +291,127 @@
   }
 }
 
-/* validating /Perms key (pdf 1.7, /V 5 /R 5 crypt) */
+static ppcrypt_status ppcrypt_authenticate_legacy (ppcrypt *crypt, ppstring *userkey, ppstring *ownerkey, ppstring *id)
+{
+  uint8_t password_hash[32];
 
+  if ((crypt->flags & PPCRYPT_USER_PASSWORD) == 0 && (crypt->flags & PPCRYPT_OWNER_PASSWORD) != 0)
+    ppcrypt_user_password_from_owner_key(crypt, ownerkey, ownerkey->size);
+  ppcrypt_compute_file_key(crypt, ownerkey->data, ownerkey->size, id->data, id->size);
+  ppcrypt_compute_user_key(crypt, id->data, id->size, password_hash); /* needs file key */
+  return memcmp(userkey->data, password_hash, (crypt->algorithm_revision >= 3 ? 16 : 32)) == 0 ? PPCRYPT_DONE : PPCRYPT_PASS;
+}
+
+/* V5 */
+
 static const uint8_t nulliv[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* AES-256 initialization vector */
 
-static ppcrypt_status ppcrypt_authenticate_perms (ppcrypt *crypt, ppstring *perms)
-{ /* decode /Perms string overriding crypt setup (should match anyway) */
+/* V5 R5..6 password hash */
+
+#define PPCRYPT_MAX_MANGLED ((127+64+48)*64) // 127 password, 64 hash, 48 /U key
+
+static void ppcrypt_password_hash_indeed (const uint8_t *password, size_t passwordlength, const uint8_t *userkey, uint8_t hash[64])
+{
+  size_t hashlength, datalength;
+  uint8_t data[PPCRYPT_MAX_MANGLED], *pdata;
+  uint8_t *key, *iv;
+  uint8_t round, i;
+  uint32_t div3;
+
+  hashlength = 32; /* initial hash is sha256 */
+  round = 0;
+  do
+  {
+    /* concat password, hash, and /U value 64 times */
+    pdata = &data[0];
+    memcpy(pdata, password, passwordlength);
+    pdata += passwordlength;
+    memcpy(pdata, hash, hashlength);
+    pdata += hashlength;
+    if (userkey != NULL)
+    {
+      memcpy(pdata, userkey, 48);
+      pdata += 48;
+    }
+    datalength = pdata - &data[0];
+    for (i = 1; i < 64; ++i, pdata += datalength)
+      memcpy(pdata, &data[0], datalength);
+    datalength *= 64;
+
+    /* encrypt the data with aes128 using hash bytes 1..16 as key and bytes 17..32 as initialization vector
+       encryption inplace, CBC, no-padding, no change to datalength */
+    key = &hash[0]; iv = &hash[16];
+    aes_encode_data(data, datalength, data, key, 16, iv, AES_NULL_PADDING);
+
+    /* get modulo 3 of first 16 bytes number of encrypted data (sum of digits modulo 3) */
+    for (i = 0, div3 = 0; i < 16; ++i)
+      div3 += data[i];
+
+    /* compute new hash using sha256/384/512 */
+    switch (div3 % 3)
+    {
+      case 0:
+        sha256_digest(data, datalength, hash, SHA_BYTES);
+        hashlength = 32;
+        break;
+      case 1:
+        sha384_digest(data, datalength, hash, SHA_BYTES);
+        hashlength = 48;
+        break;
+      case 2:
+        sha512_digest(data, datalength, hash, SHA_BYTES);
+        hashlength = 64;
+        break;
+    }
+
+    /* do 64 times, then keep going until the last byte of data <= round - 32 */
+  } while (++round < 64 || round < data[datalength - 1] + 32);
+
+}
+
+static void ppcrypt_password_hash (ppcrypt *crypt, const uint8_t *password, size_t passwordlength, const uint8_t *salt, const uint8_t *userkey, uint8_t password_hash[32])
+{
+  sha256_state sha;
+  uint8_t hash[64]; /* result password_hash is 32 bytes, but we need 64 for R6 procedure */
+
+  /* take sha256 of password, salt and /U */
+  sha256_digest_init(&sha);
+  sha256_digest_add(&sha, password, passwordlength);
+  sha256_digest_add(&sha, salt, 8);
+  if (userkey != NULL)
+    sha256_digest_add(&sha, userkey, 48);
+  sha256_digest_get(&sha, hash, SHA_BYTES);
+
+  /* V5 R5 - password_hash is the digest, V5 R6 - password_hash is mangled */
+  if (crypt->algorithm_revision >= 6)
+    ppcrypt_password_hash_indeed(password, passwordlength, userkey, hash);
+
+  memcpy(password_hash, hash, 32);
+}
+
+/* V5 permissions */
+
+static ppcrypt_status ppcrypt_authenticate_permissions (ppcrypt *crypt, ppstring *perms)
+{
   uint8_t permsdata[16];
-  //int64_t p;
-  //int i;
 
   aes_decode_data(perms->data, perms->size, permsdata, crypt->filekey, crypt->filekeylength, nulliv, AES_NULL_PADDING);
 
   if (permsdata[9] != 'a' || permsdata[10] != 'd' || permsdata[11] != 'b')
-    return PPCRYPT_FAIL;
+  { /* if we get here, the password hash is correct, we don't need to fail because of unreadable perms (found such docs) */
+    crypt->flags |= PPCRYPT_UNREADABLE_PERMISSIONS;
+    return PPCRYPT_DONE;
+  }
 
-  // do not update permissions flags; they seem to be different inside crypt string
-  //for (p = 0, i = 0; i < 8; ++i)
-  //  p = p + (permsdata[i] << (i << 3)); /* low order bytes first */
-  //crypt->permissions = (ppint)(int32_t)(p & 0x00000000FFFFFFFFLL); /* unset bits 33..64, treat as 32-bit signed int */
+  /* do not check/update permissions flags here; they might be different inside crypt string */
+  if (0)
+  {
+    int64_t p;
+    int i;
+    for (p = 0, i = 0; i < 8; ++i)
+      p = p + (permsdata[i] << (i << 3)); /* low order bytes first */
+    crypt->permissions = (ppint)((int32_t)(p & 0x00000000FFFFFFFFLL)); /* unset bits 33..64, treat as 32-bit signed int */
+  }
 
   if (permsdata[8] == 'T')
     crypt->flags &= ~PPCRYPT_NO_METADATA;
@@ -193,6 +421,61 @@
   return PPCRYPT_DONE;
 }
 
+/* V5 authentication */
+
+static ppcrypt_status ppcrypt_authenticate_user (ppcrypt *crypt, ppstring *u, ppstring *ue, ppstring *perms)
+{
+  uint8_t password_hash[32], *salt;
+
+  salt = (uint8_t *)&u->data[32]; /* validation salt */
+  ppcrypt_password_hash(crypt, crypt->userpass, crypt->userpasslength, salt, NULL, password_hash);
+  if (memcmp(u->data, password_hash, 32) != 0)
+    return PPCRYPT_PASS;
+
+  salt = (uint8_t *)&u->data[40]; /* key salt */
+  ppcrypt_password_hash(crypt, crypt->userpass, crypt->userpasslength, salt, NULL, password_hash);
+  aes_decode_data(ue->data, 32, crypt->filekey, password_hash, 32, nulliv, AES_NULL_PADDING);
+
+  return ppcrypt_authenticate_permissions(crypt, perms);
+}
+
+static ppcrypt_status ppcrypt_authenticate_owner (ppcrypt *crypt, ppstring *u, ppstring *o, ppstring *oe, ppstring *perms)
+{
+  uint8_t password_hash[32], *salt;
+
+  salt = (uint8_t *)&o->data[32]; /* validation salt */
+  ppcrypt_password_hash(crypt, crypt->ownerpass, crypt->ownerpasslength, salt, (uint8_t *)u->data, password_hash);
+  if (memcmp(o->data, password_hash, 32) != 0)
+    return PPCRYPT_PASS;
+
+  salt = (uint8_t *)&o->data[40]; /* key salt */
+  ppcrypt_password_hash(crypt, crypt->ownerpass, crypt->ownerpasslength, salt, (uint8_t *)u->data, password_hash);
+  aes_decode_data(oe->data, 32, crypt->filekey, password_hash, 32, nulliv, AES_NULL_PADDING);
+
+  return ppcrypt_authenticate_permissions(crypt, perms);
+}
+
+
+/* authentication */
+
+static ppcrypt_status ppcrypt_authenticate (ppcrypt *crypt, ppstring *u, ppstring *ue, ppstring *o, ppstring *oe, ppstring *id, ppstring *perms)
+{
+  /* V1..V4 */
+  if (crypt->algorithm_variant < 5)
+    return ppcrypt_authenticate_legacy(crypt, u, o, id);
+
+  /* V5 */
+  if (crypt->flags & PPCRYPT_USER_PASSWORD)
+    if (ppcrypt_authenticate_user(crypt, u, ue, perms) == PPCRYPT_DONE)
+      return PPCRYPT_DONE;
+  if (crypt->flags & PPCRYPT_OWNER_PASSWORD)
+    return ppcrypt_authenticate_owner(crypt, u, o, oe, perms);
+
+  return PPCRYPT_PASS;
+}
+
+/**/
+
 ppcrypt_status ppdoc_crypt_init (ppdoc *pdf, const void *userpass, size_t userpasslength, const void *ownerpass, size_t ownerpasslength)
 {
   ppcrypt *crypt;
@@ -206,15 +489,11 @@
   int cryptflags, encryptmd;
   size_t strkeylength, stmkeylength;
 
-  uint8_t password_hash[32]; /* /U and /O are 48 bytes strings for AES-256, but here we use only 32 */
-  uint8_t *validation_salt, *key_salt;
-
-  /* Every xref could theoretically have a separate encryption info. Not clarified in pdf spec but it seems that the top
-     level xref encryption info is the one to be applied to all objects in all xrefs, including older. */
   trailer = ppxref_trailer(pdf->xref);
   if ((obj = ppdict_get_obj(trailer, "Encrypt")) == NULL)
     return PPCRYPT_NONE;
-  /* Typically this is all done early, before loading body, so if /Encrypt is indirect reference, it points nothing. We have to load it here. */
+
+  /* this happens early, before loading body, so if /Encrypt is indirect reference, it points nothing */
   obj = ppobj_preloaded(pdf, obj);
   if (obj->type != PPDICT)
     return PPCRYPT_FAIL;
@@ -227,6 +506,8 @@
 
   if ((crypt = pdf->crypt) == NULL)
     crypt = pdf->crypt = ppcrypt_create(&pdf->heap);
+
+  /* get /V /R /P */
   if (!ppdict_get_uint(encrypt, "V", &crypt->algorithm_variant))
     crypt->algorithm_variant = 0;
   if (crypt->algorithm_variant < 1 || crypt->algorithm_variant > 5)
@@ -233,14 +514,15 @@
     return PPCRYPT_FAIL;
   if (!ppdict_get_uint(encrypt, "R", &crypt->algorithm_revision))
     return PPCRYPT_FAIL;
-  if (crypt->algorithm_revision >= 3)
-    crypt->flags |= PPCRYPT_OBSCURITY;
   if (!ppdict_get_int(encrypt, "P", &crypt->permissions))
     return PPCRYPT_FAIL;
+
+  /* get /O /U /ID /OE /UE */
   if ((userkey = ppdict_get_string(encrypt, "U")) == NULL || (ownerkey = ppdict_get_string(encrypt, "O")) == NULL)
     return PPCRYPT_FAIL;
   userkey = ppstring_decoded(userkey);
   ownerkey = ppstring_decoded(ownerkey);
+
   /* for some reason acrobat pads /O and /U to 127 bytes with NULL, so we don't check the exact length but ensure the minimal */
   hashlength = crypt->algorithm_variant < 5 ? 32 : 48;
   if (userkey->size < hashlength || ownerkey->size < hashlength)
@@ -266,6 +548,7 @@
       return PPCRYPT_FAIL;
   }
 
+  /* collect flags and keylength */
   switch (crypt->algorithm_revision)
   {
     case 1:
@@ -279,7 +562,7 @@
         crypt->filekeylength = 5; /* 40 bits, 5 bytes */
       crypt->flags |= PPCRYPT_RC4;
       break;
-    case 4: case 5:
+    case 4: case 5: case 6:
       if ((crypt->map = ppdict_rget_dict(encrypt, "CF")) == NULL)
         return PPCRYPT_FAIL;
       for (ppdict_first(crypt->map, pkey, obj); *pkey != NULL; ppdict_next(pkey, obj))
@@ -327,72 +610,15 @@
       return PPCRYPT_FAIL;
   }
 
-  /* password */
-
+  /* setup passwords */
   if (userpass != NULL)
-  {
-    ppcrypt_set_userpass(crypt, userpass, userpasslength);
-  }
-  else if (ownerpass != NULL)
-  {
-    if (crypt->algorithm_variant < 5) // fetch user password from owner password
-      ppcrypt_retrieve_userpass(crypt, ownerkey, ppstring_size(ownerkey));
-    else                              // open the document using owner password
-      ppcrypt_set_ownerpass(crypt, ownerpass, ownerpasslength);
-  }
-  else
-  {
-    return PPCRYPT_FAIL;
-  }
-
-  if (crypt->algorithm_variant < 5)
-  { /* authenticate by comparing a generated vs present /U entry; depending on variant 16 or 32 bytes to compare */
-    ppcrypt_filekey(crypt, ownerkey->data, ownerkey->size, id->data, id->size);
-    ppcrypt_userkey(crypt, id->data, id->size, password_hash); /* needs file key so comes after key generation */
-    if (memcmp(userkey->data, password_hash, (crypt->algorithm_revision >= 3 ? 16 : 32)) == 0)
-      return PPCRYPT_DONE;
+    ppcrypt_set_user_password(crypt, userpass, userpasslength);
+  if (ownerpass != NULL)
+    ppcrypt_set_owner_password(crypt, ownerpass, ownerpasslength);
+  if ((crypt->flags & (PPCRYPT_USER_PASSWORD|PPCRYPT_OWNER_PASSWORD)) == 0)
     return PPCRYPT_PASS;
-  }
-  if (crypt->flags & PPCRYPT_USER_PASSWORD)
-  {
-    sha256_state sha;
-    validation_salt = (uint8_t *)userkey + 32;
-    key_salt = validation_salt + 8;
-    sha256_digest_init(&sha);
-    sha256_digest_add(&sha, crypt->userpass, crypt->userpasslength);
-    sha256_digest_add(&sha, validation_salt, 8);
-    sha256_digest_get(&sha, password_hash, SHA_BYTES);
-    if (memcmp(userkey->data, password_hash, 32) != 0)
-      return PPCRYPT_PASS;
-    sha256_digest_init(&sha);
-    sha256_digest_add(&sha, crypt->userpass, crypt->userpasslength);
-    sha256_digest_add(&sha, key_salt, 8);
-    sha256_digest_get(&sha, password_hash, SHA_BYTES);
-    aes_decode_data(userkey_e->data, 32, crypt->filekey, password_hash, 32, nulliv, AES_NULL_PADDING);
-    return ppcrypt_authenticate_perms(crypt, perms);
-  }
-  if (crypt->flags & PPCRYPT_OWNER_PASSWORD)
-  {
-    sha256_state sha;
-    validation_salt = (uint8_t *)ownerkey + 32;
-    key_salt = validation_salt + 8;
 
-    sha256_digest_init(&sha);
-    sha256_digest_add(&sha, crypt->ownerpass, crypt->ownerpasslength);
-    sha256_digest_add(&sha, validation_salt, 8);
-    sha256_digest_add(&sha, userkey, 48);
-    sha256_digest_get(&sha, password_hash, SHA_BYTES);
-    if (memcmp(ownerkey->data, password_hash, 32) != 0)
-      return PPCRYPT_PASS;
-    sha256_digest_init(&sha);
-    sha256_digest_add(&sha, crypt->ownerpass, crypt->ownerpasslength);
-    sha256_digest_add(&sha, key_salt, 8);
-    sha256_digest_add(&sha, userkey, 48);
-    sha256_digest_get(&sha, password_hash, SHA_BYTES);
-    aes_decode_data(ownerkey_e->data, 32, crypt->filekey, password_hash, 32, nulliv, AES_NULL_PADDING);
-    return ppcrypt_authenticate_perms(crypt, perms);
-  }
-  return PPCRYPT_FAIL; // should never get here
+  return ppcrypt_authenticate(crypt, userkey, userkey_e, ownerkey, ownerkey_e, id, perms);
 }
 
 /* decrypting strings */
@@ -429,10 +655,10 @@
 
     if (aes)
     {
-      crypt->filekey[crypt->filekeylength + 5] = 0x73;
-      crypt->filekey[crypt->filekeylength + 6] = 0x41;
-      crypt->filekey[crypt->filekeylength + 7] = 0x6C;
-      crypt->filekey[crypt->filekeylength + 8] = 0x54;
+      crypt->filekey[crypt->filekeylength + 5] = 0x73; // s
+      crypt->filekey[crypt->filekeylength + 6] = 0x41; // A
+      crypt->filekey[crypt->filekeylength + 7] = 0x6C; // l
+      crypt->filekey[crypt->filekeylength + 8] = 0x54; // T
     }
 
     md5_digest(crypt->filekey, crypt->filekeylength + (aes ? 9 : 5), crypt->cryptkey, MD5_BYTES);

Modified: trunk/Build/source/libs/pplib/pplib-src/src/ppcrypt.h
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/src/ppcrypt.h	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/src/ppcrypt.h	2023-05-23 17:09:02 UTC (rev 67196)
@@ -6,21 +6,25 @@
 #include "utilcrypt.h"
 #include "utilcryptdef.h"
 
+#define PPCRYPT_MAX_PASSWORD 127
+#define PPCRYPT_MAX_KEY 32
+
 typedef struct {
-  ppuint algorithm_variant;  /* /V entry of encrypt dict */
-  ppuint algorithm_revision; /* /R entry of encrypt dict */
-  ppint permissions;         /* /P entry of encrypt dict */
-  ppdict *map;               /* /CF filters map of encrypt dict */
-  uint8_t userpass[32];      /* padded user password */
-  size_t userpasslength;     /* the length of unpadded user password */
-  uint8_t ownerpass[32];     /* padded owner password */
-  size_t ownerpasslength;    /* the length of unpadded owner password */
-  uint8_t filekey[32+5+4];   /* generated file key with extra space of 5..9 bytes for salt */
-  size_t filekeylength;      /* key length; usually 5, 16 or 32 bytes */
-  uint8_t cryptkey[32];      /* final crypt key for a given reference */
-  size_t cryptkeylength;     /* final crypt key length; usually keylength + 5 */
-  ppref *ref;                /* currently loaded ref (each ref may have a different key) */
-  union {                    /* cached crypt states for strings encrypted/decrypted with the same key */
+  ppuint algorithm_variant;                /* /V entry of encrypt dict */
+  ppuint algorithm_revision;               /* /R entry of encrypt dict */
+  ppint permissions;                       /* /P entry of encrypt dict */
+  ppdict *map;                             /* /CF filters map of encrypt dict */
+  uint8_t userpass[PPCRYPT_MAX_PASSWORD];  /* user password */
+  size_t userpasslength;                   /* user password length */
+  uint8_t ownerpass[PPCRYPT_MAX_PASSWORD]; /* owner password */
+  size_t ownerpasslength;                  /* owner password length */
+  uint8_t filekey[PPCRYPT_MAX_KEY+5+4];    /* file key with an extra space for salt */
+  size_t filekeylength;                    /* key length; usually 5, 16 or 32 bytes */
+  uint8_t cryptkey[PPCRYPT_MAX_KEY];       /* crypt key for a recent reference */
+  size_t cryptkeylength;                   /* crypt key length; usually keylength + 5 */
+  //ppstring *cryptkeystring;                /* todo: cached cryptkey string for V5, where all refs has the same */
+  ppref *ref;                              /* recent reference */
+  union { /* cached crypt states for strings encrypted/decrypted with the same key */
     struct {
       rc4_state rc4state;
       rc4_map rc4map;
@@ -42,7 +46,7 @@
 #define PPCRYPT_STRING_RC4 (1<<4)
 #define PPCRYPT_STREAM_AES (1<<5)
 #define PPCRYPT_STRING_AES (1<<6)
-#define PPCRYPT_OBSCURITY  (1<<7)
+#define PPCRYPT_UNREADABLE_PERMISSIONS (1<<7)
 
 #define PPCRYPT_STREAM (PPCRYPT_STREAM_AES|PPCRYPT_STREAM_RC4)
 #define PPCRYPT_STRING (PPCRYPT_STRING_AES|PPCRYPT_STRING_RC4)

Modified: trunk/Build/source/libs/pplib/pplib-src/src/pptest2.c
===================================================================
--- trunk/Build/source/libs/pplib/pplib-src/src/pptest2.c	2023-05-22 23:42:51 UTC (rev 67195)
+++ trunk/Build/source/libs/pplib/pplib-src/src/pptest2.c	2023-05-23 17:09:02 UTC (rev 67196)
@@ -28,6 +28,9 @@
 {
   printf("pplib " pplib_version ", " pplib_author "\n");
   printf("usage: %s file1.pdf file2.pdf ...\n", argv0);
+  printf("       %s file.pdf -u userpassword\n", argv0);
+  printf("       %s file.pdf -o ownerpassword\n", argv0);
+  printf("       %s file.pdf -p bothpasswords\n", argv0);
   return 0;
 }
 
@@ -36,11 +39,27 @@
   fprintf((FILE *)alien, "\nooops: %s\n", message);
 }
 
+static const char * get_next_argument (const char *opt, int *a, int argc, const char **argv)
+{
+  const char *next;
+  if ((*a) + 2 < argc)
+  {
+    next = argv[*a + 1];
+    if (strcmp(next, opt) == 0)
+    {
+      *a += 2;
+      return argv[*a];
+    }
+  }
+  return NULL;
+}
+
 int main (int argc, const char **argv)
 {
-  const char *filepath;
+  const char *filepath, *password;
   int a;
   ppdoc *pdf;
+  ppcrypt_status cryptstatus;
   ppref *pageref;
   ppdict *pagedict;
   int pageno;
@@ -61,6 +80,7 @@
   context = ppcontext_new();
   for (a = 1; a < argc; ++a)
   {
+    /* load */
     filepath = argv[a];
     printf("loading %s... ", filepath);
     pdf = ppdoc_load(filepath);
@@ -69,23 +89,35 @@
       printf("failed\n");
       continue;
     }
-    printf("done.\n");
-    switch (ppdoc_crypt_status(pdf))
+    printf("done\n");
+
+    /* decrypt */
+    if ((password = get_next_argument("-u", &a, argc, argv)) != NULL)
+      cryptstatus = ppdoc_crypt_pass(pdf, password, strlen(password), NULL, 0);
+    else if ((password = get_next_argument("-o", &a, argc, argv)) != NULL)
+      cryptstatus = ppdoc_crypt_pass(pdf, NULL, 0, password, strlen(password));
+    else if ((password = get_next_argument("-p", &a, argc, argv)) != NULL)
+      cryptstatus = ppdoc_crypt_pass(pdf, password, strlen(password), password, strlen(password));
+    else
+      cryptstatus = ppdoc_crypt_status(pdf);
+    switch (cryptstatus)
     {
       case PPCRYPT_NONE:
+        break;
       case PPCRYPT_DONE:
+        printf("opened with password '%s'\n", password != NULL ? password : "");
         break;
       case PPCRYPT_PASS:
-        if (ppdoc_crypt_pass(pdf, "dummy", 5, NULL, 0) == PPCRYPT_DONE || ppdoc_crypt_pass(pdf, NULL, 0, "dummy", 5) == PPCRYPT_DONE)
-          break;
-        printf("sorry, password needed\n");
+        printf("invalid password\n");
         ppdoc_free(pdf);
         continue;
       case PPCRYPT_FAIL:
-        printf("sorry, encryption failed\n");
+        printf("invalid encryption\n");
         ppdoc_free(pdf);
         continue;
     }
+
+    /* process */
     sprintf(outname, "%s.out", filepath);
     fh = fopen(outname, "wb");
     if (fh == NULL)



More information about the tex-live-commits mailing list.