Return to mbfl_convert.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / mbstring / libmbfl / mbfl |
1.1 misho 1: /* 2: * "streamable kanji code filter and converter" 3: * Copyright (c) 1998-2002 HappySize, Inc. All rights reserved. 4: * 5: * LICENSE NOTICES 6: * 7: * This file is part of "streamable kanji code filter and converter", 8: * which is distributed under the terms of GNU Lesser General Public 9: * License (version 2) as published by the Free Software Foundation. 10: * 11: * This software is distributed in the hope that it will be useful, 12: * but WITHOUT ANY WARRANTY; without even the implied warranty of 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14: * GNU Lesser General Public License for more details. 15: * 16: * You should have received a copy of the GNU Lesser General Public 17: * License along with "streamable kanji code filter and converter"; 18: * if not, write to the Free Software Foundation, Inc., 59 Temple Place, 19: * Suite 330, Boston, MA 02111-1307 USA 20: * 21: * The author of this file: 22: * 23: */ 24: /* 25: * The source code included in this files was separated from mbfilter.c 26: * by Moriyoshi Koizumi <moriyoshi@php.net> on 20 Dec 2002. The file 27: * mbfilter.c is included in this package . 28: * 29: */ 30: 31: #ifdef HAVE_CONFIG_H 32: #include "config.h" 33: #endif 34: 35: #ifdef HAVE_STDDEF_H 36: #include <stddef.h> 37: #endif 38: 39: #include "mbfl_encoding.h" 40: #include "mbfl_allocators.h" 41: #include "mbfl_filter_output.h" 42: #include "mbfilter_pass.h" 43: #include "mbfilter_8bit.h" 44: #include "mbfilter_wchar.h" 45: 46: #include "filters/mbfilter_euc_cn.h" 47: #include "filters/mbfilter_hz.h" 48: #include "filters/mbfilter_euc_tw.h" 49: #include "filters/mbfilter_big5.h" 50: #include "filters/mbfilter_uhc.h" 51: #include "filters/mbfilter_euc_kr.h" 52: #include "filters/mbfilter_iso2022_kr.h" 53: #include "filters/mbfilter_sjis.h" 54: #include "filters/mbfilter_sjis_open.h" 1.1.1.2 ! misho 55: #include "filters/mbfilter_sjis_2004.h" ! 56: #include "filters/mbfilter_sjis_mobile.h" ! 57: #include "filters/mbfilter_sjis_mac.h" 1.1 misho 58: #include "filters/mbfilter_cp51932.h" 59: #include "filters/mbfilter_jis.h" 60: #include "filters/mbfilter_iso2022_jp_ms.h" 1.1.1.2 ! misho 61: #include "filters/mbfilter_iso2022jp_2004.h" ! 62: #include "filters/mbfilter_iso2022jp_mobile.h" 1.1 misho 63: #include "filters/mbfilter_euc_jp.h" 1.1.1.2 ! misho 64: #include "filters/mbfilter_euc_jp_2004.h" 1.1 misho 65: #include "filters/mbfilter_euc_jp_win.h" 1.1.1.2 ! misho 66: #include "filters/mbfilter_gb18030.h" 1.1 misho 67: #include "filters/mbfilter_ascii.h" 68: #include "filters/mbfilter_koi8r.h" 69: #include "filters/mbfilter_koi8u.h" 70: #include "filters/mbfilter_cp866.h" 71: #include "filters/mbfilter_cp932.h" 72: #include "filters/mbfilter_cp936.h" 73: #include "filters/mbfilter_cp1251.h" 74: #include "filters/mbfilter_cp1252.h" 75: #include "filters/mbfilter_cp1254.h" 76: #include "filters/mbfilter_cp5022x.h" 77: #include "filters/mbfilter_iso8859_1.h" 78: #include "filters/mbfilter_iso8859_2.h" 79: #include "filters/mbfilter_iso8859_3.h" 80: #include "filters/mbfilter_iso8859_4.h" 81: #include "filters/mbfilter_iso8859_5.h" 82: #include "filters/mbfilter_iso8859_6.h" 83: #include "filters/mbfilter_iso8859_7.h" 84: #include "filters/mbfilter_iso8859_8.h" 85: #include "filters/mbfilter_iso8859_9.h" 86: #include "filters/mbfilter_iso8859_10.h" 87: #include "filters/mbfilter_iso8859_13.h" 88: #include "filters/mbfilter_iso8859_14.h" 89: #include "filters/mbfilter_iso8859_15.h" 90: #include "filters/mbfilter_base64.h" 91: #include "filters/mbfilter_qprint.h" 92: #include "filters/mbfilter_uuencode.h" 93: #include "filters/mbfilter_7bit.h" 94: #include "filters/mbfilter_utf7.h" 95: #include "filters/mbfilter_utf7imap.h" 96: #include "filters/mbfilter_utf8.h" 1.1.1.2 ! misho 97: #include "filters/mbfilter_utf8_mobile.h" 1.1 misho 98: #include "filters/mbfilter_utf16.h" 99: #include "filters/mbfilter_utf32.h" 100: #include "filters/mbfilter_byte2.h" 101: #include "filters/mbfilter_byte4.h" 102: #include "filters/mbfilter_ucs4.h" 103: #include "filters/mbfilter_ucs2.h" 104: #include "filters/mbfilter_htmlent.h" 105: #include "filters/mbfilter_armscii8.h" 106: #include "filters/mbfilter_cp850.h" 107: 108: /* hex character table "0123456789ABCDEF" */ 109: static char mbfl_hexchar_table[] = { 110: 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46 111: }; 112: 113: const struct mbfl_convert_vtbl *mbfl_convert_filter_list[] = { 114: &vtbl_utf8_wchar, 115: &vtbl_wchar_utf8, 116: &vtbl_eucjp_wchar, 117: &vtbl_wchar_eucjp, 118: &vtbl_sjis_wchar, 119: &vtbl_wchar_sjis, 120: &vtbl_sjis_open_wchar, 121: &vtbl_wchar_sjis_open, 1.1.1.2 ! misho 122: &vtbl_sjis2004_wchar, ! 123: &vtbl_wchar_sjis2004, 1.1 misho 124: &vtbl_cp51932_wchar, 125: &vtbl_wchar_cp51932, 126: &vtbl_jis_wchar, 127: &vtbl_wchar_jis, 128: &vtbl_jis_ms_wchar, 129: &vtbl_wchar_jis_ms, 130: &vtbl_2022jp_wchar, 131: &vtbl_wchar_2022jp, 132: &vtbl_2022jpms_wchar, 133: &vtbl_wchar_2022jpms, 1.1.1.2 ! misho 134: &vtbl_2022jp_2004_wchar, ! 135: &vtbl_wchar_2022jp_2004, ! 136: &vtbl_2022jp_kddi_wchar, ! 137: &vtbl_wchar_2022jp_kddi, 1.1 misho 138: &vtbl_eucjpwin_wchar, 139: &vtbl_wchar_eucjpwin, 1.1.1.2 ! misho 140: &vtbl_eucjp2004_wchar, ! 141: &vtbl_wchar_eucjp2004, 1.1 misho 142: &vtbl_cp932_wchar, 143: &vtbl_wchar_cp932, 1.1.1.2 ! misho 144: &vtbl_sjis_docomo_wchar, ! 145: &vtbl_wchar_sjis_docomo, ! 146: &vtbl_sjis_kddi_wchar, ! 147: &vtbl_wchar_sjis_kddi, ! 148: &vtbl_sjis_sb_wchar, ! 149: &vtbl_wchar_sjis_sb, ! 150: &vtbl_sjis_mac_wchar, ! 151: &vtbl_wchar_sjis_mac, ! 152: &vtbl_utf8_docomo_wchar, ! 153: &vtbl_wchar_utf8_docomo, ! 154: &vtbl_utf8_kddi_a_wchar, ! 155: &vtbl_wchar_utf8_kddi_a, ! 156: &vtbl_utf8_kddi_b_wchar, ! 157: &vtbl_wchar_utf8_kddi_b, ! 158: &vtbl_utf8_sb_wchar, ! 159: &vtbl_wchar_utf8_sb, 1.1 misho 160: &vtbl_euccn_wchar, 161: &vtbl_wchar_euccn, 162: &vtbl_cp936_wchar, 163: &vtbl_wchar_cp936, 1.1.1.2 ! misho 164: &vtbl_gb18030_wchar, ! 165: &vtbl_wchar_gb18030, 1.1 misho 166: &vtbl_hz_wchar, 167: &vtbl_wchar_hz, 168: &vtbl_euctw_wchar, 169: &vtbl_wchar_euctw, 170: &vtbl_big5_wchar, 171: &vtbl_wchar_big5, 1.1.1.2 ! misho 172: &vtbl_cp950_wchar, ! 173: &vtbl_wchar_cp950, 1.1 misho 174: &vtbl_euckr_wchar, 175: &vtbl_wchar_euckr, 176: &vtbl_uhc_wchar, 177: &vtbl_wchar_uhc, 178: &vtbl_2022kr_wchar, 179: &vtbl_wchar_2022kr, 180: &vtbl_cp1251_wchar, 181: &vtbl_wchar_cp1251, 182: &vtbl_cp866_wchar, 183: &vtbl_wchar_cp866, 184: &vtbl_koi8r_wchar, 185: &vtbl_wchar_koi8r, 186: &vtbl_koi8u_wchar, 187: &vtbl_wchar_koi8u, 188: &vtbl_cp1252_wchar, 189: &vtbl_wchar_cp1252, 190: &vtbl_cp1254_wchar, 191: &vtbl_wchar_cp1254, 192: &vtbl_cp50220_wchar, 193: &vtbl_wchar_cp50220, 194: &vtbl_cp50220raw_wchar, 195: &vtbl_wchar_cp50220raw, 196: &vtbl_cp50221_wchar, 197: &vtbl_wchar_cp50221, 198: &vtbl_cp50222_wchar, 199: &vtbl_wchar_cp50222, 200: &vtbl_ascii_wchar, 201: &vtbl_wchar_ascii, 202: &vtbl_8859_1_wchar, 203: &vtbl_wchar_8859_1, 204: &vtbl_8859_2_wchar, 205: &vtbl_wchar_8859_2, 206: &vtbl_8859_3_wchar, 207: &vtbl_wchar_8859_3, 208: &vtbl_8859_4_wchar, 209: &vtbl_wchar_8859_4, 210: &vtbl_8859_5_wchar, 211: &vtbl_wchar_8859_5, 212: &vtbl_8859_6_wchar, 213: &vtbl_wchar_8859_6, 214: &vtbl_8859_7_wchar, 215: &vtbl_wchar_8859_7, 216: &vtbl_8859_8_wchar, 217: &vtbl_wchar_8859_8, 218: &vtbl_8859_9_wchar, 219: &vtbl_wchar_8859_9, 220: &vtbl_8859_10_wchar, 221: &vtbl_wchar_8859_10, 222: &vtbl_8859_13_wchar, 223: &vtbl_wchar_8859_13, 224: &vtbl_8859_14_wchar, 225: &vtbl_wchar_8859_14, 226: &vtbl_8859_15_wchar, 227: &vtbl_wchar_8859_15, 228: &vtbl_8bit_b64, 229: &vtbl_b64_8bit, 230: &vtbl_uuencode_8bit, 231: &vtbl_wchar_html, 232: &vtbl_html_wchar, 233: &vtbl_8bit_qprint, 234: &vtbl_qprint_8bit, 235: &vtbl_8bit_7bit, 236: &vtbl_7bit_8bit, 237: &vtbl_utf7_wchar, 238: &vtbl_wchar_utf7, 239: &vtbl_utf7imap_wchar, 240: &vtbl_wchar_utf7imap, 241: &vtbl_utf16_wchar, 242: &vtbl_wchar_utf16, 243: &vtbl_utf16be_wchar, 244: &vtbl_wchar_utf16be, 245: &vtbl_utf16le_wchar, 246: &vtbl_wchar_utf16le, 247: &vtbl_utf32_wchar, 248: &vtbl_wchar_utf32, 249: &vtbl_utf32be_wchar, 250: &vtbl_wchar_utf32be, 251: &vtbl_utf32le_wchar, 252: &vtbl_wchar_utf32le, 253: &vtbl_ucs4_wchar, 254: &vtbl_wchar_ucs4, 255: &vtbl_ucs4be_wchar, 256: &vtbl_wchar_ucs4be, 257: &vtbl_ucs4le_wchar, 258: &vtbl_wchar_ucs4le, 259: &vtbl_ucs2_wchar, 260: &vtbl_wchar_ucs2, 261: &vtbl_ucs2be_wchar, 262: &vtbl_wchar_ucs2be, 263: &vtbl_ucs2le_wchar, 264: &vtbl_wchar_ucs2le, 265: &vtbl_byte4be_wchar, 266: &vtbl_wchar_byte4be, 267: &vtbl_byte4le_wchar, 268: &vtbl_wchar_byte4le, 269: &vtbl_byte2be_wchar, 270: &vtbl_wchar_byte2be, 271: &vtbl_byte2le_wchar, 272: &vtbl_wchar_byte2le, 273: &vtbl_armscii8_wchar, 274: &vtbl_wchar_armscii8, 275: &vtbl_cp850_wchar, 276: &vtbl_wchar_cp850, 277: &vtbl_pass, 278: NULL 279: }; 280: 281: static int 282: mbfl_convert_filter_common_init( 283: mbfl_convert_filter *filter, 284: enum mbfl_no_encoding from, 285: enum mbfl_no_encoding to, 286: const struct mbfl_convert_vtbl *vtbl, 287: int (*output_function)(int, void* ), 288: int (*flush_function)(void*), 289: void* data) 290: { 291: /* encoding structure */ 292: if ((filter->from = mbfl_no2encoding(from)) == NULL) { 293: return 1; 294: } 295: 296: if ((filter->to = mbfl_no2encoding(to)) == NULL) { 297: return 1; 298: } 299: 300: if (output_function != NULL) { 301: filter->output_function = output_function; 302: } else { 303: filter->output_function = mbfl_filter_output_null; 304: } 305: 306: filter->flush_function = flush_function; 307: filter->data = data; 308: filter->illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR; 309: filter->illegal_substchar = 0x3f; /* '?' */ 310: filter->num_illegalchar = 0; 311: filter->filter_ctor = vtbl->filter_ctor; 312: filter->filter_dtor = vtbl->filter_dtor; 313: filter->filter_function = vtbl->filter_function; 314: filter->filter_flush = vtbl->filter_flush; 315: filter->filter_copy = vtbl->filter_copy; 316: 317: (*filter->filter_ctor)(filter); 318: 319: return 0; 320: } 321: 322: 323: mbfl_convert_filter * 324: mbfl_convert_filter_new( 325: enum mbfl_no_encoding from, 326: enum mbfl_no_encoding to, 327: int (*output_function)(int, void* ), 328: int (*flush_function)(void*), 329: void* data) 330: { 331: mbfl_convert_filter * filter; 332: const struct mbfl_convert_vtbl *vtbl; 333: 334: vtbl = mbfl_convert_filter_get_vtbl(from, to); 335: 336: if (vtbl == NULL) { 337: vtbl = &vtbl_pass; 338: } 339: 340: /* allocate */ 341: filter = (mbfl_convert_filter *)mbfl_malloc(sizeof(mbfl_convert_filter)); 342: if (filter == NULL) { 343: return NULL; 344: } 345: 346: if (mbfl_convert_filter_common_init(filter, from, to, vtbl, 347: output_function, flush_function, data)) { 348: mbfl_free(filter); 349: return NULL; 350: } 351: 352: return filter; 353: } 354: 355: mbfl_convert_filter * 356: mbfl_convert_filter_new2( 357: const struct mbfl_convert_vtbl *vtbl, 358: int (*output_function)(int, void* ), 359: int (*flush_function)(void*), 360: void* data) 361: { 362: mbfl_convert_filter * filter; 363: 364: if (vtbl == NULL) { 365: vtbl = &vtbl_pass; 366: } 367: 368: /* allocate */ 369: filter = (mbfl_convert_filter *)mbfl_malloc(sizeof(mbfl_convert_filter)); 370: if (filter == NULL) { 371: return NULL; 372: } 373: 374: if (mbfl_convert_filter_common_init(filter, vtbl->from, vtbl->to, vtbl, 375: output_function, flush_function, data)) { 376: mbfl_free(filter); 377: return NULL; 378: } 379: 380: return filter; 381: } 382: 383: void 384: mbfl_convert_filter_delete(mbfl_convert_filter *filter) 385: { 386: if (filter) { 387: (*filter->filter_dtor)(filter); 388: mbfl_free((void*)filter); 389: } 390: } 391: 392: int 393: mbfl_convert_filter_feed(int c, mbfl_convert_filter *filter) 394: { 395: return (*filter->filter_function)(c, filter); 396: } 397: 398: int 399: mbfl_convert_filter_flush(mbfl_convert_filter *filter) 400: { 401: (*filter->filter_flush)(filter); 402: return (filter->flush_function ? (*filter->flush_function)(filter->data) : 0); 403: } 404: 405: void mbfl_convert_filter_reset(mbfl_convert_filter *filter, 406: enum mbfl_no_encoding from, enum mbfl_no_encoding to) 407: { 408: const struct mbfl_convert_vtbl *vtbl; 409: 410: /* destruct old filter */ 411: (*filter->filter_dtor)(filter); 412: 413: vtbl = mbfl_convert_filter_get_vtbl(from, to); 414: 415: if (vtbl == NULL) { 416: vtbl = &vtbl_pass; 417: } 418: 419: mbfl_convert_filter_common_init(filter, from, to, vtbl, 420: filter->output_function, filter->flush_function, filter->data); 421: } 422: 423: void 424: mbfl_convert_filter_copy( 425: mbfl_convert_filter *src, 426: mbfl_convert_filter *dest) 427: { 428: if (src->filter_copy != NULL) { 429: src->filter_copy(src, dest); 430: return; 431: } 432: 433: *dest = *src; 434: } 435: 436: int mbfl_convert_filter_devcat(mbfl_convert_filter *filter, mbfl_memory_device *src) 437: { 438: int n; 439: unsigned char *p; 440: 441: p = src->buffer; 442: n = src->pos; 443: while (n > 0) { 444: if ((*filter->filter_function)(*p++, filter) < 0) { 445: return -1; 446: } 447: n--; 448: } 449: 450: return n; 451: } 452: 453: int mbfl_convert_filter_strcat(mbfl_convert_filter *filter, const unsigned char *p) 454: { 455: int c; 456: 457: while ((c = *p++) != '\0') { 458: if ((*filter->filter_function)(c, filter) < 0) { 459: return -1; 460: } 461: } 462: 463: return 0; 464: } 465: 466: /* illegal character output function for conv-filter */ 467: int 468: mbfl_filt_conv_illegal_output(int c, mbfl_convert_filter *filter) 469: { 470: int mode_backup, ret, n, m, r; 471: 472: ret = 0; 473: mode_backup = filter->illegal_mode; 474: filter->illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE; 475: switch (mode_backup) { 476: case MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR: 477: ret = (*filter->filter_function)(filter->illegal_substchar, filter); 478: break; 479: case MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG: 480: if (c >= 0) { 481: if (c < MBFL_WCSGROUP_UCS4MAX) { /* unicode */ 482: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"U+"); 483: } else { 484: if (c < MBFL_WCSGROUP_WCHARMAX) { 485: m = c & ~MBFL_WCSPLANE_MASK; 486: switch (m) { 487: case MBFL_WCSPLANE_JIS0208: 488: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"JIS+"); 489: break; 490: case MBFL_WCSPLANE_JIS0212: 491: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"JIS2+"); 492: break; 1.1.1.2 ! misho 493: case MBFL_WCSPLANE_JIS0213: ! 494: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"JIS3+"); ! 495: break; 1.1 misho 496: case MBFL_WCSPLANE_WINCP932: 497: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"W932+"); 498: break; 1.1.1.2 ! misho 499: case MBFL_WCSPLANE_GB18030: ! 500: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"GB+"); ! 501: break; 1.1 misho 502: case MBFL_WCSPLANE_8859_1: 503: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"I8859_1+"); 504: break; 505: default: 506: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"?+"); 507: break; 508: } 509: c &= MBFL_WCSPLANE_MASK; 510: } else { 511: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"BAD+"); 512: c &= MBFL_WCSGROUP_MASK; 513: } 514: } 515: if (ret >= 0) { 516: m = 0; 517: r = 28; 518: while (r >= 0) { 519: n = (c >> r) & 0xf; 520: if (n || m) { 521: m = 1; 522: ret = (*filter->filter_function)(mbfl_hexchar_table[n], filter); 523: if (ret < 0) { 524: break; 525: } 526: } 527: r -= 4; 528: } 529: if (m == 0 && ret >= 0) { 530: ret = (*filter->filter_function)(mbfl_hexchar_table[0], filter); 531: } 532: } 533: } 534: break; 535: case MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY: 536: if (c >= 0) { 537: if (c < MBFL_WCSGROUP_UCS4MAX) { /* unicode */ 538: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)"&#x"); 539: if (ret < 0) 540: break; 541: 542: m = 0; 543: r = 28; 544: while (r >= 0) { 545: n = (c >> r) & 0xf; 546: if (n || m) { 547: m = 1; 548: ret = (*filter->filter_function)(mbfl_hexchar_table[n], filter); 549: if (ret < 0) { 550: break; 551: } 552: } 553: r -= 4; 554: } 555: if (ret < 0) { 556: break; 557: } 558: if (m == 0) { 559: ret = (*filter->filter_function)(mbfl_hexchar_table[0], filter); 560: } 561: ret = mbfl_convert_filter_strcat(filter, (const unsigned char *)";"); 562: } else { 563: ret = (*filter->filter_function)(filter->illegal_substchar, filter); 564: } 565: } 566: break; 567: default: 568: break; 569: } 570: filter->illegal_mode = mode_backup; 571: filter->num_illegalchar++; 572: 573: return ret; 574: } 575: 576: const struct mbfl_convert_vtbl * mbfl_convert_filter_get_vtbl(enum mbfl_no_encoding from, enum mbfl_no_encoding to) 577: { 578: const struct mbfl_convert_vtbl *vtbl; 579: int i; 580: 581: if (to == mbfl_no_encoding_base64 || 582: to == mbfl_no_encoding_qprint || 583: to == mbfl_no_encoding_7bit) { 584: from = mbfl_no_encoding_8bit; 585: } else if (from == mbfl_no_encoding_base64 || 586: from == mbfl_no_encoding_qprint || 587: from == mbfl_no_encoding_uuencode) { 588: to = mbfl_no_encoding_8bit; 589: } 590: 591: i = 0; 592: while ((vtbl = mbfl_convert_filter_list[i++]) != NULL){ 593: if (vtbl->from == from && vtbl->to == to) { 594: return vtbl; 595: } 596: } 597: 598: return NULL; 599: } 600: 601: /* 602: * commonly used constructor and destructor 603: */ 604: void mbfl_filt_conv_common_ctor(mbfl_convert_filter *filter) 605: { 606: filter->status = 0; 607: filter->cache = 0; 608: } 609: 610: int mbfl_filt_conv_common_flush(mbfl_convert_filter *filter) 611: { 612: filter->status = 0; 613: filter->cache = 0; 614: 615: if (filter->flush_function != NULL) { 616: (*filter->flush_function)(filter->data); 617: } 618: return 0; 619: } 620: 621: void mbfl_filt_conv_common_dtor(mbfl_convert_filter *filter) 622: { 623: filter->status = 0; 624: filter->cache = 0; 625: } 626: 627: