Skip to content

Commit

Permalink
FIX: Use InvariantCulture when parsing numbers for Text and XML formats
Browse files Browse the repository at this point in the history
Resolves #25
  • Loading branch information
cyotek committed Apr 25, 2021
1 parent dd44d7d commit dd246af
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 46 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Change Log

## 2.0.2

### Fixed

* Fixed a crash loading text or xml fonts with negative values
if the OS culture uses a different sign

## 2.0.1

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright © 2012-2020 Cyotek Ltd.
Copyright © 2012-2021 Cyotek Ltd.

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
Expand Down
65 changes: 33 additions & 32 deletions src/BitmapFont.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Text;
using System.Xml;

// AngelCode bitmap font parsing using C#
// https://www.cyotek.com/blog/angelcode-bitmap-font-parsing-using-csharp

// Copyright © 2012-2020 Cyotek Ltd.
// Copyright © 2012-2021 Cyotek Ltd.

// This work is licensed under the MIT License.
// See LICENSE.TXT for the full text
Expand Down Expand Up @@ -811,36 +812,36 @@ public virtual void LoadXml(TextReader reader)
// load the basic attributes
properties = root.SelectSingleNode("info");
_familyName = properties.Attributes["face"].Value;
_fontSize = Convert.ToInt32(properties.Attributes["size"].Value);
_bold = Convert.ToInt32(properties.Attributes["bold"].Value) != 0;
_italic = Convert.ToInt32(properties.Attributes["italic"].Value) != 0;
_unicode = Convert.ToInt32(properties.Attributes["unicode"].Value) != 0;
_stretchedHeight = Convert.ToInt32(properties.Attributes["stretchH"].Value);
_fontSize = Convert.ToInt32(properties.Attributes["size"].Value, CultureInfo.InvariantCulture);
_bold = Convert.ToInt32(properties.Attributes["bold"].Value, CultureInfo.InvariantCulture) != 0;
_italic = Convert.ToInt32(properties.Attributes["italic"].Value, CultureInfo.InvariantCulture) != 0;
_unicode = Convert.ToInt32(properties.Attributes["unicode"].Value, CultureInfo.InvariantCulture) != 0;
_stretchedHeight = Convert.ToInt32(properties.Attributes["stretchH"].Value, CultureInfo.InvariantCulture);
_charset = properties.Attributes["charset"].Value;
_smoothed = Convert.ToInt32(properties.Attributes["smooth"].Value) != 0;
_superSampling = Convert.ToInt32(properties.Attributes["aa"].Value);
_smoothed = Convert.ToInt32(properties.Attributes["smooth"].Value, CultureInfo.InvariantCulture) != 0;
_superSampling = Convert.ToInt32(properties.Attributes["aa"].Value, CultureInfo.InvariantCulture);
_padding = BitmapFontLoader.ParsePadding(properties.Attributes["padding"].Value);
_spacing = BitmapFontLoader.ParsePoint(properties.Attributes["spacing"].Value);
_outlineSize = Convert.ToInt32(properties.Attributes["outline"].Value);
_outlineSize = Convert.ToInt32(properties.Attributes["outline"].Value, CultureInfo.InvariantCulture);

// common attributes
properties = root.SelectSingleNode("common");
_baseHeight = Convert.ToInt32(properties.Attributes["base"].Value);
_lineHeight = Convert.ToInt32(properties.Attributes["lineHeight"].Value);
_textureSize = new Size(Convert.ToInt32(properties.Attributes["scaleW"].Value),
Convert.ToInt32(properties.Attributes["scaleH"].Value));
_packed = Convert.ToInt32(properties.Attributes["packed"].Value) != 0;
_alphaChannel = Convert.ToInt32(properties.Attributes["alphaChnl"].Value);
_redChannel = Convert.ToInt32(properties.Attributes["redChnl"].Value);
_greenChannel = Convert.ToInt32(properties.Attributes["greenChnl"].Value);
_blueChannel = Convert.ToInt32(properties.Attributes["blueChnl"].Value);
_baseHeight = Convert.ToInt32(properties.Attributes["base"].Value, CultureInfo.InvariantCulture);
_lineHeight = Convert.ToInt32(properties.Attributes["lineHeight"].Value, CultureInfo.InvariantCulture);
_textureSize = new Size(Convert.ToInt32(properties.Attributes["scaleW"].Value, CultureInfo.InvariantCulture),
Convert.ToInt32(properties.Attributes["scaleH"].Value, CultureInfo.InvariantCulture));
_packed = Convert.ToInt32(properties.Attributes["packed"].Value, CultureInfo.InvariantCulture) != 0;
_alphaChannel = Convert.ToInt32(properties.Attributes["alphaChnl"].Value, CultureInfo.InvariantCulture);
_redChannel = Convert.ToInt32(properties.Attributes["redChnl"].Value, CultureInfo.InvariantCulture);
_greenChannel = Convert.ToInt32(properties.Attributes["greenChnl"].Value, CultureInfo.InvariantCulture);
_blueChannel = Convert.ToInt32(properties.Attributes["blueChnl"].Value, CultureInfo.InvariantCulture);

