Fixed bug #10086: Core uses deprecated function t3lib_db->sql()
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_parsehtml_proc.php
index 4350871..0d8d5a0 100755 (executable)
@@ -1,8 +1,8 @@
 <?php
 /***************************************************************
 *  Copyright notice
-*  
-*  (c) 1999-2004 Kasper Skaarhoj (kasper@typo3.com)
+*
+*  (c) 1999-2008 Kasper Skaarhoj (kasperYYYY@typo3.com)
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -31,7 +31,7 @@
  * Revised for TYPO3 3.6 December/2003 by Kasper Skaarhoj
  * XHTML compatible.
  *
- * @author     Kasper Skaarhoj <kasper@typo3.com>
+ * @author     Kasper Skaarhoj <kasperYYYY@typo3.com>
  * @internal
  */
 /**
  *
  *
  *
- *  102: class t3lib_parsehtml_proc extends t3lib_parsehtml 
- *  137:     function init($elRef='',$recPid=0)
- *  149:     function setRelPath($path)
- *  173:     function evalWriteFile($pArr,$currentRecord)      
+ *  103: class t3lib_parsehtml_proc extends t3lib_parsehtml
+ *  138:     function init($elRef='',$recPid=0)
+ *  150:     function setRelPath($path)
+ *  174:     function evalWriteFile($pArr,$currentRecord)
  *
  *              SECTION: Main function
- *  231:     function RTE_transform($value,$specConf,$direction='rte',$thisConfig=array())     
+ *  232:     function RTE_transform($value,$specConf,$direction='rte',$thisConfig=array())
  *
  *              SECTION: Specific RTE TRANSFORMATION functions
- *  378:     function TS_images_db($value)     
- *  517:     function TS_images_rte($value)    
- *  551:     function TS_reglinks($value,$direction)           
- *  585:     function TS_links_db($value)      
- *  629:     function TS_links_rte($value)     
- *  704:     function TS_preserve_db($value)   
- *  728:     function TS_preserve_rte($value)  
- *  749:     function TS_transform_db($value,$css=FALSE)       
- *  860:     function TS_transform_rte($value,$css=0)  
- *  931:     function TS_strip_db($value)      
+ *  398:     function TS_images_db($value)
+ *  550:     function TS_images_rte($value)
+ *  589:     function TS_reglinks($value,$direction)
+ *  626:     function TS_links_db($value)
+ *  675:     function TS_links_rte($value)
+ *  760:     function TS_preserve_db($value)
+ *  784:     function TS_preserve_rte($value)
+ *  805:     function TS_transform_db($value,$css=FALSE)
+ *  922:     function transformStyledATags($value)
+ *  948:     function TS_transform_rte($value,$css=0)
+ * 1019:     function TS_strip_db($value)
  *
  *              SECTION: Generic RTE transformation, analysis and helper functions
- *  962:     function getURL($url)     
- *  976:     function HTMLcleaner_db($content,$tagList='')     
- *  997:     function getKeepTags($direction='rte',$tagList='')        
- * 1106:     function divideIntoLines($value,$count=5,$returnArray=FALSE)      
- * 1210:     function setDivTags($value,$dT='p')       
- * 1255:     function internalizeFontTags($value)      
- * 1291:     function siteUrl()        
- * 1301:     function rteImageStorageDir()     
- * 1313:     function removeTables($value,$breakChar='<br />') 
- * 1345:     function defaultTStagMapping($code,$direction='rte')      
- * 1368:     function getWHFromAttribs($attribArray)   
- * 1394:     function urlInfoForLinkTags($url) 
- * 1453:     function TS_AtagToAbs($value,$dontSetRTEKEEP=FALSE)       
+ * 1050:     function getURL($url)
+ * 1064:     function HTMLcleaner_db($content,$tagList='')
+ * 1091:     function getKeepTags($direction='rte',$tagList='')
+ * 1200:     function divideIntoLines($value,$count=5,$returnArray=FALSE)
+ * 1304:     function setDivTags($value,$dT='p')
+ * 1349:     function internalizeFontTags($value)
+ * 1385:     function siteUrl()
+ * 1395:     function rteImageStorageDir()
+ * 1407:     function removeTables($value,$breakChar='<br />')
+ * 1439:     function defaultTStagMapping($code,$direction='rte')
+ * 1462:     function getWHFromAttribs($attribArray)
+ * 1489:     function urlInfoForLinkTags($url)
+ * 1548:     function TS_AtagToAbs($value,$dontSetRTEKEEP=FALSE)
  *
- * TOTAL FUNCTIONS: 27
+ * TOTAL FUNCTIONS: 28
  * (This index is automatically created/updated by the extension "extdeveval")
  *
  */
