Merge upstream
diff --git a/phpdoc.dist.xml b/phpdoc.dist.xml
new file mode 100644
index 0000000..f1fcc62
--- /dev/null
+++ b/phpdoc.dist.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<phpdoc>
+	<title>CodeIgniter v3.0.0 API</title>
+    <parser>
+        <target>./api/</target>
+    </parser>
+    <transformer>
+        <target>./api/</target>
+    </transformer>
+    <files>
+        <directory>.</directory>
+        <ignore>./application/*</ignore>
+        <ignore>./tests/*</ignore>
+        <ignore>./user_guide_src/*</ignore>
+        <ignore>./views/*</ignore>
+    </files>
+
+    <logging>
+        <level>warn</level>
+        <paths>
+            <default>./api/log/{DATE}.log</default>
+            <errors>./api/{DATE}.errors.log</errors>
+        </paths>
+    </logging>
+</phpdoc>
\ No newline at end of file
diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php
index 793c468..349f9f2 100755
--- a/system/core/CodeIgniter.php
+++ b/system/core/CodeIgniter.php
@@ -153,7 +153,7 @@
  *
  * Note: Order here is rather important as the UTF-8
  * class needs to be used very early on, but it cannot
- * properly determine if UTf-8 can be supported until
+ * properly determine if UTF-8 can be supported until
  * after the Config class is instantiated.
  *
  */
diff --git a/system/core/Input.php b/system/core/Input.php
index 7594a2e..fc2a550 100755
--- a/system/core/Input.php
+++ b/system/core/Input.php
@@ -226,7 +226,6 @@
 	 */
 	public function cookie($index = '', $xss_clean = FALSE)
 	{
-		$index = config_item('cookie_prefix').$index;
 		return $this->_fetch_from_array($_COOKIE, $index, $xss_clean);
 	}
 
diff --git a/system/core/Router.php b/system/core/Router.php
index fe9909b..9314052 100755
--- a/system/core/Router.php
+++ b/system/core/Router.php
@@ -242,12 +242,9 @@
 			$segments[1] = 'index';
 		}
 
-		// This is being routed to a file in a sub directory
-		$this->directory and array_unshift($segments, trim($this->directory, '/'));
-
 		// Update our "routed" segment array to contain the segments.
 		// Note: If there is no custom routing, this array will be
-		// identical to $this->uri->segments		
+		// identical to $this->uri->segments
 		$this->uri->rsegments = $segments;
 	}
 
diff --git a/system/core/URI.php b/system/core/URI.php
index 705575a..cf82c58 100755
--- a/system/core/URI.php
+++ b/system/core/URI.php
@@ -645,10 +645,10 @@
 	 */
 	public function ruri_string()
 	{
-		return implode('/', $this->rsegment_array());
+		return '/'.implode('/', $this->rsegment_array());
 	}
 
 }
 
 /* End of file URI.php */
-/* Location: ./system/core/URI.php */
\ No newline at end of file
+/* Location: ./system/core/URI.php */
diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php
index 393a1cd..d0af66d 100644
--- a/system/database/DB_query_builder.php
+++ b/system/database/DB_query_builder.php
@@ -281,7 +281,7 @@
 					$v = trim($v);
 					$this->_track_aliases($v);
 
