Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public TestableValidatorLogViewModel(
UploadingProgressPercentageProvider uploadingProgressPercentageProvider,
ErrorModelProvider errorModelProvider,
string xmlContent)
: base(packageModelProvider, uploaderService, windowService, uploadingProgressPercentageProvider, errorModelProvider)
: base(packageModelProvider, uploaderService, windowService, uploadingProgressPercentageProvider, errorModelProvider, new PathConfigurationProvider())
{
_xmlContent = xmlContent;
TestSubValFilePath = Path.GetTempFileName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public TestableUploaderConfigViewModel(
IWindowService windowService,
UploadingProgressPercentageProvider uploadingProgressPercentageProvider,
ErrorModelProvider errorModelProvider)
: base(packageModelProvider, uploaderService, windowService, uploadingProgressPercentageProvider, errorModelProvider)
: base(packageModelProvider, uploaderService, windowService, uploadingProgressPercentageProvider, errorModelProvider, new PathConfigurationProvider())
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ public void Setup()
_mockPackageUploaderService.Object,
_mockWindowService.Object,
_uploadingProgressPercentageProvider,
_errorModelProvider
_errorModelProvider,
new PathConfigurationProvider()
);
}

Expand All @@ -87,8 +88,9 @@ public void Test_BranchOrFlightDisplayName()
_mockPackageUploaderService.Object,
_mockWindowService.Object,
_uploadingProgressPercentageProvider,
_errorModelProvider
);
_errorModelProvider,
new PathConfigurationProvider()
);
viewModel2.BranchOrFlightDisplayName = "Test";
Assert.AreEqual("Test", viewModel2.BranchOrFlightDisplayName);
}
Expand Down Expand Up @@ -124,7 +126,8 @@ public void Test_BranchAndFlightNames()
_mockPackageUploaderService.Object,
_mockWindowService.Object,
_uploadingProgressPercentageProvider,
_errorModelProvider
_errorModelProvider,
new PathConfigurationProvider()
);

viewModel2.BranchAndFlightNames = names; // tests the former value is successfully retrieved
Expand All @@ -146,7 +149,8 @@ public void Test_MarketGroupNames()
_mockPackageUploaderService.Object,
_mockWindowService.Object,
_uploadingProgressPercentageProvider,
_errorModelProvider
_errorModelProvider,
new PathConfigurationProvider()
);

viewModel2.MarketGroupNames = names; // tests the former value is successfully retrieved
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public TestablePackageUploadViewModel(
IWindowService windowService,
UploadingProgressPercentageProvider uploadingProgressPercentageProvider,
ErrorModelProvider errorModelProvider)
: base(packageModelProvider, uploaderService, windowService, uploadingProgressPercentageProvider, errorModelProvider)
: base(packageModelProvider, uploaderService, windowService, uploadingProgressPercentageProvider, errorModelProvider, new PathConfigurationProvider())
{
}

Expand Down
78 changes: 78 additions & 0 deletions src/PackageUploader.UI/Model/Xvc/XvcFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,84 @@ private static UInt32 NumberOfHashPagesForLevel(UInt64 dataPages, Int32 level)
return (UInt32)((dataPages + divisor - 1) / divisor);
}

private static readonly byte[] ZipLocalFileSignature = [0x50, 0x4B, 0x03, 0x04];
private static readonly byte[] ZipEocdSignature = [0x50, 0x4B, 0x05, 0x06];
private const int FirstReadSize = 4096;
private const int LastReadSize = 65 * 1024;
private const int MinFileNameOffset = 30;

/// <summary>
/// Detects whether a .msixvc file is in MSIXVC2 format by checking for ZIP signatures.
/// MSIXVC2 packages are ZIP-based and contain standard ZIP headers, while MSIXVC1
/// packages use a proprietary binary format without ZIP signatures.
/// </summary>
public static bool IsLikelyMsixvc2Package(string packagePath)
{
try
{
if (!packagePath.EndsWith(".msixvc", StringComparison.OrdinalIgnoreCase))
return false;

var fileInfo = new FileInfo(packagePath);
if (!fileInfo.Exists || fileInfo.Length < FirstReadSize)
return false;

using var stream = File.OpenRead(packagePath);

// Check first bytes for ZIP local file header at offset 0
var firstBuffer = new byte[Math.Min(FirstReadSize, fileInfo.Length)];
stream.ReadExactly(firstBuffer, 0, firstBuffer.Length);

if (firstBuffer.Length >= MinFileNameOffset &&
firstBuffer[0] == ZipLocalFileSignature[0] &&
firstBuffer[1] == ZipLocalFileSignature[1] &&
firstBuffer[2] == ZipLocalFileSignature[2] &&
firstBuffer[3] == ZipLocalFileSignature[3])
{
return true;
}

// Check last 65KB for ZIP End of Central Directory signature
long lastChunkStart = Math.Max(0, fileInfo.Length - LastReadSize);
int lastChunkSize = (int)(fileInfo.Length - lastChunkStart);
var lastBuffer = new byte[lastChunkSize];
stream.Position = lastChunkStart;
stream.ReadExactly(lastBuffer, 0, lastChunkSize);

if (LastIndexOfSignature(lastBuffer, ZipEocdSignature) >= 0)
return true;

return false;
}
catch (Exception)
{
return false;
}
}

