1 /*
2  * Copyright (C) 2010 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 android.drm;
18 
19 import java.io.BufferedInputStream;
20 import java.io.Closeable;
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.OutputStream;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 
30 /**
31  * A utility class that provides operations for parsing extended metadata embedded in
32  * DRM constraint information. If a DRM scheme has specific constraints beyond the standard
33  * constraints, the constraints will show up in the
34  * {@link DrmStore.ConstraintsColumns#EXTENDED_METADATA} key. You can use
35  * {@link DrmUtils.ExtendedMetadataParser} to iterate over those values.
36  * @deprecated Please use {@link android.media.MediaDrm}
37  */
38 @Deprecated
39 public class DrmUtils {
40     /* Should be used when we need to read from local file */
readBytes(String path)41     /* package */ static byte[] readBytes(String path) throws IOException {
42         File file = new File(path);
43         return readBytes(file);
44     }
45 
46     /* Should be used when we need to read from local file */
readBytes(File file)47     /* package */ static byte[] readBytes(File file) throws IOException {
48         FileInputStream inputStream = new FileInputStream(file);
49         BufferedInputStream bufferedStream = new BufferedInputStream(inputStream);
50         byte[] data = null;
51 
52         try {
53             int length = bufferedStream.available();
54             if (length > 0) {
55                 data = new byte[length];
56                 // read the entire data
57                 bufferedStream.read(data);
58              }
59         } finally {
60             quietlyDispose(bufferedStream);
61             quietlyDispose(inputStream);
62         }
63         return data;
64     }
65 
writeToFile(final String path, byte[] data)66     /* package */ static void writeToFile(final String path, byte[] data) throws IOException {
67         /* check for invalid inputs */
68         FileOutputStream outputStream = null;
69 
70         if (null != path && null != data) {
71             try {
72                 outputStream = new FileOutputStream(path);
73                 outputStream.write(data);
74             } finally {
75                 quietlyDispose(outputStream);
76             }
77         }
78     }
79 
removeFile(String path)80     /* package */ static void removeFile(String path) throws IOException {
81         File file = new File(path);
82         file.delete();
83     }
84 
quietlyDispose(Closeable closable)85     private static void quietlyDispose(Closeable closable) {
86         try {
87             if (null != closable) {
88                 closable.close();
89             }
90         } catch (IOException e) {
91             // no need to care, at least as of now
92         }
93     }
94 
95     /**
96      * Gets an instance of {@link DrmUtils.ExtendedMetadataParser}, which can be used to parse
97      * extended metadata embedded in DRM constraint information.
98      *
99      * @param extendedMetadata Object in which key-value pairs of extended metadata are embedded.
100      *
101      */
getExtendedMetadataParser(byte[] extendedMetadata)102     public static ExtendedMetadataParser getExtendedMetadataParser(byte[] extendedMetadata) {
103         return new ExtendedMetadataParser(extendedMetadata);
104     }
105 
106     /**
107      * Utility that parses extended metadata embedded in DRM constraint information.
108      *<p>
109      * Usage example:
110      *<p>
111      * byte[] extendedMetadata<br>
112      * &nbsp;&nbsp;&nbsp;&nbsp; =
113      *         constraints.getAsByteArray(DrmStore.ConstraintsColumns.EXTENDED_METADATA);<br>
114      * ExtendedMetadataParser parser = getExtendedMetadataParser(extendedMetadata);<br>
115      * Iterator keyIterator = parser.keyIterator();<br>
116      * while (keyIterator.hasNext()) {<br>
117      *     &nbsp;&nbsp;&nbsp;&nbsp;String extendedMetadataKey = keyIterator.next();<br>
118      *     &nbsp;&nbsp;&nbsp;&nbsp;String extendedMetadataValue =
119      *             parser.get(extendedMetadataKey);<br>
120      * }
121      */
122     public static class ExtendedMetadataParser {
123         HashMap<String, String> mMap = new HashMap<String, String>();
124 
readByte(byte[] constraintData, int arrayIndex)125         private int readByte(byte[] constraintData, int arrayIndex) {
126             //Convert byte[] into int.
127             return (int)constraintData[arrayIndex];
128         }
129 
readMultipleBytes( byte[] constraintData, int numberOfBytes, int arrayIndex)130         private String readMultipleBytes(
131                 byte[] constraintData, int numberOfBytes, int arrayIndex) {
132             byte[] returnBytes = new byte[numberOfBytes];
133             for (int j = arrayIndex, i = 0; j < arrayIndex + numberOfBytes; j++,i++) {
134                 returnBytes[i] = constraintData[j];
135             }
136             return new String(returnBytes);
137         }
138 
139         /*
140          * This will parse the following format
141          * KeyLengthValueLengthKeyValueKeyLength1ValueLength1Key1Value1..\0
142          */
ExtendedMetadataParser(byte[] constraintData)143         private ExtendedMetadataParser(byte[] constraintData) {
144             //Extract KeyValue Pair Info, till terminator occurs.
145             int index = 0;
146 
147             while (index < constraintData.length) {
148                 //Parse Key Length
149                 int keyLength = readByte(constraintData, index);
150                 index++;
151 
152                 //Parse Value Length
153                 int valueLength = readByte(constraintData, index);
154                 index++;
155 
156                 //Fetch key
157                 String strKey = readMultipleBytes(constraintData, keyLength, index);
158                 index += keyLength;
159 
160                 //Fetch Value
161                 String strValue = readMultipleBytes(constraintData, valueLength, index);
162                 if (strValue.equals(" ")) {
163                     strValue = "";
164                 }
165                 index += valueLength;
166                 mMap.put(strKey, strValue);
167             }
168         }
169 
170         /**
171          * This method returns an iterator object that can be used to iterate over
172          * all values of the metadata.
173          *
174          * @return The iterator object.
175          */
iterator()176         public Iterator<String> iterator() {
177             return mMap.values().iterator();
178         }
179 
180         /**
181          * This method returns an iterator object that can be used to iterate over
182          * all keys of the metadata.
183          *
184          * @return The iterator object.
185          */
keyIterator()186         public Iterator<String> keyIterator() {
187             return mMap.keySet().iterator();
188         }
189 
190         /**
191          * This method retrieves the metadata value associated with a given key.
192          *
193          * @param key The key whose value is being retrieved.
194          *
195          * @return The metadata value associated with the given key. Returns null
196          * if the key is not found.
197          */
get(String key)198         public String get(String key) {
199             return mMap.get(key);
200         }
201     }
202 }
203 
204