OSDN Git Service

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