#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

202 lines
6.7 KiB

// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.IO;
using System.Text;
namespace ICSharpCode.WixBinding
{
/// <summary>
/// Utility class that converts from long filenames to DOS 8.3 filenames based on the
/// rough algorithm outlined here: http://support.microsoft.com/kb/142982/EN-US/
/// apart from using an underscore instead of a '~'.
/// </summary>
public sealed class ShortFileName
{
const int MaximumFileNameWithoutExtensionLength = 8;
/// <summary>
/// The filename length to use when appending "_1" to it.
/// </summary>
const int FileNameWithoutExtensionTruncatedLength = 6;
/// <summary>
/// Maximum short filename extension length including dot.
/// </summary>
const int MaximumFileNameExtensionLength = 4;
/// <summary>
/// Maximum short filename length including extension.
/// </summary>
public const int MaximumFileNameLength = MaximumFileNameWithoutExtensionLength + MaximumFileNameExtensionLength;
/// <summary>
/// Called by Convert to check whether the specified filename exists. If it
/// does then the FileNameExists delegate is called repeatedly until it
/// finds a filename that does not exist.
/// </summary>
public delegate bool NameExists(string name);
ShortFileName()
{
}
/// <summary>
/// Converts a long filename to a short 8.3 filename.
/// </summary>
/// <param name="fileName">The long filename.</param>
/// <returns>The converted 8.3 filename. If the filename includes a
/// starting path then this is stripped from the returned value.</returns>
public static string Convert(string fileName, NameExists getFileNameExists)
{
if (fileName == null) {
return String.Empty;
}
// Remove invalid characters.
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
string extension = Path.GetExtension(fileName);
StringBuilder shortFileName = new StringBuilder();
int length = 0;
foreach (char ch in fileNameWithoutExtension) {
if (IsValidShortFileNameChar(ch)) {
shortFileName.Append(ch);
++length;
}
}
// Get truncated extension.
if (extension.Length > MaximumFileNameExtensionLength) {
extension = extension.Substring(0, MaximumFileNameExtensionLength);
}
// Truncate filename without extension if it is too long.
if (length > MaximumFileNameWithoutExtensionLength) {
shortFileName.Remove(FileNameWithoutExtensionTruncatedLength, length - FileNameWithoutExtensionTruncatedLength);
return GetTruncatedFileName(shortFileName.ToString(), extension, getFileNameExists);
}
// Add extension.
shortFileName.Append(extension);
return shortFileName.ToString().ToUpperInvariant();
}
/// <summary>
/// Converts a long filename to a short 8.3 filename.
/// </summary>
/// <param name="fileName">The long filename</param>
/// <returns>The converted 8.3 filename. If the filename includes a
/// starting path then this is stripped from the returned value.</returns>
public static string Convert(string fileName)
{
return Convert(fileName, FileNameNeverExists);
}
/// <summary>
/// Gets the unique name string by adding a digit until a unique name is
/// produced. The name string itself will be truncated as the number
/// increases in size to make sure the total length of the string is
/// always equal to start.Length + 1.
/// </summary>
/// <param name="start">The string to be used at the start of the </param>
/// <param name="getNameExists">Method called to check that the
/// name does not already exist.</param>
public static string GetUniqueName(string start, NameExists getNameExists)
{
return GetUniqueName(start, String.Empty, String.Empty, getNameExists);
}
/// <summary>
/// Gets the unique name string by adding a digit until a unique name is
/// produced. The name string itself will be truncated as the number
/// increases in size to make sure the total length of the string is
/// always equal to start.Length + numberPrefix.Length + 1 + end.Length.
/// </summary>
/// <param name="start">The string to be used at the start of the </param>
/// <param name="numberPrefix">The string to be prefixed to the number.</param>
/// <param name="end">The string to be added after the number.</param>
/// <param name="getNameExists">Method called to check that the
/// name does not already exist.</param>
public static string GetUniqueName(string start, string numberPrefix, string end, NameExists getNameExists)
{
int count = 0;
string truncatedName;
int divisor = 10;
do {
++count;
int removeCharCount = count / divisor;
if (removeCharCount > 0) {
start = start.Substring(0, start.Length - 1);
divisor *= divisor;
}
truncatedName = String.Concat(start, numberPrefix, count.ToString(), end);
} while (getNameExists(truncatedName));
return truncatedName;
}
/// <summary>
/// Determines whether the specified filename is a long name
/// and should be converted into a short name.
/// </summary>
public static bool IsLongFileName(string fileName)
{
if (fileName == null) {
return false;
}
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
string extension = Path.GetExtension(fileName);
return fileNameWithoutExtension.Length > MaximumFileNameWithoutExtensionLength ||
extension.Length > MaximumFileNameExtensionLength;
}
/// <summary>
/// Truncates the filename start and adds "_N" where N produces a filename that
/// does not exist.
/// </summary>
static string GetTruncatedFileName(string fileNameStart, string extension, NameExists getFileNameExists)
{
return GetUniqueName(fileNameStart.ToUpperInvariant(), "_", extension.ToUpperInvariant(), getFileNameExists);
}
/// <summary>
/// Default delegate that always returns false to the Convert method.
/// </summary>
static bool FileNameNeverExists(string fileName)
{
return false;
}
/// <summary>
/// Returns whether the character is considered a valid character
/// for the starting part of the filename (i.e. not including the extension).
/// </summary>
/// <remarks>
/// We include the period character here to avoid ICE03 invalid filename
/// errors.
///
/// http://msdn.microsoft.com/library/en-us/msi/setup/ice03.asp
/// </remarks>
static bool IsValidShortFileNameChar(char ch)
{
switch (ch) {
case ' ':
case '[':
case ']':
case ';':
case '=':
case ',':
case '.':
return false;
}
return true;
}
}
}