1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.content.pm;
18
19import android.os.Parcel;
20import android.os.Parcelable;
21import android.util.Base64;
22
23import java.util.Arrays;
24import java.util.jar.Attributes;
25
26/**
27 * Represents the manifest digest for a package. This is suitable for comparison
28 * of two packages to know whether the manifests are identical.
29 *
30 * @hide
31 */
32public class ManifestDigest implements Parcelable {
33    /** The digest of the manifest in our preferred order. */
34    private final byte[] mDigest;
35
36    /** Digest field names to look for in preferred order. */
37    private static final String[] DIGEST_TYPES = {
38            "SHA1-Digest", "SHA-Digest", "MD5-Digest",
39    };
40
41    /** What we print out first when toString() is called. */
42    private static final String TO_STRING_PREFIX = "ManifestDigest {mDigest=";
43
44    ManifestDigest(byte[] digest) {
45        mDigest = digest;
46    }
47
48    private ManifestDigest(Parcel source) {
49        mDigest = source.createByteArray();
50    }
51
52    static ManifestDigest fromAttributes(Attributes attributes) {
53        if (attributes == null) {
54            return null;
55        }
56
57        String encodedDigest = null;
58
59        for (int i = 0; i < DIGEST_TYPES.length; i++) {
60            final String value = attributes.getValue(DIGEST_TYPES[i]);
61            if (value != null) {
62                encodedDigest = value;
63                break;
64            }
65        }
66
67        if (encodedDigest == null) {
68            return null;
69        }
70
71        final byte[] digest = Base64.decode(encodedDigest, Base64.DEFAULT);
72        return new ManifestDigest(digest);
73    }
74
75    @Override
76    public int describeContents() {
77        return 0;
78    }
79
80    @Override
81    public boolean equals(Object o) {
82        if (!(o instanceof ManifestDigest)) {
83            return false;
84        }
85
86        final ManifestDigest other = (ManifestDigest) o;
87
88        return this == other || Arrays.equals(mDigest, other.mDigest);
89    }
90
91    @Override
92    public int hashCode() {
93        return Arrays.hashCode(mDigest);
94    }
95
96    @Override
97    public String toString() {
98        final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX.length()
99                + (mDigest.length * 3) + 1);
100
101        sb.append(TO_STRING_PREFIX);
102
103        final int N = mDigest.length;
104        for (int i = 0; i < N; i++) {
105            final byte b = mDigest[i];
106            IntegralToString.appendByteAsHex(sb, b, false);
107            sb.append(',');
108        }
109        sb.append('}');
110
111        return sb.toString();
112    }
113
114    @Override
115    public void writeToParcel(Parcel dest, int flags) {
116        dest.writeByteArray(mDigest);
117    }
118
119    public static final Parcelable.Creator<ManifestDigest> CREATOR
120            = new Parcelable.Creator<ManifestDigest>() {
121        public ManifestDigest createFromParcel(Parcel source) {
122            return new ManifestDigest(source);
123        }
124
125        public ManifestDigest[] newArray(int size) {
126            return new ManifestDigest[size];
127        }
128    };
129
130}