FOSSology  4.7.1
Open Source License Compliance by Open Source Software
common-multicompare.php
Go to the documentation of this file.
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2026 Siemens AG
4 
5  SPDX-License-Identifier: GPL-2.0-only
6 */
7 
17 function _mcIndexRemove(array &$idx, string $val, $key): void
18 {
19  if ($val === '' || !isset($idx[$val])) {
20  return;
21  }
22  $filtered = array_filter($idx[$val], function ($k) use ($key) {
23  return $k !== $key;
24  });
25  if (empty($filtered)) {
26  unset($idx[$val]);
27  } else {
28  $idx[$val] = array_values($filtered);
29  }
30 }
31 
37 function _mcFindBestMatch(array $child, array $pool,
38  array &$byName, array &$byFuzzyExt, array &$byFuzzy)
39 {
40  /* Stage 1: exact ufile_name */
41  $name = $child['ufile_name'];
42  if (isset($byName[$name])) {
43  foreach ($byName[$name] as $k) {
44  if (isset($pool[$k])) {
45  return $k;
46  }
47  }
48  }
49 
50  /* Stage 2: fuzzynameext */
51  $fe = $child['fuzzynameext'] ?? '';
52  if ($fe !== '' && isset($byFuzzyExt[$fe])) {
53  foreach ($byFuzzyExt[$fe] as $k) {
54  if (isset($pool[$k])) {
55  return $k;
56  }
57  }
58  }
59 
60  /* Stage 3: levenshtein == 1 on fuzzynameext (linear, but rare) */
61  if ($fe !== '') {
62  foreach ($pool as $k => $candidate) {
63  $cfe = $candidate['fuzzynameext'] ?? '';
64  if ($cfe !== '' && levenshtein($fe, $cfe) === 1) {
65  return $k;
66  }
67  }
68  }
69 
70  /* Stage 4: fuzzyname */
71  $f = $child['fuzzyname'] ?? '';
72  if ($f !== '' && isset($byFuzzy[$f])) {
73  foreach ($byFuzzy[$f] as $k) {
74  if (isset($pool[$k])) {
75  return $k;
76  }
77  }
78  }
79 
80  return null;
81 }
82 
83 
90 function MakeMasterN(array $ChildrenArrays): array
91 {
92  $N = count($ChildrenArrays);
93  if ($N < 2) {
94  return [];
95  }
96 
97  /* Build per-column hashmap indexes for O(1) name lookups */
98  $remaining = [];
99  $byName = [];
100  $byFuzzyExt = [];
101  $byFuzzy = [];
102 
103  foreach ($ChildrenArrays as $colIdx => $children) {
104  $remaining[$colIdx] = $children;
105  $byName[$colIdx] = [];
106  $byFuzzyExt[$colIdx] = [];
107  $byFuzzy[$colIdx] = [];
108  foreach ($children as $key => $child) {
109  $byName[$colIdx][$child['ufile_name']][] = $key;
110  $fe = $child['fuzzynameext'] ?? '';
111  if ($fe !== '') {
112  $byFuzzyExt[$colIdx][$fe][] = $key;
113  }
114  $f = $child['fuzzyname'] ?? '';
115  if ($f !== '') {
116  $byFuzzy[$colIdx][$f][] = $key;
117  }
118  }
119  }
120 
121  $masterRows = [];
122 
123  for ($anchor = 0; $anchor < $N; $anchor++) {
124  foreach ($remaining[$anchor] as $anchorKey => $anchorChild) {
125  $row = [$anchor => $anchorChild];
126  _mcIndexRemove($byName[$anchor], $anchorChild['ufile_name'], $anchorKey);
127  _mcIndexRemove($byFuzzyExt[$anchor], $anchorChild['fuzzynameext'] ?? '', $anchorKey);
128  _mcIndexRemove($byFuzzy[$anchor], $anchorChild['fuzzyname'] ?? '', $anchorKey);
129  unset($remaining[$anchor][$anchorKey]);
130 
131  for ($other = 0; $other < $N; $other++) {
132  if ($other === $anchor || isset($row[$other])) {
133  continue;
134  }
135  $matchKey = _mcFindBestMatch($anchorChild,
136  $remaining[$other],
137  $byName[$other], $byFuzzyExt[$other], $byFuzzy[$other]);
138  if ($matchKey !== null) {
139  $matched = $remaining[$other][$matchKey];
140  $row[$other] = $matched;
141  _mcIndexRemove($byName[$other], $matched['ufile_name'], $matchKey);
142  _mcIndexRemove($byFuzzyExt[$other], $matched['fuzzynameext'] ?? '', $matchKey);
143  _mcIndexRemove($byFuzzy[$other], $matched['fuzzyname'] ?? '', $matchKey);
144  unset($remaining[$other][$matchKey]);
145  }
146  }
147  $masterRows[] = $row;
148  }
149  }
150 
151  usort($masterRows, function (array $a, array $b): int {
152  $aChild = reset($a);
153  $bChild = reset($b);
154  $aName = $aChild['fuzzyname'] ?? $aChild['ufile_name'];
155  $bName = $bChild['fuzzyname'] ?? $bChild['ufile_name'];
156  return strcasecmp($aName, $bName);
157  });
158 
159  return $masterRows;
160 }
161 
162 
176 function GetDiffLinkN(array $MasterRow, int $colIdx, int $agentPk, string $filter,
177  string $pluginName, array $items, string $mode, int $baseline): string
178 {
179  global $Plugins;
180 
181  /* Resolve once per request; avoids repeated plugin registry lookups */
182  static $viewLicId = null;
183  if ($viewLicId === null) {
184  $viewLicId = plugin_find_id("view-license");
185  }
186  $ModLicView = ($viewLicId !== false && isset($Plugins[$viewLicId]))
187  ? $Plugins[$viewLicId] : null;
188 
189  $Child = $MasterRow[$colIdx];
190  $IsDir = Isdir($Child['ufile_mode']);
191  $IsContainer = Iscontainer($Child['ufile_mode']);
192 
193  $newItems = $items;
194  $newItems[$colIdx] = $Child['uploadtree_pk'];
195 
196  foreach ($items as $c => $parentPk) {
197  if ($c === $colIdx) {
198  continue;
199  }
200  if (isset($MasterRow[$c]) && !empty($MasterRow[$c]['uploadtree_pk'])) {
201  $newItems[$c] = $MasterRow[$c]['uploadtree_pk'];
202  }
203  }
204 
205  $LinkUri = null;
206  if (!empty($Child['pfile_fk']) && !empty($ModLicView)) {
207  $LinkUri = Traceback_uri();
208  $LinkUri .= "?mod=view-license&napk=$agentPk&upload=$Child[upload_fk]&item=$Child[uploadtree_pk]";
209  }
210 
211  $LicUri = null;
212  if ($IsContainer) {
213  $LicUri = "?mod=$pluginName&items=" . implode(",", $newItems);
214  $LicUri .= "&col=$colIdx&filter=" . urlencode($filter);
215  $LicUri .= "&mode=" . urlencode($mode);
216  $LicUri .= "&baseline=$baseline";
217  }
218 
219  $parts = [];
220  if ($IsContainer && $LicUri) {
221  $parts[] = "<a href='$LicUri'><b>";
222  } elseif ($LinkUri) {
223  $parts[] = "<a href='$LinkUri'>";
224  }
225 
226  $parts[] = htmlspecialchars($Child['ufile_name']);
227  if ($IsDir) {
228  $parts[] = "/";
229  }
230 
231  if ($IsContainer && $LicUri) {
232  $parts[] = "</b></a>";
233  } elseif ($LinkUri) {
234  $parts[] = "</a>";
235  }
236 
237  return implode("", $parts);
238 }
239 
240 
252 function FileListN(array &$Master, array $agentPks, string $filter, string $pluginName,
253  array $items, string $mode, int $baseline): void
254 {
255  foreach ($Master as &$row) {
256  foreach ($row as $colIdx => &$child) {
257  if (empty($child)) {
258  continue;
259  }
260  $agentPk = $agentPks[$colIdx] ?? 0;
261  $child['linkurl'] = GetDiffLinkN($row, $colIdx, $agentPk, $filter,
262  $pluginName, $items, $mode, $baseline);
263  }
264  unset($child);
265  }
266  unset($row);
267 }
268 
269 
282 function Dir2BrowseDiffN(array $path, string $filter, int $colIdx, string $pluginName,
283  array $items, string $mode, int $baseline): string
284 {
285  static $folderCache = [];
286 
287  if (empty($path)) {
288  return "<div class='card card-body p-1 bg-light'><em>No path</em></div>";
289  }
290 
291  $Last = $path[count($path) - 1];
292  $Uri2 = Traceback_uri() . "?mod=$pluginName";
293  $baseQS = "&filter=" . urlencode($filter) . "&mode=" . urlencode($mode)
294  . "&baseline=$baseline";
295 
296  $FreezeText = _("Freeze");
297  $freezeBtnId = "Freeze$colIdx";
298  $freezeOpts = "id='$freezeBtnId' onclick='Freeze($colIdx)'"
299  . " class='btn btn-outline-secondary'"
300  . " style='font-size:0.65rem;padding:1px 5px;line-height:1.3;white-space:nowrap;flex-shrink:0'";
301 
302  $uploadFk = $path[0]['upload_fk'];
303  if (!isset($folderCache[$uploadFk])) {
304  $folderCache[$uploadFk] = FolderGetFromUpload($uploadFk);
305  }
306  $FolderList = $folderCache[$uploadFk];
307 
308  $parts = [];
309  $parts[] = "<div class='card card-body p-1 bg-light'>";
310  $parts[] = "<div class='d-flex justify-content-between align-items-start'>";
311  $parts[] = "<div>";
312  $parts[] = "<strong>" . _("Folder") . ":</strong> ";
313  foreach ($FolderList as $Folder) {
314  $parts[] = "<b>" . htmlspecialchars($Folder['folder_name']) . "/</b>";
315  }
316  $parts[] = "<br>";
317 
318  /* Single-line path: parent/parent/<b>current</b> */
319  foreach ($path as $idx => $PathElt) {
320  $itemsForLink = $items;
321  $itemsForLink[$colIdx] = $PathElt['uploadtree_pk'];
322  $href = $Uri2 . "&items=" . implode(",", $itemsForLink) . "&col=$colIdx$baseQS";
323  $isLast = ($PathElt['uploadtree_pk'] == $Last['uploadtree_pk']);
324  if ($idx > 0) {
325  $parts[] = "/";
326  }
327  if ($isLast) {
328  $parts[] = "<b>" . htmlspecialchars($PathElt['ufile_name']) . "</b>";
329  } else {
330  $parts[] = "<a href='" . htmlspecialchars($href) . "'>"
331  . htmlspecialchars($PathElt['ufile_name']) . "</a>";
332  }
333  }
334 
335  $parts[] = "</div>";
336  $parts[] = "<button type='button' $freezeOpts>$FreezeText</button>";
337  $parts[] = "</div>";
338  $parts[] = "</div>";
339  return implode("", $parts);
340 }
Isdir($mode)
Definition: common-dir.php:20
Iscontainer($mode)
Definition: common-dir.php:38
FolderGetFromUpload($Uploadpk, $Folder=-1, $Stop=-1)
DEPRECATED! Given an upload number, return the folder path in an array containing folder_pk and name.
_mcFindBestMatch(array $child, array $pool, array &$byName, array &$byFuzzyExt, array &$byFuzzy)
Hashmap-accelerated best-match (O(1) for stages 1, 2, 4; O(M) only for rare stage 3).
_mcIndexRemove(array &$idx, string $val, $key)
Remove one key from a name-index bucket list (used by MakeMasterN).
GetDiffLinkN(array $MasterRow, int $colIdx, int $agentPk, string $filter, string $pluginName, array $items, string $mode, int $baseline)
Generate the navigation link for one cell in the multi-component table.
Dir2BrowseDiffN(array $path, string $filter, int $colIdx, string $pluginName, array $items, string $mode, int $baseline)
Render the folder/path breadcrumb banner for one column.
MakeMasterN(array $ChildrenArrays)
Build the master array for N file lists using hashmap-based O(M·N) matching.
FileListN(array &$Master, array $agentPks, string $filter, string $pluginName, array $items, string $mode, int $baseline)
Attach linkurl to every cell in Master (N-way version of FileList()).
Traceback_uri()
Get the URI without query to this location.
Definition: common-parm.php:97