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 
24 function NormalizeMultiCompareRoot(int $selectedItem, array $children): int
25 {
26  if (count($children) !== 1) {
27  return $selectedItem;
28  }
29 
30  $child = reset($children);
31  if (empty($child['uploadtree_pk']) ||
32  !isset($child['ufile_mode']) ||
33  !Isdir($child['ufile_mode'])) {
34  return $selectedItem;
35  }
36 
37  return intval($child['uploadtree_pk']);
38 }
39 
40 
44 function _mcIndexRemove(array &$idx, string $val, $key): void
45 {
46  if ($val === '' || !isset($idx[$val])) {
47  return;
48  }
49  $filtered = array_filter($idx[$val], function ($k) use ($key) {
50  return $k !== $key;
51  });
52  if (empty($filtered)) {
53  unset($idx[$val]);
54  } else {
55  $idx[$val] = array_values($filtered);
56  }
57 }
58 
64 function _mcFindBestMatch(array $child, array $pool,
65  array &$byName, array &$byFuzzyExt, array &$byFuzzy)
66 {
67  /* Stage 1: exact ufile_name */
68  $name = $child['ufile_name'];
69  if (isset($byName[$name])) {
70  foreach ($byName[$name] as $k) {
71  if (isset($pool[$k])) {
72  return $k;
73  }
74  }
75  }
76 
77  /* Stage 2: fuzzynameext */
78  $fe = $child['fuzzynameext'] ?? '';
79  if ($fe !== '' && isset($byFuzzyExt[$fe])) {
80  foreach ($byFuzzyExt[$fe] as $k) {
81  if (isset($pool[$k])) {
82  return $k;
83  }
84  }
85  }
86 
87  /* Stage 3: levenshtein == 1 on fuzzynameext (linear, but rare) */
88  if ($fe !== '') {
89  foreach ($pool as $k => $candidate) {
90  $cfe = $candidate['fuzzynameext'] ?? '';
91  if ($cfe !== '' && levenshtein($fe, $cfe) === 1) {
92  return $k;
93  }
94  }
95  }
96 
97  /* Stage 4: fuzzyname */
98  $f = $child['fuzzyname'] ?? '';
99  if ($f !== '' && isset($byFuzzy[$f])) {
100  foreach ($byFuzzy[$f] as $k) {
101  if (isset($pool[$k])) {
102  return $k;
103  }
104  }
105  }
106 
107  return null;
108 }
109 
110 
117 function MakeMasterN(array $ChildrenArrays): array
118 {
119  $N = count($ChildrenArrays);
120  if ($N < 2) {
121  return [];
122  }
123 
124  /* Build per-column hashmap indexes for O(1) name lookups */
125  $remaining = [];
126  $byName = [];
127  $byFuzzyExt = [];
128  $byFuzzy = [];
129 
130  foreach ($ChildrenArrays as $colIdx => $children) {
131  $remaining[$colIdx] = $children;
132  $byName[$colIdx] = [];
133  $byFuzzyExt[$colIdx] = [];
134  $byFuzzy[$colIdx] = [];
135  foreach ($children as $key => $child) {
136  $byName[$colIdx][$child['ufile_name']][] = $key;
137  $fe = $child['fuzzynameext'] ?? '';
138  if ($fe !== '') {
139  $byFuzzyExt[$colIdx][$fe][] = $key;
140  }
141  $f = $child['fuzzyname'] ?? '';
142  if ($f !== '') {
143  $byFuzzy[$colIdx][$f][] = $key;
144  }
145  }
146  }
147 
148  $masterRows = [];
149 
150  for ($anchor = 0; $anchor < $N; $anchor++) {
151  foreach ($remaining[$anchor] as $anchorKey => $anchorChild) {
152  $row = [$anchor => $anchorChild];
153  _mcIndexRemove($byName[$anchor], $anchorChild['ufile_name'], $anchorKey);
154  _mcIndexRemove($byFuzzyExt[$anchor], $anchorChild['fuzzynameext'] ?? '', $anchorKey);
155  _mcIndexRemove($byFuzzy[$anchor], $anchorChild['fuzzyname'] ?? '', $anchorKey);
156  unset($remaining[$anchor][$anchorKey]);
157 
158  for ($other = 0; $other < $N; $other++) {
159  if ($other === $anchor || isset($row[$other])) {
160  continue;
161  }
162  $matchKey = _mcFindBestMatch($anchorChild,
163  $remaining[$other],
164  $byName[$other], $byFuzzyExt[$other], $byFuzzy[$other]);
165  if ($matchKey !== null) {
166  $matched = $remaining[$other][$matchKey];
167  $row[$other] = $matched;
168  _mcIndexRemove($byName[$other], $matched['ufile_name'], $matchKey);
169  _mcIndexRemove($byFuzzyExt[$other], $matched['fuzzynameext'] ?? '', $matchKey);
170  _mcIndexRemove($byFuzzy[$other], $matched['fuzzyname'] ?? '', $matchKey);
171  unset($remaining[$other][$matchKey]);
172  }
173  }
174  $masterRows[] = $row;
175  }
176  }
177 
178  usort($masterRows, function (array $a, array $b): int {
179  $aChild = reset($a);
180  $bChild = reset($b);
181  $aName = $aChild['fuzzyname'] ?? $aChild['ufile_name'];
182  $bName = $bChild['fuzzyname'] ?? $bChild['ufile_name'];
183  return strcasecmp($aName, $bName);
184  });
185 
186  return $masterRows;
187 }
188 
189 
203 function GetDiffLinkN(array $MasterRow, int $colIdx, int $agentPk, string $filter,
204  string $pluginName, array $items, string $mode, int $baseline): string
205 {
206  global $Plugins;
207 
208  /* Resolve once per request; avoids repeated plugin registry lookups */
209  static $viewLicId = null;
210  if ($viewLicId === null) {
211  $viewLicId = plugin_find_id("view-license");
212  }
213  $ModLicView = ($viewLicId !== false && isset($Plugins[$viewLicId]))
214  ? $Plugins[$viewLicId] : null;
215 
216  $Child = $MasterRow[$colIdx];
217  $IsDir = Isdir($Child['ufile_mode']);
218  $IsContainer = Iscontainer($Child['ufile_mode']);
219 
220  $newItems = $items;
221  $newItems[$colIdx] = $Child['uploadtree_pk'];
222 
223  foreach ($items as $c => $parentPk) {
224  if ($c === $colIdx) {
225  continue;
226  }
227  if (isset($MasterRow[$c]) && !empty($MasterRow[$c]['uploadtree_pk'])) {
228  $newItems[$c] = $MasterRow[$c]['uploadtree_pk'];
229  }
230  }
231 
232  $LinkUri = null;
233  if (!empty($Child['pfile_fk']) && !empty($ModLicView)) {
234  $LinkUri = Traceback_uri();
235  $LinkUri .= "?mod=view-license&napk=$agentPk&upload=$Child[upload_fk]&item=$Child[uploadtree_pk]";
236  }
237 
238  $LicUri = null;
239  if ($IsContainer) {
240  $LicUri = "?mod=$pluginName&items=" . implode(",", $newItems);
241  $LicUri .= "&col=$colIdx&filter=" . urlencode($filter);
242  $LicUri .= "&mode=" . urlencode($mode);
243  $LicUri .= "&baseline=$baseline";
244  }
245 
246  $parts = [];
247  if ($IsContainer && $LicUri) {
248  $parts[] = "<a href='$LicUri'><b>";
249  } elseif ($LinkUri) {
250  $parts[] = "<a href='$LinkUri'>";
251  }
252 
253  $parts[] = htmlspecialchars($Child['ufile_name']);
254  if ($IsDir) {
255  $parts[] = "/";
256  }
257 
258  if ($IsContainer && $LicUri) {
259  $parts[] = "</b></a>";
260  } elseif ($LinkUri) {
261  $parts[] = "</a>";
262  }
263 
264  return implode("", $parts);
265 }
266 
267 
279 function FileListN(array &$Master, array $agentPks, string $filter, string $pluginName,
280  array $items, string $mode, int $baseline): void
281 {
282  foreach ($Master as &$row) {
283  foreach ($row as $colIdx => &$child) {
284  if (empty($child)) {
285  continue;
286  }
287  $agentPk = $agentPks[$colIdx] ?? 0;
288  $child['linkurl'] = GetDiffLinkN($row, $colIdx, $agentPk, $filter,
289  $pluginName, $items, $mode, $baseline);
290  }
291  unset($child);
292  }
293  unset($row);
294 }
295 
296 
309 function Dir2BrowseDiffN(array $path, string $filter, int $colIdx, string $pluginName,
310  array $items, string $mode, int $baseline): string
311 {
312  static $folderCache = [];
313 
314  if (empty($path)) {
315  return "<div class='card card-body p-1 bg-light'><em>No path</em></div>";
316  }
317 
318  $Last = $path[count($path) - 1];
319  $Uri2 = Traceback_uri() . "?mod=$pluginName";
320  $baseQS = "&filter=" . urlencode($filter) . "&mode=" . urlencode($mode)
321  . "&baseline=$baseline";
322 
323  $FreezeText = _("Freeze");
324  $freezeBtnId = "Freeze$colIdx";
325  $freezeOpts = "id='$freezeBtnId' onclick='Freeze($colIdx)'"
326  . " class='btn btn-outline-secondary'"
327  . " style='font-size:0.65rem;padding:1px 5px;line-height:1.3;white-space:nowrap;flex-shrink:0'";
328 
329  $uploadFk = $path[0]['upload_fk'];
330  if (!isset($folderCache[$uploadFk])) {
331  $folderCache[$uploadFk] = FolderGetFromUpload($uploadFk);
332  }
333  $FolderList = $folderCache[$uploadFk];
334 
335  $parts = [];
336  $parts[] = "<div class='card card-body p-1 bg-light'>";
337  $parts[] = "<div class='d-flex justify-content-between align-items-start'>";
338  $parts[] = "<div>";
339  $parts[] = "<strong>" . _("Folder") . ":</strong> ";
340  foreach ($FolderList as $Folder) {
341  $parts[] = "<b>" . htmlspecialchars($Folder['folder_name']) . "/</b>";
342  }
343  $parts[] = "<br>";
344 
345  /* Single-line path: parent/parent/<b>current</b> */
346  foreach ($path as $idx => $PathElt) {
347  $itemsForLink = $items;
348  $itemsForLink[$colIdx] = $PathElt['uploadtree_pk'];
349  $href = $Uri2 . "&items=" . implode(",", $itemsForLink) . "&col=$colIdx$baseQS";
350  $isLast = ($PathElt['uploadtree_pk'] == $Last['uploadtree_pk']);
351  if ($idx > 0) {
352  $parts[] = "/";
353  }
354  if ($isLast) {
355  $parts[] = "<b>" . htmlspecialchars($PathElt['ufile_name']) . "</b>";
356  } else {
357  $parts[] = "<a href='" . htmlspecialchars($href) . "'>"
358  . htmlspecialchars($PathElt['ufile_name']) . "</a>";
359  }
360  }
361 
362  $parts[] = "</div>";
363  $parts[] = "<button type='button' $freezeOpts>$FreezeText</button>";
364  $parts[] = "</div>";
365  $parts[] = "</div>";
366  return implode("", $parts);
367 }
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.
NormalizeMultiCompareRoot(int $selectedItem, array $children)
Select the effective comparison root for a tree item.
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