|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 |
|
6 const Cc = Components.classes; |
|
7 const Ci = Components.interfaces; |
|
8 const Cr = Components.results; |
|
9 const Cu = Components.utils; |
|
10 |
|
11 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); |
|
12 |
|
13 function INIProcessorFactory() { |
|
14 } |
|
15 |
|
16 INIProcessorFactory.prototype = { |
|
17 classID: Components.ID("{6ec5f479-8e13-4403-b6ca-fe4c2dca14fd}"), |
|
18 QueryInterface : XPCOMUtils.generateQI([Ci.nsIINIParserFactory]), |
|
19 |
|
20 createINIParser : function (aINIFile) { |
|
21 return new INIProcessor(aINIFile); |
|
22 } |
|
23 |
|
24 }; // end of INIProcessorFactory implementation |
|
25 |
|
26 const MODE_WRONLY = 0x02; |
|
27 const MODE_CREATE = 0x08; |
|
28 const MODE_TRUNCATE = 0x20; |
|
29 |
|
30 // nsIINIParser implementation |
|
31 function INIProcessor(aFile) { |
|
32 this._iniFile = aFile; |
|
33 this._iniData = {}; |
|
34 this._readFile(); |
|
35 } |
|
36 |
|
37 INIProcessor.prototype = { |
|
38 QueryInterface : XPCOMUtils.generateQI([Ci.nsIINIParser, Ci.nsIINIParserWriter]), |
|
39 |
|
40 __utf8Converter : null, // UCS2 <--> UTF8 string conversion |
|
41 get _utf8Converter() { |
|
42 if (!this.__utf8Converter) { |
|
43 this.__utf8Converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]. |
|
44 createInstance(Ci.nsIScriptableUnicodeConverter); |
|
45 this.__utf8Converter.charset = "UTF-8"; |
|
46 } |
|
47 return this.__utf8Converter; |
|
48 }, |
|
49 |
|
50 __utf16leConverter : null, // UCS2 <--> UTF16LE string conversion |
|
51 get _utf16leConverter() { |
|
52 if (!this.__utf16leConverter) { |
|
53 this.__utf16leConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]. |
|
54 createInstance(Ci.nsIScriptableUnicodeConverter); |
|
55 this.__utf16leConverter.charset = "UTF-16LE"; |
|
56 } |
|
57 return this.__utf16leConverter; |
|
58 }, |
|
59 |
|
60 _utfConverterReset : function() { |
|
61 this.__utf8Converter = null; |
|
62 this.__utf16leConverter = null; |
|
63 }, |
|
64 |
|
65 _iniFile : null, |
|
66 _iniData : null, |
|
67 |
|
68 /* |
|
69 * Reads the INI file and stores the data internally. |
|
70 */ |
|
71 _readFile : function() { |
|
72 // If file doesn't exist, there's nothing to do. |
|
73 if (!this._iniFile.exists() || 0 == this._iniFile.fileSize) |
|
74 return; |
|
75 |
|
76 let iniParser = Cc["@mozilla.org/xpcom/ini-parser-factory;1"] |
|
77 .getService(Ci.nsIINIParserFactory).createINIParser(this._iniFile); |
|
78 for (let section in XPCOMUtils.IterStringEnumerator(iniParser.getSections())) { |
|
79 this._iniData[section] = {}; |
|
80 for (let key in XPCOMUtils.IterStringEnumerator(iniParser.getKeys(section))) { |
|
81 this._iniData[section][key] = iniParser.getString(section, key); |
|
82 } |
|
83 } |
|
84 }, |
|
85 |
|
86 // nsIINIParser |
|
87 |
|
88 getSections : function() { |
|
89 let sections = []; |
|
90 for (let section in this._iniData) |
|
91 sections.push(section); |
|
92 return new stringEnumerator(sections); |
|
93 }, |
|
94 |
|
95 getKeys : function(aSection) { |
|
96 let keys = []; |
|
97 if (aSection in this._iniData) |
|
98 for (let key in this._iniData[aSection]) |
|
99 keys.push(key); |
|
100 return new stringEnumerator(keys); |
|
101 }, |
|
102 |
|
103 getString : function(aSection, aKey) { |
|
104 if (!(aSection in this._iniData)) |
|
105 throw Cr.NS_ERROR_FAILURE; |
|
106 if (!(aKey in this._iniData[aSection])) |
|
107 throw Cr.NS_ERROR_FAILURE; |
|
108 return this._iniData[aSection][aKey]; |
|
109 }, |
|
110 |
|
111 |
|
112 // nsIINIParserWriter |
|
113 |
|
114 setString : function(aSection, aKey, aValue) { |
|
115 const isSectionIllegal = /[\0\r\n\[\]]/; |
|
116 const isKeyValIllegal = /[\0\r\n=]/; |
|
117 |
|
118 if (isSectionIllegal.test(aSection)) |
|
119 throw Components.Exception("bad character in section name", |
|
120 Cr.ERROR_ILLEGAL_VALUE); |
|
121 if (isKeyValIllegal.test(aKey) || isKeyValIllegal.test(aValue)) |
|
122 throw Components.Exception("bad character in key/value", |
|
123 Cr.ERROR_ILLEGAL_VALUE); |
|
124 |
|
125 if (!(aSection in this._iniData)) |
|
126 this._iniData[aSection] = {}; |
|
127 |
|
128 this._iniData[aSection][aKey] = aValue; |
|
129 }, |
|
130 |
|
131 writeFile : function(aFile, aFlags) { |
|
132 |
|
133 let converter; |
|
134 function writeLine(data) { |
|
135 data += "\n"; |
|
136 data = converter.ConvertFromUnicode(data); |
|
137 data += converter.Finish(); |
|
138 outputStream.write(data, data.length); |
|
139 } |
|
140 |
|
141 if (!aFile) |
|
142 aFile = this._iniFile; |
|
143 |
|
144 let safeStream = Cc["@mozilla.org/network/safe-file-output-stream;1"]. |
|
145 createInstance(Ci.nsIFileOutputStream); |
|
146 safeStream.init(aFile, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, |
|
147 0600, null); |
|
148 |
|
149 var outputStream = Cc["@mozilla.org/network/buffered-output-stream;1"]. |
|
150 createInstance(Ci.nsIBufferedOutputStream); |
|
151 outputStream.init(safeStream, 8192); |
|
152 outputStream.QueryInterface(Ci.nsISafeOutputStream); // for .finish() |
|
153 |
|
154 if (Ci.nsIINIParserWriter.WRITE_UTF16 == aFlags |
|
155 && 'nsIWindowsRegKey' in Ci) { |
|
156 outputStream.write("\xFF\xFE", 2); |
|
157 converter = this._utf16leConverter; |
|
158 } else { |
|
159 converter = this._utf8Converter; |
|
160 } |
|
161 |
|
162 for (let section in this._iniData) { |
|
163 writeLine("[" + section + "]"); |
|
164 for (let key in this._iniData[section]) { |
|
165 writeLine(key + "=" + this._iniData[section][key]); |
|
166 } |
|
167 } |
|
168 |
|
169 outputStream.finish(); |
|
170 } |
|
171 }; |
|
172 |
|
173 function stringEnumerator(stringArray) { |
|
174 this._strings = stringArray; |
|
175 } |
|
176 stringEnumerator.prototype = { |
|
177 QueryInterface : XPCOMUtils.generateQI([Ci.nsIUTF8StringEnumerator]), |
|
178 |
|
179 _strings : null, |
|
180 _enumIndex: 0, |
|
181 |
|
182 hasMore : function() { |
|
183 return (this._enumIndex < this._strings.length); |
|
184 }, |
|
185 |
|
186 getNext : function() { |
|
187 return this._strings[this._enumIndex++]; |
|
188 } |
|
189 }; |
|
190 |
|
191 let component = [INIProcessorFactory]; |
|
192 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(component); |