root / pkpgcounter / trunk / pkpgpdls / spl1.py @ 3578

Revision 3578, 4.7 kB (checked in by jerome, 5 years ago)

Clarified dependency wrt PIL/Pillow.
Updated copyright years.
Regenerated manual page.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
RevLine 
[3410]1# -*- coding: utf-8 -*-
[408]2#
3# pkpgcounter : a generic Page Description Language parser
4#
[3578]5# (c) 2003-2019 Jerome Alet <alet@librelogiciel.com>
[463]6# This program is free software: you can redistribute it and/or modify
[408]7# it under the terms of the GNU General Public License as published by
[463]8# the Free Software Foundation, either version 3 of the License, or
[408]9# (at your option) any later version.
[3436]10#
[408]11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
[3436]15#
[408]16# You should have received a copy of the GNU General Public License
[463]17# along with this program.  If not, see <http://www.gnu.org/licenses/>.
[408]18#
19# $Id$
20#
21
22"""This modules implements a page counter for SPL1 documents."""
23
24import os
25import mmap
[533]26import struct
[408]27
28import pdlparser
[410]29import version
[408]30
31ESCAPECHARS = (chr(0x1b), chr(0x24))
32
33class Parser(pdlparser.PDLParser) :
34    """A parser for SPL1 documents."""
[555]35    format = "SPL1 (aka GDI)"
[3436]36    def isValid(self) :
[487]37        """Returns True if data is SPL1, else False."""
[522]38        if ((self.firstblock[:128].find("\033%-12345X") != -1) and \
39            (self.firstblock.find("$PJL ") != -1) and \
40             ((self.firstblock.find("LANGUAGE=SMART") != -1) or \
41              (self.firstblock.find("LANGUAGE = SMART") != -1))) :
[408]42            return True
[3436]43        else :
[408]44            return False
[3436]45
[408]46    def littleEndian(self) :
47        """Toggles to little endianness."""
48        self.unpackType = { 1 : "B", 2 : "<H", 4 : "<I" }
49        self.unpackShort = self.unpackType[2]
50        self.unpackLong = self.unpackType[4]
[533]51        # self.logdebug("Little Endian")
[408]52        return 0
[3436]53
[408]54    def bigEndian(self) :
55        """Toggles to big endianness."""
56        self.unpackType = { 1 : "B", 2 : ">H", 4 : ">I" }
57        self.unpackShort = self.unpackType[2]
58        self.unpackLong = self.unpackType[4]
[533]59        # self.logdebug("Big Endian")
[408]60        return 0
[3436]61
62    def escape(self, nextpos) :
[408]63        """Handles the ESC code."""
[409]64        self.isbitmap = False
[408]65        pos = endpos = nextpos
66        minfile = self.minfile
67        if minfile[pos : pos+8] == r"%-12345X" :
68            endpos = pos + 9
[3436]69        elif minfile[pos-1] in ESCAPECHARS :
[408]70            endpos = pos
[3436]71        else :
[408]72            return 0
73        endmark = (chr(0x1b), chr(0x00))
74        asciilimit = chr(0x80)
75        quotes = 0
76        while (minfile[endpos] not in endmark) and \
77               ((minfile[endpos] < asciilimit) or (quotes % 2)) :
78            if minfile[endpos] == '"' :
79                quotes += 1
80            endpos += 1
[3436]81
82        # Store this in a per page mapping.
[408]83        # NB : First time will be at page 0 (i.e. **before** page 1) !
84        stuff = self.escapedStuff.setdefault(self.pagecount, [])
[409]85        datas = minfile[pos-1 : endpos]
86        stuff.append(datas)
87        if datas.endswith("$PJL BITMAP START\r\n") :
88            self.isbitmap = True
[533]89            # self.logdebug("New bitmap")
[409]90        self.logdebug("Escaped datas : [%s]" % repr(datas))
[408]91        return endpos - pos + 1
[3436]92
[408]93    def getJobSize(self) :
94        """Counts pages in an SPL1 document.
[3436]95
[408]96           Algorithm by Jerome Alet.
97        """
98        infileno = self.infile.fileno()
[409]99        self.minfile = minfile = mmap.mmap(infileno, os.fstat(infileno)[6], prot=mmap.PROT_READ, flags=mmap.MAP_SHARED)
[408]100        self.pagecount = 0
101        self.escapedStuff = {}   # For escaped datas, mostly PJL commands
102        self.bigEndian()
[409]103        self.isbitmap = False
[408]104        pos = 0
[533]105        unpack = struct.unpack
[408]106        try :
107            try :
108                while 1 :
[409]109                    tag = minfile[pos]
[408]110                    if tag in ESCAPECHARS :
111                        pos += self.escape(pos+1)
[3436]112                    else :
[409]113                        if not self.isbitmap :
[410]114                            raise pdlparser.PDLParserError, "Unfortunately SPL1 is incompletely recognized. Parsing aborted. Please report the problem to %s" % version.__authoremail__
[533]115                        (offset,
116                         seqnum) = unpack(">IH", minfile[pos:pos+6])
117                        # self.logdebug("Offset : %i      Sequence Number : %i" % (offset, seqnum))
[3436]118                        if not seqnum :
[533]119                            # Sequence number resets to 0 for each new page.
[409]120                            self.pagecount += 1
[408]121                        pos += 4 + offset
[3436]122            except struct.error, msg :
[533]123                raise pdlparser.PDLParserError, "Unfortunately SPL1 is incompletely recognized (%s). Parsing aborted. Please report the problem to %s" % (msg, version.__authoremail__)
[3436]124            except IndexError : # EOF ?
[408]125                pass
126        finally :
[409]127            minfile.close()
[408]128        return self.pagecount
Note: See TracBrowser for help on using the browser.