@@ -95,20 +96,21 @@ require_once (PATH_t3lib.'class.t3lib_parsehtml.php');
 /**
  * Class for parsing HTML for the Rich Text Editor. (also called transformations)
  *
- * @author     Kasper Skaarhoj <kasper@typo3.com>
+ * @author     Kasper Skaarhoj <kasperYYYY@typo3.com>
  * @package TYPO3
  * @subpackage t3lib
  */
 class t3lib_parsehtml_proc extends t3lib_parsehtml {
 
                // Static:
-       var $headListTags = 'PRE,UL,OL,H1,H2,H3,H4,H5,H6';              // List of tags for header, pre and list containers
+       var $blockElementList = 'PRE,UL,OL,H1,H2,H3,H4,H5,H6,HR,ADDRESS,DL,DD'; // List of tags for these elements
 
                // Internal, static:
        var $recPid = 0;                                // Set this to the pid of the record manipulated by the class.
        var $elRef = '';                                // Element reference [table]:[field], eg. "tt_content:bodytext"
        var $relPath='';                                // Relative path
        var $relBackPath='';                    // Relative back-path
+       public $tsConfig = array();             // Current Page TSConfig
        var $procOptions = '';                  // Set to the TSconfig options coming from Page TSconfig
 
                // Internal, dynamic
@@ -174,10 +176,10 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
 
                        // Write file configuration:
                if (is_array($pArr))    {
-                       if ($GLOBALS['TYPO3_CONF_VARS']['BE']['staticFileEditPath'] 
-                               && substr($GLOBALS['TYPO3_CONF_VARS']['BE']['staticFileEditPath'],-1)=='/' 
+                       if ($GLOBALS['TYPO3_CONF_VARS']['BE']['staticFileEditPath']
+                               && substr($GLOBALS['TYPO3_CONF_VARS']['BE']['staticFileEditPath'],-1)=='/'
                                && @is_dir(PATH_site.$GLOBALS['TYPO3_CONF_VARS']['BE']['staticFileEditPath']))  {
-                               
+
                                $SW_p = $pArr['parameters'];
                                $SW_editFileField = trim($SW_p[0]);
                                $SW_editFile = $currentRecord[$SW_editFileField];
@@ -198,27 +200,27 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                        } else return "ERROR: staticFileEditPath was not set, not set correctly or did not exist!";
                }
        }
-       
 
 
 
-       
-       
-       
-       
-       
-       
-       
-       
-       
+
+
+
+
+
+
+
+
+
+
        /**********************************************
         *
         * Main function
         *
-        **********************************************/        
-       
+        **********************************************/
+
        /**
-        * Tranform value for RTE based on specConf in the direction specified by $direction (rte/db)
+        * Transform value for RTE based on specConf in the direction specified by $direction (rte/db)
         * This is the main function called from tcemain and transfer data classes
         *
         * @param       string          Input value
@@ -229,33 +231,43 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
         * @see t3lib_TCEmain::fillInFieldArray(), t3lib_transferData::renderRecord_typesProc()
         */
        function RTE_transform($value,$specConf,$direction='rte',$thisConfig=array())   {
-       
+
                        // Init:
-               $this->procOptions=$thisConfig['proc.'];
+               $this->tsConfig = $thisConfig;
+               $this->procOptions = $thisConfig['proc.'];
                $this->preserveTags = strtoupper(implode(',',t3lib_div::trimExplode(',',$this->procOptions['preserveTags'])));
 
+                       // dynamic configuration of blockElementList
+               if ($this->procOptions['blockElementList']) {
+                       $this->blockElementList = $this->procOptions['blockElementList'];
+               }
+
                        // Get parameters for rte_transformation:
                $p = $this->rte_p = t3lib_BEfunc::getSpecConfParametersFromArray($specConf['rte_transform']['parameters']);
 
                        // Setting modes:
                if (strcmp($this->procOptions['overruleMode'],''))      {
-                       $modes=array_unique(t3lib_div::trimExplode(',',$this->procOptions['overruleMode']));
+                       $modes = array_unique(t3lib_div::trimExplode(',',$this->procOptions['overruleMode']));
                } else {
-                       $modes=array_unique(t3lib_div::trimExplode('-',$p['mode']));
+                       $modes = array_unique(t3lib_div::trimExplode('-',$p['mode']));
                }
-               $revmodes=array_flip($modes);
+               $revmodes = array_flip($modes);
 
                        // Find special modes and extract them:
                if (isset($revmodes['ts']))     {
-                       $modes[$revmodes['ts']]='ts_transform,ts_preserve,ts_images,ts_links';
+                       $modes[$revmodes['ts']] = 'ts_transform,ts_preserve,ts_images,ts_links';
                }
                        // Find special modes and extract them:
                if (isset($revmodes['ts_css'])) {
-                       $modes[$revmodes['ts_css']]='css_transform,ts_images,ts_links';
+                       $modes[$revmodes['ts_css']] = 'css_transform,ts_images,ts_links';
                }
+
+                       // Make list unique
                $modes = array_unique(t3lib_div::trimExplode(',',implode(',',$modes),1));
+
+                       // Reverse order if direction is "rte"
                if ($direction=='rte')  {
-                       $modes=array_reverse($modes);
+                       $modes = array_reverse($modes);
                }
 
                        // Getting additional HTML cleaner configuration. These are applied either before or after the main transformation is done and is thus totally independant processing options you can set up:
@@ -276,54 +288,69 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                foreach($modes as $cmd) {
                                // ->DB
                        if ($direction=='db')   {
-                               switch($cmd)    {
-                                       case 'ts_images':
-                                               $value=$this->TS_images_db($value);
-                                       break;
-                                       case 'ts_reglinks':
-                                               $value=$this->TS_reglinks($value,'db');
-                                       break;
-                                       case 'ts_links':
-                                               $value=$this->TS_links_db($value);
-                                       break;
-                                       case 'ts_preserve':
-                                               $value=$this->TS_preserve_db($value);
-                                       break;
-                                       case 'ts_transform':
-                                       case 'css_transform':
-                                               $value = str_replace(chr(13),'',$value);        // Has a very disturbing effect, so just remove all '13' - depend on '10'
-                                               $this->allowedClasses = t3lib_div::trimExplode(',',strtoupper($this->procOptions['allowedClasses']),1);
-                                               $value=$this->TS_transform_db($value,$cmd=='css_transform');
-                                       break;
-                                       case 'ts_strip':
-                                               $value=$this->TS_strip_db($value);
-                                       break;
-                                       case 'dummy':
-                                       break;
+                                       // Checking for user defined transformation:
+                               if ($_classRef = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_parsehtml_proc.php']['transformation'][$cmd])     {
+                                       $_procObj = &t3lib_div::getUserObj($_classRef);
+                                       $_procObj->pObj = &$this;
+                                       $_procObj->transformationKey = $cmd;
+                                       $value = $_procObj->transform_db($value,$this);
+                               } else {        // ... else use defaults:
+                                       switch($cmd)    {
+                                               case 'ts_images':
+                                                       $value = $this->TS_images_db($value);
+                                               break;
+                                               case 'ts_reglinks':
+                                                       $value = $this->TS_reglinks($value,'db');
+                                               break;
+                                               case 'ts_links':
+                                                       $value = $this->TS_links_db($value);
+                                               break;
+                                               case 'ts_preserve':
+                                                       $value = $this->TS_preserve_db($value);
+                                               break;
+                                               case 'ts_transform':
+                                               case 'css_transform':
+                                                       $value = str_replace(chr(13),'',$value);        // Has a very disturbing effect, so just remove all '13' - depend on '10'
+                                                       $this->allowedClasses = t3lib_div::trimExplode(',',strtoupper($this->procOptions['allowedClasses']),1);
+                                                       $value = $this->TS_transform_db($value,$cmd=='css_transform');
+                                               break;
+                                               case 'ts_strip':
+                                                       $value = $this->TS_strip_db($value);
+                                               break;
+                                               default:
+                                               break;
+                                       }
                                }
                        }
                                // ->RTE
                        if ($direction=='rte')  {
-                               switch($cmd)    {
-                                       case 'ts_images':
-                                               $value=$this->TS_images_rte($value);
-                                       break;
-                                       case 'ts_reglinks':
-                                               $value=$this->TS_reglinks($value,'rte');
-                                       break;
-                                       case 'ts_links':
-                                               $value=$this->TS_links_rte($value);
-                                       break;
-                                       case 'ts_preserve':
-                                               $value=$this->TS_preserve_rte($value);
-                                       break;
-                                       case 'ts_transform':
-                                       case 'css_transform':
-                                               $value = str_replace(chr(13),'',$value);        // Has a very disturbing effect, so just remove all '13' - depend on '10'
-                                               $value=$this->TS_transform_rte($value,$cmd=='css_transform');
-                                       break;
-                                       case 'dummy':
-                                       break;
+                                       // Checking for user defined transformation:
+                               if ($_classRef = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_parsehtml_proc.php']['transformation'][$cmd])     {
+                                       $_procObj = &t3lib_div::getUserObj($_classRef);
+                                       $_procObj->pObj = &$this;
+                                       $value = $_procObj->transform_rte($value,$this);
+                               } else {        // ... else use defaults:
+                                       switch($cmd)    {
+                                               case 'ts_images':
+                                                       $value = $this->TS_images_rte($value);
+                                               break;
+                                               case 'ts_reglinks':
+                                                       $value = $this->TS_reglinks($value,'rte');
+                                               break;
+                                               case 'ts_links':
+                                                       $value = $this->TS_links_rte($value);
+                                               break;
+                                               case 'ts_preserve':
+                                                       $value = $this->TS_preserve_rte($value);
+                                               break;
+                                               case 'ts_transform':
+                                               case 'css_transform':
+                                                       $value = str_replace(chr(13),'',$value);        // Has a very disturbing effect, so just remove all '13' - depend on '10'
+                                                       $value = $this->TS_transform_rte($value,$cmd=='css_transform');
+                                               break;
+                                               default:
+                                               break;
+                                       }
                                }
                        }
                }
@@ -381,19 +408,29 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                $imgSplit = $this->splitTags('img',$value);
                foreach($imgSplit as $k => $v)  {
                        if ($k%2)       {       // image found, do processing:
-                       
+
                                        // Init
-                               $attribArray=$this->get_tag_attributes_classic($v,1);
+                               $attribArray = $this->get_tag_attributes_classic($v,1);
                                $siteUrl = $this->siteUrl();
+                               $sitePath = str_replace (t3lib_div::getIndpEnv('TYPO3_REQUEST_HOST'), '', $siteUrl);
+
                                $absRef = trim($attribArray['src']);            // It's always a absolute URL coming from the RTE into the Database.
 
+                                       // make path absolute if it is relative and we have a site path wich is not '/'
+                               $pI=pathinfo($absRef);
+                               if($sitePath AND !$pI['scheme'] && t3lib_div::isFirstPartOfStr($absRef,$sitePath)) {
+                                               // if site is in a subpath (eg. /~user_jim/) this path needs to be removed because it will be added with $siteUrl
+                                       $absRef = substr($absRef,strlen($sitePath));
+                                       $absRef = $siteUrl.$absRef;
+                               }
+
                                        // External image from another URL? In that case, fetch image (unless disabled feature).
                                if (!t3lib_div::isFirstPartOfStr($absRef,$siteUrl) && !$this->procOptions['dontFetchExtPictures'])      {
                                        $externalFile = $this->getUrl($absRef); // Get it
                                        if ($externalFile)      {
                                                $pU = parse_url($absRef);
                                                $pI=pathinfo($pU['path']);
-                                               
+
                                                if (t3lib_div::inList('gif,png,jpeg,jpg',strtolower($pI['extension']))) {
                                                        $filename = t3lib_div::shortMD5($absRef).'.'.$pI['extension'];
                                                        $origFilePath = PATH_site.$this->rteImageStorageDir().'RTEmagicP_'.$filename;
@@ -403,13 +440,14 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                                                t3lib_div::writeFile($C_origFilePath,$externalFile);
                                                        }
                                                        $absRef = $siteUrl.$this->rteImageStorageDir().'RTEmagicC_'.$filename.'.'.$pI['extension'];
-                                               
+
                                                        $attribArray['src']=$absRef;
-                                                       $params = t3lib_div::implodeParams($attribArray,1);
-                                                       $imgSplit[$k]='<img '.$params.' />';
+                                                       $params = t3lib_div::implodeAttributes($attribArray,1);
+                                                       $imgSplit[$k] = '<img '.$params.' />';
                                                }
                                        }
                                }
+
                                        // Check image as local file (siteURL equals the one of the image)
                                if (t3lib_div::isFirstPartOfStr($absRef,$siteUrl))      {
                                        $path = rawurldecode(substr($absRef,strlen($siteUrl))); // Rel-path, rawurldecoded for special characters.
@@ -417,7 +455,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
 
                                                // Check file existence (in relative dir to this installation!)
                                        if ($filepath && @is_file($filepath))   {
-                                       
+
                                                        // If "magic image":
                                                $pathPre=$this->rteImageStorageDir().'RTEmagicC_';
                                                if (t3lib_div::isFirstPartOfStr($path,$pathPre))        {
@@ -430,7 +468,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                                                $imgObj->init();
                                                                $imgObj->mayScaleUp=0;
                                                                $imgObj->tempPath=PATH_site.$imgObj->tempPath;
-                                                       
+
                                                                $curInfo = $imgObj->getImageDimensions($filepath);      // Image dimensions of the current image
                                                                $curWH = $this->getWHFromAttribs($attribArray); // Image dimensions as set in the image tag
                                                                        // Compare dimensions:
@@ -443,11 +481,11 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                                                        if ($imgI[3])   {
                                                                                $fI=pathinfo($imgI[3]);
                                                                                @copy($imgI[3],$filepath);      // Override the child file
-                                                                               unset($attribArray['style']);
+                                                                                       // Removing width and heigth form style attribute
+                                                                               $attribArray['style'] = preg_replace('/((?:^|)\s*(?:width|height)\s*:[^;]*(?:$|;))/si', '', $attribArray['style']);
                                                                                $attribArray['width']=$imgI[0];
                                                                                $attribArray['height']=$imgI[1];
-                                                                               if (!$attribArray['border'])    $attribArray['border']=0;
-                                                                               $params = t3lib_div::implodeParams($attribArray,1);
+                                                                               $params = t3lib_div::implodeAttributes($attribArray,1);
                                                                                $imgSplit[$k]='<img '.$params.' />';
                                                                        }
                                                                }
@@ -455,15 +493,14 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
 
                                                } elseif ($this->procOptions['plainImageMode']) {       // If "plain image" has been configured:
 
-                                                               // Image dimensions as set in the image tag
-                                                       $curWH = $this->getWHFromAttribs($attribArray); 
-                                                       $attribArray['width'] = $curWH[0];
-                                                       $attribArray['height'] = $curWH[1];
-                                                       
-                                                               // Forcing values for style and border:
-                                                       unset($attribArray['style']);
-                                                       if (!$attribArray['border'])    $attribArray['border']=0;
-                                                       
+                                                               // Image dimensions as set in the image tag, if any
+                                                       $curWH = $this->getWHFromAttribs($attribArray);
+                                                       if ($curWH[0]) $attribArray['width'] = $curWH[0];
+                                                       if ($curWH[1]) $attribArray['height'] = $curWH[1];
+
+                                                               // Removing width and heigth form style attribute
+                                                       $attribArray['style'] = preg_replace('/((?:^|)\s*(?:width|height)\s*:[^;]*(?:$|;))/si', '', $attribArray['style']);
+
                                                                // Finding dimensions of image file:
                                                        $fI = @getimagesize($filepath);
 
@@ -481,13 +518,15 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                                                        }
                                                                break;
                                                        }
-                                                       
+
                                                                // Compile the image tag again:
-                                                       $params = t3lib_div::implodeParams($attribArray,1);
+                                                       $params = t3lib_div::implodeAttributes($attribArray,1);
                                                        $imgSplit[$k]='<img '.$params.' />';
                                                }
                                        } else {        // Remove image if it was not found in a proper position on the server!
-                                               $imgSplit[$k]='';
+
+                                                       // Commented out; removing the image tag might not be that logical...
+                                               #$imgSplit[$k]='';
                                        }
                                }
 
@@ -498,14 +537,14 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                        if (t3lib_div::isFirstPartOfStr($absRef,$siteUrl))      {
                                                $attribArray['src'] = $this->relBackPath.substr($absRef,strlen($siteUrl));
                                                if (!isset($attribArray['alt']))        $attribArray['alt']='';         // Must have alt-attribute for XHTML compliance.
-                                               $imgSplit[$k]='<img '.t3lib_div::implodeParams($attribArray,1,1).' />';
+                                               $imgSplit[$k]='<img '.t3lib_div::implodeAttributes($attribArray,1,1).' />';
                                        }
                                }
                        }
