Merge pull request #10 from gunyarakun/fix-invalid-return
[cocotron.git] / Onyx2D / O2PDFFunction_Type4.m
blob637e779b0615d54997d394b4144a25961828ca3a
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>
21 #import <stddef.h>
23 @implementation O2PDFFunction_Type4
25 static void runBlock(NSMutableArray *stack,O2PDFBlock *block){
26    NSArray  *operators=[block objects];
27    NSInteger i,count=[operators count];
28    
29    for(i=0;i<count;i++){
30     O2PDFObject *check=[operators objectAtIndex:i];
31     
32     if([check objectType]!=O2PDFObjectType_identifier)
33      [stack addObject:check];
34     else {
35      NSLog(@"execute %@",check);
36      switch([(O2PDFObject_identifier *)check identifier]){
38       default:
39        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
40        break;
41        
42       case O2PDFIdentifier_abs:
43        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
44        break;
46       case O2PDFIdentifier_add:
47        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
48        break;
50       case O2PDFIdentifier_atan:
51        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
52        break;
54       case O2PDFIdentifier_ceiling:
55        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
56        break;
58       case O2PDFIdentifier_cos:
59        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
60        break;
62       case O2PDFIdentifier_cvi:
63        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
64        break;
66       case O2PDFIdentifier_cvr:{
67         O2PDFInteger value;
68        
69         if([[stack lastObject] checkForType:kO2PDFObjectTypeInteger value:&value]){
70          [stack removeLastObject];
71          [stack addObject:[O2PDFObject_Real pdfObjectWithReal:value]];
72         }
73        }
74        break;
76       case O2PDFIdentifier_div:
77        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
78        break;
80       case O2PDFIdentifier_exp:
81        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
82        break;
84       case O2PDFIdentifier_floor:
85        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
86        break;
88       case O2PDFIdentifier_idiv:
89        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
90        break;
92       case O2PDFIdentifier_ln:
93        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
94        break;
96       case O2PDFIdentifier_log:
97        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
98        break;
100       case O2PDFIdentifier_mod:
101        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
102        break;
104       case O2PDFIdentifier_mul:
105        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
106        break;
108       case O2PDFIdentifier_neg:
109        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
110        break;
112       case O2PDFIdentifier_round:
113        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
114        break;
116       case O2PDFIdentifier_sin:
117        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
118        break;
120       case O2PDFIdentifier_sqrt:
121        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
122        break;
124       case O2PDFIdentifier_sub:{
125         O2PDFReal num2,num1;
126         
127         if(![[stack lastObject] checkForType:kO2PDFObjectTypeReal value:&num2]){
128          O2PDFFix(__FILE__,__LINE__,@"sub operator typecheck fail");
129          return;
130         }
131         [stack removeLastObject];
132         
133         if(![[stack lastObject] checkForType:kO2PDFObjectTypeReal value:&num1]){
134          O2PDFFix(__FILE__,__LINE__,@"sub operator typecheck fail");
135          return;
136         }
137         [stack removeLastObject];
138         
139         [stack addObject:[O2PDFObject_Real pdfObjectWithReal:num1-num2]];
140        }
141        break;
143       case O2PDFIdentifier_truncate:
144        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
145        break;
147       case O2PDFIdentifier_and:
148        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
149        break;
151       case O2PDFIdentifier_bitshift:
152        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
153        break;
155       case O2PDFIdentifier_eq:
156        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
157        break;
159       case O2PDFIdentifier_ge:
160        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
161        break;
163       case O2PDFIdentifier_gt:
164        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
165        break;
167       case O2PDFIdentifier_le:
168        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
169        break;
171       case O2PDFIdentifier_lt:
172        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
173        break;
175       case O2PDFIdentifier_ne:
176        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
177        break;
179       case O2PDFIdentifier_not:
180        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
181        break;
183       case O2PDFIdentifier_or:
184        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
185        break;
187       case O2PDFIdentifier_xor:
188        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
189        break;
191       case O2PDFIdentifier_if:
192        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
193        break;
195       case O2PDFIdentifier_ifelse:
196        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
197        break;
199       case O2PDFIdentifier_copy:
200        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
201        break;
203       case O2PDFIdentifier_dup:
204        O2PDFFix(__FILE__,__LINE__,@"PostScript calculator operator %@",check);
205        break;
207       case O2PDFIdentifier_exch:{
208         NSInteger count=[stack count];
209         
210         [stack addObject:[stack objectAtIndex:count-2]];
211         [stack removeObjectAtIndex:count-3];
212        }
213        break;
215       case O2PDFIdentifier_index:;
216        O2PDFInteger index;
217        
218        if(![[stack lastObject] checkForType:kO2PDFObjectTypeInteger value:&index]){
219         O2PDFFix(__FILE__,__LINE__,@"roll operator typecheck fail");
220         return;
221        }
222        [stack removeLastObject];
223        
224        NSInteger count=[stack count];
225        [stack addObject:[stack objectAtIndex:(count-1)-index]];
226        break;
228       case O2PDFIdentifier_pop:
229        [stack removeLastObject];
230        break;
232       case O2PDFIdentifier_roll:;
233        O2PDFInteger rollCount,rollSize;
234        
235        if(![[stack lastObject] checkForType:kO2PDFObjectTypeInteger value:&rollCount]){
236         O2PDFFix(__FILE__,__LINE__,@"roll operator typecheck fail");
237         return;
238        }
239        
240        [stack removeLastObject];
241        
242        if(![[stack lastObject] checkForType:kO2PDFObjectTypeInteger value:&rollSize]){
243         O2PDFFix(__FILE__,__LINE__,@"roll operator typecheck fail");
244         return;
245        }
246        [stack removeLastObject];
247        
248        NSInteger stackSize=[stack count];
249        
250        while(--rollCount>=0){
251         id object=[stack objectAtIndex:stackSize-rollSize];
252         [stack addObject:object];
253         [stack removeObjectAtIndex:stackSize-(rollSize+1)];
254        }
255        
256        break;
257      }
258      
259     }
260    }
263 static void evaluate(void *info,const float *input,float *output) {
264    O2PDFFunction_Type4 *self=info;
265    float                x=input[0];
266    NSMutableArray      *stack=[NSMutableArray array];
267    
268    [stack addObject:[O2PDFObject_Real pdfObjectWithReal:x]];
269    runBlock(stack,self->_calculator);
270    
271    NSLog(@"stack=%@",stack);
273    int count=self->_rangeCount/2;
274    while(--count>=0){
275     O2PDFReal value=0.0;
276     
277     [[stack lastObject] checkForType:kO2PDFObjectTypeReal value:&value];
279     output[count]=value;
280    }
283 #define LF 10
284 #define FF 12
285 #define CR 13
287 static O2PDFIdentifier O2PostScriptClassifyIdentifier(const char *bytes,unsigned length) {
288    char name[length+1];
289    
290    strncpy(name,bytes,length);
291    name[length]='\0';
293    
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;
381        
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;
390    
391    enum {
392     STATE_SCANNING,
393     STATE_COMMENT,
394     STATE_INTEGER,
395     STATE_REAL,
396     STATE_IDENTIFIER,
397    } state=STATE_SCANNING;
398    
399    *objectp=NULL;
400    
401    for(;position<length;position++){
402     unsigned char code=bytes[position];
403         
404               //NSLog(@"state=%d,code=%c",state,code);
405         switch(state){
406           
407          case STATE_SCANNING:
408           switch(code){
409           
410            case ' ':
411            case  CR:
412            case  FF:
413            case  LF:
414            case '\t':
415             break;
416                 
417        case '%':
418         state=STATE_COMMENT;
419         break;
421        case '-':
422         state=STATE_INTEGER;
423             currentSign=-1;
424             currentInt=0;
425         break;
426         
427        case '+':
428         state=STATE_INTEGER;
429             currentSign=1;
430             currentInt=0;
431         break;
433        case '0': case '1': case '2': case '3': case '4':
434        case '5': case '6': case '7': case '8': case '9':
435         state=STATE_INTEGER;
436             currentSign=1;
437             currentInt=code-'0';
438         break;
440        case '.':
441         state=STATE_REAL;
442             currentSign=1;
443             currentReal=0;
444         currentFraction=0.1;
445         break;
446         
447        case '{':
448         *objectp=[O2PDFObject_const pdfObjectProcMark];
449         *lastPosition=position+1;
450         return YES;
452        case '}':
453         *objectp=[O2PDFObject_const pdfObjectProcMarkEnd];
454         *lastPosition=position+1;
455         return YES;
457        default:
458         state=STATE_IDENTIFIER;
459         inlineLocation=position;
460         break;
461           }
462           break;
463           
464      case STATE_COMMENT:
465       if(code==CR || code==LF || code==FF)
466        state=STATE_SCANNING;
467       break;
469      case STATE_INTEGER:
470       if(code=='.'){
471        state=STATE_REAL;
472        currentReal=currentInt;
473        currentFraction=0.1;
474       }
475       else if(code>='0' && code<='9')
476        currentInt=currentInt*10+code-'0';
477       else {
478        *objectp=[O2PDFObject_Integer pdfObjectWithInteger:currentSign*currentInt];
479        *lastPosition=position;
480        return YES;
481       }
482       break;
484      case STATE_REAL:
485       if(code>='0' && code<='9'){
486        currentReal+=currentFraction*(code-'0');
487        currentFraction*=0.1;
488       }
489       else {
490        *objectp=[O2PDFObject_Real pdfObjectWithReal:currentSign*currentReal];
491        *lastPosition=position;
492        return YES;
493       }
494       break;
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);
503        
504        if(identifier==O2PDFIdentifier_true)
505         *objectp=[O2PDFObject_Boolean pdfObjectWithTrue];
506        else if(identifier==O2PDFIdentifier_false)
507         *objectp=[O2PDFObject_Boolean pdfObjectWithFalse];
508        else
509         *objectp=[O2PDFObject_identifier pdfObjectWithIdentifier:identifier name:name length:length];
511        *lastPosition=position;
512        return YES;
513       }
514       break;
515         }
516    }
517        
518    *lastPosition=position;
519     
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];
525    O2PDFObject    *check;
526          
527    while(YES) {
529     if(!O2PDFScanCalculator(bytes,length,position,&position,&check))
530      return NO;
532 NSLog(@"check=%@",check);
534     if(check==NULL){
535      *lastPosition=position;
536      return nil;
537     }
538             
539     switch([check objectType]){
540      O2PDFBlock *block;
541      
542      case kO2PDFObjectTypeBoolean:
543      case kO2PDFObjectTypeInteger:
544      case kO2PDFObjectTypeReal:
545      case O2PDFObjectType_identifier:
546       block=[stack lastObject];
547       
548       if(block==nil){
549        O2PDFError(__FILE__,__LINE__,@"PS calculator parse error");
550        return NO;
551       }
552       
553       [block addObject:check];
554       break;
555            
556      case O2PDFObjectTypeMark_proc_open:
557        [stack addObject:[O2PDFBlock pdfBlock]];
558        break;
560      case O2PDFObjectTypeMark_proc_close:;
561        block=[stack lastObject];
562        
563        if(block==nil){
564         O2PDFError(__FILE__,__LINE__,@"PS calculator parse error");
565         return NO;
566        }
567        
568        [[block retain] autorelease];
569        [stack removeLastObject];
570        
571        O2PDFBlock *superBlock=[stack lastObject];
572        
573        if(superBlock==nil)
574         return block;
575        
576        [superBlock addObject:block];
577        break;
578        
579             
580       [stack addObject:check];
581       break;
582                   
583      default:
584       return NO;
585     }
586    }
587    
588    return NO;
591 -initWithDomain:(O2PDFArray *)domain range:(O2PDFArray *)range calculator:(NSData *)data {
592 NSLog(@"INITIALIZE TYPE 4");
593    if([super initWithDomain:domain range:range]==nil)
594     return nil;
596    _info=self;
597    _callbacks.evaluate=evaluate;
599    int lastPosition=0;
600    _calculator=[O2PDFParseCalculator([data bytes],[data length],0,&lastPosition) retain];
601    NSLog(@"calculator=%@",_calculator);
602          
603    return self;
606 -(void)dealloc {
607    [_calculator release];
608    [super dealloc];
611 -(BOOL)isLinear {
612    return NO;
615 -(O2PDFObject *)encodeReferenceWithContext:(O2PDFContext *)context {
616    O2PDFDictionary *result=[O2PDFDictionary pdfDictionary];
617    int              i;
618    
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]];
622    // FIXME  stream
623    
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:@">"];
632    
633    return result;
636 @end