OSDN Git Service

5cfe238dbb73b789a9f033dfd0bf1b1bf8f0bfda
[handbrake-jp/handbrake-jp-git.git] / libhb / deccc608sub.c
1 /*
2  * From ccextractor, leave this file as intact and close to the original as possible so that 
3  * it is easy to patch in fixes - even though this file contains code that we don't need.
4  *
5  * Note that the SRT sub generation from CC could be useful for mkv subs.
6  */
7 #include "hb.h"
8 #include "deccc608sub.h"
9
10 /*
11  * ccextractor static configuration variables.
12  */
13 static int debug_608 = 0;
14 static int trim_subs = 1;
15 static int nofontcolor = 0;
16 static enum encoding_type encoding = ENC_UTF_8;
17 static int cc_channel = 1;
18 static enum output_format write_format = OF_SRT;
19 static int sentence_cap = 1;
20 static int subs_delay = 0;
21 static LLONG screens_to_process = -1;
22 static int processed_enough = 0;
23 static int gui_mode_reports = 0;
24 static int norollup = 1;
25 static int direct_rollup = 0;
26
27 /*
28  * Get the time of the last buffer that we have received.
29  */
30 static LLONG get_fts(struct s_write *wb)
31 {
32     return wb->last_pts;
33 }
34
35 #define fatal(N, ...) // N
36 #define XMLRPC_APPEND(N, ...) // N
37
38 int     rowdata[] = {11,-1,1,2,3,4,12,13,14,15,5,6,7,8,9,10};
39 // Relationship between the first PAC byte and the row number
40
41 // The following enc_buffer is not used at the moment, if it does get used
42 // we need to bring it into the swrite struct. Same for "str".
43 #define INITIAL_ENC_BUFFER_CAPACITY             2048
44
45 unsigned char str[2048]; // Another generic general purpose buffer
46
47 #define GUARANTEE(wb, length) if (length>wb->enc_buffer_capacity)            \
48 {wb->enc_buffer_capacity*=2; wb->enc_buffer=(unsigned char*) realloc (wb->enc_buffer, wb->enc_buffer_capacity); \
49     if (wb->enc_buffer==NULL) { fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory, bailing out\n"); } \
50 }
51
52 const unsigned char pac2_attribs[][3]= // Color, font, ident
53 {
54     {COL_WHITE,     FONT_REGULAR,               0},  // 0x40 || 0x60 
55     {COL_WHITE,     FONT_UNDERLINED,            0},  // 0x41 || 0x61
56     {COL_GREEN,     FONT_REGULAR,               0},  // 0x42 || 0x62
57     {COL_GREEN,     FONT_UNDERLINED,            0},  // 0x43 || 0x63
58     {COL_BLUE,      FONT_REGULAR,               0},  // 0x44 || 0x64
59     {COL_BLUE,      FONT_UNDERLINED,            0},  // 0x45 || 0x65
60     {COL_CYAN,      FONT_REGULAR,               0},  // 0x46 || 0x66
61     {COL_CYAN,      FONT_UNDERLINED,            0},  // 0x47 || 0x67
62     {COL_RED,       FONT_REGULAR,               0},  // 0x48 || 0x68
63     {COL_RED,       FONT_UNDERLINED,            0},  // 0x49 || 0x69
64     {COL_YELLOW,    FONT_REGULAR,               0},  // 0x4a || 0x6a
65     {COL_YELLOW,    FONT_UNDERLINED,            0},  // 0x4b || 0x6b
66     {COL_MAGENTA,   FONT_REGULAR,               0},  // 0x4c || 0x6c
67     {COL_MAGENTA,   FONT_UNDERLINED,            0},  // 0x4d || 0x6d
68     {COL_WHITE,     FONT_ITALICS,               0},  // 0x4e || 0x6e
69     {COL_WHITE,     FONT_UNDERLINED_ITALICS,    0},  // 0x4f || 0x6f
70     {COL_WHITE,     FONT_REGULAR,               0},  // 0x50 || 0x70
71     {COL_WHITE,     FONT_UNDERLINED,            0},  // 0x51 || 0x71
72     {COL_WHITE,     FONT_REGULAR,               4},  // 0x52 || 0x72
73     {COL_WHITE,     FONT_UNDERLINED,            4},  // 0x53 || 0x73
74     {COL_WHITE,     FONT_REGULAR,               8},  // 0x54 || 0x74
75     {COL_WHITE,     FONT_UNDERLINED,            8},  // 0x55 || 0x75
76     {COL_WHITE,     FONT_REGULAR,               12}, // 0x56 || 0x76
77     {COL_WHITE,     FONT_UNDERLINED,            12}, // 0x57 || 0x77
78     {COL_WHITE,     FONT_REGULAR,               16}, // 0x58 || 0x78
79     {COL_WHITE,     FONT_UNDERLINED,            16}, // 0x59 || 0x79
80     {COL_WHITE,     FONT_REGULAR,               20}, // 0x5a || 0x7a
81     {COL_WHITE,     FONT_UNDERLINED,            20}, // 0x5b || 0x7b
82     {COL_WHITE,     FONT_REGULAR,               24}, // 0x5c || 0x7c
83     {COL_WHITE,     FONT_UNDERLINED,            24}, // 0x5d || 0x7d
84     {COL_WHITE,     FONT_REGULAR,               28}, // 0x5e || 0x7e
85     {COL_WHITE,     FONT_UNDERLINED,            28}  // 0x5f || 0x7f
86 };
87
88 // Preencoded strings
89 unsigned char encoded_crlf[16]; 
90 unsigned int encoded_crlf_length;
91 unsigned char encoded_br[16];
92 unsigned int encoded_br_length;
93
94 // Default color
95 unsigned char usercolor_rgb[8]="";
96 enum color_code default_color=COL_WHITE;
97
98 const char *sami_header= // TODO: Revise the <!-- comments
99 "<SAMI>\n\
100 <HEAD>\n\
101 <STYLE TYPE=\"text/css\">\n\
102 <!--\n\
103 P {margin-left: 16pt; margin-right: 16pt; margin-bottom: 16pt; margin-top: 16pt;\n\
104 text-align: center; font-size: 18pt; font-family: arial; font-weight: bold; color: #f0f0f0;}\n\
105 .UNKNOWNCC {Name:Unknown; lang:en-US; SAMIType:CC;}\n\
106 -->\n\
107 </STYLE>\n\
108 </HEAD>\n\n\
109 <BODY>\n";
110
111 const char *command_type[] =
112 {
113     "Unknown",
114     "EDM - EraseDisplayedMemory",
115     "RCL - ResumeCaptionLoading",
116     "EOC - End Of Caption",
117     "TO1 - Tab Offset, 1 column",
118     "TO2 - Tab Offset, 2 column",
119     "TO3 - Tab Offset, 3 column",
120     "RU2 - Roll up 2 rows",
121     "RU3 - Roll up 3 rows",
122     "RU4 - Roll up 4 rows",
123     "CR  - Carriage Return",
124     "ENM - Erase non-displayed memory",
125     "BS  - Backspace",
126     "RTD - Resume Text Display"
127 };
128
129 const char *font_text[]=
130 {
131     "regular",
132     "italics",
133     "underlined",
134     "underlined italics"
135 };
136
137 const char *cc_modes_text[]=
138 {
139     "Pop-Up captions"
140 };
141
142 const char *color_text[][2]=
143 {
144     {"white",""},
145     {"green","<font color=\"#00ff00\">"},
146     {"blue","<font color=\"#0000ff\">"},
147     {"cyan","<font color=\"#00ffff\">"},
148     {"red","<font color=\"#ff0000\">"},
149     {"yellow","<font color=\"#ffff00\">"},
150     {"magenta","<font color=\"#ff00ff\">"},
151     {"userdefined","<font color=\""}
152 };
153
154 int general_608_init (struct s_write *wb)
155 {
156     if( !wb->enc_buffer )
157     {
158         wb->enc_buffer=(unsigned char *) malloc (INITIAL_ENC_BUFFER_CAPACITY); 
159         if (wb->enc_buffer==NULL)
160             return -1;
161         wb->enc_buffer_capacity=INITIAL_ENC_BUFFER_CAPACITY;
162     }
163
164     if( !wb->subline) {
165         wb->subline = malloc(2048);
166     
167         if (!wb->subline)
168         {
169             return -1;
170         }
171     }
172
173     wb->new_sentence = 1;
174     wb->new_channel = 1;
175     wb->in_xds_mode = 0;
176
177     wb->hb_buffer = NULL;
178     wb->hb_last_buffer = NULL;
179     wb->last_pts = 0;
180     return 0;
181 }
182
183 /*
184  * Free up CC memory - don't call this from HB just yet since it will cause
185  * parallel encodes to fail - to be honest they will be stuffed anyway since
186  * the CC's may be overwriting the buffers.
187  */
188 void general_608_close (struct s_write *wb)
189 {
190     if( wb->enc_buffer ) {
191         free(wb->enc_buffer);
192         wb->enc_buffer_capacity = 0;
193         wb->enc_buffer_used = 0;
194     }
195     if( wb->subline ) {
196         free(wb->subline);
197     }
198
199     if( wb->hb_buffer ) {
200         hb_buffer_close( &wb->hb_buffer );
201     }
202 }
203
204
205 #include <ctype.h>
206
207 void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
208 {
209     unsigned char c1='?';
210     if (c<0x80) 
211     {   
212         // Regular line-21 character set, mostly ASCII except these exceptions
213         switch (c)
214         {
215             case 0x2a: // lowercase a, acute accent
216                 c1=0xe1;
217                 break;
218             case 0x5c: // lowercase e, acute accent
219                 c1=0xe9;
220                 break;
221             case 0x5e: // lowercase i, acute accent
222                 c1=0xed;
223                 break;                  
224             case 0x5f: // lowercase o, acute accent
225                 c1=0xf3;
226                 break;
227             case 0x60: // lowercase u, acute accent
228                 c1=0xfa;
229                 break;
230             case 0x7b: // lowercase c with cedilla
231                 c1=0xe7;
232                 break;
233             case 0x7c: // division symbol
234                 c1=0xf7;
235                 break;
236             case 0x7d: // uppercase N tilde
237                 c1=0xd1;
238                 break;
239             case 0x7e: // lowercase n tilde
240                 c1=0xf1;
241                 break;
242             default:
243                 c1=c;
244                 break;
245         }
246         *buffer=c1;
247         return;
248     }
249     switch (c)
250     {
251         // THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
252         // THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F            
253         case 0x80: // Registered symbol (R)
254             c1=0xae;
255             break;                      
256         case 0x81: // degree sign
257             c1=0xb0;
258             break;
259         case 0x82: // 1/2 symbol                        
260             c1=0xbd;
261             break;
262         case 0x83: // Inverted (open) question mark                     
263             c1=0xbf;
264             break;
265         case 0x84: // Trademark symbol (TM) - Does not exist in Latin 1
266             break;                      
267         case 0x85: // Cents symbol                      
268             c1=0xa2;
269             break;
270         case 0x86: // Pounds sterling                   
271             c1=0xa3;
272             break;
273         case 0x87: // Music note - Not in latin 1, so we use 'pilcrow'
274             c1=0xb6;
275             break;
276         case 0x88: // lowercase a, grave accent
277             c1=0xe0;
278             break;
279         case 0x89: // transparent space, we make it regular
280             c1=0x20;                    
281             break;
282         case 0x8a: // lowercase e, grave accent
283             c1=0xe8;
284             break;
285         case 0x8b: // lowercase a, circumflex accent
286             c1=0xe2;
287             break;
288         case 0x8c: // lowercase e, circumflex accent
289             c1=0xea;                    
290             break;
291         case 0x8d: // lowercase i, circumflex accent
292             c1=0xee;
293             break;
294         case 0x8e: // lowercase o, circumflex accent
295             c1=0xf4;
296             break;
297         case 0x8f: // lowercase u, circumflex accent
298             c1=0xfb;
299             break;
300         // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
301         // THAT COME FROM HI BYTE=0x12 AND LOW BETWEEN 0x20 AND 0x3F
302         case 0x90: // capital letter A with acute
303             c1=0xc1;
304             break;
305         case 0x91: // capital letter E with acute
306             c1=0xc9;
307             break;
308         case 0x92: // capital letter O with acute
309             c1=0xd3;
310             break;
311         case 0x93: // capital letter U with acute
312             c1=0xda;
313             break;
314         case 0x94: // capital letter U with diaresis
315             c1=0xdc;
316             break;
317         case 0x95: // lowercase letter U with diaeresis
318             c1=0xfc;
319             break;
320         case 0x96: // apostrophe
321             c1=0x27;                    
322             break;
323         case 0x97: // inverted exclamation mark                 
324             c1=0xa1;
325             break;
326         case 0x98: // asterisk
327             c1=0x2a;                    
328             break;
329         case 0x99: // apostrophe (yes, duped). See CCADI source code.
330             c1=0x27;                    
331             break;
332         case 0x9a: // hyphen-minus
333             c1=0x2d;                    
334             break;
335         case 0x9b: // copyright sign
336             c1=0xa9;
337             break;
338         case 0x9c: // Service Mark - not available in latin 1
339             break;
340         case 0x9d: // Full stop (.)
341             c1=0x2e;
342             break;
343         case 0x9e: // Quoatation mark
344             c1=0x22;                    
345             break;
346         case 0x9f: // Quoatation mark
347             c1=0x22;                    
348             break;
349         case 0xa0: // uppercase A, grave accent
350             c1=0xc0;
351             break;
352         case 0xa1: // uppercase A, circumflex
353             c1=0xc2;
354             break;                      
355         case 0xa2: // uppercase C with cedilla
356             c1=0xc7;
357             break;
358         case 0xa3: // uppercase E, grave accent
359             c1=0xc8;
360             break;
361         case 0xa4: // uppercase E, circumflex
362             c1=0xca;
363             break;
364         case 0xa5: // capital letter E with diaresis
365             c1=0xcb;
366             break;
367         case 0xa6: // lowercase letter e with diaresis
368             c1=0xeb;
369             break;
370         case 0xa7: // uppercase I, circumflex
371             c1=0xce;
372             break;
373         case 0xa8: // uppercase I, with diaresis
374             c1=0xcf;
375             break;
376         case 0xa9: // lowercase i, with diaresis
377             c1=0xef;
378             break;
379         case 0xaa: // uppercase O, circumflex
380             c1=0xd4;
381             break;
382         case 0xab: // uppercase U, grave accent
383             c1=0xd9;
384             break;
385         case 0xac: // lowercase u, grave accent
386             c1=0xf9;
387             break;
388         case 0xad: // uppercase U, circumflex
389             c1=0xdb;
390             break;
391         case 0xae: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
392             c1=0xab;
393             break;
394         case 0xaf: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
395             c1=0xbb;
396             break;
397         // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
398         // THAT COME FROM HI BYTE=0x13 AND LOW BETWEEN 0x20 AND 0x3F
399         case 0xb0: // Uppercase A, tilde
400             c1=0xc3;
401             break;
402         case 0xb1: // Lowercase a, tilde
403             c1=0xe3;
404             break;
405         case 0xb2: // Uppercase I, acute accent
406             c1=0xcd;
407             break;
408         case 0xb3: // Uppercase I, grave accent
409             c1=0xcc;
410             break;
411         case 0xb4: // Lowercase i, grave accent
412             c1=0xec;
413             break;
414         case 0xb5: // Uppercase O, grave accent
415             c1=0xd2;
416             break;
417         case 0xb6: // Lowercase o, grave accent
418             c1=0xf2;
419             break;
420         case 0xb7: // Uppercase O, tilde
421             c1=0xd5;
422             break;
423         case 0xb8: // Lowercase o, tilde
424             c1=0xf5;
425             break;
426         case 0xb9: // Open curly brace
427             c1=0x7b;
428             break;
429         case 0xba: // Closing curly brace
430             c1=0x7d;            
431             break;
432         case 0xbb: // Backslash
433             c1=0x5c;
434             break;
435         case 0xbc: // Caret
436             c1=0x5e;
437             break;
438         case 0xbd: // Underscore
439             c1=0x5f;
440             break;
441         case 0xbe: // Pipe (broken bar)            
442             c1=0xa6;
443             break;
444         case 0xbf: // Tilde
445             c1=0x7e; 
446             break;
447         case 0xc0: // Uppercase A, umlaut            
448             c1=0xc4;
449             break;
450         case 0xc1: // Lowercase A, umlaut
451             c1=0xe3; 
452             break;
453         case 0xc2: // Uppercase O, umlaut
454             c1=0xd6;
455             break;
456         case 0xc3: // Lowercase o, umlaut
457             c1=0xf6;
458             break;
459         case 0xc4: // Esszett (sharp S)
460             c1=0xdf;
461             break;
462         case 0xc5: // Yen symbol
463             c1=0xa5;
464             break;
465         case 0xc6: // Currency symbol
466             c1=0xa4;
467             break;            
468         case 0xc7: // Vertical bar
469             c1=0x7c;
470             break;            
471         case 0xc8: // Uppercase A, ring
472             c1=0xc5;
473             break;
474         case 0xc9: // Lowercase A, ring
475             c1=0xe5;
476             break;
477         case 0xca: // Uppercase O, slash
478             c1=0xd8;
479             break;
480         case 0xcb: // Lowercase o, slash
481             c1=0xf8;
482             break;
483         case 0xcc: // Upper left corner
484         case 0xcd: // Upper right corner
485         case 0xce: // Lower left corner
486         case 0xcf: // Lower right corner
487         default: // For those that don't have representation
488             *buffer='?'; // I'll do it eventually, I promise
489             break; // This are weird chars anyway
490     }
491     *buffer=c1; 
492 }
493
494 void get_char_in_unicode (unsigned char *buffer, unsigned char c)
495 {
496     unsigned char c1,c2;
497     switch (c)
498     {
499         case 0x84: // Trademark symbol (TM) 
500             c2=0x21;
501             c1=0x22;
502             break;
503         case 0x87: // Music note
504             c2=0x26;
505             c1=0x6a;
506             break;
507         case 0x9c: // Service Mark
508             c2=0x21;
509             c1=0x20;
510             break;
511         case 0xcc: // Upper left corner
512             c2=0x23;
513             c1=0x1c;
514             break;                      
515         case 0xcd: // Upper right corner
516             c2=0x23;
517             c1=0x1d;
518             break;
519         case 0xce: // Lower left corner
520             c2=0x23;
521             c1=0x1e;
522             break;
523         case 0xcf: // Lower right corner
524             c2=0x23;
525             c1=0x1f;
526             break;
527         default: // Everything else, same as latin-1 followed by 00                     
528             get_char_in_latin_1 (&c1,c);
529             c2=0;
530             break;
531     }
532     *buffer=c1;
533     *(buffer+1)=c2;
534 }
535
536 int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number of bytes used
537 {
538     if (c<0x80) // Regular line-21 character set, mostly ASCII except these exceptions
539     {
540         switch (c)
541         {
542         case 0x2a: // lowercase a, acute accent
543             *buffer=0xc3;
544             *(buffer+1)=0xa1;
545             return 2;
546         case 0x5c: // lowercase e, acute accent
547             *buffer=0xc3;
548             *(buffer+1)=0xa9;
549             return 2;
550         case 0x5e: // lowercase i, acute accent
551             *buffer=0xc3;
552             *(buffer+1)=0xad;
553             return 2;
554         case 0x5f: // lowercase o, acute accent
555             *buffer=0xc3;
556             *(buffer+1)=0xb3;
557             return 2;
558         case 0x60: // lowercase u, acute accent
559             *buffer=0xc3;
560             *(buffer+1)=0xba;
561             return 2;
562         case 0x7b: // lowercase c with cedilla
563             *buffer=0xc3;
564             *(buffer+1)=0xa7;
565             return 2;
566         case 0x7c: // division symbol
567             *buffer=0xc3;
568             *(buffer+1)=0xb7;
569             return 2;
570         case 0x7d: // uppercase N tilde
571             *buffer=0xc3;
572             *(buffer+1)=0x91;
573             return 2;
574         case 0x7e: // lowercase n tilde
575             *buffer=0xc3;
576             *(buffer+1)=0xb1;
577             return 2;
578         default:
579             *buffer=c;
580             return 1;
581         }
582     }
583     switch (c)
584     {
585         // THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
586         // THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F            
587         case 0x80: // Registered symbol (R)
588             *buffer=0xc2;
589             *(buffer+1)=0xae;                   
590             return 2;
591         case 0x81: // degree sign
592             *buffer=0xc2;
593             *(buffer+1)=0xb0;
594             return 2;
595         case 0x82: // 1/2 symbol
596             *buffer=0xc2;
597             *(buffer+1)=0xbd;
598             return 2;
599         case 0x83: // Inverted (open) question mark
600             *buffer=0xc2;
601             *(buffer+1)=0xbf;
602             return 2;
603         case 0x84: // Trademark symbol (TM)
604             *buffer=0xe2;
605             *(buffer+1)=0x84;
606             *(buffer+2)=0xa2;
607             return 3;
608         case 0x85: // Cents symbol
609             *buffer=0xc2;
610             *(buffer+1)=0xa2;
611             return 2;
612         case 0x86: // Pounds sterling
613             *buffer=0xc2;
614             *(buffer+1)=0xa3;
615             return 2;
616         case 0x87: // Music note                        
617             *buffer=0xe2;
618             *(buffer+1)=0x99;
619             *(buffer+2)=0xaa;
620             return 3;
621         case 0x88: // lowercase a, grave accent
622             *buffer=0xc3;
623             *(buffer+1)=0xa0;
624             return 2;
625         case 0x89: // transparent space, we make it regular
626             *buffer=0x20;                       
627             return 1;
628         case 0x8a: // lowercase e, grave accent
629             *buffer=0xc3;
630             *(buffer+1)=0xa8;
631             return 2;
632         case 0x8b: // lowercase a, circumflex accent
633             *buffer=0xc3;
634             *(buffer+1)=0xa2;
635             return 2;
636         case 0x8c: // lowercase e, circumflex accent
637             *buffer=0xc3;
638             *(buffer+1)=0xaa;
639             return 2;
640         case 0x8d: // lowercase i, circumflex accent
641             *buffer=0xc3;
642             *(buffer+1)=0xae;
643             return 2;
644         case 0x8e: // lowercase o, circumflex accent
645             *buffer=0xc3;
646             *(buffer+1)=0xb4;
647             return 2;
648         case 0x8f: // lowercase u, circumflex accent
649             *buffer=0xc3;
650             *(buffer+1)=0xbb;
651             return 2;
652         // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
653         // THAT COME FROM HI BYTE=0x12 AND LOW BETWEEN 0x20 AND 0x3F
654         case 0x90: // capital letter A with acute
655             *buffer=0xc3;
656             *(buffer+1)=0x81;
657             return 2;
658         case 0x91: // capital letter E with acute
659             *buffer=0xc3;
660             *(buffer+1)=0x89;
661             return 2;
662         case 0x92: // capital letter O with acute
663             *buffer=0xc3;
664             *(buffer+1)=0x93;
665             return 2;
666         case 0x93: // capital letter U with acute
667             *buffer=0xc3;
668             *(buffer+1)=0x9a;
669             return 2;
670         case 0x94: // capital letter U with diaresis
671             *buffer=0xc3;
672             *(buffer+1)=0x9c;
673             return 2;
674         case 0x95: // lowercase letter U with diaeresis
675             *buffer=0xc3;
676             *(buffer+1)=0xbc;
677             return 2;
678         case 0x96: // apostrophe
679             *buffer=0x27;                       
680             return 1;
681         case 0x97: // inverted exclamation mark
682             *buffer=0xc1;
683             *(buffer+1)=0xa1;
684             return 2;
685         case 0x98: // asterisk
686             *buffer=0x2a;                       
687             return 1;
688         case 0x99: // apostrophe (yes, duped). See CCADI source code.
689             *buffer=0x27;                       
690             return 1;
691         case 0x9a: // hyphen-minus
692             *buffer=0x2d;                       
693             return 1;
694         case 0x9b: // copyright sign
695             *buffer=0xc2;
696             *(buffer+1)=0xa9;
697             return 2;
698         case 0x9c: // Service mark 
699             *buffer=0xe2;                       
700             *(buffer+1)=0x84;
701             *(buffer+2)=0xa0;
702             return 3;
703         case 0x9d: // Full stop (.)
704             *buffer=0x2e;                       
705             return 1;
706         case 0x9e: // Quoatation mark
707             *buffer=0x22;                       
708             return 1;
709         case 0x9f: // Quoatation mark
710             *buffer=0x22;                       
711             return 1;
712         case 0xa0: // uppercase A, grave accent
713             *buffer=0xc3;
714             *(buffer+1)=0x80;
715             return 2;
716         case 0xa1: // uppercase A, circumflex
717             *buffer=0xc3;
718             *(buffer+1)=0x82;
719             return 2;
720         case 0xa2: // uppercase C with cedilla
721             *buffer=0xc3;
722             *(buffer+1)=0x87;
723             return 2;
724         case 0xa3: // uppercase E, grave accent
725             *buffer=0xc3;
726             *(buffer+1)=0x88;
727             return 2;
728         case 0xa4: // uppercase E, circumflex
729             *buffer=0xc3;
730             *(buffer+1)=0x8a;
731             return 2;
732         case 0xa5: // capital letter E with diaresis
733             *buffer=0xc3;
734             *(buffer+1)=0x8b;
735             return 2;
736         case 0xa6: // lowercase letter e with diaresis
737             *buffer=0xc3;
738             *(buffer+1)=0xab;
739             return 2;
740         case 0xa7: // uppercase I, circumflex
741             *buffer=0xc3;
742             *(buffer+1)=0x8e;
743             return 2;
744         case 0xa8: // uppercase I, with diaresis
745             *buffer=0xc3;
746             *(buffer+1)=0x8f;
747             return 2;
748         case 0xa9: // lowercase i, with diaresis
749             *buffer=0xc3;
750             *(buffer+1)=0xaf;
751             return 2;
752         case 0xaa: // uppercase O, circumflex
753             *buffer=0xc3;
754             *(buffer+1)=0x94;
755             return 2;
756         case 0xab: // uppercase U, grave accent
757             *buffer=0xc3;
758             *(buffer+1)=0x99;
759             return 2;
760         case 0xac: // lowercase u, grave accent
761             *buffer=0xc3;
762             *(buffer+1)=0xb9;
763             return 2;
764         case 0xad: // uppercase U, circumflex
765             *buffer=0xc3;
766             *(buffer+1)=0x9b;
767             return 2;
768         case 0xae: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
769             *buffer=0xc2;
770             *(buffer+1)=0xab;
771             return 2;
772         case 0xaf: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
773             *buffer=0xc2;
774             *(buffer+1)=0xbb;
775             return 2;
776         // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
777         // THAT COME FROM HI BYTE=0x13 AND LOW BETWEEN 0x20 AND 0x3F
778         case 0xb0: // Uppercase A, tilde
779             *buffer=0xc3;
780             *(buffer+1)=0x83;
781             return 2;
782         case 0xb1: // Lowercase a, tilde
783             *buffer=0xc3;
784             *(buffer+1)=0xa3;
785             return 2;
786         case 0xb2: // Uppercase I, acute accent
787             *buffer=0xc3;
788             *(buffer+1)=0x8d;
789             return 2;
790         case 0xb3: // Uppercase I, grave accent
791             *buffer=0xc3;
792             *(buffer+1)=0x8c;
793             return 2;
794         case 0xb4: // Lowercase i, grave accent
795             *buffer=0xc3;
796             *(buffer+1)=0xac;
797             return 2;
798         case 0xb5: // Uppercase O, grave accent
799             *buffer=0xc3;
800             *(buffer+1)=0x92;
801             return 2;
802         case 0xb6: // Lowercase o, grave accent
803             *buffer=0xc3;
804             *(buffer+1)=0xb2;
805             return 2;
806         case 0xb7: // Uppercase O, tilde
807             *buffer=0xc3;
808             *(buffer+1)=0x95;
809             return 2;
810         case 0xb8: // Lowercase o, tilde
811             *buffer=0xc3;
812             *(buffer+1)=0xb5;
813             return 2;
814         case 0xb9: // Open curly brace
815             *buffer=0x7b;
816             return 1;
817         case 0xba: // Closing curly brace
818             *buffer=0x7d;            
819             return 1;
820         case 0xbb: // Backslash
821             *buffer=0x5c;
822             return 1;
823         case 0xbc: // Caret
824             *buffer=0x5e;
825             return 1;
826         case 0xbd: // Underscore
827             *buffer=0x5f;
828             return 1;
829         case 0xbe: // Pipe (broken bar)
830             *buffer=0xc2; 
831             *(buffer+1)=0xa6;
832             return 1;
833         case 0xbf: // Tilde
834             *buffer=0x7e; // Not sure
835             return 1;
836         case 0xc0: // Uppercase A, umlaut
837             *buffer=0xc3; 
838             *(buffer+1)=0x84;
839             return 2;
840         case 0xc1: // Lowercase A, umlaut
841             *buffer=0xc3; 
842             *(buffer+1)=0xa4;
843             return 2;
844         case 0xc2: // Uppercase O, umlaut
845             *buffer=0xc3; 
846             *(buffer+1)=0x96;
847             return 2;
848         case 0xc3: // Lowercase o, umlaut
849             *buffer=0xc3; 
850             *(buffer+1)=0xb6;
851             return 2;
852         case 0xc4: // Esszett (sharp S)
853             *buffer=0xc3;
854             *(buffer+1)=0x9f;
855             return 2;
856         case 0xc5: // Yen symbol
857             *buffer=0xc2;
858             *(buffer+1)=0xa5;
859             return 2;
860         case 0xc6: // Currency symbol
861             *buffer=0xc2;
862             *(buffer+1)=0xa4;
863             return 2;
864         case 0xc7: // Vertical bar
865             *buffer=0x7c; 
866             return 1;
867         case 0xc8: // Uppercase A, ring
868             *buffer=0xc3;
869             *(buffer+1)=0x85;
870             return 2;
871         case 0xc9: // Lowercase A, ring
872             *buffer=0xc3;
873             *(buffer+1)=0xa5;
874             return 2;
875         case 0xca: // Uppercase O, slash
876             *buffer=0xc3;
877             *(buffer+1)=0x98;
878             return 2;
879         case 0xcb: // Lowercase o, slash
880             *buffer=0xc3;
881             *(buffer+1)=0xb8;
882             return 2;
883         case 0xcc: // Upper left corner
884             *buffer=0xe2;
885             *(buffer+1)=0x8c;
886             *(buffer+2)=0x9c;
887             return 3;
888         case 0xcd: // Upper right corner
889             *buffer=0xe2;
890             *(buffer+1)=0x8c;
891             *(buffer+2)=0x9d;
892             return 3;
893         case 0xce: // Lower left corner
894             *buffer=0xe2;
895             *(buffer+1)=0x8c;
896             *(buffer+2)=0x9e;
897             return 3;
898         case 0xcf: // Lower right corner
899             *buffer=0xe2;
900             *(buffer+1)=0x8c;
901             *(buffer+2)=0x9f;
902             return 3;
903         default: // 
904             *buffer='?'; // I'll do it eventually, I promise
905             return 1; // This are weird chars anyway
906     }
907 }
908
909 unsigned char cctolower (unsigned char c)
910 {
911     if (c>='A' && c<='Z')
912         return tolower(c);
913     switch (c)
914     {
915         case 0x7d: // uppercase N tilde
916             return 0x7e;
917         case 0x90: // capital letter A with acute
918             return 0x2a;
919         case 0x91: // capital letter E with acute
920             return 0x5c; 
921         case 0x92: // capital letter O with acute
922             return 0x5f; 
923         case 0x93: // capital letter U with acute
924             return 0x60; 
925         case 0xa2: // uppercase C with cedilla
926             return 0x7b; 
927         case 0xa0: // uppercase A, grave accent
928             return 0x88; 
929         case 0xa3: // uppercase E, grave accent
930             return 0x8a; 
931         case 0xa1: // uppercase A, circumflex
932             return 0x8b; 
933         case 0xa4: // uppercase E, circumflex
934             return 0x8c; 
935         case 0xa7: // uppercase I, circumflex
936             return 0x8d; 
937         case 0xaa: // uppercase O, circumflex
938             return 0x8e; 
939         case 0xad: // uppercase U, circumflex
940             return 0x8f; 
941         case 0x94: // capital letter U with diaresis
942             return 0x95; 
943         case 0xa5: // capital letter E with diaresis
944             return 0xa6; 
945         case 0xa8: // uppercase I, with diaresis
946             return 0xa9; 
947         case 0xab: // uppercase U, grave accent
948             return 0xac; 
949         case 0xb0: // Uppercase A, tilde
950             return 0xb1;
951         case 0xb2: // Uppercase I, acute accent
952             return 0x5e;
953         case 0xb3: // Uppercase I, grave accent
954             return 0xb4;
955         case 0xb5: // Uppercase O, grave accent
956             return 0xb6;
957         case 0xb7: // Uppercase O, tilde
958             return 0xb8;
959         case 0xc0: // Uppercase A, umlaut
960             return 0xc1;
961         case 0xc2: // Uppercase O, umlaut
962             return 0xc3;
963         case 0xc8: // Uppercase A, ring
964             return 0xc9;
965         case 0xca: // Uppercase O, slash
966             return 0xcb;
967     }
968     return c;
969 }
970
971 unsigned char cctoupper (unsigned char c)
972 {
973     if (c>='a' && c<='z')
974         return toupper(c);
975     switch (c)
976     {
977         case 0x7e: // lowercase n tilde
978             return 0x7d;
979         case 0x2a: // lowercase a, acute accent
980             return 0x90;
981         case 0x5c: // lowercase e, acute accent
982             return 0x91;
983         case 0x5e: // lowercase i, acute accent
984             return 0xb2;
985         case 0x5f: // lowercase o, acute accent
986             return 0x92;
987         case 0x60: // lowercase u, acute accent
988             return 0x93;
989         case 0x7b: // lowercase c with cedilla
990             return 0xa2;
991         case 0x88: // lowercase a, grave accent
992             return 0xa0;
993         case 0x8a: // lowercase e, grave accent
994             return 0xa3;
995         case 0x8b: // lowercase a, circumflex accent
996             return 0xa1;
997         case 0x8c: // lowercase e, circumflex accent
998             return 0xa4;
999         case 0x8d: // lowercase i, circumflex accent
1000             return 0xa7;
1001         case 0x8e: // lowercase o, circumflex accent
1002             return 0xaa;
1003         case 0x8f: // lowercase u, circumflex accent
1004             return 0xad;
1005         case 0x95: // lowercase letter U with diaeresis
1006             return 0x94;
1007         case 0xa6: // lowercase letter e with diaresis
1008             return 0xa5;
1009         case 0xa9: // lowercase i, with diaresis
1010             return 0xa8;
1011         case 0xac: // lowercase u, grave accent
1012             return 0xab;
1013         case 0xb1: // Lowercase a, tilde
1014             return 0xb0; 
1015         case 0xb4: // Lowercase i, grave accent
1016             return 0xb3;
1017         case 0xb6: // Lowercase o, grave accent
1018             return 0xb5; 
1019         case 0xb8: // Lowercase o, tilde        
1020             return 0xb7;
1021         case 0xc1: // Lowercase A, umlaut       
1022             return 0xc0; 
1023         case 0xc3: // Lowercase o, umlaut
1024             return 0xc2;
1025         case 0xc9: // Lowercase A, ring
1026             return 0xc8; 
1027         case 0xcb: // Lowercase o, slash
1028             return 0xca; 
1029     }
1030     return c;
1031 }
1032
1033
1034 // Encodes a generic string. Note that since we use the encoders for closed caption
1035 // data, text would have to be encoded as CCs... so using special characters here
1036 // it's a bad idea. 
1037 unsigned encode_line (unsigned char *buffer, unsigned char *text)
1038
1039     unsigned bytes=0;
1040     while (*text)
1041     {           
1042         switch (encoding)
1043         {
1044             case ENC_UTF_8:
1045             case ENC_LATIN_1:
1046                 *buffer=*text;
1047                 bytes++;
1048                 buffer++;
1049                 break;
1050         case ENC_UNICODE:                               
1051             *buffer=*text;                              
1052             *(buffer+1)=0;
1053             bytes+=2;                           
1054             buffer+=2;
1055             break;
1056         }               
1057         text++;
1058     }
1059     return bytes;
1060 }
1061
1062 #define ISSEPARATOR(c) (c==' ' || c==0x89 || ispunct(c) \
1063     || c==0x99) // This is the apostrofe. We get it here in CC encoding, not ASCII
1064
1065
1066 void correct_case (int line_num, struct eia608_screen *data)
1067 {
1068 /*     int i=0; */
1069 /*     while (i<spell_words) */
1070 /*     { */
1071 /*         char *c=(char *) data->characters[line_num]; */
1072 /*         size_t len=strlen (spell_correct[i]); */
1073 /*         while ((c=strstr (c,spell_lower[i]))!=NULL) */
1074 /*         { */
1075 /*             // Make sure it's a whole word (start of line or */
1076 /*             // preceded by space, and end of line or followed by */
1077 /*             // space) */
1078 /*             unsigned char prev; */
1079 /*             if (c==(char *) data->characters[line_num]) // Beginning of line... */
1080 /*                 prev=' '; // ...Pretend we had a blank before */
1081 /*             else */
1082 /*                 prev=*(c-1);              */
1083 /*             unsigned char next; */
1084 /*             if (c-(char *) data->characters[line_num]+len==CC608_SCREEN_WIDTH) // End of line... */
1085 /*                 next=' '; // ... pretend we have a blank later */
1086 /*             else */
1087 /*                 next=*(c+len);                        */
1088 /*             if ( ISSEPARATOR(prev) && ISSEPARATOR(next)) */
1089 /*             { */
1090 /*                 memcpy (c,spell_correct[i],len); */
1091 /*             } */
1092 /*             c++; */
1093 /*         } */
1094 /*         i++; */
1095 /*     } */
1096 }
1097
1098 void capitalize (int line_num, struct eia608_screen *data, int *new_sentence)
1099 {
1100     int i;
1101
1102     for (i=0;i<CC608_SCREEN_WIDTH;i++)
1103     {
1104         switch (data->characters[line_num][i])
1105         {
1106             case ' ': 
1107             case 0x89: // This is a transparent space
1108             case '-':
1109                 break; 
1110             case '.': // Fallthrough
1111             case '?': // Fallthrough
1112             case '!':
1113             case ':':
1114                 *new_sentence=1;
1115                 break;
1116             default:
1117                 if (*new_sentence)                      
1118                     data->characters[line_num][i]=cctoupper (data->characters[line_num][i]);
1119                 else
1120                     data->characters[line_num][i]=cctolower (data->characters[line_num][i]);
1121                 *new_sentence=0;
1122                 break;
1123         }
1124     }
1125 }
1126
1127 void find_limit_characters (unsigned char *line, int *first_non_blank, int *last_non_blank)
1128 {
1129     int i;
1130
1131     *last_non_blank=-1;
1132     *first_non_blank=-1;
1133     for (i=0;i<CC608_SCREEN_WIDTH;i++)
1134     {
1135         unsigned char c=line[i];
1136         if (c!=' ' && c!=0x89)
1137         {
1138             if (*first_non_blank==-1)
1139                 *first_non_blank=i;
1140             *last_non_blank=i;
1141         }
1142     }
1143 }
1144
1145 unsigned get_decoder_line_basic (unsigned char *buffer, int line_num, struct eia608_screen *data)
1146 {
1147     unsigned char *line = data->characters[line_num];
1148     int last_non_blank=-1;
1149     int first_non_blank=-1;
1150     unsigned char *orig=buffer; // Keep for debugging
1151     int i;
1152     find_limit_characters (line, &first_non_blank, &last_non_blank);
1153
1154     if (first_non_blank==-1)
1155     {
1156         *buffer=0;
1157         return 0;
1158     }
1159
1160     int bytes=0;
1161     for (i=first_non_blank;i<=last_non_blank;i++)
1162     {
1163         char c=line[i];
1164         switch (encoding)
1165         {
1166             case ENC_UTF_8:
1167                 bytes=get_char_in_utf_8 (buffer,c);
1168                 break;
1169             case ENC_LATIN_1:
1170                 get_char_in_latin_1 (buffer,c);
1171                 bytes=1;
1172                 break;
1173             case ENC_UNICODE:
1174                 get_char_in_unicode (buffer,c);
1175                 bytes=2;                                
1176                 break;
1177         }
1178         buffer+=bytes;
1179     }
1180     *buffer=0;
1181     return (unsigned) (buffer-orig); // Return length
1182 }
1183
1184 unsigned get_decoder_line_encoded_for_gui (unsigned char *buffer, int line_num, struct eia608_screen *data)
1185 {
1186     unsigned char *line = data->characters[line_num];   
1187     unsigned char *orig=buffer; // Keep for debugging
1188     int first=0, last=31;
1189     int i;
1190
1191     find_limit_characters(line,&first,&last);
1192     for (i=first;i<=last;i++)
1193     {   
1194         get_char_in_latin_1 (buffer,line[i]);
1195         buffer++;
1196     }
1197     *buffer=0;
1198     return (unsigned) (buffer-orig); // Return length
1199
1200 }
1201
1202 unsigned get_decoder_line_encoded (unsigned char *buffer, int line_num, struct eia608_screen *data)
1203 {
1204     int col = COL_WHITE;
1205     int underlined = 0;
1206     int italics = 0;    
1207     int i;
1208
1209     unsigned char *line = data->characters[line_num];   
1210     unsigned char *orig=buffer; // Keep for debugging
1211     int first=0, last=31;
1212     if (trim_subs)
1213         find_limit_characters(line,&first,&last);
1214     for (i=first;i<=last;i++)
1215     {   
1216         // Handle color
1217         int its_col = data->colors[line_num][i];
1218         if (its_col != col  && !nofontcolor)
1219         {
1220             if (col!=COL_WHITE) // We need to close the previous font tag
1221             {
1222                 buffer+= encode_line (buffer,(unsigned char *) "</font>");
1223             }
1224             // Add new font tag
1225             buffer+=encode_line (buffer, (unsigned char*) color_text[its_col][1]);
1226             if (its_col==COL_USERDEFINED)
1227             {
1228                 // The previous sentence doesn't copy the whole 
1229                 // <font> tag, just up to the quote before the color
1230                 buffer+=encode_line (buffer, (unsigned char*) usercolor_rgb);
1231                 buffer+=encode_line (buffer, (unsigned char*) "\">");
1232             }                   
1233
1234             col = its_col;
1235         }
1236         // Handle underlined
1237         int is_underlined = data->fonts[line_num][i] & FONT_UNDERLINED;
1238         if (is_underlined && underlined==0) // Open underline
1239         {
1240             buffer+=encode_line (buffer, (unsigned char *) "<u>");
1241         }
1242         if (is_underlined==0 && underlined) // Close underline
1243         {
1244             buffer+=encode_line (buffer, (unsigned char *) "</u>");
1245         } 
1246         underlined=is_underlined;
1247         // Handle italics
1248         int has_ita = data->fonts[line_num][i] & FONT_ITALICS;          
1249         if (has_ita && italics==0) // Open italics
1250         {
1251             buffer+=encode_line (buffer, (unsigned char *) "<i>");
1252         }
1253         if (has_ita==0 && italics) // Close italics
1254         {
1255             buffer+=encode_line (buffer, (unsigned char *) "</i>");
1256         } 
1257         italics=has_ita;
1258         int bytes=0;
1259         switch (encoding)
1260         {
1261             case ENC_UTF_8:
1262                 bytes=get_char_in_utf_8 (buffer,line[i]);
1263                 break;
1264             case ENC_LATIN_1:
1265                 get_char_in_latin_1 (buffer,line[i]);
1266                 bytes=1;
1267                 break;
1268             case ENC_UNICODE:
1269                 get_char_in_unicode (buffer,line[i]);
1270                 bytes=2;                                
1271                 break;
1272         }
1273         buffer+=bytes;        
1274     }
1275     if (italics)
1276     {
1277         buffer+=encode_line (buffer, (unsigned char *) "</i>");
1278     }
1279     if (underlined)
1280     {
1281         buffer+=encode_line (buffer, (unsigned char *) "</u>");
1282     }
1283     if (col != COL_WHITE && !nofontcolor)
1284     {
1285         buffer+=encode_line (buffer, (unsigned char *) "</font>");
1286     }
1287     *buffer=0;
1288     return (unsigned) (buffer-orig); // Return length
1289 }
1290
1291
1292 void delete_all_lines_but_current (struct eia608_screen *data, int row)
1293 {
1294     int i;
1295     for (i=0;i<15;i++)
1296     {
1297         if (i!=row)
1298         {
1299             memset(data->characters[i],' ',CC608_SCREEN_WIDTH);
1300             data->characters[i][CC608_SCREEN_WIDTH]=0;          
1301             memset (data->colors[i],default_color,CC608_SCREEN_WIDTH+1); 
1302             memset (data->fonts[i],FONT_REGULAR,CC608_SCREEN_WIDTH+1); 
1303             data->row_used[i]=0;        
1304         }
1305     }
1306 }
1307
1308 void clear_eia608_cc_buffer (struct eia608_screen *data)
1309 {
1310     int i;
1311
1312     for (i=0;i<15;i++)
1313     {
1314         memset(data->characters[i],' ',CC608_SCREEN_WIDTH);
1315         data->characters[i][CC608_SCREEN_WIDTH]=0;              
1316         memset (data->colors[i],default_color,CC608_SCREEN_WIDTH+1); 
1317         memset (data->fonts[i],FONT_REGULAR,CC608_SCREEN_WIDTH+1); 
1318         data->row_used[i]=0;        
1319     }
1320     data->empty=1;
1321 }
1322
1323 void init_eia608 (struct eia608 *data)
1324 {
1325     data->cursor_column=0;
1326     data->cursor_row=0;
1327     clear_eia608_cc_buffer (&data->buffer1);
1328     clear_eia608_cc_buffer (&data->buffer2);
1329     data->visible_buffer=1;
1330     data->last_c1=0;
1331     data->last_c2=0;
1332     data->mode=MODE_POPUP;
1333     // data->current_visible_start_cc=0;
1334     data->current_visible_start_ms=0;
1335     data->srt_counter=0;
1336     data->screenfuls_counter=0;
1337     data->channel=1;    
1338     data->color=default_color;
1339     data->font=FONT_REGULAR;
1340     data->rollup_base_row=14;
1341 }
1342
1343 struct eia608_screen *get_writing_buffer (struct s_write *wb)
1344 {
1345     struct eia608_screen *use_buffer=NULL;
1346     switch (wb->data608->mode)
1347     {
1348         case MODE_POPUP: // Write on the non-visible buffer
1349             if (wb->data608->visible_buffer==1)
1350                 use_buffer = &wb->data608->buffer2;
1351             else
1352                 use_buffer = &wb->data608->buffer1;
1353             break;
1354         case MODE_ROLLUP_2: // Write directly to screen
1355         case MODE_ROLLUP_3:
1356         case MODE_ROLLUP_4:
1357             if (wb->data608->visible_buffer==1)
1358                 use_buffer = &wb->data608->buffer1;
1359             else
1360                 use_buffer = &wb->data608->buffer2;
1361             break;
1362         default:
1363             fatal (EXIT_BUG_BUG, "Caption mode has an illegal value at get_writing_buffer(), this is a bug.\n");            
1364     }
1365     return use_buffer;
1366 }
1367
1368 void write_char (const unsigned char c, struct s_write *wb)
1369 {
1370     if (wb->data608->mode!=MODE_TEXT)
1371     {
1372         struct eia608_screen * use_buffer=get_writing_buffer(wb);
1373         /* hb_log ("\rWriting char [%c] at %s:%d:%d\n",c,
1374         use_buffer == &wb->data608->buffer1?"B1":"B2",
1375         wb->data608->cursor_row,wb->data608->cursor_column); */
1376         use_buffer->characters[wb->data608->cursor_row][wb->data608->cursor_column]=c;
1377         use_buffer->colors[wb->data608->cursor_row][wb->data608->cursor_column]=wb->data608->color;
1378         use_buffer->fonts[wb->data608->cursor_row][wb->data608->cursor_column]=wb->data608->font;       
1379         use_buffer->row_used[wb->data608->cursor_row]=1;
1380         use_buffer->empty=0;
1381         if (wb->data608->cursor_column<31)
1382             wb->data608->cursor_column++;
1383     }
1384
1385 }
1386
1387 /* Handle MID-ROW CODES. */
1388 void handle_text_attr (const unsigned char c1, const unsigned char c2, struct s_write *wb)
1389 {
1390     // Handle channel change
1391     wb->data608->channel=wb->new_channel;
1392     if (wb->data608->channel!=cc_channel)
1393         return;
1394     if (debug_608)
1395         hb_log ("\r608: text_attr: %02X %02X",c1,c2);
1396     if ( ((c1!=0x11 && c1!=0x19) ||
1397         (c2<0x20 || c2>0x2f)) && debug_608)
1398     {
1399         hb_log ("\rThis is not a text attribute!\n");
1400     }
1401     else
1402     {
1403         int i = c2-0x20;
1404         wb->data608->color=pac2_attribs[i][0];
1405         wb->data608->font=pac2_attribs[i][1];
1406         if (debug_608)
1407             hb_log ("  --  Color: %s,  font: %s\n",
1408             color_text[wb->data608->color][0],
1409             font_text[wb->data608->font]);
1410         if (wb->data608->cursor_column<31)
1411             wb->data608->cursor_column++;
1412     }
1413 }
1414
1415 void mstotime (LLONG milli, unsigned *hours, unsigned *minutes,
1416                unsigned *seconds, unsigned *ms)
1417 {
1418     // LLONG milli = (LLONG) ((ccblock*1000)/29.97);
1419     *ms=(unsigned) (milli%1000); // milliseconds
1420     milli=(milli-*ms)/1000;  // Remainder, in seconds
1421     *seconds = (int) (milli%60);
1422     milli=(milli-*seconds)/60; // Remainder, in minutes
1423     *minutes = (int) (milli%60);
1424     milli=(milli-*minutes)/60; // Remainder, in hours
1425     *hours=(int) milli;
1426 }
1427
1428 void write_subtitle_file_footer (struct s_write *wb)
1429 {
1430     switch (write_format)
1431     {
1432         case OF_SAMI:
1433             sprintf ((char *) str,"</BODY></SAMI>\n");
1434             if (debug_608 && encoding!=ENC_UNICODE)
1435             {
1436                 hb_log ("\r%s\n", str);
1437             }
1438             wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) str);
1439             //fwrite (enc_buffer,enc_buffer_used,1,wb->fh);
1440             XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
1441             break;
1442         default: // Nothing to do. Only SAMI has a footer
1443             break;
1444     }
1445 }
1446
1447 void fhb_log_encoded (FILE *fh, const char *string)
1448 {
1449     //GUARANTEE(wb, strlen (string)*3);
1450     //wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) string);
1451     //fwrite (wb->enc_buffer,wb->enc_buffer_used,1,fh);
1452 }
1453
1454 void write_subtitle_file_header (struct s_write *wb)
1455 {
1456     switch (write_format)
1457     {
1458         case OF_SRT: // Subrip subtitles have no header
1459             break; 
1460         case OF_SAMI: // This header brought to you by McPoodle's CCASDI  
1461             //fhb_log_encoded (wb->fh, sami_header);
1462             GUARANTEE(wb, strlen (sami_header)*3);
1463             wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) sami_header);
1464             //fwrite (enc_buffer,enc_buffer_used,1,wb->fh);
1465             XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
1466             break;
1467         case OF_RCWT: // Write header
1468             //fwrite (rcwt_header, sizeof(rcwt_header),1,wb->fh);
1469             break;
1470         case OF_TRANSCRIPT: // No header. Fall thru
1471         default:
1472             break;
1473     }
1474 }
1475
1476 void write_cc_line_as_transcript (struct eia608_screen *data, struct s_write *wb, int line_number)
1477 {
1478     hb_buffer_t *buffer;
1479
1480     if (sentence_cap)
1481     {
1482         capitalize(line_number,data, &wb->new_sentence);
1483         correct_case(line_number,data);
1484     }
1485     int length = get_decoder_line_basic (wb->subline, line_number, data);
1486     if (debug_608 && encoding!=ENC_UNICODE)
1487     {
1488         hb_log ("\r");
1489         hb_log ("%s\n",wb->subline);
1490     }
1491     if (length>0)
1492     {
1493         //fwrite (wb->subline, 1, length, wb->fh);
1494         /*
1495          * Put this subtitle in a hb_buffer_t and shove it into the subtitle fifo
1496          */
1497         buffer = hb_buffer_init( length + 1 );
1498         buffer->start = wb->data608->current_visible_start_ms;
1499         buffer->stop = get_fts(wb);
1500         memcpy( buffer->data, wb->subline, length + 1 );
1501         //hb_log("CC %lld: %s", buffer->stop, wb->subline);
1502
1503         if (wb->hb_last_buffer) {
1504             wb->hb_last_buffer->next = buffer;
1505         } else {
1506             wb->hb_buffer = buffer;
1507         }
1508         wb->hb_last_buffer = buffer;
1509
1510         XMLRPC_APPEND(wb->subline,length);
1511         //fwrite (encoded_crlf, 1, encoded_crlf_length,wb->fh);
1512         XMLRPC_APPEND(encoded_crlf,encoded_crlf_length);    
1513     }
1514     // fhb_log (wb->fh,encoded_crlf);
1515 }
1516
1517 int write_cc_buffer_as_transcript (struct eia608_screen *data, struct s_write *wb)
1518 {
1519     int i;
1520
1521     int wrote_something = 0;
1522     if (debug_608)
1523     {
1524         hb_log ("\n- - - TRANSCRIPT caption - - -\n");        
1525     }
1526     for (i=0;i<15;i++)
1527     {
1528         if (data->row_used[i])
1529         {               
1530             write_cc_line_as_transcript (data,wb, i);
1531         }
1532         wrote_something=1;
1533     }
1534     if (debug_608)
1535     {
1536         hb_log ("- - - - - - - - - - - -\r\n");
1537     }
1538     return wrote_something;
1539 }
1540
1541 void write_cc_buffer_to_gui (struct eia608_screen *data, struct s_write *wb)
1542 {
1543     unsigned h1,m1,s1,ms1;
1544     unsigned h2,m2,s2,ms2;    
1545     int i;
1546
1547     LLONG ms_start= wb->data608->current_visible_start_ms;
1548
1549     ms_start+=subs_delay;
1550     if (ms_start<0) // Drop screens that because of subs_delay start too early
1551         return;
1552     int time_reported=0;    
1553     for (i=0;i<15;i++)
1554     {
1555         if (data->row_used[i])
1556         {
1557             hb_log ("###SUBTITLE#");            
1558             if (!time_reported)
1559             {
1560                 LLONG ms_end = get_fts(wb)+subs_delay;          
1561                 mstotime (ms_start,&h1,&m1,&s1,&ms1);
1562                 mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
1563                 // Note, only MM:SS here as we need to save space in the preview window
1564                 hb_log ("%02u:%02u#%02u:%02u#",
1565                         h1*60+m1,s1, h2*60+m2,s2);
1566                 time_reported=1;
1567             }
1568             else
1569                 hb_log ("##");
1570             
1571             // We don't capitalize here because whatever function that was used
1572             // before to write to file already took care of it.
1573             int length = get_decoder_line_encoded_for_gui (wb->subline, i, data);
1574             fwrite (wb->subline, 1, length, stderr);
1575             fwrite ("\n",1,1,stderr);
1576         }
1577     }
1578     fflush (stderr);
1579 }
1580
1581 int write_cc_buffer_as_srt (struct eia608_screen *data, struct s_write *wb)
1582 {
1583     unsigned h1,m1,s1,ms1;
1584     unsigned h2,m2,s2,ms2;
1585     int wrote_something = 0;
1586     LLONG ms_start= wb->data608->current_visible_start_ms;
1587     int i;
1588
1589     ms_start+=subs_delay;
1590     if (ms_start<0) // Drop screens that because of subs_delay start too early
1591         return 0;
1592
1593     LLONG ms_end = get_fts(wb)+subs_delay;              
1594     mstotime (ms_start,&h1,&m1,&s1,&ms1);
1595     mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
1596     char timeline[128];   
1597     wb->data608->srt_counter++;
1598     sprintf (timeline,"%u\r\n",wb->data608->srt_counter);
1599     //wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) timeline);
1600     //fwrite (wb->enc_buffer,wb->enc_buffer_used,1,wb->fh);
1601     XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
1602     //sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
1603     //      h1,m1,s1,ms1, h2,m2,s2,ms2);
1604     //wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) timeline);
1605     if (debug_608)
1606     {
1607         hb_log ("\n- - - SRT caption - - -\n");
1608         hb_log (timeline);
1609     }
1610     //fwrite (enc_buffer,enc_buffer_used,1,wb->fh);             
1611     XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
1612     
1613     /*
1614      * Write all the lines into enc_buffer, and then write that out at the end
1615      * ensure that we only have two lines, insert a newline after the first one,
1616      * and have a big bottom line (strip spaces from any joined lines).
1617      */
1618     int line = 1;
1619     for (i=0;i<15;i++)
1620     {
1621         if (data->row_used[i])
1622         {               
1623             if (sentence_cap)
1624             {
1625                 capitalize(i,data, &wb->new_sentence);
1626                 correct_case(i,data);
1627             }
1628             /*
1629              * The intention was to use a newline but QT doesn't like it, old code still
1630              * here just in case..
1631              */
1632             if (line == 1) {
1633                 wb->enc_buffer_used = get_decoder_line_encoded (wb->enc_buffer, i, data);
1634                 line = 2;
1635             } else {
1636                 if (line == 2) {
1637                     wb->enc_buffer_used += encode_line (wb->enc_buffer+wb->enc_buffer_used,
1638                                                         (unsigned char *) " ");
1639                 } else {
1640                     wb->enc_buffer_used += encode_line (wb->enc_buffer+wb->enc_buffer_used,
1641                                                         (unsigned char *) " "); 
1642                 }
1643                 wb->enc_buffer_used += get_decoder_line_encoded (wb->enc_buffer+wb->enc_buffer_used, i, data);
1644             }
1645         }
1646     }
1647     if (wb->enc_buffer_used)
1648     {
1649         hb_buffer_t *buffer = hb_buffer_init( wb->enc_buffer_used + 2 );
1650         buffer->start = ms_start;
1651         buffer->stop = ms_end;
1652         memcpy( buffer->data, wb->enc_buffer, wb->enc_buffer_used + 1 );
1653         if (wb->hb_last_buffer) {
1654             wb->hb_last_buffer->next = buffer;
1655         } else {
1656             wb->hb_buffer = buffer;
1657         }
1658         wb->hb_last_buffer = buffer;
1659         
1660         wrote_something=1;
1661     }
1662     if (debug_608)
1663     {
1664         hb_log ("- - - - - - - - - - - -\r\n");
1665     }
1666     // fhb_log (wb->fh, encoded_crlf);
1667     //fwrite (encoded_crlf, 1, encoded_crlf_length,wb->fh);
1668     XMLRPC_APPEND(encoded_crlf,encoded_crlf_length);
1669     return wrote_something;
1670 }
1671
1672 int write_cc_buffer_as_sami (struct eia608_screen *data, struct s_write *wb)
1673 {
1674     int wrote_something=0;
1675     LLONG startms = wb->data608->current_visible_start_ms;
1676     int i;
1677
1678     startms+=subs_delay;
1679     if (startms<0) // Drop screens that because of subs_delay start too early
1680         return 0; 
1681
1682     LLONG endms   = get_fts(wb)+subs_delay;
1683     endms--; // To prevent overlapping with next line.
1684     sprintf ((char *) str,"<SYNC start=\"%llu\"><P class=\"UNKNOWNCC\">\r\n",startms);
1685     if (debug_608 && encoding!=ENC_UNICODE)
1686     {
1687         hb_log ("\r%s\n", str);
1688     }
1689     wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) str);
1690     fwrite (wb->enc_buffer,wb->enc_buffer_used,1,wb->fh);               
1691     XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
1692     for (i=0;i<15;i++)
1693     {
1694         if (data->row_used[i])
1695         {                               
1696             int length = get_decoder_line_encoded (wb->subline, i, data);
1697             if (debug_608 && encoding!=ENC_UNICODE)
1698             {
1699                 hb_log ("\r");
1700                 hb_log ("%s\n",wb->subline);
1701             }
1702             fwrite (wb->subline, 1, length, wb->fh);
1703             XMLRPC_APPEND(wb->subline,length);
1704             wrote_something=1;
1705             if (i!=14)
1706             {
1707                 fwrite (encoded_br, 1, encoded_br_length,wb->fh);                       
1708                 XMLRPC_APPEND(encoded_br, encoded_br_length);
1709             }
1710             fwrite (encoded_crlf, 1, encoded_crlf_length,wb->fh);
1711             XMLRPC_APPEND(encoded_crlf, encoded_crlf_length);
1712         }
1713     }
1714     sprintf ((char *) str,"</P></SYNC>\r\n");
1715     if (debug_608 && encoding!=ENC_UNICODE)
1716     {
1717         hb_log ("\r%s\n", str);
1718     }
1719     wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) str);
1720     fwrite (wb->enc_buffer,wb->enc_buffer_used,1,wb->fh);
1721     XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
1722     sprintf ((char *) str,"<SYNC start=\"%llu\"><P class=\"UNKNOWNCC\">&nbsp;</P></SYNC>\r\n\r\n",endms);
1723     if (debug_608 && encoding!=ENC_UNICODE)
1724     {
1725         hb_log ("\r%s\n", str);
1726     }
1727     wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) str);
1728     fwrite (wb->enc_buffer,wb->enc_buffer_used,1,wb->fh);
1729     XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
1730     return wrote_something;
1731 }
1732
1733 struct eia608_screen *get_current_visible_buffer (struct s_write *wb)
1734 {
1735     struct eia608_screen *data;
1736     if (wb->data608->visible_buffer==1)
1737         data = &wb->data608->buffer1;
1738     else
1739         data = &wb->data608->buffer2;
1740     return data;
1741 }
1742
1743
1744 int write_cc_buffer (struct s_write *wb)
1745 {
1746     struct eia608_screen *data;
1747     int wrote_something=0;
1748     if (screens_to_process!=-1 && wb->data608->screenfuls_counter>=screens_to_process)
1749     {
1750         // We are done. 
1751         processed_enough=1;
1752         return 0;
1753     }
1754     if (wb->data608->visible_buffer==1)
1755         data = &wb->data608->buffer1;
1756     else
1757         data = &wb->data608->buffer2;
1758
1759     if (!data->empty)
1760     {
1761         wb->new_sentence=1;
1762         switch (write_format)
1763         {
1764             case OF_SRT:
1765                 wrote_something = write_cc_buffer_as_srt (data, wb);
1766                 break;
1767             case OF_SAMI:
1768                 wrote_something = write_cc_buffer_as_sami (data,wb);
1769                 break;
1770             case OF_TRANSCRIPT:
1771                 wrote_something = write_cc_buffer_as_transcript (data,wb);
1772                 break;
1773         default: 
1774                 break;
1775         }
1776         if (wrote_something && gui_mode_reports)
1777             write_cc_buffer_to_gui (data,wb);
1778     }
1779     return wrote_something;
1780 }
1781
1782 void roll_up(struct s_write *wb)
1783 {
1784     struct eia608_screen *use_buffer;
1785     int i, j;
1786
1787     if (wb->data608->visible_buffer==1)
1788         use_buffer = &wb->data608->buffer1;
1789     else
1790         use_buffer = &wb->data608->buffer2;
1791     int keep_lines;
1792     switch (wb->data608->mode)
1793     {
1794         case MODE_ROLLUP_2:
1795             keep_lines=2;
1796             break;
1797         case MODE_ROLLUP_3:
1798             keep_lines=3;
1799             break;
1800         case MODE_ROLLUP_4:
1801             keep_lines=4;
1802             break;
1803         default: // Shouldn't happen
1804             keep_lines=0;
1805             break;
1806     }
1807     int firstrow=-1, lastrow=-1;
1808     // Look for the last line used
1809     int rows_now=0; // Number of rows in use right now
1810     for (i=0;i<15;i++)
1811     {
1812         if (use_buffer->row_used[i])
1813         {
1814             rows_now++;
1815             if (firstrow==-1)
1816                 firstrow=i;
1817             lastrow=i;
1818         }
1819     }
1820     
1821     if (debug_608)
1822         hb_log ("\rIn roll-up: %d lines used, first: %d, last: %d\n", rows_now, firstrow, lastrow);
1823
1824     if (lastrow==-1) // Empty screen, nothing to rollup
1825         return;
1826
1827     for (j=lastrow-keep_lines+1;j<lastrow; j++)
1828     {
1829         if (j>=0)
1830         {
1831             memcpy (use_buffer->characters[j],use_buffer->characters[j+1],CC608_SCREEN_WIDTH+1);
1832             memcpy (use_buffer->colors[j],use_buffer->colors[j+1],CC608_SCREEN_WIDTH+1);
1833             memcpy (use_buffer->fonts[j],use_buffer->fonts[j+1],CC608_SCREEN_WIDTH+1);
1834             use_buffer->row_used[j]=use_buffer->row_used[j+1];
1835         }
1836     }
1837     for (j=0;j<(1+wb->data608->cursor_row-keep_lines);j++)
1838     {
1839         memset(use_buffer->characters[j],' ',CC608_SCREEN_WIDTH);                       
1840         memset(use_buffer->colors[j],COL_WHITE,CC608_SCREEN_WIDTH);
1841         memset(use_buffer->fonts[j],FONT_REGULAR,CC608_SCREEN_WIDTH);
1842         use_buffer->characters[j][CC608_SCREEN_WIDTH]=0;
1843         use_buffer->row_used[j]=0;
1844     }
1845     memset(use_buffer->characters[lastrow],' ',CC608_SCREEN_WIDTH);
1846     memset(use_buffer->colors[lastrow],COL_WHITE,CC608_SCREEN_WIDTH);
1847     memset(use_buffer->fonts[lastrow],FONT_REGULAR,CC608_SCREEN_WIDTH);
1848
1849     use_buffer->characters[lastrow][CC608_SCREEN_WIDTH]=0;
1850     use_buffer->row_used[lastrow]=0;
1851     
1852     // Sanity check
1853     rows_now=0;
1854     for (i=0;i<15;i++)
1855         if (use_buffer->row_used[i])
1856             rows_now++;
1857     if (rows_now>keep_lines)
1858         hb_log ("Bug in roll_up, should have %d lines but I have %d.\n",
1859             keep_lines, rows_now);
1860 }
1861
1862 void erase_memory (struct s_write *wb, int displayed)
1863 {
1864     struct eia608_screen *buf;
1865     if (displayed)
1866     {
1867         if (wb->data608->visible_buffer==1)
1868             buf=&wb->data608->buffer1;
1869         else
1870             buf=&wb->data608->buffer2;
1871     }
1872     else
1873     {
1874         if (wb->data608->visible_buffer==1)
1875             buf=&wb->data608->buffer2;
1876         else
1877             buf=&wb->data608->buffer1;
1878     }
1879     clear_eia608_cc_buffer (buf);
1880 }
1881
1882 int is_current_row_empty (struct s_write *wb)
1883 {
1884     struct eia608_screen *use_buffer;
1885     int i;
1886
1887     if (wb->data608->visible_buffer==1)
1888         use_buffer = &wb->data608->buffer1;
1889     else
1890         use_buffer = &wb->data608->buffer2;
1891     for (i=0;i<CC608_SCREEN_WIDTH;i++)
1892     {
1893         if (use_buffer->characters[wb->data608->rollup_base_row][i]!=' ')
1894             return 0;
1895     }
1896     return 1;
1897 }
1898
1899 /* Process GLOBAL CODES */
1900 void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct s_write *wb)
1901 {
1902     // Handle channel change
1903     wb->data608->channel=wb->new_channel;
1904     if (wb->data608->channel!=cc_channel)
1905         return;
1906
1907     enum command_code command = COM_UNKNOWN;
1908     if (c1==0x15)
1909         c1=0x14;
1910     if ((c1==0x14 || c1==0x1C) && c2==0x2C)
1911         command = COM_ERASEDISPLAYEDMEMORY;
1912     if ((c1==0x14 || c1==0x1C) && c2==0x20)
1913         command = COM_RESUMECAPTIONLOADING;
1914     if ((c1==0x14 || c1==0x1C) && c2==0x2F)
1915         command = COM_ENDOFCAPTION;
1916     if ((c1==0x17 || c1==0x1F) && c2==0x21)
1917         command = COM_TABOFFSET1;
1918     if ((c1==0x17 || c1==0x1F) && c2==0x22)
1919         command = COM_TABOFFSET2;
1920     if ((c1==0x17 || c1==0x1F) && c2==0x23)
1921         command = COM_TABOFFSET3;
1922     if ((c1==0x14 || c1==0x1C) && c2==0x25)
1923         command = COM_ROLLUP2;
1924     if ((c1==0x14 || c1==0x1C) && c2==0x26)
1925         command = COM_ROLLUP3;
1926     if ((c1==0x14 || c1==0x1C) && c2==0x27)
1927         command = COM_ROLLUP4;
1928     if ((c1==0x14 || c1==0x1C) && c2==0x2D)
1929         command = COM_CARRIAGERETURN;
1930     if ((c1==0x14 || c1==0x1C) && c2==0x2E)
1931         command = COM_ERASENONDISPLAYEDMEMORY;
1932     if ((c1==0x14 || c1==0x1C) && c2==0x21)
1933         command = COM_BACKSPACE;
1934     if ((c1==0x14 || c1==0x1C) && c2==0x2b)
1935         command = COM_RESUMETEXTDISPLAY;
1936     if (debug_608)
1937     {
1938         hb_log ("\rCommand: %02X %02X (%s)\n",c1,c2,command_type[command]);
1939     }
1940     switch (command)
1941     {
1942         case COM_BACKSPACE:
1943             if (wb->data608->cursor_column>0)
1944             {
1945                 wb->data608->cursor_column--;
1946                 get_writing_buffer(wb)->characters[wb->data608->cursor_row][wb->data608->cursor_column]=' ';
1947             }
1948             break;
1949         case COM_TABOFFSET1:
1950             if (wb->data608->cursor_column<31)
1951                 wb->data608->cursor_column++;
1952             break;
1953         case COM_TABOFFSET2:
1954             wb->data608->cursor_column+=2;
1955             if (wb->data608->cursor_column>31)
1956                 wb->data608->cursor_column=31;
1957             break;
1958         case COM_TABOFFSET3:
1959             wb->data608->cursor_column+=3;
1960             if (wb->data608->cursor_column>31)
1961                 wb->data608->cursor_column=31;
1962             break;
1963         case COM_RESUMECAPTIONLOADING:
1964             wb->data608->mode=MODE_POPUP;
1965             break;
1966         case COM_RESUMETEXTDISPLAY:
1967             wb->data608->mode=MODE_TEXT;
1968             break;
1969         case COM_ROLLUP2:            
1970             if (wb->data608->mode==MODE_POPUP)
1971             {
1972                 if (write_cc_buffer (wb))
1973                     wb->data608->screenfuls_counter++;
1974                 erase_memory (wb, 1);                   
1975             }
1976             if (wb->data608->mode==MODE_ROLLUP_2 && !is_current_row_empty(wb))
1977             {
1978                 if (debug_608)
1979                     hb_log ("Two RU2, current line not empty. Simulating a CR\n");
1980                 handle_command(0x14, 0x2D, wb);
1981             }   
1982             wb->data608->mode=MODE_ROLLUP_2;
1983             erase_memory (wb, 0);
1984             wb->data608->cursor_column=0;
1985             wb->data608->cursor_row=wb->data608->rollup_base_row;
1986             break;
1987         case COM_ROLLUP3:
1988             if (wb->data608->mode==MODE_POPUP)
1989             {
1990                 if (write_cc_buffer (wb))
1991                     wb->data608->screenfuls_counter++;
1992                 erase_memory (wb, 1);
1993             }
1994             if (wb->data608->mode==MODE_ROLLUP_3 && !is_current_row_empty(wb))
1995             {
1996                 if (debug_608)
1997                     hb_log ("Two RU3, current line not empty. Simulating a CR\n");
1998                 handle_command(0x14, 0x2D, wb);
1999             }
2000             wb->data608->mode=MODE_ROLLUP_3;
2001             erase_memory (wb, 0);
2002             wb->data608->cursor_column=0;
2003             wb->data608->cursor_row=wb->data608->rollup_base_row;
2004             break;
2005         case COM_ROLLUP4:
2006             if (wb->data608->mode==MODE_POPUP)
2007             {
2008                 if (write_cc_buffer (wb))
2009                     wb->data608->screenfuls_counter++;
2010                 erase_memory (wb, 1);                   
2011             }
2012             if (wb->data608->mode==MODE_ROLLUP_4 && !is_current_row_empty(wb))
2013             {
2014                 if (debug_608)
2015                     hb_log ("Two RU4, current line not empty. Simulating a CR\n");
2016                 handle_command(0x14, 0x2D, wb);
2017             }
2018             
2019             wb->data608->mode=MODE_ROLLUP_4;
2020             wb->data608->cursor_column=0;
2021             wb->data608->cursor_row=wb->data608->rollup_base_row;
2022             erase_memory (wb, 0);
2023             break;
2024         case COM_CARRIAGERETURN:
2025             // In transcript mode, CR doesn't write the whole screen, to avoid
2026             // repeated lines.
2027             if (write_format==OF_TRANSCRIPT)
2028             {
2029                 write_cc_line_as_transcript(get_current_visible_buffer (wb), wb, wb->data608->cursor_row);
2030             }
2031             else
2032             {
2033                 if (norollup)
2034                     delete_all_lines_but_current (get_current_visible_buffer (wb), wb->data608->cursor_row);
2035                 if (write_cc_buffer(wb))
2036                     wb->data608->screenfuls_counter++;
2037             }
2038             roll_up(wb);                
2039             wb->data608->current_visible_start_ms=get_fts(wb);
2040             wb->data608->cursor_column=0;
2041             break;
2042         case COM_ERASENONDISPLAYEDMEMORY:
2043             erase_memory (wb,0);
2044             break;
2045         case COM_ERASEDISPLAYEDMEMORY:
2046             // Write it to disk before doing this, and make a note of the new
2047             // time it became clear.
2048             if (write_format==OF_TRANSCRIPT && 
2049                 (wb->data608->mode==MODE_ROLLUP_2 || wb->data608->mode==MODE_ROLLUP_3 ||
2050                 wb->data608->mode==MODE_ROLLUP_4))
2051             {
2052                 // In transcript mode we just write the cursor line. The previous lines
2053                 // should have been written already, so writing everything produces
2054                 // duplicate lines.                
2055                 write_cc_line_as_transcript(get_current_visible_buffer (wb), wb, wb->data608->cursor_row);
2056             }
2057             else
2058             {
2059                 if (write_cc_buffer (wb))
2060                     wb->data608->screenfuls_counter++;
2061             }
2062             erase_memory (wb,1);
2063             wb->data608->current_visible_start_ms=get_fts(wb);
2064             break;
2065         case COM_ENDOFCAPTION: // Switch buffers
2066             // The currently *visible* buffer is leaving, so now we know it's ending
2067             // time. Time to actually write it to file.
2068             if (write_cc_buffer (wb))
2069                 wb->data608->screenfuls_counter++;
2070             wb->data608->visible_buffer = (wb->data608->visible_buffer==1) ? 2 : 1;
2071             wb->data608->current_visible_start_ms=get_fts(wb);
2072             wb->data608->cursor_column=0;
2073             wb->data608->cursor_row=0;
2074             wb->data608->color=default_color;
2075             wb->data608->font=FONT_REGULAR;
2076             break;
2077         default:
2078             if (debug_608)
2079             {
2080                 hb_log ("\rNot yet implemented.\n");
2081             }
2082             break;
2083     }
2084 }
2085
2086 void handle_end_of_data (struct s_write *wb)
2087
2088     // We issue a EraseDisplayedMemory here so if there's any captions pending
2089     // they get written to file. 
2090     handle_command (0x14, 0x2c, wb); // EDM
2091 }
2092
2093 void handle_double (const unsigned char c1, const unsigned char c2, struct s_write *wb)
2094 {
2095     unsigned char c;
2096     if (wb->data608->channel!=cc_channel)
2097         return;
2098     if (c2>=0x30 && c2<=0x3f)
2099     {
2100         c=c2 + 0x50; // So if c>=0x80 && c<=0x8f, it comes from here
2101         if (debug_608)
2102             hb_log ("\rDouble: %02X %02X  -->  %c\n",c1,c2,c);
2103         write_char(c,wb);
2104     }
2105 }
2106
2107 /* Process EXTENDED CHARACTERS */
2108 unsigned char handle_extended (unsigned char hi, unsigned char lo, struct s_write *wb)
2109 {
2110     // Handle channel change
2111     if (wb->new_channel > 2) 
2112     {
2113         wb->new_channel -= 2;
2114         if (debug_608)
2115             hb_log ("\nChannel correction, now %d\n", wb->new_channel);
2116     }
2117     wb->data608->channel=wb->new_channel;
2118     if (wb->data608->channel!=cc_channel)
2119         return 0;
2120
2121     // For lo values between 0x20-0x3f
2122     unsigned char c=0;
2123
2124     if (debug_608)
2125         hb_log ("\rExtended: %02X %02X\n",hi,lo);
2126     if (lo>=0x20 && lo<=0x3f && (hi==0x12 || hi==0x13))
2127     {
2128         switch (hi)
2129         {
2130             case 0x12:
2131                 c=lo+0x70; // So if c>=0x90 && c<=0xaf it comes from here
2132                 break;
2133             case 0x13:
2134                 c=lo+0x90; // So if c>=0xb0 && c<=0xcf it comes from here
2135                 break;
2136         }
2137         // This column change is because extended characters replace 
2138         // the previous character (which is sent for basic decoders
2139         // to show something similar to the real char)
2140         if (wb->data608->cursor_column>0)        
2141             wb->data608->cursor_column--;        
2142
2143         write_char (c,wb);
2144     }
2145     return 1;
2146 }
2147
2148 /* Process PREAMBLE ACCESS CODES (PAC) */
2149 void handle_pac (unsigned char c1, unsigned char c2, struct s_write *wb)
2150 {
2151     // Handle channel change
2152     if (wb->new_channel > 2) 
2153     {
2154         wb->new_channel -= 2;
2155         if (debug_608)
2156             hb_log ("\nChannel correction, now %d\n", wb->new_channel);
2157     }
2158     wb->data608->channel=wb->new_channel;
2159     if (wb->data608->channel!=cc_channel)
2160         return;
2161
2162     int row=rowdata[((c1<<1)&14)|((c2>>5)&1)];
2163
2164     if (debug_608)
2165         hb_log ("\rPAC: %02X %02X",c1,c2);
2166
2167     if (c2>=0x40 && c2<=0x5f)
2168     {
2169         c2=c2-0x40;
2170     }
2171     else
2172     {
2173         if (c2>=0x60 && c2<=0x7f)
2174         {
2175             c2=c2-0x60;
2176         }
2177         else
2178         {
2179             if (debug_608)
2180                 hb_log ("\rThis is not a PAC!!!!!\n");
2181             return;
2182         }
2183     }
2184     int color=pac2_attribs[c2][0];
2185     int font=pac2_attribs[c2][1];
2186     int indent=pac2_attribs[c2][2];
2187     if (debug_608)
2188         hb_log ("  --  Position: %d:%d, color: %s,  font: %s\n",row,
2189         indent,color_text[color][0],font_text[font]);
2190     if (wb->data608->mode!=MODE_TEXT)
2191     {
2192         // According to Robson, row info is discarded in text mode
2193         // but column is accepted
2194         wb->data608->cursor_row=row-1 ; // Since the array is 0 based
2195     }
2196     wb->data608->rollup_base_row=row-1;
2197     wb->data608->cursor_column=indent;  
2198 }
2199
2200
2201 void handle_single (const unsigned char c1, struct s_write *wb)
2202 {       
2203     if (c1<0x20 || wb->data608->channel!=cc_channel)
2204         return; // We don't allow special stuff here
2205     if (debug_608)
2206         hb_log ("%c",c1);
2207
2208     /*if (debug_608)
2209     hb_log ("Character: %02X (%c) -> %02X (%c)\n",c1,c1,c,c); */
2210     write_char (c1,wb);
2211 }
2212
2213 int check_channel (unsigned char c1, struct s_write *wb)
2214 {
2215     if (c1==0x14) 
2216     {
2217         if (debug_608 && wb->data608->channel!=1)
2218             hb_log ("\nChannel change, now 1\n");
2219         return 1;
2220     }
2221     if (c1==0x1c) 
2222     {
2223         if (debug_608 && wb->data608->channel!=2)
2224             hb_log ("\nChannel change, now 2\n");
2225         return 2;
2226     }
2227     if (c1==0x15) 
2228     {
2229         if (debug_608 && wb->data608->channel!=3)
2230             hb_log ("\nChannel change, now 3\n");
2231         return 3;
2232     }
2233     if (c1==0x1d) 
2234     {
2235         if (debug_608 && wb->data608->channel!=4)
2236             hb_log ("\nChannel change, now 4\n");
2237         return 4;
2238     }
2239
2240     // Otherwise keep the current channel
2241     return wb->data608->channel;
2242 }
2243
2244 /* Handle Command, special char or attribute and also check for
2245 * channel changes.
2246 * Returns 1 if something was written to screen, 0 otherwise */
2247 int disCommand (unsigned char hi, unsigned char lo, struct s_write *wb)
2248 {
2249     int wrote_to_screen=0;
2250
2251     /* Full channel changes are only allowed for "GLOBAL CODES",
2252     * "OTHER POSITIONING CODES", "BACKGROUND COLOR CODES",
2253     * "MID-ROW CODES".
2254     * "PREAMBLE ACCESS CODES", "BACKGROUND COLOR CODES" and
2255     * SPECIAL/SPECIAL CHARACTERS allow only switching
2256     * between 1&3 or 2&4. */
2257     wb->new_channel = check_channel (hi,wb);
2258     //if (wb->data608->channel!=cc_channel)
2259     //    continue;
2260
2261     if (hi>=0x18 && hi<=0x1f)
2262         hi=hi-8;
2263
2264     switch (hi)
2265     {
2266         case 0x10:
2267             if (lo>=0x40 && lo<=0x5f)
2268                 handle_pac (hi,lo,wb);
2269             break;
2270         case 0x11:
2271             if (lo>=0x20 && lo<=0x2f)
2272                 handle_text_attr (hi,lo,wb);
2273             if (lo>=0x30 && lo<=0x3f)
2274             {
2275                 wrote_to_screen=1;
2276                 handle_double (hi,lo,wb);
2277             }
2278             if (lo>=0x40 && lo<=0x7f)
2279                 handle_pac (hi,lo,wb);
2280             break;
2281         case 0x12:
2282         case 0x13:
2283             if (lo>=0x20 && lo<=0x3f)
2284             {
2285                 wrote_to_screen=handle_extended (hi,lo,wb);
2286             }
2287             if (lo>=0x40 && lo<=0x7f)
2288                 handle_pac (hi,lo,wb);
2289             break;
2290         case 0x14:
2291         case 0x15:
2292             if (lo>=0x20 && lo<=0x2f)
2293                 handle_command (hi,lo,wb);
2294             if (lo>=0x40 && lo<=0x7f)
2295                 handle_pac (hi,lo,wb);
2296             break;
2297         case 0x16:
2298             if (lo>=0x40 && lo<=0x7f)
2299                 handle_pac (hi,lo,wb);
2300             break;
2301         case 0x17:
2302             if (lo>=0x21 && lo<=0x22)
2303                 handle_command (hi,lo,wb);
2304             if (lo>=0x2e && lo<=0x2f)
2305                 handle_text_attr (hi,lo,wb);
2306             if (lo>=0x40 && lo<=0x7f)
2307                 handle_pac (hi,lo,wb);
2308             break;
2309     }
2310     return wrote_to_screen;
2311 }
2312
2313 void process608 (const unsigned char *data, int length, struct s_write *wb)
2314 {
2315     static int textprinted = 0;
2316     int i;
2317
2318     if (data!=NULL)
2319     {
2320         for (i=0;i<length;i=i+2)
2321         {
2322             unsigned char hi, lo;
2323             int wrote_to_screen=0; 
2324             hi = data[i] & 0x7F; // Get rid of parity bit
2325             lo = data[i+1] & 0x7F; // Get rid of parity bit
2326
2327             if (hi==0 && lo==0) // Just padding
2328                 continue;
2329             // hb_log ("\r[%02X:%02X]\n",hi,lo);
2330
2331             if (hi>=0x01 && hi<=0x0E)
2332             {
2333                 // XDS crap - mode. Would be nice to support it eventually
2334                 // wb->data608->last_c1=0;
2335                 // wb->data608->last_c2=0;
2336                 wb->data608->channel=3; // Always channel 3
2337                 wb->in_xds_mode=1;
2338             }
2339             if (hi==0x0F) // End of XDS block
2340             {
2341                 wb->in_xds_mode=0;
2342                 continue;
2343             }
2344             if (hi>=0x10 && hi<0x1F) // Non-character code or special/extended char
2345                 // http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/CC_CODES.HTML
2346                 // http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/CC_CHARS.HTML
2347             {
2348                 // We were writing characters before, start a new line for
2349                 // diagnostic output from disCommand()
2350                 if (debug_608 && textprinted == 1 )
2351                 {
2352                     hb_log("\n");
2353                     textprinted = 0;
2354                 }
2355
2356                 wb->in_xds_mode=0; // Back to normal
2357                 if (wb->data608->last_c1==hi && wb->data608->last_c2==lo)
2358                 {
2359                     // Duplicate dual code, discard
2360                     continue;
2361                 }
2362                 wb->data608->last_c1=hi;
2363                 wb->data608->last_c2=lo;
2364                 wrote_to_screen=disCommand (hi,lo,wb);
2365             }
2366             if (hi>=0x20) // Standard characters (always in pairs)
2367             {
2368                 // Only print if the channel is active
2369                 if (wb->data608->channel!=cc_channel)
2370                     continue;
2371
2372                 if (debug_608)
2373                 {
2374                     if( textprinted == 0 )
2375                     {
2376                         hb_log("\n");
2377                         textprinted = 1;
2378                     }
2379                 }
2380
2381                 handle_single(hi,wb);
2382                 handle_single(lo,wb);
2383                 wrote_to_screen=1;
2384                 wb->data608->last_c1=0;
2385                 wb->data608->last_c2=0;
2386             }
2387
2388             if ( debug_608 && !textprinted && wb->data608->channel==cc_channel )
2389             {   // Current FTS information after the characters are shown
2390                 //hb_log("Current FTS: %s\n", print_mstime(get_fts()));
2391             }
2392
2393             if (wrote_to_screen && direct_rollup && // If direct_rollup is enabled and
2394                 (wb->data608->mode==MODE_ROLLUP_2 || // we are in rollup mode, write now.
2395                 wb->data608->mode==MODE_ROLLUP_3 ||
2396                 wb->data608->mode==MODE_ROLLUP_4))
2397             {
2398                 // We don't increase screenfuls_counter here.
2399                 write_cc_buffer (wb);
2400                 wb->data608->current_visible_start_ms=get_fts(wb);
2401             }
2402         }
2403     }
2404 }
2405
2406
2407 /* Return a pointer to a string that holds the printable characters
2408  * of the caption data block. FOR DEBUG PURPOSES ONLY! */
2409 unsigned char *debug_608toASC (unsigned char *cc_data, int channel)
2410 {
2411     static unsigned char output[3];
2412
2413     unsigned char cc_valid = (cc_data[0] & 4) >>2;
2414     unsigned char cc_type = cc_data[0] & 3;
2415     unsigned char hi, lo;
2416
2417     output[0]=' ';
2418     output[1]=' ';
2419     output[2]='\x00';
2420
2421     if (cc_valid && cc_type==channel)
2422     {
2423         hi = cc_data[1] & 0x7F; // Get rid of parity bit
2424         lo = cc_data[2] & 0x7F; // Get rid of parity bit
2425         if (hi>=0x20)
2426         {
2427             output[0]=hi;
2428             output[1]=(lo>=20 ? lo : '.');
2429             output[2]='\x00';
2430         }
2431         else
2432         {
2433             output[0]='<';
2434             output[1]='>';
2435             output[2]='\x00';
2436         }
2437     }
2438     return output;
2439 }
2440
2441
2442 struct hb_work_private_s
2443 {
2444     hb_job_t           * job;
2445     struct s_write     * cc608;
2446 };
2447
2448 int decccInit( hb_work_object_t * w, hb_job_t * job )
2449 {
2450     int retval = 1;
2451     hb_work_private_t * pv;
2452
2453     pv = calloc( 1, sizeof( hb_work_private_t ) );
2454     if( pv )
2455     {
2456         w->private_data = pv;
2457
2458         pv->job = job;
2459
2460         pv->cc608 = calloc(1, sizeof(struct s_write));
2461
2462         if( pv->cc608 )
2463         {
2464             retval = general_608_init(pv->cc608);
2465             if( !retval )
2466             {
2467                 pv->cc608->data608 = calloc(1, sizeof(struct eia608));
2468                 if( !pv->cc608->data608 )
2469                 {
2470                     retval = 1;
2471                 }
2472             }
2473         }
2474     }
2475     return retval;
2476 }
2477
2478 int decccWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
2479                hb_buffer_t ** buf_out )
2480 {
2481     hb_work_private_t * pv = w->private_data;
2482     hb_buffer_t * in = *buf_in;
2483
2484     if ( in->size <= 0 )
2485     {
2486         /* EOF on input stream - send it downstream & say that we're done */
2487         handle_end_of_data(pv->cc608);
2488         /*
2489          * Grab any pending buffer and output them with the EOF on the end
2490          */
2491         if (pv->cc608->hb_last_buffer) {
2492             pv->cc608->hb_last_buffer->next = in;
2493             *buf_out = pv->cc608->hb_buffer;
2494             *buf_in = NULL;
2495             pv->cc608->hb_buffer = NULL;
2496             pv->cc608->hb_last_buffer = NULL;
2497         } else {
2498             *buf_out = in;
2499             *buf_in = NULL;
2500         }
2501         return HB_WORK_DONE;
2502     }
2503
2504     pv->cc608->last_pts = in->start;
2505
2506     process608(in->data, in->size, pv->cc608);
2507
2508     /*
2509      * If there is one waiting then pass it on
2510      */
2511     *buf_out = pv->cc608->hb_buffer;
2512     pv->cc608->hb_buffer = NULL;
2513     pv->cc608->hb_last_buffer = NULL;
2514
2515     return HB_WORK_OK; 
2516 }
2517
2518 void decccClose( hb_work_object_t * w )
2519 {
2520     hb_work_private_t * pv = w->private_data;
2521     general_608_close( pv->cc608 );
2522     free( pv->cc608->data608 );
2523     free( pv->cc608 );
2524     free( w->private_data );
2525 }
2526
2527 hb_work_object_t hb_deccc608 =
2528 {
2529     WORK_DECCC608,
2530     "Closed Caption (608) decoder",
2531     decccInit,
2532     decccWork,
2533     decccClose
2534 };