Merge upstream branch
diff --git a/application/config/mimes.php b/application/config/mimes.php
index 8c34fd2..2a68ce9 100644
--- a/application/config/mimes.php
+++ b/application/config/mimes.php
@@ -121,8 +121,8 @@
 				'avi'	=>	array('video/x-msvideo', 'video/msvideo', 'video/avi', 'application/x-troff-msvideo'),
 				'movie'	=>	'video/x-sgi-movie',
 				'doc'	=>	'application/msword',
-				'docx'	=>	'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
-				'xlsx'	=>	'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+				'docx'	=>	array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip'),
+				'xlsx'	=>	array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip'),
 				'word'	=>	array('application/msword', 'application/octet-stream'),
 				'xl'	=>	'application/excel',
 				'eml'	=>	'message/rfc822',
diff --git a/system/core/Common.php b/system/core/Common.php
index 225227d..4919793 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -56,7 +56,7 @@
 	function is_php($version = '5.0.0')
 	{
 		static $_is_php;
-		$version = (string)$version;
+		$version = (string) $version;
 
 		if ( ! isset($_is_php[$version]))
 		{
@@ -84,7 +84,7 @@
 	function is_really_writable($file)
 	{
 		// If we're on a Unix server with safe_mode off we call is_writable
-		if (DIRECTORY_SEPARATOR === '/' AND @ini_get('safe_mode') == FALSE)
+		if (DIRECTORY_SEPARATOR === '/' && (bool) @ini_get('safe_mode') === FALSE)
 		{
 			return is_writable($file);
 		}
@@ -120,7 +120,7 @@
 /**
 * Class registry
 *
-* This function acts as a singleton.  If the requested class does not
+* This function acts as a singleton. If the requested class does not
 * exist it is instantiated and set to a static variable.  If it has
 * previously been instantiated the variable is returned.
 *
@@ -192,7 +192,7 @@
 // --------------------------------------------------------------------
 
 /**
-* Keeps track of which libraries have been loaded.  This function is
+* Keeps track of which libraries have been loaded. This function is
 * called by the load_class() function above
 *
 * @access	public
@@ -437,7 +437,7 @@
 			show_error('Status codes must be numeric', 500);
 		}
 
-		if (isset($stati[$code]) AND $text == '')
+		if (isset($stati[$code]) && $text == '')
 		{
 			$text = $stati[$code];
 		}
@@ -447,19 +447,19 @@
 			show_error('No status text available. Please check your status code number or supply your own message text.', 500);
 		}
 
-		$server_protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : FALSE;
+		$server_protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : FALSE;
 
 		if (strpos(php_sapi_name(), 'cgi') === 0)
 		{
-			header("Status: {$code} {$text}", TRUE);
+			header('Status: '.$code.' '.$text, TRUE);
 		}
-		elseif ($server_protocol == 'HTTP/1.1' OR $server_protocol == 'HTTP/1.0')
+		elseif ($server_protocol === 'HTTP/1.0')
 		{
-			header($server_protocol." {$code} {$text}", TRUE, $code);
+			header('HTTP/1.0 '.$code.' '.$text, TRUE, $code);
 		}
 		else
 		{
-			header("HTTP/1.1 {$code} {$text}", TRUE, $code);
+			header('HTTP/1.1 '.$code.' '.$text, TRUE, $code);
 		}
 	}
 }
@@ -564,14 +564,9 @@
 {
 	function html_escape($var)
 	{
-		if (is_array($var))
-		{
-			return array_map('html_escape', $var);
-		}
-		else
-		{
-			return htmlspecialchars($var, ENT_QUOTES, config_item('charset'));
-		}
+		return is_array($var)
+			? array_map('html_escape', $var)
+			: htmlspecialchars($var, ENT_QUOTES, config_item('charset'));
 	}
 }
 
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index b829bbe..6352c73 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -107,11 +107,9 @@
 	/**
 	 * Initialize Database Settings
 	 *
-	 * @access	private Called by the constructor
-	 * @param	mixed
-	 * @return	void
+	 * @return	bool
 	 */
-	function initialize()
+	public function initialize()
 	{
 		// If an existing connection resource is available
 		// there is no need to connect and select the database
@@ -125,7 +123,7 @@
 		// Connect to the database and set the connection ID
 		$this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
 
-		// No connection resource?  Check if there is a failover else throw an error
+		// No connection resource? Check if there is a failover else throw an error
 		if ( ! $this->conn_id)
 		{
 			// Check if there is a failover set
@@ -167,31 +165,19 @@
 		// ----------------------------------------------------------------
 
 		// Select the DB... assuming a database name is specified in the config file
-		if ($this->database != '')
+		if ($this->database !== '' && ! $this->db_select())
 		{
-			if ( ! $this->db_select())
-			{
-				log_message('error', 'Unable to select database: '.$this->database);
+			log_message('error', 'Unable to select database: '.$this->database);
 
-				if ($this->db_debug)
-				{
-					$this->display_error('db_unable_to_select', $this->database);
-				}
-				return FALSE;
-			}
-			else
+			if ($this->db_debug)
 			{
-				// We've selected the DB. Now we set the character set
-				if ( ! $this->db_set_charset($this->char_set, $this->dbcollat))
-				{
-					return FALSE;
-				}
-
-				return TRUE;
+				$this->display_error('db_unable_to_select', $this->database);
 			}
+			return FALSE;
 		}
 
-		return TRUE;
+		// Now we set the character set and that's all
+		return $this->db_set_charset($this->char_set, $this->dbcollat);
 	}
 
 	// --------------------------------------------------------------------
@@ -1438,7 +1424,23 @@
 
 		return $item.$alias;
 	}
+	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Dummy method that allows Active Record class to be disabled
+	 *
+	 * This function is used extensively by every db driver.
+	 *
+	 * @access	private
+	 * @return	void
+	 */
+	protected function _reset_select()
+	{
+	
+	}
+
 }
 
 /* End of file DB_driver.php */
-/* Location: ./system/database/DB_driver.php */
+/* Location: ./system/database/DB_driver.php */
\ No newline at end of file
diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php
index 2a10989..25a32f3 100644
--- a/system/database/drivers/mssql/mssql_driver.php
+++ b/system/database/drivers/mssql/mssql_driver.php
@@ -114,14 +114,25 @@
 	/**
 	 * Select the database
 	 *
-	 * @access	private called by the base class
-	 * @return	resource
+	 * @param	string	database name
+	 * @return	bool
 	 */
-	function db_select()
+	public function db_select($database = '')
 	{
+		if ($database === '')
+		{
+			$database = $this->database;
+		}
+
 		// Note: The brackets are required in the event that the DB name
 		// contains reserved characters
-		return @mssql_select_db('['.$this->database.']', $this->conn_id);
+		if (@mssql_select_db('['.$database.']', $this->conn_id))
+		{
+			$this->database = $database;
+			return TRUE;
+		}
+
+		return FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -676,4 +687,4 @@
 
 
 /* End of file mssql_driver.php */
-/* Location: ./system/database/drivers/mssql/mssql_driver.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/mssql/mssql_driver.php */
diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php
index 067710f..c88a8a7 100644
--- a/system/database/drivers/mysql/mysql_driver.php
+++ b/system/database/drivers/mysql/mysql_driver.php
@@ -119,11 +119,23 @@
 	/**
 	 * Select the database
 	 *
+	 * @param	string	database name
 	 * @return	bool
 	 */
-	public function db_select()
+	public function db_select($database = '')
 	{
-		return @mysql_select_db($this->database, $this->conn_id);
+		if ($database === '')
+		{
+			$database = $this->database;
+		}
+
+		if (@mysql_select_db($database, $this->conn_id))
+		{
+			$this->database = $database;
+			return TRUE;
+		}
+
+		return FALSE;
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/mysql/mysql_forge.php b/system/database/drivers/mysql/mysql_forge.php
index d310713..0f251b0 100644
--- a/system/database/drivers/mysql/mysql_forge.php
+++ b/system/database/drivers/mysql/mysql_forge.php
@@ -147,7 +147,7 @@
 			$sql .= 'IF NOT EXISTS ';
 		}
 
-		$sql .= $this->db->_escape_identifiers($table).' ('.$this->_process_fields($fields);
+		$sql .= $this->db->protect_identifiers($table).' ('.$this->_process_fields($fields);
 
 		if (count($primary_keys) > 0)
 		{
@@ -187,7 +187,7 @@
 	 */
 	public function _drop_table($table)
 	{
-		return 'DROP TABLE IF EXISTS '.$this->db->_escape_identifiers($table);
+		return 'DROP TABLE IF EXISTS '.$this->db->protect_identifiers($table);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/mysql/mysql_utility.php b/system/database/drivers/mysql/mysql_utility.php
index 0e7c18e..952f887 100644
--- a/system/database/drivers/mysql/mysql_utility.php
+++ b/system/database/drivers/mysql/mysql_utility.php
@@ -56,7 +56,7 @@
 	 */
 	public function _optimize_table($table)
 	{
-		return 'OPTIMIZE TABLE '.$this->db->_escape_identifiers($table);
+		return 'OPTIMIZE TABLE '.$this->db->protect_identifiers($table);
 	}
 
 	// --------------------------------------------------------------------
@@ -71,7 +71,7 @@
 	 */
 	public function _repair_table($table)
 	{
-		return 'REPAIR TABLE '.$this->db->_escape_identifiers($table);
+		return 'REPAIR TABLE '.$this->db->protect_identifiers($table);
 	}
 
 	// --------------------------------------------------------------------
@@ -102,7 +102,7 @@
 			}
 
 			// Get the table schema
-			$query = $this->db->query('SHOW CREATE TABLE `'.$this->db->database.'`.`'.$table.'`');
+			$query = $this->db->query('SHOW CREATE TABLE '.$this->db->protect_identifiers($this->db->database).'.'.$this->db->protect_identifiers($table));
 
 			// No result means the table name was invalid
 			if ($query === FALSE)
@@ -115,7 +115,7 @@
 
 			if ($add_drop == TRUE)
 			{
-				$output .= 'DROP TABLE IF EXISTS '.$table.';'.$newline.$newline;
+				$output .= 'DROP TABLE IF EXISTS '.$this->db->protect_identifiers($table).';'.$newline.$newline;
 			}
 
 			$i = 0;
@@ -135,7 +135,7 @@
 			}
 
 			// Grab all the data from the current table
-			$query = $this->db->query('SELECT * FROM '.$table);
+			$query = $this->db->query('SELECT * FROM '.$this->db->protect_identifiers($table));
 
 			if ($query->num_rows() == 0)
 			{
@@ -157,7 +157,7 @@
 							TRUE);
 
 				// Create a string of field names
-				$field_str .= '`'.$field->name.'`, ';
+				$field_str .= $this->db->protect_identifiers($field->name).', ';
 				$i++;
 			}
 
@@ -192,14 +192,15 @@
 				$val_str = preg_replace('/, $/' , '', $val_str);
 
 				// Build the INSERT string
-				$output .= 'INSERT INTO '.$table.' ('.$field_str.') VALUES ('.$val_str.');'.$newline;
+				$output .= 'INSERT INTO '.$this->db->protect_identifiers($table).' ('.$field_str.') VALUES ('.$val_str.');'.$newline;
 			}
 
-			return $output.$newline.$newline;
+			$output .= $newline.$newline;
 		}
 
 		return $output;
 	}
