Skip to content

Commit

Permalink
improving the ability to fetch basic Revit file info (version, format…
Browse files Browse the repository at this point in the history
… etc)
  • Loading branch information
salaros committed May 8, 2020
1 parent ab40a02 commit b947436
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 128 deletions.
38 changes: 26 additions & 12 deletions src/Extensions/RevitFileInfoExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using CodeCave.Revit.Toolkit.OLE;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
Expand All @@ -18,6 +19,8 @@ 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 BUILD = "Build";
public const string FORMAT = "Format";
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";
Expand All @@ -36,6 +39,12 @@ internal struct KnownRevitInfoProps
RegexOptions.IgnoreCase |
RegexOptions.CultureInvariant);

private static readonly Regex versionExtractorSimple =
new Regex(@"(?<build>\d*)_(?<revision>\d*)(\((?<arch>\w*)\))?",
RegexOptions.Compiled |
RegexOptions.IgnoreCase |
RegexOptions.CultureInvariant);

#endregion

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

if (properties.TryGetValue(KnownRevitInfoProps.FORMAT, out var formatRaw) && int.TryParse(formatRaw, out var format))
revitFileInfo.Format = format;

// Parse Revit Build string
if (!properties.ContainsKey(KnownRevitInfoProps.REVIT_BUILD))
return;
var versionObj = default(Match);
if (properties.TryGetValue(KnownRevitInfoProps.REVIT_BUILD, out var buildInfo))
versionObj = versionExtractor.Match(buildInfo);

var versionObj = versionExtractor.Match(properties[KnownRevitInfoProps.REVIT_BUILD]);
if (!versionObj.Success)
if (properties.TryGetValue(KnownRevitInfoProps.BUILD, out buildInfo))
versionObj = versionExtractorSimple.Match(buildInfo);

if (!versionObj?.Success ?? false)
return;

revitFileInfo.Vendor = versionObj?.Groups["vendor"]?.Value;
revitFileInfo.Name = versionObj?.Groups["software"]?.Value;
revitFileInfo.Is64Bit = versionObj.Groups["arch"]?.Value?.Contains("x64") ?? false;
revitFileInfo.ProductVersion = $"{versionObj.Groups["build"].Value}_{versionObj.Groups["revision"].Value}";

if (!string.IsNullOrWhiteSpace(versionObj?.Groups["vendor"]?.Value))
revitFileInfo.ProductVendor = versionObj?.Groups["vendor"]?.Value;

var versionString = string.Format("{0}.{1}.{2}",
versionObj.Groups["version"].Value,
versionObj.Groups["build"].Value,
versionObj.Groups["revision"].Value);
revitFileInfo.Version = new Version(versionString);
if (!string.IsNullOrWhiteSpace(versionObj?.Groups["software"]?.Value))
revitFileInfo.ProductName = versionObj?.Groups["software"]?.Value;
}

/// <summary>
Expand Down
65 changes: 44 additions & 21 deletions src/OLE/RevitFileInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using static CodeCave.Revit.Toolkit.RevitFileInfoExtensions;

