/* * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.print; import java.awt.Color;import java.awt.Component;import java.awt.Font;import java.awt.FontMetrics;import java.awt.GraphicsEnvironment;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.HeadlessException;import java.awt.Rectangle;import java.awt.Shape; import java.awt.image.BufferedImage; import java.awt.font.FontRenderContext; import java.awt.geom.AffineTransform;import java.awt.geom.PathIterator;import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.print.Pageable;import java.awt.print.PageFormat;import java.awt.print.Paper;import java.awt.print.Printable;import java.awt.print.PrinterException;import java.awt.print.PrinterIOException;import java.awt.print.PrinterJob; import javax.print.DocFlavor;import javax.print.PrintService;import javax.print.StreamPrintService;import javax.print.attribute.HashPrintRequestAttributeSet;import javax.print.attribute.PrintRequestAttributeSet;import javax.print.attribute.standard.Chromaticity;import javax.print.attribute.standard.Copies;import javax.print.attribute.standard.Destination;import javax.print.attribute.standard.DialogTypeSelection;import javax.print.attribute.standard.JobName;import javax.print.attribute.standard.Sides; import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.CharConversionException;import java.io.File;import java.io.InputStream;import java.io.IOException;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.OutputStream;import java.io.PrintStream; import java.util.ArrayList;import java.util.Enumeration;import java.util.Locale;import java.util.Properties; import sun.awt.CharsetString;import sun.awt.FontConfiguration;import sun.awt.FontDescriptor;import sun.awt.PlatformFont;import sun.awt.SunToolkit;import sun.font.FontManagerFactory;import sun.font.FontUtilities; import java.nio.charset.*;import java.nio.CharBuffer;import java.nio.ByteBuffer; //REMIND: Remove use of this class when IPPPrintService is moved to share directory.import java.lang.reflect.Method; /** * A class which initiates and executes a PostScript printer job. * * @author Richard Blanchard */public class PSPrinterJob extends RasterPrinterJob { /* Class Constants */ /** * Passed to the <code>setFillMode</code> * method this value forces fills to be * done using the even-odd fill rule. */ protected static final int FILL_EVEN_ODD = 1; /** * Passed to the <code>setFillMode</code> * method this value forces fills to be * done using the non-zero winding rule. */ protected static final int FILL_WINDING = 2; /* PostScript has a 64K maximum on its strings. */ private static final int MAX_PSSTR = (1024 * 64 - 1); private static final int RED_MASK = 0x00ff0000; private static final int GREEN_MASK = 0x0000ff00; private static final int BLUE_MASK = 0x000000ff; private static final int RED_SHIFT = 16; private static final int GREEN_SHIFT = 8; private static final int BLUE_SHIFT = 0; private static final int LOWNIBBLE_MASK = 0x0000000f; private static final int HINIBBLE_MASK = 0x000000f0; private static final int HINIBBLE_SHIFT = 4; private static final byte hexDigits[] = { (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F' }; private static final int PS_XRES = 300; private static final int PS_YRES = 300; private static final String ADOBE_PS_STR = "%!PS-Adobe-3.0"; private static final String EOF_COMMENT = "%%EOF"; private static final String PAGE_COMMENT = "%%Page: "; private static final String READIMAGEPROC = "/imStr 0 def /imageSrc " + "{currentfile /ASCII85Decode filter /RunLengthDecode filter " + " imStr readstring pop } def"; private static final String COPIES = "/#copies exch def"; private static final String PAGE_SAVE = "/pgSave save def"; private static final String PAGE_RESTORE = "pgSave restore"; private static final String SHOWPAGE = "showpage"; private static final String IMAGE_SAVE = "/imSave save def"; private static final String IMAGE_STR = " string /imStr exch def"; private static final String IMAGE_RESTORE = "imSave restore"; private static final String COORD_PREP = " 0 exch translate " + "1 -1 scale" + "[72 " + PS_XRES + " div " + "0 0 " + "72 " + PS_YRES + " div " + "0 0]concat"; private static final String SetFontName = "F"; private static final String DrawStringName = "S"; /** * The PostScript invocation to fill a path using the * even-odd rule. (eofill) */ private static final String EVEN_ODD_FILL_STR = "EF"; /** * The PostScript invocation to fill a path using the * non-zero winding rule. (fill) */ private static final String WINDING_FILL_STR = "WF"; /** * The PostScript to set the clip to be the current path * using the even odd rule. (eoclip) */ private static final String EVEN_ODD_CLIP_STR = "EC"; /** * The PostScript to set the clip to be the current path * using the non-zero winding rule. (clip) */ private static final String WINDING_CLIP_STR = "WC"; /** * Expecting two numbers on the PostScript stack, this * invocation moves the current pen position. (moveto) */ private static final String MOVETO_STR = " M"; /** * Expecting two numbers on the PostScript stack, this * invocation draws a PS line from the current pen * position to the point on the stack. (lineto) */ private static final String LINETO_STR = " L"; /** * This PostScript operator takes two control points * and an ending point and using the current pen * position as a starting point adds a bezier * curve to the current path. (curveto) */ private static final String CURVETO_STR = " C"; /** * The PostScript to pop a state off of the printer's * gstate stack. (grestore) */ private static final String GRESTORE_STR = "R"; /** * The PostScript to push a state on to the printer's * gstate stack. (gsave) */ private static final String GSAVE_STR = "G"; /** * Make the current PostScript path an empty path. (newpath) */ private static final String NEWPATH_STR = "N"; /** * Close the current subpath by generating a line segment * from the current position to the start of the subpath. (closepath) */ private static final String CLOSEPATH_STR = "P"; /** * Use the three numbers on top of the PS operator * stack to set the rgb color. (setrgbcolor) */ private static final String SETRGBCOLOR_STR = " SC"; /** * Use the top number on the stack to set the printer's * current gray value. (setgray) */ private static final String SETGRAY_STR = " SG"; /* Instance Variables */ private int mDestType; private String mDestination = "lp"; private boolean mNoJobSheet = false; private String mOptions; private Font mLastFont; private Color mLastColor; private Shape mLastClip; private AffineTransform mLastTransform; /* non-null if printing EPS for Java Plugin */ private EPSPrinter epsPrinter = null; /** * The metrics for the font currently set. */ FontMetrics mCurMetrics; /** * The output stream to which the generated PostScript * is written. */ PrintStream mPSStream; /* The temporary file to which we spool before sending to the printer */ File spoolFile; /** * This string holds the PostScript operator to * be used to fill a path. It can be changed * by the <code>setFillMode</code> method. */ private String mFillOpStr = WINDING_FILL_STR; /** * This string holds the PostScript operator to * be used to clip to a path. It can be changed * by the <code>setFillMode</code> method. */ private String mClipOpStr = WINDING_CLIP_STR; /** * A stack that represents the PostScript gstate stack. */ ArrayList mGStateStack = new ArrayList(); /** * The x coordinate of the current pen position. */ private float mPenX; /** * The y coordinate of the current pen position. */ private float mPenY; /** * The x coordinate of the starting point of * the current subpath. */ private float mStartPathX; /** * The y coordinate of the starting point of * the current subpath. */ private float mStartPathY; /** * An optional mapping of fonts to PostScript names. */ private static Properties mFontProps = null; /* Class static initialiser block */ static { //enable priviledges so initProps can access system properties, // open the property file, etc. java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Object run() { mFontProps = initProps(); return null; } }); } /* * Initialize PostScript font properties. * Copied from PSPrintStream */ private static Properties initProps() { // search psfont.properties for fonts // and create and initialize fontProps if it exist. String jhome = System.getProperty("java.home"); if (jhome != null){ String ulocale = SunToolkit.getStartupLocale().getLanguage(); try { File f = new File(jhome + File.separator + "lib" + File.separator + "psfontj2d.properties." + ulocale); if (!f.canRead()){ f = new File(jhome + File.separator + "lib" + File.separator + "psfont.properties." + ulocale); if (!f.canRead()){ f = new File(jhome + File.separator + "lib" + File.separator + "psfontj2d.properties"); if (!f.canRead()){ f = new File(jhome + File.separator + "lib" + File.separator + "psfont.properties"); if (!f.canRead()){ return (Properties)null; } } } } // Load property file InputStream in = new BufferedInputStream(new FileInputStream(f.getPath())); Properties props = new Properties(); props.load(in); in.close(); return props; } catch (Exception e){ return (Properties)null; } } return (Properties)null; } /* Constructors */ public PSPrinterJob() { } /* Instance Methods */ /** * Presents the user a dialog for changing properties of the * print job interactively. * @returns false if the user cancels the dialog and * true otherwise. * @exception HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ public boolean printDialog() throws HeadlessException { if (GraphicsEnvironment.isHeadless()) { throw new HeadlessException(); } if (attributes == null) { attributes = new HashPrintRequestAttributeSet(); } attributes.add(new Copies(getCopies())); attributes.add(new JobName(getJobName(), null)); boolean doPrint = false; DialogTypeSelection dts = (DialogTypeSelection)attributes.get(DialogTypeSelection.class); if (dts == DialogTypeSelection.NATIVE) { // Remove DialogTypeSelection.NATIVE to prevent infinite loop in // RasterPrinterJob. attributes.remove(DialogTypeSelection.class); doPrint = printDialog(attributes); // restore attribute attributes.add(DialogTypeSelection.NATIVE); } else { doPrint = printDialog(attributes); } if (doPrint) { JobName jobName = (JobName)attributes.get(JobName.class); if (jobName != null) { setJobName(jobName.getValue()); } Copies copies = (Copies)attributes.get(Copies.class); if (copies != null) { setCopies(copies.getValue()); } Destination dest = (Destination)attributes.get(Destination.class); if (dest != null) { try { mDestType = RasterPrinterJob.FILE; mDestination = (new File(dest.getURI())).getPath(); } catch (Exception e) { mDestination = "out.ps"; } } else { mDestType = RasterPrinterJob.PRINTER; PrintService pServ = getPrintService(); if (pServ != null) { mDestination = pServ.getName(); } } } return doPrint; } /** * Invoked by the RasterPrinterJob super class * this method is called to mark the start of a * document. */ protected void startDoc() throws PrinterException { // A security check has been performed in the // java.awt.print.printerJob.getPrinterJob method. // We use an inner class to execute the privilged open operations. // Note that we only open a file if it has been nominated by // the end-user in a dialog that we ouselves put up. OutputStream output; if (epsPrinter == null) { if (getPrintService() instanceof PSStreamPrintService) { StreamPrintService sps = (StreamPrintService)getPrintService(); mDestType = RasterPrinterJob.STREAM; if (sps.isDisposed()) { throw new PrinterException("service is disposed"); } output = sps.getOutputStream(); if (output == null) { throw new PrinterException("Null output stream");Lines 1–500 of 2213. Load more
/* * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.print; import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.awt.FontMetrics; import java.awt.GraphicsEnvironment; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.HeadlessException; import java.awt.Rectangle; import java.awt.Shape; import java.awt.image.BufferedImage; import java.awt.font.FontRenderContext; import java.awt.geom.AffineTransform; import java.awt.geom.PathIterator; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.print.Pageable; import java.awt.print.PageFormat; import java.awt.print.Paper; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterIOException; import java.awt.print.PrinterJob; import javax.print.DocFlavor; import javax.print.PrintService; import javax.print.StreamPrintService; import javax.print.attribute.HashPrintRequestAttributeSet; import javax.print.attribute.PrintRequestAttributeSet; import javax.print.attribute.standard.Chromaticity; import javax.print.attribute.standard.Copies; import javax.print.attribute.standard.Destination; import javax.print.attribute.standard.DialogTypeSelection; import javax.print.attribute.standard.JobName; import javax.print.attribute.standard.Sides; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.CharConversionException; import java.io.File; import java.io.InputStream; import java.io.IOException; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.OutputStream; import java.io.PrintStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.Locale; import java.util.Properties; import sun.awt.CharsetString; import sun.awt.FontConfiguration; import sun.awt.FontDescriptor; import sun.awt.PlatformFont; import sun.awt.SunToolkit; import sun.font.FontManagerFactory; import sun.font.FontUtilities; import java.nio.charset.*; import java.nio.CharBuffer; import java.nio.ByteBuffer; //REMIND: Remove use of this class when IPPPrintService is moved to share directory. import java.lang.reflect.Method; /** * A class which initiates and executes a PostScript printer job. * * @author Richard Blanchard */ public class PSPrinterJob extends RasterPrinterJob { /* Class Constants */ /** * Passed to the <code>setFillMode</code> * method this value forces fills to be * done using the even-odd fill rule. */ protected static final int FILL_EVEN_ODD = 1; /** * Passed to the <code>setFillMode</code> * method this value forces fills to be * done using the non-zero winding rule. */ protected static final int FILL_WINDING = 2; /* PostScript has a 64K maximum on its strings. */ private static final int MAX_PSSTR = (1024 * 64 - 1); private static final int RED_MASK = 0x00ff0000; private static final int GREEN_MASK = 0x0000ff00; private static final int BLUE_MASK = 0x000000ff; private static final int RED_SHIFT = 16; private static final int GREEN_SHIFT = 8; private static final int BLUE_SHIFT = 0; private static final int LOWNIBBLE_MASK = 0x0000000f; private static final int HINIBBLE_MASK = 0x000000f0; private static final int HINIBBLE_SHIFT = 4; private static final byte hexDigits[] = { (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F' }; private static final int PS_XRES = 300; private static final int PS_YRES = 300; private static final String ADOBE_PS_STR = "%!PS-Adobe-3.0"; private static final String EOF_COMMENT = "%%EOF"; private static final String PAGE_COMMENT = "%%Page: "; private static final String READIMAGEPROC = "/imStr 0 def /imageSrc " + "{currentfile /ASCII85Decode filter /RunLengthDecode filter " + " imStr readstring pop } def"; private static final String COPIES = "/#copies exch def"; private static final String PAGE_SAVE = "/pgSave save def"; private static final String PAGE_RESTORE = "pgSave restore"; private static final String SHOWPAGE = "showpage"; private static final String IMAGE_SAVE = "/imSave save def"; private static final String IMAGE_STR = " string /imStr exch def"; private static final String IMAGE_RESTORE = "imSave restore"; private static final String COORD_PREP = " 0 exch translate " + "1 -1 scale" + "[72 " + PS_XRES + " div " + "0 0 " + "72 " + PS_YRES + " div " + "0 0]concat"; private static final String SetFontName = "F"; private static final String DrawStringName = "S"; /** * The PostScript invocation to fill a path using the * even-odd rule. (eofill) */ private static final String EVEN_ODD_FILL_STR = "EF"; /** * The PostScript invocation to fill a path using the * non-zero winding rule. (fill) */ private static final String WINDING_FILL_STR = "WF"; /** * The PostScript to set the clip to be the current path * using the even odd rule. (eoclip) */ private static final String EVEN_ODD_CLIP_STR = "EC"; /** * The PostScript to set the clip to be the current path * using the non-zero winding rule. (clip) */ private static final String WINDING_CLIP_STR = "WC"; /** * Expecting two numbers on the PostScript stack, this * invocation moves the current pen position. (moveto) */ private static final String MOVETO_STR = " M"; /** * Expecting two numbers on the PostScript stack, this * invocation draws a PS line from the current pen * position to the point on the stack. (lineto) */ private static final String LINETO_STR = " L"; /** * This PostScript operator takes two control points * and an ending point and using the current pen * position as a starting point adds a bezier * curve to the current path. (curveto) */ private static final String CURVETO_STR = " C"; /** * The PostScript to pop a state off of the printer's * gstate stack. (grestore) */ private static final String GRESTORE_STR = "R"; /** * The PostScript to push a state on to the printer's * gstate stack. (gsave) */ private static final String GSAVE_STR = "G"; /** * Make the current PostScript path an empty path. (newpath) */ private static final String NEWPATH_STR = "N"; /** * Close the current subpath by generating a line segment * from the current position to the start of the subpath. (closepath) */ private static final String CLOSEPATH_STR = "P"; /** * Use the three numbers on top of the PS operator * stack to set the rgb color. (setrgbcolor) */ private static final String SETRGBCOLOR_STR = " SC"; /** * Use the top number on the stack to set the printer's * current gray value. (setgray) */ private static final String SETGRAY_STR = " SG"; /* Instance Variables */ private int mDestType; private String mDestination = "lp"; private boolean mNoJobSheet = false; private String mOptions; private Font mLastFont; private Color mLastColor; private Shape mLastClip; private AffineTransform mLastTransform; /* non-null if printing EPS for Java Plugin */ private EPSPrinter epsPrinter = null; /** * The metrics for the font currently set. */ FontMetrics mCurMetrics; /** * The output stream to which the generated PostScript * is written. */ PrintStream mPSStream; /* The temporary file to which we spool before sending to the printer */ File spoolFile; /** * This string holds the PostScript operator to * be used to fill a path. It can be changed * by the <code>setFillMode</code> method. */ private String mFillOpStr = WINDING_FILL_STR; /** * This string holds the PostScript operator to * be used to clip to a path. It can be changed * by the <code>setFillMode</code> method. */ private String mClipOpStr = WINDING_CLIP_STR; /** * A stack that represents the PostScript gstate stack. */ ArrayList mGStateStack = new ArrayList(); /** * The x coordinate of the current pen position. */ private float mPenX; /** * The y coordinate of the current pen position. */ private float mPenY; /** * The x coordinate of the starting point of * the current subpath. */ private float mStartPathX; /** * The y coordinate of the starting point of * the current subpath. */ private float mStartPathY; /** * An optional mapping of fonts to PostScript names. */ private static Properties mFontProps = null; /* Class static initialiser block */ static { //enable priviledges so initProps can access system properties, // open the property file, etc. java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Object run() { mFontProps = initProps(); return null; } }); } /* * Initialize PostScript font properties. * Copied from PSPrintStream */ private static Properties initProps() { // search psfont.properties for fonts // and create and initialize fontProps if it exist. String jhome = System.getProperty("java.home"); if (jhome != null){ String ulocale = SunToolkit.getStartupLocale().getLanguage(); try { File f = new File(jhome + File.separator + "lib" + File.separator + "psfontj2d.properties." + ulocale); if (!f.canRead()){ f = new File(jhome + File.separator + "lib" + File.separator + "psfont.properties." + ulocale); if (!f.canRead()){ f = new File(jhome + File.separator + "lib" + File.separator + "psfontj2d.properties"); if (!f.canRead()){ f = new File(jhome + File.separator + "lib" + File.separator + "psfont.properties"); if (!f.canRead()){ return (Properties)null; } } } } // Load property file InputStream in = new BufferedInputStream(new FileInputStream(f.getPath())); Properties props = new Properties(); props.load(in); in.close(); return props; } catch (Exception e){ return (Properties)null; } } return (Properties)null; } /* Constructors */ public PSPrinterJob() { } /* Instance Methods */ /** * Presents the user a dialog for changing properties of the * print job interactively. * @returns false if the user cancels the dialog and * true otherwise. * @exception HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ public boolean printDialog() throws HeadlessException { if (GraphicsEnvironment.isHeadless()) { throw new HeadlessException(); } if (attributes == null) { attributes = new HashPrintRequestAttributeSet(); } attributes.add(new Copies(getCopies())); attributes.add(new JobName(getJobName(), null)); boolean doPrint = false; DialogTypeSelection dts = (DialogTypeSelection)attributes.get(DialogTypeSelection.class); if (dts == DialogTypeSelection.NATIVE) { // Remove DialogTypeSelection.NATIVE to prevent infinite loop in // RasterPrinterJob. attributes.remove(DialogTypeSelection.class); doPrint = printDialog(attributes); // restore attribute attributes.add(DialogTypeSelection.NATIVE); } else { doPrint = printDialog(attributes); } if (doPrint) { JobName jobName = (JobName)attributes.get(JobName.class); if (jobName != null) { setJobName(jobName.getValue()); } Copies copies = (Copies)attributes.get(Copies.class); if (copies != null) { setCopies(copies.getValue()); } Destination dest = (Destination)attributes.get(Destination.class); if (dest != null) { try { mDestType = RasterPrinterJob.FILE; mDestination = (new File(dest.getURI())).getPath(); } catch (Exception e) { mDestination = "out.ps"; } } else { mDestType = RasterPrinterJob.PRINTER; PrintService pServ = getPrintService(); if (pServ != null) { mDestination = pServ.getName(); } } } return doPrint; } /** * Invoked by the RasterPrinterJob super class * this method is called to mark the start of a * document. */ protected void startDoc() throws PrinterException { // A security check has been performed in the // java.awt.print.printerJob.getPrinterJob method. // We use an inner class to execute the privilged open operations. // Note that we only open a file if it has been nominated by // the end-user in a dialog that we ouselves put up. OutputStream output; if (epsPrinter == null) { if (getPrintService() instanceof PSStreamPrintService) { StreamPrintService sps = (StreamPrintService)getPrintService(); mDestType = RasterPrinterJob.STREAM; if (sps.isDisposed()) { throw new PrinterException("service is disposed"); } output = sps.getOutputStream(); if (output == null) { throw new PrinterException("Null output stream");