+
 }
 
 /* End of file mysql_utility.php */
diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php
index a79b2a4..dbba12e 100644
--- a/system/database/drivers/mysqli/mysqli_driver.php
+++ b/system/database/drivers/mysqli/mysqli_driver.php
@@ -119,11 +119,23 @@
 	/**
 	 * Select the database
 	 *
+	 * @param	string	database name
 	 * @return	bool
 	 */
-	public function db_select()
+	public function db_select($database = '')
 	{
-		return @mysqli_select_db($this->conn_id, $this->database);
+		if ($database === '')
+		{
+			$database = $this->database;
+		}
+
+		if (@mysqli_select_db($this->conn_id, $database))
+		{
+			$this->database = $database;
+			return TRUE;
+		}
+
+		return FALSE;
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/database/drivers/sqlsrv/sqlsrv_driver.php b/system/database/drivers/sqlsrv/sqlsrv_driver.php
index 6fd52ef..9c50209 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_driver.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_driver.php
@@ -122,12 +122,23 @@
 	/**
 	 * Select the database
 	 *
-	 * @access	private called by the base class
-	 * @return	resource
+	 * @param	string	database name
+	 * @return	bool
 	 */
-	function db_select()
+	public function db_select($database = '')
 	{
-		return $this->_execute('USE ' . $this->database);
+		if ($database === '')
+		{
+			$database = $this->database;
+		}
+
+		if ($this->_execute('USE '.$database))
+		{
+			$this->database = $database;
+			return TRUE;
+		}
+
+		return FALSE;
 	}
 
 	// --------------------------------------------------------------------
@@ -608,4 +619,4 @@
 
 
 /* End of file mssql_driver.php */
-/* Location: ./system/database/drivers/mssql/mssql_driver.php */
\ No newline at end of file
+/* Location: ./system/database/drivers/mssql/mssql_driver.php */
diff --git a/system/helpers/inflector_helper.php b/system/helpers/inflector_helper.php
index 0bd1e11..02c425b 100644
--- a/system/helpers/inflector_helper.php
+++ b/system/helpers/inflector_helper.php
@@ -34,7 +34,7 @@
  * @subpackage	Helpers
  * @category	Helpers
  * @author		EllisLab Dev Team
- * @link		http://codeigniter.com/user_guide/helpers/directory_helper.html
+ * @link		http://codeigniter.com/user_guide/helpers/inflector_helper.html
  */
 
 
@@ -45,7 +45,6 @@
  *
  * Takes a plural word and makes it singular
  *
- * @access	public
  * @param	string
  * @return	str
  */
@@ -55,37 +54,51 @@
 	{
 		$result = strval($str);
 
+		if ( ! is_countable($result))
+		{
+			return $result;
+		}
+		
 		$singular_rules = array(
-			'/(matr)ices$/'			=> '\1ix',
-			'/(vert|ind)ices$/'		=> '\1ex',
-			'/^(ox)en/'				=> '\1',
-			'/(alias)es$/'			=> '\1',
-			'/([octop|vir])i$/'		=> '\1us',
-			'/(cris|ax|test)es$/'	=> '\1is',
-			'/(shoe)s$/'			=> '\1',
-			'/(o)es$/'				=> '\1',
-			'/(bus|campus)es$/'		=> '\1',
-			'/([m|l])ice$/'			=> '\1ouse',
-			'/(x|ch|ss|sh)es$/'		=> '\1',
-			'/(m)ovies$/'			=> '\1\2ovie',
-			'/(s)eries$/'			=> '\1\2eries',
-			'/([^aeiouy]|qu)ies$/'	=> '\1y',
-			'/([lr])ves$/'			=> '\1f',
-			'/(tive)s$/'			=> '\1',
-			'/(hive)s$/'			=> '\1',
-			'/([^f])ves$/'			=> '\1fe',
-			'/(^analy)ses$/'		=> '\1sis',
+			'/(matr)ices$/'         => '\1ix',
+			'/(vert|ind)ices$/'     => '\1ex',
+			'/^(ox)en/'             => '\1',
+			'/(alias)es$/'          => '\1',
+			'/([octop|vir])i$/'     => '\1us',
+			'/(cris|ax|test)es$/'   => '\1is',
+			'/(shoe)s$/'            => '\1',
+			'/(o)es$/'              => '\1',
+			'/(bus|campus)es$/'     => '\1',
+			'/([m|l])ice$/'         => '\1ouse',
+			'/(x|ch|ss|sh)es$/'     => '\1',
+			'/(m)ovies$/'           => '\1\2ovie',
+			'/(s)eries$/'           => '\1\2eries',
+			'/([^aeiouy]|qu)ies$/'  => '\1y',
+			'/([lr])ves$/'          => '\1f',
+			'/(tive)s$/'            => '\1',
+			'/(hive)s$/'            => '\1',
+			'/([^f])ves$/'          => '\1fe',
+			'/(^analy)ses$/'        => '\1sis',
 			'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/' => '\1\2sis',
-			'/([ti])a$/'			=> '\1um',
-			'/(p)eople$/'			=> '\1\2erson',
-			'/(m)en$/'				=> '\1an',
-			'/(s)tatuses$/'			=> '\1\2tatus',
-			'/(c)hildren$/'			=> '\1\2hild',
-			'/(n)ews$/'				=> '\1\2ews',
-			'/([^u])s$/'			=> '\1',
+			'/([ti])a$/'            => '\1um',
+			'/(p)eople$/'           => '\1\2erson',
+			'/(m)en$/'              => '\1an',
+			'/(s)tatuses$/'         => '\1\2tatus',
+			'/(c)hildren$/'         => '\1\2hild',
+			'/(n)ews$/'             => '\1\2ews',
+			'/([^us])s$/'           => '\1',
 		);
 
-		return preg_replace(array_keys($singular_values), $singular_values, $result);
+		foreach ($singular_rules as $rule => $replacement)
+		{
+			if (preg_match($rule, $result))
+			{
+				$result = preg_replace($rule, $replacement, $result);
+				break;
+			}
+		}
+
+		return $result;
 	}
 }
 
