4#include "Stroika/Foundation/StroikaPreComp.h"
8#include "Stroika/Foundation/Cache/LRUCache.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"
33using Memory::MakeSharedPtr;
34using Memory::NullCoalesce;
51 sb <<
"TypePrintName: " << fTypePrintName;
54 sb <<
", FileSuffixes: " << fFileSuffixes;
56 if (fPreferredSuffix) {
57 sb <<
", PreferredSuffix: " << fPreferredSuffix;
97 shared_ptr<IBackendRep> fBackendRep;
105 FrontendRep_ (
const shared_ptr<IBackendRep>& backendRep)
106 : FrontendRep_{backendRep, kDefaults_}
110 : fData_{Data_{.fBackendRep = backendRep}}
112 SetOverrides (overrides);
116 auto lockedData = fData_.
rwget ();
117 return lockedData->fOverrides;
121 auto lockedData = fData_.
rwget ();
122 lockedData->fOverrides = overrides;
123 lockedData->fSuffix2MediaTypeMap.
clear ();
124 for (
const auto& i : lockedData->fOverrides) {
125 if (i.fValue.fFileSuffixes) {
126 for (
const auto& si : *i.fValue.fFileSuffixes) {
127 lockedData->fSuffix2MediaTypeMap.Add (si, i.fKey, AddReplaceMode::eAddIfMissing);
132 virtual void AddOverride (
const InternetMediaType& mediaType,
const OverrideRecord& overrideRec)
override
134 auto lockedData = fData_.
rwget ();
135 lockedData->fOverrides.Add (mediaType, overrideRec);
136 lockedData->fSuffix2MediaTypeMap.clear ();
137 for (
const auto& i : lockedData->fOverrides) {
138 if (i.fValue.fFileSuffixes) {
139 for (
const auto& si : *i.fValue.fFileSuffixes) {
140 lockedData->fSuffix2MediaTypeMap.Add (si, i.fKey, AddReplaceMode::eAddIfMissing);
145 virtual shared_ptr<IBackendRep> GetBackendRep ()
const override
147 auto lockedData = fData_.
rwget ();
148 return lockedData->fBackendRep;
153 auto lockedData = fData_.
rwget ();
154 CheckData_ (&lockedData);
156 if (majorType == nullopt) {
157 result += lockedData->fOverrides.Keys ();
161 if (i.
GetType<AtomType> () == majorType) {
168 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix (
const InternetMediaType& ct)
const override
170 auto lockedData = fData_.
rwget ();
171 CheckData_ (&lockedData);
172 if (
auto o = lockedData->fOverrides.Lookup (ct)) {
173 if (o->fPreferredSuffix) {
174 return *o->fPreferredSuffix;
177 return lockedData->fBackendRep->GetPreferredAssociatedFileSuffix (ct);
181 auto lockedData = fData_.
rwget ();
182 CheckData_ (&lockedData);
184 result += lockedData->fBackendRep->GetAssociatedFileSuffixes (ct);
187 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& ct)
const override
189 auto lockedData = fData_.
rwget ();
190 CheckData_ (&lockedData);
191 if (
auto o = lockedData->fOverrides.Lookup (ct)) {
192 if (o->fTypePrintName) {
193 return *o->fTypePrintName;
196 return lockedData->fBackendRep->GetAssociatedPrettyName (ct);
198 virtual optional<InternetMediaType> GetAssociatedContentType (
const FileSuffixType& fileSuffix)
const override
200 Require (fileSuffix[0] ==
'.');
201 auto lockedData = fData_.
rwget ();
202 CheckData_ (&lockedData);
203 if (
auto o = lockedData->fSuffix2MediaTypeMap.Lookup (fileSuffix)) {
206 return lockedData->fBackendRep->GetAssociatedContentType (fileSuffix);
216 AtomType generalType = moreGeneralType.
GetType<AtomType> ();
217 AtomType generalSubType = moreGeneralType.
GetSubType<AtomType> ();
218 AtomType specificType = moreSpecificType.
GetType<AtomType> ();
219 AtomType specificSubType = moreSpecificType.
GetSubType<AtomType> ();
221 if (specificType == generalType and specificSubType == generalSubType) {
227 if (specificType == generalType) {
234 if (moreGeneralType == InternetMediaTypes::Wildcards::kText) {
235 if (IsA (InternetMediaTypes::kXML, moreSpecificType)) {
238 if (IsA (InternetMediaTypes::kJSON, moreSpecificType)) {
244 if (specificSubType == InternetMediaTypes::kRTF.GetSubType<AtomType> ()) {
249 else if (moreGeneralType == InternetMediaTypes::kXML) {
252 if (specificSubType == InternetMediaTypes::kXML.GetSubType<AtomType> ()) {
256 if (specificSubType == InternetMediaTypes::kXSLT.GetSubType<AtomType> ()) {
261 static const AtomType kXMLAtom_ =
"xml"sv;
262 if (specificSubType == kXMLAtom_) {
269 if (
auto suffix = moreSpecificType.
GetSuffix<AtomType> ()) {
270 if (moreGeneralType == InternetMediaTypes::kJSON) {
271 static const AtomType kSuffix_{
"json"sv};
272 if (suffix == kSuffix_) {
276 else if (moreGeneralType == InternetMediaTypes::kXML) {
277 static const AtomType kSuffix_{
"xml"sv};
278 if (suffix == kSuffix_) {
288 if (lockedData->rwref ().fBackendRep ==
nullptr) {
293inline InternetMediaTypeRegistry::FrontendRep_ InternetMediaTypeRegistry::kDefaultFrontEndForNoBackend_{
nullptr};
302 : fFrontEndRep_{backendRep == nullptr ? nullptr : MakeSharedPtr<FrontendRep_> (backendRep)}
308 return NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetOverrides ();
313 if (fFrontEndRep_ ==
nullptr) {
314 fFrontEndRep_ = MakeSharedPtr<FrontendRep_> (kDefaultFrontEndForNoBackend_);
317 fFrontEndRep_->SetOverrides (overrides);
322 if (fFrontEndRep_ ==
nullptr) {
323 fFrontEndRep_ = MakeSharedPtr<FrontendRep_> (kDefaultFrontEndForNoBackend_);
326 fFrontEndRep_->AddOverride (mediaType, overrideRec);
331 return Memory::NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetPreferredAssociatedFileSuffix (ct);
337 r = Memory::NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetAssociatedFileSuffixes (ct);
347 return Memory::NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetAssociatedPrettyName (ct);
353#if qStroika_Foundation_Common_Platform_Windows
354 return WindowsRegistryDefaultBackend ();
357 if (filesystem::exists (
"/usr/share/mime"sv)) {
365 if (filesystem::exists (
"/etc/mime.types"sv)) {
393#if USE_NOISY_TRACE_IN_THIS_MODULE_
397 IO::FileSystem::FileInputStream::New (
"/etc/mime.types"sv))) {
398 if (line.length () >= 2 and not line[0].StartsWith (
"#"_k)) {
404 DbgTrace (
"Ignoring exception looking parsing potential media type entry ({}): {}"_f, line[0], current_exception ());
408 for (
size_t i = 1; i < line.length (); ++i) {
409 if (line[i].empty ()) {
410 DbgTrace (
"Ignoring bad looking parsing potential media type entry ({})"_f, line);
413 Assert (not line[i].empty ());
414 String suffix =
"."sv + line[i];
415 fSuffix2MediaTypeMap_.
Add (suffix, ct);
416 fMediaType2PreferredSuffixMap_.
Add (ct, suffix, AddReplaceMode::eAddIfMissing);
417 fileSuffixes.
Add (suffix);
420 fMediaType2SuffixesMap_.
Add (ct, fileSuffixes);
424 fMediaType2PreferredSuffixMap_.
Add (InternetMediaTypes::kText_PLAIN,
".txt"sv);
425#if USE_NOISY_TRACE_IN_THIS_MODULE_
426 DbgTrace (L
"succeeded with {} fSuffix2MediaTypeMap entries, and {} fMediaType2PreferredSuffixMap entries"_f,
427 fSuffix2MediaTypeMap_.
size (), fMediaType2PreferredSuffixMap_.
size ());
441 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix (
const InternetMediaType& ct)
const override
443 if (
auto o = fMediaType2PreferredSuffixMap_.
Lookup (ct)) {
450 if (
auto i = fMediaType2SuffixesMap_.
Lookup (ct)) {
455 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& )
const override
459 virtual optional<InternetMediaType> GetAssociatedContentType (
const FileSuffixType& fileSuffix)
const override
461 Require (fileSuffix[0] ==
'.');
462 if (
auto o = fSuffix2MediaTypeMap_.
Lookup (fileSuffix)) {
468 return MakeSharedPtr<EtcMimeTypesRep_> ();
496#if USE_NOISY_TRACE_IN_THIS_MODULE_
500 auto loadGlobsFromFile = [&] (
const filesystem::path& fn) {
501 if (filesystem::exists (fn)) {
506 if (line.length () == 2) {
517 DbgTrace (
"Ignoring exception looking parsing potential media type entry ({}): {}"_f, line[0], current_exception ());
519 fSuffix2MediaTypeMap_.
Add (glob, imt, AddReplaceMode::eAddIfMissing);
520 fMediaType2PreferredSuffixMap_.
Add (imt, glob, AddReplaceMode::eAddIfMissing);
524 prevSuffixes.
Add (glob);
525 fMediaType2SuffixesMap_.
Add (imt, prevSuffixes);
530 fMediaType2PreferredSuffixMap_.
Add (InternetMediaTypes::kText_PLAIN,
".txt"_k);
538 for (
const auto& p : fDataRoots_) {
539 loadGlobsFromFile (p /
"globs");
542#if USE_NOISY_TRACE_IN_THIS_MODULE_
543 DbgTrace (
"succeeded with {} fSuffix2MediaTypeMap_ entries, and {} fMediaType2PreferredSuffixMap entries"_f,
544 fSuffix2MediaTypeMap_.
size (), fMediaType2PreferredSuffixMap_.
size ());
549#if USE_NOISY_TRACE_IN_THIS_MODULE_
553 for (
const auto& imt : fMediaType2PreferredSuffixMap_.
Keys ()) {
563 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix (
const InternetMediaType& ct)
const override
565 if (
auto o = fMediaType2PreferredSuffixMap_.
Lookup (ct)) {
572 if (
auto i = fMediaType2SuffixesMap_.
Lookup (ct)) {
577 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& ct)
const override
579 return LookupAndUpdateFromUsrShareMimePrettyName_ (ct);
581 virtual optional<InternetMediaType> GetAssociatedContentType (
const FileSuffixType& fileSuffix)
const override
583 Require (fileSuffix[0] ==
'.');
584 if (
auto o = fSuffix2MediaTypeMap_.
Lookup (fileSuffix)) {
589 optional<String> LookupAndUpdateFromUsrShareMimePrettyName_ (
const InternetMediaType& ct)
const
591#if USE_NOISY_TRACE_IN_THIS_MODULE_
595 if (
auto o = fMediaType2PrettyNameCache.
cget ()->Lookup (ct)) {
600#if qStroika_Foundation_DataExchange_XML_SupportParsing
604 optional<String> fResult;
605 bool onContentElt{
false};
607 virtual void StartElement (
const Name& name, [[maybe_unused]]
const Mapping<Name, String>& attributes)
override
609 if (name == Name{
"content"_k} and not fResult.has_value ()) {
613 virtual void EndElement ([[maybe_unused]]
const Name& name)
override
616 Assert (not fResult);
617 fResult = fAccum.
str ();
620 virtual void TextInsideElement (
const String& t)
override
627 filesystem::path mimeRoot{
"/usr/share/mime/"sv};
630 DataExchange::XML::SAXParse (IO::FileSystem::FileInputStream::New (
631 mimeRoot / (ct.
GetType () +
"/"_k + ct.
GetSubType () +
".xml"_k).As<filesystem::path> ()),
633 if (handler.fResult) {
634 fMediaType2PrettyNameCache.
rwget ()->Add (ct, *handler.fResult);
635 return *handler.fResult;
639#if USE_NOISY_TRACE_IN_THIS_MODULE_
644 DbgTrace (
"/usr/share/mime/ ignored cuz no xml reader - not compiled with libxml2 or Xerces"_f);
649 return MakeSharedPtr<UsrShareMIMERep_> ();
660 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix ([[maybe_unused]]
const InternetMediaType& ct)
const override
668 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& )
const override
672 virtual optional<InternetMediaType> GetAssociatedContentType ([[maybe_unused]]
const FileSuffixType& fileSuffix)
const override
674 Require (fileSuffix[0] ==
'.');
678 return MakeSharedPtr<DefaultEmptyBackendRep_> ();
681auto InternetMediaTypeRegistry::CloneAsSharedPtr_ (
const IFrontendRep_& t) -> shared_ptr<IFrontendRep_>
683 return Memory::MakeSharedPtr<FrontendRep_> (t.GetBackendRep (), t.GetOverrides ());
687 template <
typename K,
typename V>
688 using SynchronizedHashingCache_ =
692#if qStroika_Foundation_Common_Platform_Windows
693auto InternetMediaTypeRegistry::WindowsRegistryDefaultBackend () -> shared_ptr<IBackendRep>
711 struct WinRep_ : IBackendRep {
713 mutable SynchronizedHashingCache_<FileSuffixType, optional<String>> fFileSuffix2PrettyNameCache_{25, 7};
714 mutable SynchronizedHashingCache_<FileSuffixType, optional<InternetMediaType>> fSuffix2MediaTypeCache_{25, 7};
715 mutable SynchronizedHashingCache_<InternetMediaType, optional<FileSuffixType>> fContentType2FileSuffixCache_{25, 7};
716 mutable SynchronizedHashingCache_<InternetMediaType, Containers::Set<FileSuffixType>> fContentType2FileSuffixesCache_{25, 7};
728 for (shared_ptr<RegistryKey> sk : RegistryKey{HKEY_CLASSES_ROOT}.EnumerateSubKeys ()) {
729 String name = sk->GetFullPathOfKey ().
Tokenize ({
'\\'}).LastValue ();
731 if (
auto o = sk->Lookup (
"Content Type"sv)) {
738 DbgTrace (
"Ignoring exception parsing registry key ({}): {}"_f, o, current_exception ());
752 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix (
const InternetMediaType& ct)
const override
754 return fContentType2FileSuffixCache_.LookupValue (ct, [] (
const InternetMediaType& ct) -> optional<FileSuffixType> {
768 for (shared_ptr<RegistryKey> sk : RegistryKey{HKEY_CLASSES_ROOT}.EnumerateSubKeys ()) {
769 String name = sk->GetFullPathOfKey ().
Tokenize ({
'\\'}).LastValue ();
771 if (
auto o = sk->Lookup (
"Content Type"sv)) {
778 DbgTrace (
"Ignoring exception parsing registry key ({}): {}"_f, o, current_exception ());
790 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& ct)
const override
792 if (optional<FileSuffixType> fileSuffix = GetPreferredAssociatedFileSuffix (ct)) {
793 return fFileSuffix2PrettyNameCache_.LookupValue (*fileSuffix, [] (
const String& suffix) -> optional<String> {
796 return prettyName.As<String> ();
804 virtual optional<InternetMediaType> GetAssociatedContentType (
const FileSuffixType& fileSuffix)
const override
806 Require (fileSuffix[0] ==
'.');
807 return fSuffix2MediaTypeCache_.LookupValue (fileSuffix, [] (
const FileSuffixType& fileSuffix) -> optional<InternetMediaType> {
810 if (
auto oct = RegistryKey{HKEY_CLASSES_ROOT}.Lookup (
"{}\\Content Type"_f(fileSuffix))) {
818 return MakeSharedPtr<WinRep_> ();
824 return NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetMediaTypes (nullopt);
829 return NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetMediaTypes (majorType);
835 for (
const auto& ct : mediaTypes) {
845 if (fileSuffix.empty ()) {
848 Assert (fileSuffix[0] ==
'.');
849 return NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetAssociatedContentType (fileSuffix);
854 return IsA (InternetMediaTypes::Wildcards::kText, ct);
859 return IsA (InternetMediaTypes::Wildcards::kImage, ct);
864 return IsA (InternetMediaTypes::kXML, ct);
871 if (moreSpecificType.
GetType<AtomType> () == moreGeneralType.
GetType<AtomType> () and
875 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.