1 /* 2 * Copyright (C) 2007 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.mobile1; 18 19 import java.io.*; 20 21 /** 22 * This class provides interfaces to access the DRM raw content. 23 */ 24 public class DrmRawContent { 25 /** 26 * The "application/vnd.oma.drm.message" mime type. 27 */ 28 public static final String DRM_MIMETYPE_MESSAGE_STRING = "application/vnd.oma.drm.message"; 29 30 /** 31 * The "application/vnd.oma.drm.content" mime type. 32 */ 33 public static final String DRM_MIMETYPE_CONTENT_STRING = "application/vnd.oma.drm.content"; 34 35 /** 36 * The DRM delivery type: Forward-Lock 37 */ 38 public static final int DRM_FORWARD_LOCK = 1; 39 40 /** 41 * The DRM delivery type: Combined Delivery 42 */ 43 public static final int DRM_COMBINED_DELIVERY = 2; 44 45 /** 46 * The DRM delivery type: Separate Delivery 47 */ 48 public static final int DRM_SEPARATE_DELIVERY = 3; 49 50 /** 51 * The DRM delivery type: Separate Delivery in DRM message 52 */ 53 public static final int DRM_SEPARATE_DELIVERY_DM = 4; 54 55 /** 56 * The DRM media content length is unknown currently 57 */ 58 public static final int DRM_UNKNOWN_DATA_LEN = -1; 59 60 61 /** 62 * The id of "application/vnd.oma.drm.message" mime type. 63 */ 64 private static final int DRM_MIMETYPE_MESSAGE = 1; 65 66 /** 67 * The id of "application/vnd.oma.drm.content" mime type. 68 */ 69 private static final int DRM_MIMETYPE_CONTENT = 2; 70 71 /** 72 * Successful operation. 73 */ 74 private static final int JNI_DRM_SUCCESS = 0; 75 76 /** 77 * General failure. 78 */ 79 private static final int JNI_DRM_FAILURE = -1; 80 81 /** 82 * Indicates the end of the DRM content is reached. 83 */ 84 private static final int JNI_DRM_EOF = -2; 85 86 /** 87 * The media content length is unknown from native method 88 */ 89 private static final int JNI_DRM_UNKNOWN_DATA_LEN = -3; 90 91 /** 92 * The member to save the original InputStream data. 93 */ 94 private BufferedInputStream inData; 95 96 /** 97 * The member to save the original InputStream data length. 98 */ 99 private int inDataLen; 100 101 /** 102 * The unique id to this DRM content. It will be initialized 103 * in constructor by native method. And it will not be changed 104 * after initialization. 105 */ 106 private int id; 107 108 /** 109 * The rights issuer address of this DRM object. 110 */ 111 private String rightsIssuer; 112 113 /** 114 * The media content type of this DRM object. 115 */ 116 private String mediaType; 117 118 /** 119 * The delivery method type of this DRM object. 120 */ 121 private int rawType; 122 123 124 /** 125 * Construct a DrmRawContent object. 126 * 127 * @param inRawdata object of DRM raw data stream. 128 * @param len the length of raw data can be read. 129 * @param mimeTypeStr the mime type of the DRM content. 130 */ 131 public DrmRawContent(InputStream inRawdata, int len, String mimeTypeStr) throws DrmException, IOException { 132 int mimeType; 133 134 id = -1; 135 inData = new BufferedInputStream(inRawdata, 1024); 136 inDataLen = len; 137 138 if (DRM_MIMETYPE_MESSAGE_STRING.equals(mimeTypeStr)) 139 mimeType = DRM_MIMETYPE_MESSAGE; 140 else if (DRM_MIMETYPE_CONTENT_STRING.equals(mimeTypeStr)) 141 mimeType = DRM_MIMETYPE_CONTENT; 142 else 143 throw new IllegalArgumentException("mimeType must be DRM_MIMETYPE_MESSAGE or DRM_MIMETYPE_CONTENT"); 144 145 if (len <= 0) 146 throw new IllegalArgumentException("len must be > 0"); 147 148 /* call native method to initialize this DRM content */ 149 id = nativeConstructDrmContent(inData, inDataLen, mimeType); 150 151 if (JNI_DRM_FAILURE == id) 152 throw new DrmException("nativeConstructDrmContent() returned JNI_DRM_FAILURE"); 153 154 /* init the rights issuer field. */ 155 rightsIssuer = nativeGetRightsAddress(); 156 157 /* init the raw content type. */ 158 rawType = nativeGetDeliveryMethod(); 159 if (JNI_DRM_FAILURE == rawType) 160 throw new DrmException("nativeGetDeliveryMethod() returned JNI_DRM_FAILURE"); 161 162 /* init the media content type. */ 163 mediaType = nativeGetContentType(); 164 if (null == mediaType) 165 throw new DrmException("nativeGetContentType() returned null"); 166 } 167 168 /** 169 * Get rights address from raw Seperate Delivery content. 170 * 171 * @return the string of the rights issuer address, 172 * or null if no rights issuer. 173 */ 174 public String getRightsAddress() { 175 return rightsIssuer; 176 } 177 178 /** 179 * Get the type of the raw DRM content. 180 * 181 * @return one of the following delivery type of this DRM content: 182 * #DRM_FORWARD_LOCK 183 * #DRM_COMBINED_DELIVERY 184 * #DRM_SEPARATE_DELIVERY 185 * #DRM_SEPARATE_DELIVERY_DM 186 */ 187 public int getRawType() { 188 return rawType; 189 } 190 191 /** 192 * Get one InputStream object to read decrypted content. 193 * 194 * @param rights the rights object contain decrypted key. 195 * 196 * @return the InputStream object of decrypted media content. 197 */ 198 public InputStream getContentInputStream(DrmRights rights) { 199 if (null == rights) 200 throw new NullPointerException(); 201 202 return new DrmInputStream(rights); 203 } 204 205 /** 206 * Get the type of the decrypted media content. 207 * 208 * @return the decrypted media content type of this DRM content. 209 */ 210 public String getContentType() { 211 return mediaType; 212 } 213 214 /** 215 * Get the length of the decrypted media content. 216 * 217 * @param rights the rights object contain decrypted key. 218 * 219 * @return the length of the decrypted media content. 220 * #DRM_UNKNOWN_DATA_LEN if the length is unknown currently. 221 */ 222 public int getContentLength(DrmRights rights) throws DrmException { 223 /** 224 * Because currently the media object associate with rights object 225 * has been handled in native logic, so here it is not need to deal 226 * the rights. But for the apps, it is mandatory for user to get 227 * the rights object before get the media content length. 228 */ 229 if (null == rights) 230 throw new NullPointerException(); 231 232 int mediaLen = nativeGetContentLength(); 233 234 if (JNI_DRM_FAILURE == mediaLen) 235 throw new DrmException("nativeGetContentLength() returned JNI_DRM_FAILURE"); 236 237 if (JNI_DRM_UNKNOWN_DATA_LEN == mediaLen) 238 return DRM_UNKNOWN_DATA_LEN; 239 240 return mediaLen; 241 } 242 243 /** 244 * This class provide a InputStream to the DRM media content. 245 */ 246 class DrmInputStream extends InputStream 247 { 248 /** 249 * The flag to indicate whether this stream is closed or not. 250 */ 251 private boolean isClosed; 252 253 /** 254 * The offset of this DRM content to be reset. 255 */ 256 private int offset; 257 258 /** 259 * A byte of data to be readed. 260 */ 261 private byte[] b; 262 263 /** 264 * Construct a DrmInputStream instance. 265 */ 266 public DrmInputStream(DrmRights rights) { 267 /** 268 * Because currently the media object associate with rights object 269 * has been handled in native logic, so here it is not need to deal 270 * the rights. But for the apps, it is mandatory for user to get 271 * the rights object before get the media content data. 272 */ 273 274 isClosed = false; 275 offset = 0; 276 b = new byte[1]; 277 } 278 279 /* Non-javadoc 280 * @see java.io.InputStream#available() 281 */ 282 public int available() throws IOException { 283 /* call native method to get this DRM decrypted media content length */ 284 int len = nativeGetContentLength(); 285 286 if (JNI_DRM_FAILURE == len) 287 throw new IOException(); 288 289 /* if the length is unknown, just return 0 for available value */ 290 if (JNI_DRM_UNKNOWN_DATA_LEN == len) 291 return 0; 292 293 int availableLen = len - offset; 294 if (availableLen < 0) 295 throw new IOException(); 296 297 return availableLen; 298 } 299 300 /* Non-javadoc 301 * @see java.io.InputStream#read() 302 */ 303 public int read() throws IOException { 304 int res; 305 306 res = read(b, 0, 1); 307 308 if (-1 == res) 309 return -1; 310 311 return b[0] & 0xff; 312 } 313 314 /* Non-javadoc 315 * @see java.io.InputStream#read(byte) 316 */ 317 public int read(byte[] b) throws IOException { 318 return read(b, 0, b.length); 319 } 320 321 /* Non-javadoc 322 * @see java.io.InputStream#read(byte, int, int) 323 */ 324 public int read(byte[] b, int off, int len) throws IOException { 325 if (null == b) 326 throw new NullPointerException(); 327 if (off < 0 || len < 0 || off + len > b.length) 328 throw new IndexOutOfBoundsException(); 329 if (true == isClosed) 330 throw new IOException(); 331 332 if (0 == len) 333 return 0; 334 335 len = nativeReadContent(b, off, len, offset); 336 337 if (JNI_DRM_FAILURE == len) 338 throw new IOException(); 339 else if (JNI_DRM_EOF == len) 340 return -1; 341 342 offset += len; 343 344 return len; 345 } 346 347 /* Non-javadoc 348 * @see java.io.InputStream#markSupported() 349 */ 350 public boolean markSupported() { 351 return false; 352 } 353 354 /* Non-javadoc 355 * @see java.io.InputStream#mark(int) 356 */ 357 public void mark(int readlimit) { 358 } 359 360 /* Non-javadoc 361 * @see java.io.InputStream#reset() 362 */ 363 public void reset() throws IOException { 364 throw new IOException(); 365 } 366 367 /* Non-javadoc 368 * @see java.io.InputStream#skip() 369 */ 370 public long skip(long n) throws IOException { 371 return 0; 372 } 373 374 /* Non-javadoc 375 * @see java.io.InputStream#close() 376 */ 377 public void close() { 378 isClosed = true; 379 } 380 } 381 382 /** 383 * native method: construct a DRM content according the mime type. 384 * 385 * @param data input DRM content data to be parsed. 386 * @param len the length of the data. 387 * @param mimeType the mime type of this DRM content. the value of this field includes: 388 * #DRM_MIMETYPE_MESSAGE 389 * #DRM_MIMETYPE_CONTENT 390 * 391 * @return #the id of the DRM content if succeed. 392 * #JNI_DRM_FAILURE if fail. 393 */ 394 private native int nativeConstructDrmContent(InputStream data, int len, int mimeType); 395 396 /** 397 * native method: get this DRM content rights issuer. 398 * 399 * @return the address of rights issuer if in case of separate delivery. 400 * null if not separete delivery, or otherwise. 401 */ 402 private native String nativeGetRightsAddress(); 403 404 /** 405 * native method: get this DRM content delivery type. 406 * 407 * @return the delivery method, the value may be one of the following: 408 * #DRM_FORWARD_LOCK 409 * #DRM_COMBINED_DELIVERY 410 * #DRM_SEPARATE_DELIVERY 411 * #DRM_SEPARATE_DELIVERY_DM 412 * #JNI_DRM_FAILURE if fail. 413 */ 414 private native int nativeGetDeliveryMethod(); 415 416 /** 417 * native method: get a piece of media content data. 418 * 419 * @param buf the buffer to save DRM media content data. 420 * @param bufOff the offset of the buffer to start to save data. 421 * @param len the number of byte to read. 422 * @param mediaOff the offset of the media content data to start to read. 423 * 424 * @return the length of the media content data has been read. 425 * #JNI_DRM_EOF if reach to end of the media content. 426 * #JNI_DRM_FAILURE if fail. 427 */ 428 private native int nativeReadContent(byte[] buf, int bufOff, int len, int mediaOff); 429 430 /** 431 * native method: get this DRM content type. 432 * 433 * @return the decrypted media content type. 434 * null if fail. 435 */ 436 private native String nativeGetContentType(); 437 438 /** 439 * native method: get this DRM decrypted media content length. 440 * 441 * @return the length of decrypted media content. 442 * #JNI_DRM_FAILURE if fail. 443 * #JNI_DRM_UNKNOWN_DATA_LEN if the length is unknown currently. 444 */ 445 private native int nativeGetContentLength(); 446 447 /** 448 * The finalizer of the DRMRawContent. Do some cleanup. 449 */ 450 protected native void finalize(); 451 452 453 /** 454 * Load the shared library to link the native methods. 455 */ 456 static { 457 try { 458 System.loadLibrary("drm1_jni"); 459 } 460 catch (UnsatisfiedLinkError ule) { 461 System.err.println("WARNING: Could not load libdrm1_jni.so"); 462 } 463 } 464 } 465