@@ -96,7 +109,6 @@
  *
  * Takes a singular word and makes it plural
  *
- * @access	public
  * @param	string
  * @param	bool
  * @return	str
@@ -104,32 +116,46 @@
 if ( ! function_exists('plural'))
 {
 	function plural($str, $force = FALSE)
-	{
+	{	
 		$result = strval($str);
 
-		$plural_rules = array(
-			'/^(ox)$/'					=> '\1\2en',	 // ox
-			'/([m|l])ouse$/'			=> '\1ice',	  // mouse, louse
-			'/(matr|vert|ind)ix|ex$/'	=> '\1ices',	 // matrix, vertex, index
-			'/(x|ch|ss|sh)$/'			=> '\1es',	   // search, switch, fix, box, process, address
-			'/([^aeiouy]|qu)y$/'		=> '\1ies',	  // query, ability, agency
-			'/(hive)$/'					=> '\1s',		// archive, hive
-			'/(?:([^f])fe|([lr])f)$/'	=> '\1\2ves',	// half, safe, wife
-			'/sis$/'					=> 'ses',		// basis, diagnosis
-			'/([ti])um$/'				=> '\1a',		// datum, medium
-			'/(p)erson$/'				=> '\1eople',	// person, salesperson
-			'/(m)an$/'					=> '\1en',	   // man, woman, spokesman
-			'/(c)hild$/'				=> '\1hildren',  // child
-			'/(buffal|tomat)o$/'		=> '\1\2oes',	// buffalo, tomato
-			'/(bu|campu)s$/'			=> '\1\2ses',	// bus, campus
-			'/(alias|status|virus)/'	=> '\1es',	   // alias
-			'/(octop)us$/'				=> '\1i',		// octopus
-			'/(ax|cris|test)is$/'		=> '\1es',	   // axis, crisis
-			'/s$/'						=> 's',		  // no change (compatibility)
-			'/$/'						=> 's',
-		);
+		if ( ! is_countable($result))
+		{
+			return $result;
+		}
 
-		return preg_replace(array_keys($plural_rules), $plural_rules, $result);
+		$plural_rules = array(
+			'/^(ox)$/'                 => '\1\2en',     // ox
+			'/([m|l])ouse$/'           => '\1ice',      // mouse, louse
+			'/(matr|vert|ind)ix|ex$/'  => '\1ices',     // matrix, vertex, index
+			'/(x|ch|ss|sh)$/'          => '\1es',       // search, switch, fix, box, process, address
+			'/([^aeiouy]|qu)y$/'       => '\1ies',      // query, ability, agency
+			'/(hive)$/'                => '\1s',        // archive, hive
+			'/(?:([^f])fe|([lr])f)$/'  => '\1\2ves',    // half, safe, wife
+			'/sis$/'                   => 'ses',        // basis, diagnosis
+			'/([ti])um$/'              => '\1a',        // datum, medium
+			'/(p)erson$/'              => '\1eople',    // person, salesperson
+			'/(m)an$/'                 => '\1en',       // man, woman, spokesman
+			'/(c)hild$/'               => '\1hildren',  // child
+			'/(buffal|tomat)o$/'       => '\1\2oes',    // buffalo, tomato
+			'/(bu|campu)s$/'           => '\1\2ses',    // bus, campus
+			'/(alias|status|virus)$/'  => '\1es',       // alias
+			'/(octop)us$/'             => '\1i',        // octopus
+			'/(ax|cris|test)is$/'      => '\1es',       // axis, crisis
+			'/s$/'                     => 's',          // no change (compatibility)
+			'/$/'                      => 's',
+		);
+		
+		foreach ($plural_rules as $rule => $replacement)
+		{
+			if (preg_match($rule, $result))
+			{
+				$result = preg_replace($rule, $replacement, $result);
+				break;
+			}
+		}
+
+		return $result;
 	}
 }
 
@@ -140,7 +166,6 @@
  *
  * Takes multiple words separated by spaces or underscores and camelizes them
  *
- * @access	public
  * @param	string
  * @return	str
  */
@@ -159,7 +184,6 @@
  *
  * Takes multiple words separated by spaces and underscores them
  *
- * @access	public
  * @param	string
  * @return	str
  */
@@ -178,7 +202,6 @@
  *
  * Takes multiple words separated by the separator and changes them to spaces
  *
- * @access	public
  * @param	string $str
  * @param 	string $separator
  * @return	str
@@ -191,5 +214,22 @@
 	}
 }
 
