FOSSology  3.2.0rc1
Open Source License Compliance by Open Source Software
SpdxTwoImportSource.php
1 <?php
2 /*
3  * Copyright (C) 2015-2017, Siemens AG
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 namespace Fossology\ReportImport;
19 
21 use EasyRdf_Graph;
22 require_once 'ReportImportData.php';
23 require_once 'ReportImportDataItem.php';
24 require_once 'ImportSource.php';
25 
27 {
28  const TERMS = 'http://spdx.org/rdf/terms#';
29  const SPDX_URL = 'http://spdx.org/licenses/';
30  const SYNTAX_NS = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
31 
33  private $filename;
35  private $uri;
37  private $graph;
39  private $index;
41  private $licenseRefPrefix = "LicenseRef-";
42 
43  function __construct($filename, $uri = null)
44  {
45  $this->filename = $filename;
46  $this->uri = $uri;
47  }
48 
52  public function parse()
53  {
54  $this->graph = $this->loadGraph($this->filename, $this->uri);
55  $this->index = $this->loadIndex($this->graph);
56  return true;
57  }
58 
59  private function loadGraph($filename, $uri = null)
60  {
62  $graph = new EasyRdf_Graph();
63  $graph->parseFile($filename, 'rdfxml', $uri);
64  return $graph;
65  }
66 
67  private function loadIndex($graph)
68  {
69  return $graph->toRdfPhp();
70  }
71 
75  public function getAllFiles()
76  {
77  $fileIds = array();
78  foreach ($this->index as $subject => $property){
79  if ($this->isPropertyAFile($property))
80  {
81  $fileIds[$subject] = $this->getFileName($property);
82  }
83  }
84  return $fileIds;
85  }
86 
92  private function isPropertyOfType(&$property, $type)
93  {
94  $key = self::SYNTAX_NS . 'type';
95  $target = self::TERMS . $type;
96 
97  return is_array ($property) &&
98  array_key_exists($key, $property) &&
99  sizeof($property[$key]) === 1 &&
100  $property[$key][0]['type'] === "uri" &&
101  $property[$key][0]['value'] === $target;
102  }
103 
108  private function isPropertyAFile(&$property)
109  {
110  return $this->isPropertyOfType($property, 'File');
111  }
112 
117  public function getHashesMap($fileid)
118  {
119  if ($this->isPropertyAFile($property))
120  {
121  return array();
122  }
123 
124  $hashItems = $this->getValues($fileid, 'checksum');
125 
126  $hashes = array();
127  $keyAlgo = self::TERMS . 'algorithm';
128  $algoKeyPrefix = self::TERMS . 'checksumAlgorithm_';
129  $keyAlgoVal = self::TERMS . 'checksumValue';
130  foreach ($hashItems as $hashItem)
131  {
132  $algorithm = $hashItem[$keyAlgo][0]['value'];
133  if(substr($algorithm, 0, strlen($algoKeyPrefix)) === $algoKeyPrefix)
134  {
135  $algorithm = substr($algorithm, strlen($algoKeyPrefix));
136  }
137  $hashes[$algorithm] = $hashItem[$keyAlgoVal][0]['value'];
138  }
139 
140  return $hashes;
141  }
142 
149  private function getValue($propertyOrId, $key, $default=null)
150  {
151  $values = $this->getValues($propertyOrId, $key);
152  if(sizeof($values) === 1)
153  {
154  return $values[0];
155  }
156  return $default;
157  }
158 
164  private function getValues($propertyOrId, $key)
165  {
166  if (is_string($propertyOrId))
167  {
168  $property = $this->index[$propertyOrId];
169  }
170  else
171  {
172  $property = $propertyOrId;
173  }
174 
175  $key = self::TERMS . $key;
176  if (is_array($property) && isset($property[$key]))
177  {
178  $values = array();
179  foreach($property[$key] as $entry)
180  {
181  if($entry['type'] === 'literal')
182  {
183  $values[] = $entry['value'];
184  }
185  elseif($entry['type'] === 'uri')
186  {
187  if(array_key_exists($entry['value'],$this->index))
188  {
189  $values[$entry['value']] = $this->index[$entry['value']];
190  }
191  else
192  {
193  $values[] = $entry['value'];
194  }
195  }
196  elseif($entry['type'] === 'bnode')
197  {
198  $values[$entry['value']] = $this->index[$entry['value']];
199  }
200  else
201  {
202  error_log("ERROR: can not handle entry=[".$entry."] of type=[" . $entry['type'] . "]");
203  }
204  }
205  return $values;
206  }
207  return array();
208  }
209 
214  private function getFileName($propertyOrId)
215  {
216  return $this->getValue($propertyOrId, 'fileName');
217  }
218 
223  public function getConcludedLicenseInfoForFile($propertyId)
224  {
225  return $this->getLicenseInfoForFile($propertyId, 'licenseConcluded');
226  }
227 
232  public function getLicenseInfoInFileForFile($propertyId)
233  {
234  return $this->getLicenseInfoForFile($propertyId, 'licenseInfoInFile');
235  }
236 
237  private function stripLicenseRefPrefix($licenseId)
238  {
239  if(substr($licenseId, 0, strlen($this->licenseRefPrefix)) === $this->licenseRefPrefix)
240  {
241  return urldecode(substr($licenseId, strlen($this->licenseRefPrefix)));
242  }
243  else
244  {
245  return urldecode($licenseId);
246  }
247  }
248 
249  private function isNotNoassertion($str)
250  {
251  return ! ( strtolower($str) === self::TERMS."noassertion" ||
252  strtolower($str) === "http://spdx.org/licenses/noassertion" );
253  }
254 
255  private function parseLicenseId($licenseId)
256  {
257  if (!is_string($licenseId))
258  {
259  error_log("ERROR: Id not a string: ".$licenseId);
260  return array();
261  }
262  if (strtolower($licenseId) === self::TERMS."noassertion" ||
263  strtolower($licenseId) === "http://spdx.org/licenses/noassertion")
264  {
265  return array();
266  }
267 
268  $license = $this->index[$licenseId];
269 
270  if ($license)
271  {
272  return $this->parseLicense($license);
273  }
274  elseif(substr($licenseId, 0, strlen(self::SPDX_URL)) === self::SPDX_URL)
275  {
276  $spdxId = urldecode(substr($licenseId, strlen(self::SPDX_URL)));
277  $item = new ReportImportDataItem($spdxId);
278  return array($item);
279  }
280  else
281  {
282  error_log("ERROR: can not handle license with ID=".$licenseId);
283  return array();
284  }
285  }
286 
287  private function parseLicense($license)
288  {
289  if (is_string($license))
290  {
291  return $this->parseLicenseId($license);
292  }
293  elseif ($this->isPropertyOfType($license, 'ExtractedLicensingInfo'))
294  {
295  $licenseId = $this->stripLicenseRefPrefix($this->getValue($license,'licenseId'));
296 
297  if(strlen($licenseId) > 33 &&
298  substr($licenseId, -33, 1) === "-" &&
299  ctype_alnum(substr($licenseId, -32)))
300  {
301  $licenseId = substr($licenseId, 0, -33);
302  $item = new ReportImportDataItem($licenseId);
303  $item->setCustomText($this->getValue($license,'extractedText'));
304  return array($item);
305 
306  }
307  else
308  {
309  $item = new ReportImportDataItem($licenseId);
310  $item->setLicenseCandidate($this->getValue($license,'name', $licenseId),
311  $this->getValue($license,'extractedText'),
312  strpos($this->getValue($license,'licenseId'), $this->licenseRefPrefix));
313  return array($item);
314  }
315  }
316  elseif ($this->isPropertyOfType($license, 'License'))
317  {
318  $licenseId = $this->stripLicenseRefPrefix($this->getValue($license,'licenseId'));
319  $item = new ReportImportDataItem($licenseId);
320  $item->setLicenseCandidate($this->getValue($license,'name', $licenseId),
321  $this->getValue($license,'licenseText'),
322  strpos($this->getValue($license,'licenseId'), $this->licenseRefPrefix));
323  return array($item);
324  }
325  elseif ($this->isPropertyOfType($license, 'DisjunctiveLicenseSet') ||
326  $this->isPropertyOfType($license, 'ConjunctiveLicenseSet')
327  )
328  {
329  $output = array();
330  $subLicenses = $this->getValues($license, 'member');
331  if (sizeof($subLicenses) > 1 &&
332  $this->isPropertyOfType($license, 'DisjunctiveLicenseSet'))
333  {
334  $output[] = new ReportImportDataItem("Dual-license");
335  }
336  foreach($subLicenses as $subLicense)
337  {
338  $innerOutput = $this->parseLicense($subLicense);
339  foreach($innerOutput as $innerItem)
340  {
341  $output[] = $innerItem;
342  }
343  }
344  return $output;
345  }
346  elseif ($this->isPropertyOfType($license, 'OrLaterOperator'))
347  {
348  $output = array();
349  $subLicenses = $this->getValues($license, 'member');
350  foreach($subLicenses as $subLicense) {
352  $innerOutput = $this->parseLicense($subLicense);
353  foreach($innerOutput as $innerItem)
354  {
356  $item = new ReportImportDataItem($innerItem->getLicenseId() . "+");
357 
358  $innerLicenseCandidate = $innerItem->getLicenseCandidate();
359  $item->setLicenseCandidate($innerLicenseCandidate->getFullName() . " or later",
360  $innerLicenseCandidate->getText(),
361  false);
362  $output[] = $item;
363  }
364  }
365  return $output;
366  }
367  else
368  {
369  error_log("ERROR: can not handle license=[".$license."] of type=[".gettype($license)."]");
370  return array();
371  }
372  }
373 
379  private function getLicenseInfoForFile($propertyId, $kind)
380  {
381  $property = $this->index[$propertyId];
382  $licenses = $this->getValues($property, $kind);
383 
384  $output = array();
385  foreach ($licenses as $license)
386  {
387  $innerOutput = $this->parseLicense($license);
388  foreach($innerOutput as $innerItem)
389  {
390  $output[] = $innerItem;
391  }
392  }
393  return $output;
394  }
395 
396  private function getCopyrightTextsForFile($propertyId)
397  {
398  return array_filter(
399  array_map(
400  'trim',
401  $this->getValues($propertyId, "copyrightText")) ,
402  array($this, "isNotNoassertion"));
403  }
404 
405  public function getDataForFile($propertyId)
406  {
407  return new ReportImportData($this->getLicenseInfoInFileForFile($propertyId),
408  $this->getConcludedLicenseInfoForFile($propertyId),
409  $this->getCopyrightTextsForFile($propertyId));
410  }
411 }
getValue($propertyOrId, $key, $default=null)