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