+/**
+ * Checks if the given word has a plural version.
+ *
+ * @param   string  the word to check
+ * @return  bool    if the word is countable
+ */
+if ( ! function_exists('is_countable'))
+{
+	function is_countable($word)
+	{
+		return ! (in_array(strtolower(strval($word)), array(
+			'equipment', 'information', 'rice', 'money',
+			'species', 'series', 'fish', 'meta'
+		)));
+	}
+}
+
 /* End of file inflector_helper.php */
-/* Location: ./system/helpers/inflector_helper.php */
+/* Location: ./system/helpers/inflector_helper.php */
\ No newline at end of file
diff --git a/system/libraries/Cache/drivers/Cache_file.php b/system/libraries/Cache/drivers/Cache_file.php
index 4a81b04..a960730 100644
--- a/system/libraries/Cache/drivers/Cache_file.php
+++ b/system/libraries/Cache/drivers/Cache_file.php
@@ -99,7 +99,7 @@
 
 		if (write_file($this->_cache_path.$id, serialize($contents)))
 		{
-			@chmod($this->_cache_path.$id, 0777);
+			@chmod($this->_cache_path.$id, 0660);
 			return TRUE;
 		}
 
diff --git a/system/libraries/Cart.php b/system/libraries/Cart.php
index ba8d69b..10b5362 100644
--- a/system/libraries/Cart.php
+++ b/system/libraries/Cart.php
@@ -329,13 +329,6 @@
 			return FALSE;
 		}
 
