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};
301 : fFrontEndRep_{backendRep == nullptr ? nullptr : MakeSharedPtr<FrontendRep_> (backendRep)}
307 return NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetOverrides ();
312 if (fFrontEndRep_ ==
nullptr) {
313 fFrontEndRep_ = MakeSharedPtr<FrontendRep_> (kDefaultFrontEndForNoBackend_);
316 fFrontEndRep_->SetOverrides (overrides);
321 if (fFrontEndRep_ ==
nullptr) {
322 fFrontEndRep_ = MakeSharedPtr<FrontendRep_> (kDefaultFrontEndForNoBackend_);
325 fFrontEndRep_->AddOverride (mediaType, overrideRec);
330 return Memory::NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetPreferredAssociatedFileSuffix (ct);
336 r = Memory::NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetAssociatedFileSuffixes (ct);
346 return Memory::NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetAssociatedPrettyName (ct);
352#if qStroika_Foundation_Common_Platform_Windows
353 return WindowsRegistryDefaultBackend ();
356 if (filesystem::exists (
"/usr/share/mime"sv)) {
364 if (filesystem::exists (
"/etc/mime.types"sv)) {
392#if USE_NOISY_TRACE_IN_THIS_MODULE_
396 IO::FileSystem::FileInputStream::New (
"/etc/mime.types"sv))) {
397 if (line.length () >= 2 and not line[0].StartsWith (
"#"_k)) {
403 DbgTrace (
"Ignoring exception looking parsing potential media type entry ({}): {}"_f, line[0], current_exception ());
407 for (
size_t i = 1; i < line.length (); ++i) {
408 if (line[i].empty ()) {
409 DbgTrace (
"Ignoring bad looking parsing potential media type entry ({})"_f, line);
412 Assert (not line[i].empty ());
413 String suffix =
"."sv + line[i];
414 fSuffix2MediaTypeMap_.
Add (suffix, ct);
415 fMediaType2PreferredSuffixMap_.
Add (ct, suffix, AddReplaceMode::eAddIfMissing);
416 fileSuffixes.
Add (suffix);
419 fMediaType2SuffixesMap_.
Add (ct, fileSuffixes);
423 fMediaType2PreferredSuffixMap_.
Add (InternetMediaTypes::kText_PLAIN,
".txt"sv);
424#if USE_NOISY_TRACE_IN_THIS_MODULE_
425 DbgTrace (L
"succeeded with {} fSuffix2MediaTypeMap entries, and {} fMediaType2PreferredSuffixMap entries"_f,
426 fSuffix2MediaTypeMap_.
size (), fMediaType2PreferredSuffixMap_.
size ());
440 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix (
const InternetMediaType& ct)
const override
442 if (
auto o = fMediaType2PreferredSuffixMap_.
Lookup (ct)) {
449 if (
auto i = fMediaType2SuffixesMap_.
Lookup (ct)) {
454 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& )
const override
458 virtual optional<InternetMediaType> GetAssociatedContentType (
const FileSuffixType& fileSuffix)
const override
460 Require (fileSuffix[0] ==
'.');
461 if (
auto o = fSuffix2MediaTypeMap_.
Lookup (fileSuffix)) {
467 return MakeSharedPtr<EtcMimeTypesRep_> ();
495#if USE_NOISY_TRACE_IN_THIS_MODULE_
499 auto loadGlobsFromFile = [&] (
const filesystem::path& fn) {
500 if (filesystem::exists (fn)) {
505 if (line.length () == 2) {
516 DbgTrace (
"Ignoring exception looking parsing potential media type entry ({}): {}"_f, line[0], current_exception ());
518 fSuffix2MediaTypeMap_.
Add (glob, imt, AddReplaceMode::eAddIfMissing);
519 fMediaType2PreferredSuffixMap_.
Add (imt, glob, AddReplaceMode::eAddIfMissing);
523 prevSuffixes.
Add (glob);
524 fMediaType2SuffixesMap_.
Add (imt, prevSuffixes);
529 fMediaType2PreferredSuffixMap_.
Add (InternetMediaTypes::kText_PLAIN,
".txt"_k);
537 for (
const auto& p : fDataRoots_) {
538 loadGlobsFromFile (p /
"globs");
541#if USE_NOISY_TRACE_IN_THIS_MODULE_
542 DbgTrace (
"succeeded with {} fSuffix2MediaTypeMap_ entries, and {} fMediaType2PreferredSuffixMap entries"_f,
543 fSuffix2MediaTypeMap_.
size (), fMediaType2PreferredSuffixMap_.
size ());
548#if USE_NOISY_TRACE_IN_THIS_MODULE_
552 for (
const auto& imt : fMediaType2PreferredSuffixMap_.
Keys ()) {
562 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix (
const InternetMediaType& ct)
const override
564 if (
auto o = fMediaType2PreferredSuffixMap_.
Lookup (ct)) {
571 if (
auto i = fMediaType2SuffixesMap_.
Lookup (ct)) {
576 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& ct)
const override
578 return LookupAndUpdateFromUsrShareMimePrettyName_ (ct);
580 virtual optional<InternetMediaType> GetAssociatedContentType (
const FileSuffixType& fileSuffix)
const override
582 Require (fileSuffix[0] ==
'.');
583 if (
auto o = fSuffix2MediaTypeMap_.
Lookup (fileSuffix)) {
588 optional<String> LookupAndUpdateFromUsrShareMimePrettyName_ (
const InternetMediaType& ct)
const
590#if USE_NOISY_TRACE_IN_THIS_MODULE_
594 if (
auto o = fMediaType2PrettyNameCache.
cget ()->Lookup (ct)) {
599#if qStroika_Foundation_DataExchange_XML_SupportParsing
603 optional<String> fResult;
604 bool onContentElt{
false};
606 virtual void StartElement (
const Name& name, [[maybe_unused]]
const Mapping<Name, String>& attributes)
override
608 if (name == Name{
"content"_k} and not fResult.has_value ()) {
612 virtual void EndElement ([[maybe_unused]]
const Name& name)
override
615 Assert (not fResult);
616 fResult = fAccum.
str ();
619 virtual void TextInsideElement (
const String& t)
override
626 filesystem::path mimeRoot{
"/usr/share/mime/"sv};
629 DataExchange::XML::SAXParse (IO::FileSystem::FileInputStream::New (
630 mimeRoot / (ct.
GetType () +
"/"_k + ct.
GetSubType () +
".xml"_k).As<filesystem::path> ()),
632 if (handler.fResult) {
633 fMediaType2PrettyNameCache.
rwget ()->Add (ct, *handler.fResult);
634 return *handler.fResult;
638#if USE_NOISY_TRACE_IN_THIS_MODULE_
643 DbgTrace (
"/usr/share/mime/ ignored cuz no xml reader - not compiled with libxml2 or Xerces"_f);
648 return MakeSharedPtr<UsrShareMIMERep_> ();
659 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix ([[maybe_unused]]
const InternetMediaType& ct)
const override
667 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& )
const override
671 virtual optional<InternetMediaType> GetAssociatedContentType ([[maybe_unused]]
const FileSuffixType& fileSuffix)
const override
673 Require (fileSuffix[0] ==
'.');
677 return MakeSharedPtr<DefaultEmptyBackendRep_> ();
680auto InternetMediaTypeRegistry::CloneAsSharedPtr_ (
const IFrontendRep_& t) -> shared_ptr<IFrontendRep_>
682 return Memory::MakeSharedPtr<FrontendRep_> (t.GetBackendRep (), t.GetOverrides ());
685#if qStroika_Foundation_Common_Platform_Windows
686auto InternetMediaTypeRegistry::WindowsRegistryDefaultBackend () -> shared_ptr<IBackendRep>
704 struct WinRep_ : IBackendRep {
725 for (shared_ptr<RegistryKey> sk : RegistryKey{HKEY_CLASSES_ROOT}.EnumerateSubKeys ()) {
726 String name = sk->GetFullPathOfKey ().
Tokenize ({
'\\'}).LastValue ();
728 if (
auto o = sk->Lookup (
"Content Type"sv)) {
735 DbgTrace (
"Ignoring exception parsing registry key ({}): {}"_f, o, current_exception ());
749 virtual optional<FileSuffixType> GetPreferredAssociatedFileSuffix (
const InternetMediaType& ct)
const override
751 return fContentType2FileSuffixCache_.LookupValue (ct, [] (
const InternetMediaType& ct) -> optional<FileSuffixType> {
765 for (shared_ptr<RegistryKey> sk : RegistryKey{HKEY_CLASSES_ROOT}.EnumerateSubKeys ()) {
766 String name = sk->GetFullPathOfKey ().
Tokenize ({
'\\'}).LastValue ();
768 if (
auto o = sk->Lookup (
"Content Type"sv)) {
775 DbgTrace (
"Ignoring exception parsing registry key ({}): {}"_f, o, current_exception ());
787 virtual optional<String> GetAssociatedPrettyName (
const InternetMediaType& ct)
const override
789 if (optional<FileSuffixType> fileSuffix = GetPreferredAssociatedFileSuffix (ct)) {
790 return fFileSuffix2PrettyNameCache_.LookupValue (*fileSuffix, [] (
const String& suffix) -> optional<String> {
793 return prettyName.As<String> ();
801 virtual optional<InternetMediaType> GetAssociatedContentType (
const FileSuffixType& fileSuffix)
const override
803 Require (fileSuffix[0] ==
'.');
804 return fSuffix2MediaTypeCache_.LookupValue (fileSuffix, [] (
const FileSuffixType& fileSuffix) -> optional<InternetMediaType> {
807 if (
auto oct = RegistryKey{HKEY_CLASSES_ROOT}.Lookup (
"{}\\Content Type"_f(fileSuffix))) {
815 return MakeSharedPtr<WinRep_> ();
821 return NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetMediaTypes (nullopt);
826 return NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetMediaTypes (majorType);
832 for (
const auto& ct : mediaTypes) {
842 if (fileSuffix.empty ()) {
845 Assert (fileSuffix[0] ==
'.');
846 return NullCoalesce (fFrontEndRep_, kDefaultFrontEndForNoBackend_).GetAssociatedContentType (fileSuffix);
851 return IsA (InternetMediaTypes::Wildcards::kText, ct);
856 return IsA (InternetMediaTypes::Wildcards::kImage, ct);
861 return IsA (InternetMediaTypes::kXML, ct);
868 if (moreSpecificType.
GetType<AtomType> () == moreGeneralType.
GetType<AtomType> () and
872 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(...)
simple wrapper on LRUCache (with the same API) - but internally synchronized in a way that is more pe...
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.