Skip to content

Instantly share code, notes, and snippets.

@tomzorz
Created November 5, 2014 12:31
Show Gist options
  • Save tomzorz/96f64cc1f247bfa6406f to your computer and use it in GitHub Desktop.
Save tomzorz/96f64cc1f247bfa6406f to your computer and use it in GitHub Desktop.
Manageable WinRT NavigationState string
/// <summary>
/// A class to parse and edit the WinRT internal navigationState string (Windows 6.3.9600, 2014.11.04.)
/// </summary>
public class NavigationState
{
public static readonly Dictionary<Type, int> ValidParameterTypes = new Dictionary<Type, int>()
{
{typeof(byte), 1},
{typeof(short), 2},
{typeof(ushort), 3},
{typeof(int), 4},
{typeof(uint), 5},
{typeof(long), 6},
{typeof(ulong), 7},
{typeof(float), 8},
{typeof(double), 9},
{typeof(char), 10},
{typeof(bool), 11},
{typeof(string), 12},
{typeof(Guid), 16}
};
public NavigationState(string initialState = "1,0")
{
var split = initialState.Split(',');
if(split[0] != "1") throw new Exception("NavigationState version mismatch!");
NavigationHistory = new List<Tuple<string, object>>();
if (Convert.ToInt32(split[1]) > 0)
{
CurrentNavigationIndex = Convert.ToInt32(split[2]);
ParseState(split.Skip(3));
}
else
{
CurrentNavigationIndex = null;
}
}
private void ParseState(IEnumerable<string> list)
{
var data = list.ToList();
int currentPageNameSize = 0;
string currentPageName = "";
Type currentParameterType = null;
int currentParameterSize = 0;
object currentParameter = null;
var currentState = ParserState.PageSize;
// ReSharper disable once ForCanBeConvertedToForeach
for (var currentIndex = 0; currentIndex < data.Count; currentIndex++)
{
switch (currentState)
{
case ParserState.PageSize:
currentPageNameSize = Convert.ToInt32(data[currentIndex]);
currentState = ParserState.PageData;
break;
case ParserState.PageData:
currentPageName = data[currentIndex];
if(currentPageName.Length != currentPageNameSize) throw new Exception("Invalid NavigationState string: Page name length mismatch.");
currentState = ParserState.ParameterType;
break;
case ParserState.ParameterType:
int currentParameterTypeId = Convert.ToInt32(data[currentIndex]);
if (currentParameterTypeId == 0)
{
currentParameterType = null;
currentState = ParserState.UnknownEnding;
}
else
{
if(!ValidParameterTypes.ContainsValue(currentParameterTypeId)) throw new Exception("Invalid NavigationState string: Parameter type ID is wrong.");
currentParameterType = ValidParameterTypes.Single(x => x.Value == currentParameterTypeId).Key;
currentState = ParserState.ParameterSize;
}
break;
case ParserState.ParameterSize:
currentParameterSize = Convert.ToInt32(data[currentIndex]);
currentState = ParserState.ParameterContent;
break;
case ParserState.ParameterContent:
var tmpContent = data[currentIndex];
if (tmpContent.Length != currentParameterSize) throw new Exception("Invalid NavigationState string: Parameter data length mismatch.");
currentParameter = ParseParameter(tmpContent, currentParameterType);
currentState = ParserState.UnknownEnding;
break;
case ParserState.UnknownEnding:
NavigationHistory.Add(Tuple.Create(currentPageName, currentParameter));
currentState = ParserState.PageSize;
break;
default:
//hopefully nothing to do
break;
}
}
}
public static object ParseParameter(string tmpContent, Type cpt)
{
if (cpt == typeof (short))
{
return short.Parse(tmpContent);
}
if (cpt == typeof(ushort))
{
return ushort.Parse(tmpContent);
}
if (cpt == typeof(int))
{
return int.Parse(tmpContent);
}
if (cpt == typeof(uint))
{
return uint.Parse(tmpContent);
}
if (cpt == typeof(long))
{
return long.Parse(tmpContent);
}
if (cpt == typeof(ulong))
{
return ulong.Parse(tmpContent);
}
if (cpt == typeof(float))
{
return float.Parse(tmpContent);
}
if (cpt == typeof(double))
{
return double.Parse(tmpContent);
}
if (cpt == typeof(char))
{
return tmpContent[0];
}
if (cpt == typeof(bool))
{
return bool.Parse(tmpContent);
}
if (cpt == typeof(string))
{
return tmpContent;
}
if (cpt == typeof(Guid))
{
return Guid.Parse(tmpContent);
}
return null;
}
public static string ParameterToString(object content)
{
return content is Guid ? "{" + content.ToString() + "}" : content.ToString();
}
private enum ParserState
{
PageSize,
PageData,
ParameterType,
ParameterSize,
ParameterContent,
UnknownEnding
}
public List<Tuple<string, object>> NavigationHistory { get; set; }
public int HistoryCount
{
get { return NavigationHistory == null ? 0 : NavigationHistory.Count; }
}
public int? CurrentNavigationIndex { get; set; }
public override string ToString()
{
var sb = new StringBuilder();
//version
sb.Append("1,");
//page count
sb.Append(NavigationHistory.Count);
if (!NavigationHistory.Any())
{
return sb.ToString();
}
else
{
sb.Append(",");
}
//current index
sb.Append(CurrentNavigationIndex + ",");
//pages
foreach (var tuple in NavigationHistory)
{
//page name length
sb.Append(tuple.Item1.Length + ",");
//page name
sb.Append(tuple.Item1 + ",");
//parameter
if (tuple.Item2 != null)
{
var content = ParameterToString(tuple.Item2);
//p type
sb.Append(ValidParameterTypes[tuple.Item2.GetType()] + ",");
//p size
sb.Append(content.Length + ",");
//p content
sb.Append(tuple.Item2.ToString() + ",");
}
else
{
sb.Append("0,");
}
//unknown
sb.Append("0");
//separator
// ReSharper disable once PossibleUnintendedReferenceComparison
if (tuple != NavigationHistory.Last()) sb.Append(",");
}
return sb.ToString();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment