Subversion Repositories oidplus

Rev

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

  1. <?php
  2.  
  3. /*
  4.  * OIDplus 2.0
  5.  * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
  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.  
  20. namespace ViaThinkSoft\OIDplus;
  21.  
  22. // phpcs:disable PSR1.Files.SideEffects
  23. \defined('INSIDE_OIDPLUS') or die;
  24. // phpcs:enable PSR1.Files.SideEffects
  25.  
  26. class OIDplusFourCC extends OIDplusObject {
  27.         /**
  28.          * @var string
  29.          */
  30.         private $fourcc;
  31.  
  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) {
  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,']');
  53.                                         $out[] = (int)substr($fourcc,1,$p-1);
  54.                                         $fourcc = substr($fourcc,$p+1);
  55.                                 }
  56.                         }
  57.                 }
  58.                 if ($fourcc !== '') return false;
  59.                 return $out;
  60.         }
  61.  
  62.         /**
  63.          * @param string $fourcc
  64.          */
  65.         public function __construct(string $fourcc) {
  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.  
  73.         /**
  74.          * @param string $node_id
  75.          * @return OIDplusFourCC|null
  76.          */
  77.         public static function parse(string $node_id)/*: ?OIDplusFourCC*/ {
  78.                 @list($namespace, $fourcc) = explode(':', $node_id, 2);
  79.                 if ($namespace !== self::ns()) return null;
  80.                 return new self($fourcc);
  81.         }
  82.  
  83.         /**
  84.          * @return string
  85.          */
  86.         public static function objectTypeTitle(): string {
  87.                 return _L('Four-Character-Code (FourCC)');
  88.         }
  89.  
  90.         /**
  91.          * @return string
  92.          */
  93.         public static function objectTypeTitleShort(): string {
  94.                 return _L('FourCC');
  95.         }
  96.  
  97.         /**
  98.          * @return string
  99.          */
  100.         public static function ns(): string {
  101.                 return 'fourcc';
  102.         }
  103.  
  104.         /**
  105.          * @return string
  106.          */
  107.         public static function root(): string {
  108.                 return self::ns().':';
  109.         }
  110.  
  111.         /**
  112.          * @return bool
  113.          */
  114.         public function isRoot(): bool {
  115.                 return $this->fourcc == '';
  116.         }
  117.  
  118.         /**
  119.          * @param bool $with_ns
  120.          * @return string
  121.          */
  122.         public function nodeId(bool $with_ns=true): string {
  123.                 return $with_ns ? self::root().$this->fourcc : $this->fourcc;
  124.         }
  125.  
  126.         /**
  127.          * @param string $str
  128.          * @return string
  129.          */
  130.         public function addString(string $str): string {
  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) {
  141.                         // real FourCC
  142.                         return self::root() . $test_str;
  143.                 } else {
  144.                         // just a category
  145.                         if ($this->isRoot()) {
  146.                                 return self::root() . $str;
  147.                         } else {
  148.                                 return $this->nodeId() . '/' . $str;
  149.                         }
  150.                 }
  151.         }
  152.  
  153.         /**
  154.          * @param OIDplusObject $parent
  155.          * @return string
  156.          */
  157.         public function crudShowId(OIDplusObject $parent): string {
  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.                 }
  168.         }
  169.  
  170.         /**
  171.          * @param OIDplusObject|null $parent
  172.          * @return string
  173.          */
  174.         public function jsTreeNodeName(OIDplusObject $parent = null): string {
  175.                 if ($parent == null) return $this->objectTypeTitle();
  176.                 return $this->crudShowId($parent);
  177.         }
  178.  
  179.         /**
  180.          * @return string
  181.          */
  182.         public function defaultTitle(): string {
  183.                 return $this->fourcc;
  184.         }
  185.  
  186.         /**
  187.          * @return bool
  188.          */
  189.         public function isLeafNode(): bool {
  190.                 return self::fourcc_transform($this->fourcc) !== false;
  191.         }
  192.  
  193.         /**
  194.          * @return array
  195.          */
  196.         private function getTechInfo(): array {
  197.                 $tech_info = array();
  198.                 $tech_info[_L('FourCC code')]   = $this->fourcc;
  199.                 $tech_info[_L('C/C++ Literal')] = $this->getMultiCharLiteral();
  200.                 $tech_info[_L('Hex Dump')]      = strtoupper(implode(' ', str_split($this->getHex(true),2)));
  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).')';
  203.                 return $tech_info;
  204.         }
  205.  
  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) {
  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()) {
  221.                                 $content  = '<p>'._L('Please select a FourCC in the tree view at the left to show its contents.').'</p>';
  222.                         } else {
  223.                                 $content  = '<p>'._L('Currently, no FourCC is registered in the system.').'</p>';
  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()) {
  258.                                         $content .= '<h2>'._L('Create or change subordinate objects / categories').'</h2>';
  259.                                 } else {
  260.                                         $content .= '<h2>'._L('Subordinate objects / categories').'</h2>';
  261.                                 }
  262.                                 $content .= '%%CRUD%%';
  263.                         }
  264.                 }
  265.         }
  266.  
  267.         /**
  268.          * @return OIDplusFourCC|null
  269.          */
  270.         public function one_up()/*: ?OIDplusFourCC*/ {
  271.                 // A FourCC is a FourCC, there is no hierarchy
  272.                 return null;
  273.         }
  274.  
  275.         /**
  276.          * @param OIDplusObject|string $to
  277.          * @return int|null
  278.          */
  279.         public function distance($to) {
  280.                 // Distance between FourCCs is not possible
  281.                 return null;
  282.         }
  283.  
  284.         /**
  285.          * @return array|OIDplusAltId[]
  286.          * @throws OIDplusException
  287.          */
  288.         public function getAltIds(): array {
  289.                 if ($this->isRoot()) return array();
  290.                 if (!$this->isLeafNode()) return array();
  291.                 return parent::getAltIds();
  292.         }
  293.  
  294.         /**
  295.          * @param bool $big_endian
  296.          * @return false|int
  297.          */
  298.         private function getInt(bool $big_endian) {
  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];
  304.                 return $dec;
  305.         }
  306.  
  307.         /**
  308.          * @param bool $big_endian
  309.          * @return string
  310.          */
  311.         private function getHex(bool $big_endian): string {
  312.                 $dec = $this->getInt($big_endian);
  313.                 return str_pad(dechex($dec), 8, "0", STR_PAD_LEFT);
  314.         }
  315.  
  316.         /**
  317.          * @return false|string
  318.          */
  319.         private function getMultiCharLiteral() {
  320.                 $type = self::fourcc_transform($this->fourcc);
  321.                 if ($type === false) return false;
  322.                 return c_literal($type);
  323.         }
  324.  
  325.         /**
  326.          * @return string
  327.          * @throws OIDplusException
  328.          */
  329.         public function getDirectoryName(): string {
  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.  
  340.         /**
  341.          * @param string $mode
  342.          * @return string
  343.          */
  344.         public static function treeIconFilename(string $mode): string {
  345.                 return 'img/'.$mode.'_icon16.png';
  346.         }
  347. }
  348.