8 namespace Fossology\ReportImport;
12 use EasyRdf\RdfNamespace;
18 require_once
'ReportImportData.php';
19 require_once
'ReportImportDataItem.php';
20 require_once
'ImportSource.php';
24 const TERMS =
'https://spdx.org/rdf/3.0.0/terms#';
25 const SPDX_URL =
'http://spdx.org/licenses/';
26 const SPDX_FILE =
'spdx:File';
37 function __construct($filename, $uri =
null)
39 $this->filename = $filename;
48 RdfNamespace::set(
'spdx', self::TERMS);
49 $this->graph = $this->loadGraph($this->filename, $this->uri);
50 $this->spdxDoc = $this->getSpdxDoc();
51 return $this->graph !==
null && $this->spdxDoc !==
null;
60 private function loadGraph($filename, $uri =
null)
65 $graph->parseFile($filename,
'rdfxml', $uri);
67 $graph->parseFile($filename,
'turtle', $uri);
69 $graph->parseFile($filename,
'guess', $uri);
75 private function getSpdxDoc()
77 $docs = $this->graph->allOfType(
"spdx:SpdxDocument");
78 if (count($docs) == 1) {
81 error_log(
"ERROR: Expected exactly one SPDX document, found " . count($docs));
91 $files = $this->graph->allOfType(
"spdx:File");
93 foreach ($files as $file) {
94 $fileIds[$file->getUri()] =
trim($file->getLiteral(
"spdx:name")->getValue());
105 $fileNode = $this->graph->resource($fileId, self::SPDX_FILE);
106 if ($fileNode->getLiteral(
"spdx:name") ==
null) {
110 $algoKeyPrefix = self::TERMS .
'checksumAlgorithm_';
112 $checksums = $fileNode->getResource(
"spdx:verifiedUsing");
113 $algorithm = $checksums->allResources(
"spdx:algorithm");
114 $value = $checksums->allLiterals(
"spdx:hashValue");
115 for ($i=0;$i<count($algorithm);$i++){
117 $algo = substr($algorithm[$i]->getUri(), strlen($algoKeyPrefix));
119 $algo = $algorithm[$i]->getUri();
121 $hashes[$algo] =
trim($value[$i]);
153 $licenses = $this->graph->allOfType(
"spdx:$kind");
155 foreach ($licenses as $license) {
156 $spdxIds = $license->allResources(
'spdx:spdxId');
157 foreach ($spdxIds as $spdxId)
158 if ($spdxId == $fileId) {
159 if (!$this->isNotNoassertion($license->getUri())) {
163 foreach ($innerOutput as $innerItem) {
164 $output[] = $innerItem;
171 private function isNotNoassertion($str)
173 return !(strtolower($str) === self::TERMS .
"NoAssertionLicense" ||
174 strtolower($str) ===
"http://spdx.org/licenses/NoAssertionLicense");
188 if (is_string($license)) {
189 return $this->parseLicenseId($license);
190 } elseif ($license->isA(
'spdx:expandedlicensing_CustomLicense') ||
191 $license->isA(
'spdx:expandedlicensing_ListedLicense') ||
192 $license->isA(
'spdx:Annotation')){
194 } elseif ($license->isA(
'spdx:expandedlicensing_DisjunctiveLicenseSet') ||
195 $license->isA(
'spdx:expandedlicensing_ConjunctiveLicenseSet')) {
196 return $this->handleLicenseSet($license);
198 if ($license instanceof Resource || $license instanceof Graph) {
199 return $this->parseLicenseId($license->getUri());
201 error_log(
"ERROR: can not handle license=[" . $license .
"] of class=[" .
202 get_class($license) .
"]");
207 private function parseLicenseId($licenseId)
209 if (!is_string($licenseId)) {
210 error_log(
"ERROR: Id not a string: " . $licenseId);
213 if (!$this->isNotNoassertion($licenseId)) {
218 $spdxId = urldecode(substr($licenseId, strlen(self::SPDX_URL)));
219 $item =
new ReportImportDataItem($spdxId);
222 error_log(
"ERROR: can not handle license with ID=" . $licenseId);
236 if ($license->isA(
'spdx:expandedlicensing_CustomLicense')) {
237 $licenseIdLiteral = $license->getLiteral(
"spdx:spdxId");
239 $licenseIdLiteral = $license->getUri();
241 $licenseNameLiteral = $license->getLiteral(
"spdx:name");
242 $licenseTextLiteral = $license->getLiteral(
"spdx:simplelicensing_licenseText");
243 if ($licenseIdLiteral !=
null && $licenseNameLiteral !=
null &&
244 $licenseTextLiteral !=
null) {
245 $seeAlsoLiteral = $license->getLiteral(
"spdx:expandedlicensing_seeAlso");
246 $rawLicenseId = $licenseIdLiteral->getValue();
247 $licenseId = $this->stripLicenseRefPrefix($rawLicenseId);
249 if ($license->isA(
'spdx:expandedlicensing_CustomLicense') &&
250 (strlen($licenseId) > 33 &&
251 substr($licenseId, -33, 1) ===
"-" &&
252 ctype_alnum(substr($licenseId, -32))
254 $licenseId = substr($licenseId, 0, -33);
256 $item->setCustomText($licenseTextLiteral->getValue());
259 $item->setLicenseCandidate($licenseNameLiteral->getValue(),
260 $licenseTextLiteral->getValue(),
261 strpos($rawLicenseId, LicenseRef::SPDXREF_PREFIX),
262 ($seeAlsoLiteral !=
null) ? $seeAlsoLiteral->getValue() :
""
270 private function stripLicenseRefPrefix($licenseId)
274 return urldecode(substr($licenseId, strlen(LicenseRef::SPDXREF_PREFIX_FOSSOLOGY)));
276 return urldecode(substr($licenseId, strlen(LicenseRef::SPDXREF_PREFIX)));
278 return urldecode($licenseId);
282 private function handleLicenseSet($license)
285 $subLicenses = $license->allResources(
"spdx:expandedlicensing_member");
286 if (
sizeof($subLicenses) > 1 && $license->isA(
'spdx:expandedlicensing_DisjunctiveLicenseSet')) {
287 $output[] =
new ReportImportDataItem(
"Dual-license");
289 foreach ($subLicenses as $subLicense) {
291 $output = array_merge($output, $innerOutput);
311 $fileNode = $this->graph->resource($fileId, self::SPDX_FILE);
313 $copyrights = $fileNode->allLiterals(
"spdx:software_copyrightText");
314 if (count($copyrights) == 1 && $copyrights[0] instanceof Literal) {
315 # There should be only 1 copyright element containing 1 copyright per line
316 $copyrights = explode(
"\n",
trim($copyrights[0]->getValue()));
317 return array_map(
'trim', $copyrights);
319 # There is only 1 copyright literal or noAssertion resource
static stringEndsWith($haystack, $needle)
static stringStartsWith($haystack, $needle)
getLicenseInfoInFileForFile($propertyId)
handleLicenseInfo($license)
getCopyrightTextsForFile($fileId)
getLicenseInfoForFile($fileId, $kind)
getConcludedLicenseInfoForFile($propertyId)
char * trim(char *ptext)
Trimming whitespace.