github.com/google/osv-scalibr@v0.4.1/extractor/standalone/windows/dismpatch/dismparser/dism_parser.go (about)

     1  // Copyright 2025 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package dismparser has methods that can be used to parse DISM output
    16  package dismparser
    17  
    18  import (
    19  	"errors"
    20  	"regexp"
    21  	"strings"
    22  )
    23  
    24  var (
    25  	// ErrParsingError indicates an error while parsing the DISM output.
    26  	ErrParsingError = errors.New("could not parse DISM output successfully")
    27  
    28  	versionRegexp = regexp.MustCompile(`~(\d+\.\d+\.\d+\.\d+)$`)
    29  )
    30  
    31  // DismPkg reports information about a package as reported by the DISM tool.
    32  type DismPkg struct {
    33  	PackageIdentity string
    34  	PackageVersion  string
    35  	State           string
    36  	ReleaseType     string
    37  	InstallTime     string
    38  }
    39  
    40  var (
    41  	pkgExpFinder = regexp.MustCompile("entity :(.*)\n*State :(.*)\n*Release Type :(.*)\n*Install Time :(.*)\n*")
    42  	imgVerFinder = regexp.MustCompile("Image Version: (.*)")
    43  )
    44  
    45  // Parse parses dism output into an array of dismPackages.
    46  func Parse(input string) ([]DismPkg, string, error) {
    47  	packages := strings.Split(input, "Package Id")
    48  
    49  	imgVersion := ""
    50  	dismPackages := []DismPkg{}
    51  
    52  	for _, pkg := range packages {
    53  		matches := pkgExpFinder.FindStringSubmatch(pkg)
    54  		if len(matches) > 4 {
    55  			dismPkg := DismPkg{
    56  				PackageIdentity: strings.TrimSpace(matches[1]),
    57  				State:           strings.TrimSpace(matches[2]),
    58  				ReleaseType:     strings.TrimSpace(matches[3]),
    59  				InstallTime:     strings.TrimSpace(matches[4]),
    60  			}
    61  			dismPkg.PackageVersion = findVersion(dismPkg.PackageIdentity)
    62  			dismPackages = append(dismPackages, dismPkg)
    63  		} else {
    64  			// this is the first entry that has the image version
    65  			matches = imgVerFinder.FindStringSubmatch(pkg)
    66  			if len(matches) > 1 {
    67  				imgVersion = strings.TrimSpace(matches[1])
    68  			}
    69  		}
    70  	}
    71  
    72  	if len(dismPackages) == 0 {
    73  		return nil, "", ErrParsingError
    74  	}
    75  
    76  	return dismPackages, imgVersion, nil
    77  }
    78  
    79  func findVersion(identity string) string {
    80  	pkgVer := versionRegexp.FindStringSubmatch(identity)
    81  	if len(pkgVer) > 1 {
    82  		return pkgVer[1]
    83  	}
    84  	return ""
    85  }