#!/usr/bin/env python
"""
Module to register RISC OS alphabets as encodings with the Python codec system.

The encodings registered here are the alphabets used by RISC OS, based on the standard Python
codecs. The encodings are registered as codecs in the following format:

    riscos-alphabet-<alphabet number>
    riscos-<lower case alphabet name as given by UK territory>

This should allow the encodings to be located programatically whichever of those values are
used. The 'riscos-alphabet-111' and 'riscos-utf8' encodings are registered for orthoginality,
and map directly to the 'utf-8' encoding.

The encodings supplied here include characters in the C1 region (0x80-0x9F) to match the
representations within RISC OS. Two characters, 0x84 and 0x87 are not representable.

The 0x84 character is the 'resize' character, which does exist as a character in unicode,
but encodes into surrogates within Python. Because this breaks the single-character mapping
implementation used here, it has been mapped to the replacement character.

The 0x87 character is represented as '87' in the character set and otherwise unmapped
in RISC OS, so has been mapped to the replacement character.

Some character sets, in their specification define that code points must not be used, which
means that they are not defined within the Python codecs. As characters do exist at those
code points within RISC OS, they should be provided with a mapping, but at present are left
with replacement the character.

There are additional codecs provided for the encoding of the three symbol fonts:

    riscos-selwyn
    riscos-sidney
    riscos-wimpsymbol

Importing this module will immediately register the new codecs.

This module is intentionally Python 2/3 compatible as Python 2 code will remain for some
time.
"""

import codecs
import sys


class RISCOSAlphabet(object):
    base_array = bytes(bytearray(range(256)))

    def __init__(self, alphabet, name, base_encoding, changes=None):
        """
        Create an 8bit encoding, based on a known encoding, with some code point changes.

        @param alphabet:        RISC OS Alphabet number
        @param name:            Encoding name to use within Python codecs
        @param base_encoding:   Encoding name to use as the basis for the encoding
        @param changes:         Changes made to the encoding, as a list of dictionaries of
                                code-point -> unicode character pairs.
        """
        self.alphabet = alphabet
        self.name = name
        self.base_encoding = base_encoding
        if base_encoding:
            self.decode_table = list(self.base_array.decode(base_encoding, 'replace'))
        else:
            # No base encoding, so we just populate with the replacement character
            self.decode_table = [u'\ufffd'] * 256
        changes = changes or [{}]
        # Apply the changes from the array
        for change in changes:
            for codepoint, value in change.items():
                self.decode_table[codepoint] = value
        self.encode_table = {char: (index) for index, char in enumerate(self.decode_table)}
        self.codec = codecs.CodecInfo(self.encode, self.decode, name=name)
        self.decode_readers = {
                'strict': self._decode_strict,
                'ignore': self._decode_ignore,
                'replace': self._decode_replace,
            }
        self.encode_readers = {
                'strict': self._encode_strict,
                'ignore': self._encode_ignore,
                'replace': self._encode_replace,
            }

    def __repr__(self):
        return "<{}(alphabet={}, name={})>".format(self.__class__.__name__,
                                                   self.alphabet,
                                                   self.name)

    def encode(self, text, errors='replace'):
        encoder = self.encode_readers[errors]
        return (bytes(bytearray(encoder(char) for char in text)), len(text))

    def _encode_strict(self, c):
        nc = self.encode_table.get(c, None)
        if nc is None:
            raise UnicodeEncodeError("Cannot encode character {!r} with encoding '{}'".format(c, self.name))
        return nc

    def _encode_ignore(self, c):
        return self.encode_table.get(c, '')

    def _encode_replace(self, c):
        return self.encode_table.get(c, '?')

    # 'bytes' works differently between python 2 and python 3.
    # In python 2, it's a str, so enumerating it returns individual characters as strings.
    # In python 3, it's a bytes, and enumerating it returns the ordinal value.
    if sys.version_info.major == 2:
        def decode(self, binary, errors='strict'):
            decoder = self.decode_readers[errors]
            return (''.join(decoder(ord(x)) for x in binary), len(binary))
    else:
        def decode(self, binary, errors='strict'):
            decoder = self.decode_readers[errors]
            return (''.join(decoder(x) for x in binary), len(binary))

    def _decode_strict(self, c):
        nc = self.decode_table[c]
        if nc is u'\ufffd':
            raise UnicodeDecodeError("Cannot decode character {!r} from encoding '{}'".format(c, self.name))
        return nc

    def _decode_ignore(self, c):
        nc = self.decode_table[c]
        if nc is u'\ufffd':
            return ''
        return nc

    def _decode_replace(self, c):
        return self.decode_table[c]


class RISCOSUTF8(RISCOSAlphabet):

    def __init__(self, alphabet, name):
        """
        A representation of the UTF-8 on RISC OS, purely so that we map to standard UTF-8 codec.
        """
        self.alphabet = alphabet
        self.name = name
        self.base_encoding = 'utf-8'
        self.codec = codecs.lookup(self.base_encoding)


