blob: 98faf6d3fa3a1ea52494bc2eaf20494011b1f21d [file] [log] [blame]
Yingdi Yu3168c302015-07-04 16:45:40 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2016 Regents of the University of California.
4 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#ifndef NDN_CXX_SECURITY_TRANSFORM_BASE_HPP
23#define NDN_CXX_SECURITY_TRANSFORM_BASE_HPP
24
25#include "../../common.hpp"
Yingdi Yu38317e52015-07-22 13:58:02 -070026#include <vector>
Yingdi Yu3168c302015-07-04 16:45:40 -070027
28namespace ndn {
29namespace security {
30namespace transform {
31
32/**
33 * @file transform-base.hpp
34 *
35 * There are three types of module in a transformation chain: Source, Transform, and Sink.
36 * The ideal usage of the transformation would be:
37 *
38 * source(...) >> transform1(...) >> transform2(...) >> sink(...);
39 *
40 * When error happens in a module, the module will throw out a transform::Error, one
41 * can get the location of the module through the getIndex() method of transform::Error.
42 */
43
44/**
45 * @brief Base class of transformation error
46 */
47class Error : public std::runtime_error
48{
49public:
50 Error(size_t index, const std::string& what);
51
52 size_t
53 getIndex() const
54 {
55 return m_index;
56 }
57
58private:
59 size_t m_index;
60};
61
62/**
63 * @brief The downstream interface of a transformation module
64 *
65 * A module can accept input through this interface
66 */
67class Downstream
68{
69public:
70 /**
71 * @brief Accept input data and perform transformation.
72 *
73 * An upstream module should call this method to write data into this module.
74 * The written data will be transformed and the result will be written into the next
75 * downstream module.
76 *
77 * An upstream module can keep calling this method to until end() is called, which
78 * indicates the end of input. After that, calling this method will cause Error.
79 *
80 * If a Downstream implementation expects structured input (e.g., hex decoding requires byte-pair),
81 * it should not return less than size if final portion of input is not a complete record.
82 *
83 * @return number of bytes that has been written into this module
84 * @throws Error if this module is closed or transformation error happens.
85 */
86 size_t
87 write(const uint8_t* buf, size_t size);
88
89 /**
90 * @brief Close the input interface of a module.
91 *
92 * This method will notify this module that there is no more input and that the module
93 * should finalize transformation.
94 *
95 * Although end() can be invoked multiple times, only the first invocation takes effect.
96 */
97 void
98 end();
99
100 /**
101 * @brief Check if the input interface of a module is closed.
102 */
103 bool
104 isEnd() const
105 {
106 return m_isEnd;
107 }
108
109 /**
110 * @brief Set the module index.
111 */
112 void
113 setIndex(size_t index)
114 {
115 m_index = index;
116 }
117
118 /**
119 * @brief Get the module index.
120 */
121 size_t
122 getIndex() const
123 {
124 return m_index;
125 }
126
127protected:
128 Downstream();
129
130private:
131 /**
132 * @brief Internal implementation of write method
133 */
134 virtual size_t
135 doWrite(const uint8_t* buf, size_t size) = 0;
136
137 /**
138 * @brief Internal implementation of end method
139 */
140 virtual void
141 doEnd() = 0;
142
143private:
144 bool m_isEnd;
145 size_t m_index;
146};
147
148/**
149 * @brief The upstream interface of a transformation module
150 *
151 * A module can construct subsequent transformation chain through this interface.
152 */
153class Upstream
154{
155protected:
156 Upstream();
157
158protected:
159 /**
160 * @brief connect to next transformation module
161 */
162 void
163 appendChain(unique_ptr<Downstream> tail);
164
165 Downstream*
166 getNext()
167 {
168 return m_next.get();
169 }
170
171protected:
172 unique_ptr<Downstream> m_next;
173};
174
175/**
176 * @brief Abstraction of an intermediate transformation module
177 */
178class Transform : public Upstream,
179 public Downstream,
180 noncopyable
181{
Yingdi Yu38317e52015-07-22 13:58:02 -0700182protected:
183 typedef std::vector<uint8_t> OBuffer;
184
185 Transform();
186
187 /**
188 * @brief Read the content from output buffer and write it into next module.
Yingdi Yuae734272015-07-04 17:38:48 -0700189 *
190 * It is not guaranteed that all the content in output buffer will be flushed to next module.
Yingdi Yu38317e52015-07-22 13:58:02 -0700191 */
192 void
193 flushOutputBuffer();
194
195 /**
Yingdi Yuae734272015-07-04 17:38:48 -0700196 * @brief Read the all the content from output buffer and write it into next module.
197 * @post isOutputBufferEmpty() returns true.
198 */
199 void
200 flushAllOutput();
201
202 /**
Yingdi Yu38317e52015-07-22 13:58:02 -0700203 * @brief Set output buffer to @p buffer
204 */
205 void
206 setOutputBuffer(unique_ptr<OBuffer> buffer);
207
208 /**
209 * @brief Check if output buffer is empty
210 */
211 bool
212 isOutputBufferEmpty() const;
213
214private:
215
216 /**
217 * @brief Abstraction of data processing in an intermediate module
218 */
219 virtual size_t
220 doWrite(const uint8_t* data, size_t dataLen) final;
221
222 /**
223 * @brief Finalize transformation in this module
224 *
225 * This method will not return until all transformation result is written into next module
226 */
227 virtual void
228 doEnd() final;
229
230 /**
231 * @brief Process before transformation.
232 *
233 * @pre output buffer is empty.
234 *
235 * This method is invoked before every convert(...) invocation.
236 *
237 * This implementation does nothing. A subclass can override this method to perform
238 * specific pre-transformation procedure, e.g., read partial transformation results into
239 * output buffer.
240 */
241 virtual void
242 preTransform();
243
244 /**
245 * @brief Convert input @p data.
246 *
247 * @return The number of input bytes that have been accepted by the converter.
248 */
249 virtual size_t
250 convert(const uint8_t* data, size_t dataLen) = 0;
251
252 /**
253 * @brief Finalize the transformation.
254 *
255 * This implementation only flushes content in output buffer into next module.
256 * A subclass can override this method to perform specific finalization procedure, i.e.,
257 * finalize the transformation and flush the result into next module.
258 */
259 virtual void
260 finalize();
261
262private:
263 unique_ptr<OBuffer> m_oBuffer;
264 size_t m_outputOffset;
Yingdi Yu3168c302015-07-04 16:45:40 -0700265};
266
267/**
268 * @brief Abstraction of the transformation sink module
269 *
270 * This module does not have next module and can only accept input data
271 */
272class Sink : public Downstream,
273 noncopyable
274{
275};
276
277/**
278 * @brief Abstraction of the transformation source module
279 *
280 * This module can only accept input data from constructor
281 */
282class Source : public Upstream,
283 noncopyable
284{
285public:
286 /**
287 * @brief Connect to an intermediate transformation module.
288 */
289 Source&
290 operator>>(unique_ptr<Transform> transform);
291
292 /**
293 * @brief Connect to the last transformation module.
294 *
295 * This method will trigger the source to pump data into the transformation pipeline.
296 */
297 void
298 operator>>(unique_ptr<Sink> sink);
299
300protected:
301 Source();
302
303 /**
304 * @brief Pump all data into next transformation module.
305 */
306 void
307 pump();
308
309 /**
310 * @brief Get the source module index (should always be 0).
311 */
312 size_t
313 getIndex() const
314 {
315 return 0;
316 }
317
318private:
319 /**
320 * @brief Internal implementation of pump().
321 */
322 virtual void
323 doPump() = 0;
324
325private:
326 size_t m_nModules; // count of modules in the chain starting from this Source
327};
328
329} // namespace transform
330} // namespace security
331} // namespace ndn
332
333#endif // NDN_CXX_SECURITY_TRANSFORM_BASE_HPP