WGet.NET 4.4.1
A WinGet wrapper library for .Net.
Loading...
Searching...
No Matches
ProcessOutputReader.cs
1//--------------------------------------------------//
2// Created by basicx-StrgV //
3// https://github.com/basicx-StrgV/ //
4//--------------------------------------------------//
5using System;
6using System.Collections.Generic;
7using System.Text;
10using WGetNET.Helper;
11using WGetNET.Models;
12
14{
19 internal static class ProcessOutputReader
20 {
21 //---To Package List------------------------------------------------------------------------------------------
38 public static List<WinGetPackage> ToPackageList(string[] output, PackageAction action = PackageAction.Default, string? sourceName = null)
39 {
40 //Get top line index.
41 //The array should always contain this line.
42 //If it dose not contain this line the resulting out of range exception,
43 //that will be thrown later, will be catched in the calling method.
44 int labelLine = output.GetEntryContains("------") - 1;
45
46 if (labelLine < 0)
47 {
48 // Output does not contain any entries
49 return new List<WinGetPackage>();
50 }
51
52 int[] columnList = GetColumnList(output[labelLine]);
53
54 //Remove unneeded output Lines
55 output = output.RemoveRange(0, labelLine + 2);
56
57 return CreatePackageListFromOutput(output, columnList, action, sourceName);
58 }
59
78 private static List<WinGetPackage> CreatePackageListFromOutput(string[] output, int[] columnList, PackageAction action = PackageAction.Default, string? sourceName = null)
79 {
80 List<WinGetPackage> resultList = new();
81
82 if (columnList.Length < 3)
83 {
84 return resultList;
85 }
86
87 WinGetPackageBuilder builder = new();
88
89 for (int i = 0; i < output.Length; i++)
90 {
91 builder.Clear();
92
93 // Stop parsing the output when the end of the list is reached.
94#if NETCOREAPP3_1_OR_GREATER
95 if (string.IsNullOrWhiteSpace(output[i]) || output[i].Length < columnList[^1])
96 {
97 break;
98 }
99#elif NETSTANDARD2_0
100 if (string.IsNullOrWhiteSpace(output[i]) || output[i].Length < columnList[columnList.Length - 1])
101 {
102 break;
103 }
104#endif
105
106#if NETCOREAPP3_1_OR_GREATER
107 builder.AddId(output[i][columnList[1]..columnList[2]].Trim());
108#elif NETSTANDARD2_0
109 builder.AddId(output[i].Substring(columnList[1], (columnList[2] - columnList[1])).Trim());
110#endif
111
112#if NETCOREAPP3_1_OR_GREATER
113 builder.AddName(output[i][columnList[0]..columnList[1]].Trim());
114#elif NETSTANDARD2_0
115 builder.AddName(output[i].Substring(columnList[0], (columnList[1] - columnList[0])).Trim());
116#endif
117
118 //Set version info depending on the column count.
119 if (columnList.Length > 3)
120 {
121#if NETCOREAPP3_1_OR_GREATER
122 builder.AddVersion(output[i][columnList[2]..columnList[3]].Trim());
123 builder.AddAvailableVersion(output[i][columnList[2]..columnList[3]].Trim());
124#elif NETSTANDARD2_0
125 builder.AddVersion(output[i].Substring(columnList[2], (columnList[3] - columnList[2])).Trim());
126 builder.AddAvailableVersion(output[i].Substring(columnList[2], (columnList[3] - columnList[2])).Trim());
127#endif
128 }
129 else
130 {
131#if NETCOREAPP3_1_OR_GREATER
132 builder.AddVersion(output[i][columnList[2]..].Trim());
133 builder.AddAvailableVersion(output[i][columnList[2]..].Trim());
134#elif NETSTANDARD2_0
135 builder.AddVersion(output[i].Substring(columnList[2]).Trim());
136 builder.AddAvailableVersion(output[i].Substring(columnList[2]).Trim());
137#endif
138 }
139
140 //Set information, depending on the action and the column count.
141 if ((action == PackageAction.UpgradeList || action == PackageAction.InstalledList || action == PackageAction.Search) && columnList.Length >= 5)
142 {
143#if NETCOREAPP3_1_OR_GREATER
144 string availableVersion = output[i][columnList[3]..columnList[4]].Trim();
145#elif NETSTANDARD2_0
146 string availableVersion = output[i].Substring(columnList[3], (columnList[4] - columnList[3])).Trim();
147#endif
148 if (!string.IsNullOrWhiteSpace(availableVersion) && action != PackageAction.Search)
149 {
150 builder.AddAvailableVersion(availableVersion);
151 }
152
153#if NETCOREAPP3_1_OR_GREATER
154 builder.AddSourceName(output[i][columnList[4]..].Trim());
155#elif NETSTANDARD2_0
156 builder.AddSourceName(output[i].Substring(columnList[4]).Trim());
157#endif
158 }
159 else if ((action == PackageAction.InstalledList || action == PackageAction.Search) && columnList.Length == 4)
160 {
161#if NETCOREAPP3_1_OR_GREATER
162 builder.AddSourceName(output[i][columnList[3]..].Trim());
163#elif NETSTANDARD2_0
164 builder.AddSourceName(output[i].Substring(columnList[3]).Trim());
165#endif
166 }
167 else if ((action == PackageAction.SearchBySource || action == PackageAction.InstalledListBySource)
168 && sourceName != null && !string.IsNullOrWhiteSpace(sourceName))
169 {
170 // "sourceName" source name cant't be null here because of the following check "!string.IsNullOrWhiteSpace(sourceName)".
171 // But .NET Standard 2.0 thinks it knows better (Or I'm stupid). Therefore a second null check comes befor it.
172 builder.AddSourceName(sourceName);
173 }
174
175 resultList.Add(builder.GetInstance());
176 }
177
178 // Check for secondery list in output.
179 if (output.GetEntryContains("------") != -1)
180 {
181 List<WinGetPackage> seconderyList = ToPackageList(output, action);
182 resultList.AddRange(seconderyList);
183 }
184
185 return resultList;
186 }
187 //------------------------------------------------------------------------------------------------------------
188
189 //---To Pinned Package List-----------------------------------------------------------------------------------
200 public static List<WinGetPinnedPackage> ToPinnedPackageList(string[] output)
201 {
202 //Get top line index.
203 //The array should always contain this line.
204 //If it dose not contain this line the resulting out of range exception,
205 //that will be thrown later, will be catched in the calling method.
206 int labelLine = output.GetEntryContains("------") - 1;
207
208 if (labelLine < 0)
209 {
210 // Output does not contain any entries
211 return new List<WinGetPinnedPackage>();
212 }
213
214 int[] columnList = GetColumnList(output[labelLine], true);
215
216 //Remove unneeded output Lines
217 output = output.RemoveRange(0, labelLine + 2);
218
219 return CreatePinnedPackageListFromOutput(output, columnList);
220 }
221
234 private static List<WinGetPinnedPackage> CreatePinnedPackageListFromOutput(string[] output, int[] columnList)
235 {
236 List<WinGetPinnedPackage> resultList = new();
237
238 if (columnList.Length < 3)
239 {
240 return resultList;
241 }
242
243 WinGetPinnedPackageBuilder builder = new();
244
245 for (int i = 0; i < output.Length; i++)
246 {
247 builder.Clear();
248
249 // Stop parsing the output when the end of the list is reached.
250#if NETCOREAPP3_1_OR_GREATER
251 if (string.IsNullOrWhiteSpace(output[i]) || output[i].Length < columnList[^1])
252 {
253 break;
254 }
255#elif NETSTANDARD2_0
256 if (string.IsNullOrWhiteSpace(output[i]) || output[i].Length < columnList[columnList.Length - 1])
257 {
258 break;
259 }
260#endif
261
262#if NETCOREAPP3_1_OR_GREATER
263 builder.AddName(output[i][columnList[0]..columnList[1]].Trim());
264 builder.AddId(output[i][columnList[1]..columnList[2]].Trim());
265 builder.AddVersion(output[i][columnList[2]..columnList[3]].Trim());
266 builder.AddSourceName(output[i][columnList[3]..columnList[4]].Trim());
267
268#elif NETSTANDARD2_0
269 builder.AddName(output[i].Substring(columnList[0], (columnList[1] - columnList[0])).Trim());
270 builder.AddId(output[i].Substring(columnList[1], (columnList[2] - columnList[1])).Trim());
271 builder.AddVersion(output[i].Substring(columnList[2], (columnList[3] - columnList[2])).Trim());
272 builder.AddSourceName(output[i].Substring(columnList[3], (columnList[4] - columnList[3])).Trim());
273#endif
274
275 // Workaround for getting the pin data from the output.
276 // The normal method will not work, because "Pin type" and "Pinned version" contain spaces.
277#if NETCOREAPP3_1_OR_GREATER
278 string pinInfoString = output[i][columnList[4]..].TrimStart();
279#elif NETSTANDARD2_0
280 string pinInfoString = output[i].Substring(columnList[4]).TrimStart();
281#endif
282 int endOfTypeIndex = -1;
283 for (int j = 0; j < pinInfoString.Length; j++)
284 {
285 if (pinInfoString[j] == (char)32)
286 {
287 endOfTypeIndex = j;
288 break;
289 }
290 }
291
292#if NETCOREAPP3_1_OR_GREATER
293 if (endOfTypeIndex == -1)
294 {
295 builder.AddPinType(pinInfoString.Trim());
296 }
297 else
298 {
299 builder.AddPinType(pinInfoString[0..endOfTypeIndex].Trim());
300 builder.AddPinnedVersion(pinInfoString[endOfTypeIndex..].Trim());
301 }
302#elif NETSTANDARD2_0
303 if (endOfTypeIndex == -1)
304 {
305 builder.AddPinType(pinInfoString.Trim());
306 }
307 else
308 {
309 builder.AddPinType(pinInfoString.Substring(0, endOfTypeIndex).Trim());
310 builder.AddPinnedVersion(pinInfoString.Substring(endOfTypeIndex));
311 }
312#endif
313 // End of workaround
314
315 resultList.Add(builder.GetInstance());
316 }
317
318 // Check for secondery list in output.
319 if (output.GetEntryContains("------") != -1)
320 {
321 List<WinGetPinnedPackage> seconderyList = ToPinnedPackageList(output);
322 resultList.AddRange(seconderyList);
323 }
324
325 return resultList;
326 }
327 //------------------------------------------------------------------------------------------------------------
328
329 //---To Source List-------------------------------------------------------------------------------------------
340 public static List<WinGetSource> ToSourceList(string[] output)
341 {
342 List<WinGetSource> sourceList = new();
343
344 for (int i = 0; i < output.Length; i++)
345 {
346 SourceModel? source =
347 JsonHelper.StringToObject<SourceModel>(output[i]);
348
349 if (source != null)
350 {
351 sourceList.Add(WinGetSource.FromSourceModel(source));
352 }
353 }
354
355 return sourceList;
356 }
357 //------------------------------------------------------------------------------------------------------------
358
359 //---To WinGet info-------------------------------------------------------------------------------------------
368 public static WinGetInfo ToWingetInfo(string[] output, InfoActionVersionId actionVersionId)
369 {
370 if (output.Length <= 0)
371 {
372 return WinGetInfo.Empty;
373 }
374
375 return ReadDataByRange(output, actionVersionId);
376 }
377
383 private static string ReadVersionFromData(string[] output)
384 {
385 string version = string.Empty;
386
387 string[] versionLineContent = output[0].Split((char)32);
388 for (int i = 0; i < versionLineContent.Length; i++)
389 {
390#if NETCOREAPP3_1_OR_GREATER
391 if (versionLineContent[i].Trim().StartsWith('v'))
392 {
393 version = versionLineContent[i].Trim()[1..];
394 break;
395 }
396#elif NETSTANDARD2_0
397 if (versionLineContent[i].Trim().StartsWith("v"))
398 {
399 version = versionLineContent[i].Trim().Substring(1);
400 break;
401 }
402#endif
403 }
404
405 return version;
406 }
407
416 private static WinGetInfo ReadDataByRange(string[] output, InfoActionVersionId actionVersionId)
417 {
418 return actionVersionId switch
419 {
420 InfoActionVersionId.VersionRange1 => ReadDataForRange1(output),
421 InfoActionVersionId.VersionRange2 => ReadDataForRange2(output),
422 InfoActionVersionId.VersionRange3 => ReadDataForRange3(output),
423 InfoActionVersionId.VersionRange4 => ReadDataForRange4(output),
424 _ => WinGetInfo.Empty,
425 };
426 }
427
435 private static WinGetInfo ReadDataForRange1(string[] output)
436 {
437 WinGetInfoBuilder builder = new();
438
439 string version = ReadVersionFromData(output);
440
441 if (string.IsNullOrWhiteSpace(version))
442 {
443 // Return if version number could not be determined, because the outupt is probably not correct.
444 return WinGetInfo.Empty;
445 }
446
447 builder.AddVersion(version);
448
449 // Logs directory
450 builder.AddDirectory(ReadSingleDirectoryEntry(output, 7));
451
452 // Remove unnasesary range from output
453 output = output.RemoveRange(0, 11);
454
455 builder.AddLinks(ReadLinks(output));
456
457 return builder.GetInstance();
458 }
459
467 private static WinGetInfo ReadDataForRange2(string[] output)
468 {
469 WinGetInfoBuilder builder = new();
470
471 string version = ReadVersionFromData(output);
472
473 if (string.IsNullOrWhiteSpace(version))
474 {
475 // Return if version number could not be determined, because the outupt is probably not correct.
476 return WinGetInfo.Empty;
477 }
478
479 builder.AddVersion(version);
480
481 // Logs directory
482 builder.AddDirectory(ReadSingleDirectoryEntry(output, 7));
483
484 // User Settings directory
485 builder.AddDirectory(ReadSingleDirectoryEntry(output, 9));
486
487 // Remove unnasesary range from output
488 output = output.RemoveRange(0, 13);
489
490 builder.AddLinks(ReadLinks(output));
491
492 return builder.GetInstance();
493 }
494
502 private static WinGetInfo ReadDataForRange3(string[] output)
503 {
504 WinGetInfoBuilder builder = new();
505
506 string version = ReadVersionFromData(output);
507
508 if (string.IsNullOrWhiteSpace(version))
509 {
510 // Return if version number could not be determined, because the outupt is probably not correct.
511 return WinGetInfo.Empty;
512 }
513
514 builder.AddVersion(version);
515
516 // Logs directory
517 builder.AddDirectory(ReadSingleDirectoryEntry(output, 7));
518
519 // User Settings directory
520 builder.AddDirectory(ReadSingleDirectoryEntry(output, 9));
521
522 // Remove unnasesary range from output
523 output = output.RemoveRange(0, 13);
524
525 builder.AddLinks(ReadLinks(output));
526
527 // Remove links area and admin settings header range from output
528 output = output.RemoveRange(0, output.GetEntryContains("----") + 1);
529
530 builder.AddAdminOptions(ReadAdminSettings(output));
531
532 return builder.GetInstance();
533 }
534
542 private static WinGetInfo ReadDataForRange4(string[] output)
543 {
544 WinGetInfoBuilder builder = new();
545
546 string version = ReadVersionFromData(output);
547
548 if (string.IsNullOrWhiteSpace(version))
549 {
550 // Return if version number could not be determined, because the outupt is probably not correct.
551 return WinGetInfo.Empty;
552 }
553
554 builder.AddVersion(version);
555
556 // Remove unnasesary range from output
557 output = output.RemoveRange(0, 9);
558
559 builder.AddDirectories(ReadDirectories(output));
560
561 // Remove directories area and links header range from output
562 output = output.RemoveRange(0, output.GetEntryContains("----") + 1);
563
564 builder.AddLinks(ReadLinks(output));
565
566 // Remove links area and admin settings header range from output
567 output = output.RemoveRange(0, output.GetEntryContains("----") + 1);
568
569 builder.AddAdminOptions(ReadAdminSettings(output));
570
571 return builder.GetInstance();
572 }
573
582 private static WinGetDirectory? ReadSingleDirectoryEntry(string[] output, int index)
583 {
584 string[] entry = output[index].Split(':');
585 if (entry.Length == 2)
586 {
587 WinGetDirectoryBuilder builder = new();
588
589 builder.AddEntryName(entry[0].Trim());
590 builder.AddRawContent(entry[1].Trim());
591
592 return builder.GetInstance();
593 }
594 return null;
595 }
596
607 private static List<WinGetDirectory> ReadDirectories(string[] output)
608 {
609 List<WinGetDirectory> directories = new();
610
611 StringBuilder nameBuilder = new();
612 StringBuilder contentBuilder = new();
613
614 WinGetDirectoryBuilder directoryBuilder = new();
615
616 for (int i = 0; i < output.Length; i++)
617 {
618 directoryBuilder.Clear();
619
620 if (string.IsNullOrWhiteSpace(output[i]))
621 {
622 break;
623 }
624
625 string[] directoryEntry = output[i].Split((char)32).RemoveEmptyEntries();
626
627 nameBuilder.Clear();
628 int startOfDirectory = 0;
629 for (int j = 0; j < directoryEntry.Length; j++)
630 {
631#if NETCOREAPP3_1_OR_GREATER
632 if (directoryEntry[j].StartsWith('%') || directoryEntry[j].Contains(":\\"))
633 {
634 // Start of the directory reached, stop building name.
635 startOfDirectory = j;
636 break;
637 }
638#elif NETSTANDARD2_0
639 if (directoryEntry[j].StartsWith("%") || directoryEntry[j].Contains(":\\"))
640 {
641 // Start of the directory reached, stop building name.
642 startOfDirectory = j;
643 break;
644 }
645#endif
646
647 if (j > 0)
648 {
649 // Add a space in front of every part of the name that comes after the first on.
650 nameBuilder.Append((char)32);
651 }
652
653 nameBuilder.Append(directoryEntry[j].Trim());
654 }
655
656 directoryBuilder.AddEntryName(nameBuilder.ToString());
657
658 directoryEntry = directoryEntry.RemoveRange(0, startOfDirectory);
659
660 contentBuilder.Clear();
661 for (int j = 0; j < directoryEntry.Length; j++)
662 {
663 if (j > 0)
664 {
665 // Add a space in front of every part of the directory that comes after the first on.
666 contentBuilder.Append((char)32);
667 }
668
669 contentBuilder.Append(directoryEntry[j].Trim());
670 }
671
672 directoryBuilder.AddRawContent(contentBuilder.ToString());
673
674 WinGetDirectory? winGetDirectory = directoryBuilder.GetInstance();
675 if (winGetDirectory != null)
676 {
677 directories.Add(winGetDirectory);
678 }
679 }
680
681 return directories;
682 }
683
694 private static List<WinGetLink> ReadLinks(string[] output)
695 {
696 List<WinGetLink> links = new();
697
698 StringBuilder nameBuilder = new();
699
700 WinGetLinkBuilder linkBuilder = new();
701
702 for (int i = 0; i < output.Length; i++)
703 {
704 linkBuilder.Clear();
705
706 if (string.IsNullOrWhiteSpace(output[i]))
707 {
708 break;
709 }
710
711 string[] linksEntry = output[i].Split((char)32).RemoveEmptyEntries();
712
713#if NETCOREAPP3_1_OR_GREATER
714 linkBuilder.AddRawContent(linksEntry[^1].Trim());
715#elif NETSTANDARD2_0
716 linkBuilder.AddRawContent(linksEntry[linksEntry.Length - 1].Trim());
717#endif
718
719 // Remove link from entry, so it only contains the name
720 linksEntry = linksEntry.RemoveRange(linksEntry.Length - 1, 1);
721
722 nameBuilder.Clear();
723 for (int j = 0; j < linksEntry.Length; j++)
724 {
725 if (j > 0)
726 {
727 // Add a space in front of every part of the name that comes after the first on.
728 nameBuilder.Append((char)32);
729 }
730 nameBuilder.Append(linksEntry[j].Trim());
731 }
732
733 linkBuilder.AddEntryName(nameBuilder.ToString());
734
735 WinGetLink? winGetLink = linkBuilder.GetInstance();
736 if (winGetLink != null)
737 {
738 links.Add(winGetLink);
739 }
740 }
741
742 return links;
743 }
744
755 private static List<WinGetAdminSetting> ReadAdminSettings(string[] output)
756 {
757 List<WinGetAdminSetting> adminSetting = new();
758
759 WinGetAdminSettingBuilder adminOptionBuilder = new();
760
761 for (int i = 0; i < output.Length; i++)
762 {
763 adminOptionBuilder.Clear();
764
765 if (string.IsNullOrWhiteSpace(output[i]))
766 {
767 break;
768 }
769
770 string[] settingsEntry = output[i].Split((char)32).RemoveEmptyEntries();
771
772 if (settingsEntry.Length == 2)
773 {
774 adminOptionBuilder.AddEntryName(settingsEntry[0].Trim());
775 adminOptionBuilder.AddRawContent(settingsEntry[1].Trim());
776
777 WinGetAdminSetting? adminOption = adminOptionBuilder.GetInstance();
778 if (adminOption != null)
779 {
780 adminSetting.Add(adminOption);
781 }
782 }
783 }
784
785 return adminSetting;
786 }
787 //------------------------------------------------------------------------------------------------------------
788
789 //---To Hash--------------------------------------------------------------------------------------------------
799 public static string ResultToHash(ProcessResult result)
800 {
801 string hash = "";
802
803#if NETCOREAPP3_1_OR_GREATER
804 if (result.Output.Length > 0 && result.Output[0].Contains(':'))
805 {
806 string[] splitOutput = result.Output[0].Split(':');
807 if (splitOutput.Length >= 2)
808 {
809 hash = splitOutput[1].Trim();
810 }
811 }
812#elif NETSTANDARD2_0
813 if (result.Output.Length > 0 && result.Output[0].Contains(":"))
814 {
815 string[] splitOutput = result.Output[0].Split(':');
816 if (splitOutput.Length >= 2)
817 {
818 hash = splitOutput[1].Trim();
819 }
820 }
821#endif
822
823 return hash;
824 }
825 //------------------------------------------------------------------------------------------------------------
826
827 //---Other----------------------------------------------------------------------------------------------------
837 public static string ExportOutputToString(ProcessResult result)
838 {
839 if (result.Success)
840 {
841 StringBuilder outputBuilder = new();
842 foreach (string line in result.Output)
843 {
844 outputBuilder.Append(line);
845 }
846
847 return outputBuilder.ToString().Trim();
848 }
849 else
850 {
851 return string.Empty;
852 }
853 }
854 //------------------------------------------------------------------------------------------------------------
855
856 //---Helper---------------------------------------------------------------------------------------------------
867 private static int[] GetColumnList(string line, bool isPinnedPackageTable = false)
868 {
869 int[] columns = Array.Empty<int>();
870
871 bool checkForColumn = true;
872 for (int i = 0; i < line.Length; i++)
873 {
874 if (isPinnedPackageTable && columns.Length >= 5)
875 {
876 // Workaround for the pinned package table
877 break;
878 }
879
880 if (line[i] != ((char)32) && checkForColumn)
881 {
882 columns = columns.Add(i);
883 checkForColumn = false;
884 }
885 else if (line[i] == ((char)32))
886 {
887 checkForColumn = true;
888 }
889 }
890
891 return columns;
892 }
893 //------------------------------------------------------------------------------------------------------------
894 }
895}
Represents a winget admin settings entry.
Represents a winget directory in the info set.
Represents winget related information.
Definition WinGetInfo.cs:15
Represents a winget link in the info set.
Definition WinGetLink.cs:14
Represents a winget source.