#!/usr/bin/env python3

# compressor.py
from subprocess import Popen, PIPE

def compress(value):
    """Compresses a byte array with the xz binary"""

    process = Popen(["xz", "--compress", "--force"], stdin=PIPE, stdout=PIPE)
    return process.communicate(value)[0]

def decompress(value):
    """Decompresses a byte array with the xz binary"""

    process = Popen(["xz", "--decompress", "--stdout", "--force"],
                    stdin=PIPE, stdout=PIPE)
    return process.communicate(value)[0]

def compress_file(path):
    """Compress the file at 'path' with the xz binary"""

    process = Popen(["xz", "--compress", "--force", "--stdout", path], stdout=PIPE)
    return process.communicate()[0]

# compressor.py

import os
import sys
from optparse import OptionParser
from sys import argv
import base64
import json
from io import BytesIO

from os.path import basename
from errno import EPIPE
import lzma

def load():
    ppds_compressed = base64.b64decode(ppds_compressed_b64)
    ppds_decompressed = decompress(ppds_compressed)
    ppds = json.loads(ppds_decompressed.decode(encoding='ASCII'))
    return ppds

def ls():
    binary_name = basename(argv[0])
    ppds = load()
    for key, value in ppds.items():
        if key == 'ARCHIVE': continue
        for ppd in value[2]:
            try:
                print(ppd.replace('"', '"' + binary_name + ':', 1))
            except IOError as e:
                # Errors like broken pipes (program which takes the standard
                # output terminates before this program terminates) should not
                # generate a traceback.
                if e.errno == EPIPE: exit(0)
                raise

def cat(ppd):
    # Ignore driver's name, take only PPD's
    ppd = ppd.split(":")[-1]
    # Remove also the index
    ppd = "0/" + ppd[ppd.find("/")+1:]

    # Object for streaming decompression
    decompressor = lzma.LZMADecompressor()
    # size for one decompression i.e. ~20MB
    size = 20000000

    ppds = load()
    ppds['ARCHIVE'] = base64.b64decode(ppds['ARCHIVE'].encode('ASCII'))
    ppdtext=bytearray()

    if ppd in ppds:
        start = ppds[ppd][0]
        length = ppds[ppd][1]

        text = BytesIO(decompressor.decompress(ppds['ARCHIVE'],size))
        for i in range(int(start/size)):
            text = BytesIO(decompressor.decompress(ppds['ARCHIVE'],size))
        text.seek(start%size)

        if((size-(start%size)) < length):
            ppdtext.extend(text.read())
            length = length - (size-(start%size))
            text = BytesIO(decompressor.decompress(ppds['ARCHIVE'],size))
            while(size < length):
                ppdtext.extend(text.read())
                length = length - size
                text = BytesIO(decompressor.decompress(ppds['ARCHIVE'],size))
            ppdtext.extend(text.read(length))
        else:
            ppdtext.extend(text.read(length))
        
        return ppdtext

def main():
    usage = "usage: %prog list\n" \
            "       %prog cat URI"
    version = "%prog 1.1.0\n" \
              "Copyright (c) 2013 Vitor Baptista.\n" \
              "This is free software; see the source for copying conditions.\n" \
              "There is NO warranty; not even for MERCHANTABILITY or\n" \
              "FITNESS FOR A PARTICULAR PURPOSE."
    parser = OptionParser(usage=usage,
                          version=version)
    (options, args) = parser.parse_args()

    if len(args) == 0 or len(args) > 2:
        parser.error("incorrect number of arguments")

    if args[0].lower() == 'list':
        ls()
    elif args[0].lower() == 'cat':
        if not len(args) == 2:
            parser.error("incorrect number of arguments")
        ppd = cat(args[1])
        if not ppd:
            parser.error("Printer '%s' does not have default driver!" % args[1])
        try:
            # avoid any assumption of encoding or system locale; just print the
            # bytes of the PPD as they are
            if sys.version_info.major < 3:
                sys.stdout.write(ppd)
            else:
                sys.stdout.buffer.write(ppd)
        except IOError as e:
            # Errors like broken pipes (program which takes the standard output
            # terminates before this program terminates) should not generate a
            # traceback.
            if e.errno == EPIPE: exit(0)
            raise
    else:
        parser.error("argument " + args[0] + " invalid")

# PPDs Archive
ppds_compressed_b64 = b"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"

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        # We don't want a KeyboardInterrupt throwing a
        # traceback into stdout.
        pass