-					$v = $this->qb_from[] = $this->protect_identifiers($v, TRUE, NULL, FALSE);
+					$this->qb_from[] = $v = $this->protect_identifiers($v, TRUE, NULL, FALSE);
 
 					if ($this->qb_caching === TRUE)
 					{
diff --git a/system/helpers/smiley_helper.php b/system/helpers/smiley_helper.php
index 6b4daf6..4320dd3 100644
--- a/system/helpers/smiley_helper.php
+++ b/system/helpers/smiley_helper.php
@@ -53,7 +53,6 @@
 	function smiley_js($alias = '', $field_id = '', $inline = TRUE)
 	{
 		static $do_setup = TRUE;
-
 		$r = '';
 
 		if ($alias != '' && ! is_array($alias))
@@ -63,69 +62,58 @@
 
 		if ($do_setup === TRUE)
 		{
-				$do_setup = FALSE;
+			$do_setup = FALSE;
+			$m = array();
 
-				$m = array();
-
-				if (is_array($alias))
-				{
-					foreach ($alias as $name => $id)
-					{
-						$m[] = '"'.$name.'" : "'.$id.'"';
-					}
-				}
-
-				$m = '{'.implode(',', $m).'}';
-
-				$r .= <<<EOF
-				var smiley_map = {$m};
-
-				function insert_smiley(smiley, field_id) {
-					var el = document.getElementById(field_id), newStart;
-
-					if ( ! el && smiley_map[field_id]) {
-						el = document.getElementById(smiley_map[field_id]);
-
-						if ( ! el)
-							return false;
-					}
-
-					el.focus();
-					smiley = " " + smiley;
-
-					if ('selectionStart' in el) {
-						newStart = el.selectionStart + smiley.length;
-
-						el.value = el.value.substr(0, el.selectionStart) +
-										smiley +
-										el.value.substr(el.selectionEnd, el.value.length);
-						el.setSelectionRange(newStart, newStart);
-					}
-					else if (document.selection) {
-						document.selection.createRange().text = smiley;
-					}
-				}
-EOF;
-		}
-		else
-		{
 			if (is_array($alias))
 			{
 				foreach ($alias as $name => $id)
 				{
-					$r .= 'smiley_map["'.$name.'"] = "'.$id.'";'."\n";
+					$m[] = '"'.$name.'" : "'.$id.'"';
 				}
 			}
+
+			$m = '{'.implode(',', $m).'}';
+
+			$r .= <<<EOF
+			var smiley_map = {$m};
+
+			function insert_smiley(smiley, field_id) {
+				var el = document.getElementById(field_id), newStart;
+
+				if ( ! el && smiley_map[field_id]) {
+					el = document.getElementById(smiley_map[field_id]);
+
+					if ( ! el)
+						return false;
+				}
+
+				el.focus();
+				smiley = " " + smiley;
+
+				if ('selectionStart' in el) {
+					newStart = el.selectionStart + smiley.length;
+
+					el.value = el.value.substr(0, el.selectionStart) +
+									smiley +
+									el.value.substr(el.selectionEnd, el.value.length);
+					el.setSelectionRange(newStart, newStart);
+				}
+				else if (document.selection) {
+					document.selection.createRange().text = smiley;
+				}
+			}
+EOF;
+		}
+		elseif (is_array($alias))
+		{
+			foreach ($alias as $name => $id)
+			{
+				$r .= 'smiley_map["'.$name.'"] = "'.$id."\";\n";
+			}
 		}
 
-		if ($inline)
-		{
-			return '<script type="text/javascript" charset="utf-8">/*<![CDATA[ */'.$r.'// ]]></script>';
-		}
-		else
-		{
-			return $r;
-		}
+		return ($inline) ? '<script type="text/javascript" charset="utf-8">/*<![CDATA[ */'.$r.'// ]]></script>' : $r;
 	}
 }
 
@@ -148,18 +136,13 @@
 	function get_clickable_smileys($image_url, $alias = '', $smileys = NULL)
 	{
 		// For backward compatibility with js_insert_smiley
-
 		if (is_array($alias))
 		{
 			$smileys = $alias;
 		}
-
-		if ( ! is_array($smileys))
+		elseif (FALSE === ($smileys = _get_smiley_array()))
 		{
-			if (FALSE === ($smileys = _get_smiley_array()))
-			{
-				return $smileys;
-			}
+			return $smileys;
 		}
 
 		// Add a trailing slash to the file path if needed
@@ -169,7 +152,7 @@
 		foreach ($smileys as $key => $val)
 		{
 			// Keep duplicates from being used, which can happen if the
-			// mapping array contains multiple identical replacements.  For example:
+			// mapping array contains multiple identical replacements. For example:
 			// :-) and :) might be replaced with the same image so both smileys
 			// will be in the array.
 			if (isset($used[$smileys[$key][0]]))
@@ -177,8 +160,7 @@
 				continue;
 			}
 
-			$link[] = "<a href=\"javascript:void(0);\" onclick=\"insert_smiley('".$key."', '".$alias."')\"><img src=\"".$image_url.$smileys[$key][0]."\" width=\"".$smileys[$key][1]."\" height=\"".$smileys[$key][2]."\" alt=\"".$smileys[$key][3]."\" style=\"border:0;\" /></a>";
-
+			$link[] = '<a href="javascript:void(0);" onclick="insert_smiley(\''.$key.'\', \''.$alias.'\')"><img src="'.$image_url.$smileys[$key][0].'" alt="'.$smileys[$key][3].'" style="width: '.$smileys[$key][1].'; height: '.$smileys[$key][2].'; border: 0;" /></a>';
 			$used[$smileys[$key][0]] = TRUE;
 		}
 
