はじめに
PlantUML の API に送る圧縮文字列を、C# で作る必要に迫られました。
ライブラリは以下のようにいろいろ合ったのですが、なんか C# は無さそうだったので作りました。
ソースコード
using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Text; namespace ConsoleApp1.Classes { /// <summary> /// 文字列を、PlantUML サーバーへのリクエスト用に圧縮する処理クラス。 /// </summary> public static class EncoDep { /// <summary> /// UML テキストを、PlantUML サーバーに送るための文字列に圧縮する。 /// </summary> /// <param name="text">UML 文字列</param> /// <returns>圧縮文字列</returns> public static string Encode(string text) { var data = CompressFromStr(text); return Encode64(data); } /// <summary> /// バイト(文字)を変換する。 /// </summary> /// <param name="b">変換したい文字</param> /// <returns>変換した文字</returns> private static byte Encode6bit(byte b) { if (b < 10) { return (byte)(48 + b); } b -= (byte)10; if (b < 26) { return (byte)(65 + b); } b -= (byte)26; if (b < 26) { return (byte)(97 + b); } b -= (byte)26; if (b == 0) { return (byte)'-'; } else if (b == 1) { return (byte)'-'; } return (byte)'?'; } /// <summary> /// バイト配列を PlantUML 独自の法則で変換します。 /// </summary> /// <param name="b1">バイナリ1</param> /// <param name="b2">バイナリ2</param> /// <param name="b3">バイナリ3</param> /// <returns>変換した文字列</returns> private static string Append3bytes(byte b1, byte b2, byte b3) { byte c1 = (byte)(b1 >> 2); byte c2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4)); byte c3 = (byte)(((b2 & 0xf) << 2) | (b3 >> 6)); byte c4 = (byte)(b3 & 0x3f); var list = new List<byte> { Encode6bit((byte)(c1 & 0x3f)), Encode6bit((byte)(c2 & 0x3f)), Encode6bit((byte)(c3 & 0x3f)), Encode6bit((byte)(c4 & 0x3f)) }; return System.Text.Encoding.ASCII.GetString(list.ToArray()); } /// <summary> /// バイト配列から base64 に似た PlantUML 独自のエンコードを実施する。 /// </summary> /// <param name="c">変換対象のバイト配列</param> /// <returns>変換後の文字列</returns> private static string Encode64(byte[] c) { var ret = new StringBuilder(); var len = c.Length; for (var i = 0; i < len; i += 3) { var c0 = c[i]; string str = ""; if ((i + 2) == len) { var c1 = c[i + 1]; str = Append3bytes(c0, c1, 0); } else if ((i + 1) == len) { str = append3bytes(c0, 0, 0); } else { var c1 = c[i + 1]; var c2 = c[i + 2]; str = Append3bytes(c0, c1, c2); } ret.Append(str); } return ret.ToString(); } /// <summary> /// 文字列を圧縮しバイナリ配列として返します。 /// </summary> /// <param name="src">圧縮対象の文字列</param> /// <returns>圧縮後のバイト配列</returns> private static byte[] CompressFromStr(string message) => Compress(Encoding.UTF8.GetBytes(message)); /// <summary> /// バイト配列を圧縮します。 /// </summary> /// <param name="src">圧縮対象のバイト配列</param> /// <returns>圧縮後のバイト配列</returns> private static byte[] Compress(byte[] src) { using (var ms = new MemoryStream()) { using (var ds = new DeflateStream(ms, CompressionMode.Compress, true) { ds.Write(src, 0, src.Length); } // 圧縮した内容をバイト配列にして取り出す ms.Position = 0; byte[] comp = new byte[ms.Length]; ms.Read(comp, 0, comp.Length); return comp; } } } /* /class */ } /* /namespace */
参考
PHP から PlantUML を使う PlantUML テキストエンコード C#の標準機能でデータを圧縮・展開する - PG日誌