1 /* Copyright (c) 2007 Christopher J. W. Lloyd
3 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
9 #import "O2PDFFunction_Type4.h"
10 #import <Onyx2D/O2PDFArray.h>
11 #import <Onyx2D/O2PDFDictionary.h>
12 #import <Onyx2D/O2PDFContext.h>
13 #import <Onyx2D/O2PDFObject_Integer.h>
14 #import <Onyx2D/O2PDFObject_Real.h>
15 #import <Onyx2D/O2PDFObject_Boolean.h>
16 #import <Onyx2D/O2PDFObject_const.h>
17 #import <Onyx2D/O2PDFObject_identifier.h>
18 #import "O2PDFBlock.h"
20 #import <Foundation/NSArray.h>
23 @implementation O2PDFFunction_Type4
25 static void runBlock(NSMutableArray *stack,O2PDFBlock *block){
26 NSArray *operators=[block objects];
27 NSInteger i,count=[operators count];
30 O2PDFObject *check=[operators objectAtIndex:i];
32 if([check objectType]!=O2PDFObjectType_identifier)
33 [stack addObject:check];
35 NSLog(@"execute %@",check);
36 switch([(O2PDFObject_identifier *)check identifier]){
39 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
42 case O2PDFIdentifier_abs:
43 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
46 case O2PDFIdentifier_add:
47 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
50 case O2PDFIdentifier_atan:
51 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
54 case O2PDFIdentifier_ceiling:
55 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
58 case O2PDFIdentifier_cos:
59 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
62 case O2PDFIdentifier_cvi:
63 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
66 case O2PDFIdentifier_cvr:{
69 if([[stack lastObject] checkForType:kO2PDFObjectTypeInteger value:&value]){
70 [stack removeLastObject];
71 [stack addObject:[O2PDFObject_Real pdfObjectWithReal:value]];
76 case O2PDFIdentifier_div:
77 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
80 case O2PDFIdentifier_exp:
81 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
84 case O2PDFIdentifier_floor:
85 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
88 case O2PDFIdentifier_idiv:
89 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
92 case O2PDFIdentifier_ln:
93 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
96 case O2PDFIdentifier_log:
97 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
100 case O2PDFIdentifier_mod:
101 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
104 case O2PDFIdentifier_mul:
105 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
108 case O2PDFIdentifier_neg:
109 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
112 case O2PDFIdentifier_round:
113 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
116 case O2PDFIdentifier_sin:
117 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
120 case O2PDFIdentifier_sqrt:
121 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
124 case O2PDFIdentifier_sub:{
127 if(![[stack lastObject] checkForType:kO2PDFObjectTypeReal value:&num2]){
128 O2PDFFix(__FILE__,__LINE__,@"sub operator typecheck fail");
131 [stack removeLastObject];
133 if(![[stack lastObject] checkForType:kO2PDFObjectTypeReal value:&num1]){
134 O2PDFFix(__FILE__,__LINE__,@"sub operator typecheck fail");
137 [stack removeLastObject];
139 [stack addObject:[O2PDFObject_Real pdfObjectWithReal:num1-num2]];
143 case O2PDFIdentifier_truncate:
144 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
147 case O2PDFIdentifier_and:
148 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
151 case O2PDFIdentifier_bitshift:
152 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
155 case O2PDFIdentifier_eq:
156 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
159 case O2PDFIdentifier_ge:
160 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
163 case O2PDFIdentifier_gt:
164 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
167 case O2PDFIdentifier_le:
168 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
171 case O2PDFIdentifier_lt:
172 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
175 case O2PDFIdentifier_ne:
176 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
179 case O2PDFIdentifier_not:
180 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
183 case O2PDFIdentifier_or:
184 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
187 case O2PDFIdentifier_xor:
188 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
191 case O2PDFIdentifier_if:
192 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
195 case O2PDFIdentifier_ifelse:
196 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
199 case O2PDFIdentifier_copy:
200 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
203 case O2PDFIdentifier_dup:
204 O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
207 case O2PDFIdentifier_exch:{
208 NSInteger count=[stack count];
210 [stack addObject:[stack objectAtIndex:count-2]];
211 [stack removeObjectAtIndex:count-3];
215 case O2PDFIdentifier_index:;
218 if(![[stack lastObject] checkForType:kO2PDFObjectTypeInteger value:&index]){
219 O2PDFFix(__FILE__,__LINE__,@"roll operator typecheck fail");
222 [stack removeLastObject];
224 NSInteger count=[stack count];
225 [stack addObject:[stack objectAtIndex:(count-1)-index]];
228 case O2PDFIdentifier_pop:
229 [stack removeLastObject];
232 case O2PDFIdentifier_roll:;
233 O2PDFInteger rollCount,rollSize;
235 if(![[stack lastObject] checkForType:kO2PDFObjectTypeInteger value:&rollCount]){
236 O2PDFFix(__FILE__,__LINE__,@"roll operator typecheck fail");
240 [stack removeLastObject];
242 if(![[stack lastObject] checkForType:kO2PDFObjectTypeInteger value:&rollSize]){
243 O2PDFFix(__FILE__,__LINE__,@"roll operator typecheck fail");
246 [stack removeLastObject];
248 NSInteger stackSize=[stack count];
250 while(--rollCount>=0){
251 id object=[stack objectAtIndex:stackSize-rollSize];
252 [stack addObject:object];
253 [stack removeObjectAtIndex:stackSize-(rollSize+1)];
263 static void evaluate(void *info,const float *input,float *output) {
264 O2PDFFunction_Type4 *self=info;
266 NSMutableArray *stack=[NSMutableArray array];
268 [stack addObject:[O2PDFObject_Real pdfObjectWithReal:x]];
269 runBlock(stack,self->_calculator);
271 NSLog(@"stack=%@",stack);
273 int count=self->_rangeCount/2;
277 [[stack lastObject] checkForType:kO2PDFObjectTypeReal value:&value];
287 static O2PDFIdentifier O2PostScriptClassifyIdentifier(const char *bytes,unsigned length) {
290 strncpy(name,bytes,length);
294 if(strcmp(name,"true")==0)
295 return O2PDFIdentifier_true;
296 if(strcmp(name,"false")==0)
297 return O2PDFIdentifier_false;
299 if(strcmp(name,"abs")==0)
300 return O2PDFIdentifier_abs;
301 if(strcmp(name,"add")==0)
302 return O2PDFIdentifier_add;
303 if(strcmp(name,"atan")==0)
304 return O2PDFIdentifier_atan;
305 if(strcmp(name,"ceiling")==0)
306 return O2PDFIdentifier_ceiling;
307 if(strcmp(name,"cos")==0)
308 return O2PDFIdentifier_cos;
309 if(strcmp(name,"cvi")==0)
310 return O2PDFIdentifier_cvi;
311 if(strcmp(name,"cvr")==0)
312 return O2PDFIdentifier_cvr;
313 if(strcmp(name,"div")==0)
314 return O2PDFIdentifier_div;
315 if(strcmp(name,"exp")==0)
316 return O2PDFIdentifier_exp;
317 if(strcmp(name,"floor")==0)
318 return O2PDFIdentifier_floor;
319 if(strcmp(name,"idiv")==0)
320 return O2PDFIdentifier_idiv;
321 if(strcmp(name,"ln")==0)
322 return O2PDFIdentifier_ln;
323 if(strcmp(name,"log")==0)
324 return O2PDFIdentifier_log;
325 if(strcmp(name,"mod")==0)
326 return O2PDFIdentifier_mod;
327 if(strcmp(name,"mul")==0)
328 return O2PDFIdentifier_mul;
329 if(strcmp(name,"neg")==0)
330 return O2PDFIdentifier_neg;
331 if(strcmp(name,"round")==0)
332 return O2PDFIdentifier_round;
333 if(strcmp(name,"sin")==0)
334 return O2PDFIdentifier_sin;
335 if(strcmp(name,"sqrt")==0)
336 return O2PDFIdentifier_sqrt;
337 if(strcmp(name,"sub")==0)
338 return O2PDFIdentifier_sub;
339 if(strcmp(name,"truncate")==0)
340 return O2PDFIdentifier_truncate;
342 if(strcmp(name,"and")==0)
343 return O2PDFIdentifier_and;
344 if(strcmp(name,"bitshift")==0)
345 return O2PDFIdentifier_bitshift;
346 if(strcmp(name,"eq")==0)
347 return O2PDFIdentifier_eq;
348 if(strcmp(name,"ge")==0)
349 return O2PDFIdentifier_ge;
350 if(strcmp(name,"le")==0)
351 return O2PDFIdentifier_le;
352 if(strcmp(name,"lt")==0)
353 return O2PDFIdentifier_lt;
354 if(strcmp(name,"ne")==0)
355 return O2PDFIdentifier_ne;
356 if(strcmp(name,"not")==0)
357 return O2PDFIdentifier_not;
358 if(strcmp(name,"or")==0)
359 return O2PDFIdentifier_or;
360 if(strcmp(name,"xor")==0)
361 return O2PDFIdentifier_xor;
363 if(strcmp(name,"if")==0)
364 return O2PDFIdentifier_if;
365 if(strcmp(name,"ifelse")==0)
366 return O2PDFIdentifier_ifelse;
368 if(strcmp(name,"copy")==0)
369 return O2PDFIdentifier_copy;
370 if(strcmp(name,"dup")==0)
371 return O2PDFIdentifier_dup;
372 if(strcmp(name,"exch")==0)
373 return O2PDFIdentifier_exch;
374 if(strcmp(name,"index")==0)
375 return O2PDFIdentifier_index;
376 if(strcmp(name,"pop")==0)
377 return O2PDFIdentifier_pop;
378 if(strcmp(name,"roll")==0)
379 return O2PDFIdentifier_roll;
382 return O2PDFIdentifierUnknown;
385 // Returns YES and *objectp==NULL on end of stream
386 static BOOL O2PDFScanCalculator(const char *bytes,unsigned length,O2PDFInteger position,O2PDFInteger *lastPosition,O2PDFObject **objectp) {
387 O2PDFInteger currentSign=1,currentInt=0;
388 O2PDFReal currentReal=0,currentFraction=0;
389 int inlineLocation=0;
397 } state=STATE_SCANNING;
401 for(;position<length;position++){
402 unsigned char code=bytes[position];
404 //NSLog(@"state=%d,code=%c",state,code);
433 case '0': case '1': case '2': case '3': case '4':
434 case '5': case '6': case '7': case '8': case '9':
448 *objectp=[O2PDFObject_const pdfObjectProcMark];
449 *lastPosition=position+1;
453 *objectp=[O2PDFObject_const pdfObjectProcMarkEnd];
454 *lastPosition=position+1;
458 state=STATE_IDENTIFIER;
459 inlineLocation=position;
465 if(code==CR || code==LF || code==FF)
466 state=STATE_SCANNING;
472 currentReal=currentInt;
475 else if(code>='0' && code<='9')
476 currentInt=currentInt*10+code-'0';
478 *objectp=[O2PDFObject_Integer pdfObjectWithInteger:currentSign*currentInt];
479 *lastPosition=position;
485 if(code>='0' && code<='9'){
486 currentReal+=currentFraction*(code-'0');
487 currentFraction*=0.1;
490 *objectp=[O2PDFObject_Real pdfObjectWithReal:currentSign*currentReal];
491 *lastPosition=position;
496 case STATE_IDENTIFIER:
497 if(code==' ' || code==CR || code==FF || code==LF || code=='\t' || code=='\0' ||
498 code=='%' || code=='(' || code==')' || code=='<' || code=='>' || code==']' ||
499 code=='[' || code=='{' || code=='}' || code=='/'){
500 const char *name=bytes+inlineLocation;
501 unsigned length=position-inlineLocation;
502 O2PDFIdentifier identifier=O2PostScriptClassifyIdentifier(name,length);
504 if(identifier==O2PDFIdentifier_true)
505 *objectp=[O2PDFObject_Boolean pdfObjectWithTrue];
506 else if(identifier==O2PDFIdentifier_false)
507 *objectp=[O2PDFObject_Boolean pdfObjectWithFalse];
509 *objectp=[O2PDFObject_identifier pdfObjectWithIdentifier:identifier name:name length:length];
511 *lastPosition=position;
518 *lastPosition=position;
520 return (state==STATE_SCANNING)?YES:NO;
523 static O2PDFBlock *O2PDFParseCalculator(const char *bytes,unsigned length,O2PDFInteger position,O2PDFInteger *lastPosition) {
524 NSMutableArray *stack=[NSMutableArray array];
529 if(!O2PDFScanCalculator(bytes,length,position,&position,&check))
532 NSLog(@"check=%@",check);
535 *lastPosition=position;
539 switch([check objectType]){
542 case kO2PDFObjectTypeBoolean:
543 case kO2PDFObjectTypeInteger:
544 case kO2PDFObjectTypeReal:
545 case O2PDFObjectType_identifier:
546 block=[stack lastObject];
549 O2PDFError(__FILE__,__LINE__,@"PS calculator parse error");
553 [block addObject:check];
556 case O2PDFObjectTypeMark_proc_open:
557 [stack addObject:[O2PDFBlock pdfBlock]];
560 case O2PDFObjectTypeMark_proc_close:;
561 block=[stack lastObject];
564 O2PDFError(__FILE__,__LINE__,@"PS calculator parse error");
568 [[block retain] autorelease];
569 [stack removeLastObject];
571 O2PDFBlock *superBlock=[stack lastObject];
576 [superBlock addObject:block];
580 [stack addObject:check];
591 -initWithDomain:(O2PDFArray *)domain range:(O2PDFArray *)range calculator:(NSData *)data {
592 NSLog(@"INITIALIZE TYPE 4");
593 if([super initWithDomain:domain range:range]==nil)
597 _callbacks.evaluate=evaluate;
600 _calculator=[O2PDFParseCalculator([data bytes],[data length],0,&lastPosition) retain];
601 NSLog(@"calculator=%@",_calculator);
607 [_calculator release];
615 -(O2PDFObject *)encodeReferenceWithContext:(O2PDFContext *)context {
616 O2PDFDictionary *result=[O2PDFDictionary pdfDictionary];
619 [result setIntegerForKey:"FunctionType" value:4];
620 [result setObjectForKey:"Domain" value:[O2PDFArray pdfArrayWithNumbers:_domain count:_domainCount]];
621 [result setObjectForKey:"Range" value:[O2PDFArray pdfArrayWithNumbers:_range count:_rangeCount]];
624 return [context encodeIndirectPDFObject:result];
627 -(NSString *)description {
628 NSMutableString *result=[NSMutableString string];
629 [result appendFormat:@"<%@ %p:",isa,self];
630 [result appendFormat:@"calculator=%@",_calculator];
631 [result appendFormat:@">"];