// load texture information
foreach (XmlNode node in root.SelectNodes("pages/page"))
{
Page page;

page = new Page(Convert.ToInt32(node.Attributes["id"].Value), node.Attributes["file"].Value);
page = new Page(Convert.ToInt32(node.Attributes["id"].Value, CultureInfo.InvariantCulture), node.Attributes["file"].Value);

pageData.Add(page.Id, page);
}
Expand All @@ -852,19 +853,19 @@ public virtual void LoadXml(TextReader reader)
Character character;
int index;

index = Convert.ToInt32(node.Attributes["id"].Value);
index = Convert.ToInt32(node.Attributes["id"].Value, CultureInfo.InvariantCulture);

character = new Character(
index >= 0 ? (char)index : '\0',
Convert.ToInt32(node.Attributes["x"].Value),
Convert.ToInt32(node.Attributes["y"].Value),
Convert.ToInt32(node.Attributes["width"].Value),
Convert.ToInt32(node.Attributes["height"].Value),
Convert.ToInt32(node.Attributes["xoffset"].Value),
Convert.ToInt32(node.Attributes["yoffset"].Value),
Convert.ToInt32(node.Attributes["xadvance"].Value),
Convert.ToInt32(node.Attributes["page"].Value),
Convert.ToInt32(node.Attributes["chnl"].Value)
Convert.ToInt32(node.Attributes["x"].Value, CultureInfo.InvariantCulture),
Convert.ToInt32(node.Attributes["y"].Value, CultureInfo.InvariantCulture),
Convert.ToInt32(node.Attributes["width"].Value, CultureInfo.InvariantCulture),
Convert.ToInt32(node.Attributes["height"].Value, CultureInfo.InvariantCulture),
Convert.ToInt32(node.Attributes["xoffset"].Value, CultureInfo.InvariantCulture),
Convert.ToInt32(node.Attributes["yoffset"].Value, CultureInfo.InvariantCulture),
Convert.ToInt32(node.Attributes["xadvance"].Value, CultureInfo.InvariantCulture),
Convert.ToInt32(node.Attributes["page"].Value, CultureInfo.InvariantCulture),
Convert.ToInt32(node.Attributes["chnl"].Value, CultureInfo.InvariantCulture)
);

