bool OCGs::optContentIsVisible( Object *dictRef ) { Object dictObj; Dict *dict; Object dictType; Object ocg; Object policy; bool result = true; dictRef->fetch( m_xref, &dictObj ); if ( ! dictObj.isDict() ) { error(-1, "Unexpected oc reference target: %i", dictObj.getType() ); dictObj.free(); return result; } dict = dictObj.getDict(); // printf("checking if optContent is visible\n"); dict->lookup("Type", &dictType); if (dictType.isName("OCMD")) { // If we supported Visibility Expressions, we'd check // for a VE entry, and then call out to the parser here... // printf("found OCMD dict\n"); dict->lookup("P", &policy); dict->lookupNF("OCGs", &ocg); if (ocg.isArray()) { if (policy.isName("AllOn")) { result = allOn( ocg.getArray() ); } else if (policy.isName("AllOff")) { result = allOff( ocg.getArray() ); } else if (policy.isName("AnyOff")) { result = anyOff( ocg.getArray() ); } else if ( (!policy.isName()) || (policy.isName("AnyOn") ) ) { // this is the default result = anyOn( ocg.getArray() ); } } else if (ocg.isRef()) { OptionalContentGroup* oc = findOcgByRef( ocg.getRef() ); if ( !oc || oc->getState() == OptionalContentGroup::Off ) { result = false; } else { result = true ; } } ocg.free(); policy.free(); } else if ( dictType.isName("OCG") ) { OptionalContentGroup* oc = findOcgByRef( dictRef->getRef() ); if ( !oc || oc->getState() == OptionalContentGroup::Off ) { result=false; } } dictType.free(); dictObj.free(); // printf("visibility: %s\n", result? "on" : "off"); return result; }
void AnnotWriter::UpdateBePDFAcroForm() { if (mWrittenFonts.empty()) return; Object acroForm; Object oldDR; acroForm.initDict(mXRef); oldDR.initNull(); if (is_empty_ref(mBePDFAcroForm->GetRef())) { Ref fieldsRef = mXRefTable.GetNewRef(xrefEntryUncompressed); // create empty array for fields Object fields; fields.initArray(mXRef); WriteObject(fieldsRef, &fields); fields.free(); // create new BePDFAcroForm mBePDFAcroFormRef = mXRefTable.GetNewRef(xrefEntryUncompressed); AddName(&acroForm, "Type", "BePDFAcroForm"); AddRef(&acroForm, "Fields", fieldsRef); } else { // copy existing BePDFAcroForm except DR mBePDFAcroFormRef = mBePDFAcroForm->GetRef(); Object ref; Object oldForm; ref.initRef(mBePDFAcroFormRef.num, mBePDFAcroFormRef.gen); ref.fetch(mXRef, &oldForm); CopyDict(&oldForm, &acroForm, acroFormExcludeKeys); oldForm.dictLookup("DR", &oldDR); oldForm.free(); ref.free(); } // Add DR to BePDFAcroForm Object dr; dr.initDict(mXRef); if (oldDR.isDict()) { CopyDict(&oldDR, &dr, drExcludeKeys); oldDR.free(); } // Add font dict Object font; font.initDict(mXRef); // add old fonts AddFonts(&font, mBePDFAcroForm->GetFonts()); // add new fonts AddFonts(&font, &mWrittenFonts); AddDict(&dr, "Font", &font); AddDict(&acroForm, "DR", &dr); WriteObject(mBePDFAcroFormRef, &acroForm); acroForm.free(); }
void AnnotWriter::CopyInfoDict(Object* dict) { ASSERT(!is_empty_ref(mInfoRef)); Object info; mXRef->getTrailerDict()->dictLookup("Info", &info); CopyDict(&info, dict, infoDictExcludeKeys); info.free(); }
bool AnnotWriter::UpdatePage(int pageNo, Annotations* annots, Ref& annotArray) { bool ok = false; Object page; Ref* pageRef = mDoc->getCatalog()->getPageRef(pageNo+1); if (!mXRef->fetch(pageRef->num, pageRef->gen, &page)->isNull()) { if (HasAnnotRef(&page, annotArray)) return true; annotArray = mXRefTable.GetNewRef(xrefEntryUncompressed); if (HasEmbeddedContent(&page)) { if (!CopyContentStream(&page)) { fprintf(stderr, "Error: Could not copy content stream!"); goto error; } } if (!CopyPage(&page, *pageRef, annotArray)) { fprintf(stderr, "Error: Could not copy page!"); } else { ok = true; } } else { fprintf(stderr, "Error: Could not get page dict for page %d\n", pageNo+1); } error: page.free(); return ok; }
SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) { Object filterObj; SecurityHandler *secHdlr; #ifdef ENABLE_PLUGINS XpdfSecurityHandler *xsh; #endif encryptDictA->dictLookup("Filter", &filterObj); if (filterObj.isName("Standard")) { secHdlr = new StandardSecurityHandler(docA, encryptDictA); } else if (filterObj.isName()) { #ifdef ENABLE_PLUGINS if ((xsh = globalParams->getSecurityHandler(filterObj.getName()))) { secHdlr = new ExternalSecurityHandler(docA, encryptDictA, xsh); } else { #endif error(-1, "Couldn't find the '%s' security handler", filterObj.getName()); secHdlr = NULL; #ifdef ENABLE_PLUGINS } #endif } else { error(-1, "Missing or invalid 'Filter' entry in encryption dictionary"); secHdlr = NULL; } filterObj.free(); return secHdlr; }
/* * Функция videomaker_fnc() реализует поток записи видео с камеры робота в файл. * @ptr - указатель на структуру System. * Начинает запись видео, если поле videomaker объекта ptr истина */ void* videomaker_fnc(void *ptr) { System &syst = *((System *)ptr); VideoMaker clip; Object<Mat> *curObj = NULL; Queue<Mat> &queue = syst.queue; if(!syst.videomaker) { return NULL; } else { LOG("[I]: VideoMaker started."); } if(!clip.init(syst)) { LOG("[E]: Videomaker: Can't open output stream."); //chmod or codecs problem??? exit(EXIT_FAILURE); } while(1) { curObj = queue.waitForNewObject(curObj); clip.write(*(curObj->obj)); curObj->free(); } clip.deinit(); return NULL; }
Links *PageRenderer::CreateLinks(int pageNo) { Page *page = mDoc->getCatalog()->getPage(pageNo); Object obj; Links *links = new Links(page->getAnnots(&obj), mDoc->getCatalog()->getBaseURI()); obj.free(); return links; }
void JPXStream::init() { Object oLen; if (getDict()) getDict()->lookup("Length", &oLen); int bufSize = BUFFER_INCREASE; if (oLen.isInt()) bufSize = oLen.getInt(); oLen.free(); unsigned char *buf = (unsigned char*)gmallocn(bufSize, sizeof(unsigned char)); int index = 0; str->reset(); int c = str->getChar(); while(c != EOF) { if (index >= bufSize) { bufSize += BUFFER_INCREASE; buf = (unsigned char*)greallocn(buf, bufSize, sizeof(unsigned char)); } buf[index] = c; ++index; c = str->getChar(); } init2(buf, index, CODEC_JP2); free(buf); counter = 0; inited = gTrue; }
bool AnnotWriter::HasEmbeddedContent(Object* page) { ASSERT(page && page->isDict()); Object obj; bool embedded = !(page->dictLookupNF("Contents", &obj) && (obj.isArray() || obj.isRef() || obj.isNull())); obj.free(); return embedded; }
GooList *OutlineItem::readItemList(Object *firstItemRef, Object *lastItemRef, XRef *xrefA) { GooList *items; char* alreadyRead; OutlineItem *item; Object obj; Object *p; if (!lastItemRef->isRef()) return NULL; items = new GooList(); alreadyRead = (char *)gmalloc(xrefA->getNumObjects()); memset(alreadyRead, 0, xrefA->getNumObjects()); p = firstItemRef; while (p->isRef() && (p->getRefNum() >= 0) && (p->getRefNum() < xrefA->getNumObjects()) && !alreadyRead[p->getRefNum()]) { if (!p->fetch(xrefA, &obj)->isDict()) { obj.free(); break; } alreadyRead[p->getRefNum()] = 1; item = new OutlineItem(obj.getDict(), xrefA); obj.free(); items->append(item); if (p->getRef().num == lastItemRef->getRef().num && p->getRef().gen == lastItemRef->getRef().gen) { break; } p = &item->nextRef; } gfree(alreadyRead); if (!items->getLength()) { delete items; items = NULL; } return items; }
void AnnotWriter::WriteModDate(Ref ref) { GString* date = new GString(); AnnotUtils::CurrentDate(date); Object obj; obj.initString(date); WriteObject(ref, &obj); obj.free(); // frees date }
Annotations* PageRenderer::GetAnnotationsForPage(int pageNo) { int i = pageNo-1; if (mAnnotations.Get(i) == NULL) { Object annotsDict; mDoc->getCatalog()->getPage(pageNo)->getAnnots(&annotsDict); mAnnotations.Set(i, new Annotations(&annotsDict, mBePDFAcroForm)); annotsDict.free(); } return mAnnotations.Get(i); }
void AnnotWriter::UpdateCatalog() { // Return if BePDFAcroForm has not been written or ref exists already in Catalog if (is_empty_ref(mBePDFAcroFormRef) || !is_empty_ref(mBePDFAcroForm->GetRef())) return; // Copy catalog and add ref to new BePDFAcroForm Ref root; Object oldCatalogRef; Object oldCatalog; Object catalog; root.num = mXRef->getRootNum(); root.gen = mXRef->getRootGen(); oldCatalogRef.initRef(root.num, root.gen); oldCatalogRef.fetch(mXRef, &oldCatalog); catalog.initDict(mXRef); CopyDict(&oldCatalog, &catalog); AddRef(&catalog, "BePDFAcroForm", mBePDFAcroFormRef); WriteObject(root, &catalog); catalog.free(); oldCatalog.free(); oldCatalogRef.free(); }
OptionalContentGroup::OptionalContentGroup(Dict *ocgDict) : m_name(NULL) { Object ocgName; ocgDict->lookup("Name", &ocgName); if (!ocgName.isString()) { error(-1, "Expected the name of the OCG, but wasn't able to find it, or it isn't a String"); } else { m_name = new GooString( ocgName.getString() ); } ocgName.free(); }
/** The transition from this page to the next one. If it is set, then a PDF viewer in a presentation should perform the specified transition effect when switching from this page to the next one. \returns the transition effect for the switch to the next page, if any */ page_transition* page::transition() const { if (!d->transition) { Object o; if (d->page->getTrans(&o)->isDict()) { d->transition = new page_transition(&o); } o.free(); } return d->transition; }
/** \returns all the information keys available in the %document \see info_key, info_date */ std::vector<std::string> document::info_keys() const { if (d->is_locked) { return std::vector<std::string>(); } Object info; if (!d->doc->getDocInfo(&info)->isDict()) { info.free(); return std::vector<std::string>(); } Dict *info_dict = info.getDict(); std::vector<std::string> keys(info_dict->getLength()); for (int i = 0; i < info_dict->getLength(); ++i) { keys[i] = std::string(info_dict->getKey(i)); } info.free(); return keys; }
bool AnnotWriter::CopyPage(Object* page, Ref pageRef, Ref arrayRef) { Object copy; Object ar; ar.initRef(arrayRef.num, arrayRef.gen); CopyDict(page, ©, pageDictExcludeKeys); copy.dictAdd(copyString("Annots"), &ar); // write to file WriteObject(pageRef, ©); copy.free(); return true; }
bool AnnotWriter::HasRef(Object* dict, const char* key, Ref &ref) { Object obj; bool ok = true; ASSERT(dict && dict->isDict()); if (dict->dictLookupNF((char*)key, &obj) && obj.isRef()) { ref = obj.getRef(); } else { ref = empty_ref; ok = false; } obj.free(); return ok; }
/** Gets the time_t value value of the specified \p key of the document information. \returns the time_t value for the \p key \see info_keys, info_date */ time_type document::info_date(const std::string &key) const { if (d->is_locked) { return time_type(-1); } Object info; if (!d->doc->getDocInfo(&info)->isDict()) { info.free(); return time_type(-1); } Dict *info_dict = info.getDict(); Object obj; time_type result = time_type(-1); if (info_dict->lookup(PSTR(key.c_str()), &obj)->isString()) { result = detail::convert_date(obj.getString()->getCString()); } obj.free(); info.free(); return result; }
/** Gets the value of the specified \p key of the document information. \returns the value for the \p key, or an empty string if not available \see info_keys, info_date */ ustring document::info_key(const std::string &key) const { if (d->is_locked) { return ustring(); } Object info; if (!d->doc->getDocInfo(&info)->isDict()) { info.free(); return ustring(); } Dict *info_dict = info.getDict(); Object obj; ustring result; if (info_dict->lookup(PSTR(key.c_str()), &obj)->isString()) { result = detail::unicode_GooString_to_ustring(obj.getString()); } obj.free(); info.free(); return result; }
void AnnotWriter::WriteFont(PDFFont* font) { if (!is_empty_ref(font->GetRef())) return; // already saved font->SetRef(mXRefTable.GetNewRef(xrefEntryUncompressed)); mWrittenFonts.push_back(font); Object dict; dict.initDict(mXRef); AddName(&dict, "Type", "Font"); AddName(&dict, "Subtype", "Type1"); AddName(&dict, "BaseFont", (char*)font->GetName()); AddName(&dict, "Encoding", "WinAnsiEncoding"); WriteObject(font->GetRef(), &dict); dict.free(); }
bool AnnotWriter::UpdateAnnotArray(int pageNo, Annotations* annots, Ref annotArray) { ASSERT(annots->HasChanged()); Object array; array.initArray(mXRef); for (int i = 0; i < annots->Length(); i++) { Annotation* a = annots->At(i); if (!a->IsDeleted()) { AddToAnnots(&array, a); if (a->GetPopup()) AddToAnnots(&array, a->GetPopup()); } } // write to file WriteObject(annotArray, &array); array.free(); return true; }
bool AnnotWriter::WriteFileTrailer() { Write("trailer\r"); Object trailer; Object val; CopyDict(mXRef->getTrailerDict(), &trailer, fileTrailerExcludeKeys); trailer.dictAdd(copyString("Size"), val.initInt(mXRefTable.GetSize())); trailer.dictAdd(copyString("Prev"), val.initInt(mXRef->getLastXRefPos())); trailer.dictAdd(copyString("Root"), val.initRef(mXRef->getRootNum(), mXRef->getRootGen())); trailer.dictAdd(copyString("Info"), val.initRef(mInfoRef.num, mInfoRef.gen)); WriteObject(&trailer); Write("\rstartxref\r"); fprintf(mFile, "%d\r", mXRefOffset); Write("%%EOF\r"); trailer.free(); return true; }
Epdf_Document * epdf_document_new (const char *filename) { Epdf_Document *doc; if (!filename) return NULL; doc = (Epdf_Document *)malloc (sizeof (Epdf_Document)); if (!doc) return NULL; if (!globalParams) globalParams = new GlobalParams(); doc->pdfdoc = new PDFDoc (new GooString (filename), NULL); if (doc->pdfdoc->isOk() || doc->pdfdoc->getErrorCode() == errEncrypted) { Object obj; if (doc->pdfdoc->getErrorCode() == errEncrypted) doc->locked = true; else doc->locked = false; doc->scanner = new FontInfoScanner(doc->pdfdoc); doc->pdfdoc->getDocInfo (&obj); if (!obj.isDict ()) { obj.free (); free (doc); return NULL; } doc->dict = obj.getDict(); return doc; } free (doc); return NULL; }
void BepdfApplication::UpdateFileAttributes(PDFDoc *doc, entry_ref *ref) { BNode node(ref); if (node.InitCheck() != B_OK) return; const bool force_overwrite = (modifiers() & B_COMMAND_KEY) == B_COMMAND_KEY; if (force_overwrite) { for (int i = 0; gAttrInfo[i].name; i++) { node.RemoveAttr(gAttrInfo[i].name); } } int32 pages = (int32)doc->getNumPages(); UpdateAttr(node, "META:pages", B_INT32_TYPE, 0, &pages, sizeof(int32)); bool b = doc->isLinearized(); UpdateAttr(node, "PDF:linearized", B_BOOL_TYPE, 0, &b, sizeof(b)); double d = doc->getPDFVersion(); UpdateAttr(node, "PDF:version", B_DOUBLE_TYPE, 0, &d, sizeof(d)); Object obj; if (doc->getDocInfo(&obj) && obj.isDict()) { Dict *dict = obj.getDict(); for (int i = 0; gAttrInfo[i].name; i++) { time_t time; if (gAttrInfo[i].pdf_name == NULL) continue; BString *s = FileInfoWindow::GetProperty(dict, gAttrInfo[i].pdf_name, &time); if (s) { if (gAttrInfo[i].type_code == B_TIME_TYPE) { if (time != 0) { UpdateAttr(node, gAttrInfo[i].name, B_TIME_TYPE, 0, &time, sizeof(time)); } } else { UpdateAttr(node, gAttrInfo[i].name, B_STRING_TYPE, 0, (void*)s->String(), s->Length()+1); } delete s; } } } obj.free(); }
bool AnnotWriter::WriteAS(Ref& ref, Annotation* a) { if (is_empty_ref(ref)) return true; Object xobj; xobj.initDict(mXRef); // setup XObject dictionary AddName(&xobj, "Type", "XObject"); AddName(&xobj, "Subtype", "Form"); AddInteger(&xobj, "FormType", 1); PDFRectangle r = *a->GetRect(); r.x2 -= r.x1; r.y2 -= r.y1; r.x1 = r.y1 = 0; AddRect(&xobj, "BBox", &r); // setup resource dictionary Object resources, array, name; resources.initDict(mXRef); array.initArray(mXRef); name.initName("PDF"); array.arrayAdd(&name); resources.dictAdd(copyString("ProcSet"), &array); xobj.dictAdd(copyString("Resources"), &resources); // create appearance stream AnnotAppearance as; a->Visit(&as); // set length AddInteger(&xobj, "Length", as.GetLength()); ASSERT(as.GetLength() > 0); // write form XObject WriteObject(ref, &xobj, as.GetStream()); xobj.free(); ref = empty_ref; return true; }
// ----------------------------------------------------------------------------- static void printInfoString(Dict *infoDict, char *key, char *text, UnicodeMap *uMap) { Object obj; GooString *s1; GBool isUnicode; Unicode u; char buf[8]; int i, n; if (infoDict->lookup(key, &obj)->isString()) { fputs(text, stdout); s1 = obj.getString(); if ((s1->getChar(0) & 0xff) == 0xfe && (s1->getChar(1) & 0xff) == 0xff) { isUnicode = gTrue; i = 2; } else { isUnicode = gFalse; i = 0; } while (i < obj.getString()->getLength()) { if (isUnicode) { u = ((s1->getChar(i) & 0xff) << 8) | (s1->getChar(i+1) & 0xff); i += 2; } else { u = pdfDocEncoding[s1->getChar(i) & 0xff]; ++i; } n = uMap->mapUnicode(u, buf, sizeof(buf)); fwrite(buf, 1, n, stdout); } fputc('\n', stdout); } obj.free(); }
static void printInfoDate(Dict *infoDict, char *key, char *text) { Object obj; char *s; int year, mon, day, hour, min, sec, tz_hour, tz_minute; char tz; struct tm tmStruct; char buf[256]; if (infoDict->lookup(key, &obj)->isString()) { fputs(text, stdout); s = obj.getString()->getCString(); // TODO do something with the timezone info if ( parseDateString( s, &year, &mon, &day, &hour, &min, &sec, &tz, &tz_hour, &tz_minute ) ) { tmStruct.tm_year = year - 1900; tmStruct.tm_mon = mon - 1; tmStruct.tm_mday = day; tmStruct.tm_hour = hour; tmStruct.tm_min = min; tmStruct.tm_sec = sec; tmStruct.tm_wday = -1; tmStruct.tm_yday = -1; tmStruct.tm_isdst = -1; // compute the tm_wday and tm_yday fields if (mktime(&tmStruct) != (time_t)-1 && strftime(buf, sizeof(buf), "%c", &tmStruct)) { fputs(buf, stdout); } else { fputs(s, stdout); } } else { fputs(s, stdout); } fputc('\n', stdout); } obj.free(); }
OCGs::OCGs(Object *ocgObject, XRef *xref) : m_xref(xref) { // we need to parse the dictionary here, and build optionalContentGroups ok = gTrue; optionalContentGroups = new GooList(); Object ocgList; ocgObject->dictLookup("OCGs", &ocgList); if (!ocgList.isArray()) { error(-1, "Expected the optional content group list, but wasn't able to find it, or it isn't an Array"); ocgList.free(); ok = gFalse; return; } // we now enumerate over the ocgList, and build up the optionalContentGroups list. for(int i = 0; i < ocgList.arrayGetLength(); ++i) { Object ocg; ocgList.arrayGet(i, &ocg); if (!ocg.isDict()) { ocg.free(); break; } OptionalContentGroup *thisOptionalContentGroup = new OptionalContentGroup(ocg.getDict()); ocg.free(); ocgList.arrayGetNF(i, &ocg); // TODO: we should create a lookup map from Ref to the OptionalContentGroup thisOptionalContentGroup->setRef( ocg.getRef() ); ocg.free(); // the default is ON - we change state later, depending on BaseState, ON and OFF thisOptionalContentGroup->setState(OptionalContentGroup::On); optionalContentGroups->append(thisOptionalContentGroup); } Object defaultOcgConfig; ocgObject->dictLookup("D", &defaultOcgConfig); if (!defaultOcgConfig.isDict()) { error(-1, "Expected the default config, but wasn't able to find it, or it isn't a Dictionary"); defaultOcgConfig.free(); ocgList.free(); ok = gFalse; return; } #if 0 // this is untested - we need an example showing BaseState Object baseState; defaultOcgConfig.dictLookup("BaseState", &baseState); if (baseState.isString()) { // read the value, and set each OptionalContentGroup entry appropriately } baseState.free(); #endif Object on; defaultOcgConfig.dictLookup("ON", &on); if (on.isArray()) { // ON is an optional element for (int i = 0; i < on.arrayGetLength(); ++i) { Object reference; on.arrayGetNF(i, &reference); if (!reference.isRef()) { // there can be null entries reference.free(); break; } OptionalContentGroup *group = findOcgByRef( reference.getRef() ); reference.free(); if (!group) { error(-1, "Couldn't find group for reference"); break; } group->setState(OptionalContentGroup::On); } } on.free(); Object off; defaultOcgConfig.dictLookup("OFF", &off); if (off.isArray()) { // OFF is an optional element for (int i = 0; i < off.arrayGetLength(); ++i) { Object reference; off.arrayGetNF(i, &reference); if (!reference.isRef()) { // there can be null entries reference.free(); break; } OptionalContentGroup *group = findOcgByRef( reference.getRef() ); reference.free(); if (!group) { error(-1, "Couldn't find group for reference to set OFF"); break; } group->setState(OptionalContentGroup::Off); } } off.free(); defaultOcgConfig.dictLookup("Order", &order); defaultOcgConfig.dictLookup("RBGroups", &rbgroups); ocgList.free(); defaultOcgConfig.free(); }
StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA, Object *encryptDictA): SecurityHandler(docA) { Object versionObj, revisionObj, lengthObj; Object ownerKeyObj, userKeyObj, permObj, fileIDObj; Object fileIDObj1; Object cryptFiltersObj, streamFilterObj, stringFilterObj; Object cryptFilterObj, cfmObj, cfLengthObj; Object encryptMetadataObj; ok = gFalse; fileID = NULL; ownerKey = NULL; userKey = NULL; encryptDictA->dictLookup("V", &versionObj); encryptDictA->dictLookup("R", &revisionObj); encryptDictA->dictLookup("Length", &lengthObj); encryptDictA->dictLookup("O", &ownerKeyObj); encryptDictA->dictLookup("U", &userKeyObj); encryptDictA->dictLookup("P", &permObj); doc->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj); if (versionObj.isInt() && revisionObj.isInt() && ownerKeyObj.isString() && ownerKeyObj.getString()->getLength() == 32 && userKeyObj.isString() && userKeyObj.getString()->getLength() == 32 && permObj.isInt()) { encVersion = versionObj.getInt(); encRevision = revisionObj.getInt(); encAlgorithm = cryptRC4; // revision 2 forces a 40-bit key - some buggy PDF generators // set the Length value incorrectly if (encRevision == 2 || !lengthObj.isInt()) { fileKeyLength = 5; } else { fileKeyLength = lengthObj.getInt() / 8; } encryptMetadata = gTrue; //~ this currently only handles a subset of crypt filter functionality if (encVersion == 4 && encRevision == 4) { encryptDictA->dictLookup("CF", &cryptFiltersObj); encryptDictA->dictLookup("StmF", &streamFilterObj); encryptDictA->dictLookup("StrF", &stringFilterObj); if (cryptFiltersObj.isDict() && streamFilterObj.isName() && stringFilterObj.isName() && !strcmp(streamFilterObj.getName(), stringFilterObj.getName())) { if (cryptFiltersObj.dictLookup(streamFilterObj.getName(), &cryptFilterObj)->isDict()) { cryptFilterObj.dictLookup("CFM", &cfmObj); if (cfmObj.isName("V2")) { encVersion = 2; encRevision = 3; if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) { //~ according to the spec, this should be cfLengthObj / 8 fileKeyLength = cfLengthObj.getInt(); } cfLengthObj.free(); } else if (cfmObj.isName("AESV2")) { encVersion = 2; encRevision = 3; encAlgorithm = cryptAES; if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) { //~ according to the spec, this should be cfLengthObj / 8 fileKeyLength = cfLengthObj.getInt(); } cfLengthObj.free(); } cfmObj.free(); } cryptFilterObj.free(); } stringFilterObj.free(); streamFilterObj.free(); cryptFiltersObj.free(); if (encryptDictA->dictLookup("EncryptMetadata", &encryptMetadataObj)->isBool()) { encryptMetadata = encryptMetadataObj.getBool(); } encryptMetadataObj.free(); } permFlags = permObj.getInt(); ownerKey = ownerKeyObj.getString()->copy(); userKey = userKeyObj.getString()->copy(); if (encVersion >= 1 && encVersion <= 2 && encRevision >= 2 && encRevision <= 3) { if (fileIDObj.isArray()) { if (fileIDObj.arrayGet(0, &fileIDObj1)->isString()) { fileID = fileIDObj1.getString()->copy(); } else { fileID = new GooString(); } fileIDObj1.free(); } else { fileID = new GooString(); } ok = gTrue; } else { error(-1, "Unsupported version/revision (%d/%d) of Standard security handler", encVersion, encRevision); } } else { error(-1, "Weird encryption info"); } if (fileKeyLength > 16) { fileKeyLength = 16; } fileIDObj.free(); permObj.free(); userKeyObj.free(); ownerKeyObj.free(); lengthObj.free(); revisionObj.free(); versionObj.free(); }