private bool CheckIndices(int[] Indices, ShocoPack Pack) { // TODO: Investigate hardware acceleration for (int i = 0; i < Pack.BytesUnpacked; ++i) { if (Indices[i] > Pack.masks[i]) { return(false); } } return(true); }
/// <summary> /// Reads a C Header into a ShocoModel /// </summary> /// <param name="FileContent">C Header source</param> /// <returns>ShocoModel representation from the C Header</returns> public static ShocoModel ReadFromCHeaderContent(string FileContent) { Match match; Match subMatch; CaptureCollection captures; int dimention1; int dimention2; int minimumCharacter; int maximumCharacter; int maximumSuccessorLength; byte[] charactersById; byte[] idsByCharacter; byte[,] successorIdsByCharacterId = null; byte[,] charactersBySuccessorId = null; ShocoPack[] packs; match = Regex.Match(FileContent, @"^#define\s+MIN_CHR\s+(\d+)", RegexOptions.Multiline); if (!match.Success) { throw new ArgumentException("Could not extract MIN_CHR value", nameof(FileContent)); } if (!int.TryParse(match.Groups[1].Value, out minimumCharacter)) { throw new ArgumentException("Invalid MIN_CHR value present", nameof(FileContent)); } match = Regex.Match(FileContent, @"^#define\s+MAX_CHR\s+(\d+)", RegexOptions.Multiline); if (!match.Success) { throw new ArgumentException("Could not extract MAX_CHR value", nameof(FileContent)); } if (!int.TryParse(match.Groups[1].Value, out maximumCharacter)) { throw new ArgumentException("Invalid MAX_CHR value present", nameof(FileContent)); } match = Regex.Match(FileContent, @"^#define\s+MAX_SUCCESSOR_N\s+(\d+)", RegexOptions.Multiline); if (!match.Success) { throw new ArgumentException("Could not extract MAX_SUCCESSOR_N value", nameof(FileContent)); } if (!int.TryParse(match.Groups[1].Value, out maximumSuccessorLength)) { throw new ArgumentException("Invalid MAX_CHR value present", nameof(FileContent)); } match = Regex.Match(FileContent, @"chrs_by_chr_id\[[^{}]+?{(?:\s*'(\\[abfnrtv\\'""?e]|\\\d\d\d|\\x[\dA-Fa-f]{2}|.)'\s*,?\s*)+}"); if (!match.Success) { throw new ArgumentException("Could not extract chrs_by_chr_id values", nameof(FileContent)); } charactersById = match.Groups[1].Captures.Cast <Capture>().Select(c => c.Value).Select(UnescapeC).ToArray(); match = Regex.Match(FileContent, @"chr_ids_by_chr\[[^{}]+?{(?:\s*([\d-]+)\s*,?\s*)+}"); if (!match.Success) { throw new ArgumentException("Could not extract chr_ids_by_chr values", nameof(FileContent)); } idsByCharacter = match.Groups[1].Captures.Cast <Capture>().Select(c => c.Value).Select(ParseCByte).ToArray(); match = Regex.Match(FileContent, @"successor_ids_by_chr_id_and_chr_id\[[^{}]+?{(?:\s*{((?:\s*[\d-]+\s*,?\s*)+)}\s*,?)*}"); if (!match.Success) { throw new ArgumentException("Could not extract successor_ids_by_chr_id_and_chr_id values", nameof(FileContent)); } dimention1 = match.Groups[1].Captures.Count; dimention2 = 0; for (int d1 = 0; d1 < dimention1; d1++) { subMatch = Regex.Match(match.Groups[1].Captures[d1].Value, @"(?:\s*([\d-]+)\s*,?\s*)+"); if (!subMatch.Success) { throw new ArgumentException("Could not extract successor_ids_by_chr_id_and_chr_id values", nameof(FileContent)); } captures = subMatch.Groups[1].Captures; if (successorIdsByCharacterId == null) { dimention2 = captures.Count; successorIdsByCharacterId = new byte[dimention1, dimention2]; } for (int d2 = 0; d2 < dimention2; d2++) { successorIdsByCharacterId[d1, d2] = ParseCByte(captures[d2].Value); } } match = Regex.Match(FileContent, @"chrs_by_chr_and_successor_id\[[^{}]+?{(\s*{(?:\s*'(?:\\[abfnrtv\\'""?e]|\\\d\d\d|\\x[\dA-Fa-f]{2}|.)'\s*,?\s*)+}\s*,?)*}"); if (!match.Success) { throw new ArgumentException("Could not extract chrs_by_chr_and_successor_id values", nameof(FileContent)); } dimention1 = match.Groups[1].Captures.Count; if (dimention1 != maximumCharacter - minimumCharacter) { throw new ArgumentException("Could not extract chrs_by_chr_and_successor_id values; invalid length", nameof(FileContent)); } dimention2 = 0; for (int d1 = 0; d1 < dimention1; d1++) { subMatch = Regex.Match(match.Groups[1].Captures[d1].Value, @"(?:\s*'(\\[abfnrtv\\'""?e]|\\\d\d\d|\\x[\dA-Fa-f]{2}|.)'\s*,?\s*)+"); if (!subMatch.Success) { throw new ArgumentException("Could not extract chrs_by_chr_and_successor_id values", nameof(FileContent)); } captures = subMatch.Groups[1].Captures; if (charactersBySuccessorId == null) { dimention2 = captures.Count; charactersBySuccessorId = new byte[dimention1, dimention2]; } for (int d2 = 0; d2 < dimention2; d2++) { charactersBySuccessorId[d1, d2] = UnescapeC(captures[d2].Value); } } match = Regex.Match(FileContent, @"Pack packs\[[^{}]+?{(\s*{\s*0x[^\s,]*\s*,\s*\d+\s*,\s*\d+\s*,\s*{[^}]*}\s*,\s*{[^}]*}\s*,\s*0x[0-9A-Fa-f]{2}\s*,\s*0x[0-9A-Fa-f]{2}\s*}\s*,?)+\s*}"); if (!match.Success) { throw new ArgumentException("Could not extract packs", nameof(FileContent)); } packs = new ShocoPack[match.Groups[1].Captures.Count]; for (int i = 0; i < packs.Length; i++) { var capture = match.Groups[1].Captures[i]; subMatch = Regex.Match(capture.Value, @"\s*{\s*0x([^\s,]*)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*{(?:\s*(\d+)\s*,?)*}\s*,\s*{(?:\s*(\d+)\s*,?)*}\s*,\s*0x[0-9A-Fa-f]{2}\s*,\s*0x[0-9A-Fa-f]{2}\s*}"); if (!subMatch.Success) { throw new ArgumentException("Could not extract pack", nameof(FileContent)); } if (!uint.TryParse(subMatch.Groups[1].Value, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out var code_word)) { throw new ArgumentException("Could not extract pack code word", nameof(FileContent)); } if (!int.TryParse(subMatch.Groups[2].Value, out var bytes_packed)) { throw new ArgumentException("Could not extract pack bytes_packed", nameof(FileContent)); } if (!int.TryParse(subMatch.Groups[3].Value, out var bytes_unpacked)) { throw new ArgumentException("Could not extract pack bytes_unpacked", nameof(FileContent)); } var offsets = subMatch.Groups[4].Captures.Cast <Capture>().Select(c => c.Value).Select(int.Parse).ToArray(); var masks = subMatch.Groups[5].Captures.Cast <Capture>().Select(c => c.Value).Select(int.Parse).ToArray(); packs[i] = new ShocoPack( Header: (byte)(code_word >> 24), BytesPacked: bytes_packed, BytesUnpacked: bytes_unpacked, Offsets: offsets, Masks: masks); } return(new ShocoModel(minimumCharacter, maximumCharacter, maximumSuccessorLength, charactersById, idsByCharacter, successorIdsByCharacterId, charactersBySuccessorId, packs)); }