if (index == -1)
Expand All @@ -881,9 +882,9 @@ public virtual void LoadXml(TextReader reader)
{
Kerning key;

key = new Kerning((char)Convert.ToInt32(node.Attributes["first"].Value),
(char)Convert.ToInt32(node.Attributes["second"].Value),
Convert.ToInt32(node.Attributes["amount"].Value));
key = new Kerning((char)Convert.ToInt32(node.Attributes["first"].Value, CultureInfo.InvariantCulture),
(char)Convert.ToInt32(node.Attributes["second"].Value, CultureInfo.InvariantCulture),
Convert.ToInt32(node.Attributes["amount"].Value, CultureInfo.InvariantCulture));

if (!kerningDictionary.ContainsKey(key))
{
Expand Down
19 changes: 10 additions & 9 deletions src/BitmapFontLoader.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;

// AngelCode bitmap font parsing using C#
// https://www.cyotek.com/blog/angelcode-bitmap-font-parsing-using-csharp

// Copyright © 2012-2020 Cyotek Ltd.
// Copyright © 2012-2021 Cyotek Ltd.

// This work is licensed under the MIT License.
// See LICENSE.TXT for the full text
Expand Down Expand Up @@ -215,7 +216,7 @@ internal static BitmapFontFormat GetFileFormat(Stream stream)
/// <returns> The parsed value, or <c>false</c> if not found </returns>
internal static bool GetNamedBool(string[] parts, string name, int estimatedStart)
{
return int.TryParse(BitmapFontLoader.GetNamedString(parts, name, estimatedStart), out int v) && v > 0;
return int.TryParse(BitmapFontLoader.GetNamedString(parts, name, estimatedStart), NumberStyles.Number, CultureInfo.InvariantCulture, out int v) && v > 0;
}

/// <summary>
Expand All @@ -227,7 +228,7 @@ internal static bool GetNamedBool(string[] parts, string name, int estimatedStar
/// <returns> The parsed value, or <c>0</c> if not found </returns>
internal static int GetNamedInt(string[] parts, string name, int estimatedStart)
{
return int.TryParse(BitmapFontLoader.GetNamedString(parts, name, estimatedStart), out int result) ? result : 0;
return int.TryParse(BitmapFontLoader.GetNamedString(parts, name, estimatedStart), NumberStyles.Number, CultureInfo.InvariantCulture, out int result) ? result : 0;
}

/// <summary>
Expand Down Expand Up @@ -287,10 +288,10 @@ internal static Padding ParsePadding(string s)

return new Padding
(
int.Parse(s.Substring(lStart + 1)),
int.Parse(s.Substring(0, rStart)),
int.Parse(s.Substring(rStart + 1, bStart - rStart - 1)),
int.Parse(s.Substring(bStart + 1, lStart - bStart - 1))
int.Parse(s.Substring(lStart + 1), CultureInfo.InvariantCulture),
int.Parse(s.Substring(0, rStart), CultureInfo.InvariantCulture),
int.Parse(s.Substring(rStart + 1, bStart - rStart - 1), CultureInfo.InvariantCulture),
int.Parse(s.Substring(bStart + 1, lStart - bStart - 1), CultureInfo.InvariantCulture)
);
}

Expand All @@ -307,8 +308,8 @@ internal static Point ParsePoint(string s)

return new Point
(
int.Parse(s.Substring(0, yStart)),
int.Parse(s.Substring(yStart + 1))
int.Parse(s.Substring(0, yStart), CultureInfo.InvariantCulture),
int.Parse(s.Substring(yStart + 1), CultureInfo.InvariantCulture)
);
}

Expand Down
4 changes: 2 additions & 2 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
<Title>Cyotek BitmapFont</Title>
<Authors>Cyotek</Authors>
<Owners>Cyotek</Owners>
<VersionPrefix>2.0.1</VersionPrefix>
<VersionPrefix>2.0.2</VersionPrefix>
<VersionSuffix></VersionSuffix>
<Copyright>Copyright © 2012-2020 Cyotek Ltd. All Rights Reserved.</Copyright>
<Copyright>Copyright © 2012-2021 Cyotek Ltd. All Rights Reserved.</Copyright>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/cyotek/Cyotek.Drawing.BitmapFont</PackageProjectUrl>
<PackageIcon>icon.png</PackageIcon>
Expand Down
34 changes: 32 additions & 2 deletions tests/BitmapFontLoaderTests.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using NUnit.Framework;
using System.Globalization;
using System.IO;
using System.Threading;
using NUnit.Framework;

// AngelCode bitmap font parsing using C#
// https://www.cyotek.com/blog/angelcode-bitmap-font-parsing-using-csharp

// Copyright © 2017-2020 Cyotek Ltd.
// Copyright © 2017-2021 Cyotek Ltd.

// This work is licensed under the MIT License.
// See LICENSE.TXT for the full text
Expand Down Expand Up @@ -59,6 +61,34 @@ public void LoadFontFromFileTestCases(string baseFileName)
BitmapFontAssert.AreEqual(expected, actual);
}

[Test]
[TestCase("simple.fnt")]
[TestCase("simple-xml.fnt")]
[TestCase("simple-bin.fnt")]
public void LoadFontFromFileWithCustomCultureTestCases(string baseFileName)
{
// arrange
BitmapFont expected;
BitmapFont actual;
CultureInfo culture;
string fileName;

culture = new CultureInfo(CultureInfo.InvariantCulture.Name);
culture.NumberFormat.NegativeSign = "$";

Thread.CurrentThread.CurrentCulture = culture;

expected = this.Simple;

fileName = Path.Combine(this.DataPath, baseFileName);

// act
actual = BitmapFontLoader.LoadFontFromFile(fileName);

// assert
BitmapFontAssert.AreEqual(expected, actual);
}

[Test]
public void Text_is_supported()
{
Expand Down

0 comments on commit dd246af

Please sign in to comment.