Skip to content

Commit ab40a02

Browse files
committed
adding the ability to de-serialize PartAtom of Revit files
1 parent f2f2325 commit ab40a02

20 files changed

Lines changed: 677 additions & 105 deletions

src/Decompiled/DisplayUnitType.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,7 +1320,7 @@ public static bool TryGetCatalogString(this DisplayUnitType displayUnitType, out
13201320
/// <returns></returns>
13211321
public static bool TryGetFromCatalogString(this string catalogString, out DisplayUnitType displayUnitType)
13221322
{
1323-
var values = _dutToCatalog?.Where(u => u.Value.Equals(catalogString)).Select(x => x.Key).ToList();
1323+
var values = _dutToCatalog?.Where(u => u.Value.Equals(catalogString, StringComparison.OrdinalIgnoreCase)).Select(x => x.Key).ToList();
13241324
var valueExists = values != null && values.Any();
13251325
displayUnitType = valueExists
13261326
? values.FirstOrDefault()
@@ -1400,7 +1400,5 @@ public static bool TryGetFromUnitSymbol(this UnitSymbolType unitSymbolType, out
14001400
: DisplayUnitType.DUT_UNDEFINED;
14011401
return values.Any();
14021402
}
1403-
1404-
14051403
}
14061404
}

src/Decompiled/ParameterType.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Collections.Generic;
23
using System.Linq;
34