@@ -202,25 +184,17 @@
 	 */
 	function parse_smileys($str = '', $image_url = '', $smileys = NULL)
 	{
-		if ($image_url == '')
+		if ($image_url == '' OR ( ! is_array($smileys) && FALSE === ($smileys = _get_smiley_array())))
 		{
 			return $str;
 		}
 
-		if ( ! is_array($smileys))
-		{
-			if (FALSE === ($smileys = _get_smiley_array()))
-			{
-				return $str;
-			}
-		}
-
 		// Add a trailing slash to the file path if needed
-		$image_url = preg_replace("/(.+?)\/*$/", "\\1/",  $image_url);
+		$image_url = rtrim($image_url, '/').'/';
 
 		foreach ($smileys as $key => $val)
 		{
-			$str = str_replace($key, "<img src=\"".$image_url.$smileys[$key][0]."\" width=\"".$smileys[$key][1]."\" height=\"".$smileys[$key][2]."\" alt=\"".$smileys[$key][3]."\" style=\"border:0;\" />", $str);
+			$str = str_replace($key, '<img src="'.$image_url.$smileys[$key][0].'" alt="'.$smileys[$key][3].'" style="width: '.$smileys[$key][1].'; height: '.$smileys[$key][2].'; border: 0;" />', $str);
 		}
 
 		return $str;
@@ -249,12 +223,7 @@
 			include(APPPATH.'config/smileys.php');
 		}
 
-		if (isset($smileys) && is_array($smileys))
-		{
-			return $smileys;
-		}
-
-		return FALSE;
+		return (isset($smileys) && is_array($smileys)) ? $smileys : FALSE;
 	}
 }
 
diff --git a/system/helpers/string_helper.php b/system/helpers/string_helper.php
index b42799a..0c47d44 100644
--- a/system/helpers/string_helper.php
+++ b/system/helpers/string_helper.php
@@ -73,16 +73,14 @@
 	 */
 	function strip_slashes($str)
 	{
-		if (is_array($str))
+		if ( ! is_array($str))
 		{
-			foreach ($str as $key => $val)
-			{
-				$str[$key] = strip_slashes($val);
-			}
+			return stripslashes($str);
 		}
-		else
+
+		foreach ($str as $key => $val)
 		{
-			$str = stripslashes($str);
+			$str[$key] = strip_slashes($val);
 		}
 
 		return $str;
@@ -173,13 +171,7 @@
 	function reduce_multiples($str, $character = ',', $trim = FALSE)
 	{
 		$str = preg_replace('#'.preg_quote($character, '#').'{2,}#', $character, $str);
-
-		if ($trim === TRUE)
-		{
-			return trim($str, $character);
-		}
-
-		return $str;
+		return ($trim === TRUE) ? trim($str, $character) : $str;
 	}
 }
 