-               }               
+               }
                return implode('',$imgSplit);
        }
-       
+
        /**
         * Transformation handler: 'ts_images' / direction: "rte"
         * Processing images from database content going into the RTE.
@@ -516,6 +555,9 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
         */
        function TS_images_rte($value)  {
 
+               $siteUrl = $this->siteUrl();
+               $sitePath = str_replace (t3lib_div::getIndpEnv('TYPO3_REQUEST_HOST'), '', $siteUrl);
+
                        // Split content by <img> tags and traverse the resulting array for processing:
                $imgSplit = $this->splitTags('img',$value);
                foreach($imgSplit as $k => $v)  {
@@ -523,23 +565,25 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
 
                                        // Init
                                $attribArray=$this->get_tag_attributes_classic($v,1);
-                               $siteUrl = $this->siteUrl();
                                $absRef = trim($attribArray['src']);
 
                                        // Unless the src attribute is already pointing to an external URL:
                                if (strtolower(substr($absRef,0,4))!='http')    {
-                                       $attribArray['src'] = $siteUrl.substr($attribArray['src'],strlen($this->relBackPath));
+                                       $attribArray['src'] = substr($attribArray['src'],strlen($this->relBackPath));
+                                               // if site is in a subpath (eg. /~user_jim/) this path needs to be removed because it will be added with $siteUrl
+                                       $attribArray['src'] = preg_replace('#^'.preg_quote($sitePath,'#').'#','',$attribArray['src']);
+                                       $attribArray['src'] = $siteUrl.$attribArray['src'];
                                        if (!isset($attribArray['alt']))        $attribArray['alt']='';
-                                       $params = t3lib_div::implodeParams($attribArray);
+                                       $params = t3lib_div::implodeAttributes($attribArray);
                                        $imgSplit[$k]='<img '.$params.' />';
                                }
                        }
-               }               
+               }
 
                        // return processed content:
                return implode('',$imgSplit);
        }
-       
+
        /**
         * Transformation handler: 'ts_reglinks' / direction: "db"+"rte" depending on $direction variable.
         * Converting <A>-tags to/from abs/rel
@@ -549,9 +593,11 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
         * @return      string          Content output
         */
        function TS_reglinks($value,$direction)         {
+               $retVal = '';
+
                switch($direction)      {
                        case 'rte':
-                               return $this->TS_AtagToAbs($value,1);
+                               $retVal = $this->TS_AtagToAbs($value,1);
                        break;
                        case 'db':
                                $siteURL = $this->siteUrl();
@@ -564,42 +610,48 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                                if ($siteURL && substr($attribArray['href'],0,strlen($siteURL))==$siteURL)      {
                                                        $attribArray['href']=$this->relBackPath.substr($attribArray['href'],strlen($siteURL));
                                                }
-                                               $bTag='<a '.t3lib_div::implodeParams($attribArray,1).'>';
+                                               $bTag='<a '.t3lib_div::implodeAttributes($attribArray,1).'>';
                                                $eTag='</a>';
                                                $blockSplit[$k] = $bTag.$this->TS_reglinks($this->removeFirstAndLastTag($blockSplit[$k]),$direction).$eTag;
                                        }
                                }
-                               return implode('',$blockSplit);
+                               $retVal = implode('',$blockSplit);
                        break;
                }
