Types/OpenPackage.Source/Zip.ps1

<#
.SYNOPSIS
    Gets a zipfile as a package
.DESCRIPTION
    Gets a zipfile as an open package.
#>

param(
# The path to a tarfile.
[Parameter(Mandatory,ValueFromPipelineByPropertyName)]
[string]
$ZipFile,

# A list of file wildcards to include.
[Parameter(ValueFromPipelineByPropertyName)]
[SupportsWildcards()]
[string[]]
$Include,

# A list of file wildcards to exclude.
[Parameter(ValueFromPipelineByPropertyName)]
[SupportsWildcards()]
[string[]]
$Exclude,

# A content type map.
# This maps extensions and URIs to a content type.
[Collections.IDictionary]
$TypeMap = $(
    ([PSCustomObject]@{PSTypeName='OpenPackage.ContentTypeMap'}).TypeMap
),

# The compression option.
[IO.Packaging.CompressionOption]
[Alias('CompressionLevel')]
$CompressionOption = 'Superfast',
        
# If set, will force the redownload of various resources and remove existing files or directories
[switch]
$Force,

# If set, will include hidden files and folders, except for files beneath `.git`
[Alias('IncludeDotFiles')]
[switch]
$IncludeHidden,

# If set, will include the `.git` directory contents if found.
[switch]
$IncludeGit,

# If set, will include any content found in `/node_modules`.
[Alias('IncludeNodeModules')]
[switch]
$IncludeNodeModule
)

$namedParameters = [Ordered]@{}
foreach ($key in $namedParameters.Keys) {
    $var = $ExecutionContext.SessionState.PSVariable.Get($key)
    if ($var) {
        $namedParameters[$key] = $var.value
    }
}
$namedParameters.Remove('ZipFile')

# Put tar files into their own subdirectory
    
foreach ($resolvedItem in Get-Item -Path $ZipFile) {    
    # By reading the file with Get-Content -AsByteStream, we avoid locking the file
    # (or the file being locked by another process)

    $peekMagicBytes =  Get-Content -AsByteStream -LiteralPath $resolvedItem.FullName -First 5

    if ($peekMagicBytes[0,1] -as 'char[]' -join '' -ne 'PK') {
        return
    }
    
    $packageBytes = Get-Content -LiteralPath $resolvedItem.FullName -AsByteStream -Raw    

    # Create a memory stream from the byte array
    $memoryStream = [IO.MemoryStream]::new($packageBytes)
    # and open the package from the memory stream
    $currentPackage = [IO.Packaging.Package]::Open($memoryStream, "Open", "ReadWrite")
    # If that did not work, return.
    if (-not $currentPackage) { return }

    $packageParts = @($currentPackage.GetParts())
    
    # If we could open the file but not see the parts, it's a normal zip
    if (-not $packageParts) {
        # Close the package and the stream and try Expand-Archive.
        $currentPackage.Close()
        $memoryStream.Close()

        # To make things work, we want to extract to a folder and reload
        # it's important that the folder name matches the file name, without the extension
        $folderName = $resolvedItem.Name -replace '\.[^\.]+?$'        

        $myAppData = if ($env:OpenPackagePath) {
            # Get our first OpenPackage package path
            @($env:OpenPackagePath -split $(
                if ($IsLinux -or $IsMacOS) {
                    ':'
                } else {
                    ';'
                }
            ))[0]
        } else {
            $pwd
        }
        
        $folderPath = Join-Path $myAppData $folderName
        # If the folder path did not exist
        if (-not (Test-Path $folderPath)) {
            # create it
            $newDirectory = New-Item -ItemType Directory -Path $folderPath
            if (-not $newDirectory) {
                return
            }
        }

        # If the folder already exists, and we are not using force
        if ((Test-Path $folderPath)) {
            if (-not $Force) {
                Write-Error "$FolderPath exists, use -Force"
                return
            }
            # remove the current folder, so that no errant files show up in the package.
            Remove-Item -Path $folderPath -Recurse -Force
        }
                        
        # If that worked, expand the archive to this path (giving us a fresh copy)
        Expand-Archive -LiteralPath $resolvedItem.FullName -DestinationPath $folderPath
        if ($?) {
            # and call ourself
            return Get-OpenPackage -FilePath $folderPath @namedParameters
        } else {
            return
        }                            
    }
        
    $currentPackage = $currentPackage | 
        Add-Member NoteProperty FilePath $filePath -Force -PassThru |
        Add-Member NoteProperty MemoryStream $memoryStream -Force -PassThru
        
    # If there is no identifier, set it to the file name
    if (-not $currentPackage.PackageProperties.Identifier) {
        $currentPackage.PackageProperties.Identifier = $resolvedItem.Name
    }

    $currentPackage    
}