@@ -198,44 +190,36 @@
 	 */
 	function random_string($type = 'alnum', $len = 8)
 	{
-		switch($type)
+		switch ($type)
 		{
-			case 'basic'	: return mt_rand();
-				break;
-			case 'alnum'	:
-			case 'numeric'	:
-			case 'nozero'	:
-			case 'alpha'	:
-
-					switch ($type)
-					{
-						case 'alpha'	:	$pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
-							break;
-						case 'alnum'	:	$pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
-							break;
-						case 'numeric'	:	$pool = '0123456789';
-							break;
-						case 'nozero'	:	$pool = '123456789';
-							break;
-					}
-
-					$str = substr(str_shuffle(str_repeat($pool, ceil($len/strlen($pool)))),0,$len);
-
-					return $str;
-				break;
-			case 'unique'	:
-			case 'md5'		:
-
-						return md5(uniqid(mt_rand()));
-				break;
-			case 'encrypt'	:
-			case 'sha1'	:
-
-						$CI =& get_instance();
-						$CI->load->helper('security');
-
-						return do_hash(uniqid(mt_rand(), TRUE), 'sha1');
-				break;
+			case 'basic':
+				return mt_rand();
+			case 'alnum':
+			case 'numeric':
+			case 'nozero':
+			case 'alpha':
+				switch ($type)
+				{
+					case 'alpha':
+						$pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+						break;
+					case 'alnum':
+						$pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+						break;
+					case 'numeric':
+						$pool = '0123456789';
+						break;
+					case 'nozero':
+						$pool = '123456789';
+						break;
+				}
+				return substr(str_shuffle(str_repeat($pool, ceil($len / strlen($pool)))), 0, $len);
+			case 'unique':
+			case 'md5':
+				return md5(uniqid(mt_rand()));
+			case 'encrypt':
+			case 'sha1':
+				return sha1(uniqid(mt_rand(), TRUE));
 		}
 	}
 }
@@ -255,7 +239,6 @@
 	function increment_string($str, $separator = '_', $first = 1)
 	{
 		preg_match('/(.+)'.$separator.'([0-9]+)$/', $str, $match);
-
 		return isset($match[2]) ? $match[1].$separator.($match[2] + 1) : $str.$separator.$first;
 	}
 }
diff --git a/system/helpers/text_helper.php b/system/helpers/text_helper.php
index f53b06b..e4451ae 100644
--- a/system/helpers/text_helper.php
+++ b/system/helpers/text_helper.php
@@ -58,7 +58,7 @@
 
 		preg_match('/^\s*+(?:\S++\s*+){1,'.(int) $limit.'}/', $str, $matches);
 
-		if (strlen($str) == strlen($matches[0]))
+		if (strlen($str) === strlen($matches[0]))
 		{
 			$end_char = '';
 		}
@@ -89,14 +89,14 @@
 			return $str;
 		}
 
-		$str = preg_replace("/\s+/", ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str));
+		$str = preg_replace('/\s+/', ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str));
 
 		if (strlen($str) <= $n)
 		{
 			return $str;
 		}
 
-		$out = "";
+		$out = '';
 		foreach (explode(' ', trim($str)) as $val)
 		{
 			$out .= $val.' ';
@@ -104,7 +104,7 @@
 			if (strlen($out) >= $n)
 			{
 				$out = trim($out);
-				return (strlen($out) == strlen($str)) ? $out : $out.$end_char;
+				return (strlen($out) === strlen($str)) ? $out : $out.$end_char;
 			}
 		}
 	}
@@ -138,7 +138,7 @@
 					If the $temp array has a value but we have moved on, then it seems only
 					fair that we output that entity and restart $temp before continuing. -Paul
 				*/
