1 /*
   2  * Copyright (c) 2000, 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 package sun.print;
  27 
  28 import java.io.File;
  29 import java.net.URI;
  30 import java.net.URISyntaxException;
  31 import java.util.ArrayList;
  32 import java.util.HashMap;
  33 import javax.print.DocFlavor;
  34 import javax.print.DocPrintJob;
  35 import javax.print.PrintService;
  36 import javax.print.ServiceUIFactory;
  37 import javax.print.attribute.Attribute;
  38 import javax.print.attribute.AttributeSet;
  39 import javax.print.attribute.AttributeSetUtilities;
  40 import javax.print.attribute.EnumSyntax;
  41 import javax.print.attribute.HashAttributeSet;
  42 import javax.print.attribute.PrintServiceAttribute;
  43 import javax.print.attribute.PrintServiceAttributeSet;
  44 import javax.print.attribute.HashPrintServiceAttributeSet;
  45 import javax.print.attribute.standard.PrinterName;
  46 import javax.print.attribute.standard.PrinterIsAcceptingJobs;
  47 import javax.print.attribute.standard.QueuedJobCount;
  48 import javax.print.attribute.standard.JobName;
  49 import javax.print.attribute.standard.RequestingUserName;
  50 import javax.print.attribute.standard.Chromaticity;
  51 import javax.print.attribute.standard.Copies;
  52 import javax.print.attribute.standard.CopiesSupported;
  53 import javax.print.attribute.standard.Destination;
  54 import javax.print.attribute.standard.Fidelity;
  55 import javax.print.attribute.standard.Media;
  56 import javax.print.attribute.standard.MediaSizeName;
  57 import javax.print.attribute.standard.MediaSize;
  58 import javax.print.attribute.standard.MediaTray;
  59 import javax.print.attribute.standard.MediaPrintableArea;
  60 import javax.print.attribute.standard.OrientationRequested;
  61 import javax.print.attribute.standard.PageRanges;
  62 import javax.print.attribute.standard.PrinterState;
  63 import javax.print.attribute.standard.PrinterStateReason;
  64 import javax.print.attribute.standard.PrinterStateReasons;
  65 import javax.print.attribute.standard.Severity;
  66 import javax.print.attribute.standard.Sides;
  67 import javax.print.attribute.standard.ColorSupported;
  68 import javax.print.attribute.standard.PrintQuality;
  69 import javax.print.attribute.standard.PrinterResolution;
  70 import javax.print.attribute.standard.SheetCollate;
  71 import javax.print.event.PrintServiceAttributeListener;
  72 
  73 public class Win32PrintService implements PrintService, AttributeUpdater,
  74                                           SunPrinterJobService {
  75 
  76     public static MediaSize[] predefMedia;
  77 
  78     static {
  79         Class c = Win32MediaSize.class;
  80     }
  81 
  82     private static final DocFlavor[] supportedFlavors = {
  83         DocFlavor.BYTE_ARRAY.GIF,
  84         DocFlavor.INPUT_STREAM.GIF,
  85         DocFlavor.URL.GIF,
  86         DocFlavor.BYTE_ARRAY.JPEG,
  87         DocFlavor.INPUT_STREAM.JPEG,
  88         DocFlavor.URL.JPEG,
  89         DocFlavor.BYTE_ARRAY.PNG,
  90         DocFlavor.INPUT_STREAM.PNG,
  91         DocFlavor.URL.PNG,
  92         DocFlavor.SERVICE_FORMATTED.PAGEABLE,
  93         DocFlavor.SERVICE_FORMATTED.PRINTABLE,
  94         DocFlavor.BYTE_ARRAY.AUTOSENSE,
  95         DocFlavor.URL.AUTOSENSE,
  96         DocFlavor.INPUT_STREAM.AUTOSENSE
  97     };
  98 
  99     /* let's try to support a few of these */
 100     private static final Class[] serviceAttrCats = {
 101         PrinterName.class,
 102         PrinterIsAcceptingJobs.class,
 103         QueuedJobCount.class,
 104         ColorSupported.class,
 105     };
 106 
 107     /*  it turns out to be inconvenient to store the other categories
 108      *  separately because many attributes are in multiple categories.
 109      */
 110     private static Class[] otherAttrCats = {
 111         JobName.class,
 112         RequestingUserName.class,
 113         Copies.class,
 114         Destination.class,
 115         OrientationRequested.class,
 116         PageRanges.class,
 117         Media.class,
 118         MediaPrintableArea.class,
 119         Fidelity.class,
 120         // We support collation on 2D printer jobs, even if the driver can't.
 121         SheetCollate.class,
 122         SunAlternateMedia.class,
 123         Chromaticity.class
 124     };
 125 
 126 
 127     /*
 128      * This table together with methods findWin32Media and
 129      * findMatchingMediaSizeNameMM are declared public as these are also
 130      * used in WPrinterJob.java.
 131      */
 132     public static final MediaSizeName[] dmPaperToPrintService = {
 133       MediaSizeName.NA_LETTER, MediaSizeName.NA_LETTER,
 134       MediaSizeName.TABLOID, MediaSizeName.LEDGER,
 135       MediaSizeName.NA_LEGAL, MediaSizeName.INVOICE,
 136       MediaSizeName.EXECUTIVE, MediaSizeName.ISO_A3,
 137       MediaSizeName.ISO_A4, MediaSizeName.ISO_A4,
 138       MediaSizeName.ISO_A5, MediaSizeName.JIS_B4,
 139       MediaSizeName.JIS_B5, MediaSizeName.FOLIO,
 140       MediaSizeName.QUARTO, MediaSizeName.NA_10X14_ENVELOPE,
 141       MediaSizeName.B, MediaSizeName.NA_LETTER,
 142       MediaSizeName.NA_NUMBER_9_ENVELOPE, MediaSizeName.NA_NUMBER_10_ENVELOPE,
 143       MediaSizeName.NA_NUMBER_11_ENVELOPE, MediaSizeName.NA_NUMBER_12_ENVELOPE,
 144       MediaSizeName.NA_NUMBER_14_ENVELOPE, MediaSizeName.C,
 145       MediaSizeName.D, MediaSizeName.E,
 146       MediaSizeName.ISO_DESIGNATED_LONG, MediaSizeName.ISO_C5,
 147       MediaSizeName.ISO_C3, MediaSizeName.ISO_C4,
 148       MediaSizeName.ISO_C6, MediaSizeName.ITALY_ENVELOPE,
 149       MediaSizeName.ISO_B4, MediaSizeName.ISO_B5,
 150       MediaSizeName.ISO_B6, MediaSizeName.ITALY_ENVELOPE,
 151       MediaSizeName.MONARCH_ENVELOPE, MediaSizeName.PERSONAL_ENVELOPE,
 152       MediaSizeName.NA_10X15_ENVELOPE, MediaSizeName.NA_9X12_ENVELOPE,
 153       MediaSizeName.FOLIO, MediaSizeName.ISO_B4,
 154       MediaSizeName.JAPANESE_POSTCARD, MediaSizeName.NA_9X11_ENVELOPE,
 155     };
 156 
 157     private static final MediaTray[] dmPaperBinToPrintService = {
 158       MediaTray.TOP, MediaTray.BOTTOM, MediaTray.MIDDLE,
 159       MediaTray.MANUAL, MediaTray.ENVELOPE, Win32MediaTray.ENVELOPE_MANUAL,
 160       Win32MediaTray.AUTO, Win32MediaTray.TRACTOR,
 161       Win32MediaTray.SMALL_FORMAT, Win32MediaTray.LARGE_FORMAT,
 162       MediaTray.LARGE_CAPACITY, null, null,
 163       MediaTray.MAIN, Win32MediaTray.FORMSOURCE,
 164     };
 165 
 166     // from wingdi.h
 167     private static int DM_PAPERSIZE = 0x2;
 168     private static int DM_PRINTQUALITY = 0x400;
 169     private static int DM_YRESOLUTION = 0x2000;
 170     private static final int DMRES_MEDIUM = -3;
 171     private static final int DMRES_HIGH = -4;
 172     private static final int DMORIENT_LANDSCAPE = 2;
 173     private static final int DMDUP_VERTICAL = 2;
 174     private static final int DMDUP_HORIZONTAL = 3;
 175     private static final int DMCOLLATE_TRUE = 1;
 176 
 177     // media sizes with indices above dmPaperToPrintService' length
 178     private static final int DMPAPER_A2 = 66;
 179     private static final int DMPAPER_A6 = 70;
 180     private static final int DMPAPER_B6_JIS = 88;
 181 
 182 
 183     // Bit settings for getPrinterCapabilities which matches that
 184     // of native getCapabilities in WPrinterJob.cpp
 185     private static final int DEVCAP_COLOR = 0x0001;
 186     private static final int DEVCAP_DUPLEX = 0x0002;
 187     private static final int DEVCAP_COLLATE = 0x0004;
 188     private static final int DEVCAP_QUALITY = 0x0008;
 189     private static final int DEVCAP_POSTSCRIPT = 0x0010;
 190 
 191     private String printer;
 192     private PrinterName name;
 193     private String port;
 194 
 195     transient private PrintServiceAttributeSet lastSet;
 196     transient private ServiceNotifier notifier = null;
 197 
 198     private MediaSizeName[] mediaSizeNames;
 199     private MediaPrintableArea[] mediaPrintables;
 200     private MediaTray[] mediaTrays;
 201     private PrinterResolution[] printRes;
 202     private HashMap mpaMap;
 203     private int nCopies;
 204     private int prnCaps;
 205     private int[] defaultSettings;
 206 
 207     private boolean gotTrays;
 208     private boolean gotCopies;
 209     private boolean mediaInitialized;
 210     private boolean mpaListInitialized;
 211 
 212     private ArrayList idList;
 213     private MediaSize[] mediaSizes;
 214 
 215     private boolean isInvalid;
 216 
 217     Win32PrintService(String name) {
 218         if (name == null) {
 219             throw new IllegalArgumentException("null printer name");
 220         }
 221         printer = name;
 222 
 223         // initialize flags
 224         mediaInitialized = false;
 225         gotTrays = false;
 226         gotCopies = false;
 227         isInvalid = false;
 228         printRes = null;
 229         prnCaps = 0;
 230         defaultSettings = null;
 231         port = null;
 232     }
 233 
 234     public void invalidateService() {
 235         isInvalid = true;
 236     }
 237 
 238     public String getName() {
 239         return printer;
 240     }
 241 
 242     private PrinterName getPrinterName() {
 243         if (name == null) {
 244             name = new PrinterName(printer, null);
 245         }
 246         return name;
 247     }
 248 
 249     public int findPaperID(MediaSizeName msn) {
 250         if (msn instanceof Win32MediaSize) {
 251             Win32MediaSize winMedia = (Win32MediaSize)msn;
 252             return winMedia.getDMPaper();
 253         } else {
 254             for (int id=0; id<dmPaperToPrintService.length;id++) {
 255                 if (dmPaperToPrintService[id].equals(msn)) {
 256                     return id+1; // DMPAPER_LETTER == 1
 257                 }
 258             }
 259             if (msn.equals(MediaSizeName.ISO_A2)) {
 260                 return DMPAPER_A2;
 261             }
 262             else if (msn.equals(MediaSizeName.ISO_A6)) {
 263                 return DMPAPER_A6;
 264             }
 265             else if (msn.equals(MediaSizeName.JIS_B6)) {
 266                 return DMPAPER_B6_JIS;
 267             }
 268         }
 269 
 270         // If not found in predefined Windows ID, then we search through
 271         // the returned IDs of the driver because they can define their own
 272         // unique IDs.
 273         initMedia();
 274 
 275         if ((idList != null) && (mediaSizes != null) &&
 276             (idList.size() == mediaSizes.length)) {
 277             for (int i=0; i< idList.size(); i++) {
 278                 if (mediaSizes[i].getMediaSizeName() == msn) {
 279                     return ((Integer)idList.get(i)).intValue();
 280                 }
 281             }
 282         }
 283         return 0;
 284     }
 285 
 286     public MediaTray findMediaTray(int dmBin) {
 287         if (dmBin >= 1 && dmBin <= dmPaperBinToPrintService.length) {
 288             return dmPaperBinToPrintService[dmBin-1];
 289         }
 290         MediaTray[] trays = getMediaTrays();
 291         if (trays != null) {
 292             for (int i=0;i<trays.length;i++) {
 293                 if(trays[i] instanceof Win32MediaTray) {
 294                     Win32MediaTray win32Tray = (Win32MediaTray)trays[i];
 295                     if (win32Tray.winID == dmBin) {
 296                         return win32Tray;
 297                     }
 298                 }
 299             }
 300         }
 301         return Win32MediaTray.AUTO;
 302     }
 303 
 304     public MediaSizeName findWin32Media(int dmIndex) {
 305         if (dmIndex >= 1 && dmIndex <= dmPaperToPrintService.length) {
 306             return dmPaperToPrintService[dmIndex - 1];
 307         }
 308         switch(dmIndex) {
 309             /* matching media sizes with indices beyond
 310                dmPaperToPrintService's length */
 311             case DMPAPER_A2:
 312                 return MediaSizeName.ISO_A2;
 313             case DMPAPER_A6:
 314                 return MediaSizeName.ISO_A6;
 315             case DMPAPER_B6_JIS:
 316                 return MediaSizeName.JIS_B6;
 317             default:
 318                 return null;
 319         }
 320     }
 321 
 322     private boolean addToUniqueList(ArrayList msnList, MediaSizeName mediaName) {
 323         MediaSizeName msn;
 324         for (int i=0; i< msnList.size(); i++) {
 325             msn = (MediaSizeName)msnList.get(i);
 326             if (msn == mediaName) {
 327                 return false;
 328             }
 329         }
 330         msnList.add(mediaName);
 331         return true;
 332     }
 333 
 334     private synchronized void initMedia() {
 335         if (mediaInitialized == true) {
 336             return;
 337         }
 338         mediaInitialized = true;
 339         int[] media = getAllMediaIDs(printer, getPort());
 340         if (media == null) {
 341             return;
 342         }
 343 
 344         ArrayList msnList = new ArrayList();
 345         ArrayList printableList = new ArrayList();
 346         MediaSizeName mediaName;
 347         boolean added;
 348         boolean queryFailure = false;
 349         float[] prnArea;
 350 
 351         // Get all mediaSizes supported by the printer.
 352         // We convert media to ArrayList idList and pass this to the
 353         // function for getting mediaSizes.
 354         // This is to ensure that mediaSizes and media IDs have 1-1 correspondence.
 355         // We remove from ID list any invalid mediaSize.  Though this is rare,
 356         // it happens in HP 4050 German driver.
 357 
 358         idList = new ArrayList();
 359         for (int i=0; i < media.length; i++) {
 360             idList.add(Integer.valueOf(media[i]));
 361         }
 362 
 363         ArrayList<String> dmPaperNameList = new ArrayList<String>();
 364         mediaSizes = getMediaSizes(idList, media, dmPaperNameList);
 365         for (int i = 0; i < idList.size(); i++) {
 366 
 367             // match Win ID with our predefined ID using table
 368             mediaName = findWin32Media(((Integer)idList.get(i)).intValue());
 369             // Verify that this standard size is the same size as that
 370             // reported by the driver. This should be the case except when
 371             // the driver is mis-using a standard windows paper ID.
 372             if (mediaName != null &&
 373                 idList.size() == mediaSizes.length) {
 374                 MediaSize win32Size = MediaSize.getMediaSizeForName(mediaName);
 375                 MediaSize driverSize = mediaSizes[i];
 376                 int error = 2540; // == 1/10"
 377                 if (Math.abs(win32Size.getX(1)-driverSize.getX(1)) > error ||
 378                     Math.abs(win32Size.getY(1)-driverSize.getY(1)) > error)
 379                 {
 380                    mediaName = null;
 381                 }
 382             }
 383 
 384             // No match found, then we get the MediaSizeName out of the MediaSize
 385             // This requires 1-1 correspondence, lengths must be checked.
 386             if ((mediaName == null) && (idList.size() == mediaSizes.length)) {
 387                 mediaName = mediaSizes[i].getMediaSizeName();
 388             }
 389 
 390             // Add mediaName to the msnList
 391             if (mediaName != null) {
 392                 added = addToUniqueList(msnList, mediaName);
 393                 /* The following block allows to add such media names to the list, whose sizes
 394                  * matched with media sizes predefined in JDK, while whose paper IDs did not.
 395                  */
 396                 if (!added && (idList.size() == dmPaperNameList.size())) {
 397                     Win32MediaSize wms = Win32MediaSize.findMediaName(dmPaperNameList.get(i));
 398                     if ((wms == null) && (idList.size() == mediaSizes.length)) {
 399                         wms = new Win32MediaSize(dmPaperNameList.get(i), (Integer)idList.get(i));
 400                         mediaSizes[i] = new MediaSize(mediaSizes[i].getX(MediaSize.MM),
 401                             mediaSizes[i].getY(MediaSize.MM), MediaSize.MM, wms);
 402                     }
 403                     if (wms != null) {
 404                         mediaName = wms;
 405                         added = addToUniqueList(msnList, mediaName);
 406                     }
 407                 }
 408             }
 409         }
 410 
 411         // init mediaSizeNames
 412         mediaSizeNames = new MediaSizeName[msnList.size()];
 413         msnList.toArray(mediaSizeNames);
 414     }
 415 
 416 
 417     /*
 418      * Gets a list of MediaPrintableAreas using a call to native function.
 419      *  msn is MediaSizeName used to get a specific printable area.  If null,
 420      *  it will get all the supported MediPrintableAreas.
 421      */
 422     private synchronized MediaPrintableArea[] getMediaPrintables(MediaSizeName msn)
 423     {
 424         if (msn == null)  {
 425             if (mpaListInitialized == true) {
 426                 return mediaPrintables;
 427             }
 428         } else {
 429             // get from cached mapping of MPAs
 430             if (mpaMap != null && (mpaMap.get(msn) != null)) {
 431                 MediaPrintableArea[] mpaArr = new MediaPrintableArea[1];
 432                 mpaArr[0] = (MediaPrintableArea)mpaMap.get(msn);
 433                 return mpaArr;
 434             }
 435         }
 436 
 437         initMedia();
 438 
 439         if ((mediaSizeNames == null) && (mediaSizeNames.length == 0)) {
 440             return null;
 441         }
 442 
 443         MediaSizeName[] loopNames;
 444         if (msn != null) {
 445             loopNames = new MediaSizeName[1];
 446             loopNames[0] = msn;
 447         } else {
 448             loopNames = mediaSizeNames;
 449         }
 450 
 451         if (mpaMap == null) {
 452             mpaMap = new HashMap();
 453         }
 454 
 455         for (int i=0; i < loopNames.length; i++) {
 456             MediaSizeName mediaName = loopNames[i];
 457 
 458             if (mpaMap.get(mediaName) != null) {
 459                 continue;
 460              }
 461 
 462             if (mediaName != null) {
 463                 int defPaper = findPaperID(mediaName);
 464                 float[] prnArea = (defPaper != 0) ? getMediaPrintableArea(printer, defPaper) : null;
 465                 MediaPrintableArea printableArea = null;
 466                 if (prnArea != null) {
 467                     try {
 468                         printableArea = new MediaPrintableArea(prnArea[0],
 469                                                                prnArea[1],
 470                                                                prnArea[2],
 471                                                                prnArea[3],
 472                                                  MediaPrintableArea.INCH);
 473 
 474                         mpaMap.put(mediaName, printableArea);
 475                     }
 476                     catch (IllegalArgumentException e) {
 477                     }
 478                 } else {
 479                     // if getting  MPA failed, we use MediaSize
 480                     MediaSize ms =
 481                         MediaSize.getMediaSizeForName((MediaSizeName)mediaName);
 482 
 483                     if (ms != null) {
 484                         try {
 485                             printableArea = new MediaPrintableArea(0, 0,
 486                                                      ms.getX(MediaSize.INCH),
 487                                                      ms.getY(MediaSize.INCH),
 488                                                      MediaPrintableArea.INCH);
 489                             mpaMap.put(mediaName, printableArea);
 490                         } catch (IllegalArgumentException e) {
 491                         }
 492                     }
 493                 }
 494             } //mediaName != null
 495         }
 496 
 497        if (mpaMap.size() == 0) {
 498            return null;
 499        }
 500 
 501        if (msn != null) {
 502            if (mpaMap.get(msn) == null) {
 503                return null;
 504            }
 505            MediaPrintableArea[] mpaArr = new MediaPrintableArea[1];
 506            // by this time, we've already gotten the desired MPA
 507            mpaArr[0] = (MediaPrintableArea)mpaMap.get(msn);
 508            return mpaArr;
 509        } else {
 510            mediaPrintables = (MediaPrintableArea[])mpaMap.values().toArray(new MediaPrintableArea[0]);
 511            mpaListInitialized = true;
 512            return mediaPrintables;
 513        }
 514     }
 515 
 516 
 517     private synchronized MediaTray[] getMediaTrays() {
 518         if (gotTrays == true && mediaTrays != null) {
 519             return mediaTrays;
 520         }
 521         String prnPort = getPort();
 522         int[] mediaTr = getAllMediaTrays(printer, prnPort);
 523         String[] winMediaTrayNames = getAllMediaTrayNames(printer, prnPort);
 524 
 525         if ((mediaTr == null) || (winMediaTrayNames == null)){
 526             return null;
 527         }
 528 
 529         /* first count how many valid bins there are so we can allocate
 530          * an array of the correct size
 531          */
 532         int nTray = 0;
 533         for (int i=0; i < mediaTr.length ; i++) {
 534             if (mediaTr[i] > 0) nTray++;
 535         }
 536 
 537         MediaTray[] arr = new MediaTray[nTray];
 538         int dmBin;
 539 
 540         /* Some drivers in Win 7 don't have the same length for DC_BINS and
 541          * DC_BINNAMES so there is no guarantee that lengths of mediaTr and
 542          * winMediaTrayNames are equal. To avoid getting ArrayIndexOutOfBounds,
 543          * we need to make sure we get the minimum of the two.
 544          */
 545 
 546         for (int i = 0, j=0; i < Math.min(mediaTr.length, winMediaTrayNames.length); i++) {
 547             dmBin = mediaTr[i];
 548             if (dmBin > 0) {
 549                 // check for unsupported DMBINs and create new Win32MediaTray
 550                 if ((dmBin > dmPaperBinToPrintService.length)
 551                     || (dmPaperBinToPrintService[dmBin-1] == null)) {
 552                     arr[j++] = new Win32MediaTray(dmBin, winMediaTrayNames[i]);
 553                 } else {
 554                     arr[j++] = dmPaperBinToPrintService[dmBin-1];
 555                 }
 556             }
 557             // no else - For invalid ids, just ignore it because assigning a "default"
 558             // value may result in duplicate trays.
 559         }
 560         mediaTrays = arr;
 561         gotTrays = true;
 562         return mediaTrays;
 563     }
 564 
 565     private boolean isSameSize(float w1, float h1, float w2, float h2) {
 566         float diffX = w1 - w2;
 567         float diffY = h1 - h2;
 568         // Get diff of reverse dimensions
 569         // EPSON Stylus COLOR 860 reverses envelope's width & height
 570         float diffXrev = w1 - h2;
 571         float diffYrev = h1 - w2;
 572 
 573         if (((Math.abs(diffX)<=1) && (Math.abs(diffY)<=1)) ||
 574             ((Math.abs(diffXrev)<=1) && (Math.abs(diffYrev)<=1))){
 575           return true;
 576         } else {
 577           return false;
 578         }
 579     }
 580 
 581     public MediaSizeName findMatchingMediaSizeNameMM (float w, float h){
 582         if (predefMedia != null) {
 583             for (int k=0; k<predefMedia.length;k++) {
 584                 if (predefMedia[k] == null) {
 585                     continue;
 586                 }
 587 
 588                 if (isSameSize(predefMedia[k].getX(MediaSize.MM),
 589                                predefMedia[k].getY(MediaSize.MM),
 590                                w, h)) {
 591                   return predefMedia[k].getMediaSizeName();
 592                 }
 593             }
 594         }
 595         return null;
 596     }
 597 
 598 
 599     private MediaSize[] getMediaSizes(ArrayList idList, int[] media, ArrayList<String> dmPaperNameList) {
 600         if (dmPaperNameList == null) {
 601             dmPaperNameList = new ArrayList<String>();
 602         }
 603 
 604         String prnPort = getPort();
 605         int[] mediaSz = getAllMediaSizes(printer, prnPort);
 606         String[] winMediaNames = getAllMediaNames(printer, prnPort);
 607         MediaSizeName msn = null;
 608         MediaSize ms = null;
 609         float wid, ht;
 610 
 611         if ((mediaSz == null) || (winMediaNames == null)) {
 612             return null;
 613         }
 614 
 615         int nMedia = mediaSz.length/2;
 616         ArrayList msList = new ArrayList();
 617 
 618         for (int i = 0; i < nMedia; i++, ms=null) {
 619             wid = mediaSz[i*2]/10f;
 620             ht = mediaSz[i*2+1]/10f;
 621 
 622             // Make sure to validate wid & ht.
 623             // HP LJ 4050 (german) causes IAE in Sonderformat paper, wid & ht
 624             // returned is not constant.
 625             if ((wid <= 0) || (ht <= 0)) {
 626                 //Remove corresponding ID from list
 627                 if (nMedia == media.length) {
 628                     Integer remObj = Integer.valueOf(media[i]);
 629                     idList.remove(idList.indexOf(remObj));
 630                 }
 631                 continue;
 632             }
 633             // Find matching media using dimensions.
 634             // This call matches only with our own predefined sizes.
 635             msn = findMatchingMediaSizeNameMM(wid, ht);
 636             if (msn != null) {
 637                 ms = MediaSize.getMediaSizeForName(msn);
 638             }
 639 
 640             if (ms != null) {
 641                 msList.add(ms);
 642                 dmPaperNameList.add(winMediaNames[i]);
 643             } else {
 644                 Win32MediaSize wms = Win32MediaSize.findMediaName(winMediaNames[i]);
 645                 if (wms == null) {
 646                     wms = new Win32MediaSize(winMediaNames[i], media[i]);
 647                 }
 648                 try {
 649                     ms = new MediaSize(wid, ht, MediaSize.MM, wms);
 650                     msList.add(ms);
 651                     dmPaperNameList.add(winMediaNames[i]);
 652                 } catch(IllegalArgumentException e) {
 653                     if (nMedia == media.length) {
 654                         Integer remObj = Integer.valueOf(media[i]);
 655                         idList.remove(idList.indexOf(remObj));
 656                     }
 657                 }
 658             }
 659         }
 660 
 661         MediaSize[] arr2 = new MediaSize[msList.size()];
 662         msList.toArray(arr2);
 663 
 664         return arr2;
 665     }
 666 
 667 
 668     private PrinterIsAcceptingJobs getPrinterIsAcceptingJobs() {
 669         if (getJobStatus(printer, 2) != 1) {
 670             return PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS;
 671         }
 672         else {
 673             return PrinterIsAcceptingJobs.ACCEPTING_JOBS;
 674         }
 675     }
 676 
 677     private PrinterState getPrinterState() {
 678         if (isInvalid) {
 679             return PrinterState.STOPPED;
 680         } else {
 681             return null;
 682         }
 683     }
 684 
 685     private PrinterStateReasons getPrinterStateReasons() {
 686         if (isInvalid) {
 687             PrinterStateReasons psr = new PrinterStateReasons();
 688             psr.put(PrinterStateReason.SHUTDOWN, Severity.ERROR);
 689             return psr;
 690         } else {
 691             return null;
 692         }
 693     }
 694 
 695     private QueuedJobCount getQueuedJobCount() {
 696 
 697         int count = getJobStatus(printer, 1);
 698         if (count != -1) {
 699             return new QueuedJobCount(count);
 700         }
 701         else {
 702             return new QueuedJobCount(0);
 703         }
 704     }
 705 
 706     private boolean isSupportedCopies(Copies copies) {
 707         synchronized (this) {
 708             if (gotCopies == false) {
 709                 nCopies = getCopiesSupported(printer, getPort());
 710                 gotCopies = true;
 711             }
 712         }
 713         int numCopies = copies.getValue();
 714         return (numCopies > 0 && numCopies <= nCopies);
 715     }
 716 
 717     private boolean isSupportedMedia(MediaSizeName msn) {
 718 
 719         initMedia();
 720 
 721         if (mediaSizeNames != null) {
 722             for (int i=0; i<mediaSizeNames.length; i++) {
 723                 if (msn.equals(mediaSizeNames[i])) {
 724                     return true;
 725                 }
 726             }
 727         }
 728         return false;
 729     }
 730 
 731     private boolean isSupportedMediaPrintableArea(MediaPrintableArea mpa) {
 732 
 733         getMediaPrintables(null);
 734 
 735         if (mediaPrintables != null) {
 736             for (int i=0; i<mediaPrintables.length; i++) {
 737                 if (mpa.equals(mediaPrintables[i])) {
 738                     return true;
 739                 }
 740             }
 741         }
 742         return false;
 743     }
 744 
 745     private boolean isSupportedMediaTray(MediaTray msn) {
 746         MediaTray[] trays = getMediaTrays();
 747 
 748         if (trays != null) {
 749             for (int i=0; i<trays.length; i++) {
 750                 if (msn.equals(trays[i])) {
 751                     return true;
 752                 }
 753             }
 754         }
 755         return false;
 756     }
 757 
 758     private int getPrinterCapabilities() {
 759         if (prnCaps == 0) {
 760             prnCaps = getCapabilities(printer, getPort());
 761         }
 762         return prnCaps;
 763     }
 764 
 765     private String getPort() {
 766         if (port == null) {
 767             port = getPrinterPort(printer);
 768         }
 769         return port;
 770     }
 771 
 772    /*
 773     * NOTE: defaults indices must match those in WPrinterJob.cpp
 774     */
 775     private int[] getDefaultPrinterSettings() {
 776         if (defaultSettings == null) {
 777             defaultSettings = getDefaultSettings(printer, getPort());
 778         }
 779         return defaultSettings;
 780     }
 781 
 782     private PrinterResolution[] getPrintResolutions() {
 783         if (printRes == null) {
 784             int[] prnRes = getAllResolutions(printer, getPort());
 785             if (prnRes == null) {
 786                 printRes = new PrinterResolution[0];
 787             } else {
 788                 int nRes = prnRes.length/2;
 789 
 790                 ArrayList arrList = new ArrayList();
 791                 PrinterResolution pr;
 792 
 793                 for (int i=0; i<nRes; i++) {
 794                   try {
 795                         pr = new PrinterResolution(prnRes[i*2],
 796                                        prnRes[i*2+1], PrinterResolution.DPI);
 797                         arrList.add(pr);
 798                     } catch (IllegalArgumentException e) {
 799                     }
 800                 }
 801 
 802                 printRes = (PrinterResolution[])arrList.toArray(
 803                                         new PrinterResolution[arrList.size()]);
 804             }
 805         }
 806         return printRes;
 807     }
 808 
 809     private boolean isSupportedResolution(PrinterResolution res) {
 810         PrinterResolution[] supportedRes = getPrintResolutions();
 811         if (supportedRes != null) {
 812             for (int i=0; i<supportedRes.length; i++) {
 813                 if (res.equals(supportedRes[i])) {
 814                     return true;
 815                 }
 816             }
 817         }
 818         return false;
 819     }
 820 
 821     public DocPrintJob createPrintJob() {
 822       SecurityManager security = System.getSecurityManager();
 823       if (security != null) {
 824         security.checkPrintJobAccess();
 825       }
 826         return new Win32PrintJob(this);
 827     }
 828 
 829     private PrintServiceAttributeSet getDynamicAttributes() {
 830         PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet();
 831         attrs.add(getPrinterIsAcceptingJobs());
 832         attrs.add(getQueuedJobCount());
 833         return attrs;
 834     }
 835 
 836     public PrintServiceAttributeSet getUpdatedAttributes() {
 837         PrintServiceAttributeSet currSet = getDynamicAttributes();
 838         if (lastSet == null) {
 839             lastSet = currSet;
 840             return AttributeSetUtilities.unmodifiableView(currSet);
 841         } else {
 842             PrintServiceAttributeSet updates =
 843                 new HashPrintServiceAttributeSet();
 844             Attribute []attrs =  currSet.toArray();
 845             for (int i=0; i<attrs.length; i++) {
 846                 Attribute attr = attrs[i];
 847                 if (!lastSet.containsValue(attr)) {
 848                     updates.add(attr);
 849                 }
 850             }
 851             lastSet = currSet;
 852             return AttributeSetUtilities.unmodifiableView(updates);
 853         }
 854     }
 855 
 856     public void wakeNotifier() {
 857         synchronized (this) {
 858             if (notifier != null) {
 859                 notifier.wake();
 860             }
 861         }
 862     }
 863 
 864     public void addPrintServiceAttributeListener(PrintServiceAttributeListener
 865                                                  listener) {
 866         synchronized (this) {
 867             if (listener == null) {
 868                 return;
 869             }
 870             if (notifier == null) {
 871                 notifier = new ServiceNotifier(this);
 872             }
 873             notifier.addListener(listener);
 874         }
 875     }
 876 
 877     public void removePrintServiceAttributeListener(
 878                                       PrintServiceAttributeListener listener) {
 879         synchronized (this) {
 880             if (listener == null || notifier == null ) {
 881                 return;
 882             }
 883             notifier.removeListener(listener);
 884             if (notifier.isEmpty()) {
 885                 notifier.stopNotifier();
 886                 notifier = null;
 887             }
 888         }
 889     }
 890 
 891     public <T extends PrintServiceAttribute> T
 892         getAttribute(Class<T> category)
 893     {
 894         if (category == null) {
 895             throw new NullPointerException("category");
 896         }
 897         if (!(PrintServiceAttribute.class.isAssignableFrom(category))) {
 898             throw new IllegalArgumentException("Not a PrintServiceAttribute");
 899         }
 900         if (category == ColorSupported.class) {
 901             int caps = getPrinterCapabilities();
 902             if ((caps & DEVCAP_COLOR) != 0) {
 903                 return (T)ColorSupported.SUPPORTED;
 904             } else {
 905                 return (T)ColorSupported.NOT_SUPPORTED;
 906             }
 907         } else if (category == PrinterName.class) {
 908             return (T)getPrinterName();
 909         } else if (category == PrinterState.class) {
 910             return (T)getPrinterState();
 911         } else if (category == PrinterStateReasons.class) {
 912             return (T)getPrinterStateReasons();
 913         } else if (category == QueuedJobCount.class) {
 914             return (T)getQueuedJobCount();
 915         } else if (category == PrinterIsAcceptingJobs.class) {
 916             return (T)getPrinterIsAcceptingJobs();
 917         } else {
 918             return null;
 919         }
 920     }
 921 
 922     public PrintServiceAttributeSet getAttributes() {
 923 
 924         PrintServiceAttributeSet attrs = new  HashPrintServiceAttributeSet();
 925         attrs.add(getPrinterName());
 926         attrs.add(getPrinterIsAcceptingJobs());
 927         PrinterState prnState = getPrinterState();
 928         if (prnState != null) {
 929             attrs.add(prnState);
 930         }
 931         PrinterStateReasons prnStateReasons = getPrinterStateReasons();
 932         if (prnStateReasons != null) {
 933             attrs.add(prnStateReasons);
 934         }
 935         attrs.add(getQueuedJobCount());
 936         int caps = getPrinterCapabilities();
 937         if ((caps & DEVCAP_COLOR) != 0) {
 938             attrs.add(ColorSupported.SUPPORTED);
 939         } else {
 940             attrs.add(ColorSupported.NOT_SUPPORTED);
 941         }
 942 
 943         return AttributeSetUtilities.unmodifiableView(attrs);
 944     }
 945 
 946     public DocFlavor[] getSupportedDocFlavors() {
 947         int len = supportedFlavors.length;
 948         DocFlavor[] supportedDocFlavors;
 949         int caps = getPrinterCapabilities();
 950         // doc flavors supported
 951         // if PostScript is supported
 952         if ((caps & DEVCAP_POSTSCRIPT) != 0) {
 953             supportedDocFlavors = new DocFlavor[len+3];
 954             System.arraycopy(supportedFlavors, 0, supportedDocFlavors, 0, len);
 955             supportedDocFlavors[len] = DocFlavor.BYTE_ARRAY.POSTSCRIPT;
 956             supportedDocFlavors[len+1] = DocFlavor.INPUT_STREAM.POSTSCRIPT;
 957             supportedDocFlavors[len+2] = DocFlavor.URL.POSTSCRIPT;
 958         } else {
 959             supportedDocFlavors = new DocFlavor[len];
 960             System.arraycopy(supportedFlavors, 0, supportedDocFlavors, 0, len);
 961         }
 962         return supportedDocFlavors;
 963     }
 964 
 965     public boolean isDocFlavorSupported(DocFlavor flavor) {
 966         /* To avoid a native query which may be time-consuming
 967          * do not invoke native unless postscript support is being queried.
 968          * Instead just check the ones we 'always' support
 969          */
 970         DocFlavor[] supportedDocFlavors;
 971         if (isPostScriptFlavor(flavor)) {
 972             supportedDocFlavors = getSupportedDocFlavors();
 973         } else {
 974             supportedDocFlavors = supportedFlavors;
 975         }
 976         for (int f=0; f<supportedDocFlavors.length; f++) {
 977             if (flavor.equals(supportedDocFlavors[f])) {
 978                 return true;
 979             }
 980         }
 981         return false;
 982     }
 983 
 984     public Class<?>[] getSupportedAttributeCategories() {
 985         ArrayList categList = new ArrayList(otherAttrCats.length+3);
 986         for (int i=0; i < otherAttrCats.length; i++) {
 987             categList.add(otherAttrCats[i]);
 988         }
 989 
 990         int caps = getPrinterCapabilities();
 991 
 992         if ((caps & DEVCAP_DUPLEX) != 0) {
 993             categList.add(Sides.class);
 994         }
 995 
 996         if ((caps & DEVCAP_QUALITY) != 0) {
 997             int[] defaults = getDefaultPrinterSettings();
 998             // Added check: if supported, we should be able to get the default.
 999             if ((defaults[3] >= DMRES_HIGH) && (defaults[3] < 0)) {
1000                 categList.add(PrintQuality.class);
1001             }
1002         }
1003 
1004         PrinterResolution[] supportedRes = getPrintResolutions();
1005         if ((supportedRes!=null) && (supportedRes.length>0)) {
1006             categList.add(PrinterResolution.class);
1007         }
1008 
1009         return (Class[])categList.toArray(new Class[categList.size()]);
1010     }
1011 
1012     public boolean
1013         isAttributeCategorySupported(Class<? extends Attribute> category)
1014     {
1015 
1016         if (category == null) {
1017             throw new NullPointerException("null category");
1018         }
1019 
1020         if (!(Attribute.class.isAssignableFrom(category))) {
1021             throw new IllegalArgumentException(category +
1022                                                " is not an Attribute");
1023         }
1024 
1025         Class[] classList = getSupportedAttributeCategories();
1026         for (int i = 0; i < classList.length; i++) {
1027             if (category.equals(classList[i])) {
1028                 return true;
1029             }
1030         }
1031 
1032         return false;
1033     }
1034 
1035     public Object
1036         getDefaultAttributeValue(Class<? extends Attribute> category)
1037     {
1038         if (category == null) {
1039             throw new NullPointerException("null category");
1040         }
1041         if (!Attribute.class.isAssignableFrom(category)) {
1042             throw new IllegalArgumentException(category +
1043                                                " is not an Attribute");
1044         }
1045 
1046         if (!isAttributeCategorySupported(category)) {
1047             return null;
1048         }
1049 
1050         int[] defaults = getDefaultPrinterSettings();
1051         // indices must match those in WPrinterJob.cpp
1052         int defPaper = defaults[0];
1053         int defYRes = defaults[2];
1054         int defQuality = defaults[3];
1055         int defCopies = defaults[4];
1056         int defOrient = defaults[5];
1057         int defSides = defaults[6];
1058         int defCollate = defaults[7];
1059 
1060         if (category == Copies.class) {
1061             if (defCopies > 0) {
1062                 return new Copies(defCopies);
1063             } else {
1064                 return new Copies(1);
1065             }
1066         } else if (category == Chromaticity.class) {
1067             int caps = getPrinterCapabilities();
1068             if ((caps & DEVCAP_COLOR) == 0) {
1069                 return Chromaticity.MONOCHROME;
1070             } else {
1071                 return Chromaticity.COLOR;
1072             }
1073         } else if (category == JobName.class) {
1074             return new JobName("Java Printing", null);
1075         } else if (category == OrientationRequested.class) {
1076             if (defOrient == DMORIENT_LANDSCAPE) {
1077                 return OrientationRequested.LANDSCAPE;
1078             } else {
1079                 return OrientationRequested.PORTRAIT;
1080             }
1081         } else if (category == PageRanges.class) {
1082             return new PageRanges(1, Integer.MAX_VALUE);
1083         } else if (category == Media.class) {
1084             MediaSizeName msn = findWin32Media(defPaper);
1085             if (msn != null) {
1086                 if (!isSupportedMedia(msn) && mediaSizeNames != null) {
1087                     msn = mediaSizeNames[0];
1088                     defPaper = findPaperID(msn);
1089                 }
1090                 return msn;
1091              } else {
1092                  initMedia();
1093                  if ((mediaSizeNames != null) && (mediaSizeNames.length > 0)) {
1094                      // if 'mediaSizeNames' is not null, idList and mediaSizes
1095                      // cannot be null but to be safe, add a check
1096                      if ((idList != null) && (mediaSizes != null) &&
1097                          (idList.size() == mediaSizes.length)) {
1098                          Integer defIdObj = Integer.valueOf(defPaper);
1099                          int index = idList.indexOf(defIdObj);
1100                          if (index>=0 && index<mediaSizes.length) {
1101                              return mediaSizes[index].getMediaSizeName();
1102                          }
1103                      }
1104 
1105                      return mediaSizeNames[0];
1106                  }
1107              }
1108         } else if (category == MediaPrintableArea.class) {
1109             /* Verify defPaper */
1110             MediaSizeName msn = findWin32Media(defPaper);
1111             if (msn != null &&
1112                 !isSupportedMedia(msn) && mediaSizeNames != null) {
1113                 defPaper = findPaperID(mediaSizeNames[0]);
1114             }
1115             float[] prnArea = getMediaPrintableArea(printer, defPaper);
1116             if (prnArea != null) {
1117                 MediaPrintableArea printableArea = null;
1118                 try {
1119                     printableArea = new MediaPrintableArea(prnArea[0],
1120                                                            prnArea[1],
1121                                                            prnArea[2],
1122                                                            prnArea[3],
1123                                                            MediaPrintableArea.INCH);
1124                 } catch (IllegalArgumentException e) {
1125                 }
1126                 return printableArea;
1127             }
1128             return null;
1129         } else if (category == SunAlternateMedia.class) {
1130             return null;
1131         } else if (category == Destination.class) {
1132             try {
1133                 return new Destination((new File("out.prn")).toURI());
1134             } catch (SecurityException se) {
1135                 try {
1136                     return new Destination(new URI("file:out.prn"));
1137                 } catch (URISyntaxException e) {
1138                     return null;
1139                 }
1140             }
1141         } else if (category == Sides.class) {
1142             switch(defSides) {
1143             case DMDUP_VERTICAL :
1144                 return Sides.TWO_SIDED_LONG_EDGE;
1145             case DMDUP_HORIZONTAL :
1146                 return Sides.TWO_SIDED_SHORT_EDGE;
1147             default :
1148                 return Sides.ONE_SIDED;
1149             }
1150         } else if (category == PrinterResolution.class) {
1151             int yRes = defYRes;
1152             int xRes = defQuality;
1153             if ((xRes < 0) || (yRes < 0)) {
1154                 int res = (yRes > xRes) ? yRes : xRes;
1155                 if (res > 0) {
1156                  return new PrinterResolution(res, res, PrinterResolution.DPI);
1157                 }
1158             }
1159             else {
1160                return new PrinterResolution(xRes, yRes, PrinterResolution.DPI);
1161             }
1162         } else if (category == ColorSupported.class) {
1163             int caps = getPrinterCapabilities();
1164             if ((caps & DEVCAP_COLOR) != 0) {
1165                 return ColorSupported.SUPPORTED;
1166             } else {
1167                 return ColorSupported.NOT_SUPPORTED;
1168             }
1169         } else if (category == PrintQuality.class) {
1170             if ((defQuality < 0) && (defQuality >= DMRES_HIGH)) {
1171                 switch (defQuality) {
1172                 case DMRES_HIGH:
1173                     return PrintQuality.HIGH;
1174                 case DMRES_MEDIUM:
1175                     return PrintQuality.NORMAL;
1176                 default:
1177                     return PrintQuality.DRAFT;
1178                 }
1179             }
1180         } else if (category == RequestingUserName.class) {
1181             String userName = "";
1182             try {
1183               userName = System.getProperty("user.name", "");
1184             } catch (SecurityException se) {
1185             }
1186             return new RequestingUserName(userName, null);
1187         } else if (category == SheetCollate.class) {
1188             if (defCollate == DMCOLLATE_TRUE) {
1189                 return SheetCollate.COLLATED;
1190             } else {
1191                 return SheetCollate.UNCOLLATED;
1192             }
1193         } else if (category == Fidelity.class) {
1194             return Fidelity.FIDELITY_FALSE;
1195         }
1196         return null;
1197     }
1198 
1199     private boolean isPostScriptFlavor(DocFlavor flavor) {
1200         if (flavor.equals(DocFlavor.BYTE_ARRAY.POSTSCRIPT) ||
1201             flavor.equals(DocFlavor.INPUT_STREAM.POSTSCRIPT) ||
1202             flavor.equals(DocFlavor.URL.POSTSCRIPT)) {
1203             return true;
1204         }
1205         else {
1206             return false;
1207         }
1208     }
1209 
1210     private boolean isPSDocAttr(Class category) {
1211         if (category == OrientationRequested.class || category == Copies.class) {
1212                 return true;
1213         }
1214         else {
1215             return false;
1216         }
1217     }
1218 
1219     private boolean isAutoSense(DocFlavor flavor) {
1220         if (flavor.equals(DocFlavor.BYTE_ARRAY.AUTOSENSE) ||
1221             flavor.equals(DocFlavor.INPUT_STREAM.AUTOSENSE) ||
1222             flavor.equals(DocFlavor.URL.AUTOSENSE)) {
1223             return true;
1224         }
1225         else {
1226             return false;
1227         }
1228     }
1229 
1230     public Object
1231         getSupportedAttributeValues(Class<? extends Attribute> category,
1232                                     DocFlavor flavor,
1233                                     AttributeSet attributes)
1234     {
1235         if (category == null) {
1236             throw new NullPointerException("null category");
1237         }
1238         if (!Attribute.class.isAssignableFrom(category)) {
1239             throw new IllegalArgumentException(category +
1240                                              " does not implement Attribute");
1241         }
1242         if (flavor != null) {
1243             if (!isDocFlavorSupported(flavor)) {
1244                 throw new IllegalArgumentException(flavor +
1245                                                   " is an unsupported flavor");
1246                 // if postscript & category is already specified within the
1247                 //  PostScript data we return null
1248             } else if (isAutoSense(flavor) ||(isPostScriptFlavor(flavor) &&
1249                        (isPSDocAttr(category)))){
1250                 return null;
1251             }
1252         }
1253         if (!isAttributeCategorySupported(category)) {
1254             return null;
1255         }
1256 
1257         if (category == JobName.class) {
1258             return new JobName("Java Printing", null);
1259         } else if (category == RequestingUserName.class) {
1260           String userName = "";
1261           try {
1262             userName = System.getProperty("user.name", "");
1263           } catch (SecurityException se) {
1264           }
1265             return new RequestingUserName(userName, null);
1266         } else if (category == ColorSupported.class) {
1267             int caps = getPrinterCapabilities();
1268             if ((caps & DEVCAP_COLOR) != 0) {
1269                 return ColorSupported.SUPPORTED;
1270             } else {
1271                 return ColorSupported.NOT_SUPPORTED;
1272             }
1273         } else if (category == Chromaticity.class) {
1274             if (flavor == null ||
1275                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1276                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) ||
1277                 flavor.equals(DocFlavor.BYTE_ARRAY.GIF) ||
1278                 flavor.equals(DocFlavor.INPUT_STREAM.GIF) ||
1279                 flavor.equals(DocFlavor.URL.GIF) ||
1280                 flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) ||
1281                 flavor.equals(DocFlavor.INPUT_STREAM.JPEG) ||
1282                 flavor.equals(DocFlavor.URL.JPEG) ||
1283                 flavor.equals(DocFlavor.BYTE_ARRAY.PNG) ||
1284                 flavor.equals(DocFlavor.INPUT_STREAM.PNG) ||
1285                 flavor.equals(DocFlavor.URL.PNG)) {
1286                 int caps = getPrinterCapabilities();
1287                 if ((caps & DEVCAP_COLOR) == 0) {
1288                     Chromaticity []arr = new Chromaticity[1];
1289                     arr[0] = Chromaticity.MONOCHROME;
1290                     return (arr);
1291                 } else {
1292                     Chromaticity []arr = new Chromaticity[2];
1293                     arr[0] = Chromaticity.MONOCHROME;
1294                     arr[1] = Chromaticity.COLOR;
1295                     return (arr);
1296                 }
1297             } else {
1298                 return null;
1299             }
1300         } else if (category == Destination.class) {
1301             try {
1302                 return new Destination((new File("out.prn")).toURI());
1303             } catch (SecurityException se) {
1304                 try {
1305                     return new Destination(new URI("file:out.prn"));
1306                 } catch (URISyntaxException e) {
1307                     return null;
1308                 }
1309             }
1310         } else if (category == OrientationRequested.class) {
1311             if (flavor == null ||
1312                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1313                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) ||
1314                 flavor.equals(DocFlavor.INPUT_STREAM.GIF) ||
1315                 flavor.equals(DocFlavor.INPUT_STREAM.JPEG) ||
1316                 flavor.equals(DocFlavor.INPUT_STREAM.PNG) ||
1317                 flavor.equals(DocFlavor.BYTE_ARRAY.GIF) ||
1318                 flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) ||
1319                 flavor.equals(DocFlavor.BYTE_ARRAY.PNG) ||
1320                 flavor.equals(DocFlavor.URL.GIF) ||
1321                 flavor.equals(DocFlavor.URL.JPEG) ||
1322                 flavor.equals(DocFlavor.URL.PNG)) {
1323                 OrientationRequested []arr = new OrientationRequested[3];
1324                 arr[0] = OrientationRequested.PORTRAIT;
1325                 arr[1] = OrientationRequested.LANDSCAPE;
1326                 arr[2] = OrientationRequested.REVERSE_LANDSCAPE;
1327                 return arr;
1328             } else {
1329                 return null;
1330             }
1331         } else if ((category == Copies.class) ||
1332                    (category == CopiesSupported.class)) {
1333             synchronized (this) {
1334                 if (gotCopies == false) {
1335                     nCopies = getCopiesSupported(printer, getPort());
1336                     gotCopies = true;
1337                 }
1338             }
1339             return new CopiesSupported(1, nCopies);
1340         } else if (category == Media.class) {
1341 
1342             initMedia();
1343 
1344             int len = (mediaSizeNames == null) ? 0 : mediaSizeNames.length;
1345 
1346             MediaTray[] trays = getMediaTrays();
1347 
1348             len += (trays == null) ? 0 : trays.length;
1349 
1350             Media []arr = new Media[len];
1351             if (mediaSizeNames != null) {
1352                 System.arraycopy(mediaSizeNames, 0, arr,
1353                                  0, mediaSizeNames.length);
1354             }
1355             if (trays != null) {
1356                 System.arraycopy(trays, 0, arr,
1357                                  len - trays.length, trays.length);
1358             }
1359             return arr;
1360         } else if (category == MediaPrintableArea.class) {
1361             // if getting printable area for a specific media size
1362             Media mediaName = null;
1363             if ((attributes != null) &&
1364                 ((mediaName =
1365                   (Media)attributes.get(Media.class)) != null)) {
1366 
1367                 if (!(mediaName instanceof MediaSizeName)) {
1368                     // if an instance of MediaTray, fall thru returning
1369                     // all MediaPrintableAreas
1370                     mediaName = null;
1371                 }
1372             }
1373 
1374             MediaPrintableArea[] mpas =
1375                                   getMediaPrintables((MediaSizeName)mediaName);
1376             if (mpas != null) {
1377                 MediaPrintableArea[] arr = new MediaPrintableArea[mpas.length];
1378                 System.arraycopy(mpas, 0, arr, 0, mpas.length);
1379                 return arr;
1380             } else {
1381                 return null;
1382             }
1383         } else if (category == SunAlternateMedia.class) {
1384             return new SunAlternateMedia(
1385                               (Media)getDefaultAttributeValue(Media.class));
1386         } else if (category == PageRanges.class) {
1387             if (flavor == null ||
1388                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1389                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
1390                 PageRanges []arr = new PageRanges[1];
1391                 arr[0] = new PageRanges(1, Integer.MAX_VALUE);
1392                 return arr;
1393             } else {
1394                 return null;
1395             }
1396         } else if (category == PrinterResolution.class) {
1397             PrinterResolution[] supportedRes = getPrintResolutions();
1398             if (supportedRes == null) {
1399                 return null;
1400             }
1401             PrinterResolution []arr =
1402                 new PrinterResolution[supportedRes.length];
1403             System.arraycopy(supportedRes, 0, arr, 0, supportedRes.length);
1404             return arr;
1405         } else if (category == Sides.class) {
1406             if (flavor == null ||
1407                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1408                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
1409                 Sides []arr = new Sides[3];
1410                 arr[0] = Sides.ONE_SIDED;
1411                 arr[1] = Sides.TWO_SIDED_LONG_EDGE;
1412                 arr[2] = Sides.TWO_SIDED_SHORT_EDGE;
1413                 return arr;
1414             } else {
1415                 return null;
1416             }
1417         } else if (category == PrintQuality.class) {
1418             PrintQuality []arr = new PrintQuality[3];
1419             arr[0] = PrintQuality.DRAFT;
1420             arr[1] = PrintQuality.HIGH;
1421             arr[2] = PrintQuality.NORMAL;
1422             return arr;
1423         } else if (category == SheetCollate.class) {
1424             if (flavor == null ||
1425                 (flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1426                  flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {
1427                 SheetCollate []arr = new SheetCollate[2];
1428                 arr[0] = SheetCollate.COLLATED;
1429                 arr[1] = SheetCollate.UNCOLLATED;
1430                 return arr;
1431             } else {
1432                 return null;
1433             }
1434         } else if (category == Fidelity.class) {
1435             Fidelity []arr = new Fidelity[2];
1436             arr[0] = Fidelity.FIDELITY_FALSE;
1437             arr[1] = Fidelity.FIDELITY_TRUE;
1438             return arr;
1439         } else {
1440             return null;
1441         }
1442     }
1443 
1444     public boolean isAttributeValueSupported(Attribute attr,
1445                                              DocFlavor flavor,
1446                                              AttributeSet attributes) {
1447 
1448         if (attr == null) {
1449             throw new NullPointerException("null attribute");
1450         }
1451         Class category = attr.getCategory();
1452         if (flavor != null) {
1453             if (!isDocFlavorSupported(flavor)) {
1454                 throw new IllegalArgumentException(flavor +
1455                                                    " is an unsupported flavor");
1456                 // if postscript & category is already specified within the PostScript data
1457                 // we return false
1458             } else if (isAutoSense(flavor) || (isPostScriptFlavor(flavor) &&
1459                        (isPSDocAttr(category)))) {
1460                 return false;
1461             }
1462         }
1463 
1464         if (!isAttributeCategorySupported(category)) {
1465             return false;
1466         }
1467         else if (category == Chromaticity.class) {
1468             if ((flavor == null) ||
1469                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1470                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) ||
1471                 flavor.equals(DocFlavor.BYTE_ARRAY.GIF) ||
1472                 flavor.equals(DocFlavor.INPUT_STREAM.GIF) ||
1473                 flavor.equals(DocFlavor.URL.GIF) ||
1474                 flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) ||
1475                 flavor.equals(DocFlavor.INPUT_STREAM.JPEG) ||
1476                 flavor.equals(DocFlavor.URL.JPEG) ||
1477                 flavor.equals(DocFlavor.BYTE_ARRAY.PNG) ||
1478                 flavor.equals(DocFlavor.INPUT_STREAM.PNG) ||
1479                 flavor.equals(DocFlavor.URL.PNG)) {
1480                 int caps = getPrinterCapabilities();
1481                 if ((caps & DEVCAP_COLOR) != 0) {
1482                     return true;
1483                 } else {
1484                     return attr == Chromaticity.MONOCHROME;
1485                 }
1486             } else {
1487                 return false;
1488             }
1489         } else if (category == Copies.class) {
1490             return isSupportedCopies((Copies)attr);
1491 
1492         } else if (category == Destination.class) {
1493             URI uri = ((Destination)attr).getURI();
1494             if ("file".equals(uri.getScheme()) &&
1495                 !(uri.getSchemeSpecificPart().equals(""))) {
1496                 return true;
1497             } else {
1498             return false;
1499             }
1500 
1501         } else if (category == Media.class) {
1502             if (attr instanceof MediaSizeName) {
1503                 return isSupportedMedia((MediaSizeName)attr);
1504             }
1505             if (attr instanceof MediaTray) {
1506                 return isSupportedMediaTray((MediaTray)attr);
1507             }
1508 
1509         } else if (category == MediaPrintableArea.class) {
1510             return isSupportedMediaPrintableArea((MediaPrintableArea)attr);
1511 
1512         } else if (category == SunAlternateMedia.class) {
1513             Media media = ((SunAlternateMedia)attr).getMedia();
1514             return isAttributeValueSupported(media, flavor, attributes);
1515 
1516         } else if (category == PageRanges.class ||
1517                    category == SheetCollate.class ||
1518                    category == Sides.class) {
1519             if (flavor != null &&
1520                 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1521                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {
1522                 return false;
1523             }
1524         } else if (category == PrinterResolution.class) {
1525             if (attr instanceof PrinterResolution) {
1526                 return isSupportedResolution((PrinterResolution)attr);
1527             }
1528         } else if (category == OrientationRequested.class) {
1529             if (attr == OrientationRequested.REVERSE_PORTRAIT ||
1530                 (flavor != null) &&
1531                 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1532                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) ||
1533                 flavor.equals(DocFlavor.INPUT_STREAM.GIF) ||
1534                 flavor.equals(DocFlavor.INPUT_STREAM.JPEG) ||
1535                 flavor.equals(DocFlavor.INPUT_STREAM.PNG) ||
1536                 flavor.equals(DocFlavor.BYTE_ARRAY.GIF) ||
1537                 flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) ||
1538                 flavor.equals(DocFlavor.BYTE_ARRAY.PNG) ||
1539                 flavor.equals(DocFlavor.URL.GIF) ||
1540                 flavor.equals(DocFlavor.URL.JPEG) ||
1541                 flavor.equals(DocFlavor.URL.PNG))) {
1542                 return false;
1543             }
1544 
1545         } else if (category == ColorSupported.class) {
1546             int caps = getPrinterCapabilities();
1547             boolean isColorSup = ((caps & DEVCAP_COLOR) != 0);
1548             if  ((!isColorSup && (attr == ColorSupported.SUPPORTED)) ||
1549                 (isColorSup && (attr == ColorSupported.NOT_SUPPORTED))) {
1550                 return false;
1551             }
1552         }
1553         return true;
1554     }
1555 
1556     public AttributeSet getUnsupportedAttributes(DocFlavor flavor,
1557                                                  AttributeSet attributes) {
1558 
1559         if (flavor != null && !isDocFlavorSupported(flavor)) {
1560             throw new IllegalArgumentException("flavor " + flavor +
1561                                                "is not supported");
1562         }
1563 
1564         if (attributes == null) {
1565             return null;
1566         }
1567 
1568         Attribute attr;
1569         AttributeSet unsupp = new HashAttributeSet();
1570         Attribute []attrs = attributes.toArray();
1571         for (int i=0; i<attrs.length; i++) {
1572             try {
1573                 attr = attrs[i];
1574                 if (!isAttributeCategorySupported(attr.getCategory())) {
1575                     unsupp.add(attr);
1576                 }
1577                 else if (!isAttributeValueSupported(attr, flavor, attributes)) {
1578                     unsupp.add(attr);
1579                 }
1580             } catch (ClassCastException e) {
1581             }
1582         }
1583         if (unsupp.isEmpty()) {
1584             return null;
1585         } else {
1586             return unsupp;
1587         }
1588     }
1589 
1590     public ServiceUIFactory getServiceUIFactory() {
1591         return null;
1592     }
1593 
1594     public String toString() {
1595         return "Win32 Printer : " + getName();
1596     }
1597 
1598     public boolean equals(Object obj) {
1599         return  (obj == this ||
1600                  (obj instanceof Win32PrintService &&
1601                   ((Win32PrintService)obj).getName().equals(getName())));
1602     }
1603 
1604    public int hashCode() {
1605         return this.getClass().hashCode()+getName().hashCode();
1606     }
1607 
1608     public boolean usesClass(Class c) {
1609         return (c == sun.awt.windows.WPrinterJob.class);
1610     }
1611 
1612     private native int[] getAllMediaIDs(String printerName, String port);
1613     private native int[] getAllMediaSizes(String printerName, String port);
1614     private native int[] getAllMediaTrays(String printerName, String port);
1615     private native float[] getMediaPrintableArea(String printerName,
1616                                                  int paperSize);
1617     private native String[] getAllMediaNames(String printerName, String port);
1618     private native String[] getAllMediaTrayNames(String printerName, String port);
1619     private native int getCopiesSupported(String printerName, String port);
1620     private native int[] getAllResolutions(String printerName, String port);
1621     private native int getCapabilities(String printerName, String port);
1622 
1623     private native int[] getDefaultSettings(String printerName, String port);
1624     private native int getJobStatus(String printerName, int type);
1625     private native String getPrinterPort(String printerName);
1626 }
1627 
1628 
1629 class Win32MediaSize extends MediaSizeName {
1630     private static ArrayList winStringTable = new ArrayList();
1631     private static ArrayList winEnumTable = new ArrayList();
1632 
1633     private int dmPaperID; // driver ID for this paper.
1634 
1635     private Win32MediaSize(int x) {
1636         super(x);
1637 
1638     }
1639 
1640     private synchronized static int nextValue(String name) {
1641       winStringTable.add(name);
1642       return (winStringTable.size()-1);
1643     }
1644 
1645     public static synchronized Win32MediaSize findMediaName(String name) {
1646         int nameIndex = winStringTable.indexOf(name);
1647         if (nameIndex != -1) {
1648             return (Win32MediaSize)winEnumTable.get(nameIndex);
1649         }
1650         return null;
1651     }
1652 
1653     public Win32MediaSize(String name, int dmPaper) {
1654         super(nextValue(name));
1655         dmPaperID = dmPaper;
1656         winEnumTable.add(this);
1657     }
1658 
1659     private MediaSizeName[] getSuperEnumTable() {
1660       return (MediaSizeName[])super.getEnumValueTable();
1661     }
1662 
1663     static {
1664          /* initialize Win32PrintService.predefMedia */
1665         {
1666             Win32MediaSize winMedia = new Win32MediaSize(-1);
1667 
1668             // cannot call getSuperEnumTable directly because of static context
1669             MediaSizeName[] enumMedia = winMedia.getSuperEnumTable();
1670             if (enumMedia != null) {
1671                 Win32PrintService.predefMedia = new MediaSize[enumMedia.length];
1672 
1673                 for (int i=0; i<enumMedia.length; i++) {
1674                     Win32PrintService.predefMedia[i] =
1675                         MediaSize.getMediaSizeForName(enumMedia[i]);
1676                 }
1677             }
1678         }
1679     }
1680 
1681     int getDMPaper() {
1682         return dmPaperID;
1683     }
1684 
1685     protected String[] getStringTable() {
1686       String[] nameTable = new String[winStringTable.size()];
1687       return (String[])winStringTable.toArray(nameTable);
1688     }
1689 
1690     protected EnumSyntax[] getEnumValueTable() {
1691       MediaSizeName[] enumTable = new MediaSizeName[winEnumTable.size()];
1692       return (MediaSizeName[])winEnumTable.toArray(enumTable);
1693     }
1694 
1695 }