*.h: Revert indenting
[platform/upstream/gstreamer.git] / gst / vbidec / vbiscreen.c
1 /**
2  * Copyright (c) 2002 Billy Biggs <vektor@dumbterm.net>.
3  * Copyright (c) 2002 Doug Bell <drbell@users.sourceforge.net>.
4  *
5  * Modified and adapted to GStreamer by
6  * David I. Lehn <dlehn@users.sourceforge.net>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or (at
11  * your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <glib.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <unistd.h>
34 /*#include "osdtools.h"*/
35 /*#include "speedy.h"*/
36 #include <glib.h>
37 #include "vbiscreen.h"
38 #include "gstvbidec.h"
39
40 #define ROLL_2      6
41 #define ROLL_3      7
42 #define ROLL_4      8
43 #define POP_UP      9
44 #define PAINT_ON    10
45
46
47 #define NUM_LINES  15
48 #define ROWS       15
49 #define COLS       32
50 #define FONT_SIZE  20
51
52 typedef struct osd_string_s osd_string_t;
53 struct osd_string_s
54 {
55   int width;
56   int height;
57   int r, g, b;
58   int visible;
59   GstVBIDec *vbidec;
60 };
61
62 osd_string_t *
63 osd_string_new (char *c, int s, int w, int h, int a, void *user_data)
64 {
65   osd_string_t *os;
66
67   os = (osd_string_t *) malloc (sizeof (osd_string_t));
68   if (!os)
69     return NULL;
70   os->width = 0;
71   os->height = 0;
72   os->r = os->g = os->b = 0;
73   os->visible = 1;
74   os->vbidec = (GstVBIDec *) user_data;
75   return os;
76 }
77
78 void
79 osd_string_show_text (osd_string_t * os, char *s, int len)
80 {
81   /* FIXME: just print data when it gets here */
82   if (len > 0) {
83     gst_vbidec_show_text (os->vbidec, s, len);
84   }
85 }
86 int
87 osd_string_get_height (osd_string_t * os)
88 {
89   return os->height;
90 }
91
92 int
93 osd_string_get_width (osd_string_t * os)
94 {
95   return os->width;
96 }
97
98 void
99 osd_string_delete (osd_string_t * os)
100 {
101   free (os);
102 }
103
104 void
105 osd_string_set_colour_rgb (osd_string_t * os, int r, int g, int b)
106 {
107   os->r = r;
108   os->g = g;
109   os->b = b;
110 }
111
112 void
113 blit_colour_packed422_scanline (unsigned char *d, int w, int luma, int cb,
114     int cr)
115 {
116 }
117 int
118 osd_string_visible (osd_string_t * os)
119 {
120   return os->visible;
121 }
122
123 void
124 osd_string_composite_packed422_scanline (osd_string_t * os, unsigned char *a,
125     unsigned char *b, int w, int x, int y)
126 {
127 }
128
129 struct vbiscreen_s
130 {
131
132   osd_string_t *line[ROWS];
133
134   char buffers[ROWS * COLS * 2];
135   char text[2 * ROWS * COLS];
136   char hiddenbuf[COLS];
137   char paintbuf[ROWS * COLS];
138
139   unsigned int fgcolour;
140   unsigned int bgcolour;
141   int bg_luma, bg_cb, bg_cr;
142
143   int frame_width;
144   int frame_height;
145   int frame_aspect;
146
147   int x, y;                     /* where to draw console */
148   int width, height;            /* the size box we have to draw in */
149   int rowheight, charwidth;
150
151   int curx, cury;               /* cursor position */
152   int rows, cols;               /* 32 cols 15 rows */
153   int captions, style;          /* CC (1) or Text (0), RU2 RU3 RU4 POP_UP PAINT_ON */
154   int first_line;               /* where to start drawing */
155   int curbuffer;
156   int top_of_screen;            /* a pointer into line[] */
157   int indent;
158   int got_eoc;
159   int scroll;
160
161   char *fontfile;
162   int fontsize;
163   int verbose;
164
165   void *user_data;
166 };
167
168 vbiscreen_t *
169 vbiscreen_new (int video_width, int video_height,
170     double video_aspect, int verbose, void *user_data)
171 {
172   int i = 0, fontsize = FONT_SIZE;
173   vbiscreen_t *vs = (vbiscreen_t *) malloc (sizeof (struct vbiscreen_s));
174
175   if (!vs) {
176     return NULL;
177   }
178
179   vs->verbose = verbose;
180   vs->x = 0;
181   vs->y = 0;
182   vs->frame_width = video_width;
183   vs->frame_height = video_height;
184   vs->frame_aspect = video_aspect;
185   vs->curx = 0;
186   vs->cury = 0;
187   vs->fgcolour = 0xFFFFFFFFU;   /* white */
188   vs->bgcolour = 0xFF000000U;   /* black */
189   vs->bg_luma = 16;
190   vs->bg_cb = 128;
191   vs->bg_cr = 128;
192   vs->rows = ROWS;
193   vs->cols = COLS;
194   /*vs->fontfile = DATADIR "/FreeMonoBold.ttf"; */
195   vs->fontfile = NULL;
196   vs->fontsize = fontsize;
197   vs->width = video_width;
198   vs->height = video_height;
199   vs->first_line = 0;
200   vs->captions = 0;
201   vs->style = 0;
202   vs->curbuffer = 0;
203   vs->top_of_screen = 0;
204   vs->indent = 0;
205   memset (vs->buffers, 0, 2 * COLS * ROWS);
206   memset (vs->hiddenbuf, 0, COLS);
207   memset (vs->paintbuf, 0, ROWS * COLS);
208   vs->scroll = 0;
209
210   vs->user_data = user_data;
211
212   vs->line[0] = osd_string_new (vs->fontfile, fontsize, video_width,
213       video_height, video_aspect, user_data);
214
215   if (!vs->line[0]) {
216     vs->fontfile = "./FreeMonoBold.ttf";
217
218     vs->line[0] = osd_string_new (vs->fontfile, fontsize,
219         video_width, video_height, video_aspect, user_data);
220   }
221
222   if (!vs->line[0]) {
223     fprintf (stderr, "vbiscreen: Could not find my font (%s)!\n", vs->fontfile);
224     vbiscreen_delete (vs);
225     return NULL;
226   }
227
228   osd_string_show_text (vs->line[0], "W", 0);
229   vs->rowheight = osd_string_get_height (vs->line[0]);
230   vs->charwidth = osd_string_get_width (vs->line[0]);
231   osd_string_delete (vs->line[0]);
232
233   for (i = 0; i < ROWS; i++) {
234     vs->line[i] = osd_string_new (vs->fontfile, fontsize,
235         video_width, video_height, video_aspect, user_data);
236     if (!vs->line[i]) {
237       fprintf (stderr, "vbiscreen: Could not allocate a line.\n");
238       vbiscreen_delete (vs);
239       return NULL;
240     }
241     osd_string_set_colour_rgb (vs->line[i],
242         (vs->fgcolour & 0xff0000) >> 16,
243         (vs->fgcolour & 0xff00) >> 8, (vs->fgcolour & 0xff));
244     osd_string_show_text (vs->line[i], " ", 0);
245   }
246   memset (vs->text, 0, 2 * ROWS * COLS);
247   return vs;
248 }
249
250 void
251 blank_screen (vbiscreen_t * vs)
252 {
253   int i;
254
255   if (vs->verbose)
256     fprintf (stderr, "in blank\n");
257   for (i = 0; i < ROWS; i++) {
258     osd_string_show_text (vs->line[i], " ", 0);
259   }
260 }
261
262 void
263 clear_screen (vbiscreen_t * vs)
264 {
265   int base, i;
266
267   if (!vs)
268     return;
269
270   base = vs->top_of_screen * COLS;
271   for (i = 0; i < ROWS * COLS; i++) {
272     vs->text[base] = 0;
273     base++;
274     base %= 2 * ROWS * COLS;
275   }
276   blank_screen (vs);
277 }
278
279 void
280 clear_hidden_roll (vbiscreen_t * vs)
281 {
282   if (!vs)
283     return;
284   memset (vs->hiddenbuf, 0, COLS);
285 }
286
287 void
288 clear_hidden_pop (vbiscreen_t * vs)
289 {
290   if (!vs)
291     return;
292   memset (vs->buffers + vs->curbuffer * COLS * ROWS, 0, COLS * ROWS);
293 }
294
295 void
296 clear_hidden_paint (vbiscreen_t * vs)
297 {
298   if (!vs)
299     return;
300   memset (vs->paintbuf, 0, COLS * ROWS);
301 }
302
303 void
304 clear_displayed_pop (vbiscreen_t * vs)
305 {
306   if (!vs)
307     return;
308   memset (vs->buffers + (vs->curbuffer ^ 1) * COLS * ROWS, 0, COLS * ROWS);
309 }
310
311 void
312 vbiscreen_dump_screen_text (vbiscreen_t * vs)
313 {
314   int i, offset;
315
316   if (!vs)
317     return;
318   offset = vs->top_of_screen * COLS;
319
320   fprintf (stderr, "\n   0123456789abcdefghij012345678901");
321   for (i = 0; i < ROWS * COLS; i++) {
322     if (!(i % COLS))
323       fprintf (stderr, "\n%.2d ", i / COLS);
324     fprintf (stderr, "%c", vs->text[offset] ? vs->text[offset] : ' ');
325     offset++;
326     offset %= 2 * ROWS * COLS;
327   }
328   fprintf (stderr, "\n   0123456789abcdefghij012345678901\n   ");
329   for (i = 0; i < COLS; i++) {
330     fprintf (stderr, "%c", vs->text[offset] ? vs->text[offset] : ' ');
331     offset++;
332     offset %= 2 * ROWS * COLS;
333   }
334   fprintf (stderr, "\n   0123456789abcdefghij012345678901\n");
335 }
336
337 int
338 update_row_x (vbiscreen_t * vs, int row)
339 {
340   char text[COLS + 1];
341   int i, j, haschars = 0, base;
342
343   if (!vs)
344     return 0;
345
346   text[COLS] = 0;
347   base = ((vs->top_of_screen + row) % (2 * ROWS)) * COLS;
348   for (j = 0, i = base; i < base + COLS; i++, j++) {
349     if (vs->text[i]) {
350       text[j] = vs->text[i];
351       haschars = 1;
352     } else {
353       text[j] = ' ';
354     }
355   }
356
357   osd_string_set_colour_rgb (vs->line[row],
358       (vs->fgcolour & 0xff0000) >> 16,
359       (vs->fgcolour & 0xff00) >> 8, (vs->fgcolour & 0xff));
360   if (!haschars)
361     osd_string_show_text (vs->line[row], " ", 0);
362   else
363     osd_string_show_text (vs->line[row], text, 51);
364
365   return haschars;
366 }
367
368 void
369 update_row (vbiscreen_t * vs)
370 {
371   if (!vs)
372     return;
373
374   update_row_x (vs, vs->cury);
375   //vbiscreen_dump_screen_text( vs );
376 }
377
378 void
379 update_all_rows (vbiscreen_t * vs)
380 {
381   int row = 0;
382
383   if (!vs)
384     return;
385
386   for (row = 0; row < ROWS; row++) {
387     update_row_x (vs, row);
388   }
389   //vbiscreen_dump_screen_text( vs );
390 }
391
392 void
393 vbiscreen_delete (vbiscreen_t * vs)
394 {
395   free (vs);
396 }
397
398 void
399 copy_row_to_screen (vbiscreen_t * vs, char *row)
400 {
401   int base, i, j;
402
403   base = ((vs->top_of_screen + vs->cury) % (2 * ROWS)) * COLS;
404   for (j = 0, i = base; i < base + COLS; j++, i++) {
405     vs->text[i] = row[j];
406   }
407   update_row (vs);
408 }
409
410 void
411 scroll_screen (vbiscreen_t * vs)
412 {
413   int start_row;
414
415   if (!vs || !vs->captions || !vs->style || vs->style > ROLL_4)
416     return;
417
418   start_row = (vs->first_line + vs->top_of_screen) % (2 * ROWS);
419   if (vs->verbose)
420     fprintf (stderr, "start row : %d first line %d\n ", start_row,
421         vs->first_line);
422
423   /* zero out top row */
424   memset ((char *) (vs->text + start_row * COLS), 0, COLS);
425   vs->top_of_screen = (vs->top_of_screen + 1) % (2 * ROWS);
426   vs->curx = vs->indent;
427   update_all_rows (vs);
428   copy_row_to_screen (vs, vs->hiddenbuf);
429   clear_hidden_roll (vs);
430   vs->scroll = 26;
431 }
432
433 void
434 vbiscreen_set_verbose (vbiscreen_t * vs, int verbose)
435 {
436   vs->verbose = verbose;
437 }
438
439 void
440 vbiscreen_new_caption (vbiscreen_t * vs, int indent, int ital,
441     unsigned int colour, int row)
442 {
443   if (!vs)
444     return;
445   if (vs->verbose)
446     fprintf (stderr, "indent: %d, ital: %d, colour: 0x%x, row: %d\n", indent,
447         ital, colour, row);
448
449   if (0 && vs->captions && vs->style <= ROLL_4 && vs->style) {
450     if (row != vs->cury + 1) {
451       vs->cury = row - 1;
452       clear_hidden_roll (vs);
453     } else {
454 //            scroll_screen( vs );
455     }
456   }
457
458   if (vs->style > ROLL_4) {
459     vs->cury = ((row > 0) ? row - 1 : 0);
460   }
461
462   vs->fgcolour = colour;
463   vs->indent = indent;
464   vs->curx = indent;
465 }
466
467 void
468 vbiscreen_set_mode (vbiscreen_t * vs, int caption, int style)
469 {
470   if (!vs)
471     return;
472   if (vs->verbose)
473     fprintf (stderr, "in set mode\n");
474
475   if (vs->verbose) {
476     fprintf (stderr, "Caption: %d ", caption);
477     switch (style) {
478       case ROLL_2:
479         fprintf (stderr, "ROLL 2\n");
480         break;
481       case ROLL_3:
482         fprintf (stderr, "ROLL 3\n");
483         break;
484       case ROLL_4:
485         fprintf (stderr, "ROLL 4\n");
486         break;
487       case POP_UP:
488         fprintf (stderr, "POP UP\n");
489         break;
490       case PAINT_ON:
491         fprintf (stderr, "PAINT ON\n");
492         break;
493       default:
494         break;
495     }
496   }
497   if (!caption) {
498     /* text mode */
499     vs->cury = 0;
500   } else {
501     /* captioning mode */
502     /* styles: ru2 ru3 ru4 pop paint
503      */
504     if (style != POP_UP && vs->style == POP_UP && !vs->got_eoc) {
505       /* stupid that sometimes they dont send a EOC */
506       vbiscreen_end_of_caption (vs);
507     }
508
509     switch (style) {
510       case ROLL_2:
511       case ROLL_3:
512       case ROLL_4:
513         if (vs->style == style) {
514           return;
515         }
516         vs->first_line = ROWS - (style - 4);
517
518         if (vs->verbose)
519           fprintf (stderr, "first_line %d\n", vs->first_line);
520
521         vs->cury = ROWS - 1;
522         break;
523       case POP_UP:
524         vs->got_eoc = 0;
525         break;
526       case PAINT_ON:
527         break;
528     }
529   }
530
531   vs->captions = caption;
532   vs->style = style;
533 }
534
535 void
536 vbiscreen_tab (vbiscreen_t * vs, int cols)
537 {
538   if (!vs)
539     return;
540   if (cols < 0 || cols > 3)
541     return;
542   vs->curx += cols;
543   if (vs->curx > 31)
544     vs->curx = 31;
545 }
546
547 void
548 vbiscreen_set_colour (vbiscreen_t * vs, unsigned int col)
549 {
550   if (!vs)
551     return;
552   vs->fgcolour = col;
553 }
554
555 void
556 vbiscreen_clear_current_cell (vbiscreen_t * vs)
557 {
558   vs->text[((vs->top_of_screen + vs->cury) % (2 * ROWS)) * COLS
559       + vs->curx + vs->indent] = 0;
560 }
561
562 void
563 vbiscreen_set_current_cell (vbiscreen_t * vs, char text)
564 {
565   int base;
566
567   if (!vs)
568     return;
569   base = ((vs->top_of_screen + vs->cury) % (2 * ROWS)) * COLS;
570   if (g_ascii_isprint (text))
571     vs->text[base + vs->curx + vs->indent] = text;
572   else
573     vs->text[base + vs->curx + vs->indent] = ' ';
574 }
575
576 void
577 vbiscreen_delete_to_end (vbiscreen_t * vs)
578 {
579   int i;
580
581   if (!vs)
582     return;
583   if (vs->verbose)
584     fprintf (stderr, "in del to end\n");
585   for (i = vs->curx; i < COLS; i++) {
586     vbiscreen_clear_current_cell (vs);
587     vs->curx++;
588   }
589   vs->curx = COLS - 1;          /* is this right ? */
590   if (vs->captions && vs->style && vs->style != POP_UP)
591     update_row (vs);
592 }
593
594 void
595 vbiscreen_backspace (vbiscreen_t * vs)
596 {
597   if (!vs)
598     return;
599   if (vs->verbose)
600     fprintf (stderr, "in backspace\n");
601   if (!vs->curx)
602     return;
603   vs->curx--;
604   vbiscreen_clear_current_cell (vs);
605   update_row (vs);
606 }
607
608 void
609 vbiscreen_erase_displayed (vbiscreen_t * vs)
610 {
611   if (!vs)
612     return;
613   if (vs->verbose)
614     fprintf (stderr, "in erase disp\n");
615
616   if (vs->captions && vs->style && vs->style <= ROLL_4) {
617     clear_hidden_roll (vs);
618   }
619
620   clear_displayed_pop (vs);
621   clear_screen (vs);
622 }
623
624 void
625 vbiscreen_erase_non_displayed (vbiscreen_t * vs)
626 {
627   if (!vs)
628     return;
629   if (vs->verbose)
630     fprintf (stderr, "in erase non disp\n");
631
632   if (vs->captions && vs->style == POP_UP) {
633     memset (vs->buffers + vs->curbuffer * COLS * ROWS + vs->cury * COLS, 0,
634         COLS);
635 //        clear_hidden_pop( vs );
636   } else if (vs->captions && vs->style && vs->style <= ROLL_4) {
637     clear_hidden_roll (vs);
638   }
639 }
640
641 void
642 vbiscreen_carriage_return (vbiscreen_t * vs)
643 {
644   if (!vs)
645     return;
646   if (vs->verbose)
647     fprintf (stderr, "in CR\n");
648   if (vs->style != POP_UP) {
649     /* not sure if this is right for text mode */
650     /* in text mode, perhaps a CR on last row clears screen and goes
651      * to (0,0) */
652     scroll_screen (vs);
653   }
654
655   /* keep cursor on bottom for rollup */
656   if (vs->captions && vs->style && vs->style <= ROLL_4)
657     vs->cury--;
658
659   vs->cury++;
660   vs->curx = 0;
661 }
662
663 void
664 copy_buf_to_screen (vbiscreen_t * vs, char *buf)
665 {
666   int base, i, j;
667
668   if (!vs)
669     return;
670
671   base = vs->top_of_screen * COLS;
672   for (j = 0, i = 0; i < ROWS * COLS; i++, j++) {
673     vs->text[base] = buf[j];
674     base++;
675     base %= 2 * ROWS * COLS;
676   }
677   update_all_rows (vs);
678 }
679
680 void
681 vbiscreen_end_of_caption (vbiscreen_t * vs)
682 {
683   /*int i; */
684   if (!vs)
685     return;
686   if (vs->verbose)
687     fprintf (stderr, "in end of caption\n");
688
689   if (vs->style == PAINT_ON) {
690     copy_buf_to_screen (vs, vs->paintbuf);
691     clear_hidden_paint (vs);
692   } else if (vs->style == POP_UP) {
693     copy_buf_to_screen (vs, vs->buffers + vs->curbuffer * COLS * ROWS);
694     vs->curbuffer ^= 1;
695   }
696
697   /* to be safe? */
698   vs->curx = 0;
699   vs->cury = ROWS - 1;
700   vs->got_eoc = 1;
701 }
702
703 void
704 vbiscreen_print (vbiscreen_t * vs, char c1, char c2)
705 {
706   if (!vs)
707     return;
708   if (vs->verbose)
709     fprintf (stderr, "in print (%d, %d)[%c %c]\n", vs->curx, vs->cury, c1, c2);
710   if (vs->captions && vs->style == POP_UP) {
711     /* this all gets displayed at another time */
712     if (vs->curx != COLS - 1) {
713       *(vs->buffers + vs->curx + vs->curbuffer * ROWS * COLS +
714           vs->cury * COLS) = c1;
715       vs->curx++;
716     }
717
718     if (vs->curx != COLS - 1 && c2) {
719       *(vs->buffers + vs->curx + vs->curbuffer * ROWS * COLS +
720           vs->cury * COLS) = c2;
721       vs->curx++;
722     } else if (c2) {
723       *(vs->buffers + vs->curx + vs->curbuffer * ROWS * COLS +
724           vs->cury * COLS) = c2;
725     }
726   }
727
728   if (vs->captions && vs->style == PAINT_ON) {
729     if (vs->curx != COLS - 1) {
730       vs->paintbuf[vs->curx + vs->cury * COLS] = c1;
731       vs->curx++;
732     }
733
734     if (vs->curx != COLS - 1 && c2) {
735       vs->paintbuf[vs->curx + vs->cury * COLS] = c2;
736       vs->curx++;
737     } else if (c2) {
738       vs->paintbuf[vs->curx + vs->cury * COLS] = c2;
739     }
740   }
741
742   if (vs->captions && vs->style && vs->style <= ROLL_4) {
743     if (vs->curx != COLS - 1) {
744       vs->hiddenbuf[vs->curx] = c1;
745       vs->curx++;
746     } else {
747       vs->hiddenbuf[vs->curx] = c1;
748     }
749
750     if (vs->curx != COLS - 1 && c2) {
751       vs->hiddenbuf[vs->curx] = c2;
752       vs->curx++;
753     } else if (c2) {
754       vs->hiddenbuf[vs->curx] = c2;
755     }
756   }
757 }
758
759 void
760 vbiscreen_reset (vbiscreen_t * vs)
761 {
762   if (!vs)
763     return;
764   clear_screen (vs);
765   clear_hidden_pop (vs);
766   clear_displayed_pop (vs);
767   clear_hidden_roll (vs);
768   vs->captions = 0;
769   vs->style = 0;
770 }
771
772 void
773 vbiscreen_composite_packed422_scanline (vbiscreen_t * vs,
774     unsigned char *output, int width, int xpos, int scanline)
775 {
776   int x = 0, y = 0, row = 0, index = 0;
777
778   if (!vs)
779     return;
780   if (!output)
781     return;
782   if (scanline >= vs->y && scanline < vs->y + vs->height) {
783
784     if (0 && !vs->captions)
785       blit_colour_packed422_scanline (output + (vs->x * 2), vs->width,
786           vs->bg_luma, vs->bg_cb, vs->bg_cr);
787
788     index = vs->top_of_screen * COLS;
789     x = (vs->x + vs->charwidth) & ~1;
790     for (row = 0; row < ROWS; row++) {
791       y = vs->y + row * vs->rowheight + vs->rowheight;
792       if (osd_string_visible (vs->line[row])) {
793         if (scanline >= y && scanline < y + vs->rowheight) {
794
795           int startx;
796           int strx;
797
798           startx = x - xpos;
799           strx = 0;
800
801           if (startx < 0) {
802             strx = -startx;
803             startx = 0;
804           }
805
806
807           if (startx < width) {
808
809             if (vs->captions)
810               blit_colour_packed422_scanline (output + (startx * 2),
811                   osd_string_get_width (vs->line[row]),
812                   vs->bg_luma, vs->bg_cb, vs->bg_cr);
813
814             osd_string_composite_packed422_scanline (vs->line[row],
815                 output + (startx * 2),
816                 output + (startx * 2), width - startx, strx, scanline - y);
817           }
818         }
819         index++;
820       }
821     }
822   }
823 }