diff --git a/2019/02/Docxument.cs b/2019/02/Docxument.cs new file mode 100644 index 0000000..44af90e --- /dev/null +++ b/2019/02/Docxument.cs @@ -0,0 +1,248 @@ +using ICSharpCode.SharpZipLib.Zip; +using System; +using System.Collections.Generic; +using System.IO; +using System.Security; +using System.Text; + +namespace HiImRay +{ + public class Docxument + { + protected string Filename { get; set; } + + public int CompressionLevel { get; set; } = 9; + public Dictionary ReplacementWords = new Dictionary(); + public Dictionary>> ReplacementParagraphs = new Dictionary>>(); + + public Docxument() + { + } + + public Docxument(string filename) + { + Load(filename); + } + + public void Load(string filename) + { + this.Filename = filename; + } + + public void Save(string saveFilename) + { + int size = 2048; + byte[] buffer = new byte[size]; + int bufferSize = 0; + + // read file + ZipEntry readEntry = null; + ZipInputStream readStream = new ZipInputStream(File.OpenRead(this.Filename)); + + // write file + ZipOutputStream writeStream = new ZipOutputStream(File.Create(saveFilename)); + writeStream.SetLevel(this.CompressionLevel); + + // loop + while (true) + { + readEntry = readStream.GetNextEntry(); + if (readEntry == null) + { + break; + } + + if (string.IsNullOrWhiteSpace(readEntry.Name)) + { + break; + } + + if (!readEntry.IsFile) + { + continue; + } + + // change document + if (readEntry.Name.Equals("word/document.xml")) + { + MemoryStream ms = new MemoryStream(); + buffer = new byte[size]; + bufferSize = 0; + + do + { + bufferSize = readStream.Read(buffer, 0, buffer.Length); + ms.Write(buffer, 0, bufferSize); + } while (bufferSize > 0); + + ms.Position = 0; + + StreamReader sr = new StreamReader(ms); + StringBuilder sb = new StringBuilder(); + sb.Append(sr.ReadToEnd()); + + // make changes + sb = replaceTokens(sb, this.ReplacementWords); + sb = replaceParagraphs(sb, this.ReplacementParagraphs); + + // make readable + MemoryStream ms2 = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(sb.ToString())); + ms2.Position = 0; + + // write new document xml + writeStream.PutNextEntry(new ZipEntry(readEntry.Name)); + + buffer = new byte[size]; + bufferSize = 0; + + do + { + bufferSize = ms2.Read(buffer, 0, buffer.Length); + writeStream.Write(buffer, 0, bufferSize); + } while (bufferSize > 0); + + ms2.Close(); + ms2.Dispose(); + } + else + { + writeStream.PutNextEntry(new ZipEntry(readEntry.Name)); + + buffer = new byte[size]; + bufferSize = 0; + + do + { + bufferSize = readStream.Read(buffer, 0, buffer.Length); + writeStream.Write(buffer, 0, bufferSize); + } while (bufferSize > 0); + } + } + + writeStream.Finish(); + writeStream.Flush(); + writeStream.Close(); + writeStream.Dispose(); + + readStream.Close(); + readStream.Dispose(); + } + + protected StringBuilder replaceTokens(StringBuilder sb, Dictionary options) + { + foreach (KeyValuePair item in options) + { + sb.Replace("{{" + item.Key + "}}", SecurityElement.Escape(item.Value)); + } + + return sb; + } + + protected StringBuilder replaceParagraphs(StringBuilder sb, Dictionary>> options) + { + foreach (KeyValuePair>> item in options) + { + sb = replaceParagraph(sb, item); + } + + return sb; + } + + protected StringBuilder replaceParagraph(StringBuilder sb, KeyValuePair>> options) + { + string paragraph = sb.ToString(); + + Tuple outerCoord = getOuterParagraph(paragraph, "{{" + options.Key + "}}"); + if (outerCoord != null) + { + sb.Remove(outerCoord.Item1, outerCoord.Item2); + + Tuple innerCoord = getInnerParagraph(paragraph.Substring(outerCoord.Item1, outerCoord.Item2), "{{" + options.Key + "}}"); + string innerParagraph = paragraph.Substring((innerCoord.Item1 + outerCoord.Item1), innerCoord.Item2); + + StringBuilder innerText = new StringBuilder(); + foreach (Dictionary row in options.Value) + { + StringBuilder sb2 = new StringBuilder(); + sb2.Append(innerParagraph); + + sb2 = replaceTokens(sb2, row); + + innerText.Append(sb2.ToString()); + } + + sb.Insert(outerCoord.Item1, innerText.ToString()); + } + + return sb; + } + + protected Tuple getOuterParagraph(string fullText, string findTerm) + { + string headTerm = "(headIndex, (tailIndex - headIndex)); + } + + protected Tuple getInnerParagraph(string fullText, string findTerm) + { + string headTerm = "(headIndex, (tailIndex - headIndex)); + } + } +}