c1_changes = {
        0x80: u'\u20AC', # euro
        0x81: u'\u0174', # W circumflex
        0x82: u'\u0175', # w circumflex
        0x83: u'\u25F0', # resize icon
        0x84: u'\uFFFD', # close icon: should be u'\U0001FBC0', but that gets encoded into surrogates, which breaks the map
        0x85: u'\u0176', # Y circumflex
        0x86: u'\u0177', # y circumflex
        0x87: u'\uFFFD', # 0x87 cannot be represented in unicode
        0x88: u'\u21E6', # left
        0x89: u'\u21E8', # right
        0x8a: u'\u21E9', # down
        0x8b: u'\u21E7', # up
        0x8c: u'\u2026', # ellipsis
        0x8d: u'\u2122', # TM
        0x8e: u'\u2030', # permille
        0x8f: u'\u2022', # bullet
        0x90: u'\u2018', # left quote
        0x91: u'\u2019', # right quote
        0x92: u'\u2039', # left single guillemet
        0x93: u'\u203A', # right single guillemet
        0x94: u'\u201C', # left double quote
        0x95: u'\u201D', # right double quote
        0x96: u'\u201E', # right double quote as base line
        0x97: u'\u2013', # en dash
        0x98: u'\u2014', # em dash
        0x99: u'\u2212', # minus
        0x9a: u'\u0152', # OE ligature
        0x9b: u'\u0153', # oe ligature
        0x9c: u'\u2020', # dagger
        0x9d: u'\u2021', # double dagger
        0x9e: u'\uFB01', # fi ligature
        0x9f: u'\uFB02', # fl ligature
    }
welsh_changes = {
        0xa8: u'\u1e80', # W grave
        0xaa: u'\u1e82', # W acute
        0xac: u'\u1ef2', # Y grave
        0xaf: u'\u0178', # Y umlaut
        0xb8: u'\u1e81', # w grave
        0xba: u'\u1e83', # w acute
        0xbc: u'\u1ef3', # y grave
        0xbd: u'\u1e84', # W umlaut
        0xbe: u'\u1e85', # w umlaut
        0xd0: u'\u0174', # W circumflex
        0xde: u'\u0176', # Y circumflex
        0xf1: u'\u0175', # w circumflex
        0xfe: u'\u0177', # y circumflex
    }

# Python does not map some characters in its iso-8859-3 mapping.
# Consult https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-094.pdf for the correct mapping.
iso8859_3_changes = {
        0xa5: u'\u00a5', # Yen
        0xae: u'\u00ae', # Registered trade mark
        0xbe: u'\u00be', # 3/4
        0xc3: u'\u00c3', # Latin Capital Letter A with Tilde
        0xd0: u'\u00d0', # Latin Capital Letter Eth
        0xe3: u'\u00e3', # Latin Small Letter A with Tilde
        0xf0: u'\u00f0', # Latin Small Letter Eth
    }

# Note: Many characters are unmapped in ISO 8859-6.
# Consult https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-114.pdf for details.
iso8859_6_changes = {
        # FIXME: This should be filled with the characters as used by RISC OS.
        0xa1: u'\ufffd', # ?
        0xa2: u'\ufffd', # ?
        0xa3: u'\ufffd', # ?
        0xa5: u'\ufffd', # ?
        0xa6: u'\ufffd', # ?
        0xa7: u'\ufffd', # ?
        0xa8: u'\ufffd', # ?
        0xa9: u'\ufffd', # ?
        0xaa: u'\ufffd', # ?
        0xab: u'\ufffd', # ?
        0xae: u'\ufffd', # ?
        0xaf: u'\ufffd', # ?
        0xb0: u'\ufffd', # ?
        0xb1: u'\ufffd', # ?
        0xb2: u'\ufffd', # ?
        0xb3: u'\ufffd', # ?
        0xb4: u'\ufffd', # ?
        0xb5: u'\ufffd', # ?
        0xb6: u'\ufffd', # ?
        0xb7: u'\ufffd', # ?
        0xb8: u'\ufffd', # ?
        0xb9: u'\ufffd', # ?
        0xba: u'\ufffd', # ?
        0xbc: u'\ufffd', # ?
        0xbd: u'\ufffd', # ?
        0xbe: u'\ufffd', # ?
        0xc0: u'\ufffd', # ?
        0xdb: u'\ufffd', # ?
        0xdc: u'\ufffd', # ?
        0xdd: u'\ufffd', # ?
        0xde: u'\ufffd', # ?
        0xdf: u'\ufffd', # ?
        0xf3: u'\ufffd', # ?
        0xf4: u'\ufffd', # ?
        0xf5: u'\ufffd', # ?
        0xf6: u'\ufffd', # ?
        0xf7: u'\ufffd', # ?
        0xf8: u'\ufffd', # ?
        0xf9: u'\ufffd', # ?
        0xfa: u'\ufffd', # ?
        0xfb: u'\ufffd', # ?
        0xfc: u'\ufffd', # ?
        0xfd: u'\ufffd', # ?
        0xfe: u'\ufffd', # ?
        0xff: u'\ufffd', # ?
    }

# Note: 3 characters are unmapped in ISO 8859-7.
# Consult https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-118.pdf for details.
iso8859_7_changes = {
        # FIXME: This should be filled with the characters as used by RISC OS.
        0xaa: u'\ufffd', # ?
        0xae: u'\ufffd', # ?
        0xd2: u'\ufffd', # ?
        0xff: u'\ufffd', # ?
    }

