public void WriteZString([NotNull] string str, bool withLength, StringEncoderMode mode = StringEncoderMode.Normal) { MaybeProcessEscapeChars(ref str); var zstr = StringEncoder.Encode(str, mode); if (FinalPass && AbbreviateMode) { AbbrevFinder.AddText(str); } if (withLength) { WriteByte((byte)(zstr.Length / 2)); } position += zstr.Length; stream?.Write(zstr, 0, zstr.Length); }
public byte[] Encode(string str, int?size, StringEncoderMode mode, out int zchars) { var noAbbrevs = mode == StringEncoderMode.NoAbbreviations; if (!noAbbrevs) { Frozen = true; } var temp = new List <byte>(); var sb = new StringBuilder(str); // temporarily replace abbreviated strings with Unicode private use characters (E000-E05F) if (!noAbbrevs) { for (int i = 0; i < abbrevs.Count; i++) { var idx = abbrevs[i].Pattern.FindIn(sb); while (idx >= 0) { sb.Remove(idx, abbrevs[i].Pattern.Text.Length - 1); sb[idx] = (char)(0xE000 + abbrevs[i].Number); idx = abbrevs[i].Pattern.FindIn(sb); } } } for (int i = 0; i < sb.Length; i++) { char c = sb[i]; if (c == ' ') { temp.Add(0); } else if (c == '\n') { temp.Add(5); temp.Add(7); } else if (!noAbbrevs && c >= '\ue000' && c < '\ue060') { int abbrNum = c - '\ue000'; temp.Add((byte)(1 + abbrNum / 32)); temp.Add((byte)(abbrNum % 32)); } else { if (UnicodeTranslation.Table.TryGetValue(c, out byte b) == false) { b = (byte)c; } int idx; if ((idx = Array.IndexOf(charset[0], b)) >= 0) { temp.Add((byte)(idx + 6)); } else if ((idx = Array.IndexOf(charset[1], b)) >= 0) { temp.Add(4); temp.Add((byte)(idx + 6)); } else if ((idx = Array.IndexOf(charset[2], b)) >= 0) { temp.Add(5); temp.Add((byte)(idx + 8)); } else { temp.Add(5); temp.Add(6); temp.Add((byte)((b >> 5) & 31)); temp.Add((byte)(b & 31)); } } } zchars = temp.Count; int resultSize; if (size == null) { if (temp.Count == 0) { temp.Add(5); } while (temp.Count % 3 != 0) { temp.Add(5); } resultSize = temp.Count * 2 / 3; } else { while (temp.Count < size) { temp.Add(5); } resultSize = size.Value * 2 / 3; } var result = new byte[Math.Min(resultSize, temp.Count * 2 / 3)]; for (int i = 0, t = 0; i < result.Length;) { // _aaaaabb bbbccccc byte a = temp[t++], b = temp[t++], c = temp[t++]; result[i++] = (byte)(a << 2 | b >> 3); result[i++] = (byte)(b << 5 | c); } if (result.Length >= 2) { result[result.Length - 2] |= 0x80; } return(result); }
public byte[] Encode(string str, StringEncoderMode mode) => Encode(str, null, mode);
public byte[] Encode(string str, int?size, StringEncoderMode mode) => Encode(str, size, mode, out _);