home *** CD-ROM | disk | FTP | other *** search
/ PSION CD 2 / PsionCDVol2.iso / Programs / 720 / PDF090B4-SorceCode / pdf / XRef.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-30  |  17.9 KB  |  712 lines

  1. //========================================================================
  2. //
  3. // XRef.cc
  4. //
  5. // Copyright 1996 Derek B. Noonburg
  6. //
  7. //========================================================================
  8. //
  9. // Ported to EPOC by Sander van der Wal
  10. //
  11. // $Log: XRef.cpp $
  12. // Revision 1.2  2000-09-17 13:38:20+02  svdwal
  13. // Ported
  14. //
  15.  
  16. #ifdef __GNUC__
  17. #pragma implementation
  18. #endif
  19.  
  20. #ifndef __E32DEF_H__
  21. #include <e32def.h>
  22. #endif
  23.  
  24. // --o C library
  25. #include <stdlib.h>
  26. #include <ctype.h>
  27.  
  28. // --o GooLib
  29. #include "gmem.h"
  30.  
  31. // --o PdfLib
  32. #include "Object.h"
  33. #include "Stream.h"
  34. #include "Lexer.h"
  35. #include "Parser.h"
  36. #include "Dict.h"
  37. #include "Error.h"
  38. #include "XRef.h"
  39. #include "md5.h"
  40. #include "rc4.h"
  41.  
  42. // --o Pdf impl
  43. #include "PDFGlobal.h"
  44. #include "Pdf.rsg"
  45.  
  46.  
  47. //------------------------------------------------------------------------
  48.  
  49. #define xrefSearchSize 1024    // read this many bytes at end of file
  50.                             // to look for 'startxref'
  51.  
  52. //------------------------------------------------------------------------
  53. // The global xref table
  54. //------------------------------------------------------------------------
  55.  
  56. #ifdef __SYMBIAN32__
  57.  
  58. // Initialise global data
  59. XRefGlobal::XRefGlobal()
  60. {
  61.   xref = 0;
  62. }
  63.  
  64. #else
  65.  
  66. XRef *xref = NULL;
  67.  
  68. #endif
  69.  
  70. //------------------------------------------------------------------------
  71. // XRef
  72. //------------------------------------------------------------------------
  73.  
  74. void XRef::ConstructL(FileStream* str)
  75. {
  76.   XRef *oldXref;
  77.   int pos=0;
  78.   int i;
  79.  
  80.   ok = gTrue;
  81.   encrypted = gFalse;
  82.  
  83.   // get rid of old xref (otherwise it will try to fetch the Root object
  84.   // in the new document, using the old xref)
  85.   oldXref = Global().XRef.xref;
  86.   Global().XRef.xref = 0;
  87.  
  88.   // read the trailer
  89.   file = str->getFile();
  90.   start = str->getStart();
  91.   TRAPD(err, pos = readTrailerL(str));
  92.   if (err != KErrNone) {
  93.     ok = gFalse;
  94.     Global().XRef.xref = oldXref;
  95.     User::Leave(err);
  96.   }
  97.  
  98.   // if there was a problem with the trailer,
  99.   // try to reconstruct the xref table
  100.   if (pos == 0) {
  101.     TRAP(err, ok = constructXRefL(str));
  102.     if (err != KErrNone || !ok) {
  103.       ok = gFalse;
  104.       Global().XRef.xref = oldXref;
  105.       if (err != KErrNone)
  106.         User::Leave(err);
  107.       return;
  108.     }
  109.  
  110.   // trailer is ok - read the xref table
  111.   } 
  112.   else {
  113.     ok = gFalse;
  114.     entries = (XRefEntry *)User::Alloc(size * sizeof(XRefEntry));
  115.     if (!entries) {
  116.       ok = gFalse;
  117.       Global().XRef.xref = oldXref;
  118.       User::Leave(KErrNoMemory);
  119.     }
  120.     for (i = 0; i < size; ++i) {
  121.       entries[i].offset = -1;
  122.       entries[i].used = gFalse;
  123.     }
  124.     TRAP(err, while (readXRefL(str, &pos))) ;
  125.     if (err != KErrNone) {
  126.       ok = gFalse;
  127.       Global().XRef.xref = oldXref;
  128.       User::Leave(KErrNoMemory);
  129.     }
  130.  
  131.     // if there was a problem with the xref table,
  132.     // try to reconstruct it
  133.     if (!ok) {
  134.       User::Free(entries);
  135.       entries = 0;
  136.       size = 0;
  137.       TRAP(err, ok = constructXRefL(str));
  138.       if (err != KErrNone || !ok) {
  139.         Global().XRef.xref = oldXref;
  140.         if (err != KErrNone)
  141.           User::Leave(err);
  142.         return;
  143.       }
  144.     }
  145.   }
  146.  
  147.   // set up new xref table
  148.   Global().XRef.xref = this;
  149.  
  150.   // check for encryption
  151.   m_okToPrint = gTrue;
  152.   m_okToCopy = gTrue;
  153.   m_okToChange = gTrue;
  154.   m_okToAddNotes = gTrue;
  155.   if (checkEncryptedL()) {
  156.     if (setupDecryptionL() == gFalse) {
  157.       ok = gFalse;
  158.       Global().XRef.xref = oldXref;
  159.       return;
  160.     }
  161.   }
  162. }
  163.  
  164. XRef::~XRef() {
  165.   User::Free(entries);
  166.   trailerDict.free();
  167.   encryptionDict.free();
  168.   delete encryptionKey;
  169. }
  170.  
  171. // Read startxref position, xref table size, and root.  Returns
  172. // first xref position.
  173. int XRef::readTrailerL(FileStream *str) {
  174.   char buf[xrefSearchSize+1];
  175.   int n, pos, pos1;
  176.   char *p;
  177.   int c;
  178.   int i;  
  179.   
  180.   // read last xrefSearchSize bytes
  181.   str->setPos(-xrefSearchSize);
  182.   for (n = 0; n < xrefSearchSize; ++n) {
  183.     if ((c = str->getChar()) == EOF)
  184.       break;
  185.     buf[n] = c;
  186.   }
  187.   buf[n] = '\0';
  188.  
  189.   // find startxref
  190.   for (i = n - 9; i >= 0; --i) {
  191.     if (!strncmp(&buf[i], "startxref", 9))
  192.       break;
  193.   }
  194.   if (i < 0)
  195.     return 0;
  196.   for (p = &buf[i+9]; isspace(*p); ++p) ;
  197.   pos = atoi(p);
  198.  
  199.   // find trailer dict by looking after first xref table
  200.   // (NB: we can't just use the trailer dict at the end of the file --
  201.   // this won't work for linearized files.)
  202.   str->setPos(start + pos);
  203.   for (i = 0; i < 4; ++i)
  204.     buf[i] = str->getChar();
  205.   if (strncmp(buf, "xref", 4))
  206.     return 0;
  207.   pos1 = pos + 4;
  208.   for (;;) {
  209.     str->setPos(start + pos1);
  210.     for (i = 0; i < 35; ++i) {
  211.       if ((c = str->getChar()) == EOF)
  212.         return 0;
  213.       buf[i] = c;
  214.     }
  215.     if (!strncmp(buf, "trailer", 7))
  216.       break;
  217.     p = buf;
  218.     while (isspace(*p)) ++p;
  219.     while ('0' <= *p && *p <= '9') ++p;
  220.     while (isspace(*p)) ++p;
  221.     n = atoi(p);
  222.     while ('0' <= *p && *p <= '9') ++p;
  223.     while (isspace(*p)) ++p;
  224.     if (p == buf)
  225.       return 0;
  226.     pos1 += (p - buf) + n * 20;
  227.   }
  228.   pos1 += 7;
  229.  
  230.   // read trailer dict
  231.   RAutoObject obj;
  232.   obj.initNull();
  233.   
  234.   FileStream* stream = new(ELeave) FileStream(file, start + pos1, -1, &obj);
  235.   CleanupStack::PushL(stream);
  236.  
  237.   Lexer* lexer = new(ELeave) Lexer(stream);
  238.   CleanupStack::Pop(); // stream
  239.   CleanupStack::PushL(lexer);
  240.   lexer->ConstructL();
  241.  
  242.   Parser *parser = new(ELeave) Parser(lexer);
  243.   CleanupStack::Pop(); // lexer
  244.   CleanupStack::PushL(parser);
  245.   parser->ConstructL();
  246.  
  247.   parser->getObjL(&trailerDict);
  248.   if (trailerDict.isDict()) {
  249.     trailerDict.dictLookupNFL("Size", &obj);
  250.     if (obj.isInt())
  251.       size = obj.getInt();
  252.     else
  253.       pos = 0;
  254.     obj.free();
  255.     trailerDict.dictLookupNFL("Root", &obj);
  256.     if (obj.isRef()) {
  257.       rootNum = obj.getRefNum();
  258.       rootGen = obj.getRefGen();
  259.     } else {
  260.       pos = 0;
  261.     }
  262.     obj.free();
  263.   } else {
  264.     pos = 0;
  265.   }
  266.   CleanupStack::PopAndDestroy(); // delete parser;
  267.  
  268.   // return first xref position
  269.   return pos;
  270. }
  271.  
  272. // Read an xref table and the prev pointer from the trailer.
  273. GBool XRef::readXRefL(FileStream *str, int *pos) {
  274.   char s[20];
  275.   GBool more;
  276.   int first, n, i, j;
  277.   int c;
  278.  
  279.   // seek to xref in stream
  280.   str->setPos(start + *pos);
  281.  
  282.   // make sure it's an xref table
  283.   while ((c = str->getChar()) != EOF && isspace(c)) ;
  284.   s[0] = (char)c;
  285.   s[1] = (char)str->getChar();
  286.   s[2] = (char)str->getChar();
  287.   s[3] = (char)str->getChar();
  288.   if (!(s[0] == 'x' && s[1] == 'r' && s[2] == 'e' && s[3] == 'f'))
  289.     return ok = gFalse;
  290.  
  291.   // read xref
  292.   for (;;) {
  293.     while ((c = str->lookChar()) != EOF && isspace(c))
  294.       str->getChar();
  295.     if (c == 't')
  296.       break;
  297.     for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i)
  298.       s[i] = (char)c;
  299.     if (i == 0)
  300.        return ok = gFalse;
  301.     s[i] = '\0';
  302.     first = atoi(s);
  303.     while ((c = str->lookChar()) != EOF && isspace(c))
  304.       str->getChar();
  305.     for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i)
  306.       s[i] = (char)c;
  307.     if (i == 0)
  308.        return ok = gFalse;
  309.     s[i] = '\0';
  310.     n = atoi(s);
  311.     while ((c = str->lookChar()) != EOF && isspace(c))
  312.       str->getChar();
  313.     for (i = first; i < first + n; ++i) {
  314.       for (j = 0; j < 20; ++j) {
  315.         if ((c = str->getChar()) == EOF)
  316.             return ok = gFalse;
  317.         s[j] = (char)c;
  318.       }
  319.       if (entries[i].offset < 0) {
  320.         s[10] = '\0';
  321.         entries[i].offset = atoi(s);
  322.         s[16] = '\0';
  323.         entries[i].gen = atoi(&s[11]);
  324.         if (s[17] == 'n')
  325.           entries[i].used = gTrue;
  326.         else if (s[17] == 'f')
  327.           entries[i].used = gFalse;
  328.         else
  329.            return ok = gFalse;
  330.       }
  331.     }
  332.   }
  333.  
  334.   ok = gFalse; // on leaves, it is not ok
  335.  
  336.   // read prev pointer from trailer dictionary
  337.   RAutoObject obj, obj2;
  338.   obj.initNull();
  339.  
  340.   FileStream* stream = new(ELeave) FileStream(file, str->getPos(), -1, &obj);
  341.   CleanupStack::PushL(stream);
  342.   
  343.   Lexer* lexer = new(ELeave) Lexer(stream);
  344.   CleanupStack::Pop(); // stream
  345.   CleanupStack::PushL(lexer);
  346.   lexer->ConstructL();
  347.   
  348.   Parser *parser = new(ELeave) Parser(lexer);
  349.   CleanupStack::Pop(); // lexer
  350.   CleanupStack::PushL(parser);
  351.   parser->ConstructL();
  352.   
  353.   parser->getObjL(&obj);
  354.   if (!obj.isCmd("trailer"))
  355.     goto err1;
  356.   obj.free();
  357.   parser->getObjL(&obj);
  358.   if (!obj.isDict())
  359.     goto err1;
  360.   obj.getDict()->lookupNFL("Prev", &obj2);
  361.   if (obj2.isInt()) {
  362.     *pos = obj2.getInt();
  363.     more = gTrue;
  364.   } else {
  365.     more = gFalse;
  366.   }
  367.   obj.free();
  368.   obj2.free();
  369.  
  370.   CleanupStack::PopAndDestroy(); // delete parser;
  371.   ok = gTrue;
  372.   return more;
  373.  
  374.  err1:
  375.   obj.free();
  376.   ok = gFalse;
  377.   return gFalse;
  378. }
  379.  
  380. // Attempt to construct an xref table for a damaged file.
  381. GBool XRef::constructXRefL(FileStream *str) {
  382.   char buf[256];
  383.   int pos;
  384.   int newSize;
  385.   char *p;
  386.   GBool gotRoot;
  387.  
  388.   error(0, R_PDF_FILE_IS_DAMAGED___ATTEMPTING_TO_RECONSTRUCT_XREF_TABLE___);
  389.   gotRoot = gFalse;
  390.  
  391.   str->reset();
  392.   for (;;) {
  393.     pos = str->getPos();
  394.     if (!str->getLine(buf, 256))
  395.       break;
  396.     p = buf;
  397.  
  398.     // got trailer dictionary
  399.     if (!strncmp(p, "trailer", 7)) {
  400.       RAutoObject obj;
  401.       obj.initNull();
  402.       
  403.       FileStream* stream = new(ELeave) FileStream(file, start + pos + 8, -1, &obj);
  404.       CleanupStack::PushL(stream);
  405.  
  406.       Lexer* lexer = new(ELeave) Lexer(stream);
  407.       CleanupStack::Pop(); // stream
  408.       CleanupStack::PushL(lexer);
  409.       lexer->ConstructL();
  410.  
  411.       Parser *parser = new(ELeave) Parser(lexer);
  412.       CleanupStack::Pop(); // lexer
  413.       CleanupStack::PushL(parser);
  414.       parser->ConstructL();
  415.       
  416.       if (!trailerDict.isNone())
  417.         trailerDict.free();
  418.       parser->getObjL(&trailerDict);
  419.       if (trailerDict.isDict()) {
  420.         trailerDict.dictLookupNFL("Root", &obj);
  421.         if (obj.isRef()) {
  422.           rootNum = obj.getRefNum();
  423.           rootGen = obj.getRefGen();
  424.         gotRoot = gTrue;
  425.         }
  426.         obj.free();
  427.       } else {
  428.         pos = 0;
  429.       }
  430.       CleanupStack::PopAndDestroy(); // delete parser;
  431.  
  432.     // look for object
  433.     } 
  434.     else if (isdigit(*p)) {
  435.       int num = atoi(p);
  436.       do {
  437.         ++p;
  438.       } while (*p && isdigit(*p));
  439.       if (isspace(*p)) {
  440.         do {
  441.           ++p;
  442.         } while (*p && isspace(*p));
  443.         if (isdigit(*p)) {
  444.           int gen = atoi(p);
  445.           do {
  446.             ++p;
  447.           } while (*p && isdigit(*p));
  448.           if (isspace(*p)) {
  449.             do {
  450.               ++p;
  451.             } while (*p && isspace(*p));
  452.             if (!strncmp(p, "obj", 3)) {
  453.               if (num >= size) {
  454.                 newSize = (num + 1 + 255) & ~255;
  455.                 entries = (XRefEntry *) User::ReAllocL(entries, newSize * sizeof(XRefEntry));
  456.                 for (int i = size; i < newSize; ++i) {
  457.                   entries[i].offset = -1;
  458.                   entries[i].used = gFalse;
  459.                 }
  460.                 size = newSize;
  461.               }
  462.               if (!entries[num].used || gen >= entries[num].gen) {
  463.                 entries[num].offset = pos - start;
  464.                 entries[num].gen = gen;
  465.                 entries[num].used = gTrue;
  466.               }
  467.             }
  468.           }
  469.         }
  470.       }
  471.     }
  472.   }
  473.  
  474.   if (gotRoot)
  475.     return gTrue;
  476.  
  477.   error(-1, R_COULDN_T_FIND_TRAILER_DICTIONARY);
  478.   return gFalse;
  479. }
  480.  
  481. GBool XRef::checkEncryptedL() {
  482.   trailerDict.dictLookupL("Encrypt", &encryptionDict);
  483.   encrypted = encryptionDict.isDict();
  484.   if (encrypted)
  485.     encryptionKey = GString::NewL();
  486.   return encrypted;
  487. }
  488.  
  489. GBool XRef::okToPrint() {
  490.   return m_okToPrint;
  491. }
  492.  
  493. GBool XRef::okToCopy() {
  494.   return m_okToCopy;
  495. }
  496.  
  497. GBool XRef::okToChange() {
  498.   return m_okToChange;
  499. }
  500.  
  501. GBool XRef::okToAddNotes() {
  502.   return m_okToAddNotes;
  503. }
  504.   
  505. Object *XRef::fetchL(int num, int gen, Object *obj) {
  506.   XRefEntry *e;
  507.   RAutoObject obj1, obj2, obj3;
  508.  
  509.   // check for bogus ref - this can happen in corrupted PDF files
  510.   if (num < 0 || num >= size) {
  511.     obj->initNull();
  512.     return obj;
  513.   }
  514.  
  515.   e = &entries[num];
  516.   if (e->gen == gen && e->offset >= 0) {
  517.     obj1.initNull();
  518.     
  519.     FileStream* stream = new(ELeave) FileStream(file, start + e->offset, -1, &obj1);
  520.     CleanupStack::PushL(stream);
  521.  
  522.     Lexer* lexer = new(ELeave) Lexer(stream);
  523.     CleanupStack::Pop(); // stream
  524.     CleanupStack::PushL(lexer);
  525.     lexer->ConstructL();
  526.  
  527.     Parser *parser = new(ELeave) Parser(lexer);
  528.     CleanupStack::Pop(); // lexer
  529.     CleanupStack::PushL(parser);
  530.     parser->ConstructL();
  531.  
  532.     parser->getObjL(&obj1);
  533.     parser->getObjL(&obj2);
  534.     parser->getObjL(&obj3);
  535.     if (obj1.isInt() && obj1.getInt() == num &&
  536.     obj2.isInt() && obj2.getInt() == gen &&
  537.     obj3.isCmd("obj")) {
  538.       if (encrypted) {
  539.         parser->getEncryptedObjL(obj, num, gen);
  540.       } else {
  541.         parser->getObjL(obj);
  542.       }
  543.     } else {
  544.       obj->initNull();
  545.     }
  546.     obj1.free();
  547.     obj2.free();
  548.     obj3.free();
  549.     CleanupStack::PopAndDestroy(); // delete parser;
  550.   } else {
  551.     obj->initNull();
  552.   }
  553.   return obj;
  554. }
  555.  
  556. Object *XRef::getDocInfoL(Object *obj) {
  557.   return trailerDict.dictLookupL("Info", obj);
  558. }
  559.  
  560.  
  561. GBool XRef::setupDecryptionL() {
  562.   RAutoObject obj;
  563.   //GBool encrypted;
  564.   //GBool passwordOk;
  565.   GString* userPassword;
  566.  
  567.   // check filter
  568.   encryptionDict.dictLookupNFL("Filter", &obj);
  569.   if (!obj.isName()) {
  570.     error(-1, R_NO_FILTER_SPECIFIED__ASSUME_STANDARD_FILTER);
  571.   } else if (strcmp(obj.getName(), "Standard") != 0) {
  572.      error(-1, R_FILE_IS_ENCRYPTED_WITH_A_NON_STANDARD_FILTER);
  573.     obj.free();
  574.     return gFalse;
  575.   }
  576.   obj.free();
  577.  
  578.   // check for no user password
  579.   userPassword = GString::NewLC();
  580.   if (checkUserPasswordL(userPassword) == gFalse) {
  581.     // ask for user password  ...  check with user password
  582.     error(-1, R_PDF_FILE_IS_ENCRYPTED_WITH_A_USER_PASSWORD);
  583.     CleanupStack::PopAndDestroy(); // userPassword
  584.     return gFalse;
  585.   }
  586.   CleanupStack::PopAndDestroy(); // userPassword
  587.   userPassword = 0;
  588.  
  589.   // set permissions
  590.   encryptionDict.dictLookupNFL("P", &obj);
  591.   if (obj.isNull() || !obj.isInt()) {
  592.     error(-1, R_NO_PERMISSIONS_SPECIFIED);
  593.     return gFalse;
  594.   }
  595.   int Permissions = obj.getInt();
  596.   obj.free();
  597.   m_okToPrint = Permissions & 0x04 ? gTrue : gFalse;
  598.   m_okToChange = Permissions & 0x08 ? gTrue : gFalse;
  599.   m_okToCopy = Permissions & 0x10 ? gTrue : gFalse;
  600.   m_okToAddNotes = Permissions & 0x20 ? gTrue : gFalse;
  601.  
  602.   return gTrue;
  603. }
  604.  
  605. GBool
  606. XRef::checkUserPasswordL(GString *userPassword)
  607. {
  608.   GString* preparedPassword = GString::NewLC();
  609.   RC4KEY rc4Key;
  610.   RAutoObject obj;
  611.   char localPassword[32];
  612.  
  613.   if (preparePasswordL(userPassword, preparedPassword) == gFalse) {
  614.     CleanupStack::PopAndDestroy(); // preparedPassword
  615.     return gFalse;
  616.   }
  617.   if (MakeEncryptionKeyL(preparedPassword, encryptionKey) == gFalse) {
  618.      CleanupStack::PopAndDestroy(); // preparedPassword
  619.     return gFalse;
  620.   }
  621.   // get the User password
  622.   encryptionDict.dictLookupNFL("U", &obj);
  623.   if (obj.isNull() || !obj.isString()) {
  624.     error(-1, R_NO_USER_PASSWORD_SPECIFIED);
  625.     CleanupStack::PopAndDestroy(); // preparedPassword
  626.     return gFalse;
  627.   }
  628.   Mem::Copy(localPassword, obj.getString()->getCString(), 32);
  629.   obj.free();
  630.   // prepary RC4 key
  631.   rc4ExpandKey(&rc4Key, (unsigned char *)encryptionKey->getCString(), 5);
  632.   // encrypt User password
  633.   rc4Crypt(&rc4Key, (unsigned char *)&localPassword[0], 32);
  634.   // compare preparedPassword and decryptedPassword
  635.   for (int i=0; i<32; i++) {
  636.     if (localPassword[i] != preparedPassword->getChar(i)) {
  637.       // not equal
  638.       CleanupStack::PopAndDestroy(); // preparedPassword
  639.       return gFalse;
  640.     }
  641.   }
  642.   
  643.   CleanupStack::PopAndDestroy(); // preparedPassword
  644.   // password OK
  645.   return gTrue;
  646. }
  647.  
  648. GBool
  649. XRef::MakeEncryptionKeyL(GString *password, GString *encryptionKey)
  650. {
  651.   MD5 context;
  652.   RAutoObject obj, obj1;
  653.   unsigned char Pkey[4];
  654.  
  655.   context.update((unsigned char *)password->getCString(), 32);
  656.   // others  owner key
  657.   encryptionDict.dictLookupNFL("O", &obj);
  658.   if (obj.isNull() || !obj.isString()) {
  659.     error(-1, R_NO_OWNER_PASSWORD_SPECIFIED);
  660.     return gFalse;
  661.   }
  662.   context.update((unsigned char *)obj.getString()->getCString(), 32);
  663.   obj.free();
  664.   // permissions
  665.   encryptionDict.dictLookupNFL("P", &obj);
  666.   if (obj.isNull() || !obj.isInt()) {
  667.     error(-1, R_NO_PERMISSIONS_SPECIFIED);
  668.     return gFalse;
  669.   }
  670.   int Permissions = obj.getInt();
  671.   Pkey[0] = Guchar( Permissions        & 0xff);
  672.   Pkey[1] = Guchar((Permissions >> 8 ) & 0xff);
  673.   Pkey[2] = Guchar((Permissions >> 16) & 0xff);
  674.   Pkey[3] = Guchar((Permissions >> 24) & 0xff);
  675.   context.update(&Pkey[0], 4);
  676.   obj.free();
  677.   // first element from ID
  678.   trailerDict.dictLookupNFL("ID", &obj);
  679.   if (obj.isNull() || !obj.isArray()) {
  680.     error(-1, R_NO_ID_SPECIFIED);
  681.     return gFalse;
  682.   }
  683.   obj.arrayGetL(0, &obj1);
  684.   if (obj1.isNull() || !obj1.isString()) {
  685.     error(-1, R_NO_ID_ELEMENTS_SPECIFIED);
  686.     return gFalse;
  687.   }
  688.   context.update((unsigned char *)(obj1.getString()->getCString()), (int)(obj1.getString()->getLength()));
  689.   obj1.free();
  690.   obj.free();
  691.   context.finalize();
  692.   encryptionKey->clearL();
  693.   char *p = (char *)context.raw_digestL();
  694.   CleanupStack::PushL(p);
  695.   encryptionKey->appendL(p,5);
  696.   CleanupStack::PopAndDestroy(); // delete p;
  697.   return gTrue;
  698. }
  699.  
  700. GBool
  701. XRef::preparePasswordL(GString *password, GString *preparedPassword)
  702. {
  703.   static const char acFill[32] = {'\x28', '\xbf', '\x4e', '\x5e', '\x4e', '\x75', '\x8a', '\x41',
  704.                             '\x64', '\x00', '\x4e', '\x56', '\xff', '\xfa', '\x01', '\x08',
  705.                               '\x2e', '\x2e', '\x00', '\xb6', '\xd0', '\x68', '\x3e', '\x80',
  706.                               '\x2f', '\x0c', '\xa9', '\xfe', '\x64', '\x53', '\x69', '\x7a'};
  707.   preparedPassword->clearL();
  708.   preparedPassword->appendL(password);
  709.   preparedPassword->appendL(&acFill[0], 32);
  710.   return gTrue;
  711. }
  712.