PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/src/sys/dotnet/fan/sys/OutStream.cs

https://bitbucket.org/bedlaczech/fan-1.0
C# | 480 lines | 393 code | 46 blank | 41 comment | 50 complexity | 21b0ed421ee02790ee03b592c6cc714f MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. //
  2. // Copyright (c) 2007, Brian Frank and Andy Frank
  3. // Licensed under the Academic Free License version 3.0
  4. //
  5. // History:
  6. // 16 Jan 07 Andy Frank Creation
  7. //
  8. using Fanx.Serial;
  9. namespace Fan.Sys
  10. {
  11. /// <summary>
  12. /// OutStream.
  13. /// </summary>
  14. public class OutStream : FanObj
  15. {
  16. //////////////////////////////////////////////////////////////////////////
  17. // Construction
  18. //////////////////////////////////////////////////////////////////////////
  19. public static OutStream make(OutStream output)
  20. {
  21. OutStream self = new OutStream();
  22. make_(self, output);
  23. return self;
  24. }
  25. public static void make_(OutStream self, OutStream output)
  26. {
  27. self.m_out = output;
  28. if (output != null) self.charset(output.charset());
  29. }
  30. protected OutStream()
  31. {
  32. m_charset = Charset.utf8();
  33. m_charsetEncoder = m_charset.newEncoder();
  34. }
  35. //////////////////////////////////////////////////////////////////////////
  36. // Obj
  37. //////////////////////////////////////////////////////////////////////////
  38. public override Type @typeof() { return Sys.OutStreamType; }
  39. //////////////////////////////////////////////////////////////////////////
  40. // C# OutputStream
  41. //////////////////////////////////////////////////////////////////////////
  42. /// <summary>
  43. /// Write a byte using a Java primitive int. Most
  44. /// writes route to this method for efficient mapping to
  45. /// a java.io.OutputStream. If we aren't overriding this
  46. /// method, then route back to write(long) for the
  47. /// subclass to handle.
  48. /// <summary>
  49. public virtual OutStream w(int b)
  50. {
  51. return write(b);
  52. }
  53. //////////////////////////////////////////////////////////////////////////
  54. // OutStream
  55. //////////////////////////////////////////////////////////////////////////
  56. public virtual OutStream write(long x)
  57. {
  58. try
  59. {
  60. m_out.write(x);
  61. return this;
  62. }
  63. catch (System.NullReferenceException e)
  64. {
  65. if (m_out == null)
  66. throw UnsupportedErr.make(@typeof().qname() + " wraps null OutStream").val;
  67. else
  68. throw e;
  69. }
  70. }
  71. public virtual OutStream writeBuf(Buf buf) { return writeBuf(buf, buf.remaining()); }
  72. public virtual OutStream writeBuf(Buf buf, long n)
  73. {
  74. try
  75. {
  76. m_out.writeBuf(buf, n);
  77. return this;
  78. }
  79. catch (System.NullReferenceException e)
  80. {
  81. if (m_out == null)
  82. throw UnsupportedErr.make(@typeof().qname() + " wraps null OutStream").val;
  83. else
  84. throw e;
  85. }
  86. }
  87. public virtual Endian endian()
  88. {
  89. return m_bigEndian ? Endian.m_big : Endian.m_little;
  90. }
  91. public virtual void endian(Endian endian)
  92. {
  93. m_bigEndian = endian == Endian.m_big;
  94. }
  95. public virtual OutStream writeI2(long x)
  96. {
  97. int v = (int)x;
  98. if (m_bigEndian)
  99. return this.w((v >> 8) & 0xFF)
  100. .w((v >> 0) & 0xFF);
  101. else
  102. return this.w((v >> 0) & 0xFF)
  103. .w((v >> 8) & 0xFF);
  104. }
  105. public virtual OutStream writeI4(long x)
  106. {
  107. int v = (int)x;
  108. if (m_bigEndian)
  109. return this.w((v >> 24) & 0xFF)
  110. .w((v >> 16) & 0xFF)
  111. .w((v >> 8) & 0xFF)
  112. .w((v >> 0) & 0xFF);
  113. else
  114. return this.w((v >> 0) & 0xFF)
  115. .w((v >> 8) & 0xFF)
  116. .w((v >> 16) & 0xFF)
  117. .w((v >> 24) & 0xFF);
  118. }
  119. public virtual OutStream writeI8(long v)
  120. {
  121. if (m_bigEndian)
  122. return this.w((int)(v >> 56) & 0xFF)
  123. .w((int)(v >> 48) & 0xFF)
  124. .w((int)(v >> 40) & 0xFF)
  125. .w((int)(v >> 32) & 0xFF)
  126. .w((int)(v >> 24) & 0xFF)
  127. .w((int)(v >> 16) & 0xFF)
  128. .w((int)(v >> 8) & 0xFF)
  129. .w((int)(v >> 0) & 0xFF);
  130. else
  131. return this.w((int)(v >> 0) & 0xFF)
  132. .w((int)(v >> 8) & 0xFF)
  133. .w((int)(v >> 16) & 0xFF)
  134. .w((int)(v >> 24) & 0xFF)
  135. .w((int)(v >> 32) & 0xFF)
  136. .w((int)(v >> 40) & 0xFF)
  137. .w((int)(v >> 48) & 0xFF)
  138. .w((int)(v >> 56) & 0xFF);
  139. }
  140. public virtual OutStream writeF4(double x)
  141. {
  142. return writeI4(System.BitConverter.ToInt32(System.BitConverter.GetBytes((float)x), 0));
  143. }
  144. public virtual OutStream writeF8(double x)
  145. {
  146. return writeI8(System.BitConverter.DoubleToInt64Bits(x));
  147. }
  148. public virtual OutStream writeDecimal(BigDecimal x)
  149. {
  150. return writeUtfString(x.ToString());
  151. }
  152. public virtual OutStream writeBool(bool x)
  153. {
  154. return w(x ? 1 : 0);
  155. }
  156. public virtual OutStream writeUtf(string x) { return writeUtfString(x); }
  157. private OutStream writeUtfString(string s)
  158. {
  159. int slen = s.Length;
  160. int utflen = 0;
  161. // first we have to figure m_out the utf Length
  162. for (int i=0; i<slen; ++i)
  163. {
  164. int c = s[i];
  165. if (c <= 0x007F)
  166. utflen +=1;
  167. else if (c > 0x07FF)
  168. utflen += 3;
  169. else
  170. utflen += 2;
  171. }
  172. // sanity check
  173. if (utflen > 65536) throw IOErr.make("String too big").val;
  174. // write Length as 2 byte value
  175. w((utflen >> 8) & 0xFF);
  176. w((utflen >> 0) & 0xFF);
  177. // write characters
  178. for (int i=0; i<slen; ++i)
  179. {
  180. int c = s[i];
  181. if (c <= 0x007F)
  182. {
  183. w(c);
  184. }
  185. else if (c > 0x07FF)
  186. {
  187. w(0xE0 | ((c >> 12) & 0x0F));
  188. w(0x80 | ((c >> 6) & 0x3F));
  189. w(0x80 | ((c >> 0) & 0x3F));
  190. }
  191. else
  192. {
  193. w(0xC0 | ((c >> 6) & 0x1F));
  194. w(0x80 | ((c >> 0) & 0x3F));
  195. }
  196. }
  197. return this;
  198. }
  199. public virtual Charset charset()
  200. {
  201. return m_charset;
  202. }
  203. public virtual void charset(Charset charset)
  204. {
  205. m_charsetEncoder = charset.newEncoder();
  206. m_charset = charset;
  207. }
  208. public virtual OutStream writeChar(long c) { return writeChar((char)c); }
  209. public virtual OutStream writeChar(char c)
  210. {
  211. if (m_out != null)
  212. m_out.writeChar(c);
  213. else
  214. m_charsetEncoder.encode(c, this);
  215. return this;
  216. }
  217. public virtual OutStream writeChars(string s) { return writeChars(s, 0, s.Length); }
  218. public virtual OutStream writeChars(string s, long off) { return writeChars(s, (int)off, s.Length-(int)off); }
  219. public virtual OutStream writeChars(string s, long off, long len) { return writeChars(s, (int)off, (int)len); }
  220. public virtual OutStream writeChars(string s, int off, int len)
  221. {
  222. int end = off+len;
  223. if (m_out != null)
  224. for (int i = off; i < end; ++i)
  225. m_out.writeChar(s[i]);
  226. else
  227. for (int i = off; i < end; ++i)
  228. m_charsetEncoder.encode(s[i], this);
  229. return this;
  230. }
  231. public virtual OutStream print(object obj)
  232. {
  233. string s = obj == null ? "null" : toStr(obj);
  234. return writeChars(s, 0, s.Length);
  235. }
  236. public virtual OutStream printLine() { return printLine(""); }
  237. public virtual OutStream printLine(object obj)
  238. {
  239. string s = obj == null ? "null" : toStr(obj);
  240. writeChars(s, 0, s.Length);
  241. return writeChar('\n');
  242. }
  243. public virtual OutStream writeObj(object obj) { return writeObj(obj, null); }
  244. public virtual OutStream writeObj(object obj, Map options)
  245. {
  246. new ObjEncoder(this, options).writeObj(obj);
  247. return this;
  248. }
  249. public virtual OutStream writeProps(Map props) { return writeProps(props, true); }
  250. public virtual OutStream writeProps(Map props, bool cls)
  251. {
  252. Charset origCharset = charset();
  253. charset(Charset.utf8());
  254. try
  255. {
  256. List keys = props.keys().sort();
  257. int size = keys.sz();
  258. long eq = '=';
  259. long nl = '\n';
  260. for (int i=0; i<size; ++i)
  261. {
  262. string key = (string)keys.get(i);
  263. string val = (string)props.get(key);
  264. writePropStr(key);
  265. writeChar(eq);
  266. writePropStr(val);
  267. writeChar(nl);
  268. }
  269. return this;
  270. }
  271. finally
  272. {
  273. try { if (cls) close(); } catch (System.Exception e) { Err.dumpStack(e); }
  274. charset(origCharset);
  275. }
  276. }
  277. private void writePropStr(string s)
  278. {
  279. int len = s.Length;
  280. for (int i=0; i<len; ++i)
  281. {
  282. int ch = s[i];
  283. int peek = i+1<len ? s[i+1] : -1;
  284. // escape special chars
  285. switch (ch)
  286. {
  287. case '\n': writeChar('\\').writeChar('n'); continue;
  288. case '\r': writeChar('\\').writeChar('r'); continue;
  289. case '\t': writeChar('\\').writeChar('t'); continue;
  290. case '\\': writeChar('\\').writeChar('\\'); continue;
  291. }
  292. // escape control chars, comments, and =
  293. if ((ch < ' ') || (ch == '/' && (peek == '/' || peek == '*')) || (ch == '='))
  294. {
  295. long nib1 = FanInt.toDigit((ch>>4)&0xf, 16).longValue();
  296. long nib2 = FanInt.toDigit((ch>>0)&0xf, 16).longValue();
  297. this.writeChar('\\').writeChar('u')
  298. .writeChar('0').writeChar('0')
  299. .writeChar(nib1).writeChar(nib2);
  300. continue;
  301. }
  302. // normal character
  303. writeChar(ch);
  304. }
  305. }
  306. public OutStream writeXml(string s) { return writeXml(s, 0); }
  307. public OutStream writeXml(string s, long mask)
  308. {
  309. bool escNewlines = (mask & m_xmlEscNewlines) != 0;
  310. bool escQuotes = (mask & m_xmlEscQuotes) != 0;
  311. bool escUnicode = (mask & m_xmlEscUnicode) != 0;
  312. int len = s.Length;
  313. for (int i=0; i<len; ++i)
  314. {
  315. int ch = s[i];
  316. switch (ch)
  317. {
  318. // table switch on control chars
  319. case 0: case 1: case 2: case 3: case 4: case 5: case 6:
  320. case 7: case 8: /*case 9: case 10:*/ case 11: case 12: /*case 13:*/
  321. case 14: case 15: case 16: case 17: case 18: case 19: case 20:
  322. case 21: case 22: case 23: case 24: case 25: case 26: case 27:
  323. case 28: case 29: case 30: case 31:
  324. writeXmlEsc(ch);
  325. break;
  326. // newlines
  327. case '\n': case '\r':
  328. if (!escNewlines)
  329. writeChar((char)ch);
  330. else
  331. writeXmlEsc(ch);
  332. break;
  333. // space
  334. case ' ':
  335. writeChar(' ');
  336. break;
  337. // table switch on common ASCII chars
  338. case '!': case '#': case '$': case '%': case '(': case ')': case '*':
  339. case '+': case ',': case '-': case '.': case '/': case '0': case '1':
  340. case '2': case '3': case '4': case '5': case '6': case '7': case '8':
  341. case '9': case ':': case ';': case '=': case '?': case '@': case 'A':
  342. case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H':
  343. case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O':
  344. case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V':
  345. case 'W': case 'X': case 'Y': case 'Z': case '[': case '\\': case ']':
  346. case '^': case '_': case '`': case 'a': case 'b': case 'c': case 'd':
  347. case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
  348. case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
  349. case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y':
  350. case 'z': case '{': case '|': case '}': case '~':
  351. writeChar((char)ch);
  352. break;
  353. // XML control characters
  354. case '<':
  355. writeChars("&lt;");
  356. break;
  357. case '>':
  358. if (i > 0 && s[i-1] != ']') writeChar('>');
  359. else writeChars("&gt;");
  360. break;
  361. case '&':
  362. writeChars("&amp;");
  363. break;
  364. case '"':
  365. if (!escQuotes) writeChar((char)ch);
  366. else writeChars("&quot;");
  367. break;
  368. case '\'':
  369. if (!escQuotes) writeChar((char)ch);
  370. else writeChars("&#39;");
  371. break;
  372. // default
  373. default:
  374. if (ch <= 0xf7 || !escUnicode)
  375. writeChar((char)ch);
  376. else
  377. writeXmlEsc(ch);
  378. break;
  379. }
  380. }
  381. return this;
  382. }
  383. private void writeXmlEsc(int ch)
  384. {
  385. Charset.Encoder enc = m_charsetEncoder;
  386. string hex = "0123456789abcdef";
  387. enc.encode('&', this);
  388. enc.encode('#', this);
  389. enc.encode('x', this);
  390. if (ch > 0xff)
  391. {
  392. enc.encode(hex[(ch >> 12) & 0xf], this);
  393. enc.encode(hex[(ch >> 8) & 0xf], this);
  394. }
  395. enc.encode(hex[(ch >> 4) & 0xf], this);
  396. enc.encode(hex[(ch >> 0) & 0xf], this);
  397. enc.encode(';', this);
  398. }
  399. public static readonly long m_xmlEscNewlines = 0x01;
  400. public static readonly long m_xmlEscQuotes = 0x02;
  401. public static readonly long m_xmlEscUnicode = 0x04;
  402. public virtual OutStream flush()
  403. {
  404. if (m_out != null) m_out.flush();
  405. return this;
  406. }
  407. public virtual OutStream sync()
  408. {
  409. if (m_out != null) m_out.sync();
  410. return this;
  411. }
  412. public virtual bool close()
  413. {
  414. if (m_out != null) return m_out.close();
  415. return true;
  416. }
  417. //////////////////////////////////////////////////////////////////////////
  418. // Fields
  419. //////////////////////////////////////////////////////////////////////////
  420. internal OutStream m_out;
  421. internal bool m_bigEndian = true;
  422. internal Charset m_charset;
  423. internal Charset.Encoder m_charsetEncoder;
  424. }
  425. }