using System.Collections; using System.Collections.Generic; using System.Text.RegularExpressions; namespace Rokojori { public class SVGPathParser { public static readonly string SVGPathCommands = "mlhvcsqtaz"; List commands = new List(); List messages = new List(); public static List Parse( string d ) { var svgPath = new SVGPathParser(); var commands = svgPath.ParseCommands( d ); if ( Messages.HasError( svgPath.messages ) ) { return null; } return commands; } public static List GetMessages( string d ) { var svgPath = new SVGPathParser(); var commands = svgPath.ParseCommands( d ); return svgPath.messages; } public List ParseCommands( string d ) { for ( int i = 0; i < d.Length; i++ ) { if ( d[ i ] == ' ' ) { continue; } var lowerCase = ( d[ i ] + "" ).ToLower(); var commandIndex = SVGPathCommands.IndexOf( lowerCase ); if ( commandIndex == -1 ) { Messages.Error( messages, "Unknown command at '" + i + "'. Found " + d[ i ] ); return null; } var commandEnd = ProcessCommand( d, i ); // RJLog.Log( "Processing", d[ i ], ">>", lowerCase, " ends ", commandEnd ); if ( commandEnd == -1 || Messages.HasError( messages ) ) { Messages.Error( messages, "Command couldn't be processed at '" + i + "'. Processed " + d[ i ] ); return null; } i = commandEnd; } return commands; } int ProcessCommand( string d, int offset ) { var end = FindEnd( d, offset + 1 ); var pc = new SVGPathCommand(); pc.type = d[ offset ] + ""; pc.pathIndex = commands.Count; ReadParameters( pc, d, offset + 1, end ); commands.Add( pc ); return end; } int FindEnd( string d, int offset ) { for ( int i = offset; i < d.Length; i++ ) { var chr = ( d[ i ] + "" ).ToLower(); if ( SVGPathParser.SVGPathCommands.IndexOf( chr ) != - 1 ) { return i - 1; } } return d.Length - 1; } void ReadParameters( SVGPathCommand command, string d, int start, int end ) { var parameters = d.Substring( start, ( end + 1 ) - start ); parameters = parameters.Trim(); // RJLog.Log( "Parsing parameters:", parameters ); var regex = new Regex( " |," ); var splitted = RegexUtility.Split( parameters, " |," ); splitted.ForEach( ( s )=> { var number = RegexUtility.ParseFloat( s.Trim() ); command.paramaters.Add( number ); // RJLog.Log( s, ">>", number ); } ); } void ReadParametersOld( SVGPathCommand command, string d, int start, int end ) { var matcher = LexerMatcherLibrary.NumberMatcher; var offset = start; var isNegative = false; while ( offset < end ) { if ( d[ offset ] == ' ' || d[ offset ] == ',' ) { offset ++; isNegative = false; continue; } if ( d[ offset ] == '-' ) { offset ++; isNegative = true; continue; } var matchLength = matcher.MatchLength( d, offset ); if ( matchLength == -1 ) { Messages.Error( messages, "Found no number." + " Offset:" + offset + " Start: " + start + " End: " + end + " Part: " + "'" + d.Substring( start, end - start ) + "'" ); return; } var endIndex = offset + matchLength; if ( endIndex > end ) { Messages.Error( messages, "Number parsing exceeded expected end." + " Offset:" + offset + " Start: " + start + " End: " + end + " Match End: " + endIndex + " Part: " + "'" + d.Substring( start, end - start ) + "'" ); return; } var number = RegexUtility.ParseFloat( d.Substring( offset, matchLength ) ); if ( isNegative ) { number = -number; } offset += matchLength; command.paramaters.Add( number ); isNegative = false; } } } }