OSDN Git Service

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