1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
// vim:set ts=2 sw=2 sts=2 et ft=javascript:
Components.utils.import("resource://gre/modules/Services.jsm");
/**
* This file exports the JSMime code, polyfilling code as appropriate for use in
* Gecko.
*/
// Load the core MIME parser. Since it doesn't define EXPORTED_SYMBOLS, we must
// use the subscript loader instead.
Services.scriptloader.loadSubScript("resource:///modules/jsmime/jsmime.js");
var EXPORTED_SYMBOLS = ["jsmime"];
// A polyfill to support non-encoding-spec charsets. Since the only converter
// available to us from JavaScript has a very, very weak and inflexible API, we
// choose to rely on the regular text decoder unless absolutely necessary.
// support non-encoding-spec charsets.
function FakeTextDecoder(label="UTF-8", options = {}) {
this._reset(label);
// So nsIScriptableUnicodeConverter only gives us fatal=false, unless we are
// using UTF-8, where we only get fatal=true. The internals of said class tell
// us to use a C++-only class if we need better behavior.
}
FakeTextDecoder.prototype = {
_reset: function (label) {
this._encoder = Components.classes[
"@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
this._encoder.isInternal = true;
let manager = Components.classes[
"@mozilla.org/charset-converter-manager;1"]
.createInstance(Components.interfaces.nsICharsetConverterManager);
this._encoder.charset = manager.getCharsetAlias(label);
},
get encoding() { return this._encoder.charset; },
decode: function (input, options = {}) {
let more = 'stream' in options ? options.stream : false;
let result = "";
if (input !== undefined) {
let data = new Uint8Array(input);
result = this._encoder.convertFromByteArray(data, data.length);
}
// This isn't quite right--it won't handle errors if there are a few
// remaining bytes in the buffer, but it's the best we can do.
if (!more)
this._reset(this.encoding);
return result;
},
};
var RealTextDecoder = TextDecoder;
function FallbackTextDecoder(charset, options) {
try {
return new RealTextDecoder(charset, options);
} catch (e) {
return new FakeTextDecoder(charset, options);
}
}
TextDecoder = FallbackTextDecoder;
// The following code loads custom MIME encoders.
var CATEGORY_NAME = "custom-mime-encoder";
Services.obs.addObserver(function (subject, topic, data) {
subject = subject.QueryInterface(Components.interfaces.nsISupportsCString)
.data;
if (data == CATEGORY_NAME) {
let url = catman.getCategoryEntry(CATEGORY_NAME, subject);
Services.scriptloader.loadSubScript(url, {}, "UTF-8");
}
}, "xpcom-category-entry-added", false);
var catman = Components.classes["@mozilla.org/categorymanager;1"]
.getService(Components.interfaces.nsICategoryManager);
var entries = catman.enumerateCategory(CATEGORY_NAME);
while (entries.hasMoreElements()) {
let string = entries.getNext()
.QueryInterface(Components.interfaces.nsISupportsCString)
.data;
let url = catman.getCategoryEntry(CATEGORY_NAME, string);
Services.scriptloader.loadSubScript(url, {}, "UTF-8");
}
|