Merge "(bug 43801) add a getter for ICU version to ICUCollation"
[lhc/web/wiklou.git] / includes / media / XMP.php
index 75fdd96..e4833fc 100644 (file)
@@ -114,7 +114,7 @@ class XMPReader {
        */
        private function resetXMLParser() {
 
-               if ($this->xmlParser) {
+               if ( $this->xmlParser ) {
                        //is this needed?
                        xml_parser_free( $this->xmlParser );
                }
@@ -156,7 +156,7 @@ class XMPReader {
 
                $data = $this->results;
 
-               wfRunHooks('XMPGetResults', Array(&$data));
+               wfRunHooks( 'XMPGetResults', Array( &$data ) );
 
                if ( isset( $data['xmp-special']['AuthorsPosition'] )
                        && is_string( $data['xmp-special']['AuthorsPosition'] )
@@ -201,7 +201,7 @@ class XMPReader {
                                        // To avoid copying over the _type meta-fields.
                                        continue;
                                }
-                               foreach(  $loc as $field => $val ) {
+                               foreach( $loc as $field => $val ) {
                                        $data['xmp-general'][$field . 'Created'][] = $val;
                                }
                        }
@@ -213,10 +213,16 @@ class XMPReader {
                unset( $data['xmp-special'] );
 
                // Convert GPSAltitude to negative if below sea level.
-               if ( isset( $data['xmp-exif']['GPSAltitudeRef'] ) ) {
-                       if ( $data['xmp-exif']['GPSAltitudeRef'] == '1'
-                               && isset( $data['xmp-exif']['GPSAltitude'] )
-                       ) {
+               if ( isset( $data['xmp-exif']['GPSAltitudeRef'] )
+                       && isset( $data['xmp-exif']['GPSAltitude'] )
+               ) {
+
+                       // Must convert to a real before multiplying by -1
+                       // XMPValidate guarantees there will always be a '/' in this value.
+                       list( $nom, $denom ) = explode( '/', $data['xmp-exif']['GPSAltitude'] );
+                       $data['xmp-exif']['GPSAltitude'] = $nom / $denom;
+
+                       if ( $data['xmp-exif']['GPSAltitudeRef'] == '1' ) {
                                $data['xmp-exif']['GPSAltitude'] *= -1;
                        }
                        unset( $data['xmp-exif']['GPSAltitudeRef'] );
@@ -226,17 +232,18 @@ class XMPReader {
        }
 
        /**
-       * Main function to call to parse XMP. Use getResults to
-       * get results.
-       *
-       * Also catches any errors during processing, writes them to
-       * debug log, blanks result array and returns false.
-       *
-       * @param $content String: XMP data
-       * @param $allOfIt Boolean: If this is all the data (true) or if its split up (false). Default true
-       * @param $reset Boolean: does xml parser need to be reset. Default false
-       * @return Boolean success.
-       */
+        * Main function to call to parse XMP. Use getResults to
+        * get results.
+        *
+        * Also catches any errors during processing, writes them to
+        * debug log, blanks result array and returns false.
+        *
+        * @param $content String: XMP data
+        * @param $allOfIt Boolean: If this is all the data (true) or if its split up (false). Default true
+        * @param $reset Boolean: does xml parser need to be reset. Default false
+        * @throws MWException
+        * @return Boolean success.
+        */
        public function parse( $content, $allOfIt = true, $reset = false ) {
                if ( $reset ) {
                        $this->resetXMLParser();
@@ -248,7 +255,7 @@ class XMPReader {
                        if ( !$this->charset ) {
                                $bom = array();
                                if ( preg_match( '/\xEF\xBB\xBF|\xFE\xFF|\x00\x00\xFE\xFF|\xFF\xFE\x00\x00|\xFF\xFE/',
-                                        $content, $bom )
+                                       $content, $bom )
                                ) {
                                        switch ( $bom[0] ) {
                                                case "\xFE\xFF":
@@ -268,7 +275,7 @@ class XMPReader {
                                                        break;
                                                default:
                                                        //this should be impossible to get to
-                                                       throw new MWException("Invalid BOM");
+                                                       throw new MWException( "Invalid BOM" );
                                                        break;
 
                                        }
@@ -317,13 +324,13 @@ class XMPReader {
                $guid = substr( $content, 0, 32 );
                if ( !isset( $this->results['xmp-special']['HasExtendedXMP'] )
                        || $this->results['xmp-special']['HasExtendedXMP'] !== $guid ) {
-                       wfDebugLog('XMP', __METHOD__ . " Ignoring XMPExtended block due to wrong guid (guid= '$guid' )");
+                       wfDebugLog( 'XMP', __METHOD__ . " Ignoring XMPExtended block due to wrong guid (guid= '$guid')" );
                        return false;
                }
-               $len  = unpack( 'Nlength/Noffset', substr( $content, 32, 8 ) );
+               $len = unpack( 'Nlength/Noffset', substr( $content, 32, 8 ) );
 
-               if (!$len || $len['length'] < 4 || $len['offset'] < 0 || $len['offset'] > $len['length'] ) {
-                       wfDebugLog('XMP', __METHOD__ . 'Error reading extended XMP block, invalid length or offset.');
+               if ( !$len || $len['length'] < 4 || $len['offset'] < 0 || $len['offset'] > $len['length'] ) {
+                       wfDebugLog( 'XMP', __METHOD__ . 'Error reading extended XMP block, invalid length or offset.' );
                        return false;
                }
 
@@ -338,8 +345,8 @@ class XMPReader {
                // so the probability that it will have > 128k, and be in the wrong order is very low...
 
                if ( $len['offset'] !== $this->extendedXMPOffset ) {
-                       wfDebugLog('XMP', __METHOD__ . 'Ignoring XMPExtended block due to wrong order. (Offset was '
-                               . $len['offset'] . ' but expected ' . $this->extendedXMPOffset . ')');
+                       wfDebugLog( 'XMP', __METHOD__ . 'Ignoring XMPExtended block due to wrong order. (Offset was '
+                               . $len['offset'] . ' but expected ' . $this->extendedXMPOffset . ')' );
                        return false;
                }
 
@@ -359,7 +366,7 @@ class XMPReader {
                        $atEnd = false;
                }
 
-               wfDebugLog('XMP', __METHOD__ . 'Parsing a XMPExtended block');
+               wfDebugLog( 'XMP', __METHOD__ . 'Parsing a XMPExtended block' );
                return $this->parse( $actualContent, $atEnd );
        }
 
@@ -457,22 +464,23 @@ class XMPReader {
        }
 
        /**
-       * Hit a closing element in MODE_STRUCT, MODE_SEQ, MODE_BAG
-       * generally means we've finished processing a nested structure.
-       * resets some internal variables to indicate that.
-       *
-       * Note this means we hit the closing element not the "</rdf:Seq>".
-       *
-       * @par For example, when processing:
-       * @code{,xml}
-       * <exif:ISOSpeedRatings> <rdf:Seq> <rdf:li>64</rdf:li>
-       *   </rdf:Seq> </exif:ISOSpeedRatings>
-       * @endcode
-       *
-       * This method is called when we hit the "</exif:ISOSpeedRatings>" tag.
-       *
-       * @param $elm String namespace . space . tag name.
-       */
+        * Hit a closing element in MODE_STRUCT, MODE_SEQ, MODE_BAG
+        * generally means we've finished processing a nested structure.
+        * resets some internal variables to indicate that.
+        *
+        * Note this means we hit the closing element not the "</rdf:Seq>".
+        *
+        * @par For example, when processing:
+        * @code{,xml}
+        * <exif:ISOSpeedRatings> <rdf:Seq> <rdf:li>64</rdf:li>
+        *   </rdf:Seq> </exif:ISOSpeedRatings>
+        * @endcode
+        *
+        * This method is called when we hit the "</exif:ISOSpeedRatings>" tag.
+        *
+        * @param $elm String namespace . space . tag name.
+        * @throws MWException
+        */
        private function endElementNested( $elm ) {
 
                /* cur item must be the same as $elm, unless if in MODE_STRUCT
@@ -480,7 +488,7 @@ class XMPReader {
                if ( $this->curItem[0] !== $elm
                        && !( $elm === self::NS_RDF . ' Description'
                                && $this->mode[0] === self::MODE_STRUCT )
-                ) {
+               ) {
                        throw new MWException( "nesting mismatch. got a </$elm> but expected a </" . $this->curItem[0] . '>' );
                }
 
@@ -522,23 +530,24 @@ class XMPReader {
        }
 
        /**
-       * Hit a closing element in MODE_LI (either rdf:Seq, or rdf:Bag )
-       * Add information about what type of element this is.
-       *
-       * Note we still have to hit the outer "</property>"
-       *
-       * @par For example, when processing:
-       * @code{,xml}
-       * <exif:ISOSpeedRatings> <rdf:Seq> <rdf:li>64</rdf:li>
-       *   </rdf:Seq> </exif:ISOSpeedRatings>
-       * @endcode
-       *
-       * This method is called when we hit the "</rdf:Seq>".
-       * (For comparison, we call endElementModeSimple when we
-       * hit the "</rdf:li>")
-       *
-       * @param $elm String namespace . ' ' . element name
-       */
+        * Hit a closing element in MODE_LI (either rdf:Seq, or rdf:Bag )
+        * Add information about what type of element this is.
+        *
+        * Note we still have to hit the outer "</property>"
+        *
+        * @par For example, when processing:
+        * @code{,xml}
+        * <exif:ISOSpeedRatings> <rdf:Seq> <rdf:li>64</rdf:li>
+        *   </rdf:Seq> </exif:ISOSpeedRatings>
+        * @endcode
+        *
+        * This method is called when we hit the "</rdf:Seq>".
+        * (For comparison, we call endElementModeSimple when we
+        * hit the "</rdf:li>")
+        *
+        * @param $elm String namespace . ' ' . element name
+        * @throws MWException
+        */
        private function endElementModeLi( $elm ) {
 
                list( $ns, $tag ) = explode( ' ', $this->curItem[0], 2 );
@@ -593,17 +602,18 @@ class XMPReader {
        }
 
        /**
-       * Handler for hitting a closing element.
-       *
-       * generally just calls a helper function depending on what
-       * mode we're in.
-       *
-       * Ignores the outer wrapping elements that are optional in
-       * xmp and have no meaning.
-       *
-       * @param $parser XMLParser
-       * @param $elm String namespace . ' ' . element name
-       */
+        * Handler for hitting a closing element.
+        *
+        * generally just calls a helper function depending on what
+        * mode we're in.
+        *
+        * Ignores the outer wrapping elements that are optional in
+        * xmp and have no meaning.
+        *
+        * @param $parser XMLParser
+        * @param $elm String namespace . ' ' . element name
+        * @throws MWException
+        */
        function endElement( $parser, $elm ) {
                if ( $elm === ( self::NS_RDF . ' RDF' )
                        || $elm === 'adobe:ns:meta/ xmpmeta'
@@ -753,22 +763,23 @@ class XMPReader {
        }
 
        /**
-       * Handle an opening element when in MODE_SIMPLE
-       *
-       * This should not happen often. This is for if a simple element
-       * already opened has a child element. Could happen for a
-       * qualified element.
-       *
-       * For example:
-       * <exif:DigitalZoomRatio><rdf:Description><rdf:value>0/10</rdf:value>
-       *   <foo:someQualifier>Bar</foo:someQualifier> </rdf:Description>
-       *   </exif:DigitalZoomRatio>
-       *
-       * This method is called when processing the <rdf:Description> element
-       *
-       * @param $elm String namespace and tag names separated by space.
-       * @param $attribs Array Attributes of the element.
-       */
+        * Handle an opening element when in MODE_SIMPLE
+        *
+        * This should not happen often. This is for if a simple element
+        * already opened has a child element. Could happen for a
+        * qualified element.
+        *
+        * For example:
+        * <exif:DigitalZoomRatio><rdf:Description><rdf:value>0/10</rdf:value>
+        *   <foo:someQualifier>Bar</foo:someQualifier> </rdf:Description>
+        *   </exif:DigitalZoomRatio>
+        *
+        * This method is called when processing the <rdf:Description> element
+        *
+        * @param $elm String namespace and tag names separated by space.
+        * @param $attribs Array Attributes of the element.
+        * @throws MWException
+        */
        private function startElementModeSimple( $elm, $attribs ) {
                if ( $elm === self::NS_RDF . ' Description' ) {
                        // If this value has qualifiers
@@ -818,16 +829,17 @@ class XMPReader {
        }
 
        /**
-       * Starting an element when in MODE_INITIAL
-       * This usually happens when we hit an element inside
-       * the outer rdf:Description
-       *
-       * This is generally where most properties start.
-       *
-       * @param $ns String Namespace
-       * @param $tag String tag name (without namespace prefix)
-       * @param $attribs Array array of attributes
-       */
+        * Starting an element when in MODE_INITIAL
+        * This usually happens when we hit an element inside
+        * the outer rdf:Description
+        *
+        * This is generally where most properties start.
+        *
+        * @param $ns String Namespace
+        * @param $tag String tag name (without namespace prefix)
+        * @param $attribs Array array of attributes
+        * @throws MWException
+        */
        private function startElementModeInitial( $ns, $tag, $attribs ) {
                if ( $ns !== self::NS_RDF ) {
 
@@ -871,23 +883,24 @@ class XMPReader {
        }
 
        /**
-       * Hit an opening element when in a Struct (MODE_STRUCT)
-       * This is generally for fields of a compound property.
-       *
-       * Example of a struct (abbreviated; flash has more properties):
-       *
-       * <exif:Flash> <rdf:Description> <exif:Fired>True</exif:Fired>
-       *  <exif:Mode>1</exif:Mode></rdf:Description></exif:Flash>
-       *
-       * or:
-       *
-       * <exif:Flash rdf:parseType='Resource'> <exif:Fired>True</exif:Fired>
-       *  <exif:Mode>1</exif:Mode></exif:Flash>
-       *
-       * @param $ns String namespace
-       * @param $tag String tag name (no ns)
-       * @param $attribs Array array of attribs w/ values.
-       */
+        * Hit an opening element when in a Struct (MODE_STRUCT)
+        * This is generally for fields of a compound property.
+        *
+        * Example of a struct (abbreviated; flash has more properties):
+        *
+        * <exif:Flash> <rdf:Description> <exif:Fired>True</exif:Fired>
+        *  <exif:Mode>1</exif:Mode></rdf:Description></exif:Flash>
+        *
+        * or:
+        *
+        * <exif:Flash rdf:parseType='Resource'> <exif:Fired>True</exif:Fired>
+        *  <exif:Mode>1</exif:Mode></exif:Flash>
+        *
+        * @param $ns String namespace
+        * @param $tag String tag name (no ns)
+        * @param $attribs Array array of attribs w/ values.
+        * @throws MWException
+        */
        private function startElementModeStruct( $ns, $tag, $attribs ) {
                if ( $ns !== self::NS_RDF ) {
 
@@ -1009,14 +1022,15 @@ class XMPReader {
        }
 
        /**
-       * Hits an opening element.
-       * Generally just calls a helper based on what MODE we're in.
-       * Also does some initial set up for the wrapper element
-       *
-       * @param $parser XMLParser
-       * @param $elm String namespace "<space>" element
-       * @param $attribs Array attribute name => value
-       */
+        * Hits an opening element.
+        * Generally just calls a helper based on what MODE we're in.
+        * Also does some initial set up for the wrapper element
+        *
+        * @param $parser XMLParser
+        * @param $elm String namespace "<space>" element
+        * @param $attribs Array attribute name => value
+        * @throws MWException
+        */
        function startElement( $parser, $elm, $attribs ) {
 
                if ( $elm === self::NS_RDF . ' RDF'
@@ -1094,19 +1108,20 @@ class XMPReader {
        }
 
        /**
-       * Process attributes.
-       * Simple values can be stored as either a tag or attribute
-       *
-       * Often the initial "<rdf:Description>" tag just has all the simple
-       * properties as attributes.
-       *
-       * @par Example:
-       * @code
-       * <rdf:Description rdf:about="" xmlns:exif="http://ns.adobe.com/exif/1.0/" exif:DigitalZoomRatio="0/10">
-       * @endcode
-       *
-       * @param $attribs Array attribute=>value array.
-       */
+        * Process attributes.
+        * Simple values can be stored as either a tag or attribute
+        *
+        * Often the initial "<rdf:Description>" tag just has all the simple
+        * properties as attributes.
+        *
+        * @par Example:
+        * @code
+        * <rdf:Description rdf:about="" xmlns:exif="http://ns.adobe.com/exif/1.0/" exif:DigitalZoomRatio="0/10">
+        * @endcode
+        *
+        * @param $attribs Array attribute=>value array.
+        * @throws MWException
+        */
        private function doAttribs( $attribs ) {
 
                // first check for rdf:parseType attribute, as that can change