/*
* @(#)Teletext.java - constants/decode of teletext System B
*
* Copyright (c) 2001-2009 by dvb.matt, All Rights Reserved.
*
* This file is part of ProjectX, a free Java based demux utility.
* By the authors, ProjectX is intended for educational purposes only,
* as a non-commercial test project.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* Support for SRT with font tags, W3C TTML and GPAC TTEXT
* added by Simon Liddicott
*
*/
package net.sourceforge.dvb.projectx.subtitle;
import java.util.Hashtable;
import java.util.ArrayList;
import java.util.Arrays;
import net.sourceforge.dvb.projectx.common.Common;
import net.sourceforge.dvb.projectx.common.Keys;
public class Teletext extends Object {
//DM30072004 081.7 int07 add
private Hashtable page_modifications = new Hashtable();
private boolean use = false;
private int display_row = 0;
private int display_column = 0;
private short[] active_set;
private short[] active_national_set;
public Teletext()
{}
private final String[] GPACHeader = {
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>",
"<!-- GPAC 3GPP Text Stream -->",
"<TextStream version=\"1.1\">",
"<TextStreamHeader width=\"704\" height=\"60\" layer=\"0\" translation_x=\"0\" translation_y=\"340\">",
"<TextSampleDescription horizontalJustification=\"center\" verticalJustification=\"bottom\" backColor=\"0 0 0 ff\" verticalText=\"no\" fillTextRegion=\"no\" continuousKaraoke=\"no\" scroll=\"None\">",
"<FontTable>",
"<FontTableEntry fontName=\"Arial\" fontID=\"1\"/>",
"</FontTable>",
"<TextBox top=\"0\" left=\"0\" bottom=\"60\" right=\"704\"/>",
"<Style styles=\"Normal\" fontID=\"1\" fontSize=\"24\" color=\"ff ff ff ff\"/>",
"</TextSampleDescription>",
"</TextStreamHeader>"
};
private final String[] GPACFooter = {
"</TextSample>",
"</TextStream>"
};
private final String[] W3CHeader = {
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<tt xmlns=\"http://www.w3.org/2006/10/ttaf1\" xmlns:ttp=\"http://www.w3.org/2006/10/ttaf1#parameter\" ttp:timeBase=\"media\" xmlns:tts=\"http://www.w3.org/2006/10/ttaf1#style\" xml:lang=\"en\" xmlns:ttm=\"http://www.w3.org/2006/10/ttaf1#metadata\">",
"<head>",
"<metadata/>",
"<styling>",
"<style id=\"s0\" tts:backgroundColor=\"black\" tts:fontStyle=\"normal\" tts:fontSize=\"16\" tts:fontFamily=\"arial\" tts:color=\"white\" />",
"</styling>",
"<layout/>",
"</head>",
"<body tts:textAlign=\"center\" style=\"s0\">",
"<div>"
};
private final String[] W3CFooter = {
"</p>",
"</div>",
"</body>",
"</tt>"
};
private final String[] ssaHeader = {
"[Script Info]",
"; This is a Sub Station Alpha v4 script.",
"; For Sub Station Alpha info and downloads,",
"; go to http://www.eswat.demon.co.uk/",
"; or email kotus@eswat.demon.co.uk",
"; to burn-in these subtitles into an AVI, just install subtitler2.3 PlugIn for VirtualDub, see doom9.org",
"Title: Subtitles taken from TV teletext",
"Original Script: by their respective owner",
"ScriptType: v4.00",
"Collisions: Normal",
"PlayResY: 240", // maybe replaced [10]
"PlayDepth: 0",
"Timer: 100.0000", // maybe replaced [12]
"[V4 Styles]",
"Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding",
"Style: MainB,Arial,14,&H00FFFF,&H00FFFF,&H00FFFF,0,0,-1,1,2,4,1,16,16,16,0,0",
"Style: MainT,Arial,14,&HFFFFFF,&HFFFFFF,&HFFFFFF,0,1,0,1,2,4,1,16,16,16,0,0",
"Style: MainI,Arial,14,&HFFFFFF,&HFFFFFF,&HFFFFFF,0,1,1,1,2,4,1,16,16,16,0,0", //DM30122003 081.6 int10 add
"Style: MainC,Courier New,14,&HFFFFFF,&HFFFFFF,&HFFFFFF,0,1,0,1,2,4,1,16,16,16,0,0",
"[Events]",
"Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text",
"Comment: Marked=0,0:00:00.00,0:00:00.01,MainB,,0000,0000,0000,!Effect,This script was created by decoding a tv teletext stream to build coloured subtitles"
};
private final String[] ssaLine = {
"Dialogue: Marked=0,",
",MainT,,0000,0000,0000,!Effect,{\\q2\\a2}"
};
//DM26052004 081.7 int03 changed
private final String[] stlHeader = {
"",
"//Font select and font size",
"$FontName = Arial",
"$FontSize = 30",
"//Character attributes (global)",
"$Bold = FALSE",
"$UnderLined = FALSE",
"$Italic = FALSE",
"//Position Control",
"$HorzAlign = Center",
"$VertAlign = Bottom",
"$XOffset = 10",
"$YOffset = 10",
"//Contrast Control",
"$TextContrast = 15",
"$Outline1Contrast = 8",
"$Outline2Contrast = 15",
"$BackgroundContrast = 0",
"//Effects Control",
"$ForceDisplay = FALSE",
"$FadeIn = 0",
"$FadeOut = 0",
"//Other Controls",
"$TapeOffset = FALSE",
"//Colors",
"$ColorIndex1 = 0",
"$ColorIndex2 = 1",
"$ColorIndex3 = 2",
"$ColorIndex4 = 3",
"//Subtitles"
};
//DM14052004 081.7 int02 add
private final String[] sonHeader = {
"st_format\t2",
"Display_Start\tnon_forced",
"TV_Type\t\tPAL",
"Tape_Type\tNON_DROP",
"Pixel_Area\t(0 575)",
"Directory\t",
"",
"SP_NUMBER\tSTART\t\tEND\t\tFILE_NAME"
};
/**
private final String[] colors = {
"{\\c&HC0C0C0&}", // black /gray
"{\\c&H4040FF&}", // red
"{\\c&H00FF00&}", // green
"{\\c&H00FFFF&}", // yellow
"{\\c&HFF409B&}", // blue //DM15032004 081.6 int18 changed
"{\\c&HFF00FF&}", // magenta
"{\\c&HFFFF00&}", // cyan
"{\\c&HFFFFFF&}", // white
};
**/
private final String[][][] colors = {
{
},
{
{
"{\\c&HC0C0C0&}", // black /gray
"{\\c&H4040FF&}", // red
"{\\c&H00FF00&}", // green
"{\\c&H00FFFF&}", // yellow
"{\\c&HFF409B&}", // blue //DM15032004 081.6 int18 changed
"{\\c&HFF00FF&}", // magenta
"{\\c&HFFFF00&}", // cyan
"{\\c&HFFFFFF&}", // white
},
{""},
},
{
{
"<font color=\"#C0C0C0\">", // black /gray
"<font color=\"#4040FF\">", // red
"<font color=\"#00FF00\">", // green
"<font color=\"#00FFFF\">", // yellow
"<font color=\"#FF409B\">", // blue //DM15032004 081.6 int18 changed
"<font color=\"#FF00FF\">", // magenta
"<font color=\"#FFFF00\">", // cyan
"<font color=\"#FFFFFF\">", // white
},
{"</font>"},
},
{
{
"<span tts:color=\"#C0C0C0\">", // black /gray
"<span tts:color=\"red\">", // red
"<span tts:color=\"green\">", // green
"<span tts:color=\"yellow\">", // yellow
"<span tts:color=\"#FF409B\">", // blue //DM15032004 081.6 int18 changed
"<span tts:color=\"#FF00FF\">", // magenta
"<span tts:color=\"cyan\">", // cyan
"<span tts:color=\"white\">", // white
},
{"</span>"},
},
{
{
"c0 c0 c0 ff", // black /gray
"40 40 ff ff", // red
"00 ff 00 ff", // green
"00 ff ff ff", // yellow
"ff 40 9b ff", // blue //DM15032004 081.6 int18 changed
"ff 00 ff ff", // magenta
"ff ff 00 ff", // cyan
"ff ff ff ff", // white
},
{""},
},
};
//DM14052004 081.7 int02 add
public String[] getSONHead(String path, long frame_rate)
{
if (frame_rate != 3600)
{
sonHeader[2] = "TV_Type\t\tNTSC";
sonHeader[3] = "Tape_Type\tDROP";
}
else
{
sonHeader[2] = "TV_Type\t\tPAL";
sonHeader[3] = "Tape_Type\tNON_DROP";
}
sonHeader[5] = "Directory\t" + path;
return sonHeader;
}
/*****************
* return STL header *
*****************/
public String[] getSTLHead(String version)
{
stlHeader[0] = "//Generated by " + version;
return stlHeader;
}
/*****************
* return GPAC header *
*****************/
public String[] getGPACHead()
{
return GPACHeader;
}
/*****************
* return GPAC footer *
*****************/
public String[] getGPACFoot()
{
return GPACFooter;
}
/*****************
* return W3C header *
*****************/
public String[] getW3CHead()
{
return W3CHeader;
}
/*****************
* return W3C footer *
*****************/
public String[] getW3CFoot()
{
return W3CFooter;
}
/*****************
* return SSA header *
*****************/
public String[] getSSAHead()
{
return ssaHeader;
}
/*****************
* return SSA line *
*****************/
public String[] getSSALine()
{
return ssaLine;
}
/*****************
* return SMPTE *
*****************/
public String SMPTE(String time, long videoframetime)
{
StringBuffer a = new StringBuffer();
a.append(time.substring(0, 8) + ":00");
String b = "" + (Integer.parseInt(time.substring(9, 12)) / ((int)videoframetime / 90));
a.replace((b.length() == 1) ? 10 : 9 , 11, b);
return a.toString();
}
/*****************
* change endian *
*****************/
public byte bytereverse(byte n)
{
n = (byte) (((n >> 1) & 0x55) | ((n << 1) & 0xaa));
n = (byte) (((n >> 2) & 0x33) | ((n << 2) & 0xcc));
n = (byte) (((n >> 4) & 0x0f) | ((n << 4) & 0xf0));
return n;
}
public byte bytereverse(int n)
{
return bytereverse((byte) n);
}
/**************
* set parity *
**************/
public byte parity(byte n)
{
boolean par=true;
if (n == 0)
return n;
for (int a=0; a < 8; a++)
if ((n>>>a & 1) == 1)
par = !par;
if (par)
return (byte)(0x80 | n);
return n;
}
/****************
* check parity *
****************/
public boolean cparity(byte n)
{
boolean par=true;
if (n == 0)
return true;
for (int a=0; a < 7; a++)
if ((n>>>a & 1) == 1)
par = !par;
if (par && (1 & n>>>7) == 1)
return true;
else if (!par && (1 & n>>>7) == 0)
return true;
return false;
}
//DM24052004 081.7 int03 introduced
//no error correction ATM
public int hamming_24_18(byte b[], int off)
{
int val = 0;
val |= (0xFE & b[off + 2])>>>1;
val |= (0xFE & b[off + 1])<<6;
val |= (0xE & b[off])<<13;
val |= (0x20 & b[off])<<12;
return val;
}
/******************
* hamming decode 8/4 *
******************/
public int hamming_8_4(byte a)
{
switch (0xFF & a)
{
case 0x0B:
return 1;
case 0x1C:
return 6;
case 0x26:
return 2;
case 0x31:
return 5;
case 0x40:
return 8;
case 0x57:
return 15;
case 0x6D:
return 11;
case 0x7A:
return 12;
case 0x85:
return 3;
case 0x92:
return 4;
case 0xA8:
return 0;
case 0xBF:
return 7;
case 0xCE:
return 10;
case 0xD9:
return 13;
case 0xE3:
return 9;
case 0xF4:
return 14;
default:
return -1; // decoding error , not yet corrected
}
}
/**
* hamming encode 8/4
*/
private byte[] hamming_8_4_values = {
(byte) 0xA8, 0x0B, 0x26, (byte) 0x85, (byte) 0x92, 0x31, 0x1C, (byte) 0xBF, 0x40,
(byte) 0xE3, (byte) 0xCE, 0x6D, 0x7A, (byte) 0xD9, (byte) 0xF4, 0x57
};
/**
* make suppic from teletext *
*/
public int[] buildCharArray(byte[] packet, int offset, int len, int row, int character_set, boolean checkParity, boolean boxed_mode, boolean alignment)
{
// return int char<<8 | 0xF0 & active_color backgrnd | 0xF & active_color foregrnd
boolean ascii = true;
boolean mosaic = false;
boolean toggle = false;
int chars[] = new int[len];
int active_color = 7; // init with white ascii color per line + black background
int parity_error = 0;
int[] boxed_area = { -1, -1 };
int language_code = Common.getSettings().getIntProperty(Keys.KEY_TtxLanguagePair) - 1;
int primary_set_mapping = language_code < 0 ? 0 : language_code;
int primary_national_set_mapping = character_set;
// int secondary_set_mapping = primary_set_mapping;
// int secondary_national_set_mapping = primary_national_set_mapping;
int secondary_set_mapping = 0; //latin
int secondary_national_set_mapping = 0; //latin
if (page_modifications.containsKey("primary_set"))
secondary_set_mapping = primary_set_mapping = Integer.parseInt(page_modifications.get("primary_set").toString());
if (page_modifications.containsKey("primary_national_set"))
secondary_national_set_mapping = primary_national_set_mapping = Integer.parseInt(page_modifications.get("primary_national_set").toString());
if (page_modifications.containsKey("secondary_set"))
{
secondary_set_mapping = Integer.parseInt(page_modifications.get("secondary_set").toString());
secondary_national_set_mapping = Integer.parseInt(page_modifications.get("secondary_national_set").toString());
}
active_set = CharSet.getActive_G0_Set(primary_set_mapping, primary_national_set_mapping, row);
active_national_set = CharSet.getActiveNationalSubset(primary_set_mapping, primary_national_set_mapping, row);
for (int c = offset, val, i = 0; i < len; c++, i++)
{
val = row<<16 | i;
if (page_modifications.containsKey("" + val))
{
chars[i] = active_color | (int)(page_modifications.get("" + val).toString().charAt(0))<<8;
continue;
}
//if error, switch to graphics mode (= space)
if (checkParity && !cparity(packet[c]))
{
parity_error++;
packet[i] = 8;
}
int char_value = 0x7F & bytereverse(packet[c]);
//0x80..FF are outside
if (char_value>>>3 == 0) //0x0..7
{
ascii = true;
mosaic = false;
chars[i] = (active_set[32]<<8 | active_color);
active_color = (0xF0 & active_color) | char_value;
continue;
}
else if (char_value>>>4 == 0) //0x8..F
{
if (char_value == 0xB) //start box
boxed_area[0] = i;
else if (char_value == 0xA) //end box
if (boxed_area[1] <= boxed_area[0])
boxed_area[1] = i;
chars[i] = active_set[32]<<8 | active_color;
continue;
}
else if (char_value < 24) //0x10..17
{
ascii = false;
mosaic = true;
chars[i] = active_set[32]<<8 | active_color;
continue;
}
else if (char_value < 27) //0x18..1A
{
chars[i] = active_set[32]<<8 | active_color;
continue;
}
else if (char_value < 32) //0x1B..1F
{
switch (char_value) //1d=new bg with last color, 1c=black bg, 1b ESC
{
case 0x1B:
if (toggle)
{
active_set = CharSet.getActive_G0_Set(primary_set_mapping, primary_national_set_mapping, row);
active_national_set = CharSet.getActiveNationalSubset(primary_set_mapping, primary_national_set_mapping, row);
}
else
{
active_set = CharSet.getActive_G0_Set(secondary_set_mapping, secondary_national_set_mapping, row);
active_national_set = CharSet.getActiveNationalSubset(secondary_set_mapping, secondary_national_set_mapping, row);
}
toggle = !toggle;
break;
case 0x1C: // set black background
active_color &= 0xF;
if (!ascii && !mosaic) // switch ascii on
ascii = true;
break;
//new background same as foreground color
//any following is invisible until a diff. foreground is set
case 0x1D:
ascii = false;
active_color = active_color & 0xF | (0xF & active_color)<<4; //HHM
}
chars[i] = active_set[32]<<8 | active_color;
continue;
}
else if (char_value == 0x7F) //0x7F
{
chars[i] = active_set[32]<<8 | active_color;
continue;
}
if (!ascii)
{
chars[i] = active_set[32]<<8 | active_color;
continue;
}
if (active_national_set != null)
{
// all chars 0x20..7F special characters
switch (char_value)
{
case 0x23:
chars[i] = active_color | active_national_set[0]<<8;
continue;
case 0x24:
chars[i] = active_color | active_national_set[1]<<8;
continue;
case 0x40:
chars[i] = active_color | active_national_set[2]<<8;
continue;
case 0x5b:
chars[i] = active_color | active_national_set[3]<<8;
continue;
case 0x5c:
chars[i] = active_color | active_national_set[4]<<8;
continue;
case 0x5d:
chars[i] = active_color | active_national_set[5]<<8;
continue;
case 0x5e:
chars[i] = active_color | active_national_set[6]<<8;
continue;
case 0x5f:
chars[i] = active_color | active_national_set[7]<<8;
continue;
case 0x60:
chars[i] = active_color | active_national_set[8]<<8;
continue;
case 0x7b:
chars[i] = active_color | active_national_set[9]<<8;
continue;
case 0x7c:
chars[i] = active_color | active_national_set[10]<<8;
continue;
case 0x7d:
chars[i] = active_color | active_national_set[11]<<8;
continue;
case 0x7e:
chars[i] = active_color | active_national_set[12]<<8;
continue;
}
}
chars[i] = active_color | active_set[char_value]<<8;
continue;
}
if (boxed_mode)
{
if (boxed_area[0] >= 0)
{
for (int i = 0; i < boxed_area[0] && i < chars.length; i++)
chars[i] = active_set[32]<<8 | 7;
for (int i = boxed_area[1]; i > boxed_area[0] && i < chars.length; i++)
chars[i] = active_set[32]<<8 | 7;
}
else
Arrays.fill(chars, (active_set[32]<<8 | 7));
}
String test = "";
for (int s = 0; s < chars.length; s++)
test += (char)(chars[s]>>>8);
// ab 3 parit�tsfehlern zeile droppen
if (checkParity && parity_error > 0)
{
String msg = "!> line " + row + ", parity check failed at " + parity_error + " of " + len + " characters: '" + test + "'";
if (parity_error > Common.getSettings().getIntProperty(Keys.KEY_SubtitlePanel_MaxParityErrors))
{
test = "";
msg += ", line dropped..";
}
Common.setMessage(msg);
}
int trimlen = test.trim().length();
if (trimlen == 0)
return null;
else if (trimlen < 40 && alignment)
{
int offs = 0;
int noffs = 0;
while (test.startsWith(" ", offs))
offs++;
noffs = (chars.length - trimlen) / 2;
System.arraycopy(chars, offs, chars, noffs, trimlen);
Arrays.fill(chars, 0, noffs, (active_set[32]<<8 | 7));
Arrays.fill(chars, noffs + trimlen, chars.length, (active_set[32]<<8 | 7));
}
return chars;
}
/**
* make strings from teletext
*/
public String buildString(byte[] packet, int offset, int len, int row, int character_set, int color, boolean checkParity)
{
return buildString(packet, offset, len, row, character_set, color, checkParity, false);
}
/**
* make strings from teletext
*/
public String buildString(byte[] packet, int offset, int len, int row, int character_set, int color, boolean checkParity, boolean boxed_mode)
{
return buildString(packet, offset, len, row, character_set, color, checkParity, boxed_mode, 0);
}
/**
* make strings from teletext
* color 1 = save color strings for ssa
* color 2 = save color strings for srt coloured
* color 3 = save color strings for W3C Timed Text
* color 4 = save color strings for GPAC Timed Text
*/
public String buildString(byte[] packet, int offset, int len, int row, int character_set, int color, boolean checkParity, boolean boxed_mode, int page_characters)
{
boolean ascii = true;
boolean mosaic = false;
boolean toggle = false;
StringBuffer line_buffer = new StringBuffer();
StringBuffer color_buffer = new StringBuffer();
ColorIndex color_index;
ArrayList color_list = new ArrayList();
int parity_error = 0;
int[] boxed_area = { -1, -1 };
int language_code = Common.getSettings().getIntProperty(Keys.KEY_TtxLanguagePair) - 1;
int primary_set_mapping = language_code < 0 ? 0 : language_code;
int primary_national_set_mapping = character_set;
// int secondary_set_mapping = primary_set_mapping;
// int secondary_national_set_mapping = primary_national_set_mapping;
int secondary_set_mapping = 0; //latin
int secondary_national_set_mapping = 0; //latin
if (page_modifications.containsKey("primary_set"))
secondary_set_mapping = primary_set_mapping = Integer.parseInt(page_modifications.get("primary_set").toString());
if (page_modifications.containsKey("primary_national_set"))
secondary_national_set_mapping = primary_national_set_mapping = Integer.parseInt(page_modifications.get("primary_national_set").toString());
if (page_modifications.containsKey("secondary_set"))
{
secondary_set_mapping = Integer.parseInt(page_modifications.get("secondary_set").toString());
secondary_national_set_mapping = Integer.parseInt(page_modifications.get("secondary_national_set").toString());
}
active_set = CharSet.getActive_G0_Set(primary_set_mapping, primary_national_set_mapping, row);
active_national_set = CharSet.getActiveNationalSubset(primary_set_mapping, primary_national_set_mapping, row);
loopi:
for (int c = offset, val, i = 0; i < len; c++, i++)
{
val = row<<16 | i;
if (page_modifications.containsKey(String.valueOf(val)))
{
line_buffer.append(page_modifications.get(String.valueOf(val)));
continue;
}
//if error, switch to graphics mode (= space), by loosing all following chars
if (checkParity && !cparity(packet[c]))
{
parity_error++;
packet[c] = 8;
}
int char_value = 0x7F & bytereverse(packet[c]);
//0x80..FF are outside
if (char_value>>>3 == 0) //0x0..7, set ascii foreground color
{
ascii = true;
mosaic = false;
//line_buffer.append(color == 1 ? colors[char_value] : "");
if (color >= 1)
color_list.add(new ColorIndex(i, char_value));
line_buffer.append((char)active_set[32]);
continue;
}
else if (char_value>>>4 == 0) //0x8..F, flash/steady/box/size
{
if (char_value == 0xB) //start box
boxed_area[0] = i;
else if (char_value == 0xA) //end box
if (boxed_area[1] <= boxed_area[0])
boxed_area[1] = i;
line_buffer.append((char)active_set[32]);
continue;
}
else if (char_value < 24) //0x10..17, mosaic color codes
{
ascii = false;
mosaic = true;
line_buffer.append((char)active_set[32]);
continue;
}
else if (char_value < 27) //0x18..1A, mosaic modes
{
line_buffer.append((char)active_set[32]);
continue;
}
else if (char_value < 32) //0x1B..1F, background + mosaic modes
{
if (char_value == 0x1B) //ESC
{
if (toggle)
{
active_set = CharSet.getActive_G0_Set(primary_set_mapping, primary_national_set_mapping, row);
active_national_set = CharSet.getActiveNationalSubset(primary_set_mapping, primary_national_set_mapping, row);
}
else
{
active_set = CharSet.getActive_G0_Set(secondary_set_mapping, secondary_national_set_mapping, row);
active_national_set = CharSet.getActiveNationalSubset(secondary_set_mapping, secondary_national_set_mapping, row);
}
toggle = !toggle;
}
//new background is black
//check whether it is not in mosaic mode
//check whether foreground is black too, is ignored - assumed to be readably string
if (char_value == 0x1C)
{
if (!ascii && !mosaic) // switch ascii on
ascii = true;
}
//new background same as foreground color
//any following is invisible until a diff. foreground is set, hide the char's, keep mosaic mode
if (char_value == 0x1D)
ascii = false;
line_buffer.append((char)active_set[32]);
continue;
}
else if (char_value == 0x7F) //0x7F
{
line_buffer.append((char)active_set[32]);
continue;
}
if (!ascii)
{
line_buffer.append((char)active_set[32]);
continue;
}
if (active_national_set != null)
{
// all chars 0x20..7F
switch (char_value) // special national characters
{
case 0x23:
line_buffer.append((char)active_national_set[0]);
continue loopi;
case 0x24:
line_buffer.append((char)active_national_set[1]);
continue loopi;
case 0x40:
line_buffer.append((char)active_national_set[2]);
continue loopi;
case 0x5b:
line_buffer.append((char)active_national_set[3]);
continue loopi;
case 0x5c:
line_buffer.append((char)active_national_set[4]);
continue loopi;
case 0x5d:
line_buffer.append((char)active_national_set[5]);
continue loopi;
case 0x5e:
line_buffer.append((char)active_national_set[6]);
continue loopi;
case 0x5f:
line_buffer.append((char)active_national_set[7]);
continue loopi;
case 0x60:
line_buffer.append((char)active_national_set[8]);
continue loopi;
case 0x7b:
line_buffer.append((char)active_national_set[9]);
continue loopi;
case 0x7c:
line_buffer.append((char)active_national_set[10]);
continue loopi;
case 0x7d:
line_buffer.append((char)active_national_set[11]);
continue loopi;
case 0x7e:
line_buffer.append((char)active_national_set[12]);
continue loopi;
}
}
line_buffer.append((char)active_set[char_value]);
continue loopi;
}
// ab 3 parit�tsfehlern zeile droppen
if (checkParity && parity_error > 0)
{
String msg = "!> line " + row + ", parity check failed at " + parity_error + " of " + len + " characters: '" + line_buffer.toString() + "'";
if (parity_error > Common.getSettings().getIntProperty(Keys.KEY_SubtitlePanel_MaxParityErrors))
{
line_buffer.setLength(0);
color = 0;
msg += ", line dropped..";
}
Common.setMessage(msg);
}
if (boxed_mode)
{
if (boxed_area[0] >= 0 && line_buffer.length() > 0)
{
for (int i = 0; i < boxed_area[0]; i++)
line_buffer.setCharAt(i, (char)active_set[32]);
for (int i = boxed_area[1]; i > boxed_area[0] && i < line_buffer.length(); i++)
line_buffer.setCharAt(i, (char)active_set[32]);
}
else
line_buffer.setLength(0);
}
//insert color strings heading
if (color >= 1 && line_buffer.length() > 0)
{
ColorIndex ci;
ColorIndex cip;
int ltrimCnt = ltrimCount(line_buffer.toString());
line_buffer.replace(0, line_buffer.length(), line_buffer.toString().trim());
/**
for (int i = color_list.size() - 1; i >= 0; i--)
{
ci = (ColorIndex) color_list.get(i);
line_buffer.insert(ci.getIndex(), colors[ci.getColor()]);
}
**/
if(color == 4)
{
for (int i = 0; i < color_list.size(); i++)
{
ci = (ColorIndex) color_list.get(i);
//if (color_list.contains(i+1))
if (i < color_list.size() + 1)
{
cip = (ColorIndex) color_list.get(i);
color_buffer.append("|<Style fromChar=\""+(ci.getIndexTrim(ltrimCnt, line_buffer.length()) + page_characters)+"\" toChar=\""+(cip.getIndexTrim(ltrimCnt,line_buffer.length()) + page_characters + 1)+"\" color=\""+colors[color][0][ci.getColor()]+"\"/>");
}
else
{
color_buffer.append("|<Style fromChar=\""+(ci.getIndexTrim(ltrimCnt, line_buffer.length()) + page_characters)+"\" toChar=\""+((line_buffer.length() +1) + page_characters)+"\" color=\""+colors[color][0][ci.getColor()]+"\"/>");
}
}
}
else
{
for (int i = color_list.size() - 1; i >= 0; i--)
{
ci = (ColorIndex) color_list.get(i);
line_buffer.insert(ci.getIndexTrim(ltrimCnt, line_buffer.length()), (i > 0 ? colors[color][1][0] : "") + colors[color][0][ci.getColor()]);
if (i == 0)
line_buffer.append(colors[color][1][0]);
}
}
}
// String line = line_buffer.toString();
String line = null;
if(color == 4) {
line = color_buffer.toString();
}
else
{
line = line_buffer.toString();
}
if (color == 1)
{
line = line.trim();
if (line.length() > 0)
// line = colors[7] + line;
line = colors[color][0][7] + line;
}
return line;
}
//DM30072004 081.7 int07 add
public void clearEnhancements()
{
page_modifications.clear();
use = false;
display_row = 0;
display_column = 0;
active_set = CharSet.getActive_G0_Set(0, 0, 0);
active_national_set = CharSet.getActiveNationalSubset(0, 0, 0);
}
//analyze triplets etc.
//DM30072004 081.7 int07 add
public void setEnhancements(byte packet[], int row, int character_set)
{
int val, mapping, position = 0, code;
byte address, mode, data, designation;
designation = bytereverse((byte)((0xF & hamming_8_4(packet[6]))<<4));
//Common.setMessage("row " + row + " /designation " + designation);
if ((row == 29 && designation == 0) || (row == 29 && designation == 4) || (row == 28 && designation == 4))
{
// read triplet 1
val = hamming_24_18(packet, 7);
code = val<<3;
if (row == 28 && designation == 0 && (0x3F800 & val) != 0)
return; // not X/28/0 format 1
// read triplet 2
val = hamming_24_18(packet, 10);
code |= (7 & val>>15);
//primary set
mapping = 0xFE & bytereverse((byte)(0x7F & code>>7));
page_modifications.put("primary_set", "" + (0xF & mapping>>4));
if (row != 29)
page_modifications.put("primary_national_set", "" + character_set);
//secondary set
mapping = 0xFE & bytereverse((byte)(0x7F & code));
page_modifications.put("secondary_set", "" + (0xF & mapping>>4));
page_modifications.put("secondary_national_set", "" + (7 & mapping>>1));
}
if (row != 26)
return;
for (int a = 7; a < 46; a += 3)
{
val = hamming_24_18(packet, a);
address = bytereverse( (byte)(0xFC & val>>10));
mode = bytereverse( (byte)(0xF8 & val>>4));
data = bytereverse( (byte)(0xFE & val<<1));
/**
Common.setMessage("triplet " + a + " / " + Integer.toBinaryString(val));
Common.setMessage(" address " + address );
Common.setMessage(" mode " + mode );
Common.setMessage(" data " + data );
**/
if (address >= 40) //40..63 means row 24,1..23
{
if (address == 63 && mode == 31) //termination
break;
if (mode != 4 && mode != 1)
{
use = false;
continue;
}
display_row = address == 40 ? 0 : address - 40;
display_column = mode == 1 ? 0 : data;
use = true;
}
else //0..39 means column 0..39
{
if (!use)
continue;
display_column = address;
String str = "";
if (mode == 15) //char from G2 set
str += (char)CharSet.getActive_G2_Set(0, character_set, display_row)[data];
else if (mode == 16) //char from G0 set w/o diacr.
str += (char)CharSet.getActive_G0_Set(0, character_set, display_row)[data];
//combination fixed table (because it won't work here when combine unicode chars)
else if (mode > 16) //char from G0 set w/ diacr.
str += (char)CharSet.getCombinedCharacter(data, mode & 0xF);
else
continue;
position = display_row<<16 | display_column;
page_modifications.put("" + position, str);
/**
Common.setMessage("replaced char " + str + " /m " + mode + " /row " + display_row + " /col " + display_column);
**/
}
}
}
/**
*
*/
private class ColorIndex {
private int index;
private int color;
public ColorIndex(int val_1, int val_2)
{
index = val_1;
color = val_2;
}
public int getIndex()
{
return index;
}
public int getColor()
{
return color;
}
public int getIndexTrim(int ltrim, int length)
{
int value;
if ( index - ltrim < 0 )
{
value = 0;
}
else if ( index - ltrim > length )
{
value = length;
}
else {
value = index-ltrim;
}
return value;
}
}
///////////////////////
/**
*
*/
private byte[] TTX_TS_Packet = {
0x47, 0x40, (byte)0x9F, 0x10, // TS header - PID 0x9F - count 0
0x00, 0x00, 0x01, (byte)0xBD, // pes id
0x00, (byte)0xB2, // pes length, fixed - matching 3 rows (0 + 2 variable)
(byte)0x84, (byte)0x80, // flags
0x24, // pes extension length (36 bytes)
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF, //psb with PTS
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
0x10, // TTX identifier
// 3x header 100
//update=0, erase=1, interrupt=0, magazine=1, page_number=00, suppressed_head=0, subpage_number=0000, news=0, inhibit=0, character_set=0, subtitle=0, magazine_serial=1
// 022C E7E4 40A8 A8A8 A80B A8A8 A840 - VBI 7 - Header row 0 - mag 1 page 00
0x02, 0x2C, (byte)0xE7, (byte)0xE4, 0x40, (byte)0xA8, (byte)0xA8,
(byte)0xA8, (byte)0xA8, 0x0B, (byte)0xA8, (byte)0xA8, (byte)0xA8, 0x40, // 1-00-00 14 bytes
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 16 String row 0
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 17- 31 String row 0
// 022C E8E4 40A8 A8A8 A80B A8A8 A840 - VBI 8 - Header row 0 - mag 1 page 00
0x02, 0x2C, (byte)0xE8, (byte)0xE4, 0x40, (byte)0xA8, (byte)0xA8,
(byte)0xA8, (byte)0xA8, 0x0B, (byte)0xA8, (byte)0xA8, (byte)0xA8, 0x40, // 1-00-00 14 bytes
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 16 String row 0
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 17- 31 String row 0
// 022C E9E4 40A8 A8A8 A80B A8A8 A840 - VBI 9 - Header row 0 - mag 1 page 00
0x02, 0x2C, (byte)0xE9, (byte)0xE4, 0x40, (byte)0xA8, (byte)0xA8,
(byte)0xA8, (byte)0xA8, 0x0B, (byte)0xA8, (byte)0xA8, (byte)0xA8, 0x40, // 1-00-00 14 bytes
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 16 String row 0
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 // 17- 31 String row 0
};
/**
*
*/
private byte[][][] TTX_Row = {
{
{
// 032C E8E4 4031 - VBI 8 - run in - row 20
0x03, 0x2C, (byte)0xE8, (byte)0xE4, (byte)0x40, (byte)0x31, // 1-20-50 6 bytes
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 19 String row 22
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 // 20- 39 String row 22
},{
// 032C E9E4 E331 - VBI 9 - run in - row 21
0x03, 0x2C, (byte)0xE9, (byte)0xE4, (byte)0xE3, (byte)0x31, // 1-21-50 6 bytes
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 19 String row 22
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 // 20- 39 String row 22
},{
// 032C EAE4 40D9 - VBI 10 - run in - row 22
0x03, 0x2C, (byte)0xEA, (byte)0xE4, (byte)0x40, (byte)0xD9, // 1-22-50 6 bytes
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 19 String row 22
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 // 20- 39 String row 22
},{
// 032C EBE4 E3D9 - VBI 11 - run in - row 23
0x03, 0x2C, (byte)0xEB, (byte)0xE4, (byte)0xE3, (byte)0xD9, // 1-23-50 6 bytes
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 19 String row 23
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 // 20- 39 String row 23
}
},{
{
// 032C E8E4 400B - VBI 8 - run in - row 16
0x03, 0x2C, (byte)0xE8, (byte)0xE4, (byte)0x40, (byte)0x0B, // 1-16-50 6 bytes
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 19 String row 16
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 // 20- 39 String row 16
},{
// 032C E9E4 40E3 - VBI 9 - run in - row 18
0x03, 0x2C, (byte)0xE9, (byte)0xE4, (byte)0x40, (byte)0xE3, // 1-18-50 6 bytes
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 19 String row 18
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 // 20- 39 String row 18
},{
// 032C EAE4 4031 - VBI 10 - run in - row 20
0x03, 0x2C, (byte)0xEA, (byte)0xE4, (byte)0x40, (byte)0x31, // 1-20-50 6 bytes
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 19 String row 20
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 // 20- 39 String row 20
},{
// 032C EBE4 40D9 - VBI 11 - run in - row 22
0x03, 0x2C, (byte)0xEB, (byte)0xE4, (byte)0x40, (byte)0xD9, // 1-22-50 6 bytes
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 19 String row 22
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 // 20- 39 String row 22
}
}
};
/**
*
*/
private byte[] TTX_Heading150Row = {
//update=1, erase=1, interrupt=0, magazine=1, page_number=50, suppressed_head=1, subpage_number=0000, news=0, inhibit=0, character_set=0, subtitle=1, magazine_serial=1
// 032C E7E4 40A8 A8CE A80B A80B 7A40 - VBI 7 - Header row 0 - mag 1 page 50
0x03, 0x2C, (byte)0xE7, (byte)0xE4, 0x40, (byte)0xA8, (byte)0xA8, (byte)0xCE, (byte)0xA8, 0x0B, (byte)0xA8, 0x0B, 0x7A, 0x40, // 1-00-50 14 bytes
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 16 String row 0
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 // 17- 31 String row 0
};
/**
*
*/
private byte[] TTX_PaddingRow = {
// FF 2C FF...
(byte)0xFF, 0x2C,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF
};
/**
*
*/
public byte[] getTTXPadding_TSPacket(int ts_count, byte[] pts_value)
{
byte[] ttx1 = new byte[TTX_TS_Packet.length * 2];
//default page = 100, use as is
System.arraycopy(TTX_TS_Packet, 0, ttx1, 0, TTX_TS_Packet.length);
System.arraycopy(TTX_TS_Packet, 0, ttx1, TTX_TS_Packet.length, TTX_TS_Packet.length);
//ts packet count
ttx1[3] = (byte) (0x10 | 0xF & ts_count);
ttx1[0xBF] = (byte) (0x10 | 0xF & (ts_count + 1));
//pts value
System.arraycopy(pts_value, 0, ttx1, 13, 5);
System.arraycopy(pts_value, 0, ttx1, 0xC9, 5);
int[] row_pos = { 0x32, 0x60, 0x8E, 0xEE, 0x11C, 0x14A }; //pos start for 6 rows
//insert padding
for (int i = 1; i < 6; i++)
System.arraycopy(TTX_PaddingRow, 0, ttx1, row_pos[i], TTX_PaddingRow.length);
return ttx1;
}
/**
*
*/
public byte[] getTTX_TSPacket(ArrayList rowList, int ts_count, byte[] pts_value)
{
byte[] ttx1 = new byte[TTX_TS_Packet.length * 2];
//default page = 100, works also as termination of 150
System.arraycopy(TTX_TS_Packet, 0, ttx1, 0, TTX_TS_Packet.length);
System.arraycopy(TTX_TS_Packet, 0, ttx1, TTX_TS_Packet.length, TTX_TS_Packet.length);
//ts packet count
ttx1[3] = (byte) (0x10 | 0xF & ts_count);
ttx1[0xBF] = (byte) (0x10 | 0xF & (ts_count + 1));
//pts value
System.arraycopy(pts_value, 0, ttx1, 13, 5);
System.arraycopy(pts_value, 0, ttx1, 0xC9, 5);
byte[] row;
int[] row_pos = { 0x32, 0x60, 0x8E, 0xEE, 0x11C, 0x14A }; //pos start for 6 rows
int doubleheight = 1;
//replace row 0 with header page 150
System.arraycopy(TTX_Heading150Row, 0, ttx1, row_pos[0], TTX_Heading150Row.length);
//character_set mapping
int control_bits = ((Integer) mapping_table.get("subset")).intValue()<<1;
//magazine serial
control_bits |= 1;
ttx1[row_pos[0] + 13] = hamming_8_4_values[(0xFF & bytereverse(control_bits))>>4];
//insert 1 string per row
for (int i = 0, j = rowList.size(); i < j; i++)
{
row = setCharacterMapping(rowList.get(i).toString());
row = centerString(row, doubleheight);
//row = centerString(rowList.get(i).toString().getBytes(), doubleheight);
for (int k = 0; k < row.length; k++)
row[k] = bytereverse(parity(row[k])); //make them TTX compatible
System.arraycopy(TTX_Row[doubleheight][TTX_Row[doubleheight].length - j + i], 0, ttx1, row_pos[i + 1], TTX_Row[doubleheight][TTX_Row[doubleheight].length - j + i].length); //insert row
System.arraycopy(row, 0, ttx1, row_pos[i + 1] + 6, row.length); // insert string
}
//prevent duplicate vbi line number
for (int i = 0, vbi = 0xE7; i < row_pos.length; i++, vbi++)
ttx1[row_pos[i] + 2] = (byte) vbi;
//insert padding
// for (int i = rowList.size() + 1; i < 4; i++)
// System.arraycopy(TTX_PaddingRow, 0, ttx1, row_pos[i + 2], TTX_PaddingRow.length);
return ttx1;
}
/**
*
*/
private byte[] setCharacterMapping(String str)
{
char[] ch = str.toCharArray();
byte[] row = new byte[ch.length];
String tmp;
for (int i = 0, j = ch.length; i < j; i++)
{
tmp = String.valueOf((short) ch[i]);
if (mapping_table.containsKey(tmp))
row[i] = ((Integer) mapping_table.get(tmp)).byteValue();
else
row[i] = (byte) ch[i];
}
return row;
}
/**
* Get the number of spaces to calculate color places after trim
*/
private int ltrimCount(String str)
{
if (str == null || str.length() < 1)
return 0;
int i = 0;
int j = str.length() -1;
while (i <= j && str.charAt(i) == ' ')
i++;
int value = i-1;
return value;
}
/**
*
*/
private byte[] centerString(byte[] row, int doubleheight)
{
int max_length = 40;
byte[] new_row = new byte[max_length];
int row_length = row.length;
if (row_length > max_length - doubleheight)
row_length = max_length - doubleheight;
int leadg_space = doubleheight + ((new_row.length - row_length) / 2);
int trail_space = max_length - row_length - leadg_space;
Arrays.fill(new_row, (byte) 0x20); //set all spaces
if (doubleheight == 1)
new_row[0] = 0x0D; // double height
//string length must not exceed 38,39 chars for boxing
while (leadg_space - doubleheight < 2)
{
leadg_space++;
trail_space--;
if (leadg_space + row_length > 40)
row_length--;
}
System.arraycopy(row, 0, new_row, leadg_space, row_length); //copy string
new_row[leadg_space - 2] = 0x0B; // start box
new_row[leadg_space - 1] = 0x0B; // start box rpt
for (int i = leadg_space + row_length, j = 0; i < max_length && j < 2; i++, j++)
new_row[leadg_space + row_length] = 0x0A; // end box
return new_row;
}
//
private Hashtable mapping_table = new Hashtable();
/**
*
*/
public void setMappingTable()
{
mapping_table.clear();
//mapping requires x/28 or M/29 rows - cant be handled automatically
int mapping = Common.getSettings().getIntProperty(Keys.KEY_TtxLanguagePair) - 1;
mapping = mapping < 0 ? 0 : mapping;
int subset = mapping == 0 ? 4 : 0; //DE
mapping_table.put("mapping", new Integer(mapping));
mapping_table.put("subset", new Integer(subset));
active_set = CharSet.getActive_G0_Set(mapping, subset, 0);
active_national_set = CharSet.getActiveNationalSubset(mapping, subset, 0);
for (int i = 0x20, j = active_set.length - 1; i < j; i++) //0x20 to 0x7E (0x7F is full sign)
mapping_table.put(String.valueOf(active_set[i]), new Integer(i));
int[] map = { 0x23, 0x24, 0x40, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x7B, 0x7C, 0x7D, 0x7E };
for (int i = 0, j = active_national_set.length; subset >= 0 && i < j; i++)
mapping_table.put(String.valueOf(active_national_set[i]), new Integer(map[i]));
}
}