#!/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
