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