diff --git a/js/__snapshots__/regionParser.test.js.snap b/js/__snapshots__/regionParser.test.js.snap index 8be85f71..ebbee1ca 100644 --- a/js/__snapshots__/regionParser.test.js.snap +++ b/js/__snapshots__/regionParser.test.js.snap @@ -397,3 +397,28 @@ Object { ], } `; + +exports[`regionParser parses a file with section headers but no info 1`] = ` +Object { + "equalizer": Array [ + "0,0 0,115 20,20 274,115 274,0", + ], + "normal": Array [ + "1,0 275,0 275,115 1,115", + ], +} +`; + +exports[`regionParser parses the EVAunit region.txt 1`] = ` +Object { + "equalizer": Array [ + "4,0 4,3 2,3 0,5 0,116 275,116 275,5 273,3 270,3 270,0 237,0 237,3 183,3 183,0 129,0 129,3 17,3 17,0", + ], + "normal": Array [ + "9,0 9,3 2,3 0,5 0,104 2,107 4,107 4,116 17,116 17,107 129,107 129,116 183,116 183,107 237,107 237,116 270,116 270,107 272,107 275,104 275,5 273,3 271,3 272,4 266,4 266,3 261,3 262,4 256,4 256,3 251,3 252,4 246,4 246,3 243,3 243,0", + ], + "windowshade": Array [ + "9,0 9,3 2,3 0,5 0,14 275,14 275,5 273,3 271,3 271,4 266,4 266,3 261,3 261,4 256,4 256,3 251,3 251,4 246,4 246,3 243,3 243,0 157,0 157,3 130,3 130,0", + ], +} +`; diff --git a/js/__tests__/fixtures/region_empty_sections.txt b/js/__tests__/fixtures/region_empty_sections.txt new file mode 100755 index 00000000..acee9f77 --- /dev/null +++ b/js/__tests__/fixtures/region_empty_sections.txt @@ -0,0 +1,20 @@ +[Normal] +; This region info generated by Winamp region.txt generator which is made by Maxim. +; http://winamp.mwos.cjb.net +; Note to skin authors: You can remove these comments so long as you leave one copy of the two lines above. +NumPoints=8,4,6 +PointList= 1,0 275,0 275,115 1,115 + + + + +[Equalizer] +NumPoints=12 +PointList= 0,0 0,115 20,20 274,115 274,0 + + +[WindowShade] + + + +[EqualizerWS] diff --git a/js/__tests__/fixtures/region_eva.txt b/js/__tests__/fixtures/region_eva.txt new file mode 100755 index 00000000..f0ea7f01 --- /dev/null +++ b/js/__tests__/fixtures/region_eva.txt @@ -0,0 +1,13 @@ +;Regions for EVA unit-02 Skin! +;(c) Jasterz 2004 +[Normal] +NumPoints=36 +PointList=9,0 9,3 2,3 0,5 0,104 2,107 4,107 4,116 17,116 17,107 129,107 129,116 183,116 183,107 237,107 237,116 270,116 270,107 272,107 275,104 275,5 273,3 271,3 272,4 266,4 266,3 261,3 262,4 256,4 256,3 251,3 252,4 246,4 246,3 243,3 243,0 + +[WindowShade] +NumPoints=26 +PointList=9,0 9,3 2,3 0,5 0,14 275,14 275,5 273,3 271,3 271,4 266,4 266,3 261,3 261,4 256,4 256,3 251,3 251,4 246,4 246,3 243,3 243,0 157,0 157,3 130,3 130,0 + +[Equalizer] +NumPoints=18 +PointList=4,0 4,3 2,3 0,5 0,116 275,116 275,5 273,3 270,3 270,0 237,0 237,3 183,3 183,0 129,0 129,3 17,3 17,0 \ No newline at end of file diff --git a/js/regionParser.js b/js/regionParser.js index 1d37252d..48e86fb9 100644 --- a/js/regionParser.js +++ b/js/regionParser.js @@ -1,8 +1,8 @@ import { parseIni } from "./utils"; -function pointPairs(arr) { +export function pointPairs(arr) { const pairedValues = []; - for (let i = 0; i <= arr.length; i += 2) { + for (let i = 0; i < arr.length; i += 2) { pairedValues.push(`${arr[i]},${arr[i + 1]}`); } return pairedValues; @@ -11,18 +11,29 @@ function pointPairs(arr) { export default function regionParser(regionStr) { const iniData = parseIni(regionStr); const data = {}; - Object.keys(iniData).forEach(key => { - const numPoints = iniData[key].numpoints.split(/\s*,\s*/); - // coords can be separated by spaces, or by commas - const coords = iniData[key].pointlist.split(/\s*[, ]\s*/); - const pointList = pointPairs(coords); + Object.keys(iniData).forEach(section => { + const { numpoints, pointlist } = iniData[section]; + if (!numpoints || !pointlist) { + return; + } + const pointCounts = numpoints.split(/\s*,\s*/); + // points can be separated by spaces, or by commas + const points = pointPairs(pointlist.split(/\s*[, ]\s*/)); let pointIndex = 0; - data[key] = numPoints.map(numStr => { + const polygons = pointCounts.map(numStr => { const num = Number(numStr); - const polygon = pointList.slice(pointIndex, pointIndex + num).join(" "); + const polygon = points.slice(pointIndex, pointIndex + num).join(" "); + if (!polygon.length) { + // It's possible that the skin author specified more polygons than provided points. + return null; + } pointIndex += num; return polygon; }); + const validPolygons = polygons.filter(polygon => polygon != null); + if (validPolygons.length) { + data[section] = validPolygons; + } }); return data; diff --git a/js/regionParser.test.js b/js/regionParser.test.js index d4be5be9..091e8cc0 100644 --- a/js/regionParser.test.js +++ b/js/regionParser.test.js @@ -1,5 +1,13 @@ import fs from "fs"; -import regionParser from "./regionParser"; +import regionParser, { pointPairs } from "./regionParser"; + +describe("pointPairs", () => { + it("8", () => { + expect( + pointPairs(["1", "0", "275", "0", "275", "115", "1", "115"]) + ).toEqual(["1,0", "275,0", "275,115", "1,115"]); + }); +}); describe("regionParser", () => { it("parses the default file as empty", () => { @@ -16,4 +24,18 @@ describe("regionParser", () => { ); expect(regionParser(regionTxt)).toMatchSnapshot(); }); + it("parses a file with section headers but no info", () => { + const regionTxt = fs.readFileSync( + "./js/__tests__/fixtures/region_empty_sections.txt", + "utf8" + ); + expect(regionParser(regionTxt)).toMatchSnapshot(); + }); + it("parses the EVAunit region.txt", () => { + const regionTxt = fs.readFileSync( + "./js/__tests__/fixtures/region_eva.txt", + "utf8" + ); + expect(regionParser(regionTxt)).toMatchSnapshot(); + }); });