1 /**
2 * Filter
3 * 
4 * Copyright:
5 * (C) 1999-2007 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 * (C) 2013 Joel Low
8 *
9 * License:
10 * Botan is released under the Simplified BSD License (see LICENSE.md)
11 */
12 module botan.filters.filter;
13 
14 import memutils.vector;
15 import botan.utils.types;
16 import botan.filters.secqueue;
17 import botan.utils.exceptn;
18 
19 interface Filterable {
20 public:
21     /**
22     * Returns: descriptive name for this filter
23     */
24     @property string name() const;
25     
26     /**
27     * Write a portion of a message to this filter.
28     *
29     * Params:
30     *  input = the input as a ubyte array
31     *  length = the length of the ubyte array input
32     */
33     void write(const(ubyte)* input, size_t length);
34     
35     /**
36     * Start a new message. Must be closed by endMsg() before another
37     * message can be started.
38     */
39     void startMsg();
40     
41     /**
42     * Notify that the current message is finished; flush buffers and
43     * do end-of-message processing (if any).
44     */
45     void endMsg();
46     
47     /**
48     * Check whether this filter is an attachable filter.
49     * Returns: true if this filter is attachable, false otherwise
50     */
51     bool attachable();
52 
53     /**
54     * Params:
55     *  filters = the filters to set
56     *  count = number of items in filters
57     */
58     void setNext(Filter* filters, size_t size);
59 
60 }
61 
62 /**
63 * This class represents general abstract filter objects.
64 */
65 abstract class Filter : Filterable
66 {
67 public:
68     /**
69     * Write a portion of a message to this filter.
70     *
71     * Params:
72     *  input = the input as a ubyte array
73     */
74     final void write(const(ubyte)[] input) { write(input.ptr, input.length); }
75 
76     abstract void write(const(ubyte)* input, size_t length);
77 
78     /**
79     * Params:
80     *  input = some input for the filter
81     *  length = the length of in
82     */
83     void send(const(ubyte)* input, size_t length)
84     {
85         if (!length)
86             return;
87         
88         bool nothing_attached = true;
89         foreach (size_t j; 0 .. totalPorts())
90             if (m_next[j])
91         {
92             if (m_write_queue.length)
93                 m_next[j].write(m_write_queue.ptr, m_write_queue.length);
94             m_next[j].write(input, length);
95             nothing_attached = false;
96         }
97         
98         if (nothing_attached)
99             m_write_queue ~= input[0 .. length];
100         else
101             m_write_queue.clear();
102     }
103 
104 
105     /**
106     * Params:
107     *  input = some input for the filter
108     */
109     final void send(ubyte input) { send(&input, 1); }
110 
111     /**
112     * Params:
113     *  input = some input for the filter
114     */
115     final void send(ALLOC)(auto const ref Vector!(ubyte, ALLOC) input) { send(input.ptr, input.length); }
116 
117     /**
118     * Params:
119     *  input = some input for the filter
120     */
121     final void send(ALLOC)(auto const ref RefCounted!(Vector!(ubyte, ALLOC), ALLOC) input) { send(input.ptr, input.length); }
122 
123     /**
124     * Params:
125     *  input = some input for the filter
126     *  length = the number of bytes of in to send
127     */
128     final void send(ALLOC)(auto const ref Vector!(ubyte, ALLOC) input, size_t length)
129     {
130         send(input.ptr, length);
131     }
132 
133     /**
134     * Params:
135     *  input = some input for the filter
136     *  length = the number of bytes of in to send
137     */
138     final void send(ALLOC)(auto const ref RefCounted!(Vector!(ubyte, ALLOC), ALLOC) input, size_t length)
139     {
140         send(input.ptr, length);
141     }
142 
143     /*
144     * Filter Constructor
145     */
146     this()
147     {
148         m_next.resize(1);
149         m_port_num = 0;
150         m_filter_owns = 0;
151         m_owned = false;
152     }
153 
154     /**
155     * Start a new message in this and all following filters. Only for
156     * internal use, not intended for use in client applications.
157     */
158     void newMsg()
159     {
160         startMsg();
161         foreach (size_t j; 0 .. totalPorts())
162             if (m_next[j])
163                 m_next[j].newMsg();
164     }
165 
166     /**
167     * End a new message in this and all following filters. Only for
168     * internal use, not intended for use in client applications.
169     */
170     void finishMsg()
171     {
172         endMsg();
173         foreach (size_t j; 0 .. totalPorts())
174             if (m_next[j])
175                 m_next[j].finishMsg();
176     }
177 
178     /*
179     * Return the total number of ports
180     */
181     size_t totalPorts() const
182     {
183         return m_next.length;
184     }
185 
186     size_t currentPort() const { return m_port_num; }
187 
188     /**
189     * Set the active port
190     * Params:
191     *  new_port = the new value
192     */
193     void setPort(size_t new_port)
194     {
195         if (new_port >= totalPorts())
196             throw new InvalidArgument("Filter: Invalid port number");
197         m_port_num = new_port;
198     }
199 
200     size_t owns() const { return m_filter_owns; }
201 
202     /**
203     * Attach another filter to this one
204     * Params:
205     *  new_filter = filter to attach
206     */
207     void attach(Filter new_filter)
208     {
209         if (new_filter)
210         {
211             Filter last = this;
212             while (last.getNext())
213                 last = last.getNext();
214             last.m_next[last.currentPort()] = new_filter;
215         }
216     }
217 
218     /**
219     * Params:
220     *  filters = the filters to set
221     *  size = number of items in filters
222     */
223     override void setNext(Filter* filters, size_t size)
224     {
225         m_next.clear();
226         
227         m_port_num = 0;
228         m_filter_owns = 0;
229         
230         while (size && filters && (filters[size-1] is null))
231             --size;
232         
233         if (filters && size)
234             m_next[] = filters[0 .. size];
235     }
236 
237 
238     /*
239     * Return the next Filter in the logical chain
240     */
241     Filter getNext() const
242     {
243         if (m_port_num < m_next.length)
244             return m_next[m_port_num];
245         return null;
246     }
247 
248     abstract bool attachable() { return true; }
249     abstract void startMsg() {}
250     abstract void endMsg() {}
251     abstract @property string name() const;
252 
253     SecureVector!ubyte m_write_queue;
254     Vector!Filter m_next;
255     size_t m_port_num, m_filter_owns;
256 
257     // true if filter belongs to a pipe -. prohibit filter sharing!
258     bool m_owned;
259 }
260 
261 /**
262 * This is the abstract FanoutFilter base class.
263 **/
264 class FanoutFilter : Filter, Filterable
265 {
266 protected:
267     /**
268     * Increment the number of filters past us that we own
269     */
270     void incrOwns() { ++m_filter_owns; }
271 
272     void setNext(Filter f, size_t n) { super.setNext(&f, 1); }
273 
274     override void setPort(size_t n) { setPort(n); }
275 
276     override void setNext(Filter* f, size_t n) { super.setNext(f, n); }
277 
278     override void attach(Filter f) { attach(f); }
279 
280 }
281 
282 /**
283 * The type of checking to be performed by decoders:
284 * NONE - no checks, IGNORE_WS - perform checks, but ignore
285 * whitespaces, FULL_CHECK - perform checks, also complain
286 * about white spaces.
287 */
288 alias DecoderChecking = ubyte;
289 enum : DecoderChecking { NONE, IGNORE_WS, FULL_CHECK }