From 142e787a9cdc585453e38eda26da7388ecfbec7f Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 29 Nov 2018 16:46:08 -0800 Subject: [PATCH] Create MIMETypeLibrary for general MIME type detection --- .../shared/src/shared/MIMETypeLibrary.cpp | 85 +++++++++++++++++ libraries/shared/src/shared/MIMETypeLibrary.h | 91 +++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 libraries/shared/src/shared/MIMETypeLibrary.cpp create mode 100644 libraries/shared/src/shared/MIMETypeLibrary.h diff --git a/libraries/shared/src/shared/MIMETypeLibrary.cpp b/libraries/shared/src/shared/MIMETypeLibrary.cpp new file mode 100644 index 0000000000..4f12f373fe --- /dev/null +++ b/libraries/shared/src/shared/MIMETypeLibrary.cpp @@ -0,0 +1,85 @@ +// +// MIMETypeLibrary.cpp +// libraries/shared/src/shared +// +// Created by Sabrina Shanman on 2018/11/29. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "MIMETypeLibrary.h" + +MIMETypeLibrary::ID MIMETypeLibrary::registerMIMEType(const MIMEType& mimeType) { + ID id; + withWriteLock([&](){ + id = nextID++; + _mimeTypes.emplace_back(id, mimeType); + }); + return id; +} + +void MIMETypeLibrary::unregisterMIMEType(const MIMETypeLibrary::ID& id) { + withWriteLock([&](){ + for (auto it = _mimeTypes.begin(); it != _mimeTypes.end(); it++) { + if ((*it).id == id) { + _mimeTypes.erase(it); + break; + } + } + }); +} + +MIMEType MIMETypeLibrary::getMIMEType(const MIMETypeLibrary::ID& id) const { + return resultWithReadLock([&](){ + for (auto& supportedFormat : _mimeTypes) { + if (supportedFormat.id == id) { + return supportedFormat.mimeType; + } + } + return MIMEType::NONE; + }); +} + +MIMETypeLibrary::ID MIMETypeLibrary::findMatchingMIMEType(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url, const std::string& webMediaType) const { + return resultWithReadLock([&](){ + // Check file contents + for (auto& mimeType : _mimeTypes) { + for (auto& fileSignature : mimeType.mimeType.fileSignatures) { + auto testBytes = data.mid(fileSignature.byteOffset, (int)fileSignature.bytes.size()).toStdString(); + if (testBytes == fileSignature.bytes) { + return mimeType.id; + } + } + } + + // Check file extension + std::string urlString = url.path().toStdString(); + std::size_t extensionSeparator = urlString.rfind('.'); + if (extensionSeparator != std::string::npos) { + std::string detectedExtension = urlString.substr(extensionSeparator + 1); + for (auto& supportedFormat : _mimeTypes) { + for (auto& extension : supportedFormat.mimeType.extensions) { + if (extension == detectedExtension) { + return supportedFormat.id; + } + } + } + } + + // Check web media type + if (webMediaType != "") { + for (auto& supportedFormat : _mimeTypes) { + for (auto& candidateWebMediaType : supportedFormat.mimeType.webMediaTypes) { + if (candidateWebMediaType == webMediaType) { + return supportedFormat.id; + } + } + } + } + + // Supported file type not found. + return INVALID_ID; + }); +} diff --git a/libraries/shared/src/shared/MIMETypeLibrary.h b/libraries/shared/src/shared/MIMETypeLibrary.h new file mode 100644 index 0000000000..62bc28cdad --- /dev/null +++ b/libraries/shared/src/shared/MIMETypeLibrary.h @@ -0,0 +1,91 @@ +// +// MIMETypeLibrary.h +// libraries/shared/src/shared +// +// Created by Sabrina Shanman on 2018/11/28. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_MIMETypeLibrary_h +#define hifi_MIMETypeLibrary_h + +#include +#include +#include +#include + +#include "HifiTypes.h" + +#include "ReadWriteLockable.h" + +// A short sequence of bytes, typically at the beginning of the file, which identifies the file format +class FileSignature { +public: + FileSignature(const std::string& bytes, int byteOffset) : + bytes(bytes), + byteOffset(byteOffset) { + } + FileSignature(const FileSignature& fileSignature) : + bytes(fileSignature.bytes), + byteOffset(fileSignature.byteOffset) { + } + + std::string bytes; + int byteOffset; +}; + +// A named file extension with a list of known ways to positively identify the file type +class MIMEType { +public: + MIMEType(const std::string& name) : + name(name) { + } + MIMEType() {}; + MIMEType(const MIMEType& mimeType) : + name(mimeType.name), + extensions(mimeType.extensions), + webMediaTypes(mimeType.webMediaTypes), + fileSignatures(mimeType.fileSignatures) { + } + + static MIMEType NONE; + + std::string name; + std::vector extensions; + std::vector webMediaTypes; + std::vector fileSignatures; +}; + +MIMEType MIMEType::NONE = MIMEType(""); + +class MIMETypeLibrary : ReadWriteLockable { +public: + using ID = unsigned int; + static const ID INVALID_ID { 0 }; + + ID registerMIMEType(const MIMEType& mimeType); + void unregisterMIMEType(const ID& id); + + MIMEType getMIMEType(const ID& id) const; + ID findMatchingMIMEType(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url, const std::string& webMediaType) const; + +protected: + ID nextID { 1 }; + + class Entry { + public: + Entry(const ID& id, const MIMEType& mimeType) : + id(id), + mimeType(mimeType) { + } + ID id; + MIMEType mimeType; + }; + + std::vector _mimeTypes; +}; + +#endif // hifi_MIMETypeLibrary_h