# Note: Many characters are unmapped in ISO 8859-8.
# Consult https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-121.pdf for details.
iso8859_8_changes = {
        # FIXME: This should be filled with the characters as used by RISC OS.
        0xa1: u'\ufffd', # ?
        0xbf: u'\ufffd', # ?
        0xc0: u'\ufffd', # ?
        0xc1: u'\ufffd', # ?
        0xc2: u'\ufffd', # ?
        0xc3: u'\ufffd', # ?
        0xc4: u'\ufffd', # ?
        0xc5: u'\ufffd', # ?
        0xc6: u'\ufffd', # ?
        0xc7: u'\ufffd', # ?
        0xc8: u'\ufffd', # ?
        0xc9: u'\ufffd', # ?
        0xca: u'\ufffd', # ?
        0xcb: u'\ufffd', # ?
        0xcc: u'\ufffd', # ?
        0xcd: u'\ufffd', # ?
        0xce: u'\ufffd', # ?
        0xcf: u'\ufffd', # ?
        0xd0: u'\ufffd', # ?
        0xd1: u'\ufffd', # ?
        0xd2: u'\ufffd', # ?
        0xd3: u'\ufffd', # ?
        0xd4: u'\ufffd', # ?
        0xd5: u'\ufffd', # ?
        0xd6: u'\ufffd', # ?
        0xd7: u'\ufffd', # ?
        0xd8: u'\ufffd', # ?
        0xd9: u'\ufffd', # ?
        0xda: u'\ufffd', # ?
        0xdb: u'\ufffd', # ?
        0xdc: u'\ufffd', # ?
        0xdd: u'\ufffd', # ?
        0xde: u'\ufffd', # ?
        0xfb: u'\ufffd', # ?
        0xfc: u'\ufffd', # ?
        0xff: u'\ufffd', # ?
    }


# Encoding for the WIMPSymbol font
wimpsymbol_changes = {
        0x80: u'\u2714',  # HEAVY CHECK MARK
        0x84: u'\u2718',  # HEAVY BALLOT X
        0x88: u'\u21d0',  # LEFTWARDS DOUBLE ARROW
        0x89: u'\u21d2',  # RIGHTWARDS DOUBLE ARROW
        0x8a: u'\u21d3',  # DOWNWARDS DOUBLE ARROW
        0x8b: u'\u21d1',  # UPWARDS DOUBLE ARROW
    }


