Parsing PDF documents with Quartz - ios

I am trying to parse a PDF document with the Quartz framework and have copy & pasted the code snippets from the Apple documentation into my source code.
Unfortunately, it does not retrieve any data. It just iterates over the pages, logs the number of the current page to the console and crashes at the end.
Do you have any idea on what is wrong with the code?
static void op_MP (CGPDFScannerRef s, void *info)
{
const char *name;
if (!CGPDFScannerPopName(s, &name))
return;
printf("MP /%s\n", name);
}
static void op_DP (CGPDFScannerRef s, void *info)
{
const char *name;
if (!CGPDFScannerPopName(s, &name))
return;
NSLog(#"DP /%s\n", name);
}
static void op_BMC (CGPDFScannerRef s, void *info)
{
const char *name;
if (!CGPDFScannerPopName(s, &name))
return;
NSLog(#"BMC /%s\n", name);
}
static void op_BDC (CGPDFScannerRef s, void *info)
{
const char *name;
if (!CGPDFScannerPopName(s, &name))
return;
NSLog(#"BDC /%s\n", name);
}
static void op_EMC (CGPDFScannerRef s, void *info)
{
const char *name;
if (!CGPDFScannerPopName(s, &name))
return;
NSLog(#"EMC /%s\n", name);
}
static void op_TJ (CGPDFScannerRef s, void *info)
{
const char *name;
if (!CGPDFScannerPopName(s, &name))
return;
NSLog(#"TJ /%s\n", name);
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
CGPDFDocumentRef myDocument;
NSString *urlAddress = [[NSBundle mainBundle] pathForResource:#"test" ofType:#"pdf"];
NSURL *fileUrl = [NSURL fileURLWithPath:urlAddress];
CFURLRef url = (__bridge CFURLRef)fileUrl;
myDocument = CGPDFDocumentCreateWithURL(url);
CFRelease (url);
if (myDocument == NULL) {// 2
NSLog(#"can't open `%#'.", fileUrl);
}
if (!CGPDFDocumentIsUnlocked (myDocument)) {// 4
CGPDFDocumentRelease(myDocument);
}
else if (CGPDFDocumentGetNumberOfPages(myDocument) == 0) {// 5
CGPDFDocumentRelease(myDocument);
}
else {
CGPDFOperatorTableRef myTable;
myTable = CGPDFOperatorTableCreate();
CGPDFOperatorTableSetCallback (myTable, "MP", &op_MP);
CGPDFOperatorTableSetCallback (myTable, "DP", &op_DP);
CGPDFOperatorTableSetCallback (myTable, "BMC", &op_BMC);
CGPDFOperatorTableSetCallback (myTable, "BDC", &op_BDC);
CGPDFOperatorTableSetCallback (myTable, "EMC", &op_EMC);
CGPDFOperatorTableSetCallback (myTable, "Tj", &op_TJ);
int k;
CGPDFPageRef myPage;
CGPDFScannerRef myScanner;
CGPDFContentStreamRef myContentStream;
int numOfPages = CGPDFDocumentGetNumberOfPages (myDocument);// 1
for (k = 0; k < numOfPages; k++) {
myPage = CGPDFDocumentGetPage (myDocument, k + 1 );// 2
myContentStream = CGPDFContentStreamCreateWithPage (myPage);// 3
myScanner = CGPDFScannerCreate (myContentStream, myTable, NULL);// 4
CGPDFScannerScan (myScanner);// 5
CGPDFPageRelease (myPage);// 6
CGPDFScannerRelease (myScanner);// 7
CGPDFContentStreamRelease (myContentStream);// 8
NSLog(#"processed page %i",k);
}
CGPDFOperatorTableRelease(myTable);
CGPDFDocumentRelease(myDocument);
}
return YES;
}

I did not run the code but the first 5 operators might not exist in your page content. Also some of them have a name operand, some of them do not have any operands (such as EMC). Also the Tj operator has a string operand, not a name.
Remove all the pop name methods and leave only the logging and you might get some output. Then look in the PDF specification to see the exact operands for each operator and update your code accordingly.

While I can't give you a solution to your example code crash, last time we needed to do this we based our parser on PDFKitten.
https://github.com/KurtCode/PDFKitten
If you are interested in the parsing code, the interesting stuff is located in Scanner.m:
https://github.com/KurtCode/PDFKitten/blob/master/PDFKitten/Scanner.m
Given the complexity of PDF parsing I would suggest working with this library as a base and moving from there. If you need a polished implementation on a deadline, then PSPDFKit is probably the most well-developed (but expensive) package.

It's about the CFRelease(url). Delete it and it will be okay.
"(__bridge T) op casts the operand to the destination type T. If T is a retainable object pointer type, then op must have a non-retainable pointer type."

Related

How to hook Apple's `os_log_with_type` method in Objective-C

I want to hook "React Native" RCTLog logs method _RCTLogJavaScriptInternal , The source codes is:
void _RCTLogJavaScriptInternal(RCTLogLevel level, NSString *message)
{
RCTLogFunction logFunction = RCTGetLocalLogFunction();
BOOL log = RCT_DEBUG || (logFunction != nil);
if (log && level >= RCTGetLogThreshold()) {
if (logFunction) {
logFunction(level, RCTLogSourceJavaScript, nil, nil, message);
}
}
}
RCTLogFunction RCTDefaultLogFunction =
^(RCTLogLevel level,
RCTLogSource source,
__unused NSString *fileName,
__unused NSNumber *lineNumber,
NSString *message) {
os_log_with_type(RCTLogForLogSource(source), RCTLogTypeForLogLevel(level), "%{public}s", message.UTF8String);
};
So if I just hook Apple's os_log_with_type, I will get the RCTLog logs.
This is my codes, but not working. Please help me. Thanks!!!!
#import <os/log.h>
#import "fishhook.h"
static void (*original_oslog)((os_log_t log, os_log_type_t type, const char *format, ...));
void hook_oslog(os_log_t log, os_log_type_t type, const char *format, ...) {
NSLog(#"hook success!");
}
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
struct rebinding oslog_rebinding = { "os_log_with_type", hook_oslog, (void *)&original_oslog };
rebind_symbols((struct rebinding[1]){oslog_rebinding}, 1);
});
}
Final, I found solution. Not need to hook, Related API have been provided by React Native already.
RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
NSLog(#"%#", message);
});

How to get CNAME of a domain in iOS

I would like to resolve a domain and get its CNAME and ip info, like the following:
example.com -> cname.com -> ip address
I searched a lot and know how to get the ip address, e.g. by CFHost. But I still don't know how to get other information, like its CNAME.
Should I do this with CFHost or something else?
You can use below code for your purpose
+ (void) getCNAME {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
DNSServiceRef serviceRef;
DNSServiceErrorType error;
error = DNSServiceQueryRecord(&serviceRef, 0, 0, "apple.com", kDNSServiceType_CNAME,
kDNSServiceClass_IN, queryCallback, NULL);
if (error != kDNSServiceErr_NoError){
NSLog(#"DNS Service error");
}
DNSServiceProcessResult(serviceRef);
DNSServiceRefDeallocate(serviceRef);
});}
static void queryCallback(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char *fullname,
uint16_t rrtype,
uint16_t rrclass,
uint16_t rdlen,
const void *rdata,
uint32_t ttl,
void *context) {
if (errorCode == kDNSServiceErr_NoError && rdlen > 1) {
NSMutableData *txtData = [NSMutableData dataWithCapacity:rdlen];
for (uint16_t i = 1; i < rdlen; i += 256) {
[txtData appendBytes:rdata + i length:MIN(rdlen - i, 255)];
}
NSString *theTXT = [[NSString alloc] initWithBytes:txtData.bytes length:txtData.length encoding:NSASCIIStringEncoding];
NSLog(#"CNAME: %#", theTXT);
}}

Issue with digital signature generated using Podofo library

I'm using OpenSSL to generate digital signature for a PDF by PoDoFo library.
Here is the logic for signature handler
OpenSSLSignatureHandler.h
#import <Foundation/Foundation.h>
// OpenSSL includes
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pkcs12.h>
#include <openssl/pkcs7.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#interface OpenSSLSignatureHandler : NSObject
{
SHA_CTX m_sha_ctx;
EVP_PKEY* mp_pkey; // private key
X509* mp_x509; // signing certificate
STACK_OF(X509)* mp_ca; // certificate chain up to the CA
}
- (id) initWithCert:(NSString*) p12file password: (NSString*) password;
- (void) AppendData: (NSData*)data;
- (NSData*) getSignature;
#end
OpenSSLSignatureHandler.m
#import "OpenSSLSignatureHandler.h"
#include <string>
#implementation OpenSSLSignatureHandler
- (id) initWithCert:(NSString*) p12file password: (NSString*) password{
if (self = [super init]) {
// Initialize OpenSSL library
CRYPTO_malloc_init();
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
FILE* fp = fopen([p12file cStringUsingEncoding: NSASCIIStringEncoding], "rb");
if (fp == NULL)
#throw ([NSException exceptionWithName: #"PDFNet Exception" reason: #"Cannot open private key." userInfo: nil]);
PKCS12* p12 = d2i_PKCS12_fp(fp, NULL);
fclose(fp);
if (p12 == NULL)
#throw ([NSException exceptionWithName: #"PDFNet Exception" reason: #"Cannot parse private key." userInfo: nil]);
mp_pkey = NULL;
mp_x509 = NULL;
mp_ca = NULL;
int parseResult = PKCS12_parse(p12, [password cStringUsingEncoding: NSASCIIStringEncoding], &mp_pkey, &mp_x509, &mp_ca);
PKCS12_free(p12);
if (parseResult == 0)
#throw ([NSException exceptionWithName: #"PDFNet Exception" reason: #"Cannot parse private key." userInfo: nil]);
//initialize sha context
SHA1_Init(&m_sha_ctx);
}
return self;
}
- (void) AppendData: (NSData*)data
{
SHA1_Update(&m_sha_ctx, [data bytes], [data length]);
return;
}
- (BOOL) Reset
{
SHA1_Init(&m_sha_ctx);
return (YES);
}
- (NSData*) getSignature
{
unsigned char sha_buffer[SHA_DIGEST_LENGTH];
memset((void*) sha_buffer, 0, SHA_DIGEST_LENGTH);
SHA1_Final(sha_buffer, &m_sha_ctx);
PKCS7* p7 = PKCS7_new();
PKCS7_set_type(p7, NID_pkcs7_signed);
PKCS7_SIGNER_INFO* p7Si = PKCS7_add_signature(p7, mp_x509, mp_pkey, EVP_sha1());
PKCS7_add_attrib_content_type(p7Si, OBJ_nid2obj(NID_pkcs7_data));
PKCS7_add0_attrib_signing_time(p7Si, NULL);
PKCS7_add1_attrib_digest(p7Si, (const unsigned char*) sha_buffer, SHA_DIGEST_LENGTH);
PKCS7_add_certificate(p7, mp_x509);
int c = 0;
for ( ; c < sk_X509_num(mp_ca); c++) {
X509* cert = sk_X509_value(mp_ca, c);
PKCS7_add_certificate(p7, cert);
}
PKCS7_set_detached(p7, 1);
PKCS7_content_new(p7, NID_pkcs7_data);
PKCS7_SIGNER_INFO_sign(p7Si);
int p7Len = i2d_PKCS7(p7, NULL);
NSMutableData* signature = [NSMutableData data];
unsigned char* p7Buf = (unsigned char*) malloc(p7Len);
if (p7Buf != NULL) {
unsigned char* pP7Buf = p7Buf;
i2d_PKCS7(p7, &pP7Buf);
[signature appendBytes: (const void*) p7Buf length: p7Len];
free(p7Buf);
}
PKCS7_free(p7);
return (signature);
}
- (void) dealloc
{
sk_X509_free(mp_ca);
X509_free(mp_x509);
EVP_PKEY_free(mp_pkey);
// Release OpenSSL resource usage
ERR_free_strings();
EVP_cleanup();
[super dealloc];
}
#end
Using podofo to embed signature
void CreateSimpleForm( PoDoFo::PdfPage* pPage, PoDoFo::PdfStreamedDocument* pDoc, const PoDoFo::PdfData &signatureData )
{
PoDoFo::PdfPainter painter;
PoDoFo::PdfFont* pFont = pDoc->CreateFont( "Courier" );
painter.SetPage( pPage );
painter.SetFont( pFont );
painter.DrawText( 10000 * CONVERSION_CONSTANT, 280000 * CONVERSION_CONSTANT, "PoDoFo Sign Test" );
painter.FinishPage();
PoDoFo::PdfSignatureField signField( pPage, PoDoFo::PdfRect( 0, 0, 0, 0 ), pDoc );
signField.SetFieldName("SignatureFieldName");
signField.SetSignature(signatureData);
signField.SetSignatureReason("Document verification");
// Set time of signing
signField.SetSignatureDate( PoDoFo::PdfDate() );
}
+(void)addDigitalSignatureOnPage:(NSInteger)pageIndex outpath:(NSString*)path/*doc:(PoDoFo::PdfMemDocument*)aDoc*/{
PoDoFo::PdfPage* pPage;
PoDoFo::PdfSignOutputDevice signer([path UTF8String]);
// Reserve space for signature
signer.SetSignatureSize(1024);
if([[NSFileManager defaultManager] fileExistsAtPath:path]){
PoDoFo::PdfStreamedDocument writer( &signer, PoDoFo::ePdfVersion_1_5 );
// Disable default appearance
writer.GetAcroForm(PoDoFo::ePdfCreateObject, PoDoFo::PdfAcroForm::ePdfAcroFormDefaultAppearance_None);
pPage = writer.CreatePage(PoDoFo::PdfPage::CreateStandardPageSize(PoDoFo::ePdfPageSize_A4 ) );
TEST_SAFE_OP( CreateSimpleForm( pPage, &writer, *signer.GetSignatureBeacon() ) );
TEST_SAFE_OP( writer.Close() );
}
// Check if position of signature was found
if(signer.HasSignaturePosition()) {
// Adjust ByteRange for signature
signer.AdjustByteRange();
// Read data for signature and count it
// We have to seek at the beginning of the file
signer.Seek(0);
//OpenSSLSignatureHandler
NSString * p12certpath = [[NSBundle mainBundle] pathForResource:#"iphone-cert" ofType:#"p12"];
OpenSSLSignatureHandler*signatureHandler = [[OpenSSLSignatureHandler alloc] initWithCert:p12certpath password:#"test123$"];
char buff[65536];
size_t len;
while( (len = signer.ReadForSignature(buff, 65536))>0 )
{
NSData* data = [NSData dataWithBytes:(const void *)buff length:len];
[signatureHandler AppendData:data];
}
const PoDoFo::PdfData *pSignature = NULL;
// NSString *pkcsMessage = [[signatureHandler getSignature] base64EncodedString];
// NSLog(#"OpenSSLSignatureHandler signature message = %#",pkcsMessage);
// const char * cstr = [pkcsMessage UTF8String];
// if(pSignature==NULL)pSignature = new PoDoFo::PdfData(cstr, sizeof(cstr));
unsigned char *bytePtr = (unsigned char *)[[signatureHandler getSignature] bytes];
std::string str;
str.append(reinterpret_cast<const char*>(bytePtr));
// Paste signature to the file
if(pSignature==NULL)pSignature = new PoDoFo::PdfData(str.c_str(), sizeof(str));
NSLog(#"str = %s",str.c_str());
NSLog(#"sizeof(str) = %lu",sizeof(str));
signer.SetSignature(*pSignature);
}
signer.Flush();
}
But the signature that's embeded in the PDF is always empty
can some help with this issue ?

Parse whole pdf-page to NSString on an iPhone

I've been trying to parse a pdf-page of text to NSString for a while now and the only thing I can find are methods to search for specific stringvalues.
What I'd like to do is parse a single page of PDF without using any external libraries such as PDFKitten, PDFKit etc.
I'd like to have the data in an NSArray, NSString or NSDictionary if possible.
Thanks :D!
A piece of what I've tried so far.
CGPDFDocumentRef MyGetPDFDocumentRef (const char *filename) {
CFStringRef path;
CFURLRef url;
CGPDFDocumentRef document;
path = CFStringCreateWithCString (NULL, filename,kCFStringEncodingUTF8);
url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, 0);
CFRelease (path);
document = CGPDFDocumentCreateWithURL (url);// 2
CFRelease(url);
int count = CGPDFDocumentGetNumberOfPages (document);// 3
if (count == 0) {
printf("`%s' needs at least one page!", filename);
return NULL;
}
return document;
}
// table methods to parse pdf
static void op_MP (CGPDFScannerRef s, void *info) {
const char *name;
if (!CGPDFScannerPopName(s, &name))
return;
printf("MP /%s\n", name);
}
static void op_DP (CGPDFScannerRef s, void *info) {
const char *name;
if (!CGPDFScannerPopName(s, &name))
return;
printf("DP /%s\n", name);
}
static void op_BMC (CGPDFScannerRef s, void *info) {
const char *name;
if (!CGPDFScannerPopName(s, &name))
return;
printf("BMC /%s\n", name);
}
static void op_BDC (CGPDFScannerRef s, void *info) {
const char *name;
if (!CGPDFScannerPopName(s, &name))
return;
printf("BDC /%s\n", name);
}
static void op_EMC (CGPDFScannerRef s, void *info) {
const char *name;
if (!CGPDFScannerPopName(s, &name))
return;
printf("EMC /%s\n", name);
}
void MyDisplayPDFPage (CGContextRef myContext,size_t pageNumber,const char *filename) {
CGPDFDocumentRef document;
CGPDFPageRef page;
document = MyGetPDFDocumentRef (filename);// 1
totalPages=CGPDFDocumentGetNumberOfPages(document);
page = CGPDFDocumentGetPage (document, 1);// 2
CGPDFDictionaryRef d;
d = CGPDFPageGetDictionary(page);
CGPDFScannerRef myScanner;
CGPDFOperatorTableRef myTable;
myTable = CGPDFOperatorTableCreate();
CGPDFOperatorTableSetCallback (myTable, "MP", &op_MP);
CGPDFOperatorTableSetCallback (myTable, "DP", &op_DP);
CGPDFOperatorTableSetCallback (myTable, "BMC", &op_BMC);
CGPDFOperatorTableSetCallback (myTable, "BDC", &op_BDC);
CGPDFOperatorTableSetCallback (myTable, "EMC", &op_EMC);
CGPDFContentStreamRef myContentStream = CGPDFContentStreamCreateWithPage (page);// 3
myScanner = CGPDFScannerCreate (myContentStream, myTable, NULL);// 4
CGPDFScannerScan (myScanner);// 5
CGPDFStringRef str;
d = CGPDFPageGetDictionary(page);
if (CGPDFDictionaryGetString(d, "Lorem", &str)){
CFStringRef s;
s = CGPDFStringCopyTextString(str);
if (s != NULL) {
NSLog(#"%# testing it", s);
}
CFRelease(s);
}
}
- (void)viewDidLoad {
[super viewDidLoad];
MyDisplayPDFPage(UIGraphicsGetCurrentContext(), 1, [[[NSBundle mainBundle] pathForResource:#"TestPage" ofType:#"pdf"] UTF8String]);
}
Quartz provides functions that let you inspect the PDF document structure and the content stream. Inspecting the document structure lets you read the entries in the document catalog and the contents associated with each entry. By recursively traversing the catalog, you can inspect the entire document.
A PDF content stream is just what its name suggests—a sequential stream of data such as 'BT 12 /F71 Tf (draw this text) Tj . . . ' where PDF operators and their descriptors are mixed with the actual PDF content. Inspecting the content stream requires that you access it sequentially.
This developer.apple documentation shows how to examine the structure of a PDF document and parse the contents of a PDF document.

Query DNS to find NAPTR in iOS

I have been having a lot of trouble finding a way to query the DNS to find the NAPTR in iOS. There seem to be many relatively simple ways to resolve to an IP, but I specifically need to find all NAPTR records in a DNS lookup. I'd prefer to do so without having to bring in any external libraries if at all possible. If anyone has been able to do this (or something similar that I can extrapolate from) I'd appreciate any pointers.
All code must function in iOS 5.0+
I ended up using DNSServiceQueryRecord.
DNSServiceRef sdRef;
DNSServiceQueryRecord(&sdRef, 0, 0,
"google.com",
kDNSServiceType_NAPTR,
kDNSServiceClass_IN,
callback,
NULL);
DNSServiceProcessResult(sdRef);
DNSServiceRefDeallocate(sdRef);
In actual use, I found that there was an issue where the app would hang indefinitely if there were no results, so I ended up having to adjust my code to add a timeout on the result.
/*
Attempt to fetch the NAPTR from the stored server address. Since iOS will continue waiting
until told directly to stop (even if there is no result) we must set our own timeout on the
request (set to 5 seconds).
On success, the callback function is called. On timeout, the kSRVLookupComplete notification
is sent.
*/
- (void)attemptNAPTRFetch {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
DNSServiceRef sdRef;
DNSServiceErrorType err;
err = DNSServiceQueryRecord(&sdRef, 0, 0,
[server cStringUsingEncoding:[NSString defaultCStringEncoding]],
kDNSServiceType_NAPTR,
kDNSServiceClass_IN,
callback,
NULL);
// This stuff is necessary so we don't hang forever if there are no results
int dns_sd_fd = DNSServiceRefSockFD(sdRef);
int nfds = dns_sd_fd + 1;
fd_set readfds;
struct timeval tv;
int result;
int stopNow = 0;
int timeOut = 5; // Timeout in seconds
while (!stopNow) {
FD_ZERO(&readfds);
FD_SET(dns_sd_fd, &readfds);
tv.tv_sec = timeOut;
tv.tv_usec = 0;
result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
if (result > 0) {
if(FD_ISSET(dns_sd_fd, &readfds)) {
err = DNSServiceProcessResult(sdRef);
if (err != kDNSServiceErr_NoError){
NSLog(#"There was an error");
}
stopNow = 1;
}
}
else {
printf("select() returned %d errno %d %s\n", result, errno, strerror(errno));
if (errno != EINTR) {
stopNow = 1;
postNotification(kSRVLookupComplete, nil);
}
}
}
DNSServiceRefDeallocate(sdRef);
});
}
Then, for the callback:
static void callback(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char *fullname,
uint16_t rrtype,
uint16_t rrclass,
uint16_t rdlen,
const void *rdata,
uint32_t ttl,
void *context)
{
uint16_t order, pref;
char flag;
NSMutableString *service = [[NSMutableString alloc] init];
NSMutableString *replacement = [[NSMutableString alloc] init];
const char *data = (const char*)rdata;
order = data[1];
pref = data[3];
flag = data[5];
int i = 7;
while (data[i] != 0){
[service appendString:[NSString stringWithFormat:#"%c", data[i]]];
i++;
}
i += 2;
while(data[i] != 0){
if(data[i] >= 32 && data[i] <= 127)
[replacement appendString:[NSString stringWithFormat:#"%c", data[i]]];
else
[replacement appendString:#"."];
i++;
}
NSLog(#"\nOrder: %i\nPreference: %i\nFlag: %c\nService: %#\nReplacement: %#\n", order, pref, flag, service, replacement);
}
This seems to do the trick for me. You would of course do any other necessary work using all the parsed data in the callback or store the data somewhere to be used later.

Resources