/* * DBeaver - Universal Database Manager * Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jkiss.dbeaver.utils; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.app.DBPPlatform; import org.jkiss.dbeaver.model.data.DBDContent; import org.jkiss.dbeaver.model.data.DBDContentCached; import org.jkiss.dbeaver.model.data.DBDContentStorage; import org.jkiss.dbeaver.model.exec.DBCException; import org.jkiss.dbeaver.model.messages.ModelMessages; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import org.jkiss.utils.ArrayUtils; import org.jkiss.utils.CommonUtils; import org.jkiss.utils.IOUtils; import java.io.*; import java.net.URI; import java.text.MessageFormat; import java.util.Locale; /** * Content manipulation utilities */ public class ContentUtils { static final int STREAM_COPY_BUFFER_SIZE = 10000; private static final String LOB_DIR = ".lob"; //$NON-NLS-1$ private static final Log log = Log.getLog(ContentUtils.class); static { GeneralUtils.BOM_MAP.put(GeneralUtils.DEFAULT_ENCODING, new byte[] {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF} ); GeneralUtils.BOM_MAP.put("UTF-16", new byte[] {(byte) 0xFE, (byte) 0xFF} ); GeneralUtils.BOM_MAP.put("UTF-16BE", new byte[] {(byte) 0xFE, (byte) 0xFF} ); GeneralUtils.BOM_MAP.put("UTF-16LE", new byte[] {(byte) 0xFF, (byte) 0xFE} ); GeneralUtils.BOM_MAP.put("UTF-32", new byte[] { 0x0, 0x0, (byte) 0xFE, (byte) 0xFF} ); GeneralUtils.BOM_MAP.put("UTF-32BE", new byte[] { 0x0, 0x0, (byte) 0xFE, (byte) 0xFF} ); GeneralUtils.BOM_MAP.put("UTF-32LE", new byte[] { (byte) 0xFE, (byte) 0xFF, 0x0, 0x0} ); } public static File getLobFolder(DBRProgressMonitor monitor, DBPPlatform application) throws IOException { return application.getTempFolder(monitor, LOB_DIR); } public static File createTempContentFile(DBRProgressMonitor monitor, DBPPlatform application, String fileName) throws IOException { return makeTempFile( monitor, getLobFolder(monitor, application), fileName, "data"); /* try { String charset = application.getPreferenceStore().getString(ModelPreferences.CONTENT_HEX_ENCODING); file.setCharset(charset, monitor.getNestedMonitor()); } catch (CoreException e) { log.error("Can't set file charset", e); } return file; */ } public static File makeTempFile(DBRProgressMonitor monitor, File folder, String name, String extension) throws IOException { name = CommonUtils.escapeFileName(name); File tempFile = new File(folder, name + "-" + System.currentTimeMillis() + "." + extension); //$NON-NLS-1$ //$NON-NLS-2$ if (!tempFile.createNewFile()){ throw new IOException(MessageFormat.format(ModelMessages.DBeaverCore_error_can_create_temp_file, tempFile.getAbsolutePath(), folder.getAbsoluteFile())); } return tempFile; } public static void deleteTempFile(DBRProgressMonitor monitor, IFile file) { try { file.delete(true, false, monitor.getNestedMonitor()); } catch (CoreException e) { log.warn("Can't delete temporary file '" + file.getFullPath().toString() + "'", e); } } public static void saveContentToFile(InputStream contentStream, File file, DBRProgressMonitor monitor) throws IOException { try (OutputStream os = new FileOutputStream(file)) { copyStreams(contentStream, file.length(), os, monitor); } // Check for cancel if (monitor.isCanceled()) { // Delete output file if (!file.delete()) { log.warn("Can't delete incomplete file '" + file.getAbsolutePath() + "'"); } } } public static void saveContentToFile(Reader contentReader, File file, String charset, DBRProgressMonitor monitor) throws IOException { try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), charset)) { copyStreams(contentReader, file.length(), writer, monitor); } // Check for cancel if (monitor.isCanceled()) { // Delete output file if (!file.delete()) { log.warn("Can't delete incomplete file '" + file.getAbsolutePath() + "'"); } } } public static void copyStreams( InputStream inputStream, long contentLength, OutputStream outputStream, DBRProgressMonitor monitor) throws IOException { monitor.beginTask("Copy binary content", contentLength < 0 ? STREAM_COPY_BUFFER_SIZE : (int) contentLength); try { byte[] buffer = new byte[STREAM_COPY_BUFFER_SIZE]; for (;;) { if (monitor.isCanceled()) { break; } int count = inputStream.read(buffer); if (count <= 0) { break; } outputStream.write(buffer, 0, count); monitor.worked(STREAM_COPY_BUFFER_SIZE); } } finally { monitor.done(); } } public static void copyStreams( Reader reader, long contentLength, Writer writer, DBRProgressMonitor monitor) throws IOException { monitor.beginTask("Copy character content", contentLength < 0 ? STREAM_COPY_BUFFER_SIZE : (int) contentLength); try { char[] buffer = new char[STREAM_COPY_BUFFER_SIZE]; for (;;) { if (monitor.isCanceled()) { break; } int count = reader.read(buffer); if (count <= 0) { break; } writer.write(buffer, 0, count); monitor.worked(STREAM_COPY_BUFFER_SIZE); } } finally { monitor.done(); } } public static long calculateContentLength( File file, String charset) throws IOException { return calculateContentLength( new FileInputStream(file), charset); } public static long calculateContentLength( InputStream stream, String charset) throws IOException { return calculateContentLength( new InputStreamReader( stream, charset)); } public static long calculateContentLength( Reader reader) throws IOException { try { long length = 0; char[] buffer = new char[STREAM_COPY_BUFFER_SIZE]; for (;;) { int count = reader.read(buffer); if (count <= 0) { break; } length += count; } return length; } finally { reader.close(); } } public static void close(Closeable closeable) { try { closeable.close(); } catch (IOException e) { log.warn("Error closing stream", e); } } public static void copyStreamToFile(DBRProgressMonitor monitor, InputStream inputStream, long contentLength, IFile localFile) throws IOException { //localFile.appendContents(inputStream, true, false, monitor.getNestedMonitor()); File file = localFile.getLocation().toFile(); try { try (OutputStream outputStream = new FileOutputStream(file)) { ContentUtils.copyStreams(inputStream, contentLength, outputStream, monitor); } } finally { inputStream.close(); } syncFile(monitor, localFile); } public static void copyReaderToFile(DBRProgressMonitor monitor, Reader reader, long contentLength, String charset, IFile localFile) throws IOException { try { if (charset == null) { charset = localFile.getCharset(); } else { localFile.setCharset(charset, monitor.getNestedMonitor()); } } catch (CoreException e) { log.warn("Can't set content charset", e); } File file = localFile.getLocation().toFile(); try { try (OutputStream outputStream = new FileOutputStream(file)) { Writer writer = new OutputStreamWriter(outputStream, charset == null ? GeneralUtils.DEFAULT_ENCODING : charset); ContentUtils.copyStreams(reader, contentLength, writer, monitor); writer.flush(); } } finally { reader.close(); } syncFile(monitor, localFile); } public static void syncFile(DBRProgressMonitor monitor, IResource localFile) { // Sync file with contents try { localFile.refreshLocal(IFile.DEPTH_ZERO, monitor.getNestedMonitor()); } catch (CoreException e) { log.warn("Can't synchronize file '" + localFile + "' with contents", e); } } public static IFile getUniqueFile(IFolder folder, String fileName, String fileExt) { IFile file = folder.getFile(fileName + "." + fileExt); int index = 1; while (file.exists()) { file = folder.getFile(fileName + "-" + index + "." + fileExt); index++; } return file; } public static String readFileToString(File file) throws IOException { try (InputStream fileStream = new FileInputStream(file)) { UnicodeReader unicodeReader = new UnicodeReader(fileStream, GeneralUtils.UTF8_ENCODING); StringBuilder result = new StringBuilder((int) file.length()); char[] buffer = new char[4000]; for (;;) { int count = unicodeReader.read(buffer); if (count <= 0) { break; } result.append(buffer, 0, count); } return result.toString(); } } public static String readToString(InputStream is, String charset) throws IOException { return IOUtils.readToString(new UnicodeReader(is, charset)); } @Nullable public static IFile convertPathToWorkspaceFile(IPath path) { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); IFile file = root.getFileForLocation(path); if (file != null) { return file; } // Probably we have a path to some linked resource IPath folderPath = path.removeLastSegments(1); URI folderURI = folderPath.toFile().toURI(); IContainer[] containers = root.findContainersForLocationURI(folderURI); if (!ArrayUtils.isEmpty(containers)) { IContainer container = containers[0]; file = container.getFile(path.removeFirstSegments(path.segmentCount() - 1)); } return file; } @Nullable public static IPath convertPathToWorkspacePath(IPath path) { IFile wFile = convertPathToWorkspaceFile(path); return wFile == null ? null : wFile.getFullPath(); } public static boolean isTextContent(DBDContent content) { String contentType = content == null ? null : content.getContentType(); return contentType != null && contentType.toLowerCase(Locale.ENGLISH).startsWith("text"); } public static boolean isTextValue(Object value) { if (value == null) { return false; } if (value instanceof CharSequence) { return true; } if (value instanceof byte[]) { for (byte b : (byte[])value) { if (!Character.isLetterOrDigit(b) && !Character.isSpaceChar(b) && !Character.isISOControl(b)) { return false; } } } return true; } public static boolean isXML(DBDContent content) { return MimeTypes.TEXT_XML.equalsIgnoreCase(content.getContentType()); } public static boolean isJSON(DBDContent content) { return MimeTypes.TEXT_JSON.equalsIgnoreCase(content.getContentType()); } @NotNull public static String getContentStringValue(@NotNull DBRProgressMonitor monitor, @NotNull DBDContent object) throws DBCException { DBDContentStorage data = object.getContents(monitor); if (data != null) { if (data instanceof DBDContentCached) { Object cachedValue = ((DBDContentCached) data).getCachedValue(); if (cachedValue instanceof String) { return (String) cachedValue; } } try { Reader contentReader = data.getContentReader(); if (contentReader != null) { try { StringWriter buf = new StringWriter(); ContentUtils.copyStreams(contentReader, object.getContentLength(), buf, monitor); return buf.toString(); } finally { IOUtils.close(contentReader); } } } catch (IOException e) { log.debug("Can't extract string from content", e); } } return object.toString(); } @NotNull public static byte[] getContentBinaryValue(@NotNull DBRProgressMonitor monitor, @NotNull DBDContent object) throws DBCException { DBDContentStorage data = object.getContents(monitor); if (data != null) { if (data instanceof DBDContentCached) { Object cachedValue = ((DBDContentCached) data).getCachedValue(); if (cachedValue instanceof byte[]) { return (byte[]) cachedValue; } } try { InputStream contentStream = data.getContentStream(); if (contentStream != null) { try { ByteArrayOutputStream buf = new ByteArrayOutputStream(); ContentUtils.copyStreams(contentStream, object.getContentLength(), buf, monitor); return buf.toByteArray(); } finally { IOUtils.close(contentStream); } } } catch (IOException e) { log.debug("Can't extract string from content", e); } } return null; } public static void deleteTempFile(File tempFile) { if (!tempFile.delete()) { log.warn("Can't delete temp file '" + tempFile.getAbsolutePath() + "'"); } } public static boolean deleteFileRecursive(File file) { if (file.isDirectory()) { File[] files = file.listFiles(); if (files != null) { for (File ch : files) { if (!deleteFileRecursive(ch)) { return false; } } } } return file.delete(); } }