1 /*
   2  * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.imageio.spi;
  27 
  28 import java.io.IOException;
  29 import java.lang.reflect.Constructor;
  30 import java.lang.reflect.Method;
  31 import java.util.Arrays;
  32 import java.util.Iterator;
  33 import javax.imageio.ImageReader;
  34 import javax.imageio.metadata.IIOMetadata;
  35 import javax.imageio.metadata.IIOMetadataFormat;
  36 import javax.imageio.metadata.IIOMetadataFormatImpl;
  37 import javax.imageio.stream.ImageInputStream;
  38 
  39 /**
  40  * A superclass containing instance variables and methods common to
  41  * <code>ImageReaderSpi</code> and <code>ImageWriterSpi</code>.
  42  *
  43  * @see IIORegistry
  44  * @see ImageReaderSpi
  45  * @see ImageWriterSpi
  46  *
  47  */
  48 public abstract class ImageReaderWriterSpi extends IIOServiceProvider {
  49 
  50     /**
  51      * An array of strings to be returned from
  52      * <code>getFormatNames</code>, initially <code>null</code>.
  53      * Constructors should set this to a non-<code>null</code> value.
  54      */
  55     protected String[] names = null;
  56 
  57     /**
  58      * An array of strings to be returned from
  59      * <code>getFileSuffixes</code>, initially <code>null</code>.
  60      */
  61     protected String[] suffixes = null;
  62 
  63     /**
  64      * An array of strings to be returned from
  65      * <code>getMIMETypes</code>, initially <code>null</code>.
  66      */
  67     protected String[] MIMETypes = null;
  68 
  69     /**
  70      * A <code>String</code> containing the name of the associated
  71      * plug-in class, initially <code>null</code>.
  72      */
  73     protected String pluginClassName = null;
  74 
  75     /**
  76      * A boolean indicating whether this plug-in supports the
  77      * standard metadata format for stream metadata, initially
  78      * <code>false</code>.
  79      */
  80     protected boolean supportsStandardStreamMetadataFormat = false;
  81 
  82     /**
  83      * A <code>String</code> containing the name of the native stream
  84      * metadata format supported by this plug-in, initially
  85      * <code>null</code>.
  86      */
  87     protected String nativeStreamMetadataFormatName = null;
  88 
  89     /**
  90      * A <code>String</code> containing the class name of the native
  91      * stream metadata format supported by this plug-in, initially
  92      * <code>null</code>.
  93      */
  94     protected String nativeStreamMetadataFormatClassName = null;
  95 
  96     /**
  97      * An array of <code>String</code>s containing the names of any
  98      * additional stream metadata formats supported by this plug-in,
  99      * initially <code>null</code>.
 100      */
 101     protected String[] extraStreamMetadataFormatNames = null;
 102 
 103     /**
 104      * An array of <code>String</code>s containing the class names of
 105      * any additional stream metadata formats supported by this plug-in,
 106      * initially <code>null</code>.
 107      */
 108     protected String[] extraStreamMetadataFormatClassNames = null;
 109 
 110     /**
 111      * A boolean indicating whether this plug-in supports the
 112      * standard metadata format for image metadata, initially
 113      * <code>false</code>.
 114      */
 115     protected boolean supportsStandardImageMetadataFormat = false;
 116 
 117     /**
 118      * A <code>String</code> containing the name of the
 119      * native stream metadata format supported by this plug-in,
 120      * initially <code>null</code>.
 121      */
 122     protected String nativeImageMetadataFormatName = null;
 123 
 124     /**
 125      * A <code>String</code> containing the class name of the
 126      * native stream metadata format supported by this plug-in,
 127      * initially <code>null</code>.
 128      */
 129     protected String nativeImageMetadataFormatClassName = null;
 130 
 131     /**
 132      * An array of <code>String</code>s containing the names of any
 133      * additional image metadata formats supported by this plug-in,
 134      * initially <code>null</code>.
 135      */
 136     protected String[] extraImageMetadataFormatNames = null;
 137 
 138     /**
 139      * An array of <code>String</code>s containing the class names of
 140      * any additional image metadata formats supported by this
 141      * plug-in, initially <code>null</code>.
 142      */
 143     protected String[] extraImageMetadataFormatClassNames = null;
 144 
 145     /**
 146      * Constructs an <code>ImageReaderWriterSpi</code> with a given
 147      * set of values.
 148      *
 149      * @param vendorName the vendor name, as a non-<code>null</code>
 150      * <code>String</code>.
 151      * @param version a version identifier, as a non-<code>null</code>
 152      * <code>String</code>.
 153      * @param names a non-<code>null</code> array of
 154      * <code>String</code>s indicating the format names.  At least one
 155      * entry must be present.
 156      * @param suffixes an array of <code>String</code>s indicating the
 157      * common file suffixes.  If no suffixes are defined,
 158      * <code>null</code> should be supplied.  An array of length 0
 159      * will be normalized to <code>null</code>.
 160      * @param MIMETypes an array of <code>String</code>s indicating
 161      * the format's MIME types.  If no MIME types are defined,
 162      * <code>null</code> should be supplied.  An array of length 0
 163      * will be normalized to <code>null</code>.
 164      * @param pluginClassName the fully-qualified name of the
 165      * associated <code>ImageReader</code> or <code>ImageWriter</code>
 166      * class, as a non-<code>null</code> <code>String</code>.
 167      * @param supportsStandardStreamMetadataFormat a
 168      * <code>boolean</code> that indicates whether a stream metadata
 169      * object can use trees described by the standard metadata format.
 170      * @param nativeStreamMetadataFormatName a
 171      * <code>String</code>, or <code>null</code>, to be returned from
 172      * <code>getNativeStreamMetadataFormatName</code>.
 173      * @param nativeStreamMetadataFormatClassName a
 174      * <code>String</code>, or <code>null</code>, to be used to instantiate
 175      * a metadata format object to be returned from
 176      * <code>getNativeStreamMetadataFormat</code>.
 177      * @param extraStreamMetadataFormatNames an array of
 178      * <code>String</code>s, or <code>null</code>, to be returned from
 179      * <code>getExtraStreamMetadataFormatNames</code>.  An array of length
 180      * 0 is normalized to <code>null</code>.
 181      * @param extraStreamMetadataFormatClassNames an array of
 182      * <code>String</code>s, or <code>null</code>, to be used to instantiate
 183      * a metadata format object to be returned from
 184      * <code>getStreamMetadataFormat</code>.  An array of length
 185      * 0 is normalized to <code>null</code>.
 186      * @param supportsStandardImageMetadataFormat a
 187      * <code>boolean</code> that indicates whether an image metadata
 188      * object can use trees described by the standard metadata format.
 189      * @param nativeImageMetadataFormatName a
 190      * <code>String</code>, or <code>null</code>, to be returned from
 191      * <code>getNativeImageMetadataFormatName</code>.
 192      * @param nativeImageMetadataFormatClassName a
 193      * <code>String</code>, or <code>null</code>, to be used to instantiate
 194      * a metadata format object to be returned from
 195      * <code>getNativeImageMetadataFormat</code>.
 196      * @param extraImageMetadataFormatNames an array of
 197      * <code>String</code>s to be returned from
 198      * <code>getExtraImageMetadataFormatNames</code>.  An array of length 0
 199      * is normalized to <code>null</code>.
 200      * @param extraImageMetadataFormatClassNames an array of
 201      * <code>String</code>s, or <code>null</code>, to be used to instantiate
 202      * a metadata format object to be returned from
 203      * <code>getImageMetadataFormat</code>.  An array of length
 204      * 0 is normalized to <code>null</code>.
 205      *
 206      * @exception IllegalArgumentException if <code>vendorName</code>
 207      * is <code>null</code>.
 208      * @exception IllegalArgumentException if <code>version</code>
 209      * is <code>null</code>.
 210      * @exception IllegalArgumentException if <code>names</code>
 211      * is <code>null</code> or has length 0.
 212      * @exception IllegalArgumentException if <code>pluginClassName</code>
 213      * is <code>null</code>.
 214      */
 215     public ImageReaderWriterSpi(String vendorName,
 216                                 String version,
 217                                 String[] names,
 218                                 String[] suffixes,
 219                                 String[] MIMETypes,
 220                                 String pluginClassName,
 221                                 boolean supportsStandardStreamMetadataFormat,
 222                                 String nativeStreamMetadataFormatName,
 223                                 String nativeStreamMetadataFormatClassName,
 224                                 String[] extraStreamMetadataFormatNames,
 225                                 String[] extraStreamMetadataFormatClassNames,
 226                                 boolean supportsStandardImageMetadataFormat,
 227                                 String nativeImageMetadataFormatName,
 228                                 String nativeImageMetadataFormatClassName,
 229                                 String[] extraImageMetadataFormatNames,
 230                                 String[] extraImageMetadataFormatClassNames) {
 231         super(vendorName, version);
 232         if (names == null) {
 233             throw new IllegalArgumentException("names == null!");
 234         }
 235         if (names.length == 0) {
 236             throw new IllegalArgumentException("names.length == 0!");
 237         }
 238         if (pluginClassName == null) {
 239             throw new IllegalArgumentException("pluginClassName == null!");
 240         }
 241 
 242         this.names = names.clone();
 243         // If length == 0, leave it null
 244         if (suffixes != null && suffixes.length > 0) {
 245             this.suffixes = suffixes.clone();
 246         }
 247         // If length == 0, leave it null
 248         if (MIMETypes != null && MIMETypes.length > 0) {
 249             this.MIMETypes = MIMETypes.clone();
 250         }
 251         this.pluginClassName = pluginClassName;
 252 
 253         this.supportsStandardStreamMetadataFormat =
 254             supportsStandardStreamMetadataFormat;
 255         this.nativeStreamMetadataFormatName = nativeStreamMetadataFormatName;
 256         this.nativeStreamMetadataFormatClassName =
 257             nativeStreamMetadataFormatClassName;
 258         // If length == 0, leave it null
 259         if (extraStreamMetadataFormatNames != null &&
 260             extraStreamMetadataFormatNames.length > 0) {
 261             this.extraStreamMetadataFormatNames =
 262                 extraStreamMetadataFormatNames.clone();
 263         }
 264         // If length == 0, leave it null
 265         if (extraStreamMetadataFormatClassNames != null &&
 266             extraStreamMetadataFormatClassNames.length > 0) {
 267             this.extraStreamMetadataFormatClassNames =
 268                 extraStreamMetadataFormatClassNames.clone();
 269         }
 270         this.supportsStandardImageMetadataFormat =
 271             supportsStandardImageMetadataFormat;
 272         this.nativeImageMetadataFormatName = nativeImageMetadataFormatName;
 273         this.nativeImageMetadataFormatClassName =
 274             nativeImageMetadataFormatClassName;
 275         // If length == 0, leave it null
 276         if (extraImageMetadataFormatNames != null &&
 277             extraImageMetadataFormatNames.length > 0) {
 278             this.extraImageMetadataFormatNames =
 279                 extraImageMetadataFormatNames.clone();
 280         }
 281         // If length == 0, leave it null
 282         if (extraImageMetadataFormatClassNames != null &&
 283             extraImageMetadataFormatClassNames.length > 0) {
 284             this.extraImageMetadataFormatClassNames =
 285                 extraImageMetadataFormatClassNames.clone();
 286         }
 287     }
 288 
 289     /**
 290      * Constructs a blank <code>ImageReaderWriterSpi</code>.  It is up
 291      * to the subclass to initialize instance variables and/or
 292      * override method implementations in order to provide working
 293      * versions of all methods.
 294      */
 295     public ImageReaderWriterSpi() {
 296     }
 297 
 298     /**
 299      * Returns an array of <code>String</code>s containing
 300      * human-readable names for the formats that are generally usable
 301      * by the <code>ImageReader</code> or <code>ImageWriter</code>
 302      * implementation associated with this service provider.  For
 303      * example, a single <code>ImageReader</code> might be able to
 304      * process both PBM and PNM files.
 305      *
 306      * @return a non-<code>null</code> array of <code>String</code>s
 307      * or length at least 1 containing informal format names
 308      * associated with this reader or writer.
 309      */
 310     public String[] getFormatNames() {
 311         return names.clone();
 312     }
 313 
 314     /**
 315      * Returns an array of <code>String</code>s containing a list of
 316      * file suffixes associated with the formats that are generally
 317      * usable by the <code>ImageReader</code> or
 318      * <code>ImageWriter</code> implementation associated with this
 319      * service provider.  For example, a single
 320      * <code>ImageReader</code> might be able to process files with
 321      * '.pbm' and '.pnm' suffixes, or both '.jpg' and '.jpeg'
 322      * suffixes.  If there are no known file suffixes,
 323      * <code>null</code> will be returned.
 324      *
 325      * <p> Returning a particular suffix does not guarantee that files
 326      * with that suffix can be processed; it merely indicates that it
 327      * may be worthwhile attempting to decode or encode such files
 328      * using this service provider.
 329      *
 330      * @return an array of <code>String</code>s or length at least 1
 331      * containing common file suffixes associated with this reader or
 332      * writer, or <code>null</code>.
 333      */
 334     public String[] getFileSuffixes() {
 335         return suffixes == null ? null : suffixes.clone();
 336     }
 337 
 338     /**
 339      * Returns an array of <code>String</code>s containing a list of
 340      * MIME types associated with the formats that are generally
 341      * usable by the <code>ImageReader</code> or
 342      * <code>ImageWriter</code> implementation associated with this
 343      * service provider.
 344      *
 345      * <p> Ideally, only a single MIME type would be required in order
 346      * to describe a particular format.  However, for several reasons
 347      * it is necessary to associate a list of types with each service
 348      * provider.  First, many common image file formats do not have
 349      * standard MIME types, so a list of commonly used unofficial
 350      * names will be required, such as <code>image/x-pbm</code> and
 351      * <code>image/x-portable-bitmap</code>.  Some file formats have
 352      * official MIME types but may sometimes be referred to using
 353      * their previous unofficial designations, such as
 354      * <code>image/x-png</code> instead of the official
 355      * <code>image/png</code>.  Finally, a single service provider may
 356      * be capable of parsing multiple distinct types from the MIME
 357      * point of view, for example <code>image/x-xbitmap</code> and
 358      * <code>image/x-xpixmap</code>.
 359      *
 360      * <p> Returning a particular MIME type does not guarantee that
 361      * files claiming to be of that type can be processed; it merely
 362      * indicates that it may be worthwhile attempting to decode or
 363      * encode such files using this service provider.
 364      *
 365      * @return an array of <code>String</code>s or length at least 1
 366      * containing MIME types associated with this reader or writer, or
 367      * <code>null</code>.
 368      */
 369     public String[] getMIMETypes() {
 370         return MIMETypes == null ? null : MIMETypes.clone();
 371     }
 372 
 373     /**
 374      * Returns the fully-qualified class name of the
 375      * <code>ImageReader</code> or <code>ImageWriter</code> plug-in
 376      * associated with this service provider.
 377      *
 378      * @return the class name, as a non-<code>null</code>
 379      * <code>String</code>.
 380      */
 381     public String getPluginClassName() {
 382         return pluginClassName;
 383     }
 384 
 385     /**
 386      * Returns <code>true</code> if the standard metadata format is
 387      * among the document formats recognized by the
 388      * <code>getAsTree</code> and <code>setFromTree</code> methods on
 389      * the stream metadata objects produced or consumed by this
 390      * plug-in.
 391      *
 392      * @return <code>true</code> if the standard format is supported
 393      * for stream metadata.
 394      */
 395     public boolean isStandardStreamMetadataFormatSupported() {
 396         return supportsStandardStreamMetadataFormat;
 397     }
 398 
 399     /**
 400      * Returns the name of the "native" stream metadata format for
 401      * this plug-in, which typically allows for lossless encoding and
 402      * transmission of the stream metadata stored in the format handled by
 403      * this plug-in.  If no such format is supported,
 404      * <code>null</code>will be returned.
 405      *
 406      * <p> The default implementation returns the
 407      * <code>nativeStreamMetadataFormatName</code> instance variable,
 408      * which is typically set by the constructor.
 409      *
 410      * @return the name of the native stream metadata format, or
 411      * <code>null</code>.
 412      *
 413      */
 414     public String getNativeStreamMetadataFormatName() {
 415         return nativeStreamMetadataFormatName;
 416     }
 417 
 418     /**
 419      * Returns an array of <code>String</code>s containing the names
 420      * of additional document formats, other than the native and
 421      * standard formats, recognized by the
 422      * <code>getAsTree</code> and <code>setFromTree</code> methods on
 423      * the stream metadata objects produced or consumed by this
 424      * plug-in.
 425      *
 426      * <p> If the plug-in does not handle metadata, null should be
 427      * returned.
 428      *
 429      * <p> The set of formats may differ according to the particular
 430      * images being read or written; this method should indicate all
 431      * the additional formats supported by the plug-in under any
 432      * circumstances.
 433      *
 434      * <p> The default implementation returns a clone of the
 435      * <code>extraStreamMetadataFormatNames</code> instance variable,
 436      * which is typically set by the constructor.
 437      *
 438      * @return an array of <code>String</code>s, or null.
 439      *
 440      * @see IIOMetadata#getMetadataFormatNames
 441      * @see #getExtraImageMetadataFormatNames
 442      * @see #getNativeStreamMetadataFormatName
 443      */
 444     public String[] getExtraStreamMetadataFormatNames() {
 445         return extraStreamMetadataFormatNames == null ?
 446             null : extraStreamMetadataFormatNames.clone();
 447     }
 448 
 449     /**
 450      * Returns <code>true</code> if the standard metadata format is
 451      * among the document formats recognized by the
 452      * <code>getAsTree</code> and <code>setFromTree</code> methods on
 453      * the image metadata objects produced or consumed by this
 454      * plug-in.
 455      *
 456      * @return <code>true</code> if the standard format is supported
 457      * for image metadata.
 458      */
 459     public boolean isStandardImageMetadataFormatSupported() {
 460         return supportsStandardImageMetadataFormat;
 461     }
 462 
 463     /**
 464      * Returns the name of the "native" image metadata format for
 465      * this plug-in, which typically allows for lossless encoding and
 466      * transmission of the image metadata stored in the format handled by
 467      * this plug-in.  If no such format is supported,
 468      * <code>null</code>will be returned.
 469      *
 470      * <p> The default implementation returns the
 471      * <code>nativeImageMetadataFormatName</code> instance variable,
 472      * which is typically set by the constructor.
 473      *
 474      * @return the name of the native image metadata format, or
 475      * <code>null</code>.
 476      *
 477      * @see #getExtraImageMetadataFormatNames
 478      */
 479     public String getNativeImageMetadataFormatName() {
 480         return nativeImageMetadataFormatName;
 481     }
 482 
 483     /**
 484      * Returns an array of <code>String</code>s containing the names
 485      * of additional document formats, other than the native and
 486      * standard formats, recognized by the
 487      * <code>getAsTree</code> and <code>setFromTree</code> methods on
 488      * the image metadata objects produced or consumed by this
 489      * plug-in.
 490      *
 491      * <p> If the plug-in does not handle image metadata, null should
 492      * be returned.
 493      *
 494      * <p> The set of formats may differ according to the particular
 495      * images being read or written; this method should indicate all
 496      * the additional formats supported by the plug-in under any circumstances.
 497      *
 498      * <p> The default implementation returns a clone of the
 499      * <code>extraImageMetadataFormatNames</code> instance variable,
 500      * which is typically set by the constructor.
 501      *
 502      * @return an array of <code>String</code>s, or null.
 503      *
 504      * @see IIOMetadata#getMetadataFormatNames
 505      * @see #getExtraStreamMetadataFormatNames
 506      * @see #getNativeImageMetadataFormatName
 507      */
 508     public String[] getExtraImageMetadataFormatNames() {
 509         return extraImageMetadataFormatNames == null ?
 510             null : extraImageMetadataFormatNames.clone();
 511     }
 512 
 513     /**
 514      * Returns an <code>IIOMetadataFormat</code> object describing the
 515      * given stream metadata format, or <code>null</code> if no
 516      * description is available.  The supplied name must be the native
 517      * stream metadata format name, the standard metadata format name,
 518      * or one of those returned by
 519      * <code>getExtraStreamMetadataFormatNames</code>.
 520      *
 521      * @param formatName the desired stream metadata format.
 522      *
 523      * @return an <code>IIOMetadataFormat</code> object.
 524      *
 525      * @exception IllegalArgumentException if <code>formatName</code>
 526      * is <code>null</code> or is not a supported name.
 527      */
 528     public IIOMetadataFormat getStreamMetadataFormat(String formatName) {
 529         return getMetadataFormat(formatName,
 530                                  supportsStandardStreamMetadataFormat,
 531                                  nativeStreamMetadataFormatName,
 532                                  nativeStreamMetadataFormatClassName,
 533                                  extraStreamMetadataFormatNames,
 534                                  extraStreamMetadataFormatClassNames);
 535     }
 536 
 537     /**
 538      * Returns an <code>IIOMetadataFormat</code> object describing the
 539      * given image metadata format, or <code>null</code> if no
 540      * description is available.  The supplied name must be the native
 541      * iamge metadata format name, the standard metadata format name,
 542      * or one of those returned by
 543      * <code>getExtraImageMetadataFormatNames</code>.
 544      *
 545      * @param formatName the desired image metadata format.
 546      *
 547      * @return an <code>IIOMetadataFormat</code> object.
 548      *
 549      * @exception IllegalArgumentException if <code>formatName</code>
 550      * is <code>null</code> or is not a supported name.
 551      */
 552     public IIOMetadataFormat getImageMetadataFormat(String formatName) {
 553         return getMetadataFormat(formatName,
 554                                  supportsStandardImageMetadataFormat,
 555                                  nativeImageMetadataFormatName,
 556                                  nativeImageMetadataFormatClassName,
 557                                  extraImageMetadataFormatNames,
 558                                  extraImageMetadataFormatClassNames);
 559     }
 560 
 561     private IIOMetadataFormat getMetadataFormat(String formatName,
 562                                                 boolean supportsStandard,
 563                                                 String nativeName,
 564                                                 String nativeClassName,
 565                                                 String [] extraNames,
 566                                                 String [] extraClassNames) {
 567         if (formatName == null) {
 568             throw new IllegalArgumentException("formatName == null!");
 569         }
 570         if (supportsStandard && formatName.equals
 571                 (IIOMetadataFormatImpl.standardMetadataFormatName)) {
 572 
 573             return IIOMetadataFormatImpl.getStandardFormatInstance();
 574         }
 575         String formatClassName = null;
 576         if (formatName.equals(nativeName)) {
 577             formatClassName = nativeClassName;
 578         } else if (extraNames != null) {
 579             for (int i = 0; i < extraNames.length; i++) {
 580                 if (formatName.equals(extraNames[i])) {
 581                     formatClassName = extraClassNames[i];
 582                     break;  // out of for
 583                 }
 584             }
 585         }
 586         if (formatClassName == null) {
 587             throw new IllegalArgumentException("Unsupported format name");
 588         }
 589         try {
 590             Class cls = Class.forName(formatClassName, true,
 591                                       ClassLoader.getSystemClassLoader());
 592             Method meth = cls.getMethod("getInstance");
 593             return (IIOMetadataFormat) meth.invoke(null);
 594         } catch (Exception e) {
 595             RuntimeException ex =
 596                 new IllegalStateException ("Can't obtain format");
 597             ex.initCause(e);
 598             throw ex;
 599         }
 600     }
 601 }