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

/mcs/class/I18N/Common/ByteEncoding.cs

https://github.com/grendello/mono
C# | 495 lines | 295 code | 41 blank | 159 comment | 59 complexity | 4d0e333e3e408263c68517855ed62dfb MD5 | raw file
  1. /*
  2. * ByteEncoding.cs - Implementation of the "I18N.Common.ByteEncoding" class.
  3. *
  4. * Copyright (c) 2002 Southern Storm Software, Pty Ltd
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining
  7. * a copy of this software and associated documentation files (the "Software"),
  8. * to deal in the Software without restriction, including without limitation
  9. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10. * and/or sell copies of the Software, and to permit persons to whom the
  11. * Software is furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included
  14. * in all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  20. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  21. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  22. * OTHER DEALINGS IN THE SOFTWARE.
  23. */
  24. namespace I18N.Common
  25. {
  26. using System;
  27. using System.Runtime.InteropServices;
  28. using System.Text;
  29. // This class provides an abstract base for encodings that use a single
  30. // byte per character. The bulk of the work is done in this class, with
  31. // subclasses providing implementations of the "ToBytes" methods to perform
  32. // the char->byte conversion.
  33. [Serializable]
  34. public abstract class ByteEncoding : MonoEncoding
  35. {
  36. // Internal state.
  37. protected char[] toChars;
  38. protected String encodingName;
  39. protected String bodyName;
  40. protected String headerName;
  41. protected String webName;
  42. protected bool isBrowserDisplay;
  43. protected bool isBrowserSave;
  44. protected bool isMailNewsDisplay;
  45. protected bool isMailNewsSave;
  46. protected int windowsCodePage;
  47. static byte [] isNormalized;
  48. static byte [] isNormalizedComputed;
  49. static byte [] normalization_bytes;
  50. // Constructor.
  51. protected ByteEncoding(int codePage, char[] toChars,
  52. String encodingName, String bodyName,
  53. String headerName, String webName,
  54. bool isBrowserDisplay, bool isBrowserSave,
  55. bool isMailNewsDisplay, bool isMailNewsSave,
  56. int windowsCodePage)
  57. : base(codePage)
  58. {
  59. if (toChars.Length != byte.MaxValue + 1)
  60. throw new ArgumentException("toChars");
  61. this.toChars = toChars;
  62. this.encodingName = encodingName;
  63. this.bodyName = bodyName;
  64. this.headerName = headerName;
  65. this.webName = webName;
  66. this.isBrowserDisplay = isBrowserDisplay;
  67. this.isBrowserSave = isBrowserSave;
  68. this.isMailNewsDisplay = isMailNewsDisplay;
  69. this.isMailNewsSave = isMailNewsSave;
  70. this.windowsCodePage = windowsCodePage;
  71. }
  72. public override bool IsAlwaysNormalized (NormalizationForm form)
  73. {
  74. if (form != NormalizationForm.FormC)
  75. return false;
  76. if (isNormalized == null)
  77. isNormalized = new byte [0x10000 / 8];
  78. if (isNormalizedComputed == null)
  79. isNormalizedComputed = new byte [0x10000 / 8];
  80. if (normalization_bytes == null) {
  81. normalization_bytes = new byte [0x100];
  82. lock (normalization_bytes) {
  83. for (int i = 0; i < 0x100; i++)
  84. normalization_bytes [i] = (byte) i;
  85. }
  86. }
  87. byte offset = (byte) (1 << (CodePage % 8));
  88. if ((isNormalizedComputed [CodePage / 8] & offset) == 0) {
  89. Encoding e = Clone () as Encoding;
  90. e.DecoderFallback = new DecoderReplacementFallback ("");
  91. string s = e.GetString (normalization_bytes);
  92. // note that the flag only stores FormC information.
  93. if (s != s.Normalize (form))
  94. isNormalized [CodePage / 8] |= offset;
  95. isNormalizedComputed [CodePage / 8] |= offset;
  96. }
  97. return (isNormalized [CodePage / 8] & offset) == 0;
  98. }
  99. public override bool IsSingleByte {
  100. get { return true; }
  101. }
  102. public override int GetByteCount(String s)
  103. {
  104. if(s == null)
  105. {
  106. throw new ArgumentNullException("s");
  107. }
  108. return s.Length;
  109. }
  110. // Get the number of bytes needed to encode a character buffer.
  111. public unsafe override int GetByteCountImpl (char* chars, int count)
  112. {
  113. return count;
  114. }
  115. // Convert an array of characters into a byte buffer,
  116. // once the parameters have been validated.
  117. protected unsafe abstract void ToBytes (
  118. char* chars, int charCount, byte* bytes, int byteCount);
  119. /*
  120. protected unsafe virtual void ToBytes (
  121. char* chars, int charCount, byte* bytes, int byteCount)
  122. {
  123. // When it is not overriden, use ToBytes() with arrays.
  124. char [] carr = new char [charCount];
  125. Marshal.Copy ((IntPtr) chars, carr, 0, charCount);
  126. byte [] barr = new byte [byteCount];
  127. Marshal.Copy ((IntPtr) bytes, barr, 0, byteCount);
  128. ToBytes (carr, 0, charCount, barr, 0);
  129. }
  130. */
  131. // Convert an array of characters into a byte buffer,
  132. // once the parameters have been validated.
  133. protected unsafe virtual void ToBytes(char[] chars, int charIndex, int charCount,
  134. byte[] bytes, int byteIndex)
  135. {
  136. // When it is not overriden, use ToBytes() with pointers
  137. // (this is the ideal solution)
  138. if (charCount == 0 || bytes.Length == byteIndex)
  139. return;
  140. if (charIndex < 0 || charIndex > chars.Length) {
  141. throw new ArgumentOutOfRangeException
  142. ("charIndex", Strings.GetString("ArgRange_Array"));
  143. }
  144. if (byteIndex < 0 || byteIndex > bytes.Length) {
  145. throw new ArgumentOutOfRangeException
  146. ("byteIndex", Strings.GetString("ArgRange_Array"));
  147. }
  148. if (charCount < 0 || charIndex + charCount > chars.Length || byteIndex + charCount > bytes.Length) {
  149. throw new ArgumentOutOfRangeException
  150. ("charCount", Strings.GetString("ArgRange_Array"));
  151. }
  152. fixed (char* cptr = chars) {
  153. fixed (byte* bptr = bytes) {
  154. ToBytes (cptr + charIndex, charCount,
  155. bptr + byteIndex, bytes.Length - byteIndex);
  156. }
  157. }
  158. }
  159. /*
  160. // Convert a string into a byte buffer, once the parameters
  161. // have been validated.
  162. protected unsafe virtual void ToBytes(String s, int charIndex, int charCount,
  163. byte[] bytes, int byteIndex)
  164. {
  165. // When it is not overriden, use ToBytes() with pointers
  166. // (Ideal solution)
  167. if (s.Length == 0 || bytes.Length == byteIndex)
  168. return;
  169. fixed (char* cptr = s) {
  170. fixed (byte* bptr = bytes) {
  171. ToBytes (cptr + charIndex, charCount,
  172. bptr + byteIndex, bytes.Length - byteIndex);
  173. }
  174. }
  175. }
  176. */
  177. //[CLSCompliant (false)]
  178. public unsafe override int GetBytesImpl (char* chars, int charCount, byte* bytes, int byteCount)
  179. {
  180. ToBytes (chars, charCount, bytes, byteCount);
  181. return charCount;
  182. }
  183. /*
  184. // Get the bytes that result from encoding a character buffer.
  185. public override int GetBytes(char[] chars, int charIndex, int charCount,
  186. byte[] bytes, int byteIndex)
  187. {
  188. if(chars == null)
  189. {
  190. throw new ArgumentNullException("chars");
  191. }
  192. if(bytes == null)
  193. {
  194. throw new ArgumentNullException("bytes");
  195. }
  196. if(charIndex < 0 || charIndex > chars.Length)
  197. {
  198. throw new ArgumentOutOfRangeException
  199. ("charIndex", Strings.GetString("ArgRange_Array"));
  200. }
  201. if(charCount < 0 || charCount > (chars.Length - charIndex))
  202. {
  203. throw new ArgumentOutOfRangeException
  204. ("charCount", Strings.GetString("ArgRange_Array"));
  205. }
  206. if(byteIndex < 0 || byteIndex > bytes.Length)
  207. {
  208. throw new ArgumentOutOfRangeException
  209. ("byteIndex", Strings.GetString("ArgRange_Array"));
  210. }
  211. if((bytes.Length - byteIndex) < charCount)
  212. {
  213. throw new ArgumentException
  214. (Strings.GetString("Arg_InsufficientSpace"));
  215. }
  216. ToBytes(chars, charIndex, charCount, bytes, byteIndex);
  217. return charCount;
  218. }
  219. // Convenience wrappers for "GetBytes".
  220. public override int GetBytes(String s, int charIndex, int charCount,
  221. byte[] bytes, int byteIndex)
  222. {
  223. if(s == null)
  224. {
  225. throw new ArgumentNullException("s");
  226. }
  227. if(bytes == null)
  228. {
  229. throw new ArgumentNullException("bytes");
  230. }
  231. if(charIndex < 0 || charIndex > s.Length)
  232. {
  233. throw new ArgumentOutOfRangeException
  234. ("charIndex",
  235. Strings.GetString("ArgRange_StringIndex"));
  236. }
  237. if(charCount < 0 || charCount > (s.Length - charIndex))
  238. {
  239. throw new ArgumentOutOfRangeException
  240. ("charCount",
  241. Strings.GetString("ArgRange_StringRange"));
  242. }
  243. if(byteIndex < 0 || byteIndex > bytes.Length)
  244. {
  245. throw new ArgumentOutOfRangeException
  246. ("byteIndex", Strings.GetString("ArgRange_Array"));
  247. }
  248. if((bytes.Length - byteIndex) < charCount)
  249. {
  250. throw new ArgumentException
  251. (Strings.GetString("Arg_InsufficientSpace"));
  252. }
  253. ToBytes(s, charIndex, charCount, bytes, byteIndex);
  254. return charCount;
  255. }
  256. */
  257. // Get the number of characters needed to decode a byte buffer.
  258. public override int GetCharCount(byte[] bytes, int index, int count)
  259. {
  260. if(bytes == null)
  261. {
  262. throw new ArgumentNullException("bytes");
  263. }
  264. if(index < 0 || index > bytes.Length)
  265. {
  266. throw new ArgumentOutOfRangeException
  267. ("index", Strings.GetString("ArgRange_Array"));
  268. }
  269. if(count < 0 || count > (bytes.Length - index))
  270. {
  271. throw new ArgumentOutOfRangeException
  272. ("count", Strings.GetString("ArgRange_Array"));
  273. }
  274. return count;
  275. }
  276. // Get the characters that result from decoding a byte buffer.
  277. public override int GetChars(byte[] bytes, int byteIndex, int byteCount,
  278. char[] chars, int charIndex)
  279. {
  280. if(bytes == null)
  281. {
  282. throw new ArgumentNullException("bytes");
  283. }
  284. if(chars == null)
  285. {
  286. throw new ArgumentNullException("chars");
  287. }
  288. if(byteIndex < 0 || byteIndex > bytes.Length)
  289. {
  290. throw new ArgumentOutOfRangeException
  291. ("byteIndex", Strings.GetString("ArgRange_Array"));
  292. }
  293. if(byteCount < 0 || byteCount > (bytes.Length - byteIndex))
  294. {
  295. throw new ArgumentOutOfRangeException
  296. ("byteCount", Strings.GetString("ArgRange_Array"));
  297. }
  298. if(charIndex < 0 || charIndex > chars.Length)
  299. {
  300. throw new ArgumentOutOfRangeException
  301. ("charIndex", Strings.GetString("ArgRange_Array"));
  302. }
  303. if((chars.Length - charIndex) < byteCount)
  304. {
  305. throw new ArgumentException
  306. (Strings.GetString("Arg_InsufficientSpace"));
  307. }
  308. int count = byteCount;
  309. char[] cvt = toChars;
  310. while(count-- > 0)
  311. {
  312. chars[charIndex++] = cvt[(int)(bytes[byteIndex++])];
  313. }
  314. return byteCount;
  315. }
  316. // Get the maximum number of bytes needed to encode a
  317. // specified number of characters.
  318. public override int GetMaxByteCount(int charCount)
  319. {
  320. if(charCount < 0)
  321. {
  322. throw new ArgumentOutOfRangeException
  323. ("charCount",
  324. Strings.GetString("ArgRange_NonNegative"));
  325. }
  326. return charCount;
  327. }
  328. // Get the maximum number of characters needed to decode a
  329. // specified number of bytes.
  330. public override int GetMaxCharCount(int byteCount)
  331. {
  332. if(byteCount < 0)
  333. {
  334. throw new ArgumentOutOfRangeException
  335. ("byteCount",
  336. Strings.GetString("ArgRange_NonNegative"));
  337. }
  338. return byteCount;
  339. }
  340. // Decode a buffer of bytes into a string.
  341. public unsafe override String GetString(byte[] bytes, int index, int count)
  342. {
  343. if(bytes == null)
  344. {
  345. throw new ArgumentNullException("bytes");
  346. }
  347. if(index < 0 || index > bytes.Length)
  348. {
  349. throw new ArgumentOutOfRangeException
  350. ("index", Strings.GetString("ArgRange_Array"));
  351. }
  352. if(count < 0 || count > (bytes.Length - index))
  353. {
  354. throw new ArgumentOutOfRangeException
  355. ("count", Strings.GetString("ArgRange_Array"));
  356. }
  357. if (count == 0)
  358. return string.Empty;
  359. string s = new string ((char) 0, count);
  360. fixed (byte* bytePtr = bytes)
  361. fixed (char* charPtr = s)
  362. fixed (char* cvt = toChars) {
  363. byte* b = bytePtr + index;
  364. char* c = charPtr;
  365. while(count-- != 0)
  366. *(c++) = cvt[*(b++)];
  367. }
  368. return s;
  369. }
  370. public override String GetString(byte[] bytes)
  371. {
  372. if(bytes == null)
  373. {
  374. throw new ArgumentNullException("bytes");
  375. }
  376. return GetString (bytes, 0, bytes.Length);
  377. }
  378. #if !ECMA_COMPAT
  379. // Get the mail body name for this encoding.
  380. public override String BodyName
  381. {
  382. get
  383. {
  384. return bodyName;
  385. }
  386. }
  387. // Get the human-readable name for this encoding.
  388. public override String EncodingName
  389. {
  390. get
  391. {
  392. return encodingName;
  393. }
  394. }
  395. // Get the mail agent header name for this encoding.
  396. public override String HeaderName
  397. {
  398. get
  399. {
  400. return headerName;
  401. }
  402. }
  403. // Determine if this encoding can be displayed in a Web browser.
  404. public override bool IsBrowserDisplay
  405. {
  406. get
  407. {
  408. return isBrowserDisplay;
  409. }
  410. }
  411. // Determine if this encoding can be saved from a Web browser.
  412. public override bool IsBrowserSave
  413. {
  414. get
  415. {
  416. return isBrowserSave;
  417. }
  418. }
  419. // Determine if this encoding can be displayed in a mail/news agent.
  420. public override bool IsMailNewsDisplay
  421. {
  422. get
  423. {
  424. return isMailNewsDisplay;
  425. }
  426. }
  427. // Determine if this encoding can be saved from a mail/news agent.
  428. public override bool IsMailNewsSave
  429. {
  430. get
  431. {
  432. return isMailNewsSave;
  433. }
  434. }
  435. // Get the IANA-preferred Web name for this encoding.
  436. public override String WebName
  437. {
  438. get
  439. {
  440. return webName;
  441. }
  442. }
  443. // Get the Windows code page represented by this object.
  444. public override int WindowsCodePage
  445. {
  446. get
  447. {
  448. return windowsCodePage;
  449. }
  450. }
  451. #endif // !ECMA_COMPAT
  452. }; // class ByteEncoding
  453. }; // namespace I18N.Encoding