-		// Is the new quantity different than what is already saved in the cart?
-		// If it's the same there's nothing to do
-		if ($this->_cart_contents[$items['rowid']]['qty'] == $items['qty'])
-		{
-			return FALSE;
-		}
-
 		// Is the quantity zero?  If so we will remove the item from the cart.
 		// If the quantity is greater than zero we are updating
 		if ($items['qty'] == 0)
diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php
index 0a6a2af..2ee734a 100644
--- a/system/libraries/Form_validation.php
+++ b/system/libraries/Form_validation.php
@@ -703,11 +703,11 @@
 	 *
 	 * @param	string	the field name
 	 * @param	string
-	 * @return	void
+	 * @return	string
 	 */
 	public function set_value($field = '', $default = '')
 	{
-		if ( ! isset($this->_field_data[$field]))
+		if ( ! isset($this->_field_data[$field], $this->_field_data[$field]['postdata']))
 		{
 			return $default;
 		}
@@ -736,13 +736,9 @@
 	 */
 	public function set_select($field = '', $value = '', $default = FALSE)
 	{
-		if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata']))
+		if ( ! isset($this->_field_data[$field], $this->_field_data[$field]['postdata']))
 		{
-			if ($default === TRUE AND count($this->_field_data) === 0)
-			{
-				return ' selected="selected"';
-			}
-			return '';
+			return ($default === TRUE && count($this->_field_data) === 0) ? ' selected="selected"' : '';
 		}
 
 		$field = $this->_field_data[$field]['postdata'];
@@ -754,12 +750,9 @@
 				return '';
 			}
 		}
