1package android.content.pm;
2
3import android.os.Parcel;
4import android.os.Parcelable;
5import android.util.Base64;
6
7import java.util.Arrays;
8import java.util.jar.Attributes;
9
10/**
11 * Represents the manifest digest for a package. This is suitable for comparison
12 * of two packages to know whether the manifests are identical.
13 *
14 * @hide
15 */
16public class ManifestDigest implements Parcelable {
17    /** The digest of the manifest in our preferred order. */
18    private final byte[] mDigest;
19
20    /** Digest field names to look for in preferred order. */
21    private static final String[] DIGEST_TYPES = {
22            "SHA1-Digest", "SHA-Digest", "MD5-Digest",
23    };
24
25    /** What we print out first when toString() is called. */
26    private static final String TO_STRING_PREFIX = "ManifestDigest {mDigest=";
27
28    ManifestDigest(byte[] digest) {
29        mDigest = digest;
30    }
31
32    private ManifestDigest(Parcel source) {
33        mDigest = source.createByteArray();
34    }
35
36    static ManifestDigest fromAttributes(Attributes attributes) {
37        if (attributes == null) {
38            return null;
39        }
40
41        String encodedDigest = null;
42
43        for (int i = 0; i < DIGEST_TYPES.length; i++) {
44            final String value = attributes.getValue(DIGEST_TYPES[i]);
45            if (value != null) {
46                encodedDigest = value;
47                break;
48            }
49        }
50
51        if (encodedDigest == null) {
52            return null;
53        }
54
55        final byte[] digest = Base64.decode(encodedDigest, Base64.DEFAULT);
56        return new ManifestDigest(digest);
57    }
58
59    @Override
60    public int describeContents() {
61        return 0;
62    }
63
64    @Override
65    public boolean equals(Object o) {
66        if (!(o instanceof ManifestDigest)) {
67            return false;
68        }
69
70        final ManifestDigest other = (ManifestDigest) o;
71
72        return this == other || Arrays.equals(mDigest, other.mDigest);
73    }
74
75    @Override
76    public int hashCode() {
77        return Arrays.hashCode(mDigest);
78    }
79
80    @Override
81    public String toString() {
82        final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX.length()
83                + (mDigest.length * 3) + 1);
84
85        sb.append(TO_STRING_PREFIX);
86
87        final int N = mDigest.length;
88        for (int i = 0; i < N; i++) {
89            final byte b = mDigest[i];
90            IntegralToString.appendByteAsHex(sb, b, false);
91            sb.append(',');
92        }
93        sb.append('}');
94
95        return sb.toString();
96    }
97
98    @Override
99    public void writeToParcel(Parcel dest, int flags) {
100        dest.writeByteArray(mDigest);
101    }
102
103    public static final Parcelable.Creator<ManifestDigest> CREATOR
104            = new Parcelable.Creator<ManifestDigest>() {
105        public ManifestDigest createFromParcel(Parcel source) {
106            return new ManifestDigest(source);
107        }
108
109        public ManifestDigest[] newArray(int size) {
110            return new ManifestDigest[size];
111        }
112    };
113
114}