1 /*******************************************************************************
2 
3         copyright:      Copyright (c) 2007 Kris Bell. All rights reserved
4 
5         license:        BSD style: $(LICENSE)
6 
7         version:        Initial release: Oct 2007
8 
9         author:         Kris
10 
11 *******************************************************************************/
12 
13 module tango.io.stream.Digester;
14 
15 private import tango.io.device.Conduit;
16 
17 private import tango.util.digest.Digest;
18 
19 /*******************************************************************************
20 
21         Inject a digest filter into an input stream, updating the digest
22         as information flows through it.
23 
24 *******************************************************************************/
25 
26 class DigestInput : InputFilter, InputFilter.Mutator
27 {
28         private Digest filter;
29 
30         /***********************************************************************
31 
32                 Accepts any input stream, and any digest derivation.
33 
34         ***********************************************************************/
35 
36         this (InputStream stream, Digest digest)
37         {
38                 super (stream);
39                 filter = digest;
40         }
41 
42         /***********************************************************************
43 
44                 Read from conduit into a target array. The provided dst
45                 will be populated with content from the conduit.
46 
47                 Returns the number of bytes read, which may be less than
48                 requested in dst (or IOStream.Eof for end-of-flow.)
49 
50         ***********************************************************************/
51 
52         final override size_t read (void[] dst)
53         {
54                 auto len = source.read (dst);
55                 if (len != Eof)
56                     filter.update (dst [0 .. len]);
57                 return len;
58         }
59 
60         /***********************************************************************
61 
62                 Slurp remaining stream content and return this.
63 
64         ***********************************************************************/
65 
66         final DigestInput slurp (void[] dst = null)
67         {
68                 if (dst.length is 0)
69                     dst.length = conduit.bufferSize;
70 
71                 while (read(dst) != Eof) {}
72                 return this;
73         }
74 
75         /********************************************************************
76 
77                 Return the Digest instance we were created with. Use this
78                 to access the resultant binary or hex digest value.
79 
80         *********************************************************************/
81 
82         final Digest digest()
83         {
84                 return filter;
85         }
86 }
87 
88 
89 /*******************************************************************************
90 
91         Inject a digest filter into an output stream, updating the digest
92         as information flows through it. Here's an example where we calculate
93         an MD5 digest as a side-effect of copying a file:
94         ---
95         auto output = new DigestOutput(new FileOutput("output"), new Md5);
96         output.copy (new FileInput("input"));
97 
98         Stdout.formatln ("hex digest: {}", output.digest.hexDigest);
99         ---
100 
101 *******************************************************************************/
102 
103 class DigestOutput : OutputFilter, InputFilter.Mutator
104 {
105         private Digest filter;
106 
107         /***********************************************************************
108 
109                 Accepts any output stream, and any digest derivation.
110 
111         ***********************************************************************/
112 
113         this (OutputStream stream, Digest digest)
114         {
115                 super (stream);
116                 filter = digest;
117         }
118 
119         /***********************************************************************
120 
121                 Write to conduit from a source array. The provided src
122                 content will be written to the conduit.
123 
124                 Returns the number of bytes written from src, which may
125                 be less than the quantity provided.
126 
127         ***********************************************************************/
128 
129         final override size_t write (const(void)[] src)
130         {
131                 auto len = sink.write (src);
132                 if (len != Eof)
133                     filter.update (src[0 .. len]);
134                 return len;
135         }
136 
137         /********************************************************************
138 
139                 Return the Digest instance we were created with. Use this
140                 to access the resultant binary or hex digest value.
141 
142         *********************************************************************/
143 
144         final Digest digest()
145         {
146                 return filter;
147         }
148 }
149 
150 
151 /*******************************************************************************
152 
153 *******************************************************************************/
154 
155 debug (DigestStream)
156 {
157         import tango.io.Stdout;
158         import tango.io.device.Array;
159         import tango.util.digest.Md5;
160         import tango.io.stream.FileStream;
161 
162         void main()
163         {
164                 auto output = new DigestOutput(new Array(1024, 1024), new Md5);
165                 output.copy (new FileInput("Digester.d"));
166 
167                 Stdout.formatln ("hex digest:{}", output.digest.hexDigest);
168         }
169 }