1 /*
2 * WebP (.webp) image decoder
3 * Copyright (c) 2013 Aneesh Dogra <aneesh@sugarlabs.org>
4 * Copyright (c) 2013 Justin Ruggles <justin.ruggles@gmail.com>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 /**
24 * @file
25 * WebP image decoder
26 *
27 * @author Aneesh Dogra <aneesh@sugarlabs.org>
28 * Container and Lossy decoding
29 *
30 * @author Justin Ruggles <justin.ruggles@gmail.com>
31 * Lossless decoder
32 * Compressed alpha for lossy
33 *
34 * Unimplemented:
35 * - Animation
36 * - ICC profile
37 * - Exif and XMP metadata
38 */
39
40 #define BITSTREAM_READER_LE
48
49 #define VP8X_FLAG_ANIMATION 0x02
50 #define VP8X_FLAG_XMP_METADATA 0x04
51 #define VP8X_FLAG_EXIF_METADATA 0x08
52 #define VP8X_FLAG_ALPHA 0x10
53 #define VP8X_FLAG_ICC 0x20
54
55 #define MAX_PALETTE_SIZE 256
56 #define MAX_CACHE_BITS 11
57 #define NUM_CODE_LENGTH_CODES 19
58 #define HUFFMAN_CODES_PER_META_CODE 5
59 #define NUM_LITERAL_CODES 256
60 #define NUM_LENGTH_CODES 24
61 #define NUM_DISTANCE_CODES 40
62 #define NUM_SHORT_DISTANCES 120
63 #define MAX_HUFFMAN_CODE_LENGTH 15
64
69 };
70
72 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
73 };
74
76 { 0, 1 }, { 1, 0 }, { 1, 1 }, { -1, 1 }, { 0, 2 }, { 2, 0 }, { 1, 2 }, { -1, 2 },
77 { 2, 1 }, { -2, 1 }, { 2, 2 }, { -2, 2 }, { 0, 3 }, { 3, 0 }, { 1, 3 }, { -1, 3 },
78 { 3, 1 }, { -3, 1 }, { 2, 3 }, { -2, 3 }, { 3, 2 }, { -3, 2 }, { 0, 4 }, { 4, 0 },
79 { 1, 4 }, { -1, 4 }, { 4, 1 }, { -4, 1 }, { 3, 3 }, { -3, 3 }, { 2, 4 }, { -2, 4 },
80 { 4, 2 }, { -4, 2 }, { 0, 5 }, { 3, 4 }, { -3, 4 }, { 4, 3 }, { -4, 3 }, { 5, 0 },
81 { 1, 5 }, { -1, 5 }, { 5, 1 }, { -5, 1 }, { 2, 5 }, { -2, 5 }, { 5, 2 }, { -5, 2 },
82 { 4, 4 }, { -4, 4 }, { 3, 5 }, { -3, 5 }, { 5, 3 }, { -5, 3 }, { 0, 6 }, { 6, 0 },
83 { 1, 6 }, { -1, 6 }, { 6, 1 }, { -6, 1 }, { 2, 6 }, { -2, 6 }, { 6, 2 }, { -6, 2 },
84 { 4, 5 }, { -4, 5 }, { 5, 4 }, { -5, 4 }, { 3, 6 }, { -3, 6 }, { 6, 3 }, { -6, 3 },
85 { 0, 7 }, { 7, 0 }, { 1, 7 }, { -1, 7 }, { 5, 5 }, { -5, 5 }, { 7, 1 }, { -7, 1 },
86 { 4, 6 }, { -4, 6 }, { 6, 4 }, { -6, 4 }, { 2, 7 }, { -2, 7 }, { 7, 2 }, { -7, 2 },
87 { 3, 7 }, { -3, 7 }, { 7, 3 }, { -7, 3 }, { 5, 6 }, { -5, 6 }, { 6, 5 }, { -6, 5 },
88 { 8, 0 }, { 4, 7 }, { -4, 7 }, { 7, 4 }, { -7, 4 }, { 8, 1 }, { 8, 2 }, { 6, 6 },
89 { -6, 6 }, { 8, 3 }, { 5, 7 }, { -5, 7 }, { 7, 5 }, { -7, 5 }, { 8, 4 }, { 6, 7 },
90 { -6, 7 }, { 7, 6 }, { -7, 6 }, { 8, 5 }, { 7, 7 }, { -7, 7 }, { 8, 6 }, { 8, 7 }
91 };
92
96 };
97
103 };
104
110 };
111
127 };
128
135 };
136
137 /* The structure of WebP lossless is an optional series of transformation data,
138 * followed by the primary image. The primary image also optionally contains
139 * an entropy group mapping if there are multiple entropy groups. There is a
140 * basic image type called an "entropy coded image" that is used for all of
141 * these. The type of each entropy coded image is referred to by the
142 * specification as its role. */
144 /* Primary Image: Stores the actual pixels of the image. */
146
147 /* Entropy Image: Defines which Huffman group to use for different areas of
148 * the primary image. */
150
151 /* Predictors: Defines which predictor type to use for different areas of
152 * the primary image. */
154
155 /* Color Transform Data: Defines the color transformation for different
156 * areas of the primary image. */
158
159 /* Color Index: Stored as an image of height == 1. */
161
163 };
164
167 int simple;
/* whether to use simple mode */
171
182
197
204
205 #define GET_PIXEL(frame, x, y) \
206 ((frame)->data[0] + (y) * frame->linesize[0] + 4 * (x))
207
208 #define GET_PIXEL_COMP(frame, x, y, c) \
209 (*((frame)->data[0] + (y) * frame->linesize[0] + 4 * (x) + c))
210
212 {
213 int i, j;
214
222 }
224 }
225 memset(img, 0, sizeof(*img));
226 }
227
228
229 /* Differs from get_vlc2() in the following ways:
230 * - codes are bit-reversed
231 * - assumes 8-bit table to make reversal simpler
232 * - assumes max depth of 2 since the max code length for WebP is 15
233 */
235 {
238 int code;
239
242
247
248 if (n < 0) {
251
253
258 }
260
262
263 return code;
264 }
265
267 {
271 else
273 } else
275 }
276
278 int alphabet_size)
279 {
281 int max_code_length = 0;
282 uint16_t *codes;
283
284 for (sym = 0; sym < alphabet_size; sym++)
285 max_code_length =
FFMAX(max_code_length, code_lengths[sym]);
286
289
290 codes =
av_malloc(alphabet_size *
sizeof(*codes));
291 if (!codes)
293
294 code = 0;
296 for (len = 1; len <= max_code_length; len++) {
297 for (sym = 0; sym < alphabet_size; sym++) {
298 if (code_lengths[sym] != len)
299 continue;
300 codes[sym] = code++;
302 }
303 code <<= 1;
304 }
308 }
309
311 code_lengths, sizeof(*code_lengths), sizeof(*code_lengths),
312 codes, sizeof(*codes), sizeof(*codes), 0);
313 if (ret < 0) {
316 }
318
320 return 0;
321 }
322
324 {
326
329 else
331
334
336 }
337
339 int alphabet_size)
340 {
341 HuffReader code_len_hc = { { 0 }, 0, 0, { 0 } };
342 int *code_lengths = NULL;
344 int i, symbol, max_symbol, prev_code_len,
ret;
346
349
350 for (i = 0; i < num_codes; i++)
352
355 if (ret < 0)
357
358 code_lengths = av_mallocz_array(alphabet_size, sizeof(*code_lengths));
359 if (!code_lengths) {
362 }
363
367 if (max_symbol > alphabet_size) {
369 max_symbol, alphabet_size);
372 }
373 } else {
374 max_symbol = alphabet_size;
375 }
376
377 prev_code_len = 8;
378 symbol = 0;
379 while (symbol < alphabet_size) {
380 int code_len;
381
382 if (!max_symbol--)
383 break;
385 if (code_len < 16) {
386 /* Code length code [0..15] indicates literal code lengths. */
387 code_lengths[symbol++] = code_len;
388 if (code_len)
389 prev_code_len = code_len;
390 } else {
391 int repeat = 0,
length = 0;
392 switch (code_len) {
393 case 16:
394 /* Code 16 repeats the previous non-zero value [3..6] times,
395 * i.e., 3 + ReadBits(2) times. If code 16 is used before a
396 * non-zero value has been emitted, a value of 8 is repeated. */
399 break;
400 case 17:
401 /* Code 17 emits a streak of zeros [3..10], i.e.,
402 * 3 + ReadBits(3) times. */
404 break;
405 case 18:
406 /* Code 18 emits a streak of zeros of length [11..138], i.e.,
407 * 11 + ReadBits(7) times. */
409 break;
410 }
411 if (symbol + repeat > alphabet_size) {
413 "invalid symbol %d + repeat %d > alphabet size %d\n",
414 symbol, repeat, alphabet_size);
417 }
418 while (repeat-- > 0)
419 code_lengths[symbol++] =
length;
420 }
421 }
422
424
429 }
430
432 int w, int h);
433
434 #define PARSE_BLOCK_SIZE(w, h) do { \
435 block_bits = get_bits(&s->gb, 3) + 2; \
436 blocks_w = FFALIGN((w), 1 << block_bits) >> block_bits; \
437 blocks_h = FFALIGN((h), 1 << block_bits) >> block_bits; \
438 } while (0)
439
441 {
443 int ret, block_bits,
width, blocks_w, blocks_h, x,
y, max;
444
448
450
452 if (ret < 0)
454
457
458 /* the number of huffman groups is determined by the maximum group number
459 * coded in the entropy image */
460 max = 0;
465 }
466 }
468
469 return 0;
470 }
471
473 {
474 int block_bits, blocks_w, blocks_h,
ret;
475
477
479 blocks_h);
480 if (ret < 0)
482
484
485 return 0;
486 }
487
489 {
490 int block_bits, blocks_w, blocks_h,
ret;
491
493
495 blocks_h);
496 if (ret < 0)
498
500
501 return 0;
502 }
503
505 {
507 int width_bits, index_size,
ret, x;
509
511
512 if (index_size <= 2)
513 width_bits = 3;
514 else if (index_size <= 4)
515 width_bits = 2;
516 else if (index_size <= 16)
517 width_bits = 1;
518 else
519 width_bits = 0;
520
522 index_size, 1);
523 if (ret < 0)
525
528 if (width_bits > 0)
530
531 /* color index values are delta-coded */
533 for (x = 4; x < img->
frame->
width * 4; x++, ct++)
534 ct[0] += ct[-4];
535
536 return 0;
537 }
538
541 {
543 int group = 0;
544
549 }
550
552 }
553
555 {
558 }
559
561 int w, int h)
562 {
566
567 img = &s->
image[role];
569
574 }
575
579
583 } else
585 if (ret < 0)
587
594 }
599 } else {
601 }
602
606 if (ret < 0)
609 }
615
622
625 } else {
627 if (ret < 0)
629 }
630 }
631 }
632
636
637 x = 0; y = 0;
640
644 /* literal pixel values */
652 x++;
653 if (x == width) {
654 x = 0;
655 y++;
656 }
658 /* LZ77 backwards mapping */
660
661 /* parse length and distance */
663 if (prefix_code < 4) {
664 length = prefix_code + 1;
665 } else {
667 int offset = 2 + (prefix_code & 1) << extra_bits;
668 length = offset +
get_bits(&s->
gb, extra_bits) + 1;
669 }
671 if (prefix_code < 4) {
672 distance = prefix_code + 1;
673 } else {
675 int offset = 2 + (prefix_code & 1) << extra_bits;
676 distance = offset +
get_bits(&s->
gb, extra_bits) + 1;
677 }
678
679 /* find reference location */
683 distance =
FFMAX(1, xi + yi * width);
684 } else {
686 }
687 ref_x = x;
689 if (distance <= x) {
691 distance = 0;
692 } else {
693 ref_x = 0;
694 distance -= x;
695 }
696 while (distance >= width) {
697 ref_y--;
699 }
700 if (distance > 0) {
702 ref_y--;
703 }
704 ref_x =
FFMAX(0, ref_x);
705 ref_y =
FFMAX(0, ref_y);
706
707 /* copy pixels
708 * source and dest regions can overlap and wrap lines, so just
709 * copy per-pixel */
710 for (i = 0; i <
length; i++) {
713
717 x++;
718 ref_x++;
719 if (x == width) {
720 x = 0;
721 y++;
722 }
723 if (ref_x == width) {
724 ref_x = 0;
725 ref_y++;
726 }
728 break;
729 }
730 } else {
731 /* read from color cache */
734
738 }
741 "color cache index out-of-bounds\n");
743 }
745 x++;
746 if (x == width) {
747 x = 0;
748 y++;
749 }
750 }
751 }
752
753 return 0;
754 }
755
756 /* PRED_MODE_BLACK */
759 {
761 }
762
763 /* PRED_MODE_L */
766 {
768 }
769
770 /* PRED_MODE_T */
773 {
775 }
776
777 /* PRED_MODE_TR */
780 {
782 }
783
784 /* PRED_MODE_TL */
787 {
789 }
790
791 /* PRED_MODE_AVG_T_AVG_L_TR */
794 {
795 p[0] = p_t[0] + (p_l[0] + p_tr[0] >> 1) >> 1;
796 p[1] = p_t[1] + (p_l[1] + p_tr[1] >> 1) >> 1;
797 p[2] = p_t[2] + (p_l[2] + p_tr[2] >> 1) >> 1;
798 p[3] = p_t[3] + (p_l[3] + p_tr[3] >> 1) >> 1;
799 }
800
801 /* PRED_MODE_AVG_L_TL */
804 {
805 p[0] = p_l[0] + p_tl[0] >> 1;
806 p[1] = p_l[1] + p_tl[1] >> 1;
807 p[2] = p_l[2] + p_tl[2] >> 1;
808 p[3] = p_l[3] + p_tl[3] >> 1;
809 }
810
811 /* PRED_MODE_AVG_L_T */
814 {
815 p[0] = p_l[0] + p_t[0] >> 1;
816 p[1] = p_l[1] + p_t[1] >> 1;
817 p[2] = p_l[2] + p_t[2] >> 1;
818 p[3] = p_l[3] + p_t[3] >> 1;
819 }
820
821 /* PRED_MODE_AVG_TL_T */
824 {
825 p[0] = p_tl[0] + p_t[0] >> 1;
826 p[1] = p_tl[1] + p_t[1] >> 1;
827 p[2] = p_tl[2] + p_t[2] >> 1;
828 p[3] = p_tl[3] + p_t[3] >> 1;
829 }
830
831 /* PRED_MODE_AVG_T_TR */
834 {
835 p[0] = p_t[0] + p_tr[0] >> 1;
836 p[1] = p_t[1] + p_tr[1] >> 1;
837 p[2] = p_t[2] + p_tr[2] >> 1;
838 p[3] = p_t[3] + p_tr[3] >> 1;
839 }
840
841 /* PRED_MODE_AVG_AVG_L_TL_AVG_T_TR */
844 {
845 p[0] = (p_l[0] + p_tl[0] >> 1) + (p_t[0] + p_tr[0] >> 1) >> 1;
846 p[1] = (p_l[1] + p_tl[1] >> 1) + (p_t[1] + p_tr[1] >> 1) >> 1;
847 p[2] = (p_l[2] + p_tl[2] >> 1) + (p_t[2] + p_tr[2] >> 1) >> 1;
848 p[3] = (p_l[3] + p_tl[3] >> 1) + (p_t[3] + p_tr[3] >> 1) >> 1;
849 }
850
851 /* PRED_MODE_SELECT */
854 {
855 int diff = (
FFABS(p_l[0] - p_tl[0]) -
FFABS(p_t[0] - p_tl[0])) +
856 (
FFABS(p_l[1] - p_tl[1]) -
FFABS(p_t[1] - p_tl[1])) +
857 (
FFABS(p_l[2] - p_tl[2]) -
FFABS(p_t[2] - p_tl[2])) +
858 (
FFABS(p_l[3] - p_tl[3]) -
FFABS(p_t[3] - p_tl[3]));
859 if (diff <= 0)
861 else
863 }
864
865 /* PRED_MODE_ADD_SUBTRACT_FULL */
868 {
869 p[0] = av_clip_uint8(p_l[0] + p_t[0] - p_tl[0]);
870 p[1] = av_clip_uint8(p_l[1] + p_t[1] - p_tl[1]);
871 p[2] = av_clip_uint8(p_l[2] + p_t[2] - p_tl[2]);
872 p[3] = av_clip_uint8(p_l[3] + p_t[3] - p_tl[3]);
873 }
874
876 {
877 int d = a + b >> 1;
878 return av_clip_uint8(d + (d - c) / 2);
879 }
880
881 /* PRED_MODE_ADD_SUBTRACT_HALF */
884 {
889 }
890
894
900 };
901
903 {
904 uint8_t *dec, *p_l, *p_tl, *p_t, *p_tr;
906
911 if (x == frame->
width - 1)
913 else
915
916 inverse_predict[
m](p, p_l, p_tl, p_t, p_tr);
917
918 dec[0] += p[0];
919 dec[1] += p[1];
920 dec[2] += p[2];
921 dec[3] += p[3];
922 }
923
925 {
929
935
936 if (x == 0) {
937 if (y == 0)
939 else
941 } else if (y == 0)
943
944 if (m > 13) {
946 "invalid predictor mode: %d\n", m);
948 }
950 }
951 }
952 return 0;
953 }
954
957 {
959 }
960
962 {
966
969
976
980 }
981 }
982 return 0;
983 }
984
986 {
989
993 p[1] += p[2];
994 p[3] += p[2];
995 }
996 }
997 return 0;
998 }
999
1001 {
1006
1009
1014
1016 if (!line)
1018
1024 i = 0;
1027 p[2] =
get_bits(&gb_g, pixel_bits);
1028 i++;
1031 i = 0;
1032 }
1033 }
1034 }
1036 }
1037
1041 i = p[2];
1045 }
1048 }
1049 }
1050
1051 return 0;
1052 }
1053
1055 int *got_frame,
uint8_t *data_start,
1056 unsigned int data_size, int is_alpha_chunk)
1057 {
1060
1061 if (!is_alpha_chunk) {
1064 }
1065
1067 if (ret < 0)
1069
1070 if (!is_alpha_chunk) {
1074 }
1075
1081 }
1086 }
1089 if (ret < 0)
1092
1094
1098 }
1099 } else {
1104 }
1105
1106 /* parse transformations */
1112 switch (transform) {
1115 break;
1118 break;
1121 break;
1122 }
1123 if (ret < 0)
1124 goto free_and_return;
1125 }
1126
1127 /* decode primary image */
1129 if (is_alpha_chunk)
1132 if (ret < 0) {
1134 goto free_and_return;
1135 }
1136
1137 /* apply transformations */
1142 break;
1145 break;
1148 break;
1151 break;
1152 }
1153 if (ret < 0) {
1155 goto free_and_return;
1156 }
1157 }
1158
1159 *got_frame = 1;
1162 ret = data_size;
1163
1164 free_and_return:
1167
1169 }
1170
1172 {
1175
1177
1178 /* filter first row using horizontal filter */
1179 dec = frame->
data[3] + 1;
1180 for (x = 1; x < frame->
width; x++, dec++)
1181 *dec += *(dec - 1);
1182
1183 /* filter first column using vertical filter */
1184 dec = frame->
data[3] + ls;
1185 for (y = 1; y < frame->
height; y++, dec += ls)
1186 *dec += *(dec - ls);
1187
1188 /* filter the rest using the specified filter */
1189 switch (m) {
1191 for (y = 1; y < frame->
height; y++) {
1192 dec = frame->
data[3] + y * ls + 1;
1193 for (x = 1; x < frame->
width; x++, dec++)
1194 *dec += *(dec - 1);
1195 }
1196 break;
1198 for (y = 1; y < frame->
height; y++) {
1199 dec = frame->
data[3] + y * ls + 1;
1200 for (x = 1; x < frame->
width; x++, dec++)
1201 *dec += *(dec - ls);
1202 }
1203 break;
1205 for (y = 1; y < frame->
height; y++) {
1206 dec = frame->
data[3] + y * ls + 1;
1207 for (x = 1; x < frame->
width; x++, dec++)
1208 dec[0] += av_clip_uint8(*(dec - 1) + *(dec - ls) - *(dec - ls - 1));
1209 }
1210 break;
1211 }
1212 }
1213
1216 unsigned int data_size)
1217 {
1220
1223
1225 for (y = 0; y < s->
height; y++)
1230 int alpha_got_frame = 0;
1231
1235
1237 data_start, data_size, 1);
1238 if (ret < 0) {
1241 }
1242 if (!alpha_got_frame) {
1245 }
1246
1247 /* copy green component of alpha image to alpha plane of primary image */
1248 for (y = 0; y < s->
height; y++) {
1251 for (x = 0; x < s->
width; x++) {
1252 *pp = *ap;
1253 pp++;
1254 ap += 4;
1255 }
1256 }
1258 }
1259
1260 /* apply alpha filtering */
1263
1264 return 0;
1265 }
1266
1268 int *got_frame,
uint8_t *data_start,
1269 unsigned int data_size)
1270 {
1274
1280 }
1282
1283 if (data_size > INT_MAX) {
1286 }
1287
1289 pkt.
data = data_start;
1290 pkt.
size = data_size;
1291
1296 if (ret < 0)
1298 }
1300 }
1301
1304 {
1309 uint32_t chunk_type, chunk_size;
1310 int vp8x_flags = 0;
1311
1315 *got_frame = 0;
1318
1321
1322 if (bytestream2_get_le32(&gb) !=
MKTAG(
'R',
'I',
'F',
'F')) {
1325 }
1326
1327 chunk_size = bytestream2_get_le32(&gb);
1330
1331 if (bytestream2_get_le32(&gb) !=
MKTAG(
'W',
'E',
'B',
'P')) {
1334 }
1335
1337 char chunk_str[5] = { 0 };
1338
1339 chunk_type = bytestream2_get_le32(&gb);
1340 chunk_size = bytestream2_get_le32(&gb);
1341 if (chunk_size == UINT32_MAX)
1343 chunk_size += chunk_size & 1;
1344
1347
1348 switch (chunk_type) {
1349 case MKTAG(
'V',
'P',
'8',
' '):
1350 if (!*got_frame) {
1353 chunk_size);
1354 if (ret < 0)
1356 }
1358 break;
1359 case MKTAG(
'V',
'P',
'8',
'L'):
1360 if (!*got_frame) {
1363 chunk_size, 0);
1364 if (ret < 0)
1366 }
1368 break;
1369 case MKTAG(
'V',
'P',
'8',
'X'):
1370 vp8x_flags = bytestream2_get_byte(&gb);
1372 s->
width = bytestream2_get_le24(&gb) + 1;
1373 s->
height = bytestream2_get_le24(&gb) + 1;
1375 if (ret < 0)
1377 break;
1378 case MKTAG(
'A',
'L',
'P',
'H'): {
1379 int alpha_header, filter_m, compression;
1380
1383 "ALPHA chunk present, but alpha bit not set in the "
1384 "VP8X header\n");
1385 }
1386 if (chunk_size == 0) {
1389 }
1390 alpha_header = bytestream2_get_byte(&gb);
1394
1395 filter_m = (alpha_header >> 2) & 0x03;
1396 compression = alpha_header & 0x03;
1397
1400 "skipping unsupported ALPHA chunk\n");
1401 } else {
1405 }
1406
1407 break;
1408 }
1409 case MKTAG(
'I',
'C',
'C',
'P'):
1410 case MKTAG(
'A',
'N',
'I',
'M'):
1411 case MKTAG(
'A',
'N',
'M',
'F'):
1412 case MKTAG(
'E',
'X',
'I',
'F'):
1413 case MKTAG(
'X',
'M',
'P',
' '):
1414 AV_WL32(chunk_str, chunk_type);
1416 chunk_str);
1418 break;
1419 default:
1420 AV_WL32(chunk_str, chunk_type);
1422 chunk_str);
1424 break;
1425 }
1426 }
1427
1428 if (!*got_frame) {
1431 }
1432
1434 }
1435
1437 {
1439
1442
1443 return 0;
1444 }
1445
1455 };