Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<Copyright>Copyright 2009-$([System.DateTime]::Today.Year) Olivier Nizet</Copyright>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<LangVersion>preview</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Version>4.0.0</Version>
</PropertyGroup>
Expand Down
76 changes: 22 additions & 54 deletions src/Html2OpenXml/Collections/HtmlAttributeCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace HtmlToOpenXml;
readonly struct HtmlAttributeCollection
{
// Style key associated with a pointer to rawValue.
private readonly Dictionary<string, Range> attributes = [];
private readonly Dictionary<string, Range> attributes = [with(comparer: StringComparer.OrdinalIgnoreCase)];
private readonly string rawValue;


Expand All @@ -38,67 +38,35 @@ public static HtmlAttributeCollection ParseStyle(string? htmlStyles)
var collection = new HtmlAttributeCollection(htmlStyles!);
if (string.IsNullOrWhiteSpace(htmlStyles)) return collection;

var span = htmlStyles.AsSpan();
int startIndex = 0;
bool foundKey = false;
string? key = null;
var stylesSpan = htmlStyles.AsSpan();

while (span.Length > 0)
Span<Range> tokens = stackalloc Range[20];
var tokenCount = stylesSpan.SplitCompositeAttribute(tokens, ';');
if (tokenCount == 0)
return collection;

for (int i = 0; i < tokenCount; i++)
{
// Encoded ':' and ';' characters are valid for browser
// <span style="text-decoration&#58;underline&#59;color:red">
int index = span.IndexOfAny(';', '&', ':');
var segmentSpan = stylesSpan[tokens[i]];
int index = segmentSpan.IndexOfAny('&', ':');
int charsConsumed = 0;

if (index == -1)
{
if (foundKey)
{
// process the last value
collection.attributes[key!] = new Range(startIndex, startIndex + span.Length);
}
break;
}
continue; // no key:value -> ignore this style

var separator = span[index];
if (separator == ';' && foundKey)
if ((charsConsumed = HtmlEntities.IsColon(segmentSpan.Slice(index))) > 0)
{
if (index > 0)
collection.attributes[key!] = new Range(startIndex, startIndex + index);
foundKey = false;
index++;
}
else if (separator == ';' && !foundKey)
{
// unexpected semicolon (ie, key with no value) -> ignore this style
index++;
}
else if (separator == ':' && !foundKey)
{
key = span.Slice(0, index).Trim().ToString().ToLowerInvariant();
foundKey = true;
index++;
}
// html-encoded semicolon
else if (foundKey && span.Slice(index).StartsWith(['&','#','5','9',';']))
{
if (index > 0)
collection.attributes[key!] = new Range(startIndex, startIndex + index);
foundKey = false;
index += 5; // length of "&#58;"
}
else if (!foundKey && span.Slice(index).StartsWith(['&','#','5','8',';']))
{
key = span.Slice(0, index).Trim().ToString().ToLowerInvariant();
foundKey = true;
index += 5; // length of "&#58;"
}
else
{
span = span.Slice(index + 1);
continue;
}
var key = segmentSpan.Slice(0, index).Trim();
var startIndex = index + charsConsumed;

span = span.Slice(index);
startIndex += index;
if (key.Length == 0) continue; // empty key
if (segmentSpan.Length <= startIndex + 1) continue; // empty value

var rng = new Range(tokens[i].Start.Value + startIndex, tokens[i].End);
collection.attributes[key.ToString()] = rng;
}
}

return collection;
Expand Down
2 changes: 1 addition & 1 deletion src/Html2OpenXml/Expressions/HyperlinkExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public override IEnumerable<OpenXmlElement> Interpret (ParsingContext context)
// ensure the links does not start with javascript:
else if (AngleSharpExtensions.TryParseUrl(att, UriKind.Absolute, out var uri))
{
var extLink = context.HostingPart.AddHyperlinkRelationship(uri!, true);
var extLink = context.HostingPart.AddHyperlinkRelationship(uri, true);

h = new Hyperlink(
) { History = true, Id = extLink.Id };
Expand Down
13 changes: 8 additions & 5 deletions src/Html2OpenXml/Expressions/Image/ImageExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,12 @@ class ImageExpression(IHtmlImageElement node) : ImageExpressionBase(node)

// Bug reported by Erik2014. Inline 64 bit images can be too big and Uri.TryCreate will fail silently with a SizeLimit error.
// To circumvent this buffer size, we will work either on the Uri, either on the original src.
if (src == null ||
(!DataUri.IsWellFormed(src) && !AngleSharpExtensions.TryParseUrl(src, UriKind.RelativeOrAbsolute, out var _)))
if (src == null)
return null;

var isDataUri = DataUri.IsDataUri(src);
if (!isDataUri &&
!AngleSharpExtensions.TryParseUrl(src, UriKind.RelativeOrAbsolute, out var _))
{
return null;
}
Expand Down Expand Up @@ -118,10 +122,9 @@ class ImageExpression(IHtmlImageElement node) : ImageExpressionBase(node)
new pic.Picture(
new pic.NonVisualPictureProperties
{
NonVisualDrawingProperties = new pic.NonVisualDrawingProperties()
{
NonVisualDrawingProperties = new pic.NonVisualDrawingProperties() {
Id = imageObjId,
Name = DataUri.IsWellFormed(src) ? string.Empty : src,
Name = isDataUri ? string.Empty : src,
Description = alt
},
NonVisualPictureDrawingProperties = new pic.NonVisualPictureDrawingProperties(
Expand Down
8 changes: 6 additions & 2 deletions src/Html2OpenXml/HtmlConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -335,9 +335,13 @@ private static async Task PreloadImages(AngleSharp.Dom.IDocument htmlDocument,
if (!imageUris.Any())
return;

#if NET5_0_OR_GREATER
await Parallel.ForEachAsync(imageUris,
#else
await imageUris.ForEachAsync(
async (img, cts) => await imageLoader.Download(img, cts),
parallelOptions).ConfigureAwait(false);
#endif
parallelOptions,
async (img, cts) => await imageLoader.Download(img, cts)).ConfigureAwait(false);
}

/// <summary>
Expand Down
3 changes: 3 additions & 0 deletions src/Html2OpenXml/HtmlToOpenXml.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net5.0'))">
<DefineConstants>$(DefineConstants);NET5_0_OR_GREATER</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net9.0'))">
<DefineConstants>$(DefineConstants);NET9_0_OR_GREATER</DefineConstants>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AngleSharp" Version="1.8.0" />
Expand Down
Loading
Loading