public static List <string> FormatEncodedData(string data) { List <string> lines = new List <string>(); /* Tokenize the string into "blocks" */ BlockStack stack = new BlockStack(data); List <DataBlock> BlocksForLine = new List <DataBlock>(); EncodeTags lastTypeOnLine = EncodeTags.NONE; while (stack.Count > 0) { BlocksForLine.Clear(); int lineLength = 0; DataBlock currentBlock; if (lines.Count > 0) { if (lastTypeOnLine != EncodeTags.COMMA && stack.Peek().Type != EncodeTags.COMMA && stack.Peek().Type != lastTypeOnLine) { /* different types, inject an empty of the previous type */ DataBlock dummy = new DataBlock() { Type = lastTypeOnLine, Contents = "()" }; BlocksForLine.Add(dummy); lineLength += dummy.Length; } } while (stack.Count > 0) { currentBlock = stack.Pop(); if (lineLength + currentBlock.Length <= 70) { BlocksForLine.Add(currentBlock); lineLength += currentBlock.Length; } else { stack.Push(currentBlock); break; } } /* We've filled the line with as many full blocks as we can */ /* If next block is a length of 4 for ASCII or 5 for BINARY, add it */ if (lineLength < 70 && stack.Count > 0) { var needsSplit = true; switch (stack.Peek().Type) { case EncodeTags.ASCII: if (stack.Peek().Length == 4) { BlocksForLine.Add(stack.Pop()); needsSplit = false; } break; case EncodeTags.BINARY: if (stack.Peek().Length == 5) { BlocksForLine.Add(stack.Pop()); needsSplit = false; } break; case EncodeTags.COMMA: BlocksForLine.Add(stack.Pop()); needsSplit = false; break; } if (needsSplit) { /* determine if we can split it */ var blockToSplit = stack.Pop(); Tuple <DataBlock, DataBlock> splitParts = blockToSplit.Split(70 - lineLength); if (splitParts.Item2 != null) { stack.Push(splitParts.Item2); } BlocksForLine.Add(splitParts.Item1); } } else { if (BlocksForLine.Sum(b => b.Length) == 70) { if (stack.Count > 0 && BlocksForLine.Last().Type == EncodeTags.COMMA) { var blockToSplit = stack.Pop(); Tuple <DataBlock, DataBlock> splitParts = blockToSplit.Split(70 - lineLength); if (splitParts.Item2 != null) { stack.Push(splitParts.Item2); } BlocksForLine.Add(splitParts.Item1); } } } lastTypeOnLine = BlocksForLine.Last().Type; /* if the next token happens to be a comma, just add it?*/ if (stack.Count > 0 && stack.Peek().Type == EncodeTags.COMMA) { BlocksForLine.Add(stack.Pop()); lastTypeOnLine = EncodeTags.COMMA; } /* Process all blocks to string */ StringBuilder line = new StringBuilder(); foreach (DataBlock block in BlocksForLine) { switch (block.Type) { case EncodeTags.ASCII: line.Append("A"); break; case EncodeTags.BINARY: line.Append("B"); break; } line.Append(block.Contents); } var lineText = line.ToString(); lines.Add(lineText); line.Clear(); line = null; } return(lines); }
public static string EncodeData(byte[] data) { StringBuilder sb = new StringBuilder(); EncodeTags currentTag = EncodeTags.NONE; foreach (byte b in data) { if (b >= 32 && b < 127 && (char)b != ']' && (char)b != '[') { /* we'll treat this as an ascii character */ switch (currentTag) { case EncodeTags.NONE: sb.Append("A("); currentTag = EncodeTags.ASCII; break; case EncodeTags.BINARY: sb.Append(")A("); currentTag = EncodeTags.ASCII; break; case EncodeTags.ASCII: break; } if ((char)b == ')' || (char)b == '(') { sb.Append($"\\{(char)b}"); } else if ((char)b == '\\') { sb.Append("\\\\"); } else { sb.Append((char)b); } } else { /* we'll treat this as a binary */ switch (currentTag) { case EncodeTags.NONE: sb.Append("B("); currentTag = EncodeTags.BINARY; break; case EncodeTags.ASCII: sb.Append(")B("); currentTag = EncodeTags.BINARY; break; case EncodeTags.BINARY: break; } sb.Append(EncodeByte(b)); } } if (currentTag != EncodeTags.NONE) { sb.Append(")"); } return(sb.ToString()); }