From 3ba25d4bbfa517ec14e9e55d61facd6e8eea4b88 Mon Sep 17 00:00:00 2001 From: ShadelessFox Date: Mon, 30 Aug 2021 11:42:43 +0300 Subject: [PATCH] #12933 Resolve target file from Windows shortcut (.lnk) and open editor --- .../META-INF/MANIFEST.MF | 1 + plugins/org.jkiss.dbeaver.core/plugin.xml | 11 +++ .../shortcuts/ShortcutsHandlerImpl.java | 99 +++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 plugins/org.jkiss.dbeaver.core/src/org/jkiss/dbeaver/ui/resources/shortcuts/ShortcutsHandlerImpl.java diff --git a/plugins/org.jkiss.dbeaver.core/META-INF/MANIFEST.MF b/plugins/org.jkiss.dbeaver.core/META-INF/MANIFEST.MF index 183e9d0c01..dc75bf8d41 100644 --- a/plugins/org.jkiss.dbeaver.core/META-INF/MANIFEST.MF +++ b/plugins/org.jkiss.dbeaver.core/META-INF/MANIFEST.MF @@ -22,6 +22,7 @@ Export-Package: org.jkiss.dbeaver, org.jkiss.dbeaver.ui.preferences, org.jkiss.dbeaver.ui.resources, org.jkiss.dbeaver.ui.resources.bookmarks, + org.jkiss.dbeaver.ui.resources.shortcuts, org.jkiss.dbeaver.ui.views, org.jkiss.dbeaver.ui.views.process, org.jkiss.dbeaver.ui.views.qm diff --git a/plugins/org.jkiss.dbeaver.core/plugin.xml b/plugins/org.jkiss.dbeaver.core/plugin.xml index 423c406eee..ea7f630b35 100644 --- a/plugins/org.jkiss.dbeaver.core/plugin.xml +++ b/plugins/org.jkiss.dbeaver.core/plugin.xml @@ -29,6 +29,14 @@ name="%content-type.org.jkiss.dbeaver.bookmark.name" priority="normal" describer="org.jkiss.dbeaver.ui.resources.bookmarks.BookmarkContentTypeDescriber"/> + + + + + + + + @@ -1131,6 +1139,9 @@ + + + diff --git a/plugins/org.jkiss.dbeaver.core/src/org/jkiss/dbeaver/ui/resources/shortcuts/ShortcutsHandlerImpl.java b/plugins/org.jkiss.dbeaver.core/src/org/jkiss/dbeaver/ui/resources/shortcuts/ShortcutsHandlerImpl.java new file mode 100644 index 0000000000..a2e47e7e14 --- /dev/null +++ b/plugins/org.jkiss.dbeaver.core/src/org/jkiss/dbeaver/ui/resources/shortcuts/ShortcutsHandlerImpl.java @@ -0,0 +1,99 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2021 DBeaver Corp and others + * + * 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.ui.resources.shortcuts; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.jkiss.code.NotNull; +import org.jkiss.dbeaver.DBException; +import org.jkiss.dbeaver.ui.UIUtils; +import org.jkiss.dbeaver.ui.editors.EditorUtils; +import org.jkiss.dbeaver.ui.resources.AbstractResourceHandler; + +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.file.Files; + +/** + * Windows Shell Link (.lnk) handler + */ +public class ShortcutsHandlerImpl extends AbstractResourceHandler { + @Override + public void openResource(@NotNull IResource resource) throws CoreException, DBException { + try { + final File path = resource.getLocation().toFile(); + final File resolved = resolve(path); + + EditorUtils.openExternalFileEditor(resolved, UIUtils.getActiveWorkbenchWindow()); + } catch (IOException e) { + throw new DBException("Error resolving shell link path", e); + } + } + + @Override + public int getFeatures(IResource resource) { + if (resource instanceof IFile) { + return FEATURE_OPEN | FEATURE_DELETE | FEATURE_RENAME; + } + return super.getFeatures(resource); + } + + /** + * Resolves absolute path from given Shell Link file. + *

+ * See Shell Link (.LNK) Binary File Format + */ + @NotNull + private static File resolve(@NotNull File shellLinkFile) throws IOException { + final ByteBuffer buf = ByteBuffer + .wrap(Files.readAllBytes(shellLinkFile.toPath())) + .order(ByteOrder.LITTLE_ENDIAN); + + if ((buf.getInt(20) & 1) > 0) { + // Check the flags, if LinkTargetIDList is present, then seek to sizeof(ShellLinkHeader) + sizeof(LinkTargetIDList) + buf.position(buf.getInt(0) + buf.getShort(76) + 2); + } else { + // Otherwise, seek past linkFlags + buf.position(24); + } + + // There's no better way to determine whether path is stored in unicode format + final boolean unicode = buf.getInt(buf.position() + 4) >= 36; + final StringBuilder path = new StringBuilder(); + + // Seek past fields we're not interested in (if `unicode` there are three additional fields) + buf.position(buf.position() + buf.getInt(buf.position() + (unicode ? 28 : 16))); + + while (true) { + final char ch = unicode ? buf.getChar() : (char) buf.get(); + if (ch == 0) { + // Hit string terminator, stop + break; + } + path.append(ch); + if (path.length() > 260) { + // Maximum path length on Windows is 260 characters. Let's pretend no one uses NTFS' `\\?\` prefix + break; + } + } + + return new File(path.toString()); + } +} -- GitLab