Home Reference Source

src/encode/EUCJPMS.js

  1. /**
  2. * The script is part of MojiJS.
  3. *
  4. * AUTHOR:
  5. * natade (http://twitter.com/natadea)
  6. *
  7. * LICENSE:
  8. * The MIT license https://opensource.org/licenses/MIT
  9. */
  10.  
  11. import SJIS from "./SJIS.js";
  12. import CP932 from "./CP932.js";
  13.  
  14. /**
  15. * eucJP-ms の変換マップ作成用クラス
  16. * @ignore
  17. */
  18. class EUCJPMSMAP {
  19.  
  20. /**
  21. * 変換マップを初期化
  22. */
  23. static init() {
  24. if(EUCJPMSMAP.is_initmap) {
  25. return;
  26. }
  27. EUCJPMSMAP.is_initmap = true;
  28.  
  29. /**
  30. * 変換マップ
  31. * CP932のIBM拡張文字の一部は、eucJP-msのG3の83区から84区に配列されている。
  32. * @type {Object<number, number>}
  33. */
  34. const eucjpms_to_cp932_map = {
  35. 0xf3f3: 0xfa40, 0xf3f4: 0xfa41, 0xf3f5: 0xfa42, 0xf3f6: 0xfa43, 0xf3f7: 0xfa44,
  36. 0xf3f8: 0xfa45, 0xf3f9: 0xfa46, 0xf3fa: 0xfa47, 0xf3fb: 0xfa48, 0xf3fc: 0xfa49, 0xf3fd: 0x8754, 0xf3fe: 0x8755,
  37. 0xf4a1: 0x8756, 0xf4a2: 0x8757, 0xf4a3: 0x8758, 0xf4a4: 0x8759, 0xf4a5: 0x875a, 0xf4a6: 0x875b, 0xf4a7: 0x875c,
  38. 0xf4a8: 0x875d, 0xf4a9: 0xfa56, 0xf4aa: 0xfa57, 0xf4ab: 0x878a, 0xf4ac: 0x8782, 0xf4ad: 0x8784, 0xf4ae: 0xfa62, 0xf4af: 0xfa6a,
  39. 0xf4b0: 0xfa7c, 0xf4b1: 0xfa83, 0xf4b2: 0xfa8a, 0xf4b3: 0xfa8b, 0xf4b4: 0xfa90, 0xf4b5: 0xfa92, 0xf4b6: 0xfa96, 0xf4b7: 0xfa9b,
  40. 0xf4b8: 0xfa9c, 0xf4b9: 0xfa9d, 0xf4ba: 0xfaaa, 0xf4bb: 0xfaae, 0xf4bc: 0xfab0, 0xf4bd: 0xfab1, 0xf4be: 0xfaba, 0xf4bf: 0xfabd,
  41. 0xf4c0: 0xfac1, 0xf4c1: 0xfacd, 0xf4c2: 0xfad0, 0xf4c3: 0xfad5, 0xf4c4: 0xfad8, 0xf4c5: 0xfae0, 0xf4c6: 0xfae5, 0xf4c7: 0xfae8,
  42. 0xf4c8: 0xfaea, 0xf4c9: 0xfaee, 0xf4ca: 0xfaf2, 0xf4cb: 0xfb43, 0xf4cc: 0xfb44, 0xf4cd: 0xfb50, 0xf4ce: 0xfb58, 0xf4cf: 0xfb5e,
  43. 0xf4d0: 0xfb6e, 0xf4d1: 0xfb70, 0xf4d2: 0xfb72, 0xf4d3: 0xfb75, 0xf4d4: 0xfb7c, 0xf4d5: 0xfb7d, 0xf4d6: 0xfb7e, 0xf4d7: 0xfb80,
  44. 0xf4d8: 0xfb82, 0xf4d9: 0xfb85, 0xf4da: 0xfb86, 0xf4db: 0xfb89, 0xf4dc: 0xfb8d, 0xf4dd: 0xfb8e, 0xf4de: 0xfb92, 0xf4df: 0xfb94,
  45. 0xf4e0: 0xfb9d, 0xf4e1: 0xfb9e, 0xf4e2: 0xfb9f, 0xf4e3: 0xfba0, 0xf4e4: 0xfba1, 0xf4e5: 0xfba9, 0xf4e6: 0xfbac, 0xf4e7: 0xfbae,
  46. 0xf4e8: 0xfbb0, 0xf4e9: 0xfbb1, 0xf4ea: 0xfbb3, 0xf4eb: 0xfbb4, 0xf4ec: 0xfbb6, 0xf4ed: 0xfbb7, 0xf4ee: 0xfbb8, 0xf4ef: 0xfbd3,
  47. 0xf4f0: 0xfbda, 0xf4f1: 0xfbe8, 0xf4f2: 0xfbe9, 0xf4f3: 0xfbea, 0xf4f4: 0xfbee, 0xf4f5: 0xfbf0, 0xf4f6: 0xfbf2, 0xf4f7: 0xfbf6,
  48. 0xf4f8: 0xfbf7, 0xf4f9: 0xfbf9, 0xf4fa: 0xfbfa, 0xf4fb: 0xfbfc, 0xf4fc: 0xfc42, 0xf4fd: 0xfc49, 0xf4fe: 0xfc4b
  49. };
  50.  
  51. /**
  52. * @type {Object<number, number>}
  53. */
  54. const cp932_to_eucjpms_map = {};
  55. for(const key in eucjpms_to_cp932_map) {
  56. const x = eucjpms_to_cp932_map[key];
  57. cp932_to_eucjpms_map[x] = parseInt(key, 10);
  58. }
  59.  
  60. EUCJPMSMAP.cp932_to_eucjpms_map = cp932_to_eucjpms_map;
  61. EUCJPMSMAP.eucjpms_to_cp932_map = eucjpms_to_cp932_map;
  62. }
  63. /**
  64. * @returns {Object<number, number>}
  65. */
  66. static CP932_TO_EUCJPMS() {
  67. EUCJPMSMAP.init();
  68. return EUCJPMSMAP.cp932_to_eucjpms_map;
  69. }
  70. /**
  71. * @returns {Object<number, number>}
  72. */
  73. static EUCJPMS_TO_CP932() {
  74. EUCJPMSMAP.init();
  75. return EUCJPMSMAP.eucjpms_to_cp932_map;
  76. }
  77.  
  78. }
  79.  
  80. /**
  81. * 変換マップを初期化したかどうか
  82. * @type {boolean}
  83. */
  84. EUCJPMSMAP.is_initmap = false;
  85.  
  86. /**
  87. * 変換用マップ
  88. * @type {Object<number, number>}
  89. */
  90. EUCJPMSMAP.cp932_to_eucjpms_map = null;
  91.  
  92. /**
  93. * 変換用マップ
  94. * @type {Object<number, number>}
  95. */
  96. EUCJPMSMAP.eucjpms_to_cp932_map = null;
  97.  
  98. /**
  99. * eucJP-ms を扱うクラス
  100. * @ignore
  101. */
  102. export default class EUCJPMS {
  103.  
  104. /**
  105. * 文字列を eucJP-ms のバイナリ配列に変換
  106. * - 日本語文字は2バイトとして、配列も2つ分、使用します。
  107. * @param {String} text - 変換したいテキスト
  108. * @returns {Array<number>} eucJP-ms のデータが入ったバイナリ配列
  109. */
  110. static toEUCJPMSBinary(text) {
  111. const sjis_array = CP932.toCP932Array(text);
  112. const bin = [];
  113. const map = EUCJPMSMAP.CP932_TO_EUCJPMS();
  114. const SS2 = 0x8E; // C1制御文字 シングルシフト2
  115. const SS3 = 0x8F; // C1制御文字 シングルシフト3
  116. for(let i = 0; i < sjis_array.length; i++) {
  117. const code = sjis_array[i];
  118. const kuten = SJIS.toKuTenFromSJISCode(code);
  119. if(code < 0x80) {
  120. // G0 ASCII
  121. bin.push(code);
  122. }
  123. else if(code < 0xE0) {
  124. // G2 半角カタカナ
  125. bin.push(SS2);
  126. bin.push(code);
  127. }
  128. else {
  129. const eucjpms_code = map[code];
  130. if(!eucjpms_code) {
  131. // G1
  132. bin.push(kuten.ku + 0xA0);
  133. bin.push(kuten.ten + 0xA0);
  134. }
  135. else {
  136. // シングルシフト SS3 で G3 を呼び出す。
  137. // G3 は、eucJP-ms の場合 IBM拡張文字 を表す。
  138. bin.push(SS3);
  139. bin.push(eucjpms_code >> 8);
  140. bin.push(eucjpms_code & 0xff);
  141. }
  142. }
  143. }
  144. return bin;
  145. }
  146.  
  147. /**
  148. * eucJP-ms の配列から文字列に変換
  149. * @param {Array<number>} eucjp - 変換したいテキスト
  150. * @returns {String} 変換後のテキスト
  151. */
  152. static fromEUCJPMSBinary(eucjp) {
  153. const sjis_array = [];
  154. const ng = "?".charCodeAt(0);
  155. const map = EUCJPMSMAP.EUCJPMS_TO_CP932();
  156. const SS2 = 0x8E; // C1制御文字 シングルシフト2
  157. const SS3 = 0x8F; // C1制御文字 シングルシフト3
  158. for(let i = 0; i < eucjp.length; i++) {
  159. let x1, x2;
  160. x1 = eucjp[i];
  161. // ASCII
  162. if(x1 < 0x80) {
  163. sjis_array.push(x1);
  164. continue;
  165. }
  166. if(i >= eucjp.length - 1) {
  167. // 文字が足りない
  168. break;
  169. }
  170. {
  171. // 3バイト読み込み(G3)
  172. if(x1 === SS3) {
  173. // 文字が足りない
  174. if(i >= eucjp.length - 2) {
  175. break;
  176. }
  177. x1 = eucjp[i + 1];
  178. x2 = eucjp[i + 2];
  179. // シングルシフト SS3 で G3 を呼び出す。
  180. // G3 は、eucJP-ms の場合 IBM拡張文字 を表す。
  181. const nec_code = map[(x1 << 8 | x2)];
  182. if(nec_code) {
  183. sjis_array.push(nec_code);
  184. }
  185. else {
  186. sjis_array.push(ng);
  187. }
  188. i += 2;
  189. continue;
  190. }
  191. // 2バイト読み込み
  192. else {
  193. x2 = eucjp[i + 1];
  194. i += 1;
  195. }
  196. }
  197. // 半角カタカナ
  198. if(x1 === SS2) {
  199. sjis_array.push(x2);
  200. continue;
  201. }
  202.  
  203. // 日本語
  204. if((0xA1 <= x1) && (x1 <= 0xFE) && (0xA1 <= x2) && (x2 <= 0xFE)) {
  205. const kuten = {
  206. ku : x1 - 0xA0,
  207. ten : x2 - 0xA0
  208. };
  209. sjis_array.push(SJIS.toSJISCodeFromKuTen(kuten));
  210. }
  211. else {
  212. sjis_array.push(ng);
  213. }
  214. }
  215. return CP932.fromCP932Array(sjis_array);
  216. }
  217.  
  218.  
  219. }