root / pkpgcounter / trunk / bin / pkpgcounter @ 195

Revision 195, 9.0 kB (checked in by jerome, 19 years ago)

Ensure that pkpgcounter doesn't run anymore, until all the big
changes are finished

  • Property svn:executable set to *
  • 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20#
21# $Id$
22#
23#
24
25import sys
26import tempfile
27   
28from pdlanalyzer import version
29
30KILOBYTE = 1024   
31MEGABYTE = 1024 * KILOBYTE   
32LASTBLOCKSIZE = int(KILOBYTE / 4)
33
34class PDLAnalyzer :   
35    """Generic PDL Analyzer class."""
36    def __init__(self, filename, debug=0) :
37        """Initializes the PDL analyzer.
38       
39           filename is the name of the file or '-' for stdin.
40           filename can also be a file-like object which
41           supports read() and seek().
42        """
43        self.debug = debug
44        self.filename = filename
45        try :
46            import psyco 
47        except ImportError :   
48            sys.stderr.write("pkpgcounter : you should install psyco if possible, this would greatly speedup parsing.\n")
49            pass # Psyco is not installed
50        else :   
51            # Psyco is installed, tell it to compile
52            # the CPU intensive methods : PCL and PCLXL
53            # parsing will greatly benefit from this,
54            # for PostScript and PDF the difference is
55            # barely noticeable since they are already
56            # almost optimal, and much more speedy anyway.
57            psyco.bind(PostScriptAnalyzer.getJobSize)
58            psyco.bind(PDFAnalyzer.getJobSize)
59            psyco.bind(ESCP2Analyzer.getJobSize)
60            psyco.bind(PCLAnalyzer.getJobSize)
61            psyco.bind(PCLXLAnalyzer.getJobSize)
62       
63    def getJobSize(self) :   
64        """Returns the job's size."""
65        self.openFile()
66        try :
67            pdlhandler = self.detectPDLHandler()
68        except PDLAnalyzerError, msg :   
69            self.closeFile()
70            raise PDLAnalyzerError, "ERROR : Unknown file format for %s (%s)" % (self.filename, msg)
71        else :
72            try :
73                size = pdlhandler(self.infile, self.debug).getJobSize()
74            finally :   
75                self.closeFile()
76            return size
77       
78    def openFile(self) :   
79        """Opens the job's data stream for reading."""
80        self.mustclose = 0  # by default we don't want to close the file when finished
81        if hasattr(self.filename, "read") and hasattr(self.filename, "seek") :
82            # filename is in fact a file-like object
83            infile = self.filename
84        elif self.filename == "-" :
85            # we must read from stdin
86            infile = sys.stdin
87        else :   
88            # normal file
89            self.infile = open(self.filename, "rb")
90            self.mustclose = 1
91            return
92           
93        # Use a temporary file, always seekable contrary to standard input.
94        self.infile = tempfile.TemporaryFile(mode="w+b")
95        while 1 :
96            data = infile.read(MEGABYTE) 
97            if not data :
98                break
99            self.infile.write(data)
100        self.infile.flush()   
101        self.infile.seek(0)
102           
103    def closeFile(self) :       
104        """Closes the job's data stream if we can close it."""
105        if self.mustclose :
106            self.infile.close()   
107        else :   
108            # if we don't have to close the file, then
109            # ensure the file pointer is reset to the
110            # start of the file in case the process wants
111            # to read the file again.
112            try :
113                self.infile.seek(0)
114            except :   
115                pass    # probably stdin, which is not seekable
116       
117    def isPostScript(self, sdata, edata) :   
118        """Returns 1 if data is PostScript, else 0."""
119        if sdata.startswith("%!") or \
120           sdata.startswith("\004%!") or \
121           sdata.startswith("\033%-12345X%!PS") or \
122           ((sdata[:128].find("\033%-12345X") != -1) and \
123             ((sdata.find("LANGUAGE=POSTSCRIPT") != -1) or \
124              (sdata.find("LANGUAGE = POSTSCRIPT") != -1) or \
125              (sdata.find("LANGUAGE = Postscript") != -1))) or \
126              (sdata.find("%!PS-Adobe") != -1) :
127            if self.debug : 
128                sys.stderr.write("%s is a PostScript file\n" % str(self.filename))
129            return 1
130        else :   
131            return 0
132       
133    def isPDF(self, sdata, edata) :   
134        """Returns 1 if data is PDF, else 0."""
135        if sdata.startswith("%PDF-") or \
136           sdata.startswith("\033%-12345X%PDF-") or \
137           ((sdata[:128].find("\033%-12345X") != -1) and (sdata.upper().find("LANGUAGE=PDF") != -1)) or \
138           (sdata.find("%PDF-") != -1) :
139            if self.debug : 
140                sys.stderr.write("%s is a PDF file\n" % str(self.filename))
141            return 1
142        else :   
143            return 0
144       
145    def isPCL(self, sdata, edata) :   
146        """Returns 1 if data is PCL, else 0."""
147        if sdata.startswith("\033E\033") or \
148           (sdata.startswith("\033*rbC") and (not edata[-3:] == "\f\033@")) or \
149           sdata.startswith("\033%8\033") or \
150           (sdata.find("\033%-12345X") != -1) :
151            if self.debug : 
152                sys.stderr.write("%s is a PCL3/4/5 file\n" % str(self.filename))
153            return 1
154        else :   
155            return 0
156       
157    def isPCLXL(self, sdata, edata) :   
158        """Returns 1 if data is PCLXL aka PCL6, else 0."""
159        if ((sdata[:128].find("\033%-12345X") != -1) and \
160             (sdata.find(" HP-PCL XL;") != -1) and \
161             ((sdata.find("LANGUAGE=PCLXL") != -1) or \
162              (sdata.find("LANGUAGE = PCLXL") != -1))) :
163            if self.debug : 
164                sys.stderr.write("%s is a PCLXL (aka PCL6) file\n" % str(self.filename))
165            return 1
166        else :   
167            return 0
168           
169    def isESCP2(self, sdata, edata) :       
170        """Returns 1 if data is ESC/P2, else 0."""
171        if sdata.startswith("\033@") or \
172           sdata.startswith("\033*") or \
173           sdata.startswith("\n\033@") or \
174           sdata.startswith("\0\0\0\033\1@EJL") : # ESC/P Raster ??? Seen on Stylus Photo 1284
175            if self.debug : 
176                sys.stderr.write("%s is an ESC/P2 file\n" % str(self.filename))
177            return 1
178        else :   
179            return 0
180   
181    def detectPDLHandler(self) :   
182        """Tries to autodetect the document format.
183       
184           Returns the correct PDL handler class or None if format is unknown
185        """   
186        # Try to detect file type by reading first block of datas   
187        self.infile.seek(0)
188        firstblock = self.infile.read(4 * KILOBYTE)
189        try :
190            self.infile.seek(-LASTBLOCKSIZE, 2)
191            lastblock = self.infile.read(LASTBLOCKSIZE)
192        except IOError :   
193            lastblock = ""
194           
195        self.infile.seek(0)
196        if self.isPostScript(firstblock, lastblock) :
197            return PostScriptAnalyzer
198        elif self.isPCLXL(firstblock, lastblock) :   
199            return PCLXLAnalyzer
200        elif self.isPDF(firstblock, lastblock) :   
201            return PDFAnalyzer
202        elif self.isPCL(firstblock, lastblock) :   
203            return PCLAnalyzer
204        elif self.isESCP2(firstblock, lastblock) :   
205            return ESCP2Analyzer
206        else :   
207            raise PDLAnalyzerError, "Analysis of first data block failed."
208           
209def main() :   
210    """Entry point for PDL Analyzer."""
211   
212    sys.stderr.write("Big changes are currently occuring in the developpment version, please use the stable version for now !\n")
213    sys.exit(-1)
214   
215    if (len(sys.argv) < 2) or ((not sys.stdin.isatty()) and ("-" not in sys.argv[1:])) :
216        sys.argv.append("-")
217       
218    if ("-h" in sys.argv[1:]) or ("--help" in sys.argv[1:]) :
219        print "usage : pkpgcounter file1 file2 ... fileN"
220    elif ("-v" in sys.argv[1:]) or ("--version" in sys.argv[1:]) :
221        print "%s" % version.__version__
222    else :
223        totalsize = 0   
224        debug = 0
225        minindex = 1
226        if sys.argv[1] == "--debug" :
227            minindex = 2
228            debug = 1
229        for arg in sys.argv[minindex:] :
230            try :
231                parser = PDLAnalyzer(arg, debug)
232                totalsize += parser.getJobSize()
233            except PDLAnalyzerError, msg :   
234                sys.stderr.write("ERROR: %s\n" % msg)
235                sys.stderr.flush()
236        print "%s" % totalsize
237   
238if __name__ == "__main__" :   
239    main()
Note: See TracBrowser for help on using the browser.