FusionDirectory
class_IconTheme.inc
1 <?php
2 /*
3  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
4  Copyright (C) 2011-2016 FusionDirectory
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20 
22 {
23 }
24 
30 {
31  /* Nominal (unscaled) size of the icons in this directory.
32  * Required. */
33  private $Size;
34 
35  /* Specifies the minimum (unscaled) size that the icons in this directory can be scaled to.
36  * Defaults to the value of Size if not present. */
37  private $MinSize;
38 
39  /* Specifies the maximum (unscaled) size that the icons in this directory can be scaled to.
40  * Defaults to the value of Size if not present. */
41  private $MaxSize;
42 
43  /* The type of icon sizes for the icons in this directory.
44  * Valid types are Fixed, Scalable and Threshold.
45  * The type decides what other keys in the section are used.
46  * If not specified, the default is Threshold. */
47  private $Type = 'Threshold';
48 
49  /* The icons in this directory can be used if the size differ at most this much from the desired (unscaled) size.
50  * Defaults to 2 if not present. */
51  private $Threshold = 2;
52 
53  function __construct ($infos)
54  {
55  $this->Size = $infos['Size'];
56  $this->MinSize = $infos['Size'];
57  $this->MaxSize = $infos['Size'];
58  foreach (['Type', 'MaxSize', 'MinSize', 'Threshold'] as $key) {
59  if (isset($infos[$key])) {
60  $this->$key = $infos[$key];
61  }
62  }
63  /* Thanks to this Threshold and Scaled are the same */
64  if ($this->Type == 'Threshold') {
65  $this->MinSize = $this->Size - $this->Threshold;
66  $this->MaxSize = $this->Size + $this->Threshold;
67  }
68  }
69 
70  function MatchesSize ($size)
71  {
72  switch ($this->Type) {
73  case 'Fixed':
74  return ($this->Size == $size);
75  case 'Threshold':
76  case 'Scalable':
77  default:
78  return (($this->MinSize <= $size) && ($size <= $this->MaxSize));
79  }
80  }
81 
82  function SizeDistance ($size)
83  {
84  switch ($this->Type) {
85  case 'Fixed':
86  return abs($this->Size - $size);
87  case 'Threshold':
88  case 'Scalable':
89  default:
90  if ($size < $this->MinSize) {
91  return $this->MinSize - $size;
92  }
93  if ($size > $this->MaxSize) {
94  return $size - $this->MaxSize;
95  }
96  return 0;
97  }
98  }
99 }
100 
106 {
107  private $subdirs = [];
108  private $path;
109  private $parent;
110 
111  function __construct ($folder, $default_parent)
112  {
113  $this->path = $folder;
114  $datas = @parse_ini_file($folder . '/index.theme', TRUE, INI_SCANNER_RAW);
115  if ($datas === FALSE) {
116  throw new ThemeFileParsingException('Error while parsing theme file');
117  }
118  if (isset($datas['Icon Theme']['Directories']) && !empty($datas['Icon Theme']['Directories'])) {
119  $dirs = preg_split('/,/', $datas['Icon Theme']['Directories']);
120  foreach ($dirs as $name) {
121  if (isset($datas[$name])) {
122  $this->subdirs[strtolower($datas[$name]['Context'])][$name] = new IconThemeDir($datas[$name]);
123  }
124  }
125  }
126 
127  if (isset($datas['Icon Theme']['Inherits'])) {
128  $this->parent = $datas['Icon Theme']['Inherits'];
129  } else {
130  $this->parent = $default_parent;
131  }
132  }
133 
134  function FindIcon ($context, $icon, $size)
135  {
136  $context = strtolower($context);
137  return $this->FindIconHelper($context, $icon, $size);
138  }
139 
140  function FindIconHelper ($context, $icon, $size)
141  {
142  $filename = $this->LookupIcon($context, $icon, $size);
143  if ($filename != NULL) {
144  return $filename;
145  }
146  if (isset(static::$fallbacks[$context . '/' . $icon])) {
147  foreach (static::$fallbacks[$context . '/' . $icon] as $fallback) {
148  $filename = $this->LookupIcon($fallback[0], $fallback[1], $size);
149  if ($filename != NULL) {
150  return $filename;
151  }
152  }
153  }
154 
155  if ($this->parent !== NULL) {
156  $parentTheme = $this->findTheme($this->parent);
157  if ($parentTheme === NULL) {
158  $parentTheme = $this->findTheme(static::$default_theme);
159  }
160  return $parentTheme->FindIconHelper($context, $icon, $size);
161  }
162 
163  return NULL;
164  }
165 
166  function LookupIcon ($context, $iconname, $size)
167  {
168  if (!isset($this->subdirs[$context])) {
169  return NULL;
170  }
171  foreach ($this->subdirs[$context] as $path => &$subdir) {
172  if ($subdir->MatchesSize($size)) {
173  foreach (static::$extensions as $extension) {
174  $filename = $this->path . '/' . $path . '/' . $iconname . '.' . $extension;
175  if (file_exists($filename)) {
176  return $filename;
177  }
178  }
179  }
180  }
181  unset($subdir);
182  if (static::$find_closest) {
183  $minimal_size = PHP_INT_MAX;
184  foreach ($this->subdirs[$context] as $path => &$subdir) {
185  if (($sizedistance = $subdir->SizeDistance($size)) < $minimal_size) {
186  foreach (static::$extensions as $extension) {
187  $filename = $this->path . '/' . $path . '/' . $iconname . '.' . $extension;
188  if (file_exists($filename)) {
189  $closest_filename = $filename;
190  $minimal_size = $sizedistance;
191  }
192  }
193  }
194  }
195  unset($subdir);
196  if (isset($closest_filename)) {
197  return $closest_filename;
198  }
199  }
200  return NULL;
201  }
202 
203  static public $default_theme = 'breezy';
204  static public $extensions = ['png', 'xpm', 'svg'];
205  static public $find_closest = FALSE;
206 
207  /* We store themes in the session. To do otherwise, override these methods. */
208  static public $session_var = 'IconThemes';
209 
210  static public function loadThemes ($path)
211  {
212  $themes = [];
213  if ($dir = opendir("$path")) {
214  while (($file = readdir($dir)) !== FALSE) {
215  if (file_exists("$path/$file/index.theme") && !preg_match("/^\./", $file)) {
216  try {
217  if ($file == static::$default_theme) {
218  $themes[$file] = new IconTheme("$path/$file", NULL);
219  } else {
220  $themes[$file] = new IconTheme("$path/$file", static::$default_theme);
221  }
222  } catch (ThemeFileParsingException $e) {
223  continue;
224  }
225  }
226  }
227  }
228  $_SESSION[static::$session_var] = $themes;
229  }
230 
231  static public function findThemeIcon ($theme, $context, $icon, $size)
232  {
233  // We have to sanitize the $icon received from $_GET['icon']. Fixing vulnerability : CWE-35
234  if (!preg_match('/^[a-zA-Z0-9_\-]+$/', $icon)) {
235  trigger_error('Error: Wrong icon name received');
236  die('Error: wrong icon name received');
237  }
238  if (!isset($_SESSION[static::$session_var])) {
239  trigger_error('Error: no theme found in session');
240  die('Error: no theme found in session');
241  }
242  if (isset($_SESSION[static::$session_var][$theme])) {
243  return $_SESSION[static::$session_var][$theme]->FindIcon($context, $icon, $size);
244  }
245  return $_SESSION[static::$session_var][static::$default_theme]->FindIcon($context, $icon, $size);
246  }
247 
248  public function findTheme ($theme)
249  {
250  if (isset($_SESSION[static::$session_var][$theme])) {
251  return $_SESSION[static::$session_var][$theme];
252  }
253  return NULL;
254  }
255 
256  /* Fallback system */
257  static public $fallbacks = [
258  'types/user-group' => [
259  ['applications', 'system-users']
260  ],
261  'types/resource-group' => [
262  ['actions', 'resource-group']
263  ],
264  'types/user' => [
265  ['places', 'user-identity'],
266  ['status', 'avatar-default'],
267  ],
268  'types/contact' => [
269  ['mimetypes', 'x-office-contact'],
270  ],
271  'types/certificate' => [
272  ['mimetypes', 'stock_certificate'],
273  ['mimetypes', 'application-certificate'],
274  ['actions', 'view-certificate'],
275  ],
276  'applications/user-info' => [
277  ['actions', 'user-properties'],
278  ['types', 'contact'],
279  ['mimetypes', 'x-office-contact'],
280  ['types', 'user'],
281  ['places', 'user-identity'],
282  ['status', 'avatar-default'],
283  ],
284  'applications/office-calendar' => [
285  ['mimetypes', 'x-office-calendar'],
286  ],
287  'applications/os-linux' => [
288  ['applications', 'linux'],
289  ],
290  'applications/os-windows' => [
291  ['applications', 'windows'],
292  ],
293  'applications/samba' => [
294  ['applications', 'os-windows'],
295  ['applications', 'windows'],
296  ],
297  'applications/config-language' => [
298  ['applications', 'locale'],
299  ['applications', 'preferences-desktop-locale'],
300  ],
301  'mimetypes/text-csv' => [
302  ['mimetypes', 'x-office-spreadsheet'],
303  ['mimetypes', 'text-x-generic'],
304  ],
305  'mimetypes/application-pdf' => [
306  ['mimetypes', 'x-office-document'],
307  ],
308  'actions/application-exit' => [
309  ['actions', 'system-log-out'],
310  ],
311  'actions/archive' => [
312  ['mimetypes', 'application-x-archive'],
313  ],
314  'actions/document-export' => [
315  ['actions', 'document-send'],
316  ],
317  'actions/download' => [
318  ['actions', 'document-save'],
319  ],
320  'actions/document-restore' => [
321  ['actions', 'document-import'],
322  ['actions', 'document-open'],
323  ],
324  'actions/document-edit' => [
325  ['actions', 'edit'],
326  ['applications', 'text-editor'],
327  ['applications', 'accessories-text-editor'],
328  ['actions', 'document-open'],
329  ],
330  'actions/snapshot' => [
331  ['actions', 'document-save'],
332  ],
333  'actions/system-reboot' => [
334  ['actions', 'view-refresh'],
335  ],
336  'actions/system-update' => [
337  ['applications', 'system-software-update'],
338  ],
339  'actions/system-reinstall' => [
340  ['applications', 'system-installer'],
341  ],
342  'actions/task-start' => [
343  ['actions', 'media-playback-start'],
344  ],
345  'actions/task-stop' => [
346  ['actions', 'media-playback-stop'],
347  ],
348  'actions/task-schedule' => [
349  ['actions', 'chronometer'],
350  ['actions', 'smallclock'],
351  ],
352  'actions/up' => [
353  ['actions', 'go-up'],
354  ['actions', 'arrow-up'],
355  ],
356  'actions/upload' => [
357  ['actions', 'document-import'],
358  ['actions', 'up'],
359  ],
360  'actions/down' => [
361  ['actions', 'go-down'],
362  ['actions', 'arrow-down'],
363  ],
364  'actions/previous' => [
365  ['actions', 'go-previous'],
366  ['actions', 'arrow-left'],
367  ],
368  'actions/next' => [
369  ['actions', 'go-next'],
370  ['actions', 'arrow-right'],
371  ],
372  'actions/submit' => [
373  ['actions', 'go-jump'],
374  ],
375  'categories/settings' => [
376  ['categories', 'gnome-settings'],
377  ['categories', 'preferences-other'],
378  ['categories', 'preferences-system'],
379  ],
380  'categories/checks' => [
381  ['actions', 'view-task'],
382  ['actions', 'view-calendar-tasks'],
383  ['actions', 'checkbox'],
384  ['status', 'task-complete'],
385  ],
386  'devices/server' => [
387  ['places', 'server'],
388  ['places', 'network-server'],
389  ],
390  'devices/media-cdrom' => [
391  ['devices', 'media-optical'],
392  ],
393  'devices/terminal' => [
394  ['applications', 'utilities-terminal'],
395  ],
396  'devices/computer-windows' => [
397  ['applications', 'os-windows'],
398  ['applications', 'windows'],
399  ],
400  'devices/template' => [
401  ['actions', 'document-new'],
402  ],
403  'status/object-locked' => [
404  ['status', 'changes-prevent'],
405  ],
406  'status/object-unlocked' => [
407  ['status', 'changes-allow'],
408  ],
409  'status/task-waiting' => [
410  ['actions', 'task-schedule'],
411  ],
412  'places/folder-network' => [
413  ['places', 'folder-remote'],
414  ],
415  ];
416 }
Icon theme.
Icon theme directory.