blob: 45342558ccc48eef364f608d1530a29a6410b335 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Namespace object for file type utility functions.
*/
function FileType() {}
/**
* @typedef {{
* name: !string,
* type: !string,
* icon: !string,
* subtype: !string,
* pattern: (RegExp|undefined),
* mimePattern: (RegExp|undefined)
* }}
*/
FileType.Descriptor;
/**
* Description of known file types.
* Pair type-subtype defines order when sorted by file type.
* @type {Array<!FileType.Descriptor>}
*/
FileType.types = [
// Images
{
type: 'image',
name: 'IMAGE_FILE_TYPE',
subtype: 'JPEG',
pattern: /\.jpe?g$/i,
mimePattern: /image\/jpeg/i,
},
{
type: 'image',
name: 'IMAGE_FILE_TYPE',
subtype: 'BMP',
pattern: /\.bmp$/i,
mimePattern: /image\/bmp/i,
},
{
type: 'image',
name: 'IMAGE_FILE_TYPE',
subtype: 'GIF',
pattern: /\.gif$/i,
mimePattern: /image\/gif/i,
},
{
type: 'image',
name: 'IMAGE_FILE_TYPE',
subtype: 'ICO',
pattern: /\.ico$/i,
mimePattern: /image\/x\-icon/i,
},
{
type: 'image',
name: 'IMAGE_FILE_TYPE',
subtype: 'PNG',
pattern: /\.png$/i,
mimePattern: /image\/png/i
},
{
type: 'image',
name: 'IMAGE_FILE_TYPE',
subtype: 'WebP',
pattern: /\.webp$/i,
mimePattern: /image\/webp/i
},
{
type: 'image',
name: 'IMAGE_FILE_TYPE',
subtype: 'TIFF',
pattern: /\.tiff?$/i,
mimePattern: /image\/tiff/i
},
{
type: 'image',
name: 'IMAGE_FILE_TYPE',
subtype: 'SVG',
pattern: /\.svg$/i,
mimePattern: /image\/svg\+xml/i
},
// Raw
{
type: 'raw',
name: 'IMAGE_FILE_TYPE',
subtype: 'ARW',
pattern: /\.arw$/i,
icon: 'image'
},
{
type: 'raw',
name: 'IMAGE_FILE_TYPE',
subtype: 'CR2',
pattern: /\.cr2$/i,
icon: 'image'
},
{
type: 'raw',
name: 'IMAGE_FILE_TYPE',
subtype: 'DNG',
pattern: /\.dng$/i,
icon: 'image'
},
{
type: 'raw',
name: 'IMAGE_FILE_TYPE',
subtype: 'NEF',
pattern: /\.nef$/i,
icon: 'image'
},
{
type: 'raw',
name: 'IMAGE_FILE_TYPE',
subtype: 'NRW',
pattern: /\.nrw$/i,
icon: 'image'
},
{
type: 'raw',
name: 'IMAGE_FILE_TYPE',
subtype: 'ORF',
pattern: /\.orf$/i,
icon: 'image'
},
{
type: 'raw',
name: 'IMAGE_FILE_TYPE',
subtype: 'RAF',
pattern: /\.raf$/i,
icon: 'image'
},
{
type: 'raw',
name: 'IMAGE_FILE_TYPE',
subtype: 'RW2',
pattern: /\.rw2$/i,
icon: 'image'
},
// Video
{
type: 'video',
name: 'VIDEO_FILE_TYPE',
subtype: '3GP',
pattern: /\.3gpp?$/i,
mimePattern: /video\/3gpp/i
},
{
type: 'video',
name: 'VIDEO_FILE_TYPE',
subtype: 'AVI',
pattern: /\.avi$/i,
mimePattern: /video\/x\-msvideo/i
},
{
type: 'video',
name: 'VIDEO_FILE_TYPE',
subtype: 'QuickTime',
pattern: /\.mov$/i,
mimePattern: /video\/quicktime/i
},
{
type: 'video',
name: 'VIDEO_FILE_TYPE',
subtype: 'MKV',
pattern: /\.mkv$/i,
mimePattern: /video\/x\-matroska/i
},
{
type: 'video',
name: 'VIDEO_FILE_TYPE',
subtype: 'MPEG',
pattern: /\.m(p4|4v|pg|peg|pg4|peg4)$/i,
mimePattern: /video\/mp(4|eg)/i
},
{
type: 'video',
name: 'VIDEO_FILE_TYPE',
subtype: 'OGG',
pattern: /\.og(m|v|x)$/i,
mimePattern: /(application|video)\/ogg/i
},
{
type: 'video',
name: 'VIDEO_FILE_TYPE',
subtype: 'WebM',
pattern: /\.webm$/i,
mimePattern: /video\/webm/i
},
// Audio
{
type: 'audio',
name: 'AUDIO_FILE_TYPE',
subtype: 'AMR',
pattern: /\.amr$/i,
mimePattern: /audio\/amr/i
},
{
type: 'audio',
name: 'AUDIO_FILE_TYPE',
subtype: 'FLAC',
pattern: /\.flac$/i,
mimePattern: /audio\/flac/i
},
{
type: 'audio',
name: 'AUDIO_FILE_TYPE',
subtype: 'MP3',
pattern: /\.mp3$/i,
mimePattern: /audio\/mpeg/i
},
{
type: 'audio',
name: 'AUDIO_FILE_TYPE',
subtype: 'MPEG',
pattern: /\.m4a$/i,
mimePattern: /audio\/mp4a-latm/i
},
{
type: 'audio',
name: 'AUDIO_FILE_TYPE',
subtype: 'OGG',
pattern: /\.og(a|g)$/i,
mimePattern: /audio\/ogg/i
},
{
type: 'audio',
name: 'AUDIO_FILE_TYPE',
subtype: 'WAV',
pattern: /\.wav$/i,
mimePattern: /audio\/x\-wav/i
},
// Text
{
type: 'text',
name: 'PLAIN_TEXT_FILE_TYPE',
subtype: 'TXT',
pattern: /\.txt$/i,
mimePattern: /text\/plain/i
},
// Archive
{
type: 'archive',
name: 'ZIP_ARCHIVE_FILE_TYPE',
subtype: 'ZIP',
pattern: /\.zip$/i,
mimePattern: /application\/zip/i
},
{
type: 'archive',
name: 'RAR_ARCHIVE_FILE_TYPE',
subtype: 'RAR',
pattern: /\.rar$/i,
mimePattern: /application\/x\-rar\-compressed/i
},
{
type: 'archive',
name: 'TAR_ARCHIVE_FILE_TYPE',
subtype: 'TAR',
pattern: /\.tar$/i,
mimePattern: /application\/x\-tar/i
},
{
type: 'archive',
name: 'TAR_BZIP2_ARCHIVE_FILE_TYPE',
subtype: 'TBZ2',
pattern: /\.(tar\.bz2|tbz|tbz2)$/i,
mimePattern: /application\/x\-bzip2/i
},
{
type: 'archive',
name: 'TAR_GZIP_ARCHIVE_FILE_TYPE',
subtype: 'TGZ',
pattern: /\.(tar\.|t)gz$/i,
mimePattern: /application\/x\-gzip/i
},
// Hosted docs.
{
type: 'hosted',
icon: 'gdoc',
name: 'GDOC_DOCUMENT_FILE_TYPE',
subtype: 'doc',
pattern: /\.gdoc$/i
},
{
type: 'hosted',
icon: 'gsheet',
name: 'GSHEET_DOCUMENT_FILE_TYPE',
subtype: 'sheet',
pattern: /\.gsheet$/i
},
{
type: 'hosted',
icon: 'gslides',
name: 'GSLIDES_DOCUMENT_FILE_TYPE',
subtype: 'slides',
pattern: /\.gslides$/i
},
{
type: 'hosted',
icon: 'gdraw',
name: 'GDRAW_DOCUMENT_FILE_TYPE',
subtype: 'draw',
pattern: /\.gdraw$/i
},
{
type: 'hosted',
icon: 'gtable',
name: 'GTABLE_DOCUMENT_FILE_TYPE',
subtype: 'table',
pattern: /\.gtable$/i
},
{
type: 'hosted',
icon: 'glink',
name: 'GLINK_DOCUMENT_FILE_TYPE',
subtype: 'glink',
pattern: /\.glink$/i
},
{
type: 'hosted',
icon: 'gform',
name: 'GFORM_DOCUMENT_FILE_TYPE',
subtype: 'form',
pattern: /\.gform$/i
},
{
// We use extension ".gmaps" to avoid conflict, but use singular form
// (gmap/map) in other parts to be consistent with other file type.
type: 'hosted',
icon: 'gmap',
name: 'GMAP_DOCUMENT_FILE_TYPE',
subtype: 'map',
pattern: /\.gmaps$/i
},
{
type: 'hosted',
icon: 'gsite',
name: 'GSITE_DOCUMENT_FILE_TYPE',
subtype: 'site',
pattern: /\.gsite$/i
},
// Others
{
type: 'document',
icon: 'pdf',
name: 'PDF_DOCUMENT_FILE_TYPE',
subtype: 'PDF',
pattern: /\.pdf$/i,
mimePattern: /application\/pdf/i
},
{
type: 'document',
name: 'HTML_DOCUMENT_FILE_TYPE',
subtype: 'HTML',
pattern: /\.(html?|mht(ml)?|shtml|xht(ml)?)$/i,
mimePattern: /text\/html/i
},
{
type: 'document',
icon: 'word',
name: 'WORD_DOCUMENT_FILE_TYPE',
subtype: 'Word',
pattern: /\.(doc|docx)$/i,
mimePattern: new RegExp(
'application/(msword|vnd\\.' +
'openxmlformats-officedocument\\.wordprocessingml\\.document)',
'i')
},
{
type: 'document',
icon: 'ppt',
name: 'POWERPOINT_PRESENTATION_FILE_TYPE',
subtype: 'PPT',
pattern: /\.(ppt|pptx)$/i,
mimePattern: new RegExp(
'application/vnd\\.(ms-powerpoint|' +
'openxmlformats-officedocument\\.presentationml\\.presentation)',
'i')
},
{
type: 'document',
icon: 'excel',
name: 'EXCEL_FILE_TYPE',
subtype: 'Excel',
pattern: /\.(xls|xlsx)$/i,
mimePattern: new RegExp(
'application/vnd\\.(ms-excel|' +
'openxmlformats-officedocument\\.spreadsheetml\\.sheet)',
'i')
}
];
/**
* A special type for directory.
* @type{!FileType.Descriptor}
* @const
*/
FileType.DIRECTORY = {
name: 'FOLDER',
type: '.folder',
icon: 'folder',
subtype: ''
};
/**
* A special placeholder for unknown types with no extension.
* @type{!FileType.Descriptor}
* @const
*/
FileType.PLACEHOLDER = {
name: 'NO_EXTENSION_FILE_TYPE',
type: 'UNKNOWN',
icon: '',
subtype: ''
};
/**
* Returns the file path extension for a given file.
*
* @param {Entry|FilesAppEntry} entry Reference to the file.
* @return {string} The extension including a leading '.', or empty string if
* not found.
*/
FileType.getExtension = entry => {
// No extension for a directory.
if (entry.isDirectory) {
return '';
}
const extensionStartIndex = entry.name.lastIndexOf('.');
if (extensionStartIndex === -1 ||
extensionStartIndex === entry.name.length - 1) {
return '';
}
return entry.name.substr(extensionStartIndex);
};
/**
* Gets the file type object for a given file name (base name). Use getType()
* if possible, since this method can't recognize directories.
*
* @param {string} name Name of the file.
* @return {!FileType.Descriptor} The matching descriptor or a placeholder.
*/
FileType.getTypeForName = name => {
const types = FileType.types;
for (let i = 0; i < types.length; i++) {
if (types[i].pattern.test(name)) {
return types[i];
}
}
// Unknown file type.
const match = /\.[^\/\.]+$/.exec(name);
const extension = match ? match[0] : '';
if (extension === '') {
return FileType.PLACEHOLDER;
}
// subtype is the extension excluding the first dot.
return {
name: 'GENERIC_FILE_TYPE',
type: 'UNKNOWN',
subtype: extension.substr(1).toUpperCase(),
icon: ''
};
};
/**
* Gets the file type object for a given entry. If mime type is provided, then
* uses it with higher priority than the extension.
*
* @param {(Entry|FilesAppEntry)} entry Reference to the entry.
* @param {string=} opt_mimeType Optional mime type for the entry.
* @return {!FileType.Descriptor} The matching descriptor or a placeholder.
*/
FileType.getType = (entry, opt_mimeType) => {
if (entry.isDirectory) {
return FileType.DIRECTORY;
}
if (opt_mimeType) {
for (let i = 0; i < FileType.types.length; i++) {
if (FileType.types[i].mimePattern &&
FileType.types[i].mimePattern.test(opt_mimeType)) {
return FileType.types[i];
}
}
}
for (let i = 0; i < FileType.types.length; i++) {
if (FileType.types[i].pattern.test(entry.name)) {
return FileType.types[i];
}
}
// Unknown file type.
const extension = FileType.getExtension(entry);
if (extension === '') {
return FileType.PLACEHOLDER;
}
// subtype is the extension excluding the first dot.
return {
name: 'GENERIC_FILE_TYPE',
type: 'UNKNOWN',
subtype: extension.substr(1).toUpperCase(),
icon: ''
};
};
/**
* Gets the media type for a given file.
*
* @param {Entry} entry Reference to the file.
* @param {string=} opt_mimeType Optional mime type for the file.
* @return {string} The value of 'type' property from one of the elements in
* FileType.types or undefined.
*/
FileType.getMediaType = (entry, opt_mimeType) => {
return FileType.getType(entry, opt_mimeType).type;
};
/**
* @param {Entry} entry Reference to the file.
* @param {string=} opt_mimeType Optional mime type for the file.
* @return {boolean} True if audio file.
*/
FileType.isAudio = (entry, opt_mimeType) => {
return FileType.getMediaType(entry, opt_mimeType) === 'audio';
};
/**
* Returns whether the |entry| is image file that can be opened in browser.
* Note that it returns false for RAW images.
* @param {Entry} entry Reference to the file.
* @param {string=} opt_mimeType Optional mime type for the file.
* @return {boolean} True if image file.
*/
FileType.isImage = (entry, opt_mimeType) => {
return FileType.getMediaType(entry, opt_mimeType) === 'image';
};
/**
* @param {Entry} entry Reference to the file.
* @param {string=} opt_mimeType Optional mime type for the file.
* @return {boolean} True if video file.
*/
FileType.isVideo = (entry, opt_mimeType) => {
return FileType.getMediaType(entry, opt_mimeType) === 'video';
};
/**
* @param {Entry} entry Reference to the file.
* @param {string=} opt_mimeType Optional mime type for the file.
* @return {boolean} True if raw file.
*/
FileType.isRaw = (entry, opt_mimeType) => {
return FileType.getMediaType(entry, opt_mimeType) === 'raw';
};
/**
* Files with more pixels won't have preview.
* @param {!Array<string>} types
* @param {Entry} entry Reference to the file.
* @param {string=} opt_mimeType Optional mime type for the file.
* @return {boolean} True if type is in specified set
*/
FileType.isType = (types, entry, opt_mimeType) => {
const type = FileType.getMediaType(entry, opt_mimeType);
return !!type && types.indexOf(type) !== -1;
};
/**
* @param {Entry} entry Reference to the file.
* @param {string=} opt_mimeType Optional mime type for the file.
* @return {boolean} Returns true if the file is hosted.
*/
FileType.isHosted = (entry, opt_mimeType) => {
return FileType.getType(entry, opt_mimeType).type === 'hosted';
};
/**
* @param {Entry|VolumeEntry} entry Reference to the file.
* @param {string=} opt_mimeType Optional mime type for the file.
* @param {VolumeManagerCommon.RootType=} opt_rootType The root type of the
* entry.
* @return {string} Returns string that represents the file icon.
* It refers to a file 'images/filetype_' + icon + '.png'.
*/
FileType.getIcon = (entry, opt_mimeType, opt_rootType) => {
const fileType = FileType.getType(entry, opt_mimeType);
const overridenIcon = FileType.getIconOverrides(entry, opt_rootType);
return entry.iconName || overridenIcon || fileType.icon || fileType.type ||
'unknown';
};
/**
* Returns a string to be used as an attribute value to customize the entry
* icon.
*
* @param {Entry|FilesAppEntry} entry
* @param {VolumeManagerCommon.RootType=} opt_rootType The root type of the
* entry.
* @return {string}
*/
FileType.getIconOverrides = (entry, opt_rootType) => {
// Overrides per RootType and defined by fullPath.
const overrides = {
[VolumeManagerCommon.RootType.DOWNLOADS]: {
'/Downloads': VolumeManagerCommon.VolumeType.DOWNLOADS,
'/PvmDefault': 'plugin_vm',
},
};
const root = overrides[opt_rootType];
return root ? root[entry.fullPath] : '';
};