+               return $retVal;
        }
-       
+
        /**
         * Transformation handler: 'ts_links' / direction: "db"
-        * Converting <A>-tags to <LINK tags>
+        * Converting <A>-tags to <link tags>
         *
         * @param       string          Content input
         * @return      string          Content output
         * @see TS_links_rte()
         */
        function TS_links_db($value)    {
-       
+
                        // Split content into <a> tag blocks and process:
                $blockSplit = $this->splitIntoBlock('A',$value);
                foreach($blockSplit as $k => $v)        {
                        if ($k%2)       {       // If an A-tag was found:
-                               $attribArray=$this->get_tag_attributes_classic($this->getFirstTag($v),1);
+                               $attribArray = $this->get_tag_attributes_classic($this->getFirstTag($v),1);
                                $info = $this->urlInfoForLinkTags($attribArray['href']);
-                               
+
                                        // Check options:
                                $attribArray_copy = $attribArray;
                                unset($attribArray_copy['href']);
                                unset($attribArray_copy['target']);
                                unset($attribArray_copy['class']);
+                               unset($attribArray_copy['title']);
+                               if ($attribArray_copy['rteerror'])      {       // Unset "rteerror" and "style" attributes if "rteerror" is set!
+                                       unset($attribArray_copy['style']);
+                                       unset($attribArray_copy['rteerror']);
+                               }
                                if (!count($attribArray_copy))  {       // Only if href, target and class are the only attributes, we can alter the link!
                                                // Creating the TYPO3 pseudo-tag "<LINK>" for the link (includes href/url, target and class attributes):
-                                       $bTag='<LINK '.$info['url'].($attribArray['target']?' '.$attribArray['target']:($attribArray['class']?' -':'')).($attribArray['class']?' '.$attribArray['class']:'').'>';
-                                       $eTag='</LINK>';
+                                       $bTag='<link '.$info['url'].($info['query']?',0,'.$info['query']:'').($attribArray['target']?' '.$attribArray['target']:(($attribArray['class'] || $attribArray['title'])?' -':'')).($attribArray['class']?' '.$attribArray['class']:($attribArray['title']?' -':'')).($attribArray['title']?' "'.$attribArray['title'].'"':'').'>';
+                                       $eTag='</link>';
                                        $blockSplit[$k] = $bTag.$this->TS_links_db($this->removeFirstAndLastTag($blockSplit[$k])).$eTag;
                                } else {        // ... otherwise store the link as a-tag.
                                                // Unsetting 'rtekeep' attribute if that had been set.
@@ -609,7 +661,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                        if ($siteURL && substr($attribArray['href'],0,strlen($siteURL))==$siteURL)      {
                                                $attribArray['href']=$this->relBackPath.substr($attribArray['href'],strlen($siteURL));
                                        }
-                                       $bTag='<a '.t3lib_div::implodeParams($attribArray,1).'>';
+                                       $bTag='<a '.t3lib_div::implodeAttributes($attribArray,1).'>';
                                        $eTag='</a>';
                                        $blockSplit[$k] = $bTag.$this->TS_links_db($this->removeFirstAndLastTag($blockSplit[$k])).$eTag;
                                }
@@ -620,7 +672,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
 
        /**
         * Transformation handler: 'ts_links' / direction: "rte"
-        * Converting <LINK tags> to <A>-tags
+        * Converting <link tags> to <A>-tags
         *
         * @param       string          Content input
         * @return      string          Content output
@@ -628,14 +680,15 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
         */
        function TS_links_rte($value)   {
                $value = $this->TS_AtagToAbs($value);
-               
-                       // Split content by the TYPO3 pseudo tag "<LINK>":
+
+                       // Split content by the TYPO3 pseudo tag "<link>":
                $blockSplit = $this->splitIntoBlock('link',$value,1);
                foreach($blockSplit as $k => $v)        {
+                       $error = '';
                        if ($k%2)       {       // block:
-                               $tagCode = t3lib_div::trimExplode(' ',trim(substr($this->getFirstTag($v),0,-1)),1);
-                               $link_param=$tagCode[1];
-                               $href='';
+                               $tagCode = t3lib_div::unQuoteFilenames(trim(substr($this->getFirstTag($v),0,-1)),true);
+                               $link_param = $tagCode[1];
+                               $href = '';
                                $siteUrl = $this->siteUrl();
                                        // Parsing the typolink data. This parsing is roughly done like in tslib_content->typolink()
                                if(strstr($link_param,'@'))     {               // mailadr
@@ -657,12 +710,15 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                        } elseif($fileChar)     {       // file (internal)
                                                $href = $siteUrl.$link_param;
                                        } else {        // integer or alias (alias is without slashes or periods or commas, that is 'nospace,alphanum_x,lower,unique' according to tables.php!!)
-                                               $link_params_parts=explode('#',$link_param);
+                                               $link_params_parts = explode('#',$link_param);
                                                $idPart = trim($link_params_parts[0]);          // Link-data del
-                                               if (!strcmp($idPart,''))        {$idPart=$this->recPid;}        // If no id or alias is given, set it to class record pid
-                                               if ($link_params_parts[1] && !$sectionMark)     {
-                                                       $sectionMark='#'.trim($link_params_parts[1]);
-                                               }
+                                               if (!strcmp($idPart,''))        { $idPart=$this->recPid; }      // If no id or alias is given, set it to class record pid
+
+// FIXME commented because useless - what is it for?
+//                                             if ($link_params_parts[1] && !$sectionMark)     {
+//                                                     $sectionMark = '#'.trim($link_params_parts[1]);
+//                                             }
+
                                                        // Splitting the parameter by ',' and if the array counts more than 1 element it's a id/type/? pair
                                                $pairParts = t3lib_div::trimExplode(',',$idPart);
                                                if (count($pairParts)>1)        {
@@ -672,29 +728,39 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                                        // Checking if the id-parameter is an alias.
                                                if (!t3lib_div::testInt($idPart))       {
                                                        list($idPartR) = t3lib_BEfunc::getRecordsByField('pages','alias',$idPart);
-                                                       $idPart=intval($idPartR['uid']);
+                                                       $idPart = intval($idPartR['uid']);
                                                }
-                                               $page = t3lib_BEfunc::getRecord('pages',$idPart);
+                                               $page = t3lib_BEfunc::getRecord('pages', $idPart);
                                                if (is_array($page))    {       // Page must exist...
-                                                       $href = $siteUrl.'?id='.$link_param;
+                                                       $pairParts = t3lib_div::trimExplode(',',$link_param);
+                                                       $href = $siteUrl.'?id='.$pairParts[0].($pairParts[2]?$pairParts[2]:'');
+                                               } else if(strtolower(substr($link_param, 0, 7)) == 'record:') {
+                                                               // linkHandler - allowing links to start with "record:"
+                                                       $href = $link_param;
                                                } else {
-                                                       $href='';
-                                                       $error='no page: '.$idPart;
+                                                       #$href = '';
+                                                       $href = $siteUrl.'?id='.$link_param;
+                                                       $error = 'No page found: '.$idPart;
                                                }
-                                       }               
+                                       }
                                }
 
                                // Setting the A-tag:
-                               $bTag='<a href="'.htmlspecialchars($href).'"'.($tagCode[2]&&$tagCode[2]!='-'?' target="'.htmlspecialchars($tagCode[2]).'"':'').($tagCode[3]?' class="'.htmlspecialchars($tagCode[3]).'"':'').'>';
-                               $eTag='</a>';
+                               $bTag = '<a href="'.htmlspecialchars($href).'"'.
+                                                       ($tagCode[2]&&$tagCode[2]!='-' ? ' target="'.htmlspecialchars($tagCode[2]).'"' : '').
+                                                       ($tagCode[3]&&$tagCode[3]!='-' ? ' class="'.htmlspecialchars($tagCode[3]).'"' : '').
+                                                       ($tagCode[4] ? ' title="'.htmlspecialchars($tagCode[4]).'"' : '').
+                                                       ($error ? ' rteerror="'.htmlspecialchars($error).'" style="background-color: yellow; border:2px red solid; color: black;"' : '').       // Should be OK to add the style; the transformation back to databsae will remove it...
+                                                       '>';
+                               $eTag = '</a>';
                                $blockSplit[$k] = $bTag.$this->TS_links_rte($this->removeFirstAndLastTag($blockSplit[$k])).$eTag;
-                       }                       
+                       }
                }
-               
+
                        // Return content:
                return implode('',$blockSplit);
        }
-       
+
        /**
         * Preserve special tags
         *
@@ -718,7 +784,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                }
                return implode('',$blockSplit);
        }
-       
+
        /**
         * Preserve special tags
         *
@@ -727,7 +793,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
         */
        function TS_preserve_rte($value)        {
                if (!$this->preserveTags)       return $value;
-               
+
                $blockSplit = $this->splitIntoBlock($this->preserveTags,$value);
                foreach($blockSplit as $k => $v)        {
                        if ($k%2)       {       // block:
@@ -747,17 +813,23 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
         * @see TS_transform_rte()
         */
        function TS_transform_db($value,$css=FALSE)     {
-       
+
                        // safety... so forever loops are avoided (they should not occur, but an error would potentially do this...)
                $this->TS_transform_db_safecounter--;
-               if ($this->TS_transform_db_safecounter<0)       return $value;  
+               if ($this->TS_transform_db_safecounter<0)       return $value;
 
                        // Split the content from RTE by the occurence of these blocks:
-               $blockSplit = $this->splitIntoBlock('TABLE,BLOCKQUOTE,'.$this->headListTags,$value);
+               $blockSplit = $this->splitIntoBlock('TABLE,BLOCKQUOTE,'.($this->procOptions['preserveDIVSections']?'DIV,':'').$this->blockElementList,$value);
 
                $cc=0;
                $aC = count($blockSplit);
-               
+
+                       // Avoid superfluous linebreaks by transform_db after ending headListTag
+               while($aC && !strcmp(trim($blockSplit[$aC-1]),''))      {
+                       unset($blockSplit[$aC-1]);
+                       $aC = count($blockSplit);
+               }
+
                        // Traverse the blocks
                foreach($blockSplit as $k => $v)        {
                        $cc++;
@@ -768,11 +840,13 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                        // Init:
                                $tag=$this->getFirstTag($v);
                                $tagName=strtolower($this->getFirstTagName($v));
-                               
+
                                        // Process based on the tag:
                                switch($tagName)        {
                                        case 'blockquote':      // Keep blockquotes, but clean the inside recursively in the same manner as the main code
-                                               $blockSplit[$k]='<'.$tagName.'>'.$this->TS_transform_db($this->removeFirstAndLastTag($blockSplit[$k]),$css).'</'.$tagName.'>'.$lastBR;
+                                       case 'dd' :             // Do the same on dd elements
+                                       case 'div':             // Do the same on div sections, if they were splitted
+                                               $blockSplit[$k]=$tag.$this->TS_transform_db($this->removeFirstAndLastTag($blockSplit[$k]),$css).'</'.$tagName.'>'.$lastBR;
                                        break;
                                        case 'ol':
                                        case 'ul':      // Transform lists into <typolist>-tags:
@@ -780,7 +854,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                                        if (!isset($this->procOptions['typolist']) || $this->procOptions['typolist'])   {
                                                                $parts = $this->getAllParts($this->splitIntoBlock('LI',$this->removeFirstAndLastTag($blockSplit[$k])),1,0);
                                                                while(list($k2)=each($parts))   {
-                                                                       $parts[$k2]=ereg_replace(chr(10).'|'.chr(13),'',$parts[$k2]);   // remove all linesbreaks!
+                                                                       $parts[$k2]=preg_replace('/['.preg_quote(chr(10).chr(13)).']+/','',$parts[$k2]);        // remove all linesbreaks!
                                                                        $parts[$k2]=$this->defaultTStagMapping($parts[$k2],'db');
                                                                        $parts[$k2]=$this->cleanFontTags($parts[$k2],0,0,0);
                                                                        $parts[$k2] = $this->HTMLcleaner_db($parts[$k2],strtolower($this->procOptions['allowTagsInTypolists']?$this->procOptions['allowTagsInTypolists']:'br,font,b,i,u,a,img,span,strong,em'));
@@ -789,14 +863,14 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                                                $blockSplit[$k]='<typolist'.$params.'>'.chr(10).implode(chr(10),$parts).chr(10).'</typolist>'.$lastBR;
                                                        }
                                                } else {
-                                                       $blockSplit[$k].=$lastBR;
+                                                       $blockSplit[$k]=preg_replace('/['.preg_quote(chr(10).chr(13)).']+/',' ',$this->transformStyledATags($blockSplit[$k])).$lastBR;
                                                }
                                        break;
                                        case 'table':   // Tables are NOT allowed in any form (unless preserveTables is set or CSS is the mode)
                                                if (!$this->procOptions['preserveTables'] && !$css)     {
                                                        $blockSplit[$k]=$this->TS_transform_db($this->removeTables($blockSplit[$k]));
                                                } else {
-                                                       $blockSplit[$k]=str_replace(chr(10),'',$blockSplit[$k]).$lastBR;
+                                                       $blockSplit[$k]=preg_replace('/['.preg_quote(chr(10).chr(13)).']+/',' ',$this->transformStyledATags($blockSplit[$k])).$lastBR;
                                                }
                                        break;
                                        case 'h1':
@@ -809,7 +883,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                                        $attribArray=$this->get_tag_attributes_classic($tag);
                                                                // Processing inner content here:
                                                        $innerContent = $this->HTMLcleaner_db($this->removeFirstAndLastTag($blockSplit[$k]));
-                                                       
+
                                                        if (!isset($this->procOptions['typohead']) || $this->procOptions['typohead'])   {
                                                                $type = intval(substr($tagName,1));
                                                                $blockSplit[$k]='<typohead'.
@@ -830,21 +904,47 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                                                                                $lastBR;
                                                        }
                                                } else {
-                                                       $blockSplit[$k].=$lastBR;
+                                                               // Eliminate true linebreaks inside Hx tags
+                                                       $blockSplit[$k]=preg_replace('/['.preg_quote(chr(10).chr(13)).']+/',' ',$this->transformStyledATags($blockSplit[$k])).$lastBR;
                                                }
                                        break;
                                        default:
-                                               $blockSplit[$k].=$lastBR;
+                                                       // Eliminate true linebreaks inside other headlist tags and after hr tag
+                                               $blockSplit[$k]=preg_replace('/['.preg_quote(chr(10).chr(13)).']+/',' ',$this->transformStyledATags($blockSplit[$k])).$lastBR;
                                        break;
                                }
                        } else {        // NON-block:
                                if (strcmp(trim($blockSplit[$k]),''))   {
-                                       $blockSplit[$k]=$this->divideIntoLines($blockSplit[$k]).$lastBR;
+                                       $blockSplit[$k]=$this->divideIntoLines(preg_replace('/['.preg_quote(chr(10).chr(13)).']+/',' ',$blockSplit[$k])).$lastBR;
+                                       $blockSplit[$k]=$this->transformStyledATags($blockSplit[$k]);
                                } else unset($blockSplit[$k]);
                        }
                }
                $this->TS_transform_db_safecounter++;
-               
+
+               return implode('',$blockSplit);
+       }
+
+       /**
+        * Wraps a-tags that contain a style attribute with a span-tag
+        *
+        * @param       string          Content input
+        * @return      string          Content output
+        */
+       function transformStyledATags($value)   {
+               $blockSplit = $this->splitIntoBlock('A',$value);
+               foreach($blockSplit as $k => $v)        {
+                       if ($k%2)       {       // If an A-tag was found:
+                               $attribArray = $this->get_tag_attributes_classic($this->getFirstTag($v),1);
+                               if ($attribArray['style'])      {       // If "style" attribute is set!
+                                       $attribArray_copy['style'] = $attribArray['style'];
+                                       unset($attribArray['style']);
+                                       $bTag='<span '.t3lib_div::implodeAttributes($attribArray_copy,1).'><a '.t3lib_div::implodeAttributes($attribArray,1).'>';
+                                       $eTag='</a></span>';
+                                       $blockSplit[$k] = $bTag.$this->removeFirstAndLastTag($blockSplit[$k]).$eTag;
+                               }
+                       }
+               }
                return implode('',$blockSplit);
        }
 
@@ -860,31 +960,33 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
        function TS_transform_rte($value,$css=0)        {
 
                        // Split the content from Database by the occurence of these blocks:
-               $blockSplit = $this->splitIntoBlock('TABLE,BLOCKQUOTE,TYPOLIST,TYPOHEAD,'.$this->headListTags,$value);
-               
+               $blockSplit = $this->splitIntoBlock('TABLE,BLOCKQUOTE,TYPOLIST,TYPOHEAD,'.($this->procOptions['preserveDIVSections']?'DIV,':'').$this->blockElementList,$value);
+
                        // Traverse the blocks
                foreach($blockSplit as $k => $v)        {
                        if ($k%2)       {       // Inside one of the blocks:
-                       
+
                                        // Init:
-                               $tag=$this->getFirstTag($v);
-                               $tagName=strtolower($this->getFirstTagName($v));
-                               $attribArray=$this->get_tag_attributes_classic($tag);
-                               
+                               $tag = $this->getFirstTag($v);
+                               $tagName = strtolower($this->getFirstTagName($v));
+                               $attribArray = $this->get_tag_attributes_classic($tag);
+
                                        // Based on tagname, we do transformations:
                                switch($tagName)        {
-                                       case 'blockquote':      // Keep blockquotes:
+                                       case 'blockquote':      // Keep blockquotes
+                                       case 'dd':              // Keep definitions
+                                       case 'div':             // Keep div sections, if they were splitted
                                                $blockSplit[$k] = $tag.
-                                                                                       $this->TS_transform_rte($this->removeFirstAndLastTag($blockSplit[$k]),$css).
-                                                                                       '</'.$tagName.'>';
+                                                                       $this->TS_transform_rte($this->removeFirstAndLastTag($blockSplit[$k]),$css).
+                                                                       '</'.$tagName.'>';
                                        break;
                                        case 'typolist':        // Transform typolist blocks into OL/UL lists. Type 1 is expected to be numerical block
                                                if (!isset($this->procOptions['typolist']) || $this->procOptions['typolist'])   {
                                                        $tListContent = $this->removeFirstAndLastTag($blockSplit[$k]);
                                                        $tListContent = ereg_replace('^[ ]*'.chr(10),'',$tListContent);
                                                        $tListContent = ereg_replace(chr(10).'[ ]*$','',$tListContent);
-                                                       $lines=explode(chr(10),$tListContent);
-                                                       $typ= $attribArray['type']==1?'ol':'ul';
+                                                       $lines = explode(chr(10),$tListContent);
+                                                       $typ = $attribArray['type']==1 ? 'ol' : 'ul';
                                                        $blockSplit[$k] = '<'.$typ.'>'.chr(10).
                                                                                                '<li>'.implode('</li>'.chr(10).'<li>',$lines).'</li>'.
                                                                                                '</'.$typ.'>';
@@ -892,8 +994,8 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                        break;
                                        case 'typohead':        // Transform typohead into Hx tags.
                                                if (!isset($this->procOptions['typohead']) || $this->procOptions['typohead'])   {
-                                                       $tC=$this->removeFirstAndLastTag($blockSplit[$k]);
-                                                       $typ=t3lib_div::intInRange($attribArray['type'],0,6);
+                                                       $tC = $this->removeFirstAndLastTag($blockSplit[$k]);
+                                                       $typ = t3lib_div::intInRange($attribArray['type'],0,6);
                                                        if (!$typ)      $typ=6;
                                                        $align = $attribArray['align']?' align="'.$attribArray['align'].'"': '';
                                                        $class = $attribArray['class']?' class="'.$attribArray['class'].'"': '';
@@ -903,24 +1005,24 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                                }
                                        break;
                                }
-                               $blockSplit[$k+1]=ereg_replace('^[ ]*'.chr(10),'',$blockSplit[$k+1]);   // Removing linebreak if typohead
+                               $blockSplit[$k+1] = ereg_replace('^[ ]*'.chr(10),'',$blockSplit[$k+1]); // Removing linebreak if typohead
                        } else {        // NON-block:
                                $nextFTN = $this->getFirstTagName($blockSplit[$k+1]);
                                $singleLineBreak = $blockSplit[$k]==chr(10);
-                               if (t3lib_div::inList('TABLE,BLOCKQUOTE,TYPOLIST,TYPOHEAD,'.$this->headListTags,$nextFTN))      {       // Removing linebreak if typolist/typohead
-                                       $blockSplit[$k]=ereg_replace(chr(10).'[ ]*$','',$blockSplit[$k]);
+                               if (t3lib_div::inList('TABLE,BLOCKQUOTE,TYPOLIST,TYPOHEAD,'.($this->procOptions['preserveDIVSections']?'DIV,':'').$this->blockElementList,$nextFTN))    {       // Removing linebreak if typolist/typohead
+                                       $blockSplit[$k] = ereg_replace(chr(10).'[ ]*$','',$blockSplit[$k]);
                                }
                                        // If $blockSplit[$k] is blank then unset the line. UNLESS the line happend to be a single line break.
                                if (!strcmp($blockSplit[$k],'') && !$singleLineBreak)   {
-                                       unset($blockSplit[$k]); 
+                                       unset($blockSplit[$k]);
                                } else {
-                                       $blockSplit[$k]=$this->setDivTags($blockSplit[$k],($this->procOptions['useDIVasParagraphTagForRTE']?'div':'p'));
+                                       $blockSplit[$k] = $this->setDivTags($blockSplit[$k],($this->procOptions['useDIVasParagraphTagForRTE']?'div':'p'));
                                }
                        }
                }
                return implode(chr(10),$blockSplit);
-       }       
-       
+       }
+
        /**
         * Transformation handler: 'ts_strip' / direction: "db"
         * Removing all non-allowed tags
@@ -932,20 +1034,20 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                $value = strip_tags($value,'<'.implode('><',explode(',','b,i,u,a,img,br,div,center,pre,font,hr,sub,sup,p,strong,em,li,ul,ol,blockquote')).'>');
                return $value;
        }
-       
-       
-       
-       
-       
-       
-       
-       
-       
-       
-       
-       
-       
-       
+
+
+
+
+
+
+
+
+
+
+
+
+
+
        /***************************************************************
         *
         * Generic RTE transformation, analysis and helper functions
@@ -981,8 +1083,14 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                }
                $kUknown = $this->procOptions['dontRemoveUnknownTags_db'] ? 1 : 0;              // Default: remove unknown tags.
                $hSC = $this->procOptions['dontUndoHSC_db'] ? 0 : -1;                                   // Default: re-convert literals to characters (that is &lt; to <)
-               
-               return $this->HTMLcleaner($content,$keepTags,$kUknown,$hSC);
+
+                       // Create additional configuration in order to honor the setting RTE.default.proc.HTMLparser_db.xhtml_cleaning=1
+               $addConfig=array();
+               if ((is_array($this->procOptions['HTMLparser_db.']) && $this->procOptions['HTMLparser_db.']['xhtml_cleaning']) || (is_array($this->procOptions['entryHTMLparser_db.']) && $this->procOptions['entryHTMLparser_db.']['xhtml_cleaning']) || (is_array($this->procOptions['exitHTMLparser_db.']) && $this->procOptions['exitHTMLparser_db.']['xhtml_cleaning']))   {
+                       $addConfig['xhtml']=1;
+               }
+
+               return $this->HTMLcleaner($content,$keepTags,$kUknown,$hSC,$addConfig);
         }
 
        /**
@@ -1004,49 +1112,55 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                        // Construct default list of tags to keep:
                                $typoScript_list = 'b,i,u,a,img,br,div,center,pre,font,hr,sub,sup,p,strong,em,li,ul,ol,blockquote,strike,span';
                                $keepTags = array_flip(t3lib_div::trimExplode(',',$typoScript_list.','.strtolower($this->procOptions['allowTags']),1));
-                               
+
                                        // For tags to deny, remove them from $keepTags array:
                                $denyTags = t3lib_div::trimExplode(',',$this->procOptions['denyTags'],1);
                                foreach($denyTags as $dKe)      {
                                        unset($keepTags[$dKe]);
                                }
                        }
-                       
+
                                // Based on the direction of content, set further options:
                        switch ($direction)     {
 
                                        // GOING from database to Rich Text Editor:
                                case 'rte':
-                                               // Transform bold/italics tags to strong/em
-                                       if (isset($keepTags['b']))      {$keepTags['b']=array('remap'=>'STRONG');}
-                                       if (isset($keepTags['i']))      {$keepTags['i']=array('remap'=>'EM');}
+
+                                       if (!isset($this->procOptions['transformBoldAndItalicTags']) || $this->procOptions['transformBoldAndItalicTags']) {
+                                                       // Transform bold/italics tags to strong/em
+                                               if (isset($keepTags['b']))      {$keepTags['b']=array('remap'=>'STRONG');}
+                                               if (isset($keepTags['i']))      {$keepTags['i']=array('remap'=>'EM');}
+                                       }
 
                                                // Transforming keepTags array so it can be understood by the HTMLcleaner function. This basically converts the format of the array from TypoScript (having .'s) to plain multi-dimensional array.
                                        list($keepTags) = $this->HTMLparserConfig($this->procOptions['HTMLparser_rte.'],$keepTags);
                                break;
-                               
+
                                        // GOING from RTE to database:
                                case 'db':
-                                               // Transform strong/em back to bold/italics:
-                                       if (isset($keepTags['strong'])) { $keepTags['strong']=array('remap'=>'b'); }
-                                       if (isset($keepTags['em']))             { $keepTags['em']=array('remap'=>'i'); }
-                                       
+
+                                       if (!isset($this->procOptions['transformBoldAndItalicTags']) || $this->procOptions['transformBoldAndItalicTags']) {
+                                                       // Transform strong/em back to bold/italics:
+                                               if (isset($keepTags['strong'])) { $keepTags['strong']=array('remap'=>'b'); }
+                                               if (isset($keepTags['em']))     { $keepTags['em']=array('remap'=>'i'); }
+                                       }
+
                                                // Setting up span tags if they are allowed:
                                        if (isset($keepTags['span']))           {
                                                $classes=array_merge(array(''),$this->allowedClasses);
                                                $keepTags['span']=array(
-                                                       'allowedAttribs'=>'class',
+                                                       'allowedAttribs' => 'id,class,style,title,lang,xml:lang,dir',
                                                        'fixAttrib' => Array(
                                                                'class' => Array (
                                                                        'list' => $classes,
                                                                        'removeIfFalse' => 1
-                                                               )
+                                                               ),
                                                        ),
                                                        'rmTagIfNoAttrib' => 1
                                                );
                                                if (!$this->procOptions['allowedClasses'])      unset($keepTags['span']['fixAttrib']['class']['list']);
                                        }
-                                       
+
                                                // Setting up font tags if they are allowed:
                                        if (isset($keepTags['font']))           {
                                                $colors=array_merge(array(''),t3lib_div::trimExplode(',',$this->procOptions['allowedFontColors'],1));
@@ -1068,7 +1182,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                                );
                                                if (!$this->procOptions['allowedFontColors'])   unset($keepTags['font']['fixAttrib']['color']['list']);
                                        }
-                                               
+
                                                // Setting further options, getting them from the processiong options:
                                        $TSc = $this->procOptions['HTMLparser_db.'];
                                        if (!$TSc['globalNesting'])     $TSc['globalNesting']='b,i,u,a,center,font,sub,sup,strong,em,strike,span';
@@ -1078,7 +1192,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                        list($keepTags) = $this->HTMLparserConfig($TSc,$keepTags);
                                break;
                        }
-                       
+
                                // Caching (internally, in object memory) the result unless tagList is set:
                        if (!$tagList)  {
                                $this->getKeepTags_cache[$direction] = $keepTags;
@@ -1086,11 +1200,11 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                return $keepTags;
                        }
                }
-               
+
                        // Return result:
                return $this->getKeepTags_cache[$direction];
        }
-                
+
        /**
         * This resolves the $value into parts based on <div></div>-sections and <p>-sections and <br />-tags. These are returned as lines separated by chr(10).
         * This point is to resolve the HTML-code returned from RTE into ordinary lines so it's 'human-readable'
@@ -1104,10 +1218,10 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
         * @see setDivTags()
         */
        function divideIntoLines($value,$count=5,$returnArray=FALSE)    {
-       
+
                        // Internalize font tags (move them from OUTSIDE p/div to inside it that is the case):
                if ($this->procOptions['internalizeFontTags'])  {$value = $this->internalizeFontTags($value);}
-               
+
                        // Setting configuration for processing:
                $allowTagsOutside = t3lib_div::trimExplode(',',strtolower($this->procOptions['allowTagsOutside']?$this->procOptions['allowTagsOutside']:'img'),1);
                $remapParagraphTag = strtoupper($this->procOptions['remapParagraphTag']);
@@ -1118,12 +1232,12 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                } else {
                        $keepAttribListArr = array();
                }
-                       
+
                        // Returns plainly the value if there was no div/p sections in it
                if (count($divSplit)<=1 || $count<=0)   {
                        return $value;
                }
-               
+
                        // Traverse the splitted sections:
                foreach($divSplit as $k => $v)  {
                        if ($k%2)       {       // Inside
@@ -1134,23 +1248,23 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                if (is_array($subLines))        {       // So, if there happend to be sub-nesting of p/div, this is written directly as the new content of THIS section. (This would be considered 'an error')
                                        // No noting.
                                } else {        //... but if NO subsection was found, we process it as a TRUE line without erronous content:
-                                       $subLines=array($subLines);
+                                       $subLines = array($subLines);
                                        if (!$this->procOptions['dontConvBRtoParagraph'])       {       // process break-tags, if configured for. Simply, the breaktags will here be treated like if each was a line of content...
                                                $subLines = spliti('<br[[:space:]]*[\/]?>',$v);
                                        }
-                                       
+
                                                // Traverse sublines (there is typically one, except if <br/> has been converted to lines as well!)
                                        reset($subLines);
                                        while(list($sk)=each($subLines))        {
-                                       
+
                                                        // Clear up the subline for DB.
                                                $subLines[$sk]=$this->HTMLcleaner_db($subLines[$sk]);
-                                               
+
                                                        // Get first tag, attributes etc:
                                                $fTag = $this->getFirstTag($divSplit[$k]);
                                                $tagName=strtolower($this->getFirstTagName($divSplit[$k]));
                                                $attribs=$this->get_tag_attributes($fTag);
-                                               
+
                                                        // Keep attributes (lowercase)
                                                $newAttribs=array();
                                                if (count($keepAttribListArr))  {
@@ -1158,7 +1272,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                                                if (isset($attribs[0][$keepA])) { $newAttribs[$keepA] = $attribs[0][$keepA]; }
                                                        }
                                                }
-                                               
+
                                                        // ALIGN attribute:
                                                if (!$this->procOptions['skipAlign'] && strcmp(trim($attribs[0]['align']),'') && strtolower($attribs[0]['align'])!='left')      {       // Set to value, but not 'left'
                                                        $newAttribs['align']=strtolower($attribs[0]['align']);
@@ -1173,7 +1287,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
 
                                                        // Remove any line break char (10 or 13)
                                                $subLines[$sk]=ereg_replace(chr(10).'|'.chr(13),'',$subLines[$sk]);
-                                               
+
                                                        // If there are any attributes or if we are supposed to remap the tag, then do so:
                                                if (count($newAttribs) && strcmp($remapParagraphTag,'1'))               {
                                                        if ($remapParagraphTag=='P')    $tagName='p';
@@ -1184,16 +1298,20 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                }
                                        // Add the processed line(s)
                                $divSplit[$k] = implode(chr(10),$subLines);
-                               
-                                       // If it turns out the line is just blank (containing a &nbsp; possibly) then just make it pure blank:
-                               if (trim(strip_tags($divSplit[$k]))=='&nbsp;')          $divSplit[$k]='';
+
+                                       // If it turns out the line is just blank (containing a &nbsp; possibly) then just make it pure blank.
+                                       // But, prevent filtering of lines that are blank in sense above, but whose tags contain attributes.
+                                       // Those attributes should have been filtered before; if they are still there they must be considered as possible content.
+                               if (trim(strip_tags($divSplit[$k]))=='&nbsp;' && !preg_match('/\<(img)(\s[^>]*)?\/?>/si', $divSplit[$k]) && !preg_match('/\<([^>]*)?( align| class| style| id| title| dir| lang| xml:lang)([^>]*)?>/si', trim($divSplit[$k]))) {
+                                       $divSplit[$k]='';
+                               }
                        } else {        // outside div:
                                        // Remove positions which are outside div/p tags and without content
                                $divSplit[$k]=trim(strip_tags($divSplit[$k],'<'.implode('><',$allowTagsOutside).'>'));
                                if (!strcmp($divSplit[$k],''))  unset($divSplit[$k]);   // Remove part if it's empty
                        }
                }
-               
+
                        // Return value:
                return $returnArray ? $divSplit : implode(chr(10),$divSplit);
        }
@@ -1208,7 +1326,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
         * @see divideIntoLines()
         */
        function setDivTags($value,$dT='p')     {
-       
+
                        // First, setting configuration for the HTMLcleaner function. This will process each line between the <div>/<p> section on their way to the RTE
                $keepTags = $this->getKeepTags('rte');
                $kUknown = $this->procOptions['dontProtectUnknownTags_rte'] ? 0 : 'protect';    // Default: remove unknown tags.
@@ -1218,7 +1336,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                        // Divide the content into lines, based on chr(10):
                $parts = explode(chr(10),$value);
                foreach($parts as $k => $v)     {
-               
+
                                // Processing of line content:
                        if (!strcmp(trim($parts[$k]),''))       {       // If the line is blank, set it to &nbsp;
                                $parts[$k]='&nbsp;';
@@ -1226,17 +1344,17 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                $parts[$k]=$this->HTMLcleaner($parts[$k],$keepTags,$kUknown,$hSC);
                                if ($convNBSP)  $parts[$k]=str_replace('&amp;nbsp;','&nbsp;',$parts[$k]);
                        }
-                       
+
                                // Wrapping the line in <$dT> is not already wrapped:
                        $testStr = strtolower(trim($parts[$k]));
                        if (substr($testStr,0,4)!='<div' || substr($testStr,-6)!='</div>')      {
                                if (substr($testStr,0,2)!='<p' || substr($testStr,-4)!='</p>')  {
                                                // Only set p-tags if there is not already div or p tags:
-                                       $parts[$k]='<'.$dT.'>'.$parts[$k].'</'.$dT.'>'; 
+                                       $parts[$k]='<'.$dT.'>'.$parts[$k].'</'.$dT.'>';
                                }
                        }
                }
-                       
+
                        // Implode result:
                return implode(chr(10),$parts);
        }
@@ -1260,7 +1378,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                foreach($fontSplit as $k => $v) {
                        if ($k%2)       {       // Inside
                                $fTag = $this->getFirstTag($v); // Fint font-tag
-                               
+
                                $divSplit_sub = $this->splitIntoBlock('div,p',$this->removeFirstAndLastTag($v),1);
                                if (count($divSplit_sub)>1)     {       // If there were div/p sections inside the font-tag, do something about it...
                                                // traverse those sections:
@@ -1281,7 +1399,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
 
                return implode('',$fontSplit);
        }
-       
+
        /**
         * Returns SiteURL based on thisScript.
         *
@@ -1301,7 +1419,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
        function rteImageStorageDir()   {
                return $this->rte_p['imgpath'] ? $this->rte_p['imgpath'] : $GLOBALS['TYPO3_CONF_VARS']['BE']['RTE_imageStorageDir'];
        }
-       
+
        /**
         * Remove all tables from incoming code
         * The function is trying to to this is some more or less respectfull way. The approach is to resolve each table cells content and implode it all by <br /> chars. Thus at least the content is preserved in some way.
@@ -1311,10 +1429,10 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
         * @return      string          Output value
         */
        function removeTables($value,$breakChar='<br />')       {
-       
+
                        // Splitting value into table blocks:
                $tableSplit = $this->splitIntoBlock('table',$value);
-               
+
                        // Traverse blocks of tables:
                foreach($tableSplit as $k => $v)        {
                        if ($k%2)       {
@@ -1330,11 +1448,11 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                }
                        }
                }
-               
+
                        // Implode it all again:
                return implode($breakChar,$tableSplit);
        }
-       
+
        /**
         * Default tag mapping for TS
         *
@@ -1357,7 +1475,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                }
                return $code;
        }
-       
+
        /**
         * Finds width and height from attrib-array
         * If the width and height is found in the style-attribute, use that!
@@ -1370,6 +1488,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                if ($style)     {
                        $regex='[[:space:]]*:[[:space:]]*([0-9]*)[[:space:]]*px';
                                // Width
+                       $reg = array();
                        eregi('width'.$regex,$style,$reg);
                        $w = intval($reg[1]);
                                // Height
@@ -1384,7 +1503,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                }
                return array(intval($w),intval($h));
        }
-       
+
        /**
         * Parse <A>-tag href and return status of email,external,file or page
         *
@@ -1400,11 +1519,11 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                } else {
                        $curURL = $this->siteUrl();     // 100502, removed this: 'http://'.t3lib_div::getThisUrl(); Reason: The url returned had typo3/ in the end - should be only the site's url as far as I see...
                        for($a=0;$a<strlen($url);$a++)  {
-                               if ($url[$a]!=$curURL[$a])      {
+                               if ($url{$a}!=$curURL{$a})      {
                                        break;
                                }
                        }
-                       
+
                        $info['relScriptPath']=substr($curURL,$a);
                        $info['relUrl']=substr($url,$a);
                        $info['url']=$url;
@@ -1412,7 +1531,7 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
 
                        $siteUrl_parts = parse_url($url);
                        $curUrl_parts = parse_url($curURL);
-                       
+
                        if ($siteUrl_parts['host']==$curUrl_parts['host']       // Hosts should match
                                && (!$info['relScriptPath']     || (defined('TYPO3_mainDir') && substr($info['relScriptPath'],0,strlen(TYPO3_mainDir))==TYPO3_mainDir)))        {       // If the script path seems to match or is empty (FE-EDIT)
 
@@ -1424,12 +1543,14 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                                        $info['type']='anchor';
                                } elseif (!trim($uP['path']) || !strcmp($uP['path'],'index.php'))       {
                                        $pp = explode('id=',$uP['query']);
-                                       $id = trim($pp[1]);
+                                       $parameters = explode('&', $pp[1]);
+                                       $id = array_shift($parameters);
                                        if ($id)        {
                                                $info['pageid']=$id;
                                                $info['cElement']=$uP['fragment'];
                                                $info['url']=$id.($info['cElement']?'#'.$info['cElement']:'');
                                                $info['type']='page';
+                                               $info['query'] = $parameters[0]?'&'.implode('&', $parameters):'';
                                        }
                                } else {
                                        $info['url']=$info['relUrl'];
@@ -1455,15 +1576,20 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
                reset($blockSplit);
                while(list($k,$v)=each($blockSplit))    {
                        if ($k%2)       {       // block:
-                               $attribArray=$this->get_tag_attributes_classic($this->getFirstTag($v),1);
+                               $attribArray = $this->get_tag_attributes_classic($this->getFirstTag($v),1);
+
                                        // Checking if there is a scheme, and if not, prepend the current url.
-                               $uP = parse_url(strtolower($attribArray['href']));
-                               if (!$uP['scheme'])     {
-                                       $attribArray['href']=$this->siteUrl().substr($attribArray['href'],strlen($this->relBackPath));
+                               if (strlen($attribArray['href']))       {       // ONLY do this if href has content - the <a> tag COULD be an anchor and if so, it should be preserved...
+                                       $uP = parse_url(strtolower($attribArray['href']));
+                                       if (!$uP['scheme'])     {
+                                               $attribArray['href'] = $this->siteUrl().substr($attribArray['href'],strlen($this->relBackPath));
+                                       }
+                               } else {
+                                       $attribArray['rtekeep'] = 1;
                                }
-                               if (!$dontSetRTEKEEP)   $attribArray['rtekeep']=1;
+                               if (!$dontSetRTEKEEP)   $attribArray['rtekeep'] = 1;
 
-                               $bTag='<a '.t3lib_div::implodeParams($attribArray,1).'>';
+                               $bTag='<a '.t3lib_div::implodeAttributes($attribArray,1).'>';
                                $eTag='</a>';
                                $blockSplit[$k] = $bTag.$this->TS_AtagToAbs($this->removeFirstAndLastTag($blockSplit[$k])).$eTag;
                        }
@@ -1476,4 +1602,5 @@ class t3lib_parsehtml_proc extends t3lib_parsehtml {
 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_parsehtml_proc.php'])   {
        include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_parsehtml_proc.php']);
 }
-?>
+
+?>
\ No newline at end of file