1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
5 */
6
7"use strict";
8
9var EXPORTED_SYMBOLS = ["EnigmailData"];
10
11const SCRIPTABLEUNICODECONVERTER_CONTRACTID =
12  "@mozilla.org/intl/scriptableunicodeconverter";
13
14const HEX_TABLE = "0123456789abcdef";
15
16function converter(charset) {
17  let unicodeConv = Cc[SCRIPTABLEUNICODECONVERTER_CONTRACTID].getService(
18    Ci.nsIScriptableUnicodeConverter
19  );
20  unicodeConv.charset = charset || "utf-8";
21  return unicodeConv;
22}
23
24var EnigmailData = {
25  getUnicodeData(data) {
26    if (!data) {
27      throw new Error("EnigmailData.getUnicodeData invalid parameter");
28    }
29    // convert output to Unicode
30    var tmpStream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
31      Ci.nsIStringInputStream
32    );
33    tmpStream.setData(data, data.length);
34    var inStream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
35      Ci.nsIScriptableInputStream
36    );
37    inStream.init(tmpStream);
38    return inStream.read(tmpStream.available());
39  },
40
41  decodeQuotedPrintable(str) {
42    return unescape(
43      str.replace(/%/g, "=25").replace(new RegExp("=", "g"), "%")
44    );
45  },
46
47  decodeBase64(str) {
48    return atob(str.replace(/[\s\r\n]*/g, ""));
49  },
50
51  /***
52   * Encode a string in base64, with a max. line length of 72 characters
53   */
54  encodeBase64(str) {
55    return btoa(str).replace(/(.{72})/g, "$1\r\n");
56  },
57
58  convertToUnicode(text, charset) {
59    if (!text || (charset && charset.toLowerCase() == "iso-8859-1")) {
60      return text;
61    }
62
63    // Encode plaintext
64    try {
65      return converter(charset).ConvertToUnicode(text);
66    } catch (ex) {
67      return text;
68    }
69  },
70
71  convertFromUnicode(text, charset) {
72    if (!text) {
73      return "";
74    }
75
76    try {
77      return converter(charset).ConvertFromUnicode(text);
78    } catch (ex) {
79      return text;
80    }
81  },
82
83  convertGpgToUnicode(text) {
84    if (typeof text === "string") {
85      text = text.replace(/\\x3a/gi, "\\e3A");
86      var a = text.search(/\\x[0-9a-fA-F]{2}/);
87      while (a >= 0) {
88        var ch = unescape("%" + text.substr(a + 2, 2));
89        var r = new RegExp("\\" + text.substr(a, 4));
90        text = text.replace(r, ch);
91
92        a = text.search(/\\x[0-9a-fA-F]{2}/);
93      }
94
95      text = EnigmailData.convertToUnicode(text, "utf-8").replace(
96        /\\e3A/g,
97        ":"
98      );
99    }
100
101    return text;
102  },
103
104  pack(value, bytes) {
105    let str = "";
106    let mask = 0xff;
107    for (let j = 0; j < bytes; j++) {
108      str = String.fromCharCode((value & mask) >> (j * 8)) + str;
109      mask <<= 8;
110    }
111
112    return str;
113  },
114
115  unpack(str) {
116    let len = str.length;
117    let value = 0;
118
119    for (let j = 0; j < len; j++) {
120      value <<= 8;
121      value |= str.charCodeAt(j);
122    }
123
124    return value;
125  },
126
127  bytesToHex(str) {
128    let len = str.length;
129
130    let hex = "";
131    for (let j = 0; j < len; j++) {
132      let charCode = str.charCodeAt(j);
133      hex +=
134        HEX_TABLE.charAt((charCode & 0xf0) >> 4) +
135        HEX_TABLE.charAt(charCode & 0x0f);
136    }
137
138    return hex;
139  },
140
141  /**
142   * Convert an ArrayBuffer (or Uint8Array) object into a string
143   */
144  arrayBufferToString(buffer) {
145    const MAXLEN = 102400;
146
147    let uArr = new Uint8Array(buffer);
148    let ret = "";
149    let len = buffer.byteLength;
150
151    for (let j = 0; j < Math.floor(len / MAXLEN) + 1; j++) {
152      ret += String.fromCharCode.apply(
153        null,
154        uArr.subarray(j * MAXLEN, (j + 1) * MAXLEN)
155      );
156    }
157
158    return ret;
159  },
160};
161