OSDN Git Service

- Add CoreAudio AAC as one of the encoder on Mac OS X.
[handbrake-jp/handbrake-jp-git.git] / libhb / deccc608sub.c
1 /*
2  * From ccextractor, leave this file as intact and close to the original as possible so that 
3  * it is easy to patch in fixes - even though this file contains code that we don't need.
4  *
5  * Note that the SRT sub generation from CC could be useful for mkv subs.
6  */
7 #include "hb.h"
8 #include "deccc608sub.h"
9
10 /*
11  * ccextractor static configuration variables.
12  */
13 static int debug_608 = 0;
14 static int trim_subs = 1;
15 static int nofontcolor = 0;
16 static enum encoding_type encoding = ENC_UTF_8;
17 static int cc_channel = 1;
18 static enum output_format write_format = OF_SRT;
19 static int sentence_cap = 1;
20 static int subs_delay = 0;
21 static LLONG screens_to_process = -1;
22 static int processed_enough = 0;
23 static int gui_mode_reports = 0;
24 static int norollup = 1;
25 static int direct_rollup = 0;
26
27 /*
28  * Get the time of the last buffer that we have received.
29  */
30 static LLONG get_fts(struct s_write *wb)
31 {
32     return wb->last_pts;
33 }
34
35 #define fatal(N, ...) // N
36 #define XMLRPC_APPEND(N, ...) // N
37
38 int     rowdata[] = {11,-1,1,2,3,4,12,13,14,15,5,6,7,8,9,10};
39 // Relationship between the first PAC byte and the row number
40
41 // The following enc_buffer is not used at the moment, if it does get used
42 // we need to bring it into the swrite struct. Same for "str".
43 #define INITIAL_ENC_BUFFER_CAPACITY             2048
44
45 unsigned char str[2048]; // Another generic general purpose buffer
46
47 #define GUARANTEE(wb, length) if (length>wb->enc_buffer_capacity)            \
48 {wb->enc_buffer_capacity*=2; wb->enc_buffer=(unsigned char*) realloc (wb->enc_buffer, wb->enc_buffer_capacity); \
49     if (wb->enc_buffer==NULL) { fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory, bailing out\n"); } \
50 }
51
52 const unsigned char pac2_attribs[][3]= // Color, font, ident
53 {
54     {COL_WHITE,     FONT_REGULAR,               0},  // 0x40 || 0x60 
55     {COL_WHITE,     FONT_UNDERLINED,            0},  // 0x41 || 0x61
56     {COL_GREEN,     FONT_REGULAR,               0},  // 0x42 || 0x62
57     {COL_GREEN,     FONT_UNDERLINED,            0},  // 0x43 || 0x63
58     {COL_BLUE,      FONT_REGULAR,               0},  // 0x44 || 0x64
59     {COL_BLUE,      FONT_UNDERLINED,            0},  // 0x45 || 0x65
60     {COL_CYAN,      FONT_REGULAR,               0},  // 0x46 || 0x66
61     {COL_CYAN,      FONT_UNDERLINED,            0},  // 0x47 || 0x67
62     {COL_RED,       FONT_REGULAR,               0},  // 0x48 || 0x68
63     {COL_RED,       FONT_UNDERLINED,            0},  // 0x49 || 0x69
64     {COL_YELLOW,    FONT_REGULAR,               0},  // 0x4a || 0x6a
65     {COL_YELLOW,    FONT_UNDERLINED,            0},  // 0x4b || 0x6b
66     {COL_MAGENTA,   FONT_REGULAR,               0},  // 0x4c || 0x6c
67     {COL_MAGENTA,   FONT_UNDERLINED,            0},  // 0x4d || 0x6d
68     {COL_WHITE,     FONT_ITALICS,               0},  // 0x4e || 0x6e
69     {COL_WHITE,     FONT_UNDERLINED_ITALICS,    0},  // 0x4f || 0x6f
70     {COL_WHITE,     FONT_REGULAR,               0},  // 0x50 || 0x70
71     {COL_WHITE,     FONT_UNDERLINED,            0},  // 0x51 || 0x71
72     {COL_WHITE,     FONT_REGULAR,               4},  // 0x52 || 0x72
73     {COL_WHITE,     FONT_UNDERLINED,            4},  // 0x53 || 0x73
74     {COL_WHITE,     FONT_REGULAR,               8},  // 0x54 || 0x74
75     {COL_WHITE,     FONT_UNDERLINED,            8},  // 0x55 || 0x75
76     {COL_WHITE,     FONT_REGULAR,               12}, // 0x56 || 0x76
77     {COL_WHITE,     FONT_UNDERLINED,            12}, // 0x57 || 0x77
78     {COL_WHITE,     FONT_REGULAR,               16}, // 0x58 || 0x78
79     {COL_WHITE,     FONT_UNDERLINED,            16}, // 0x59 || 0x79
80     {COL_WHITE,     FONT_REGULAR,               20}, // 0x5a || 0x7a
81     {COL_WHITE,     FONT_UNDERLINED,            20}, // 0x5b || 0x7b
82     {COL_WHITE,     FONT_REGULAR,               24}, // 0x5c || 0x7c
83     {COL_WHITE,     FONT_UNDERLINED,            24}, // 0x5d || 0x7d
84     {COL_WHITE,     FONT_REGULAR,               28}, // 0x5e || 0x7e
85     {COL_WHITE,     FONT_UNDERLINED,            28}  // 0x5f || 0x7f
86 };
87
88 // Preencoded strings
89 unsigned char encoded_crlf[16]; 
90 unsigned int encoded_crlf_length;
91 unsigned char encoded_br[16];
92 unsigned int encoded_br_length;
93
94 // Default color
95 unsigned char usercolor_rgb[8]="";
96 enum color_code default_color=COL_WHITE;
97
98 const char *sami_header= // TODO: Revise the <!-- comments
99 "<SAMI>\n\
100 <HEAD>\n\
101 <STYLE TYPE=\"text/css\">\n\
102 <!--\n\
103 P {margin-left: 16pt; margin-right: 16pt; margin-bottom: 16pt; margin-top: 16pt;\n\
104 text-align: center; font-size: 18pt; font-family: arial; font-weight: bold; color: #f0f0f0;}\n\
105 .UNKNOWNCC {Name:Unknown; lang:en-US; SAMIType:CC;}\n\
106 -->\n\
107 </STYLE>\n\
108 </HEAD>\n\n\
109 <BODY>\n";
110
111 const char *command_type[] =
112 {
113     "Unknown",
114     "EDM - EraseDisplayedMemory",
115     "RCL - ResumeCaptionLoading",
116     "EOC - End Of Caption",
117     "TO1 - Tab Offset, 1 column",
118     "TO2 - Tab Offset, 2 column",
119     "TO3 - Tab Offset, 3 column",
120     "RU2 - Roll up 2 rows",
121     "RU3 - Roll up 3 rows",
122     "RU4 - Roll up 4 rows",
123     "CR  - Carriage Return",
124     "ENM - Erase non-displayed memory",
125     "BS  - Backspace",
126     "RTD - Resume Text Display"
127 };
128
129 const char *font_text[]=
130 {
131     "regular",
132     "italics",
133     "underlined",
134     "underlined italics"
135 };
136
137 const char *cc_modes_text[]=
138 {
139     "Pop-Up captions"
140 };
141
142 const char *color_text[][2]=
143 {
144     {"white",""},
145     {"green","<font color=\"#00ff00\">"},
146     {"blue","<font color=\"#0000ff\">"},
147     {"cyan","<font color=\"#00ffff\">"},
148     {"red","<font color=\"#ff0000\">"},
149     {"yellow","<font color=\"#ffff00\">"},
150     {"magenta","<font color=\"#ff00ff\">"},
151     {"userdefined","<font color=\""}
152 };
153
154 int general_608_init (struct s_write *wb)
155 {
156     if( !wb->enc_buffer )
157     {
158         wb->enc_buffer=(unsigned char *) malloc (INITIAL_ENC_BUFFER_CAPACITY); 
159         if (wb->enc_buffer==NULL)
160             return -1;
161         wb->enc_buffer_capacity=INITIAL_ENC_BUFFER_CAPACITY;
162     }
163
164     if( !wb->subline) {
165         wb->subline = malloc(2048);
166     
167         if (!wb->subline)
168         {
169             return -1;
170         }
171     }
172
173     wb->new_sentence = 1;
174     wb->new_channel = 1;
175     wb->in_xds_mode = 0;
176
177     wb->hb_buffer = NULL;
178     wb->hb_last_buffer = NULL;
179     wb->last_pts = 0;
180     return 0;
181 }
182
183 /*
184  * Free up CC memory - don't call this from HB just yet since it will cause
185  * parallel encodes to fail - to be honest they will be stuffed anyway since
186  * the CC's may be overwriting the buffers.
187  */
188 void general_608_close (struct s_write *wb)
189 {
190     if( wb->enc_buffer ) {
191         free(wb->enc_buffer);
192         wb->enc_buffer_capacity = 0;
193         wb->enc_buffer_used = 0;
194     }
195     if( wb->subline ) {
196         free(wb->subline);
197     }
198
199     if( wb->hb_buffer ) {
200         hb_buffer_close( &wb->hb_buffer );
201     }
202 }
203
204
205 #include <ctype.h>
206
207 void get_char_in_latin_1 (unsigned char *buffer, unsigned char c)
208 {
209     unsigned char c1='?';
210     if (c<0x80) 
211     {   
212         // Regular line-21 character set, mostly ASCII except these exceptions
213         switch (c)
214         {
215             case 0x2a: // lowercase a, acute accent
216                 c1=0xe1;
217                 break;
218             case 0x5c: // lowercase e, acute accent
219                 c1=0xe9;
220                 break;
221             case 0x5e: // lowercase i, acute accent
222                 c1=0xed;
223                 break;                  
224             case 0x5f: // lowercase o, acute accent
225                 c1=0xf3;
226                 break;
227             case 0x60: // lowercase u, acute accent
228                 c1=0xfa;
229                 break;
230             case 0x7b: // lowercase c with cedilla
231                 c1=0xe7;
232                 break;
233             case 0x7c: // division symbol
234                 c1=0xf7;
235                 break;
236             case 0x7d: // uppercase N tilde
237                 c1=0xd1;
238                 break;
239             case 0x7e: // lowercase n tilde
240                 c1=0xf1;
241                 break;
242             default:
243                 c1=c;
244                 break;
245         }
246         *buffer=c1;
247         return;
248     }
249     switch (c)
250     {
251         // THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
252         // THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F            
253         case 0x80: // Registered symbol (R)
254             c1=0xae;
255             break;                      
256         case 0x81: // degree sign
257             c1=0xb0;
258             break;
259         case 0x82: // 1/2 symbol                        
260             c1=0xbd;
261             break;
262         case 0x83: // Inverted (open) question mark                     
263             c1=0xbf;
264             break;
265         case 0x84: // Trademark symbol (TM) - Does not exist in Latin 1
266             break;                      
267         case 0x85: // Cents symbol                      
268             c1=0xa2;
269             break;
270         case 0x86: // Pounds sterling                   
271             c1=0xa3;
272             break;
273         case 0x87: // Music note - Not in latin 1, so we use 'pilcrow'
274             c1=0xb6;
275             break;
276         case 0x88: // lowercase a, grave accent
277             c1=0xe0;
278             break;
279         case 0x89: // transparent space, we make it regular
280             c1=0x20;                    
281             break;
282         case 0x8a: // lowercase e, grave accent
283             c1=0xe8;
284             break;
285         case 0x8b: // lowercase a, circumflex accent
286             c1=0xe2;
287             break;
288         case 0x8c: // lowercase e, circumflex accent
289             c1=0xea;                    
290             break;
291         case 0x8d: // lowercase i, circumflex accent
292             c1=0xee;
293             break;
294         case 0x8e: // lowercase o, circumflex accent
295             c1=0xf4;
296             break;
297         case 0x8f: // lowercase u, circumflex accent
298             c1=0xfb;
299             break;
300         // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
301         // THAT COME FROM HI BYTE=0x12 AND LOW BETWEEN 0x20 AND 0x3F
302         case 0x90: // capital letter A with acute
303             c1=0xc1;
304             break;
305         case 0x91: // capital letter E with acute
306             c1=0xc9;
307             break;
308         case 0x92: // capital letter O with acute
309             c1=0xd3;
310             break;
311         case 0x93: // capital letter U with acute
312             c1=0xda;
313             break;
314         case 0x94: // capital letter U with diaresis
315             c1=0xdc;
316             break;
317         case 0x95: // lowercase letter U with diaeresis
318             c1=0xfc;
319             break;
320         case 0x96: // apostrophe
321             c1=0x27;                    
322             break;
323         case 0x97: // inverted exclamation mark                 
324             c1=0xa1;
325             break;
326         case 0x98: // asterisk
327             c1=0x2a;                    
328             break;
329         case 0x99: // apostrophe (yes, duped). See CCADI source code.
330             c1=0x27;                    
331             break;
332         case 0x9a: // hyphen-minus
333             c1=0x2d;                    
334             break;
335         case 0x9b: // copyright sign
336             c1=0xa9;
337             break;
338         case 0x9c: // Service Mark - not available in latin 1
339             break;
340         case 0x9d: // Full stop (.)
341             c1=0x2e;
342             break;
343         case 0x9e: // Quoatation mark
344             c1=0x22;                    
345             break;
346         case 0x9f: // Quoatation mark
347             c1=0x22;                    
348             break;
349         case 0xa0: // uppercase A, grave accent
350             c1=0xc0;
351             break;
352         case 0xa1: // uppercase A, circumflex
353             c1=0xc2;
354             break;                      
355         case 0xa2: // uppercase C with cedilla
356             c1=0xc7;
357             break;
358         case 0xa3: // uppercase E, grave accent
359             c1=0xc8;
360             break;
361         case 0xa4: // uppercase E, circumflex
362             c1=0xca;
363             break;
364         case 0xa5: // capital letter E with diaresis
365             c1=0xcb;
366             break;
367         case 0xa6: // lowercase letter e with diaresis
368             c1=0xeb;
369             break;
370         case 0xa7: // uppercase I, circumflex
371             c1=0xce;
372             break;
373         case 0xa8: // uppercase I, with diaresis
374             c1=0xcf;
375             break;
376         case 0xa9: // lowercase i, with diaresis
377             c1=0xef;
378             break;
379         case 0xaa: // uppercase O, circumflex
380             c1=0xd4;
381             break;
382         case 0xab: // uppercase U, grave accent
383             c1=0xd9;
384             break;
385         case 0xac: // lowercase u, grave accent
386             c1=0xf9;
387             break;
388         case 0xad: // uppercase U, circumflex
389             c1=0xdb;
390             break;
391         case 0xae: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
392             c1=0xab;
393             break;
394         case 0xaf: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
395             c1=0xbb;
396             break;
397         // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
398         // THAT COME FROM HI BYTE=0x13 AND LOW BETWEEN 0x20 AND 0x3F
399         case 0xb0: // Uppercase A, tilde
400             c1=0xc3;
401             break;
402         case 0xb1: // Lowercase a, tilde
403             c1=0xe3;
404             break;
405         case 0xb2: // Uppercase I, acute accent
406             c1=0xcd;
407             break;
408         case 0xb3: // Uppercase I, grave accent
409             c1=0xcc;
410             break;
411         case 0xb4: // Lowercase i, grave accent
412             c1=0xec;
413             break;
414         case 0xb5: // Uppercase O, grave accent
415             c1=0xd2;
416             break;
417         case 0xb6: // Lowercase o, grave accent
418             c1=0xf2;
419             break;
420         case 0xb7: // Uppercase O, tilde
421             c1=0xd5;
422             break;
423         case 0xb8: // Lowercase o, tilde
424             c1=0xf5;
425             break;
426         case 0xb9: // Open curly brace
427             c1=0x7b;
428             break;
429         case 0xba: // Closing curly brace
430             c1=0x7d;            
431             break;
432         case 0xbb: // Backslash
433             c1=0x5c;
434             break;
435         case 0xbc: // Caret
436             c1=0x5e;
437             break;
438         case 0xbd: // Underscore
439             c1=0x5f;
440             break;
441         case 0xbe: // Pipe (broken bar)            
442             c1=0xa6;
443             break;
444         case 0xbf: // Tilde
445             c1=0x7e; 
446             break;
447         case 0xc0: // Uppercase A, umlaut            
448             c1=0xc4;
449             break;
450         case 0xc1: // Lowercase A, umlaut
451             c1=0xe3; 
452             break;
453         case 0xc2: // Uppercase O, umlaut
454             c1=0xd6;
455             break;
456         case 0xc3: // Lowercase o, umlaut
457             c1=0xf6;
458             break;
459         case 0xc4: // Esszett (sharp S)
460             c1=0xdf;
461             break;
462         case 0xc5: // Yen symbol
463             c1=0xa5;
464             break;
465         case 0xc6: // Currency symbol
466             c1=0xa4;
467             break;            
468         case 0xc7: // Vertical bar
469             c1=0x7c;
470             break;            
471         case 0xc8: // Uppercase A, ring
472             c1=0xc5;
473             break;
474         case 0xc9: // Lowercase A, ring
475             c1=0xe5;
476             break;
477         case 0xca: // Uppercase O, slash
478             c1=0xd8;
479             break;
480         case 0xcb: // Lowercase o, slash
481             c1=0xf8;
482             break;
483         case 0xcc: // Upper left corner
484         case 0xcd: // Upper right corner
485         case 0xce: // Lower left corner
486         case 0xcf: // Lower right corner
487         default: // For those that don't have representation
488             *buffer='?'; // I'll do it eventually, I promise
489             break; // This are weird chars anyway
490     }
491     *buffer=c1; 
492 }
493
494 void get_char_in_unicode (unsigned char *buffer, unsigned char c)
495 {
496     unsigned char c1,c2;
497     switch (c)
498     {
499         case 0x84: // Trademark symbol (TM) 
500             c2=0x21;
501             c1=0x22;
502             break;
503         case 0x87: // Music note
504             c2=0x26;
505             c1=0x6a;
506             break;
507         case 0x9c: // Service Mark
508             c2=0x21;
509             c1=0x20;
510             break;
511         case 0xcc: // Upper left corner
512             c2=0x23;
513             c1=0x1c;
514             break;                      
515         case 0xcd: // Upper right corner
516             c2=0x23;
517             c1=0x1d;
518             break;
519         case 0xce: // Lower left corner
520             c2=0x23;
521             c1=0x1e;
522             break;
523         case 0xcf: // Lower right corner
524             c2=0x23;
525             c1=0x1f;
526             break;
527         default: // Everything else, same as latin-1 followed by 00                     
528             get_char_in_latin_1 (&c1,c);
529             c2=0;
530             break;
531     }
532     *buffer=c1;
533     *(buffer+1)=c2;
534 }
535
536 int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number of bytes used
537 {
538     if (c==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=0xc1;
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 (LLONG milli, unsigned *hours, unsigned *minutes,
1418                unsigned *seconds, unsigned *ms)
1419 {
1420     // LLONG milli = (LLONG) ((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 %lld: %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     LLONG 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                 LLONG 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     LLONG 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     LLONG 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 *) " ");
1641                 } else {
1642                     wb->enc_buffer_used += encode_line (wb->enc_buffer+wb->enc_buffer_used,
1643                                                         (unsigned char *) " "); 
1644                 }
1645                 wb->enc_buffer_used += get_decoder_line_encoded (wb->enc_buffer+wb->enc_buffer_used, i, data);
1646             }
1647         }
1648     }
1649     if (wb->enc_buffer_used)
1650     {
1651         hb_buffer_t *buffer = hb_buffer_init( wb->enc_buffer_used + 1 );
1652         buffer->start = ms_start;
1653         buffer->stop = ms_end;
1654         memcpy( buffer->data, wb->enc_buffer, wb->enc_buffer_used + 1 );
1655         if (wb->hb_last_buffer) {
1656             wb->hb_last_buffer->next = buffer;
1657         } else {
1658             wb->hb_buffer = buffer;
1659         }
1660         wb->hb_last_buffer = buffer;
1661         
1662         wrote_something=1;
1663     }
1664     if (debug_608)
1665     {
1666         hb_log ("- - - - - - - - - - - -\r\n");
1667     }
1668     // fhb_log (wb->fh, encoded_crlf);
1669     //fwrite (encoded_crlf, 1, encoded_crlf_length,wb->fh);
1670     XMLRPC_APPEND(encoded_crlf,encoded_crlf_length);
1671     return wrote_something;
1672 }
1673
1674 int write_cc_buffer_as_sami (struct eia608_screen *data, struct s_write *wb)
1675 {
1676     int wrote_something=0;
1677     LLONG startms = wb->data608->current_visible_start_ms;
1678     int i;
1679
1680     startms+=subs_delay;
1681     if (startms<0) // Drop screens that because of subs_delay start too early
1682         return 0; 
1683
1684     LLONG endms   = get_fts(wb)+subs_delay;
1685     endms--; // To prevent overlapping with next line.
1686     sprintf ((char *) str,"<SYNC start=\"%llu\"><P class=\"UNKNOWNCC\">\r\n",startms);
1687     if (debug_608 && encoding!=ENC_UNICODE)
1688     {
1689         hb_log ("\r%s\n", str);
1690     }
1691     wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) str);
1692     fwrite (wb->enc_buffer,wb->enc_buffer_used,1,wb->fh);               
1693     XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
1694     for (i=0;i<15;i++)
1695     {
1696         if (data->row_used[i])
1697         {                               
1698             int length = get_decoder_line_encoded (wb->subline, i, data);
1699             if (debug_608 && encoding!=ENC_UNICODE)
1700             {
1701                 hb_log ("\r");
1702                 hb_log ("%s\n",wb->subline);
1703             }
1704             fwrite (wb->subline, 1, length, wb->fh);
1705             XMLRPC_APPEND(wb->subline,length);
1706             wrote_something=1;
1707             if (i!=14)
1708             {
1709                 fwrite (encoded_br, 1, encoded_br_length,wb->fh);                       
1710                 XMLRPC_APPEND(encoded_br, encoded_br_length);
1711             }
1712             fwrite (encoded_crlf, 1, encoded_crlf_length,wb->fh);
1713             XMLRPC_APPEND(encoded_crlf, encoded_crlf_length);
1714         }
1715     }
1716     sprintf ((char *) str,"</P></SYNC>\r\n");
1717     if (debug_608 && encoding!=ENC_UNICODE)
1718     {
1719         hb_log ("\r%s\n", str);
1720     }
1721     wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) str);
1722     fwrite (wb->enc_buffer,wb->enc_buffer_used,1,wb->fh);
1723     XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
1724     sprintf ((char *) str,"<SYNC start=\"%llu\"><P class=\"UNKNOWNCC\">&nbsp;</P></SYNC>\r\n\r\n",endms);
1725     if (debug_608 && encoding!=ENC_UNICODE)
1726     {
1727         hb_log ("\r%s\n", str);
1728     }
1729     wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) str);
1730     fwrite (wb->enc_buffer,wb->enc_buffer_used,1,wb->fh);
1731     XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
1732     return wrote_something;
1733 }
1734
1735 struct eia608_screen *get_current_visible_buffer (struct s_write *wb)
1736 {
1737     struct eia608_screen *data;
1738     if (wb->data608->visible_buffer==1)
1739         data = &wb->data608->buffer1;
1740     else
1741         data = &wb->data608->buffer2;
1742     return data;
1743 }
1744
1745
1746 int write_cc_buffer (struct s_write *wb)
1747 {
1748     struct eia608_screen *data;
1749     int wrote_something=0;
1750     if (screens_to_process!=-1 && wb->data608->screenfuls_counter>=screens_to_process)
1751     {
1752         // We are done. 
1753         processed_enough=1;
1754         return 0;
1755     }
1756     if (wb->data608->visible_buffer==1)
1757         data = &wb->data608->buffer1;
1758     else
1759         data = &wb->data608->buffer2;
1760
1761     if (!data->empty)
1762     {
1763         wb->new_sentence=1;
1764         switch (write_format)
1765         {
1766             case OF_SRT:
1767                 wrote_something = write_cc_buffer_as_srt (data, wb);
1768                 break;
1769             case OF_SAMI:
1770                 wrote_something = write_cc_buffer_as_sami (data,wb);
1771                 break;
1772             case OF_TRANSCRIPT:
1773                 wrote_something = write_cc_buffer_as_transcript (data,wb);
1774                 break;
1775         default: 
1776                 break;
1777         }
1778         if (wrote_something && gui_mode_reports)
1779             write_cc_buffer_to_gui (data,wb);
1780     }
1781     return wrote_something;
1782 }
1783
1784 void roll_up(struct s_write *wb)
1785 {
1786     struct eia608_screen *use_buffer;
1787     int i, j;
1788
1789     if (wb->data608->visible_buffer==1)
1790         use_buffer = &wb->data608->buffer1;
1791     else
1792         use_buffer = &wb->data608->buffer2;
1793     int keep_lines;
1794     switch (wb->data608->mode)
1795     {
1796         case MODE_ROLLUP_2:
1797             keep_lines=2;
1798             break;
1799         case MODE_ROLLUP_3:
1800             keep_lines=3;
1801             break;
1802         case MODE_ROLLUP_4:
1803             keep_lines=4;
1804             break;
1805         default: // Shouldn't happen
1806             keep_lines=0;
1807             break;
1808     }
1809     int firstrow=-1, lastrow=-1;
1810     // Look for the last line used
1811     int rows_now=0; // Number of rows in use right now
1812     for (i=0;i<15;i++)
1813     {
1814         if (use_buffer->row_used[i])
1815         {
1816             rows_now++;
1817             if (firstrow==-1)
1818                 firstrow=i;
1819             lastrow=i;
1820         }
1821     }
1822     
1823     if (debug_608)
1824         hb_log ("\rIn roll-up: %d lines used, first: %d, last: %d\n", rows_now, firstrow, lastrow);
1825
1826     if (lastrow==-1) // Empty screen, nothing to rollup
1827         return;
1828
1829     for (j=lastrow-keep_lines+1;j<lastrow; j++)
1830     {
1831         if (j>=0)
1832         {
1833             memcpy (use_buffer->characters[j],use_buffer->characters[j+1],CC608_SCREEN_WIDTH+1);
1834             memcpy (use_buffer->colors[j],use_buffer->colors[j+1],CC608_SCREEN_WIDTH+1);
1835             memcpy (use_buffer->fonts[j],use_buffer->fonts[j+1],CC608_SCREEN_WIDTH+1);
1836             use_buffer->row_used[j]=use_buffer->row_used[j+1];
1837         }
1838     }
1839     for (j=0;j<(1+wb->data608->cursor_row-keep_lines);j++)
1840     {
1841         memset(use_buffer->characters[j],' ',CC608_SCREEN_WIDTH);                       
1842         memset(use_buffer->colors[j],COL_WHITE,CC608_SCREEN_WIDTH);
1843         memset(use_buffer->fonts[j],FONT_REGULAR,CC608_SCREEN_WIDTH);
1844         use_buffer->characters[j][CC608_SCREEN_WIDTH]=0;
1845         use_buffer->row_used[j]=0;
1846     }
1847     memset(use_buffer->characters[lastrow],' ',CC608_SCREEN_WIDTH);
1848     memset(use_buffer->colors[lastrow],COL_WHITE,CC608_SCREEN_WIDTH);
1849     memset(use_buffer->fonts[lastrow],FONT_REGULAR,CC608_SCREEN_WIDTH);
1850
1851     use_buffer->characters[lastrow][CC608_SCREEN_WIDTH]=0;
1852     use_buffer->row_used[lastrow]=0;
1853     
1854     // Sanity check
1855     rows_now=0;
1856     for (i=0;i<15;i++)
1857         if (use_buffer->row_used[i])
1858             rows_now++;
1859     if (rows_now>keep_lines)
1860         hb_log ("Bug in roll_up, should have %d lines but I have %d.\n",
1861             keep_lines, rows_now);
1862 }
1863
1864 void erase_memory (struct s_write *wb, int displayed)
1865 {
1866     struct eia608_screen *buf;
1867     if (displayed)
1868     {
1869         if (wb->data608->visible_buffer==1)
1870             buf=&wb->data608->buffer1;
1871         else
1872             buf=&wb->data608->buffer2;
1873     }
1874     else
1875     {
1876         if (wb->data608->visible_buffer==1)
1877             buf=&wb->data608->buffer2;
1878         else
1879             buf=&wb->data608->buffer1;
1880     }
1881     clear_eia608_cc_buffer (buf);
1882 }
1883
1884 int is_current_row_empty (struct s_write *wb)
1885 {
1886     struct eia608_screen *use_buffer;
1887     int i;
1888
1889     if (wb->data608->visible_buffer==1)
1890         use_buffer = &wb->data608->buffer1;
1891     else
1892         use_buffer = &wb->data608->buffer2;
1893     for (i=0;i<CC608_SCREEN_WIDTH;i++)
1894     {
1895         if (use_buffer->characters[wb->data608->rollup_base_row][i]!=' ')
1896             return 0;
1897     }
1898     return 1;
1899 }
1900
1901 /* Process GLOBAL CODES */
1902 void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct s_write *wb)
1903 {
1904     // Handle channel change
1905     wb->data608->channel=wb->new_channel;
1906     if (wb->data608->channel!=cc_channel)
1907         return;
1908
1909     enum command_code command = COM_UNKNOWN;
1910     if (c1==0x15)
1911         c1=0x14;
1912     if ((c1==0x14 || c1==0x1C) && c2==0x2C)
1913         command = COM_ERASEDISPLAYEDMEMORY;
1914     if ((c1==0x14 || c1==0x1C) && c2==0x20)
1915         command = COM_RESUMECAPTIONLOADING;
1916     if ((c1==0x14 || c1==0x1C) && c2==0x2F)
1917         command = COM_ENDOFCAPTION;
1918     if ((c1==0x17 || c1==0x1F) && c2==0x21)
1919         command = COM_TABOFFSET1;
1920     if ((c1==0x17 || c1==0x1F) && c2==0x22)
1921         command = COM_TABOFFSET2;
1922     if ((c1==0x17 || c1==0x1F) && c2==0x23)
1923         command = COM_TABOFFSET3;
1924     if ((c1==0x14 || c1==0x1C) && c2==0x25)
1925         command = COM_ROLLUP2;
1926     if ((c1==0x14 || c1==0x1C) && c2==0x26)
1927         command = COM_ROLLUP3;
1928     if ((c1==0x14 || c1==0x1C) && c2==0x27)
1929         command = COM_ROLLUP4;
1930     if ((c1==0x14 || c1==0x1C) && c2==0x2D)
1931         command = COM_CARRIAGERETURN;
1932     if ((c1==0x14 || c1==0x1C) && c2==0x2E)
1933         command = COM_ERASENONDISPLAYEDMEMORY;
1934     if ((c1==0x14 || c1==0x1C) && c2==0x21)
1935         command = COM_BACKSPACE;
1936     if ((c1==0x14 || c1==0x1C) && c2==0x2b)
1937         command = COM_RESUMETEXTDISPLAY;
1938     if (debug_608)
1939     {
1940         hb_log ("\rCommand: %02X %02X (%s)\n",c1,c2,command_type[command]);
1941     }
1942     switch (command)
1943     {
1944         case COM_BACKSPACE:
1945             if (wb->data608->cursor_column>0)
1946             {
1947                 wb->data608->cursor_column--;
1948                 get_writing_buffer(wb)->characters[wb->data608->cursor_row][wb->data608->cursor_column]=' ';
1949             }
1950             break;
1951         case COM_TABOFFSET1:
1952             if (wb->data608->cursor_column<31)
1953                 wb->data608->cursor_column++;
1954             break;
1955         case COM_TABOFFSET2:
1956             wb->data608->cursor_column+=2;
1957             if (wb->data608->cursor_column>31)
1958                 wb->data608->cursor_column=31;
1959             break;
1960         case COM_TABOFFSET3:
1961             wb->data608->cursor_column+=3;
1962             if (wb->data608->cursor_column>31)
1963                 wb->data608->cursor_column=31;
1964             break;
1965         case COM_RESUMECAPTIONLOADING:
1966             wb->data608->mode=MODE_POPUP;
1967             break;
1968         case COM_RESUMETEXTDISPLAY:
1969             wb->data608->mode=MODE_TEXT;
1970             break;
1971         case COM_ROLLUP2:            
1972             if (wb->data608->mode==MODE_POPUP)
1973             {
1974                 if (write_cc_buffer (wb))
1975                     wb->data608->screenfuls_counter++;
1976                 erase_memory (wb, 1);                   
1977             }
1978             if (wb->data608->mode==MODE_ROLLUP_2 && !is_current_row_empty(wb))
1979             {
1980                 if (debug_608)
1981                     hb_log ("Two RU2, current line not empty. Simulating a CR\n");
1982                 handle_command(0x14, 0x2D, wb);
1983             }   
1984             wb->data608->mode=MODE_ROLLUP_2;
1985             erase_memory (wb, 0);
1986             wb->data608->cursor_column=0;
1987             wb->data608->cursor_row=wb->data608->rollup_base_row;
1988             break;
1989         case COM_ROLLUP3:
1990             if (wb->data608->mode==MODE_POPUP)
1991             {
1992                 if (write_cc_buffer (wb))
1993                     wb->data608->screenfuls_counter++;
1994                 erase_memory (wb, 1);
1995             }
1996             if (wb->data608->mode==MODE_ROLLUP_3 && !is_current_row_empty(wb))
1997             {
1998                 if (debug_608)
1999                     hb_log ("Two RU3, current line not empty. Simulating a CR\n");
2000                 handle_command(0x14, 0x2D, wb);
2001             }
2002             wb->data608->mode=MODE_ROLLUP_3;
2003             erase_memory (wb, 0);
2004             wb->data608->cursor_column=0;
2005             wb->data608->cursor_row=wb->data608->rollup_base_row;
2006             break;
2007         case COM_ROLLUP4:
2008             if (wb->data608->mode==MODE_POPUP)
2009             {
2010                 if (write_cc_buffer (wb))
2011                     wb->data608->screenfuls_counter++;
2012                 erase_memory (wb, 1);                   
2013             }
2014             if (wb->data608->mode==MODE_ROLLUP_4 && !is_current_row_empty(wb))
2015             {
2016                 if (debug_608)
2017                     hb_log ("Two RU4, current line not empty. Simulating a CR\n");
2018                 handle_command(0x14, 0x2D, wb);
2019             }
2020             
2021             wb->data608->mode=MODE_ROLLUP_4;
2022             wb->data608->cursor_column=0;
2023             wb->data608->cursor_row=wb->data608->rollup_base_row;
2024             erase_memory (wb, 0);
2025             break;
2026         case COM_CARRIAGERETURN:
2027             // In transcript mode, CR doesn't write the whole screen, to avoid
2028             // repeated lines.
2029             if (write_format==OF_TRANSCRIPT)
2030             {
2031                 write_cc_line_as_transcript(get_current_visible_buffer (wb), wb, wb->data608->cursor_row);
2032             }
2033             else
2034             {
2035                 if (norollup)
2036                     delete_all_lines_but_current (get_current_visible_buffer (wb), wb->data608->cursor_row);
2037                 if (write_cc_buffer(wb))
2038                     wb->data608->screenfuls_counter++;
2039             }
2040             roll_up(wb);                
2041             wb->data608->current_visible_start_ms=get_fts(wb);
2042             wb->data608->cursor_column=0;
2043             break;
2044         case COM_ERASENONDISPLAYEDMEMORY:
2045             erase_memory (wb,0);
2046             break;
2047         case COM_ERASEDISPLAYEDMEMORY:
2048             // Write it to disk before doing this, and make a note of the new
2049             // time it became clear.
2050             if (write_format==OF_TRANSCRIPT && 
2051                 (wb->data608->mode==MODE_ROLLUP_2 || wb->data608->mode==MODE_ROLLUP_3 ||
2052                 wb->data608->mode==MODE_ROLLUP_4))
2053             {
2054                 // In transcript mode we just write the cursor line. The previous lines
2055                 // should have been written already, so writing everything produces
2056                 // duplicate lines.                
2057                 write_cc_line_as_transcript(get_current_visible_buffer (wb), wb, wb->data608->cursor_row);
2058             }
2059             else
2060             {
2061                 if (write_cc_buffer (wb))
2062                     wb->data608->screenfuls_counter++;
2063             }
2064             erase_memory (wb,1);
2065             wb->data608->current_visible_start_ms=get_fts(wb);
2066             break;
2067         case COM_ENDOFCAPTION: // Switch buffers
2068             // The currently *visible* buffer is leaving, so now we know it's ending
2069             // time. Time to actually write it to file.
2070             if (write_cc_buffer (wb))
2071                 wb->data608->screenfuls_counter++;
2072             wb->data608->visible_buffer = (wb->data608->visible_buffer==1) ? 2 : 1;
2073             wb->data608->current_visible_start_ms=get_fts(wb);
2074             wb->data608->cursor_column=0;
2075             wb->data608->cursor_row=0;
2076             wb->data608->color=default_color;
2077             wb->data608->font=FONT_REGULAR;
2078             break;
2079         default:
2080             if (debug_608)
2081             {
2082                 hb_log ("\rNot yet implemented.\n");
2083             }
2084             break;
2085     }
2086 }
2087
2088 void handle_end_of_data (struct s_write *wb)
2089
2090     // We issue a EraseDisplayedMemory here so if there's any captions pending
2091     // they get written to file. 
2092     handle_command (0x14, 0x2c, wb); // EDM
2093 }
2094
2095 void handle_double (const unsigned char c1, const unsigned char c2, struct s_write *wb)
2096 {
2097     unsigned char c;
2098     if (wb->data608->channel!=cc_channel)
2099         return;
2100     if (c2>=0x30 && c2<=0x3f)
2101     {
2102         c=c2 + 0x50; // So if c>=0x80 && c<=0x8f, it comes from here
2103         if (debug_608)
2104             hb_log ("\rDouble: %02X %02X  -->  %c\n",c1,c2,c);
2105         write_char(c,wb);
2106     }
2107 }
2108
2109 /* Process EXTENDED CHARACTERS */
2110 unsigned char handle_extended (unsigned char hi, unsigned char lo, struct s_write *wb)
2111 {
2112     // Handle channel change
2113     if (wb->new_channel > 2) 
2114     {
2115         wb->new_channel -= 2;
2116         if (debug_608)
2117             hb_log ("\nChannel correction, now %d\n", wb->new_channel);
2118     }
2119     wb->data608->channel=wb->new_channel;
2120     if (wb->data608->channel!=cc_channel)
2121         return 0;
2122
2123     // For lo values between 0x20-0x3f
2124     unsigned char c=0;
2125
2126     if (debug_608)
2127         hb_log ("\rExtended: %02X %02X\n",hi,lo);
2128     if (lo>=0x20 && lo<=0x3f && (hi==0x12 || hi==0x13))
2129     {
2130         switch (hi)
2131         {
2132             case 0x12:
2133                 c=lo+0x70; // So if c>=0x90 && c<=0xaf it comes from here
2134                 break;
2135             case 0x13:
2136                 c=lo+0x90; // So if c>=0xb0 && c<=0xcf it comes from here
2137                 break;
2138         }
2139         // This column change is because extended characters replace 
2140         // the previous character (which is sent for basic decoders
2141         // to show something similar to the real char)
2142         if (wb->data608->cursor_column>0)        
2143             wb->data608->cursor_column--;        
2144
2145         write_char (c,wb);
2146     }
2147     return 1;
2148 }
2149
2150 /* Process PREAMBLE ACCESS CODES (PAC) */
2151 void handle_pac (unsigned char c1, unsigned char c2, struct s_write *wb)
2152 {
2153     // Handle channel change
2154     if (wb->new_channel > 2) 
2155     {
2156         wb->new_channel -= 2;
2157         if (debug_608)
2158             hb_log ("\nChannel correction, now %d\n", wb->new_channel);
2159     }
2160     wb->data608->channel=wb->new_channel;
2161     if (wb->data608->channel!=cc_channel)
2162         return;
2163
2164     int row=rowdata[((c1<<1)&14)|((c2>>5)&1)];
2165
2166     if (debug_608)
2167         hb_log ("\rPAC: %02X %02X",c1,c2);
2168
2169     if (c2>=0x40 && c2<=0x5f)
2170     {
2171         c2=c2-0x40;
2172     }
2173     else
2174     {
2175         if (c2>=0x60 && c2<=0x7f)
2176         {
2177             c2=c2-0x60;
2178         }
2179         else
2180         {
2181             if (debug_608)
2182                 hb_log ("\rThis is not a PAC!!!!!\n");
2183             return;
2184         }
2185     }
2186     int color=pac2_attribs[c2][0];
2187     int font=pac2_attribs[c2][1];
2188     int indent=pac2_attribs[c2][2];
2189     if (debug_608)
2190         hb_log ("  --  Position: %d:%d, color: %s,  font: %s\n",row,
2191         indent,color_text[color][0],font_text[font]);
2192     if (wb->data608->mode!=MODE_TEXT)
2193     {
2194         // According to Robson, row info is discarded in text mode
2195         // but column is accepted
2196         wb->data608->cursor_row=row-1 ; // Since the array is 0 based
2197     }
2198     wb->data608->rollup_base_row=row-1;
2199     wb->data608->cursor_column=indent;  
2200 }
2201
2202
2203 void handle_single (const unsigned char c1, struct s_write *wb)
2204 {       
2205     if (c1<0x20 || wb->data608->channel!=cc_channel)
2206         return; // We don't allow special stuff here
2207     if (debug_608)
2208         hb_log ("%c",c1);
2209
2210     /*if (debug_608)
2211     hb_log ("Character: %02X (%c) -> %02X (%c)\n",c1,c1,c,c); */
2212     write_char (c1,wb);
2213 }
2214
2215 int check_channel (unsigned char c1, struct s_write *wb)
2216 {
2217     if (c1==0x14) 
2218     {
2219         if (debug_608 && wb->data608->channel!=1)
2220             hb_log ("\nChannel change, now 1\n");
2221         return 1;
2222     }
2223     if (c1==0x1c) 
2224     {
2225         if (debug_608 && wb->data608->channel!=2)
2226             hb_log ("\nChannel change, now 2\n");
2227         return 2;
2228     }
2229     if (c1==0x15) 
2230     {
2231         if (debug_608 && wb->data608->channel!=3)
2232             hb_log ("\nChannel change, now 3\n");
2233         return 3;
2234     }
2235     if (c1==0x1d) 
2236     {
2237         if (debug_608 && wb->data608->channel!=4)
2238             hb_log ("\nChannel change, now 4\n");
2239         return 4;
2240     }
2241
2242     // Otherwise keep the current channel
2243     return wb->data608->channel;
2244 }
2245
2246 /* Handle Command, special char or attribute and also check for
2247 * channel changes.
2248 * Returns 1 if something was written to screen, 0 otherwise */
2249 int disCommand (unsigned char hi, unsigned char lo, struct s_write *wb)
2250 {
2251     int wrote_to_screen=0;
2252
2253     /* Full channel changes are only allowed for "GLOBAL CODES",
2254     * "OTHER POSITIONING CODES", "BACKGROUND COLOR CODES",
2255     * "MID-ROW CODES".
2256     * "PREAMBLE ACCESS CODES", "BACKGROUND COLOR CODES" and
2257     * SPECIAL/SPECIAL CHARACTERS allow only switching
2258     * between 1&3 or 2&4. */
2259     wb->new_channel = check_channel (hi,wb);
2260     //if (wb->data608->channel!=cc_channel)
2261     //    continue;
2262
2263     if (hi>=0x18 && hi<=0x1f)
2264         hi=hi-8;
2265
2266     switch (hi)
2267     {
2268         case 0x10:
2269             if (lo>=0x40 && lo<=0x5f)
2270                 handle_pac (hi,lo,wb);
2271             break;
2272         case 0x11:
2273             if (lo>=0x20 && lo<=0x2f)
2274                 handle_text_attr (hi,lo,wb);
2275             if (lo>=0x30 && lo<=0x3f)
2276             {
2277                 wrote_to_screen=1;
2278                 handle_double (hi,lo,wb);
2279             }
2280             if (lo>=0x40 && lo<=0x7f)
2281                 handle_pac (hi,lo,wb);
2282             break;
2283         case 0x12:
2284         case 0x13:
2285             if (lo>=0x20 && lo<=0x3f)
2286             {
2287                 wrote_to_screen=handle_extended (hi,lo,wb);
2288             }
2289             if (lo>=0x40 && lo<=0x7f)
2290                 handle_pac (hi,lo,wb);
2291             break;
2292         case 0x14:
2293         case 0x15:
2294             if (lo>=0x20 && lo<=0x2f)
2295                 handle_command (hi,lo,wb);
2296             if (lo>=0x40 && lo<=0x7f)
2297                 handle_pac (hi,lo,wb);
2298             break;
2299         case 0x16:
2300             if (lo>=0x40 && lo<=0x7f)
2301                 handle_pac (hi,lo,wb);
2302             break;
2303         case 0x17:
2304             if (lo>=0x21 && lo<=0x22)
2305                 handle_command (hi,lo,wb);
2306             if (lo>=0x2e && lo<=0x2f)
2307                 handle_text_attr (hi,lo,wb);
2308             if (lo>=0x40 && lo<=0x7f)
2309                 handle_pac (hi,lo,wb);
2310             break;
2311     }
2312     return wrote_to_screen;
2313 }
2314
2315 void process608 (const unsigned char *data, int length, struct s_write *wb)
2316 {
2317     static int textprinted = 0;
2318     int i;
2319
2320     if (data!=NULL)
2321     {
2322         for (i=0;i<length;i=i+2)
2323         {
2324             unsigned char hi, lo;
2325             int wrote_to_screen=0; 
2326             hi = data[i] & 0x7F; // Get rid of parity bit
2327             lo = data[i+1] & 0x7F; // Get rid of parity bit
2328
2329             if (hi==0 && lo==0) // Just padding
2330                 continue;
2331             // hb_log ("\r[%02X:%02X]\n",hi,lo);
2332
2333             if (hi>=0x01 && hi<=0x0E)
2334             {
2335                 // XDS crap - mode. Would be nice to support it eventually
2336                 // wb->data608->last_c1=0;
2337                 // wb->data608->last_c2=0;
2338                 wb->data608->channel=3; // Always channel 3
2339                 wb->in_xds_mode=1;
2340             }
2341             if (hi==0x0F) // End of XDS block
2342             {
2343                 wb->in_xds_mode=0;
2344                 continue;
2345             }
2346             if (hi>=0x10 && hi<0x1F) // Non-character code or special/extended char
2347                 // http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/CC_CODES.HTML
2348                 // http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/CC_CHARS.HTML
2349             {
2350                 // We were writing characters before, start a new line for
2351                 // diagnostic output from disCommand()
2352                 if (debug_608 && textprinted == 1 )
2353                 {
2354                     hb_log("\n");
2355                     textprinted = 0;
2356                 }
2357
2358                 wb->in_xds_mode=0; // Back to normal
2359                 if (wb->data608->last_c1==hi && wb->data608->last_c2==lo)
2360                 {
2361                     // Duplicate dual code, discard
2362                     continue;
2363                 }
2364                 wb->data608->last_c1=hi;
2365                 wb->data608->last_c2=lo;
2366                 wrote_to_screen=disCommand (hi,lo,wb);
2367             }
2368             if (hi>=0x20) // Standard characters (always in pairs)
2369             {
2370                 // Only print if the channel is active
2371                 if (wb->data608->channel!=cc_channel)
2372                     continue;
2373
2374                 if (debug_608)
2375                 {
2376                     if( textprinted == 0 )
2377                     {
2378                         hb_log("\n");
2379                         textprinted = 1;
2380                     }
2381                 }
2382
2383                 handle_single(hi,wb);
2384                 handle_single(lo,wb);
2385                 wrote_to_screen=1;
2386                 wb->data608->last_c1=0;
2387                 wb->data608->last_c2=0;
2388             }
2389
2390             if ( debug_608 && !textprinted && wb->data608->channel==cc_channel )
2391             {   // Current FTS information after the characters are shown
2392                 //hb_log("Current FTS: %s\n", print_mstime(get_fts()));
2393             }
2394
2395             if (wrote_to_screen && direct_rollup && // If direct_rollup is enabled and
2396                 (wb->data608->mode==MODE_ROLLUP_2 || // we are in rollup mode, write now.
2397                 wb->data608->mode==MODE_ROLLUP_3 ||
2398                 wb->data608->mode==MODE_ROLLUP_4))
2399             {
2400                 // We don't increase screenfuls_counter here.
2401                 write_cc_buffer (wb);
2402                 wb->data608->current_visible_start_ms=get_fts(wb);
2403             }
2404         }
2405     }
2406 }
2407
2408
2409 /* Return a pointer to a string that holds the printable characters
2410  * of the caption data block. FOR DEBUG PURPOSES ONLY! */
2411 unsigned char *debug_608toASC (unsigned char *cc_data, int channel)
2412 {
2413     static unsigned char output[3];
2414
2415     unsigned char cc_valid = (cc_data[0] & 4) >>2;
2416     unsigned char cc_type = cc_data[0] & 3;
2417     unsigned char hi, lo;
2418
2419     output[0]=' ';
2420     output[1]=' ';
2421     output[2]='\x00';
2422
2423     if (cc_valid && cc_type==channel)
2424     {
2425         hi = cc_data[1] & 0x7F; // Get rid of parity bit
2426         lo = cc_data[2] & 0x7F; // Get rid of parity bit
2427         if (hi>=0x20)
2428         {
2429             output[0]=hi;
2430             output[1]=(lo>=20 ? lo : '.');
2431             output[2]='\x00';
2432         }
2433         else
2434         {
2435             output[0]='<';
2436             output[1]='>';
2437             output[2]='\x00';
2438         }
2439     }
2440     return output;
2441 }
2442
2443
2444 struct hb_work_private_s
2445 {
2446     hb_job_t           * job;
2447     struct s_write     * cc608;
2448 };
2449
2450 int decccInit( hb_work_object_t * w, hb_job_t * job )
2451 {
2452     int retval = 1;
2453     hb_work_private_t * pv;
2454
2455     pv = calloc( 1, sizeof( hb_work_private_t ) );
2456     if( pv )
2457     {
2458         w->private_data = pv;
2459
2460         pv->job = job;
2461
2462         pv->cc608 = calloc(1, sizeof(struct s_write));
2463
2464         if( pv->cc608 )
2465         {
2466             retval = general_608_init(pv->cc608);
2467             if( !retval )
2468             {
2469                 pv->cc608->data608 = calloc(1, sizeof(struct eia608));
2470                 if( !pv->cc608->data608 )
2471                 {
2472                     retval = 1;
2473                 }
2474             }
2475         }
2476     }
2477     return retval;
2478 }
2479
2480 int decccWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
2481                hb_buffer_t ** buf_out )
2482 {
2483     hb_work_private_t * pv = w->private_data;
2484     hb_buffer_t * in = *buf_in;
2485
2486     if ( in->size <= 0 )
2487     {
2488         /* EOF on input stream - send it downstream & say that we're done */
2489         handle_end_of_data(pv->cc608);
2490         /*
2491          * Grab any pending buffer and output them with the EOF on the end
2492          */
2493         if (pv->cc608->hb_last_buffer) {
2494             pv->cc608->hb_last_buffer->next = in;
2495             *buf_out = pv->cc608->hb_buffer;
2496             *buf_in = NULL;
2497             pv->cc608->hb_buffer = NULL;
2498             pv->cc608->hb_last_buffer = NULL;
2499         } else {
2500             *buf_out = in;
2501             *buf_in = NULL;
2502         }
2503         return HB_WORK_DONE;
2504     }
2505
2506     pv->cc608->last_pts = in->start;
2507
2508     process608(in->data, in->size, pv->cc608);
2509
2510     /*
2511      * If there is one waiting then pass it on
2512      */
2513     *buf_out = pv->cc608->hb_buffer;
2514     pv->cc608->hb_buffer = NULL;
2515     pv->cc608->hb_last_buffer = NULL;
2516
2517     return HB_WORK_OK; 
2518 }
2519
2520 void decccClose( hb_work_object_t * w )
2521 {
2522     hb_work_private_t * pv = w->private_data;
2523     general_608_close( pv->cc608 );
2524     free( pv->cc608->data608 );
2525     free( pv->cc608 );
2526     free( w->private_data );
2527 }
2528
2529 hb_work_object_t hb_deccc608 =
2530 {
2531     WORK_DECCC608,
2532     "Closed Caption (608) decoder",
2533     decccInit,
2534     decccWork,
2535     decccClose
2536 };