#!/usr/local/bin/python
# -*- encoding: iso-8859-1 -*-
# (El comentario anterior es requerido por Python para saber qué codificación
# usa este código fuente en los comentarios y strings. No tiene nada qué ver
# con el encoding de la página web que genera, ni con la codificación de la
# tabla mostrada en esa página web)
#
# ================================================================
# Este script recibe como entrada el nombre de una codificación
# de 8 bits, como por ejemplo "iso-8859-15", o "windows-1252", o
# "cp850", etc y produce como resultado una tabla de códigos que
# muestra para cada posible código entre 128 y 255 el carácter 
# asociado a ese código y el valor del código que tendría ese
# carácter en UNICODE
#
# La tabla está organizada por filas y columnas de modo que 
# a partir de esta organización es posible reconstruir el código
# del carácter en la codificación que se había especificado
# como entrada
#
# La página web generada, a su vez, tiene codificación utf-8 para
# evitar que el navegador muestre caracteres inapropiados,
# especialmente en los primeros códigos que suelen ser de control
# en los estándares iso 8859.
#
# (c) 2005 JL Diaz <jldiaz@uniovi.es>
#     Distribuido bajo los términos de la GNU General Public License (GPL)
#     Los términos de esta licencia pueden consultarse en:
#     http://www.gnu.org/licenses/gpl.txt              (english)
#     http://gugs.sindominio.net/licencias/gples.html  (español)
# ================================================================

# Este es el encoding que mostrará por defecto, si el usuario
# no especifica otro. 

encoding="windows-1252"

# La forma de especificar otro es en el URL de la página (método
# POST), por ejemplo: 
#
# http://www.atc.uniovi.es/cgi-bin/encodings?encoding=iso-8859-1

# Importamos sys para el exit, y cgi para acceder al parámetro
# encoding del URL, si el usuario ha dado uno.
import sys, cgi

# Generar el tipo de contenido de la página
print "Content-Type: text/html\n"

# Obtener el campo "encoding" del URL
form=cgi.FieldStorage()
if (form.has_key("encoding")): encoding=form["encoding"].value

# Verificar si es un encoding válido
try:
  unicode('a', encoding)
  # Simplemente intento codificar una 'a' usando ese encoding
  # Si se genera una excepción es que python no soporta el encoding dado
except:
  print '''
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Error</title>
</head><body>
<h1>Error</h1>
El <i>encoding</i> %s es desconocido</p>
</body></html>'''
 % encoding
  sys.exit();

# ================================================================
# Si todo va bien, generamos la página web con la tabla
# Comenzamos con las cabeceras y el contenido fijo
print '''
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>C&oacute;digo %s</title>
<style><!--
@media screen, print {
body {
      margin-top: 1em;
      font-family: verdana, arial, helvetica;
      background-color: white;
}
table {
  border: 0;
  padding: 0;
  border-spacing: 2px;
  border-collapse: collapse;
}
tr, td {
  border: 1px solid gray;
  padding: 1ex;
}
td.top {
  background-color: #aaddff;
  border-bottom: 3px solid black;
  font-weight: bold;
}
td.izda {
  background-color: #aaddff;
  border-right: 3px solid black;
  font-weight: bold;
}
td.esquina {
  background-color: #aaddff;
}
.char {
  font-size: 170%%;
}
.code {
  font-size: 60%%;
  font-family: courier;
}
}
-->
</style>
</head>
<body>
<h1 align="center">%s</h1>
<table align="center">
<tr><td class="esquina">&nbsp;</td>
'''
 % (encoding, encoding)

# Generar la primera fila de la tabla
for i in range(0,16):
    print '<td align="center" class="top"><code>%s%X</code></td>'\
             % (unicode("·""iso-8859-1").encode("utf-8"), i)
print "</tr>"

rango=range(8,16)
if encoding=="ascii": rango=range(0,8)

# Generar cada una de las filas restantes
for j in rango:
    print '<tr><td align="center" class="izda"><code>%X%s</code></td>'\
          % (j, unicode("·""iso-8859-1").encode("utf-8"))
    # Para cada fila, generar cada carácter
    for i in range(0,16):
        # Color por defecto del fondo de la celda (se cambiará a
        # gris si esa celda contiene un carácter inválido)
        color="#ffffff"
        valor=j*16+i            # Valor numérico del carácter a mostrar

        # Averiguamos a qué carácter corresponde ese valor numérico
        # usando la función unicode de python. Esta función recibe dos
        # parámetros: 
        #   1) una cadena, codificada con algún encoding, el que sea, 
        #   2) Otra cadena que indica qué encoding usa la primera
        # El resultado es una representación "unicode" que Python usa
        # internamente, la cual a su vez podrá ser codificada de
        # diferentes formas (utf-8, utf-16, etc). 
        # Si la cadena 1) contiene algún carácter inválido de acuerdo
        # con el encoding 2), se genera una excepción

        # En nuestro caso, la cadena 1) siempre constará de una sola
        # letra, el carácter a mostrar cuyo valor es j*16+i, y la
        # cadena 2) será el valor del encoding especificado por el usuario
        try:
          caracter=unicode(chr(valor), encoding)
          # Si la conversión ha tenido éxito, el carácter es válido y 
          # podemos mostrarlo. Para ello lo recodificamos como utf-8
          letra=caracter.encode("utf-8")

          # Además, para obtener su valor UNICODE, lo codificamos
          # también en utf-16 big endian
          uni=caracter.encode("utf-16be")

          # A partir de su representación utf-16, puedo calcular el
          # valor numérico de su código UNICODE, y convierto ese
          # valor a una cadena hexadecimal
          codigo="U+%04X" % (ord(uni[0])*256+ord(uni[1]))

          # Si se trata de un carácter de control, cambiamos color fondo
          if (ord(caracter)<0x20or (ord(caracter)>0x7E and ord(caracter)<0xA0):
            color="#cccccc"
            letra=u'\0'.encode("utf-8")
        except:
          # Si se produce una excepción, es que el carácter no está
          # definido en la codificación dada. En este caso mostramos
          # el carácter unicode nulo, que suele ser una caja en la
          # mayoría de las fuentes, ponemos el fondo de la celda gris
          # y ponemos "..." como valor de su unicode
          letra=u'\0'.encode("utf-8")
          color="#cccccc"
          codigo="..."
 
        # Finalmente imprimimos esa celda
        print '''<td align="center" valign="bottom" bgcolor="%s">
                 <span class="char">%s</span>
                 <br /><span class="code">%s</span></td>'''
 \
               % (color, letra, codigo)
    print "</tr>"

# Cerrar los tags que terminan el documento
print '''
</table>
</body>
</html>
'''