private static int LastIndexOfSignature(byte[] buffer, byte[] signature)
{
if (buffer.Length < signature.Length)
return -1;

for (int i = buffer.Length - signature.Length; i >= 0; i--)
{
bool match = true;
for (int j = 0; j < signature.Length; j++)
{
if (buffer[i + j] != signature[j])
{
match = false;
break;
}
}
if (match)
return i;
}

return -1;
}

public static void GetBuildAndKeyId(string packagePath, out Guid buildId, out Guid keyId)
{
using FileStream stream = File.OpenRead(packagePath);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
72 changes: 58 additions & 14 deletions src/PackageUploader.UI/View/PackageUploadView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -178,22 +178,31 @@
Height="32"
Margin="0,0,0,10"/>

<StackPanel Grid.Row="4"
<StackPanel Grid.Row="4"
Grid.Column="0"
Margin="0, 5, 0, 0"
Orientation="Horizontal"
HorizontalAlignment="Left"
Visibility="{Binding PackageErrorMessage, Converter={StaticResource StringNotEmptyToVisibilityConverter}}">
<Image Source="/Resources/AppIcon/ErrorIcon.png"
<Image Source="/Resources/AppIcon/ErrorIcon.png"
Width="16"
Height="16"
VerticalAlignment="Top"
Margin="0,0,5,0"/>
<TextBlock Text="{Binding PackageErrorMessage}"
<TextBlock Text="{Binding PackageErrorMessage}"
Foreground="{DynamicResource PrimaryTextBrush}"
HorizontalAlignment="Left"
TextWrapping="Wrap"/>
</StackPanel>
</StackPanel>
<TextBlock Grid.Row="4"
Grid.Column="0"
Margin="0, 5, 0, 0"
Text="{Binding Msixvc2InfoMessage}"
Foreground="{DynamicResource SecondaryTextBrush}"
HorizontalAlignment="Left"
TextWrapping="Wrap"
Visibility="{Binding Msixvc2InfoMessage, Converter={StaticResource StringNotEmptyToVisibilityConverter}}"/>

</Grid>
<Expander Style="{StaticResource CustomExpanderStyle}" Margin="0,10,0,20">
<Expander.Header>
Expand Down Expand Up @@ -496,7 +505,12 @@
<StackPanel Grid.Column="0" Orientation="Vertical" HorizontalAlignment="Left">
<TextBlock Text="{x:Static strings:PackageUpload.DestinationTitleText}"
d:Text="Branch"
Foreground="{DynamicResource SecondaryTextBrush}"/>
Foreground="{DynamicResource SecondaryTextBrush}"
Visibility="{Binding IsMsixvc2Package, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=Invert}"/>
<TextBlock Text="{x:Static strings:Msixvc2Upload.DestinationTitleText}"
d:Text="Destination"
Foreground="{DynamicResource SecondaryTextBrush}"
Visibility="{Binding IsMsixvc2Package, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<TextBlock Text="{Binding BranchOrFlightDisplayName}"
Foreground="{DynamicResource PrimaryTextBrush}"/>
</StackPanel>
Expand All @@ -511,22 +525,36 @@
<!-- Destination / Market — compact mode: stacked -->
<StackPanel Grid.Row="1" Grid.Column="1" Margin="0,0,0,4"
Visibility="{Binding IsCompactMode, Converter={StaticResource BooleanToVisibilityConverter}}">
<TextBlock Text="{x:Static strings:PackageUpload.DestinationTitleText}" Foreground="{DynamicResource SecondaryTextBrush}"/>
<TextBlock Text="{x:Static strings:PackageUpload.DestinationTitleText}" Foreground="{DynamicResource SecondaryTextBrush}"
Visibility="{Binding IsMsixvc2Package, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=Invert}"/>
<TextBlock Text="{x:Static strings:Msixvc2Upload.DestinationTitleText}" Foreground="{DynamicResource SecondaryTextBrush}"
Visibility="{Binding IsMsixvc2Package, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<TextBlock Text="{Binding BranchOrFlightDisplayName}" Foreground="{DynamicResource PrimaryTextBrush}" Margin="0,0,0,4"/>
<TextBlock Text="{x:Static strings:PackageUpload.MarketTitleText}" Foreground="{DynamicResource SecondaryTextBrush}"/>
<TextBlock Text="{Binding MarketGroupName}" Foreground="{DynamicResource PrimaryTextBrush}"/>
</StackPanel>
<!-- File name (MSIXVC1) / Package Identity name (MSIXVC2) -->
<StackPanel Grid.Row="2"
Grid.Column="1"
Orientation="Vertical"
HorizontalAlignment="Left"
Margin="{DynamicResource PreviewItemMargin}">
<TextBlock Text="{x:Static strings:PackageUpload.FileNameTitleText}"
d:Text="File name"
Foreground="{DynamicResource SecondaryTextBrush}"/>
Foreground="{DynamicResource SecondaryTextBrush}"
Visibility="{Binding IsMsixvc2Package, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=Invert}"/>
<TextBlock Text="{x:Static strings:Msixvc2Upload.PackageIdentityNameTitleText}"
d:Text="Package Identity name"
Foreground="{DynamicResource SecondaryTextBrush}"
Visibility="{Binding IsMsixvc2Package, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<TextBlock Text="{Binding PackageName}"
Foreground="{DynamicResource PrimaryTextBrush}"
TextWrapping="Wrap"/>
TextWrapping="Wrap"
Visibility="{Binding IsMsixvc2Package, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=Invert}"/>
<TextBlock Text="{Binding PackageIdentityName}"
Foreground="{DynamicResource PrimaryTextBrush}"
TextWrapping="Wrap"
Visibility="{Binding IsMsixvc2Package, Converter={StaticResource BooleanToVisibilityConverter}}"/>
</StackPanel>
<!-- StoreID / Size / Family — standard mode: side by side -->
<Grid Grid.Row="3" Grid.Column="1"
Expand All @@ -546,7 +574,12 @@
<StackPanel Grid.Column="1" Orientation="Vertical" HorizontalAlignment="Left">
<TextBlock Text="{x:Static strings:PackageUpload.SizeTitleText}"
d:Text="Size"
Foreground="{DynamicResource SecondaryTextBrush}"/>
Foreground="{DynamicResource SecondaryTextBrush}"
Visibility="{Binding IsMsixvc2Package, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=Invert}"/>
<TextBlock Text="{x:Static strings:Msixvc2Upload.FolderSizeTitleText}"
d:Text="Folder size"
Foreground="{DynamicResource SecondaryTextBrush}"
Visibility="{Binding IsMsixvc2Package, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<TextBlock Text="{Binding PackageSize}"
Foreground="{DynamicResource PrimaryTextBrush}"/>
</StackPanel>
Expand All @@ -563,7 +596,10 @@
Visibility="{Binding IsCompactMode, Converter={StaticResource BooleanToVisibilityConverter}}">
<TextBlock Text="{x:Static strings:PackageUpload.StoreIdTitleText}" Foreground="{DynamicResource SecondaryTextBrush}"/>
<TextBlock Text="{Binding BigId}" Foreground="{DynamicResource PrimaryTextBrush}" Margin="0,0,0,4"/>
<TextBlock Text="{x:Static strings:PackageUpload.SizeTitleText}" Foreground="{DynamicResource SecondaryTextBrush}"/>
<TextBlock Text="{x:Static strings:PackageUpload.SizeTitleText}" Foreground="{DynamicResource SecondaryTextBrush}"
Visibility="{Binding IsMsixvc2Package, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=Invert}"/>
<TextBlock Text="{x:Static strings:Msixvc2Upload.FolderSizeTitleText}" Foreground="{DynamicResource SecondaryTextBrush}"
Visibility="{Binding IsMsixvc2Package, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<TextBlock Text="{Binding PackageSize}" Foreground="{DynamicResource PrimaryTextBrush}" Margin="0,0,0,4"/>
<TextBlock Text="{x:Static strings:PackageUpload.FamilyTitleText}" Foreground="{DynamicResource SecondaryTextBrush}"/>
<TextBlock Text="{Binding PackageType}" Foreground="{DynamicResource PrimaryTextBrush}"/>
Expand All @@ -574,8 +610,8 @@
</Grid>

<!-- Button panel -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,20,0,0">
<Button Grid.Column="0"
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,20,0,0">
<Button Grid.Column="0"
d:Content="Cancel"
Content="{x:Static strings:PackageUpload.CancelContentText}"
Command="{Binding CancelButtonCommand}"
Expand All @@ -587,7 +623,7 @@
AutomationProperties.HelpText="{x:Static strings:PackageUpload.CancelButtonHelpText}"
TabIndex="4" />

<Button Grid.Column="1"
<Button Grid.Column="1"
d:Content="Upload Package"
Content="{x:Static strings:PackageUpload.UploadButtonContentText}"
Command="{Binding UploadPackageCommand}"
Expand All @@ -598,7 +634,15 @@
d:AutomationProperties.HelpText="Start uploading the package"
AutomationProperties.HelpText="{x:Static strings:PackageUpload.UploadButtonHelpText}"
TabIndex="5" />
</StackPanel>
</StackPanel>

<!-- makepkg2 unavailable warning for MSIXVC2 packages -->
<TextBlock Text="{Binding MakePkg2UnavailableMessage}"
Foreground="{DynamicResource ErrorRedBrush}"
Visibility="{Binding MakePkg2UnavailableMessage, Converter={StaticResource StringNotEmptyToVisibilityConverter}}"
TextWrapping="Wrap"
HorizontalAlignment="Right"
Margin="0,5,0,0" />
</StackPanel>
</ScrollViewer>
</Grid>
Expand Down
Loading
Loading