Subversion Repositories oidplus

Rev

Rev 1124 | Rev 1271 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
844 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
1086 daniel-mar 5
 * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
844 daniel-mar 6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
1050 daniel-mar 20
namespace ViaThinkSoft\OIDplus;
844 daniel-mar 21
 
1086 daniel-mar 22
// phpcs:disable PSR1.Files.SideEffects
23
\defined('INSIDE_OIDPLUS') or die;
24
// phpcs:enable PSR1.Files.SideEffects
25
 
844 daniel-mar 26
class OIDplusFourCC extends OIDplusObject {
1130 daniel-mar 27
        /**
28
         * @var string
29
         */
844 daniel-mar 30
        private $fourcc;
31
 
1116 daniel-mar 32
        /**
33
         * FourCC Syntax examples:
34
         * fourcc_transform('8BIM')       === array(56,66,73,77);   // Adobe Photoshop
35
         * fourcc_transform('AVI')        === array(65,86,73,32);   // AVI File (padded with whitespace)
36
         * fourcc_transform('Y3[10][10]') === array(89,51,10,10);   // 10bit Y'CbCr 4:2:2 video
37
         * Non-FourCC:  fourcc_transform returns false.
38
         * @param string $fourcc
39
         * @return array|false
40
         */
41
        private function fourcc_transform(string $fourcc) {
844 daniel-mar 42
                $out = array();
43
                if ($fourcc === '') return false;
44
                for ($i=0; $i<4; $i++) {
45
                        if (strlen($fourcc) === 0) {
46
                                $out[] = 0x20; // fill with whitespace
47
                        } else {
48
                                if ($fourcc[0] !== '[') {
49
                                        $out[] = ord($fourcc[0]);
50
                                        $fourcc = substr($fourcc,1);
51
                                } else {
52
                                        $p = strpos($fourcc,']');
926 daniel-mar 53
                                        $out[] = (int)substr($fourcc,1,$p-1);
844 daniel-mar 54
                                        $fourcc = substr($fourcc,$p+1);
55
                                }
56
                        }
57
                }
58
                if ($fourcc !== '') return false;
59
                return $out;
60
        }
61
 
1116 daniel-mar 62
        /**
1130 daniel-mar 63
         * @param string $fourcc
1116 daniel-mar 64
         */
1130 daniel-mar 65
        public function __construct(string $fourcc) {
844 daniel-mar 66
                if (self::fourcc_transform($fourcc) !== false) {
67
                        $this->fourcc = $fourcc; // leaf node
68
                } else {
69
                        $this->fourcc = $fourcc; // It is a category name
70
                }
71
        }
72
 
1116 daniel-mar 73
        /**
74
         * @param string $node_id
75
         * @return OIDplusFourCC|null
76
         */
77
        public static function parse(string $node_id)/*: ?OIDplusFourCC*/ {
844 daniel-mar 78
                @list($namespace, $fourcc) = explode(':', $node_id, 2);
1116 daniel-mar 79
                if ($namespace !== self::ns()) return null;
844 daniel-mar 80
                return new self($fourcc);
81
        }
82
 
1116 daniel-mar 83
        /**
84
         * @return string
85
         */
86
        public static function objectTypeTitle(): string {
844 daniel-mar 87
                return _L('Four-Character-Code (FourCC)');
88
        }
89
 
1116 daniel-mar 90
        /**
91
         * @return string
92
         */
93
        public static function objectTypeTitleShort(): string {
844 daniel-mar 94
                return _L('FourCC');
95
        }
96
 
1116 daniel-mar 97
        /**
98
         * @return string
99
         */
100
        public static function ns(): string {
844 daniel-mar 101
                return 'fourcc';
102
        }
103
 
1116 daniel-mar 104
        /**
105
         * @return string
106
         */
107
        public static function root(): string {
860 daniel-mar 108
                return self::ns().':';
844 daniel-mar 109
        }
110
 
1116 daniel-mar 111
        /**
112
         * @return bool
113
         */
114
        public function isRoot(): bool {
844 daniel-mar 115
                return $this->fourcc == '';
116
        }
117
 
1116 daniel-mar 118
        /**
119
         * @param bool $with_ns
120
         * @return string
121
         */
122
        public function nodeId(bool $with_ns=true): string {
859 daniel-mar 123
                return $with_ns ? self::root().$this->fourcc : $this->fourcc;
844 daniel-mar 124
        }
125
 
1116 daniel-mar 126
        /**
127
         * @param string $str
128
         * @return string
129
         */
130
        public function addString(string $str): string {
845 daniel-mar 131
 
132
                // Y3[10] [10] --> Y3[10][10]
133
                $test_str = trim($str);
134
                do {
135
                        $test_str2 = $test_str;
136
                        $test_str = str_replace(' [', '[', $test_str);
137
                        $test_str = str_replace('] ', ']', $test_str);
138
                } while ($test_str2 != $test_str);
139
 
140
                if (self::fourcc_transform($test_str) !== false) {
844 daniel-mar 141
                        // real FourCC
858 daniel-mar 142
                        return self::root() . $test_str;
844 daniel-mar 143
                } else {
144
                        // just a category
858 daniel-mar 145
                        if ($this->isRoot()) {
146
                                return self::root() . $str;
147
                        } else {
148
                                return $this->nodeId() . '/' . $str;
149
                        }
844 daniel-mar 150
                }
151
        }
152
 
1116 daniel-mar 153
        /**
154
         * @param OIDplusObject $parent
155
         * @return string
156
         */
157
        public function crudShowId(OIDplusObject $parent): string {
850 daniel-mar 158
                if ($this->isLeafNode()) {
159
                        // We don't parse '/' in a valid FourCC code (i.e. Leaf node)
160
                        return $this->nodeId(false);
161
                } else {
162
                        if ($parent->isRoot()) {
163
                                return substr($this->nodeId(), strlen($parent->nodeId()));
164
                        } else {
165
                                return substr($this->nodeId(), strlen($parent->nodeId())+1);
166
                        }
167
                }
844 daniel-mar 168
        }
169
 
1116 daniel-mar 170
        /**
171
         * @param OIDplusObject|null $parent
172
         * @return string
173
         */
174
        public function jsTreeNodeName(OIDplusObject $parent = null): string {
844 daniel-mar 175
                if ($parent == null) return $this->objectTypeTitle();
176
                return $this->crudShowId($parent);
177
        }
178
 
1116 daniel-mar 179
        /**
180
         * @return string
181
         */
182
        public function defaultTitle(): string {
844 daniel-mar 183
                return $this->fourcc;
184
        }
185
 
1116 daniel-mar 186
        /**
187
         * @return bool
188
         */
189
        public function isLeafNode(): bool {
844 daniel-mar 190
                return self::fourcc_transform($this->fourcc) !== false;
191
        }
192
 
1116 daniel-mar 193
        /**
194
         * @return array
195
         */
196
        private function getTechInfo(): array {
844 daniel-mar 197
                $tech_info = array();
845 daniel-mar 198
                $tech_info[_L('FourCC code')]   = $this->fourcc;
199
                $tech_info[_L('C/C++ Literal')] = $this->getMultiCharLiteral();
844 daniel-mar 200
                $tech_info[_L('Hex Dump')]      = strtoupper(implode(' ', str_split($this->getHex(true),2)));
1054 daniel-mar 201
                $tech_info[_L('Big Endian')]    = '0x'.$this->getHex(true).' ('.$this->getInt(true).')';
202
                $tech_info[_L('Little Endian')] = '0x'.$this->getHex(false).' ('.$this->getInt(false).')';
844 daniel-mar 203
                return $tech_info;
204
        }
205
 
1116 daniel-mar 206
        /**
207
         * @param string $title
208
         * @param string $content
209
         * @param string $icon
210
         * @return void
211
         * @throws OIDplusException
212
         */
213
        public function getContentPage(string &$title, string &$content, string &$icon) {
844 daniel-mar 214
                $icon = file_exists(__DIR__.'/img/main_icon.png') ? OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon.png' : '';
215
 
216
                if ($this->isRoot()) {
217
                        $title = OIDplusFourCC::objectTypeTitle();
218
 
219
                        $res = OIDplus::db()->query("select * from ###objects where parent = ?", array(self::root()));
220
                        if ($res->any()) {
962 daniel-mar 221
                                $content  = '<p>'._L('Please select a FourCC in the tree view at the left to show its contents.').'</p>';
844 daniel-mar 222
                        } else {
962 daniel-mar 223
                                $content  = '<p>'._L('Currently, no FourCC is registered in the system.').'</p>';
844 daniel-mar 224
                        }
225
 
226
                        if (!$this->isLeafNode()) {
227
                                if (OIDplus::authUtils()->isAdminLoggedIn()) {
228
                                        $content .= '<h2>'._L('Manage root objects / categories').'</h2>';
229
                                } else {
230
                                        $content .= '<h2>'._L('Available objects / categories').'</h2>';
231
                                }
232
                                $content .= '%%CRUD%%';
233
                        }
234
                } else {
235
                        $title = $this->getTitle();
236
 
237
                        if ($this->isLeafNode()) {
238
                                $tech_info = $this->getTechInfo();
239
                                $tech_info_html = '';
240
                                if (count($tech_info) > 0) {
241
                                        $tech_info_html .= '<h2>'._L('Technical information').'</h2>';
242
                                        $tech_info_html .= '<table border="0">';
243
                                        foreach ($tech_info as $key => $value) {
244
                                                $tech_info_html .= '<tr><td>'.$key.': </td><td><code>'.str_replace(' ','&nbsp;',$value).'</code></td></tr>';
245
                                        }
246
                                        $tech_info_html .= '</table>';
247
                                }
248
 
249
                                $content = $tech_info_html;
250
                        } else {
251
                                $content = '';
252
                        }
253
 
254
                        $content .= '<h2>'._L('Description').'</h2>%%DESC%%';
255
 
256
                        if (!$this->isLeafNode()) {
257
                                if ($this->userHasWriteRights()) {
928 daniel-mar 258
                                        $content .= '<h2>'._L('Create or change subordinate objects / categories').'</h2>';
844 daniel-mar 259
                                } else {
928 daniel-mar 260
                                        $content .= '<h2>'._L('Subordinate objects / categories').'</h2>';
844 daniel-mar 261
                                }
262
                                $content .= '%%CRUD%%';
263
                        }
264
                }
265
        }
266
 
1116 daniel-mar 267
        /**
268
         * @return OIDplusFourCC|null
269
         */
270
        public function one_up()/*: ?OIDplusFourCC*/ {
844 daniel-mar 271
                // A FourCC is a FourCC, there is no hierarchy
1116 daniel-mar 272
                return null;
844 daniel-mar 273
        }
274
 
1116 daniel-mar 275
        /**
1130 daniel-mar 276
         * @param OIDplusObject|string $to
277
         * @return int|null
1116 daniel-mar 278
         */
844 daniel-mar 279
        public function distance($to) {
280
                // Distance between FourCCs is not possible
281
                return null;
282
        }
283
 
1116 daniel-mar 284
        /**
285
         * @return array|OIDplusAltId[]
286
         * @throws OIDplusException
287
         */
288
        public function getAltIds(): array {
844 daniel-mar 289
                if ($this->isRoot()) return array();
290
                if (!$this->isLeafNode()) return array();
1130 daniel-mar 291
                return parent::getAltIds();
844 daniel-mar 292
        }
293
 
1116 daniel-mar 294
        /**
1130 daniel-mar 295
         * @param bool $big_endian
296
         * @return false|int
1116 daniel-mar 297
         */
1130 daniel-mar 298
        private function getInt(bool $big_endian) {
844 daniel-mar 299
                $type = self::fourcc_transform($this->fourcc);
300
                if ($type === false) return false;
301
                $dec = 0;
302
                if (!$big_endian) $type = array_reverse($type);
303
                for ($i=0;$i<4;$i++) $dec = ($dec<<8) + $type[$i];
1054 daniel-mar 304
                return $dec;
305
        }
306
 
1116 daniel-mar 307
        /**
1130 daniel-mar 308
         * @param bool $big_endian
1116 daniel-mar 309
         * @return string
310
         */
1130 daniel-mar 311
        private function getHex(bool $big_endian): string {
1054 daniel-mar 312
                $dec = $this->getInt($big_endian);
1130 daniel-mar 313
                return str_pad(dechex($dec), 8, "0", STR_PAD_LEFT);
844 daniel-mar 314
        }
315
 
1116 daniel-mar 316
        /**
317
         * @return false|string
318
         */
845 daniel-mar 319
        private function getMultiCharLiteral() {
844 daniel-mar 320
                $type = self::fourcc_transform($this->fourcc);
321
                if ($type === false) return false;
926 daniel-mar 322
                return c_literal($type);
844 daniel-mar 323
        }
324
 
1116 daniel-mar 325
        /**
326
         * @return string
327
         * @throws OIDplusException
328
         */
329
        public function getDirectoryName(): string {
844 daniel-mar 330
                if ($this->isLeafNode()) {
331
                        // Leaf (FourCC)
332
                        // Example output: "fourcc_23496d52" for 'fourcc:#ImR'
333
                        return $this->ns().'_'.$this->getHex(true);
334
                } else {
335
                        // Category
336
                        return parent::getDirectoryName();
337
                }
338
        }
339
 
1116 daniel-mar 340
        /**
341
         * @param string $mode
342
         * @return string
343
         */
344
        public static function treeIconFilename(string $mode): string {
844 daniel-mar 345
                return 'img/'.$mode.'_icon16.png';
346
        }
850 daniel-mar 347
}