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