OSDN Git Service

Removed double EOF for CC's (one from dvd and one from cc), fixed compiler warnings...
[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( length + 1 );
1494         buffer->start = wb->data608->current_visible_start_ms;
1495         buffer->stop = get_fts(wb);
1496         memcpy( buffer->data, wb->subline, length + 1 );
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             if (length > 0)
1619             {
1620                 hb_buffer_t *buffer = hb_buffer_init( length + 1 );
1621                 buffer->start = ms_start;
1622                 buffer->stop = ms_end;
1623                 memcpy( buffer->data, wb->subline, length + 1 );
1624                 
1625                 hb_fifo_push( wb->subtitle->fifo_raw, buffer );
1626                 
1627                 //fwrite (wb->subline, 1, length, wb->fh);
1628                 XMLRPC_APPEND(wb->subline,length);
1629                 //fwrite (encoded_crlf, 1, encoded_crlf_length,wb->fh);
1630                 XMLRPC_APPEND(encoded_crlf,encoded_crlf_length);
1631                 wrote_something=1;
1632                 // fhb_log (wb->fh,encoded_crlf);
1633             }
1634         }
1635     }
1636     if (debug_608)
1637     {
1638         hb_log ("- - - - - - - - - - - -\r\n");
1639     }
1640     // fhb_log (wb->fh, encoded_crlf);
1641     //fwrite (encoded_crlf, 1, encoded_crlf_length,wb->fh);
1642     XMLRPC_APPEND(encoded_crlf,encoded_crlf_length);
1643     return wrote_something;
1644 }
1645
1646 int write_cc_buffer_as_sami (struct eia608_screen *data, struct s_write *wb)
1647 {
1648     int wrote_something=0;
1649     LLONG startms = wb->data608->current_visible_start_ms;
1650     int i;
1651
1652     startms+=subs_delay;
1653     if (startms<0) // Drop screens that because of subs_delay start too early
1654         return 0; 
1655
1656     LLONG endms   = get_fts(wb)+subs_delay;
1657     endms--; // To prevent overlapping with next line.
1658     sprintf ((char *) str,"<SYNC start=\"%llu\"><P class=\"UNKNOWNCC\">\r\n",startms);
1659     if (debug_608 && encoding!=ENC_UNICODE)
1660     {
1661         hb_log ("\r%s\n", str);
1662     }
1663     enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
1664     fwrite (enc_buffer,enc_buffer_used,1,wb->fh);               
1665     XMLRPC_APPEND(enc_buffer,enc_buffer_used);
1666     for (i=0;i<15;i++)
1667     {
1668         if (data->row_used[i])
1669         {                               
1670             int length = get_decoder_line_encoded (wb->subline, i, data);
1671             if (debug_608 && encoding!=ENC_UNICODE)
1672             {
1673                 hb_log ("\r");
1674                 hb_log ("%s\n",wb->subline);
1675             }
1676             fwrite (wb->subline, 1, length, wb->fh);
1677             XMLRPC_APPEND(wb->subline,length);
1678             wrote_something=1;
1679             if (i!=14)
1680             {
1681                 fwrite (encoded_br, 1, encoded_br_length,wb->fh);                       
1682                 XMLRPC_APPEND(encoded_br, encoded_br_length);
1683             }
1684             fwrite (encoded_crlf, 1, encoded_crlf_length,wb->fh);
1685             XMLRPC_APPEND(encoded_crlf, encoded_crlf_length);
1686         }
1687     }
1688     sprintf ((char *) str,"</P></SYNC>\r\n");
1689     if (debug_608 && encoding!=ENC_UNICODE)
1690     {
1691         hb_log ("\r%s\n", str);
1692     }
1693     enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
1694     fwrite (enc_buffer,enc_buffer_used,1,wb->fh);
1695     XMLRPC_APPEND(enc_buffer,enc_buffer_used);
1696     sprintf ((char *) str,"<SYNC start=\"%llu\"><P class=\"UNKNOWNCC\">&nbsp;</P></SYNC>\r\n\r\n",endms);
1697     if (debug_608 && encoding!=ENC_UNICODE)
1698     {
1699         hb_log ("\r%s\n", str);
1700     }
1701     enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
1702     fwrite (enc_buffer,enc_buffer_used,1,wb->fh);
1703     XMLRPC_APPEND(enc_buffer,enc_buffer_used);
1704     return wrote_something;
1705 }
1706
1707 struct eia608_screen *get_current_visible_buffer (struct s_write *wb)
1708 {
1709     struct eia608_screen *data;
1710     if (wb->data608->visible_buffer==1)
1711         data = &wb->data608->buffer1;
1712     else
1713         data = &wb->data608->buffer2;
1714     return data;
1715 }
1716
1717
1718 int write_cc_buffer (struct s_write *wb)
1719 {
1720     struct eia608_screen *data;
1721     int wrote_something=0;
1722     if (screens_to_process!=-1 && wb->data608->screenfuls_counter>=screens_to_process)
1723     {
1724         // We are done. 
1725         processed_enough=1;
1726         return 0;
1727     }
1728     if (wb->data608->visible_buffer==1)
1729         data = &wb->data608->buffer1;
1730     else
1731         data = &wb->data608->buffer2;
1732
1733     if (!data->empty)
1734     {
1735         wb->new_sentence=1;
1736         switch (write_format)
1737         {
1738             case OF_SRT:
1739                 wrote_something = write_cc_buffer_as_srt (data, wb);
1740                 break;
1741             case OF_SAMI:
1742                 wrote_something = write_cc_buffer_as_sami (data,wb);
1743                 break;
1744             case OF_TRANSCRIPT:
1745                 wrote_something = write_cc_buffer_as_transcript (data,wb);
1746                 break;
1747         default: 
1748                 break;
1749         }
1750         if (wrote_something && gui_mode_reports)
1751             write_cc_buffer_to_gui (data,wb);
1752     }
1753     return wrote_something;
1754 }
1755
1756 void roll_up(struct s_write *wb)
1757 {
1758     struct eia608_screen *use_buffer;
1759     int i, j;
1760
1761     if (wb->data608->visible_buffer==1)
1762         use_buffer = &wb->data608->buffer1;
1763     else
1764         use_buffer = &wb->data608->buffer2;
1765     int keep_lines;
1766     switch (wb->data608->mode)
1767     {
1768         case MODE_ROLLUP_2:
1769             keep_lines=2;
1770             break;
1771         case MODE_ROLLUP_3:
1772             keep_lines=3;
1773             break;
1774         case MODE_ROLLUP_4:
1775             keep_lines=4;
1776             break;
1777         default: // Shouldn't happen
1778             keep_lines=0;
1779             break;
1780     }
1781     int firstrow=-1, lastrow=-1;
1782     // Look for the last line used
1783     int rows_now=0; // Number of rows in use right now
1784     for (i=0;i<15;i++)
1785     {
1786         if (use_buffer->row_used[i])
1787         {
1788             rows_now++;
1789             if (firstrow==-1)
1790                 firstrow=i;
1791             lastrow=i;
1792         }
1793     }
1794     
1795     if (debug_608)
1796         hb_log ("\rIn roll-up: %d lines used, first: %d, last: %d\n", rows_now, firstrow, lastrow);
1797
1798     if (lastrow==-1) // Empty screen, nothing to rollup
1799         return;
1800
1801     for (j=lastrow-keep_lines+1;j<lastrow; j++)
1802     {
1803         if (j>=0)
1804         {
1805             memcpy (use_buffer->characters[j],use_buffer->characters[j+1],CC608_SCREEN_WIDTH+1);
1806             memcpy (use_buffer->colors[j],use_buffer->colors[j+1],CC608_SCREEN_WIDTH+1);
1807             memcpy (use_buffer->fonts[j],use_buffer->fonts[j+1],CC608_SCREEN_WIDTH+1);
1808             use_buffer->row_used[j]=use_buffer->row_used[j+1];
1809         }
1810     }
1811     for (j=0;j<(1+wb->data608->cursor_row-keep_lines);j++)
1812     {
1813         memset(use_buffer->characters[j],' ',CC608_SCREEN_WIDTH);                       
1814         memset(use_buffer->colors[j],COL_WHITE,CC608_SCREEN_WIDTH);
1815         memset(use_buffer->fonts[j],FONT_REGULAR,CC608_SCREEN_WIDTH);
1816         use_buffer->characters[j][CC608_SCREEN_WIDTH]=0;
1817         use_buffer->row_used[j]=0;
1818     }
1819     memset(use_buffer->characters[lastrow],' ',CC608_SCREEN_WIDTH);
1820     memset(use_buffer->colors[lastrow],COL_WHITE,CC608_SCREEN_WIDTH);
1821     memset(use_buffer->fonts[lastrow],FONT_REGULAR,CC608_SCREEN_WIDTH);
1822
1823     use_buffer->characters[lastrow][CC608_SCREEN_WIDTH]=0;
1824     use_buffer->row_used[lastrow]=0;
1825     
1826     // Sanity check
1827     rows_now=0;
1828     for (i=0;i<15;i++)
1829         if (use_buffer->row_used[i])
1830             rows_now++;
1831     if (rows_now>keep_lines)
1832         hb_log ("Bug in roll_up, should have %d lines but I have %d.\n",
1833             keep_lines, rows_now);
1834 }
1835
1836 void erase_memory (struct s_write *wb, int displayed)
1837 {
1838     struct eia608_screen *buf;
1839     if (displayed)
1840     {
1841         if (wb->data608->visible_buffer==1)
1842             buf=&wb->data608->buffer1;
1843         else
1844             buf=&wb->data608->buffer2;
1845     }
1846     else
1847     {
1848         if (wb->data608->visible_buffer==1)
1849             buf=&wb->data608->buffer2;
1850         else
1851             buf=&wb->data608->buffer1;
1852     }
1853     clear_eia608_cc_buffer (buf);
1854 }
1855
1856 int is_current_row_empty (struct s_write *wb)
1857 {
1858     struct eia608_screen *use_buffer;
1859     int i;
1860
1861     if (wb->data608->visible_buffer==1)
1862         use_buffer = &wb->data608->buffer1;
1863     else
1864         use_buffer = &wb->data608->buffer2;
1865     for (i=0;i<CC608_SCREEN_WIDTH;i++)
1866     {
1867         if (use_buffer->characters[wb->data608->rollup_base_row][i]!=' ')
1868             return 0;
1869     }
1870     return 1;
1871 }
1872
1873 /* Process GLOBAL CODES */
1874 void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct s_write *wb)
1875 {
1876     // Handle channel change
1877     wb->data608->channel=wb->new_channel;
1878     if (wb->data608->channel!=cc_channel)
1879         return;
1880
1881     enum command_code command = COM_UNKNOWN;
1882     if (c1==0x15)
1883         c1=0x14;
1884     if ((c1==0x14 || c1==0x1C) && c2==0x2C)
1885         command = COM_ERASEDISPLAYEDMEMORY;
1886     if ((c1==0x14 || c1==0x1C) && c2==0x20)
1887         command = COM_RESUMECAPTIONLOADING;
1888     if ((c1==0x14 || c1==0x1C) && c2==0x2F)
1889         command = COM_ENDOFCAPTION;
1890     if ((c1==0x17 || c1==0x1F) && c2==0x21)
1891         command = COM_TABOFFSET1;
1892     if ((c1==0x17 || c1==0x1F) && c2==0x22)
1893         command = COM_TABOFFSET2;
1894     if ((c1==0x17 || c1==0x1F) && c2==0x23)
1895         command = COM_TABOFFSET3;
1896     if ((c1==0x14 || c1==0x1C) && c2==0x25)
1897         command = COM_ROLLUP2;
1898     if ((c1==0x14 || c1==0x1C) && c2==0x26)
1899         command = COM_ROLLUP3;
1900     if ((c1==0x14 || c1==0x1C) && c2==0x27)
1901         command = COM_ROLLUP4;
1902     if ((c1==0x14 || c1==0x1C) && c2==0x2D)
1903         command = COM_CARRIAGERETURN;
1904     if ((c1==0x14 || c1==0x1C) && c2==0x2E)
1905         command = COM_ERASENONDISPLAYEDMEMORY;
1906     if ((c1==0x14 || c1==0x1C) && c2==0x21)
1907         command = COM_BACKSPACE;
1908     if ((c1==0x14 || c1==0x1C) && c2==0x2b)
1909         command = COM_RESUMETEXTDISPLAY;
1910     if (debug_608)
1911     {
1912         hb_log ("\rCommand: %02X %02X (%s)\n",c1,c2,command_type[command]);
1913     }
1914     switch (command)
1915     {
1916         case COM_BACKSPACE:
1917             if (wb->data608->cursor_column>0)
1918             {
1919                 wb->data608->cursor_column--;
1920                 get_writing_buffer(wb)->characters[wb->data608->cursor_row][wb->data608->cursor_column]=' ';
1921             }
1922             break;
1923         case COM_TABOFFSET1:
1924             if (wb->data608->cursor_column<31)
1925                 wb->data608->cursor_column++;
1926             break;
1927         case COM_TABOFFSET2:
1928             wb->data608->cursor_column+=2;
1929             if (wb->data608->cursor_column>31)
1930                 wb->data608->cursor_column=31;
1931             break;
1932         case COM_TABOFFSET3:
1933             wb->data608->cursor_column+=3;
1934             if (wb->data608->cursor_column>31)
1935                 wb->data608->cursor_column=31;
1936             break;
1937         case COM_RESUMECAPTIONLOADING:
1938             wb->data608->mode=MODE_POPUP;
1939             break;
1940         case COM_RESUMETEXTDISPLAY:
1941             wb->data608->mode=MODE_TEXT;
1942             break;
1943         case COM_ROLLUP2:            
1944             if (wb->data608->mode==MODE_POPUP)
1945             {
1946                 if (write_cc_buffer (wb))
1947                     wb->data608->screenfuls_counter++;
1948                 erase_memory (wb, 1);                   
1949             }
1950             if (wb->data608->mode==MODE_ROLLUP_2 && !is_current_row_empty(wb))
1951             {
1952                 if (debug_608)
1953                     hb_log ("Two RU2, current line not empty. Simulating a CR\n");
1954                 handle_command(0x14, 0x2D, wb);
1955             }   
1956             wb->data608->mode=MODE_ROLLUP_2;
1957             erase_memory (wb, 0);
1958             wb->data608->cursor_column=0;
1959             wb->data608->cursor_row=wb->data608->rollup_base_row;
1960             break;
1961         case COM_ROLLUP3:
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_3 && !is_current_row_empty(wb))
1969             {
1970                 if (debug_608)
1971                     hb_log ("Two RU3, current line not empty. Simulating a CR\n");
1972                 handle_command(0x14, 0x2D, wb);
1973             }
1974             wb->data608->mode=MODE_ROLLUP_3;
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_ROLLUP4:
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_4 && !is_current_row_empty(wb))
1987             {
1988                 if (debug_608)
1989                     hb_log ("Two RU4, current line not empty. Simulating a CR\n");
1990                 handle_command(0x14, 0x2D, wb);
1991             }
1992             
1993             wb->data608->mode=MODE_ROLLUP_4;
1994             wb->data608->cursor_column=0;
1995             wb->data608->cursor_row=wb->data608->rollup_base_row;
1996             erase_memory (wb, 0);
1997             break;
1998         case COM_CARRIAGERETURN:
1999             // In transcript mode, CR doesn't write the whole screen, to avoid
2000             // repeated lines.
2001             if (write_format==OF_TRANSCRIPT)
2002             {
2003                 write_cc_line_as_transcript(get_current_visible_buffer (wb), wb, wb->data608->cursor_row);
2004             }
2005             else
2006             {
2007                 if (norollup)
2008                     delete_all_lines_but_current (get_current_visible_buffer (wb), wb->data608->cursor_row);
2009                 if (write_cc_buffer(wb))
2010                     wb->data608->screenfuls_counter++;
2011             }
2012             roll_up(wb);                
2013             wb->data608->current_visible_start_ms=get_fts(wb);
2014             wb->data608->cursor_column=0;
2015             break;
2016         case COM_ERASENONDISPLAYEDMEMORY:
2017             erase_memory (wb,0);
2018             break;
2019         case COM_ERASEDISPLAYEDMEMORY:
2020             // Write it to disk before doing this, and make a note of the new
2021             // time it became clear.
2022             if (write_format==OF_TRANSCRIPT && 
2023                 (wb->data608->mode==MODE_ROLLUP_2 || wb->data608->mode==MODE_ROLLUP_3 ||
2024                 wb->data608->mode==MODE_ROLLUP_4))
2025             {
2026                 // In transcript mode we just write the cursor line. The previous lines
2027                 // should have been written already, so writing everything produces
2028                 // duplicate lines.                
2029                 write_cc_line_as_transcript(get_current_visible_buffer (wb), wb, wb->data608->cursor_row);
2030             }
2031             else
2032             {
2033                 if (write_cc_buffer (wb))
2034                     wb->data608->screenfuls_counter++;
2035             }
2036             erase_memory (wb,1);
2037             wb->data608->current_visible_start_ms=get_fts(wb);
2038             break;
2039         case COM_ENDOFCAPTION: // Switch buffers
2040             // The currently *visible* buffer is leaving, so now we know it's ending
2041             // time. Time to actually write it to file.
2042             if (write_cc_buffer (wb))
2043                 wb->data608->screenfuls_counter++;
2044             wb->data608->visible_buffer = (wb->data608->visible_buffer==1) ? 2 : 1;
2045             wb->data608->current_visible_start_ms=get_fts(wb);
2046             wb->data608->cursor_column=0;
2047             wb->data608->cursor_row=0;
2048             wb->data608->color=default_color;
2049             wb->data608->font=FONT_REGULAR;
2050             break;
2051         default:
2052             if (debug_608)
2053             {
2054                 hb_log ("\rNot yet implemented.\n");
2055             }
2056             break;
2057     }
2058 }
2059
2060 void handle_end_of_data (struct s_write *wb)
2061
2062     hb_buffer_t *buffer;
2063
2064     // We issue a EraseDisplayedMemory here so if there's any captions pending
2065     // they get written to file. 
2066     handle_command (0x14, 0x2c, wb); // EDM
2067
2068     /*
2069      * At the end of the subtitle stream HB wants an empty buffer
2070      */
2071     buffer = hb_buffer_init( 0 );
2072     hb_fifo_push( wb->subtitle->fifo_raw, buffer );
2073 }
2074
2075 void handle_double (const unsigned char c1, const unsigned char c2, struct s_write *wb)
2076 {
2077     unsigned char c;
2078     if (wb->data608->channel!=cc_channel)
2079         return;
2080     if (c2>=0x30 && c2<=0x3f)
2081     {
2082         c=c2 + 0x50; // So if c>=0x80 && c<=0x8f, it comes from here
2083         if (debug_608)
2084             hb_log ("\rDouble: %02X %02X  -->  %c\n",c1,c2,c);
2085         write_char(c,wb);
2086     }
2087 }
2088
2089 /* Process EXTENDED CHARACTERS */
2090 unsigned char handle_extended (unsigned char hi, unsigned char lo, struct s_write *wb)
2091 {
2092     // Handle channel change
2093     if (wb->new_channel > 2) 
2094     {
2095         wb->new_channel -= 2;
2096         if (debug_608)
2097             hb_log ("\nChannel correction, now %d\n", wb->new_channel);
2098     }
2099     wb->data608->channel=wb->new_channel;
2100     if (wb->data608->channel!=cc_channel)
2101         return 0;
2102
2103     // For lo values between 0x20-0x3f
2104     unsigned char c=0;
2105
2106     if (debug_608)
2107         hb_log ("\rExtended: %02X %02X\n",hi,lo);
2108     if (lo>=0x20 && lo<=0x3f && (hi==0x12 || hi==0x13))
2109     {
2110         switch (hi)
2111         {
2112             case 0x12:
2113                 c=lo+0x70; // So if c>=0x90 && c<=0xaf it comes from here
2114                 break;
2115             case 0x13:
2116                 c=lo+0x90; // So if c>=0xb0 && c<=0xcf it comes from here
2117                 break;
2118         }
2119         // This column change is because extended characters replace 
2120         // the previous character (which is sent for basic decoders
2121         // to show something similar to the real char)
2122         if (wb->data608->cursor_column>0)        
2123             wb->data608->cursor_column--;        
2124
2125         write_char (c,wb);
2126     }
2127     return 1;
2128 }
2129
2130 /* Process PREAMBLE ACCESS CODES (PAC) */
2131 void handle_pac (unsigned char c1, unsigned char c2, struct s_write *wb)
2132 {
2133     // Handle channel change
2134     if (wb->new_channel > 2) 
2135     {
2136         wb->new_channel -= 2;
2137         if (debug_608)
2138             hb_log ("\nChannel correction, now %d\n", wb->new_channel);
2139     }
2140     wb->data608->channel=wb->new_channel;
2141     if (wb->data608->channel!=cc_channel)
2142         return;
2143
2144     int row=rowdata[((c1<<1)&14)|((c2>>5)&1)];
2145
2146     if (debug_608)
2147         hb_log ("\rPAC: %02X %02X",c1,c2);
2148
2149     if (c2>=0x40 && c2<=0x5f)
2150     {
2151         c2=c2-0x40;
2152     }
2153     else
2154     {
2155         if (c2>=0x60 && c2<=0x7f)
2156         {
2157             c2=c2-0x60;
2158         }
2159         else
2160         {
2161             if (debug_608)
2162                 hb_log ("\rThis is not a PAC!!!!!\n");
2163             return;
2164         }
2165     }
2166     int color=pac2_attribs[c2][0];
2167     int font=pac2_attribs[c2][1];
2168     int indent=pac2_attribs[c2][2];
2169     if (debug_608)
2170         hb_log ("  --  Position: %d:%d, color: %s,  font: %s\n",row,
2171         indent,color_text[color][0],font_text[font]);
2172     if (wb->data608->mode!=MODE_TEXT)
2173     {
2174         // According to Robson, row info is discarded in text mode
2175         // but column is accepted
2176         wb->data608->cursor_row=row-1 ; // Since the array is 0 based
2177     }
2178     wb->data608->rollup_base_row=row-1;
2179     wb->data608->cursor_column=indent;  
2180 }
2181
2182
2183 void handle_single (const unsigned char c1, struct s_write *wb)
2184 {       
2185     if (c1<0x20 || wb->data608->channel!=cc_channel)
2186         return; // We don't allow special stuff here
2187     if (debug_608)
2188         hb_log ("%c",c1);
2189
2190     /*if (debug_608)
2191     hb_log ("Character: %02X (%c) -> %02X (%c)\n",c1,c1,c,c); */
2192     write_char (c1,wb);
2193 }
2194
2195 int check_channel (unsigned char c1, struct s_write *wb)
2196 {
2197     if (c1==0x14) 
2198     {
2199         if (debug_608 && wb->data608->channel!=1)
2200             hb_log ("\nChannel change, now 1\n");
2201         return 1;
2202     }
2203     if (c1==0x1c) 
2204     {
2205         if (debug_608 && wb->data608->channel!=2)
2206             hb_log ("\nChannel change, now 2\n");
2207         return 2;
2208     }
2209     if (c1==0x15) 
2210     {
2211         if (debug_608 && wb->data608->channel!=3)
2212             hb_log ("\nChannel change, now 3\n");
2213         return 3;
2214     }
2215     if (c1==0x1d) 
2216     {
2217         if (debug_608 && wb->data608->channel!=4)
2218             hb_log ("\nChannel change, now 4\n");
2219         return 4;
2220     }
2221
2222     // Otherwise keep the current channel
2223     return wb->data608->channel;
2224 }
2225
2226 /* Handle Command, special char or attribute and also check for
2227 * channel changes.
2228 * Returns 1 if something was written to screen, 0 otherwise */
2229 int disCommand (unsigned char hi, unsigned char lo, struct s_write *wb)
2230 {
2231     int wrote_to_screen=0;
2232
2233     /* Full channel changes are only allowed for "GLOBAL CODES",
2234     * "OTHER POSITIONING CODES", "BACKGROUND COLOR CODES",
2235     * "MID-ROW CODES".
2236     * "PREAMBLE ACCESS CODES", "BACKGROUND COLOR CODES" and
2237     * SPECIAL/SPECIAL CHARACTERS allow only switching
2238     * between 1&3 or 2&4. */
2239     wb->new_channel = check_channel (hi,wb);
2240     //if (wb->data608->channel!=cc_channel)
2241     //    continue;
2242
2243     if (hi>=0x18 && hi<=0x1f)
2244         hi=hi-8;
2245
2246     switch (hi)
2247     {
2248         case 0x10:
2249             if (lo>=0x40 && lo<=0x5f)
2250                 handle_pac (hi,lo,wb);
2251             break;
2252         case 0x11:
2253             if (lo>=0x20 && lo<=0x2f)
2254                 handle_text_attr (hi,lo,wb);
2255             if (lo>=0x30 && lo<=0x3f)
2256             {
2257                 wrote_to_screen=1;
2258                 handle_double (hi,lo,wb);
2259             }
2260             if (lo>=0x40 && lo<=0x7f)
2261                 handle_pac (hi,lo,wb);
2262             break;
2263         case 0x12:
2264         case 0x13:
2265             if (lo>=0x20 && lo<=0x3f)
2266             {
2267                 wrote_to_screen=handle_extended (hi,lo,wb);
2268             }
2269             if (lo>=0x40 && lo<=0x7f)
2270                 handle_pac (hi,lo,wb);
2271             break;
2272         case 0x14:
2273         case 0x15:
2274             if (lo>=0x20 && lo<=0x2f)
2275                 handle_command (hi,lo,wb);
2276             if (lo>=0x40 && lo<=0x7f)
2277                 handle_pac (hi,lo,wb);
2278             break;
2279         case 0x16:
2280             if (lo>=0x40 && lo<=0x7f)
2281                 handle_pac (hi,lo,wb);
2282             break;
2283         case 0x17:
2284             if (lo>=0x21 && lo<=0x22)
2285                 handle_command (hi,lo,wb);
2286             if (lo>=0x2e && lo<=0x2f)
2287                 handle_text_attr (hi,lo,wb);
2288             if (lo>=0x40 && lo<=0x7f)
2289                 handle_pac (hi,lo,wb);
2290             break;
2291     }
2292     return wrote_to_screen;
2293 }
2294
2295 void process608 (const unsigned char *data, int length, struct s_write *wb)
2296 {
2297     static int textprinted = 0;
2298     int i;
2299
2300     if (data!=NULL)
2301     {
2302         for (i=0;i<length;i=i+2)
2303         {
2304             unsigned char hi, lo;
2305             int wrote_to_screen=0; 
2306             hi = data[i] & 0x7F; // Get rid of parity bit
2307             lo = data[i+1] & 0x7F; // Get rid of parity bit
2308
2309             if (hi==0 && lo==0) // Just padding
2310                 continue;
2311             // hb_log ("\r[%02X:%02X]\n",hi,lo);
2312
2313             if (hi>=0x01 && hi<=0x0E)
2314             {
2315                 // XDS crap - mode. Would be nice to support it eventually
2316                 // wb->data608->last_c1=0;
2317                 // wb->data608->last_c2=0;
2318                 wb->data608->channel=3; // Always channel 3
2319                 wb->in_xds_mode=1;
2320             }
2321             if (hi==0x0F) // End of XDS block
2322             {
2323                 wb->in_xds_mode=0;
2324                 continue;
2325             }
2326             if (hi>=0x10 && hi<0x1F) // Non-character code or special/extended char
2327                 // http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/CC_CODES.HTML
2328                 // http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/CC_CHARS.HTML
2329             {
2330                 // We were writing characters before, start a new line for
2331                 // diagnostic output from disCommand()
2332                 if (debug_608 && textprinted == 1 )
2333                 {
2334                     hb_log("\n");
2335                     textprinted = 0;
2336                 }
2337
2338                 wb->in_xds_mode=0; // Back to normal
2339                 if (wb->data608->last_c1==hi && wb->data608->last_c2==lo)
2340                 {
2341                     // Duplicate dual code, discard
2342                     continue;
2343                 }
2344                 wb->data608->last_c1=hi;
2345                 wb->data608->last_c2=lo;
2346                 wrote_to_screen=disCommand (hi,lo,wb);
2347             }
2348             if (hi>=0x20) // Standard characters (always in pairs)
2349             {
2350                 // Only print if the channel is active
2351                 if (wb->data608->channel!=cc_channel)
2352                     continue;
2353
2354                 if (debug_608)
2355                 {
2356                     if( textprinted == 0 )
2357                     {
2358                         hb_log("\n");
2359                         textprinted = 1;
2360                     }
2361                 }
2362
2363                 handle_single(hi,wb);
2364                 handle_single(lo,wb);
2365                 wrote_to_screen=1;
2366                 wb->data608->last_c1=0;
2367                 wb->data608->last_c2=0;
2368             }
2369
2370             if ( debug_608 && !textprinted && wb->data608->channel==cc_channel )
2371             {   // Current FTS information after the characters are shown
2372                 //hb_log("Current FTS: %s\n", print_mstime(get_fts()));
2373             }
2374
2375             if (wrote_to_screen && direct_rollup && // If direct_rollup is enabled and
2376                 (wb->data608->mode==MODE_ROLLUP_2 || // we are in rollup mode, write now.
2377                 wb->data608->mode==MODE_ROLLUP_3 ||
2378                 wb->data608->mode==MODE_ROLLUP_4))
2379             {
2380                 // We don't increase screenfuls_counter here.
2381                 write_cc_buffer (wb);
2382                 wb->data608->current_visible_start_ms=get_fts(wb);
2383             }
2384         }
2385     }
2386 }
2387
2388
2389 /* Return a pointer to a string that holds the printable characters
2390  * of the caption data block. FOR DEBUG PURPOSES ONLY! */
2391 unsigned char *debug_608toASC (unsigned char *cc_data, int channel)
2392 {
2393     static unsigned char output[3];
2394
2395     unsigned char cc_valid = (cc_data[0] & 4) >>2;
2396     unsigned char cc_type = cc_data[0] & 3;
2397     unsigned char hi, lo;
2398
2399     output[0]=' ';
2400     output[1]=' ';
2401     output[2]='\x00';
2402
2403     if (cc_valid && cc_type==channel)
2404     {
2405         hi = cc_data[1] & 0x7F; // Get rid of parity bit
2406         lo = cc_data[2] & 0x7F; // Get rid of parity bit
2407         if (hi>=0x20)
2408         {
2409             output[0]=hi;
2410             output[1]=(lo>=20 ? lo : '.');
2411             output[2]='\x00';
2412         }
2413         else
2414         {
2415             output[0]='<';
2416             output[1]='>';
2417             output[2]='\x00';
2418         }
2419     }
2420     return output;
2421 }