OLD | NEW |
1 /* $Id: tif_dir.c,v 1.113 2012-06-14 20:32:53 fwarmerdam Exp $ */ | 1 /* $Id: tif_dir.c,v 1.121 2015-05-31 23:11:43 bfriesen Exp $ */ |
2 | 2 |
3 /* | 3 /* |
4 * Copyright (c) 1988-1997 Sam Leffler | 4 * Copyright (c) 1988-1997 Sam Leffler |
5 * Copyright (c) 1991-1997 Silicon Graphics, Inc. | 5 * Copyright (c) 1991-1997 Silicon Graphics, Inc. |
6 * | 6 * |
7 * Permission to use, copy, modify, distribute, and sell this software and | 7 * Permission to use, copy, modify, distribute, and sell this software and |
8 * its documentation for any purpose is hereby granted without fee, provided | 8 * its documentation for any purpose is hereby granted without fee, provided |
9 * that (i) the above copyright notices and this permission notice appear in | 9 * that (i) the above copyright notices and this permission notice appear in |
10 * all copies of the software and related documentation, and (ii) the names of | 10 * all copies of the software and related documentation, and (ii) the names of |
11 * Sam Leffler and Silicon Graphics may not be used in any advertising or | 11 * Sam Leffler and Silicon Graphics may not be used in any advertising or |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 } | 153 } |
154 | 154 |
155 static int | 155 static int |
156 _TIFFVSetField(TIFF* tif, uint32 tag, va_list ap) | 156 _TIFFVSetField(TIFF* tif, uint32 tag, va_list ap) |
157 { | 157 { |
158 static const char module[] = "_TIFFVSetField"; | 158 static const char module[] = "_TIFFVSetField"; |
159 | 159 |
160 TIFFDirectory* td = &tif->tif_dir; | 160 TIFFDirectory* td = &tif->tif_dir; |
161 int status = 1; | 161 int status = 1; |
162 uint32 v32, i, v; | 162 uint32 v32, i, v; |
| 163 double dblval; |
163 char* s; | 164 char* s; |
164 const TIFFField *fip = TIFFFindField(tif, tag, TIFF_ANY); | 165 const TIFFField *fip = TIFFFindField(tif, tag, TIFF_ANY); |
165 uint32 standard_tag = tag; | 166 uint32 standard_tag = tag; |
166 | 167 » if( fip == NULL ) /* cannot happen since OkToChangeTag() already checks
it */ |
| 168 » return 0; |
167 /* | 169 /* |
168 * We want to force the custom code to be used for custom | 170 * We want to force the custom code to be used for custom |
169 * fields even if the tag happens to match a well known | 171 * fields even if the tag happens to match a well known |
170 * one - important for reinterpreted handling of standard | 172 * one - important for reinterpreted handling of standard |
171 * tag values in custom directories (ie. EXIF) | 173 * tag values in custom directories (ie. EXIF) |
172 */ | 174 */ |
173 if (fip->field_bit == FIELD_CUSTOM) { | 175 if (fip->field_bit == FIELD_CUSTOM) { |
174 standard_tag = 0; | 176 standard_tag = 0; |
175 } | 177 } |
176 | 178 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 else | 278 else |
277 setDoubleArrayOneValue(&td->td_sminsamplevalue, va_arg(a
p, double), td->td_samplesperpixel); | 279 setDoubleArrayOneValue(&td->td_sminsamplevalue, va_arg(a
p, double), td->td_samplesperpixel); |
278 break; | 280 break; |
279 case TIFFTAG_SMAXSAMPLEVALUE: | 281 case TIFFTAG_SMAXSAMPLEVALUE: |
280 if (tif->tif_flags & TIFF_PERSAMPLE) | 282 if (tif->tif_flags & TIFF_PERSAMPLE) |
281 _TIFFsetDoubleArray(&td->td_smaxsamplevalue, va_arg(ap,
double*), td->td_samplesperpixel); | 283 _TIFFsetDoubleArray(&td->td_smaxsamplevalue, va_arg(ap,
double*), td->td_samplesperpixel); |
282 else | 284 else |
283 setDoubleArrayOneValue(&td->td_smaxsamplevalue, va_arg(a
p, double), td->td_samplesperpixel); | 285 setDoubleArrayOneValue(&td->td_smaxsamplevalue, va_arg(a
p, double), td->td_samplesperpixel); |
284 break; | 286 break; |
285 case TIFFTAG_XRESOLUTION: | 287 case TIFFTAG_XRESOLUTION: |
286 » » td->td_xresolution = (float) va_arg(ap, double); | 288 dblval = va_arg(ap, double); |
| 289 if( dblval < 0 ) |
| 290 goto badvaluedouble; |
| 291 » » td->td_xresolution = (float) dblval; |
287 break; | 292 break; |
288 case TIFFTAG_YRESOLUTION: | 293 case TIFFTAG_YRESOLUTION: |
289 » » td->td_yresolution = (float) va_arg(ap, double); | 294 dblval = va_arg(ap, double); |
| 295 if( dblval < 0 ) |
| 296 goto badvaluedouble; |
| 297 » » td->td_yresolution = (float) dblval; |
290 break; | 298 break; |
291 case TIFFTAG_PLANARCONFIG: | 299 case TIFFTAG_PLANARCONFIG: |
292 v = (uint16) va_arg(ap, uint16_vap); | 300 v = (uint16) va_arg(ap, uint16_vap); |
293 if (v != PLANARCONFIG_CONTIG && v != PLANARCONFIG_SEPARATE) | 301 if (v != PLANARCONFIG_CONTIG && v != PLANARCONFIG_SEPARATE) |
294 goto badvalue; | 302 goto badvalue; |
295 td->td_planarconfig = (uint16) v; | 303 td->td_planarconfig = (uint16) v; |
296 break; | 304 break; |
297 case TIFFTAG_XPOSITION: | 305 case TIFFTAG_XPOSITION: |
298 td->td_xposition = (float) va_arg(ap, double); | 306 td->td_xposition = (float) va_arg(ap, double); |
299 break; | 307 break; |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
442 | 450 |
443 /* | 451 /* |
444 * This can happen if multiple images are open with different | 452 * This can happen if multiple images are open with different |
445 * codecs which have private tags. The global tag information | 453 * codecs which have private tags. The global tag information |
446 * table may then have tags that are valid for one file but not | 454 * table may then have tags that are valid for one file but not |
447 * the other. If the client tries to set a tag that is not valid | 455 * the other. If the client tries to set a tag that is not valid |
448 * for the image's codec then we'll arrive here. This | 456 * for the image's codec then we'll arrive here. This |
449 * happens, for example, when tiffcp is used to convert between | 457 * happens, for example, when tiffcp is used to convert between |
450 * compression schemes and codec-specific tags are blindly copie
d. | 458 * compression schemes and codec-specific tags are blindly copie
d. |
451 */ | 459 */ |
452 » » if(fip == NULL || fip->field_bit != FIELD_CUSTOM) { | 460 » » if(fip->field_bit != FIELD_CUSTOM) { |
453 TIFFErrorExt(tif->tif_clientdata, module, | 461 TIFFErrorExt(tif->tif_clientdata, module, |
454 "%s: Invalid %stag \"%s\" (not supported by codec)", | 462 "%s: Invalid %stag \"%s\" (not supported by codec)", |
455 tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "", | 463 tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "", |
456 » » » fip ? fip->field_name : "Unknown"); | 464 » » » fip->field_name); |
457 status = 0; | 465 status = 0; |
458 break; | 466 break; |
459 } | 467 } |
460 | 468 |
461 /* | 469 /* |
462 * Find the existing entry for this custom value. | 470 * Find the existing entry for this custom value. |
463 */ | 471 */ |
464 tv = NULL; | 472 tv = NULL; |
465 for (iCustom = 0; iCustom < td->td_customValueCount; iCustom++)
{ | 473 for (iCustom = 0; iCustom < td->td_customValueCount; iCustom++)
{ |
466 if (td->td_customValues[iCustom].info->field_tag == tag)
{ | 474 if (td->td_customValues[iCustom].info->field_tag == tag)
{ |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
686 badvalue32: | 694 badvalue32: |
687 { | 695 { |
688 const TIFFField* fip=TIFFFieldWithTag(tif,tag); | 696 const TIFFField* fip=TIFFFieldWithTag(tif,tag); |
689 TIFFErrorExt(tif->tif_clientdata, module, | 697 TIFFErrorExt(tif->tif_clientdata, module, |
690 "%s: Bad value %u for \"%s\" tag", | 698 "%s: Bad value %u for \"%s\" tag", |
691 tif->tif_name, v32, | 699 tif->tif_name, v32, |
692 fip ? fip->field_name : "Unknown"); | 700 fip ? fip->field_name : "Unknown"); |
693 va_end(ap); | 701 va_end(ap); |
694 } | 702 } |
695 return (0); | 703 return (0); |
| 704 badvaluedouble: |
| 705 { |
| 706 const TIFFField* fip=TIFFFieldWithTag(tif,tag); |
| 707 TIFFErrorExt(tif->tif_clientdata, module, |
| 708 "%s: Bad value %f for \"%s\" tag", |
| 709 tif->tif_name, dblval, |
| 710 fip ? fip->field_name : "Unknown"); |
| 711 va_end(ap); |
| 712 } |
| 713 return (0); |
696 } | 714 } |
697 | 715 |
698 /* | 716 /* |
699 * Return 1/0 according to whether or not | 717 * Return 1/0 according to whether or not |
700 * it is permissible to set the tag's value. | 718 * it is permissible to set the tag's value. |
701 * Note that we allow ImageLength to be changed | 719 * Note that we allow ImageLength to be changed |
702 * so that we can append and extend to images. | 720 * so that we can append and extend to images. |
703 * Any other tag may not be altered once writing | 721 * Any other tag may not be altered once writing |
704 * has commenced, unless its value has no effect | 722 * has commenced, unless its value has no effect |
705 * on the format of the data that is written. | 723 * on the format of the data that is written. |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
802 (*tif->tif_tagmethods.vsetfield)(tif, tag, ap) : 0; | 820 (*tif->tif_tagmethods.vsetfield)(tif, tag, ap) : 0; |
803 } | 821 } |
804 | 822 |
805 static int | 823 static int |
806 _TIFFVGetField(TIFF* tif, uint32 tag, va_list ap) | 824 _TIFFVGetField(TIFF* tif, uint32 tag, va_list ap) |
807 { | 825 { |
808 TIFFDirectory* td = &tif->tif_dir; | 826 TIFFDirectory* td = &tif->tif_dir; |
809 int ret_val = 1; | 827 int ret_val = 1; |
810 uint32 standard_tag = tag; | 828 uint32 standard_tag = tag; |
811 const TIFFField* fip = TIFFFindField(tif, tag, TIFF_ANY); | 829 const TIFFField* fip = TIFFFindField(tif, tag, TIFF_ANY); |
| 830 if( fip == NULL ) /* cannot happen since TIFFGetField() already checks i
t */ |
| 831 return 0; |
812 | 832 |
813 /* | 833 /* |
814 * We want to force the custom code to be used for custom | 834 * We want to force the custom code to be used for custom |
815 * fields even if the tag happens to match a well known | 835 * fields even if the tag happens to match a well known |
816 * one - important for reinterpreted handling of standard | 836 * one - important for reinterpreted handling of standard |
817 * tag values in custom directories (ie. EXIF) | 837 * tag values in custom directories (ie. EXIF) |
818 */ | 838 */ |
819 if (fip->field_bit == FIELD_CUSTOM) { | 839 if (fip->field_bit == FIELD_CUSTOM) { |
820 standard_tag = 0; | 840 standard_tag = 0; |
821 } | 841 } |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
999 | 1019 |
1000 /* | 1020 /* |
1001 * This can happen if multiple images are open | 1021 * This can happen if multiple images are open |
1002 * with different codecs which have private | 1022 * with different codecs which have private |
1003 * tags. The global tag information table may | 1023 * tags. The global tag information table may |
1004 * then have tags that are valid for one file | 1024 * then have tags that are valid for one file |
1005 * but not the other. If the client tries to | 1025 * but not the other. If the client tries to |
1006 * get a tag that is not valid for the image's | 1026 * get a tag that is not valid for the image's |
1007 * codec then we'll arrive here. | 1027 * codec then we'll arrive here. |
1008 */ | 1028 */ |
1009 » » » » if( fip == NULL || fip->field_bit != FIELD_CUSTO
M ) | 1029 » » » » if( fip->field_bit != FIELD_CUSTOM ) |
1010 { | 1030 { |
1011 TIFFErrorExt(tif->tif_clientdata, "_TIFF
VGetField", | 1031 TIFFErrorExt(tif->tif_clientdata, "_TIFF
VGetField", |
1012 "%s: Invalid %stag \"%s\" " | 1032 "%s: Invalid %stag \"%s\" " |
1013 "(not supported by codec)", | 1033 "(not supported by codec)", |
1014 tif->tif_name, | 1034 tif->tif_name, |
1015 isPseudoTag(tag) ? "pseudo-" : "", | 1035 isPseudoTag(tag) ? "pseudo-" : "", |
1016 » » » » » fip ? fip->field_name : "Unknown"); | 1036 » » » » » fip->field_name); |
1017 ret_val = 0; | 1037 ret_val = 0; |
1018 break; | 1038 break; |
1019 } | 1039 } |
1020 | 1040 |
1021 /* | 1041 /* |
1022 * Do we have a custom value? | 1042 * Do we have a custom value? |
1023 */ | 1043 */ |
1024 ret_val = 0; | 1044 ret_val = 0; |
1025 for (i = 0; i < td->td_customValueCount; i++) { | 1045 for (i = 0; i < td->td_customValueCount; i++) { |
1026 TIFFTagValue *tv = td->td_customValues +
i; | 1046 TIFFTagValue *tv = td->td_customValues +
i; |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1295 td->td_ycbcrsubsampling[0] = 2; | 1315 td->td_ycbcrsubsampling[0] = 2; |
1296 td->td_ycbcrsubsampling[1] = 2; | 1316 td->td_ycbcrsubsampling[1] = 2; |
1297 td->td_ycbcrpositioning = YCBCRPOSITION_CENTERED; | 1317 td->td_ycbcrpositioning = YCBCRPOSITION_CENTERED; |
1298 tif->tif_postdecode = _TIFFNoPostDecode; | 1318 tif->tif_postdecode = _TIFFNoPostDecode; |
1299 tif->tif_foundfield = NULL; | 1319 tif->tif_foundfield = NULL; |
1300 tif->tif_tagmethods.vsetfield = _TIFFVSetField; | 1320 tif->tif_tagmethods.vsetfield = _TIFFVSetField; |
1301 tif->tif_tagmethods.vgetfield = _TIFFVGetField; | 1321 tif->tif_tagmethods.vgetfield = _TIFFVGetField; |
1302 tif->tif_tagmethods.printdir = NULL; | 1322 tif->tif_tagmethods.printdir = NULL; |
1303 /* | 1323 /* |
1304 * Give client code a chance to install their own | 1324 * Give client code a chance to install their own |
1305 » * tag extensions & methods, prior to compression overloads. | 1325 » * tag extensions & methods, prior to compression overloads, |
| 1326 » * but do some prior cleanup first. (http://trac.osgeo.org/gdal/ticket/
5054) |
1306 */ | 1327 */ |
| 1328 if (tif->tif_nfieldscompat > 0) { |
| 1329 uint32 i; |
| 1330 |
| 1331 for (i = 0; i < tif->tif_nfieldscompat; i++) { |
| 1332 if (tif->tif_fieldscompat[i].allocated_size) |
| 1333 _TIFFfree(tif->tif_fieldscompat[
i].fields); |
| 1334 } |
| 1335 _TIFFfree(tif->tif_fieldscompat); |
| 1336 tif->tif_nfieldscompat = 0; |
| 1337 tif->tif_fieldscompat = NULL; |
| 1338 } |
1307 if (_TIFFextender) | 1339 if (_TIFFextender) |
1308 (*_TIFFextender)(tif); | 1340 (*_TIFFextender)(tif); |
1309 (void) TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); | 1341 (void) TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); |
1310 /* | 1342 /* |
1311 * NB: The directory is marked dirty as a result of setting | 1343 * NB: The directory is marked dirty as a result of setting |
1312 * up the default compression scheme. However, this really | 1344 * up the default compression scheme. However, this really |
1313 * isn't correct -- we want TIFF_DIRTYDIRECT to be set only | 1345 * isn't correct -- we want TIFF_DIRTYDIRECT to be set only |
1314 * if the user does something. We could just do the setup | 1346 * if the user does something. We could just do the setup |
1315 * by hand, but it seems better to use the normal mechanism | 1347 * by hand, but it seems better to use the normal mechanism |
1316 * (i.e. TIFFSetField). | 1348 * (i.e. TIFFSetField). |
(...skipping 20 matching lines...) Expand all Loading... |
1337 if (!(tif->tif_flags&TIFF_BIGTIFF)) | 1369 if (!(tif->tif_flags&TIFF_BIGTIFF)) |
1338 { | 1370 { |
1339 tmsize_t poffa,poffb,poffc,poffd; | 1371 tmsize_t poffa,poffb,poffc,poffd; |
1340 uint16 dircount; | 1372 uint16 dircount; |
1341 uint32 nextdir32; | 1373 uint32 nextdir32; |
1342 poffa=(tmsize_t)poff; | 1374 poffa=(tmsize_t)poff; |
1343 poffb=poffa+sizeof(uint16); | 1375 poffb=poffa+sizeof(uint16); |
1344 if (((uint64)poffa!=poff)||(poffb<poffa)||(poffb<(tmsize
_t)sizeof(uint16))||(poffb>tif->tif_size)) | 1376 if (((uint64)poffa!=poff)||(poffb<poffa)||(poffb<(tmsize
_t)sizeof(uint16))||(poffb>tif->tif_size)) |
1345 { | 1377 { |
1346 TIFFErrorExt(tif->tif_clientdata,module,"Error f
etching directory count"); | 1378 TIFFErrorExt(tif->tif_clientdata,module,"Error f
etching directory count"); |
| 1379 *nextdir=0; |
1347 return(0); | 1380 return(0); |
1348 } | 1381 } |
1349 _TIFFmemcpy(&dircount,tif->tif_base+poffa,sizeof(uint16)
); | 1382 _TIFFmemcpy(&dircount,tif->tif_base+poffa,sizeof(uint16)
); |
1350 if (tif->tif_flags&TIFF_SWAB) | 1383 if (tif->tif_flags&TIFF_SWAB) |
1351 TIFFSwabShort(&dircount); | 1384 TIFFSwabShort(&dircount); |
1352 poffc=poffb+dircount*12; | 1385 poffc=poffb+dircount*12; |
1353 poffd=poffc+sizeof(uint32); | 1386 poffd=poffc+sizeof(uint32); |
1354 if ((poffc<poffb)||(poffc<dircount*12)||(poffd<poffc)||(
poffd<(tmsize_t)sizeof(uint32))||(poffd>tif->tif_size)) | 1387 if ((poffc<poffb)||(poffc<dircount*12)||(poffd<poffc)||(
poffd<(tmsize_t)sizeof(uint32))||(poffd>tif->tif_size)) |
1355 { | 1388 { |
1356 TIFFErrorExt(tif->tif_clientdata,module,"Error f
etching directory link"); | 1389 TIFFErrorExt(tif->tif_clientdata,module,"Error f
etching directory link"); |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1446 return(0); | 1479 return(0); |
1447 } | 1480 } |
1448 dircount16 = (uint16)dircount64; | 1481 dircount16 = (uint16)dircount64; |
1449 if (off != NULL) | 1482 if (off != NULL) |
1450 *off = TIFFSeekFile(tif, | 1483 *off = TIFFSeekFile(tif, |
1451 dircount16*20, SEEK_CUR); | 1484 dircount16*20, SEEK_CUR); |
1452 else | 1485 else |
1453 (void) TIFFSeekFile(tif, | 1486 (void) TIFFSeekFile(tif, |
1454 dircount16*20, SEEK_CUR); | 1487 dircount16*20, SEEK_CUR); |
1455 if (!ReadOK(tif, nextdir, sizeof (uint64))) { | 1488 if (!ReadOK(tif, nextdir, sizeof (uint64))) { |
1456 » » » » TIFFErrorExt(tif->tif_clientdata, module, "%s: E
rror fetching directory link", | 1489 » » » » TIFFErrorExt(tif->tif_clientdata, module, |
| 1490 "%s: Error fetching directory link"
, |
1457 tif->tif_name); | 1491 tif->tif_name); |
1458 return (0); | 1492 return (0); |
1459 } | 1493 } |
1460 if (tif->tif_flags & TIFF_SWAB) | 1494 if (tif->tif_flags & TIFF_SWAB) |
1461 TIFFSwabLong8(nextdir); | 1495 TIFFSwabLong8(nextdir); |
1462 } | 1496 } |
1463 return (1); | 1497 return (1); |
1464 } | 1498 } |
1465 } | 1499 } |
1466 | 1500 |
1467 /* | 1501 /* |
1468 * Count the number of directories in a file. | 1502 * Count the number of directories in a file. |
1469 */ | 1503 */ |
1470 uint16 | 1504 uint16 |
1471 TIFFNumberOfDirectories(TIFF* tif) | 1505 TIFFNumberOfDirectories(TIFF* tif) |
1472 { | 1506 { |
| 1507 static const char module[] = "TIFFNumberOfDirectories"; |
1473 uint64 nextdir; | 1508 uint64 nextdir; |
1474 uint16 n; | 1509 uint16 n; |
1475 if (!(tif->tif_flags&TIFF_BIGTIFF)) | 1510 if (!(tif->tif_flags&TIFF_BIGTIFF)) |
1476 nextdir = tif->tif_header.classic.tiff_diroff; | 1511 nextdir = tif->tif_header.classic.tiff_diroff; |
1477 else | 1512 else |
1478 nextdir = tif->tif_header.big.tiff_diroff; | 1513 nextdir = tif->tif_header.big.tiff_diroff; |
1479 n = 0; | 1514 n = 0; |
1480 while (nextdir != 0 && TIFFAdvanceDirectory(tif, &nextdir, NULL)) | 1515 while (nextdir != 0 && TIFFAdvanceDirectory(tif, &nextdir, NULL)) |
1481 » » n++; | 1516 { |
| 1517 if (n != 65535) { |
| 1518 ++n; |
| 1519 } |
| 1520 » » else |
| 1521 { |
| 1522 TIFFErrorExt(tif->tif_clientdata, module, |
| 1523 "Directory count exceeded 65535 limit," |
| 1524 " giving up on counting."); |
| 1525 return (65535); |
| 1526 } |
| 1527 } |
1482 return (n); | 1528 return (n); |
1483 } | 1529 } |
1484 | 1530 |
1485 /* | 1531 /* |
1486 * Set the n-th directory as the current directory. | 1532 * Set the n-th directory as the current directory. |
1487 * NB: Directories are numbered starting at 0. | 1533 * NB: Directories are numbered starting at 0. |
1488 */ | 1534 */ |
1489 int | 1535 int |
1490 TIFFSetDirectory(TIFF* tif, uint16 dirn) | 1536 TIFFSetDirectory(TIFF* tif, uint16 dirn) |
1491 { | 1537 { |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1650 } | 1696 } |
1651 | 1697 |
1652 /* vim: set ts=8 sts=8 sw=8 noet: */ | 1698 /* vim: set ts=8 sts=8 sw=8 noet: */ |
1653 /* | 1699 /* |
1654 * Local Variables: | 1700 * Local Variables: |
1655 * mode: c | 1701 * mode: c |
1656 * c-basic-offset: 8 | 1702 * c-basic-offset: 8 |
1657 * fill-column: 78 | 1703 * fill-column: 78 |
1658 * End: | 1704 * End: |
1659 */ | 1705 */ |
1660 | |
OLD | NEW |