blob: 653e5eedbe5becd60588c963bb13c957ac92af63 [file] [log] [blame]
Jeff Gaston01547b22017-08-21 20:13:28 -07001// Copyright 2017 Google Inc. All rights reserved.
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
15package jar
16
17import (
Colin Cross635acc92017-09-12 22:50:46 -070018 "bytes"
Jeff Gaston01547b22017-08-21 20:13:28 -070019 "fmt"
Colin Cross635acc92017-09-12 22:50:46 -070020 "io/ioutil"
21 "os"
Jeff Gaston01547b22017-08-21 20:13:28 -070022 "strings"
Colin Cross635acc92017-09-12 22:50:46 -070023 "time"
24
25 "android/soong/third_party/zip"
Jeff Gaston01547b22017-08-21 20:13:28 -070026)
27
Colin Cross34540312017-09-06 12:52:37 -070028const (
29 MetaDir = "META-INF/"
30 ManifestFile = MetaDir + "MANIFEST.MF"
31 ModuleInfoClass = "module-info.class"
32)
33
Colin Crossbddcf132017-10-04 17:02:23 -070034var DefaultTime = time.Date(2008, 1, 1, 0, 0, 0, 0, time.UTC)
Colin Cross635acc92017-09-12 22:50:46 -070035
36var MetaDirExtra = [2]byte{0xca, 0xfe}
37
Jeff Gaston01547b22017-08-21 20:13:28 -070038// EntryNamesLess tells whether <filepathA> should precede <filepathB> in
39// the order of files with a .jar
40func EntryNamesLess(filepathA string, filepathB string) (less bool) {
41 diff := index(filepathA) - index(filepathB)
42 if diff == 0 {
43 return filepathA < filepathB
44 }
45 return diff < 0
46}
47
48// Treats trailing * as a prefix match
49func patternMatch(pattern, name string) bool {
50 if strings.HasSuffix(pattern, "*") {
51 return strings.HasPrefix(name, strings.TrimSuffix(pattern, "*"))
52 } else {
53 return name == pattern
54 }
55}
56
57var jarOrder = []string{
Colin Cross34540312017-09-06 12:52:37 -070058 MetaDir,
59 ManifestFile,
60 MetaDir + "*",
Jeff Gaston01547b22017-08-21 20:13:28 -070061 "*",
62}
63
64func index(name string) int {
65 for i, pattern := range jarOrder {
66 if patternMatch(pattern, name) {
67 return i
68 }
69 }
70 panic(fmt.Errorf("file %q did not match any pattern", name))
71}
Colin Cross635acc92017-09-12 22:50:46 -070072
73func MetaDirFileHeader() *zip.FileHeader {
74 dirHeader := &zip.FileHeader{
75 Name: MetaDir,
76 Extra: []byte{MetaDirExtra[1], MetaDirExtra[0], 0, 0},
77 }
78 dirHeader.SetMode(0700 | os.ModeDir)
79 dirHeader.SetModTime(DefaultTime)
80
81 return dirHeader
82}
83
84// Convert manifest source path to zip header and contents. If path is empty uses a default
85// manifest.
86func ManifestFileContents(src string) (*zip.FileHeader, []byte, error) {
87 b, err := manifestContents(src)
88 if err != nil {
89 return nil, nil, err
90 }
91
92 fh := &zip.FileHeader{
93 Name: ManifestFile,
94 Method: zip.Store,
95 UncompressedSize64: uint64(len(b)),
96 }
Colin Cross2825cb32017-09-29 13:57:10 -070097 fh.SetMode(0700)
98 fh.SetModTime(DefaultTime)
Colin Cross635acc92017-09-12 22:50:46 -070099
100 return fh, b, nil
101}
102
103// Convert manifest source path to contents. If path is empty uses a default manifest.
104func manifestContents(src string) ([]byte, error) {
105 var givenBytes []byte
106 var err error
107
108 if src != "" {
109 givenBytes, err = ioutil.ReadFile(src)
110 if err != nil {
111 return nil, err
112 }
113 }
114
115 manifestMarker := []byte("Manifest-Version:")
116 header := append(manifestMarker, []byte(" 1.0\nCreated-By: soong_zip\n")...)
117
118 var finalBytes []byte
119 if !bytes.Contains(givenBytes, manifestMarker) {
120 finalBytes = append(append(header, givenBytes...), byte('\n'))
121 } else {
122 finalBytes = givenBytes
123 }
124
125 return finalBytes, nil
126}