Source: Ini.js

this.Ini = this.Ini || Class.extend( /** @lends Ini# */ {
	/**
	 * @class Ini file reader.
	 * @param {String} filename name of the ini file to open.
	 * @augments Class
	 * @constructs
	 * @throws {Error} when the filename is falsy value or when failed to open file.
	 */
	initialize: function(filename) {
		this.sr = new StreamReader(filename);
	},
	/**
	 * Load data from ini file.
	 * @returns {Object} Deserialized data.
	 * @throws {Error} when the structure of ini file is invalid.
	 */
	Load: function() {
		var data = {},
			currentSection, lineCnt = 0,
			line, pair, key, val;

		function isBlankOrComment(line) {
			line = line.trim();
			return (line.length === 0 || line.substr(0, 2) === '//' || line.charAt(0) === '\'');
		}

		function isSectionDeclaration(line) {
			return !!line.trim().match(/^\[.+\]$/);
		}

		while ((line = this.sr.ReadLine()) !== null) {
			lineCnt++;
			if (isBlankOrComment(line)) {
				continue;
			}
			if (isSectionDeclaration(line)) {
				currentSection = data[line.trim().replace(/\[|\]/g, '')] = {};
			}
			pair = line.split('=').map(function(v) {
				return v.trim();
			});
			if (pair.length !== 2) {
				continue;
			}
			if (!currentSection) {
				throw new Error('Ini: declare section statement before key-value statements.');
			}
			key = pair[0];
			val = pair[1];
			if (val.match(/^(\-){0,1}\d+(\.\d+){0,1}$/g)) {
				val = +val;
			}
			if (currentSection[key]) {
				throw new Error('Ini: the key is already defined: ' + key + ' in line:' + lineCnt);
			}
			currentSection[key] = val;
		}
		this.sr.Close();
		return data;
	}
});