namespace CodeCave.Revit.Toolkit
namespace CodeCave.Revit.Toolkit.OLE
{
public class RevitFileInfo
{
static RevitFileInfo()
{
#if !NET45
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
#endif
}

#region Properties

/// <summary>
Expand Down Expand Up @@ -58,22 +67,34 @@ public class RevitFileInfo
/// </value>
public FamilyType[] Types => PartAtom?.Family?.Parts;

public Version Version { get; internal set; }
public string ProductVendor { get; internal set; } = "Autodesk";

public string Name { get; internal set; }
public string ProductVersion { get; internal set; }

public string Vendor { get; internal set; }
public string ProductName { get; internal set; } = "Revit";

public object Architecture { get; internal set; }
public int Format { get; internal set; }

public bool Is64Bit { get; internal set; }
public bool Is64Bit { get; internal set; } = true;

public string FilePath { get; private set; }

#endregion

#region Methods

public static int GetFormatFromFile(string filePath)
{
if (string.IsNullOrWhiteSpace(filePath) || !File.Exists(filePath))
throw new ArgumentException("Please supply a valid path to a Revit document", nameof(filePath));

var properties = GetProperties(filePath);
if (properties.TryGetValue(KnownRevitInfoProps.FORMAT, out var formatRaw) && int.TryParse(formatRaw, out var format))
return format;

throw new InvalidDataException($"Couldn't read format information from the followin file: '{filePath}'");
}

/// <summary>
/// Gets a <see cref="RevitFileInfo" /> instance from the given file path.
/// </summary>
Expand All @@ -84,8 +105,8 @@ public class RevitFileInfo
/// <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");
if (string.IsNullOrWhiteSpace(filePath) || !File.Exists(filePath))
throw new ArgumentException("Please supply a valid path to a Revit document", nameof(filePath));

var rfi = new RevitFileInfo
{
Expand Down Expand Up @@ -130,28 +151,25 @@ public static RevitFileInfo GetFromFile(string filePath)
/// <returns></returns>
internal static Dictionary<string, string> GetProperties(string filePath)
{
var basicInfo = OleDataReader.GetRawBytes(filePath, "BasicFileInfo");
var basicInfo = OleDataReader.GetRawBytes(filePath, RevitFileMap.OleStreams.BASIC_FILE_INFO);
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 asd = new Regex(@"\p{IsCJKUnifiedIdeographs}");

foreach (var encoding in RevitFileMap.SupportedEncodings)
{
var basicInfoString = encoding.GetString(basicInfo)?.TrimEnd('\u0a0d');
using var basicInfoReader = new StringReader(basicInfoString);
if (asd.IsMatch(basicInfoString))
continue;

using var basicInfoReader = new StringReader(basicInfoString?.Replace("\0", string.Empty));

// 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)
var parts = stringLine.Split(new[] { ":" }, StringSplitOptions.None);
if (parts.Length != 2 || IsInvalidProperty(parts.FirstOrDefault()))
continue;
fileProps.Add(parts[0].Trim(), parts[1].Trim());
}
Expand All @@ -163,6 +181,11 @@ internal static Dictionary<string, string> GetProperties(string filePath)
return fileProps;
}

private static bool IsInvalidProperty(string input)
{
return input?.Any(c => char.IsControl(c)) ?? true;
}

#endregion
}
}
37 changes: 37 additions & 0 deletions src/OLE/RevitFileMap.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Text;

namespace CodeCave.Revit.Toolkit.OLE
{
internal struct RevitFileMap
{
internal struct OleStreams
{
public const string IMAGE_STREAM = "RevitPreview4.0";
public const string BASIC_FILE_INFO = "BasicFileInfo";
}

internal struct PngImageMarker
{
public const int MARKER_10 = 10; // 0x0A
public const int MARKER_13 = 13; // 0x0D
public const int MARKER_26 = 26; // 0x1A
public const int MARKER_71 = 71; // 0x47
public const int MARKER_78 = 78; // 0x4E
public const int MARKER_80 = 80; // 0x50
public const int MARKER_137 = 137; // 0x89
}

public static readonly Encoding[] SupportedEncodings = new[]
{
Encoding.BigEndianUnicode,
Encoding.UTF8,
Encoding.Unicode,
Encoding.ASCII,
Encoding.GetEncoding(1251),
Encoding.UTF32,
Encoding.GetEncoding(1252),
Encoding.UTF7,
Encoding.Default
};
}
}
67 changes: 0 additions & 67 deletions src/OLE/RevitFileVersionInfo.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace CodeCave.Revit.Toolkit.Thumbnails
/// http://thebuildingcoder.typepad.com/blog/2008/10/rvt-file-version.html
/// </summary>
/// <seealso cref="ThumbnailExtractor" />
public class RfaTumbnailExtractor : ThumbnailExtractor
public partial class RevitTumbnailExtractor : ThumbnailExtractor
{
#region Methods

Expand Down Expand Up @@ -60,7 +60,7 @@ public override MemoryStream ExtractStream(string pathToFile)
{
try
{
var thumbnailBytes = OleDataReader.GetRawBytes(pathToFile, RevitFileMap.OleStorage.IMAGE_STREAM);
var thumbnailBytes = OleDataReader.GetRawBytes(pathToFile, RevitFileMap.OleStreams.IMAGE_STREAM);
return ExtractStream(thumbnailBytes);
}
catch (Exception ex)
Expand All @@ -73,7 +73,7 @@ public override MemoryStream ExtractStream(MemoryStream memoryStream)
{
try
{
var thumbnailBytes = OleDataReader.GetRawBytes(memoryStream, RevitFileMap.OleStorage.IMAGE_STREAM);
var thumbnailBytes = OleDataReader.GetRawBytes(memoryStream, RevitFileMap.OleStreams.IMAGE_STREAM);
return ExtractStream(thumbnailBytes);
}
catch (Exception ex)
Expand Down Expand Up @@ -177,28 +177,5 @@ private static int GetPngOffset(byte[] thumbnailBytes)
}

#endregion Helpers

#region Revit file map

internal struct RevitFileMap
{
internal struct OleStorage
{
public const string IMAGE_STREAM = "RevitPreview4.0";
}

internal struct PngImageMarker
{
public const int MARKER_10 = 10; // 0x0A
public const int MARKER_13 = 13; // 0x0D
public const int MARKER_26 = 26; // 0x1A
public const int MARKER_71 = 71; // 0x47
public const int MARKER_78 = 78; // 0x4E
public const int MARKER_80 = 80; // 0x50
public const int MARKER_137 = 137; // 0x89
}
}

#endregion
}
}
2 changes: 1 addition & 1 deletion src/Revit.Toolkit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
<PackageReference Include="OpenMcdf-2" Version="2.1.2" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
<PackageReference Include="System.Drawing.Common" Version="4.5.1" Condition="'$(TargetFramework)' == 'netstandard2.0' Or '$(TargetFramework)' == 'netcoreapp2.1'" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.1" Condition="'$(TargetFramework)' != 'net45'" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.0" Condition="'$(TargetFramework)' != 'net45'" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion tests/ThumbnailFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public void RfaThumbnailIsGenerated(string rfaRelativePath)
var rfaThumbnailPath = Path.ChangeExtension(Path.Combine(Environment.CurrentDirectory, Path.GetFileName(rfaFilePath)), "png");

// act
var rfaThumbnailer = new RfaTumbnailExtractor();
var rfaThumbnailer = new RevitTumbnailExtractor();
var fileExtracted = rfaThumbnailer.TryExtractFile(rfaFilePath, rfaThumbnailPath);

// assert
Expand Down

0 comments on commit b947436

Please sign in to comment.