4#include "Stroika/Foundation/StroikaPreComp.h"
8#include "Stroika/Foundation/Cache/SynchronizedLRUCache.h"
13#if qStroika_Foundation_Common_Platform_Windows
14#include "Stroika/Foundation/Common/Platform/Windows/Registry.h"
17#if qStroika_Foundation_Common_Platform_Windows
18#include "Stroika/Foundation/Execution/Platform/Windows/Exception.h"
31using Memory::NullCoalesce;
48 sb <<
"TypePrintName: " << fTypePrintName;
51 sb <<
", FileSuffixes: " << fFileSuffixes;
53 if (fPreferredSuffix) {
54 sb <<
", PreferredSuffix: " << fPreferredSuffix;
94 shared_ptr<IBackendRep> fBackendRep;
102 FrontendRep_ (
const shared_ptr<IBackendRep>& backendRep)
103 : FrontendRep_{backendRep, kDefaults_}
107 : fData_{Data_{.fBackendRep = backendRep}}
109 SetOverrides (overrides);
113 auto lockedData = fData_.
rwget ();
114 return lockedData->fOverrides;
118 auto lockedData = fData_.
rwget ();
119 lockedData->fOverrides = overrides;
120 lockedData->fSuffix2MediaTypeMap.
clear ();
121 for (
const auto& i : lockedData->fOverrides) {
122 if (i.fValue.fFileSuffixes) {
123 for (
const auto& si : *i.fValue.fFileSuffixes) {
124 lockedData->fSuffix2MediaTypeMap.Add (si, i.fKey, AddReplaceMode::eAddIfMissing);
129 virtual void AddOverride (
const InternetMediaType& mediaType,
const OverrideRecord& overrideRec)
override
131 auto lockedData = fData_.
rwget ();
132 lockedData->fOverrides.Add (mediaType, overrideRec);
133 lockedData->fSuffix2MediaTypeMap.clear ();
134 for (
const auto& i : lockedData->fOverrides) {
135 if (i.fValue.fFileSuffixes) {
136 for (
const auto& si : *i.fValue.fFileSuffixes) {
137 lockedData->fSuffix2MediaTypeMap.Add (si, i.fKey, AddReplaceMode::eAddIfMissing);
142 virtual shared_ptr<IBackendRep> GetBackendRep ()
const override
144 auto lockedData = fData_.
rwget ();
145 return lockedData->fBackendRep;
150 auto lockedData = fData_.
rwget ();
151 CheckData_ (&lockedData);
153 if (majorType == nullopt) {
154 result += lockedData->fOverrides.Keys ();
158 if (i.
GetType<AtomType> () == majorType) {
165 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix (
const InternetMediaType& ct)
const override
167 auto lockedData = fData_.
rwget ();
168 CheckData_ (&lockedData);
169 if (
auto o = lockedData->fOverrides.Lookup (ct)) {
170 if (o->fPreferredSuffix) {
171 return *o->fPreferredSuffix;
174 return lockedData->fBackendRep->GetPreferredAssociatedFileSuffix (ct);
178 auto lockedData = fData_.
rwget ();
179 CheckData_ (&lockedData);
181 result += lockedData->fBackendRep->GetAssociatedFileSuffixes (ct);
184 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& ct)
const override
186 auto lockedData = fData_.
rwget ();
187 CheckData_ (&lockedData);
188 if (
auto o = lockedData->fOverrides.Lookup (ct)) {
189 if (o->fTypePrintName) {
190 return *o->fTypePrintName;
193 return lockedData->fBackendRep->GetAssociatedPrettyName (ct);
195 virtual optional<InternetMediaType> GetAssociatedContentType (
const FileSuffixType& fileSuffix)
const override
197 Require (fileSuffix[0] ==
'.');
198 auto lockedData = fData_.
rwget ();
199 CheckData_ (&lockedData);
200 if (
auto o = lockedData->fSuffix2MediaTypeMap.Lookup (fileSuffix)) {
203 return lockedData->fBackendRep->GetAssociatedContentType (fileSuffix);
213 AtomType generalType = moreGeneralType.
GetType<AtomType> ();
214 AtomType generalSubType = moreGeneralType.
GetSubType<AtomType> ();
215 AtomType specificType = moreSpecificType.
GetType<AtomType> ();
216 AtomType specificSubType = moreSpecificType.
GetSubType<AtomType> ();
218 if (specificType == generalType and specificSubType == generalSubType) {
224 if (specificType == generalType) {
231 if (moreGeneralType == InternetMediaTypes::Wildcards::kText) {
232 if (IsA (InternetMediaTypes::kXML, moreSpecificType)) {
235 if (IsA (InternetMediaTypes::kJSON, moreSpecificType)) {
241 if (specificSubType == InternetMediaTypes::kRTF.GetSubType<AtomType> ()) {
246 else if (moreGeneralType == InternetMediaTypes::kXML) {
249 if (specificSubType == InternetMediaTypes::kXML.GetSubType<AtomType> ()) {
253 if (specificSubType == InternetMediaTypes::kXSLT.GetSubType<AtomType> ()) {
258 static const AtomType kXMLAtom_ =
"xml"sv;
259 if (specificSubType == kXMLAtom_) {
266 if (
auto suffix = moreSpecificType.
GetSuffix<AtomType> ()) {
267 if (moreGeneralType == InternetMediaTypes::kJSON) {
268 static const AtomType kSuffix_{
"json"sv};
269 if (suffix == kSuffix_) {
273 else if (moreGeneralType == InternetMediaTypes::kXML) {
274 static const AtomType kSuffix_{
"xml"sv};
275 if (suffix == kSuffix_) {
285 if (lockedData->rwref ().fBackendRep ==
nullptr) {
290inline InternetMediaTypeRegistry::FrontendRep_ InternetMediaTypeRegistry::kDefaultFrontEndForNoBackend_{
nullptr};
297auto InternetMediaTypeRegistry::Rep_Cloner_::operator() (
const IFrontendRep_& t)
const -> shared_ptr<IFrontendRep_>
299 return make_shared<FrontendRep_> (t.GetBackendRep (), t.GetOverrides ());
309 : fFrontEndRep_{backendRep == nullptr ? nullptr : make_shared<FrontendRep_> (backendRep)}
315 return NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetOverrides ();
320 if (fFrontEndRep_ ==
nullptr) {
321 fFrontEndRep_ = make_shared<FrontendRep_> (kDefaultFrontEndForNoBackend_);
324 fFrontEndRep_->SetOverrides (overrides);
329 if (fFrontEndRep_ ==
nullptr) {
330 fFrontEndRep_ = make_shared<FrontendRep_> (kDefaultFrontEndForNoBackend_);
333 fFrontEndRep_->AddOverride (mediaType, overrideRec);
338 return Memory::NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetPreferredAssociatedFileSuffix (ct);
344 r = Memory::NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetAssociatedFileSuffixes (ct);
354 return Memory::NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetAssociatedPrettyName (ct);
360#if qStroika_Foundation_Common_Platform_Windows
361 return WindowsRegistryDefaultBackend ();
364 if (filesystem::exists (
"/usr/share/mime"sv)) {
372 if (filesystem::exists (
"/etc/mime.types"sv)) {
400#if USE_NOISY_TRACE_IN_THIS_MODULE_
404 IO::FileSystem::FileInputStream::New (
"/etc/mime.types"sv))) {
405 if (line.length () >= 2 and not line[0].StartsWith (
"#"_k)) {
411 DbgTrace (
"Ignoring exception looking parsing potential media type entry ({}): {}"_f, line[0], current_exception ());
415 for (
size_t i = 1; i < line.length (); ++i) {
416 Assert (not line[i].empty ());
417 String suffix =
"."sv + line[i];
418 fSuffix2MediaTypeMap_.
Add (suffix, ct);
419 fMediaType2PreferredSuffixMap_.
Add (ct, suffix, AddReplaceMode::eAddIfMissing);
420 fileSuffixes.
Add (suffix);
422 fMediaType2SuffixesMap_.
Add (ct, fileSuffixes);
426 fMediaType2PreferredSuffixMap_.
Add (InternetMediaTypes::kText_PLAIN,
".txt"sv);
427#if USE_NOISY_TRACE_IN_THIS_MODULE_
428 DbgTrace (L
"succeeded with {} fSuffix2MediaTypeMap entries, and {} fMediaType2PreferredSuffixMap entries"_f,
429 fSuffix2MediaTypeMap_.
size (), fMediaType2PreferredSuffixMap_.
size ());
443 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix (
const InternetMediaType& ct)
const override
445 if (
auto o = fMediaType2PreferredSuffixMap_.
Lookup (ct)) {
452 if (
auto i = fMediaType2SuffixesMap_.
Lookup (ct)) {
457 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& )
const override
461 virtual optional<InternetMediaType> GetAssociatedContentType (
const FileSuffixType& fileSuffix)
const override
463 Require (fileSuffix[0] ==
'.');
464 if (
auto o = fSuffix2MediaTypeMap_.
Lookup (fileSuffix)) {
470 return make_shared<EtcMimeTypesRep_> ();
498#if USE_NOISY_TRACE_IN_THIS_MODULE_
502 auto loadGlobsFromFile = [&] (
const filesystem::path& fn) {
503 if (filesystem::exists (fn)) {
508 if (line.length () == 2) {
519 DbgTrace (
"Ignoring exception looking parsing potential media type entry ({}): {}"_f, line[0], current_exception ());
521 fSuffix2MediaTypeMap_.
Add (glob, imt, AddReplaceMode::eAddIfMissing);
522 fMediaType2PreferredSuffixMap_.
Add (imt, glob, AddReplaceMode::eAddIfMissing);
526 prevSuffixes.
Add (glob);
527 fMediaType2SuffixesMap_.
Add (imt, prevSuffixes);
532 fMediaType2PreferredSuffixMap_.
Add (InternetMediaTypes::kText_PLAIN,
".txt"_k);
540 for (
const auto& p : fDataRoots_) {
541 loadGlobsFromFile (p /
"globs");
544#if USE_NOISY_TRACE_IN_THIS_MODULE_
545 DbgTrace (
"succeeded with {} fSuffix2MediaTypeMap_ entries, and {} fMediaType2PreferredSuffixMap entries"_f,
546 fSuffix2MediaTypeMap_.
size (), fMediaType2PreferredSuffixMap_.
size ());
551#if USE_NOISY_TRACE_IN_THIS_MODULE_
555 for (
const auto& imt : fMediaType2PreferredSuffixMap_.
Keys ()) {
565 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix (
const InternetMediaType& ct)
const override
567 if (
auto o = fMediaType2PreferredSuffixMap_.
Lookup (ct)) {
574 if (
auto i = fMediaType2SuffixesMap_.
Lookup (ct)) {
579 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& ct)
const override
581 return LookupAndUpdateFromUsrShareMimePrettyName_ (ct);
583 virtual optional<InternetMediaType> GetAssociatedContentType (
const FileSuffixType& fileSuffix)
const override
585 Require (fileSuffix[0] ==
'.');
586 if (
auto o = fSuffix2MediaTypeMap_.
Lookup (fileSuffix)) {
591 optional<String> LookupAndUpdateFromUsrShareMimePrettyName_ (
const InternetMediaType& ct)
const
593#if USE_NOISY_TRACE_IN_THIS_MODULE_
597 if (
auto o = fMediaType2PrettyNameCache.
cget ()->Lookup (ct)) {
602#if qStroika_Foundation_DataExchange_XML_SupportParsing
606 optional<String> fResult;
607 bool onContentElt{
false};
609 virtual void StartElement (
const Name& name, [[maybe_unused]]
const Mapping<Name, String>& attributes)
override
611 if (name == Name{
"content"_k} and not fResult.has_value ()) {
615 virtual void EndElement ([[maybe_unused]]
const Name& name)
override
618 Assert (not fResult);
619 fResult = fAccum.
str ();
622 virtual void TextInsideElement (
const String& t)
override
629 filesystem::path mimeRoot{
"/usr/share/mime/"sv};
632 DataExchange::XML::SAXParse (IO::FileSystem::FileInputStream::New (
633 mimeRoot / (ct.
GetType () +
"/"_k + ct.
GetSubType () +
".xml"_k).As<filesystem::path> ()),
635 if (handler.fResult) {
636 fMediaType2PrettyNameCache.
rwget ()->Add (ct, *handler.fResult);
637 return *handler.fResult;
641#if USE_NOISY_TRACE_IN_THIS_MODULE_
646 DbgTrace (
"/usr/share/mime/ ignored cuz no xml reader - not compiled with Xerces");
651 return make_shared<UsrShareMIMERep_> ();
662 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix ([[maybe_unused]]
const InternetMediaType& ct)
const override
670 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& )
const override
674 virtual optional<InternetMediaType> GetAssociatedContentType ([[maybe_unused]]
const FileSuffixType& fileSuffix)
const override
676 Require (fileSuffix[0] ==
'.');
680 return make_shared<DefaultEmptyBackendRep_> ();
683#if qStroika_Foundation_Common_Platform_Windows
684auto InternetMediaTypeRegistry::WindowsRegistryDefaultBackend () -> shared_ptr<IBackendRep>
702 struct WinRep_ : IBackendRep {
723 for (shared_ptr<RegistryKey> sk : RegistryKey{HKEY_CLASSES_ROOT}.EnumerateSubKeys ()) {
724 String name = sk->GetFullPathOfKey ().
Tokenize ({
'\\'}).LastValue ();
726 if (
auto o = sk->Lookup (
"Content Type"sv)) {
733 DbgTrace (
"Ignoring exception parsing registry key ({}): {}"_f, o, current_exception ());
747 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix (
const InternetMediaType& ct)
const override
749 return fContentType2FileSuffixCache_.LookupValue (ct, [] (
const InternetMediaType& ct) -> optional<FileSuffixType> {
763 for (shared_ptr<RegistryKey> sk : RegistryKey{HKEY_CLASSES_ROOT}.EnumerateSubKeys ()) {
764 String name = sk->GetFullPathOfKey ().
Tokenize ({
'\\'}).LastValue ();
766 if (
auto o = sk->Lookup (
"Content Type"sv)) {
773 DbgTrace (
"Ignoring exception parsing registry key ({}): {}"_f, o, current_exception ());
785 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& ct)
const override
787 if (optional<FileSuffixType> fileSuffix = GetPreferredAssociatedFileSuffix (ct)) {
788 return fFileSuffix2PrettyNameCache_.LookupValue (*fileSuffix, [] (
const String& suffix) -> optional<String> {
791 return prettyName.As<String> ();
799 virtual optional<InternetMediaType> GetAssociatedContentType (
const FileSuffixType& fileSuffix)
const override
801 Require (fileSuffix[0] ==
'.');
802 return fSuffix2MediaTypeCache_.LookupValue (fileSuffix, [] (
const FileSuffixType& fileSuffix) -> optional<InternetMediaType> {
805 if (
auto oct = RegistryKey{HKEY_CLASSES_ROOT}.Lookup (
"{}\\Content Type"_f(fileSuffix))) {
813 return make_shared<WinRep_> ();
819 return NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetMediaTypes (nullopt);
824 return NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetMediaTypes (majorType);
830 for (
const auto& ct : mediaTypes) {
840 if (fileSuffix.empty ()) {
843 Assert (fileSuffix[0] ==
'.');
844 return NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetAssociatedContentType (fileSuffix);
849 return IsA (InternetMediaTypes::Wildcards::kText, ct);
854 return IsA (InternetMediaTypes::Wildcards::kImage, ct);
859 return IsA (InternetMediaTypes::kXML, ct);
866 if (moreSpecificType.
GetType<AtomType> () == moreGeneralType.
GetType<AtomType> () and
870 return NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).IsA (moreGeneralType, moreSpecificType);
const OT & NullCoalesce(const OT &l, const OT &r)
return one of l, or r, with first preference for which is engaged, and second preference for left-to-...
#define Stroika_Foundation_Debug_OptionalizeTraceArgs(...)
LRUCache implements a simple least-recently-used caching strategy, with optional hashing (of keys) to...
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
nonvirtual String str() const
String is like std::u32string, except it is much easier to use, often much more space efficient,...
nonvirtual String SubString(SZ from) const
nonvirtual bool StartsWith(const Character &c, CompareOptions co=eWithCase) const
nonvirtual Containers::Sequence< String > Tokenize() const
nonvirtual bool Add(ArgByValueType< key_type > key, ArgByValueType< mapped_type > newElt, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
nonvirtual optional< mapped_type > Lookup(ArgByValueType< key_type > key) const
nonvirtual mapped_type LookupValue(ArgByValueType< key_type > key, ArgByValueType< mapped_type > defaultValue=mapped_type{}) const
nonvirtual Iterable< key_type > Keys() const
A generalization of a vector: a container whose elements are keyed by the natural numbers.
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
nonvirtual void Add(ArgByValueType< value_type > item)
This COULD be easily used to read CSV files, or tab-delimited files, for example.
nonvirtual Iterable< Sequence< String > > ReadMatrix(const Streams::InputStream::Ptr< byte > &in) const
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...
nonvirtual ReadableReference cget() const
get a read-only smart pointer to the underlying Synchronized<> object, holding the readlock the whole...
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
nonvirtual void Apply(const function< void(ArgByValueType< T > item)> &doToElement, Execution::SequencePolicy seq=Execution::SequencePolicy::eDEFAULT) const
Run the argument function (or lambda) on each element of the container.
nonvirtual size_t size() const
Returns the number of items contained.