15a77537f31715ac32112f47a569eded13dce5f1bJohn Reck/* 25a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * Copyright (C) 2010 The Android Open Source Project 35a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * 45a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * Licensed under the Apache License, Version 2.0 (the "License"); 55a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * you may not use this file except in compliance with the License. 65a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * You may obtain a copy of the License at 75a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * 85a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * http://www.apache.org/licenses/LICENSE-2.0 95a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * 105a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * Unless required by applicable law or agreed to in writing, software 115a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * distributed under the License is distributed on an "AS IS" BASIS, 125a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * See the License for the specific language governing permissions and 145a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * limitations under the License. 155a77537f31715ac32112f47a569eded13dce5f1bJohn Reck */ 165a77537f31715ac32112f47a569eded13dce5f1bJohn Reck 175a77537f31715ac32112f47a569eded13dce5f1bJohn Reckpackage android.drm; 185a77537f31715ac32112f47a569eded13dce5f1bJohn Reck 195a77537f31715ac32112f47a569eded13dce5f1bJohn Reckimport java.io.BufferedInputStream; 205a77537f31715ac32112f47a569eded13dce5f1bJohn Reckimport java.io.File; 215a77537f31715ac32112f47a569eded13dce5f1bJohn Reckimport java.io.FileInputStream; 225a77537f31715ac32112f47a569eded13dce5f1bJohn Reckimport java.io.FileNotFoundException; 235a77537f31715ac32112f47a569eded13dce5f1bJohn Reckimport java.io.FileOutputStream; 245a77537f31715ac32112f47a569eded13dce5f1bJohn Reckimport java.io.IOException; 255a77537f31715ac32112f47a569eded13dce5f1bJohn Reckimport java.io.InputStream; 265a77537f31715ac32112f47a569eded13dce5f1bJohn Reckimport java.io.OutputStream; 275a77537f31715ac32112f47a569eded13dce5f1bJohn Reckimport java.util.HashMap; 285a77537f31715ac32112f47a569eded13dce5f1bJohn Reckimport java.util.Iterator; 295a77537f31715ac32112f47a569eded13dce5f1bJohn Reck 305a77537f31715ac32112f47a569eded13dce5f1bJohn Reck/** 315a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * A utility class that provides operations for parsing extended metadata embedded in 325a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * DRM constraint information. If a DRM scheme has specific constraints beyond the standard 335a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * constraints, the constraints will show up in the 345a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * {@link DrmStore.ConstraintsColumns#EXTENDED_METADATA} key. You can use 355a77537f31715ac32112f47a569eded13dce5f1bJohn Reck * {@link DrmUtils.ExtendedMetadataParser} to iterate over those values. 365a77537f31715ac32112f47a569eded13dce5f1bJohn Reck */ 375a77537f31715ac32112f47a569eded13dce5f1bJohn Reckpublic class DrmUtils { 385a77537f31715ac32112f47a569eded13dce5f1bJohn Reck /* Should be used when we need to read from local file */ 395a77537f31715ac32112f47a569eded13dce5f1bJohn Reck /* package */ static byte[] readBytes(String path) throws IOException { 405a77537f31715ac32112f47a569eded13dce5f1bJohn Reck File file = new File(path); 415a77537f31715ac32112f47a569eded13dce5f1bJohn Reck return readBytes(file); 425a77537f31715ac32112f47a569eded13dce5f1bJohn Reck } 435a77537f31715ac32112f47a569eded13dce5f1bJohn Reck 445a77537f31715ac32112f47a569eded13dce5f1bJohn Reck /* Should be used when we need to read from local file */ 455a77537f31715ac32112f47a569eded13dce5f1bJohn Reck /* package */ static byte[] readBytes(File file) throws IOException { 465a77537f31715ac32112f47a569eded13dce5f1bJohn Reck FileInputStream inputStream = new FileInputStream(file); 475a77537f31715ac32112f47a569eded13dce5f1bJohn Reck BufferedInputStream bufferedStream = new BufferedInputStream(inputStream); 485a77537f31715ac32112f47a569eded13dce5f1bJohn Reck byte[] data = null; 49914c5591baeb86bf30a5bc28930071442a822d60Ben Murdoch 505a77537f31715ac32112f47a569eded13dce5f1bJohn Reck try { 515a77537f31715ac32112f47a569eded13dce5f1bJohn Reck int length = bufferedStream.available(); 525a77537f31715ac32112f47a569eded13dce5f1bJohn Reck if (length > 0) { 535a77537f31715ac32112f47a569eded13dce5f1bJohn Reck data = new byte[length]; 545a77537f31715ac32112f47a569eded13dce5f1bJohn Reck // read the entire data 555a77537f31715ac32112f47a569eded13dce5f1bJohn Reck bufferedStream.read(data); 565a77537f31715ac32112f47a569eded13dce5f1bJohn Reck } 575a77537f31715ac32112f47a569eded13dce5f1bJohn Reck } finally { 585a77537f31715ac32112f47a569eded13dce5f1bJohn Reck quiteDispose(bufferedStream); 595a77537f31715ac32112f47a569eded13dce5f1bJohn Reck quiteDispose(inputStream); 605a77537f31715ac32112f47a569eded13dce5f1bJohn Reck } 615a77537f31715ac32112f47a569eded13dce5f1bJohn Reck return data; 625a77537f31715ac32112f47a569eded13dce5f1bJohn Reck } 635a77537f31715ac32112f47a569eded13dce5f1bJohn Reck 645a77537f31715ac32112f47a569eded13dce5f1bJohn Reck /* package */ static void writeToFile(final String path, byte[] data) throws IOException { 655a77537f31715ac32112f47a569eded13dce5f1bJohn Reck /* check for invalid inputs */ 662b00b825565a166e9969df25597c1df75ee28dacKristian Monsen FileOutputStream outputStream = null; 675a77537f31715ac32112f47a569eded13dce5f1bJohn Reck 685a77537f31715ac32112f47a569eded13dce5f1bJohn Reck if (null != path && null != data) { 695a77537f31715ac32112f47a569eded13dce5f1bJohn Reck try { 705a77537f31715ac32112f47a569eded13dce5f1bJohn Reck outputStream = new FileOutputStream(path); 715a77537f31715ac32112f47a569eded13dce5f1bJohn Reck outputStream.write(data); 725a77537f31715ac32112f47a569eded13dce5f1bJohn Reck } finally { 735a77537f31715ac32112f47a569eded13dce5f1bJohn Reck quiteDispose(outputStream); 745a77537f31715ac32112f47a569eded13dce5f1bJohn Reck } 755a77537f31715ac32112f47a569eded13dce5f1bJohn Reck } 765a77537f31715ac32112f47a569eded13dce5f1bJohn Reck } 775a77537f31715ac32112f47a569eded13dce5f1bJohn Reck 785a77537f31715ac32112f47a569eded13dce5f1bJohn Reck /* package */ static void removeFile(String path) throws IOException { 795a77537f31715ac32112f47a569eded13dce5f1bJohn Reck File file = new File(path); 805a77537f31715ac32112f47a569eded13dce5f1bJohn Reck file.delete(); 815a77537f31715ac32112f47a569eded13dce5f1bJohn Reck } 825a77537f31715ac32112f47a569eded13dce5f1bJohn Reck 835a77537f31715ac32112f47a569eded13dce5f1bJohn Reck private static void quiteDispose(InputStream stream) { 845a77537f31715ac32112f47a569eded13dce5f1bJohn Reck try { 855a77537f31715ac32112f47a569eded13dce5f1bJohn Reck if (null != stream) { 865a77537f31715ac32112f47a569eded13dce5f1bJohn Reck stream.close(); 875a77537f31715ac32112f47a569eded13dce5f1bJohn Reck } 885a77537f31715ac32112f47a569eded13dce5f1bJohn Reck } catch (IOException e) { 895a77537f31715ac32112f47a569eded13dce5f1bJohn Reck // no need to care, at least as of now 905a77537f31715ac32112f47a569eded13dce5f1bJohn Reck } 91 } 92 93 private static void quiteDispose(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 */ 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 133 private int readByte(byte[] constraintData, int arrayIndex) { 134 //Convert byte[] into int. 135 return (int)constraintData[arrayIndex]; 136 } 137 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 */ 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 public Iterator<String> iterator() { 179 return mMap.values().iterator(); 180 } 181 182 public Iterator<String> keyIterator() { 183 return mMap.keySet().iterator(); 184 } 185 186 public String get(String key) { 187 return mMap.get(key); 188 } 189 } 190} 191 192