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