# Encoding for the Selwyn font
selwyn_changes = {
        0x20: u'\u0020',  # SPACE
        0x21: u'\u2701',  # UPPER BLADE SCISSORS
        0x22: u'\u2702',  # BLACK SCISSORS
        0x23: u'\u2703',  # LOWER BLADE SCISSORS
        0x24: u'\u2704',  # WHITE SCISSORS
        0x25: u'\u2741',  # EIGHT PETALLED OUTLINED BLACK FLORETTE
        0x26: u'\u2706',  # TELEPHONE LOCATION SIGN
        0x27: u'\u2707',  # TAPE DRIVE
        0x28: u'\u2708',  # AIRPLANE
        0x29: u'\u2709',  # ENVELOPE
        0x2a: u'\u261b',  # BLACK RIGHT POINTING INDEX
        0x2b: u'\u261e',  # WHITE RIGHT POINTING INDEX
        0x2c: u'\u270c',  # VICTORY HAND
        0x2d: u'\u270d',  # WRITING HAND
        0x2e: u'\u270e',  # LOWER RIGHT PENCIL
        0x2f: u'\u270f',  # PENCIL
        0x30: u'\u2710',  # UPPER RIGHT PENCIL
        0x31: u'\u2711',  # WHITE NIB
        0x32: u'\u2712',  # BLACK NIB
        0x33: u'\u2713',  # CHECK MARK
        0x34: u'\u2742',  # CIRCLED OPEN CENTRE EIGHT POINTED STAR
        0x35: u'\u2715',  # MULTIPLICATION X
        0x36: u'\u2716',  # HEAVY MULTIPLICATION X
        0x37: u'\u2717',  # BALLOT X
        0x38: u'\u2743',  # HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK
        0x39: u'\u2719',  # OUTLINED GREEK CROSS
        0x3a: u'\u271a',  # HEAVY GREEK CROSS
        0x3b: u'\u271b',  # OPEN CENTRE CROSS
        0x3c: u'\u271c',  # HEAVY OPEN CENTRE CROSS
        0x3d: u'\u271d',  # LATIN CROSS
        0x3e: u'\u271e',  # SHADOWED WHITE LATIN CROSS
        0x3f: u'\u271f',  # OUTLINED LATIN CROSS
        0x40: u'\u2720',  # MALTESE CROSS
        0x41: u'\u2721',  # STAR OF DAVID
        0x42: u'\u2722',  # FOUR TEARDROP-SPOKED ASTERISK
        0x43: u'\u2723',  # FOUR BALLOON-SPOKED ASTERISK
        0x44: u'\u2724',  # HEAVY FOUR BALLOON-SPOKED ASTERISK
        0x45: u'\u2725',  # FOUR CLUB-SPOKED ASTERISK
        0x46: u'\u2726',  # BLACK FOUR POINTED STAR
        0x47: u'\u2727',  # WHITE FOUR POINTED STAR
        0x48: u'\u2745',  # TIGHT TRIFOLIATE SNOWFLAKE
        0x49: u'\u2729',  # STRESS OUTLINED WHITE STAR
        0x4a: u'\u272a',  # CIRCLED WHITE STAR
        0x4b: u'\u272b',  # OPEN CENTRE BLACK STAR
        0x4c: u'\u272c',  # BLACK CENTRE WHITE STAR
        0x4d: u'\u272d',  # OUTLINED BLACK STAR
        0x4e: u'\u272e',  # HEAVY OUTLINED BLACK STAR
        0x4f: u'\u272f',  # PINWHEEL STAR
        0x50: u'\u2730',  # SHADOWED WHITE STAR
        0x51: u'\u2731',  # HEAVY ASTERISK
        0x52: u'\u2732',  # OPEN CENTRE ASTERISK
        0x53: u'\u2733',  # EIGHT SPOKED ASTERISK
        0x54: u'\u2734',  # EIGHT POINTED BLACK STAR
        0x55: u'\u2735',  # EIGHT POINTED PINWHEEL STAR
        0x56: u'\u2736',  # SIX POINTED BLACK STAR
        0x57: u'\u2737',  # EIGHT POINTED RECTILINEAR BLACK STAR
        0x58: u'\u2738',  # HEAVY EIGHT POINTED RECTILINEAR BLACK STAR
        0x59: u'\u2739',  # TWELVE POINTED BLACK STAR
        0x5a: u'\u273a',  # SIXTEEN POINTED ASTERISK
        0x5b: u'\u273b',  # TEARDROP-SPOKED ASTERISK
        0x5c: u'\u273c',  # OPEN CENTRE TEARDROP-SPOKED ASTERISK
        0x5d: u'\u2746',  # HEAVY CHEVRON SNOWFLAKE
        0x5e: u'\u273e',  # SIX PETALLED BLACK AND WHITE FLORETTE
        0x5f: u'\u273f',  # BLACK FLORETTE
        0x60: u'\u2740',  # WHITE FLORETTE
        0x61: u'\u260e',  # BLACK TELEPHONE
        0x62: u'\u2714',  # HEAVY CHECK MARK
        0x63: u'\u2718',  # HEAVY BALLOT X
        0x64: u'\u2744',  # SNOWFLAKE
        0x65: u'\u2605',  # BLACK STAR
        0x66: u'\u273d',  # HEAVY TEARDROP-SPOKED ASTERISK
        0x67: u'\u2750',  # UPPER RIGHT DROP-SHADOWED WHITE SQUARE
        0x68: u'\u2751',  # LOWER RIGHT SHADOWED WHITE SQUARE
        0x69: u'\u2752',  # UPPER RIGHT SHADOWED WHITE SQUARE
        0x6a: u'\u25c6',  # BLACK DIAMOND
        0x6b: u'\u27a7',  # SQUAT BLACK RIGHTWARDS ARROW
        0x6c: u'\u25cf',  # BLACK CIRCLE
        0x6d: u'\u274d',  # SHADOWED WHITE CIRCLE
        0x6e: u'\u25a0',  # BLACK SQUARE
        0x6f: u'\u274f',  # LOWER RIGHT DROP-SHADOWED WHITE SQUARE
        0x70: u'\u2747',  # SPARKLE
        0x71: u'\u2748',  # HEAVY SPARKLE
        0x72: u'\u2749',  # BALLOON-SPOKED ASTERISK
        0x73: u'\u25b2',  # BLACK UP-POINTING TRIANGLE
        0x74: u'\u25bc',  # BLACK DOWN-POINTING TRIANGLE
        0x75: u'\u274a',  # EIGHT TEARDROP-SPOKED PROPELLER ASTERISK
        0x76: u'\u2756',  # BLACK DIAMOND MINUS WHITE X
        0x77: u'\u25d7',  # RIGHT HALF BLACK CIRCLE
        0x78: u'\u2758',  # LIGHT VERTICAL BAR
        0x79: u'\u2759',  # MEDIUM VERTICAL BAR
        0x7a: u'\u275a',  # HEAVY VERTICAL BAR
        0x7b: u'\u275b',  # HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT
        0x7c: u'\u275c',  # HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT
        0x7d: u'\u275d',  # HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT
        0x7e: u'\u275e',  # HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT
        0x92: u'\u276c',  # MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT
        0x93: u'\u2771',  # HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT
        0x94: u'\u2770',  # HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT
        0x95: u'\u276a',  # MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT
        0x96: u'\u2768',  # MEDIUM LEFT PARENTHESIS ORNAMENT
        0x97: u'\u2773',  # LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT
        0x98: u'\u276e',  # HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT
        0x99: u'\u276f',  # HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT
        0x9a: u'\u2772',  # LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT
        0x9b: u'\u276d',  # MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT
        0x9c: u'\u2769',  # MEDIUM RIGHT PARENTHESIS ORNAMENT
        0x9d: u'\u276b',  # MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT
        0x9e: u'\u2774',  # MEDIUM LEFT CURLY BRACKET ORNAMENT
        0x9f: u'\u2775',  # MEDIUM RIGHT CURLY BRACKET ORNAMENT
        0xa1: u'\u2761',  # CURVED STEM PARAGRAPH SIGN ORNAMENT
        0xa2: u'\u2762',  # HEAVY EXCLAMATION MARK ORNAMENT
        0xa3: u'\u2763',  # HEAVY HEART EXCLAMATION MARK ORNAMENT
        0xa4: u'\u2764',  # HEAVY BLACK HEART
        0xa5: u'\u2765',  # ROTATED HEAVY BLACK HEART BULLET
        0xa6: u'\u2766',  # FLORAL HEART
        0xa7: u'\u2767',  # ROTATED FLORAL HEART BULLET
        0xa8: u'\u2663',  # BLACK CLUB SUIT
        0xa9: u'\u2666',  # BLACK DIAMOND SUIT
        0xaa: u'\u2665',  # BLACK HEART SUIT
        0xab: u'\u2660',  # BLACK SPADE SUIT
        0xac: u'\u2460',  # CIRCLED DIGIT ONE
        0xad: u'\u2461',  # CIRCLED DIGIT TWO
        0xae: u'\u2462',  # CIRCLED DIGIT THREE
        0xaf: u'\u2463',  # CIRCLED DIGIT FOUR
        0xb0: u'\u2464',  # CIRCLED DIGIT FIVE
        0xb1: u'\u2465',  # CIRCLED DIGIT SIX
        0xb2: u'\u2466',  # CIRCLED DIGIT SEVEN
        0xb3: u'\u2467',  # CIRCLED DIGIT EIGHT
        0xb4: u'\u2468',  # CIRCLED DIGIT NINE
        0xb5: u'\u2469',  # CIRCLED NUMBER TEN
        0xb6: u'\u2776',  # DINGBAT NEGATIVE CIRCLED DIGIT ONE
        0xb7: u'\u2777',  # DINGBAT NEGATIVE CIRCLED DIGIT TWO
        0xb8: u'\u2778',  # DINGBAT NEGATIVE CIRCLED DIGIT THREE
        0xb9: u'\u2779',  # DINGBAT NEGATIVE CIRCLED DIGIT FOUR
        0xba: u'\u277a',  # DINGBAT NEGATIVE CIRCLED DIGIT FIVE
        0xbb: u'\u277b',  # DINGBAT NEGATIVE CIRCLED DIGIT SIX
        0xbc: u'\u277c',  # DINGBAT NEGATIVE CIRCLED DIGIT SEVEN
        0xbd: u'\u277d',  # DINGBAT NEGATIVE CIRCLED DIGIT EIGHT
        0xbe: u'\u277e',  # DINGBAT NEGATIVE CIRCLED DIGIT NINE
        0xbf: u'\u277f',  # DINGBAT NEGATIVE CIRCLED NUMBER TEN
        0xc0: u'\u2780',  # DINGBAT CIRCLED SANS-SERIF DIGIT ONE
        0xc1: u'\u2781',  # DINGBAT CIRCLED SANS-SERIF DIGIT TWO
        0xc2: u'\u2782',  # DINGBAT CIRCLED SANS-SERIF DIGIT THREE
        0xc3: u'\u2783',  # DINGBAT CIRCLED SANS-SERIF DIGIT FOUR
        0xc4: u'\u2784',  # DINGBAT CIRCLED SANS-SERIF DIGIT FIVE
        0xc5: u'\u2785',  # DINGBAT CIRCLED SANS-SERIF DIGIT SIX
        0xc6: u'\u2786',  # DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN
        0xc7: u'\u2787',  # DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT
        0xc8: u'\u2788',  # DINGBAT CIRCLED SANS-SERIF DIGIT NINE
        0xc9: u'\u2789',  # DINGBAT CIRCLED SANS-SERIF NUMBER TEN
        0xca: u'\u278a',  # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE
        0xcb: u'\u278b',  # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO
        0xcc: u'\u278c',  # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE
        0xcd: u'\u278d',  # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR
        0xce: u'\u278e',  # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE
        0xcf: u'\u278f',  # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX
        0xd0: u'\u2790',  # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN
        0xd1: u'\u2791',  # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT
        0xd2: u'\u2792',  # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE
        0xd3: u'\u2793',  # DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN
        0xd4: u'\u2794',  # HEAVY WIDE-HEADED RIGHTWARDS ARROW
        0xd5: u'\u2192',  # RIGHTWARDS ARROW
        0xd6: u'\u2194',  # LEFT RIGHT ARROW
        0xd7: u'\u2195',  # UP DOWN ARROW
        0xd8: u'\u2798',  # HEAVY SOUTH EAST ARROW
        0xd9: u'\u2799',  # HEAVY RIGHTWARDS ARROW
        0xda: u'\u279a',  # HEAVY NORTH EAST ARROW
        0xdb: u'\u279b',  # DRAFTING POINT RIGHTWARDS ARROW
        0xdc: u'\u279c',  # HEAVY ROUND-TIPPED RIGHTWARDS ARROW
        0xdd: u'\u279d',  # TRIANGLE-HEADED RIGHTWARDS ARROW
        0xde: u'\u279e',  # HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW
        0xdf: u'\u279f',  # DASHED TRIANGLE-HEADED RIGHTWARDS ARROW
        0xe0: u'\u27a0',  # HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW
        0xe1: u'\u27a1',  # BLACK RIGHTWARDS ARROW
        0xe2: u'\u27a2',  # THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD
        0xe3: u'\u27a3',  # THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD
        0xe4: u'\u27a4',  # BLACK RIGHTWARDS ARROWHEAD
        0xe5: u'\u27a5',  # HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW
        0xe6: u'\u27a6',  # HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW
        0xe7: u'\u274b',  # HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK
        0xe8: u'\u27a8',  # HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW
        0xe9: u'\u27a9',  # RIGHT-SHADED WHITE RIGHTWARDS ARROW
        0xea: u'\u27aa',  # LEFT-SHADED WHITE RIGHTWARDS ARROW
        0xeb: u'\u27ab',  # BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW
        0xec: u'\u27ac',  # FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW
        0xed: u'\u27ad',  # HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW
        0xee: u'\u27ae',  # HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW
        0xef: u'\u27af',  # NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW
        0xf1: u'\u27b1',  # NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW
        0xf2: u'\u27b2',  # CIRCLED HEAVY WHITE RIGHTWARDS ARROW
        0xf3: u'\u27b3',  # WHITE-FEATHERED RIGHTWARDS ARROW
        0xf4: u'\u27b4',  # BLACK-FEATHERED SOUTH EAST ARROW
        0xf5: u'\u27b5',  # BLACK-FEATHERED RIGHTWARDS ARROW
        0xf6: u'\u27b6',  # BLACK-FEATHERED NORTH EAST ARROW
        0xf7: u'\u27b7',  # HEAVY BLACK-FEATHERED SOUTH EAST ARROW
        0xf8: u'\u27b8',  # HEAVY BLACK-FEATHERED RIGHTWARDS ARROW
        0xf9: u'\u27b9',  # HEAVY BLACK-FEATHERED NORTH EAST ARROW
        0xfa: u'\u27ba',  # TEARDROP-BARBED RIGHTWARDS ARROW
        0xfb: u'\u27bb',  # HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW
        0xfc: u'\u27bc',  # WEDGE-TAILED RIGHTWARDS ARROW
        0xfd: u'\u27bd',  # HEAVY WEDGE-TAILED RIGHTWARDS ARROW
        0xfe: u'\u27be',  # OPEN-OUTLINED RIGHTWARDS ARROW
    }


