Index: trunk/phase3/RELEASE-NOTES-1.19 |
— | — | @@ -223,6 +223,8 @@ |
224 | 224 | * (bug 33321) Adding a line to MediaWiki:Sidebar that contains a pipe, but doesn't |
225 | 225 | have any pipes after being transformed by MessageCache, causes exception on |
226 | 226 | all pages. |
| 227 | +* Files with IPTC blocks we can't read no longer prevent extraction of exif |
| 228 | + or other metadata. |
227 | 229 | |
228 | 230 | === API changes in 1.19 === |
229 | 231 | * (bug 19838) siprop=interwikimap can now use the interwiki cache. |
Index: trunk/phase3/tests/phpunit/includes/media/BitmapMetadataHandlerTest.php |
— | — | @@ -56,6 +56,16 @@ |
57 | 57 | $meta['JPEGFileComment'][0] ); |
58 | 58 | } |
59 | 59 | |
| 60 | + /** |
| 61 | + * Make sure a bad iptc block doesn't stop the other metadata |
| 62 | + * from being extracted. |
| 63 | + */ |
| 64 | + public function testBadIPTC() { |
| 65 | + $meta = BitmapMetadataHandler::Jpeg( $this->filePath . |
| 66 | + 'iptc-invalid-psir.jpg' ); |
| 67 | + $this->assertEquals( 'Created with GIMP', $meta['JPEGFileComment'][0] ); |
| 68 | + } |
| 69 | + |
60 | 70 | public function testIPTCDates() { |
61 | 71 | $meta = BitmapMetadataHandler::Jpeg( $this->filePath . |
62 | 72 | 'iptc-timetest.jpg' ); |
Index: trunk/phase3/tests/phpunit/includes/media/JpegMetadataExtractorTest.php |
— | — | @@ -59,7 +59,7 @@ |
60 | 60 | public function testPSIRExtraction() { |
61 | 61 | $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-psir.jpg' ); |
62 | 62 | $expected = '50686f746f73686f7020332e30003842494d04040000000000181c02190004746573741c02190003666f6f1c020000020004'; |
63 | | - $this->assertEquals( $expected, bin2hex( $res['PSIR'] ) ); |
| 63 | + $this->assertEquals( $expected, bin2hex( $res['PSIR'][0] ) ); |
64 | 64 | } |
65 | 65 | public function testXMPExtractionAltAppId() { |
66 | 66 | $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-alt.jpg' ); |
— | — | @@ -70,19 +70,19 @@ |
71 | 71 | |
72 | 72 | public function testIPTCHashComparisionNoHash() { |
73 | 73 | $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-psir.jpg' ); |
74 | | - $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'] ); |
| 74 | + $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] ); |
75 | 75 | |
76 | 76 | $this->assertEquals( 'iptc-no-hash', $res ); |
77 | 77 | } |
78 | 78 | public function testIPTCHashComparisionBadHash() { |
79 | 79 | $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-iptc-bad-hash.jpg' ); |
80 | | - $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'] ); |
| 80 | + $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] ); |
81 | 81 | |
82 | 82 | $this->assertEquals( 'iptc-bad-hash', $res ); |
83 | 83 | } |
84 | 84 | public function testIPTCHashComparisionGoodHash() { |
85 | 85 | $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-iptc-good-hash.jpg' ); |
86 | | - $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'] ); |
| 86 | + $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] ); |
87 | 87 | |
88 | 88 | $this->assertEquals( 'iptc-good-hash', $res ); |
89 | 89 | } |
Index: trunk/phase3/tests/phpunit/data/media/iptc-invalid-psir.jpg |
Cannot display: file marked as a binary type. |
svn:mime-type = image/jpeg |
Property changes on: trunk/phase3/tests/phpunit/data/media/iptc-invalid-psir.jpg |
___________________________________________________________________ |
Added: svn:mime-type |
90 | 90 | + image/jpeg |
Index: trunk/phase3/includes/media/BitmapMetadataHandler.php |
— | — | @@ -32,7 +32,15 @@ |
33 | 33 | * @param String $app13 String containing app13 block from jpeg file |
34 | 34 | */ |
35 | 35 | private function doApp13 ( $app13 ) { |
36 | | - $this->iptcType = JpegMetadataExtractor::doPSIR( $app13 ); |
| 36 | + try { |
| 37 | + $this->iptcType = JpegMetadataExtractor::doPSIR( $app13 ); |
| 38 | + } catch ( MWException $e ) { |
| 39 | + // Error reading the iptc hash information. |
| 40 | + // This probably means the App13 segment is something other than what we expect. |
| 41 | + // However, still try to read it, and treat it as if the hash didn't exist. |
| 42 | + wfDebug( "Error parsing iptc data of file: " . $e->getMessage() . "\n" ); |
| 43 | + $this->iptcType = 'iptc-no-hash'; |
| 44 | + } |
37 | 45 | |
38 | 46 | $iptc = IPTC::parse( $app13 ); |
39 | 47 | $this->addMetadata( $iptc, $this->iptcType ); |
— | — | @@ -122,8 +130,10 @@ |
123 | 131 | if ( isset( $seg['COM'] ) && isset( $seg['COM'][0] ) ) { |
124 | 132 | $meta->addMetadata( Array( 'JPEGFileComment' => $seg['COM'] ), 'native' ); |
125 | 133 | } |
126 | | - if ( isset( $seg['PSIR'] ) ) { |
127 | | - $meta->doApp13( $seg['PSIR'] ); |
| 134 | + if ( isset( $seg['PSIR'] ) && count( $seg['PSIR'] ) > 0 ) { |
| 135 | + foreach( $seg['PSIR'] as $curPSIRValue ) { |
| 136 | + $meta->doApp13( $curPSIRValue ); |
| 137 | + } |
128 | 138 | } |
129 | 139 | if ( isset( $seg['XMP'] ) && $showXMP ) { |
130 | 140 | $xmp = new XMPReader(); |
Index: trunk/phase3/includes/media/JpegMetadataExtractor.php |
— | — | @@ -31,6 +31,7 @@ |
32 | 32 | $segments = array( |
33 | 33 | 'XMP_ext' => array(), |
34 | 34 | 'COM' => array(), |
| 35 | + 'PSIR' => array(), |
35 | 36 | ); |
36 | 37 | |
37 | 38 | if ( !$filename ) { |
— | — | @@ -122,7 +123,7 @@ |
123 | 124 | // APP13 - PSIR. IPTC and some photoshop stuff |
124 | 125 | $temp = self::jpegExtractMarker( $fh ); |
125 | 126 | if ( substr( $temp, 0, 14 ) === "Photoshop 3.0\x00" ) { |
126 | | - $segments["PSIR"] = $temp; |
| 127 | + $segments["PSIR"][] = $temp; |
127 | 128 | } |
128 | 129 | } elseif ( $buffer === "\xD9" || $buffer === "\xDA" ) { |
129 | 130 | // EOI - end of image or SOS - start of scan. either way we're past any interesting segments |
— | — | @@ -162,11 +163,12 @@ |
163 | 164 | * This should generally be called by BitmapMetadataHandler::doApp13() |
164 | 165 | * |
165 | 166 | * @param String $app13 photoshop psir app13 block from jpg. |
| 167 | + * @throws MWException (It gets caught next level up though) |
166 | 168 | * @return String if the iptc hash is good or not. |
167 | 169 | */ |
168 | 170 | public static function doPSIR ( $app13 ) { |
169 | 171 | if ( !$app13 ) { |
170 | | - return; |
| 172 | + throw new MWException( "No App13 segment given" ); |
171 | 173 | } |
172 | 174 | // First compare hash with real thing |
173 | 175 | // 0x404 contains IPTC, 0x425 has hash |
— | — | @@ -218,8 +220,8 @@ |
219 | 221 | |
220 | 222 | // this should not happen, but check. |
221 | 223 | if ( $lenData['len'] + $offset > $appLen ) { |
222 | | - wfDebug( __METHOD__ . " PSIR data too long.\n" ); |
223 | | - return 'iptc-no-hash'; |
| 224 | + throw new MWException( "PSIR data too long. (item length=" . $lenData['len'] |
| 225 | + . "; offset=$offset; total length=$appLen)" ); |
224 | 226 | } |
225 | 227 | |
226 | 228 | if ( $valid ) { |