1// 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 ( 18 "bytes" 19 "fmt" 20 "os" 21 "strings" 22 "time" 23 24 "android/soong/third_party/zip" 25) 26 27const ( 28 MetaDir = "META-INF/" 29 ManifestFile = MetaDir + "MANIFEST.MF" 30 ModuleInfoClass = "module-info.class" 31) 32 33var DefaultTime = time.Date(2008, 1, 1, 0, 0, 0, 0, time.UTC) 34 35var MetaDirExtra = [2]byte{0xca, 0xfe} 36 37// EntryNamesLess tells whether <filepathA> should precede <filepathB> in 38// the order of files with a .jar 39func EntryNamesLess(filepathA string, filepathB string) (less bool) { 40 diff := index(filepathA) - index(filepathB) 41 if diff == 0 { 42 return filepathA < filepathB 43 } 44 return diff < 0 45} 46 47// Treats trailing * as a prefix match 48func patternMatch(pattern, name string) bool { 49 if strings.HasSuffix(pattern, "*") { 50 return strings.HasPrefix(name, strings.TrimSuffix(pattern, "*")) 51 } else { 52 return name == pattern 53 } 54} 55 56var jarOrder = []string{ 57 MetaDir, 58 ManifestFile, 59 MetaDir + "*", 60 "*", 61} 62 63func index(name string) int { 64 for i, pattern := range jarOrder { 65 if patternMatch(pattern, name) { 66 return i 67 } 68 } 69 panic(fmt.Errorf("file %q did not match any pattern", name)) 70} 71 72func MetaDirFileHeader() *zip.FileHeader { 73 dirHeader := &zip.FileHeader{ 74 Name: MetaDir, 75 Extra: []byte{MetaDirExtra[1], MetaDirExtra[0], 0, 0}, 76 } 77 dirHeader.SetMode(0700 | os.ModeDir) 78 dirHeader.SetModTime(DefaultTime) 79 80 return dirHeader 81} 82 83// Create a manifest zip header and contents using the provided contents if any. 84func ManifestFileContents(contents []byte) (*zip.FileHeader, []byte, error) { 85 b, err := manifestContents(contents) 86 if err != nil { 87 return nil, nil, err 88 } 89 90 fh := &zip.FileHeader{ 91 Name: ManifestFile, 92 Method: zip.Store, 93 UncompressedSize64: uint64(len(b)), 94 } 95 fh.SetMode(0700) 96 fh.SetModTime(DefaultTime) 97 98 return fh, b, nil 99} 100 101// Create manifest contents, using the provided contents if any. 102func manifestContents(contents []byte) ([]byte, error) { 103 manifestMarker := []byte("Manifest-Version:") 104 header := append(manifestMarker, []byte(" 1.0\nCreated-By: soong_zip\n")...) 105 106 var finalBytes []byte 107 if !bytes.Contains(contents, manifestMarker) { 108 finalBytes = append(append(header, contents...), byte('\n')) 109 } else { 110 finalBytes = contents 111 } 112 113 return finalBytes, nil 114} 115