00001
00002
00003
00004 #include <cassert>
00005 #include <cstdlib>
00006
00007 #include "mythcontext.h"
00008 #include "cc708decoder.h"
00009
00010 #define LOC QString("CC708: ")
00011 #define LOC_ERR QString("CC708, Error: ")
00012
00013 #define DEBUG_CC_SERVICE 0
00014 #define DEBUG_CC_SERVICE_2 0
00015 #define DEBUG_CC_RAWPACKET 0
00016 #define DEBUG_CC_SERVICE_BLOCK 0
00017
00018 typedef enum
00019 {
00020 NTSC_CC_f1 = 0,
00021 NTSC_CC_f2 = 1,
00022 DTVCC_PACKET_DATA = 2,
00023 DTVCC_PACKET_START = 3,
00024 };
00025
00026 const char* cc_types[4] =
00027 {
00028 "NTSC line 21 field 1 closed captions"
00029 "NTSC line 21 field 2 closed captions"
00030 "DTVCC Channel Packet Data"
00031 "DTVCC Channel Packet Start"
00032 };
00033
00034 static void parse_cc_packet(CC708Reader *cb_cbs, CaptionPacket *pkt);
00035
00036 CC708Reader::CC708Reader()
00037 {
00038 for (uint i=0; i<64; i++)
00039 {
00040 buf_alloc[i] = 512;
00041 buf[i] = (unsigned char*) malloc(buf_alloc[i]);
00042 buf_size[i] = 0;
00043 delayed[i] = 0;
00044
00045 temp_str_alloc[i] = 512;
00046 temp_str_size[i] = 0;
00047 temp_str[i] = (short*) malloc(temp_str_alloc[i] * sizeof(short));
00048 }
00049 }
00050
00051 CC708Reader::~CC708Reader()
00052 {
00053 for (uint i=0; i<64; i++)
00054 {
00055 free(buf[i]);
00056 free(temp_str[i]);
00057 }
00058 }
00059
00060 void CC708Decoder::decode_cc_data(uint cc_type, uint data1, uint data2)
00061 {
00062 if (DTVCC_PACKET_START == cc_type)
00063 {
00064
00065
00066
00067 if (partialPacket.size && reader)
00068 parse_cc_packet(reader, &partialPacket);
00069
00070 partialPacket.data[0] = data1;
00071 partialPacket.data[1] = data2;
00072 partialPacket.size = 2;
00073 }
00074 else if (DTVCC_PACKET_DATA == cc_type)
00075 {
00076
00077
00078
00079 partialPacket.data[partialPacket.size + 0] = data1;
00080 partialPacket.data[partialPacket.size + 1] = data2;
00081 partialPacket.size += 2;
00082 }
00083 }
00084
00085 #define DEBUG_CAPTIONS 0
00086
00087 typedef enum
00088 {
00089 NUL = 0x00,
00090 EXT1 = 0x01,
00091 ETX = 0x03,
00092 BS = 0x08,
00093 FF = 0x0C,
00094 CR = 0x0D,
00095 HCR = 0x0E,
00096 P16 = 0x18,
00097 } C0;
00098
00099 typedef enum
00100 {
00101 CW0=0x80, CW1, CW2, CW3, CW4, CW5, CW6, CW7,
00102 CLW, DSW, HDW, TGW, DLW, DLY, DLC, RST,
00103 SPA=0x90, SPC, SPL, SWA=0x97,
00104 DF0, DF1, DF2, DF3, DF4, DF5, DF6, DF7,
00105 } C1;
00106
00107 extern ushort CCtableG0[0x60];
00108 extern ushort CCtableG1[0x60];
00109 extern ushort CCtableG2[0x60];
00110 extern ushort CCtableG3[0x60];
00111
00112 static void append_character(CC708Reader *cc, uint service_num, short ch);
00113 static void parse_cc_service_stream(CC708Reader *cc, uint service_num);
00114 static int handle_cc_c0_ext1_p16(CC708Reader *cc, uint service_num, int i);
00115 static int handle_cc_c1(CC708Reader *cc, uint service_num, int i);
00116 static int handle_cc_c2(CC708Reader *cc, uint service_num, int i);
00117 static int handle_cc_c3(CC708Reader *cc, uint service_num, int i);
00118
00119 #define SEND_STR \
00120 do { \
00121 if (cc->temp_str_size[service_num]) \
00122 { \
00123 cc->TextWrite(service_num, \
00124 cc->temp_str[service_num], \
00125 cc->temp_str_size[service_num]); \
00126 cc->temp_str_size[service_num] = 0; \
00127 } \
00128 } while (0)
00129
00130 static void parse_cc_service_stream(CC708Reader* cc, uint service_num)
00131 {
00132 const int blk_size = cc->buf_size[service_num];
00133 int blk_start = 0, dlc_loc = 0, rst_loc = 0, i = 0;
00134
00135
00136 for (i = 0; i < blk_size; i++)
00137 {
00138 if (RST == cc->buf[service_num][i])
00139 rst_loc = dlc_loc = i;
00140 else if (DLC == cc->buf[service_num][i])
00141 dlc_loc = i;
00142 }
00143
00144
00145 if (rst_loc)
00146 {
00147 cc->Reset(service_num);
00148 cc->delayed[service_num] = 0;
00149 blk_start = rst_loc + 1;
00150 }
00151
00152
00153 if (dlc_loc && cc->delayed[service_num])
00154 {
00155 cc->DelayCancel(service_num);
00156 cc->delayed[service_num] = 0;
00157 }
00158
00159
00160 if (cc->delayed[service_num] && blk_size >= 126)
00161 {
00162 cc->DelayCancel(service_num);
00163 cc->delayed[service_num] = 0;
00164 dlc_loc = blk_size - 1;
00165 }
00166
00167
00168
00169
00170
00171
00172
00173 for (int i = (cc->delayed[service_num]) ? blk_size : blk_start;
00174 i < blk_size; )
00175 {
00176 const int old_i = i;
00177 const int code = cc->buf[service_num][i];
00178 if (0x0 == code)
00179 {
00180 i++;
00181 }
00182 else if (code <= 0x1f)
00183 {
00184
00185 i = handle_cc_c0_ext1_p16(cc, service_num, i);
00186 }
00187 else if (code <= 0x7f)
00188 {
00189
00190 short character = CCtableG0[code-0x20];
00191 append_character(cc, service_num, character);
00192 i++;
00193 }
00194 else if (code <= 0x9f)
00195 {
00196
00197 i = handle_cc_c1(cc, service_num, i);
00198 }
00199 else if (code <= 0xff)
00200 {
00201
00202 short character = CCtableG1[code-0xA0];
00203 append_character(cc, service_num, character);
00204 i++;
00205 }
00206
00207 #if DEBUG_CC_SERVICE
00208 fprintf(stderr, "i %i, blk_size %i\n", i, blk_size);
00209 #endif
00210
00211
00212 if (old_i == i)
00213 {
00214 #if DEBUG_CC_SERVICE
00215 fprintf(stderr, "old_i == i == %1\n", i);
00216 for (int i=0; i < blk_size; i++)
00217 fprintf(stderr, "0x%x ", cc->buf[service_num][i]);
00218 fprintf(stderr, "\n");
00219 #endif
00220 if (blk_size - i > 10)
00221 {
00222 fprintf(stderr, "eia-708 decoding error...");
00223 cc->Reset(service_num);
00224 cc->delayed[service_num] = 0;
00225 i = cc->buf_size[service_num];
00226 }
00227
00228 break;
00229 }
00230 else if (cc->delayed[service_num] && dlc_loc < i)
00231 {
00232
00233 break;
00234 }
00235 else if (cc->delayed[service_num])
00236 {
00237
00238 cc->DelayCancel(service_num);
00239 cc->delayed[service_num] = 0;
00240 }
00241 }
00242
00243
00244 assert(((int)blk_size - i) >= 0);
00245 if ((blk_size - i) > 0)
00246 {
00247 memmove(cc->buf[service_num], cc->buf[service_num] + i,
00248 blk_size - i);
00249 cc->buf_size[service_num] -= i;
00250 }
00251 else
00252 {
00253 if (0 != (blk_size - i))
00254 {
00255 fprintf(stderr, "parse_cc_service_stream buffer error "
00256 "i(%i) buf_size(%i)\n", i, blk_size);
00257 for (i=0; i < blk_size; i++)
00258 fprintf(stderr, "0x%x ", cc->buf[service_num][i]);
00259 fprintf(stderr, "\n");
00260 }
00261 cc->buf_size[service_num] = 0;
00262 }
00263 }
00264
00265 static int handle_cc_c0_ext1_p16(CC708Reader* cc, uint service_num, int i)
00266 {
00267
00268 const int code = cc->buf[service_num][i];
00269 if (code<=0xf)
00270 {
00271
00272 if (ETX==code)
00273 SEND_STR;
00274 else if (BS==code)
00275 append_character(cc, service_num, 0x08);
00276 else if (FF==code)
00277 append_character(cc, service_num, 0x0c);
00278 else if (CR==code)
00279 append_character(cc, service_num, 0x0d);
00280 else if (HCR==code)
00281 append_character(cc, service_num, 0x0d);
00282 i++;
00283 }
00284 else if (code<=0x17)
00285 {
00286
00287 const int blk_size = cc->buf_size[service_num];
00288 if (EXT1==code && ((i+1)<blk_size))
00289 {
00290 const int code2 = cc->buf[service_num][i+1];
00291 if (code2<=0x1f)
00292 {
00293
00294 i = handle_cc_c2(cc, service_num, i+1);
00295 }
00296 else if (code2<=0x7f)
00297 {
00298
00299 append_character(cc, service_num, CCtableG2[code2-0x20]);
00300 i+=2;
00301 }
00302 else if (code2<=0x9f)
00303 {
00304
00305 i = handle_cc_c3(cc, service_num, i);
00306 }
00307 else if (code2<=0xff)
00308 {
00309
00310 append_character(cc, service_num, CCtableG3[code2-0xA0]);
00311 i+=2;
00312 }
00313 }
00314 else if ((i+1)<blk_size)
00315 i+=2;
00316 }
00317 else if (code<=0x1f)
00318 {
00319
00320 const int blk_size = cc->buf_size[service_num];
00321 if (P16==code && ((i+2)<blk_size))
00322 {
00323
00324 }
00325 if ((i+2)<blk_size)
00326 i+=3;
00327 }
00328 return i;
00329 }
00330
00331 static int handle_cc_c1(CC708Reader* cc, uint service_num, int i)
00332 {
00333 const int blk_size = cc->buf_size[service_num];
00334 const int code = cc->buf[service_num][i];
00335
00336 const unsigned char* blk_buf = cc->buf[service_num];
00337 if (code<=CW7)
00338 {
00339 SEND_STR;
00340 cc->SetCurrentWindow(service_num, code-0x80);
00341 i+=1;
00342 }
00343 else if (DLC == cc->buf[service_num][i])
00344 {
00345
00346
00347
00348
00349 i+=1;
00350 }
00351 else if (code>=CLW && code<=DLY && ((i+1)<blk_size))
00352 {
00353 int param1 = blk_buf[i+1];
00354 SEND_STR;
00355 if (CLW==code)
00356 cc->ClearWindows(service_num, param1);
00357 else if (DSW==code)
00358 cc->DisplayWindows(service_num, param1);
00359 else if (HDW==code)
00360 cc->HideWindows(service_num, param1);
00361 else if (TGW==code)
00362 cc->ToggleWindows(service_num, param1);
00363 else if (DLW==code)
00364 cc->DeleteWindows(service_num, param1);
00365 else if (DLY==code)
00366 {
00367 cc->Delay(service_num, param1);
00368 cc->delayed[service_num] = 1;
00369 }
00370 i+=2;
00371 }
00372 else if (SPA==code && ((i+2)<blk_size))
00373 {
00374 int pen_size = (blk_buf[i+1] ) & 0x3;
00375 int offset = (blk_buf[i+1]>>2) & 0x3;
00376 int text_tag = (blk_buf[i+1]>>4) & 0xf;
00377 int font_tag = (blk_buf[i+2] ) & 0x7;
00378 int edge_type = (blk_buf[i+2]>>3) & 0x7;
00379 int underline = (blk_buf[i+2]>>4) & 0x1;
00380 int italic = (blk_buf[i+2]>>5) & 0x1;
00381 SEND_STR;
00382 cc->SetPenAttributes(service_num, pen_size, offset, text_tag,
00383 font_tag, edge_type, underline, italic);
00384 i+=3;
00385 }
00386 else if (SPC==code && ((i+3)<blk_size))
00387 {
00388 int fg_color = (blk_buf[i+1] ) & 0x3f;
00389 int fg_opacity = (blk_buf[i+1]>>6) & 0x03;
00390 int bg_color = (blk_buf[i+2] ) & 0x3f;
00391 int bg_opacity = (blk_buf[i+2]>>6) & 0x03;
00392 int edge_color = (blk_buf[i+3]>>6) & 0x3f;
00393 SEND_STR;
00394 cc->SetPenColor(service_num, fg_color, fg_opacity,
00395 bg_color, bg_opacity, edge_color);
00396 i+=4;
00397 }
00398 else if (SPL==code && ((i+2)<blk_size))
00399 {
00400 int row = blk_buf[i+1] & 0x0f;
00401 int col = blk_buf[i+2] & 0x3f;
00402 SEND_STR;
00403 cc->SetPenLocation(service_num, row, col);
00404 i+=3;
00405 }
00406 else if (SWA==code && ((i+4)<blk_size))
00407 {
00408 int fill_color = (blk_buf[i+1] ) & 0x3f;
00409 int fill_opacity = (blk_buf[i+1]>>6) & 0x03;
00410 int border_color = (blk_buf[i+2] ) & 0x3f;
00411 int border_type01 = (blk_buf[i+2]>>6) & 0x03;
00412 int justify = (blk_buf[i+3] ) & 0x03;
00413 int scroll_dir = (blk_buf[i+3]>>2) & 0x03;
00414 int print_dir = (blk_buf[i+3]>>4) & 0x03;
00415 int word_wrap = (blk_buf[i+3]>>6) & 0x01;
00416 int border_type = (blk_buf[i+3]>>5) | border_type01;
00417 int display_eff = (blk_buf[i+4] ) & 0x03;
00418 int effect_dir = (blk_buf[i+4]>>2) & 0x03;
00419 int effect_speed = (blk_buf[i+4]>>4) & 0x0f;
00420 SEND_STR;
00421 cc->SetWindowAttributes(
00422 service_num, fill_color, fill_opacity, border_color, border_type,
00423 scroll_dir, print_dir, effect_dir,
00424 display_eff, effect_speed, justify, word_wrap);
00425 i+=5;
00426 }
00427 else if ((code>=DF0) && (code<=DF7) && ((i+6)<blk_size))
00428 {
00429
00430 int priority = ( blk_buf[i+1] ) & 0x7;
00431 int col_lock = (blk_buf[i+1]>>3) & 0x1;
00432 int row_lock = (blk_buf[i+1]>>4) & 0x1;
00433 int visible = (blk_buf[i+1]>>5) & 0x1;
00434
00435 int anchor_vertical = blk_buf[i+2] & 0x7f;
00436 int relative_pos = (blk_buf[i+2]>>7);
00437
00438 int anchor_horizontal = blk_buf[i+3];
00439
00440 int row_count = blk_buf[i+4] & 0xf;
00441 int anchor_point = blk_buf[i+4]>>4;
00442
00443 int col_count = blk_buf[i+5] & 0x3f;
00444
00445 int pen_style = blk_buf[i+6] & 0x7;
00446 int win_style = (blk_buf[i+6]>>3) & 0x7;
00447 SEND_STR;
00448 cc->DefineWindow(service_num, code-0x98, priority, visible,
00449 anchor_point, relative_pos,
00450 anchor_vertical, anchor_horizontal,
00451 row_count, col_count, row_lock, col_lock,
00452 pen_style, win_style);
00453 i+=7;
00454 }
00455 #if DEBUG_CC_SERVICE
00456 else
00457 {
00458 fprintf(stderr, "handle_cc_c1: (NOT HANDLED) "
00459 "code(0x%02x) i(%i) blk_size(%i)\n", code, i, blk_size);
00460 }
00461 #endif
00462
00463 return i;
00464 }
00465
00466 static int handle_cc_c2(CC708Reader* cc, uint service_num, int i)
00467 {
00468 const int blk_size = cc->buf_size[service_num];
00469 const int code = cc->buf[service_num][i+1];
00470
00471 if ((code<=0x7) && ((i+1)<blk_size)){
00472 i+=2;
00473 SEND_STR;
00474 }
00475 else if ((code<=0xf) && ((i+2)<blk_size))
00476 {
00477 i+=3;
00478 SEND_STR;
00479 }
00480 else if ((code<=0x17) && ((i+3)<blk_size))
00481 {
00482 i+=4;
00483 SEND_STR;
00484 }
00485 else if ((code<=0x1f) && ((i+4)<blk_size))
00486 {
00487 i+=5;
00488 SEND_STR;
00489 }
00490 return i;
00491 }
00492
00493 static int handle_cc_c3(CC708Reader* cc, uint service_num, int i)
00494 {
00495 const unsigned char* blk_buf = cc->buf[service_num];
00496 const int blk_size = cc->buf_size[service_num];
00497 const int code = cc->buf[service_num][i+1];
00498
00499 if ((code<=0x87) && ((i+5)<blk_size))
00500 {
00501 i+=6;
00502 SEND_STR;
00503 }
00504 else if ((code<=0x8f) && ((i+6)<blk_size))
00505 {
00506 i+=7;
00507 SEND_STR;
00508 }
00509 else if ((i+2)<blk_size)
00510 {
00511 int length = blk_buf[i+2]&0x3f;
00512 if ((i+length)<blk_size)
00513 {
00514 i+=1+length;
00515 SEND_STR;
00516 }
00517 }
00518 return i;
00519 }
00520
00521 static void rightsize_buf(CC708Reader* cc, uint service_num, uint block_size)
00522 {
00523 uint min_new_size = block_size + cc->buf_size[service_num];
00524 if (min_new_size >= cc->buf_alloc[service_num])
00525 {
00526 uint new_alloc = cc->buf_alloc[service_num];
00527 for (uint i = 0; (i < 32) && (new_alloc <= min_new_size); i++)
00528 new_alloc *= 2;
00529
00530 cc->buf[service_num] =
00531 (unsigned char*) realloc(cc->buf[service_num], new_alloc);
00532 cc->buf_alloc[service_num] = (cc->buf[service_num]) ? new_alloc : 0;
00533
00534 #if DEBUG_CC_SERVICE_2
00535 fprintf(stderr, "rightsize_buf: srv %i to %i bytes",
00536 service_num, cc->buf_alloc[service_num]);
00537 #endif
00538 }
00539 assert(min_new_size < cc->buf_alloc[service_num]);
00540 }
00541
00542 static void append_cc(CC708Reader* cc, uint service_num,
00543 const unsigned char* blk_buf, int block_size)
00544 {
00545 assert(cc);
00546 rightsize_buf(cc, service_num, block_size);
00547
00548 memcpy(cc->buf[service_num] + cc->buf_size[service_num],
00549 blk_buf, block_size);
00550
00551 cc->buf_size[service_num] += block_size;
00552 #if DEBUG_CC_SERVICE_2
00553 {
00554 uint i;
00555 fprintf(stderr, "append_cc: ");
00556 for (i = 0; i < cc->buf_size[service_num]; i++)
00557 fprintf(stderr, "0x%x ", cc->buf[service_num][i]);
00558 fprintf(stderr, "\n");
00559 }
00560 #endif
00561 parse_cc_service_stream(cc, service_num);
00562 }
00563
00564 static void parse_cc_packet(CC708Reader* cb_cbs, CaptionPacket* pkt)
00565 {
00566 const unsigned char* pkt_buf = pkt->data;
00567 const int pkt_size = pkt->size;
00568 int off = 1;
00569 int service_number = 0;
00570 int block_data_offset = 0;
00571 int len = ((((int)pkt_buf[0]) & 0x3f)<<1) - 1;
00572 int seq_num = (((int)pkt_buf[0])>>6)&0x3;
00573
00574 if (len < 0)
00575 return;
00576 #if DEBUG_CC_RAWPACKET
00577 #else
00578 if (len > pkt_size)
00579 #endif
00580 {
00581 int j;
00582 fprintf(stderr, "CC length(%2i) seq_num(%i) ", len, seq_num);
00583 for (j = 0; j < pkt_size; j++)
00584 fprintf(stderr, "0x%x ", pkt_buf[j]);
00585 fprintf(stderr, "\n");
00586 }
00587
00588 assert(pkt_size<127);
00589
00590 while (pkt_buf[off] && off<pkt_size)
00591 {
00592 int block_size = pkt_buf[off] & 0x1f;
00593 service_number = (pkt_buf[off]>>5) & 0x7;
00594 block_data_offset = (0x7==service_number && block_size!=0) ?
00595 off+2 : off+1;
00596 #if DEBUG_CC_SERVICE_BLOCK
00597 fprintf(stderr, "service_block size(%i) num(%i) off(%i) ",
00598 block_size, service_number, block_data_offset);
00599 #endif
00600 if (off+2 == block_data_offset)
00601 {
00602 int extended_service_number = pkt_buf[off+2] & 0x3f;
00603 #if DEBUG_CC_SERVICE_BLOCK
00604 fprintf(stderr, "ext_svc_num(%i) ", extended_service_number);
00605 #endif
00606 service_number = extended_service_number;
00607 }
00608 if (service_number)
00609 {
00610 #if DEBUG_CC_SERVICE
00611 int i;
00612 if (!(2==block_size &&
00613 0==pkt_buf[block_data_offset] &&
00614 0==pkt_buf[block_data_offset+1]))
00615 {
00616 fprintf(stderr, "service %i: ", service_number);
00617 for (i=0; i<block_size; i++)
00618 fprintf(stderr, "0x%x ", pkt_buf[block_data_offset+i]);
00619 fprintf(stderr, "\n");
00620 }
00621 #endif
00622 append_cc(cb_cbs, service_number,
00623 &pkt_buf[block_data_offset], block_size);
00624 }
00625 off+=block_size+1;
00626 }
00627 if (off<pkt_size)
00628 assert(pkt_buf[off]==0);
00629 }
00630
00631 static void append_character(CC708Reader *cc, uint service_num, short ch)
00632 {
00633 if (cc->temp_str_size[service_num]+2 > cc->temp_str_alloc[service_num])
00634 {
00635 int new_alloc = (cc->temp_str_alloc[service_num]) ?
00636 cc->temp_str_alloc[service_num] * 2 : 64;
00637
00638 cc->temp_str[service_num] = (short*)
00639 realloc(cc->temp_str[service_num], new_alloc * sizeof(short));
00640
00641 assert(cc->temp_str[service_num]);
00642 cc->temp_str_alloc[service_num] = new_alloc;
00643 }
00644
00645 if (cc->temp_str[service_num])
00646 {
00647 int i = cc->temp_str_size[service_num];
00648 cc->temp_str[service_num][i] = ch;
00649 cc->temp_str_size[service_num]++;
00650 }
00651 else
00652 {
00653 cc->temp_str_size[service_num] = 0;
00654 cc->temp_str_alloc[service_num]=0;
00655 }
00656 }
00657
00658 ushort CCtableG0[0x60] =
00659 {
00660
00661
00662 ' ', '!','\"', '#', '$', '%', '&', '\'',
00663 '(', ')', '*', '+', ',', '-', '.', '/',
00664 '0', '1', '2', '3', '4', '5', '6', '7',
00665 '8', '9', ':', ';', '<', '=', '>', '?',
00666
00667 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
00668 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
00669 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
00670 'X', 'Y', 'Z', '[', '\\',']', '^', '_',
00671
00672 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
00673 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
00674 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
00675 'x', 'y', 'z', '{', '|', '}', '~', 0x1d16,
00676 };
00677
00678 ushort CCtableG1[0x60] =
00679 {
00680
00681
00682 0xA0,
00683 '¡', '¢', '£', '¤', '¥', '¦', '§',
00684 '¨', '©', 'ª', '«', '¬', '', '®', '¯',
00685 '°', '±', '²', '³', '´', 'µ', '¶', '·',
00686 '¸', '¹', 'º', '»', '¼', '½', '¾', '¿',
00687
00688 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç',
00689 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï',
00690 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', '×',
00691 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'Þ', 'ß',
00692
00693 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç',
00694 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï',
00695 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', '÷',
00696 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'þ', 'ÿ',
00697 };
00698
00699 ushort CCtableG2[0x60] =
00700 {
00701 ' ',
00702 0xA0,
00703 0, 0,
00704 0, 0x2026,
00705 0, 0,
00706 0, 0,
00707 0x160,
00708 0x152, 0,
00709 0, 0,
00710 0x2DA, 0x2018,
00711 0x2019, 0x201c,
00712 0x201d, '*',
00713 0, 0,
00714 0, '#',
00715 0x161,
00716 0x153, '#',
00717 0, 0x178,
00718
00719
00720
00721
00722
00723 0, 0, 0, 0,
00724 0, 0, 0, 0,
00725 0, 0, 0, 0,
00726 0, 0, 0, 0,
00727
00728 0, 0, 0, 0,
00729 0, 0, 0, 0,
00730 0, 0, 0, 0,
00731 0, 0, 0, 0,
00732
00733 0, 0, 0, 0,
00734 0, 0, 0, 0,
00735 0, 0, 0, 0,
00736 0, 0, 0, 0,
00737
00738 0, 0,
00739 0, 0,
00740 0, 0,
00741 0x215b, 0x215c,
00742 0x215d, 0x215e,
00743 0x2502, 0x2510,
00744 0x2514, 0x2500,
00745 0x2518, 0x250c,
00746 };
00747
00748 ushort CCtableG3[0x60] =
00749 {
00750
00751 '#',
00752 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00753 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00754
00755 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00756 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00757
00758 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00759 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00760 };