]> git.sesse.net Git - casparcg/blob - protocol/util/strategy_adapters.h
Fixed bug in \r\n delimiter handling in protocol code
[casparcg] / protocol / util / strategy_adapters.h
1 /*\r
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
3 *\r
4 * This file is part of CasparCG (www.casparcg.com).\r
5 *\r
6 * CasparCG is free software: you can redistribute it and/or modify\r
7 * it under the terms of the GNU General Public License as published by\r
8 * the Free Software Foundation, either version 3 of the License, or\r
9 * (at your option) any later version.\r
10 *\r
11 * CasparCG is distributed in the hope that it will be useful,\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14 * GNU General Public License for more details.\r
15 *\r
16 * You should have received a copy of the GNU General Public License\r
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
18 *\r
19 * Author: Helge Norberg, helge.norberg@svt.se\r
20 */\r
21 \r
22 #pragma once\r
23 \r
24 #include <boost/algorithm/string/split.hpp>\r
25 \r
26 #include "protocol_strategy.h"\r
27 #include "ProtocolStrategy.h"\r
28 \r
29 namespace caspar { namespace IO {\r
30 \r
31 /**\r
32  * A protocol strategy factory adapter for converting incoming data from a\r
33  * specific codepage to utf-16. The client_connection will do the reversed\r
34  * conversion.\r
35  *\r
36  * The adapter is not safe if the codepage contains multibyte-characters and\r
37  * the data is chunked with potentially incomplete characters, therefore it\r
38  * must be wrapped in an adapter providing complete chunks like\r
39  * delimiter_based_chunking_strategy_factory.\r
40  */\r
41 class to_unicode_adapter_factory : public protocol_strategy_factory<char>\r
42 {\r
43         std::string codepage_;\r
44         protocol_strategy_factory<wchar_t>::ptr unicode_strategy_factory_;\r
45 public:\r
46         to_unicode_adapter_factory(\r
47                         const std::string& codepage, \r
48                         const protocol_strategy_factory<wchar_t>::ptr& unicode_strategy_factory);\r
49 \r
50         virtual protocol_strategy<char>::ptr create(\r
51                         const client_connection<char>::ptr& client_connection);\r
52 };\r
53 \r
54 /**\r
55  * Protocol strategy adapter for ensuring that only complete chunks or\r
56  * "packets" are delivered to the wrapped strategy. The chunks are determined\r
57  * by a given delimiter.\r
58  */\r
59 template<class CharT>\r
60 class delimiter_based_chunking_strategy : public protocol_strategy<CharT>\r
61 {\r
62         std::basic_string<CharT> delimiter_;\r
63         std::basic_string<CharT> input_;\r
64         typename protocol_strategy<CharT>::ptr strategy_;\r
65 public:\r
66         delimiter_based_chunking_strategy(\r
67                         const std::basic_string<CharT>& delimiter, \r
68                         const typename protocol_strategy<CharT>::ptr& strategy)\r
69                 : delimiter_(delimiter)\r
70                 , strategy_(strategy)\r
71         {\r
72         }\r
73 \r
74         virtual void parse(const std::basic_string<CharT>& data)\r
75         {\r
76                 input_ += data;\r
77 \r
78                 //boost::iter_split(split, input_, boost::algorithm::first_finder(delimiter_)) was painfully slow in debug-build\r
79 \r
80                 auto delim_pos = input_.find(delimiter_);\r
81                 while(delim_pos != std::string::npos)\r
82                 {\r
83                         strategy_->parse(input_.substr(0, delim_pos));\r
84 \r
85                         input_ = std::move(input_.substr(delim_pos+delimiter_.size()));\r
86                         delim_pos = input_.find_first_of(delimiter_);\r
87                 }\r
88         }\r
89 };\r
90 \r
91 template<class CharT>\r
92 class delimiter_based_chunking_strategy_factory \r
93         : public protocol_strategy_factory<CharT>\r
94 {\r
95         std::basic_string<CharT> delimiter_;\r
96         typename protocol_strategy_factory<CharT>::ptr strategy_factory_;\r
97 public:\r
98         delimiter_based_chunking_strategy_factory(\r
99                         const std::basic_string<CharT>& delimiter, \r
100                         const typename protocol_strategy_factory<CharT>::ptr& strategy_factory)\r
101                 : delimiter_(delimiter)\r
102                 , strategy_factory_(strategy_factory)\r
103         {\r
104         }\r
105 \r
106         virtual typename protocol_strategy<CharT>::ptr create(\r
107                         const typename client_connection<CharT>::ptr& client_connection)\r
108         {\r
109                 return spl::make_shared<delimiter_based_chunking_strategy<CharT>>(\r
110                         delimiter_, strategy_factory_->create(client_connection));\r
111         }\r
112 };\r
113 \r
114 /**\r
115  * Adapts an IProtocolStrategy to be used as a\r
116  * protocol_strategy_factory<wchar_t>.\r
117  *\r
118  * Use wrap_legacy_protocol() to wrap it as a protocol_strategy_factory<char>\r
119  * for use directly by the async event server.\r
120  */\r
121 class legacy_strategy_adapter_factory \r
122         : public protocol_strategy_factory<wchar_t>\r
123 {\r
124         ProtocolStrategyPtr strategy_;\r
125 public:\r
126         legacy_strategy_adapter_factory(const ProtocolStrategyPtr& strategy);\r
127 \r
128         virtual protocol_strategy<wchar_t>::ptr create(\r
129                         const client_connection<wchar_t>::ptr& client_connection);\r
130 };\r
131 \r
132 /**\r
133  * Wraps an IProtocolStrategy in a legacy_strategy_adapter_factory, wrapped in\r
134  * a to_unicode_adapter_factory (using the codepage reported by the \r
135  * IProtocolStrategy) wrapped in a delimiter_based_chunking_strategy_factory\r
136  * with the given delimiter string.\r
137  *\r
138  * @param delimiter The delimiter to use to separate messages.\r
139  * @param strategy  The legacy protocol strategy (the same instance will serve\r
140  *                  all connections).\r
141  *\r
142  * @return the adapted strategy.\r
143  */\r
144 protocol_strategy_factory<char>::ptr wrap_legacy_protocol(\r
145                 const std::string& delimiter, \r
146                 const ProtocolStrategyPtr& strategy);\r
147 \r
148 }}\r