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"
32using Memory::MakeSharedPtr;
33using Memory::NullCoalesce;
50 sb <<
"TypePrintName: " << fTypePrintName;
53 sb <<
", FileSuffixes: " << fFileSuffixes;
55 if (fPreferredSuffix) {
56 sb <<
", PreferredSuffix: " << fPreferredSuffix;
96 shared_ptr<IBackendRep> fBackendRep;
104 FrontendRep_ (
const shared_ptr<IBackendRep>& backendRep)
105 : FrontendRep_{backendRep, kDefaults_}
109 : fData_{Data_{.fBackendRep = backendRep}}
111 SetOverrides (overrides);
115 auto lockedData = fData_.
rwget ();
116 return lockedData->fOverrides;
120 auto lockedData = fData_.
rwget ();
121 lockedData->fOverrides = overrides;
122 lockedData->fSuffix2MediaTypeMap.
clear ();
123 for (
const auto& i : lockedData->fOverrides) {
124 if (i.fValue.fFileSuffixes) {
125 for (
const auto& si : *i.fValue.fFileSuffixes) {
126 lockedData->fSuffix2MediaTypeMap.Add (si, i.fKey, AddReplaceMode::eAddIfMissing);
131 virtual void AddOverride (
const InternetMediaType& mediaType,
const OverrideRecord& overrideRec)
override
133 auto lockedData = fData_.
rwget ();
134 lockedData->fOverrides.Add (mediaType, overrideRec);
135 lockedData->fSuffix2MediaTypeMap.clear ();
136 for (
const auto& i : lockedData->fOverrides) {
137 if (i.fValue.fFileSuffixes) {
138 for (
const auto& si : *i.fValue.fFileSuffixes) {
139 lockedData->fSuffix2MediaTypeMap.Add (si, i.fKey, AddReplaceMode::eAddIfMissing);
144 virtual shared_ptr<IBackendRep> GetBackendRep ()
const override
146 auto lockedData = fData_.
rwget ();
147 return lockedData->fBackendRep;
152 auto lockedData = fData_.
rwget ();
153 CheckData_ (&lockedData);
155 if (majorType == nullopt) {
156 result += lockedData->fOverrides.Keys ();
160 if (i.
GetType<AtomType> () == majorType) {
167 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix (
const InternetMediaType& ct)
const override
169 auto lockedData = fData_.
rwget ();
170 CheckData_ (&lockedData);
171 if (
auto o = lockedData->fOverrides.Lookup (ct)) {
172 if (o->fPreferredSuffix) {
173 return *o->fPreferredSuffix;
176 return lockedData->fBackendRep->GetPreferredAssociatedFileSuffix (ct);
180 auto lockedData = fData_.
rwget ();
181 CheckData_ (&lockedData);
183 result += lockedData->fBackendRep->GetAssociatedFileSuffixes (ct);
186 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& ct)
const override
188 auto lockedData = fData_.
rwget ();
189 CheckData_ (&lockedData);
190 if (
auto o = lockedData->fOverrides.Lookup (ct)) {
191 if (o->fTypePrintName) {
192 return *o->fTypePrintName;
195 return lockedData->fBackendRep->GetAssociatedPrettyName (ct);
197 virtual optional<InternetMediaType> GetAssociatedContentType (
const FileSuffixType& fileSuffix)
const override
199 Require (fileSuffix[0] ==
'.');
200 auto lockedData = fData_.
rwget ();
201 CheckData_ (&lockedData);
202 if (
auto o = lockedData->fSuffix2MediaTypeMap.Lookup (fileSuffix)) {
205 return lockedData->fBackendRep->GetAssociatedContentType (fileSuffix);
215 AtomType generalType = moreGeneralType.
GetType<AtomType> ();
216 AtomType generalSubType = moreGeneralType.
GetSubType<AtomType> ();
217 AtomType specificType = moreSpecificType.
GetType<AtomType> ();
218 AtomType specificSubType = moreSpecificType.
GetSubType<AtomType> ();
220 if (specificType == generalType and specificSubType == generalSubType) {
226 if (specificType == generalType) {
233 if (moreGeneralType == InternetMediaTypes::Wildcards::kText) {
234 if (IsA (InternetMediaTypes::kXML, moreSpecificType)) {
237 if (IsA (InternetMediaTypes::kJSON, moreSpecificType)) {
243 if (specificSubType == InternetMediaTypes::kRTF.GetSubType<AtomType> ()) {
248 else if (moreGeneralType == InternetMediaTypes::kXML) {
251 if (specificSubType == InternetMediaTypes::kXML.GetSubType<AtomType> ()) {
255 if (specificSubType == InternetMediaTypes::kXSLT.GetSubType<AtomType> ()) {
260 static const AtomType kXMLAtom_ =
"xml"sv;
261 if (specificSubType == kXMLAtom_) {
268 if (
auto suffix = moreSpecificType.
GetSuffix<AtomType> ()) {
269 if (moreGeneralType == InternetMediaTypes::kJSON) {
270 static const AtomType kSuffix_{
"json"sv};
271 if (suffix == kSuffix_) {
275 else if (moreGeneralType == InternetMediaTypes::kXML) {
276 static const AtomType kSuffix_{
"xml"sv};
277 if (suffix == kSuffix_) {
287 if (lockedData->rwref ().fBackendRep ==
nullptr) {
292inline InternetMediaTypeRegistry::FrontendRep_ InternetMediaTypeRegistry::kDefaultFrontEndForNoBackend_{
nullptr};
299auto InternetMediaTypeRegistry::Rep_Cloner_::operator() (
const IFrontendRep_& t)
const -> shared_ptr<IFrontendRep_>
301 return MakeSharedPtr<FrontendRep_> (t.GetBackendRep (), t.GetOverrides ());
311 : fFrontEndRep_{backendRep == nullptr ? nullptr : MakeSharedPtr<FrontendRep_> (backendRep)}
317 return NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetOverrides ();
322 if (fFrontEndRep_ ==
nullptr) {
323 fFrontEndRep_ = MakeSharedPtr<FrontendRep_> (kDefaultFrontEndForNoBackend_);
326 fFrontEndRep_->SetOverrides (overrides);
331 if (fFrontEndRep_ ==
nullptr) {
332 fFrontEndRep_ = MakeSharedPtr<FrontendRep_> (kDefaultFrontEndForNoBackend_);
335 fFrontEndRep_->AddOverride (mediaType, overrideRec);
340 return Memory::NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetPreferredAssociatedFileSuffix (ct);
346 r = Memory::NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetAssociatedFileSuffixes (ct);
356 return Memory::NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetAssociatedPrettyName (ct);
362#if qStroika_Foundation_Common_Platform_Windows
363 return WindowsRegistryDefaultBackend ();
366 if (filesystem::exists (
"/usr/share/mime"sv)) {
374 if (filesystem::exists (
"/etc/mime.types"sv)) {
402#if USE_NOISY_TRACE_IN_THIS_MODULE_
406 IO::FileSystem::FileInputStream::New (
"/etc/mime.types"sv))) {
407 if (line.length () >= 2 and not line[0].StartsWith (
"#"_k)) {
413 DbgTrace (
"Ignoring exception looking parsing potential media type entry ({}): {}"_f, line[0], current_exception ());
417 for (
size_t i = 1; i < line.length (); ++i) {
418 if (line[i].empty ()) {
419 DbgTrace (
"Ignoring bad looking parsing potential media type entry ({})"_f, line);
422 Assert (not line[i].empty ());
423 String suffix =
"."sv + line[i];
424 fSuffix2MediaTypeMap_.
Add (suffix, ct);
425 fMediaType2PreferredSuffixMap_.
Add (ct, suffix, AddReplaceMode::eAddIfMissing);
426 fileSuffixes.
Add (suffix);
429 fMediaType2SuffixesMap_.
Add (ct, fileSuffixes);
433 fMediaType2PreferredSuffixMap_.
Add (InternetMediaTypes::kText_PLAIN,
".txt"sv);
434#if USE_NOISY_TRACE_IN_THIS_MODULE_
435 DbgTrace (L
"succeeded with {} fSuffix2MediaTypeMap entries, and {} fMediaType2PreferredSuffixMap entries"_f,
436 fSuffix2MediaTypeMap_.
size (), fMediaType2PreferredSuffixMap_.
size ());
450 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix (
const InternetMediaType& ct)
const override
452 if (
auto o = fMediaType2PreferredSuffixMap_.
Lookup (ct)) {
459 if (
auto i = fMediaType2SuffixesMap_.
Lookup (ct)) {
464 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& )
const override
468 virtual optional<InternetMediaType> GetAssociatedContentType (
const FileSuffixType& fileSuffix)
const override
470 Require (fileSuffix[0] ==
'.');
471 if (
auto o = fSuffix2MediaTypeMap_.
Lookup (fileSuffix)) {
477 return MakeSharedPtr<EtcMimeTypesRep_> ();
505#if USE_NOISY_TRACE_IN_THIS_MODULE_
509 auto loadGlobsFromFile = [&] (
const filesystem::path& fn) {
510 if (filesystem::exists (fn)) {
515 if (line.length () == 2) {
526 DbgTrace (
"Ignoring exception looking parsing potential media type entry ({}): {}"_f, line[0], current_exception ());
528 fSuffix2MediaTypeMap_.
Add (glob, imt, AddReplaceMode::eAddIfMissing);
529 fMediaType2PreferredSuffixMap_.
Add (imt, glob, AddReplaceMode::eAddIfMissing);
533 prevSuffixes.
Add (glob);
534 fMediaType2SuffixesMap_.
Add (imt, prevSuffixes);
539 fMediaType2PreferredSuffixMap_.
Add (InternetMediaTypes::kText_PLAIN,
".txt"_k);
547 for (
const auto& p : fDataRoots_) {
548 loadGlobsFromFile (p /
"globs");
551#if USE_NOISY_TRACE_IN_THIS_MODULE_
552 DbgTrace (
"succeeded with {} fSuffix2MediaTypeMap_ entries, and {} fMediaType2PreferredSuffixMap entries"_f,
553 fSuffix2MediaTypeMap_.
size (), fMediaType2PreferredSuffixMap_.
size ());
558#if USE_NOISY_TRACE_IN_THIS_MODULE_
562 for (
const auto& imt : fMediaType2PreferredSuffixMap_.
Keys ()) {
572 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix (
const InternetMediaType& ct)
const override
574 if (
auto o = fMediaType2PreferredSuffixMap_.
Lookup (ct)) {
581 if (
auto i = fMediaType2SuffixesMap_.
Lookup (ct)) {
586 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& ct)
const override
588 return LookupAndUpdateFromUsrShareMimePrettyName_ (ct);
590 virtual optional<InternetMediaType> GetAssociatedContentType (
const FileSuffixType& fileSuffix)
const override
592 Require (fileSuffix[0] ==
'.');
593 if (
auto o = fSuffix2MediaTypeMap_.
Lookup (fileSuffix)) {
598 optional<String> LookupAndUpdateFromUsrShareMimePrettyName_ (
const InternetMediaType& ct)
const
600#if USE_NOISY_TRACE_IN_THIS_MODULE_
604 if (
auto o = fMediaType2PrettyNameCache.
cget ()->Lookup (ct)) {
609#if qStroika_Foundation_DataExchange_XML_SupportParsing
613 optional<String> fResult;
614 bool onContentElt{
false};
616 virtual void StartElement (
const Name& name, [[maybe_unused]]
const Mapping<Name, String>& attributes)
override
618 if (name == Name{
"content"_k} and not fResult.has_value ()) {
622 virtual void EndElement ([[maybe_unused]]
const Name& name)
override
625 Assert (not fResult);
626 fResult = fAccum.
str ();
629 virtual void TextInsideElement (
const String& t)
override
636 filesystem::path mimeRoot{
"/usr/share/mime/"sv};
639 DataExchange::XML::SAXParse (IO::FileSystem::FileInputStream::New (
640 mimeRoot / (ct.
GetType () +
"/"_k + ct.
GetSubType () +
".xml"_k).As<filesystem::path> ()),
642 if (handler.fResult) {
643 fMediaType2PrettyNameCache.
rwget ()->Add (ct, *handler.fResult);
644 return *handler.fResult;
648#if USE_NOISY_TRACE_IN_THIS_MODULE_
653 DbgTrace (
"/usr/share/mime/ ignored cuz no xml reader - not compiled with libxml2 or Xerces"_f);
658 return MakeSharedPtr<UsrShareMIMERep_> ();
669 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix ([[maybe_unused]]
const InternetMediaType& ct)
const override
677 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& )
const override
681 virtual optional<InternetMediaType> GetAssociatedContentType ([[maybe_unused]]
const FileSuffixType& fileSuffix)
const override
683 Require (fileSuffix[0] ==
'.');
687 return MakeSharedPtr<DefaultEmptyBackendRep_> ();
690#if qStroika_Foundation_Common_Platform_Windows
691auto InternetMediaTypeRegistry::WindowsRegistryDefaultBackend () -> shared_ptr<IBackendRep>
709 struct WinRep_ : IBackendRep {
730 for (shared_ptr<RegistryKey> sk : RegistryKey{HKEY_CLASSES_ROOT}.EnumerateSubKeys ()) {
731 String name = sk->GetFullPathOfKey ().
Tokenize ({
'\\'}).LastValue ();
733 if (
auto o = sk->Lookup (
"Content Type"sv)) {
740 DbgTrace (
"Ignoring exception parsing registry key ({}): {}"_f, o, current_exception ());
754 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix (
const InternetMediaType& ct)
const override
756 return fContentType2FileSuffixCache_.LookupValue (ct, [] (
const InternetMediaType& ct) -> optional<FileSuffixType> {
770 for (shared_ptr<RegistryKey> sk : RegistryKey{HKEY_CLASSES_ROOT}.EnumerateSubKeys ()) {
771 String name = sk->GetFullPathOfKey ().
Tokenize ({
'\\'}).LastValue ();
773 if (
auto o = sk->Lookup (
"Content Type"sv)) {
780 DbgTrace (
"Ignoring exception parsing registry key ({}): {}"_f, o, current_exception ());
792 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& ct)
const override
794 if (optional<FileSuffixType> fileSuffix = GetPreferredAssociatedFileSuffix (ct)) {
795 return fFileSuffix2PrettyNameCache_.LookupValue (*fileSuffix, [] (
const String& suffix) -> optional<String> {
798 return prettyName.As<String> ();
806 virtual optional<InternetMediaType> GetAssociatedContentType (
const FileSuffixType& fileSuffix)
const override
808 Require (fileSuffix[0] ==
'.');
809 return fSuffix2MediaTypeCache_.LookupValue (fileSuffix, [] (
const FileSuffixType& fileSuffix) -> optional<InternetMediaType> {
812 if (
auto oct = RegistryKey{HKEY_CLASSES_ROOT}.Lookup (
"{}\\Content Type"_f(fileSuffix))) {
820 return MakeSharedPtr<WinRep_> ();
826 return NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetMediaTypes (nullopt);
831 return NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetMediaTypes (majorType);
837 for (
const auto& ct : mediaTypes) {
847 if (fileSuffix.empty ()) {
850 Assert (fileSuffix[0] ==
'.');
851 return NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetAssociatedContentType (fileSuffix);
856 return IsA (InternetMediaTypes::Wildcards::kText, ct);
861 return IsA (InternetMediaTypes::Wildcards::kImage, ct);
866 return IsA (InternetMediaTypes::kXML, ct);
873 if (moreSpecificType.
GetType<AtomType> () == moreGeneralType.
GetType<AtomType> () and
877 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.