# Encoding for the Sidney font
sidney_changes = {
        0x20: u'\u0020',  # SPACE
        0x21: u'\u0021',  # EXCLAMATION MARK
        0x22: u'\u2200',  # FOR ALL
        0x23: u'\u0023',  # NUMBER SIGN
        0x24: u'\u2203',  # THERE EXISTS
        0x25: u'\u0025',  # PERCENT SIGN
        0x26: u'\u0026',  # AMPERSAND
        0x27: u'\u220b',  # CONTAINS AS MEMBER
        0x28: u'\u0028',  # LEFT PARENTHESIS
        0x29: u'\u0029',  # RIGHT PARENTHESIS
        0x2a: u'\u2217',  # ASTERISK OPERATOR
        0x2b: u'\u002b',  # PLUS SIGN
        0x2c: u'\u002c',  # COMMA
        0x2d: u'\u2212',  # MINUS SIGN
        0x2e: u'\u002e',  # FULL STOP
        0x2f: u'\u002f',  # SOLIDUS
        0x30: u'\u0030',  # DIGIT ZERO
        0x31: u'\u0031',  # DIGIT ONE
        0x32: u'\u0032',  # DIGIT TWO
        0x33: u'\u0033',  # DIGIT THREE
        0x34: u'\u0034',  # DIGIT FOUR
        0x35: u'\u0035',  # DIGIT FIVE
        0x36: u'\u0036',  # DIGIT SIX
        0x37: u'\u0037',  # DIGIT SEVEN
        0x38: u'\u0038',  # DIGIT EIGHT
        0x39: u'\u0039',  # DIGIT NINE
        0x3a: u'\u003a',  # COLON
        0x3b: u'\u003b',  # SEMICOLON
        0x3c: u'\u003c',  # LESS-THAN SIGN
        0x3d: u'\u003d',  # EQUALS SIGN
        0x3e: u'\u003e',  # GREATER-THAN SIGN
        0x3f: u'\u003f',  # QUESTION MARK
        0x40: u'\u2245',  # APPROXIMATELY EQUAL TO
        0x41: u'\u0391',  # GREEK CAPITAL LETTER ALPHA
        0x42: u'\u0392',  # GREEK CAPITAL LETTER BETA
        0x43: u'\u03a7',  # GREEK CAPITAL LETTER CHI
        0x44: u'\u2206',  # INCREMENT
        0x45: u'\u0395',  # GREEK CAPITAL LETTER EPSILON
        0x46: u'\u03a6',  # GREEK CAPITAL LETTER PHI
        0x47: u'\u0393',  # GREEK CAPITAL LETTER GAMMA
        0x48: u'\u0397',  # GREEK CAPITAL LETTER ETA
        0x49: u'\u0399',  # GREEK CAPITAL LETTER IOTA
        0x4a: u'\u03d1',  # GREEK THETA SYMBOL
        0x4b: u'\u039a',  # GREEK CAPITAL LETTER KAPPA
        0x4c: u'\u039b',  # GREEK CAPITAL LETTER LAMDA
        0x4d: u'\u039c',  # GREEK CAPITAL LETTER MU
        0x4e: u'\u039d',  # GREEK CAPITAL LETTER NU
        0x4f: u'\u039f',  # GREEK CAPITAL LETTER OMICRON
        0x50: u'\u03a0',  # GREEK CAPITAL LETTER PI
        0x51: u'\u0398',  # GREEK CAPITAL LETTER THETA
        0x52: u'\u03a1',  # GREEK CAPITAL LETTER RHO
        0x53: u'\u03a3',  # GREEK CAPITAL LETTER SIGMA
        0x54: u'\u03a4',  # GREEK CAPITAL LETTER TAU
        0x55: u'\u03a5',  # GREEK CAPITAL LETTER UPSILON
        0x56: u'\u03c2',  # GREEK SMALL LETTER FINAL SIGMA
        0x57: u'\u2126',  # OHM SIGN
        0x58: u'\u039e',  # GREEK CAPITAL LETTER XI
        0x59: u'\u03a8',  # GREEK CAPITAL LETTER PSI
        0x5a: u'\u0396',  # GREEK CAPITAL LETTER ZETA
        0x5b: u'\u005b',  # LEFT SQUARE BRACKET
        0x5c: u'\u2234',  # THEREFORE
        0x5d: u'\u005d',  # RIGHT SQUARE BRACKET
        0x5e: u'\u22a5',  # UP TACK
        0x5f: u'\u005f',  # LOW LINE
        0x60: u'\u203e',  # OVERLINE
        0x61: u'\u03b1',  # GREEK SMALL LETTER ALPHA
        0x62: u'\u03b2',  # GREEK SMALL LETTER BETA
        0x63: u'\u03c7',  # GREEK SMALL LETTER CHI
        0x64: u'\u03b4',  # GREEK SMALL LETTER DELTA
        0x65: u'\u03b5',  # GREEK SMALL LETTER EPSILON
        0x66: u'\u03c6',  # GREEK SMALL LETTER PHI
        0x67: u'\u03b3',  # GREEK SMALL LETTER GAMMA
        0x68: u'\u03b7',  # GREEK SMALL LETTER ETA
        0x69: u'\u03b9',  # GREEK SMALL LETTER IOTA
        0x6a: u'\u03d5',  # GREEK PHI SYMBOL
        0x6b: u'\u03ba',  # GREEK SMALL LETTER KAPPA
        0x6c: u'\u03bb',  # GREEK SMALL LETTER LAMDA
        0x6d: u'\u00b5',  # MICRO SIGN
        0x6e: u'\u03bd',  # GREEK SMALL LETTER NU
        0x6f: u'\u03bf',  # GREEK SMALL LETTER OMICRON
        0x70: u'\u03c0',  # GREEK SMALL LETTER PI
        0x71: u'\u03b8',  # GREEK SMALL LETTER THETA
        0x72: u'\u03c1',  # GREEK SMALL LETTER RHO
        0x73: u'\u03c3',  # GREEK SMALL LETTER SIGMA
        0x74: u'\u03c4',  # GREEK SMALL LETTER TAU
        0x75: u'\u03c5',  # GREEK SMALL LETTER UPSILON
        0x76: u'\u03d6',  # GREEK PI SYMBOL
        0x77: u'\u03c9',  # GREEK SMALL LETTER OMEGA
        0x78: u'\u03be',  # GREEK SMALL LETTER XI
        0x79: u'\u03c8',  # GREEK SMALL LETTER PSI
        0x7a: u'\u03b6',  # GREEK SMALL LETTER ZETA
        0x7b: u'\u007b',  # LEFT CURLY BRACKET
        0x7c: u'\u007c',  # VERTICAL LINE
        0x7d: u'\u007d',  # RIGHT CURLY BRACKET
        0x7e: u'\u223c',  # TILDE OPERATOR
        0xa1: u'\u03d2',  # GREEK UPSILON WITH HOOK SYMBOL
        0xa2: u'\u2032',  # PRIME
        0xa3: u'\u2264',  # LESS-THAN OR EQUAL TO
        0xa4: u'\u2044',  # FRACTION SLASH
        0xa5: u'\u221e',  # INFINITY
        0xa6: u'\u0192',  # LATIN SMALL LETTER F WITH HOOK
        0xa7: u'\u2663',  # BLACK CLUB SUIT
        0xa8: u'\u2666',  # BLACK DIAMOND SUIT
        0xa9: u'\u2665',  # BLACK HEART SUIT
        0xaa: u'\u2660',  # BLACK SPADE SUIT
        0xab: u'\u2194',  # LEFT RIGHT ARROW
        0xac: u'\u2190',  # LEFTWARDS ARROW
        0xad: u'\u2191',  # UPWARDS ARROW
        0xae: u'\u2192',  # RIGHTWARDS ARROW
        0xaf: u'\u2193',  # DOWNWARDS ARROW
        0xb0: u'\u00b0',  # DEGREE SIGN
        0xb1: u'\u00b1',  # PLUS-MINUS SIGN
        0xb2: u'\u2033',  # DOUBLE PRIME
        0xb3: u'\u2265',  # GREATER-THAN OR EQUAL TO
        0xb4: u'\u00d7',  # MULTIPLICATION SIGN
        0xb5: u'\u221d',  # PROPORTIONAL TO
        0xb6: u'\u2202',  # PARTIAL DIFFERENTIAL
        0xb7: u'\u2022',  # BULLET
        0xb8: u'\u00f7',  # DIVISION SIGN
        0xb9: u'\u2260',  # NOT EQUAL TO
        0xba: u'\u2261',  # IDENTICAL TO
        0xbb: u'\u2248',  # ALMOST EQUAL TO
        0xbc: u'\u2026',  # HORIZONTAL ELLIPSIS
        0xbd: u'\u23d0',  # VERTICAL LINE EXTENSION
        0xbe: u'\u23af',  # HORIZONTAL LINE EXTENSION
        0xbf: u'\u21b5',  # DOWNWARDS ARROW WITH CORNER LEFTWARDS
        0xc0: u'\u2135',  # ALEF SYMBOL
        0xc1: u'\u2111',  # BLACK-LETTER CAPITAL I
        0xc2: u'\u211c',  # BLACK-LETTER CAPITAL R
        0xc3: u'\u2118',  # SCRIPT CAPITAL P
        0xc4: u'\u2297',  # CIRCLED TIMES
        0xc5: u'\u2295',  # CIRCLED PLUS
        0xc6: u'\u2205',  # EMPTY SET
        0xc7: u'\u2229',  # INTERSECTION
        0xc8: u'\u222a',  # UNION
        0xc9: u'\u2283',  # SUPERSET OF
        0xca: u'\u2287',  # SUPERSET OF OR EQUAL TO
        0xcb: u'\u2284',  # NOT A SUBSET OF
        0xcc: u'\u2282',  # SUBSET OF
        0xcd: u'\u2286',  # SUBSET OF OR EQUAL TO
        0xce: u'\u2208',  # ELEMENT OF
        0xcf: u'\u2209',  # NOT AN ELEMENT OF
        0xd0: u'\u2220',  # ANGLE
        0xd1: u'\u2207',  # NABLA
        0xd2: u'\u00ae',  # REGISTERED SIGN
        0xd3: u'\u00a9',  # COPYRIGHT SIGN
        0xd4: u'\u2122',  # TRACE MARK SIGN
        0xd5: u'\u220f',  # N-ARY PRODUCT
        0xd6: u'\u221a',  # SQUARE ROOT
        0xd7: u'\u22c5',  # DOT OPERATOR
        0xd8: u'\u00ac',  # NOT SIGN
        0xd9: u'\u2227',  # LOGICAL AND
        0xda: u'\u2228',  # LOGICAL OR
        0xdb: u'\u21d4',  # LEFT RIGHT DOUBLE ARROW
        0xdc: u'\u21d0',  # LEFTWARDS DOUBLE ARROW
        0xdd: u'\u21d1',  # UPWARDS DOUBLE ARROW
        0xde: u'\u21d2',  # RIGHTWARDS DOUBLE ARROW
        0xdf: u'\u21d3',  # DOWNWARDS DOUBLE ARROW
        0xe0: u'\u25ca',  # LOZENGE
        0xe1: u'\u2329',  # LEFT-POINTING ANGLE BRACKET
        0xe2: u'\u00ae',  # REGISTERED SIGN
        0xe3: u'\u00a9',  # COPYRIGHT SIGN
        0xe4: u'\u2122',  # TRACE MARK SIGN
        0xe5: u'\u2211',  # N-ARY SUMMATION
        0xe6: u'\u239b',  # LEFT PARENTHESIS UPPER HOOK
        0xe7: u'\u239c',  # LEFT PARENTHESIS EXTENSION
        0xe8: u'\u239d',  # LEFT PARENTHESIS LOWER HOOK
        0xe9: u'\u23a1',  # LEFT SQUARE BRACKET UPPER CORNER
        0xea: u'\u23a2',  # LEFT SQUARE BRACKET EXTENSION
        0xeb: u'\u23a3',  # LEFT SQUARE BRACKET LOWER CORNER
        0xec: u'\u23a7',  # LEFT CURLY BRACKET UPPER HOOK
        0xed: u'\u23a8',  # LEFT CURLY BRACKET MIDDLE PIECE
        0xee: u'\u23a9',  # LEFT CURLY BRACKET LOWER HOOK
        0xef: u'\u23aa',  # CURLY BRACKET EXTENSION
        0xf0: u'\u20ac',  # EURO SIGN
        0xf1: u'\u232a',  # RIGHT-POINTING ANGLE BRACKET
        0xf2: u'\u222b',  # INTEGRAL
        0xf3: u'\u2320',  # TOP HALF INTEGRAL
        0xf4: u'\u23ae',  # INTEGRAL EXTENSION
        0xf5: u'\u2321',  # BOTTOM HALF INTEGRAL
        0xf6: u'\u239b',  # LEFT PARENTHESIS UPPER HOOK
        0xf7: u'\u239c',  # LEFT PARENTHESIS EXTENSION
        0xf8: u'\u239d',  # LEFT PARENTHESIS LOWER HOOK
        0xf9: u'\u23a4',  # RIGHT SQUARE BRACKET UPPER CORNER
        0xfa: u'\u23a5',  # RIGHT SQUARE BRACKET EXTENSION
        0xfb: u'\u23a6',  # RIGHT SQUARE BRACKET LOWER CORNER
        0xfc: u'\u23ab',  # RIGHT CURLY BRACKET UPPER HOOK
        0xfd: u'\u23ac',  # RIGHT CURLY BRACKET MIDDLE PIECE
        0xfe: u'\u23ad',  # RIGHT CURLY BRACKET LOWER HOOK
    }


