Skip to content

Commit b947436

Browse files
committed
improving the ability to fetch basic Revit file info (version, format etc)
1 parent ab40a02 commit b947436

File tree

7 files changed

+112
-128
lines changed

7 files changed

+112
-128
lines changed

src/Extensions/RevitFileInfoExtensions.cs

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
using CodeCave.Revit.Toolkit.OLE;
2+
using System;
23
using System.Collections.Generic;
34
using System.Globalization;
45
using System.Linq;
@@ -18,6 +19,8 @@ internal struct KnownRevitInfoProps
1819
public const string USERNAME = "Username";
1920
public const string CENTRAL_MODEL_PATH = "Central Model Path";
2021
public const string REVIT_BUILD = "Revit Build";
22+
public const string BUILD = "Build";
23+
public const string FORMAT = "Format";
2124
public const string LAST_SAVE_PATH = "Last Save Path";
2225
public const string OPEN_WORKSET_DEFAULT = "Open Workset Default";
2326
public const string PROJECT_SPARK_FILE = "Project Spark File";
@@ -36,6 +39,12 @@ internal struct KnownRevitInfoProps
3639
RegexOptions.IgnoreCase |
3740
RegexOptions.CultureInvariant);
3841

42+
private static readonly Regex versionExtractorSimple =
43+
new Regex(@"(?<build>\d*)_(?<revision>\d*)(\((?<arch>\w*)\))?",
44+
RegexOptions.Compiled |
45+
RegexOptions.IgnoreCase |
46+
RegexOptions.CultureInvariant);
47+
3948
#endregion
4049

4150
#region Methods
@@ -68,23 +77,28 @@ public static void ParseRevit(this RevitFileInfo revitFileInfo, Dictionary<strin
6877
{
6978
if (properties == null) throw new ArgumentNullException(nameof(properties));
7079

80+
if (properties.TryGetValue(KnownRevitInfoProps.FORMAT, out var formatRaw) && int.TryParse(formatRaw, out var format))
81+
revitFileInfo.Format = format;
82+
7183
// Parse Revit Build string
72-
if (!properties.ContainsKey(KnownRevitInfoProps.REVIT_BUILD))
73-
return;
84+
var versionObj = default(Match);
85+
if (properties.TryGetValue(KnownRevitInfoProps.REVIT_BUILD, out var buildInfo))
86+
versionObj = versionExtractor.Match(buildInfo);
7487

75-
var versionObj = versionExtractor.Match(properties[KnownRevitInfoProps.REVIT_BUILD]);
76-
if (!versionObj.Success)
88+
if (properties.TryGetValue(KnownRevitInfoProps.BUILD, out buildInfo))
89+
versionObj = versionExtractorSimple.Match(buildInfo);
90+
91+
if (!versionObj?.Success ?? false)
7792
return;
7893

79-
revitFileInfo.Vendor = versionObj?.Groups["vendor"]?.Value;
80-
revitFileInfo.Name = versionObj?.Groups["software"]?.Value;
8194
revitFileInfo.Is64Bit = versionObj.Groups["arch"]?.Value?.Contains("x64") ?? false;
95+
revitFileInfo.ProductVersion = $"{versionObj.Groups["build"].Value}_{versionObj.Groups["revision"].Value}";
96+
97+
if (!string.IsNullOrWhiteSpace(versionObj?.Groups["vendor"]?.Value))
98+
revitFileInfo.ProductVendor = versionObj?.Groups["vendor"]?.Value;
8299

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);
100+
if (!string.IsNullOrWhiteSpace(versionObj?.Groups["software"]?.Value))
101+
revitFileInfo.ProductName = versionObj?.Groups["software"]?.Value;
88102
}
89103

90104
/// <summary>

src/OLE/RevitFileInfo.cs

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,20 @@
55
using System.IO;
66
using System.Linq;
77
using System.Text;
8+
using System.Text.RegularExpressions;
9+
using static CodeCave.Revit.Toolkit.RevitFileInfoExtensions;
810

