1<?php
2	/**
3
4	*/
5
6	// must be run within Dokuwiki
7	if (!defined('DOKU_INC')) die();
8
9	if (!defined('DOKU_LF')) define('DOKU_LF', "\n");
10	if (!defined('DOKU_TAB')) define('DOKU_TAB', "\t");
11	if(!defined('EPUB_DIR')) define('EPUB_DIR',realpath(dirname(__FILE__).'/../').'/');
12	require_once DOKU_INC.'inc/parser/xhtml.php';
13
14	class renderer_plugin_epub extends Doku_Renderer_xhtml {
15		private $opf_handle;
16		private $oebps;
17		private $current_page;
18		private $allow_url_fopen;
19		private $isWin;
20        private $audio_link;
21         private $audio_nmsp;
22         private $audio_nmsp_orig;
23         private $video_link;
24         private $video_nmsp;
25         private $video_nmsp_orig;
26	     function getInfo() {
27			return array(
28            'author' => 'Myron Turner',
29            'email'  => 'turnermm02@shaw.ca',
30            'date'   => '2011-07-1',
31            'name'   => 'epub',
32            'desc'   => 'renderer for ebook creator',
33            'url'    => 'http://www.dokuwiki.org/plugin:epub');
34		}
35
36	    function __construct() {
37            $this->allow_url_fopen=ini_get ( 'allow_url_fopen' ) ;
38            $this->isWin=function_exists('epub_isWindows') ? epub_isWindows() : false;
39            $this->mpeg_settings('audio') ;
40            $this->mpeg_settings('video') ;
41		}
42
43        function mpeg_settings($which) {
44            if($which == 'audio') {
45			$this->audio_link = $this->getConf('audio_fn');
46                $nmsp = 'audio_nmsp';
47            }
48            else {
49                $this->video_link = $this->getConf('video_fn');
50                $nmsp = 'video_nmsp';
51            }
52            $nmsp = $this->getConf($nmsp);
53            $nmsp = str_replace(' ','',$nmsp);
54            $nmsp = str_replace(',','|',$nmsp);
55            $nmsp_orig = $nmsp;
56            $nmsp = str_replace(':','_',$nmsp);
57            if($which == 'audio') {
58                $this->audio_nmsp = $nmsp;
59                $this->audio_nmsp_orig = $nmsp_orig;
60                return;
61            }
62            $this->video_nmsp = $nmsp;
63            $this->video_nmsp_orig = $nmsp_orig;
64		}
65
66		/**
67			* Make available as XHTML replacement renderer
68		*/
69		public function canRender($format){
70			if($format == 'xhtml') return true;
71			return false;
72		}
73
74		function set_oebps() {
75		   $this->oebps = epub_get_oebps();
76		}
77        function set_current_page($page) {
78		   $this->current_page=$page;
79		}
80
81		function opf_handle() {
82			if(!$this->opf_handle) {
83				$this->opf_handle= fopen($this->oebps. 'content.opf', 'a');
84			}
85			return $this->opf_handle;
86		}
87
88		function is_epubid($id) {
89			return is_epub_pageid($id);
90		}
91		/**
92			* Simplified header printing with PDF bookmarks
93		*/
94		function header($text, $level, $pos) {
95			if(!$text) return; //skip empty headlines
96		    $hid = $this->_headerToLink($text, true);
97			// print header
98			$this->doc .= DOKU_LF."<h$level id='$hid'>";
99			$this->doc .= $this->_xmlEntities($text);
100			$this->doc .= "</h$level>".DOKU_LF;
101		}
102
103		/**
104			* Wrap centered media in a div to center it
105		*/
106		function _media ($src, $title=NULL, $align=NULL, $width=NULL,
107		$height=NULL, $cache=NULL, $render = true) {
108			$mtype = mimetype($src);
109			if(!$title) $title = $src;
110		    $external = false;
111            $src = trim($src);
112            $out = "";
113            if(strpos($src,'http://') === 0) $external = true;
114            if($external && !$this->allow_url_fopen)  {
115                $link = $this->create_external_link($src);
116                return $this->_formatLink($link);
117            }
118			$src = $this->copy_media($src,$external);
119
120			if(strpos($mtype[1],'image') !== false)       {
121				$out .= $this->set_image($src,$width,$height,$align);
122			}
123            else if(strpos($mtype[1],'audio') !== false)       {
124				if($this->audio_link)  $out .= '</p><div style="text-align:center">' ;
125               $out .= $this->set_audio($src,$mtype,$title) ;
126                if($this->audio_link) {  // set audio footnote
127                 list($title,$rest) = explode('(', $title);
128                     $mpfile = str_replace('Audio/',"",$src);
129                         $display_name = $title;
130                         $title = $mpfile;
131                     $out .=  $this->_formatLink( array('class'=>'media mediafile mf_mp3','title'=>$title,'name'=>$title, 'display'=>$display_name) )  ."\n</div><p>";
132			    }
133			}
134         else if(strpos($mtype[1],'video') !== false)       {
135                     if($this->video_link)  $out .= '</p><div style="text-align:center">' ;//$out .= '<div style="text-align:center">' ;
136                $out .= $this->set_video($src,$mtype,$title) ;
137                    if($this->video_link) {
138                          list($title,$rest) = explode('(', $title);
139                         $mpfile = str_replace('Video/',"",$src);
140                         $display_name = $title;
141                         $title = $mpfile;
142                         $out .=  $this->_formatLink( array('class'=>'media mediafile mf_mp4','title'=>$title,'name'=>$title, 'display'=>$display_name) )  ."\n</div><p>";
143                    }
144         }
145			else {
146				$out .= "<a href='$src'>$title</a>";
147			}
148			return $out;
149		}
150
151        function create_external_link($name) {
152            return array(
153                "target" => "",
154                "style" => "",
155                "pre" => "",
156                "suf" => "",
157                  "type"=>'ext_media',
158                "more" =>  'rel="nofollow"',
159                "class" => 'urlextern',
160                "url" => $name,
161                "name" => basename($name),
162                "title" => $name
163              );
164        }
165
166		/**
167			* hover info makes no sense in PDFs, so drop acronyms
168		*/
169		function acronym($acronym) {
170			$this->doc .= $this->_xmlEntities($acronym);
171		}
172
173
174		function is_image($link,&$type) {
175
176			if(strpos($link['class'],'media') === false)  {
177				$type=$link['class'];
178				return false;
179			}
180
181			$mime_type = mimetype($link['title']);
182			if(!$mime_type[1] ) {
183				list($url,$rest) = explode('?', $link['url']);
184				$mime_type = mimetype($url);
185                if(!$mime_type[1]) {
186                    $mime_type = mimetype($rest);
187                }
188			}
189
190			if(!$mime_type[1]) {
191				$type = 'other';
192				return false;
193			}
194
195			list($type,$ext) = explode('/', $mime_type[1] );
196
197			if($type != 'image') {
198				$type='media';
199				return false;
200			}
201
202			return true;
203		}
204		/**
205			* reformat links if needed
206		*/
207
208		function _formatLink($link){
209			$type = "";
210
211			if($this->is_image($link,$type)) {
212				if(preg_match('#media\s*=\s*http#',$link['url'])) {
213					$name = $this->copy_media($link['title'],true);
214					if($name) {
215  		  			    return $this->set_image($name) ;
216					}
217					else return $this->set_image('');
218				}
219				elseif(strpos($link['name'],'<img') !== false) {
220					$name = $this->copy_media($link['title']);
221					if(strpos($link['name'],'fetch.php') !== false) {
222                        $t = $link['title'];
223						$link['name'] = preg_replace("#src=.*?$t\"#", "src=\"$name\"",$link['name']);
224						if(strpos($link['name'],'alt=""') !==false) {
225							$link['name'] = str_replace('alt=""','alt="'. $link['title'] . '"', $link['name']);
226						}
227						return $this->clean_image_link($link['name']);
228					}
229                     elseif(strpos($link['url'],'fetch.php') !== false) {
230                         if(preg_match('/src=\"(.*?)\"/',$link['name'],$matches)) {
231                             $link['name'] = '<a href="' . $matches[1] .'">' . $link['title'] . '</a>';
232                             return $this->clean_image_link($link['name']);
233                         }
234                    }
235                    $link['name'] = $this->clean_image_link($link['name']);
236
237					return $link['name'];
238				}
239
240				$name = $this->copy_media($link['title']);
241				return $this->set_image($name);
242			}
243            elseif($link['class'] == 'media' && strpos($link['name'],'<img') !== false) {
244                $this->doc .= '<a href="'  .  $link['url']  .'" class="media" title="' . $link['title'] . '"  rel="nofollow">' . $link['name'] . '</a>';
245                return;
246            }
247
248			if((strpos($link['class'],'wikilink') !== false ) && $type!='media') {  //internal link
249				$orig = "";
250				$name = $this->local_name($link,$orig,$frag);
251				if(!$this->is_epubid($orig)) {
252					$doku_base = DOKU_BASE;
253					$doku_base = trim($doku_base,'/');
254					$fnote =  DOKU_URL .  "doku.php?id=$orig";
255					return $this->set_footnote($link,$fnote);
256				}
257
258               $name = epub_clean_name($name);
259				$name .='.html';
260                if($link['class'] == 'wikilink2') {
261                    $wfn =  wikiFN($orig);
262                    if( file_exists($wfn) ) $link['class'] =  'wikilink1';
263                }
264
265			}
266			else if($type=='media') {  //internal media
267				$orig = "";
268				$name = $this->local_name($link,$orig);
269                if(!empty($link['display'])) {
270                    $link['name'] = $link['display'];
271                    if(strpos($link['class'],'mp3') !== false) {
272                    $orig = preg_replace('/^(' .  $this->audio_nmsp  . ')_/', "$1:", $orig);
273                        $orig = preg_replace('/^(' .  $this->audio_nmsp_orig  . ')_/', "$1:", $orig);  //two levels deep
274                    }
275                    else if(strpos($link['class'],'mp4') !== false) {
276                        $orig = preg_replace('/^(' .  $this->video_nmsp  . ')_/', "$1:", $orig);
277                        $orig = preg_replace('/^(' .  $this->video_nmsp_orig  . ')_/', "$1:", $orig);
278                    }
279                }
280			    $note_url =  DOKU_URL .  "lib/exe/fetch.php?media=" . $orig;
281                $link['class'] = 'wikilink1';
282				$out = $this->set_footnote($link,$note_url);
283				$out=preg_replace('/<a\s+href=\'\'>(.*?)<\/a>(?=<a)/',"$1",$out);		//remove link markup from link name
284				return $out;
285			}
286			elseif($link['class'] != 'media') {   //  or urlextern	or samba share or . . .
287                $out = $this->set_footnote($link,trim($link['url']));		// creates an entry in output for the link  with a live footnote to the link
288                if(isset($link['type']) && $link['type'] == 'ext_media') {
289                    $this->doc .= $out;
290                }
291                else return $out;
292			}
293
294			if(!$name) return;
295			$link['url'] = $name;
296            if($frag) $link['url'] .="#$frag";
297			return parent::_formatLink($link);
298		}
299
300         function clean_image_link($link) {
301                $link = str_replace('Images/Images',"Images",$link);
302                $link = preg_replace('#[\.\/]*Images#', "../Images", $link );
303                return $link;
304         }
305         function set_footnote($link, $note_url="") {
306 					$out = $link['name'];
307					$fn_id = epub_fn();
308					$link['name'] = "[$fn_id]";
309                    if(preg_match("/media\s*=\s*(http.*)/", $link['url'],$matches)) {   //format external  urls
310                        $note_url = urldecode($matches[1]);
311                    }
312					$link['url'] = 'footnotes.html#' .$this->current_page;
313					$link['class'] = 'wikilink1';
314                    $id = 'backto_' . $fn_id;
315					$hash_link="<a id='$id' name='$id'></a>";
316					$out .= $hash_link . parent::_formatLink($link); // . '</a>';
317					epub_write_footnote($fn_id,$this->current_page,$note_url);
318					return $out;
319
320         }
321
322        function smiley($smiley) {
323            static $smileys;
324             if(!$smileys) $smileys = getSmileys();
325
326             if ( array_key_exists($smiley, $this->smileys) ) {
327                 $spath = DOKU_INC . 'lib/images/smileys/'.$smileys[$smiley];
328                 $name = $this->copy_media($spath,true);
329                 $this->doc .= $this->_media($name);
330             }
331         }
332
333        function local_name($link,&$orig="", &$frag ="") {
334            $base_name= basename($link['url']);
335            $title = $link['title']? ltrim($link['title'],':'): "";
336            list($starturl,$frag) = explode('#',$link['url']);
337            if ($title) {
338                $name = $title;
339            }
340            elseif($base_name) {
341                list($name,$rest) = explode('?',$base_name);
342            }
343
344            if($name) {
345                $orig = ltrim($name,':');
346                return epub_clean_name(str_replace(':','_',$name));
347            }
348            return false;
349        }
350
351		function copy_media($media,$external=false) {
352			$name =  epub_clean_name(str_replace(':','_',basename($media)));
353            $ret_name = $name;
354
355			$mime_type = mimetype($name);
356			list($type,$ext) = explode('/', $mime_type[1] );
357			if($type !== 'image' && $type != 'audio' && $type != 'video')  return;
358			if($external) {
359                if(!$this->allow_url_fopen) return;
360                $tmp =  str_replace('https://',"",$media);
361                $tmp =  str_replace('http://',"",$media);
362                $tmp =  str_replace('www.',"",$tmp);
363				if($this->isWin) {
364				    $tmp =  preg_replace('/^[A-Z]:/',"",$tmp);
365				}
366                $tmp=ltrim($tmp,'/\/');
367
368                $elems=explode('/',$tmp);
369				if($this->isWin) {
370				    $elems=explode('\\',$tmp);
371				}
372                if(count($elems && $elems[0])) {
373                    $elems[0] = preg_replace('#/\W#','_',$elems[0]);
374                    $name = $elems[0]. "_" . $name;
375                }
376            }
377          if($type == 'audio') {
378               $name = "Audio/$name";
379           }
380          else if($type == 'video') {
381               $name = "Video/$name";
382           }
383           else if(!preg_match("/^Images/", $name)) {
384                $name = "Images/$name";
385            }
386
387		    $file = $this->oebps . $name;
388			if(file_exists($file)) return $name;
389			if(!$external) {
390				$media = mediaFN($media);
391			}
392
393			if(copy ($media ,  $file)) {
394				epub_write_item($name,$mime_type[1]) ;
395				return $name;
396			}
397            else if(!$this->isWin && epub_save_image($media ,  $file)) {
398            	epub_write_item($name,$mime_type[1]) ;
399				return $name;
400            }
401			return false;
402		}
403
404		function set_image($img,$width=null,$height=null,$align=null) {
405			$w="";
406			$h="";
407			if($width)   $w= ' width="' . $width . '"';
408			if($height)   $h= ' height="' .$height . '"';
409            $img = $this->clean_image_link($img);
410            $class='media';
411            if($align) {
412                $class .= $align;
413            }
414			return '<img src="' . $img . '"' .  "$h $w " . ' alt="'. $img . '" class="' .  $class . '" />';
415		}
416        function set_audio($src,$mtype,$title) {
417            $src = "../$src";
418            $type = $mtype[1];
419            $out = '<audio class="mediacenter" controls="controls">' . "\n";
420            $out .= "<source src= '$src' type='$type' />" .
421            "\n<a href='$src' title='$title'>$title</a></audio>\n";
422            return $out;
423        }
424
425        function set_video($src,$mtype,$title) {
426            $src = "../$src";
427            $type = $mtype[1];
428            $out = '<video class="mediacenter" controls="controls">' . "\n";
429            $out .= "<source src= '$src' type='$type' />" .
430            "\n<a href='$src' title='$title'>$title</a></video>\n";
431            return $out;
432        }
433
434        function plugin($name,$data,$state = '', $match = '') {
435
436		    if($name !='mathpublish' && $name !='ditaa' && $name !='graphviz') return parent::plugin($name,$data);
437
438		    $mode ='xhtml';
439		    $renderer =p_get_renderer($mode );
440            $plugin =& plugin_load('syntax',$name);
441            if($plugin != null) {
442                $plugin->render($mode,$renderer,$data);
443
444		        if($name == 'ditaa') {
445			        epub_check_for_ditaa($renderer->doc,$this);
446                }
447				else if($name =='mathpublish') {
448
449					epub_check_for_math($renderer->doc,$this);
450				}
451				else if($name =='graphviz') {
452					epub_check_for_graphviz($renderer->doc,$this,$data,$plugin);
453				}
454				$this->doc .= $renderer->doc;
455		    }
456        }
457
458		/**
459			* no obfuscation for email addresses
460		*/
461		function emaillink($address, $name = NULL,$returnonly = false) {
462			global $conf;
463			$old = $conf['mailguard'];
464			$conf['mailguard'] = 'none';
465			parent::emaillink($address, $name);
466			$conf['mailguard'] = $old;
467		}
468
469		function write($what,$handle) {
470			fwrite($handle,"$what\n");
471			fflush($handle);
472		}
473	}
474
475