OSDN Git Service

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