1d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi/* 2d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * Copyright (C) 2010 The Android Open Source Project 3d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * 4d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * Licensed under the Apache License, Version 2.0 (the "License"); 5d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * you may not use this file except in compliance with the License. 6d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * You may obtain a copy of the License at 7d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * 8d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * http://www.apache.org/licenses/LICENSE-2.0 9d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * 10d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * Unless required by applicable law or agreed to in writing, software 11d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * distributed under the License is distributed on an "AS IS" BASIS, 12d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * See the License for the specific language governing permissions and 14d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * limitations under the License. 15d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi */ 16d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 17d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshipackage android.drm; 18d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 19d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshiimport java.io.BufferedInputStream; 2021d71a4c8aa70ef9e133d18097a855cc23f29faeisaidimport java.io.Closeable; 21d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshiimport java.io.File; 22d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshiimport java.io.FileInputStream; 23d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshiimport java.io.FileOutputStream; 24d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshiimport java.io.IOException; 25d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshiimport java.io.InputStream; 26d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshiimport java.io.OutputStream; 27d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshiimport java.util.HashMap; 28d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshiimport java.util.Iterator; 29d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 30d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi/** 310e092f806b0a4b81785a52da8ba22d2d47087de5Bill Gruber * A utility class that provides operations for parsing extended metadata embedded in 320e092f806b0a4b81785a52da8ba22d2d47087de5Bill Gruber * DRM constraint information. If a DRM scheme has specific constraints beyond the standard 330e092f806b0a4b81785a52da8ba22d2d47087de5Bill Gruber * constraints, the constraints will show up in the 340e092f806b0a4b81785a52da8ba22d2d47087de5Bill Gruber * {@link DrmStore.ConstraintsColumns#EXTENDED_METADATA} key. You can use 350e092f806b0a4b81785a52da8ba22d2d47087de5Bill Gruber * {@link DrmUtils.ExtendedMetadataParser} to iterate over those values. 36d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi */ 37d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshipublic class DrmUtils { 38d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi /* Should be used when we need to read from local file */ 39d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi /* package */ static byte[] readBytes(String path) throws IOException { 40d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi File file = new File(path); 41d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi return readBytes(file); 42d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 43d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 44d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi /* Should be used when we need to read from local file */ 45d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi /* package */ static byte[] readBytes(File file) throws IOException { 46d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi FileInputStream inputStream = new FileInputStream(file); 47d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi BufferedInputStream bufferedStream = new BufferedInputStream(inputStream); 48d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi byte[] data = null; 49d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 50d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi try { 51d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi int length = bufferedStream.available(); 52d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi if (length > 0) { 53d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi data = new byte[length]; 54d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi // read the entire data 55d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi bufferedStream.read(data); 56d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 57d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } finally { 58f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong quietlyDispose(bufferedStream); 59f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong quietlyDispose(inputStream); 60d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 61d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi return data; 62d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 63d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 64d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi /* package */ static void writeToFile(final String path, byte[] data) throws IOException { 65d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi /* check for invalid inputs */ 66d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi FileOutputStream outputStream = null; 67d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 68d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi if (null != path && null != data) { 69d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi try { 70d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi outputStream = new FileOutputStream(path); 71d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi outputStream.write(data); 72d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } finally { 73f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong quietlyDispose(outputStream); 74d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 75d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 76d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 77d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 78d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi /* package */ static void removeFile(String path) throws IOException { 79d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi File file = new File(path); 80d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi file.delete(); 81d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 82d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 8321d71a4c8aa70ef9e133d18097a855cc23f29faeisaid private static void quietlyDispose(Closeable closable) { 84d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi try { 8521d71a4c8aa70ef9e133d18097a855cc23f29faeisaid if (null != closable) { 8621d71a4c8aa70ef9e133d18097a855cc23f29faeisaid closable.close(); 87d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 88d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } catch (IOException e) { 89d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi // no need to care, at least as of now 90d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 91d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 92d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 93d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi /** 940e092f806b0a4b81785a52da8ba22d2d47087de5Bill Gruber * Gets an instance of {@link DrmUtils.ExtendedMetadataParser}, which can be used to parse 950e092f806b0a4b81785a52da8ba22d2d47087de5Bill Gruber * extended metadata embedded in DRM constraint information. 96d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * 970e092f806b0a4b81785a52da8ba22d2d47087de5Bill Gruber * @param extendedMetadata Object in which key-value pairs of extended metadata are embedded. 98d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * 99d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi */ 100d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi public static ExtendedMetadataParser getExtendedMetadataParser(byte[] extendedMetadata) { 101d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi return new ExtendedMetadataParser(extendedMetadata); 102d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 103d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 104d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi /** 1050e092f806b0a4b81785a52da8ba22d2d47087de5Bill Gruber * Utility that parses extended metadata embedded in DRM constraint information. 1060e092f806b0a4b81785a52da8ba22d2d47087de5Bill Gruber *<p> 1070e092f806b0a4b81785a52da8ba22d2d47087de5Bill Gruber * Usage example: 1080e092f806b0a4b81785a52da8ba22d2d47087de5Bill Gruber *<p> 109d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * byte[] extendedMetadata<br> 110d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * = 111d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * constraints.getAsByteArray(DrmStore.ConstraintsColumns.EXTENDED_METADATA);<br> 112d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * ExtendedMetadataParser parser = getExtendedMetadataParser(extendedMetadata);<br> 113d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * Iterator keyIterator = parser.keyIterator();<br> 114d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * while (keyIterator.hasNext()) {<br> 115d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * String extendedMetadataKey = keyIterator.next();<br> 116d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * String extendedMetadataValue = 117d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * parser.get(extendedMetadataKey);<br> 118d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * } 119d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi */ 120d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi public static class ExtendedMetadataParser { 121d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi HashMap<String, String> mMap = new HashMap<String, String>(); 122d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 123d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi private int readByte(byte[] constraintData, int arrayIndex) { 124d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi //Convert byte[] into int. 125d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi return (int)constraintData[arrayIndex]; 126d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 127d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 128d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi private String readMultipleBytes( 129d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi byte[] constraintData, int numberOfBytes, int arrayIndex) { 130d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi byte[] returnBytes = new byte[numberOfBytes]; 131d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi for (int j = arrayIndex, i = 0; j < arrayIndex + numberOfBytes; j++,i++) { 132d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi returnBytes[i] = constraintData[j]; 133d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 134d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi return new String(returnBytes); 135d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 136d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 137d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi /* 138d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * This will parse the following format 139d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi * KeyLengthValueLengthKeyValueKeyLength1ValueLength1Key1Value1..\0 140d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi */ 141d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi private ExtendedMetadataParser(byte[] constraintData) { 142d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi //Extract KeyValue Pair Info, till terminator occurs. 143d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi int index = 0; 144d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 145d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi while (index < constraintData.length) { 146d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi //Parse Key Length 147d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi int keyLength = readByte(constraintData, index); 148d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi index++; 149d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 150d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi //Parse Value Length 151d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi int valueLength = readByte(constraintData, index); 152d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi index++; 153d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 154d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi //Fetch key 155d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi String strKey = readMultipleBytes(constraintData, keyLength, index); 156d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi index += keyLength; 157d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 158d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi //Fetch Value 159d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi String strValue = readMultipleBytes(constraintData, valueLength, index); 160c7b3ccc564448cb4b918728421f9402bc18278c5Takeshi Aimi if (strValue.equals(" ")) { 161c7b3ccc564448cb4b918728421f9402bc18278c5Takeshi Aimi strValue = ""; 162c7b3ccc564448cb4b918728421f9402bc18278c5Takeshi Aimi } 163d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi index += valueLength; 164d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi mMap.put(strKey, strValue); 165d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 166d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 167d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 168f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong /** 169f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong * This method returns an iterator object that can be used to iterate over 170f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong * all values of the metadata. 171f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong * 172f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong * @return The iterator object. 173f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong */ 174d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi public Iterator<String> iterator() { 175d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi return mMap.values().iterator(); 176d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 177d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 178f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong /** 179f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong * This method returns an iterator object that can be used to iterate over 180f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong * all keys of the metadata. 181f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong * 182f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong * @return The iterator object. 183f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong */ 184d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi public Iterator<String> keyIterator() { 185d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi return mMap.keySet().iterator(); 186d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 187d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 188f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong /** 189f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong * This method retrieves the metadata value associated with a given key. 190f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong * 191f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong * @param key The key whose value is being retrieved. 192f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong * 193f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong * @return The metadata value associated with the given key. Returns null 194f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong * if the key is not found. 195f7a68fc98550859019bb0636fc3e8d88cb50e6a6James Dong */ 196d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi public String get(String key) { 197d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi return mMap.get(key); 198d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 199d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi } 200d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi} 201d074e30ce44b9e33da43b67a4515b8986ca72b26aimitakeshi 202