-				if (count($temp) == 1)
+				if (count($temp) === 1)
 				{
 					$out  .= '&#'.array_shift($temp).';';
 					$count = 1;
@@ -148,16 +148,18 @@
 			}
 			else
 			{
-				if (count($temp) == 0)
+				if (count($temp) === 0)
 				{
 					$count = ($ordinal < 224) ? 2 : 3;
 				}
 
 				$temp[] = $ordinal;
 
-				if (count($temp) == $count)
+				if (count($temp) === $count)
 				{
-					$number = ($count == 3) ? (($temp['0'] % 16) * 4096) + (($temp['1'] % 64) * 64) + ($temp['2'] % 64) : (($temp['0'] % 32) * 64) + ($temp['1'] % 64);
+					$number = ($count === 3)
+							? (($temp[0] % 16) * 4096) + (($temp[1] % 64) * 64) + ($temp[2] % 64)
+							: (($temp[0] % 32) * 64) + ($temp[1] % 64);
 
 					$out .= '&#'.$number.';';
 					$count = 1;
@@ -187,10 +189,9 @@
 	{
 		if (preg_match_all('/\&#(\d+)\;/', $str, $matches))
 		{
-			for ($i = 0, $s = count($matches['0']); $i < $s; $i++)
+			for ($i = 0, $s = count($matches[0]); $i < $s; $i++)
 			{
-				$digits = $matches['1'][$i];
-
+				$digits = $matches[1][$i];
 				$out = '';
 
 				if ($digits < 128)
@@ -200,25 +201,24 @@
 				}
 				elseif ($digits < 2048)
 				{
-					$out .= chr(192 + (($digits - ($digits % 64)) / 64));
-					$out .= chr(128 + ($digits % 64));
+					$out .= chr(192 + (($digits - ($digits % 64)) / 64)).chr(128 + ($digits % 64));
 				}
 				else
 				{
-					$out .= chr(224 + (($digits - ($digits % 4096)) / 4096));
-					$out .= chr(128 + ((($digits % 4096) - ($digits % 64)) / 64));
-					$out .= chr(128 + ($digits % 64));
+					$out .= chr(224 + (($digits - ($digits % 4096)) / 4096))
+						.chr(128 + ((($digits % 4096) - ($digits % 64)) / 64))
+						.chr(128 + ($digits % 64));
 				}
 
-				$str = str_replace($matches['0'][$i], $out, $str);
+				$str = str_replace($matches[0][$i], $out, $str);
 			}
 		}
 
 		if ($all)
 		{
-			$str = str_replace(array("&amp;", "&lt;", "&gt;", "&quot;", "&apos;", "&#45;"),
-								array("&","<",">","\"", "'", "-"),
-								$str);
+			return str_replace(array('&amp;', '&lt;', '&gt;', '&quot;', '&apos;', '&#45;'),
+						array('&', '<', '>', '"', "'", '-'),
+						$str);
 		}
 
 		return $str;
@@ -286,27 +286,33 @@
 	 */
 	function highlight_code($str)
 	{
-		// The highlight string function encodes and highlights
-		// brackets so we need them to start raw
-		$str = str_replace(array('&lt;', '&gt;'), array('<', '>'), $str);
-
-		// Replace any existing PHP tags to temporary markers so they don't accidentally
-		// break the string out of PHP, and thus, thwart the highlighting.
-		$str = str_replace(array('<?', '?>', '<%', '%>', '\\', '</script>'),
-					array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'),
+		/* The highlight string function encodes and highlights
+		 * brackets so we need them to start raw.
+		 *
+		 * Also replace any existing PHP tags to temporary markers
+		 * so they don't accidentally break the string out of PHP,
+		 * and thus, thwart the highlighting.
+		 */
+		$str = str_replace(array('&lt;', '&gt;', '<?', '?>', '<%', '%>', '\\', '</script>'),
+					array('<', '>', 'phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'),
 					$str);
 
 		// The highlight_string function requires that the text be surrounded
 		// by PHP tags, which we will remove later
-		$str = '<?php '.$str.' ?>'; // <?
-
-		// All the magic happens here, baby!
-		$str = highlight_string($str, TRUE);
+		$str = highlight_string('<?php '.$str.' ?>', TRUE);
 
 		// Remove our artificially added PHP, and the syntax highlighting that came with it
-		$str = preg_replace('/<span style="color: #([A-Z0-9]+)">&lt;\?php(&nbsp;| )/i', '<span style="color: #$1">', $str);
-		$str = preg_replace('/(<span style="color: #[A-Z0-9]+">.*?)\?&gt;<\/span>\n<\/span>\n<\/code>/is', "$1</span>\n</span>\n</code>", $str);
-		$str = preg_replace('/<span style="color: #[A-Z0-9]+"\><\/span>/i', '', $str);
+		$str = preg_replace(array(
+						'/<span style="color: #([A-Z0-9]+)">&lt;\?php(&nbsp;| )/i',
+						'/(<span style="color: #[A-Z0-9]+">.*?)\?&gt;<\/span>\n<\/span>\n<\/code>/is',
+						'/<span style="color: #[A-Z0-9]+"\><\/span>/i'
+					),
+					array(
+						'<span style="color: #$1">',
+						"$1</span>\n</span>\n</code>",
+						''
+					),
+					$str);
 
 		// Replace our markers back to PHP tags.
 		return str_replace(array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'),
@@ -339,7 +345,7 @@
 
 		if ($phrase != '')
 		{
-			return preg_replace('/('.preg_quote($phrase, '/').')/i', $tag_open."\\1".$tag_close, $str);
+			return preg_replace('/('.preg_quote($phrase, '/').')/i', $tag_open.'\\1'.$tag_close, $str);
 		}
 
 		return $str;
@@ -358,18 +364,23 @@
 	 */
 	function convert_accented_characters($str)
 	{
-		if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php'))
-		{
-			include(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php');
-		}
-		elseif (is_file(APPPATH.'config/foreign_chars.php'))
-		{
-			include(APPPATH.'config/foreign_chars.php');
-		}
+		global $foreign_characters;
 
-		if ( ! isset($foreign_characters))
+		if ( ! isset($foreign_characters) OR ! is_array($foreign_characters))
 		{
-			return $str;
+			if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php'))
+			{
+				include(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php');
+			}
+			elseif (is_file(APPPATH.'config/foreign_chars.php'))
+			{
+				include(APPPATH.'config/foreign_chars.php');
+			}
+
+			if ( ! isset($foreign_characters) OR ! is_array($foreign_characters))
+			{
+				return $str;
+			}
 		}
 
 		return preg_replace(array_keys($foreign_characters), array_values($foreign_characters), $str);
@@ -378,27 +389,29 @@
 
 // ------------------------------------------------------------------------
 
+/**
+ * Word Wrap
+ *
+ * Wraps text at the specified character. Maintains the integrity of words.
+ * Anything placed between {unwrap}{/unwrap} will not be word wrapped, nor
+ * will URLs.
+ *
+ * @param	string	the text string
+ * @param	int	the number of characters to wrap at
+ * @return	string
+ */
 if ( ! function_exists('word_wrap'))
 {
-	/**
-	 * Word Wrap
-	 *
-	 * Wraps text at the specified character.  Maintains the integrity of words.
-	 * Anything placed between {unwrap}{/unwrap} will not be word wrapped, nor
-	 * will URLs.
-	 *
-	 * @param	string	the text string
-	 * @param	int	the number of characters to wrap at
-	 * @return	string
-	 */
-	function word_wrap($str, $charlim = '76')
+	function word_wrap($str, $charlim = 76)
 	{
-		// Se the character limit
+		// Set the character limit
 		if ( ! is_numeric($charlim))
+		{
 			$charlim = 76;
+		}
 
 		// Reduce multiple spaces
-		$str = preg_replace("| +|", " ", $str);
+		$str = preg_replace('| +|', ' ', $str);
 
 		// Standardize newlines
 		if (strpos($str, "\r") !== FALSE)
@@ -409,22 +422,22 @@
 		// If the current word is surrounded by {unwrap} tags we'll
 		// strip the entire chunk and replace it with a marker.
 		$unwrap = array();
-		if (preg_match_all("|(\{unwrap\}.+?\{/unwrap\})|s", $str, $matches))
+		if (preg_match_all('|(\{unwrap\}.+?\{/unwrap\})|s', $str, $matches))
 		{
-			for ($i = 0; $i < count($matches['0']); $i++)
+			for ($i = 0, $c = count($matches[0]); $i < $c; $i++)
 			{
-				$unwrap[] = $matches['1'][$i];
-				$str = str_replace($matches['1'][$i], "{{unwrapped".$i."}}", $str);
+				$unwrap[] = $matches[1][$i];
+				$str = str_replace($matches[1][$i], '{{unwrapped'.$i.'}}', $str);
 			}
 		}
 
 		// Use PHP's native function to do the initial wordwrap.
 		// We set the cut flag to FALSE so that any individual words that are
-		// too long get left alone.  In the next step we'll deal with them.
+		// too long get left alone. In the next step we'll deal with them.
 		$str = wordwrap($str, $charlim, "\n", FALSE);
 
 		// Split the string into individual lines of text and cycle through them
-		$output = "";
+		$output = '';
 		foreach (explode("\n", $str) as $line)
 		{
 			// Is the line within the allowed character count?
@@ -439,28 +452,26 @@
 			while ((strlen($line)) > $charlim)
 			{
 				// If the over-length word is a URL we won't wrap it
-				if (preg_match("!\[url.+\]|://|wwww.!", $line))
+				if (preg_match('!\[url.+\]|://|wwww.!', $line))
 				{
 					break;
 				}
 
 				// Trim the word down
-				$temp .= substr($line, 0, $charlim-1);
-				$line = substr($line, $charlim-1);
+				$temp .= substr($line, 0, $charlim - 1);
+				$line = substr($line, $charlim - 1);
 			}
 
 			// If $temp contains data it means we had to split up an over-length
 			// word into smaller chunks so we'll add it back to our current line
 			if ($temp != '')
 			{
-				$output .= $temp."\n".$line;
+				$output .= $temp."\n".$line."\n";
 			}
 			else
 			{
-				$output .= $line;
+				$output .= $line."\n";
 			}
-
-			$output .= "\n";
 		}
 
 		// Put our markers back
@@ -468,14 +479,12 @@
 		{
 			foreach ($unwrap as $key => $val)
 			{
-				$output = str_replace("{{unwrapped".$key."}}", $val, $output);
+				$output = str_replace('{{unwrapped'.$key.'}}', $val, $output);
 			}
 		}
 
-		// Remove the unwrap tags
-		$output = str_replace(array('{unwrap}', '{/unwrap}'), '', $output);
-
-		return $output;
+		// Remove the unwrap tags and return
+		return str_replace(array('{unwrap}', '{/unwrap}'), '', $output);
 	}
 }
 
@@ -506,7 +515,6 @@
 		}
 
 		$beg = substr($str, 0, floor($max_length * $position));
-
 		$position = ($position > 1) ? 1 : $position;
 
 		if ($position === 1)
diff --git a/system/libraries/Javascript.php b/system/libraries/Javascript.php
index 629a3ad..dd2df69 100644
--- a/system/libraries/Javascript.php
+++ b/system/libraries/Javascript.php
@@ -723,7 +723,7 @@
 		{
 			if (is_object($result))
 			{
-				$json_result = $result->result_array();
+				$json_result = is_callable(array($result, 'result_array')) ? $result->result_array() : (array) $result;
 			}
 			elseif (is_array($result))
 			{
diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php
index 0fe73d6..3d29118 100644
--- a/system/libraries/Pagination.php
+++ b/system/libraries/Pagination.php
@@ -94,17 +94,16 @@
 		{
 			foreach ($params as $key => $val)
 			{
-				if (isset($this->$key))
+				if ($key === 'anchor_class')
+				{
+					$this->anchor_class = ($val != '') ? 'class="'.$val.'" ' : '';
+				}
+				elseif (isset($this->$key))
 				{
 					$this->$key = $val;
 				}
 			}
 		}
-
-		if ($this->anchor_class != '')
-		{
-			$this->anchor_class = 'class="'.$this->anchor_class.'" ';
-		}
 	}
 
 	// --------------------------------------------------------------------
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index bdb418f..bbbe6f7 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -214,6 +214,7 @@
 -  Fixed a bug in SQLSRV's delete() method where like() and limit() conditions were ignored.
 -  Fixed a bug (#1265) - Database connections were always closed, regardless of the 'pconnect' option value.
 -  Fixed a bug (#128) - :doc:`Language Library <libraries/language>` did not correctly keep track of loaded language files.
+-  Fixed a bug (#1242) Added Windows path compatibility to function read_dir of ZIP library
 
 Version 2.1.1
 =============