riscos_alphabets = [
        # 100 is BBCFont
        RISCOSAlphabet(101, 'riscos-latin1', 'iso-8859-1', changes=[c1_changes]),
        RISCOSAlphabet(102, 'riscos-latin2', 'iso-8859-2', changes=[c1_changes]),
        RISCOSAlphabet(103, 'riscos-latin3', 'iso-8859-3', changes=[c1_changes, iso8859_3_changes]),
        RISCOSAlphabet(104, 'riscos-latin4', 'iso-8859-4', changes=[c1_changes]),
        RISCOSAlphabet(105, 'riscos-cyrillic', 'iso-8859-5', changes=[c1_changes]),
        RISCOSAlphabet(106, 'riscos-arabic', 'iso-8859-6', changes=[c1_changes, iso8859_6_changes]),
        RISCOSAlphabet(107, 'riscos-greek', 'iso-8859-7', changes=[c1_changes, iso8859_7_changes]),
        RISCOSAlphabet(108, 'riscos-hebrew', 'iso-8859-8', changes=[c1_changes, iso8859_8_changes]),
        RISCOSAlphabet(109, 'riscos-latin5', 'iso-8859-9', changes=[c1_changes]),
        RISCOSAlphabet(110, 'riscos-welsh', 'iso-8859-1', changes=[c1_changes, welsh_changes]),  # ISO-IR-182
        RISCOSUTF8(111, 'riscos-utf8'), # The lack of hyphen matches convention for alphabet names
        RISCOSAlphabet(112, 'riscos-latin9', 'iso-8859-15', changes=[c1_changes]),
        RISCOSAlphabet(113, 'riscos-latin6', 'iso-8859-10', changes=[c1_changes]),
        RISCOSAlphabet(114, 'riscos-latin7', 'iso-8859-13', changes=[c1_changes]),
        RISCOSAlphabet(115, 'riscos-latin8', 'iso-8859-14', changes=[c1_changes]),
        RISCOSAlphabet(116, 'riscos-latin10', 'iso-8859-16', changes=[c1_changes]),
        # Special mappings for the additional fonts
        RISCOSAlphabet(None, 'riscos-sidney', None, changes=[sidney_changes]),
        RISCOSAlphabet(None, 'riscos-selwyn', None, changes=[selwyn_changes]),
        RISCOSAlphabet(None, 'riscos-wimpsymbol', None, changes=[wimpsymbol_changes]),
    ]
riscos_alphabets_map = {encoding.name: encoding.codec for encoding in riscos_alphabets}
def custom_search_function(encoding_name):
    if encoding_name.startswith('riscos-alphabet-'):
        _, _, number = encoding_name.split('-', 2)
        try:
            alphabet_number = int(number)
            for encoding in riscos_alphabets:
                if encoding.alphabet and \
                   encoding.alphabet == alphabet_number:
                    return encoding.codec
        except ValueError:
            return None
    return riscos_alphabets_map.get(encoding_name, None)


codecs.register(custom_search_function)
