root / pkpgcounter / trunk / pkpgpdls / pclxl.py @ 307

Revision 307, 28.2 kB (checked in by jerome, 18 years ago)

Ensure that the input file is closed in all cases.
Skip faulty tags (due to unavailable PCLXL Class 3.0 specification) in PCLXL parser

  • Property svn:eol-style set to native
  • Property svn:keywords set to Auth Date Id Rev
Line 
1#! /usr/bin/env python
2# -*- coding: ISO-8859-15 -*-
3#
4# pkpgcounter : a generic Page Description Language parser
5#
6# (c) 2003, 2004, 2005, 2006 Jerome Alet <alet@librelogiciel.com>
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20#
21# $Id$
22#
23
24import sys
25import os
26import mmap
27from struct import unpack
28
29import pdlparser
30import pjl
31
32class Parser(pdlparser.PDLParser) :
33    """A parser for PCLXL (aka PCL6) documents."""
34    mediasizes = { 
35                    0 : "Letter",
36                    1 : "Legal",
37                    2 : "A4",
38                    3 : "Executive",
39                    4 : "Ledger",
40                    5 : "A3",
41                    6 : "COM10Envelope",
42                    7 : "MonarchEnvelope",
43                    8 : "C5Envelope",
44                    9 : "DLEnvelope",
45                    10 : "JB4",
46                    11 : "JB5",
47                    12 : "B5Envelope",
48                    12 : "B5",
49                    14 : "JPostcard",
50                    15 : "JDoublePostcard",
51                    16 : "A5",
52                    17 : "A6",
53                    18 : "JB6",
54                    19 : "JIS8K",
55                    20 : "JIS16K",
56                    21 : "JISExec",
57                    96 : "Default",
58                 }   
59                 
60    mediasources = {             
61                     0 : "Default",
62                     1 : "Auto",
63                     2 : "Manual",
64                     3 : "MultiPurpose",
65                     4 : "UpperCassette",
66                     5 : "LowerCassette",
67                     6 : "EnvelopeTray",
68                     7 : "ThirdCassette",
69                   }
70                   
71    orientations = {               
72                     0 : "Portrait",
73                     1 : "Landscape",
74                     2 : "ReversePortrait",
75                     3 : "ReverseLandscape",
76                     4 : "Default",
77                   }
78           
79    def isValid(self) :   
80        """Returns 1 if data is PCLXL aka PCL6, else 0."""
81        if ((self.firstblock[:128].find("\033%-12345X") != -1) and \
82             (self.firstblock.find(" HP-PCL XL;") != -1) and \
83             ((self.firstblock.find("LANGUAGE=PCLXL") != -1) or \
84              (self.firstblock.find("LANGUAGE = PCLXL") != -1))) :
85            self.logdebug("DEBUG: Input file is in the PCLXL (aka PCL6) format.")
86            return 1
87        else :   
88            return 0
89           
90    def beginPage(self) :
91        """Indicates the beginning of a new page, and extracts media information."""
92        self.pagecount += 1
93       
94        # Default values
95        mediatypelabel = "Plain"
96        mediasourcelabel = "Main"
97        mediasizelabel = "Default"
98        orientationlabel = "Portrait"
99        duplexmode = None
100       
101        # Now go upstream to decode media type, size, source, and orientation
102        # this saves time because we don't need a complete parser !
103        minfile = self.minfile
104       
105        # self.logdebug("--------------")   
106        # for i in range(100) :
107        #     self.logdebug("%08i ==> 0x%02x ==> '%s'"  % (self.pos - 98 + i, ord(self.minfile[self.pos - 98 + i]), self.minfile[self.pos - 98 + i]))
108        # self.logdebug("--------------")   
109           
110        pos = self.pos - 2
111        while pos > 0 : # safety check : don't go back to far !
112            val = ord(minfile[pos])
113            if val in (0x44, 0x48, 0x41) : # if previous endPage or openDataSource or beginSession (first page)
114                break
115            if val == 0x26 :   
116                mediasource = ord(minfile[pos - 2])
117                mediasourcelabel = self.mediasources.get(mediasource, str(mediasource))
118                pos -= 4
119            elif val == 0x25 :
120                while (pos > 0) and (ord(minfile[pos]) != 0xc0) :
121                    # we search the preceding ubyte tag
122                    pos -= 1
123                if pos > 0 :
124                    if ord(minfile[pos-1]) == 0xc8 :
125                        # if we found an ubyte_array then the media
126                        # size is completely spelled
127                        arraylength = ord(minfile[pos+1])
128                        mediasizelabel = minfile[pos+2:pos+2+arraylength].title()
129                        pos -= 1
130                    else :   
131                        # if we just found an ubyte, then the media
132                        # size is known by its index
133                        mediasize = ord(minfile[pos+1])
134                        mediasizelabel = self.mediasizes.get(mediasize, str(mediasize))
135                    pos -= 1 
136            elif val == 0x28 :   
137                orientation = ord(minfile[pos - 2])
138                orientationlabel = self.orientations.get(orientation, str(orientation))
139                pos -= 4
140            elif val == 0x27 :   
141                savepos = pos
142                pos -= 1
143                startpos = size = None 
144                while pos > 0 : # safety check : don't go back to far !
145                    val = ord(minfile[pos])
146                    pos -= 1   
147                    if val == 0xc8 :
148                        length = self.tags[ord(minfile[pos+2])] # will probably always be a byte or uint16
149                        if length == 1 :   
150                            startpos = pos + 4
151                            size = unpack("B", self.minfile[pos+3:startpos])[0]
152                        elif length == 2 :   
153                            startpos = pos + 5
154                            size = unpack(self.endianness + "H", self.minfile[pos+3:startpos])[0]
155                        elif length == 4 :   
156                            startpos = pos + 7
157                            size = unpack(self.endianness + "I", self.minfile[pos+3:startpos])[0]
158                        else :   
159                            raise pdlparser.PDLParserError, "Error on size at %s : %s" % (pos+2, length)
160                        break
161                mediatypelabel = minfile[startpos:startpos+size]
162            elif val == 0x34 :   
163                duplexmode = "Simplex"
164                pos -= 2
165            elif val in (0x35, 0x36) :   
166                duplexmode = "Duplex"
167                pos -= 2
168            # else : TODO : CUSTOM MEDIA SIZE AND UNIT !
169            else :   
170                pos -= 1  # ignored
171        self.pages[self.pagecount] = { "copies" : 1, 
172                                       "orientation" : orientationlabel, 
173                                       "mediatype" : mediatypelabel, 
174                                       "mediasize" : mediasizelabel,
175                                       "mediasource" : mediasourcelabel,
176                                       "duplex" : duplexmode,
177                                     } 
178        return 0
179       
180    def endPage(self) :   
181        """Indicates the end of a page."""
182        pos = self.pos
183        pos3 = pos - 3
184        minfile = self.minfile
185        if minfile[pos3:pos-1] == self.setNumberOfCopies :
186            # The EndPage operator may be preceded by a PageCopies attribute
187            # So set number of copies for current page.
188            # From what I read in PCLXL documentation, the number
189            # of copies is an unsigned 16 bits integer
190            try :
191                self.pages[self.pagecount]["copies"] = unpack(self.endianness + "H", minfile[pos-5:pos3])[0]
192            except KeyError :   
193                self.logdebug("It looks like this PCLXL file is corrupted.")
194        return 0
195       
196    def setColorSpace(self) :   
197        """Changes the color space."""
198        if self.minfile[self.pos-4:self.pos-1] == self.RGBColorSpace :
199            self.iscolor = 1
200        return 0
201           
202    def array_8(self) :   
203        """Handles byte arrays."""
204        pos = self.pos
205        datatype = self.minfile[pos]
206        pos += 1
207        length = self.tags[ord(datatype)]
208        if callable(length) :
209            self.pos = pos
210            length = length()
211            pos = self.pos
212        posl = pos + length
213        self.pos = posl
214        if length == 1 :   
215            return unpack("B", self.minfile[pos:posl])[0]
216        elif length == 2 :   
217            return unpack(self.endianness + "H", self.minfile[pos:posl])[0]
218        elif length == 4 :   
219            return unpack(self.endianness + "I", self.minfile[pos:posl])[0]
220        else :   
221            raise pdlparser.PDLParserError, "Error on array size at %s" % self.pos
222       
223    def array_16(self) :   
224        """Handles byte arrays."""
225        pos = self.pos
226        datatype = self.minfile[pos]
227        pos += 1
228        length = self.tags[ord(datatype)]
229        if callable(length) :
230            self.pos = pos
231            length = length()
232            pos = self.pos
233        posl = pos + length
234        self.pos = posl
235        if length == 1 :   
236            return 2 * unpack("B", self.minfile[pos:posl])[0]
237        elif length == 2 :   
238            return 2 * unpack(self.endianness + "H", self.minfile[pos:posl])[0]
239        elif length == 4 :   
240            return 2 * unpack(self.endianness + "I", self.minfile[pos:posl])[0]
241        else :   
242            raise pdlparser.PDLParserError, "Error on array size at %s" % self.pos
243       
244    def array_32(self) :   
245        """Handles byte arrays."""
246        pos = self.pos
247        datatype = self.minfile[pos]
248        pos += 1
249        length = self.tags[ord(datatype)]
250        if callable(length) :
251            self.pos = pos
252            length = length()
253            pos = self.pos
254        posl = pos + length
255        self.pos = posl
256        if length == 1 :   
257            return 4 * unpack("B", self.minfile[pos:posl])[0]
258        elif length == 2 :   
259            return 4 * unpack(self.endianness + "H", self.minfile[pos:posl])[0]
260        elif length == 4 :   
261            return 4 * unpack(self.endianness + "I", self.minfile[pos:posl])[0]
262        else :   
263            raise pdlparser.PDLParserError, "Error on array size at %s" % self.pos
264       
265    def embeddedDataSmall(self) :
266        """Handle small amounts of data."""
267        pos = self.pos
268        length = ord(self.minfile[pos])
269        self.pos = pos + 1
270        return length
271       
272    def embeddedData(self) :
273        """Handle normal amounts of data."""
274        pos = self.pos
275        pos4 = pos + 4
276        self.pos = pos4
277        return unpack(self.endianness + "I", self.minfile[pos:pos4])[0]
278       
279    def littleEndian(self) :       
280        """Toggles to little endianness."""
281        self.endianness = "<" # little endian
282        return 0
283       
284    def bigEndian(self) :   
285        """Toggles to big endianness."""
286        self.endianness = ">" # big endian
287        return 0
288   
289    def reservedForFutureUse(self) :
290        """Outputs something when a reserved byte is encountered."""
291        self.logdebug("Byte at %x is out of the PCLXL Protocol Class 2.0 Specification" % self.pos)
292        return 0   
293       
294    def passThrough(self) :   
295        """Passthrough mode, as detailed in PCLXL Feature Reference Protocol Class 3.0 Supplement."""
296        # TODO : do something here to skip the block.
297        self.logdebug("PassThrough marker detected at %x" % self.pos)
298        return 0
299       
300    def escape(self) :   
301        """Handles the ESC code."""
302        pos = endpos = self.pos
303        if self.minfile[pos : pos+8] == r"%-12345X" :
304            endpos = pos + 9
305            endmark = chr(0x0c) + chr(0x00) + chr(0x1b)
306            asciilimit = chr(0x80)
307            quotes = 0
308            while (self.minfile[endpos] not in endmark) and \
309                   ((self.minfile[endpos] < asciilimit) or (quotes % 2)) :
310                if self.minfile[endpos] == '"' :
311                    quotes += 1
312                endpos += 1
313               
314            # Store this in a per page mapping.   
315            # NB : First time will be at page 0 (i.e. **before** page 1) !
316            stuff = self.escapedStuff.setdefault(self.pagecount, [])
317            stuff.append(self.minfile[pos : endpos])
318            self.logdebug("Escaped datas : [%s]" % repr(self.minfile[pos : endpos]))
319        return endpos - pos
320       
321    def getJobSize(self) :
322        """Counts pages in a PCLXL (PCL6) document.
323       
324           Algorithm by Jerome Alet.
325           
326           The documentation used for this was :
327         
328           HP PCL XL Feature Reference
329           Protocol Class 2.0
330           http://www.hpdevelopersolutions.com/downloads/64/358/xl_ref20r22.pdf
331           
332           Protocol Class 2.1 Supplement
333           xl_ref21.pdf
334           
335           Protocol Class 3.0 Supplement
336           xl_refsup30r089.pdf
337        """
338        self.iscolor = None
339        self.endianness = None
340        found = 0
341        while not found :
342            line = self.infile.readline()
343            if not line :
344                break
345            pos = line.find(" HP-PCL XL;")   
346            if pos != -1 :
347                found = 1
348                endian = ord(line[pos - 1])
349                if endian == 0x29 :
350                    self.littleEndian()
351                elif endian == 0x28 :   
352                    self.bigEndian()
353                # elif endian == 0x27 : # TODO : This is the ESC code : parse it for PJL statements !
354                #
355                else :   
356                    raise pdlparser.PDLParserError, "Unknown endianness marker 0x%02x at start !" % endian
357        if not found :
358            raise pdlparser.PDLParserError, "This file doesn't seem to be PCLXL (aka PCL6)"
359           
360        # Initialize Media Sources
361        for i in range(8, 256) :
362            self.mediasources[i] = "ExternalTray%03i" % (i - 7)
363           
364        # Initialize table of tags
365        self.tags = [ 0 ] * 256   
366       
367        self.tags[0x1b] = self.escape # The escape code
368       
369        # GhostScript's sources tell us that HP printers
370        # only accept little endianness, but we can handle both.
371        self.tags[0x28] = self.bigEndian    # BigEndian
372        self.tags[0x29] = self.littleEndian # LittleEndian
373       
374        self.tags[0x43] = self.beginPage    # BeginPage
375        self.tags[0x44] = self.endPage      # EndPage
376        self.tags[0x45] = self.reservedForFutureUse # reserved
377        self.tags[0x46] = self.reservedForFutureUse # reserved
378       
379        self.tags[0x4a] = self.reservedForFutureUse # reserved
380        self.tags[0x4b] = self.reservedForFutureUse # reserved
381        self.tags[0x4c] = self.reservedForFutureUse # reserved
382        self.tags[0x4d] = self.reservedForFutureUse # reserved
383        self.tags[0x4e] = self.reservedForFutureUse # reserved
384       
385        self.tags[0x56] = self.reservedForFutureUse # TODO : documentation not clear about reserved status
386       
387        self.tags[0x57] = self.reservedForFutureUse # reserved
388        self.tags[0x58] = self.reservedForFutureUse # reserved
389        self.tags[0x59] = self.reservedForFutureUse # reserved
390        self.tags[0x5a] = self.reservedForFutureUse # reserved
391       
392        self.tags[0x6a] = self.setColorSpace    # to detect color/b&w mode
393       
394        self.tags[0x83] = self.reservedForFutureUse # reserved
395       
396        self.tags[0x87] = self.reservedForFutureUse # reserved
397        self.tags[0x88] = self.reservedForFutureUse # reserved
398        self.tags[0x89] = self.reservedForFutureUse # reserved
399        self.tags[0x8a] = self.reservedForFutureUse # reserved
400        self.tags[0x8b] = self.reservedForFutureUse # reserved
401        self.tags[0x8c] = self.reservedForFutureUse # reserved
402        self.tags[0x8d] = self.reservedForFutureUse # reserved
403        self.tags[0x8e] = self.reservedForFutureUse # reserved
404        self.tags[0x8f] = self.reservedForFutureUse # reserved
405        self.tags[0x90] = self.reservedForFutureUse # reserved
406       
407        self.tags[0x92] = self.reservedForFutureUse # reserved
408       
409        self.tags[0x94] = self.reservedForFutureUse # reserved
410       
411        self.tags[0x9a] = self.reservedForFutureUse # reserved
412        self.tags[0x9c] = self.reservedForFutureUse # reserved
413       
414        self.tags[0xa4] = self.reservedForFutureUse # reserved
415        self.tags[0xa5] = self.reservedForFutureUse # reserved
416        self.tags[0xa6] = self.reservedForFutureUse # reserved
417        self.tags[0xa7] = self.reservedForFutureUse # reserved
418       
419        self.tags[0xaa] = self.reservedForFutureUse # reserved
420        self.tags[0xab] = self.reservedForFutureUse # reserved
421        self.tags[0xac] = self.reservedForFutureUse # reserved
422        self.tags[0xad] = self.reservedForFutureUse # reserved
423        self.tags[0xae] = self.reservedForFutureUse # reserved
424        self.tags[0xaf] = self.reservedForFutureUse # reserved
425       
426        self.tags[0xb7] = self.reservedForFutureUse # reserved
427       
428        self.tags[0xba] = self.reservedForFutureUse # reserved
429        self.tags[0xbb] = self.reservedForFutureUse # reserved
430        self.tags[0xbc] = self.reservedForFutureUse # reserved
431        self.tags[0xbd] = self.reservedForFutureUse # reserved
432        self.tags[0xbe] = self.reservedForFutureUse # reserved
433       
434        self.tags[0xbf] = self.passThrough # From PCLXL Feature Reference Protocol Class 3.0 Supplement
435       
436        self.tags[0xc0] = 1 # ubyte
437        self.tags[0xc1] = 2 # uint16
438        self.tags[0xc2] = 4 # uint32
439        self.tags[0xc3] = 2 # sint16
440        self.tags[0xc4] = 4 # sint32
441        self.tags[0xc5] = 4 # real32
442       
443        self.tags[0xc6] = self.reservedForFutureUse # reserved
444        self.tags[0xc7] = self.reservedForFutureUse # reserved
445       
446        self.tags[0xc8] = self.array_8  # ubyte_array
447        self.tags[0xc9] = self.array_16 # uint16_array
448        self.tags[0xca] = self.array_32 # uint32_array
449        self.tags[0xcb] = self.array_16 # sint16_array
450        self.tags[0xcc] = self.array_32 # sint32_array
451        self.tags[0xcd] = self.array_32 # real32_array
452       
453        self.tags[0xce] = self.reservedForFutureUse # reserved
454        self.tags[0xcf] = self.reservedForFutureUse # reserved
455       
456        self.tags[0xd0] = 2 # ubyte_xy
457        self.tags[0xd1] = 4 # uint16_xy
458        self.tags[0xd2] = 8 # uint32_xy
459        self.tags[0xd3] = 4 # sint16_xy
460        self.tags[0xd4] = 8 # sint32_xy
461        self.tags[0xd5] = 8 # real32_xy
462        self.tags[0xd6] = self.reservedForFutureUse # reserved
463        self.tags[0xd7] = self.reservedForFutureUse # reserved
464        self.tags[0xd8] = self.reservedForFutureUse # reserved
465        self.tags[0xd9] = self.reservedForFutureUse # reserved
466        self.tags[0xda] = self.reservedForFutureUse # reserved
467        self.tags[0xdb] = self.reservedForFutureUse # reserved
468        self.tags[0xdc] = self.reservedForFutureUse # reserved
469        self.tags[0xdd] = self.reservedForFutureUse # reserved
470        self.tags[0xde] = self.reservedForFutureUse # reserved
471        self.tags[0xdf] = self.reservedForFutureUse # reserved
472       
473        self.tags[0xe0] = 4  # ubyte_box
474        self.tags[0xe1] = 8  # uint16_box
475        self.tags[0xe2] = 16 # uint32_box
476        self.tags[0xe3] = 8  # sint16_box
477        self.tags[0xe4] = 16 # sint32_box
478        self.tags[0xe5] = 16 # real32_box
479        self.tags[0xe6] = self.reservedForFutureUse # reserved
480        self.tags[0xe7] = self.reservedForFutureUse # reserved
481        self.tags[0xe8] = self.reservedForFutureUse # reserved
482        self.tags[0xe9] = self.reservedForFutureUse # reserved
483        self.tags[0xea] = self.reservedForFutureUse # reserved
484        self.tags[0xeb] = self.reservedForFutureUse # reserved
485        self.tags[0xec] = self.reservedForFutureUse # reserved
486        self.tags[0xed] = self.reservedForFutureUse # reserved
487        self.tags[0xee] = self.reservedForFutureUse # reserved
488        self.tags[0xef] = self.reservedForFutureUse # reserved
489       
490        self.tags[0xf0] = self.reservedForFutureUse # reserved
491        self.tags[0xf1] = self.reservedForFutureUse # reserved
492        self.tags[0xf2] = self.reservedForFutureUse # reserved
493        self.tags[0xf3] = self.reservedForFutureUse # reserved
494        self.tags[0xf4] = self.reservedForFutureUse # reserved
495        self.tags[0xf5] = self.reservedForFutureUse # reserved
496        self.tags[0xf6] = self.reservedForFutureUse # reserved
497        self.tags[0xf7] = self.reservedForFutureUse # reserved
498       
499        self.tags[0xf8] = 1 # attr_ubyte
500        self.tags[0xf9] = 2 # attr_uint16
501       
502        self.tags[0xfa] = self.embeddedData      # dataLength
503        self.tags[0xfb] = self.embeddedDataSmall # dataLengthByte
504       
505        self.tags[0xfc] = self.reservedForFutureUse # reserved
506        self.tags[0xfd] = self.reservedForFutureUse # reserved
507        self.tags[0xfe] = self.reservedForFutureUse # reserved
508        self.tags[0xff] = self.reservedForFutureUse # reserved
509           
510        # color spaces   
511        self.BWColorSpace = "".join([chr(0x00), chr(0xf8), chr(0x03)])
512        self.GrayColorSpace = "".join([chr(0x01), chr(0xf8), chr(0x03)])
513        self.RGBColorSpace = "".join([chr(0x02), chr(0xf8), chr(0x03)])
514       
515        # set number of copies
516        self.setNumberOfCopies = "".join([chr(0xf8), chr(0x31)]) 
517       
518        infileno = self.infile.fileno()
519        self.pages = { 0 : { "copies" : 1, 
520                             "orientation" : "Default", 
521                             "mediatype" : "Plain", 
522                             "mediasize" : "Default", 
523                             "mediasource" : "Default", 
524                             "duplex" : None,
525                           } 
526                     }     
527        self.minfile = minfile = mmap.mmap(infileno, os.fstat(infileno)[6], prot=mmap.PROT_READ, flags=mmap.MAP_SHARED)
528        tags = self.tags
529        self.pagecount = 0
530        self.escapedStuff = {}
531        self.pos = pos = oldpos = 0
532        try :
533            try :
534                while 1 :
535                    try :
536                        char = minfile[pos]
537                    except OverflowError :   
538                        pos = oldpos + 1
539                    pos += 1
540                    length = tags[ord(char)]
541                    if length :
542                        if callable(length) :   
543                            self.pos = pos
544                            length = length()
545                            pos = self.pos
546                        oldpos = pos   
547                        pos += length   
548            except IndexError : # EOF ?           
549                pass
550        finally :
551            self.minfile.close()
552           
553        # now handle number of copies for each page (may differ).
554        if self.iscolor :
555            colormode = "Color"
556        else :   
557            colormode = "BW"
558           
559        defaultduplexmode = "Simplex"
560        defaultpapersize = ""
561        defaultpjlcopies = 1   
562        oldpjlcopies = -1
563        oldduplexmode = ""
564        oldpapersize = ""
565        for pnum in range(1, self.pagecount + 1) :
566            # if no number of copies defined, take 1, as explained
567            # in PCLXL documentation.
568            # NB : is number of copies is 0, the page won't be output
569            # but the formula below is still correct : we want
570            # to decrease the total number of pages in this case.
571            page = self.pages.get(pnum, self.pages.get(1, { "copies" : 1, "mediasize" : "Default", "duplex" : None }))
572            pjlstuff = self.escapedStuff.get(pnum, self.escapedStuff.get(0, []))
573            if pjlstuff :
574                pjlparser = pjl.PJLParser("".join(pjlstuff))
575                nbdefaultcopies = int(pjlparser.default_variables.get("COPIES", -1))
576                nbcopies = int(pjlparser.environment_variables.get("COPIES", -1))
577                nbdefaultqty = int(pjlparser.default_variables.get("QTY", -1))
578                nbqty = int(pjlparser.environment_variables.get("QTY", -1))
579                if nbdefaultcopies > -1 :
580                    defaultpjlcopies = nbdefaultcopies
581                if nbdefaultqty > -1 :
582                    defaultpjlcopies = nbdefaultqty
583                if nbcopies > -1 :
584                    pjlcopies = nbcopies
585                elif nbqty > -1 :
586                    pjlcopies = nbqty
587                else :
588                    if oldpjlcopies == -1 :   
589                        pjlcopies = defaultpjlcopies
590                    else :   
591                        pjlcopies = oldpjlcopies   
592                if page["duplex"] :       
593                    duplexmode = page["duplex"]
594                else :   
595                    defaultdm = pjlparser.default_variables.get("DUPLEX", "")
596                    if defaultdm :
597                        if defaultdm.upper() == "ON" :
598                            defaultduplexmode = "Duplex"
599                        else :   
600                            defaultduplexmode = "Simplex"
601                    envdm = pjlparser.environment_variables.get("DUPLEX", "")
602                    if envdm :
603                        if envdm.upper() == "ON" :
604                            duplexmode = "Duplex"
605                        else :   
606                            duplexmode = "Simplex"
607                    else :       
608                        if not oldduplexmode :
609                            duplexmode = defaultduplexmode
610                        else :   
611                            duplexmode = oldduplexmode
612                defaultps = pjlparser.default_variables.get("PAPER", "")
613                if defaultps :
614                    defaultpapersize = defaultps
615                envps = pjlparser.environment_variables.get("PAPER", "")
616                if envps :
617                    papersize = envps
618                else :   
619                    if not oldpapersize :
620                        papersize = defaultpapersize
621                    else :   
622                        papersize = oldpapersize
623            else :       
624                if oldpjlcopies == -1 :
625                    pjlcopies = defaultpjlcopies
626                else :   
627                    pjlcopies = oldpjlcopies
628                if not oldduplexmode :
629                    duplexmode = defaultduplexmode
630                else :   
631                    duplexmode = oldduplexmode
632                if not oldpapersize :   
633                    papersize = defaultpapersize
634                else :   
635                    papersize = oldpapersize
636                duplexmode = oldduplexmode
637                papersize = oldpapersize or page["mediasize"]
638            if page["mediasize"] != "Default" :
639                papersize = page["mediasize"]
640            if not duplexmode :   
641                duplexmode = oldduplexmode or defaultduplexmode
642            oldpjlcopies = pjlcopies   
643            oldduplexmode = duplexmode
644            oldpapersize = papersize
645            copies = pjlcopies * page["copies"]
646            self.pagecount += (copies - 1)
647            self.logdebug("%s*%s*%s*%s*%s*%s*%s" % (copies, 
648                                                 page["mediatype"], 
649                                                 papersize, 
650                                                 page["orientation"], 
651                                                 page["mediasource"], 
652                                                 duplexmode, 
653                                                 colormode))
654        return self.pagecount
655       
656def test() :       
657    """Test function."""
658    if (len(sys.argv) < 2) or ((not sys.stdin.isatty()) and ("-" not in sys.argv[1:])) :
659        sys.argv.append("-")
660    totalsize = 0   
661    for arg in sys.argv[1:] :
662        if arg == "-" :
663            infile = sys.stdin
664            mustclose = 0
665        else :   
666            infile = open(arg, "rb")
667            mustclose = 1
668        try :
669            parser = Parser(infile, debug=1)
670            totalsize += parser.getJobSize()
671        except pdlparser.PDLParserError, msg :   
672            sys.stderr.write("ERROR: %s\n" % msg)
673            sys.stderr.flush()
674        if mustclose :   
675            infile.close()
676    print "%s" % totalsize
677   
678if __name__ == "__main__" :   
679    test()
Note: See TracBrowser for help on using the browser.