9-
namespace CodeCave.Revit.Toolkit
11+
namespace CodeCave.Revit.Toolkit.OLE
1012
{
1113
public class RevitFileInfo
1214
{
15+
static RevitFileInfo()
16+
{
17+
#if !NET45
18+
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
19+
#endif
20+
}
21+
1322
#region Properties
1423

1524
/// <summary>
@@ -58,22 +67,34 @@ public class RevitFileInfo
5867
/// </value>
5968
public FamilyType[] Types => PartAtom?.Family?.Parts;
6069

61-
public Version Version { get; internal set; }
70+
public string ProductVendor { get; internal set; } = "Autodesk";
6271

63-
public string Name { get; internal set; }
72+
public string ProductVersion { get; internal set; }
6473

65-
public string Vendor { get; internal set; }
74+
public string ProductName { get; internal set; } = "Revit";
6675

67-
public object Architecture { get; internal set; }
76+
public int Format { get; internal set; }
6877

69-
public bool Is64Bit { get; internal set; }
78+
public bool Is64Bit { get; internal set; } = true;
7079

7180
public string FilePath { get; private set; }
7281

7382
#endregion
7483

7584
#region Methods
7685

86+
public static int GetFormatFromFile(string filePath)
87+
{
88+
if (string.IsNullOrWhiteSpace(filePath) || !File.Exists(filePath))
89+
throw new ArgumentException("Please supply a valid path to a Revit document", nameof(filePath));
90+
91+
var properties = GetProperties(filePath);
92+
if (properties.TryGetValue(KnownRevitInfoProps.FORMAT, out var formatRaw) && int.TryParse(formatRaw, out var format))
93+
return format;
94+
95+
throw new InvalidDataException($"Couldn't read format information from the followin file: '{filePath}'");
96+
}
97+
7798
/// <summary>
7899
/// Gets a <see cref="RevitFileInfo" /> instance from the given file path.
79100
/// </summary>
@@ -84,8 +105,8 @@ public class RevitFileInfo
84105
/// <exception cref="T:System.ArgumentException">filePath is invalid</exception>
85106
public static RevitFileInfo GetFromFile(string filePath)
86107
{
87-
if (string.IsNullOrWhiteSpace(filePath))
88-
throw new ArgumentException("filePath is invalid");
108+
if (string.IsNullOrWhiteSpace(filePath) || !File.Exists(filePath))
109+
throw new ArgumentException("Please supply a valid path to a Revit document", nameof(filePath));
89110

90111
var rfi = new RevitFileInfo
91112
{
@@ -130,28 +151,25 @@ public static RevitFileInfo GetFromFile(string filePath)
130151
/// <returns></returns>
131152
internal static Dictionary<string, string> GetProperties(string filePath)
132153
{
133-
var basicInfo = OleDataReader.GetRawBytes(filePath, "BasicFileInfo");
154+
var basicInfo = OleDataReader.GetRawBytes(filePath, RevitFileMap.OleStreams.BASIC_FILE_INFO);
134155
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-
};
143156

144-
foreach (var encoding in supportedEncodeings)
157+
var asd = new Regex(@"\p{IsCJKUnifiedIdeographs}");
158+
159+
foreach (var encoding in RevitFileMap.SupportedEncodings)
145160
{
146161
var basicInfoString = encoding.GetString(basicInfo)?.TrimEnd('\u0a0d');
147-
using var basicInfoReader = new StringReader(basicInfoString);
162+
if (asd.IsMatch(basicInfoString))
163+
continue;
164+
165+
using var basicInfoReader = new StringReader(basicInfoString?.Replace("\0", string.Empty));
148166

149167
// ReSharper disable once RedundantAssignment
150168
var stringLine = basicInfoReader.ReadLine(); // skip the first line
151169
while (!string.IsNullOrWhiteSpace(stringLine = basicInfoReader.ReadLine()))
152170
{
153-
var parts = stringLine.Split(new[] { ":" }, 2, StringSplitOptions.None);
154-
if (parts.Length != 2)
171+
var parts = stringLine.Split(new[] { ":" }, StringSplitOptions.None);
172+
if (parts.Length != 2 || IsInvalidProperty(parts.FirstOrDefault()))
155173
continue;
156174
fileProps.Add(parts[0].Trim(), parts[1].Trim());
157175
}
@@ -163,6 +181,11 @@ internal static Dictionary<string, string> GetProperties(string filePath)
163181
return fileProps;
164182
}
165183

184+
private static bool IsInvalidProperty(string input)
185+
{
186+
return input?.Any(c => char.IsControl(c)) ?? true;
187+
}
188+
166189
#endregion
167190
}
168191
}

src/OLE/RevitFileMap.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System.Text;
2+
3+
namespace CodeCave.Revit.Toolkit.OLE
4+
{
5+
internal struct RevitFileMap
6+
{
7+
internal struct OleStreams
8+
{
9+
public const string IMAGE_STREAM = "RevitPreview4.0";
10+
public const string BASIC_FILE_INFO = "BasicFileInfo";
11+
}
12+
13+
internal struct PngImageMarker
14+
{
15+
public const int MARKER_10 = 10; // 0x0A
16+
public const int MARKER_13 = 13; // 0x0D
17+
public const int MARKER_26 = 26; // 0x1A
18+
public const int MARKER_71 = 71; // 0x47
19+
public const int MARKER_78 = 78; // 0x4E
20+
public const int MARKER_80 = 80; // 0x50
21+
public const int MARKER_137 = 137; // 0x89
22+
}
23+
24+
public static readonly Encoding[] SupportedEncodings = new[]
25+
{
26+
Encoding.BigEndianUnicode,
27+
Encoding.UTF8,
28+
Encoding.Unicode,
29+
Encoding.ASCII,
30+
Encoding.GetEncoding(1251),
31+
Encoding.UTF32,
32+
Encoding.GetEncoding(1252),
33+
Encoding.UTF7,
34+
Encoding.Default
35+
};
36+
}
37+
}

src/OLE/RevitFileVersionInfo.cs

Lines changed: 0 additions & 67 deletions
This file was deleted.

src/Thumbnails/RfaTumbnailExtractor.cs renamed to src/OLE/RevitTumbnailExtractor.cs

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace CodeCave.Revit.Toolkit.Thumbnails
1010
/// http://thebuildingcoder.typepad.com/blog/2008/10/rvt-file-version.html
1111
/// </summary>
1212
/// <seealso cref="ThumbnailExtractor" />
13-
public class RfaTumbnailExtractor : ThumbnailExtractor
13+
public partial class RevitTumbnailExtractor : ThumbnailExtractor
1414
{
1515
#region Methods
1616

@@ -60,7 +60,7 @@ public override MemoryStream ExtractStream(string pathToFile)
6060
{
6161
try
6262
{
63-
var thumbnailBytes = OleDataReader.GetRawBytes(pathToFile, RevitFileMap.OleStorage.IMAGE_STREAM);
63+
var thumbnailBytes = OleDataReader.GetRawBytes(pathToFile, RevitFileMap.OleStreams.IMAGE_STREAM);
6464
return ExtractStream(thumbnailBytes);
6565
}
6666
catch (Exception ex)
@@ -73,7 +73,7 @@ public override MemoryStream ExtractStream(MemoryStream memoryStream)
7373
{
7474
try
7575
{
76-
var thumbnailBytes = OleDataReader.GetRawBytes(memoryStream, RevitFileMap.OleStorage.IMAGE_STREAM);
76+
var thumbnailBytes = OleDataReader.GetRawBytes(memoryStream, RevitFileMap.OleStreams.IMAGE_STREAM);
7777
return ExtractStream(thumbnailBytes);
7878
}
7979
catch (Exception ex)
@@ -177,28 +177,5 @@ private static int GetPngOffset(byte[] thumbnailBytes)
177177
}
178178

179179
#endregion Helpers
180-
181-
#region Revit file map
182-
183-
internal struct RevitFileMap
184-
{
185-
internal struct OleStorage
186-
{
187-
public const string IMAGE_STREAM = "RevitPreview4.0";
188-
}
189-
190-
internal struct PngImageMarker
191-
{
192-
public const int MARKER_10 = 10; // 0x0A
193-
public const int MARKER_13 = 13; // 0x0D
194-
public const int MARKER_26 = 26; // 0x1A
195-
public const int MARKER_71 = 71; // 0x47
196-
public const int MARKER_78 = 78; // 0x4E
197-
public const int MARKER_80 = 80; // 0x50
198-
public const int MARKER_137 = 137; // 0x89
199-
}
200-
}
201-
202-
#endregion
203180
}
204181
}

src/Revit.Toolkit.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
<PackageReference Include="OpenMcdf-2" Version="2.1.2" />
6262
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
6363
<PackageReference Include="System.Drawing.Common" Version="4.5.1" Condition="'$(TargetFramework)' == 'netstandard2.0' Or '$(TargetFramework)' == 'netcoreapp2.1'" />
64-
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.1" Condition="'$(TargetFramework)' != 'net45'" />
64+
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.0" Condition="'$(TargetFramework)' != 'net45'" />
6565
</ItemGroup>
6666

6767
<ItemGroup>

tests/ThumbnailFixture.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public void RfaThumbnailIsGenerated(string rfaRelativePath)
3030
var rfaThumbnailPath = Path.ChangeExtension(Path.Combine(Environment.CurrentDirectory, Path.GetFileName(rfaFilePath)), "png");
3131

3232
// act
33-
var rfaThumbnailer = new RfaTumbnailExtractor();
33+
var rfaThumbnailer = new RevitTumbnailExtractor();
3434
var fileExtracted = rfaThumbnailer.TryExtractFile(rfaFilePath, rfaThumbnailPath);
3535

3636
// assert

0 commit comments

Comments
 (0)