-		else
+		elseif (($field == '' OR $value == '') OR ($field != $value))
 		{
-			if (($field == '' OR $value == '') OR ($field != $value))
-			{
-				return '';
-			}
+			return '';
 		}
 
 		return ' selected="selected"';
@@ -779,13 +772,9 @@
 	 */
 	public function set_radio($field = '', $value = '', $default = FALSE)
 	{
-		if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata']))
+		if ( ! isset($this->_field_data[$field], $this->_field_data[$field]['postdata']))
 		{
-			if ($default === TRUE AND count($this->_field_data) === 0)
-			{
-				return ' checked="checked"';
-			}
-			return '';
+			return ($default === TRUE && count($this->_field_data) === 0) ? ' checked="checked"' : '';
 		}
 
 		$field = $this->_field_data[$field]['postdata'];
@@ -869,9 +858,7 @@
 			return FALSE;
 		}
 
-		$field = $_POST[$field];
-
-		return ($str === $field);
+		return ($str === $_POST[$field]);
 	}
 
 	// --------------------------------------------------------------------
@@ -908,7 +895,7 @@
 	 */
 	public function min_length($str, $val)
 	{
-		if (preg_match("/[^0-9]/", $val))
+		if (preg_match('/[^0-9]/', $val))
 		{
 			return FALSE;
 		}
@@ -932,7 +919,7 @@
 	 */
 	public function max_length($str, $val)
 	{
-		if (preg_match("/[^0-9]/", $val))
+		if (preg_match('/[^0-9]/', $val))
 		{
 			return FALSE;
 		}
@@ -956,7 +943,7 @@
 	 */
 	public function exact_length($str, $val)
 	{
-		if (preg_match("/[^0-9]/", $val))
+		if (preg_match('/[^0-9]/', $val))
 		{
 			return FALSE;
 		}
@@ -1170,7 +1157,7 @@
 	 */
 	public function is_natural_no_zero($str)
 	{
-		return ($str != 0 AND preg_match('/^[0-9]+$/', $str));
+		return ($str != 0 && preg_match('/^[0-9]+$/', $str));
 	}
 
 	// --------------------------------------------------------------------
@@ -1217,7 +1204,7 @@
 			return $data;
 		}
 
-		return str_replace(array("'", '"', '<', '>'), array("&#39;", "&quot;", '&lt;', '&gt;'), stripslashes($data));
+		return str_replace(array("'", '"', '<', '>'), array('&#39;', '&quot;', '&lt;', '&gt;'), stripslashes($data));
 	}
 
 	// --------------------------------------------------------------------
@@ -1283,7 +1270,6 @@
 	}
 
 }
-// END Form Validation Class
 
 /* End of file Form_validation.php */
 /* Location: ./system/libraries/Form_validation.php */
