• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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