| /* |
| Copyright 2018 Google LLC |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| https://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| package main |
| |
| import ( |
| "archive/zip" |
| "fmt" |
| "io" |
| "strings" |
| ) |
| |
| // manifestIndexNewline scans manifest and returns the index of the first |
| // newline and the index of the byte following the newline. |
| func manifestIndexNewline(manifest string) (int, int, error) { |
| // A newline in a jar manifest is denoted with CR LF, CR, or LF. |
| n := strings.IndexByte(manifest, '\n') |
| r := strings.IndexByte(manifest, '\r') |
| if n < 0 && r < 0 { |
| return -1, -1, fmt.Errorf("no newline in '%s'", manifest) |
| } |
| |
| if n < 0 { |
| // Only CR. |
| return r, r + 1, nil |
| } |
| if r < 0 || n < r { |
| // Only LF or we have both but the LF comes first. |
| return n, n + 1, nil |
| } |
| |
| // We have both CR and LF and the CR comes before the LF. Check for the |
| // special case of adjacent CR LF, which together denode a newline. |
| if n == r+1 { |
| return r, n + 1, nil |
| } |
| |
| return r, r + 1, nil |
| } |
| |
| // jarManifestValue returns the value associated with key in the manifest of |
| // the jar file named jarFileName. |
| func jarManifestValue(jarFileName string, key string) (string, error) { |
| r, err := zip.OpenReader(jarFileName) |
| if err != nil { |
| return "", err |
| } |
| defer r.Close() |
| |
| for _, f := range r.File { |
| if f.Name != "META-INF/MANIFEST.MF" { |
| continue |
| } |
| |
| rc, err := f.Open() |
| if err != nil { |
| return "", err |
| } |
| defer rc.Close() |
| |
| bytes, err := io.ReadAll(rc) |
| if err != nil { |
| return "", err |
| } |
| contents := string(bytes) |
| |
| found := strings.Index(contents, key+":") |
| if found < 0 { |
| return "", fmt.Errorf("manifest of jar %s contains no key %s", jarFileName, key) |
| } |
| |
| label := "" |
| rest := contents[found+len(key+":"):] |
| for len(rest) > 0 && rest[0] == ' ' { |
| newline, next, err := manifestIndexNewline(rest) |
| if err != nil { |
| return "", fmt.Errorf("bad value for key %s in manifest of jar %s", key, jarFileName) |
| } |
| label += rest[1:newline] |
| rest = rest[next:] |
| } |
| return label, nil |
| } |
| return "", fmt.Errorf("jar file %s has no manifest", jarFileName) |
| } |