1 /*
2 
3 Copyright (c) 2002-2008, Yauheni Akhotnikau
4 Copyright (c) 2008-2013, The SObjectizer Project
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 - Redistributions of source code must retain the above copyright notice, this
11 list of conditions and the following disclaimer.
12 
13 - Redistributions in binary form must reproduce the above copyright notice, this
14 list of conditions and the following disclaimer in the documentation and/or
15 other materials provided with the distribution.
16 
17 - The name of the author may not be used to endorse or promote products derived
18 from this software without specific prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
21 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
23 EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
25 OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
28 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
29 OF SUCH DAMAGE.
30 
31 */
32 
33 /*!
34 	\file oess_2/tlv/h/compound.hpp
35 	\brief ����� %oess_2::tlv::coumpound_tlv_t.
36 */
37 
38 #if !defined( _OESS_2__TLV__COMPOUND_HPP_ )
39 #define _OESS_2__TLV__COMPOUND_HPP_
40 
41 #include <oess_2/tlv/h/declspec.hpp>
42 
43 #include <map>
44 #include <string>
45 #include <functional>
46 #include <algorithm>
47 
48 #include <cpp_util_2/h/nocopy.hpp>
49 
50 #include <oess_2/defs/h/ex.hpp>
51 
52 #include <oess_2/io/h/substream.hpp>
53 
54 #include <oess_2/tlv/h/errno.hpp>
55 #include <oess_2/tlv/h/base.hpp>
56 #include <oess_2/tlv/h/default_processors.hpp>
57 
58 namespace oess_2
59 {
60 
61 namespace tlv
62 {
63 
64 //
65 // tlv_add_caller_t
66 //
67 
68 //! ��������������� ����� ��� ��������� ���������
69 //! ����������� TLV � ���������� TLV.
70 /*!
71 	\since v.1.0.9
72 
73 	��� ������������� compound_tlv_t ��������� ���� ���������:
74 	��� ����������� TLV ������ ���� �������� � ����������
75 	TLV ����������� compound_tlv_t::tlv_add(). ���� �� ����������
76 	TLV ����� ����� ����������� TLV, �� ����� ������ �������
77 	tlv_add ��� ������-�� �� ���. ��� �������� � ��������������������
78 	������.
79 
80 	����� tlv_add_caller_t �������� ��� �������� ��������� �������:
81 	- ��� ������� ������������ TLV, ������������ � ��������������
82 	������ compound_tlv_t::tlv_add(), ����������� ������� ����
83 	tlv_add_caller_t;
84 	- � ����������� ������� �� �������� ���������� ����������
85 	������ �� ������ compound_tlv_t:
86 
87 \code
88 typedef oess_2::tlv::compound_tlv_t<tag_type_t > compound_t;
89 class	my_compound_tlv_t :
90 	public compound_t
91 {
92 	private :
93 		oess_2::tlv::tagged_scalar_wrapper_t<
94 				0x02, string_tlv_t >
95 			m_member_1;
96 		const tlv_add_t	m_member_1_inserter;
97 
98 		oess_2::tlv::tagged_scalar_wrapper_t<
99 				0x05, oess_2::tlv::scalar_tlv_t<
100 					tag_type_t, oess_2::ushort_t > >
101 			m_member_2;
102 		const tlv_add_t	m_member_2_inserter;
103 
104 	public :
105 		my_compound_tlv_t(
106 			const std::string & member_1,
107 			oess_2::ushort_t member_2 )
108 			:
109 				compound_t( 0x01 ),
110 				m_member_1( member_1 ),
111 				m_member_1_inserter( tlv_self(), m_member_1 ),
112 
113 				m_member_2( member_2 ),
114 				m_member_2_inserter( tlv_self(), m_member_2 ),
115 		{
116 		}
117 
118 		my_compound_tlv_t()
119 			:
120 				compound_t( 0x01 ),
121 				m_member_1_inserter( tlv_self(), m_member_1 ),
122 				m_member_2_inserter( tlv_self(), m_member_2 )
123 		{
124 		}
125 };
126 \endcode
127 */
128 template< class Compound >
129 class	tlv_add_caller_t
130 {
131 	public :
132 		/*!
133 			������ �������� ����� tlv_add() � ������� owner.
134 		*/
tlv_add_caller_t(Compound & owner,tlv_base_t & nested)135 		tlv_add_caller_t(
136 			//! ���������� TLV.
137 			Compound & owner,
138 			//! ��������� TLV.
139 			tlv_base_t & nested )
140 		{
141 			owner.tlv_add( nested );
142 		}
143 };
144 
145 //
146 // compound_tlv_t
147 //
148 
149 //! TLV ��� ������������ ��������� ��������.
150 /*!
151 	������� compound_tlv_t �� ����� ������������.
152 
153 \par ������ (��. oess_2::tlv::basic_string_tlv_t)
154 \code
155 typedef oess_2::tlv::compound_tlv_t<oess_2::ushort_t > compound_t;
156 class	my_compound_tlv_t :
157 	public compound_t
158 {
159 	private :
160 		oess_2::tlv::basic_string_tlv_t<
161 				oess_2::ushort, oess_2::char_t >
162 			m_member_1;
163 		oess_2::tlv::basic_string_tlv_t<
164 				oess_2::ushort, oess_2::char_t >
165 			m_member_2;
166 	public :
167 		my_compound_tlv_t() :
168 			compound_t( 0x01 ),
169 			m_member_1( 0x02 ),
170 			m_member_2( 0x03 )
171 		{
172 			tlv_add( 0x02, m_member_1 );
173 			tlv_add( 0x03, m_member_2 );
174 		}
175 };
176 \endcode
177 */
178 template<
179 	class Tag_type,
180 	class Tag_processor = default_tag_processor_t< Tag_type >,
181 	class Length_processor = default_length_processor_t< Tag_type > >
182 class	compound_tlv_t :
183 	public tlv_base_t,
184 	private cpp_util_2::nocopy_t
185 {
186 	public :
187 		//! ������� ��� compound_tlv_t< Tag_type,
188 		//! Tag_processor, Length_processor >.
189 		typedef compound_tlv_t< Tag_type,
190 				Tag_processor, Length_processor >
191 			self_t;
192 
193 		//! ��� ������� %tlv_add_caller_t ���
194 		//! ������� ���������� TLV.
195 		/*! \since v.1.0.9 */
196 		typedef tlv_add_caller_t< self_t >	tlv_add_t;
197 
198 	private :
199 		//! ��� ������� �������� TLV.
200 		typedef std::map< default_tag_type_t, tlv_base_t * >
201 			tlv_map_t;
202 
203 		//! �������� ��� std::for_each.
204 		/*!
205 			��������� ������ ���� �������� TLV.
206 		*/
207 		class	length_calc_t :
208 			public std::unary_function<
209 				const typename tlv_map_t::value_type &, void >
210 		{
211 			private :
212 				size_t &	m_length;
213 			public :
length_calc_t(size_t & length)214 				length_calc_t( size_t & length )
215 					:
216 						m_length( length )
217 				{
218 				}
219 
220 				result_type
operator ()(argument_type a)221 				operator()( argument_type a )
222 				{
223 					m_length += a.second->tlv_size();
224 				}
225 		};
226 
227 		//! �������� ��� std::for_each.
228 		/*!
229 			���������� ��� �������� TLV.
230 		*/
231 		class	packer_t :
232 			public std::unary_function<
233 				const typename tlv_map_t::value_type &, void >
234 		{
235 			private :
236 				oess_2::io::ostream_t &	m_stream;
237 			public :
packer_t(oess_2::io::ostream_t & stream)238 				packer_t( oess_2::io::ostream_t & stream )
239 					:
240 						m_stream( stream )
241 				{
242 				}
243 
244 				result_type
operator ()(argument_type a)245 				operator()( argument_type a )
246 				{
247 					a.second->tlv_pack( m_stream );
248 				}
249 		};
250 
251 		//! �������� ���� Tag.
252 		Tag_processor	m_tag;
253 
254 		//! ���������� ���� Length.
255 		Length_processor	m_length;
256 
257 		//! �������� TLV.
258 		tlv_map_t	m_tlvs;
259 
260 		//! ������� ������� TLV �� ������.
261 		/*!
262 			����������, ����� �� ������ ��� ���� ��������� ���� Tag.
263 		*/
264 		void
try_unpack_tlv(default_tag_type_t tag,oess_2::io::istream_t & s)265 		try_unpack_tlv(
266 			//! ���� Tag, ����������� �� ������.
267 			default_tag_type_t tag,
268 			//! �����, �� �������� ���������� ������.
269 			oess_2::io::istream_t & s )
270 		{
271 			typename tlv_map_t::iterator it = m_tlvs.find( tag );
272 			if( it != m_tlvs.end() )
273 				// ��� ��������.
274 				it->second->tlv_unpack( s, tag );
275 			else
276 				// ��� �� ��������.
277 				tlv_on_unexpected_tag( tag, s );
278 		}
279 
280 
281 	protected :
282 		//! ���������� �� ���������� TLV, ������� ���
283 		//! ��������� �� ������� ������.
284 		/*!
285 			���������� � ������� ������ ��������� ����������
286 			oess_2::io::physic_ex_t � �����
287 			oess_2::tlv::err::c_unexpected_tag.
288 		*/
289 		virtual void
tlv_on_unexpected_tag(default_tag_type_t tag,oess_2::io::istream_t & s)290 		tlv_on_unexpected_tag(
291 			//! ���� Tag, ����������� �� ������.
292 			default_tag_type_t tag,
293 			//! �����, �� �������� ���������� ������.
294 			/*!
295 				����������� ������ ����� ������������ ������
296 				�������� ��� ���������� �� ������ �������� TLV.
297 			*/
298 			oess_2::io::istream_t & s )
299 		{
300 			OESS_THROW_PHYSIC( oess_2::tlv::err::c_unexpected_tag,
301 				"compound tag: " << m_tag.query_tag()
302 				<< ", child tag found: " << tag )
303 		}
304 
305 	public :
compound_tlv_t(Tag_type id)306 		compound_tlv_t( Tag_type id )
307 			:
308 				m_tag( id )
309 		{
310 		}
311 
~compound_tlv_t()312 		virtual ~compound_tlv_t()
313 		{
314 		}
315 
316 		//! �������� �������� Tag.
317 		virtual default_tag_type_t
tlv_tag() const318 		tlv_tag() const
319 		{
320 			return m_tag.query_tag();
321 		}
322 
323 		//! �������� �������� TLV.
324 		/*!
325 			���� � compound_tlv_t ��� ��� ������ TLV
326 			Tag, ������ tlv.tlv_tag(), �� ��� �������� ��������.
327 		*/
328 		void
tlv_add(tlv_base_t & tlv)329 		tlv_add(
330 			//! �������� TLV.
331 			/*!
332 				��������� ������ ������ ������������ ��� �����,
333 				���� �� ������ � ������� compound_tlv_t.
334 			*/
335 			tlv_base_t & tlv )
336 		{
337 			m_tlvs[ tlv.tlv_tag() ] = &tlv;
338 		}
339 
340 		//! �������� �������� TLV � ��������� ����� Tag.
341 		/*!
342 			���� � compound_tlv_t ��� ��� ������ TLV � �����
343 			Tag, �� ��� �������� ��������.
344 
345 			������ ����� ������������ ��� �������, �����
346 			�������� ������ tlv ������ ������������ TLV �
347 			���� Tag (�.�. tag != tlv.tlv_tag()).
348 
349 			���� ��� �������, ����� ������ tlv ����� ��������
350 			� ����������� ��������������� TLV, ������ �� �������
351 			����� ����������� �������� Tag.
352 		*/
353 		void
tlv_add(default_tag_type_t tag,tlv_base_t & tlv)354 		tlv_add(
355 			//! ���� Tag ��� ��������� TLV.
356 			default_tag_type_t tag,
357 			//! �������� TLV.
358 			/*!
359 				��������� ������ ������ ������������ ��� �����,
360 				���� �� ������ � ������� compound_tlv_t.
361 			*/
362 			tlv_base_t & tlv )
363 		{
364 			m_tlvs[ tag ] = &tlv;
365 		}
366 
367 		//! ������ �������� TLV � ��������� ����� Tag.
368 		/*!
369 			���������� ��������� TLV ������� �� ���������.
370 		*/
371 		void
tlv_remove(default_tag_type_t tag)372 		tlv_remove(
373 			//! ������������� ���������� TLV.
374 			default_tag_type_t tag )
375 		{
376 			m_tlvs.erase( tag );
377 		}
378 
379 		//! ���������� ����, ������� ���������
380 		//! ��� ������������� ����� TLV (� ������ Tag, Length,
381 		//! Value).
382 		virtual size_t
tlv_size() const383 		tlv_size() const
384 		{
385 			size_t length = 0;
386 			std::for_each( m_tlvs.begin(), m_tlvs.end(),
387 				length_calc_t( length ) );
388 
389 			length += m_length.tlv_length_size( length );
390 			length += m_tag.tlv_tag_size();
391 
392 			return length;
393 		}
394 
395 		//! ���������� �������� TLV �� ������.
396 		virtual void
tlv_unpack(oess_2::io::istream_t & s,default_tag_type_t)397 		tlv_unpack(
398 			//! �����, � ������� ������� �������� �����
399 			//! �������������� ������ ����� Length � Value.
400 			oess_2::io::istream_t & s,
401 			//! � ������ ������ ������������.
402 			default_tag_type_t )
403 		{
404 			size_t length;
405 			m_length.tlv_unpack_length( s, length );
406 
407 			// ��������������� ��������� �������� TLV.
408 			oess_2::io::isubstream_t tmp_istream( s, length );
409 			while( !tmp_istream.eof() )
410 			{
411 				Tag_processor tag;
412 				tag.tlv_unpack_tag( tmp_istream );
413 
414 				try_unpack_tlv( tag.query_tag(), tmp_istream );
415 			}
416 		}
417 
418 		//! ������ TLV � �������� �����.
419 		virtual void
tlv_pack(oess_2::io::ostream_t & s) const420 		tlv_pack(
421 			//! �����, � ������� ������� �������� �����
422 			//! �������������� ������ TLV.
423 			oess_2::io::ostream_t & s ) const
424 		{
425 			// ����� ���� �������� �����.
426 			size_t length = 0;
427 			std::for_each( m_tlvs.begin(), m_tlvs.end(),
428 				length_calc_t( length ) );
429 
430 			m_tag.tlv_pack_tag( s );
431 			m_length.tlv_pack_length( s, length );
432 			if( length )
433 			{
434 				packer_t packer( s );
435 				std::for_each( m_tlvs.begin(), m_tlvs.end(), packer );
436 			}
437 		}
438 
439 		//! ���������� ������ �� ������ ����.
440 		/*! \since v.1.0.9
441 
442 			������������ ��� ������������� ������
443 			tlv_add_caller_t. */
444 		self_t &
tlv_self()445 		tlv_self()
446 		{
447 			return *this;
448 		}
449 };
450 
451 } /* namespace tlv */
452 
453 } /* namespace oess_2 */
454 
455 #endif
456 
457