/*******************************************************************************
* Copyright (c) 2016 Weasis Team and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Nicolas Roduit - initial API and implementation
*******************************************************************************/
package org.weasis.core.api.media;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.weasis.core.api.internal.mime.InvalidMagicMimeEntryException;
import org.weasis.core.api.internal.mime.MagicMimeEntry;
import org.weasis.core.api.util.FileUtil;
/**
* The Class MimeInspector is a manager for mime types.
*/
public class MimeInspector {
private static final Logger LOGGER = LoggerFactory.getLogger(MimeInspector.class);
public static final String UNKNOWN_MIME_TYPE = "application/x-unknown-mime-type"; //$NON-NLS-1$
public static final Icon unknownIcon = new ImageIcon(MimeInspector.class.getResource("/icon/22x22/unknown.png")); //$NON-NLS-1$
public static final Icon textIcon =
new ImageIcon(MimeInspector.class.getResource("/icon/22x22/text-x-generic.png")); //$NON-NLS-1$
public static final Icon htmlIcon = new ImageIcon(MimeInspector.class.getResource("/icon/22x22/text-html.png")); //$NON-NLS-1$
public static final Icon imageIcon =
new ImageIcon(MimeInspector.class.getResource("/icon/22x22/image-x-generic.png")); //$NON-NLS-1$
public static final Icon audioIcon =
new ImageIcon(MimeInspector.class.getResource("/icon/22x22/audio-x-generic.png")); //$NON-NLS-1$
public static final Icon videoIcon =
new ImageIcon(MimeInspector.class.getResource("/icon/22x22/video-x-generic.png")); //$NON-NLS-1$
public static final Icon dicomIcon = new ImageIcon(MimeInspector.class.getResource("/icon/22x22/dicom.png")); //$NON-NLS-1$
public static final Icon dicomVideo = new ImageIcon(MimeInspector.class.getResource("/icon/22x22/dicom-video.png")); //$NON-NLS-1$
public static final Icon pdfIcon = new ImageIcon(MimeInspector.class.getResource("/icon/22x22/pdf.png")); //$NON-NLS-1$
private static final Properties mimeTypes = new Properties();
private static final ArrayList<MagicMimeEntry> mMagicMimeEntries = new ArrayList<>();
// Initialize the class in preparation for mime type detection
static {
InputStream fileStream = null;
try {
// Load the default supplied mime types
fileStream = MimeInspector.class.getResourceAsStream("/mime-types.properties"); //$NON-NLS-1$
mimeTypes.load(fileStream);
} catch (IOException e) {
LOGGER.error("Error when reading mime-types", e); //$NON-NLS-1$
} finally {
FileUtil.safeClose(fileStream);
}
// Parse and initialize the magic.mime rules
InputStream is = MimeInspector.class.getResourceAsStream("/magic.mime"); //$NON-NLS-1$
if (is != null) {
try (InputStreamReader streamReader = new InputStreamReader(is, "UTF8")) { //$NON-NLS-1$
MimeInspector.parse(streamReader); // $NON-NLS-1$
} catch (Exception e) {
LOGGER.error("Parse magic mime-types", e); //$NON-NLS-1$
}
}
}
private MimeInspector() {
}
public static boolean isMatchingMimeTypeFromMagicNumber(final File file, String mimeType) {
if (file == null || mimeType == null || !file.canRead()) {
return false;
} else if (file.isDirectory()) {
return "application/directory".equals(mimeType); //$NON-NLS-1$
}
MagicMimeEntry me = getMagicMimeEntry(mimeType);
if (me != null) {
// Otherwise find Mime Type from the magic number in file
try (RandomAccessFile raf = new RandomAccessFile(file, "r")) {//$NON-NLS-1$
if (mimeType.equals(me.getMatch(raf))) {
return true;
}
} catch (IOException e) {
LOGGER.error("", e); //$NON-NLS-1$
}
}
return false;
}
public static boolean isMatchingMimeTypeFromMagicNumber(final byte[] byteArray, String mimeType) {
if (byteArray == null || byteArray.length == 0 || mimeType == null) {
return false;
}
MagicMimeEntry me = getMagicMimeEntry(mimeType);
if (me != null) {
try {
if (mimeType.equals(me.getMatch(byteArray))) {
return true;
}
} catch (IOException e) {
LOGGER.error("", e); //$NON-NLS-1$
}
}
return false;
}
public static String getMimeTypeFromMagicNumber(final File file) {
if (file == null || !file.canRead()) {
return null;
} else if (file.isDirectory()) {
return "application/directory"; //$NON-NLS-1$
}
String mimeType = null;
// Otherwise find Mime Type from the magic number in file
try (RandomAccessFile raf = new RandomAccessFile(file, "r")) {//$NON-NLS-1$
mimeType = MimeInspector.getMagicMimeType(raf);
} catch (IOException e) {
LOGGER.error("Error when getting mime-type", e); //$NON-NLS-1$
}
return mimeType;
}
public static String getMimeType(final File file) {
if (file == null || !file.canRead()) {
return null;
}
// Get the file extension
String fileName = file.getName();
int lastPos = fileName.lastIndexOf("."); //$NON-NLS-1$
String extension = lastPos > 0 ? fileName.substring(lastPos + 1).trim() : null;
// Get Mime Type form the extension if the length > 0 and < 5
if (extension != null && extension.length() > 0 && extension.length() < 5) {
String mimeType = mimeTypes.getProperty(extension.toLowerCase());
if (mimeType != null) {
String[] mimes = mimeType.split(","); //$NON-NLS-1$
// When several Mimes for an extension, try to find from magic number
if (mimes.length > 1) {
return Optional.ofNullable(getMimeTypeFromMagicNumber(file)).orElse(mimes[0]);
}
return mimeType;
}
}
return getMimeTypeFromMagicNumber(file);
}
private static void parse(Reader r) throws IOException {
BufferedReader br = new BufferedReader(r);
ArrayList<String> sequence = new ArrayList<>();
String line = br.readLine();
while (true) {
if (line == null) {
break;
}
line = line.trim();
if (line.length() == 0 || line.charAt(0) == '#') {
line = br.readLine();
continue;
}
sequence.add(line);
// read the following lines until a line does not begin with '>' or EOF
while (true) {
line = br.readLine();
if (line == null) {
addEntry(sequence);
sequence.clear();
break;
}
line = line.trim();
if (line.length() == 0 || line.charAt(0) == '#') {
continue;
}
if (line.charAt(0) != '>') {
addEntry(sequence);
sequence.clear();
break;
}
sequence.add(line);
}
}
if (!sequence.isEmpty()) {
addEntry(sequence);
}
}
private static void addEntry(ArrayList<String> aStringArray) {
try {
MagicMimeEntry magicEntry = new MagicMimeEntry(aStringArray);
mMagicMimeEntries.add(magicEntry);
} catch (InvalidMagicMimeEntryException e) {
LOGGER.error("Error when adding mime {}", aStringArray, e); //$NON-NLS-1$
}
}
private static String getMagicMimeType(RandomAccessFile raf) throws IOException {
for (int i = 0; i < mMagicMimeEntries.size(); i++) {
MagicMimeEntry me = mMagicMimeEntries.get(i);
String mtype = me.getMatch(raf);
if (mtype != null) {
return mtype;
}
}
return null;
}
private static MagicMimeEntry getMagicMimeEntry(String mimeType) {
if (mimeType != null) {
for (MagicMimeEntry m : mMagicMimeEntries) {
if (mimeType.equals(m.getMimeType())) {
return m;
}
}
}
return null;
}
// Utility method to get the major part of a mime type
public static String getMajorComponent(String mimeType) {
if (mimeType == null) {
return ""; //$NON-NLS-1$
}
int offset = mimeType.indexOf("/"); //$NON-NLS-1$
if (offset == -1) {
return mimeType;
} else {
return mimeType.substring(0, offset);
}
}
// Utility method to get the minor part of a mime type
public static String getMinorComponent(String mimeType) {
if (mimeType == null) {
return ""; //$NON-NLS-1$
}
int offset = mimeType.indexOf("/"); //$NON-NLS-1$
if (offset == -1) {
return mimeType;
} else {
return mimeType.substring(offset + 1);
}
}
// Utility method that gets the extension of a file from its name if it has one
public static String getFileExtension(String fileName) {
int lastPos;
if (fileName == null || (lastPos = fileName.lastIndexOf(".")) < 0) { //$NON-NLS-1$
return null;
}
String extension = fileName.substring(lastPos + 1);
// Could be that the path actually had a '.' in it so lets check
if (extension.contains(File.separator)) {
return null;
}
return extension;
}
public static List<String> getExtensions(String mime) {
if (mime == null) {
return Collections.emptyList();
}
ArrayList<String> list = new ArrayList<>();
String[] mimes = mime.split(","); //$NON-NLS-1$
Set<Entry<Object, Object>> entries = mimeTypes.entrySet();
for (Entry<Object, Object> entry : entries) {
String key = (String) entry.getKey();
String val = (String) entry.getValue();
if (val != null) {
Arrays.stream(mimes).filter(val::equals).forEach(s -> list.add(key));
}
}
return list;
}
}