├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── YAPDFKit-TestSuite ├── Info.plist └── YAPDFKit_TestSuite.m ├── YAPDFKit.podspec ├── YAPDFKit.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── Parser.xccheckout ├── xcshareddata │ └── xcschemes │ │ ├── YAPDFKit-TestSuite.xcscheme │ │ └── YAPDFKit.xcscheme └── xcuserdata │ └── pim.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist └── YAPDFKit ├── 2-page-pages-export.pdf ├── PDFParser.h ├── Utils.c ├── Utils.h ├── YAPDFKit-Prefix.pch ├── YPArray.h ├── YPArray.m ├── YPAttribute.h ├── YPAttribute.m ├── YPBool.h ├── YPBool.m ├── YPDictionary.h ├── YPDictionary.m ├── YPDocument.h ├── YPDocument.m ├── YPHexString.h ├── YPHexString.m ├── YPName.h ├── YPName.m ├── YPNumber.h ├── YPNumber.m ├── YPObject.h ├── YPObject.m ├── YPObjectReference.h ├── YPObjectReference.m ├── YPObjectStream.h ├── YPObjectStream.m ├── YPPages.h ├── YPPages.m ├── YPString.h ├── YPString.m ├── YPXref.h ├── YPXref.m ├── main.m ├── pdfzlib.h ├── pdfzlib.m └── test_in.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | YAPDFKit.xcodeproj/project.xcworkspace/xcuserdata/pim.xcuserdatad/UserInterfaceState.xcuserstate 2 | YAPDFKit.xcodeproj/xcuserdata/pim.xcuserdatad/xcschemes/YAPDFKit.xcscheme 3 | .DS_Store 4 | build 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | osx_image: xcode7.3 2 | language: objective-c 3 | os: osx 4 | xcode_project: YAPDFKit.xcodeproj # path to your xcodeproj folder 5 | xcode_scheme: YAPDFKit-TestSuite 6 | 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Pim Snel 4 | Copyright (c) 2014 Ptenster. All rights reserved. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # YAPDFKit 2 | 3 | [![Build 4 | Status](https://travis-ci.org/mipmip/YAPDFKit.svg?branch=master)](https://travis-ci.org/mipmip/YAPDFKit) 5 | 6 | Yet another PDF Kit is a independent PDF Kit written in objective-c for 7 | parsing and manipulating PDF's. YAPDFKit is completely independent of Apple's PDFKit 8 | 9 | For specific cases YAPDFKit can be of great help, but it's currently in an Alpha state. 10 | 11 | 12 | ## Requirements 13 | 14 | ### Platform targets 15 | 16 | - Usable in OS X and iOS projects 17 | - Oldest Mac target: Mac OS X 10.7 18 | 19 | ### Functionality targets 20 | 21 | - Parser to create PDF Structure 22 | - Extract Deflated and other filtered content 23 | - Some essential Postscript knowledge and features 24 | - Modify PDF Objects directly in PDF 25 | 26 | ## Example 27 | 28 | Use these includes: 29 | 30 | ```objective-c 31 | 32 | #import 33 | #import "YPDocument.h" 34 | ``` 35 | 36 | In this example we add a purple rectangle below the text of every page. See main.c for a working version of this example. 37 | 38 | ![image](http://picdrop.t3lab.com/NSrEN4xSRj.png) ![image](http://picdrop.t3lab.com/3uoRlT8HjT.png) 39 | 40 | ```objective-c 41 | 42 | NSString *file =@"/tmp/2-page-pages-export.pdf"; 43 | 44 | NSData *fileData = [NSData dataWithContentsOfFile:file]; 45 | 46 | YPDocument *document = [[YPDocument alloc] initWithData:fileData]; 47 | 48 | YPPages *pg = [[YPPages alloc] initWithDocument:document]; 49 | NSLog(@"page count: %d", [pg getPageCount]); 50 | 51 | //All Pages unsorted 52 | NSArray * allPages = [document getAllObjectsWithKey:@"Type" value:@"Page"]; 53 | 54 | for (YPObject* page in allPages) { 55 | 56 | NSString *docContentNumber = [[document getInfoForKey:@"Contents" inObject:[page getObjectNumber]] getReferenceNumber]; 57 | YPObject * pageContentsObject = [document getObjectByNumber:docContentNumber]; 58 | 59 | NSData *plainContent = [pageContentsObject getUncompressedStreamContentsAsData]; 60 | 61 | NSData *data2 = [@"q /Cs1 cs 0.4 0 0.6 sc 250 600 100 100 re f q " dataUsingEncoding:NSASCIIStringEncoding]; 62 | 63 | NSRange firstPartRange = {0,64}; 64 | NSRange lastPartRange = {64, ([plainContent length]-64)}; 65 | NSData *data1 = [plainContent subdataWithRange:firstPartRange]; 66 | NSData *data3 = [plainContent subdataWithRange:lastPartRange]; 67 | 68 | NSMutableData * newPlainContent = [data1 mutableCopy]; 69 | [newPlainContent appendData:data2]; 70 | [newPlainContent appendData:data3]; 71 | 72 | [pageContentsObject setStreamContentsWithData:newPlainContent]; 73 | [document addObjectToUpdateQueue:pageContentsObject]; 74 | } 75 | 76 | [document updateDocumentData]; 77 | [[document modifiedPDFData] writeToFile:@"/tmp/2-page-pages-export-mod.pdf" atomically:YES]; 78 | 79 | ``` 80 | 81 | 82 | 83 | 84 | ## Roadmap 85 | 86 | ### Milestone 1: update page contents object 87 | 88 | - [x] Return all document objects 89 | - [x] Deflate content object stream 90 | - [x] cleanup deflate function 91 | - [x] Enable Existing Tests 92 | - [x] Enable travis 93 | - [x] Add some file intergration tests 94 | - [x] Return all document pages 95 | - [x] Return page content object 96 | - [x] Add new object at file bottom 97 | - [x] Add new xref table at file bottom 98 | - [x] Add new trailer 99 | - [x] calculate file length 100 | - [x] calc object length 101 | - [x] fix and check all offsets; 102 | 103 | ### Milestone 2: first CocoaPod Release 104 | - [x] Make podspec 105 | - [x] Replace PDF prefix with YAPDF everywhere 106 | 107 | ### Milestone 3: first CocoaPod Release 108 | - [x] remove nsstring convertion for streams 109 | - [x] add included pdf in main.c 110 | - [x] cleanup file reader 111 | 112 | ### Backlog 113 | - [ ] more examples 114 | - [ ] Return all page objects / per page 115 | - [ ] add inflate function 116 | - [ ] Exact Text (ProcessOutput) 117 | - [ ] Code Coverage 118 | - [ ] Rename all object attributes classes with a name including object 119 | 120 | ## Motivation 121 | This project started because we needed to remove white 122 | backgrounds from PDF's made by Applications like Apple Pages. YAPDFKit 123 | is used in the [PDF Letterhead App](http://pdfletterhead.net). 124 | 125 | ![image](http://picdrop.t3lab.com/DXf3SaNc8d.png) 126 | 127 | ![image](http://picdrop.t3lab.com/cAobHdySJ6.png) 128 | 129 | ## Contributing 130 | 1. Fork it ( https://github.com/[my-github-username]/YAPDFKit/fork ) 131 | 2. Create your feature branch (`git checkout -b my-new-feature`) 132 | 3. Commit your changes (`git commit -am 'Add some feature'`) 133 | 4. Push to the branch (`git push origin my-new-feature`) 134 | 5. Create a new Pull Request 135 | 136 | ## Credits 137 | - YAPDFKit is a fork of [PDFCoolParser](https://github.com/kozliappi/PDFCoolParser) by @kozliappi. 138 | - YAPDFKit is sponsored by [Lingewoud](http://lingewoud.com) and [MunsterMade](http://munstermade.com). 139 | 140 | ![image](http://picdrop.t3lab.com/yCWqnH5FWq.png) 141 | -------------------------------------------------------------------------------- /YAPDFKit-TestSuite/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /YAPDFKit-TestSuite/YAPDFKit_TestSuite.m: -------------------------------------------------------------------------------- 1 | // 2 | // YAPDFKit_TestSuite.m 3 | // YAPDFKit-TestSuite 4 | // 5 | // Created by Pim Snel on 11-02-16. 6 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 7 | 8 | #import 9 | #import 10 | #import "YPDocument.h" 11 | #import "YPPages.h" 12 | #import "YPObject.h" 13 | #import "YPArray.h" 14 | #import "YPBool.h" 15 | #import "YPHexString.h" 16 | #import "YPName.h" 17 | #import "YPNumber.h" 18 | #import "YPString.h" 19 | #import "YPObjectReference.h" 20 | 21 | @interface YAPDFKit_TestSuite : XCTestCase 22 | @property YPDocument* document; 23 | //- (void) setupDocumentCMethod:(NSString*)fileName; 24 | 25 | @end 26 | 27 | @implementation YAPDFKit_TestSuite 28 | 29 | - (void)setUp { 30 | [super setUp]; 31 | // Put setup code here. This method is called before the invocation of each test method in the class. 32 | } 33 | 34 | - (void)tearDown { 35 | // Put teardown code here. This method is called after the invocation of each test method in the class. 36 | [super tearDown]; 37 | } 38 | 39 | - (YPDocument *) setupDocumentCMethod:(NSString*)fileName { 40 | // open pdf in memory 41 | NSBundle *bundle = [NSBundle bundleForClass:[self class]]; 42 | NSString *pdfPath = [bundle pathForResource:fileName ofType:@"pdf"]; 43 | 44 | if (pdfPath != nil) { 45 | 46 | //NSLog(@"pdf: %@", pdfPath); 47 | //Open the PDF source file: 48 | FILE* filei = fopen([pdfPath UTF8String], "rb"); 49 | 50 | //Get the file length: 51 | int fseekres = fseek(filei,0, SEEK_END); //fseek==0 if ok 52 | long filelen = ftell(filei); 53 | fseekres = fseek(filei,0, SEEK_SET); 54 | 55 | //Read the entire file into memory (!): 56 | char *buffer = malloc(filelen*sizeof(char)); //Allocates the buffer 57 | ZeroMemory(buffer, filelen); 58 | 59 | if (!fread(buffer, filelen, 1 ,filei)) { 60 | NSLog(@"Error, reading file!"); 61 | } 62 | 63 | NSData* fileData = [NSData dataWithBytes:(const void *)buffer length:filelen]; 64 | 65 | // NSLog(@"data: %@",fileData); 66 | return [[YPDocument alloc] initWithData:fileData]; 67 | 68 | } else { 69 | NSLog(@"Error, file not found!"); 70 | } 71 | return nil; 72 | } 73 | - (YPDocument *) setupDocumentObCMethod:(NSString*)fileName { 74 | // open pdf in memory 75 | NSBundle *bundle = [NSBundle bundleForClass:[self class]]; 76 | NSString *pdfPath = [bundle pathForResource:fileName ofType:@"pdf"]; 77 | 78 | if (pdfPath != nil) { 79 | 80 | NSData *fileData = [NSData dataWithContentsOfFile:pdfPath]; 81 | // NSLog(@"data: %@",fileData); 82 | return [[YPDocument alloc] initWithData:fileData]; 83 | 84 | } else { 85 | NSLog(@"Error, file not found!"); 86 | } 87 | return nil; 88 | } 89 | 90 | 91 | 92 | /* 93 | * Тест для ссылок на объект 94 | * Test object references 95 | */ 96 | - (void)testObjectReferenceParsing 97 | { 98 | char example[] = "325 0 R"; 99 | NSData *exampleData = [NSData dataWithBytes:example length:sizeof(example)]; 100 | NSInteger first, second; 101 | YPObject *obj = [[YPObject alloc] initWithData:exampleData first:&first second:&second]; 102 | 103 | XCTAssert([obj.value isKindOfClass:[YPObjectReference class]], @"Failed to parse object reference"); 104 | YPObjectReference *ref = obj.value; 105 | XCTAssert([[ref getReferenceNumber] isEqualToString:@"325 0"], @"Wrong reference number in object reference"); 106 | } 107 | 108 | /* 109 | * Тест для имен 110 | */ 111 | - (void)testObjectNameParsing 112 | { 113 | char example[] = "/TestName"; 114 | NSData *exampleData = [NSData dataWithBytes:example length:sizeof(example)]; 115 | NSInteger first, second; 116 | YPObject *obj = [[YPObject alloc] initWithData:exampleData first:&first second:&second]; 117 | XCTAssert([obj.value isKindOfClass:[NSString class]], @"Failed to parse PDF name"); 118 | YPName *name = obj.value; 119 | XCTAssert([name isEqualToString:@"TestName"], @"Wrong value of a name"); 120 | } 121 | 122 | /* 123 | * Тест для bool 124 | */ 125 | - (void)testObjectBoolParsing 126 | { 127 | char example[] = "true"; 128 | NSData *exampleData = [NSData dataWithBytes:example length:sizeof(example)]; 129 | NSInteger first, second; 130 | YPObject *obj = [[YPObject alloc] initWithData:exampleData first:&first second:&second]; 131 | XCTAssert([obj.value isKindOfClass:[YPBool class]], @"Failed to parse PDF name"); 132 | YPBool *b = obj.value; 133 | XCTAssert(b.value, @"Wrong value of a name"); 134 | } 135 | 136 | /* 137 | * Тест для чисел с дробной частью 138 | */ 139 | - (void)testObjectFloatNumberParsing 140 | { 141 | char example[] = "+325.0"; 142 | NSData *exampleData = [NSData dataWithBytes:example length:sizeof(example)]; 143 | NSInteger first, second; 144 | YPObject *obj = [[YPObject alloc] initWithData:exampleData first:&first second:&second]; 145 | 146 | XCTAssert([obj.value isKindOfClass:[YPNumber class]], @"Failed to parse real number"); 147 | YPNumber *num = obj.value; 148 | XCTAssert(num.real, @"Wrong type detected in real number"); 149 | XCTAssertFalse(num.intValue, @"Int value detected in a float number"); 150 | 151 | float f = 325.0; 152 | XCTAssertEqual(num.realValue, f, @"Wrong value of a float number"); 153 | 154 | } 155 | 156 | /* 157 | * Тест для целых чисел 158 | */ 159 | - (void)testObjectIntNumberParsing 160 | { 161 | char example[] = "-100"; 162 | NSData *exampleData = [NSData dataWithBytes:example length:sizeof(example)]; 163 | NSInteger first, second; 164 | YPObject *obj = [[YPObject alloc] initWithData:exampleData first:&first second:&second]; 165 | 166 | XCTAssert([obj.value isKindOfClass:[YPNumber class]], @"Failed to parse int number"); 167 | YPNumber *num = obj.value; 168 | XCTAssertFalse(num.real, @"Wrong type detected in int number"); 169 | 170 | int i = -100; 171 | XCTAssertEqual(num.intValue, i, @"Wrong value of an int number"); 172 | XCTAssertFalse(num.realValue, @"Float value detected in an int number"); 173 | } 174 | 175 | /* 176 | * Тест для бинарных строк 177 | */ 178 | - (void)testObjectHexStringParsing 179 | { 180 | char example[] = ""; 181 | NSData *exampleData = [NSData dataWithBytes:example length:sizeof(example)]; 182 | NSInteger first, second; 183 | YPObject *obj = [[YPObject alloc] initWithData:exampleData first:&first second:&second]; 184 | XCTAssert([obj.value isKindOfClass:[NSString class]], @"Failed to parse hexstring"); 185 | XCTAssert([obj.value isEqualToString:@"abcdef0123456789ABCDEF"], @"Failed to parse hexstring value"); 186 | } 187 | 188 | /* 189 | * Тест для строк 190 | */ 191 | - (void)testObjectStringParsing 192 | { 193 | char example[] = "(String)"; 194 | NSData *exampleData = [NSData dataWithBytes:example length:sizeof(example)]; 195 | NSInteger first, second; 196 | YPObject *obj = [[YPObject alloc] initWithData:exampleData first:&first second:&second]; 197 | 198 | XCTAssert([obj.value isKindOfClass:[NSString class]], @"Failed to parse string"); 199 | NSString *str = obj.value; 200 | XCTAssert([str isEqualToString:@"String"], @"Failed to parse string value"); 201 | 202 | char example1[] = "(String(with)brackets)"; 203 | NSData *exampleData1 = [NSData dataWithBytes:example1 length:sizeof(example1)]; 204 | YPObject *obj1 = [[YPObject alloc] initWithData:exampleData1 first:&first second:&second]; 205 | 206 | XCTAssert([obj1.value isKindOfClass:[NSString class]], @"Failed to parse string with brackets"); 207 | NSString *str1 = obj1.value; 208 | XCTAssert([str1 isEqualToString:@"String(with)brackets"], @"Failed to parse string with brackets value"); 209 | 210 | char example2[] = "(String\\(withbracket)"; 211 | NSData *exampleData2 = [NSData dataWithBytes:example2 length:sizeof(example2)]; 212 | YPObject *obj2 = [[YPObject alloc] initWithData:exampleData2 first:&first second:&second]; 213 | 214 | XCTAssert([obj2.value isKindOfClass:[NSString class]], @"Failed to parse string with bracket ("); 215 | NSString *str2 = obj2.value; 216 | XCTAssert([str2 isEqualToString:@"String\\(withbracket"], @"Failed to parse string with bracket ( value"); 217 | 218 | char example3[] = "(String\\)withbracket)"; 219 | NSData *exampleData3 = [NSData dataWithBytes:example3 length:sizeof(example3)]; 220 | YPObject *obj3 = [[YPObject alloc] initWithData:exampleData3 first:&first second:&second]; 221 | 222 | XCTAssert([obj3.value isKindOfClass:[NSString class]], @"Failed to parse string with bracket )"); 223 | NSString *str3 = obj3.value; 224 | XCTAssert([str3 isEqualToString:@"String\\)withbracket"], @"Failed to parse string with bracket ) value"); 225 | } 226 | 227 | /* 228 | * Тест для массивов 229 | */ 230 | - (void)testObjectArrayParsing 231 | { 232 | char example[] = "[/array +123 -115.5 123 0 R <>>>>> [ 0 1 [ 2 3 [ 4 5 ] ] ] false"; 233 | NSData *exampleData = [NSData dataWithBytes:example length:sizeof(example)]; 234 | NSInteger first, second; 235 | YPObject *obj = [[YPObject alloc] initWithData:exampleData first:&first second:&second]; 236 | 237 | XCTAssert([obj.value isKindOfClass:[NSArray class]], @"Failed to parse array"); 238 | NSArray *arr = obj.value; 239 | 240 | XCTAssert([[arr objectAtIndex:0] isKindOfClass:[NSString class]], @"Failed to parse name in array"); 241 | XCTAssert([[arr objectAtIndex:0] isEqualToString:@"array"], @"Failed to parse value of name in array"); 242 | 243 | XCTAssert([[arr objectAtIndex:1] isKindOfClass:[YPNumber class]], @"Failed to parse number in array"); 244 | XCTAssert([[arr objectAtIndex:1] intValue] == 123, @"Failed to parse value of integer in array"); 245 | 246 | XCTAssert([[arr objectAtIndex:2] isKindOfClass:[YPNumber class]], @"Failed to parse number in array"); 247 | XCTAssert([[arr objectAtIndex:2] realValue] == -115.5, @"Failed to parse value of float in array"); 248 | 249 | XCTAssert([[arr objectAtIndex:3] isKindOfClass:[YPObjectReference class]], @"Failed to parse object reference in array"); 250 | YPObjectReference *ref = [arr objectAtIndex:3]; 251 | XCTAssert([[ref getReferenceNumber] isEqualToString:@"123 0"], @"Failed to detect reference number in array"); 252 | 253 | XCTAssert([[arr objectAtIndex:4] isKindOfClass:[NSDictionary class]], @"Failed to parse dictionary in array"); 254 | NSDictionary *dict = [arr objectAtIndex:4]; 255 | XCTAssert([[dict objectForKey:@"dict"] isKindOfClass:[NSDictionary class]], @"Failed to parse dict in dictionary in array"); 256 | NSDictionary *dict1 = [dict objectForKey:@"dict"]; 257 | XCTAssert([[dict1 objectForKey:@"dict1"] isKindOfClass:[NSDictionary class]], @"Failed to parse dict1 in dictionary in array"); 258 | NSDictionary *dict2 = [dict1 objectForKey:@"dict1"]; 259 | XCTAssert([[dict2 objectForKey:@"dict2"] isKindOfClass:[YPNumber class]], @"Failed to parse number in dictionary in array"); 260 | XCTAssert([[dict2 objectForKey:@"dict2"] intValue] == 123, @"Failed to parse number value in dictionary in array"); 261 | 262 | XCTAssert([[arr objectAtIndex:5] isKindOfClass:[NSArray class]], @"Failed to parse array in array"); 263 | NSArray *arr1 = [arr objectAtIndex:5]; 264 | XCTAssert ([[arr1 objectAtIndex:2] isKindOfClass:[NSArray class]], @"Failed to parse arr1 in array"); 265 | XCTAssert ([[arr1 objectAtIndex:2] isKindOfClass:[NSArray class]], @"Failed to parse arr2 in array"); 266 | 267 | XCTAssert([[arr objectAtIndex:6] isKindOfClass:[YPBool class]], @"Failed to parse bool in array"); 268 | YPBool *b = [arr objectAtIndex:6]; 269 | XCTAssertFalse(b.value, @"Failed to parse bool value in array"); 270 | } 271 | 272 | /* 273 | * Тест для словарей 274 | */ 275 | - (void)testObjectDictionaryParsing 276 | { 277 | char example[] = "<>>>>> /bool_v false >>"; 278 | NSData *exampleData = [NSData dataWithBytes:example length:sizeof(example)]; 279 | NSInteger first, second; 280 | YPObject *obj = [[YPObject alloc] initWithData:exampleData first:&first second:&second]; 281 | 282 | XCTAssert([obj.value isKindOfClass:[NSDictionary class]], @"Failed to parse dictionary"); 283 | NSMutableDictionary *dict = obj.value; 284 | 285 | XCTAssert([[dict valueForKey:@"array"] isKindOfClass:[NSArray class]], @"Failed to parse array in dictionary"); 286 | NSArray *arr = [dict valueForKey:@"array"]; 287 | 288 | XCTAssert([[arr objectAtIndex:0] isKindOfClass:[YPNumber class]], @"Failed to parse array in dictionary value 0"); 289 | XCTAssert([[arr objectAtIndex:0] intValue] == 0, @"Failed to parse array in dictionary value 0: incorrect value"); 290 | XCTAssert([[arr objectAtIndex:1] isKindOfClass:[YPNumber class]], @"Failed to parse array in dictionary value 1"); 291 | XCTAssert([[arr objectAtIndex:1] intValue] == 1, @"Failed to parse array in dictionary value 1: incorrect value"); 292 | XCTAssert([[arr objectAtIndex:2] isKindOfClass:[NSArray class]], @"Failed to parse array in dictionary value 2"); 293 | NSArray *arr1 = [arr objectAtIndex:2]; 294 | XCTAssert([[arr1 objectAtIndex:0] isKindOfClass:[YPNumber class]], @"Failed to parse array1 in dictionary value 0"); 295 | XCTAssert([[arr1 objectAtIndex:0] intValue] == 2, @"Failed to parse array1 in dictionary value 0: incorrect value"); 296 | XCTAssert([[arr1 objectAtIndex:1] isKindOfClass:[YPNumber class]], @"Failed to parse array1 in dictionary value 1"); 297 | XCTAssert([[arr1 objectAtIndex:1] intValue] == 3, @"Failed to parse array1 in dictionary value 1: incorrect value"); 298 | XCTAssert([[arr1 objectAtIndex:2] isKindOfClass:[NSArray class]], @"Failed to parse array1 in dictionary value 2"); 299 | NSArray *arr2 = [arr1 objectAtIndex:2]; 300 | XCTAssert([[arr2 objectAtIndex:0] isKindOfClass:[YPNumber class]], @"Failed to parse array2 in dictionary value 0"); 301 | XCTAssert([[arr2 objectAtIndex:0] intValue] == 4, @"Failed to parse array2 in dictionary value 0: incorrect value"); 302 | XCTAssert([[arr2 objectAtIndex:1] isKindOfClass:[YPNumber class]], @"Failed to parse array2 in dictionary value 1"); 303 | XCTAssert([[arr2 objectAtIndex:1] intValue] == 5, @"Failed to parse array2 in dictionary value 1: incorrect value"); 304 | 305 | XCTAssert([[dict valueForKey:@"integer"] isKindOfClass:[YPNumber class]], @"Failed to parse integer in dictionary"); 306 | NSLog(@"%@", [dict valueForKey:@"integer"]); 307 | NSLog(@"%@", [dict valueForKey:@"real"]); 308 | NSLog(@"%@", [dict valueForKey:@"reference"]); 309 | XCTAssert([[dict valueForKey:@"integer"] intValue] == 123, @"Failed to parse integer value in dictionary"); 310 | 311 | XCTAssert([[dict valueForKey:@"real"] isKindOfClass:[YPNumber class]], @"Failed to parse float number in dictionary"); 312 | XCTAssertEqual([[dict valueForKey:@"real"] realValue], -115.5, @"Failed to parse float number value in dictionary"); 313 | 314 | XCTAssert([[dict valueForKey:@"reference"] isKindOfClass:[YPObjectReference class]], @"Failed to parse object reference in dictionary"); 315 | XCTAssert([[[dict valueForKey:@"reference"] getReferenceNumber] isEqual:@"123 0"], @"Failed to parse object reference number in dictionary"); 316 | 317 | XCTAssert([[dict valueForKey:@"dictionary"] isKindOfClass:[NSDictionary class]], @"Failed to parse dictionary in dictionary"); 318 | NSDictionary *dict1 = [dict valueForKey:@"dictionary"]; 319 | XCTAssert([[dict1 valueForKey:@"dict"] isKindOfClass:[NSDictionary class]], @"Failed to parse dictionary1 in dictionary"); 320 | NSDictionary *dict2 = [dict1 valueForKey:@"dict"]; 321 | XCTAssert([[dict2 valueForKey:@"dict1"] isKindOfClass:[NSDictionary class]], @"Failed to parse dictionary2 in dictionary"); 322 | NSDictionary *dict3 = [dict2 valueForKey:@"dict1"]; 323 | XCTAssert([[dict3 valueForKey:@"dict2"] isKindOfClass:[YPNumber class]], @"Failed to parse dictionary3 in dictionary"); 324 | XCTAssert([[dict3 valueForKey:@"dict2"] intValue] == 123, @"Failed to parse value in final dictionary"); 325 | 326 | XCTAssert([[dict valueForKey:@"bool_v"] isKindOfClass:[YPBool class]], @"Failed to parse bool in dictionary"); 327 | YPBool *b = [dict valueForKey:@"bool_v"]; 328 | XCTAssertFalse( b.value, @"Failed to parse object reference number in dictionary"); 329 | } 330 | 331 | 332 | - (void)xtestPerformanceExample { 333 | // This is an example of a performance test case. 334 | [self measureBlock:^{ 335 | // Put the code you want to measure the time of here. 336 | }]; 337 | } 338 | 339 | 340 | - (void)testDocumentPDFInfo 341 | { 342 | YPDocument * document = [self setupDocumentCMethod:@"2-page-pages-export"]; 343 | XCTAssert([document isKindOfClass:[YPDocument class]], @"Failed to setup document "); 344 | 345 | NSString * testString = @"Size: 21059 bytes\n\ 346 | Version: 1.3\n\ 347 | Binary: True\n\ 348 | Objects: 35\n\ 349 | Streams: 7\n\ 350 | Comments: 2\n"; 351 | 352 | // NSLog(@"doc info %@",[document getPDFInfo]); 353 | // NSLog(@"doc info %@",testString); 354 | XCTAssert([[document getPDFInfo] isEqualToString:testString], @"Wrong Document info"); 355 | 356 | } 357 | 358 | - (void)xtestDocumentMetaData 359 | { 360 | YPDocument * document = [self setupDocumentCMethod:@"2-page-pages-export"]; 361 | 362 | NSString * testString = @"File: fcexploit.pdf\n \ 363 | Size: 25169 bytes\n \ 364 | Version: 1.3\n \ 365 | Binary: True\n \ 366 | Objects: 35\n \ 367 | Streams: 7\n \ 368 | Comments: 0"; 369 | 370 | // NSLog(@"doc info %@",[document getPDFMetaData]); 371 | XCTAssert([[document getPDFMetaData] isEqualToString:testString], @"Wrong Document info"); 372 | } 373 | 374 | - (void)testDocumentAllPages 375 | { 376 | 377 | YPDocument * document = [self setupDocumentCMethod:@"2-page-pages-export"]; 378 | 379 | YPPages *pg = [[YPPages alloc] initWithDocument:document]; 380 | [pg getPageCount]; 381 | [pg getPagesTree]; 382 | } 383 | 384 | - (void)testDocumentContentsPages 385 | { 386 | 387 | } 388 | 389 | - (void)testYPObjects 390 | { 391 | YPDocument * document = [self setupDocumentObCMethod:@"2-page-pages-export"]; 392 | XCTAssert([document isKindOfClass:[YPDocument class]], @"Failed to setup document "); 393 | 394 | //[document getInfoForKey:@"Type"]; 395 | 396 | //SOME FEATURES 397 | //NSLog(@"dict: %lu", (unsigned long)[[document allObjects] count]); 398 | 399 | NSDictionary *pdfObjs = [document allObjects]; 400 | 401 | XCTAssert([pdfObjs count] == 35, @"Their should be 35 objects"); 402 | 403 | for(id key in pdfObjs) { 404 | id pdfObject = [pdfObjs objectForKey:key]; 405 | XCTAssert([key isKindOfClass:[NSString class]], @"Wrong key type in object iteration "); 406 | 407 | //NSLog(@"Objectnumber: %@",[pdfObject getObjectNumber]); 408 | //NSLog(@"contents: %@",[pdfObject getContents]); 409 | 410 | if([pdfObject getStreamObject]) 411 | { 412 | //NSLog(@"Objectnumber: %@",[pdfObject getObjectNumber]); 413 | //NSLog(@"stream object: %@",[pdfObject getStreamObject]); 414 | //NSLog(@"stream unenc: %@",[[pdfObject getStreamObject] getDecompressedDataAsString]); 415 | } 416 | } 417 | 418 | //id pdfObject = [pdfObjs objectForKey:@"21 0"]; 419 | //NSLog(@"class %@", [[pdfObject getContents] class]); 420 | 421 | XCTAssert([[[pdfObjs[@"21 0"] getContents] firstObject] isKindOfClass:[NSDictionary class]], @"Wrong content type"); 422 | 423 | //YPPages *pg = [[YPPages alloc] initWithDocument:document]; 424 | //[pg getPageCount]; 425 | //[pg getPagesTree]; 426 | 427 | /* 428 | if ([document errorMessage]) { 429 | NSLog(@"%@", [document errorMessage]); 430 | } 431 | else { 432 | NSLog(@"%@", [document version]); 433 | } 434 | */ 435 | 436 | 437 | //XCTAssert([obj.value isEqualToString:@"abcdef0123456789ABCDEF"], @"Failed to parse hexstring value"); 438 | } 439 | @end 440 | -------------------------------------------------------------------------------- /YAPDFKit.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint YAPDFKit.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 12 | # 13 | # These will help people to find your library, and whilst it 14 | # can feel like a chore to fill in it's definitely to your advantage. The 15 | # summary should be tweet-length, and the description more in depth. 16 | # 17 | 18 | s.name = "YAPDFKit" 19 | s.version = "0.1.3" 20 | s.summary = "Yet another PDF Kit for parsing and modifying PDF's." 21 | 22 | # This description is used to generate tags and improve search results. 23 | # * Think: What does it do? Why did you write it? What is the focus? 24 | # * Try to keep it short, snappy and to the point. 25 | # * Write the description between the DESC delimiters below. 26 | # * Finally, don't worry about the indent, CocoaPods strips it! 27 | s.description = <<-DESC 28 | Yet another PDF Kit is a independent PDF Kit written in objective-c for 29 | parsing and manipulating PDF's. YAPDFKit is completely independant of Apple's 30 | PDFKit. 31 | DESC 32 | 33 | s.homepage = "https://github.com/mipmip/YAPDFKit" 34 | # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif" 35 | 36 | 37 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 38 | # 39 | # Licensing your code is important. See http://choosealicense.com for more info. 40 | # CocoaPods will detect a license file if there is a named LICENSE* 41 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'. 42 | # 43 | 44 | #s.license = "MIT (example)" 45 | s.license = { :type => "MIT", :file => "LICENSE" } 46 | 47 | 48 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 49 | # 50 | # Specify the authors of the library, with email addresses. Email addresses 51 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also 52 | # accepts just a name if you'd rather not provide an email address. 53 | # 54 | # Specify a social_media_url where others can refer to, for example a twitter 55 | # profile URL. 56 | # 57 | 58 | s.author = { "Pim Snel" => "pim@lingewoud.nl" } 59 | # Or just: s.author = "Pim Snel" 60 | # s.authors = { "Pim Snel" => "pim@lingewoud.nl" } 61 | s.social_media_url = "https://twitter.com/mipselaer" 62 | 63 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 64 | # 65 | # If this Pod runs only on iOS or OS X, then specify the platform and 66 | # the deployment target. You can optionally include the target after the platform. 67 | # 68 | 69 | # s.platform = :ios 70 | # s.platform = :ios, "5.0" 71 | 72 | # When using multiple platforms 73 | # s.ios.deployment_target = "5.0" 74 | # s.osx.deployment_target = "10.7" 75 | # s.watchos.deployment_target = "2.0" 76 | # s.tvos.deployment_target = "9.0" 77 | 78 | 79 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 80 | # 81 | # Specify the location from where the source should be retrieved. 82 | # Supports git, hg, bzr, svn and HTTP. 83 | # 84 | 85 | s.source = { :git => "https://github.com/mipmip/YAPDFKit.git", :tag => "0.1.2" } 86 | 87 | 88 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 89 | # 90 | # CocoaPods is smart about how it includes source code. For source files 91 | # giving a folder will include any swift, h, m, mm, c & cpp files. 92 | # For header files it will include any header in the folder. 93 | # Not including the public_header_files will make all headers public. 94 | # 95 | 96 | s.source_files = "Classes", "YAPDFKit/**/*.{h,m,c}" 97 | #s.exclude_files = "Classes/Exclude" 98 | 99 | # s.public_header_files = "Classes/**/*.h" 100 | 101 | 102 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 103 | # 104 | # A list of resources included with the Pod. These are copied into the 105 | # target bundle with a build phase script. Anything else will be cleaned. 106 | # You can preserve files from being cleaned, please don't preserve 107 | # non-essential files like tests, examples and documentation. 108 | # 109 | 110 | # s.resource = "icon.png" 111 | # s.resources = "Resources/*.png" 112 | 113 | # s.preserve_paths = "FilesToSave", "MoreFilesToSave" 114 | 115 | 116 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 117 | # 118 | # Link your library with frameworks, or libraries. Libraries do not include 119 | # the lib prefix of their name. 120 | # 121 | 122 | # s.framework = "SomeFramework" 123 | # s.frameworks = "SomeFramework", "AnotherFramework" 124 | 125 | s.library = "z" 126 | # s.libraries = "iconv", "xml2" 127 | 128 | 129 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 130 | # 131 | # If your library depends on compiler flags you can set them in the xcconfig hash 132 | # where they will only apply to your library. If you depend on other Podspecs 133 | # you can include multiple dependencies to ensure it works. 134 | 135 | s.requires_arc = true 136 | 137 | # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" } 138 | # s.dependency "JSONKit", "~> 1.4" 139 | 140 | end 141 | -------------------------------------------------------------------------------- /YAPDFKit.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 192F1D27191E483800D98CB6 /* YPDocument.m in Sources */ = {isa = PBXBuildFile; fileRef = 192F1D26191E483800D98CB6 /* YPDocument.m */; }; 11 | 19871301192FFB290022A279 /* YPObjectReference.m in Sources */ = {isa = PBXBuildFile; fileRef = 19871300192FFB290022A279 /* YPObjectReference.m */; }; 12 | 198807661929F2F300D2770D /* YPObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 198807651929F2F300D2770D /* YPObject.m */; }; 13 | 198DDE8C191E279B00B11929 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 198DDE8B191E279B00B11929 /* Foundation.framework */; }; 14 | 198DDE8F191E279B00B11929 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 198DDE8E191E279B00B11929 /* main.m */; }; 15 | 198E62421933420700D8C4D7 /* YPDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 198E62411933420700D8C4D7 /* YPDictionary.m */; }; 16 | 198E62451933422400D8C4D7 /* YPArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 198E62441933422400D8C4D7 /* YPArray.m */; }; 17 | 198E6248193342AF00D8C4D7 /* YPString.m in Sources */ = {isa = PBXBuildFile; fileRef = 198E6247193342AF00D8C4D7 /* YPString.m */; }; 18 | 198E624B193342C900D8C4D7 /* YPHexString.m in Sources */ = {isa = PBXBuildFile; fileRef = 198E624A193342C900D8C4D7 /* YPHexString.m */; }; 19 | 198E624E19334C8200D8C4D7 /* YPBool.m in Sources */ = {isa = PBXBuildFile; fileRef = 198E624D19334C8200D8C4D7 /* YPBool.m */; }; 20 | 198E62511933563100D8C4D7 /* YPName.m in Sources */ = {isa = PBXBuildFile; fileRef = 198E62501933563100D8C4D7 /* YPName.m */; }; 21 | 1991B7C0192D4A4C009C06FC /* Utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 1991B7BF192D4A4C009C06FC /* Utils.c */; }; 22 | 19958FC41935C3880018467C /* YPPages.m in Sources */ = {isa = PBXBuildFile; fileRef = 19958FC31935C3880018467C /* YPPages.m */; }; 23 | 19D8FF471933FB79003D557C /* YPNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 19D8FF461933FB79003D557C /* YPNumber.m */; }; 24 | 3E02FE1B1C6B88BD0093CEEF /* YPObjectStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E02FE1A1C6B88BD0093CEEF /* YPObjectStream.m */; }; 25 | 3E114A2E1C6E9DBD00664230 /* YPXref.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E114A2D1C6E9DBD00664230 /* YPXref.m */; }; 26 | 3E114A2F1C6E9DBD00664230 /* YPXref.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E114A2D1C6E9DBD00664230 /* YPXref.m */; }; 27 | 3E5BFA551C6D3C050087630B /* libz.1.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E5BFA531C6D3B910087630B /* libz.1.dylib */; }; 28 | 3E5BFA641C6D41930087630B /* YAPDFKit_TestSuite.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E5BFA631C6D41930087630B /* YAPDFKit_TestSuite.m */; }; 29 | 3E5BFA6A1C6D428B0087630B /* YPHexString.m in Sources */ = {isa = PBXBuildFile; fileRef = 198E624A193342C900D8C4D7 /* YPHexString.m */; }; 30 | 3E5BFA6C1C6D428B0087630B /* YPDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 198E62411933420700D8C4D7 /* YPDictionary.m */; }; 31 | 3E5BFA6E1C6D428B0087630B /* YPArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 198E62441933422400D8C4D7 /* YPArray.m */; }; 32 | 3E5BFA701C6D428B0087630B /* YPBool.m in Sources */ = {isa = PBXBuildFile; fileRef = 198E624D19334C8200D8C4D7 /* YPBool.m */; }; 33 | 3E5BFA721C6D428B0087630B /* YPName.m in Sources */ = {isa = PBXBuildFile; fileRef = 198E62501933563100D8C4D7 /* YPName.m */; }; 34 | 3E5BFA741C6D428B0087630B /* YPString.m in Sources */ = {isa = PBXBuildFile; fileRef = 198E6247193342AF00D8C4D7 /* YPString.m */; }; 35 | 3E5BFA761C6D428B0087630B /* pdfzlib.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EC10EA51C62CA140079C21C /* pdfzlib.m */; }; 36 | 3E5BFA781C6D428B0087630B /* Utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 1991B7BF192D4A4C009C06FC /* Utils.c */; }; 37 | 3E5BFA7A1C6D428B0087630B /* YPNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 19D8FF461933FB79003D557C /* YPNumber.m */; }; 38 | 3E5BFA7C1C6D428B0087630B /* YPObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 198807651929F2F300D2770D /* YPObject.m */; }; 39 | 3E5BFA7E1C6D428B0087630B /* YPObjectStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E02FE1A1C6B88BD0093CEEF /* YPObjectStream.m */; }; 40 | 3E5BFA801C6D428B0087630B /* YPDocument.m in Sources */ = {isa = PBXBuildFile; fileRef = 192F1D26191E483800D98CB6 /* YPDocument.m */; }; 41 | 3E5BFA821C6D428B0087630B /* YPPages.m in Sources */ = {isa = PBXBuildFile; fileRef = 19958FC31935C3880018467C /* YPPages.m */; }; 42 | 3E5BFA841C6D428B0087630B /* YPObjectReference.m in Sources */ = {isa = PBXBuildFile; fileRef = 19871300192FFB290022A279 /* YPObjectReference.m */; }; 43 | 3E5BFA851C6D43310087630B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 198DDE8B191E279B00B11929 /* Foundation.framework */; }; 44 | 3E5BFA871C6D45C00087630B /* libz.1.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E5BFA531C6D3B910087630B /* libz.1.dylib */; }; 45 | 3E5BFA891C6DDF020087630B /* 2-page-pages-export.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 3E5BFA881C6DDF020087630B /* 2-page-pages-export.pdf */; }; 46 | 3E9250941C73471400744747 /* YPAttribute.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E9250931C73471400744747 /* YPAttribute.m */; }; 47 | 3E9250951C73471400744747 /* YPAttribute.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E9250931C73471400744747 /* YPAttribute.m */; }; 48 | 3E9250A11C7B68C800744747 /* 2-page-pages-export.pdf in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3E5BFA881C6DDF020087630B /* 2-page-pages-export.pdf */; }; 49 | 3EC10EA61C62CA140079C21C /* pdfzlib.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EC10EA51C62CA140079C21C /* pdfzlib.m */; }; 50 | /* End PBXBuildFile section */ 51 | 52 | /* Begin PBXCopyFilesBuildPhase section */ 53 | 198DDE86191E279B00B11929 /* CopyFiles */ = { 54 | isa = PBXCopyFilesBuildPhase; 55 | buildActionMask = 12; 56 | dstPath = /tmp; 57 | dstSubfolderSpec = 0; 58 | files = ( 59 | 3E9250A11C7B68C800744747 /* 2-page-pages-export.pdf in CopyFiles */, 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | /* End PBXCopyFilesBuildPhase section */ 64 | 65 | /* Begin PBXFileReference section */ 66 | 192F1D25191E483800D98CB6 /* YPDocument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = YPDocument.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 67 | 192F1D26191E483800D98CB6 /* YPDocument.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = YPDocument.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 68 | 198712FF192FFB290022A279 /* YPObjectReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YPObjectReference.h; sourceTree = ""; }; 69 | 19871300192FFB290022A279 /* YPObjectReference.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YPObjectReference.m; sourceTree = ""; }; 70 | 198807641929F2F300D2770D /* YPObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YPObject.h; sourceTree = ""; }; 71 | 198807651929F2F300D2770D /* YPObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YPObject.m; sourceTree = ""; }; 72 | 198A6A3D194C885E0085588C /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 73 | 198DDE88191E279B00B11929 /* YAPDFKit */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = YAPDFKit; sourceTree = BUILT_PRODUCTS_DIR; }; 74 | 198DDE8B191E279B00B11929 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 75 | 198DDE8E191E279B00B11929 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = main.m; path = YAPDFKit/main.m; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 76 | 198DDE91191E279B00B11929 /* YAPDFKit-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "YAPDFKit-Prefix.pch"; sourceTree = ""; }; 77 | 198E62401933420700D8C4D7 /* YPDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = YPDictionary.h; sourceTree = ""; }; 78 | 198E62411933420700D8C4D7 /* YPDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = YPDictionary.m; sourceTree = ""; }; 79 | 198E62431933422400D8C4D7 /* YPArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = YPArray.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 80 | 198E62441933422400D8C4D7 /* YPArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = YPArray.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 81 | 198E6246193342AF00D8C4D7 /* YPString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YPString.h; sourceTree = ""; }; 82 | 198E6247193342AF00D8C4D7 /* YPString.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YPString.m; sourceTree = ""; }; 83 | 198E6249193342C900D8C4D7 /* YPHexString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YPHexString.h; sourceTree = ""; }; 84 | 198E624A193342C900D8C4D7 /* YPHexString.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YPHexString.m; sourceTree = ""; }; 85 | 198E624C19334C8200D8C4D7 /* YPBool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = YPBool.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 86 | 198E624D19334C8200D8C4D7 /* YPBool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = YPBool.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 87 | 198E624F1933563100D8C4D7 /* YPName.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YPName.h; sourceTree = ""; }; 88 | 198E62501933563100D8C4D7 /* YPName.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YPName.m; sourceTree = ""; }; 89 | 1991B7BE192D4A1B009C06FC /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Utils.h; sourceTree = ""; }; 90 | 1991B7BF192D4A4C009C06FC /* Utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Utils.c; sourceTree = ""; }; 91 | 19958FC21935C3880018467C /* YPPages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YPPages.h; sourceTree = ""; }; 92 | 19958FC31935C3880018467C /* YPPages.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YPPages.m; sourceTree = ""; }; 93 | 19D8FF451933FB79003D557C /* YPNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YPNumber.h; sourceTree = ""; }; 94 | 19D8FF461933FB79003D557C /* YPNumber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YPNumber.m; sourceTree = ""; }; 95 | 3E02FE171C6B75810093CEEF /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 96 | 3E02FE191C6B88BC0093CEEF /* YPObjectStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YPObjectStream.h; sourceTree = ""; }; 97 | 3E02FE1A1C6B88BD0093CEEF /* YPObjectStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YPObjectStream.m; sourceTree = ""; }; 98 | 3E114A2C1C6E9DBD00664230 /* YPXref.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YPXref.h; sourceTree = ""; }; 99 | 3E114A2D1C6E9DBD00664230 /* YPXref.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YPXref.m; sourceTree = ""; }; 100 | 3E5BFA531C6D3B910087630B /* libz.1.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.1.dylib; path = ../../../../../usr/lib/libz.1.dylib; sourceTree = ""; }; 101 | 3E5BFA611C6D41930087630B /* YAPDFKit-TestSuite.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "YAPDFKit-TestSuite.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 102 | 3E5BFA631C6D41930087630B /* YAPDFKit_TestSuite.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = YAPDFKit_TestSuite.m; sourceTree = ""; }; 103 | 3E5BFA651C6D41930087630B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 104 | 3E5BFA881C6DDF020087630B /* 2-page-pages-export.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = "2-page-pages-export.pdf"; sourceTree = ""; }; 105 | 3E9250921C73471400744747 /* YPAttribute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YPAttribute.h; sourceTree = ""; }; 106 | 3E9250931C73471400744747 /* YPAttribute.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YPAttribute.m; sourceTree = ""; }; 107 | 3EC10EA41C62CA140079C21C /* pdfzlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pdfzlib.h; sourceTree = ""; }; 108 | 3EC10EA51C62CA140079C21C /* pdfzlib.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = pdfzlib.m; sourceTree = ""; }; 109 | /* End PBXFileReference section */ 110 | 111 | /* Begin PBXFrameworksBuildPhase section */ 112 | 198DDE85191E279B00B11929 /* Frameworks */ = { 113 | isa = PBXFrameworksBuildPhase; 114 | buildActionMask = 2147483647; 115 | files = ( 116 | 3E5BFA551C6D3C050087630B /* libz.1.dylib in Frameworks */, 117 | 198DDE8C191E279B00B11929 /* Foundation.framework in Frameworks */, 118 | ); 119 | runOnlyForDeploymentPostprocessing = 0; 120 | }; 121 | 3E5BFA5E1C6D41930087630B /* Frameworks */ = { 122 | isa = PBXFrameworksBuildPhase; 123 | buildActionMask = 2147483647; 124 | files = ( 125 | 3E5BFA871C6D45C00087630B /* libz.1.dylib in Frameworks */, 126 | 3E5BFA851C6D43310087630B /* Foundation.framework in Frameworks */, 127 | ); 128 | runOnlyForDeploymentPostprocessing = 0; 129 | }; 130 | /* End PBXFrameworksBuildPhase section */ 131 | 132 | /* Begin PBXGroup section */ 133 | 198DDE7F191E279B00B11929 = { 134 | isa = PBXGroup; 135 | children = ( 136 | 3E02FE171C6B75810093CEEF /* README.md */, 137 | 198DDE8D191E279B00B11929 /* YAPDFKit */, 138 | 3E5BFA621C6D41930087630B /* YAPDFKit-TestSuite */, 139 | 198DDE8A191E279B00B11929 /* Frameworks */, 140 | 198DDE89191E279B00B11929 /* Products */, 141 | ); 142 | sourceTree = ""; 143 | }; 144 | 198DDE89191E279B00B11929 /* Products */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 198DDE88191E279B00B11929 /* YAPDFKit */, 148 | 3E5BFA611C6D41930087630B /* YAPDFKit-TestSuite.xctest */, 149 | ); 150 | name = Products; 151 | sourceTree = ""; 152 | }; 153 | 198DDE8A191E279B00B11929 /* Frameworks */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | 3E5BFA531C6D3B910087630B /* libz.1.dylib */, 157 | 198DDE8B191E279B00B11929 /* Foundation.framework */, 158 | 198A6A3D194C885E0085588C /* XCTest.framework */, 159 | ); 160 | name = Frameworks; 161 | sourceTree = ""; 162 | }; 163 | 198DDE8D191E279B00B11929 /* YAPDFKit */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | 3EC10EA81C64DD2D0079C21C /* ObjectAttributes */, 167 | 3EC10EA71C64DCF90079C21C /* Utils */, 168 | 198807641929F2F300D2770D /* YPObject.h */, 169 | 198807651929F2F300D2770D /* YPObject.m */, 170 | 3E9250921C73471400744747 /* YPAttribute.h */, 171 | 3E9250931C73471400744747 /* YPAttribute.m */, 172 | 192F1D25191E483800D98CB6 /* YPDocument.h */, 173 | 192F1D26191E483800D98CB6 /* YPDocument.m */, 174 | 3E114A2C1C6E9DBD00664230 /* YPXref.h */, 175 | 3E114A2D1C6E9DBD00664230 /* YPXref.m */, 176 | 19958FC21935C3880018467C /* YPPages.h */, 177 | 19958FC31935C3880018467C /* YPPages.m */, 178 | 198DDE8E191E279B00B11929 /* main.m */, 179 | 198DDE90191E279B00B11929 /* Supporting Files */, 180 | ); 181 | path = YAPDFKit; 182 | sourceTree = ""; 183 | }; 184 | 198DDE90191E279B00B11929 /* Supporting Files */ = { 185 | isa = PBXGroup; 186 | children = ( 187 | 3E5BFA881C6DDF020087630B /* 2-page-pages-export.pdf */, 188 | 198DDE91191E279B00B11929 /* YAPDFKit-Prefix.pch */, 189 | ); 190 | name = "Supporting Files"; 191 | sourceTree = ""; 192 | }; 193 | 3E5BFA621C6D41930087630B /* YAPDFKit-TestSuite */ = { 194 | isa = PBXGroup; 195 | children = ( 196 | 3E5BFA631C6D41930087630B /* YAPDFKit_TestSuite.m */, 197 | 3E5BFA651C6D41930087630B /* Info.plist */, 198 | ); 199 | path = "YAPDFKit-TestSuite"; 200 | sourceTree = ""; 201 | }; 202 | 3EC10EA71C64DCF90079C21C /* Utils */ = { 203 | isa = PBXGroup; 204 | children = ( 205 | 3EC10EA41C62CA140079C21C /* pdfzlib.h */, 206 | 3EC10EA51C62CA140079C21C /* pdfzlib.m */, 207 | 1991B7BE192D4A1B009C06FC /* Utils.h */, 208 | 1991B7BF192D4A4C009C06FC /* Utils.c */, 209 | ); 210 | name = Utils; 211 | sourceTree = ""; 212 | }; 213 | 3EC10EA81C64DD2D0079C21C /* ObjectAttributes */ = { 214 | isa = PBXGroup; 215 | children = ( 216 | 19D8FF451933FB79003D557C /* YPNumber.h */, 217 | 19D8FF461933FB79003D557C /* YPNumber.m */, 218 | 198712FF192FFB290022A279 /* YPObjectReference.h */, 219 | 19871300192FFB290022A279 /* YPObjectReference.m */, 220 | 3E02FE191C6B88BC0093CEEF /* YPObjectStream.h */, 221 | 3E02FE1A1C6B88BD0093CEEF /* YPObjectStream.m */, 222 | 198E62401933420700D8C4D7 /* YPDictionary.h */, 223 | 198E62411933420700D8C4D7 /* YPDictionary.m */, 224 | 198E6249193342C900D8C4D7 /* YPHexString.h */, 225 | 198E624A193342C900D8C4D7 /* YPHexString.m */, 226 | 198E62431933422400D8C4D7 /* YPArray.h */, 227 | 198E62441933422400D8C4D7 /* YPArray.m */, 228 | 198E624C19334C8200D8C4D7 /* YPBool.h */, 229 | 198E624D19334C8200D8C4D7 /* YPBool.m */, 230 | 198E624F1933563100D8C4D7 /* YPName.h */, 231 | 198E62501933563100D8C4D7 /* YPName.m */, 232 | 198E6246193342AF00D8C4D7 /* YPString.h */, 233 | 198E6247193342AF00D8C4D7 /* YPString.m */, 234 | ); 235 | name = ObjectAttributes; 236 | sourceTree = ""; 237 | }; 238 | /* End PBXGroup section */ 239 | 240 | /* Begin PBXNativeTarget section */ 241 | 198DDE87191E279B00B11929 /* YAPDFKit */ = { 242 | isa = PBXNativeTarget; 243 | buildConfigurationList = 198DDE96191E279B00B11929 /* Build configuration list for PBXNativeTarget "YAPDFKit" */; 244 | buildPhases = ( 245 | 198DDE84191E279B00B11929 /* Sources */, 246 | 198DDE85191E279B00B11929 /* Frameworks */, 247 | 198DDE86191E279B00B11929 /* CopyFiles */, 248 | 3E92509F1C7B678A00744747 /* Resources */, 249 | ); 250 | buildRules = ( 251 | ); 252 | dependencies = ( 253 | ); 254 | name = YAPDFKit; 255 | productName = Parser; 256 | productReference = 198DDE88191E279B00B11929 /* YAPDFKit */; 257 | productType = "com.apple.product-type.tool"; 258 | }; 259 | 3E5BFA601C6D41930087630B /* YAPDFKit-TestSuite */ = { 260 | isa = PBXNativeTarget; 261 | buildConfigurationList = 3E5BFA661C6D41930087630B /* Build configuration list for PBXNativeTarget "YAPDFKit-TestSuite" */; 262 | buildPhases = ( 263 | 3E5BFA5D1C6D41930087630B /* Sources */, 264 | 3E5BFA5E1C6D41930087630B /* Frameworks */, 265 | 3E5BFA5F1C6D41930087630B /* Resources */, 266 | ); 267 | buildRules = ( 268 | ); 269 | dependencies = ( 270 | ); 271 | name = "YAPDFKit-TestSuite"; 272 | productName = "YAPDFKit-TestSuite"; 273 | productReference = 3E5BFA611C6D41930087630B /* YAPDFKit-TestSuite.xctest */; 274 | productType = "com.apple.product-type.bundle.unit-test"; 275 | }; 276 | /* End PBXNativeTarget section */ 277 | 278 | /* Begin PBXProject section */ 279 | 198DDE80191E279B00B11929 /* Project object */ = { 280 | isa = PBXProject; 281 | attributes = { 282 | CLASSPREFIX = ""; 283 | LastUpgradeCheck = 0720; 284 | ORGANIZATIONNAME = Lingewoud; 285 | TargetAttributes = { 286 | 3E5BFA601C6D41930087630B = { 287 | CreatedOnToolsVersion = 7.2.1; 288 | }; 289 | }; 290 | }; 291 | buildConfigurationList = 198DDE83191E279B00B11929 /* Build configuration list for PBXProject "YAPDFKit" */; 292 | compatibilityVersion = "Xcode 3.2"; 293 | developmentRegion = English; 294 | hasScannedForEncodings = 0; 295 | knownRegions = ( 296 | en, 297 | ); 298 | mainGroup = 198DDE7F191E279B00B11929; 299 | productRefGroup = 198DDE89191E279B00B11929 /* Products */; 300 | projectDirPath = ""; 301 | projectRoot = ""; 302 | targets = ( 303 | 198DDE87191E279B00B11929 /* YAPDFKit */, 304 | 3E5BFA601C6D41930087630B /* YAPDFKit-TestSuite */, 305 | ); 306 | }; 307 | /* End PBXProject section */ 308 | 309 | /* Begin PBXResourcesBuildPhase section */ 310 | 3E5BFA5F1C6D41930087630B /* Resources */ = { 311 | isa = PBXResourcesBuildPhase; 312 | buildActionMask = 2147483647; 313 | files = ( 314 | 3E5BFA891C6DDF020087630B /* 2-page-pages-export.pdf in Resources */, 315 | ); 316 | runOnlyForDeploymentPostprocessing = 0; 317 | }; 318 | 3E92509F1C7B678A00744747 /* Resources */ = { 319 | isa = PBXResourcesBuildPhase; 320 | buildActionMask = 2147483647; 321 | files = ( 322 | ); 323 | runOnlyForDeploymentPostprocessing = 0; 324 | }; 325 | /* End PBXResourcesBuildPhase section */ 326 | 327 | /* Begin PBXSourcesBuildPhase section */ 328 | 198DDE84191E279B00B11929 /* Sources */ = { 329 | isa = PBXSourcesBuildPhase; 330 | buildActionMask = 2147483647; 331 | files = ( 332 | 198DDE8F191E279B00B11929 /* main.m in Sources */, 333 | 3E114A2E1C6E9DBD00664230 /* YPXref.m in Sources */, 334 | 3E9250941C73471400744747 /* YPAttribute.m in Sources */, 335 | 198E62421933420700D8C4D7 /* YPDictionary.m in Sources */, 336 | 3EC10EA61C62CA140079C21C /* pdfzlib.m in Sources */, 337 | 19958FC41935C3880018467C /* YPPages.m in Sources */, 338 | 1991B7C0192D4A4C009C06FC /* Utils.c in Sources */, 339 | 198807661929F2F300D2770D /* YPObject.m in Sources */, 340 | 198E6248193342AF00D8C4D7 /* YPString.m in Sources */, 341 | 192F1D27191E483800D98CB6 /* YPDocument.m in Sources */, 342 | 3E02FE1B1C6B88BD0093CEEF /* YPObjectStream.m in Sources */, 343 | 198E62511933563100D8C4D7 /* YPName.m in Sources */, 344 | 19871301192FFB290022A279 /* YPObjectReference.m in Sources */, 345 | 198E624B193342C900D8C4D7 /* YPHexString.m in Sources */, 346 | 198E62451933422400D8C4D7 /* YPArray.m in Sources */, 347 | 198E624E19334C8200D8C4D7 /* YPBool.m in Sources */, 348 | 19D8FF471933FB79003D557C /* YPNumber.m in Sources */, 349 | ); 350 | runOnlyForDeploymentPostprocessing = 0; 351 | }; 352 | 3E5BFA5D1C6D41930087630B /* Sources */ = { 353 | isa = PBXSourcesBuildPhase; 354 | buildActionMask = 2147483647; 355 | files = ( 356 | 3E5BFA6A1C6D428B0087630B /* YPHexString.m in Sources */, 357 | 3E5BFA6C1C6D428B0087630B /* YPDictionary.m in Sources */, 358 | 3E9250951C73471400744747 /* YPAttribute.m in Sources */, 359 | 3E5BFA6E1C6D428B0087630B /* YPArray.m in Sources */, 360 | 3E5BFA701C6D428B0087630B /* YPBool.m in Sources */, 361 | 3E5BFA721C6D428B0087630B /* YPName.m in Sources */, 362 | 3E5BFA741C6D428B0087630B /* YPString.m in Sources */, 363 | 3E114A2F1C6E9DBD00664230 /* YPXref.m in Sources */, 364 | 3E5BFA761C6D428B0087630B /* pdfzlib.m in Sources */, 365 | 3E5BFA781C6D428B0087630B /* Utils.c in Sources */, 366 | 3E5BFA7A1C6D428B0087630B /* YPNumber.m in Sources */, 367 | 3E5BFA7C1C6D428B0087630B /* YPObject.m in Sources */, 368 | 3E5BFA7E1C6D428B0087630B /* YPObjectStream.m in Sources */, 369 | 3E5BFA801C6D428B0087630B /* YPDocument.m in Sources */, 370 | 3E5BFA821C6D428B0087630B /* YPPages.m in Sources */, 371 | 3E5BFA841C6D428B0087630B /* YPObjectReference.m in Sources */, 372 | 3E5BFA641C6D41930087630B /* YAPDFKit_TestSuite.m in Sources */, 373 | ); 374 | runOnlyForDeploymentPostprocessing = 0; 375 | }; 376 | /* End PBXSourcesBuildPhase section */ 377 | 378 | /* Begin XCBuildConfiguration section */ 379 | 198DDE94191E279B00B11929 /* Debug */ = { 380 | isa = XCBuildConfiguration; 381 | buildSettings = { 382 | ALWAYS_SEARCH_USER_PATHS = NO; 383 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 384 | CLANG_CXX_LIBRARY = "libc++"; 385 | CLANG_ENABLE_MODULES = YES; 386 | CLANG_ENABLE_OBJC_ARC = YES; 387 | CLANG_WARN_BOOL_CONVERSION = YES; 388 | CLANG_WARN_CONSTANT_CONVERSION = YES; 389 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 390 | CLANG_WARN_EMPTY_BODY = YES; 391 | CLANG_WARN_ENUM_CONVERSION = YES; 392 | CLANG_WARN_INT_CONVERSION = YES; 393 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 394 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 395 | COPY_PHASE_STRIP = NO; 396 | ENABLE_TESTABILITY = YES; 397 | GCC_C_LANGUAGE_STANDARD = gnu99; 398 | GCC_DYNAMIC_NO_PIC = NO; 399 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 400 | GCC_OPTIMIZATION_LEVEL = 0; 401 | GCC_PREPROCESSOR_DEFINITIONS = ( 402 | "DEBUG=1", 403 | "$(inherited)", 404 | ); 405 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 406 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 407 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 408 | GCC_WARN_UNDECLARED_SELECTOR = YES; 409 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 410 | GCC_WARN_UNUSED_FUNCTION = YES; 411 | GCC_WARN_UNUSED_VARIABLE = YES; 412 | MACOSX_DEPLOYMENT_TARGET = 10.7; 413 | ONLY_ACTIVE_ARCH = YES; 414 | SDKROOT = macosx; 415 | }; 416 | name = Debug; 417 | }; 418 | 198DDE95191E279B00B11929 /* Release */ = { 419 | isa = XCBuildConfiguration; 420 | buildSettings = { 421 | ALWAYS_SEARCH_USER_PATHS = NO; 422 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 423 | CLANG_CXX_LIBRARY = "libc++"; 424 | CLANG_ENABLE_MODULES = YES; 425 | CLANG_ENABLE_OBJC_ARC = YES; 426 | CLANG_WARN_BOOL_CONVERSION = YES; 427 | CLANG_WARN_CONSTANT_CONVERSION = YES; 428 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 429 | CLANG_WARN_EMPTY_BODY = YES; 430 | CLANG_WARN_ENUM_CONVERSION = YES; 431 | CLANG_WARN_INT_CONVERSION = YES; 432 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 433 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 434 | COPY_PHASE_STRIP = YES; 435 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 436 | ENABLE_NS_ASSERTIONS = NO; 437 | GCC_C_LANGUAGE_STANDARD = gnu99; 438 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 439 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 440 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 441 | GCC_WARN_UNDECLARED_SELECTOR = YES; 442 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 443 | GCC_WARN_UNUSED_FUNCTION = YES; 444 | GCC_WARN_UNUSED_VARIABLE = YES; 445 | MACOSX_DEPLOYMENT_TARGET = 10.7; 446 | SDKROOT = macosx; 447 | }; 448 | name = Release; 449 | }; 450 | 198DDE97191E279B00B11929 /* Debug */ = { 451 | isa = XCBuildConfiguration; 452 | buildSettings = { 453 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 454 | GCC_PREFIX_HEADER = "YAPDFKit/YAPDFKit-Prefix.pch"; 455 | PRODUCT_NAME = YAPDFKit; 456 | }; 457 | name = Debug; 458 | }; 459 | 198DDE98191E279B00B11929 /* Release */ = { 460 | isa = XCBuildConfiguration; 461 | buildSettings = { 462 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 463 | GCC_PREFIX_HEADER = "YAPDFKit/YAPDFKit-Prefix.pch"; 464 | PRODUCT_NAME = YAPDFKit; 465 | }; 466 | name = Release; 467 | }; 468 | 3E5BFA671C6D41930087630B /* Debug */ = { 469 | isa = XCBuildConfiguration; 470 | buildSettings = { 471 | CLANG_WARN_UNREACHABLE_CODE = YES; 472 | CODE_SIGN_IDENTITY = "-"; 473 | COMBINE_HIDPI_IMAGES = YES; 474 | DEBUG_INFORMATION_FORMAT = dwarf; 475 | ENABLE_STRICT_OBJC_MSGSEND = YES; 476 | ENABLE_TESTABILITY = YES; 477 | GCC_NO_COMMON_BLOCKS = YES; 478 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 479 | GCC_PREFIX_HEADER = "YAPDFKit/YAPDFKit-Prefix.pch"; 480 | INFOPLIST_FILE = "YAPDFKit-TestSuite/Info.plist"; 481 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 482 | MACOSX_DEPLOYMENT_TARGET = 10.11; 483 | MTL_ENABLE_DEBUG_INFO = YES; 484 | PRODUCT_BUNDLE_IDENTIFIER = "com.lingewoud.YAPDFKit-TestSuite"; 485 | PRODUCT_NAME = "$(TARGET_NAME)"; 486 | }; 487 | name = Debug; 488 | }; 489 | 3E5BFA681C6D41930087630B /* Release */ = { 490 | isa = XCBuildConfiguration; 491 | buildSettings = { 492 | CLANG_WARN_UNREACHABLE_CODE = YES; 493 | CODE_SIGN_IDENTITY = "-"; 494 | COMBINE_HIDPI_IMAGES = YES; 495 | COPY_PHASE_STRIP = NO; 496 | ENABLE_STRICT_OBJC_MSGSEND = YES; 497 | GCC_NO_COMMON_BLOCKS = YES; 498 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 499 | GCC_PREFIX_HEADER = "YAPDFKit/YAPDFKit-Prefix.pch"; 500 | INFOPLIST_FILE = "YAPDFKit-TestSuite/Info.plist"; 501 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 502 | MACOSX_DEPLOYMENT_TARGET = 10.11; 503 | MTL_ENABLE_DEBUG_INFO = NO; 504 | PRODUCT_BUNDLE_IDENTIFIER = "com.lingewoud.YAPDFKit-TestSuite"; 505 | PRODUCT_NAME = "$(TARGET_NAME)"; 506 | }; 507 | name = Release; 508 | }; 509 | /* End XCBuildConfiguration section */ 510 | 511 | /* Begin XCConfigurationList section */ 512 | 198DDE83191E279B00B11929 /* Build configuration list for PBXProject "YAPDFKit" */ = { 513 | isa = XCConfigurationList; 514 | buildConfigurations = ( 515 | 198DDE94191E279B00B11929 /* Debug */, 516 | 198DDE95191E279B00B11929 /* Release */, 517 | ); 518 | defaultConfigurationIsVisible = 0; 519 | defaultConfigurationName = Release; 520 | }; 521 | 198DDE96191E279B00B11929 /* Build configuration list for PBXNativeTarget "YAPDFKit" */ = { 522 | isa = XCConfigurationList; 523 | buildConfigurations = ( 524 | 198DDE97191E279B00B11929 /* Debug */, 525 | 198DDE98191E279B00B11929 /* Release */, 526 | ); 527 | defaultConfigurationIsVisible = 0; 528 | defaultConfigurationName = Release; 529 | }; 530 | 3E5BFA661C6D41930087630B /* Build configuration list for PBXNativeTarget "YAPDFKit-TestSuite" */ = { 531 | isa = XCConfigurationList; 532 | buildConfigurations = ( 533 | 3E5BFA671C6D41930087630B /* Debug */, 534 | 3E5BFA681C6D41930087630B /* Release */, 535 | ); 536 | defaultConfigurationIsVisible = 0; 537 | defaultConfigurationName = Release; 538 | }; 539 | /* End XCConfigurationList section */ 540 | }; 541 | rootObject = 198DDE80191E279B00B11929 /* Project object */; 542 | } 543 | -------------------------------------------------------------------------------- /YAPDFKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /YAPDFKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /YAPDFKit.xcodeproj/project.xcworkspace/xcshareddata/Parser.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | C533055F-79EA-40BF-9D59-39C9AEBCD206 9 | IDESourceControlProjectName 10 | Parser 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | C3584FEB-5AC8-4386-A103-5050E1AD9BD2 14 | https://github.com/kozliappi/PDFCoolParser.git 15 | 16 | IDESourceControlProjectPath 17 | Parser.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | C3584FEB-5AC8-4386-A103-5050E1AD9BD2 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/kozliappi/PDFCoolParser.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | C3584FEB-5AC8-4386-A103-5050E1AD9BD2 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | C3584FEB-5AC8-4386-A103-5050E1AD9BD2 36 | IDESourceControlWCCName 37 | Parser 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /YAPDFKit.xcodeproj/xcshareddata/xcschemes/YAPDFKit-TestSuite.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 55 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 74 | 80 | 81 | 82 | 83 | 85 | 86 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /YAPDFKit.xcodeproj/xcshareddata/xcschemes/YAPDFKit.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /YAPDFKit.xcodeproj/xcuserdata/pim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /YAPDFKit.xcodeproj/xcuserdata/pim.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | YAPDFKit-TestSuite.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 2 11 | 12 | YAPDFKit.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 198A6A3B194C885E0085588C 21 | 22 | primary 23 | 24 | 25 | 198DDE87191E279B00B11929 26 | 27 | primary 28 | 29 | 30 | 3E5BFA601C6D41930087630B 31 | 32 | primary 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /YAPDFKit/2-page-pages-export.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdfletterhead/YAPDFKit/ae6dc0a899259c3458b3d1c3225b8fefd05da49d/YAPDFKit/2-page-pages-export.pdf -------------------------------------------------------------------------------- /YAPDFKit/PDFParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // PDFParser.h 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 10.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PDFParser : NSObject 12 | { 13 | NSData *fileData; 14 | } 15 | 16 | - (void) setFileData:(NSString*)path; 17 | - (void) initWithContentsOfFile:(NSString*)path; 18 | 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /YAPDFKit/Utils.c: -------------------------------------------------------------------------------- 1 | // 2 | // Utils.c 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 22.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | 10 | #include 11 | 12 | int isBlank(char ch) 13 | { 14 | return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; 15 | } 16 | 17 | int isNum(char ch) 18 | { 19 | return '0' <= ch && ch <= '9'; 20 | } 21 | 22 | int isHexSymbol(char ch) 23 | { 24 | return ('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F'); 25 | } 26 | 27 | void skipBlankSymbols(const char * rawData, size_t *idx) 28 | { 29 | size_t i = *idx; 30 | 31 | while(rawData[i] == ' ' || rawData[i] == '\n' || rawData[i] == '\r' || rawData[i] == '\t') { 32 | i++; 33 | } 34 | 35 | *idx = i; 36 | } 37 | 38 | void dumpCharArray(const char * rawData, size_t size) 39 | { 40 | for (int j = 0; j < size; j++ ) { 41 | printf("%c", rawData[j]); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /YAPDFKit/Utils.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // Utils.h 4 | // YAPDFKit 5 | // 6 | // Created by Aliona on 22.05.14. 7 | // Copyright (c) 2014 Ptenster. All rights reserved. 8 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 9 | 10 | #ifndef Parser_Utils_h 11 | #define Parser_Utils_h 12 | 13 | /** 14 | * Проверяет, является ли символ ch пустым. Пустыми считаются 15 | * следующие символы: пробел, перенос строки и символ табуляции. 16 | * @return 1, если символ пустой и 0 если символ не пустой 17 | */ 18 | int isBlank(char ch); 19 | 20 | /** 21 | * Проверяет, является ли символ ch числом (0-9). 22 | * @return 1, если текущий символ - число и 0 в противном случае 23 | */ 24 | int isNum(char ch); 25 | 26 | /** 27 | * Проверяет, является ли символ ch символом шестнадцатеричной строки 28 | * [0-9] [a-f] [A-F] 29 | * @return 1, если является и 0 в противном случае 30 | */ 31 | int isHexSymbol(char ch); 32 | 33 | /** 34 | * Пропускает пустые символы (пробел, перенос строки и символ табуляции), 35 | * увеличивая индекс текущего символа. 36 | * @param rawData - текст, idx - номер текущего просматриваемого символа 37 | */ 38 | void skipBlankSymbols(const char * rawData, size_t *idx); 39 | 40 | void dumpCharArray(const char * rawData, size_t size); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /YAPDFKit/YAPDFKit-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #ifdef __OBJC__ 8 | #import 9 | #endif 10 | -------------------------------------------------------------------------------- /YAPDFKit/YPArray.h: -------------------------------------------------------------------------------- 1 | // 2 | // YPArray.h 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 26.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import 10 | 11 | /** 12 | * Тип PDF Array * 13 | * Массив может содержать любой другой тип объектов, 14 | * в том числе и массив. Элементы массива отделяются 15 | * друг от друга пробелами. 16 | */ 17 | @interface YPArray : NSArray 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /YAPDFKit/YPArray.m: -------------------------------------------------------------------------------- 1 | // 2 | // YPArray.m 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 26.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import "YPArray.h" 10 | 11 | @implementation YPArray 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /YAPDFKit/YPAttribute.h: -------------------------------------------------------------------------------- 1 | // 2 | // YPAttribute.h 3 | // YAPDFKit 4 | // 5 | // Created by Pim Snel on 16-02-16. 6 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface YPAttribute : NSObject 12 | 13 | @property NSString *attributeAsString; 14 | @property NSString *attributeType; 15 | 16 | - (id)initWithString:(NSString*)string; 17 | - (NSString*)determineAttributeType:(NSString*)string; 18 | @end 19 | -------------------------------------------------------------------------------- /YAPDFKit/YPAttribute.m: -------------------------------------------------------------------------------- 1 | // 2 | // YPAttribute.m 3 | // YAPDFKit 4 | // 5 | // Created by Pim Snel on 16-02-16. 6 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 7 | // 8 | 9 | #import "YPAttribute.h" 10 | 11 | @implementation YPAttribute 12 | @synthesize attributeAsString, attributeType; 13 | 14 | - (id)initWithString:(NSString*)string 15 | { 16 | if (self = [super init]) { 17 | 18 | attributeAsString = string; 19 | attributeType = [self determineAttributeType:string]; 20 | 21 | return self; 22 | } 23 | 24 | return nil; 25 | } 26 | 27 | - (NSString*)determineAttributeType:(NSString*)string 28 | { 29 | if([string isKindOfClass:[NSString class]]) 30 | { 31 | 32 | const char *cstring = [string UTF8String]; 33 | size_t len = strlen(cstring) + 1; 34 | 35 | char charString[len]; 36 | memcpy(charString, cstring, len); 37 | 38 | //ISNUMBER 39 | if(charString[0] == '+' || charString[0] == '-' || isdigit(charString[0])) 40 | { 41 | 42 | } 43 | 44 | //ISREFERENCE 45 | if(isdigit(charString[0])) 46 | { 47 | if([self isObjectReference:string]) 48 | { 49 | return @"reference"; 50 | } 51 | } 52 | 53 | //ISDICT 54 | if(charString[0]=='<') 55 | { 56 | 57 | } 58 | 59 | //ISARRAY 60 | if(charString[0]=='[') 61 | { 62 | 63 | } 64 | 65 | //ISSTRING 66 | if(charString[0]=='(') 67 | { 68 | 69 | } 70 | 71 | //ISNAME 72 | if(charString[0]=='/') 73 | { 74 | 75 | } 76 | 77 | //ISBOOL 78 | if(charString[0]=='f' || charString[0]=='t') 79 | { 80 | 81 | } 82 | 83 | //ISBINARYSTRING 84 | 85 | 86 | return @"unknown"; 87 | } 88 | else 89 | { 90 | return @"unknown"; 91 | } 92 | } 93 | 94 | - (BOOL)isObjectReference:(NSString*)string 95 | { 96 | NSArray *chunks = [string componentsSeparatedByString: @" "]; 97 | if([chunks count] == 3) 98 | { 99 | if([chunks[0] intValue]> 0 && [chunks[1] intValue] > 0 && [chunks[2] isEqualToString: @"R"]) 100 | { 101 | return YES; 102 | } 103 | } 104 | return NO; 105 | } 106 | 107 | @end 108 | -------------------------------------------------------------------------------- /YAPDFKit/YPBool.h: -------------------------------------------------------------------------------- 1 | // 2 | // YPBool.h 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 26.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import 10 | 11 | /** 12 | * Тип PDF Boolean * 13 | * Принимает значения true или false. 14 | */ 15 | @interface YPBool : NSObject 16 | 17 | /** 18 | * Значение: true или false 19 | */ 20 | @property (nonatomic) BOOL value; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /YAPDFKit/YPBool.m: -------------------------------------------------------------------------------- 1 | // 2 | // YPBool.m 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 26.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import "YPBool.h" 10 | 11 | @implementation YPBool 12 | 13 | @synthesize value; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /YAPDFKit/YPDictionary.h: -------------------------------------------------------------------------------- 1 | // 2 | // YPDictionary.h 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 26.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import 10 | 11 | /** 12 | * Тип PDF Dictionary * 13 | * Словарь состоит из пар "ключ-значение", где 14 | * ключом всегда является имя (PDF Name). Может 15 | * содержать тип (Type) и подтип (Subtype или S), 16 | * значения которых всегда имя (PDF Name). 17 | */ 18 | @interface YPDictionary : NSObject 19 | 20 | @property NSMutableDictionary* nsdict; 21 | 22 | -(id)initWithDictionary:(NSDictionary*) dict; 23 | -(id)objectForKey:(id)aKey; 24 | -(void)setObject:(id)anObject forKey:(id)aKey; 25 | -(void)removeObjectForKey:(id)aKey; 26 | -(NSString*) stringValue; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /YAPDFKit/YPDictionary.m: -------------------------------------------------------------------------------- 1 | // 2 | // YPDictionary.m 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 26.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import "YPDictionary.h" 10 | #import "YPObjectReference.h" 11 | 12 | @implementation YPDictionary 13 | 14 | @synthesize nsdict; 15 | 16 | -(id)initWithDictionary:(NSDictionary*) dict 17 | { 18 | if (self = [super init]) { 19 | 20 | //self = [self initWithDictionary:dict]; 21 | 22 | if(dict){ 23 | 24 | nsdict = [NSMutableDictionary dictionaryWithDictionary:dict]; 25 | } 26 | 27 | return self; 28 | } 29 | 30 | return nil; 31 | } 32 | 33 | -(id)objectForKey:(id)aKey 34 | { 35 | return nsdict[aKey]; 36 | } 37 | 38 | -(void)setObject:(id)anObject forKey:(id)aKey 39 | { 40 | nsdict[aKey] = anObject; 41 | } 42 | 43 | -(void)removeObjectForKey:(id)aKey 44 | { 45 | [nsdict removeObjectForKey:aKey]; 46 | } 47 | 48 | -(id)description 49 | { 50 | return nsdict; 51 | } 52 | 53 | -(NSString*) stringValue 54 | { 55 | NSMutableString* blockString = (NSMutableString*)@""; 56 | blockString = (NSMutableString*)[blockString stringByAppendingString:@"<< "]; 57 | 58 | for (NSString* key in nsdict ) { 59 | id value = [nsdict objectForKey:key]; 60 | 61 | blockString = (NSMutableString*)[blockString stringByAppendingFormat:@"/%@ ",key]; 62 | 63 | if ([value isKindOfClass:[NSString class]]) { 64 | 65 | blockString = (NSMutableString*)[blockString stringByAppendingFormat:@"/%@ ",value]; 66 | } 67 | else if([value isKindOfClass:[YPObjectReference class]]) { 68 | blockString = (NSMutableString*)[blockString stringByAppendingFormat:@"%@ ",value]; 69 | } 70 | else if([value isKindOfClass:[NSNumber class]]) { 71 | blockString = (NSMutableString*)[blockString stringByAppendingFormat:@"%@ ",value]; 72 | } 73 | } 74 | 75 | blockString = (NSMutableString*)[blockString stringByAppendingString:@">>\n"]; 76 | 77 | return (NSString*)blockString; 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /YAPDFKit/YPDocument.h: -------------------------------------------------------------------------------- 1 | // 2 | // YPDocument.h 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 10.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | // 9 | 10 | #import 11 | 12 | #import "YPObject.h" 13 | #import "YPXref.h" 14 | #import "YPPages.h" 15 | #import "YPObjectReference.h" 16 | #import "YPAttribute.h" 17 | #import "Utils.h" 18 | 19 | @class YPObject; 20 | 21 | @interface YPDocument : NSObject 22 | { 23 | NSString *_errorMessage; 24 | NSString *_version; 25 | // NSMutableDictionary *_contents; 26 | } 27 | 28 | @property NSMutableData* modifiedPDFData; 29 | @property NSMutableArray* updateObjectQueue; 30 | @property NSInteger *lastTrailerOffset; 31 | 32 | @property NSMutableDictionary* objects; 33 | @property NSInteger docSize; 34 | @property NSMutableArray* comments; 35 | 36 | - (id)initWithData:(NSData*)data; 37 | 38 | - (NSString*) version; 39 | - (NSString*) errorMessage; 40 | - (NSString*) getPDFInfo; 41 | - (NSString*) getDocumentCatalog; 42 | - (NSString*) getPDFMetaData; 43 | - (NSDictionary*) getObjectsWithStreams; 44 | - (NSArray*) getAllObjectsWithKey:(NSString *)key; 45 | - (NSArray*) getAllObjectsWithKey:(NSString *)key value:(NSString *)value; 46 | - (YPObject*) getObjectByNumber:(NSString*)number; 47 | 48 | - (BOOL)isBinary; 49 | - (id) getInfoForKey:(NSString *)key; 50 | - (id) getInfoForKey:(NSString *)key inObject:(NSString *)objectNumber; 51 | 52 | - (NSString *)getObjectNumberForKey:(NSString *)key value:(NSString*)value; 53 | - (NSDictionary*)allObjects; 54 | 55 | - (void) addObjectToUpdateQueue:(YPObject *)pdfObject; 56 | - (void) updateDocumentData; 57 | @end 58 | -------------------------------------------------------------------------------- /YAPDFKit/YPDocument.m: -------------------------------------------------------------------------------- 1 | // 2 | // YPDocument.m 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 10.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Modify by LiuQiang 3.23.16 8 | // mail:liulcsy@163.com 9 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 10 | 11 | 12 | #import "YPDocument.h" 13 | /* 14 | #import "YPObject.h" 15 | #import "YPXref.h" 16 | #import "YPPages.h" 17 | #import "YPObjectReference.h" 18 | #import "YPAttribute.h" 19 | #import "Utils.h" 20 | */ 21 | 22 | enum ParserStates { 23 | ERROR_STATE = -1, 24 | BEGIN_STATE = 0, 25 | FILL_VERSION_STATE, 26 | SEARCH_NEXT_PDF_STRUCTURE_STATE, 27 | NEXT_PDF_STRUCTURE_STATE, 28 | IN_PDF_COMMENT_STATE, 29 | IN_PDF_OBJECT_STATE, 30 | IN_PDF_XREF_STATE, 31 | DEFAULT_STATE, 32 | }; 33 | 34 | const char* strblock(const char* p, int(^func)(char ch)) 35 | { 36 | for (; *p && func(*p); ++p) { 37 | } 38 | return p; 39 | } 40 | 41 | @implementation YPDocument 42 | 43 | @synthesize objects; 44 | @synthesize comments; 45 | @synthesize docSize; 46 | @synthesize modifiedPDFData; 47 | @synthesize updateObjectQueue; 48 | @synthesize lastTrailerOffset; 49 | 50 | - (id)initWithData:(NSData*)data 51 | { 52 | if (self = [super init]) { 53 | 54 | _version = @""; 55 | objects = [[NSMutableDictionary alloc] init]; 56 | comments = [[NSMutableArray alloc] init]; 57 | docSize = [data length]; 58 | 59 | modifiedPDFData = [[NSMutableData alloc] initWithData:data]; 60 | updateObjectQueue = [[NSMutableArray alloc] init]; 61 | 62 | char *buffer = malloc(data.length + 1); 63 | memcpy(buffer, data.bytes, data.length); 64 | buffer[data.length] = 0; 65 | NSData *dataWithNull = [NSData dataWithBytes:buffer length:data.length + 1]; 66 | free(buffer); 67 | 68 | [self parseData:dataWithNull]; 69 | [self linkObjectsWithContents]; 70 | 71 | return self; 72 | } 73 | return nil; 74 | } 75 | 76 | - (NSDictionary*)allObjects 77 | { 78 | return objects; 79 | } 80 | 81 | - (NSString*)version 82 | { 83 | return _version; 84 | } 85 | 86 | - (NSString*)errorMessage 87 | { 88 | return _errorMessage; 89 | } 90 | 91 | - (void)parseData:(NSData*)data 92 | { 93 | enum ParserStates state = BEGIN_STATE; 94 | 95 | if (data.length < 5) { 96 | _errorMessage = @"Too short file"; 97 | return; 98 | } 99 | 100 | NSUInteger i = 0; 101 | 102 | while (i < data.length && _errorMessage == nil) { 103 | switch (state) { 104 | case BEGIN_STATE: 105 | state = [self handleBeginState:data idx:&i]; 106 | break; 107 | 108 | case FILL_VERSION_STATE: 109 | state = [self handleVersionState:data idx:&i]; 110 | break; 111 | 112 | case SEARCH_NEXT_PDF_STRUCTURE_STATE: 113 | state = [self handleSearchNextPDFStructureState:data idx:&i]; 114 | break; 115 | 116 | case NEXT_PDF_STRUCTURE_STATE: 117 | state = [self handleNextPDFStructureState:data idx:&i]; 118 | break; 119 | 120 | case IN_PDF_COMMENT_STATE: 121 | state = [self handleInPDFCommentState:data idx:&i]; 122 | break; 123 | 124 | case IN_PDF_OBJECT_STATE: 125 | state = [self handleInPDFObjectState:data idx:&i]; 126 | break; 127 | 128 | case IN_PDF_XREF_STATE: 129 | state = [self handleInPDFXrefState:data idx:&i]; 130 | break; 131 | 132 | default: 133 | ++i; 134 | break; 135 | } 136 | } 137 | } 138 | 139 | - (enum ParserStates)handleBeginState:(NSData*)data idx:(NSUInteger*)idx 140 | { 141 | const char *rawData = (const char *)[data bytes]; 142 | 143 | NSUInteger i = *idx; 144 | if(rawData[i] == '%') { 145 | char buffer[] = {rawData[i], rawData[i+1], rawData[i+2], rawData[i+3], rawData[i+4], 0}; 146 | if (strncmp("%PDF-", buffer, sizeof(buffer) / sizeof(char))) { 147 | _errorMessage = @"Failed to read pdf header"; 148 | return ERROR_STATE; 149 | } 150 | *idx += sizeof(buffer) - 1; 151 | return FILL_VERSION_STATE; 152 | } 153 | _errorMessage = @"File must begin with '%' symbol"; 154 | return ERROR_STATE; 155 | } 156 | 157 | - (enum ParserStates)handleVersionState:(NSData*)data idx:(NSUInteger*)idx 158 | { 159 | const char *rawData = (const char *)[data bytes]; 160 | 161 | NSUInteger i = *idx; 162 | for (; rawData[i] != '\r' && rawData[i] != '\n'; ++i) { 163 | char buffer[] = {rawData[i], 0}; 164 | _version = [_version stringByAppendingString:@(buffer)]; 165 | 166 | 167 | //NSDictionary *dict = [NSDictionary dictionaryWithObject:_version forKey:@"version"]; 168 | //[_objects addObject:dict]; 169 | } 170 | 171 | *idx = i; 172 | return SEARCH_NEXT_PDF_STRUCTURE_STATE; 173 | } 174 | 175 | - (enum ParserStates)handleSearchNextPDFStructureState:(NSData*)data idx:(NSUInteger*)idx 176 | { 177 | const char *rawData = (const char *)[data bytes]; 178 | 179 | NSUInteger i = *idx; 180 | for (; isBlank(rawData[i]); ++i) { 181 | } 182 | 183 | *idx = i; 184 | return NEXT_PDF_STRUCTURE_STATE; 185 | } 186 | 187 | - (enum ParserStates)handleNextPDFStructureState:(NSData*)data idx:(NSUInteger*)idx 188 | { 189 | const char *rawData = (const char *)[data bytes]; 190 | 191 | NSUInteger i = *idx; 192 | enum ParserStates state = ERROR_STATE; 193 | 194 | switch (rawData[i]) { 195 | case '%': 196 | state = IN_PDF_COMMENT_STATE; 197 | ++i; 198 | break; 199 | 200 | case 'x': 201 | state = IN_PDF_XREF_STATE; 202 | break; 203 | 204 | case '0': 205 | case '1': 206 | case '2': 207 | case '3': 208 | case '4': 209 | case '5': 210 | case '6': 211 | case '7': 212 | case '8': 213 | case '9': 214 | state = IN_PDF_OBJECT_STATE; 215 | break; 216 | 217 | default: 218 | state = DEFAULT_STATE; 219 | break; 220 | } 221 | *idx = i; 222 | return state; 223 | } 224 | 225 | - (enum ParserStates)handleInPDFCommentState:(NSData*)data idx:(NSUInteger*)idx 226 | { 227 | const char *rawData = (const char*)[data bytes]; 228 | NSUInteger i = *idx; 229 | 230 | NSUInteger endOfCommentIdx = i; 231 | while (rawData[endOfCommentIdx] != '\r' && rawData[endOfCommentIdx] != '\n' && endOfCommentIdx < data.length) { 232 | ++endOfCommentIdx; 233 | } 234 | char* buffer = malloc((endOfCommentIdx - i) + 1); 235 | memcpy(buffer, &rawData[i], (endOfCommentIdx - i) + 1); 236 | buffer[endOfCommentIdx - i] = 0; 237 | NSString* comment = [NSString stringWithCString:buffer encoding:NSASCIIStringEncoding]; 238 | i = endOfCommentIdx; 239 | 240 | [comments addObject:comment]; 241 | 242 | *idx = i; 243 | return SEARCH_NEXT_PDF_STRUCTURE_STATE; 244 | } 245 | 246 | - (enum ParserStates)handleInPDFObjectState:(NSData*)data idx:(NSUInteger*)idx 247 | { 248 | const char *rawData = (const char*)[data bytes]; 249 | NSUInteger dataLength = data.length; 250 | 251 | size_t i = *idx; 252 | NSString *firstObjNum = @""; 253 | NSString *secondObjNum = @""; 254 | 255 | for(; i < dataLength; ++i) { 256 | if(isNum(rawData[i])) { 257 | char buffer[] = {rawData[i], 0}; 258 | firstObjNum = [firstObjNum stringByAppendingString:@(buffer)]; 259 | } else { 260 | break; 261 | } 262 | } 263 | 264 | if (!isBlank(rawData[i])) { 265 | _errorMessage = @"Unknown object syntax"; 266 | return ERROR_STATE; 267 | } 268 | 269 | for (; i+3 < dataLength; ++i) { 270 | if (rawData[i] == ' ' && rawData[i+1] == 'o' && rawData[i+2] == 'b' && rawData[i+3] == 'j') { 271 | i += 4; 272 | break; 273 | } 274 | char buffer[] = {rawData[i], 0}; 275 | secondObjNum = [secondObjNum stringByAppendingString:@(buffer)]; 276 | } 277 | 278 | NSInteger first = [firstObjNum integerValue]; 279 | NSInteger second = [secondObjNum integerValue]; 280 | 281 | skipBlankSymbols(rawData, &i); 282 | 283 | const char* objBodyBegin = &rawData[i]; 284 | const char* objBodyEnd = &rawData[i]; 285 | 286 | for (; i+6 < dataLength; ++i) { 287 | if (rawData[i-1] != '\\' && rawData[i] == 'e' && rawData[i+1] == 'n' && rawData[i+2] == 'd' && rawData[i+3] == 'o' && rawData[i+4] == 'b' && rawData[i+5] == 'j') { 288 | objBodyEnd = &rawData[i-1]; 289 | i += 6; 290 | break; 291 | } 292 | } 293 | 294 | skipBlankSymbols(rawData, &i); 295 | NSData *objectData = NULL; 296 | 297 | if(objBodyEnd - objBodyBegin > 0) { 298 | objectData = [NSData dataWithBytes:objBodyBegin length:objBodyEnd - objBodyBegin]; 299 | } 300 | 301 | YPObject *p = [[YPObject alloc] initWithData:objectData first:&first second:&second]; 302 | [objects setObject:p forKey:[p getObjectNumber]]; 303 | 304 | *idx = i; 305 | return SEARCH_NEXT_PDF_STRUCTURE_STATE; 306 | } 307 | 308 | - (enum ParserStates)handleInPDFXrefState:(NSData*)data idx:(NSUInteger*)idx 309 | { 310 | size_t i = *idx; 311 | const char *rawData = (const char*)[data bytes]; 312 | NSUInteger dataLength = data.length; 313 | 314 | if(!(i+3 < dataLength && rawData[i] == 'x' && rawData[i+1] == 'r' && rawData[i+2] == 'e' && rawData[i+3] == 'f')) { 315 | _errorMessage = @"Xref unknown syntax"; 316 | return ERROR_STATE; 317 | } 318 | 319 | i += 4; 320 | const char* xrefBegin = &rawData[i]; 321 | const char* xrefEnd = NULL; 322 | 323 | for (; i+9 < dataLength; ++i) { 324 | if (rawData[i] == 't') { 325 | char buffer[] = {rawData[i], rawData[i+1], rawData[i+2], rawData[i+3], rawData[i+4], rawData[i+5], rawData[i+6], 0}; 326 | if (![@(buffer) isEqualToString:@"trailer"]) { 327 | _errorMessage = @"Xref unknown syntax"; 328 | return ERROR_STATE; 329 | } 330 | lastTrailerOffset = (NSInteger*)i; 331 | 332 | xrefEnd = &rawData[i]; 333 | i += 7; 334 | break; 335 | } 336 | } 337 | 338 | // NOTE We may use xrefData in the future 339 | NSData *xrefData = [NSData dataWithBytes:xrefBegin length:xrefEnd - xrefBegin]; 340 | 341 | skipBlankSymbols(rawData, &i); 342 | const char* trailerBegin = &rawData[i]; 343 | const char* trailerEnd = NULL; 344 | 345 | for (; i+9 < dataLength; ++i) { 346 | if (rawData[i] == 's') { 347 | xrefEnd = &rawData[i]; 348 | char buffer[] = {rawData[i], rawData[i+1], rawData[i+2], rawData[i+3], rawData[i+4], rawData[i+5], rawData[i+6], rawData[i+7], rawData[i+8], 0}; 349 | if (![@(buffer) isEqualToString:@"startxref"]) { 350 | _errorMessage = @"Xref unknown syntax"; 351 | return ERROR_STATE; 352 | } 353 | 354 | trailerEnd = &rawData[i]; 355 | i += 9; 356 | break; 357 | } 358 | } 359 | 360 | // NOTE We may use trailerData in the future 361 | NSData *trailerData = [NSData dataWithBytes:trailerBegin length:trailerEnd - trailerBegin]; 362 | 363 | 364 | BOOL logTrailerData = NO; 365 | if(logTrailerData) 366 | { 367 | NSLog(@"\nXref: %@ \nTrailer: %@", xrefData, trailerData); 368 | } 369 | 370 | skipBlankSymbols(rawData, &i); 371 | 372 | NSString *someNum = @""; 373 | while (i < dataLength && isNum(rawData[i])) { 374 | char buffer[] = {rawData[i], 0}; 375 | someNum = [someNum stringByAppendingString:@(buffer)]; 376 | ++i; 377 | } 378 | 379 | *idx = i; 380 | return SEARCH_NEXT_PDF_STRUCTURE_STATE; 381 | } 382 | 383 | - (void) linkObjectsWithContents 384 | { 385 | for (NSString *key in objects) { 386 | YPObject* object = [objects objectForKey:key]; 387 | if (object.references) { 388 | NSMutableDictionary *cpReference = [[NSMutableDictionary alloc] init]; 389 | for(NSString *reference in object.references) { 390 | if ([objects objectForKey:reference]) { 391 | YPObject *referenceTo = [objects objectForKey:reference]; 392 | [cpReference setObject:referenceTo forKey:reference]; 393 | } 394 | } 395 | object.references = cpReference; 396 | } 397 | } 398 | } 399 | 400 | - (NSArray*) getAllObjectsWithKey:(NSString *)key{ 401 | NSMutableArray * infoArray = [[NSMutableArray alloc] init]; 402 | for (NSString* obj in objects) { 403 | YPObject *current = [objects objectForKey:obj]; 404 | id currentValue = [current value]; 405 | 406 | if ([currentValue isKindOfClass:[NSDictionary class]] && [currentValue objectForKey:key]) { 407 | [infoArray addObject:current]; 408 | } 409 | } 410 | return (NSArray*)infoArray; 411 | } 412 | 413 | - (NSArray *)getAllObjectsWithKey:(NSString *)key value:(NSString *)value 414 | { 415 | NSMutableArray * infoArray = [[NSMutableArray alloc] init]; 416 | NSArray* objWithKeyType = [self getAllObjectsWithKey:@"Type"]; 417 | 418 | for (YPObject* obj in objWithKeyType) { 419 | NSString * valForKey = [self getInfoForKey:key inObject:[obj getObjectNumber]]; 420 | if ([valForKey isEqualToString:value]) 421 | { 422 | [infoArray addObject:obj]; 423 | } 424 | } 425 | 426 | return (NSArray*)infoArray; 427 | } 428 | 429 | - (id) getInfoForKey:(NSString *)key 430 | { 431 | id info = nil; 432 | for (NSString* obj in objects) { 433 | YPObject *current = [objects objectForKey:obj]; 434 | id currentValue = [current value]; 435 | if ([currentValue isKindOfClass:[NSDictionary class]] && [currentValue objectForKey:key]) { 436 | info = [currentValue objectForKey:key]; 437 | } 438 | } 439 | return info; 440 | } 441 | 442 | - (id) getInfoForKey:(NSString *)key inObject:(NSString *)objectNumber 443 | { 444 | id info = nil; 445 | YPObject *object = [objects objectForKey:objectNumber]; 446 | id objectValue = [object value]; 447 | id objectContents = [object getContents]; 448 | 449 | if ([objectValue isKindOfClass:[NSDictionary class]] && [objectValue objectForKey:key]) { 450 | info = [objectValue objectForKey:key]; 451 | } 452 | 453 | //Some times the key is defined as name. Try to search for it: 454 | if(!info && objectContents && [objectContents containsObject:@"Contents"]) 455 | { 456 | size_t index = [objectContents indexOfObject:@"Contents"]; 457 | if([objectContents count] > index+1) 458 | { 459 | YPAttribute* attr = [[YPAttribute alloc] initWithString: objectContents[(index+1)]]; 460 | if([attr.attributeType isEqualToString:@"reference"]) 461 | { 462 | YPObjectReference* ref = [[YPObjectReference alloc] initWithReferenceString:objectContents[(index+1)]]; 463 | info = ref; 464 | } 465 | else 466 | { 467 | info = objectContents[index+1]; 468 | } 469 | } 470 | } 471 | 472 | return info; 473 | } 474 | 475 | - (NSString *)getObjectNumberForKey:(NSString *)key value:(NSString *)value 476 | { 477 | NSString *num = @""; 478 | for (NSString* obj in objects) { 479 | YPObject *current = [objects objectForKey:obj]; 480 | id currentValue = [current value]; 481 | if ([currentValue isKindOfClass:[NSDictionary class]] && [currentValue objectForKey:key]) { 482 | if (value && ![value isEqualToString:[currentValue objectForKey:key] ]) { 483 | continue; 484 | } 485 | num = [current getObjectNumber]; 486 | } 487 | } 488 | return num; 489 | } 490 | 491 | 492 | - (BOOL)isBinary 493 | { 494 | if([comments[0] canBeConvertedToEncoding:NSASCIIStringEncoding]) 495 | { 496 | return false; 497 | } 498 | else 499 | { 500 | return true; 501 | } 502 | 503 | 504 | return false; 505 | } 506 | 507 | - (NSDictionary*)getObjectsWithStreams 508 | { 509 | NSMutableDictionary * dict = [[NSMutableDictionary alloc] init]; 510 | 511 | for(id key in objects) { 512 | id pdfObject = [objects objectForKey:key]; 513 | 514 | id stream = [pdfObject getStreamObject]; 515 | 516 | if(stream) 517 | { 518 | [dict setObject:stream forKey:key]; 519 | } 520 | } 521 | 522 | return (NSDictionary*)dict; 523 | } 524 | 525 | 526 | - (NSString*)getPDFInfo 527 | { 528 | NSMutableString* infoString = (NSMutableString*)@""; 529 | infoString = (NSMutableString*)[infoString stringByAppendingFormat:@"Size: %ld bytes\n",(long)docSize]; 530 | infoString = (NSMutableString*)[infoString stringByAppendingFormat:@"Version: %@\n",_version]; 531 | 532 | if([self isBinary]) 533 | { 534 | infoString = (NSMutableString*)[infoString stringByAppendingString:@"Binary: True\n"]; 535 | } 536 | else 537 | { 538 | infoString = (NSMutableString*)[infoString stringByAppendingString:@"Binary: False\n"]; 539 | } 540 | infoString = (NSMutableString*)[infoString stringByAppendingFormat:@"Objects: %ld\n",(size_t)[objects count]]; 541 | infoString = (NSMutableString*)[infoString stringByAppendingFormat:@"Streams: %ld\n",(size_t)[[self getObjectsWithStreams] count]]; 542 | infoString = (NSMutableString*)[infoString stringByAppendingFormat:@"Comments: %ld\n",(size_t)[comments count]]; 543 | 544 | return (NSString*)infoString; 545 | } 546 | 547 | - (NSString*)getPDFMetaData 548 | { 549 | return nil; 550 | } 551 | 552 | - (NSString *) getDocumentCatalog 553 | { 554 | NSString *catalogNum = [self getObjectNumberForKey:@"Type" value:@"Catalog"]; 555 | 556 | return catalogNum; 557 | } 558 | 559 | - (YPObject*) getObjectByNumber:(NSString*)number 560 | { 561 | //number is nil 562 | if([number length] == 0) 563 | return nil; 564 | 565 | YPObject* object = [objects objectForKey:number]; 566 | return object; 567 | } 568 | 569 | - (void) addObjectToUpdateQueue:(YPObject *)pdfObject 570 | { 571 | //pdfObject is nil 572 | if(!pdfObject) 573 | return; 574 | 575 | //add to update array 576 | [updateObjectQueue addObject:pdfObject]; 577 | //[pdfObject getUncompressedStreamContents]; 578 | } 579 | 580 | - (void) updateDocumentData 581 | { 582 | //previous trailor 583 | //NSNumber* prevTrailer; 584 | 585 | //NSNumber* offSet; //[NSNumber numberWithInt: (int)[modifiedPDFData length]]; 586 | YPXref * xref = [[YPXref alloc] init]; 587 | 588 | //create object blocks and add to data 589 | for (YPObject * obj in updateObjectQueue) { 590 | 591 | NSNumber* offset = [NSNumber numberWithInt: (int)[modifiedPDFData length]]; 592 | [xref addObjectEntry:offset generation:[NSNumber numberWithInt:1] deleted:NO]; 593 | 594 | NSData *data = [obj createObjectDataBlock]; 595 | [modifiedPDFData appendData:data]; 596 | } 597 | 598 | //write update xref 599 | NSNumber* startXref = [NSNumber numberWithInt: (int)[modifiedPDFData length]]; 600 | [modifiedPDFData appendData:[[xref stringValue] dataUsingEncoding:NSUTF8StringEncoding]]; 601 | 602 | [modifiedPDFData appendData:[[self createTrailerBlock:startXref previousTrailorOffset:(int)lastTrailerOffset] dataUsingEncoding:NSUTF8StringEncoding]]; 603 | 604 | //write new trailer 605 | } 606 | 607 | - (NSString*) createTrailerBlock:(NSNumber*)startxref previousTrailorOffset:(NSInteger)prev 608 | { 609 | /* 610 | trailer 611 | << /Size 36 /Root 19 0 R /Info 1 0 R /ID [ 612 | ] >> 613 | startxref 614 | 20181 615 | %%EOF 616 | */ 617 | 618 | NSMutableString* blockString = (NSMutableString*)@"trailer\n"; 619 | blockString = (NSMutableString*)[blockString stringByAppendingString:@"<< "]; 620 | blockString = (NSMutableString*)[blockString stringByAppendingFormat:@"/Size %lu ",(unsigned long)[objects count]]; 621 | blockString = (NSMutableString*)[blockString stringByAppendingFormat:@"/Root %@ R ",[self getDocumentCatalog]]; 622 | blockString = (NSMutableString*)[blockString stringByAppendingFormat:@"/Prev %ld ",(long)prev]; 623 | blockString = (NSMutableString*)[blockString stringByAppendingString:@">>\n"]; 624 | blockString = (NSMutableString*)[blockString stringByAppendingFormat:@"startxref\n%@\n",startxref]; 625 | blockString = (NSMutableString*)[blockString stringByAppendingString:@"%%EOF"]; 626 | 627 | return blockString; 628 | } 629 | 630 | - (void) writeToFile 631 | { 632 | 633 | } 634 | 635 | @end 636 | -------------------------------------------------------------------------------- /YAPDFKit/YPHexString.h: -------------------------------------------------------------------------------- 1 | // 2 | // YPHexString.h 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 26.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import 10 | 11 | /** 12 | * Тип PDF Hexadecimal String * 13 | * Бинарная строка, содержит символы [0-9] [A-F] [a-f]. 14 | * Всегда четное количество символов. 15 | */ 16 | @interface YPHexString : NSString 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /YAPDFKit/YPHexString.m: -------------------------------------------------------------------------------- 1 | // 2 | // YPHexString.m 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 26.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import "YPHexString.h" 10 | 11 | @implementation YPHexString 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /YAPDFKit/YPName.h: -------------------------------------------------------------------------------- 1 | // 2 | // YPName.h 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 26.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import 10 | 11 | /** 12 | * Тип PDF Name * 13 | * Начинается с символа '/', может содержать код 14 | * шестнадцатеричного числа. Не содержит пробельных 15 | * символов. 16 | */ 17 | @interface YPName : NSMutableString 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /YAPDFKit/YPName.m: -------------------------------------------------------------------------------- 1 | // 2 | // YPName.m 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 26.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import "YPName.h" 10 | 11 | @implementation YPName 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /YAPDFKit/YPNumber.h: -------------------------------------------------------------------------------- 1 | // 2 | // YPNumber.h 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 27.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import 10 | 11 | /** 12 | * Тип PDF Number * 13 | * Принимает целое или дробное значение. 14 | * Может содержать знак + или - 15 | * Дробная часть отделяется точкой. 16 | */ 17 | @interface YPNumber : NSObject 18 | 19 | /** 20 | * Принимает значение true, если число дробное 21 | * и false в противном случае 22 | */ 23 | @property BOOL real; 24 | 25 | /** 26 | * Значение для real = false (целое число) 27 | */ 28 | @property int intValue; 29 | 30 | /** 31 | * Значение для real = true (дробное число) 32 | */ 33 | @property float realValue; 34 | 35 | /** 36 | * Инициализация для целого числа 37 | */ 38 | - (void) initWithInt:(NSInteger)i; 39 | 40 | /** 41 | * Инициализация для дробного числа 42 | */ 43 | - (void) initWithReal:(float)f; 44 | @end 45 | -------------------------------------------------------------------------------- /YAPDFKit/YPNumber.m: -------------------------------------------------------------------------------- 1 | // 2 | // YPNumber.m 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 27.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import "YPNumber.h" 10 | 11 | @implementation YPNumber 12 | @synthesize real, intValue, realValue; 13 | - (void) initWithInt:(NSInteger)i 14 | { 15 | intValue = (int)i; 16 | real = NO; 17 | } 18 | - (void) initWithReal:(float)f 19 | { 20 | realValue = f; 21 | real = YES; 22 | } 23 | - (NSString *)description 24 | { 25 | NSString *desc = @""; 26 | if (real) { 27 | desc = [NSString stringWithFormat:@"%f",realValue]; 28 | } else { 29 | desc = [NSString stringWithFormat:@"%d",intValue]; 30 | } 31 | return desc; 32 | } 33 | @end 34 | -------------------------------------------------------------------------------- /YAPDFKit/YPObject.h: -------------------------------------------------------------------------------- 1 | // 2 | // YPObject.h 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 19.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YPObjectStream.h" 11 | #import "YPDictionary.h" 12 | 13 | @class YPDocument; 14 | 15 | @interface YPObject : NSObject 16 | 17 | @property NSInteger firstNumber; 18 | @property NSInteger secondNumber; 19 | 20 | 21 | @property YPObjectStream *stream; 22 | @property YPDictionary *dictionary; 23 | 24 | 25 | @property id value; 26 | 27 | @property NSMutableDictionary *references; 28 | 29 | - (id)initWithData :(NSData*)d first:(NSInteger*)first second:(NSInteger*)second; 30 | - (NSString *)getObjectNumber; 31 | - (id)getValueByName:(NSString *)n; 32 | - (NSArray*)getContents; 33 | - (YPObjectStream *)getStreamObject; 34 | - (id)getObjectForKeyInDict:(NSString*)key; 35 | - (NSData*) createObjectDataBlock; 36 | - (void) setStreamContentsWithData:(NSData*)data; 37 | - (NSString*)getUncompressedStreamContents; 38 | - (NSData*)getUncompressedStreamContentsAsData; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /YAPDFKit/YPObject.m: -------------------------------------------------------------------------------- 1 | // 2 | // YPObject.m 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 19.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Modify by LiuQiang on 25-03-16 8 | // mail:liulcsy@163.com 9 | 10 | #import "YPObject.h" 11 | #import "YPArray.h" 12 | #import "YPHexString.h" 13 | #import "YPBool.h" 14 | #import "YPDictionary.h" 15 | #import "YPName.h" 16 | #import "YPNumber.h" 17 | #import "YPString.h" 18 | #import "YPObjectReference.h" 19 | #import "Utils.h" 20 | 21 | @implementation YPObject 22 | { 23 | const char * rawData; 24 | NSUInteger dataLength; 25 | size_t * index; 26 | NSMutableArray * contents; 27 | NSMutableDictionary * pdfContents; 28 | } 29 | 30 | @synthesize value, firstNumber, secondNumber, references, stream, dictionary; 31 | 32 | - (id)initWithData :(NSData*)d first:(NSInteger*)first second:(NSInteger*)second 33 | { 34 | if (self = [super init]) { 35 | 36 | rawData = (const char *)[d bytes]; 37 | dataLength = d.length; 38 | 39 | //pdfContents = documentContents; 40 | [self run]; 41 | 42 | firstNumber = *first; 43 | secondNumber = *second; 44 | 45 | //references = [[NSMutableArray alloc] init]; 46 | 47 | if([contents count] != 0) { 48 | value = [contents objectAtIndex:0]; 49 | } else { 50 | NSLog(@"EMPTY OBJ %ld %ld",(long)firstNumber,(long)secondNumber); 51 | } 52 | 53 | return self; 54 | } 55 | 56 | NSLog(@"init with nil"); 57 | return nil; 58 | } 59 | 60 | - (void)run 61 | { 62 | index = 0; 63 | size_t i = 0; 64 | contents = [[NSMutableArray alloc] init]; 65 | for (; i < dataLength; ++i) { 66 | NSObject *obj = [[NSObject alloc] init]; 67 | obj = [self checkNextStruct:&i]; 68 | if(obj) { 69 | [contents addObject:obj]; 70 | } 71 | } 72 | index = &i; 73 | 74 | } 75 | 76 | - (NSObject *)checkNextStruct:(size_t *)idx 77 | { 78 | size_t i = *idx; 79 | 80 | NSObject *structure; 81 | 82 | if (!(i < dataLength)) { 83 | return nil; 84 | } 85 | 86 | if (rawData[i] == '<') { 87 | if(rawData[i+1] == '<') { 88 | structure = [self checkDict:&i]; 89 | } else { 90 | structure = [self checkBinaryString:&i]; 91 | } 92 | } else if (rawData[i] == '[') { 93 | structure = [self checkArray:&i]; 94 | } else if (rawData[i] == '(') { 95 | structure = [self checkString:&i]; 96 | } else if (rawData[i] == '/') { 97 | structure = [self checkName:&i]; 98 | } else if (isNum(rawData[i]) || rawData[i] == '+' || rawData[i] == '-') { 99 | structure = [self checkNum:&i]; 100 | } else if (rawData[i] == 't' || rawData[i] == 'f') { 101 | structure = [self checkBool:&i]; 102 | } else if (rawData[i] == 's') { 103 | 104 | stream = [self checkStream:&i]; 105 | 106 | 107 | } else if (isBlank(rawData[i])) { 108 | skipBlankSymbols(rawData, &i); 109 | 110 | [self checkNextStruct:&i]; 111 | } 112 | 113 | *idx = i; 114 | 115 | return structure; 116 | } 117 | 118 | - (NSDictionary *)checkDict:(size_t *)idx 119 | { 120 | NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; 121 | size_t i = *idx; 122 | i += 2; 123 | 124 | for(; i < dataLength; ++i) { 125 | 126 | NSString *key = nil; 127 | NSObject *obj = nil; 128 | 129 | skipBlankSymbols(rawData, &i); 130 | 131 | if (rawData[i] == '>' && i+1 < dataLength && rawData[i+1] == '>') { 132 | ++i; 133 | break; 134 | } 135 | 136 | if (rawData[i] == '/') { 137 | key = [self checkName:&i 138 | ]; 139 | } 140 | 141 | skipBlankSymbols(rawData, &i); 142 | 143 | obj = [self checkNextStruct:&i]; 144 | 145 | if(key && obj) { 146 | [dict setObject:obj forKey:key]; 147 | } 148 | } 149 | 150 | *idx = i; 151 | 152 | dictionary = [[YPDictionary alloc] initWithDictionary:(NSDictionary*)dict]; 153 | 154 | return (NSDictionary*)dict; 155 | } 156 | 157 | - (NSArray *)checkArray:(size_t *)idx 158 | { 159 | NSMutableArray *array = [[NSMutableArray alloc] init]; 160 | size_t i = *idx; 161 | ++i; 162 | 163 | for(; i < dataLength; ++i) { 164 | 165 | NSObject *obj = nil; 166 | skipBlankSymbols(rawData, &i); 167 | 168 | if (rawData[i] == ']' && rawData[i-1] != '\\') { 169 | break; 170 | } 171 | 172 | obj = [self checkNextStruct:&i]; 173 | 174 | if(obj) { 175 | [array addObject:obj]; 176 | } 177 | } 178 | 179 | YPArray *pdfArray = (YPArray*)array; 180 | *idx = i; 181 | return pdfArray; 182 | } 183 | 184 | - (YPBool *)checkBool:(size_t *)idx 185 | { 186 | YPBool *b = [[YPBool alloc] init]; 187 | NSUInteger i = *idx; 188 | 189 | if (i+4 < dataLength) { 190 | char buffer[] = {rawData[i], rawData[i+1], rawData[i+2], rawData[i+3], 0}; 191 | if([@(buffer) isEqualToString:@"fals"] && i+5 < dataLength && rawData[i+4] == 'e') { 192 | b.value = NO; 193 | i = i+4; 194 | } else if ([@(buffer) isEqualToString:@"true"]) { 195 | b.value = YES; 196 | i = i+3; 197 | } 198 | } 199 | 200 | *idx = i; 201 | return b; 202 | } 203 | 204 | - (YPHexString *)checkBinaryString:(size_t *)idx 205 | { 206 | NSString *str = @""; 207 | YPHexString *binary; 208 | NSUInteger i = *idx; 209 | ++i; 210 | 211 | for (; i > 0 && i < dataLength; ++i) { 212 | if(rawData[i] == '>') { 213 | break; 214 | } 215 | if (!isHexSymbol(rawData[i])) { 216 | return nil; //error "Hex string contains non-hex symbols" 217 | } 218 | char buffer[] = {rawData[i], 0}; 219 | str = [str stringByAppendingString:@(buffer)]; 220 | } 221 | 222 | // если в строке нечетное количество символов, 223 | // подразумевается, что последний символ "0" 224 | if ([str length] % 2) { 225 | str = [str stringByAppendingString:@"0"]; 226 | } 227 | 228 | *idx = i; 229 | binary = (YPHexString *)str; 230 | 231 | return binary; 232 | } 233 | 234 | - (YPString *)checkString:(size_t *)idx 235 | { 236 | NSString *str = @""; 237 | YPString *pdfString; 238 | NSUInteger i = *idx; 239 | NSUInteger brackets = 0; 240 | ++i; 241 | 242 | for (; i < dataLength; ++i) { 243 | if (rawData[i] == '(' && rawData[i-1] != '\\') { 244 | brackets++; 245 | } else if (brackets && rawData[i] == ')') { 246 | brackets--; 247 | } else if(rawData[i] == ')' && !brackets && rawData[i-1] != '\\') { 248 | break; 249 | } 250 | char buffer[] = {rawData[i], 0}; 251 | if (@(buffer)) { 252 | str = [str stringByAppendingString:@(buffer)]; 253 | } 254 | } 255 | 256 | *idx = i; 257 | pdfString = (YPString *)str; 258 | return pdfString; 259 | } 260 | 261 | - (YPName *)checkName:(size_t *)idx 262 | { 263 | NSString *name = @""; 264 | YPName *pdfName; 265 | NSUInteger i = *idx; 266 | ++i; 267 | 268 | for (; i < dataLength && !isBlank(rawData[i]) && rawData[i]!='>' && rawData[i]!='/'; ++i) { 269 | char buffer[] = {rawData[i], 0}; 270 | name = [name stringByAppendingString:@(buffer)]; 271 | } 272 | 273 | *idx = i; 274 | pdfName = (YPName *)name; 275 | return pdfName; 276 | } 277 | 278 | - (id)checkNum:(size_t *)idx 279 | { 280 | NSString *num = @""; 281 | NSString *secondNum = @""; 282 | NSUInteger i = *idx; 283 | BOOL isReal = NO; 284 | 285 | do { 286 | if (rawData[i] == '.') { 287 | if(isReal) { 288 | return nil; // error "Incorrect number syntax: two dots in a number." 289 | } 290 | isReal = YES; 291 | } 292 | char buffer[] = {rawData[i], 0}; 293 | num = [num stringByAppendingString:@(buffer)]; 294 | ++i; 295 | } while ( i < dataLength && (isNum(rawData[i]) || rawData[i] == '.')); 296 | 297 | if (i+3< dataLength && isBlank(rawData[i]) && isNum(rawData[i+1]) && isBlank(rawData[i+2]) && rawData[i+3] == 'R') { 298 | char buffer[] = {rawData[i+1], 0}; 299 | secondNum = [secondNum stringByAppendingString:@(buffer)]; 300 | YPObjectReference *objRef = [self objRef:num:secondNum]; 301 | i += 3; 302 | *idx = i; 303 | return objRef; 304 | } 305 | 306 | --i; 307 | *idx = i; 308 | 309 | YPNumber *pdfNum = [[YPNumber alloc] init]; 310 | if(isReal) { 311 | float f = [num floatValue]; 312 | [pdfNum initWithReal:f]; 313 | } else { 314 | NSUInteger igr = [num integerValue]; 315 | [pdfNum initWithInt:igr]; 316 | } 317 | 318 | return pdfNum; 319 | } 320 | 321 | - (YPObjectReference *)objRef:(NSString *)firstNum :(NSString *)secondNum 322 | { 323 | YPObjectReference *ref = [[YPObjectReference alloc]initWithNum:firstNum:secondNum]; 324 | NSString *refNum = [ref getReferenceNumber]; 325 | if (!references) { 326 | references = [[NSMutableDictionary alloc] init]; 327 | } 328 | [references setObject:refNum forKey:refNum]; 329 | return ref; 330 | } 331 | 332 | 333 | - (YPObjectStream *)checkStream:(size_t *)idx 334 | { 335 | NSUInteger i = *idx; 336 | 337 | const char *b = NULL; 338 | if (i+5 < dataLength) { 339 | char buffer[] = {rawData[i], rawData[i+1], rawData[i+2], rawData[i+3], rawData[i+4], rawData[i+5],0}; 340 | if (![@(buffer)isEqualToString:@"stream"]){ 341 | return nil; //error 342 | } 343 | i += 5; 344 | b = &rawData[i+2]; 345 | } 346 | 347 | const char* e = NULL; 348 | for(; i < dataLength; ++i) { 349 | if (rawData[i] == 'e' && rawData[i-1] != '/' && i+8 < dataLength) { 350 | char buffer[] = {rawData[i], rawData[i+1], rawData[i+2], rawData[i+3], rawData[i+4], rawData[i+5], rawData[i+6], rawData[i+7], rawData[i+8], 0}; 351 | 352 | /* This check must be activated 353 | if (![@(buffer)isEqualToString:@"endstream"]){ 354 | return nil; //error 355 | } 356 | */ 357 | 358 | if ([@(buffer)isEqualToString:@"endstream"]){ 359 | e = &rawData[i-1]; 360 | break; 361 | } 362 | } 363 | } 364 | 365 | YPObjectStream * returnStream = [[YPObjectStream alloc] initWithData:[NSData dataWithBytes:b length:e - b]]; 366 | 367 | i += 8; 368 | *idx = i; 369 | return returnStream; 370 | } 371 | 372 | /// METHODS AVAILABLE AFTER PARSING 373 | /// ------------------------------- 374 | 375 | - (YPObjectStream *)getStreamObject { 376 | return stream; 377 | } 378 | 379 | 380 | - (NSArray*)getContents { 381 | return contents; 382 | } 383 | 384 | - (id)getObjectForKeyInDict:(NSString*)key 385 | { 386 | id info = nil; 387 | id objectValue = [self value]; 388 | if ([objectValue isKindOfClass:[NSDictionary class]] && [objectValue objectForKey:key]) { 389 | info = [objectValue objectForKey:key]; 390 | } 391 | return info; 392 | } 393 | 394 | - (NSString *)getObjectNumber 395 | { 396 | NSString *num = @""; 397 | 398 | NSString *first = [NSString stringWithFormat:@"%ld",(long)firstNumber]; 399 | NSString *second = [NSString stringWithFormat:@"%ld",(long)secondNumber]; 400 | num = [num stringByAppendingString:first]; 401 | num = [num stringByAppendingString:@" "]; 402 | num = [num stringByAppendingString:second]; 403 | 404 | return num; 405 | } 406 | 407 | - (id)getValueByName:(NSString *)n 408 | { 409 | NSObject *obj = [[NSObject alloc] init]; 410 | if ([value isKindOfClass:[YPDictionary class]] && [value objectForKey:n]) { 411 | 412 | } 413 | return obj; 414 | } 415 | 416 | // You should not use this is for update tasks as the content gets corrupts 417 | - (NSString*)getUncompressedStreamContents 418 | { 419 | if(stream) 420 | { 421 | NSString *filter = [dictionary objectForKey:@"Filter"]; 422 | return [[self stream] getDecompressedDataAsString:filter]; 423 | } 424 | 425 | return nil; 426 | } 427 | 428 | - (NSData*)getUncompressedStreamContentsAsData 429 | { 430 | //filter may be array 431 | NSString *flateDecode = nil; 432 | if(stream) 433 | { 434 | id filter = [dictionary objectForKey:@"Filter"]; 435 | 436 | if ([filter isKindOfClass:[NSString class]]) { 437 | flateDecode = filter; 438 | } 439 | if ([filter isKindOfClass:[NSArray class]]) { 440 | flateDecode = filter[0]; 441 | } 442 | return [[self stream] getDecompressedData:flateDecode]; 443 | } 444 | return nil; 445 | } 446 | 447 | - (void) setStreamContentsWithData:(NSData*)data 448 | { 449 | [dictionary removeObjectForKey:@"Filter"]; 450 | stream = [[YPObjectStream alloc] initWithData:data andFilter:@"None"]; 451 | } 452 | 453 | - (NSData*) createObjectDataBlock 454 | { 455 | NSString* startstring =[@"" stringByAppendingFormat:@"%@ obj\n",[self getObjectNumber]]; 456 | NSData*startData =[startstring dataUsingEncoding:NSASCIIStringEncoding]; 457 | 458 | NSMutableData* blockData = [[NSMutableData alloc] initWithData:startData]; 459 | 460 | if(dictionary) 461 | { 462 | //if stream set of replace length 463 | if(stream) 464 | { 465 | [dictionary setObject:[NSNumber numberWithInt:(int)[stream length]] forKey:@"Length"]; 466 | 467 | // For now we do not support Filters for created blocks, so we'll remove the key 468 | [dictionary removeObjectForKey:@"Filter"]; 469 | } 470 | 471 | [blockData appendData:[[dictionary stringValue] dataUsingEncoding:NSUTF8StringEncoding]]; 472 | 473 | if(stream) 474 | { 475 | [blockData appendData:[@"stream\n" dataUsingEncoding:NSUTF8StringEncoding]]; 476 | [blockData appendData:[self getUncompressedStreamContentsAsData]]; 477 | [blockData appendData:[@"endstream\n" dataUsingEncoding:NSUTF8StringEncoding]]; 478 | } 479 | } 480 | 481 | [blockData appendData:[@"endobj\n" dataUsingEncoding:NSUTF8StringEncoding]]; 482 | return (NSData*)blockData; 483 | } 484 | 485 | @end -------------------------------------------------------------------------------- /YAPDFKit/YPObjectReference.h: -------------------------------------------------------------------------------- 1 | // 2 | // YPObjectReference.h 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 24.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | @class YPObject; 10 | 11 | @interface YPObjectReference : NSObject 12 | { 13 | NSInteger firstNumber; 14 | NSInteger secondNumber; 15 | } 16 | 17 | @property YPObject* link; 18 | 19 | - (id)initWithNum :(NSString *)first :(NSString *)second; 20 | - (id)initWithReferenceString:(NSString *)string; 21 | - (NSString *)getReferenceNumber; 22 | @end 23 | -------------------------------------------------------------------------------- /YAPDFKit/YPObjectReference.m: -------------------------------------------------------------------------------- 1 | // 2 | // YPObjectReference.m 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 24.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import "YPObjectReference.h" 10 | #import "YPObject.h" 11 | 12 | @implementation YPObjectReference 13 | 14 | @synthesize link; 15 | 16 | - (id)initWithNum :(NSString *)first :(NSString *)second 17 | { 18 | if (self = [super init]) { 19 | firstNumber = [first integerValue]; 20 | secondNumber = [second integerValue]; 21 | return self; 22 | } 23 | return nil; 24 | } 25 | 26 | - (id)initWithReferenceString:(NSString *)string 27 | { 28 | if (self = [super init]) { 29 | 30 | NSLog(@"hallo: %@", string); 31 | NSArray *chunks = [string componentsSeparatedByString: @" "]; 32 | 33 | firstNumber = [chunks[0] integerValue]; 34 | secondNumber = [chunks[1] integerValue]; 35 | return self; 36 | } 37 | return nil; 38 | } 39 | 40 | - (NSString *)description 41 | { 42 | NSString *desc = @""; 43 | NSString *first = [NSString stringWithFormat:@"%ld",(long)firstNumber]; 44 | NSString *second = [NSString stringWithFormat:@"%ld",(long)secondNumber]; 45 | desc = [desc stringByAppendingString:first]; 46 | desc = [desc stringByAppendingString:@" "]; 47 | desc = [desc stringByAppendingString:second]; 48 | desc = [desc stringByAppendingString:@" R"]; 49 | 50 | return desc; 51 | } 52 | 53 | - (NSString *)getReferenceNumber 54 | { 55 | NSString *num = @""; 56 | 57 | NSString *first = [NSString stringWithFormat:@"%ld",(long)firstNumber]; 58 | NSString *second = [NSString stringWithFormat:@"%ld",(long)secondNumber]; 59 | num = [num stringByAppendingString:first]; 60 | num = [num stringByAppendingString:@" "]; 61 | num = [num stringByAppendingString:second]; 62 | 63 | return num; 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /YAPDFKit/YPObjectStream.h: -------------------------------------------------------------------------------- 1 | // 2 | // PDFStream.m 3 | // YAPDFKit 4 | // 5 | // Created by Pim Snel on 10-02-16. 6 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 7 | 8 | #import 9 | #include "pdfzlib.h" 10 | 11 | // Stream contents in YPObject 12 | @interface YPObjectStream : NSObject 13 | 14 | @property NSData* rawData; 15 | 16 | - (id)initWithData :(NSData*)data; 17 | - (id)initWithData:(NSData*)data andFilter:(NSString*)filter; 18 | - (NSData *)getDecompressedData:(NSString*)filter; 19 | - (NSString *)getDecompressedDataAsString:(NSString*)filter; 20 | - (unsigned long) length; 21 | - (NSData*) getRawData; 22 | @end 23 | -------------------------------------------------------------------------------- /YAPDFKit/YPObjectStream.m: -------------------------------------------------------------------------------- 1 | // 2 | // PDFStream.m 3 | // YAPDFKit 4 | // 5 | // Created by Pim Snel on 10-02-16. 6 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 7 | // Modify by Liuqiang on 25-03-16. 8 | 9 | #import "YPObjectStream.h" 10 | 11 | @implementation YPObjectStream 12 | 13 | - (id)initWithData :(NSData*)data 14 | { 15 | if (self = [super init]) { 16 | 17 | if(data){ 18 | 19 | _rawData = data; 20 | } 21 | 22 | return self; 23 | } 24 | 25 | return nil; 26 | } 27 | 28 | - (id)initWithData:(NSData*)data andFilter:(NSString*)filter 29 | { 30 | if (self = [super init]) { 31 | 32 | if([filter isEqualToString:@"FlateDecode"]) 33 | { 34 | _rawData = inflateStringData(data); 35 | } 36 | else if([filter isEqualToString:@"None"]) 37 | { 38 | _rawData = data; 39 | } 40 | else 41 | { 42 | _rawData = data; 43 | } 44 | 45 | return self; 46 | } 47 | 48 | return nil; 49 | } 50 | 51 | 52 | 53 | 54 | - (NSData*) getRawData 55 | { 56 | return _rawData; 57 | } 58 | 59 | - (unsigned long) length 60 | { 61 | return [_rawData length]; 62 | } 63 | 64 | -(NSData*)getDecompressedData:(NSArray*)filter 65 | { 66 | //filter may be array 67 | NSString *flateDecode = filter; 68 | if([flateDecode isEqualToString:@"FlateDecode"]) 69 | { 70 | return deflateData(_rawData); 71 | } 72 | else if([flateDecode isEqualToString:@"None"]) 73 | { 74 | return _rawData; 75 | } 76 | else 77 | { 78 | return _rawData; 79 | } 80 | return nil; 81 | } 82 | 83 | 84 | - (NSString *)getDecompressedDataAsString:(NSString*)filter 85 | { 86 | if([filter isEqualToString:@"FlateDecode"]) 87 | { 88 | return deflateDataAsString(_rawData); 89 | } 90 | else if([filter isEqualToString:@"None"]) 91 | { 92 | NSString* plain = [[NSString alloc] initWithData:_rawData encoding:NSUTF8StringEncoding]; 93 | 94 | return plain; 95 | } 96 | else 97 | { 98 | NSString* plain = [[NSString alloc] initWithData:_rawData encoding:NSUTF8StringEncoding]; 99 | 100 | return plain; 101 | } 102 | return nil; 103 | } 104 | 105 | @end 106 | -------------------------------------------------------------------------------- /YAPDFKit/YPPages.h: -------------------------------------------------------------------------------- 1 | // 2 | // YPPages.h 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 28.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import "YPDocument.h" 10 | 11 | @interface YPPages : NSObject 12 | 13 | @property id pageInfoObjectNum; 14 | 15 | - (id)initWithDocument:(YPDocument *)d; 16 | - (int)getPageCount; 17 | - (id)getPagesTree; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /YAPDFKit/YPPages.m: -------------------------------------------------------------------------------- 1 | // 2 | // YPPages.m 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 28.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import "YPPages.h" 10 | #import "YPDictionary.h" 11 | #import "YPObject.h" 12 | #import "YPObjectReference.h" 13 | 14 | @implementation YPPages 15 | { 16 | YPDocument* document; 17 | } 18 | 19 | @synthesize pageInfoObjectNum; 20 | 21 | - (id)initWithDocument:(YPDocument *)d 22 | { 23 | if (self = [super init]) { 24 | document = d; 25 | } 26 | return self; 27 | } 28 | 29 | /* 30 | - (NSString *)getDocumentCatalog 31 | { 32 | NSString *catalogNum = [document getObjectNumberForKey:@"Type":@"Catalog"]; 33 | return catalogNum; 34 | } 35 | */ 36 | 37 | - (void)getPageObjectNum 38 | { 39 | NSString *catalogNum = [document getDocumentCatalog]; 40 | YPObjectReference *pageObjRef = [document getInfoForKey:@"Pages" inObject:catalogNum]; 41 | pageInfoObjectNum = [pageObjRef getReferenceNumber]; 42 | } 43 | 44 | - (int)getPageCount 45 | { 46 | [self getPageObjectNum]; 47 | NSString* pageCount = [document getInfoForKey:@"Count" inObject:pageInfoObjectNum]; 48 | return [pageCount intValue]; 49 | } 50 | 51 | - (id)getPagesTree 52 | { 53 | id pageTree; 54 | [self getPageObjectNum]; 55 | pageTree = [document getInfoForKey:@"Kids" inObject:pageInfoObjectNum]; 56 | 57 | return pageTree; 58 | } 59 | 60 | - (id)getPageNumber:(YPDocument *)d 61 | { 62 | id page; 63 | [self getPageObjectNum]; 64 | 65 | if ([d getInfoForKey:@"Kids" inObject:pageInfoObjectNum]) { 66 | 67 | } 68 | 69 | return page; 70 | } 71 | 72 | 73 | //getPagesInfo 74 | //getCount 75 | //getPageNumber 76 | 77 | 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /YAPDFKit/YPString.h: -------------------------------------------------------------------------------- 1 | // 2 | // YPString.h 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 26.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import 10 | 11 | /** 12 | * Тип PDF String * 13 | * Строка, заключенная в скобки. Может содержать 14 | * закрытые парные не экранированные скобки или 15 | * не закрытые, но экранированные скобки. 16 | */ 17 | @interface YPString : NSString 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /YAPDFKit/YPString.m: -------------------------------------------------------------------------------- 1 | // 2 | // YPString.m 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 26.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import "YPString.h" 10 | 11 | @implementation YPString 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /YAPDFKit/YPXref.h: -------------------------------------------------------------------------------- 1 | // 2 | // YPXref.h 3 | // YAPDFKit 4 | // 5 | // Created by Pim Snel on 13-02-16. 6 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 7 | 8 | #import 9 | 10 | @interface YPXref : NSObject 11 | 12 | @property NSMutableArray * objectEntries; 13 | //@property NSDictionary * objectEntry; 14 | 15 | - (NSString*)stringValue; 16 | - (void) addObjectEntry:(NSNumber*)offset generation:(NSNumber*)aGeneration deleted:(BOOL)isDeleted; 17 | @end 18 | -------------------------------------------------------------------------------- /YAPDFKit/YPXref.m: -------------------------------------------------------------------------------- 1 | // 2 | // YPXref.m 3 | // YAPDFKit 4 | // 5 | // Created by Pim Snel on 13-02-16. 6 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 7 | 8 | #import "YPXref.h" 9 | 10 | @implementation YPXref 11 | 12 | @synthesize objectEntries; 13 | 14 | - (id)init 15 | { 16 | if (self = [super init]) { 17 | 18 | objectEntries = [NSMutableArray array]; 19 | 20 | return self; 21 | } 22 | 23 | return nil; 24 | } 25 | 26 | - (NSString*) stringValue 27 | { 28 | NSMutableString* blockString = (NSMutableString*)@"xref\n"; 29 | blockString = (NSMutableString*)[blockString stringByAppendingFormat:@"0 %lu\n",(unsigned long)[objectEntries count]]; 30 | 31 | for(NSDictionary* e in objectEntries) 32 | { 33 | blockString = (NSMutableString*)[blockString stringByAppendingFormat:@"%@ %@ %@\n",e[@"offset"],e[@"generation"],e[@"deleted"]]; 34 | } 35 | 36 | return blockString; 37 | } 38 | 39 | - (void) addObjectEntry:(NSNumber*)offset generation:(NSNumber*)aGeneration deleted:(BOOL)isDeleted 40 | { 41 | NSString *offsetString = [NSString stringWithFormat:@"%010d",[offset intValue]] ; 42 | NSString *generationString = [NSString stringWithFormat:@"%05d",[aGeneration intValue]] ; 43 | 44 | NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: 45 | offsetString, @"offset", 46 | generationString,@"generation", 47 | isDeleted?@"f":@"n", @"deleted", 48 | nil]; 49 | [objectEntries addObject:[NSDictionary dictionaryWithDictionary:dict]]; 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /YAPDFKit/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // YAPDFKit 4 | // 5 | // Created by Aliona on 10.05.14. 6 | // Copyright (c) 2014 Ptenster. All rights reserved. 7 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 8 | 9 | #import 10 | #import "YPDocument.h" 11 | 12 | enum ParserStates { 13 | BEGIN_STATE = 0, 14 | FILL_VERSION_STATE, 15 | DEFAULT_STATE, 16 | }; 17 | 18 | 19 | int main(int argc, const char * argv[]) 20 | { 21 | @autoreleasepool { 22 | 23 | NSString *intro = @"\n"\ 24 | " __ _____ ____ ____ ______ __ __ _ __\n"\ 25 | " \\ \\/ / | / __ \\/ __ \\/ ____/ / //_/(_) /_\n"\ 26 | " \\ / /| | / /_/ / / / / /_ / ,< / / __/\n"\ 27 | " / / ___ | / ____/ /_/ / __/ / /| |/ / /_\n"\ 28 | " /_/_/ |_| /_/ /_____/_/ /_/ |_/_/\\__/\n"\ 29 | "\n"\ 30 | "\n"\ 31 | "Main.c is shows an example usage of YAPDFKit.\n"\ 32 | "\n"\ 33 | "- It reads a two page PDF (/tmp/2-page-pages-export.pdf)\n"\ 34 | "- iterates through all pages\n"\ 35 | "- unpacks the content stream\n"\ 36 | "- adds a purple rectangle below the text\n"\ 37 | "- updates the PDF by adding an updates object block and writing a new xref\n"\ 38 | " table.\n"\ 39 | "\n"\ 40 | "You can see the result.\n"\ 41 | "\n"\ 42 | "open /tmp/2-page-pages-export-mod.pdf\n"\ 43 | "\n"\ 44 | "Enjoy using YAPDFKit\n"; 45 | 46 | NSLog(@"%@\n",intro); 47 | 48 | NSString *file =@"/tmp/2-page-pages-export.pdf"; 49 | NSData *fileData = [NSData dataWithContentsOfFile:file]; 50 | YPDocument *document = [[YPDocument alloc] initWithData:fileData]; 51 | YPPages *pg = [[YPPages alloc] initWithDocument:document]; 52 | NSLog(@"page count: %d", [pg getPageCount]); 53 | //All Pages unsorted 54 | NSArray * allPages = [document getAllObjectsWithKey:@"Type" value:@"Page"]; 55 | for (YPObject* page in allPages) { 56 | 57 | NSString *ob_num = [page getObjectNumber]; 58 | // NSString *rn_num = [ob_num getReferenceNumber]; 59 | 60 | NSString *docContentNumber = [[document getInfoForKey:@"Contents" inObject:ob_num] getReferenceNumber]; 61 | if (!docContentNumber) { 62 | NSLog(@"docContentNumber is nil"); 63 | return nil; 64 | } 65 | YPObject *pageContentsObject = [document getObjectByNumber:docContentNumber]; 66 | NSData *plainContent = [pageContentsObject getUncompressedStreamContentsAsData]; 67 | NSData *data2 = [@"q /Cs1 cs 0.4 0 0.6 sc 250 600 100 100 re f q " dataUsingEncoding:NSASCIIStringEncoding]; 68 | NSRange firstPartRange = {0,64}; 69 | NSRange lastPartRange = {64, ([plainContent length]-64)}; 70 | NSData *data1 = [plainContent subdataWithRange:firstPartRange]; 71 | NSData *data3 = [plainContent subdataWithRange:lastPartRange]; 72 | NSMutableData * newPlainContent = [data1 mutableCopy]; 73 | [newPlainContent appendData:data2]; 74 | [newPlainContent appendData:data3]; 75 | [pageContentsObject setStreamContentsWithData:newPlainContent]; 76 | [document addObjectToUpdateQueue:pageContentsObject]; 77 | } 78 | [document updateDocumentData]; 79 | [[document modifiedPDFData] writeToFile:@"/tmp/2-page-pages-export-mod.pdf" atomically:YES]; 80 | } 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /YAPDFKit/pdfzlib.h: -------------------------------------------------------------------------------- 1 | // 2 | // pdflib.h 3 | // YAPDFKit 4 | // 5 | // Created by Pim Snel on 10-02-16. 6 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 7 | // 8 | 9 | #import 10 | NSData* deflateData(NSData * data); 11 | NSString* deflateDataAsString(NSData * data); 12 | NSData* inflateStringData(NSData* data); 13 | void ZeroMemory(void * buffer, long sizeOf); 14 | -------------------------------------------------------------------------------- /YAPDFKit/pdfzlib.m: -------------------------------------------------------------------------------- 1 | // 2 | // pdflib.m 3 | // YAPDFKit 4 | // 5 | // Created by Pim Snel on 10-02-16. 6 | // Copyright © 2016-2019 Lingewoud. All rights reserved. 7 | // 8 | 9 | // Based on zachron's pdfiphone solution 10 | // https://github.com/zachron/pdfiphone 11 | 12 | // The implementation was slightly changed so that ir returns an NSString 13 | // instead of creating a temporary text file and reading a string from there. 14 | // This new approach lets the NSString object handle the encoding of the PDF 15 | // file, so as to support a wider variety of characters. 16 | 17 | // Adobe has a web site that converts PDF files to text for free, 18 | // so why would you need something like this? Several reasons: 19 | // 20 | // 1) This code is entirely free including for commericcial use. It only 21 | // requires ZLIB (from www.zlib.org) which is entirely free as well. 22 | // 23 | // 2) This code tries to put tabs into appropriate places in the text, 24 | // which means that if your PDF file contains mostly one large table, 25 | // you can easily take the output of this program and directly read it 26 | // into Excel! Otherwise if you select and copy the text and paste it into 27 | // Excel there is no way to extract the various columns again. 28 | // 29 | // This code assumes that the PDF file has text objects compressed 30 | // using FlateDecode (which seems to be standard). 31 | // 32 | // This code is free. Use it for any purpose. 33 | // The author assumes no liability whatsoever for the use of this code. 34 | // Use it at your own risk! 35 | 36 | 37 | // PDF file strings (based on PDFReference15_v5.pdf from www.adobve.com: 38 | // 39 | // BT = Beginning of a text object, ET = end of a text object 40 | // 5 Ts = superscript 41 | // -5 Ts = subscript 42 | // Td move to start next line 43 | 44 | #include "pdfzlib.h" 45 | 46 | #include 47 | #include 48 | 49 | #include 50 | #include 51 | 52 | #import 53 | #include "zlib.h" 54 | 55 | NSMutableString *result; 56 | 57 | void ZeroMemory(void * buffer, long sizeOf) 58 | { 59 | memset(buffer, 0, sizeOf); 60 | } 61 | 62 | //Keep this many previous recent characters for back reference: 63 | #define oldchar 15 64 | 65 | //Convert a recent set of characters into a number if there is one. 66 | //Otherwise return -1: 67 | float ExtractNumber(const char* search, int lastcharoffset) 68 | { 69 | int i = lastcharoffset; 70 | while (i>0 && search[i]==' ') i--; 71 | while (i>0 && (isdigit(search[i]) || search[i]=='.')) i--; 72 | float flt=-1.0; 73 | char buffer[oldchar+5]; 74 | ZeroMemory(buffer,sizeof(buffer)); 75 | strncpy(buffer, search+i+1, lastcharoffset-i); 76 | if (buffer[0] && sscanf(buffer, "%f", &flt)) 77 | { 78 | return flt; 79 | } 80 | return -1.0; 81 | } 82 | 83 | //Check if a certain 2 character token just came along (e.g. BT): 84 | bool seen2(const char* search, char* recent) 85 | { 86 | if ( recent[oldchar-3]==search[0] 87 | && recent[oldchar-2]==search[1] 88 | && (recent[oldchar-1]==' ' || recent[oldchar-1]==0x0d || recent[oldchar-1]==0x0a) 89 | && (recent[oldchar-4]==' ' || recent[oldchar-4]==0x0d || recent[oldchar-4]==0x0a) 90 | ) 91 | { 92 | return true; 93 | } 94 | return false; 95 | } 96 | 97 | //This method processes an uncompressed Adobe (text) object and extracts text. 98 | void ProcessOutput(char* output, size_t len) 99 | { 100 | //Are we currently inside a text object? 101 | bool intextobject = false; 102 | 103 | //Is the next character literal (e.g. \\ to get a \ character or \( to get ( ): 104 | bool nextliteral = false; 105 | 106 | //() Bracket nesting level. Text appears inside () 107 | int rbdepth = 0; 108 | 109 | //Keep previous chars to get extract numbers etc.: 110 | char oc[oldchar]; 111 | int j=0; 112 | for (j=0; j1.0) 125 | { 126 | [result appendFormat:@"\n"]; 127 | } 128 | if (num<1.0) 129 | { 130 | [result appendFormat:@"\t"]; 131 | } 132 | } 133 | if (rbdepth==0 && seen2("ET", oc)) 134 | { 135 | //End of a text object, also go to a new line. 136 | intextobject = false; 137 | [result appendFormat:@"\n"]; 138 | } 139 | else if (c=='(' && rbdepth==0 && !nextliteral) 140 | { 141 | //Start outputting text! 142 | rbdepth=1; 143 | //See if a space or tab (>1000) is called for by looking 144 | //at the number in front of ( 145 | int num = ExtractNumber(oc,oldchar-1); 146 | if (num>0) 147 | { 148 | if (num>1000.0) 149 | { 150 | [result appendFormat:@"\t"]; 151 | } 152 | else if (num>100.0) 153 | { 154 | [result appendFormat:@" "]; 155 | } 156 | } 157 | } 158 | else if (c==')' && rbdepth==1 && !nextliteral) 159 | { 160 | //Stop outputting text 161 | rbdepth=0; 162 | [result appendFormat:@"\n"]; 163 | } 164 | else if (rbdepth==1) 165 | { 166 | //Just a normal text character: 167 | if (c=='\\' && !nextliteral) 168 | { 169 | //Only print out next character no matter what. Do not interpret. 170 | nextliteral = true; 171 | } 172 | else 173 | { 174 | nextliteral = false; 175 | 176 | [result appendFormat:@"%c", c]; 177 | 178 | } 179 | } 180 | } 181 | //Store the recent characters for when we have to go back for a number: 182 | for (j=0; j= 0 || rst2 == -5) 239 | if (rst2 >= 0) 240 | { 241 | NSData * retdata = [[NSData alloc] initWithBytes:output length: zstrm.total_out]; 242 | //Ok, got something, extract the text: 243 | //size_t totout = zstrm.total_out; 244 | //printf("rawxxx: %s",output); 245 | //ProcessOutput(output, totout); 246 | //NSLog(@"text %@",result); 247 | //NSString *decompr = [NSString stringWithCString:output encoding:NSUTF8StringEncoding]; 248 | 249 | // printf("\nraw: %s",output); 250 | // NSString *decompr = [NSString stringWithUTF8String:(char *)output]; 251 | 252 | free(output); 253 | return retdata; 254 | 255 | 256 | } 257 | 258 | 259 | } 260 | 261 | free(output); 262 | return nil; 263 | } 264 | 265 | NSString* deflateDataAsString(NSData * data) 266 | { 267 | 268 | //Skip to beginning and end of the data stream: 269 | const char* buffer = data.bytes; 270 | size_t streamstart = 0; 271 | size_t streamend = data.length; 272 | 273 | if (buffer[streamstart]==0x0d && buffer[streamstart+1]==0x0a) streamstart+=2; 274 | else if (buffer[streamstart]==0x0a) streamstart++; 275 | 276 | if (buffer[streamend-2]==0x0d && buffer[streamend-1]==0x0a) streamend-=2; 277 | else if (buffer[streamend-1]==0x0a) streamend--; 278 | 279 | //Assume output will fit into 100 times input buffer: 280 | size_t outsize = (streamend - streamstart)*100; 281 | char *output = malloc(outsize*sizeof(char)); //Allocates the output 282 | ZeroMemory(output, outsize); 283 | 284 | //Now use zlib to inflate: 285 | z_stream zstrm; 286 | ZeroMemory(&zstrm, sizeof(zstrm)); 287 | 288 | zstrm.avail_in = (uInt)streamend - (uInt)streamstart + (uInt)1; 289 | zstrm.avail_out = (uInt)outsize; 290 | 291 | 292 | // NSLog(@"z avail_in : %d, z avail_out: %d", zstrm.avail_in , zstrm.avail_out); 293 | zstrm.next_in = (Bytef*)(buffer + streamstart); 294 | zstrm.next_out = (Bytef*)output; 295 | 296 | int rsti = inflateInit(&zstrm); 297 | if (rsti == Z_OK) 298 | { 299 | int rst2 = inflate (&zstrm, Z_FINISH); 300 | // if (rst2 >= 0 || rst2 == -5) 301 | if (rst2 >= 0) 302 | { 303 | //Ok, got something, extract the text: 304 | //size_t totout = zstrm.total_out; 305 | //printf("raw: %s",output); 306 | //ProcessOutput(output, totout); 307 | //NSLog(@"text %@",result); 308 | NSString *decompr = [NSString stringWithCString:output encoding:NSUTF8StringEncoding]; 309 | // printf("\nraw: %s",output); 310 | // NSString *decompr = [NSString stringWithUTF8String:(char *)output]; 311 | 312 | if(decompr) 313 | { 314 | free(output); 315 | return decompr; 316 | } 317 | else 318 | { 319 | NSString *decompr2 = [NSString stringWithCString:output encoding:NSMacOSRomanStringEncoding]; 320 | // NSLog(@"\nraw2: %@",decompr2); 321 | free(output); 322 | return decompr2; 323 | } 324 | 325 | 326 | 327 | return decompr; 328 | } 329 | 330 | 331 | } 332 | 333 | free(output); 334 | return nil; 335 | } 336 | 337 | 338 | 339 | -------------------------------------------------------------------------------- /YAPDFKit/test_in.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdfletterhead/YAPDFKit/ae6dc0a899259c3458b3d1c3225b8fefd05da49d/YAPDFKit/test_in.pdf --------------------------------------------------------------------------------