diff --git a/system/libraries/Image_lib.php b/system/libraries/Image_lib.php
index 5ea830f..9826eab 100644
--- a/system/libraries/Image_lib.php
+++ b/system/libraries/Image_lib.php
@@ -251,7 +251,7 @@
 		}
 		else
 		{
-			if (function_exists('realpath') && @realpath($this->new_image) !== FALSE)
+			if (strpos($this->new_image, '/') === FALSE AND strpos($this->new_image, '\\') === FALSE)
 			{
 				$full_dest_path = str_replace('\\', '/', realpath($this->new_image));
 			}
diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php
index 0c63886..82383f6 100644
--- a/system/libraries/Upload.php
+++ b/system/libraries/Upload.php
@@ -1026,47 +1026,104 @@
 	 */
 	protected function _file_mime_type($file)
 	{
-		// Use if the Fileinfo extension, if available (only versions above 5.3 support the FILEINFO_MIME_TYPE flag)
-		if ( (float) substr(phpversion(), 0, 3) >= 5.3 && function_exists('finfo_file'))
+		// We'll need this to validate the MIME info string (e.g. text/plain; charset=us-ascii)
+		$regexp = '/^([a-z\-]+\/[a-z0-9\-\.\+]+)(;\s.+)?$/';
+
+		/* Fileinfo extension - most reliable method
+		 *
+		 * Unfortunately, prior to PHP 5.3 - it's only available as a PECL extension and the
+		 * more convenient FILEINFO_MIME_TYPE flag doesn't exist.
+		 */
+		if (function_exists('finfo_file'))
 		{
-			$finfo = new finfo(FILEINFO_MIME_TYPE);
-			if ($finfo !== FALSE) // This is possible, if there is no magic MIME database file found on the system
+			$finfo = finfo_open(FILEINFO_MIME);
+			if (is_resource($finfo)) // It is possible that a FALSE value is returned, if there is no magic MIME database file found on the system
 			{
-				$file_type = $finfo->file($file['tmp_name']);
+				$mime = @finfo_file($finfo, $file['tmp_name']);
+				finfo_close($finfo);
 
 				/* According to the comments section of the PHP manual page,
 				 * it is possible that this function returns an empty string
 				 * for some files (e.g. if they don't exist in the magic MIME database)
 				 */
-				if (strlen($file_type) > 1)
+				if (is_string($mime) && preg_match($regexp, $mime, $matches))
 				{
-					$this->file_type = $file_type;
+					$this->file_type = $matches[1];
 					return;
 				}
 			}
 		}
 
-		// Fall back to the deprecated mime_content_type(), if available
+		/* This is an ugly hack, but UNIX-type systems provide a "native" way to detect the file type,
+		 * which is still more secure than depending on the value of $_FILES[$field]['type'], and as it
+		 * was reported in issue #750 (https://github.com/EllisLab/CodeIgniter/issues/750) - it's better
+		 * than mime_content_type() as well, hence the attempts to try calling the command line with
+		 * three different functions.
+		 *
+		 * Notes:
+		 *	- the DIRECTORY_SEPARATOR comparison ensures that we're not on a Windows system
+		 *	- many system admins would disable the exec(), shell_exec(), popen() and similar functions
+		 *	  due to security concerns, hence the function_exists() checks
+		 */
+		if (DIRECTORY_SEPARATOR !== '\\')
+		{
+			$cmd = 'file --brief --mime ' . escapeshellarg($file['tmp_name']) . ' 2>&1';
+
+			if (function_exists('exec'))
+			{
+				/* This might look confusing, as $mime is being populated with all of the output when set in the second parameter.
+				 * However, we only neeed the last line, which is the actual return value of exec(), and as such - it overwrites
+				 * anything that could already be set for $mime previously. This effectively makes the second parameter a dummy
+				 * value, which is only put to allow us to get the return status code.
+				 */
+				$mime = @exec($cmd, $mime, $return_status);
+				if ($return_status === 0 && is_string($mime) && preg_match($regexp, $mime, $matches))
+				{
+					$this->file_type = $matches[1];
+					return;
+				}
+			}
+
+			if ( (bool) @ini_get('safe_mode') === FALSE && function_exists('shell_exec'))
+			{
+				$mime = @shell_exec($cmd);
+				if (strlen($mime) > 0)
+				{
+					$mime = explode("\n", trim($mime));
+					if (preg_match($regexp, $mime[(count($mime) - 1)], $matches))
+					{
+						$this->file_type = $matches[1];
+						return;
+					}
+				}
+			}
+
+			if (function_exists('popen'))
+			{
+				$proc = @popen($cmd, 'r');
+				if (is_resource($proc))
+				{
+					$mime = @fread($test, 512);
+					@pclose($proc);
+					if ($mime !== FALSE)
+					{
+						$mime = explode("\n", trim($mime));
+						if (preg_match($regexp, $mime[(count($mime) - 1)], $matches))
+						{
+							$this->file_type = $matches[1];
+							return;
+						}
+					}
+				}
+			}
+		}
+
+		// Fall back to the deprecated mime_content_type(), if available (still better than $_FILES[$field]['type'])
 		if (function_exists('mime_content_type'))
 		{
 			$this->file_type = @mime_content_type($file['tmp_name']);
-			return;
-		}
-
-		/* This is an ugly hack, but UNIX-type systems provide a native way to detect the file type,
-		 * which is still more secure than depending on the value of $_FILES[$field]['type'].
-		 *
-		 * Notes:
-		 *	- a 'W' in the substr() expression bellow, would mean that we're using Windows
-		 *	- many system admins would disable the exec() function due to security concerns, hence the function_exists() check
-		 */
-		if (DIRECTORY_SEPARATOR !== '\\' && function_exists('exec'))
-		{
-			$output = array();
-			@exec('file --brief --mime-type ' . escapeshellarg($file['tmp_path']), $output, $return_code);
-			if ($return_code === 0 && strlen($output[0]) > 0) // A return status code != 0 would mean failed execution
+			if (strlen($this->file_type) > 0) // It's possible that mime_content_type() returns FALSE or an empty string
 			{
-				$this->file_type = rtrim($output[0]);
 				return;
 			}
 		}
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 1fcf400..35e8767 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -39,6 +39,7 @@
    -  url_title() will now trim extra dashes from beginning and end.
    -  Added XHTML Basic 1.1 doctype to :doc:`HTML Helper <helpers/html_helper>`.
    -  Changed humanize() to include a second param for the separator.
+   -  Refactored ``plural()`` and ``singular()`` to avoid double pluralization and support more words.
    -  Added date_range() to the :doc:`Date Helper <helpers/html_helper>`.
 
 -  Database
@@ -52,6 +53,7 @@
    -  MySQLi driver now supports persistent connections when running on PHP >= 5.3.
    -  Added dsn if the group connections in the config use PDO or any driver which need DSN.
    -  Improved PDO database support.
+   -  An optional database name parameter was added db_select().
 
 -  Libraries
 
@@ -106,11 +108,36 @@
 -  Fixed a hosting edge case where an empty $_SERVER['HTTPS'] variable would evaluate to 'on'
 -  Fixed a bug (#154) - ``CI_Session::sess_update()`` caused the session to be destroyed on pages where multiple AJAX requests were executed at once.
 -  Fixed a possible bug in ``CI_Input::is_ajax_request()`` where some clients might not send the X-Requested-With HTTP header value exactly as 'XmlHttpRequest'.
+-  Fixed a bug (#1039) - MySQL's _backup() method failed due to a table name not being escaped.
+-  Fixed a bug (#1070) - CI_DB_driver::initialize() didn't set a character set if a database is not selected.
+-  Fixed a bug (#177) - CI_Form_validation::set_value() didn't set the default value if POST data is NULL.
+
+
+Version 2.1.1
+=============
+
+Release Date: Not Released
+
+-  General Changes
+   -  Fixed support for docx, xlsx files in mimes.php.
+
+-  Libraries
+   -  Further improved MIME type detection in the :doc:`File Uploading Library <libraries/file_uploading>`.
+
+
+Bug fixes for 2.1.1
+-------------------
+
+-  Fixed a bug (#697) - A wrong array key was used in the Upload library to check for mime-types.
+-  Fixed a bug - form_open() compared $action against site_url() instead of base_url().
+-  Fixed a bug - CI_Upload::_file_mime_type() could've failed if mime_content_type() is used for the detection and returns FALSE.
+-  Fixed a bug (#538) - Windows paths were ignored when using the :doc:`Image Manipulation Library <libraries/image_lib>` to create a new file.
+
 
 Version 2.1.0
 =============
 
-Release Date: Not Released
+Release Date: November 14, 2011
 
 -  General Changes
 
diff --git a/user_guide_src/source/database/connecting.rst b/user_guide_src/source/database/connecting.rst
index a834cc0..fb45241 100644
--- a/user_guide_src/source/database/connecting.rst
+++ b/user_guide_src/source/database/connecting.rst
@@ -122,6 +122,12 @@
 	| $DB1->result();
 	| etc...
 
+.. note:: You don't need to create separate database configurations if you
+	only need to use a different database on the same connection. You
+	can switch to a different database when you need to, like this:
+
+	| $this->db->db_select($database2_name);
+
 Reconnecting / Keeping the Connection Alive
 ===========================================