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.stream.FilterOutputStream; 13 14 import hunt.stream.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 */ 36 class FilterOutputStream : OutputStream { 37 /** 38 * The underlying output stream to be filtered. 39 */ 40 protected OutputStream outputStream; 41 42 /** 43 * Whether the stream is closed; implicitly initialized to false. 44 */ 45 private bool closed; 46 47 /** 48 * Object used to prevent a race on the 'closed' instance variable. 49 */ 50 private Object closeLock; 51 52 /** 53 * Creates an output stream filter built on top of the specified 54 * underlying output stream. 55 * 56 * @param outputStream the underlying output stream to be assigned to 57 * the field {@code this.outputStream} for later use, or 58 * <code>null</code> if this instance is to be 59 * created without an underlying stream. 60 */ 61 this(OutputStream outputStream) { 62 this.outputStream = outputStream; 63 closeLock = new Object(); 64 } 65 66 /** 67 * Writes the specified <code>byte</code> to this output stream. 68 * <p> 69 * The <code>write</code> method of <code>FilterOutputStream</code> 70 * calls the <code>write</code> method of its underlying output stream, 71 * that is, it performs {@code outputStream.write(b)}. 72 * <p> 73 * Implements the abstract {@code write} method of {@code OutputStream}. 74 * 75 * @param b the <code>byte</code>. 76 * @exception IOException if an I/O error occurs. 77 */ 78 override 79 void write(int b) { 80 outputStream.write(b); 81 } 82 83 /** 84 * Writes <code>b.length</code> bytes to this output stream. 85 * <p> 86 * The <code>write</code> method of <code>FilterOutputStream</code> 87 * calls its <code>write</code> method of three arguments with the 88 * arguments <code>b</code>, <code>0</code>, and 89 * <code>b.length</code>. 90 * <p> 91 * Note that this method does not call the one-argument 92 * <code>write</code> method of its underlying output stream with 93 * the single argument <code>b</code>. 94 * 95 * @param b the data to be written. 96 * @exception IOException if an I/O error occurs. 97 * @see java.io.FilterOutputStream#write(byte[], int, int) 98 */ 99 override 100 void write(byte[] b) { 101 write(b, 0, cast(int)b.length); 102 } 103 104 /** 105 * Writes <code>len</code> bytes from the specified 106 * <code>byte</code> array starting at offset <code>off</code> to 107 * this output stream. 108 * <p> 109 * The <code>write</code> method of <code>FilterOutputStream</code> 110 * calls the <code>write</code> method of one argument on each 111 * <code>byte</code> to output. 112 * <p> 113 * Note that this method does not call the <code>write</code> method 114 * of its underlying output stream with the same arguments. Subclasses 115 * of <code>FilterOutputStream</code> should provide a more efficient 116 * implementation of this method. 117 * 118 * @param b the data. 119 * @param off the start offset in the data. 120 * @param len the number of bytes to write. 121 * @exception IOException if an I/O error occurs. 122 * @see java.io.FilterOutputStream#write(int) 123 */ 124 override 125 void write(byte[] b, int off, int len) { 126 if ((off | len | (b.length - (len + off)) | (off + len)) < 0) 127 throw new IndexOutOfBoundsException(); 128 129 for (int i = 0 ; i < len ; i++) { 130 write(b[off + i]); 131 } 132 } 133 134 /** 135 * Flushes this output stream and forces any buffered output bytes 136 * to be written out to the stream. 137 * <p> 138 * The <code>flush</code> method of <code>FilterOutputStream</code> 139 * calls the <code>flush</code> method of its underlying output stream. 140 * 141 * @exception IOException if an I/O error occurs. 142 * @see java.io.FilterOutputStream#outputStream 143 */ 144 override 145 void flush() { 146 outputStream.flush(); 147 } 148 149 /** 150 * Closes this output stream and releases any system resources 151 * associated with the stream. 152 * <p> 153 * When not already closed, the {@code close} method of {@code 154 * FilterOutputStream} calls its {@code flush} method, and then 155 * calls the {@code close} method of its underlying output stream. 156 * 157 * @exception IOException if an I/O error occurs. 158 * @see java.io.FilterOutputStream#flush() 159 * @see java.io.FilterOutputStream#outputStream 160 */ 161 override 162 void close() { 163 if (closed) { 164 return; 165 } 166 synchronized (closeLock) { 167 if (closed) { 168 return; 169 } 170 closed = true; 171 } 172 173 Throwable flushException = null; 174 try { 175 flush(); 176 } catch (Throwable e) { 177 flushException = e; 178 throw e; 179 } finally { 180 outputStream.close(); 181 } 182 } 183 }