Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
ServiceDescriptionSchema.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#include "Stroika/Frameworks/StroikaPreComp.h"
5
6#include "Stroika/Foundation/Containers/Mapping.h"
9
11
12/*
13 * The UPnP service description (SCPD) schema, embedded - with one correction, which is most of what this file is
14 * about. @see DeviceDescriptionSchema.cpp for why each schema is a translation unit of its own, and for why a copy is
15 * carried here at all.
16 *
17 * The schema is https://upnp.org/schemas/service-1-0.xsd as it stood 2026-10-13.
18 *
19 * THE CORRECTION: as published, the schema restricts stateVariable's sendEvents and multicast attributes to the
20 * enumeration {"1", "0"}. The specification it describes says otherwise, in prose - UPnP Device Architecture 1.0,
21 * service description: "sendEvents attribute defines whether event messages will be generated when the value of this
22 * state variable changes; non-evented state variables have sendEvents="no"; default is sendEvents="yes"". multicast,
23 * added in 1.1, is spelled the same way, and every UPnP implementation writes both as yes/no.
24 *
25 * So the published schema rejects every real device, Stroika's own output among them - which makes it useless as a
26 * validator in exactly the way a caller would want to use it. The two enumerations are widened here to accept yes and
27 * no as well as 1 and 0, and nothing else about the schema is touched: the file stays what upnp.org serves, byte for
28 * byte, so it can be diffed against the source at any time, and the one disagreement lives here where the reason for
29 * it can be read. It is also the ONLY disagreement - with these two widened, a full SCPD holds as published
30 * (@see Tests/55's DescriptionsValidateAgainstPublishedSchemas_, which checks both halves of that).
31 *
32 * Embedded as BYTES rather than written as a C++ string literal, for the same reason SOAP's is: a schema is someone
33 * else's file, and a literal would be read as cp1252 by the MSVC builds, which are passed no /utf-8, the day one of
34 * them gains a character outside ASCII.
35 *
36 * @todo the xxd rule in this directory's Makefile, and the .embed it generates, go away for #embed once every
37 * compiler Stroika supports has it - the file, and everything said above, stay as they are.
38 */
39// the embed too, not just the function - @see DeviceDescriptionSchema.cpp
40#if qStroika_Foundation_DataExchange_XML_SupportParsing and qStroika_Foundation_DataExchange_XML_SupportSchema and qStroika_Foundation_DataExchange_XML_SupportDOM
41namespace {
42 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wunused-variable\""); // warning suppression for Schemas_service_1_0_xsd_len
43 constexpr
44#include "service-1-0.xsd.embed"
45 DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Wunused-variable\"");
46}
47
48using namespace Stroika::Foundation;
50
51using namespace Stroika::Frameworks;
52using namespace Stroika::Frameworks::UPnP;
53
54XML::Schema::Ptr UPnP::ServiceDescriptionSchema (const XML::Options& o)
55{
56 // compiled once per provider, and kept, as DeviceDescriptionSchema is
58 auto compiled = sCompiled_.rwget ();
59 const XML::Providers::IXMLProvider* provider = &o.GetProvider ();
60 if (optional<XML::Schema::Ptr> s = compiled->Lookup (provider)) {
61 return *s;
62 }
63 static constexpr string_view kAsPublished_{"<xsd:enumeration value=\"1\"/>"sv};
64 static constexpr string_view kWidened_{"<xsd:enumeration value=\"1\"/><xsd:enumeration value=\"yes\"/><xsd:enumeration value=\"no\"/>"sv};
65 string corrected{reinterpret_cast<const char*> (Schemas_service_1_0_xsd), std::size (Schemas_service_1_0_xsd)};
66 // [[maybe_unused]]: Assert is the only reader, and on a compiler with neither [[assume]] nor MSVC's __assume it
67 // compiles to nothing at all (Common/StdCompat.h) - which would leave this set and never read
68 [[maybe_unused]] unsigned nWidened{0};
69 for (size_t i = corrected.find (kAsPublished_); i != string::npos; i = corrected.find (kAsPublished_, i + kWidened_.length ())) {
70 corrected.replace (i, kAsPublished_.length (), kWidened_);
71 ++nWidened;
72 }
73 // sendEvents and multicast, and nothing else in the file is written that way. A published schema that had changed
74 // would land here first
75 Assert (nWidened == 2);
76 XML::Schema::Ptr s = XML::Schema::New (Memory::BLOB{as_bytes (span{corrected})}, nullptr, o);
77 compiled->Add (provider, s);
78 return s;
79}
80#endif
Wrap any object with Synchronized<> and it can be used similarly to the base type,...
nonvirtual WritableReference rwget()
get a read-write smart pointer to the underlying Synchronized<> object, holding the full lock the who...
How XML is read and written - for now, with which provider - taken last by each XML function (DOM::Do...