1 /*
2  * Copyright (C) 2019 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 
17 package com.android.providers.media.util;
18 
19 import android.media.ExifInterface;
20 import android.text.TextUtils;
21 
22 import androidx.annotation.NonNull;
23 import androidx.annotation.Nullable;
24 
25 /**
26  * Parser for Extensible Metadata Platform (XMP) metadata. Designed to mirror
27  * ergonomics of {@link ExifInterface}.
28  * <p>
29  * Since values can be repeated multiple times within the same XMP data, this
30  * parser prefers the first valid definition of a specific value, and it ignores
31  * any subsequent attempts to redefine that value.
32  */
33 public class XmpInterface {
34     private final String mFormat;
35     private final String mDocumentId;
36     private final String mInstanceId;
37     private final String mOriginalDocumentId;
38 
39     private final @NonNull byte[] mRedactedXmp;
40 
XmpInterface(String format, String documentId, String instanceId, String originalDocumentId, @NonNull byte[] redactedXmp)41     private XmpInterface(String format, String documentId,
42             String instanceId, String originalDocumentId, @NonNull byte[] redactedXmp) {
43         mFormat = format;
44         mDocumentId = documentId;
45         mInstanceId = instanceId;
46         mOriginalDocumentId = originalDocumentId;
47         mRedactedXmp = redactedXmp;
48     }
49 
50     static class Builder {
51         String mFormat;
52         String mDocumentId;
53         String mInstanceId;
54         String mOriginalDocumentId;
55         byte[] mRedactedXmp;
56 
format(String format)57         Builder format(String format) {
58             mFormat = maybeOverride(mFormat, format);
59             return this;
60         }
61 
documentId(String documentId)62         Builder documentId(String documentId) {
63             mDocumentId = maybeOverride(mDocumentId, documentId);
64             return this;
65         }
66 
instanceId(String instanceId)67         Builder instanceId(String instanceId) {
68             mInstanceId = maybeOverride(mInstanceId, instanceId);
69             return this;
70         }
71 
originalDocumentId(String originalDocumentId)72         Builder originalDocumentId(String originalDocumentId) {
73             mOriginalDocumentId = maybeOverride(mOriginalDocumentId, originalDocumentId);
74             return this;
75         }
76 
Builder(byte[] redactedXmp)77         Builder(byte[] redactedXmp) {
78             mRedactedXmp = redactedXmp;
79         }
80 
build()81         XmpInterface build() {
82             return new XmpInterface(mFormat, mDocumentId, mInstanceId, mOriginalDocumentId,
83                     mRedactedXmp);
84         }
85 
maybeOverride(@ullable String existing, @Nullable String current)86         private static @Nullable String maybeOverride(@Nullable String existing,
87                 @Nullable String current) {
88             if (!TextUtils.isEmpty(existing)) {
89                 // If already defined, first definition always wins
90                 return existing;
91             } else if (!TextUtils.isEmpty(current)) {
92                 // If current defined, it wins
93                 return current;
94             } else {
95                 // Otherwise, null wins to prevent weird empty strings
96                 return null;
97             }
98         }
99     }
100 
getFormat()101     public @Nullable String getFormat() {
102         return mFormat;
103     }
104 
getDocumentId()105     public @Nullable String getDocumentId() {
106         return mDocumentId;
107     }
108 
getInstanceId()109     public @Nullable String getInstanceId() {
110         return mInstanceId;
111     }
112 
getOriginalDocumentId()113     public @Nullable String getOriginalDocumentId() {
114         return mOriginalDocumentId;
115     }
116 
getRedactedXmp()117     public @NonNull byte[] getRedactedXmp() {
118         return mRedactedXmp;
119     }
120 }
121