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

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:]

    ppds = load()
    # Encode to binary, decode base64, decompress and convert to bytes again
    ppds['ARCHIVE'] = BytesIO(decompress(base64.b64decode(ppds['ARCHIVE'].encode('ASCII'))))

    if ppd in ppds:
        start = ppds[ppd][0]
        length = ppds[ppd][1]
        ppds['ARCHIVE'].seek(start)
        return ppds['ARCHIVE'].read(length)

def main():
    usage = "usage: %prog list\n" \
            "       %prog cat URI"
    version = "%prog 1.0.2\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
