-
-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
adding the ability to de-serialize PartAtom of Revit files
- Loading branch information
Showing
20 changed files
with
677 additions
and
105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Globalization; | ||
using System.Linq; | ||
using System.Text.RegularExpressions; | ||
|
||
namespace CodeCave.Revit.Toolkit | ||
{ | ||
public static class RevitFileInfoExtensions | ||
{ | ||
#region Constants | ||
|
||
/// <summary> | ||
/// List of known Revit file properties. | ||
/// </summary> | ||
internal struct KnownRevitInfoProps | ||
{ | ||
public const string USERNAME = "Username"; | ||
public const string CENTRAL_MODEL_PATH = "Central Model Path"; | ||
public const string REVIT_BUILD = "Revit Build"; | ||
public const string LAST_SAVE_PATH = "Last Save Path"; | ||
public const string OPEN_WORKSET_DEFAULT = "Open Workset Default"; | ||
public const string PROJECT_SPARK_FILE = "Project Spark File"; | ||
public const string CENTRAL_MODEL_IDENTITY = "Central Model Identity"; | ||
public const string LOCALE = "Locale when saved"; | ||
public const string LOCAL_SAVED_TO_CENTRAL = "All Local Changes Saved To Central"; | ||
public const string CENTRAL_MODEL_VERSION = "Central model's version number corresponding to the last reload latest"; | ||
public const string CENTRAL_MODEL_GUID = "Central model's episode GUID corresponding to the last reload latest"; | ||
public const string UNIQUE_DOCUMENT_GUID = "Unique Document GUID"; | ||
public const string UNIQUE_DOCUMENT_INCREMENT = "Unique Document Increments"; | ||
} | ||
|
||
private static readonly Regex versionExtractor = | ||
new Regex(@"(?<vendor>\w*) (?<software>(\w|\s)*) (?<version>\d{4}) \(Build\: (?<build>\d*)_(?<revision>\d*)(\((?<arch>\w*)\))?\)", | ||
RegexOptions.Compiled | | ||
RegexOptions.IgnoreCase | | ||
RegexOptions.CultureInvariant); | ||
|
||
#endregion | ||
|
||
#region Methods | ||
|
||
/// <summary> | ||
/// Parses the username. | ||
/// </summary> | ||
/// <param name="revitFileInfo">The revit file information.</param> | ||
/// <param name="properties">The properties.</param> | ||
/// <exception cref="T:System.ArgumentNullException">properties</exception> | ||
public static void ParseUsername(this RevitFileInfo revitFileInfo, Dictionary<string, string> properties) | ||
{ | ||
if (properties == null) | ||
throw new ArgumentNullException(nameof(properties)); | ||
|
||
// Parse username field | ||
if (!properties.ContainsKey(KnownRevitInfoProps.USERNAME)) | ||
return; | ||
|
||
revitFileInfo.Username = properties[KnownRevitInfoProps.USERNAME]; | ||
} | ||
|
||
/// <summary> | ||
/// Parses the revit. | ||
/// </summary> | ||
/// <param name="revitFileInfo">The revit file information.</param> | ||
/// <param name="properties">The properties.</param> | ||
/// <exception cref="T:System.ArgumentNullException">properties</exception> | ||
public static void ParseRevit(this RevitFileInfo revitFileInfo, Dictionary<string, string> properties) | ||
{ | ||
if (properties == null) throw new ArgumentNullException(nameof(properties)); | ||
|
||
// Parse Revit Build string | ||
if (!properties.ContainsKey(KnownRevitInfoProps.REVIT_BUILD)) | ||
return; | ||
|
||
var versionObj = versionExtractor.Match(properties[KnownRevitInfoProps.REVIT_BUILD]); | ||
if (!versionObj.Success) | ||
return; | ||
|
||
revitFileInfo.Vendor = versionObj?.Groups["vendor"]?.Value; | ||
revitFileInfo.Name = versionObj?.Groups["software"]?.Value; | ||
revitFileInfo.Is64Bit = versionObj.Groups["arch"]?.Value?.Contains("x64") ?? false; | ||
|
||
var versionString = string.Format("{0}.{1}.{2}", | ||
versionObj.Groups["version"].Value, | ||
versionObj.Groups["build"].Value, | ||
versionObj.Groups["revision"].Value); | ||
revitFileInfo.Version = new Version(versionString); | ||
} | ||
|
||
/// <summary> | ||
/// Parses the locale. | ||
/// </summary> | ||
/// <param name="revitFileInfo">The revit file information.</param> | ||
/// <param name="properties">The properties.</param> | ||
/// <exception cref="T:System.ArgumentNullException">properties</exception> | ||
public static void ParseLocale(this RevitFileInfo revitFileInfo, Dictionary<string, string> properties) | ||
{ | ||
if (properties == null) throw new ArgumentNullException(nameof(properties)); | ||
|
||
// Parse last saved locale | ||
if (!properties.ContainsKey(KnownRevitInfoProps.LOCALE)) | ||
return; | ||
|
||
var localeRaw = properties[KnownRevitInfoProps.LOCALE]; | ||
revitFileInfo.Locale = CultureInfo | ||
.GetCultures(CultureTypes.NeutralCultures) | ||
.FirstOrDefault(c => c.ThreeLetterWindowsLanguageName == localeRaw); | ||
} | ||
|
||
/// <summary> | ||
/// Parses the document information. | ||
/// </summary> | ||
/// <param name="revitFileInfo">The revit file information.</param> | ||
/// <param name="properties">The properties.</param> | ||
/// <exception cref="T:System.ArgumentNullException">properties</exception> | ||
public static void ParseDocumentInfo(this RevitFileInfo revitFileInfo, Dictionary<string, string> properties) | ||
{ | ||
if (properties == null) throw new ArgumentNullException(nameof(properties)); | ||
|
||
// Parse document unique id | ||
if (!properties.ContainsKey(KnownRevitInfoProps.UNIQUE_DOCUMENT_GUID)) | ||
return; | ||
|
||
var guidRaw = properties[KnownRevitInfoProps.UNIQUE_DOCUMENT_GUID]; | ||
revitFileInfo.Guid = new Guid(guidRaw); | ||
} | ||
|
||
#endregion | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
using CodeCave.Revit.Toolkit.OLE; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Globalization; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Text; | ||
|
||
namespace CodeCave.Revit.Toolkit | ||
{ | ||
public class RevitFileInfo | ||
{ | ||
#region Properties | ||
|
||
/// <summary> | ||
/// Gets the username. | ||
/// </summary> | ||
/// <value>The username.</value> | ||
public string Username { get; internal set; } | ||
|
||
/// <summary> | ||
/// Gets the unique identifier. | ||
/// </summary> | ||
/// <value> | ||
/// The unique identifier. | ||
/// </value> | ||
public Guid Guid { get; internal set; } | ||
|
||
/// <summary> | ||
/// Gets the locale. | ||
/// </summary> | ||
/// <value> | ||
/// The locale. | ||
/// </value> | ||
public CultureInfo Locale { get; internal set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the part atom. | ||
/// </summary> | ||
/// <value> | ||
/// The part atom. | ||
/// </value> | ||
public PartAtom PartAtom { get; private set; } | ||
|
||
/// <summary> | ||
/// Gets the category. | ||
/// </summary> | ||
/// <value> | ||
/// The category. | ||
/// </value> | ||
public string Category => PartAtom?.Category; | ||
|
||
/// <summary> | ||
/// Gets the types. | ||
/// </summary> | ||
/// <value> | ||
/// The types. | ||
/// </value> | ||
public FamilyType[] Types => PartAtom?.Family?.Parts; | ||
|
||
public Version Version { get; internal set; } | ||
|
||
public string Name { get; internal set; } | ||
|
||
public string Vendor { get; internal set; } | ||
|
||
public object Architecture { get; internal set; } | ||
|
||
public bool Is64Bit { get; internal set; } | ||
|
||
public string FilePath { get; private set; } | ||
|
||
#endregion | ||
|
||
#region Methods | ||
|
||
/// <summary> | ||
/// Gets a <see cref="RevitFileInfo" /> instance from the given file path. | ||
/// </summary> | ||
/// <param name="filePath">The file path.</param> | ||
/// <param name="readProperties">if set to <c>true</c> [read properties].</param> | ||
/// <param name="readTypes">if set to <c>true</c> [read types].</param> | ||
/// <returns></returns> | ||
/// <exception cref="T:System.ArgumentException">filePath is invalid</exception> | ||
public static RevitFileInfo GetFromFile(string filePath) | ||
{ | ||
if (string.IsNullOrWhiteSpace(filePath)) | ||
throw new ArgumentException("filePath is invalid"); | ||
|
||
var rfi = new RevitFileInfo | ||
{ | ||
FilePath = filePath | ||
}; | ||
|
||
// Read basic file info from metadata | ||
try | ||
{ | ||
var properties = GetProperties(filePath); | ||
rfi.ParseDocumentInfo(properties); | ||
rfi.ParseLocale(properties); | ||
rfi.ParseRevit(properties); | ||
rfi.ParseUsername(properties); | ||
} | ||
catch (Exception) | ||
{ | ||
// TODO log the error | ||
} | ||
|
||
// Read family types from part atom | ||
try | ||
{ | ||
rfi.PartAtom = PartAtom.GetFromFile(filePath); | ||
} | ||
catch (Exception) | ||
{ | ||
// TODO log the error | ||
} | ||
|
||
return rfi; | ||
} | ||
|
||
#endregion | ||
|
||
#region Helpers | ||
|
||
/// <summary> | ||
/// Gets the properties. | ||
/// </summary> | ||
/// <param name="filePath">The file path.</param> | ||
/// <returns></returns> | ||
internal static Dictionary<string, string> GetProperties(string filePath) | ||
{ | ||
var basicInfo = OleDataReader.GetRawBytes(filePath, "BasicFileInfo"); | ||
var fileProps = new Dictionary<string, string>(); | ||
var supportedEncodeings = new[] | ||
{ | ||
Encoding.Unicode, | ||
Encoding.BigEndianUnicode, | ||
Encoding.UTF8, | ||
Encoding.ASCII, | ||
Encoding.Default, | ||
}; | ||
|
||
foreach (var encoding in supportedEncodeings) | ||
{ | ||
var basicInfoString = encoding.GetString(basicInfo)?.TrimEnd('\u0a0d'); | ||
using var basicInfoReader = new StringReader(basicInfoString); | ||
|
||
// ReSharper disable once RedundantAssignment | ||
var stringLine = basicInfoReader.ReadLine(); // skip the first line | ||
while (!string.IsNullOrWhiteSpace(stringLine = basicInfoReader.ReadLine())) | ||
{ | ||
var parts = stringLine.Split(new[] { ":" }, 2, StringSplitOptions.None); | ||
if (parts.Length != 2) | ||
continue; | ||
fileProps.Add(parts[0].Trim(), parts[1].Trim()); | ||
} | ||
|
||
if (fileProps.Any()) | ||
break; | ||
} | ||
|
||
return fileProps; | ||
} | ||
|
||
#endregion | ||
} | ||
} |
Oops, something went wrong.