@ -82,6 +82,16 @@ namespace MediaBrowser.Common.Implementations.IO
throw new ArgumentNullException ( "target" ) ;
}
if ( string . IsNullOrEmpty ( shortcutPath ) )
{
throw new ArgumentNullException ( "shortcutPath" ) ;
}
if ( string . IsNullOrEmpty ( target ) )
{
throw new ArgumentNullException ( "target" ) ;
}
File . WriteAllText ( shortcutPath , target ) ;
}
@ -92,6 +102,11 @@ namespace MediaBrowser.Common.Implementations.IO
/// <returns>FileSystemInfo.</returns>
public FileSystemInfo GetFileSystemInfo ( string path )
{
if ( string . IsNullOrEmpty ( path ) )
{
throw new ArgumentNullException ( "path" ) ;
}
// Take a guess to try and avoid two file system hits, but we'll double-check by calling Exists
if ( Path . HasExtension ( path ) )
{
@ -172,7 +187,6 @@ namespace MediaBrowser.Common.Implementations.IO
/// Gets the creation time UTC.
/// </summary>
/// <param name="info">The info.</param>
/// <param name="logger">The logger.</param>
/// <returns>DateTime.</returns>
public DateTime GetLastWriteTimeUtc ( FileSystemInfo info )
{
@ -224,6 +238,16 @@ namespace MediaBrowser.Common.Implementations.IO
/// <param name="file2">The file2.</param>
public void SwapFiles ( string file1 , string file2 )
{
if ( string . IsNullOrEmpty ( file1 ) )
{
throw new ArgumentNullException ( "file1" ) ;
}
if ( string . IsNullOrEmpty ( file2 ) )
{
throw new ArgumentNullException ( "file2" ) ;
}
var temp1 = Path . GetTempFileName ( ) ;
var temp2 = Path . GetTempFileName ( ) ;
@ -247,6 +271,11 @@ namespace MediaBrowser.Common.Implementations.IO
/// <param name="path">The path.</param>
private void RemoveHiddenAttribute ( string path )
{
if ( string . IsNullOrEmpty ( path ) )
{
throw new ArgumentNullException ( "path" ) ;
}
var currentFile = new FileInfo ( path ) ;
// This will fail if the file is hidden
@ -258,127 +287,52 @@ namespace MediaBrowser.Common.Implementations.IO
}
}
}
}
/// <summary>
/// Adapted from http://stackoverflow.com/questions/309495/windows-shortcut-lnk-parser-in-java
/// </summary>
internal class WindowsShortcut
{
public bool IsDirectory { get ; private set ; }
public bool IsLocal { get ; private set ; }
public string ResolvedPath { get ; private set ; }
public WindowsShortcut ( string file )
public bool ContainsSubPath ( string parentPath , string path )
{
ParseLink ( File . ReadAllBytes ( file ) , Encoding . UTF8 ) ;
}
private static bool isMagicPresent ( byte [ ] link )
{
const int magic = 0x0000004C ;
const int magic_offset = 0x00 ;
return link . Length > = 32 & & bytesToDword ( link , magic_offset ) = = magic ;
}
/ * *
* Gobbles up link data by parsing it and storing info in member fields
* @param link all the bytes from the . lnk file
* /
private void ParseLink ( byte [ ] link , Encoding encoding )
{
if ( ! isMagicPresent ( link ) )
throw new IOException ( "Invalid shortcut; magic is missing" , 0 ) ;
// get the flags byte
byte flags = link [ 0x14 ] ;
// get the file attributes byte
const int file_atts_offset = 0x18 ;
byte file_atts = link [ file_atts_offset ] ;
byte is_dir_mask = ( byte ) 0x10 ;
if ( ( file_atts & is_dir_mask ) > 0 )
{
IsDirectory = true ;
}
else
if ( string . IsNullOrEmpty ( parentPath ) )
{
IsDirectory = false ;
throw new ArgumentNullException ( "parentPath" ) ;
}
// if the shell settings are present, skip them
const int shell_offset = 0x4c ;
const byte has_shell_mask = ( byte ) 0x01 ;
int shell_len = 0 ;
if ( ( flags & has_shell_mask ) > 0 )
if ( string . IsNullOrEmpty ( path ) )
{
// the plus 2 accounts for the length marker itself
shell_len = bytesToWord ( link , shell_offset ) + 2 ;
throw new ArgumentNullException ( "path" ) ;
}
return path . IndexOf ( parentPath . TrimEnd ( Path . DirectorySeparatorChar ) + Path . DirectorySeparatorChar , StringComparison . OrdinalIgnoreCase ) ! = - 1 ;
}
// get to the file settings
int file_start = 0x4c + shell_len ;
const int file_location_info_flag_offset_offset = 0x08 ;
int file_location_info_flag = link [ file_start + file_location_info_flag_offset_offset ] ;
IsLocal = ( file_location_info_flag & 2 ) = = 0 ;
// get the local volume and local system values
//final int localVolumeTable_offset_offset = 0x0C;
const int basename_offset_offset = 0x10 ;
const int networkVolumeTable_offset_offset = 0x14 ;
const int finalname_offset_offset = 0x18 ;
int finalname_offset = link [ file_start + finalname_offset_offset ] + file_start ;
String finalname = getNullDelimitedString ( link , finalname_offset , encoding ) ;
if ( IsLocal )
public bool IsRootPath ( string path )
{
if ( string . IsNullOrEmpty ( path ) )
{
int basename_offset = link [ file_start + basename_offset_offset ] + file_start ;
String basename = getNullDelimitedString ( link , basename_offset , encoding ) ;
ResolvedPath = basename + finalname ;
throw new ArgumentNullException ( "path" ) ;
}
else
var parent = Path . GetDirectoryName ( path ) ;
if ( ! string . IsNullOrEmpty ( parent ) )
{
int networkVolumeTable_offset = link [ file_start + networkVolumeTable_offset_offset ] + file_start ;
int shareName_offset_offset = 0x08 ;
int shareName_offset = link [ networkVolumeTable_offset + shareName_offset_offset ]
+ networkVolumeTable_offset ;
String shareName = getNullDelimitedString ( link , shareName_offset , encoding ) ;
ResolvedPath = shareName + "\\" + finalname ;
return false ;
}
return true ;
}
p rivate static string getNullDelimitedString ( byte [ ] bytes , int off , Encoding encoding )
public string NormalizePath ( string path )
{
int len = 0 ;
// count bytes until the null character (0)
while ( true )
if ( string . IsNullOrEmpty ( path ) )
{
if ( bytes [ off + len ] = = 0 )
{
break ;
}
len + + ;
throw new ArgumentNullException ( "path" ) ;
}
return encoding . GetString ( bytes , off , len ) ;
}
/ *
* convert two bytes into a short note , this is little endian because it ' s
* for an Intel only OS .
* /
private static int bytesToWord ( byte [ ] bytes , int off )
{
return ( ( bytes [ off + 1 ] & 0xff ) < < 8 ) | ( bytes [ off ] & 0xff ) ;
}
if ( path . EndsWith ( ":\\" , StringComparison . OrdinalIgnoreCase ) )
{
return path ;
}
private static int bytesToDword ( byte [ ] bytes , int off )
{
return ( bytesToWord ( bytes , off + 2 ) < < 16 ) | bytesToWord ( bytes , off ) ;
return path . TrimEnd ( Path . DirectorySeparatorChar ) ;
}
}
}