package org.sigmah.shared.util; /* * #%L * Sigmah * %% * Copyright (C) 2010 - 2016 URD * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.sigmah.client.util.ClientUtils; /** * File types enumeration. * * @author Denis Colliot (dcolliot@ideia.fr) */ public enum FileType { _DEFAULT(null, "application/octet-stream"), CSS(FileExtension.CSS, "text/css"), CSV(FileExtension.CSV, "text/csv"), DOC(FileExtension.DOC, "application/msword"), DOCX(FileExtension.DOCX, "application/vnd.openxmlformats-officedocument.wordprocessingml.document"), DOCXML(FileExtension.XML, "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"), EML(FileExtension.EML, "message/rfc822"), GIF(FileExtension.GIF, "image/gif"), HTML(FileExtension.HTML, "text/html"), JPEG(FileExtension.JPEG, "image/jpeg"), JPG(FileExtension.JPG, "image/jpeg"), JS(FileExtension.JS, "application/javascript"), MSG(FileExtension.MSG, "application/vnd.ms-outlook"), ODS(FileExtension.ODS, "application/vnd.oasis.opendocument.spreadsheet"), PDF(FileExtension.PDF, "application/pdf"), PNG(FileExtension.PNG, "image/png"), PPS(FileExtension.PPS, "application/pps"), PPSX(FileExtension.PPSX, "application/vnd.openxmlformats-officedocument.presentationml.slideshow"), PPT(FileExtension.PPT, "application/vnd.ms-powerpoint"), PPTX(FileExtension.PPTX, "application/vnd.openxmlformats-officedocument.presentationml.presentation"), RTF(FileExtension.RTF, "application/rtf"), TIF(FileExtension.TIF, "application/x-tif"), TIFF(FileExtension.TIFF, "image/tiff"), TXT(FileExtension.TXT, "text/plain"), URL(FileExtension.URL, "text/url"), XHTML(FileExtension.XHTML, "application/xhtml+xml"), XLS(FileExtension.XLS, "application/vnd.ms-excel"), XLSX(FileExtension.XLSX, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"), XML(FileExtension.XML, "application/xml"), ZIP(FileExtension.ZIP, "application/zip"), ; private final FileExtension extension; private final String contentType; private FileType(FileExtension extension, String contentType) { this.extension = extension; this.contentType = contentType == null ? "" : contentType; } /** * Returns the {@code FileType} corresponding label. * * @return the {@code FileType} corresponding label. */ public String getContentType() { return contentType; } /** * Returns the current {@code FileType} extension value (with separator). * * <pre> * FileType._DEFAULT.getExtension() → ""; * FileType.TXT.getExtension() → ".txt"; * FileType.DOCXML.getExtension() → ".xml"; * FileType.XML.getExtension() → ".xml"; * FileType.PDF.getExtension() → ".pdf"; * </pre> * * @return the current {@code FileType} extension value (with extension separator). */ public String getExtension() { return getExtension(true); } /** * Returns the current {@code FileType} extension value (with separator). * * <pre> * FileType._DEFAULT.getExtension(true) → ""; * FileType._DEFAULT.getExtension(false) → ""; * FileType.TXT.getExtension(true) → ".txt"; * FileType.TXT.getExtension(false) → "txt"; * FileType.PDF.getExtension(true) → ".pdf"; * FileType.PDF.getExtension(false) → "pdf"; * </pre> * * @param addExtensionSeparator * {@code true} to add extension separator. * @return the current {@code FileType} extension value (with extension separator). */ public String getExtension(boolean addExtensionSeparator) { if (extension == null) { return ""; } if (addExtensionSeparator) { return '.' + extension.name().toLowerCase(); } else { return extension.name().toLowerCase(); } } // ---------------------------------------------------------------------- // // UTILITY METHODS. // // ---------------------------------------------------------------------- /** * File extensions enumeration. * * @author Denis Colliot (dcolliot@ideia.fr) */ private static enum FileExtension { CSS, CSV, DOC, DOCX, EML, GIF, HTML, JPEG, JPG, JS, MSG, ODS, PDF, PNG, PPS, PPSX, PPT, PPTX, RTF, TIF, TIFF, TXT, URL, XHTML, XLS, XLSX, XML(FileType.XML), // Multiple FileTypes reference this extension. ZIP; private final FileType associatedFileType; private FileExtension() { this(null); } private FileExtension(FileType associatedFileType) { this.associatedFileType = associatedFileType; } public FileType getAssociatedFileType() { if (associatedFileType != null) { return associatedFileType; } try { return FileType.valueOf(name()); } catch (Exception e) { return null; } } } /** * Retrieves the {@code FileType} from the given {@code contentType}. * * @param contentType * The content-type label. * @return the {@code FileType} from the given {@code contentType}, or {@code null} if no known file type can be * parsed. */ public static final FileType fromContentType(final String contentType) { return fromContentType(contentType, null); } /** * Retrieves the {@code FileType} from the given {@code contentType}.<br> * If no known file type can be parsed, returns the given {@code defaultType}. * * @param contentType * The content-type label. * @param defaultType * The default type returned if no known file type can be parsed. * @return the {@code FileType} from the given {@code contentType}, or {@code defaultType} if no known file type can * be parsed. */ public static final FileType fromContentType(final String contentType, final FileType defaultType) { if (ClientUtils.isBlank(contentType)) { return defaultType; } for (final FileType type : values()) { if (type.contentType.equalsIgnoreCase(contentType.trim())) { return type; } } return defaultType; } /** * Retrieves the {@code FileType} from the given {@code extension}. * * <pre> * fromExtension(null) → null * fromExtension("") → null * fromExtension("pdf") → FileType.PDF * fromExtension(".pdf") → FileType.PDF * fromExtension(" .pdf ") → FileType.PDF * fromExtension("toto") → null * </pre> * * @param extension * The file extension. * @return the {@code FileType} from the given {@code extension}, or {@code null} if no known file type can be parsed. */ public static final FileType fromExtension(final String extension) { return fromExtension(extension, null); } /** * Retrieves the {@code FileType} from the given {@code extension}.<br> * If no known file type can be parsed, returns the given {@code defaultType}. * * <pre> * fromExtension(null) → (defaultType) * fromExtension("") → (defaultType) * fromExtension("pdf") → FileType.PDF * fromExtension(".pdf") → FileType.PDF * fromExtension(" .pdf ") → FileType.PDF * fromExtension("toto") → (defaultType) * </pre> * * @param extension * The file extension. * @param defaultType * The default type returned if no known file type can be parsed. * @return the {@code FileType} from the given {@code extension}, or {@code defaultType} if no known file type can be * parsed. */ public static final FileType fromExtension(final String extension, final FileType defaultType) { if (ClientUtils.isBlank(extension)) { return defaultType; } final FileExtension fileExtension; try { fileExtension = FileExtension.valueOf(extension.trim().replaceAll("\\.", "").toUpperCase()); } catch (Exception e) { return defaultType; } return fileExtension.getAssociatedFileType(); } /** * Builds the {@code String} describing given {@code fileTypes} extensions. * If {@code fileTypes} is {@code null} or empty, returns empty String. * * <pre> * asExtensions(false, FileType.PDF, FileType.CSV) → "*.pdf;*.csv" * asExtensions(true, FileType.PDF, FileType.CSV) → "pdf, csv" * </pre> * * @param description * {@code true} to add {@code *.} before each file type extension. * description = {@code false} → {@code *.pdf} * description = {@code true} → {@code pdf} * @param fileTypes * The {@code FileType} instances. * @return the {@code String} describing given {@code fileTypes} extensions. */ public static final String asExtensions(final boolean description, final FileType... fileTypes) { final StringBuilder builder = new StringBuilder(); if (fileTypes == null) { return builder.toString(); } for (final FileType type : fileTypes) { if (type == null || ClientUtils.isBlank(type.getExtension())) { continue; } if (builder.length() > 0) { builder.append(description ? ", " : ';'); } if (!description) { builder.append('*'); } builder.append(type.getExtension(!description)); } return builder.toString(); } /** * Retrieves the {@code FileType} collection corresponding to the given {@code extensions} (separated by {@code ","} * ). * Unknown extensions are ignored. * * <pre> * fromString(" csv, jpeg,pdf, truc, txt") → [FileType.CSV, FileType.JPEG, FileType.PDF, FileType.TXT] * </pre> * * @param extensions * The file extension(s) (separated by {@code ","} if more than one). * @return the {@code FileType} collection corresponding to the given {@code extensions} (never {@code null}). * Returned collection is sorted with enum order. */ public final static List<FileType> fromString(final String extensions) { final List<FileType> fileTypes = new ArrayList<FileType>(); if (ClientUtils.isBlank(extensions)) { return fileTypes; } for (final String extension : extensions.split(",")) { final FileType fileType = fromExtension(ClientUtils.trimToEmpty(extension)); if (fileType != null) { fileTypes.add(fileType); } } Collections.sort(fileTypes); return fileTypes; } /** * Returns if the given {@code filename} extension correspond to {@code type} extension. * * @param type * The file type. * @param filename * The file name. * @return {@code true} if the given {@code filename} extension correspond to {@code type} extension. */ public static boolean isExtension(FileType type, String filename) { if (filename == null || type == null) { return false; } return filename.toLowerCase().endsWith(type.getExtension()); } // --------------------------------------------------------------------------------------------------- // // EXTENSIONS UTILITY METHODS. // // --------------------------------------------------------------------------------------------------- /** * The extension separator character. */ public static final char EXTENSION_SEPARATOR = '.'; /** * The Unix separator character. */ private static final char UNIX_SEPARATOR = '/'; /** * The Windows separator character. */ private static final char WINDOWS_SEPARATOR = '\\'; /** * Gets the extension of a filename. * <p> * This method returns the textual part of the filename after the last dot. There must be no directory separator after * the dot. * * <pre> * foo.txt → "txt" * a/b/c.jpg → "jpg" * a/b.txt/c → "" * a/b/c → "" * </pre> * <p> * The output will be the same irrespective of the machine that the code is running on. * * @param filename * the filename to retrieve the extension of. * @return the extension of the file or an empty string if none exists or <code>null</code> if the filename is * <code>null</code>. */ public static String getExtension(final String filename) { if (filename == null) { return null; } int index = indexOfExtension(filename); if (index == -1) { return ""; } else { return filename.substring(index + 1); } } /** * Returns the index of the last directory separator character. * <p> * This method will handle a file in either Unix or Windows format. The position of the last forward or backslash is * returned. * <p> * The output will be the same irrespective of the machine that the code is running on. * * @param filename * the filename to find the last path separator in, null returns -1 * @return the index of the last separator character, or -1 if there is no such character */ public static int indexOfLastSeparator(String filename) { if (filename == null) { return -1; } int lastUnixPos = filename.lastIndexOf(UNIX_SEPARATOR); int lastWindowsPos = filename.lastIndexOf(WINDOWS_SEPARATOR); return Math.max(lastUnixPos, lastWindowsPos); } /** * Returns the index of the last extension separator character, which is a dot. * <p> * This method also checks that there is no directory separator after the last dot. To do this it uses * {@link #indexOfLastSeparator(String)} which will handle a file in either Unix or Windows format. * <p> * The output will be the same irrespective of the machine that the code is running on. * * @param filename * the filename to find the last path separator in, null returns -1 * @return the index of the last separator character, or -1 if there is no such character */ public static int indexOfExtension(String filename) { if (filename == null) { return -1; } int extensionPos = filename.lastIndexOf(EXTENSION_SEPARATOR); int lastSeparator = indexOfLastSeparator(filename); return lastSeparator > extensionPos ? -1 : extensionPos; } }