mirror of
https://github.com/aelurum/AssetStudio.git
synced 2025-05-25 05:40:21 -04:00
[GUI] Add support for .lnk files via Drag&Drop. Close #13
This commit is contained in:
parent
51d259464b
commit
632e5f8d08
@ -82,7 +82,7 @@ namespace AssetStudio
|
|||||||
MergeSplitAssets(fullPath, true);
|
MergeSplitAssets(fullPath, true);
|
||||||
fileList.AddRange(Directory.GetFiles(fullPath, "*.*", SearchOption.AllDirectories));
|
fileList.AddRange(Directory.GetFiles(fullPath, "*.*", SearchOption.AllDirectories));
|
||||||
}
|
}
|
||||||
else
|
else if (File.Exists(fullPath))
|
||||||
{
|
{
|
||||||
parentPath = Path.GetDirectoryName(fullPath);
|
parentPath = Path.GetDirectoryName(fullPath);
|
||||||
fileList.Add(fullPath);
|
fileList.Add(fullPath);
|
||||||
|
@ -35,10 +35,13 @@ namespace AssetStudio
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ReadStringToNull(this BinaryReader reader, int maxLength = 32767)
|
public static string ReadStringToNull(this BinaryReader reader, int maxLength = 32767, Encoding encoding = null)
|
||||||
{
|
{
|
||||||
|
if (encoding?.CodePage == 1200) //Unicode (UTF-16LE)
|
||||||
|
return reader.ReadUnicodeStringToNull(maxLength * 2);
|
||||||
|
|
||||||
var bytes = new List<byte>();
|
var bytes = new List<byte>();
|
||||||
int count = 0;
|
var count = 0;
|
||||||
while (reader.BaseStream.Position != reader.BaseStream.Length && count < maxLength)
|
while (reader.BaseStream.Position != reader.BaseStream.Length && count < maxLength)
|
||||||
{
|
{
|
||||||
var b = reader.ReadByte();
|
var b = reader.ReadByte();
|
||||||
@ -49,7 +52,24 @@ namespace AssetStudio
|
|||||||
bytes.Add(b);
|
bytes.Add(b);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
return Encoding.UTF8.GetString(bytes.ToArray());
|
return encoding?.GetString(bytes.ToArray()) ?? Encoding.UTF8.GetString(bytes.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ReadUnicodeStringToNull(this BinaryReader reader, int maxLength)
|
||||||
|
{
|
||||||
|
var bytes = new List<byte>();
|
||||||
|
var count = 0;
|
||||||
|
while (reader.BaseStream.Position != reader.BaseStream.Length && count < maxLength)
|
||||||
|
{
|
||||||
|
var b = reader.ReadBytes(2);
|
||||||
|
if (b.Length < 2 || (b[0] == 0 && b[1] == 0))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytes.AddRange(b);
|
||||||
|
count += 2;
|
||||||
|
}
|
||||||
|
return Encoding.Unicode.GetString(bytes.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Quaternion ReadQuaternion(this BinaryReader reader)
|
public static Quaternion ReadQuaternion(this BinaryReader reader)
|
||||||
|
@ -146,14 +146,25 @@ namespace AssetStudioGUI
|
|||||||
private async void AssetStudioGUIForm_DragDrop(object sender, DragEventArgs e)
|
private async void AssetStudioGUIForm_DragDrop(object sender, DragEventArgs e)
|
||||||
{
|
{
|
||||||
var paths = (string[])e.Data.GetData(DataFormats.FileDrop);
|
var paths = (string[])e.Data.GetData(DataFormats.FileDrop);
|
||||||
if (paths.Length > 0)
|
if (paths.Length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ResetForm();
|
||||||
|
for (var i = 0; i < paths.Length; i++)
|
||||||
{
|
{
|
||||||
ResetForm();
|
if (paths[i].ToLower().EndsWith(".lnk"))
|
||||||
assetsManager.SpecifyUnityVersion = specifyUnityVersion.Text;
|
{
|
||||||
await Task.Run(() => assetsManager.LoadFilesAndFolders(out openDirectoryBackup, paths));
|
var targetPath = LnkReader.GetLnkTarget(paths[i]);
|
||||||
saveDirectoryBackup = openDirectoryBackup;
|
if (!string.IsNullOrEmpty(targetPath))
|
||||||
BuildAssetStructures();
|
{
|
||||||
|
paths[i] = targetPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
assetsManager.SpecifyUnityVersion = specifyUnityVersion.Text;
|
||||||
|
await Task.Run(() => assetsManager.LoadFilesAndFolders(out openDirectoryBackup, paths));
|
||||||
|
saveDirectoryBackup = openDirectoryBackup;
|
||||||
|
BuildAssetStructures();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void loadFile_Click(object sender, EventArgs e)
|
private async void loadFile_Click(object sender, EventArgs e)
|
||||||
|
164
AssetStudioGUI/Components/LnkReader.cs
Normal file
164
AssetStudioGUI/Components/LnkReader.cs
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
// Shortcut (.lnk) file reader
|
||||||
|
// by aelurum
|
||||||
|
// Based on https://github.com/libyal/liblnk/blob/main/documentation/Windows%20Shortcut%20File%20(LNK)%20format.asciidoc
|
||||||
|
|
||||||
|
using AssetStudio;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace AssetStudioGUI
|
||||||
|
{
|
||||||
|
public static class LnkReader
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
private enum LnkDataFlags
|
||||||
|
{
|
||||||
|
//The LNK file contains a link target identifier
|
||||||
|
HasTargetIDList = 0x00000001,
|
||||||
|
//The LNK file contains location information
|
||||||
|
HasLinkInfo = 0x00000002,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
private enum LnkLocFlags
|
||||||
|
{
|
||||||
|
//The linked file is on a volume
|
||||||
|
//If set the volume information and the local path contain data
|
||||||
|
VolumeIDAndLocalBasePath = 0x0001,
|
||||||
|
//The linked file is on a network share
|
||||||
|
//If set the network share information and common path contain data
|
||||||
|
CommonNetworkRelativeLinkAndPathSuffix = 0x0002
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
private enum PathTypeFlags
|
||||||
|
{
|
||||||
|
IsUnicodeLocalPath = 0x01,
|
||||||
|
IsUnicodeNetShareName = 0x02,
|
||||||
|
IsUnicodeCommonPath = 0x04
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetLnkTarget(string filePath)
|
||||||
|
{
|
||||||
|
var targetPath = string.Empty;
|
||||||
|
var pathType = (PathTypeFlags)0;
|
||||||
|
Encoding sysEncoding;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sysEncoding = GetSysEncoding();
|
||||||
|
Logger.Debug($"System default text encoding: {sysEncoding.CodePage}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Error("Text encoding error", ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var reader = new FileReader(filePath))
|
||||||
|
{
|
||||||
|
reader.Endian = EndianType.LittleEndian;
|
||||||
|
|
||||||
|
var headerSize = reader.ReadUInt32(); //76 bytes
|
||||||
|
reader.Position = 20; //skip LNK class identifier (GUID)
|
||||||
|
var dataFlags = (LnkDataFlags)reader.ReadUInt32();
|
||||||
|
if ((dataFlags & LnkDataFlags.HasLinkInfo) == 0)
|
||||||
|
{
|
||||||
|
Logger.Warning("Unsupported type of .lnk file. Link info was not found.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
reader.Position = headerSize;
|
||||||
|
|
||||||
|
//Skip the shell item ID list
|
||||||
|
if ((dataFlags & LnkDataFlags.HasTargetIDList) != 0)
|
||||||
|
{
|
||||||
|
var itemIDListSize = reader.ReadUInt16();
|
||||||
|
reader.Position += itemIDListSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
//The offsets is relative to the start of the location information block
|
||||||
|
var locInfoPos = reader.Position;
|
||||||
|
var locInfoFullSize = reader.ReadUInt32();
|
||||||
|
if (locInfoFullSize == 0)
|
||||||
|
{
|
||||||
|
Logger.Warning("Unsupported type of .lnk file. Link info was not found.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var locInfoHeaderSize = reader.ReadUInt32();
|
||||||
|
var locFlags = (LnkLocFlags)reader.ReadUInt32();
|
||||||
|
//Offset to the volume information block
|
||||||
|
var offsetVolumeInfo = reader.ReadUInt32();
|
||||||
|
//Offset to the ANSI local path
|
||||||
|
var offsetLocalPath = reader.ReadUInt32();
|
||||||
|
//Offset to the network share information block
|
||||||
|
var offsetNetInfo = reader.ReadUInt32();
|
||||||
|
//Offset to the ANSI common path. 0 if not available
|
||||||
|
var offsetCommonPath = reader.ReadUInt32();
|
||||||
|
if (locInfoHeaderSize > 28)
|
||||||
|
{
|
||||||
|
//Offset to the Unicode local path
|
||||||
|
offsetLocalPath = reader.ReadUInt32();
|
||||||
|
pathType |= PathTypeFlags.IsUnicodeLocalPath;
|
||||||
|
}
|
||||||
|
if (locInfoHeaderSize > 32)
|
||||||
|
{
|
||||||
|
//Offset to the Unicode common path
|
||||||
|
offsetCommonPath = reader.ReadUInt32();
|
||||||
|
pathType |= PathTypeFlags.IsUnicodeCommonPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Read local path, if exist
|
||||||
|
if (offsetLocalPath > 0)
|
||||||
|
{
|
||||||
|
reader.Position = locInfoPos + offsetLocalPath;
|
||||||
|
targetPath = (pathType & PathTypeFlags.IsUnicodeLocalPath) != 0
|
||||||
|
? reader.ReadStringToNull(encoding: Encoding.Unicode)
|
||||||
|
: reader.ReadStringToNull(encoding: sysEncoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Read network path, if exist
|
||||||
|
if (locFlags == LnkLocFlags.CommonNetworkRelativeLinkAndPathSuffix)
|
||||||
|
{
|
||||||
|
reader.Position = locInfoPos + offsetNetInfo;
|
||||||
|
var netInfoSize = reader.ReadUInt32();
|
||||||
|
var netInfoFlags = reader.ReadUInt32();
|
||||||
|
//Offset to the ANSI network share name. The offset is relative to the start of the network share information block
|
||||||
|
var offsetNetShareName = reader.ReadUInt32();
|
||||||
|
if (offsetNetShareName > 20)
|
||||||
|
{
|
||||||
|
reader.Position = locInfoPos + offsetNetInfo + 20;
|
||||||
|
//Offset to the Unicode network share name
|
||||||
|
offsetNetShareName = reader.ReadUInt32();
|
||||||
|
pathType |= PathTypeFlags.IsUnicodeNetShareName;
|
||||||
|
}
|
||||||
|
if (offsetNetShareName > 0)
|
||||||
|
{
|
||||||
|
reader.Position = locInfoPos + offsetNetInfo + offsetNetShareName;
|
||||||
|
targetPath = (pathType & PathTypeFlags.IsUnicodeNetShareName) != 0
|
||||||
|
? reader.ReadStringToNull(encoding: Encoding.Unicode)
|
||||||
|
: reader.ReadStringToNull(encoding: sysEncoding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Read common path, if exist
|
||||||
|
if (offsetCommonPath > 0)
|
||||||
|
{
|
||||||
|
reader.Position = locInfoPos + offsetCommonPath;
|
||||||
|
var commonPath = (pathType & PathTypeFlags.IsUnicodeCommonPath) != 0
|
||||||
|
? reader.ReadStringToNull(encoding: Encoding.Unicode)
|
||||||
|
: reader.ReadStringToNull(encoding: sysEncoding);
|
||||||
|
targetPath = Path.Combine(targetPath, commonPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return targetPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Encoding GetSysEncoding()
|
||||||
|
{
|
||||||
|
#if !NETFRAMEWORK
|
||||||
|
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||||
|
#endif
|
||||||
|
return Encoding.GetEncoding(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user