1 /* 2 * Hunt - A refined core library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.io.FilterOutputStream; 13 14 import hunt.io.Common; 15 import hunt.Exceptions; 16 17 version(HUNT_DEBUG) { 18 import hunt.logging; 19 } 20 21 /** 22 * This class is the superclass of all classes that filter output 23 * streams. These streams sit on top of an already existing output 24 * stream (the <i>underlying</i> output stream) which it uses as its 25 * basic sink of data, but possibly transforming the data along the 26 * way or providing additional functionality. 27 * <p> 28 * The class <code>FilterOutputStream</code> itself simply overrides 29 * all methods of <code>OutputStream</code> with versions that pass 30 * all requests to the underlying output stream. Subclasses of 31 * <code>FilterOutputStream</code> may further override some of these 32 * methods as well as provide additional methods and fields. 33 * 34 * @author Jonathan Payne 35 * @since 1.0 36 */ 37 class FilterOutputStream : OutputStream { 38 /** 39 * The underlying output stream to be filtered. 40 */ 41 protected OutputStream outputStream; 42 43 /** 44 * Whether the stream is closed; implicitly initialized to false. 45 */ 46 private bool closed; 47 48 /** 49 * Object used to prevent a race on the 'closed' instance variable. 50 */ 51 private Object closeLock; 52 53 /** 54 * Creates an output stream filter built on top of the specified 55 * underlying output stream. 56 * 57 * @param outputStream the underlying output stream to be assigned to 58 * the field {@code this.outputStream} for later use, or 59 * <code>null</code> if this instance is to be 60 * created without an underlying stream. 61 */ 62 this(OutputStream outputStream) { 63 this.outputStream = outputStream; 64 closeLock = new Object(); 65 } 66 67 /** 68 * Writes the specified <code>byte</code> to this output stream. 69 * <p> 70 * The <code>write</code> method of <code>FilterOutputStream</code> 71 * calls the <code>write</code> method of its underlying output stream, 72 * that is, it performs {@code outputStream.write(b)}. 73 * <p> 74 * Implements the abstract {@code write} method of {@code OutputStream}. 75 * 76 * @param b the <code>byte</code>. 77 * @exception IOException if an I/O error occurs. 78 */ 79 override 80 void write(int b) { 81 outputStream.write(b); 82 } 83 84 /** 85 * Writes <code>b.length</code> bytes to this output stream. 86 * <p> 87 * The <code>write</code> method of <code>FilterOutputStream</code> 88 * calls its <code>write</code> method of three arguments with the 89 * arguments <code>b</code>, <code>0</code>, and 90 * <code>b.length</code>. 91 * <p> 92 * Note that this method does not call the one-argument 93 * <code>write</code> method of its underlying output stream with 94 * the single argument <code>b</code>. 95 * 96 * @param b the data to be written. 97 * @exception IOException if an I/O error occurs. 98 * @see java.io.FilterOutputStream#write(byte[], int, int) 99 */ 100 override 101 void write(byte[] b) { 102 write(b, 0, cast(int)b.length); 103 } 104 105 /** 106 * Writes <code>len</code> bytes from the specified 107 * <code>byte</code> array starting at offset <code>off</code> to 108 * this output stream. 109 * <p> 110 * The <code>write</code> method of <code>FilterOutputStream</code> 111 * calls the <code>write</code> method of one argument on each 112 * <code>byte</code> to output. 113 * <p> 114 * Note that this method does not call the <code>write</code> method 115 * of its underlying output stream with the same arguments. Subclasses 116 * of <code>FilterOutputStream</code> should provide a more efficient 117 * implementation of this method. 118 * 119 * @param b the data. 120 * @param off the start offset in the data. 121 * @param len the number of bytes to write. 122 * @exception IOException if an I/O error occurs. 123 * @see java.io.FilterOutputStream#write(int) 124 */ 125 override 126 void write(byte[] b, int off, int len) { 127 if ((off | len | (b.length - (len + off)) | (off + len)) < 0) 128 throw new IndexOutOfBoundsException(); 129 130 for (int i = 0 ; i < len ; i++) { 131 write(b[off + i]); 132 } 133 } 134 135 /** 136 * Flushes this output stream and forces any buffered output bytes 137 * to be written out to the stream. 138 * <p> 139 * The <code>flush</code> method of <code>FilterOutputStream</code> 140 * calls the <code>flush</code> method of its underlying output stream. 141 * 142 * @exception IOException if an I/O error occurs. 143 * @see java.io.FilterOutputStream#outputStream 144 */ 145 override 146 void flush() { 147 outputStream.flush(); 148 } 149 150 /** 151 * Closes this output stream and releases any system resources 152 * associated with the stream. 153 * <p> 154 * When not already closed, the {@code close} method of {@code 155 * FilterOutputStream} calls its {@code flush} method, and then 156 * calls the {@code close} method of its underlying output stream. 157 * 158 * @exception IOException if an I/O error occurs. 159 * @see java.io.FilterOutputStream#flush() 160 * @see java.io.FilterOutputStream#outputStream 161 */ 162 override 163 void close() { 164 if (closed) { 165 return; 166 } 167 synchronized (closeLock) { 168 if (closed) { 169 return; 170 } 171 closed = true; 172 } 173 174 Throwable flushException = null; 175 try { 176 flush(); 177 } catch (Throwable e) { 178 flushException = e; 179 throw e; 180 } finally { 181 outputStream.close(); 182 } 183 } 184 }