safer float parsing

This commit is contained in:
vcoppe
2025-04-04 08:56:53 +02:00
parent f4879a9e8a
commit a7cfe36b2e

View File

@@ -19,6 +19,24 @@ const attributesWithNamespace = {
width: 'gpx_style:width', width: 'gpx_style:width',
}; };
const floatPatterns = [
/[-+]?\d*\.\d+$/, // decimal
/[-+]?\d+$/, // integer
];
function safeParseFloat(value: string): number {
const parsed = parseFloat(value);
if (!isNaN(parsed)) {
return parsed;
}
for (const pattern of floatPatterns) {
const match = value.match(pattern);
if (match) {
return parseFloat(match[0]);
}
}
return 0.0;
}
export function parseGPX(gpxData: string): GPXFile { export function parseGPX(gpxData: string): GPXFile {
const parser = new XMLParser({ const parser = new XMLParser({
ignoreAttributes: false, ignoreAttributes: false,
@@ -38,7 +56,7 @@ export function parseGPX(gpxData: string): GPXFile {
}, },
attributeValueProcessor(attrName, attrValue, jPath) { attributeValueProcessor(attrName, attrValue, jPath) {
if (attrName === 'lat' || attrName === 'lon') { if (attrName === 'lat' || attrName === 'lon') {
return parseFloat(attrValue); return safeParseFloat(attrValue);
} }
return attrValue; return attrValue;
}, },
@@ -52,7 +70,7 @@ export function parseGPX(gpxData: string): GPXFile {
tagValueProcessor(tagName, tagValue, jPath, hasAttributes, isLeafNode) { tagValueProcessor(tagName, tagValue, jPath, hasAttributes, isLeafNode) {
if (isLeafNode) { if (isLeafNode) {
if (tagName === 'ele') { if (tagName === 'ele') {
return parseFloat(tagValue); return safeParseFloat(tagValue);
} }
if (tagName === 'time') { if (tagName === 'time') {
@@ -67,14 +85,14 @@ export function parseGPX(gpxData: string): GPXFile {
tagName === 'gpx_style:opacity' || tagName === 'gpx_style:opacity' ||
tagName === 'gpx_style:width' tagName === 'gpx_style:width'
) { ) {
return parseFloat(tagValue); return safeParseFloat(tagValue);
} }
if (tagName === 'gpxpx:PowerExtension') { if (tagName === 'gpxpx:PowerExtension') {
// Finish the transformation of the simple <power> tag to the more complex <gpxpx:PowerExtension> tag // Finish the transformation of the simple <power> tag to the more complex <gpxpx:PowerExtension> tag
// Note that this only targets the transformed <power> tag, since it must be a leaf node // Note that this only targets the transformed <power> tag, since it must be a leaf node
return { return {
'gpxpx:PowerInWatts': parseFloat(tagValue), 'gpxpx:PowerInWatts': safeParseFloat(tagValue),
}; };
} }
} }