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