1<?php
2/**
3 * visrep-Plugin: Parses visrep-blocks
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Carl-Christian Salvesen <calle@ioslo.net>
7 * @author     Andreas Gohr <andi@splitbrain.org>
8 * @author     Ionut Stoica <stoica.ionut@gmail.com>
9 */
10
11
12if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
13if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
14require_once(DOKU_PLUGIN.'syntax.php');
15
16class syntax_plugin_visrep extends DokuWiki_Syntax_Plugin {
17
18    /**
19     * What about paragraphs?
20     */
21    function getPType(){
22        return 'block';
23    }
24
25    /**
26     * What kind of syntax are we?
27     */
28    function getType(){
29        return 'substition';
30    }
31
32    /**
33     * Where to sort in?
34     */
35    function getSort(){
36        return 200;
37    }
38
39    /**
40     * Connect pattern to lexer
41     */
42    function connectTo($mode) {
43        $this->Lexer->addSpecialPattern('<visrep.*?>\n.*?\n</visrep>', $mode, 'plugin_visrep');
44    }
45
46    /**
47     * Handle the match
48     */
49    function handle($match, $state, $pos, &$handler) {
50
51        $info = $this->getInfo();
52        $xml = sprintf("<?xml version=\"1.0\" encoding=\"utf-8\"?>%s", $match);
53
54        $dom = simplexml_load_string($xml);
55        $dat = (array)$dom->attributes();
56        $attrs = empty($dat['@attributes']) || !is_array($dat['@attributes']) ? array() : $dat['@attributes'];
57
58        $defaults = array(
59          'theme'    => NULL,  // napking | serious
60          'width'     => 0,
61          'height'    => 0,
62          'align'     => '',
63          'data-layout'    => NULL, // dot|neato|twopi|circo|fdp
64          'data-engine'    => strtolower(empty($attrs['data-engine']) ? 'unknown' : $attrs['data-engine']),
65          'data-version'   => $info['date'],
66          'md5'       => md5($match),
67        );
68        $input = trim((string)$dom);
69        $return = array_merge(
70          $defaults,
71          $attrs
72        );
73
74        // store input for later use
75        io_saveFile($this->_cachename($return, 'txt'), $this->_data($return, $input));
76
77        return $return;
78    }
79
80    function _data($attrs, $input) {
81      $data = $input;
82      switch ($attrs['data-engine']) {
83        case 'blockdiag':
84        case 'seqdiag':
85        case 'actdiag':
86        case 'nwdiag':
87        case 'rackdiag':
88        case 'packetdiag':
89          $data = sprintf("%s {\n%s\n}", $attrs['data-engine'], $data);
90          break;
91        default:
92          $data = preg_replace('~(.*)' . preg_quote('}', '~') . '~', '$1' . "\nsize=\"%s,%s\"; resolution=72;\n}", $data, 1);
93          break;
94      }
95      return $data;
96    }
97
98    /**
99     * Cache file is based on parameters that influence the result image
100     */
101    function _cachename($data, $ext) {
102        return getcachename(join('x', array_values($data)),'.visrep.'.$ext);
103    }
104
105    /**
106     * Create output
107     */
108    function render($format, &$R, $data) {
109        if($format == 'xhtml') {
110            $attrs = array();
111
112            if(is_a($R,'renderer_plugin_dw2pdf')){
113              $url = 'dw2pdf://'.$this->_imgfile($data);
114            } else {
115              $url = DOKU_BASE.'lib/plugins/visrep/img.php?'.buildURLparams($data);
116            }
117
118            foreach ($data as $k=>$v) {
119              if ($k == 'md5') continue;
120              if (is_null($v) || strlen($v) == 0) continue;
121              if (in_array($k, array('width', 'height'))) continue;
122              $attrs[] = sprintf('%s = "%s"', htmlspecialchars($k, ENT_QUOTES, 'UTF-8'), htmlspecialchars($v, ENT_QUOTES, 'UTF-8'));
123            }
124
125            $attrs[] = sprintf('src = "%s"', $url);
126            $code = sprintf('<img %s alt="" class="dokuwiki-visrep-image"/>', implode(' ', $attrs));
127
128
129            $R->doc .= $w_start . $code . $w_end;
130            return true;
131        } elseif($format == 'odt'){
132            $src = $this->_imgfile($data);
133            $R->_odtAddImage($src, $data['width'], $data['height'], $data['align']);
134            return true;
135        }
136        return false;
137    }
138
139    /**
140     * Return path to the rendered image on our local system
141     */
142    function _imgfile($data) {
143        $cache  = $this->_cachename($data, 'png');
144        // create the file if needed
145        if (!file_exists($cache)) {
146          $in = $this->_cachename($data, 'txt');
147          $ok = $this->_run($data, $in, $cache);
148          if(!$ok) return false;
149          clearstatcache();
150        }
151
152        // resized version
153        //if ($data['width']){
154        //    $cache = media_resize_image($cache, 'png', $data['width'], $data['height']);
155        //}
156
157        // something went wrong, we're missing the file
158        if(!file_exists($cache)) return false;
159        return $cache;
160    }
161
162    /**
163     * Run the visrep program
164     */
165    function _run($data,$in,$out) {
166        global $conf;
167
168        $loc = 'path_'.$data['data-engine'];
169        $cmd = $this->getConf($loc);
170
171        if ($this->_isBlockDiag($data['data-engine'])) {
172          if (!empty($data['width']) && !empty($data['height'])) {
173            $cmd .= sprintf(' --size=%dx%d', $data['width'], $data['height']);
174          }
175          // $cmd .= ' -a';
176          $cmd .= ' -o '.str_ireplace('/', DIRECTORY_SEPARATOR, escapeshellarg($out));
177          $cmd .= ' '.str_ireplace('/', DIRECTORY_SEPARATOR, escapeshellarg($in));
178        }
179
180        if ($data['data-engine'] == 'graphviz') {
181          $cmd .= ' -Tpng';
182          if (isset($data['layout']) && in_array($data['layout'], array('dot', 'neato', 'fdp', 'twopi', 'circo'))) {
183            $cmd .= ' -K'.$data['layout'];
184          }
185          $cmd .= ' -o'.str_ireplace('/', DIRECTORY_SEPARATOR, escapeshellarg($out));
186          $cmd .= ' '.str_ireplace('/', DIRECTORY_SEPARATOR, escapeshellarg($in));
187        }
188
189        exec($cmd, $output, $error);
190
191        if ($error != 0){
192            if($conf['debug']){
193                dbglog(join("\n",$output),'visrep command failed: '.$cmd);
194            }
195            return false;
196        }
197
198        return true;
199    }
200
201
202    function _isBlockDiag($engine) {
203      return in_array($engine, array('seqdiag', 'blockdiag', 'actdiag', 'nwdiag', 'rackdiag', 'packetdiag'));
204    }
205
206}
207
208
209
210