@@ -449,7 +450,7 @@ static ParameterTypeExtensions()
449450
/// <returns></returns>
450451
public static ParameterType FromSharedDataType(this string dataType)
451452
{
452-
var values = _parameterTypes2Shared?.Where(u => u.Value.Equals(dataType)).Select(x => x.Key).ToArray();
453+
var values = _parameterTypes2Shared?.Where(u => u.Value.Equals(dataType, StringComparison.OrdinalIgnoreCase)).Select(x => x.Key).ToArray();
453454
return (values != null && values.Any())
454455
? values.FirstOrDefault()
455456
: ParameterType.Invalid;

src/Decompiled/UnitType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ public static bool TryGetGroup(this UnitType unitType, out UnitGroup group)
610610
/// <returns></returns>
611611
public static bool TryGetUnitTypeFromCatalogString(this string catalogString, out UnitType unitType)
612612
{
613-
var values = _utToCatalog?.Where(u => u.Value.Equals(catalogString)).Select(x => x.Key).ToList();
613+
var values = _utToCatalog?.Where(u => u.Value.Equals(catalogString, System.StringComparison.OrdinalIgnoreCase)).Select(x => x.Key).ToList();
614614
var valueExists = values != null && values.Any();
615615
unitType = valueExists
616616
? values.FirstOrDefault()
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Globalization;
4+
using System.Linq;
5+
using System.Text.RegularExpressions;
6+
7+
namespace CodeCave.Revit.Toolkit
8+
{
9+
public static class RevitFileInfoExtensions
10+
{
11+
#region Constants
12+
13+
/// <summary>
14+
/// List of known Revit file properties.
15+
/// </summary>
16+
internal struct KnownRevitInfoProps
17+
{
18+
public const string USERNAME = "Username";
19+
public const string CENTRAL_MODEL_PATH = "Central Model Path";
20+
public const string REVIT_BUILD = "Revit Build";
21+
public const string LAST_SAVE_PATH = "Last Save Path";
22+
public const string OPEN_WORKSET_DEFAULT = "Open Workset Default";
23+
public const string PROJECT_SPARK_FILE = "Project Spark File";
24+
public const string CENTRAL_MODEL_IDENTITY = "Central Model Identity";
25+
public const string LOCALE = "Locale when saved";
26+
public const string LOCAL_SAVED_TO_CENTRAL = "All Local Changes Saved To Central";
27+
public const string CENTRAL_MODEL_VERSION = "Central model's version number corresponding to the last reload latest";
28+
public const string CENTRAL_MODEL_GUID = "Central model's episode GUID corresponding to the last reload latest";
29+
public const string UNIQUE_DOCUMENT_GUID = "Unique Document GUID";
30+
public const string UNIQUE_DOCUMENT_INCREMENT = "Unique Document Increments";
31+
}
32+
33+
private static readonly Regex versionExtractor =
34+
new Regex(@"(?<vendor>\w*) (?<software>(\w|\s)*) (?<version>\d{4}) \(Build\: (?<build>\d*)_(?<revision>\d*)(\((?<arch>\w*)\))?\)",
35+
RegexOptions.Compiled |
36+
RegexOptions.IgnoreCase |
37+
RegexOptions.CultureInvariant);
38+
39+
#endregion
40+
41+
#region Methods
42+
43+
/// <summary>
44+
/// Parses the username.
45+
/// </summary>
46+
/// <param name="revitFileInfo">The revit file information.</param>
47+
/// <param name="properties">The properties.</param>
48+
/// <exception cref="T:System.ArgumentNullException">properties</exception>
49+
public static void ParseUsername(this RevitFileInfo revitFileInfo, Dictionary<string, string> properties)
50+
{
51+
if (properties == null)
52+
throw new ArgumentNullException(nameof(properties));
53+
54+
// Parse username field
55+
if (!properties.ContainsKey(KnownRevitInfoProps.USERNAME))
56+
return;
57+
58+
revitFileInfo.Username = properties[KnownRevitInfoProps.USERNAME];
59+
}
60+
61+
/// <summary>
62+
/// Parses the revit.
63+
/// </summary>
64+
/// <param name="revitFileInfo">The revit file information.</param>
65+
/// <param name="properties">The properties.</param>
66+
/// <exception cref="T:System.ArgumentNullException">properties</exception>
67+
public static void ParseRevit(this RevitFileInfo revitFileInfo, Dictionary<string, string> properties)
68+
{
69+
if (properties == null) throw new ArgumentNullException(nameof(properties));
70+
71+
// Parse Revit Build string
72+
if (!properties.ContainsKey(KnownRevitInfoProps.REVIT_BUILD))
73+
return;
74+
75+
var versionObj = versionExtractor.Match(properties[KnownRevitInfoProps.REVIT_BUILD]);
76+
if (!versionObj.Success)
77+
return;
78+
79+
revitFileInfo.Vendor = versionObj?.Groups["vendor"]?.Value;
80+
revitFileInfo.Name = versionObj?.Groups["software"]?.Value;
81+
revitFileInfo.Is64Bit = versionObj.Groups["arch"]?.Value?.Contains("x64") ?? false;
82+
83+
var versionString = string.Format("{0}.{1}.{2}",
84+
versionObj.Groups["version"].Value,
85+
versionObj.Groups["build"].Value,
86+
versionObj.Groups["revision"].Value);
87+
revitFileInfo.Version = new Version(versionString);
88+
}
89+
90+
/// <summary>
91+
/// Parses the locale.
92+
/// </summary>
93+
/// <param name="revitFileInfo">The revit file information.</param>
94+
/// <param name="properties">The properties.</param>
95+
/// <exception cref="T:System.ArgumentNullException">properties</exception>
96+
public static void ParseLocale(this RevitFileInfo revitFileInfo, Dictionary<string, string> properties)
97+
{
98+
if (properties == null) throw new ArgumentNullException(nameof(properties));
99+
100+
// Parse last saved locale
101+
if (!properties.ContainsKey(KnownRevitInfoProps.LOCALE))
102+
return;
103+
104+
var localeRaw = properties[KnownRevitInfoProps.LOCALE];
105+
revitFileInfo.Locale = CultureInfo
106+
.GetCultures(CultureTypes.NeutralCultures)
107+
.FirstOrDefault(c => c.ThreeLetterWindowsLanguageName == localeRaw);
108+
}
109+
110+
/// <summary>
111+
/// Parses the document information.
112+
/// </summary>
113+
/// <param name="revitFileInfo">The revit file information.</param>
114+
/// <param name="properties">The properties.</param>
115+
/// <exception cref="T:System.ArgumentNullException">properties</exception>
116+
public static void ParseDocumentInfo(this RevitFileInfo revitFileInfo, Dictionary<string, string> properties)
117+
{
118+
if (properties == null) throw new ArgumentNullException(nameof(properties));
119+
120+
// Parse document unique id
121+
if (!properties.ContainsKey(KnownRevitInfoProps.UNIQUE_DOCUMENT_GUID))
122+
return;
123+
124+
var guidRaw = properties[KnownRevitInfoProps.UNIQUE_DOCUMENT_GUID];
125+
revitFileInfo.Guid = new Guid(guidRaw);
126+
}
127+
128+
#endregion
129+
}
130+
}

src/OLE/OleDataReader.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace CodeCave.Revit.Toolkit.OLE
1010
/// <summary>
1111
/// A reader for OLE metadata information stored in Revit files
1212
/// </summary>
13-
public class OleDataReader
13+
public static class OleDataReader
1414
{
1515
/// <summary>
1616
/// Gets the raw XML data.
@@ -167,13 +167,9 @@ public static TResult GetData<TResult>(string pathToFile, string oleStream, Enco
167167
{
168168
var stringData = GetRawString(pathToFile, oleStream, enc);
169169
var xmlSerializer = new XmlSerializer(typeof(TResult));
170-
using (var stringReader = new StringReader(stringData))
171-
{
172-
using (var xmlReader = XmlReader.Create(stringReader))
173-
{
174-
resultObject = xmlSerializer.Deserialize(xmlReader) as TResult;
175-
}
176-
}
170+
using var stringReader = new StringReader(stringData);
171+
using var xmlReader = XmlReader.Create(stringReader);
172+
resultObject = xmlSerializer.Deserialize(xmlReader) as TResult;
177173
}
178174
catch (Exception ex)
179175
{

src/OLE/RevitFileInfo.cs

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
using CodeCave.Revit.Toolkit.OLE;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Globalization;
5+
using System.IO;
6+
using System.Linq;
7+
using System.Text;
8+
9+
namespace CodeCave.Revit.Toolkit
10+
{
11+
public class RevitFileInfo
12+
{
13+
#region Properties
14+
15+
/// <summary>
16+
/// Gets the username.
17+
/// </summary>
18+
/// <value>The username.</value>
19+
public string Username { get; internal set; }
20+
21+
/// <summary>
22+
/// Gets the unique identifier.
23+
/// </summary>
24+
/// <value>
25+
/// The unique identifier.
26+
/// </value>
27+
public Guid Guid { get; internal set; }
28+
29+
/// <summary>
30+
/// Gets the locale.
31+
/// </summary>
32+
/// <value>
33+
/// The locale.
34+
/// </value>
35+
public CultureInfo Locale { get; internal set; }
36+
37+
/// <summary>
38+
/// Gets or sets the part atom.
39+
/// </summary>
40+
/// <value>
41+
/// The part atom.
42+
/// </value>
43+
public PartAtom PartAtom { get; private set; }
44+
45+
/// <summary>
46+
/// Gets the category.
47+
/// </summary>
48+
/// <value>
49+
/// The category.
50+
/// </value>
51+
public string Category => PartAtom?.Category;
52+
53+
/// <summary>
54+
/// Gets the types.
55+
/// </summary>
56+
/// <value>
57+
/// The types.
58+
/// </value>
59+
public FamilyType[] Types => PartAtom?.Family?.Parts;
60+
61+
public Version Version { get; internal set; }
62+
63+
public string Name { get; internal set; }
64+
65+
public string Vendor { get; internal set; }
66+
67+
public object Architecture { get; internal set; }
68+
69+
public bool Is64Bit { get; internal set; }
70+
71+
public string FilePath { get; private set; }
72+
73+
#endregion
74+
75+
#region Methods
76+
77+
/// <summary>
78+
/// Gets a <see cref="RevitFileInfo" /> instance from the given file path.
79+
/// </summary>
80+
/// <param name="filePath">The file path.</param>
81+
/// <param name="readProperties">if set to <c>true</c> [read properties].</param>
82+
/// <param name="readTypes">if set to <c>true</c> [read types].</param>
83+
/// <returns></returns>
84+
/// <exception cref="T:System.ArgumentException">filePath is invalid</exception>
85+
public static RevitFileInfo GetFromFile(string filePath)
86+
{
87+
if (string.IsNullOrWhiteSpace(filePath))
88+
throw new ArgumentException("filePath is invalid");
89+
90+
var rfi = new RevitFileInfo
91+
{
92+
FilePath = filePath
93+
};
94+
95+
// Read basic file info from metadata
96+
try
97+
{
98+
var properties = GetProperties(filePath);
99+
rfi.ParseDocumentInfo(properties);
100+
rfi.ParseLocale(properties);
101+
rfi.ParseRevit(properties);
102+
rfi.ParseUsername(properties);
103+
}
104+
catch (Exception)
105+
{
106+
// TODO log the error
107+
}
108+
109+
// Read family types from part atom
110+
try
111+
{
112+
rfi.PartAtom = PartAtom.GetFromFile(filePath);
113+
}
114+
catch (Exception)
115+
{
116+
// TODO log the error
117+
}
118+
119+
return rfi;
120+
}
121+
122+
#endregion
123+
124+
#region Helpers
125+
126+
/// <summary>
127+
/// Gets the properties.
128+
/// </summary>
129+
/// <param name="filePath">The file path.</param>
130+
/// <returns></returns>
131+
internal static Dictionary<string, string> GetProperties(string filePath)
132+
{
133+
var basicInfo = OleDataReader.GetRawBytes(filePath, "BasicFileInfo");
134+
var fileProps = new Dictionary<string, string>();
135+
var supportedEncodeings = new[]
136+
{
137+
Encoding.Unicode,
138+
Encoding.BigEndianUnicode,
139+
Encoding.UTF8,
140+
Encoding.ASCII,
141+
Encoding.Default,
142+
};
143+
144+
foreach (var encoding in supportedEncodeings)
145+
{
146+
var basicInfoString = encoding.GetString(basicInfo)?.TrimEnd('\u0a0d');
147+
using var basicInfoReader = new StringReader(basicInfoString);
148+
149+
// ReSharper disable once RedundantAssignment
150+
var stringLine = basicInfoReader.ReadLine(); // skip the first line
151+
while (!string.IsNullOrWhiteSpace(stringLine = basicInfoReader.ReadLine()))
152+
{
153+
var parts = stringLine.Split(new[] { ":" }, 2, StringSplitOptions.None);
154+
if (parts.Length != 2)
155+
continue;
156+
fileProps.Add(parts[0].Trim(), parts[1].Trim());
157+
}
158+
159+
if (fileProps.Any())
160+
break;
161+
}
162+
163+
return fileProps;
164+
}
165+
166+
#endregion
167+
}
168+
}

0 commit comments

Comments
 (0)