michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: michael@0: const Cc = Components.classes; michael@0: const Ci = Components.interfaces; michael@0: const Cr = Components.results; michael@0: const Cu = Components.utils; michael@0: michael@0: Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: michael@0: function INIProcessorFactory() { michael@0: } michael@0: michael@0: INIProcessorFactory.prototype = { michael@0: classID: Components.ID("{6ec5f479-8e13-4403-b6ca-fe4c2dca14fd}"), michael@0: QueryInterface : XPCOMUtils.generateQI([Ci.nsIINIParserFactory]), michael@0: michael@0: createINIParser : function (aINIFile) { michael@0: return new INIProcessor(aINIFile); michael@0: } michael@0: michael@0: }; // end of INIProcessorFactory implementation michael@0: michael@0: const MODE_WRONLY = 0x02; michael@0: const MODE_CREATE = 0x08; michael@0: const MODE_TRUNCATE = 0x20; michael@0: michael@0: // nsIINIParser implementation michael@0: function INIProcessor(aFile) { michael@0: this._iniFile = aFile; michael@0: this._iniData = {}; michael@0: this._readFile(); michael@0: } michael@0: michael@0: INIProcessor.prototype = { michael@0: QueryInterface : XPCOMUtils.generateQI([Ci.nsIINIParser, Ci.nsIINIParserWriter]), michael@0: michael@0: __utf8Converter : null, // UCS2 <--> UTF8 string conversion michael@0: get _utf8Converter() { michael@0: if (!this.__utf8Converter) { michael@0: this.__utf8Converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]. michael@0: createInstance(Ci.nsIScriptableUnicodeConverter); michael@0: this.__utf8Converter.charset = "UTF-8"; michael@0: } michael@0: return this.__utf8Converter; michael@0: }, michael@0: michael@0: __utf16leConverter : null, // UCS2 <--> UTF16LE string conversion michael@0: get _utf16leConverter() { michael@0: if (!this.__utf16leConverter) { michael@0: this.__utf16leConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]. michael@0: createInstance(Ci.nsIScriptableUnicodeConverter); michael@0: this.__utf16leConverter.charset = "UTF-16LE"; michael@0: } michael@0: return this.__utf16leConverter; michael@0: }, michael@0: michael@0: _utfConverterReset : function() { michael@0: this.__utf8Converter = null; michael@0: this.__utf16leConverter = null; michael@0: }, michael@0: michael@0: _iniFile : null, michael@0: _iniData : null, michael@0: michael@0: /* michael@0: * Reads the INI file and stores the data internally. michael@0: */ michael@0: _readFile : function() { michael@0: // If file doesn't exist, there's nothing to do. michael@0: if (!this._iniFile.exists() || 0 == this._iniFile.fileSize) michael@0: return; michael@0: michael@0: let iniParser = Cc["@mozilla.org/xpcom/ini-parser-factory;1"] michael@0: .getService(Ci.nsIINIParserFactory).createINIParser(this._iniFile); michael@0: for (let section in XPCOMUtils.IterStringEnumerator(iniParser.getSections())) { michael@0: this._iniData[section] = {}; michael@0: for (let key in XPCOMUtils.IterStringEnumerator(iniParser.getKeys(section))) { michael@0: this._iniData[section][key] = iniParser.getString(section, key); michael@0: } michael@0: } michael@0: }, michael@0: michael@0: // nsIINIParser michael@0: michael@0: getSections : function() { michael@0: let sections = []; michael@0: for (let section in this._iniData) michael@0: sections.push(section); michael@0: return new stringEnumerator(sections); michael@0: }, michael@0: michael@0: getKeys : function(aSection) { michael@0: let keys = []; michael@0: if (aSection in this._iniData) michael@0: for (let key in this._iniData[aSection]) michael@0: keys.push(key); michael@0: return new stringEnumerator(keys); michael@0: }, michael@0: michael@0: getString : function(aSection, aKey) { michael@0: if (!(aSection in this._iniData)) michael@0: throw Cr.NS_ERROR_FAILURE; michael@0: if (!(aKey in this._iniData[aSection])) michael@0: throw Cr.NS_ERROR_FAILURE; michael@0: return this._iniData[aSection][aKey]; michael@0: }, michael@0: michael@0: michael@0: // nsIINIParserWriter michael@0: michael@0: setString : function(aSection, aKey, aValue) { michael@0: const isSectionIllegal = /[\0\r\n\[\]]/; michael@0: const isKeyValIllegal = /[\0\r\n=]/; michael@0: michael@0: if (isSectionIllegal.test(aSection)) michael@0: throw Components.Exception("bad character in section name", michael@0: Cr.ERROR_ILLEGAL_VALUE); michael@0: if (isKeyValIllegal.test(aKey) || isKeyValIllegal.test(aValue)) michael@0: throw Components.Exception("bad character in key/value", michael@0: Cr.ERROR_ILLEGAL_VALUE); michael@0: michael@0: if (!(aSection in this._iniData)) michael@0: this._iniData[aSection] = {}; michael@0: michael@0: this._iniData[aSection][aKey] = aValue; michael@0: }, michael@0: michael@0: writeFile : function(aFile, aFlags) { michael@0: michael@0: let converter; michael@0: function writeLine(data) { michael@0: data += "\n"; michael@0: data = converter.ConvertFromUnicode(data); michael@0: data += converter.Finish(); michael@0: outputStream.write(data, data.length); michael@0: } michael@0: michael@0: if (!aFile) michael@0: aFile = this._iniFile; michael@0: michael@0: let safeStream = Cc["@mozilla.org/network/safe-file-output-stream;1"]. michael@0: createInstance(Ci.nsIFileOutputStream); michael@0: safeStream.init(aFile, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, michael@0: 0600, null); michael@0: michael@0: var outputStream = Cc["@mozilla.org/network/buffered-output-stream;1"]. michael@0: createInstance(Ci.nsIBufferedOutputStream); michael@0: outputStream.init(safeStream, 8192); michael@0: outputStream.QueryInterface(Ci.nsISafeOutputStream); // for .finish() michael@0: michael@0: if (Ci.nsIINIParserWriter.WRITE_UTF16 == aFlags michael@0: && 'nsIWindowsRegKey' in Ci) { michael@0: outputStream.write("\xFF\xFE", 2); michael@0: converter = this._utf16leConverter; michael@0: } else { michael@0: converter = this._utf8Converter; michael@0: } michael@0: michael@0: for (let section in this._iniData) { michael@0: writeLine("[" + section + "]"); michael@0: for (let key in this._iniData[section]) { michael@0: writeLine(key + "=" + this._iniData[section][key]); michael@0: } michael@0: } michael@0: michael@0: outputStream.finish(); michael@0: } michael@0: }; michael@0: michael@0: function stringEnumerator(stringArray) { michael@0: this._strings = stringArray; michael@0: } michael@0: stringEnumerator.prototype = { michael@0: QueryInterface : XPCOMUtils.generateQI([Ci.nsIUTF8StringEnumerator]), michael@0: michael@0: _strings : null, michael@0: _enumIndex: 0, michael@0: michael@0: hasMore : function() { michael@0: return (this._enumIndex < this._strings.length); michael@0: }, michael@0: michael@0: getNext : function() { michael@0: return this._strings[this._enumIndex++]; michael@0: } michael@0: }; michael@0: michael@0: let component = [INIProcessorFactory]; michael@0: this.NSGetFactory = XPCOMUtils.generateNSGetFactory(component);