00001 /******************************************************************************* 00002 00003 @file DeviceConduit.d 00004 00005 Copyright (c) 2004 Kris Bell 00006 00007 This software is provided 'as-is', without any express or implied 00008 warranty. In no event will the authors be held liable for damages 00009 of any kind arising from the use of this software. 00010 00011 Permission is hereby granted to anyone to use this software for any 00012 purpose, including commercial applications, and to alter it and/or 00013 redistribute it freely, subject to the following restrictions: 00014 00015 1. The origin of this software must not be misrepresented; you must 00016 not claim that you wrote the original software. If you use this 00017 software in a product, an acknowledgment within documentation of 00018 said product would be appreciated but is not required. 00019 00020 2. Altered source versions must be plainly marked as such, and must 00021 not be misrepresented as being the original software. 00022 00023 3. This notice may not be removed or altered from any distribution 00024 of the source. 00025 00026 4. Derivative works are permitted, but they must carry this notice 00027 in full and credit the original source. 00028 00029 00030 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00031 00032 00033 @version Initial version; May 2005 00034 00035 @author Kris 00036 00037 *******************************************************************************/ 00038 00039 module mango.io.DeviceConduit; 00040 00041 private import mango.sys.OS; 00042 00043 private import mango.io.Buffer, 00044 mango.io.Conduit, 00045 mango.io.Exception; 00046 00047 /******************************************************************************* 00048 00049 Implements a means of reading and writing a file device. Conduits 00050 are the primary means of accessing external data, and are usually 00051 routed through a Buffer. 00052 00053 *******************************************************************************/ 00054 00055 class DeviceConduit : Conduit 00056 { 00057 // expose conduit.copy() methods also 00058 alias Conduit.copy copy; 00059 alias Conduit.read read; 00060 alias Conduit.write write; 00061 00062 /*********************************************************************** 00063 00064 Construct a conduit with the given style and seek abilities. 00065 Conduits are either seekable or non-seekable. 00066 00067 ***********************************************************************/ 00068 00069 this (ConduitStyle.Bits style, bool seekable) 00070 { 00071 super (style, seekable); 00072 } 00073 00074 /*********************************************************************** 00075 00076 Create a FileConduit on the provided FileDevice. This is 00077 strictly for adapting existing devices such as Stdout and 00078 friends. 00079 00080 ***********************************************************************/ 00081 00082 this (FileDevice device) 00083 { 00084 // say we're not seekable 00085 super (device.style, false); 00086 00087 // open the file 00088 reopen (device); 00089 } 00090 00091 /*********************************************************************** 00092 00093 Callback to close the file. This is invoked from the Resource 00094 base-class when the resource is being closed. 00095 00096 ***********************************************************************/ 00097 00098 override void close () 00099 { 00100 super.close (); 00101 _close (); 00102 } 00103 00104 /*********************************************************************** 00105 00106 Make a reasonable attempt to clean up 00107 00108 ***********************************************************************/ 00109 00110 ~this () 00111 { 00112 if (! isHalting) 00113 _close (); 00114 } 00115 00116 /*********************************************************************** 00117 00118 Return a preferred size for buffering conduit I/O 00119 00120 ***********************************************************************/ 00121 00122 uint bufferSize () 00123 { 00124 return 1024 * 16; 00125 } 00126 00127 /*********************************************************************** 00128 00129 Return the name of this device 00130 00131 ***********************************************************************/ 00132 00133 protected char[] getName() 00134 { 00135 return "<device>"; 00136 } 00137 00138 00139 /*********************************************************************** 00140 00141 Windows-specific code 00142 00143 ***********************************************************************/ 00144 00145 version (Win32) 00146 { 00147 protected HANDLE handle; 00148 00149 /*************************************************************** 00150 00151 Throw an IOException noting the last error 00152 00153 ***************************************************************/ 00154 00155 final void error () 00156 { 00157 throw new IOException (getName() ~ ": " ~ OS.error); 00158 } 00159 00160 /*************************************************************** 00161 00162 Return the device handle 00163 00164 ***************************************************************/ 00165 00166 package final HANDLE getHandle () 00167 { 00168 return handle; 00169 } 00170 00171 /*************************************************************** 00172 00173 Gain access to the standard IO handles (console etc). 00174 00175 ***************************************************************/ 00176 00177 protected void reopen (FileDevice device) 00178 { 00179 handle = cast(HANDLE) device.id; 00180 } 00181 00182 /*************************************************************** 00183 00184 Close the underlying file 00185 00186 ***************************************************************/ 00187 00188 protected void _close () 00189 { 00190 if (handle) 00191 if (! CloseHandle (handle)) 00192 error (); 00193 handle = null; 00194 } 00195 00196 /*************************************************************** 00197 00198 Read a chunk of bytes from the file into the provided 00199 array (typically that belonging to an IBuffer) 00200 00201 ***************************************************************/ 00202 00203 protected override uint reader (void[] dst) 00204 { 00205 DWORD read; 00206 void *p = dst; 00207 00208 if (! ReadFile (handle, p, dst.length, &read, null)) 00209 error (); 00210 00211 if (read == 0 && dst.length > 0) 00212 return Eof; 00213 return read; 00214 } 00215 00216 /*************************************************************** 00217 00218 Write a chunk of bytes to the file from the provided 00219 array (typically that belonging to an IBuffer) 00220 00221 ***************************************************************/ 00222 00223 protected override uint writer (void[] src) 00224 { 00225 DWORD written; 00226 00227 if (! WriteFile (handle, src, src.length, &written, null)) 00228 error (); 00229 00230 return written; 00231 } 00232 } 00233 00234 00235 /*********************************************************************** 00236 00237 Unix-specific code. 00238 00239 ***********************************************************************/ 00240 00241 version (Posix) 00242 { 00243 protected int handle = -1; 00244 00245 /*************************************************************** 00246 00247 Throw an IOException noting the last error 00248 00249 ***************************************************************/ 00250 00251 final void error () 00252 { 00253 throw new IOException (getName() ~ ": " ~ 00254 OS.error); 00255 } 00256 00257 /*************************************************************** 00258 00259 Return the device handle 00260 00261 ***************************************************************/ 00262 00263 package final int getHandle () 00264 { 00265 return handle; 00266 } 00267 00268 /*************************************************************** 00269 00270 Gain access to the standard IO handles (console etc). 00271 00272 ***************************************************************/ 00273 00274 protected void reopen (FileDevice device) 00275 { 00276 handle = device.id; 00277 } 00278 00279 /*************************************************************** 00280 00281 Close the underlying file 00282 00283 ***************************************************************/ 00284 00285 protected void _close () 00286 { 00287 if (handle) 00288 if (posix.close (handle) == -1) 00289 error (); 00290 handle = 0; 00291 } 00292 00293 /*************************************************************** 00294 00295 Read a chunk of bytes from the file into the provided 00296 array (typically that belonging to an IBuffer) 00297 00298 ***************************************************************/ 00299 00300 protected override uint reader (void[] dst) 00301 { 00302 int read = posix.read (handle, dst, dst.length); 00303 if (read == -1) 00304 error (); 00305 else 00306 if (read == 0 && dst.length > 0) 00307 return Eof; 00308 return read; 00309 } 00310 00311 /*************************************************************** 00312 00313 Write a chunk of bytes to the file from the provided 00314 array (typically that belonging to an IBuffer) 00315 00316 ***************************************************************/ 00317 00318 protected override uint writer (void[] src) 00319 { 00320 int written = posix.write (handle, src, src.length); 00321 if (written == -1) 00322 error (); 00323 return written; 00324 } 00325 } 00326 } 00327 00328 00329 /******************************************************************************* 00330 00331 Class used to wrap an existing file-oriented handle, such as Stdout 00332 and its cohorts. 00333 00334 *******************************************************************************/ 00335 00336 class FileDevice 00337 { 00338 private uint _id; 00339 private ConduitStyle.Bits style; 00340 00341 this (uint id, ConduitStyle.Bits style) 00342 { 00343 this.style = style; 00344 this._id = id; 00345 } 00346 00347 int id() 00348 { 00349 return _id; 00350 } 00351 } 00352 00353