Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
DeviceDescription.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Frameworks/StroikaPreComp.h"
5
6#include <sstream>
7
10#include "Stroika/Foundation/DataExchange/StructuredStreamEvents/ObjectReader.h"
12#include "Stroika/Foundation/DataExchange/XML/WriterUtils.h"
15
16#include "DeviceDescription.h"
17
18// Comment this in to turn on aggressive noisy DbgTrace in this module
19// #define USE_NOISY_TRACE_IN_THIS_MODULE_ 1
20
21using std::byte;
22
23using namespace Stroika::Foundation;
25
26using namespace Stroika::Frameworks;
27using namespace Stroika::Frameworks::UPnP;
28
29/*
30 ********************************************************************************
31 ************************* DeviceDescription::Icon ******************************
32 ********************************************************************************
33 */
35{
37 sb << "{"sv;
38 sb << "MimeType: "sv << fMimeType;
39 sb << ", HorizontalPixels: "sv << fHorizontalPixels;
40 sb << ", VerticalPixels: "sv << fVerticalPixels;
41 sb << ", ColorDepth : "sv << fColorDepth;
42 sb << ", URL: "sv << fURL;
43 sb << "}"sv;
44 return sb;
45}
46
47/*
48 ********************************************************************************
49 ************************ DeviceDescription::Service ****************************
50 ********************************************************************************
51 */
52String DeviceDescription::Service::ToString () const
53{
55 sb << "{"sv;
56 sb << "Service-ID: "sv << fServiceID;
57 sb << ", SCPD-URL: "sv << fSCPDURL;
58 sb << ", Control-URL: "sv << fControlURL;
59 sb << ", Event-Sub-URL: "sv << fEventSubURL;
60 sb << "}"sv;
61 return sb;
62}
63
64/*
65 ********************************************************************************
66 ******************************* DeviceDescription ******************************
67 ********************************************************************************
68 */
70{
72 sb << "{"sv;
73 if (fPresentationURL) {
74 sb << "Presentation-URL: "sv << fPresentationURL;
75 }
76 sb << ", Device-Type: "sv << fDeviceType;
77 sb << ", Manufacture-Name: "sv << fManufactureName;
78 sb << ", Friendly-Name: "sv << fFriendlyName;
79 if (fManufacturingURL) {
80 sb << ", Manufacturing-URL: "sv << fManufacturingURL;
81 }
82 if (fModelDescription) {
83 sb << ", Model-Description: "sv << fModelDescription;
84 }
85 sb << ", Model-Name: "sv << fModelName;
86 if (fModelNumber) {
87 sb << ", Model-Number: "sv << fModelNumber;
88 }
89 if (fModelURL) {
90 sb << ", Model-URL: "sv << *fModelURL;
91 }
92 if (fSerialNumber) {
93 sb << ", Serial-Number: "sv << fSerialNumber;
94 }
95 sb << ", UDN: "sv << fUDN;
96 if (fUPC) {
97 sb << ", UPC: "sv << fUPC;
98 }
99 if (fIcons) {
100 sb << ", Icons: "sv << fIcons;
101 }
102 if (fServices) {
103 sb << ", Services: "sv << fServices;
104 }
105 sb << "}"sv;
106 return sb;
107}
108
109ObjectVariantMapper DeviceDescription::mkMapper_ ()
110{
111 ObjectVariantMapper mapper;
112
113 mapper.AddClass<Icon> ({
114 {"mimetype"sv, &Icon::fMimeType},
115 {"width"sv, &Icon::fHorizontalPixels},
116 {"height"sv, &Icon::fVerticalPixels},
117 {"depth"sv, &Icon::fColorDepth},
118 {"url"sv, &Icon::fURL},
119 });
121 mapper.AddCommonType<optional<Collection<Icon>>> ();
122
123 mapper.AddClass<Service> ({
124 {"serviceType"sv, &Service::fServiceType},
125 {"serviceId"sv, &Service::fServiceID},
126 {"SCPDURL"sv, &Service::fSCPDURL},
127 {"controlURL"sv, &Service::fControlURL},
128 {"eventSubURL"sv, &Service::fEventSubURL},
129 });
131 mapper.AddCommonType<optional<Collection<Service>>> ();
132
133 mapper.AddCommonType<optional<String>> ();
134 mapper.AddCommonType<optional<URI>> ();
135
136 mapper.AddClass<DeviceDescription> ({
137 {"presentationURL"sv, &DeviceDescription::fPresentationURL},
138 {"deviceType"sv, &DeviceDescription::fDeviceType},
139 {"manufacturer"sv, &DeviceDescription::fManufactureName},
140 {"friendlyName"sv, &DeviceDescription::fFriendlyName},
141 {"manufacturerURL"sv, &DeviceDescription::fManufacturingURL},
142 {"modelDescription"sv, &DeviceDescription::fModelDescription},
143 {"modelName"sv, &DeviceDescription::fModelName},
144 {"modelNumber"sv, &DeviceDescription::fModelNumber},
145 {"modelURL"sv, &DeviceDescription::fModelURL},
146 {"serialNumber"sv, &DeviceDescription::fSerialNumber},
147 {"UDN"sv, &DeviceDescription::fUDN},
148 {"UPC"sv, &DeviceDescription::fUPC},
149 {"iconList"sv, &DeviceDescription::fIcons},
150 {"serviceList"sv, &DeviceDescription::fServices},
151 });
152 return mapper;
153};
154
155/*
156 ********************************************************************************
157 ********************************* UPnP::Serialize ******************************
158 ********************************************************************************
159 */
160Memory::BLOB UPnP::Serialize (const DeviceDescription& dd)
161{
162 using namespace DataExchange::XML;
163
164 /*
165 // very very rough prelim draft
166 *Example based on
167 http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.0.pdf
168 */
169 stringstream tmp;
170 tmp << "<?xml version=\"1.0\"?>" << endl;
171 tmp << "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">" << endl;
172 tmp << " <specVersion>" << endl;
173 tmp << " <major>1</major>" << endl;
174 tmp << " <minor>0</minor>" << endl;
175 tmp << " </specVersion>" << endl;
176 tmp << " <device>" << endl;
177 tmp << " <deviceType>" << QuoteForXML (dd.fDeviceType) << "</deviceType>" << endl;
178 tmp << " <friendlyName>" << QuoteForXML (dd.fFriendlyName) << "</friendlyName>" << endl;
179 tmp << " <manufacturer>" << QuoteForXML (dd.fManufactureName) << "</manufacturer>" << endl;
180 if (dd.fManufacturingURL) {
181 tmp << " <manufacturerURL>" << QuoteForXML (dd.fManufacturingURL->As<String> ()) << "</manufacturerURL>" << endl;
182 }
183 if (dd.fModelDescription) {
184 tmp << " <modelDescription>" << QuoteForXML (dd.fModelDescription) << "</modelDescription>" << endl;
185 }
186 tmp << " <modelName>" << QuoteForXML (dd.fModelName) << "</modelName>" << endl;
187 if (dd.fModelNumber) {
188 tmp << " <modelNumber>" << QuoteForXML (dd.fModelNumber) << "</modelNumber>" << endl;
189 }
190 if (dd.fModelURL) {
191 tmp << " <modelURL>" << QuoteForXML (dd.fModelURL->As<String> ()) << "</modelURL>" << endl;
192 }
193 if (dd.fSerialNumber) {
194 tmp << " <serialNumber>" << QuoteForXML (dd.fSerialNumber) << "</serialNumber>" << endl;
195 }
196 tmp << " <UDN>" << QuoteForXML (dd.fUDN) << "</UDN>" << endl;
197 if (dd.fUPC) {
198 tmp << " <UPC>" << QuoteForXML (*dd.fUPC) << "</UPC>" << endl;
199 }
200 if (dd.fIcons) {
201 tmp << " <iconList>" << endl;
202 for (const DeviceDescription::Icon& i : *dd.fIcons) {
203 tmp << " <icon>" << endl;
204 tmp << " <mimetype>" << QuoteForXML (i.fMimeType.As<String> ()) << "</mimetype>" << endl;
205 tmp << " <width>" << i.fHorizontalPixels << "</width>" << endl;
206 tmp << " <height>" << i.fVerticalPixels << "</height>" << endl;
207 tmp << " <depth>" << i.fColorDepth << "</depth>" << endl;
208 tmp << " <url>" << QuoteForXML (i.fURL.As<String> ()) << "</url>" << endl;
209 tmp << " </icon>" << endl;
210 }
211 tmp << " </iconList>" << endl;
212 }
213 if (dd.fServices) {
214 tmp << " <serviceList>" << endl;
215 for (const DeviceDescription::Service& i : *dd.fServices) {
216 tmp << " <service>" << endl;
217 tmp << " <serviceType>" << QuoteForXML (i.fServiceType) << "</serviceType>" << endl;
218 tmp << " <serviceId>" << QuoteForXML (i.fServiceID) << "</serviceId>" << endl;
219 tmp << " <SCPDURL>" << QuoteForXML (i.fSCPDURL.As<String> ()) << "</SCPDURL>" << endl;
220 tmp << " <controlURL>" << QuoteForXML (i.fControlURL.As<String> ()) << "</controlURL>" << endl;
221 tmp << " <eventSubURL>" << QuoteForXML (i.fEventSubURL.As<String> ()) << "</eventSubURL>" << endl;
222 tmp << " </service>" << endl;
223 }
224 tmp << " </serviceList>" << endl;
225 }
226
227#if 0
228 tmp << " <deviceList>" << endl;
229 // <!-- Description of embedded devices defined by a UPnP Forum working committee
230 // (if any) go here -->
231 // <!-- Description of embedded devices added by UPnP vendor (if any) go here -->
232 tmp << " </deviceList>" << endl;
233#endif
234
235 if (dd.fPresentationURL.has_value ()) {
236 tmp << " <presentationURL>" << QuoteForXML (dd.fPresentationURL->As<String> ()) << "</presentationURL>" << endl;
237 }
238 tmp << " </device>" << endl;
239 tmp << "</root>" << endl;
240 return Streams::iostream::InputStreamFromStdIStream::New<byte> (tmp).ReadAll ();
241}
242
243/*
244 ********************************************************************************
245 ******************************* UPnP::DeSerialize ******************************
246 ********************************************************************************
247 */
248DeviceDescription UPnP::DeSerialize (const Memory::BLOB& b)
249{
250 using namespace Stroika::Foundation::DataExchange;
251 using namespace Stroika::Foundation::DataExchange::StructuredStreamEvents;
252 using namespace Stroika::Foundation::DataExchange::XML;
253
254 static const ObjectReader::Registry kTypesRegistry_ = [] () {
255 ObjectReader::Registry registry;
256 registry.AddCommonType<String> ();
257 registry.AddCommonType<optional<String>> ();
258 registry.AddCommonType<uint16_t> ();
259 registry.AddCommonType<URI> ();
260 registry.AddCommonType<optional<URI>> ();
261 registry.AddCommonReader_Simple<InternetMediaType> ([] (const String& s) { return InternetMediaType{s}; });
263 {Name{"mimetype"sv}, &DeviceDescription::Icon::fMimeType},
264 {Name{"width"sv}, &DeviceDescription::Icon::fHorizontalPixels},
265 {Name{"height"sv}, &DeviceDescription::Icon::fVerticalPixels},
266 {Name{"depth"sv}, &DeviceDescription::Icon::fColorDepth},
267 {Name{"url"sv}, &DeviceDescription::Icon::fURL},
268 });
269 registry.AddCommonReader_Class<DeviceDescription::Service> ({
270 {Name{"serviceType"sv}, &DeviceDescription::Service::fServiceType},
271 {Name{"serviceId"sv}, &DeviceDescription::Service::fServiceID},
272 {Name{"SCPDURL"sv}, &DeviceDescription::Service::fSCPDURL},
273 {Name{"controlURL"sv}, &DeviceDescription::Service::fControlURL},
274 });
276 registry.AddCommonType<optional<Collection<DeviceDescription::Icon>>> ();
278 registry.AddCommonType<optional<Collection<DeviceDescription::Service>>> ();
280 {Name{"presentationURL"sv}, &DeviceDescription::fPresentationURL},
281 {Name{"deviceType"sv}, &DeviceDescription::fDeviceType},
282 {Name{"manufacturer"sv}, &DeviceDescription::fManufactureName},
283 {Name{"friendlyName"sv}, &DeviceDescription::fFriendlyName},
284 {Name{"manufacturerURL"sv}, &DeviceDescription::fManufacturingURL},
285 {Name{"modelDescription"sv}, &DeviceDescription::fModelDescription},
286 {Name{"modelName"sv}, &DeviceDescription::fModelName},
287 {Name{"modelNumber"sv}, &DeviceDescription::fModelNumber},
288 {Name{"modelURL"sv}, &DeviceDescription::fModelURL},
289 {Name{"serialNum"sv}, &DeviceDescription::fSerialNumber},
290 {Name{"UDN"sv}, &DeviceDescription::fUDN},
291 {Name{"UPC"sv}, &DeviceDescription::fUPC},
292 {Name{"iconList"sv}, &DeviceDescription::fIcons},
293 {Name{"serviceList"sv}, &DeviceDescription::fServices},
294 });
295 return registry;
296 }();
297
298 DeviceDescription deviceDescription;
299#if USE_NOISY_TRACE_IN_THIS_MODULE_
300 DbgTrace (L"xml data: %s", Streams::BinaryToText::Reader::New (b).ReadAll ().c_str ());
301#endif
302#if qStroika_Foundation_DataExchange_XML_SupportParsing
303 {
305 kTypesRegistry_, make_shared<ObjectReader::ReadDownToReader> (kTypesRegistry_.MakeContextReader (&deviceDescription), Name{"device"sv})};
306 XML::SAXParse (b, &ctx);
307 }
308#else
309 WeakAssertNotImplemented (); // may want to allow to continue, as this may not be critical functionality, but you probably want XML parser when running this code...
310#endif
311#if USE_NOISY_TRACE_IN_THIS_MODULE_
312 DbgTrace ("deviceDescription: {}"_f, deviceDescription);
313#endif
314 return deviceDescription;
315}
#define WeakAssertNotImplemented()
Definition Assertions.h:483
#define DbgTrace
Definition Trace.h:309
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
A Collection<T> is a container to manage an un-ordered collection of items, without equality defined ...
Definition Collection.h:102
ObjectVariantMapper can be used to map C++ types to and from variant-union types, which can be transp...
nonvirtual void AddClass(const Traversal::Iterable< StructFieldInfo > &fieldDescriptions, const ClassMapperOptions< CLASS > &mapperOptions={})
nonvirtual void AddCommonType(ARGS &&... args)
nonvirtual void AddCommonReader_Class(const Traversal::Iterable< StructFieldInfo > &fieldDescriptions)
nonvirtual void AddCommonReader_Simple(const function< T(String)> &converterFromString2T)
Add reader for any type that is stringish: provide convert function from string to T; Simple wrapper ...
nonvirtual shared_ptr< IElementConsumer > MakeContextReader(type_index ti, void *destinationObject) const
Ptr New(const InputStream::Ptr< byte > &src, optional< AutomaticCodeCvtFlags > codeCvtFlags={}, optional< SeekableFlag > seekable={}, ReadAhead readAhead=eReadAheadAllowed)
Create an InputStream::Ptr<Character> from the arguments (usually binary source) - which can be used ...