summaryrefslogtreecommitdiff
path: root/apps/plugins/png/png.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/png/png.c')
-rw-r--r--apps/plugins/png/png.c438
1 files changed, 230 insertions, 208 deletions
diff --git a/apps/plugins/png/png.c b/apps/plugins/png/png.c
index e24434fc72..9e3b780907 100644
--- a/apps/plugins/png/png.c
+++ b/apps/plugins/png/png.c
@@ -260,7 +260,7 @@ static unsigned LodePNG_decompress(unsigned char* out, size_t* outsize, const un
260 z_stream stream; 260 z_stream stream;
261 int err; 261 int err;
262 262
263 error_msg = ""; 263 rb->strcpy(error_msg, "");
264 264
265 stream.next_in = (Bytef*)in; 265 stream.next_in = (Bytef*)in;
266 stream.avail_in = (uInt)insize; 266 stream.avail_in = (uInt)insize;
@@ -284,7 +284,8 @@ static unsigned LodePNG_decompress(unsigned char* out, size_t* outsize, const un
284 *outsize = stream.total_out; 284 *outsize = stream.total_out;
285 285
286 err = inflateEnd(&stream); 286 err = inflateEnd(&stream);
287 error_msg = stream.msg; 287 if (stream.msg != Z_NULL)
288 rb->strcpy(error_msg, stream.msg);
288 return err; 289 return err;
289 290
290} 291}
@@ -1324,6 +1325,60 @@ void LodePNG_Decoder_cleanup(LodePNG_Decoder* decoder)
1324 LodePNG_InfoPng_cleanup(&decoder->infoPng); 1325 LodePNG_InfoPng_cleanup(&decoder->infoPng);
1325} 1326}
1326 1327
1328#define PNG_ERROR_MIN 27
1329#define PNG_ERROR_MAX 74
1330static const unsigned char *png_error_messages[PNG_ERROR_MAX-PNG_ERROR_MIN+1] =
1331{
1332 "png file smaller than a png header", /*27*/
1333 "incorrect png signature", /*28*/
1334 "first chunk is not IHDR", /*29*/
1335 "chunk length too large", /*30*/
1336 "illegal PNG color type or bpp", /*31*/
1337 "illegal PNG compression method", /*32*/
1338 "illegal PNG filter method", /*33*/
1339 "illegal PNG interlace method", /*34*/
1340 "chunk length of a chunk is too large or the chunk too small", /*35*/
1341 "illegal PNG filter type encountered", /*36*/
1342 "illegal bit depth for this color type given", /*37*/
1343 "the palette is too big (more than 256 colors)", /*38*/
1344 "more palette alpha values given in tRNS, than there are colors in the palette", /*39*/
1345 "tRNS chunk has wrong size for greyscale image", /*40*/
1346 "tRNS chunk has wrong size for RGB image", /*41*/
1347 "tRNS chunk appeared while it was not allowed for this color type", /*42*/
1348 "bKGD chunk has wrong size for palette image", /*43*/
1349 "bKGD chunk has wrong size for greyscale image", /*44*/
1350 "bKGD chunk has wrong size for RGB image", /*45*/
1351 "value encountered in indexed image is larger than the palette size", /*46*/
1352 "value encountered in indexed image is larger than the palette size", /*47*/
1353 "input file is empty", /*48*/
1354 NULL, /*49*/
1355 NULL, /*50*/
1356 NULL, /*51*/
1357 NULL, /*52*/
1358 NULL, /*53*/
1359 NULL, /*54*/
1360 NULL, /*55*/
1361 NULL, /*56*/
1362 "invalid CRC", /*57*/
1363 NULL, /*58*/
1364 "conversion to unexisting or unsupported color type or bit depth", /*59*/
1365 NULL, /*60*/
1366 NULL, /*61*/
1367 NULL, /*62*/
1368 "png chunk too long", /*63*/
1369 NULL, /*64*/
1370 NULL, /*65*/
1371 NULL, /*66*/
1372 NULL, /*67*/
1373 NULL, /*68*/
1374 "unknown critical chunk", /*69*/
1375 NULL, /*70*/
1376 NULL, /*71*/
1377 NULL, /*72*/
1378 "invalid tIME chunk size", /*73*/
1379 "invalid pHYs chunk size", /*74*/
1380};
1381
1327bool png_ext(const char ext[]) 1382bool png_ext(const char ext[])
1328{ 1383{
1329 if (!ext) 1384 if (!ext)
@@ -1454,9 +1509,9 @@ int show_menu(void) /* return 1 to quit */
1454 "Quit"); 1509 "Quit");
1455 1510
1456 static const struct opt_items slideshow[2] = { 1511 static const struct opt_items slideshow[2] = {
1457 { "Disable", -1 }, 1512 { "Disable", -1 },
1458 { "Enable", -1 }, 1513 { "Enable", -1 },
1459 }; 1514 };
1460 1515
1461 result=rb->do_menu(&menu, NULL, NULL, false); 1516 result=rb->do_menu(&menu, NULL, NULL, false);
1462 1517
@@ -1598,7 +1653,8 @@ int scroll_bmp(struct LodePNG_Decoder* decoder)
1598 { 1653 {
1599 if (slideshow_enabled) 1654 if (slideshow_enabled)
1600 button = rb->button_get_w_tmo(png_settings.ss_timeout * HZ); 1655 button = rb->button_get_w_tmo(png_settings.ss_timeout * HZ);
1601 else button = rb->button_get(true); 1656 else
1657 button = rb->button_get(true);
1602 1658
1603 running_slideshow = false; 1659 running_slideshow = false;
1604 1660
@@ -1681,10 +1737,12 @@ int scroll_bmp(struct LodePNG_Decoder* decoder)
1681 case PNG_RC_MENU: 1737 case PNG_RC_MENU:
1682#endif 1738#endif
1683 case PNG_MENU: 1739 case PNG_MENU:
1740
1684 if (show_menu() == 1) 1741 if (show_menu() == 1)
1685 return PLUGIN_OK; 1742 return PLUGIN_OK;
1686 else 1743
1687 return PLUGIN_REFRESH; 1744 draw_image(decoder);
1745 rb->lcd_update();
1688 1746
1689 break; 1747 break;
1690 default: 1748 default:
@@ -1755,6 +1813,140 @@ unsigned max_downscale(struct LodePNG_Decoder* decoder)
1755 return downscale; 1813 return downscale;
1756} 1814}
1757 1815
1816/* load image from filename. */
1817int load_image(char* filename, struct LodePNG_Decoder* decoder)
1818{
1819 int fd;
1820 long time = 0; /* measured ticks */
1821 int w, h; /* used to center output */
1822
1823 fd = rb->open(filename, O_RDONLY);
1824 if (fd < 0)
1825 {
1826 rb->snprintf(print,sizeof(print),"err opening %s:%d",filename,fd);
1827 rb->splash(HZ, print);
1828 return PLUGIN_ERROR;
1829 }
1830 image_size = rb->filesize(fd);
1831
1832 DEBUGF("reading file '%s'\n", filename);
1833
1834 if (!running_slideshow) {
1835 rb->snprintf(print, sizeof(print), "%s:", rb->strrchr(filename,'/')+1);
1836 rb->lcd_puts(0, 0, print);
1837 rb->lcd_update();
1838 }
1839
1840 if (image_size > memory_size) {
1841 decoder->error = FILE_TOO_LARGE;
1842 rb->close(fd);
1843#ifndef SIMULATOR
1844 if (running_slideshow && immediate_ata_off) {
1845 /* running slideshow and time is long enough: power down disk */
1846 rb->storage_sleep();
1847 }
1848#endif
1849
1850 } else {
1851 if (!running_slideshow) {
1852 rb->snprintf(print, sizeof(print), "loading %lu bytes", image_size);
1853 rb->lcd_puts(0, 1, print);
1854 rb->lcd_update();
1855 }
1856
1857 image = memory_max - image_size + 1;
1858 rb->read(fd, image, image_size);
1859 rb->close(fd);
1860
1861 if (!running_slideshow) {
1862 rb->snprintf(print, sizeof(print), "decoding image");
1863 rb->lcd_puts(0, 2, print);
1864 rb->lcd_update();
1865 }
1866#ifndef SIMULATOR
1867 else if (immediate_ata_off) {
1868 /* running slideshow and time is long enough: power down disk */
1869 rb->storage_sleep();
1870 }
1871#endif
1872
1873 decoder->settings.color_convert = 1;
1874 decoder->infoRaw.color.colorType = 2;
1875 decoder->infoRaw.color.bitDepth = 8;
1876
1877 LodePNG_inspect(decoder, image, image_size);
1878
1879 if (!decoder->error) {
1880
1881 if (!running_slideshow) {
1882 rb->snprintf(print, sizeof(print), "image %dx%d",
1883 decoder->infoPng.width, decoder->infoPng.height);
1884 rb->lcd_puts(0, 2, print);
1885 rb->lcd_update();
1886
1887 rb->snprintf(print, sizeof(print), "decoding %d*%d",
1888 decoder->infoPng.width, decoder->infoPng.height);
1889 rb->lcd_puts(0, 3, print);
1890 rb->lcd_update();
1891 }
1892
1893 /* the actual decoding */
1894 time = *rb->current_tick;
1895#ifdef HAVE_ADJUSTABLE_CPU_FREQ
1896 rb->cpu_boost(true);
1897 LodePNG_decode(decoder, image, image_size, cb_progress);
1898 rb->cpu_boost(false);
1899#else
1900 LodePNG_decode(decoder, image, image_size, cb_progress);
1901#endif /*HAVE_ADJUSTABLE_CPU_FREQ*/
1902 }
1903 }
1904
1905 time = *rb->current_tick - time;
1906
1907 if (!running_slideshow && !decoder->error)
1908 {
1909 rb->snprintf(print, sizeof(print), " %ld.%02ld sec ", time/HZ, time%HZ);
1910 rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */
1911 rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print);
1912 rb->lcd_update();
1913 }
1914
1915 if (decoder->error) {
1916 if (decoder->error == FILE_TOO_LARGE || decoder->error == OUT_OF_MEMORY
1917 || decoder->error == Z_MEM_ERROR)
1918 return PLUGIN_OUTOFMEM;
1919
1920 if (decoder->error >= PNG_ERROR_MIN && decoder->error <= PNG_ERROR_MAX
1921 && png_error_messages[decoder->error-PNG_ERROR_MIN] != NULL)
1922 {
1923 rb->splash(HZ, png_error_messages[decoder->error-PNG_ERROR_MIN]);
1924 }
1925 else
1926 {
1927 switch (decoder->error) {
1928 case PLUGIN_ABORT:
1929 break;
1930 case OUT_OF_MEMORY:
1931 case Z_MEM_ERROR:
1932 rb->splash(HZ, "Out of Memory");break;
1933 case FILE_TOO_LARGE:
1934 rb->splash(HZ, "File too large");break;
1935 case Z_DATA_ERROR:
1936 rb->splash(HZ, decoder->error_msg);break;
1937 default:
1938 rb->splashf(HZ, "other error : %ld", decoder->error);break;
1939 }
1940 }
1941
1942 if (decoder->error == PLUGIN_ABORT)
1943 return PLUGIN_ABORT;
1944 else
1945 return PLUGIN_ERROR;
1946 }
1947 return PLUGIN_OK;
1948}
1949
1758/* return decoded or cached image */ 1950/* return decoded or cached image */
1759fb_data *get_image(struct LodePNG_Decoder* decoder, int ds) 1951fb_data *get_image(struct LodePNG_Decoder* decoder, int ds)
1760{ 1952{
@@ -1778,7 +1970,7 @@ fb_data *get_image(struct LodePNG_Decoder* decoder, int ds)
1778 rb->lcd_puts(0, 3, print); 1970 rb->lcd_puts(0, 3, print);
1779 rb->lcd_update(); 1971 rb->lcd_update();
1780 } 1972 }
1781 static struct bitmap bmp_src, bmp_dst; 1973 struct bitmap bmp_src, bmp_dst;
1782 1974
1783 int size = decoder->width * decoder->height; 1975 int size = decoder->width * decoder->height;
1784 1976
@@ -1792,6 +1984,7 @@ fb_data *get_image(struct LodePNG_Decoder* decoder, int ds)
1792 } 1984 }
1793 1985
1794 disp[ds] = disp_buf; 1986 disp[ds] = disp_buf;
1987 disp_buf = (fb_data *)((intptr_t)(disp[ds] + size + 3) & ~3);
1795 1988
1796 bmp_src.width = decoder->infoPng.width; 1989 bmp_src.width = decoder->infoPng.width;
1797 bmp_src.height = decoder->infoPng.height; 1990 bmp_src.height = decoder->infoPng.height;
@@ -1807,8 +2000,6 @@ fb_data *get_image(struct LodePNG_Decoder* decoder, int ds)
1807#else 2000#else
1808 smooth_resize_bitmap(&bmp_src, &bmp_dst); 2001 smooth_resize_bitmap(&bmp_src, &bmp_dst);
1809#endif /*HAVE_ADJUSTABLE_CPU_FREQ*/ 2002#endif /*HAVE_ADJUSTABLE_CPU_FREQ*/
1810
1811 disp_buf = (fb_data *)((intptr_t)(disp[ds] + size + 3) & ~3);
1812 } else { 2003 } else {
1813 disp[ds] = converted_image; 2004 disp[ds] = converted_image;
1814 return converted_image; 2005 return converted_image;
@@ -1848,132 +2039,28 @@ void get_view(struct LodePNG_Decoder* decoder, int* p_cx, int* p_cy)
1848/* load, decode, display the image */ 2039/* load, decode, display the image */
1849int load_and_show(char* filename) 2040int load_and_show(char* filename)
1850{ 2041{
1851 int fd;
1852 int status; 2042 int status;
1853 long time=0; /* measured ticks */
1854 int cx=0, cy=0; /* view center */ 2043 int cx=0, cy=0; /* view center */
1855 int w, h; /* used to center output */
1856
1857 LodePNG_Decoder_init(&decoder);
1858 2044
1859 rb->lcd_clear_display();
1860
1861 fd = rb->open(filename, O_RDONLY);
1862 if (fd < 0)
1863 {
1864 rb->snprintf(print,sizeof(print),"err opening %s:%d",filename,fd);
1865 rb->splash(HZ, print);
1866 return PLUGIN_ERROR;
1867 }
1868 image_size = rb->filesize(fd);
1869 memset(&disp, 0, sizeof(disp));
1870
1871 DEBUGF("reading file '%s'\n", filename);
1872
1873 if (!running_slideshow) {
1874#if LCD_DEPTH > 1 2045#if LCD_DEPTH > 1
1875 rb->lcd_set_foreground(LCD_WHITE); 2046 rb->lcd_set_foreground(LCD_WHITE);
1876 rb->lcd_set_background(LCD_BLACK); 2047 rb->lcd_set_background(LCD_BLACK);
1877 rb->lcd_set_backdrop(NULL); 2048 rb->lcd_set_backdrop(NULL);
1878#endif
1879
1880 rb->lcd_clear_display();
1881 rb->snprintf(print, sizeof(print), "%s:", rb->strrchr(filename,'/')+1);
1882 rb->lcd_puts(0, 0, print);
1883 rb->lcd_update();
1884 }
1885
1886 if (rb->button_get(false) == PNG_MENU) {
1887 decoder.error = PLUGIN_ABORT;
1888 rb->close(fd);
1889
1890 } else if (image_size > memory_size) {
1891 decoder.error = FILE_TOO_LARGE;
1892 rb->close(fd);
1893
1894 } else {
1895 if (!running_slideshow) {
1896 rb->snprintf(print, sizeof(print), "loading %lu bytes", image_size);
1897 rb->lcd_puts(0, 1, print);
1898 rb->lcd_update();
1899 }
1900
1901 image = memory_max - image_size + 1;
1902 rb->read(fd, image, image_size);
1903 rb->close(fd);
1904
1905 if (!running_slideshow) {
1906 rb->snprintf(print, sizeof(print), "decoding image");
1907 rb->lcd_puts(0, 2, print);
1908 rb->lcd_update();
1909 }
1910#ifndef SIMULATOR
1911 else if (immediate_ata_off) {
1912 /* running slideshow and time is long enough: power down disk */
1913 rb->storage_sleep();
1914 }
1915#endif 2049#endif
2050 rb->lcd_clear_display();
1916 2051
1917 decoder.settings.color_convert = 1; 2052 memset(&disp, 0, sizeof(disp));
1918 decoder.infoRaw.color.colorType = 2; 2053 LodePNG_Decoder_init(&decoder);
1919 decoder.infoRaw.color.bitDepth = 8;
1920
1921 if (rb->button_get(false) == PNG_MENU) {
1922 decoder.error = PLUGIN_ABORT;
1923 } else {
1924 LodePNG_inspect(&decoder, image, image_size);
1925 }
1926
1927 if (!decoder.error) {
1928
1929 if (!running_slideshow) {
1930 rb->snprintf(print, sizeof(print), "image %dx%d",
1931 decoder.infoPng.width, decoder.infoPng.height);
1932 rb->lcd_puts(0, 2, print);
1933 rb->lcd_update();
1934 }
1935
1936 if (!running_slideshow)
1937 {
1938 rb->snprintf(print, sizeof(print), "decoding %d*%d",
1939 decoder.infoPng.width, decoder.infoPng.height);
1940 rb->lcd_puts(0, 3, print);
1941 rb->lcd_update();
1942 }
1943
1944 /* the actual decoding */
1945 time = *rb->current_tick;
1946#ifdef HAVE_ADJUSTABLE_CPU_FREQ
1947 rb->cpu_boost(true);
1948 LodePNG_decode(&decoder, image, image_size, cb_progress);
1949 rb->cpu_boost(false);
1950#else
1951 LodePNG_decode(&decoder, image, image_size, cb_progress);
1952#endif /*HAVE_ADJUSTABLE_CPU_FREQ*/
1953 }
1954 }
1955
1956 if (decoder.error == PLUGIN_ABORT || decoder.error == FILE_TOO_LARGE) {
1957#ifndef SIMULATOR
1958 if (immediate_ata_off) {
1959 /* running slideshow and time is long enough: power down disk */
1960 rb->storage_sleep();
1961 }
1962#endif
1963 }
1964 2054
1965 time = *rb->current_tick - time; 2055 if (rb->button_get(false) == PNG_MENU)
2056 status = PLUGIN_ABORT;
2057 else
2058 status = load_image(filename, &decoder);
1966 2059
1967 if (!running_slideshow && !decoder.error) 2060 if (status == PLUGIN_OUTOFMEM)
1968 { 2061 {
1969 rb->snprintf(print, sizeof(print), " %ld.%02ld sec ", time/HZ, time%HZ);
1970 rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */
1971 rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print);
1972 rb->lcd_update();
1973 }
1974
1975#if PLUGIN_BUFFER_SIZE >= MIN_MEM 2062#if PLUGIN_BUFFER_SIZE >= MIN_MEM
1976 if (plug_buf && (decoder.error == FILE_TOO_LARGE || decoder.error == OUT_OF_MEMORY || decoder.error == Z_MEM_ERROR)) 2063 if (plug_buf)
1977 { 2064 {
1978 rb->lcd_setfont(FONT_SYSFIXED); 2065 rb->lcd_setfont(FONT_SYSFIXED);
1979 rb->lcd_clear_display(); 2066 rb->lcd_clear_display();
@@ -2029,87 +2116,23 @@ int load_and_show(char* filename)
2029 } 2116 }
2030 } 2117 }
2031 } 2118 }
2032 //else 2119 else
2033#endif 2120#endif
2034 2121 {
2035 if (decoder.error) { 2122 rb->splash(HZ, "Out of Memory");
2036 2123 file_pt[curfile] = NULL;
2037 switch (decoder.error) { 2124 return change_filename(direction);
2038 case PLUGIN_ABORT:
2039 rb->splash(HZ, "aborted");break;
2040 case 27:
2041 rb->splash(HZ, "png file smaller than a png header");break;
2042 case 28:
2043 rb->splash(HZ, "incorrect png signature");break;
2044 case 29:
2045 rb->splash(HZ, "first chunk is not IHDR");break;
2046 case 30:
2047 rb->splash(HZ, "chunk length too large");break;
2048 case 31:
2049 rb->splash(HZ, "illegal PNG color type or bpp");break;
2050 case 32:
2051 rb->splash(HZ, "illegal PNG compression method");break;
2052 case 33:
2053 rb->splash(HZ, "illegal PNG filter method");break;
2054 case 34:
2055 rb->splash(HZ, "illegal PNG interlace method");break;
2056 case 35:
2057 rb->splash(HZ, "chunk length of a chunk is too large or the chunk too small");break;
2058 case 36:
2059 rb->splash(HZ, "illegal PNG filter type encountered");break;
2060 case 37:
2061 rb->splash(HZ, "illegal bit depth for this color type given");break;
2062 case 38:
2063 rb->splash(HZ, "the palette is too big (more than 256 colors)");break;
2064 case 39:
2065 rb->splash(HZ, "more palette alpha values given in tRNS, than there are colors in the palette");break;
2066 case 40:
2067 rb->splash(HZ, "tRNS chunk has wrong size for greyscale image");break;
2068 case 41:
2069 rb->splash(HZ, "tRNS chunk has wrong size for RGB image");break;
2070 case 42:
2071 rb->splash(HZ, "tRNS chunk appeared while it was not allowed for this color type");break;
2072 case 43:
2073 rb->splash(HZ, "bKGD chunk has wrong size for palette image");break;
2074 case 44:
2075 rb->splash(HZ, "bKGD chunk has wrong size for greyscale image");break;
2076 case 45:
2077 rb->splash(HZ, "bKGD chunk has wrong size for RGB image");break;
2078 case 46:
2079 case 47:
2080 rb->splash(HZ, "value encountered in indexed image is larger than the palette size");break;
2081 case 48:
2082 rb->splash(HZ, "input file is empty");break;
2083 case OUT_OF_MEMORY:
2084 case Z_MEM_ERROR:
2085 rb->splash(HZ, "Out of Memory");break;
2086 case 57:
2087 rb->splash(HZ, "invalid CRC");break;
2088 case 59:
2089 rb->splash(HZ, "conversion to unexisting or unsupported color type or bit depth");break;
2090 case 63:
2091 rb->splash(HZ, "png chunk too long");break;
2092 case 69:
2093 rb->splash(HZ, "unknown critical chunk");break;
2094 case 73:
2095 rb->splash(HZ, "invalid tIME chunk size");break;
2096 case 74:
2097 rb->splash(HZ, "invalid pHYs chunk size");break;
2098 case FILE_TOO_LARGE:
2099 rb->splash(HZ, "File too large");break;
2100 case Z_DATA_ERROR:
2101 rb->splash(HZ, decoder.error_msg);break;
2102 default:
2103 rb->splashf(HZ, "other error : %ld", decoder.error);break;
2104 }
2105
2106 if (decoder.error == PLUGIN_ABORT) {
2107 return PLUGIN_OK;
2108 } else {
2109 file_pt[curfile] = NULL;
2110 return change_filename(direction);
2111 }
2112 } 2125 }
2126 }
2127 else if (status == PLUGIN_ERROR)
2128 {
2129 file_pt[curfile] = NULL;
2130 return change_filename(direction);
2131 }
2132 else if (status == PLUGIN_ABORT) {
2133 rb->splash(HZ, "aborted");
2134 return PLUGIN_OK;
2135 }
2113 2136
2114 disp_buf = (fb_data *)((intptr_t)(converted_image + converted_image_size + 3) & ~3); 2137 disp_buf = (fb_data *)((intptr_t)(converted_image + converted_image_size + 3) & ~3);
2115 ds_max = max_downscale(&decoder); /* check display constraint */ 2138 ds_max = max_downscale(&decoder); /* check display constraint */
@@ -2231,7 +2254,7 @@ enum plugin_status plugin_start(const void* parameter)
2231 do 2254 do
2232 { 2255 {
2233 condition = load_and_show(np_file); 2256 condition = load_and_show(np_file);
2234 }while (condition != PLUGIN_OK && condition != PLUGIN_USB_CONNECTED 2257 } while (condition != PLUGIN_OK && condition != PLUGIN_USB_CONNECTED
2235 && condition != PLUGIN_ERROR); 2258 && condition != PLUGIN_ERROR);
2236 2259
2237 if (rb->memcmp(&png_settings, &old_settings, sizeof (png_settings))) 2260 if (rb->memcmp(&png_settings, &old_settings, sizeof (png_settings)))
@@ -2252,4 +2275,3 @@ enum plugin_status plugin_start(const void* parameter)
2252 2275
2253 return condition; 2276 return condition;
2254} 2277}
2255