1 /*
   2  * Copyright (c) 1997, 2013, 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 /*
  27  **********************************************************************
  28  **********************************************************************
  29  **********************************************************************
  30  *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
  31  *** As  an unpublished  work pursuant to Title 17 of the United    ***
  32  *** States Code.  All rights reserved.                             ***
  33  **********************************************************************
  34  **********************************************************************
  35  **********************************************************************/
  36 
  37 package java.awt.color;
  38 
  39 import sun.java2d.cmm.PCMM;
  40 import sun.java2d.cmm.CMSManager;
  41 import sun.java2d.cmm.Profile;
  42 import sun.java2d.cmm.ProfileDataVerifier;
  43 import sun.java2d.cmm.ProfileDeferralMgr;
  44 import sun.java2d.cmm.ProfileDeferralInfo;
  45 import sun.java2d.cmm.ProfileActivator;
  46 
  47 import java.io.File;
  48 import java.io.FileInputStream;
  49 import java.io.FileNotFoundException;
  50 import java.io.FileOutputStream;
  51 import java.io.FilePermission;
  52 import java.io.IOException;
  53 import java.io.InputStream;
  54 import java.io.ObjectInputStream;
  55 import java.io.ObjectOutputStream;
  56 import java.io.ObjectStreamException;
  57 import java.io.OutputStream;
  58 import java.io.Serializable;
  59 
  60 import java.util.StringTokenizer;
  61 
  62 import java.security.AccessController;
  63 import java.security.PrivilegedAction;
  64 
  65 
  66 /**
  67  * A representation of color profile data for device independent and
  68  * device dependent color spaces based on the International Color
  69  * Consortium Specification ICC.1:2001-12, File Format for Color Profiles,
  70  * (see <A href="http://www.color.org"> http://www.color.org</A>).
  71  * <p>
  72  * An ICC_ColorSpace object can be constructed from an appropriate
  73  * ICC_Profile.
  74  * Typically, an ICC_ColorSpace would be associated with an ICC
  75  * Profile which is either an input, display, or output profile (see
  76  * the ICC specification).  There are also device link, abstract,
  77  * color space conversion, and named color profiles.  These are less
  78  * useful for tagging a color or image, but are useful for other
  79  * purposes (in particular device link profiles can provide improved
  80  * performance for converting from one device's color space to
  81  * another's).
  82  * <p>
  83  * ICC Profiles represent transformations from the color space of
  84  * the profile (e.g. a monitor) to a Profile Connection Space (PCS).
  85  * Profiles of interest for tagging images or colors have a PCS
  86  * which is one of the two specific device independent
  87  * spaces (one CIEXYZ space and one CIELab space) defined in the
  88  * ICC Profile Format Specification.  Most profiles of interest
  89  * either have invertible transformations or explicitly specify
  90  * transformations going both directions.
  91  * @see ICC_ColorSpace
  92  */
  93 
  94 
  95 public class ICC_Profile implements Serializable {
  96 
  97     private static final long serialVersionUID = -3938515861990936766L;
  98 
  99     private transient Profile cmmProfile;
 100 
 101     private transient ProfileDeferralInfo deferralInfo;
 102     private transient ProfileActivator profileActivator;
 103 
 104     // Registry of singleton profile objects for specific color spaces
 105     // defined in the ColorSpace class (e.g. CS_sRGB), see
 106     // getInstance(int cspace) factory method.
 107     private static ICC_Profile sRGBprofile;
 108     private static ICC_Profile XYZprofile;
 109     private static ICC_Profile PYCCprofile;
 110     private static ICC_Profile GRAYprofile;
 111     private static ICC_Profile LINEAR_RGBprofile;
 112 
 113 
 114     /**
 115      * Profile class is input.
 116      */
 117     public static final int CLASS_INPUT = 0;
 118 
 119     /**
 120      * Profile class is display.
 121      */
 122     public static final int CLASS_DISPLAY = 1;
 123 
 124     /**
 125      * Profile class is output.
 126      */
 127     public static final int CLASS_OUTPUT = 2;
 128 
 129     /**
 130      * Profile class is device link.
 131      */
 132     public static final int CLASS_DEVICELINK = 3;
 133 
 134     /**
 135      * Profile class is color space conversion.
 136      */
 137     public static final int CLASS_COLORSPACECONVERSION = 4;
 138 
 139     /**
 140      * Profile class is abstract.
 141      */
 142     public static final int CLASS_ABSTRACT = 5;
 143 
 144     /**
 145      * Profile class is named color.
 146      */
 147     public static final int CLASS_NAMEDCOLOR = 6;
 148 
 149 
 150     /**
 151      * ICC Profile Color Space Type Signature: 'XYZ '.
 152      */
 153     public static final int icSigXYZData        = 0x58595A20;    /* 'XYZ ' */
 154 
 155     /**
 156      * ICC Profile Color Space Type Signature: 'Lab '.
 157      */
 158     public static final int icSigLabData        = 0x4C616220;    /* 'Lab ' */
 159 
 160     /**
 161      * ICC Profile Color Space Type Signature: 'Luv '.
 162      */
 163     public static final int icSigLuvData        = 0x4C757620;    /* 'Luv ' */
 164 
 165     /**
 166      * ICC Profile Color Space Type Signature: 'YCbr'.
 167      */
 168     public static final int icSigYCbCrData        = 0x59436272;    /* 'YCbr' */
 169 
 170     /**
 171      * ICC Profile Color Space Type Signature: 'Yxy '.
 172      */
 173     public static final int icSigYxyData        = 0x59787920;    /* 'Yxy ' */
 174 
 175     /**
 176      * ICC Profile Color Space Type Signature: 'RGB '.
 177      */
 178     public static final int icSigRgbData        = 0x52474220;    /* 'RGB ' */
 179 
 180     /**
 181      * ICC Profile Color Space Type Signature: 'GRAY'.
 182      */
 183     public static final int icSigGrayData        = 0x47524159;    /* 'GRAY' */
 184 
 185     /**
 186      * ICC Profile Color Space Type Signature: 'HSV'.
 187      */
 188     public static final int icSigHsvData        = 0x48535620;    /* 'HSV ' */
 189 
 190     /**
 191      * ICC Profile Color Space Type Signature: 'HLS'.
 192      */
 193     public static final int icSigHlsData        = 0x484C5320;    /* 'HLS ' */
 194 
 195     /**
 196      * ICC Profile Color Space Type Signature: 'CMYK'.
 197      */
 198     public static final int icSigCmykData        = 0x434D594B;    /* 'CMYK' */
 199 
 200     /**
 201      * ICC Profile Color Space Type Signature: 'CMY '.
 202      */
 203     public static final int icSigCmyData        = 0x434D5920;    /* 'CMY ' */
 204 
 205     /**
 206      * ICC Profile Color Space Type Signature: '2CLR'.
 207      */
 208     public static final int icSigSpace2CLR        = 0x32434C52;    /* '2CLR' */
 209 
 210     /**
 211      * ICC Profile Color Space Type Signature: '3CLR'.
 212      */
 213     public static final int icSigSpace3CLR        = 0x33434C52;    /* '3CLR' */
 214 
 215     /**
 216      * ICC Profile Color Space Type Signature: '4CLR'.
 217      */
 218     public static final int icSigSpace4CLR        = 0x34434C52;    /* '4CLR' */
 219 
 220     /**
 221      * ICC Profile Color Space Type Signature: '5CLR'.
 222      */
 223     public static final int icSigSpace5CLR        = 0x35434C52;    /* '5CLR' */
 224 
 225     /**
 226      * ICC Profile Color Space Type Signature: '6CLR'.
 227      */
 228     public static final int icSigSpace6CLR        = 0x36434C52;    /* '6CLR' */
 229 
 230     /**
 231      * ICC Profile Color Space Type Signature: '7CLR'.
 232      */
 233     public static final int icSigSpace7CLR        = 0x37434C52;    /* '7CLR' */
 234 
 235     /**
 236      * ICC Profile Color Space Type Signature: '8CLR'.
 237      */
 238     public static final int icSigSpace8CLR        = 0x38434C52;    /* '8CLR' */
 239 
 240     /**
 241      * ICC Profile Color Space Type Signature: '9CLR'.
 242      */
 243     public static final int icSigSpace9CLR        = 0x39434C52;    /* '9CLR' */
 244 
 245     /**
 246      * ICC Profile Color Space Type Signature: 'ACLR'.
 247      */
 248     public static final int icSigSpaceACLR        = 0x41434C52;    /* 'ACLR' */
 249 
 250     /**
 251      * ICC Profile Color Space Type Signature: 'BCLR'.
 252      */
 253     public static final int icSigSpaceBCLR        = 0x42434C52;    /* 'BCLR' */
 254 
 255     /**
 256      * ICC Profile Color Space Type Signature: 'CCLR'.
 257      */
 258     public static final int icSigSpaceCCLR        = 0x43434C52;    /* 'CCLR' */
 259 
 260     /**
 261      * ICC Profile Color Space Type Signature: 'DCLR'.
 262      */
 263     public static final int icSigSpaceDCLR        = 0x44434C52;    /* 'DCLR' */
 264 
 265     /**
 266      * ICC Profile Color Space Type Signature: 'ECLR'.
 267      */
 268     public static final int icSigSpaceECLR        = 0x45434C52;    /* 'ECLR' */
 269 
 270     /**
 271      * ICC Profile Color Space Type Signature: 'FCLR'.
 272      */
 273     public static final int icSigSpaceFCLR        = 0x46434C52;    /* 'FCLR' */
 274 
 275 
 276     /**
 277      * ICC Profile Class Signature: 'scnr'.
 278      */
 279     public static final int icSigInputClass       = 0x73636E72;    /* 'scnr' */
 280 
 281     /**
 282      * ICC Profile Class Signature: 'mntr'.
 283      */
 284     public static final int icSigDisplayClass     = 0x6D6E7472;    /* 'mntr' */
 285 
 286     /**
 287      * ICC Profile Class Signature: 'prtr'.
 288      */
 289     public static final int icSigOutputClass      = 0x70727472;    /* 'prtr' */
 290 
 291     /**
 292      * ICC Profile Class Signature: 'link'.
 293      */
 294     public static final int icSigLinkClass        = 0x6C696E6B;    /* 'link' */
 295 
 296     /**
 297      * ICC Profile Class Signature: 'abst'.
 298      */
 299     public static final int icSigAbstractClass    = 0x61627374;    /* 'abst' */
 300 
 301     /**
 302      * ICC Profile Class Signature: 'spac'.
 303      */
 304     public static final int icSigColorSpaceClass  = 0x73706163;    /* 'spac' */
 305 
 306     /**
 307      * ICC Profile Class Signature: 'nmcl'.
 308      */
 309     public static final int icSigNamedColorClass  = 0x6e6d636c;    /* 'nmcl' */
 310 
 311 
 312     /**
 313      * ICC Profile Rendering Intent: Perceptual.
 314      */
 315     public static final int icPerceptual            = 0;
 316 
 317     /**
 318      * ICC Profile Rendering Intent: RelativeColorimetric.
 319      */
 320     public static final int icRelativeColorimetric    = 1;
 321 
 322     /**
 323      * ICC Profile Rendering Intent: Media-RelativeColorimetric.
 324      * @since 1.5
 325      */
 326     public static final int icMediaRelativeColorimetric = 1;
 327 
 328     /**
 329      * ICC Profile Rendering Intent: Saturation.
 330      */
 331     public static final int icSaturation            = 2;
 332 
 333     /**
 334      * ICC Profile Rendering Intent: AbsoluteColorimetric.
 335      */
 336     public static final int icAbsoluteColorimetric    = 3;
 337 
 338     /**
 339      * ICC Profile Rendering Intent: ICC-AbsoluteColorimetric.
 340      * @since 1.5
 341      */
 342     public static final int icICCAbsoluteColorimetric = 3;
 343 
 344 
 345     /**
 346      * ICC Profile Tag Signature: 'head' - special.
 347      */
 348     public static final int icSigHead      = 0x68656164; /* 'head' - special */
 349 
 350     /**
 351      * ICC Profile Tag Signature: 'A2B0'.
 352      */
 353     public static final int icSigAToB0Tag         = 0x41324230;    /* 'A2B0' */
 354 
 355     /**
 356      * ICC Profile Tag Signature: 'A2B1'.
 357      */
 358     public static final int icSigAToB1Tag         = 0x41324231;    /* 'A2B1' */
 359 
 360     /**
 361      * ICC Profile Tag Signature: 'A2B2'.
 362      */
 363     public static final int icSigAToB2Tag         = 0x41324232;    /* 'A2B2' */
 364 
 365     /**
 366      * ICC Profile Tag Signature: 'bXYZ'.
 367      */
 368     public static final int icSigBlueColorantTag  = 0x6258595A;    /* 'bXYZ' */
 369 
 370     /**
 371      * ICC Profile Tag Signature: 'bXYZ'.
 372      * @since 1.5
 373      */
 374     public static final int icSigBlueMatrixColumnTag = 0x6258595A; /* 'bXYZ' */
 375 
 376     /**
 377      * ICC Profile Tag Signature: 'bTRC'.
 378      */
 379     public static final int icSigBlueTRCTag       = 0x62545243;    /* 'bTRC' */
 380 
 381     /**
 382      * ICC Profile Tag Signature: 'B2A0'.
 383      */
 384     public static final int icSigBToA0Tag         = 0x42324130;    /* 'B2A0' */
 385 
 386     /**
 387      * ICC Profile Tag Signature: 'B2A1'.
 388      */
 389     public static final int icSigBToA1Tag         = 0x42324131;    /* 'B2A1' */
 390 
 391     /**
 392      * ICC Profile Tag Signature: 'B2A2'.
 393      */
 394     public static final int icSigBToA2Tag         = 0x42324132;    /* 'B2A2' */
 395 
 396     /**
 397      * ICC Profile Tag Signature: 'calt'.
 398      */
 399     public static final int icSigCalibrationDateTimeTag = 0x63616C74;
 400                                                                    /* 'calt' */
 401 
 402     /**
 403      * ICC Profile Tag Signature: 'targ'.
 404      */
 405     public static final int icSigCharTargetTag    = 0x74617267;    /* 'targ' */
 406 
 407     /**
 408      * ICC Profile Tag Signature: 'cprt'.
 409      */
 410     public static final int icSigCopyrightTag     = 0x63707274;    /* 'cprt' */
 411 
 412     /**
 413      * ICC Profile Tag Signature: 'crdi'.
 414      */
 415     public static final int icSigCrdInfoTag       = 0x63726469;    /* 'crdi' */
 416 
 417     /**
 418      * ICC Profile Tag Signature: 'dmnd'.
 419      */
 420     public static final int icSigDeviceMfgDescTag = 0x646D6E64;    /* 'dmnd' */
 421 
 422     /**
 423      * ICC Profile Tag Signature: 'dmdd'.
 424      */
 425     public static final int icSigDeviceModelDescTag = 0x646D6464;  /* 'dmdd' */
 426 
 427     /**
 428      * ICC Profile Tag Signature: 'devs'.
 429      */
 430     public static final int icSigDeviceSettingsTag =  0x64657673;  /* 'devs' */
 431 
 432     /**
 433      * ICC Profile Tag Signature: 'gamt'.
 434      */
 435     public static final int icSigGamutTag         = 0x67616D74;    /* 'gamt' */
 436 
 437     /**
 438      * ICC Profile Tag Signature: 'kTRC'.
 439      */
 440     public static final int icSigGrayTRCTag       = 0x6b545243;    /* 'kTRC' */
 441 
 442     /**
 443      * ICC Profile Tag Signature: 'gXYZ'.
 444      */
 445     public static final int icSigGreenColorantTag = 0x6758595A;    /* 'gXYZ' */
 446 
 447     /**
 448      * ICC Profile Tag Signature: 'gXYZ'.
 449      * @since 1.5
 450      */
 451     public static final int icSigGreenMatrixColumnTag = 0x6758595A;/* 'gXYZ' */
 452 
 453     /**
 454      * ICC Profile Tag Signature: 'gTRC'.
 455      */
 456     public static final int icSigGreenTRCTag      = 0x67545243;    /* 'gTRC' */
 457 
 458     /**
 459      * ICC Profile Tag Signature: 'lumi'.
 460      */
 461     public static final int icSigLuminanceTag     = 0x6C756d69;    /* 'lumi' */
 462 
 463     /**
 464      * ICC Profile Tag Signature: 'meas'.
 465      */
 466     public static final int icSigMeasurementTag   = 0x6D656173;    /* 'meas' */
 467 
 468     /**
 469      * ICC Profile Tag Signature: 'bkpt'.
 470      */
 471     public static final int icSigMediaBlackPointTag = 0x626B7074;  /* 'bkpt' */
 472 
 473     /**
 474      * ICC Profile Tag Signature: 'wtpt'.
 475      */
 476     public static final int icSigMediaWhitePointTag = 0x77747074;  /* 'wtpt' */
 477 
 478     /**
 479      * ICC Profile Tag Signature: 'ncl2'.
 480      */
 481     public static final int icSigNamedColor2Tag   = 0x6E636C32;    /* 'ncl2' */
 482 
 483     /**
 484      * ICC Profile Tag Signature: 'resp'.
 485      */
 486     public static final int icSigOutputResponseTag = 0x72657370;   /* 'resp' */
 487 
 488     /**
 489      * ICC Profile Tag Signature: 'pre0'.
 490      */
 491     public static final int icSigPreview0Tag      = 0x70726530;    /* 'pre0' */
 492 
 493     /**
 494      * ICC Profile Tag Signature: 'pre1'.
 495      */
 496     public static final int icSigPreview1Tag      = 0x70726531;    /* 'pre1' */
 497 
 498     /**
 499      * ICC Profile Tag Signature: 'pre2'.
 500      */
 501     public static final int icSigPreview2Tag      = 0x70726532;    /* 'pre2' */
 502 
 503     /**
 504      * ICC Profile Tag Signature: 'desc'.
 505      */
 506     public static final int icSigProfileDescriptionTag = 0x64657363;
 507                                                                    /* 'desc' */
 508 
 509     /**
 510      * ICC Profile Tag Signature: 'pseq'.
 511      */
 512     public static final int icSigProfileSequenceDescTag = 0x70736571;
 513                                                                    /* 'pseq' */
 514 
 515     /**
 516      * ICC Profile Tag Signature: 'psd0'.
 517      */
 518     public static final int icSigPs2CRD0Tag       = 0x70736430;    /* 'psd0' */
 519 
 520     /**
 521      * ICC Profile Tag Signature: 'psd1'.
 522      */
 523     public static final int icSigPs2CRD1Tag       = 0x70736431;    /* 'psd1' */
 524 
 525     /**
 526      * ICC Profile Tag Signature: 'psd2'.
 527      */
 528     public static final int icSigPs2CRD2Tag       = 0x70736432;    /* 'psd2' */
 529 
 530     /**
 531      * ICC Profile Tag Signature: 'psd3'.
 532      */
 533     public static final int icSigPs2CRD3Tag       = 0x70736433;    /* 'psd3' */
 534 
 535     /**
 536      * ICC Profile Tag Signature: 'ps2s'.
 537      */
 538     public static final int icSigPs2CSATag        = 0x70733273;    /* 'ps2s' */
 539 
 540     /**
 541      * ICC Profile Tag Signature: 'ps2i'.
 542      */
 543     public static final int icSigPs2RenderingIntentTag = 0x70733269;
 544                                                                    /* 'ps2i' */
 545 
 546     /**
 547      * ICC Profile Tag Signature: 'rXYZ'.
 548      */
 549     public static final int icSigRedColorantTag   = 0x7258595A;    /* 'rXYZ' */
 550 
 551     /**
 552      * ICC Profile Tag Signature: 'rXYZ'.
 553      * @since 1.5
 554      */
 555     public static final int icSigRedMatrixColumnTag = 0x7258595A;  /* 'rXYZ' */
 556 
 557     /**
 558      * ICC Profile Tag Signature: 'rTRC'.
 559      */
 560     public static final int icSigRedTRCTag        = 0x72545243;    /* 'rTRC' */
 561 
 562     /**
 563      * ICC Profile Tag Signature: 'scrd'.
 564      */
 565     public static final int icSigScreeningDescTag = 0x73637264;    /* 'scrd' */
 566 
 567     /**
 568      * ICC Profile Tag Signature: 'scrn'.
 569      */
 570     public static final int icSigScreeningTag     = 0x7363726E;    /* 'scrn' */
 571 
 572     /**
 573      * ICC Profile Tag Signature: 'tech'.
 574      */
 575     public static final int icSigTechnologyTag    = 0x74656368;    /* 'tech' */
 576 
 577     /**
 578      * ICC Profile Tag Signature: 'bfd '.
 579      */
 580     public static final int icSigUcrBgTag         = 0x62666420;    /* 'bfd ' */
 581 
 582     /**
 583      * ICC Profile Tag Signature: 'vued'.
 584      */
 585     public static final int icSigViewingCondDescTag = 0x76756564;  /* 'vued' */
 586 
 587     /**
 588      * ICC Profile Tag Signature: 'view'.
 589      */
 590     public static final int icSigViewingConditionsTag = 0x76696577;/* 'view' */
 591 
 592     /**
 593      * ICC Profile Tag Signature: 'chrm'.
 594      */
 595     public static final int icSigChromaticityTag  = 0x6368726d;    /* 'chrm' */
 596 
 597     /**
 598      * ICC Profile Tag Signature: 'chad'.
 599      * @since 1.5
 600      */
 601     public static final int icSigChromaticAdaptationTag = 0x63686164;/* 'chad' */
 602 
 603     /**
 604      * ICC Profile Tag Signature: 'clro'.
 605      * @since 1.5
 606      */
 607     public static final int icSigColorantOrderTag = 0x636C726F;    /* 'clro' */
 608 
 609     /**
 610      * ICC Profile Tag Signature: 'clrt'.
 611      * @since 1.5
 612      */
 613     public static final int icSigColorantTableTag = 0x636C7274;    /* 'clrt' */
 614 
 615 
 616     /**
 617      * ICC Profile Header Location: profile size in bytes.
 618      */
 619     public static final int icHdrSize         = 0;  /* Profile size in bytes */
 620 
 621     /**
 622      * ICC Profile Header Location: CMM for this profile.
 623      */
 624     public static final int icHdrCmmId        = 4;  /* CMM for this profile */
 625 
 626     /**
 627      * ICC Profile Header Location: format version number.
 628      */
 629     public static final int icHdrVersion      = 8;  /* Format version number */
 630 
 631     /**
 632      * ICC Profile Header Location: type of profile.
 633      */
 634     public static final int icHdrDeviceClass  = 12; /* Type of profile */
 635 
 636     /**
 637      * ICC Profile Header Location: color space of data.
 638      */
 639     public static final int icHdrColorSpace   = 16; /* Color space of data */
 640 
 641     /**
 642      * ICC Profile Header Location: PCS - XYZ or Lab only.
 643      */
 644     public static final int icHdrPcs          = 20; /* PCS - XYZ or Lab only */
 645 
 646     /**
 647      * ICC Profile Header Location: date profile was created.
 648      */
 649     public static final int icHdrDate       = 24; /* Date profile was created */
 650 
 651     /**
 652      * ICC Profile Header Location: icMagicNumber.
 653      */
 654     public static final int icHdrMagic        = 36; /* icMagicNumber */
 655 
 656     /**
 657      * ICC Profile Header Location: primary platform.
 658      */
 659     public static final int icHdrPlatform     = 40; /* Primary Platform */
 660 
 661     /**
 662      * ICC Profile Header Location: various bit settings.
 663      */
 664     public static final int icHdrFlags        = 44; /* Various bit settings */
 665 
 666     /**
 667      * ICC Profile Header Location: device manufacturer.
 668      */
 669     public static final int icHdrManufacturer = 48; /* Device manufacturer */
 670 
 671     /**
 672      * ICC Profile Header Location: device model number.
 673      */
 674     public static final int icHdrModel        = 52; /* Device model number */
 675 
 676     /**
 677      * ICC Profile Header Location: device attributes.
 678      */
 679     public static final int icHdrAttributes   = 56; /* Device attributes */
 680 
 681     /**
 682      * ICC Profile Header Location: rendering intent.
 683      */
 684     public static final int icHdrRenderingIntent = 64; /* Rendering intent */
 685 
 686     /**
 687      * ICC Profile Header Location: profile illuminant.
 688      */
 689     public static final int icHdrIlluminant   = 68; /* Profile illuminant */
 690 
 691     /**
 692      * ICC Profile Header Location: profile creator.
 693      */
 694     public static final int icHdrCreator      = 80; /* Profile creator */
 695 
 696     /**
 697      * ICC Profile Header Location: profile's ID.
 698      * @since 1.5
 699      */
 700     public static final int icHdrProfileID = 84; /* Profile's ID */
 701 
 702 
 703     /**
 704      * ICC Profile Constant: tag type signature.
 705      */
 706     public static final int icTagType          = 0;    /* tag type signature */
 707 
 708     /**
 709      * ICC Profile Constant: reserved.
 710      */
 711     public static final int icTagReserved      = 4;    /* reserved */
 712 
 713     /**
 714      * ICC Profile Constant: curveType count.
 715      */
 716     public static final int icCurveCount       = 8;    /* curveType count */
 717 
 718     /**
 719      * ICC Profile Constant: curveType data.
 720      */
 721     public static final int icCurveData        = 12;   /* curveType data */
 722 
 723     /**
 724      * ICC Profile Constant: XYZNumber X.
 725      */
 726     public static final int icXYZNumberX       = 8;    /* XYZNumber X */
 727 
 728 
 729     /**
 730      * Constructs an ICC_Profile object with a given ID.
 731      */
 732     ICC_Profile(Profile p) {
 733         this.cmmProfile = p;
 734     }
 735 
 736 
 737     /**
 738      * Constructs an ICC_Profile object whose loading will be deferred.
 739      * The ID will be 0 until the profile is loaded.
 740      */
 741     ICC_Profile(ProfileDeferralInfo pdi) {
 742         this.deferralInfo = pdi;
 743         this.profileActivator = new ProfileActivator() {
 744             public void activate() throws ProfileDataException {
 745                 activateDeferredProfile();
 746             }
 747         };
 748         ProfileDeferralMgr.registerDeferral(this.profileActivator);
 749     }
 750 
 751 
 752     /**
 753      * Frees the resources associated with an ICC_Profile object.
 754      */
 755     protected void finalize () {
 756         if (cmmProfile != null) {
 757             CMSManager.getModule().freeProfile(cmmProfile);
 758         } else if (profileActivator != null) {
 759             ProfileDeferralMgr.unregisterDeferral(profileActivator);
 760         }
 761     }
 762 
 763 
 764     /**
 765      * Constructs an ICC_Profile object corresponding to the data in
 766      * a byte array.  Throws an IllegalArgumentException if the data
 767      * does not correspond to a valid ICC Profile.
 768      * @param data the specified ICC Profile data
 769      * @return an <code>ICC_Profile</code> object corresponding to
 770      *          the data in the specified <code>data</code> array.
 771      */
 772     public static ICC_Profile getInstance(byte[] data) {
 773     ICC_Profile thisProfile;
 774 
 775         Profile p = null;
 776 
 777         if (ProfileDeferralMgr.deferring) {
 778             ProfileDeferralMgr.activateProfiles();
 779         }
 780 
 781         ProfileDataVerifier.verify(data);
 782 
 783         try {
 784             p = CMSManager.getModule().loadProfile(data);
 785         } catch (CMMException c) {
 786             throw new IllegalArgumentException("Invalid ICC Profile Data");
 787         }
 788 
 789         try {
 790             if ((getColorSpaceType (p) == ColorSpace.TYPE_GRAY) &&
 791                 (getData (p, icSigMediaWhitePointTag) != null) &&
 792                 (getData (p, icSigGrayTRCTag) != null)) {
 793                 thisProfile = new ICC_ProfileGray (p);
 794             }
 795             else if ((getColorSpaceType (p) == ColorSpace.TYPE_RGB) &&
 796                 (getData (p, icSigMediaWhitePointTag) != null) &&
 797                 (getData (p, icSigRedColorantTag) != null) &&
 798                 (getData (p, icSigGreenColorantTag) != null) &&
 799                 (getData (p, icSigBlueColorantTag) != null) &&
 800                 (getData (p, icSigRedTRCTag) != null) &&
 801                 (getData (p, icSigGreenTRCTag) != null) &&
 802                 (getData (p, icSigBlueTRCTag) != null)) {
 803                 thisProfile = new ICC_ProfileRGB (p);
 804             }
 805             else {
 806                 thisProfile = new ICC_Profile (p);
 807             }
 808         } catch (CMMException c) {
 809             thisProfile = new ICC_Profile (p);
 810         }
 811         return thisProfile;
 812     }
 813 
 814 
 815 
 816     /**
 817      * Constructs an ICC_Profile corresponding to one of the specific color
 818      * spaces defined by the ColorSpace class (for example CS_sRGB).
 819      * Throws an IllegalArgumentException if cspace is not one of the
 820      * defined color spaces.
 821      *
 822      * @param cspace the type of color space to create a profile for.
 823      * The specified type is one of the color
 824      * space constants defined in the  <CODE>ColorSpace</CODE> class.
 825      *
 826      * @return an <code>ICC_Profile</code> object corresponding to
 827      *          the specified <code>ColorSpace</code> type.
 828      * @exception IllegalArgumentException If <CODE>cspace</CODE> is not
 829      * one of the predefined color space types.
 830      */
 831     public static ICC_Profile getInstance (int cspace) {
 832         ICC_Profile thisProfile = null;
 833         String fileName;
 834 
 835         switch (cspace) {
 836         case ColorSpace.CS_sRGB:
 837             synchronized(ICC_Profile.class) {
 838                 if (sRGBprofile == null) {
 839                     /*
 840                      * Deferral is only used for standard profiles.
 841                      * Enabling the appropriate access privileges is handled
 842                      * at a lower level.
 843                      */
 844                     ProfileDeferralInfo pInfo =
 845                         new ProfileDeferralInfo("sRGB.pf",
 846                                                 ColorSpace.TYPE_RGB, 3,
 847                                                 CLASS_DISPLAY);
 848                     sRGBprofile = getDeferredInstance(pInfo);
 849                 }
 850                 thisProfile = sRGBprofile;
 851             }
 852 
 853             break;
 854 
 855         case ColorSpace.CS_CIEXYZ:
 856             synchronized(ICC_Profile.class) {
 857                 if (XYZprofile == null) {
 858                     ProfileDeferralInfo pInfo =
 859                         new ProfileDeferralInfo("CIEXYZ.pf",
 860                                                 ColorSpace.TYPE_XYZ, 3,
 861                                                 CLASS_DISPLAY);
 862                     XYZprofile = getDeferredInstance(pInfo);
 863                 }
 864                 thisProfile = XYZprofile;
 865             }
 866 
 867             break;
 868 
 869         case ColorSpace.CS_PYCC:
 870             synchronized(ICC_Profile.class) {
 871                 if (PYCCprofile == null) {
 872                     if (standardProfileExists("PYCC.pf"))
 873                     {
 874                         ProfileDeferralInfo pInfo =
 875                             new ProfileDeferralInfo("PYCC.pf",
 876                                                     ColorSpace.TYPE_3CLR, 3,
 877                                                     CLASS_DISPLAY);
 878                         PYCCprofile = getDeferredInstance(pInfo);
 879                     } else {
 880                         throw new IllegalArgumentException(
 881                                 "Can't load standard profile: PYCC.pf");
 882                     }
 883                 }
 884                 thisProfile = PYCCprofile;
 885             }
 886 
 887             break;
 888 
 889         case ColorSpace.CS_GRAY:
 890             synchronized(ICC_Profile.class) {
 891                 if (GRAYprofile == null) {
 892                     ProfileDeferralInfo pInfo =
 893                         new ProfileDeferralInfo("GRAY.pf",
 894                                                 ColorSpace.TYPE_GRAY, 1,
 895                                                 CLASS_DISPLAY);
 896                     GRAYprofile = getDeferredInstance(pInfo);
 897                 }
 898                 thisProfile = GRAYprofile;
 899             }
 900 
 901             break;
 902 
 903         case ColorSpace.CS_LINEAR_RGB:
 904             synchronized(ICC_Profile.class) {
 905                 if (LINEAR_RGBprofile == null) {
 906                     ProfileDeferralInfo pInfo =
 907                         new ProfileDeferralInfo("LINEAR_RGB.pf",
 908                                                 ColorSpace.TYPE_RGB, 3,
 909                                                 CLASS_DISPLAY);
 910                     LINEAR_RGBprofile = getDeferredInstance(pInfo);
 911                 }
 912                 thisProfile = LINEAR_RGBprofile;
 913             }
 914 
 915             break;
 916 
 917         default:
 918             throw new IllegalArgumentException("Unknown color space");
 919         }
 920 
 921         return thisProfile;
 922     }
 923 
 924     /* This asserts system privileges, so is used only for the
 925      * standard profiles.
 926      */
 927     private static ICC_Profile getStandardProfile(final String name) {
 928 
 929         return AccessController.doPrivileged(
 930             new PrivilegedAction<ICC_Profile>() {
 931                  public ICC_Profile run() {
 932                      ICC_Profile p = null;
 933                      try {
 934                          p = getInstance (name);
 935                      } catch (IOException ex) {
 936                          throw new IllegalArgumentException(
 937                                "Can't load standard profile: " + name);
 938                      }
 939                      return p;
 940                  }
 941              });
 942     }
 943 
 944     /**
 945      * Constructs an ICC_Profile corresponding to the data in a file.
 946      * fileName may be an absolute or a relative file specification.
 947      * Relative file names are looked for in several places: first, relative
 948      * to any directories specified by the java.iccprofile.path property;
 949      * second, relative to any directories specified by the java.class.path
 950      * property; finally, in a directory used to store profiles always
 951      * available, such as the profile for sRGB.  Built-in profiles use .pf as
 952      * the file name extension for profiles, e.g. sRGB.pf.
 953      * This method throws an IOException if the specified file cannot be
 954      * opened or if an I/O error occurs while reading the file.  It throws
 955      * an IllegalArgumentException if the file does not contain valid ICC
 956      * Profile data.
 957      * @param fileName The file that contains the data for the profile.
 958      *
 959      * @return an <code>ICC_Profile</code> object corresponding to
 960      *          the data in the specified file.
 961      * @exception IOException If the specified file cannot be opened or
 962      * an I/O error occurs while reading the file.
 963      *
 964      * @exception IllegalArgumentException If the file does not
 965      * contain valid ICC Profile data.
 966      *
 967      * @exception SecurityException If a security manager is installed
 968      * and it does not permit read access to the given file.
 969      */
 970     public static ICC_Profile getInstance(String fileName) throws IOException {
 971         ICC_Profile thisProfile;
 972         InputStream is = null;
 973 
 974 
 975         File f = getProfileFile(fileName);
 976         if (f != null) {
 977             is = new FileInputStream(f);
 978         } else {
 979             is = getStandardProfileInputStream(fileName);
 980         }
 981         if (is == null) {
 982             throw new IOException("Cannot open file " + fileName);
 983         }
 984 
 985         thisProfile = getInstance(is);
 986 
 987         is.close();    /* close the file */
 988 
 989         return thisProfile;
 990     }
 991 
 992 
 993     /**
 994      * Constructs an ICC_Profile corresponding to the data in an InputStream.
 995      * This method throws an IllegalArgumentException if the stream does not
 996      * contain valid ICC Profile data.  It throws an IOException if an I/O
 997      * error occurs while reading the stream.
 998      * @param s The input stream from which to read the profile data.
 999      *
1000      * @return an <CODE>ICC_Profile</CODE> object corresponding to the
1001      *     data in the specified <code>InputStream</code>.
1002      *
1003      * @exception IOException If an I/O error occurs while reading the stream.
1004      *
1005      * @exception IllegalArgumentException If the stream does not
1006      * contain valid ICC Profile data.
1007      */
1008     public static ICC_Profile getInstance(InputStream s) throws IOException {
1009     byte profileData[];
1010 
1011         if (s instanceof ProfileDeferralInfo) {
1012             /* hack to detect profiles whose loading can be deferred */
1013             return getDeferredInstance((ProfileDeferralInfo) s);
1014         }
1015 
1016         if ((profileData = getProfileDataFromStream(s)) == null) {
1017             throw new IllegalArgumentException("Invalid ICC Profile Data");
1018         }
1019 
1020         return getInstance(profileData);
1021     }
1022 
1023 
1024     static byte[] getProfileDataFromStream(InputStream s) throws IOException {
1025     byte profileData[];
1026     int profileSize;
1027 
1028         byte header[] = new byte[128];
1029         int bytestoread = 128;
1030         int bytesread = 0;
1031         int n;
1032 
1033         while (bytestoread != 0) {
1034             if ((n = s.read(header, bytesread, bytestoread)) < 0) {
1035                 return null;
1036             }
1037             bytesread += n;
1038             bytestoread -= n;
1039         }
1040         if (header[36] != 0x61 || header[37] != 0x63 ||
1041             header[38] != 0x73 || header[39] != 0x70) {
1042             return null;   /* not a valid profile */
1043         }
1044         profileSize = ((header[0] & 0xff) << 24) |
1045                       ((header[1] & 0xff) << 16) |
1046                       ((header[2] & 0xff) <<  8) |
1047                        (header[3] & 0xff);
1048         profileData = new byte[profileSize];
1049         System.arraycopy(header, 0, profileData, 0, 128);
1050         bytestoread = profileSize - 128;
1051         bytesread = 128;
1052         while (bytestoread != 0) {
1053             if ((n = s.read(profileData, bytesread, bytestoread)) < 0) {
1054                 return null;
1055             }
1056             bytesread += n;
1057             bytestoread -= n;
1058         }
1059 
1060         return profileData;
1061     }
1062 
1063 
1064     /**
1065      * Constructs an ICC_Profile for which the actual loading of the
1066      * profile data from a file and the initialization of the CMM should
1067      * be deferred as long as possible.
1068      * Deferral is only used for standard profiles.
1069      * If deferring is disabled, then getStandardProfile() ensures
1070      * that all of the appropriate access privileges are granted
1071      * when loading this profile.
1072      * If deferring is enabled, then the deferred activation
1073      * code will take care of access privileges.
1074      * @see activateDeferredProfile()
1075      */
1076     static ICC_Profile getDeferredInstance(ProfileDeferralInfo pdi) {
1077         if (!ProfileDeferralMgr.deferring) {
1078             return getStandardProfile(pdi.filename);
1079         }
1080         if (pdi.colorSpaceType == ColorSpace.TYPE_RGB) {
1081             return new ICC_ProfileRGB(pdi);
1082         } else if (pdi.colorSpaceType == ColorSpace.TYPE_GRAY) {
1083             return new ICC_ProfileGray(pdi);
1084         } else {
1085             return new ICC_Profile(pdi);
1086         }
1087     }
1088 
1089 
1090     void activateDeferredProfile() throws ProfileDataException {
1091         byte profileData[];
1092         final String fileName = deferralInfo.filename;
1093 
1094         profileActivator = null;
1095         deferralInfo = null;
1096         InputStream is = getStandardProfileInputStream(fileName);
1097         if (is == null) {
1098             throw new ProfileDataException("Cannot open file " + fileName);
1099         }
1100         try {
1101             profileData = getProfileDataFromStream(is);
1102             is.close();    /* close the file */
1103         }
1104         catch (IOException e) {
1105             ProfileDataException pde = new
1106                 ProfileDataException("Invalid ICC Profile Data" + fileName);
1107             pde.initCause(e);
1108             throw pde;
1109         }
1110         if (profileData == null) {
1111             throw new ProfileDataException("Invalid ICC Profile Data" +
1112                 fileName);
1113         }
1114         try {
1115             cmmProfile = CMSManager.getModule().loadProfile(profileData);
1116         } catch (CMMException c) {
1117             ProfileDataException pde = new
1118                 ProfileDataException("Invalid ICC Profile Data" + fileName);
1119             pde.initCause(c);
1120             throw pde;
1121         }
1122     }
1123 
1124 
1125     /**
1126      * Returns profile major version.
1127      * @return  The major version of the profile.
1128      */
1129     public int getMajorVersion() {
1130     byte[] theHeader;
1131 
1132         theHeader = getData(icSigHead); /* getData will activate deferred
1133                                            profiles if necessary */
1134 
1135         return (int) theHeader[8];
1136     }
1137 
1138     /**
1139      * Returns profile minor version.
1140      * @return The minor version of the profile.
1141      */
1142     public int getMinorVersion() {
1143     byte[] theHeader;
1144 
1145         theHeader = getData(icSigHead); /* getData will activate deferred
1146                                            profiles if necessary */
1147 
1148         return (int) theHeader[9];
1149     }
1150 
1151     /**
1152      * Returns the profile class.
1153      * @return One of the predefined profile class constants.
1154      */
1155     public int getProfileClass() {
1156     byte[] theHeader;
1157     int theClassSig, theClass;
1158 
1159         if (deferralInfo != null) {
1160             return deferralInfo.profileClass; /* Need to have this info for
1161                                                  ICC_ColorSpace without
1162                                                  causing a deferred profile
1163                                                  to be loaded */
1164         }
1165 
1166         theHeader = getData(icSigHead);
1167 
1168         theClassSig = intFromBigEndian (theHeader, icHdrDeviceClass);
1169 
1170         switch (theClassSig) {
1171         case icSigInputClass:
1172             theClass = CLASS_INPUT;
1173             break;
1174 
1175         case icSigDisplayClass:
1176             theClass = CLASS_DISPLAY;
1177             break;
1178 
1179         case icSigOutputClass:
1180             theClass = CLASS_OUTPUT;
1181             break;
1182 
1183         case icSigLinkClass:
1184             theClass = CLASS_DEVICELINK;
1185             break;
1186 
1187         case icSigColorSpaceClass:
1188             theClass = CLASS_COLORSPACECONVERSION;
1189             break;
1190 
1191         case icSigAbstractClass:
1192             theClass = CLASS_ABSTRACT;
1193             break;
1194 
1195         case icSigNamedColorClass:
1196             theClass = CLASS_NAMEDCOLOR;
1197             break;
1198 
1199         default:
1200             throw new IllegalArgumentException("Unknown profile class");
1201         }
1202 
1203         return theClass;
1204     }
1205 
1206     /**
1207      * Returns the color space type.  Returns one of the color space type
1208      * constants defined by the ColorSpace class.  This is the
1209      * "input" color space of the profile.  The type defines the
1210      * number of components of the color space and the interpretation,
1211      * e.g. TYPE_RGB identifies a color space with three components - red,
1212      * green, and blue.  It does not define the particular color
1213      * characteristics of the space, e.g. the chromaticities of the
1214      * primaries.
1215      * @return One of the color space type constants defined in the
1216      * <CODE>ColorSpace</CODE> class.
1217      */
1218     public int getColorSpaceType() {
1219         if (deferralInfo != null) {
1220             return deferralInfo.colorSpaceType; /* Need to have this info for
1221                                                    ICC_ColorSpace without
1222                                                    causing a deferred profile
1223                                                    to be loaded */
1224         }
1225         return    getColorSpaceType(cmmProfile);
1226     }
1227 
1228     static int getColorSpaceType(Profile p) {
1229     byte[] theHeader;
1230     int theColorSpaceSig, theColorSpace;
1231 
1232         theHeader = getData(p, icSigHead);
1233         theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace);
1234         theColorSpace = iccCStoJCS (theColorSpaceSig);
1235         return theColorSpace;
1236     }
1237 
1238     /**
1239      * Returns the color space type of the Profile Connection Space (PCS).
1240      * Returns one of the color space type constants defined by the
1241      * ColorSpace class.  This is the "output" color space of the
1242      * profile.  For an input, display, or output profile useful
1243      * for tagging colors or images, this will be either TYPE_XYZ or
1244      * TYPE_Lab and should be interpreted as the corresponding specific
1245      * color space defined in the ICC specification.  For a device
1246      * link profile, this could be any of the color space type constants.
1247      * @return One of the color space type constants defined in the
1248      * <CODE>ColorSpace</CODE> class.
1249      */
1250     public int getPCSType() {
1251         if (ProfileDeferralMgr.deferring) {
1252             ProfileDeferralMgr.activateProfiles();
1253         }
1254         return getPCSType(cmmProfile);
1255     }
1256 
1257 
1258     static int getPCSType(Profile p) {
1259     byte[] theHeader;
1260     int thePCSSig, thePCS;
1261 
1262         theHeader = getData(p, icSigHead);
1263         thePCSSig = intFromBigEndian(theHeader, icHdrPcs);
1264         thePCS = iccCStoJCS(thePCSSig);
1265         return thePCS;
1266     }
1267 
1268 
1269     /**
1270      * Write this ICC_Profile to a file.
1271      *
1272      * @param fileName The file to write the profile data to.
1273      *
1274      * @exception IOException If the file cannot be opened for writing
1275      * or an I/O error occurs while writing to the file.
1276      */
1277     public void write(String fileName) throws IOException {
1278     FileOutputStream outputFile;
1279     byte profileData[];
1280 
1281         profileData = getData(); /* this will activate deferred
1282                                     profiles if necessary */
1283         outputFile = new FileOutputStream(fileName);
1284         outputFile.write(profileData);
1285         outputFile.close ();
1286     }
1287 
1288 
1289     /**
1290      * Write this ICC_Profile to an OutputStream.
1291      *
1292      * @param s The stream to write the profile data to.
1293      *
1294      * @exception IOException If an I/O error occurs while writing to the
1295      * stream.
1296      */
1297     public void write(OutputStream s) throws IOException {
1298     byte profileData[];
1299 
1300         profileData = getData(); /* this will activate deferred
1301                                     profiles if necessary */
1302         s.write(profileData);
1303     }
1304 
1305 
1306     /**
1307      * Returns a byte array corresponding to the data of this ICC_Profile.
1308      * @return A byte array that contains the profile data.
1309      * @see #setData(int, byte[])
1310      */
1311     public byte[] getData() {
1312     int profileSize;
1313     byte[] profileData;
1314 
1315         if (ProfileDeferralMgr.deferring) {
1316             ProfileDeferralMgr.activateProfiles();
1317         }
1318 
1319         PCMM mdl = CMSManager.getModule();
1320 
1321         /* get the number of bytes needed for this profile */
1322         profileSize = mdl.getProfileSize(cmmProfile);
1323 
1324         profileData = new byte [profileSize];
1325 
1326         /* get the data for the profile */
1327         mdl.getProfileData(cmmProfile, profileData);
1328 
1329         return profileData;
1330     }
1331 
1332 
1333     /**
1334      * Returns a particular tagged data element from the profile as
1335      * a byte array.  Elements are identified by signatures
1336      * as defined in the ICC specification.  The signature
1337      * icSigHead can be used to get the header.  This method is useful
1338      * for advanced applets or applications which need to access
1339      * profile data directly.
1340      *
1341      * @param tagSignature The ICC tag signature for the data element you
1342      * want to get.
1343      *
1344      * @return A byte array that contains the tagged data element. Returns
1345      * <code>null</code> if the specified tag doesn't exist.
1346      * @see #setData(int, byte[])
1347      */
1348     public byte[] getData(int tagSignature) {
1349 
1350         if (ProfileDeferralMgr.deferring) {
1351             ProfileDeferralMgr.activateProfiles();
1352         }
1353 
1354         return getData(cmmProfile, tagSignature);
1355     }
1356 
1357 
1358     static byte[] getData(Profile p, int tagSignature) {
1359     int tagSize;
1360     byte[] tagData;
1361 
1362         try {
1363             PCMM mdl = CMSManager.getModule();
1364 
1365             /* get the number of bytes needed for this tag */
1366             tagSize = mdl.getTagSize(p, tagSignature);
1367 
1368             tagData = new byte[tagSize]; /* get an array for the tag */
1369 
1370             /* get the tag's data */
1371             mdl.getTagData(p, tagSignature, tagData);
1372         } catch(CMMException c) {
1373             tagData = null;
1374         }
1375 
1376         return tagData;
1377     }
1378 
1379     /**
1380      * Sets a particular tagged data element in the profile from
1381      * a byte array. The array should contain data in a format, corresponded
1382      * to the {@code tagSignature} as defined in the ICC specification, section 10.
1383      * This method is useful for advanced applets or applications which need to
1384      * access profile data directly.
1385      *
1386      * @param tagSignature The ICC tag signature for the data element
1387      * you want to set.
1388      * @param tagData the data to set for the specified tag signature
1389      * @throws IllegalArgumentException if {@code tagSignature} is not a signature
1390      *         as defined in the ICC specification.
1391      * @throws IllegalArgumentException if a content of the {@code tagData}
1392      *         array can not be interpreted as valid tag data, corresponding
1393      *         to the {@code tagSignature}.
1394      * @see #getData
1395      */
1396     public void setData(int tagSignature, byte[] tagData) {
1397 
1398         if (ProfileDeferralMgr.deferring) {
1399             ProfileDeferralMgr.activateProfiles();
1400         }
1401 
1402         CMSManager.getModule().setTagData(cmmProfile, tagSignature, tagData);
1403     }
1404 
1405     /**
1406      * Sets the rendering intent of the profile.
1407      * This is used to select the proper transform from a profile that
1408      * has multiple transforms.
1409      */
1410     void setRenderingIntent(int renderingIntent) {
1411         byte[] theHeader = getData(icSigHead);/* getData will activate deferred
1412                                                  profiles if necessary */
1413         intToBigEndian (renderingIntent, theHeader, icHdrRenderingIntent);
1414                                                  /* set the rendering intent */
1415         setData (icSigHead, theHeader);
1416     }
1417 
1418 
1419     /**
1420      * Returns the rendering intent of the profile.
1421      * This is used to select the proper transform from a profile that
1422      * has multiple transforms.  It is typically set in a source profile
1423      * to select a transform from an output profile.
1424      */
1425     int getRenderingIntent() {
1426         byte[] theHeader = getData(icSigHead);/* getData will activate deferred
1427                                                  profiles if necessary */
1428 
1429         int renderingIntent = intFromBigEndian(theHeader, icHdrRenderingIntent);
1430                                                  /* set the rendering intent */
1431 
1432         /* According to ICC spec, only the least-significant 16 bits shall be
1433          * used to encode the rendering intent. The most significant 16 bits
1434          * shall be set to zero. Thus, we are ignoring two most significant
1435          * bytes here.
1436          *
1437          *  See http://www.color.org/ICC1v42_2006-05.pdf, section 7.2.15.
1438          */
1439         return (0xffff & renderingIntent);
1440     }
1441 
1442 
1443     /**
1444      * Returns the number of color components in the "input" color
1445      * space of this profile.  For example if the color space type
1446      * of this profile is TYPE_RGB, then this method will return 3.
1447      *
1448      * @return The number of color components in the profile's input
1449      * color space.
1450      *
1451      * @throws ProfileDataException if color space is in the profile
1452      *         is invalid
1453      */
1454     public int getNumComponents() {
1455     byte[]    theHeader;
1456     int    theColorSpaceSig, theNumComponents;
1457 
1458         if (deferralInfo != null) {
1459             return deferralInfo.numComponents; /* Need to have this info for
1460                                                   ICC_ColorSpace without
1461                                                   causing a deferred profile
1462                                                   to be loaded */
1463         }
1464         theHeader = getData(icSigHead);
1465 
1466         theColorSpaceSig = intFromBigEndian (theHeader, icHdrColorSpace);
1467 
1468         switch (theColorSpaceSig) {
1469         case icSigGrayData:
1470             theNumComponents = 1;
1471             break;
1472 
1473         case icSigSpace2CLR:
1474             theNumComponents = 2;
1475             break;
1476 
1477         case icSigXYZData:
1478         case icSigLabData:
1479         case icSigLuvData:
1480         case icSigYCbCrData:
1481         case icSigYxyData:
1482         case icSigRgbData:
1483         case icSigHsvData:
1484         case icSigHlsData:
1485         case icSigCmyData:
1486         case icSigSpace3CLR:
1487             theNumComponents = 3;
1488             break;
1489 
1490         case icSigCmykData:
1491         case icSigSpace4CLR:
1492             theNumComponents = 4;
1493             break;
1494 
1495         case icSigSpace5CLR:
1496             theNumComponents = 5;
1497             break;
1498 
1499         case icSigSpace6CLR:
1500             theNumComponents = 6;
1501             break;
1502 
1503         case icSigSpace7CLR:
1504             theNumComponents = 7;
1505             break;
1506 
1507         case icSigSpace8CLR:
1508             theNumComponents = 8;
1509             break;
1510 
1511         case icSigSpace9CLR:
1512             theNumComponents = 9;
1513             break;
1514 
1515         case icSigSpaceACLR:
1516             theNumComponents = 10;
1517             break;
1518 
1519         case icSigSpaceBCLR:
1520             theNumComponents = 11;
1521             break;
1522 
1523         case icSigSpaceCCLR:
1524             theNumComponents = 12;
1525             break;
1526 
1527         case icSigSpaceDCLR:
1528             theNumComponents = 13;
1529             break;
1530 
1531         case icSigSpaceECLR:
1532             theNumComponents = 14;
1533             break;
1534 
1535         case icSigSpaceFCLR:
1536             theNumComponents = 15;
1537             break;
1538 
1539         default:
1540             throw new ProfileDataException ("invalid ICC color space");
1541         }
1542 
1543         return theNumComponents;
1544     }
1545 
1546 
1547     /**
1548      * Returns a float array of length 3 containing the X, Y, and Z
1549      * components of the mediaWhitePointTag in the ICC profile.
1550      */
1551     float[] getMediaWhitePoint() {
1552         return getXYZTag(icSigMediaWhitePointTag);
1553                                            /* get the media white point tag */
1554     }
1555 
1556 
1557     /**
1558      * Returns a float array of length 3 containing the X, Y, and Z
1559      * components encoded in an XYZType tag.
1560      */
1561     float[] getXYZTag(int theTagSignature) {
1562     byte[] theData;
1563     float[] theXYZNumber;
1564     int i1, i2, theS15Fixed16;
1565 
1566         theData = getData(theTagSignature); /* get the tag data */
1567                                             /* getData will activate deferred
1568                                                profiles if necessary */
1569 
1570         theXYZNumber = new float [3];        /* array to return */
1571 
1572         /* convert s15Fixed16Number to float */
1573         for (i1 = 0, i2 = icXYZNumberX; i1 < 3; i1++, i2 += 4) {
1574             theS15Fixed16 = intFromBigEndian(theData, i2);
1575             theXYZNumber [i1] = ((float) theS15Fixed16) / 65536.0f;
1576         }
1577         return theXYZNumber;
1578     }
1579 
1580 
1581     /**
1582      * Returns a gamma value representing a tone reproduction
1583      * curve (TRC).  If the profile represents the TRC as a table rather
1584      * than a single gamma value, then an exception is thrown.  In this
1585      * case the actual table can be obtained via getTRC().
1586      * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
1587      * icSigGreenTRCTag, or icSigBlueTRCTag.
1588      * @return the gamma value as a float.
1589      * @exception ProfileDataException if the profile does not specify
1590      *            the TRC as a single gamma value.
1591      */
1592     float getGamma(int theTagSignature) {
1593     byte[] theTRCData;
1594     float theGamma;
1595     int theU8Fixed8;
1596 
1597         theTRCData = getData(theTagSignature); /* get the TRC */
1598                                                /* getData will activate deferred
1599                                                   profiles if necessary */
1600 
1601         if (intFromBigEndian (theTRCData, icCurveCount) != 1) {
1602             throw new ProfileDataException ("TRC is not a gamma");
1603         }
1604 
1605         /* convert u8Fixed8 to float */
1606         theU8Fixed8 = (shortFromBigEndian(theTRCData, icCurveData)) & 0xffff;
1607 
1608         theGamma = ((float) theU8Fixed8) / 256.0f;
1609 
1610         return theGamma;
1611     }
1612 
1613 
1614     /**
1615      * Returns the TRC as an array of shorts.  If the profile has
1616      * specified the TRC as linear (gamma = 1.0) or as a simple gamma
1617      * value, this method throws an exception, and the getGamma() method
1618      * should be used to get the gamma value.  Otherwise the short array
1619      * returned here represents a lookup table where the input Gray value
1620      * is conceptually in the range [0.0, 1.0].  Value 0.0 maps
1621      * to array index 0 and value 1.0 maps to array index length-1.
1622      * Interpolation may be used to generate output values for
1623      * input values which do not map exactly to an index in the
1624      * array.  Output values also map linearly to the range [0.0, 1.0].
1625      * Value 0.0 is represented by an array value of 0x0000 and
1626      * value 1.0 by 0xFFFF, i.e. the values are really unsigned
1627      * short values, although they are returned in a short array.
1628      * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
1629      * icSigGreenTRCTag, or icSigBlueTRCTag.
1630      * @return a short array representing the TRC.
1631      * @exception ProfileDataException if the profile does not specify
1632      *            the TRC as a table.
1633      */
1634     short[] getTRC(int theTagSignature) {
1635     byte[] theTRCData;
1636     short[] theTRC;
1637     int i1, i2, nElements, theU8Fixed8;
1638 
1639         theTRCData = getData(theTagSignature); /* get the TRC */
1640                                                /* getData will activate deferred
1641                                                   profiles if necessary */
1642 
1643         nElements = intFromBigEndian(theTRCData, icCurveCount);
1644 
1645         if (nElements == 1) {
1646             throw new ProfileDataException("TRC is not a table");
1647         }
1648 
1649         /* make the short array */
1650         theTRC = new short [nElements];
1651 
1652         for (i1 = 0, i2 = icCurveData; i1 < nElements; i1++, i2 += 2) {
1653             theTRC[i1] = shortFromBigEndian(theTRCData, i2);
1654         }
1655 
1656         return theTRC;
1657     }
1658 
1659 
1660     /* convert an ICC color space signature into a Java color space type */
1661     static int iccCStoJCS(int theColorSpaceSig) {
1662     int theColorSpace;
1663 
1664         switch (theColorSpaceSig) {
1665         case icSigXYZData:
1666             theColorSpace = ColorSpace.TYPE_XYZ;
1667             break;
1668 
1669         case icSigLabData:
1670             theColorSpace = ColorSpace.TYPE_Lab;
1671             break;
1672 
1673         case icSigLuvData:
1674             theColorSpace = ColorSpace.TYPE_Luv;
1675             break;
1676 
1677         case icSigYCbCrData:
1678             theColorSpace = ColorSpace.TYPE_YCbCr;
1679             break;
1680 
1681         case icSigYxyData:
1682             theColorSpace = ColorSpace.TYPE_Yxy;
1683             break;
1684 
1685         case icSigRgbData:
1686             theColorSpace = ColorSpace.TYPE_RGB;
1687             break;
1688 
1689         case icSigGrayData:
1690             theColorSpace = ColorSpace.TYPE_GRAY;
1691             break;
1692 
1693         case icSigHsvData:
1694             theColorSpace = ColorSpace.TYPE_HSV;
1695             break;
1696 
1697         case icSigHlsData:
1698             theColorSpace = ColorSpace.TYPE_HLS;
1699             break;
1700 
1701         case icSigCmykData:
1702             theColorSpace = ColorSpace.TYPE_CMYK;
1703             break;
1704 
1705         case icSigCmyData:
1706             theColorSpace = ColorSpace.TYPE_CMY;
1707             break;
1708 
1709         case icSigSpace2CLR:
1710             theColorSpace = ColorSpace.TYPE_2CLR;
1711             break;
1712 
1713         case icSigSpace3CLR:
1714             theColorSpace = ColorSpace.TYPE_3CLR;
1715             break;
1716 
1717         case icSigSpace4CLR:
1718             theColorSpace = ColorSpace.TYPE_4CLR;
1719             break;
1720 
1721         case icSigSpace5CLR:
1722             theColorSpace = ColorSpace.TYPE_5CLR;
1723             break;
1724 
1725         case icSigSpace6CLR:
1726             theColorSpace = ColorSpace.TYPE_6CLR;
1727             break;
1728 
1729         case icSigSpace7CLR:
1730             theColorSpace = ColorSpace.TYPE_7CLR;
1731             break;
1732 
1733         case icSigSpace8CLR:
1734             theColorSpace = ColorSpace.TYPE_8CLR;
1735             break;
1736 
1737         case icSigSpace9CLR:
1738             theColorSpace = ColorSpace.TYPE_9CLR;
1739             break;
1740 
1741         case icSigSpaceACLR:
1742             theColorSpace = ColorSpace.TYPE_ACLR;
1743             break;
1744 
1745         case icSigSpaceBCLR:
1746             theColorSpace = ColorSpace.TYPE_BCLR;
1747             break;
1748 
1749         case icSigSpaceCCLR:
1750             theColorSpace = ColorSpace.TYPE_CCLR;
1751             break;
1752 
1753         case icSigSpaceDCLR:
1754             theColorSpace = ColorSpace.TYPE_DCLR;
1755             break;
1756 
1757         case icSigSpaceECLR:
1758             theColorSpace = ColorSpace.TYPE_ECLR;
1759             break;
1760 
1761         case icSigSpaceFCLR:
1762             theColorSpace = ColorSpace.TYPE_FCLR;
1763             break;
1764 
1765         default:
1766             throw new IllegalArgumentException ("Unknown color space");
1767         }
1768 
1769         return theColorSpace;
1770     }
1771 
1772 
1773     static int intFromBigEndian(byte[] array, int index) {
1774         return (((array[index]   & 0xff) << 24) |
1775                 ((array[index+1] & 0xff) << 16) |
1776                 ((array[index+2] & 0xff) <<  8) |
1777                  (array[index+3] & 0xff));
1778     }
1779 
1780 
1781     static void intToBigEndian(int value, byte[] array, int index) {
1782             array[index]   = (byte) (value >> 24);
1783             array[index+1] = (byte) (value >> 16);
1784             array[index+2] = (byte) (value >>  8);
1785             array[index+3] = (byte) (value);
1786     }
1787 
1788 
1789     static short shortFromBigEndian(byte[] array, int index) {
1790         return (short) (((array[index]   & 0xff) << 8) |
1791                          (array[index+1] & 0xff));
1792     }
1793 
1794 
1795     static void shortToBigEndian(short value, byte[] array, int index) {
1796             array[index]   = (byte) (value >> 8);
1797             array[index+1] = (byte) (value);
1798     }
1799 
1800 
1801     /*
1802      * fileName may be an absolute or a relative file specification.
1803      * Relative file names are looked for in several places: first, relative
1804      * to any directories specified by the java.iccprofile.path property;
1805      * second, relative to any directories specified by the java.class.path.
1806      * The built-in profile files are now loaded as resources, since they
1807      * may not be individual disk files, and so this method will not find
1808      * these and on a null return, the caller needs to try as resources.
1809      * Built-in profiles use .pf as the file name extension for profiles,
1810      * e.g. sRGB.pf.
1811      */
1812     private static File getProfileFile(String fileName) {
1813         String path, dir, fullPath;
1814 
1815         File f = new File(fileName); /* try absolute file name */
1816         if (f.isAbsolute()) {
1817             /* Rest of code has little sense for an absolute pathname,
1818                so return here. */
1819             return f.isFile() ? f : null;
1820         }
1821         if ((!f.isFile()) &&
1822                 ((path = System.getProperty("java.iccprofile.path")) != null)){
1823                                     /* try relative to java.iccprofile.path */
1824                 StringTokenizer st =
1825                     new StringTokenizer(path, File.pathSeparator);
1826                 while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) {
1827                     dir = st.nextToken();
1828                         fullPath = dir + File.separatorChar + fileName;
1829                     f = new File(fullPath);
1830                     if (!isChildOf(f, dir)) {
1831                         f = null;
1832                     }
1833                 }
1834             }
1835 
1836         if (((f == null) || (!f.isFile())) &&
1837                 ((path = System.getProperty("java.class.path")) != null)) {
1838                                     /* try relative to java.class.path */
1839                 StringTokenizer st =
1840                     new StringTokenizer(path, File.pathSeparator);
1841                 while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) {
1842                     dir = st.nextToken();
1843                         fullPath = dir + File.separatorChar + fileName;
1844                     f = new File(fullPath);
1845                 }
1846         }
1847 
1848         if (f != null && !f.isFile()) {
1849             f = null;
1850         }
1851         return f;
1852     }
1853 
1854     /**
1855      * Returns a stream corresponding to a built-in profile
1856      * specified by fileName.
1857      * If there is no built-in profile with such name, then the method
1858      * returns null.
1859      */
1860     private static InputStream getStandardProfileInputStream(String fileName) {
1861         return AccessController.doPrivileged(
1862             new PrivilegedAction<InputStream>() {
1863                 public InputStream run () {
1864                     return
1865                         PCMM.class.getResourceAsStream("profiles/" + fileName);
1866                 }
1867             }, null, new FilePermission("<<ALL FILES>>", "read"));
1868     }
1869 
1870     /**
1871      * Checks whether given file resides inside give directory.
1872      */
1873     private static boolean isChildOf(File f, String dirName) {
1874         try {
1875             File dir = new File(dirName);
1876             String canonicalDirName = dir.getCanonicalPath();
1877             if (!canonicalDirName.endsWith(File.separator)) {
1878                 canonicalDirName += File.separator;
1879             }
1880             String canonicalFileName = f.getCanonicalPath();
1881             return canonicalFileName.startsWith(canonicalDirName);
1882         } catch (IOException e) {
1883             /* we do not expect the IOException here, because invocation
1884              * of this function is always preceded by isFile() call.
1885              */
1886             return false;
1887         }
1888     }
1889 
1890     /**
1891      * Checks whether built-in profile specified by fileName exists.
1892      */
1893     private static boolean standardProfileExists(final String fileName) {
1894         return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
1895                 public Boolean run() {
1896                     return PCMM.class.getResource("profiles/"+fileName) != null;
1897                 }
1898             });
1899     }
1900 
1901 
1902     /*
1903      * Serialization support.
1904      *
1905      * Directly deserialized profiles are useless since they are not
1906      * registered with CMM.  We don't allow constructor to be called
1907      * directly and instead have clients to call one of getInstance
1908      * factory methods that will register the profile with CMM.  For
1909      * deserialization we implement readResolve method that will
1910      * resolve the bogus deserialized profile object with one obtained
1911      * with getInstance as well.
1912      *
1913      * There are two primary factory methods for construction of ICC
1914      * profiles: getInstance(int cspace) and getInstance(byte[] data).
1915      * This implementation of ICC_Profile uses the former to return a
1916      * cached singleton profile object, other implementations will
1917      * likely use this technique too.  To preserve the singleton
1918      * pattern across serialization we serialize cached singleton
1919      * profiles in such a way that deserializing VM could call
1920      * getInstance(int cspace) method that will resolve deserialized
1921      * object into the corresponding singleton as well.
1922      *
1923      * Since the singletons are private to ICC_Profile the readResolve
1924      * method have to be `protected' instead of `private' so that
1925      * singletons that are instances of subclasses of ICC_Profile
1926      * could be correctly deserialized.
1927      */
1928 
1929 
1930     /**
1931      * Version of the format of additional serialized data in the
1932      * stream.  Version&nbsp;<code>1</code> corresponds to Java&nbsp;2
1933      * Platform,&nbsp;v1.3.
1934      * @since 1.3
1935      * @serial
1936      */
1937     private int iccProfileSerializedDataVersion = 1;
1938 
1939 
1940     /**
1941      * Writes default serializable fields to the stream.  Writes a
1942      * string and an array of bytes to the stream as additional data.
1943      *
1944      * @param s stream used for serialization.
1945      * @throws IOException
1946      *     thrown by <code>ObjectInputStream</code>.
1947      * @serialData
1948      *     The <code>String</code> is the name of one of
1949      *     <code>CS_<var>*</var></code> constants defined in the
1950      *     {@link ColorSpace} class if the profile object is a profile
1951      *     for a predefined color space (for example
1952      *     <code>"CS_sRGB"</code>).  The string is <code>null</code>
1953      *     otherwise.
1954      *     <p>
1955      *     The <code>byte[]</code> array is the profile data for the
1956      *     profile.  For predefined color spaces <code>null</code> is
1957      *     written instead of the profile data.  If in the future
1958      *     versions of Java API new predefined color spaces will be
1959      *     added, future versions of this class may choose to write
1960      *     for new predefined color spaces not only the color space
1961      *     name, but the profile data as well so that older versions
1962      *     could still deserialize the object.
1963      */
1964     private void writeObject(ObjectOutputStream s)
1965       throws IOException
1966     {
1967         s.defaultWriteObject();
1968 
1969         String csName = null;
1970         if (this == sRGBprofile) {
1971             csName = "CS_sRGB";
1972         } else if (this == XYZprofile) {
1973             csName = "CS_CIEXYZ";
1974         } else if (this == PYCCprofile) {
1975             csName = "CS_PYCC";
1976         } else if (this == GRAYprofile) {
1977             csName = "CS_GRAY";
1978         } else if (this == LINEAR_RGBprofile) {
1979             csName = "CS_LINEAR_RGB";
1980         }
1981 
1982         // Future versions may choose to write profile data for new
1983         // predefined color spaces as well, if any will be introduced,
1984         // so that old versions that don't recognize the new CS name
1985         // may fall back to constructing profile from the data.
1986         byte[] data = null;
1987         if (csName == null) {
1988             // getData will activate deferred profile if necessary
1989             data = getData();
1990         }
1991 
1992         s.writeObject(csName);
1993         s.writeObject(data);
1994     }
1995 
1996     // Temporary storage used by readObject to store resolved profile
1997     // (obtained with getInstance) for readResolve to return.
1998     private transient ICC_Profile resolvedDeserializedProfile;
1999 
2000     /**
2001      * Reads default serializable fields from the stream.  Reads from
2002      * the stream a string and an array of bytes as additional data.
2003      *
2004      * @param s stream used for deserialization.
2005      * @throws IOException
2006      *     thrown by <code>ObjectInputStream</code>.
2007      * @throws ClassNotFoundException
2008      *     thrown by <code>ObjectInputStream</code>.
2009      * @serialData
2010      *     The <code>String</code> is the name of one of
2011      *     <code>CS_<var>*</var></code> constants defined in the
2012      *     {@link ColorSpace} class if the profile object is a profile
2013      *     for a predefined color space (for example
2014      *     <code>"CS_sRGB"</code>).  The string is <code>null</code>
2015      *     otherwise.
2016      *     <p>
2017      *     The <code>byte[]</code> array is the profile data for the
2018      *     profile.  It will usually be <code>null</code> for the
2019      *     predefined profiles.
2020      *     <p>
2021      *     If the string is recognized as a constant name for
2022      *     predefined color space the object will be resolved into
2023      *     profile obtained with
2024      *     <code>getInstance(int&nbsp;cspace)</code> and the profile
2025      *     data are ignored.  Otherwise the object will be resolved
2026      *     into profile obtained with
2027      *     <code>getInstance(byte[]&nbsp;data)</code>.
2028      * @see #readResolve()
2029      * @see #getInstance(int)
2030      * @see #getInstance(byte[])
2031      */
2032     private void readObject(ObjectInputStream s)
2033       throws IOException, ClassNotFoundException
2034     {
2035         s.defaultReadObject();
2036 
2037         String csName = (String)s.readObject();
2038         byte[] data = (byte[])s.readObject();
2039 
2040         int cspace = 0;         // ColorSpace.CS_* constant if known
2041         boolean isKnownPredefinedCS = false;
2042         if (csName != null) {
2043             isKnownPredefinedCS = true;
2044             if (csName.equals("CS_sRGB")) {
2045                 cspace = ColorSpace.CS_sRGB;
2046             } else if (csName.equals("CS_CIEXYZ")) {
2047                 cspace = ColorSpace.CS_CIEXYZ;
2048             } else if (csName.equals("CS_PYCC")) {
2049                 cspace = ColorSpace.CS_PYCC;
2050             } else if (csName.equals("CS_GRAY")) {
2051                 cspace = ColorSpace.CS_GRAY;
2052             } else if (csName.equals("CS_LINEAR_RGB")) {
2053                 cspace = ColorSpace.CS_LINEAR_RGB;
2054             } else {
2055                 isKnownPredefinedCS = false;
2056             }
2057         }
2058 
2059         if (isKnownPredefinedCS) {
2060             resolvedDeserializedProfile = getInstance(cspace);
2061         } else {
2062             resolvedDeserializedProfile = getInstance(data);
2063         }
2064     }
2065 
2066     /**
2067      * Resolves instances being deserialized into instances registered
2068      * with CMM.
2069      * @return ICC_Profile object for profile registered with CMM.
2070      * @throws ObjectStreamException
2071      *     never thrown, but mandated by the serialization spec.
2072      * @since 1.3
2073      */
2074     protected Object readResolve() throws ObjectStreamException {
2075         return resolvedDeserializedProfile;
2076     }
2077 }