00001 /******************************************************************************* 00002 00003 @file IConduit.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 00027 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00028 00029 00030 @version Initial version, March 2004 00031 @author Kris 00032 00033 00034 *******************************************************************************/ 00035 00036 module mango.io.model.IConduit; 00037 00038 private import mango.io.model.IBuffer; 00039 00040 private import mango.io.model.IResource; 00041 00042 /******************************************************************************* 00043 00044 Conduits provide virtualized access to external content, and 00045 represent things like files or Internet connections. Conduits 00046 are modelled by mango.io.model.IConduit, and implemented via 00047 classes FileConduit and SocketConduit. 00048 00049 Additional kinds of conduit are easy to construct: one either 00050 subclasses mango.io.Conduit, or implements mango.io.model.IConduit. 00051 A conduit reads and writes from/to an IBuffer in large chunks, 00052 typically the entire buffer. 00053 00054 *******************************************************************************/ 00055 00056 interface IConduit : IResource, IConduitSource, IConduitSink 00057 { 00058 /*********************************************************************** 00059 00060 Declare the End Of File identifer 00061 00062 ***********************************************************************/ 00063 00064 enum {Eof = -1}; 00065 00066 /*********************************************************************** 00067 00068 Attach a filter to the IConduit input. The filter is invoked 00069 via its reader(void[]) method whenever a block of content is 00070 being read; the void[] array represents content destination. 00071 The filter should return the number of bytes it has actually 00072 produced: less than or equal to the length of the provided 00073 array. 00074 00075 Filters are chained together such that the last filter added 00076 is the first one invoked. It is the responsibility of each 00077 filter to invoke the next link in the chain; for example: 00078 00079 @code 00080 class MungingInputFilter : FilterInput 00081 { 00082 int reader (void[] dst) 00083 { 00084 // read the next X bytes 00085 int count = next.reader (dst); 00086 00087 // set everything to '*' ! 00088 dst[0..count] = '*'; 00089 00090 // say how many we read 00091 return count; 00092 } 00093 } 00094 @endcode 00095 00096 Notice how this filter invokes the 'next' instance before 00097 munging the content ... the far end of the chain is where 00098 the original IConduit reader is attached, so it will get 00099 invoked eventually assuming each filter invokes 'next'. 00100 If the next reader fails it will return IConduit.Eof, as 00101 should your filter (or throw an IOException). From a client 00102 perspective, filters are attached like this: 00103 00104 @code 00105 FileConduit fc = new FileConduit (...); 00106 00107 fc.attach (new ZipInputFilter); 00108 fc.attach (new MungingInputFilter); 00109 @endcode 00110 00111 Again, the last filter attached is the first one invoked 00112 when a block of content is actually read. Each filter has 00113 two additional methods that it may use to control behavior: 00114 00115 @code 00116 class FilterInput : IFilterInput 00117 { 00118 protected IFilterInput next; 00119 00120 void bind (IFilterInput next) 00121 { 00122 this.next = next; 00123 } 00124 00125 void unbind () 00126 { 00127 } 00128 } 00129 @endcode 00130 00131 The first method is invoked when the filter is attached to a 00132 conduit, while the second is invoked just before the conduit 00133 is closed. Both of these may be overridden by the filter for 00134 whatever purpose desired. 00135 00136 Note that an input filter can choose to sidestep reading from 00137 the conduit (per the usual case), and produce its input from 00138 somewhere else entirely. This mechanism supports the notion 00139 of 'piping' between multiple conduits, or between a conduit 00140 and something else entirely; it's a bridging mechanism. 00141 00142 ***********************************************************************/ 00143 00144 void attach (IConduitSource input); 00145 00146 /*********************************************************************** 00147 00148 Attach a filter to the IConduit output. The filter is invoked 00149 via its writer(void[]) method whenever a block of content is 00150 being written; the void[] array supplies writeable content. 00151 The filter should return the number of bytes it has actually 00152 consumed: less than or equal to the length of the provided 00153 array. 00154 00155 Filters are chained together such that the last filter added 00156 is the first one invoked. It is the responsibility of each 00157 filter to invoke the next link in the chain; for example: 00158 00159 @code 00160 class MungingOutputFilter : FilterOutput 00161 { 00162 int writer (void[] src) 00163 { 00164 char[src.length] tmp; 00165 00166 // set everything to '*' 00167 tmp = '*'; 00168 00169 // write the munged output 00170 return next.writer (tmp); 00171 } 00172 } 00173 @endcode 00174 00175 Notice how the filter invokes the 'next' instance after 00176 munging the content ... the far end of the chain is where 00177 the original IConduit writer is attached, so it will get 00178 invoked eventually assuming each filter invokes 'next'. 00179 If the next writer fails it will return IConduit.Eof, as 00180 should your filter (or throw an IOException). At the client 00181 level, filters are attached like this: 00182 00183 @code 00184 FileConduit fc = new FileConduit (...); 00185 00186 fc.attach (new ZipOutputFilter); 00187 fc.attach (new MungingOutputFilter); 00188 @endcode 00189 00190 Again, the last filter attached is the first one invoked 00191 when a block of content is actually written. Each filter has 00192 two additional methods that it may use to control behavior: 00193 00194 @code 00195 class FilterOutput : IFilterOutput 00196 { 00197 protected IFilterOutput next; 00198 00199 void bind (IFilterOutput next) 00200 { 00201 this.next = next; 00202 } 00203 00204 void unbind () 00205 { 00206 } 00207 } 00208 @endcode 00209 00210 The first method is invoked when the filter is attached to a 00211 conduit, while the second is invoked just before the conduit 00212 is closed. Both of these may be overridden by the filter for 00213 whatever purpose desired. 00214 00215 Note that an output filter can choose to sidestep writing to 00216 the conduit (per the usual case), and direct its output to 00217 somewhere else entirely. This mechanism supports the notion 00218 of 'piping' between multiple conduits, or between a conduit 00219 and something else entirely; as with the input-filter case, 00220 this is a bridging mechanism. 00221 00222 ***********************************************************************/ 00223 00224 void attach (IConduitSink output); 00225 00226 /*********************************************************************** 00227 00228 read from conduit into a target buffer 00229 00230 ***********************************************************************/ 00231 00232 int read (IBuffer target); 00233 00234 /*********************************************************************** 00235 00236 write to conduit from a source buffer 00237 00238 ***********************************************************************/ 00239 00240 int write (IBuffer source); 00241 00242 /*********************************************************************** 00243 00244 Transfer the content of this conduit to another one. 00245 Returns true if all content was successfully copied. 00246 00247 ***********************************************************************/ 00248 00249 IConduit copy (IConduit source); 00250 00251 /*********************************************************************** 00252 00253 Flush buffer content out to this conduit. 00254 00255 Returns true if all content is flushed; false if writing 00256 results in an Eof condition. 00257 00258 ***********************************************************************/ 00259 00260 IConduit flush (IBuffer source); 00261 00262 /*********************************************************************** 00263 00264 Create a Buffer of a conduit-specific size 00265 00266 ***********************************************************************/ 00267 00268 IBuffer createBuffer (); 00269 00270 /*********************************************************************** 00271 00272 Returns true is this conduit can be read from 00273 00274 ***********************************************************************/ 00275 00276 bool isReadable (); 00277 00278 /*********************************************************************** 00279 00280 Returns true if this conduit can be written to 00281 00282 ***********************************************************************/ 00283 00284 bool isWritable (); 00285 00286 /*********************************************************************** 00287 00288 Returns true if this conduit is seekable (whether it 00289 implements ISeekable) 00290 00291 ***********************************************************************/ 00292 00293 bool isSeekable (); 00294 } 00295 00296 00297 00298 /******************************************************************************* 00299 00300 Defines an input-filter contract. The filter is invoked 00301 via its reader(void[]) method whenever a block of content is 00302 being read; the void[] array represents content destination. 00303 The filter should return the number of bytes it has actually 00304 produced: less than or equal to the length of the provided 00305 array. 00306 00307 Filters are chained together such that the last filter added 00308 is the first one invoked. It is the responsibility of each 00309 filter to invoke the next link in the chain; for example: 00310 00311 @code 00312 class MungingInputFilter : FilterInput 00313 { 00314 int reader (void[] dst) 00315 { 00316 // read the next X bytes 00317 int count = next.reader (dst); 00318 00319 // set everything to '*' ! 00320 dst[0..count] = '*'; 00321 00322 // say how many we read 00323 return count; 00324 } 00325 } 00326 @endcode 00327 00328 Notice how this filter invokes the 'next' instance before 00329 munging the content ... the far end of the chain is where 00330 the original IConduit reader is attached, so it will get 00331 invoked eventually assuming each filter invokes 'next'. 00332 If the next reader fails it will return IConduit.Eof, as 00333 should your filter (or throw an IOException). From a client 00334 perspective, filters are attached like this: 00335 00336 @code 00337 FileConduit fc = new FileConduit (...); 00338 00339 fc.attach (new ZipInputFilter); 00340 fc.attach (new MungingInputFilter); 00341 @endcode 00342 00343 Again, the last filter attached is the first one invoked 00344 when a block of content is actually read. Each filter has 00345 two additional methods that it may use to control behavior: 00346 00347 @code 00348 class FilterInput : IFilterInput 00349 { 00350 protected IFilterInput next; 00351 00352 void bind (IFilterInput next) 00353 { 00354 this.next = next; 00355 } 00356 00357 void unbind () 00358 { 00359 } 00360 } 00361 @endcode 00362 00363 The first method is invoked when the filter is attached to a 00364 conduit, while the second is invoked just before the conduit 00365 is closed. Both of these may be overridden by the filter for 00366 whatever purpose desired. 00367 00368 Note that an input filter can choose to sidestep reading from 00369 the conduit (per the usual case), and produce its input from 00370 somewhere else entirely. This mechanism supports the notion 00371 of 'piping' between multiple conduits, or between a conduit 00372 and something else entirely; it's a bridging mechanism. 00373 00374 *******************************************************************************/ 00375 00376 interface IConduitSource 00377 { 00378 /*********************************************************************** 00379 00380 conduit-specific reader 00381 00382 ***********************************************************************/ 00383 00384 int reader (void[] dst); 00385 00386 /*********************************************************************** 00387 00388 ***********************************************************************/ 00389 00390 void bind (IConduitSource next); 00391 00392 /*********************************************************************** 00393 00394 ***********************************************************************/ 00395 00396 void unbind (); 00397 } 00398 00399 00400 /******************************************************************************* 00401 00402 Defines an output-filter contract. The filter is invoked 00403 via its writer(void[]) method whenever a block of content is 00404 being written; the void[] array supplies writeable content. 00405 The filter should return the number of bytes it has actually 00406 consumed: less than or equal to the length of the provided 00407 array. 00408 00409 Filters are chained together such that the last filter added 00410 is the first one invoked. It is the responsibility of each 00411 filter to invoke the next link in the chain; for example: 00412 00413 @code 00414 class MungingOutputFilter : FilterOutput 00415 { 00416 int writer (void[] src) 00417 { 00418 char[src.length] tmp; 00419 00420 // set everything to '*' 00421 tmp = '*'; 00422 00423 // write the munged output 00424 return next.writer (tmp); 00425 } 00426 } 00427 @endcode 00428 00429 Notice how the filter invokes the 'next' instance after 00430 munging the content ... the far end of the chain is where 00431 the original IConduit writer is attached, so it will get 00432 invoked eventually assuming each filter invokes 'next'. 00433 If the next writer fails it will return IConduit.Eof, as 00434 should your filter (or throw an IOException). At the client 00435 level, filters are attached like this: 00436 00437 @code 00438 FileConduit fc = new FileConduit (...); 00439 00440 fc.attach (new ZipOutputFilter); 00441 fc.attach (new MungingOutputFilter); 00442 @endcode 00443 00444 Again, the last filter attached is the first one invoked 00445 when a block of content is actually written. Each filter has 00446 two additional methods that it may use to control behavior: 00447 00448 @code 00449 class FilterOutput : IFilterOutput 00450 { 00451 protected IFilterOutput next; 00452 00453 void bind (IFilterOutput next) 00454 { 00455 this.next = next; 00456 } 00457 00458 void unbind () 00459 { 00460 } 00461 } 00462 @endcode 00463 00464 The first method is invoked when the filter is attached to a 00465 conduit, while the second is invoked just before the conduit 00466 is closed. Both of these may be overridden by the filter for 00467 whatever purpose desired. 00468 00469 Note that an output filter can choose to sidestep writing to 00470 the conduit (per the usual case), and direct its output to 00471 somewhere else entirely. This mechanism supports the notion 00472 of 'piping' between multiple conduits, or between a conduit 00473 and something else entirely; as with the input-filter case, 00474 this is a bridging mechanism. 00475 00476 *******************************************************************************/ 00477 00478 interface IConduitSink 00479 { 00480 /*********************************************************************** 00481 00482 conduit-specific writer 00483 00484 ***********************************************************************/ 00485 00486 int writer (void[] src); 00487 00488 /*********************************************************************** 00489 00490 ***********************************************************************/ 00491 00492 void bind (IConduitSink next); 00493 00494 /*********************************************************************** 00495 00496 ***********************************************************************/ 00497 00498 void unbind (); 00499 } 00500 00501 00502 00503 00504 /******************************************************************************* 00505 00506 Models the ability to seek within a conduit. 00507 00508 *******************************************************************************/ 00509 00510 interface ISeekable 00511 { 00512 /*********************************************************************** 00513 00514 The anchor positions supported by ISeekable 00515 00516 ***********************************************************************/ 00517 00518 enum SeekAnchor { 00519 Begin = 0, 00520 Current = 1, 00521 End = 2, 00522 }; 00523 00524 /*********************************************************************** 00525 00526 Return the current conduit position (such as file position) 00527 00528 ***********************************************************************/ 00529 00530 long getPosition (); 00531 00532 /*********************************************************************** 00533 00534 Move the file position to the given offset (from the conduit 00535 start) and return the adjusted position. 00536 00537 ***********************************************************************/ 00538 00539 long seek (long offset); 00540 00541 /*********************************************************************** 00542 00543 Move the file position to the given offset from the provided 00544 anchor point, and return the adjusted position. 00545 00546 ***********************************************************************/ 00547 00548 long seek (long offset, SeekAnchor anchor); 00549 } 00550