diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | 54b6cfa9a9e5b861a9930af873580d6dc20f773c (patch) | |
tree | 35051494d2af230dce54d6b31c6af8fc24091316 /media/libdrm/mobile1 | |
download | frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.zip frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.gz frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.bz2 |
Initial Contribution
Diffstat (limited to 'media/libdrm/mobile1')
26 files changed, 9076 insertions, 0 deletions
diff --git a/media/libdrm/mobile1/Android.mk b/media/libdrm/mobile1/Android.mk new file mode 100644 index 0000000..2065cd2 --- /dev/null +++ b/media/libdrm/mobile1/Android.mk @@ -0,0 +1,81 @@ +LOCAL_PATH := $(call my-dir) + +# --------------------------------------- +# First project +# +# Build DRM1 core library +# +# Output: libdrm1.so +# --------------------------------------- +include $(CLEAR_VARS) + +ifeq ($(TARGET_ARCH), arm) +LOCAL_DRM_CFLAG = -DDRM_DEVICE_ARCH_ARM +endif + +ifeq ($(TARGET_ARCH), x86) +LOCAL_DRM_CFLAG = -DDRM_DEVICE_ARCH_X86 +endif + +# DRM 1.0 core source files +LOCAL_SRC_FILES := \ + src/objmng/drm_decoder.c \ + src/objmng/drm_file.c \ + src/objmng/drm_i18n.c \ + src/objmng/drm_time.c \ + src/objmng/drm_api.c \ + src/objmng/drm_rights_manager.c \ + src/parser/parser_dcf.c \ + src/parser/parser_dm.c \ + src/parser/parser_rel.c \ + src/xml/xml_tinyparser.c + +# Header files path +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/include/objmng \ + $(LOCAL_PATH)/include/parser \ + $(LOCAL_PATH)/include/xml \ + external/aes \ + $(call include-path-for, system-core)/cutils + +LOCAL_CFLAGS := $(LOCAL_DRM_CFLAG) + +LOCAL_SHARED_LIBRARIES := \ + libaes \ + libutils \ + libcutils + +LOCAL_MODULE := libdrm1 + +include $(BUILD_SHARED_LIBRARY) + +# --------------------------------------- +# Second project +# +# Build DRM1 Java Native Interface(JNI) library +# +# Output: libdrm1_jni.so +# ------------------------------------------------ +include $(CLEAR_VARS) + +# Source files of DRM1 Java Native Interfaces +LOCAL_SRC_FILES := \ + src/jni/drm1_jni.c + +# Header files path +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/include/parser \ + $(JNI_H_INCLUDE) \ + $(call include-path-for, system-core)/cutils \ + external/aes + + +LOCAL_SHARED_LIBRARIES := libdrm1 \ + libutils \ + libcutils + +LOCAL_MODULE := libdrm1_jni + +include $(BUILD_SHARED_LIBRARY) diff --git a/media/libdrm/mobile1/include/drm_common_types.h b/media/libdrm/mobile1/include/drm_common_types.h new file mode 100644 index 0000000..c6bea61 --- /dev/null +++ b/media/libdrm/mobile1/include/drm_common_types.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COMMON_TYPES_H__ +#define __COMMON_TYPES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <assert.h> +#include <ctype.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define Trace(...) + +#ifdef __cplusplus +} +#endif + +#endif /* __COMMON_TYPES_H__ */ diff --git a/media/libdrm/mobile1/include/jni/drm1_jni.h b/media/libdrm/mobile1/include/jni/drm1_jni.h new file mode 100644 index 0000000..64e78ad --- /dev/null +++ b/media/libdrm/mobile1/include/jni/drm1_jni.h @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DRM1_JNI_H__ +#define __DRM1_JNI_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class android_drm_mobile1_DrmRawContent */ + +#undef android_drm_mobile1_DrmRawContent_DRM_FORWARD_LOCK +#define android_drm_mobile1_DrmRawContent_DRM_FORWARD_LOCK 1L +#undef android_drm_mobile1_DrmRawContent_DRM_COMBINED_DELIVERY +#define android_drm_mobile1_DrmRawContent_DRM_COMBINED_DELIVERY 2L +#undef android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY +#define android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY 3L +#undef android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY_DM +#define android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY_DM 4L +#undef android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_MESSAGE +#define android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_MESSAGE 1L +#undef android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_CONTENT +#define android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_CONTENT 2L +#undef android_drm_mobile1_DrmRawContent_JNI_DRM_SUCCESS +#define android_drm_mobile1_DrmRawContent_JNI_DRM_SUCCESS 0L +#undef android_drm_mobile1_DrmRawContent_JNI_DRM_FAILURE +#define android_drm_mobile1_DrmRawContent_JNI_DRM_FAILURE -1L +#undef android_drm_mobile1_DrmRawContent_JNI_DRM_EOF +#define android_drm_mobile1_DrmRawContent_JNI_DRM_EOF -2L +#undef android_drm_mobile1_DrmRawContent_JNI_DRM_UNKNOWN_DATA_LEN +#define android_drm_mobile1_DrmRawContent_JNI_DRM_UNKNOWN_DATA_LEN -3L +/* + * Class: android_drm_mobile1_DrmRawContent + * Method: nativeConstructDrmContent + * Signature: (Ljava/io/InputStream;II)I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRawContent_nativeConstructDrmContent + (JNIEnv *, jobject, jobject, jint, jint); + +/* + * Class: android_drm_mobile1_DrmRawContent + * Method: nativeGetRightsAddress + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_android_drm_mobile1_DrmRawContent_nativeGetRightsAddress + (JNIEnv *, jobject); + +/* + * Class: android_drm_mobile1_DrmRawContent + * Method: nativeGetDeliveryMethod + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRawContent_nativeGetDeliveryMethod + (JNIEnv *, jobject); + +/* + * Class: android_drm_mobile1_DrmRawContent + * Method: nativeReadPieceOfContent + * Signature: ([BIII)I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRawContent_nativeReadContent + (JNIEnv *, jobject, jbyteArray, jint, jint, jint); + +/* + * Class: android_drm_mobile1_DrmRawContent + * Method: nativeGetContentType + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_android_drm_mobile1_DrmRawContent_nativeGetContentType + (JNIEnv *, jobject); + +/* + * Class: android_drm_mobile1_DrmRawContent + * Method: nativeGetContentLength + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRawContent_nativeGetContentLength + (JNIEnv *, jobject); + +/* + * Class: android_drm_mobile1_DrmRawContent + * Method: finalize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_android_drm_mobile1_DrmRawContent_finalize + (JNIEnv *, jobject); + +/* Header for class android_drm_mobile1_DrmRights */ + +#undef android_drm_mobile1_DrmRights_DRM_PERMISSION_PLAY +#define android_drm_mobile1_DrmRights_DRM_PERMISSION_PLAY 1L +#undef android_drm_mobile1_DrmRights_DRM_PERMISSION_DISPLAY +#define android_drm_mobile1_DrmRights_DRM_PERMISSION_DISPLAY 2L +#undef android_drm_mobile1_DrmRights_DRM_PERMISSION_EXECUTE +#define android_drm_mobile1_DrmRights_DRM_PERMISSION_EXECUTE 3L +#undef android_drm_mobile1_DrmRights_DRM_PERMISSION_PRINT +#define android_drm_mobile1_DrmRights_DRM_PERMISSION_PRINT 4L +#undef android_drm_mobile1_DrmRights_DRM_CONSUME_RIGHTS_SUCCESS +#define android_drm_mobile1_DrmRights_DRM_CONSUME_RIGHTS_SUCCESS 0L +#undef android_drm_mobile1_DrmRights_DRM_CONSUME_RIGHTS_FAILURE +#define android_drm_mobile1_DrmRights_DRM_CONSUME_RIGHTS_FAILURE -1L +#undef android_drm_mobile1_DrmRights_JNI_DRM_SUCCESS +#define android_drm_mobile1_DrmRights_JNI_DRM_SUCCESS 0L +#undef android_drm_mobile1_DrmRights_JNI_DRM_FAILURE +#define android_drm_mobile1_DrmRights_JNI_DRM_FAILURE -1L +/* + * Class: android_drm_mobile1_DrmRights + * Method: nativeGetConstraintInfo + * Signature: (ILandroid/drm/mobile1/DrmConstraintInfo;)I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRights_nativeGetConstraintInfo + (JNIEnv *, jobject, jint, jobject); + +/* + * Class: android_drm_mobile1_DrmRights + * Method: nativeConsumeRights + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRights_nativeConsumeRights + (JNIEnv *, jobject, jint); + +/* Header for class android_drm_mobile1_DrmRightsManager */ + +#undef android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_XML +#define android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_XML 3L +#undef android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_WBXML +#define android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_WBXML 4L +#undef android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_MESSAGE +#define android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_MESSAGE 1L +#undef android_drm_mobile1_DrmRightsManager_JNI_DRM_SUCCESS +#define android_drm_mobile1_DrmRightsManager_JNI_DRM_SUCCESS 0L +#undef android_drm_mobile1_DrmRightsManager_JNI_DRM_FAILURE +#define android_drm_mobile1_DrmRightsManager_JNI_DRM_FAILURE -1L +/* Inaccessible static: singleton */ +/* + * Class: android_drm_mobile1_DrmRightsManager + * Method: nativeInstallDrmRights + * Signature: (Ljava/io/InputStream;IILandroid/drm/mobile1/DrmRights;)I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRightsManager_nativeInstallDrmRights + (JNIEnv *, jobject, jobject, jint, jint, jobject); + +/* + * Class: android_drm_mobile1_DrmRightsManager + * Method: nativeQueryRights + * Signature: (Landroid/drm/mobile1/DrmRawContent;Landroid/drm/mobile1/DrmRights;)I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRightsManager_nativeQueryRights + (JNIEnv *, jobject, jobject, jobject); + +/* + * Class: android_drm_mobile1_DrmRightsManager + * Method: nativeGetRightsNumber + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRightsManager_nativeGetNumOfRights + (JNIEnv *, jobject); + +/* + * Class: android_drm_mobile1_DrmRightsManager + * Method: nativeGetRightsList + * Signature: ([Landroid/drm/mobile1/DrmRights;I)I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRightsManager_nativeGetRightsList + (JNIEnv *, jobject, jobjectArray, jint); + +/* + * Class: android_drm_mobile1_DrmRightsManager + * Method: nativeDeleteRights + * Signature: (Landroid/drm/mobile1/DrmRights;)I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRightsManager_nativeDeleteRights + (JNIEnv *, jobject, jobject); + +/** + * DRM return value defines + */ +#define JNI_DRM_SUCCESS \ + android_drm_mobile1_DrmRawContent_JNI_DRM_SUCCESS /**< Successful operation */ +#define JNI_DRM_FAILURE \ + android_drm_mobile1_DrmRawContent_JNI_DRM_FAILURE /**< General failure */ +#define JNI_DRM_EOF \ + android_drm_mobile1_DrmRawContent_JNI_DRM_EOF /**< Indicates the end of the DRM content is reached */ +#define JNI_DRM_UNKNOWN_DATA_LEN \ + android_drm_mobile1_DrmRawContent_JNI_DRM_UNKNOWN_DATA_LEN /**< Indicates the data length is unknown */ + +/** + * DRM MIME type defines + */ +#define JNI_DRM_MIMETYPE_MESSAGE \ + android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_MESSAGE /**< The "application/vnd.oma.drm.message" MIME type */ +#define JNI_DRM_MIMETYPE_CONTENT \ + android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_CONTENT /**< The "application/vnd.oma.drm.content" MIME type */ +#define JNI_DRM_MIMETYPE_RIGHTS_XML \ + android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_XML /**< The "application/vnd.oma.drm.rights+xml" MIME type */ +#define JNI_DRM_MIMETYPE_RIGHTS_WBXML \ + android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_WBXML /**< The "application/vnd.oma.drm.rights+wbxml" MIME type */ + +/** + * DRM permission defines + */ +#define JNI_DRM_PERMISSION_PLAY \ + android_drm_mobile1_DrmRights_DRM_PERMISSION_PLAY /**< The permission to play */ +#define JNI_DRM_PERMISSION_DISPLAY \ + android_drm_mobile1_DrmRights_DRM_PERMISSION_DISPLAY /**< The permission to display */ +#define JNI_DRM_PERMISSION_EXECUTE \ + android_drm_mobile1_DrmRights_DRM_PERMISSION_EXECUTE /**< The permission to execute */ +#define JNI_DRM_PERMISSION_PRINT \ + android_drm_mobile1_DrmRights_DRM_PERMISSION_PRINT /**< The permission to print */ + +/** + * DRM delivery type defines + */ +#define JNI_DRM_FORWARD_LOCK \ + android_drm_mobile1_DrmRawContent_DRM_FORWARD_LOCK /**< forward lock */ +#define JNI_DRM_COMBINED_DELIVERY \ + android_drm_mobile1_DrmRawContent_DRM_COMBINED_DELIVERY /**< combined delivery */ +#define JNI_DRM_SEPARATE_DELIVERY \ + android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY /**< separate delivery */ +#define JNI_DRM_SEPARATE_DELIVERY_DM \ + android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY_DM /**< separate delivery DRM message */ +#ifdef __cplusplus +} +#endif +#endif /* __DRM1_JNI_H__ */ + diff --git a/media/libdrm/mobile1/include/objmng/drm_decoder.h b/media/libdrm/mobile1/include/objmng/drm_decoder.h new file mode 100644 index 0000000..a769c81 --- /dev/null +++ b/media/libdrm/mobile1/include/objmng/drm_decoder.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file drm_decoder.h + * + * provide service to decode base64 data. + * + * <!-- #interface list begin --> + * \section drm decoder interface + * - drm_decodeBase64() + * <!-- #interface list end --> + */ + +#ifndef __DRM_DECODER_H__ +#define __DRM_DECODER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +/** + * Decode base64 + * \param dest dest buffer to save decode base64 data + * \param destLen dest buffer length + * \param src source data to be decoded + * \param srcLen source buffer length, and when return, give out how many bytes has been decoded + * \return + * -when success, return a positive integer of dest buffer length, + * if input dest buffer is NULL or destLen is 0, + * return dest buffer length that user should allocate to save decoding data + * -when failed, return -1 + */ +int32_t drm_decodeBase64(uint8_t * dest, int32_t destLen, uint8_t * src, int32_t * srcLen); + +#ifdef __cplusplus +} +#endif + +#endif /* __DRM_DECODER_H__ */ diff --git a/media/libdrm/mobile1/include/objmng/drm_file.h b/media/libdrm/mobile1/include/objmng/drm_file.h new file mode 100644 index 0000000..b94ddd0 --- /dev/null +++ b/media/libdrm/mobile1/include/objmng/drm_file.h @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * File Porting Layer. + */ +#ifndef __DRM_FILE_H__ +#define __DRM_FILE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +/** Type value of a regular file or file name. */ +#define DRM_FILE_ISREG 1 +/** Type value of a directory or directory name. */ +#define DRM_FILE_ISDIR 2 +/** Type value of a filter name */ +#define DRM_FILE_ISFILTER 3 + + +/** Return code that indicates successful completion of an operation. */ +#define DRM_FILE_SUCCESS 0 +/** Indicates that an operation failed. */ +#define DRM_FILE_FAILURE -1 +/** Indicates that the a DRM_file_read() call reached the end of the file. */ +#define DRM_FILE_EOF -2 + + +/** Open for read access. */ +#define DRM_FILE_MODE_READ 1 +/** Open for write access. */ +#define DRM_FILE_MODE_WRITE 2 + + +#ifndef MAX_FILENAME_LEN +/** Maximum number of characters that a filename may have. By default assumes + * that the entry results of DRM_file_listNextEntry() are returned in the async state + * buffer, after the #DRM_file_result_s, and calculates the maximum name + * from that. + */ +#define MAX_FILENAME_LEN 1024 +#endif + + +/** + * Performs one-time initialization of the File System (FS). + * This function is called once during the lifetime of an application, + * and before any call to <code>DRM_file_*</code> functions by this application. + * When several applications are using the file interface, this function may be called + * several times, once per application. + * + * @return #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. + */ +int32_t DRM_file_startup(void); + +/** + * Returns the length of a file (by name, opened or unopened). + * + * @param name Name of the file, UCS-2 encoded. + * @param nameChars Number characters encoded in name. + * asynchronous operation returns #DRM_FILE_WOULDBLOCK. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_FAILURE or the file length. + */ +int32_t DRM_file_getFileLength(const uint16_t* name, + int32_t nameChars); + +/** + * Initializes a list iteration session. + * + * @param prefix Prefix that must be matched, UCS-2 encoded. * + * @param prefixChars Number characters encoded in prefix. + * @param session List session identifier. + * @param iteration List iteration identifier. + * + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. + */ +int32_t DRM_file_listOpen(const uint16_t* prefix, + int32_t prefixChars, + int32_t* session, + int32_t* iteration); + +/** + * Used to fetch a list of file names that match a given name prefix. + * + * @param prefix See DRM_file_listOpen(). This does not change during the + * iteration session. + * @param prefixChars See DRM_file_listOpen(). This does not change during + * the iteration session. + * @param entry Buffer parameter to return the next file name that matches the + * #prefix parameter, if any, when the function returns a positive number of + * characters. + * @param entryBytes Size of entry in bytes. + * @param session See DRM_file_listOpen(). + * @param iteration See DRM_file_listOpen(). + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_FAILURE or the number of + * characters encoded in entry. Returns 0 when the end of the list is reached. + */ +int32_t DRM_file_listNextEntry(const uint16_t* prefix, + int32_t prefixChars, + uint16_t* entry, + int32_t entryBytes, + int32_t* session, + int32_t* iteration); + +/** + * Ends a list iteration session. Notifies the implementation + * that the list session is over and that any session resources + * can be released. + * + * @param session See DRM_file_listOpen(). + * @param iteration See DRM_file_listOpen(). + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. + */ +int32_t DRM_file_listClose(int32_t session, int32_t iteration); + +/** + * Renames a file, given its old name. The file or directory is renamed + * immediately on the actual file system upon invocation of this method. + * Any open handles on the file specified by oldName become invalid after + * this method has been called. + * + * @param oldName Current file name (unopened), UCS-2 encoded. + * @param oldNameChars Number of characters encoded on oldName. + * @param newName New name for the file (unopened), UCS-2 encoded. + * @param newNameChars Number of characters encoded on newName. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. In particular, + * #DRM_FILE_FAILURE if a file or directory already exists with the new name. + */ +int32_t DRM_file_rename(const uint16_t* oldName, + int32_t oldNameChars, + const uint16_t* newName, + int32_t newNameChars); + +/** + * Tests if a file exists given its name. + * + * @param name Name of the file, UCS-2 encoded. + * @param nameChars Number of characters encoded in name. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_ISREG, #DRM_FILE_ISDIR, #DRM_FILE_FAILURE. If name + * exists, returns #DRM_FILE_ISREG if it is a regular file and #DRM_FILE_ISDIR if it is a directory. + * Returns #DRM_FILE_FAILURE in all other cases, including those where name exists but is neither + * a regular file nor a directory. Platforms that do not support directories MUST NOT return + * #DRM_FILE_ISDIR. + */ +int32_t DRM_file_exists(const uint16_t* name, + int32_t nameChars); + +/** + * Opens a file with the given name and returns its file handle. + * + * @param name Name of the file, UCS-2 encoded. + * @param nameChars Number of characters encoded in name. + * @param mode Any combination of the #DRM_FILE_MODE_READ and + * #DRM_FILE_MODE_WRITE flags. If the file does not exist and mode contains the + * #DRM_FILE_MODE_WRITE flag, then the file is automatically created. If the + * file exists and the mode contains the #DRM_FILE_MODE_WRITE flag, the file is + * opened so it can be modified, but the data is not modified by the open call. + * In all cases the current position is set to the start of the file. + * The following table shows how to map the mode semantics above to UNIX + * fopen-style modes. For brevity in the table, R=#DRM_FILE_MODE_READ, + * W=#DRM_FILE_MODE_WRITE, E=File exists: + * <table> + * <tr><td>RW</td><td>E</td><td>Maps-to</td></tr> + * <tr><td>00</td><td>0</td><td>Return #DRM_FILE_FAILURE</td></tr> + * <tr><td>00</td><td>1</td><td>Return #DRM_FILE_FAILURE</td></tr> + * <tr><td>01</td><td>0</td><td>Use fopen mode "w"</td></tr> + * <tr><td>01</td><td>1</td><td>Use fopen mode "a" and fseek to the start</td></tr> + * <tr><td>10</td><td>0</td><td>Return #DRM_FILE_FAILURE</td></tr> + * <tr><td>10</td><td>1</td><td>Use fopen mode "r"</td></tr> + * <tr><td>11</td><td>0</td><td>Use fopen mode "w+"</td></tr> + * <tr><td>11</td><td>1</td><td>Use fopen mode "r+"</td></tr> + * </table> + * @param handle Pointer where the result handle value is placed when the function + * is called synchronously. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. + */ +int32_t DRM_file_open(const uint16_t* name, + int32_t nameChars, + int32_t mode, + int32_t* handle); + +/** + * Deletes a file given its name, UCS-2 encoded. The file or directory is + * deleted immediately on the actual file system upon invocation of this + * method. Any open handles on the file specified by name become invalid + * after this method has been called. + * + * If the port needs to ensure that a specific application does not exceed a given storage + * space quota, then the bytes freed by the deletion must be added to the available space for + * that application. + * + * @param name Name of the file, UCS-2 encoded. + * @param nameChars Number of characters encoded in name. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. + */ +int32_t DRM_file_delete(const uint16_t* name, + int32_t nameChars); + +/** + * Read bytes from a file at the current position to a buffer. Afterwards the + * new file position is the byte after the last byte read. + * DRM_FILE_FAILURE is returned if the handle is invalid (e.g., as a + * consquence of DRM_file_delete, DRM_file_rename, or DRM_file_close). + * + * @param handle File handle as returned by DRM_file_open(). + * @param dst Buffer where the data is to be copied. + * @param length Number of bytes to be copied. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE, #DRM_FILE_EOF + * or the number of bytes that were read, i.e. in the range 0..length. + */ +int32_t DRM_file_read(int32_t handle, + uint8_t* dst, + int32_t length); + +/** + * Write bytes from a buffer to the file at the current position. If the + * current position + number of bytes written > current size of the file, + * then the file is grown. Afterwards the new file position is the byte + * after the last byte written. + * DRM_FILE_FAILURE is returned if the handle is invalid (e.g., as a + * consquence of DRM_file_delete, DRM_file_rename, or DRM_file_close). + * + * @param handle File handle as returned by DRM_file_open(). + * @param src Buffer that contains the bytes to be written. + * @param length Number of bytes to be written. + * If the port needs to ensure that a specific application does not exceed a given storage + * space quota, the implementation must make sure the call does not violate that invariant. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_FAILURE or the number of bytes + * that were written. This number must be in the range 0..length. + * Returns #DRM_FILE_FAILURE when storage is full or exceeds quota. + */ +int32_t DRM_file_write(int32_t handle, + const uint8_t* src, + int32_t length); + +/** + * Closes a file. + * DRM_FILE_SUCCESS is returned if the handle is invalid (e.g., as a + * consquence of DRM_file_delete or DRM_file_rename). + * + * @param handle File handle as returned by DRM_file_open(). + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. + */ +int32_t DRM_file_close(int32_t handle); + +/** + * Sets the current position in an opened file. + * DRM_FILE_FAILURE is returned if the handle is invalid (e.g., as a + * consquence of DRM_file_delete, DRM_file_rename, or DRM_file_close). + * + * @param handle File handle as returned by DRM_file_open(). + * @param value The new current position of the file. If value is greater + * than the length of the file then the file should be extended. The contents + * of the newly extended portion of the file is undefined. + * If the port needs to ensure that a specific application does not exceed a given storage + * space quota, the implementation must make sure the call does not violate that invariant. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. + * Returns #DRM_FILE_FAILURE when storage is full or exceeds quota. + */ +int32_t DRM_file_setPosition(int32_t handle, int32_t value); + +/** + * Creates a directory with the assigned name and full file permissions on + * the file system. The full path to the new directory must already exist. + * The directory is created immediately on the actual file system upon + * invocation of this method. + * + * @param name Name of the directory, UCS-2 encoded. + * @param nameChars Number of characters encoded in name. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. + */ +int32_t DRM_file_mkdir(const uint16_t* name, + int32_t nameChars); + +#ifdef __cplusplus +} +#endif + +#endif /* __DRM_FILE_H__ */ diff --git a/media/libdrm/mobile1/include/objmng/drm_i18n.h b/media/libdrm/mobile1/include/objmng/drm_i18n.h new file mode 100644 index 0000000..7487e9b --- /dev/null +++ b/media/libdrm/mobile1/include/objmng/drm_i18n.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __DRM_I18N_H__ +#define __DRM_I18N_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +/** + * @name Charset value defines + * @ingroup i18n + * + * Charset value defines + * see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/unicode_81rn.asp + */ +typedef enum { + DRM_CHARSET_GBK = 936, /** Simplified Chinese GBK (CP936) */ + DRM_CHARSET_GB2312 = 20936, /** Simplified Chinese GB2312 (CP936) */ + DRM_CHARSET_BIG5 = 950, /** BIG5 (CP950) */ + DRM_CHARSET_LATIN1 = 28591, /** ISO 8859-1, Latin 1 */ + DRM_CHARSET_LATIN2 = 28592, /** ISO 8859-2, Latin 2 */ + DRM_CHARSET_LATIN3 = 28593, /** ISO 8859-3, Latin 3 */ + DRM_CHARSET_LATIN4 = 28594, /** ISO 8859-4, Latin 4 */ + DRM_CHARSET_CYRILLIC = 28595, /** ISO 8859-5, Cyrillic */ + DRM_CHARSET_ARABIC = 28596, /** ISO 8859-6, Arabic */ + DRM_CHARSET_GREEK = 28597, /** ISO 8859-7, Greek */ + DRM_CHARSET_HEBREW = 28598, /** ISO 8859-8, Hebrew */ + DRM_CHARSET_LATIN5 = 28599, /** ISO 8859-9, Latin 5 */ + DRM_CHARSET_LATIN6 = 865, /** ISO 8859-10, Latin 6 (not sure here) */ + DRM_CHARSET_THAI = 874, /** ISO 8859-11, Thai */ + DRM_CHARSET_LATIN7 = 1257, /** ISO 8859-13, Latin 7 (not sure here) */ + DRM_CHARSET_LATIN8 = 38598, /** ISO 8859-14, Latin 8 (not sure here) */ + DRM_CHARSET_LATIN9 = 28605, /** ISO 8859-15, Latin 9 */ + DRM_CHARSET_LATIN10 = 28606, /** ISO 8859-16, Latin 10 */ + DRM_CHARSET_UTF8 = 65001, /** UTF-8 */ + DRM_CHARSET_UTF16LE = 1200, /** UTF-16 LE */ + DRM_CHARSET_UTF16BE = 1201, /** UTF-16 BE */ + DRM_CHARSET_HINDI = 57002, /** Hindi/Mac Devanagari */ + DRM_CHARSET_UNSUPPORTED = -1 +} DRM_Charset_t; + +/** + * Convert multibyte string of specified charset to unicode string. + * Note NO terminating '\0' will be appended to the output unicode string. + * + * @param charset Charset of the multibyte string. + * @param mbs Multibyte string to be converted. + * @param mbsLen Number of the bytes (in mbs) to be converted. + * @param wcsBuf Buffer for the converted unicode characters. + * If wcsBuf is NULL, the function returns the number of unicode + * characters required for the buffer. + * @param bufSizeInWideChar The size (in wide char) of wcsBuf + * @param bytesConsumed The number of bytes in mbs that have been successfully + * converted. The value of *bytesConsumed is undefined + * if wcsBuf is NULL. + * + * @return Number of the successfully converted unicode characters if wcsBuf + * is not NULL. If wcsBuf is NULL, returns required unicode buffer + * size. -1 for unrecoverable errors. + */ +int32_t DRM_i18n_mbsToWcs(DRM_Charset_t charset, + const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed); + +/** + * Convert unicode string to multibyte string with specified charset. + * Note NO terminating '\0' will be appended to the output multibyte string. + * + * @param charset Charset of the multibyte string to be converted to. + * @param wcs Unicode string to be converted. + * @param wcsLen Number of the unicode characters (in wcs) to be converted. + * @param mbsBuf Buffer for converted multibyte characters. + * If mbsBuf is NULL, the function returns the number of bytes + * required for the buffer. + * @param bufSizeInByte The size (in byte) of mbsBuf. + * + * @return Number of the successfully converted bytes. + */ +int32_t DRM_i18n_wcsToMbs(DRM_Charset_t charset, + const uint16_t *wcs, int32_t wcsLen, + uint8_t *mbsBuf, int32_t bufSizeInByte); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/media/libdrm/mobile1/include/objmng/drm_inner.h b/media/libdrm/mobile1/include/objmng/drm_inner.h new file mode 100644 index 0000000..55234f8 --- /dev/null +++ b/media/libdrm/mobile1/include/objmng/drm_inner.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DRM_INNER_H__ +#define __DRM_INNER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +#define INT_2_YMD_HMS(year, mon, day, date, hour, min, sec, time) do{\ + year = date / 10000;\ + mon = date % 10000 / 100;\ + day = date %100;\ + hour = time / 10000;\ + min = time % 10000 / 100;\ + sec = time % 100;\ +}while(0) + +/** + * Define the max malloc length for a DRM. + */ +#define DRM_MAX_MALLOC_LEN (50 * 1024) /* 50K */ + +#define DRM_ONE_AES_BLOCK_LEN 16 +#define DRM_TWO_AES_BLOCK_LEN 32 + +typedef struct _T_DRM_DM_Binary_Node { + uint8_t boundary[256]; +} T_DRM_DM_Binary_Node; + +typedef struct _T_DRM_DM_Base64_Node { + uint8_t boundary[256]; + uint8_t b64DecodeData[4]; + int32_t b64DecodeDataLen; +} T_DRM_DM_Base64_Node; + +typedef struct _T_DRM_Dcf_Node { + uint8_t rightsIssuer[256]; + int32_t encContentLength; + uint8_t aesDecData[16]; + int32_t aesDecDataLen; + int32_t aesDecDataOff; + uint8_t aesBackupBuf[16]; + int32_t bAesBackupBuf; +} T_DRM_Dcf_Node; + +typedef struct _T_DRM_Session_Node { + int32_t sessionId; + int32_t inputHandle; + int32_t mimeType; + int32_t (*getInputDataLengthFunc)(int32_t inputHandle); + int32_t (*readInputDataFunc)(int32_t inputHandle, uint8_t* buf, int32_t bufLen); + int32_t (*seekInputDataFunc)(int32_t inputHandle, int32_t offset); + int32_t deliveryMethod; + int32_t transferEncoding; + uint8_t contentType[64]; + int32_t contentLength; + int32_t contentOffset; + uint8_t contentID[256]; + uint8_t* rawContent; + int32_t rawContentLen; + int32_t bEndData; + uint8_t* readBuf; + int32_t readBufLen; + int32_t readBufOff; + void* infoStruct; + struct _T_DRM_Session_Node* next; +} T_DRM_Session_Node; + +#ifdef __cplusplus +} +#endif + +#endif /* __DRM_INNER_H__ */ diff --git a/media/libdrm/mobile1/include/objmng/drm_rights_manager.h b/media/libdrm/mobile1/include/objmng/drm_rights_manager.h new file mode 100644 index 0000000..dd2116c --- /dev/null +++ b/media/libdrm/mobile1/include/objmng/drm_rights_manager.h @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DRM_RIGHTS_MANAGER_H__ +#define __DRM_RIGHTS_MANAGER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> +#include <parser_rel.h> +#include <aes.h> + +#ifdef DRM_DEVICE_ARCH_ARM +#define ANDROID_DRM_CORE_PATH "/data/drm/rights/" +#define DRM_UID_FILE_PATH "/data/drm/rights/uid.txt" +#else +#define ANDROID_DRM_CORE_PATH "/home/user/golf/esmertec/device/out/debug/host/linux-x86/product/sim/data/data/com.android.drm.mobile1/" +#define DRM_UID_FILE_PATH "/home/user/golf/esmertec/device/out/debug/host/linux-x86/product/sim/data/data/com.android.drm.mobile1/uid.txt" +#endif + +#define EXTENSION_NAME_INFO ".info" + +#define GET_ID 1 +#define GET_UID 2 + +#define GET_ROAMOUNT 1 +#define GET_ALL_RO 2 +#define SAVE_ALL_RO 3 +#define GET_A_RO 4 +#define SAVE_A_RO 5 + +/** + * Get the id or uid from the "uid.txt" file. + * + * \param Uid The content id for a specially DRM object. + * \param id The id number managed by DRM engine for a specially DRM object. + * \param option The option to get id or uid, the value includes: GET_ID, GET_UID. + * + * \return + * -TRUE, if the operation successfully. + * -FALSE, if the operation failed. + */ +int32_t drm_readFromUidTxt(uint8_t* Uid, int32_t* id, int32_t option); + +/** + * Save or read the rights information on the "id.info" file. + * + * \param id The id number managed by DRM engine for a specially DRM object. + * \param Ro The rights structure to save the rights information. + * \param RoAmount The number of rights for this DRM object. + * \param option The option include: GET_ROAMOUNT, GET_ALL_RO, SAVE_ALL_RO, GET_A_RO, SAVE_A_RO. + * + * \return + * -TRUE, if the operation successfully. + * -FALSE, if the operation failed. + */ +int32_t drm_writeOrReadInfo(int32_t id, T_DRM_Rights* Ro, int32_t* RoAmount, int32_t option); + +/** + * Append a rights information to DRM engine storage. + * + * \param Ro The rights structure to save the rights information. + * + * return + * -TRUE, if the operation successfully. + * -FALSE, if the operation failed. + */ +int32_t drm_appendRightsInfo(T_DRM_Rights* rights); + +/** + * Get the mex id number from the "uid.txt" file. + * + * \return + * -an integer to indicate the max id number. + * -(-1), if the operation failed. + */ +int32_t drm_getMaxIdFromUidTxt(); + +/** + * Remove the "id.info" file if all the rights for this DRM object has been deleted. + * + * \param id The id number managed by DRM engine for a specially DRM object. + * + * \return + * -TRUE, if the operation successfully. + * -FALSE, if the operation failed. + */ +int32_t drm_removeIdInfoFile(int32_t id); + +/** + * Update the "uid.txt" file when delete the rights object. + * + * \param id The id number managed by DRM engine for a specially DRM object. + * + * \return + * -TRUE, if the operation successfully. + * -FALSE, if the operation failed. + */ +int32_t drm_updateUidTxtWhenDelete(int32_t id); + +/** + * Get the CEK according the given content id. + * + * \param uid The content id for a specially DRM object. + * \param KeyValue The buffer to save the CEK. + * + * \return + * -TRUE, if the operation successfully. + * -FALSE, if the operation failed. + */ +int32_t drm_getKey(uint8_t* uid, uint8_t* KeyValue); + +/** + * Discard the padding bytes in DCF decrypted data. + * + * \param decryptedBuf The aes decrypted data buffer to be scanned. + * \param decryptedBufLen The length of the buffer. And save the output result. + * + * \return + * -0 + */ +void drm_discardPaddingByte(uint8_t *decryptedBuf, int32_t *decryptedBufLen); + +/** + * Decrypt the media data according the CEK. + * + * \param Buffer The buffer to decrypted and also used to save the output data. + * \param BufferLen The length of the buffer data and also save the output data length. + * \param ctx The structure of the CEK. + * + * \return + * -0 + */ +int32_t drm_aesDecBuffer(uint8_t * Buffer, int32_t * BufferLen, aes_decrypt_ctx ctx[1]); + +/** + * Update the DCF data length according the CEK. + * + * \param pDcfLastData The last several byte for the DCF. + * \param keyValue The CEK of the DRM content. + * \param moreBytes Output the more bytes for discarded. + * + * \return + * -TRUE, if the operation successfully. + * -FALSE, if the operation failed. + */ +int32_t drm_updateDcfDataLen(uint8_t* pDcfLastData, uint8_t* keyValue, int32_t* moreBytes); + +/** + * Check and update the rights for a specially DRM content. + * + * \param id The id number managed by DRM engine for a specially DRM object. + * \param permission The permission to be check and updated. + * + * \return + * -DRM_SUCCESS, if there is a valid rights and update it successfully. + * -DRM_NO_RIGHTS, if there is no rights for this content. + * -DRM_RIGHTS_PENDING, if the rights is pending. + * -DRM_RIGHTS_EXPIRED, if the rights has expired. + * -DRM_RIGHTS_FAILURE, if there is some other error occur. + */ +int32_t drm_checkRoAndUpdate(int32_t id, int32_t permission); + +#ifdef __cplusplus +} +#endif + +#endif /* __DRM_RIGHTS_MANAGER_H__ */ diff --git a/media/libdrm/mobile1/include/objmng/drm_time.h b/media/libdrm/mobile1/include/objmng/drm_time.h new file mode 100644 index 0000000..9b013e6 --- /dev/null +++ b/media/libdrm/mobile1/include/objmng/drm_time.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * @file + * Time Porting Layer + * + * Basic support functions that are needed by time. + * + * <!-- #interface list begin --> + * \section drm_time Interface + * - DRM_time_getElapsedSecondsFrom1970() + * - DRM_time_sleep() + * - DRM_time_getSysTime() + * <!-- #interface list end --> + */ + +#ifndef __DRM_TIME_H__ +#define __DRM_TIME_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <time.h> +#include <drm_common_types.h> + +/** the time format */ +typedef struct __db_system_time_ +{ + uint16_t year; + uint16_t month; + uint16_t day; + uint16_t hour; + uint16_t min; + uint16_t sec; +} T_DB_TIME_SysTime; + +/** + * Get the system time.it's up to UTC + * \return Return the time in elapsed seconds. + */ +uint32_t DRM_time_getElapsedSecondsFrom1970(void); + +/** + * Suspend the execution of the current thread for a specified interval + * \param ms suspended time by millisecond + */ +void DRM_time_sleep(uint32_t ms); + +/** + * function: get current system time + * \param time_ptr[OUT] the system time got + * \attention + * time_ptr must not be NULL + */ +void DRM_time_getSysTime(T_DB_TIME_SysTime *time_ptr); + +#ifdef __cplusplus +} +#endif + +#endif /* __DRM_TIME_H__ */ diff --git a/media/libdrm/mobile1/include/objmng/svc_drm.h b/media/libdrm/mobile1/include/objmng/svc_drm.h new file mode 100644 index 0000000..789343f --- /dev/null +++ b/media/libdrm/mobile1/include/objmng/svc_drm.h @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __SVC_DRM_NEW_H__ +#define __SVC_DRM_NEW_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +/** + * Define the mime type of DRM data. + */ +#define TYPE_DRM_MESSAGE 0x48 /**< The mime type is "application/vnd.oma.drm.message" */ +#define TYPE_DRM_CONTENT 0x49 /**< The mime type is "application/vnd.oma.drm.content" */ +#define TYPE_DRM_RIGHTS_XML 0x4a /**< The mime type is "application/vnd.oma.drm.rights+xml" */ +#define TYPE_DRM_RIGHTS_WBXML 0x4b /**< The mime type is "application/vnd.oma.drm.rights+wbxml" */ +#define TYPE_DRM_UNKNOWN 0xff /**< The mime type is unknown */ + +/** + * Define the delivery methods. + */ +#define FORWARD_LOCK 1 /**< Forward_lock */ +#define COMBINED_DELIVERY 2 /**< Combined delivery */ +#define SEPARATE_DELIVERY 3 /**< Separate delivery */ +#define SEPARATE_DELIVERY_FL 4 /**< Separate delivery but DCF is forward-lock */ + +/** + * Define the permissions. + */ +#define DRM_PERMISSION_PLAY 0x01 /**< Play */ +#define DRM_PERMISSION_DISPLAY 0x02 /**< Display */ +#define DRM_PERMISSION_EXECUTE 0x04 /**< Execute */ +#define DRM_PERMISSION_PRINT 0x08 /**< Print */ +#define DRM_PERMISSION_FORWARD 0x10 /**< Forward */ + +/** + * Define the constraints. + */ +#define DRM_NO_CONSTRAINT 0x80 /**< Indicate have no constraint, it can use freely */ +#define DRM_END_TIME_CONSTRAINT 0x08 /**< Indicate have end time constraint */ +#define DRM_INTERVAL_CONSTRAINT 0x04 /**< Indicate have interval constraint */ +#define DRM_COUNT_CONSTRAINT 0x02 /**< Indicate have count constraint */ +#define DRM_START_TIME_CONSTRAINT 0x01 /**< Indicate have start time constraint */ +#define DRM_NO_PERMISSION 0x00 /**< Indicate no rights */ + +/** + * Define the return values for those interface. + */ +#define DRM_SUCCESS 0 +#define DRM_FAILURE -1 +#define DRM_MEDIA_EOF -2 +#define DRM_RIGHTS_DATA_INVALID -3 +#define DRM_MEDIA_DATA_INVALID -4 +#define DRM_SESSION_NOT_OPENED -5 +#define DRM_NO_RIGHTS -6 +#define DRM_NOT_SD_METHOD -7 +#define DRM_RIGHTS_PENDING -8 +#define DRM_RIGHTS_EXPIRED -9 +#define DRM_UNKNOWN_DATA_LEN -10 + +/** + * The input DRM data structure, include DM, DCF, DR, DRC. + */ +typedef struct _T_DRM_Input_Data { + /** + * The handle of the input DRM data. + */ + int32_t inputHandle; + + /** + * The mime type of the DRM data, if the mime type set to unknown, DRM engine + * will try to scan the input data to confirm the mime type, but we must say that + * the scan and check of mime type is not strictly precise. + */ + int32_t mimeType; + + /** + * The function to get input data length, this function should be implement by out module, + * and DRM engine will call-back it. + * + * \param inputHandle The handle of the DRM data. + * + * \return + * -A positive integer indicate the length of input data. + * -0, if some error occurred. + */ + int32_t (*getInputDataLength)(int32_t inputHandle); + + /** + * The function to read the input data, this function should be implement by out module, + * and DRM engine will call-back it. + * + * \param inputHandle The handle of the DRM data. + * \param buf The buffer mallocced by DRM engine to save the data. + * \param bufLen The length of the buffer. + * + * \return + * -A positive integer indicate the actually length of byte has been read. + * -0, if some error occurred. + * -(-1), if reach to the end of the data. + */ + int32_t (*readInputData)(int32_t inputHandle, uint8_t* buf, int32_t bufLen); + + /** + * The function to seek the current file pointer, this function should be implement by out module, + * and DRM engine will call-back it. + * + * \param inputHandle The handle of the DRM data. + * \param offset The offset from the start position to be seek. + * + * \return + * -0, if seek operation success. + * -(-1), if seek operation fail. + */ + int32_t (*seekInputData)(int32_t inputHandle, int32_t offset); +} T_DRM_Input_Data; + +/** + * The constraint structure. + */ +typedef struct _T_DRM_Constraint_Info { + uint8_t indicator; /**< Whether there is a right */ + uint8_t unUsed[3]; + int32_t count; /**< The constraint of count */ + int32_t startDate; /**< The constraint of start date */ + int32_t startTime; /**< The constraint of start time */ + int32_t endDate; /**< The constraint of end date */ + int32_t endTime; /**< The constraint of end time */ + int32_t intervalDate; /**< The constraint of interval date */ + int32_t intervalTime; /**< The constraint of interval time */ +} T_DRM_Constraint_Info; + +/** + * The rights permission and constraint information structure. + */ +typedef struct _T_DRM_Rights_Info { + uint8_t roId[256]; /**< The unique id for a specially rights object */ + T_DRM_Constraint_Info playRights; /**< Constraint of play */ + T_DRM_Constraint_Info displayRights; /**< Constraint of display */ + T_DRM_Constraint_Info executeRights; /**< Constraint of execute */ + T_DRM_Constraint_Info printRights; /**< Constraint of print */ +} T_DRM_Rights_Info; + +/** + * The list node of the Rights information structure. + */ +typedef struct _T_DRM_Rights_Info_Node { + T_DRM_Rights_Info roInfo; + struct _T_DRM_Rights_Info_Node *next; +} T_DRM_Rights_Info_Node; + +/** + * Install a rights object to DRM engine, include the rights in Combined Delivery cases. + * Because all the rights object is managed by DRM engine, so every incoming rights object + * must be install to the engine first, or the DRM engine will not recognize it. + * + * \param data The rights object data or Combined Delivery case data. + * \param pRightsInfo The structure to save this rights information. + * + * \return + * -DRM_SUCCESS, when install successfully. + * -DRM_RIGHTS_DATA_INVALID, when the input rights data is invalid. + * -DRM_FAILURE, when some other error occur. + */ +int32_t SVC_drm_installRights(T_DRM_Input_Data data, T_DRM_Rights_Info* pRightsInfo); + +/** + * Open a session for a special DRM object, it will parse the input DRM data, and then user + * can try to get information for this DRM object, or try to use it if the rights is valid. + * + * \param data The DRM object data, DM or DCF. + * + * \return + * -A handle for this opened DRM object session. + * -DRM_MEDIA_DATA_INVALID, when the input DRM object data is invalid. + * -DRM_FAILURE, when some other error occurred. + */ +int32_t SVC_drm_openSession(T_DRM_Input_Data data); + +/** + * Get the delivery method of the DRM object. + * + * \param session The handle for this DRM object session. + * + * \return + * -The delivery method of this DRM object, include: FORWARD_LOCK, COMBINED_DELIVERY, SEPARATE_DELIVERY, SEPARATE_DELIVERY_FL. + * -DRM_FAILURE, when some other error occurred. + */ +int32_t SVC_drm_getDeliveryMethod(int32_t session); + +/** + * Get DRM object media object content type. + * + * \param session The handle for this DRM object session. + * \param mediaType The buffer to save the media type string, 64 bytes is enough. + * + * \return + * -DRM_SUCCESS, when get the media object content type successfully. + * -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_getContentType(int32_t session, uint8_t* mediaType); + +/** + * Check whether a specific DRM object has the specific permission rights or not. + * + * \param session The handle for this DRM object session. + * \param permission Specify the permission to be checked. + * + * \return + * -DRM_SUCCESS, when it has the rights for the permission. + * -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed. + * -DRM_NO_RIGHTS, when it has no rights. + * -DRM_RIGHTS_PENDING, when it has the rights, but currently it is pending. + * -DRM_RIGHTS_EXPIRED, when the rights has expired. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_checkRights(int32_t session, int32_t permission); + +/** + * Consume the rights when try to use the DRM object. + * + * \param session The handle for this DRM object session. + * \param permission Specify the permission to be checked. + * + * \return + * -DRM_SUCCESS, when consume rights successfully. + * -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed. + * -DRM_NO_RIGHTS, when it has no rights. + * -DRM_RIGHTS_PENDING, when it has the rights, but currently it is pending. + * -DRM_RIGHTS_EXPIRED, when the rights has expired. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_consumeRights(int32_t session, int32_t permission); + +/** + * Get DRM media object content data length. + * + * \param session The handle for this DRM object session. + * + * \return + * -A positive integer indicate the length of the media object content data. + * -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed. + * -DRM_NO_RIGHTS, when the rights object is not existed. + * -DRM_UNKNOWN_DATA_LEN, when DRM object media data length is unknown in case of DCF has no rights. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_getContentLength(int32_t session); + +/** + * Get DRM media object content data. Support get the data piece by piece if the content is too large. + * + * \param session The handle for this DRM object session. + * \param offset The offset to start to get content. + * \param mediaBuf The buffer to save media object data. + * \param mediaBufLen The length of the buffer. + * + * \return + * -A positive integer indicate the actually length of the data has been got. + * -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed. + * -DRM_NO_RIGHTS, when the rights object is not existed. + * -DRM_MEDIA_EOF, when reach to the end of the media data. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_getContent(int32_t session, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen); + +/** + * Get the rights issuer address, this interface is specially for Separate Delivery method. + * + * \param session The handle for this DRM object session. + * \param rightsIssuer The buffer to save rights issuer, 256 bytes are enough. + * + * \return + * -DRM_SUCCESS, when get the rights issuer successfully. + * -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed. + * -DRM_NOT_SD_METHOD, when it is not a Separate Delivery DRM object. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_getRightsIssuer(int32_t session, uint8_t* rightsIssuer); + +/** + * Get DRM object constraint informations. + * + * \param session The handle for this DRM object session. + * \param rights The structue to save the rights object information. + * + * \return + * -DRM_SUCCESS, when get the rights information successfully. + * -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed. + * -DRM_NO_RIGHTS, when this DRM object has not rights. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_getRightsInfo(int32_t session, T_DRM_Rights_Info* rights); + +/** + * Close the opened session, after closed, the handle become invalid. + * + * \param session The handle for this DRM object session. + * + * \return + * -DRM_SUCCESS, when close operation success. + * -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_closeSession(int32_t session); + +/** + * Check and update the given rights according the given permission. + * + * \param contentID The unique id of the rights object. + * \param permission The permission to be updated. + * + * \return + * -DRM_SUCCESS, when update operation success. + * -DRM_NO_RIGHTS, when it has no rights. + * -DRM_RIGHTS_PENDING, when it has the rights, but currently it is pending. + * -DRM_RIGHTS_EXPIRED, when the rights has expired. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_updateRights(uint8_t* contentID, int32_t permission); + +/** + * Scan all the rights object in current DRM engine, and get all their information. + * + * \param ppRightsInfo The pointer to the list structure to save rights info. + * + * \return + * -DRM_SUCCESS, when get information successfully. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_viewAllRights(T_DRM_Rights_Info_Node **ppRightsInfo); + +/** + * Free the allocated memory when call "SVC_drm_viewAllRights". + * + * \param pRightsHeader The header pointer of the list to be free. + * + * \return + * -DRM_SUCCESS, when free operation successfully. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_freeRightsInfoList(T_DRM_Rights_Info_Node *pRightsHeader); + +/** + * Delete a specify rights. + * + * \param roId The unique id of the rights. + * + * \return + * -DRM_SUCCESS, when free operation successfully. + * -DRM_NO_RIGHTS, when there is not this rights object. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_deleteRights(uint8_t* roId); + +#ifdef __cplusplus +} +#endif + +#endif /* __SVC_DRM_NEW_H__ */ diff --git a/media/libdrm/mobile1/include/parser/parser_dcf.h b/media/libdrm/mobile1/include/parser/parser_dcf.h new file mode 100644 index 0000000..c63a195 --- /dev/null +++ b/media/libdrm/mobile1/include/parser/parser_dcf.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __PARSER_DCF_H__ +#define __PARSER_DCF_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +#define MAX_ENCRYPTION_METHOD_LEN 64 +#define MAX_RIGHTS_ISSUER_LEN 256 +#define MAX_CONTENT_NAME_LEN 64 +#define MAX_CONTENT_DESCRIPTION_LEN 256 +#define MAX_CONTENT_VENDOR_LEN 256 +#define MAX_ICON_URI_LEN 256 +#define MAX_CONTENT_TYPE_LEN 64 +#define MAX_CONTENT_URI_LEN 256 + +#define HEADER_ENCRYPTION_METHOD "Encryption-Method: " +#define HEADER_RIGHTS_ISSUER "Rights-Issuer: " +#define HEADER_CONTENT_NAME "Content-Name: " +#define HEADER_CONTENT_DESCRIPTION "Content-Description: " +#define HEADER_CONTENT_VENDOR "Content-Vendor: " +#define HEADER_ICON_URI "Icon-Uri: " + +#define HEADER_ENCRYPTION_METHOD_LEN 19 +#define HEADER_RIGHTS_ISSUER_LEN 15 +#define HEADER_CONTENT_NAME_LEN 14 +#define HEADER_CONTENT_DESCRIPTION_LEN 21 +#define HEADER_CONTENT_VENDOR_LEN 16 +#define HEADER_ICON_URI_LEN 10 + +#define UINT_VAR_FLAG 0x80 +#define UINT_VAR_DATA 0x7F +#define MAX_UINT_VAR_BYTE 5 +#define DRM_UINT_VAR_ERR -1 + +typedef struct _T_DRM_DCF_Info { + uint8_t Version; + uint8_t ContentTypeLen; /**< Length of the ContentType field */ + uint8_t ContentURILen; /**< Length of the ContentURI field */ + uint8_t unUsed; + uint8_t ContentType[MAX_CONTENT_TYPE_LEN]; /**< The MIME media type of the plaintext data */ + uint8_t ContentURI[MAX_CONTENT_URI_LEN]; /**< The unique identifier of this content object */ + int32_t HeadersLen; /**< Length of the Headers field */ + int32_t EncryptedDataLen; /**< Length of the encrypted data field */ + int32_t DecryptedDataLen; /**< Length of the decrypted data field */ + uint8_t Encryption_Method[MAX_ENCRYPTION_METHOD_LEN]; /**< Encryption method */ + uint8_t Rights_Issuer[MAX_RIGHTS_ISSUER_LEN]; /**< Rights issuer */ + uint8_t Content_Name[MAX_CONTENT_NAME_LEN]; /**< Content name */ + uint8_t ContentDescription[MAX_CONTENT_DESCRIPTION_LEN]; /**< Content description */ + uint8_t ContentVendor[MAX_CONTENT_VENDOR_LEN]; /**< Content vendor */ + uint8_t Icon_URI[MAX_ICON_URI_LEN]; /**< Icon URI */ +} T_DRM_DCF_Info; + +/** + * Parse the DRM content format data + * + * \param buffer (in)Input the DCF format data + * \param bufferLen (in)The input buffer length + * \param pDcfInfo (out)A structure pointer which contain information of DCF headers + * \param ppEncryptedData (out)The location of encrypted data + * + * \return + * -TRUE, when success + * -FALSE, when failed + */ +int32_t drm_dcfParser(uint8_t *buffer, int32_t bufferLen, T_DRM_DCF_Info *pDcfInfo, + uint8_t **ppEncryptedData); + +#ifdef __cplusplus +} +#endif + +#endif /* __PARSER_DCF_H__ */ diff --git a/media/libdrm/mobile1/include/parser/parser_dm.h b/media/libdrm/mobile1/include/parser/parser_dm.h new file mode 100644 index 0000000..ec8b6b2 --- /dev/null +++ b/media/libdrm/mobile1/include/parser/parser_dm.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __PARSER_DM_H__ +#define __PARSER_DM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +#define MAX_CONTENT_TYPE_LEN 64 +#define MAX_CONTENT_ID 256 +#define MAX_CONTENT_BOUNDARY_LEN 256 +#define MAX_RIGHTS_ISSUER_LEN 256 + +#define DRM_MIME_TYPE_RIGHTS_XML "application/vnd.oma.drm.rights+xml" +#define DRM_MIME_TYPE_CONTENT "application/vnd.oma.drm.content" + +#define HEADERS_TRANSFER_CODING "Content-Transfer-Encoding:" +#define HEADERS_CONTENT_TYPE "Content-Type:" +#define HEADERS_CONTENT_ID "Content-ID:" + +#define TRANSFER_CODING_TYPE_7BIT "7bit" +#define TRANSFER_CODING_TYPE_8BIT "8bit" +#define TRANSFER_CODING_TYPE_BINARY "binary" +#define TRANSFER_CODING_TYPE_BASE64 "base64" + +#define DRM_UID_TYPE_FORWORD_LOCK "forwardlock" +#define DRM_NEW_LINE_CRLF "\r\n" + +#define HEADERS_TRANSFER_CODING_LEN 26 +#define HEADERS_CONTENT_TYPE_LEN 13 +#define HEADERS_CONTENT_ID_LEN 11 + +#define DRM_MESSAGE_CODING_7BIT 0 /* default */ +#define DRM_MESSAGE_CODING_8BIT 1 +#define DRM_MESSAGE_CODING_BINARY 2 +#define DRM_MESSAGE_CODING_BASE64 3 + +#define DRM_B64_DEC_BLOCK 3 +#define DRM_B64_ENC_BLOCK 4 + +typedef struct _T_DRM_DM_Info { + uint8_t contentType[MAX_CONTENT_TYPE_LEN]; /**< Content type */ + uint8_t contentID[MAX_CONTENT_ID]; /**< Content ID */ + uint8_t boundary[MAX_CONTENT_BOUNDARY_LEN]; /**< DRM message's boundary */ + uint8_t deliveryType; /**< The Delivery type */ + uint8_t transferEncoding; /**< Transfer encoding type */ + int32_t contentOffset; /**< The offset of the media content from the original DRM data */ + int32_t contentLen; /**< The length of the media content */ + int32_t rightsOffset; /**< The offset of the rights object in case of combined delivery */ + int32_t rightsLen; /**< The length of the rights object in case of combined delivery */ + uint8_t rightsIssuer[MAX_RIGHTS_ISSUER_LEN];/**< The rights issuer address in case of separate delivery */ +} T_DRM_DM_Info; + +/** + * Search the string in a limited length. + * + * \param str The original string + * \param strSearch The sub-string to be searched + * \param len The length limited + * + * \return + * -NULL, when there is not the searched string in length + * -The pointer of this sub-string + */ +const uint8_t* drm_strnstr(const uint8_t* str, const uint8_t* strSearch, int32_t len); + +/** + * Parse the DRM message format data. + * + * \param buffer (in)Input the DRM message format data + * \param bufferLen (in)The input buffer length + * \param pDmInfo (out)A structure pointer which contain information of DRM message headers + * + * \return + * -TRUE, when success + * -FALSE, when failed + */ +int32_t drm_parseDM(const uint8_t* buffer, int32_t bufferLen, T_DRM_DM_Info* pDmInfo); + +#ifdef __cplusplus +} +#endif + +#endif /* __PARSER_DM_H__ */ diff --git a/media/libdrm/mobile1/include/parser/parser_rel.h b/media/libdrm/mobile1/include/parser/parser_rel.h new file mode 100644 index 0000000..8def199 --- /dev/null +++ b/media/libdrm/mobile1/include/parser/parser_rel.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __PARSER_REL_H__ +#define __PARSER_REL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +#define WRITE_RO_FLAG(whoIsAble, boolValue, Indicator, RIGHTS) do{\ + whoIsAble = boolValue;\ + Indicator |= RIGHTS;\ +}while(0) + +#define CHECK_VALIDITY(ret) do{\ + if(ret == NULL){\ + if(XML_ERROR_NO_SUCH_NODE != xml_errno)\ + return FALSE;\ + }\ + else\ + {\ + if(XML_ERROR_OK != xml_errno)\ + return FALSE;\ + }\ +}while(0) + +#define YMD_HMS_2_INT(year, mon, day, date, hour, min, sec, time) do{\ + date = year * 10000 + mon * 100 + day;\ + time = hour * 10000 + min * 100 + sec;\ +}while(0) + +#define DRM_UID_LEN 256 +#define DRM_KEY_LEN 16 + +#define XML_DOM_PARSER + +typedef struct _T_DRM_DATETIME { + int32_t date; /**< year * 10000 + mon *100 + day */ + int32_t time; /**< hour * 10000 + min *100 + sec */ +} T_DRM_DATETIME; + +typedef struct _T_DRM_Rights_Constraint { + uint8_t Indicator; /**< Indicate which is constrainted, the first one indicate 0001, second one indicate 0010 */ + uint8_t unUsed[3]; + int32_t Count; /**< The times that can be used */ + T_DRM_DATETIME StartTime; /**< The starting time */ + T_DRM_DATETIME EndTime; /**< The ending time */ + T_DRM_DATETIME Interval; /**< The interval time */ +} T_DRM_Rights_Constraint; + +typedef struct _T_DRM_Rights { + uint8_t Version[8]; /**< Version number */ + uint8_t uid[256]; /**< record the rights object name */ + uint8_t KeyValue[16]; /**< Decode base64 */ + int32_t bIsPlayable; /**< Is playable */ + int32_t bIsDisplayable; /**< Is displayable */ + int32_t bIsExecuteable; /**< Is executeable */ + int32_t bIsPrintable; /**< Is printable */ + T_DRM_Rights_Constraint PlayConstraint; /**< Play constraint */ + T_DRM_Rights_Constraint DisplayConstraint; /**< Display constraint */ + T_DRM_Rights_Constraint ExecuteConstraint; /**< Execute constraint */ + T_DRM_Rights_Constraint PrintConstraint; /**< Print constraint */ +} T_DRM_Rights; + +/** + * Input year and month, return how many days that month have + * \param year (in)Input the year + * \param month (in)Input the month + * \return + * -A positive integer, which is how many days that month have + * -When wrong input, return -1 + */ +int32_t drm_monthDays(int32_t year, int32_t month); + +/** + * Check whether the date and time is valid. + * \param year year of the date + * \param month month of the date + * \param day day of the date + * \param hour hour of the time + * \param min minute of the time + * \param sec second of the time + * \return + * -when it is a valid time, return 0 + * -when it is a invalid time, return -1 + */ +int32_t drm_checkDate(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t min, int32_t sec); + +/** + * Parse the rights object include xml format and wbxml format data + * + * \param buffer (in)Input the DRM rights object data + * \param bufferLen (in)The buffer length + * \param format (in)Which format, xml or wbxml + * \param pRights (out)A structure pointer which save the rights information + * + * \return + * -TRUE, when success + * -FALSE, when failed + */ +int32_t drm_relParser(uint8_t* buffer, int32_t bufferLen, int32_t Format, T_DRM_Rights* pRights); + +#ifdef __cplusplus +} +#endif + +#endif /* __PARSER_REL_H__ */ diff --git a/media/libdrm/mobile1/include/xml/wbxml_tinyparser.h b/media/libdrm/mobile1/include/xml/wbxml_tinyparser.h new file mode 100644 index 0000000..1c40467 --- /dev/null +++ b/media/libdrm/mobile1/include/xml/wbxml_tinyparser.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __WBXML_TINYPARSER_H__ +#define __WBXML_TINYPARSER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +#define REL_TAG_RIGHTS 0x05 +#define REL_TAG_CONTEXT 0x06 +#define REL_TAG_VERSION 0x07 +#define REL_TAG_UID 0x08 +#define REL_TAG_AGREEMENT 0x09 +#define REL_TAG_ASSET 0x0A +#define REL_TAG_KEYINFO 0x0B +#define REL_TAG_KEYVALUE 0x0C +#define REL_TAG_PERMISSION 0x0D +#define REL_TAG_PLAY 0x0E +#define REL_TAG_DISPLAY 0x0F +#define REL_TAG_EXECUTE 0x10 +#define REL_TAG_PRINT 0x11 +#define REL_TAG_CONSTRAINT 0x12 +#define REL_TAG_COUNT 0x13 +#define REL_TAG_DATETIME 0x14 +#define REL_TAG_START 0x15 +#define REL_TAG_END 0x16 +#define REL_TAG_INTERVAL 0x17 + +#define REL_CHECK_WBXML_HEADER(x) ((x != NULL) && (x[0] == 0x03) && (x[1] == 0x0E) && (x[2] == 0x6A)) + +#ifdef __cplusplus +} +#endif + +#endif /* __WBXML_TINYPARSER_H__ */ diff --git a/media/libdrm/mobile1/include/xml/xml_tinyParser.h b/media/libdrm/mobile1/include/xml/xml_tinyParser.h new file mode 100644 index 0000000..4ad65b8 --- /dev/null +++ b/media/libdrm/mobile1/include/xml/xml_tinyParser.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __XML_TINYPARSER_H__ +#define __XML_TINYPARSER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +#define XML_DOM_PARSER +#define WBXML_DOM_PARSER +#define XML_DOM_CHECK_ENDTAG +#define XML_ENABLE_ERRNO +#define WBXML_OLD_VERSION /* for drm only */ + +#ifdef DEBUG_MODE +void XML_PrintMallocInfo(); +#endif /* DEBUG_MODE */ + +#define XML_TRUE 1 +#define XML_FALSE 0 +#define XML_EOF 0 +#define XML_TAG_START 0 +#define XML_TAG_END 1 +#define XML_TAG_SELF 2 + +#define XML_MAX_PROPERTY_LEN 256 +#define XML_MAX_ATTR_NAME_LEN 256 +#define XML_MAX_ATTR_VALUE_LEN 256 +#define XML_MAX_VALUE_LEN 256 + +#define XML_ERROR_OK 0 +#define XML_ERROR_BUFFER_NULL -1 +#define XML_ERROR_ATTR_NAME -2 +#define XML_ERROR_ATTR_MISSED_EQUAL -3 +#define XML_ERROR_PROPERTY_NAME -4 +#define XML_ERROR_ATTR_VALUE -5 +#define XML_ERROR_ENDTAG -6 +#define XML_ERROR_NO_SUCH_NODE -7 +#define XML_ERROR_PROPERTY_END -8 +#define XML_ERROR_VALUE -9 +#define XML_ERROR_NO_START_TAG -14 +#define XML_ERROR_NOVALUE -15 + +#define WBXML_ERROR_MISSED_CONTENT -10 +#define WBXML_ERROR_MBUINT32 -11 +#define WBXML_ERROR_MISSED_STARTTAG -12 +#define WBXML_ERROR_MISSED_ENDTAG -13 + +#ifdef XML_ENABLE_ERRNO +extern int32_t xml_errno; +#define XML_ERROR(x) do { xml_errno = x; } while (0) +#else /* XML_ENABLE_ERRNO */ +#define XML_ERROR +#endif /* XML_ENABLE_ERRNO */ + +#ifdef XML_DOM_PARSER +uint8_t *XML_DOM_getNode(uint8_t *buffer, const uint8_t *const node); +uint8_t *XML_DOM_getNodeValue(uint8_t *buffer, uint8_t *node, + uint8_t **value, int32_t *valueLen); + +uint8_t *XML_DOM_getValue(uint8_t *buffer, uint8_t **pValue, int32_t *valueLen); +uint8_t *XML_DOM_getAttr(uint8_t *buffer, uint8_t **pName, int32_t *nameLen, + uint8_t **pValue, int32_t *valueLen); + +uint8_t *XML_DOM_getNextNode(uint8_t *buffer, uint8_t **pNodeName, + int32_t *nodenameLen); + +uint8_t *XML_DOM_getTag(uint8_t *buffer, int32_t *tagLen, int32_t *tagType); +#endif /* XML_DOM_PARSER */ + +#ifdef WBXML_DOM_PARSER + +#define WBXML_WITH_ATTR 0x80 +#define WBXML_WITH_CONTENT 0x40 +#define WBXML_ATTR_END 0x01 +#define WBXML_CONTENT_END 0x01 + +#define WBXML_SWITCH_PAGE 0x00 +#define WBXML_STR_I 0x03 +#define WBXML_END 0x00 +#define WBXML_OPAUE 0xC3 +#define WBXML_STR_T 0x83 +#define WBXML_OPAQUE 0xC3 + +#define WBXML_GET_TAG(x) ((x) & 0x3F) /* get 6-digits */ +#define WBXML_HAS_ATTR(x) ((x) & WBXML_WITH_ATTR) +#define WBXML_HAS_CONTENT(x) ((x) & WBXML_WITH_CONTENT) + +typedef struct _WBXML { + uint8_t version; + uint8_t unUsed[3]; + uint32_t publicid; + uint32_t charset; + int32_t strTableLen; + uint8_t *strTable; + uint8_t *Content; + uint8_t *End; + uint8_t *curPtr; + int32_t depth; +} WBXML; + +typedef int32_t XML_BOOL; + +#ifdef WBXML_OLD_VERSION +uint8_t *WBXML_DOM_getNode(uint8_t *buffer, int32_t bufferLen, + uint8_t *node); +uint8_t *WBXML_DOM_getNodeValue(uint8_t *buffer, int32_t bufferLen, + uint8_t *node, + uint8_t **value, + int32_t *valueLen); +#endif /* WBXML_OLD_VERSION */ + +XML_BOOL WBXML_DOM_Init(WBXML * pWbxml, uint8_t *buffer, + int32_t bufferLen); +XML_BOOL WBXML_DOM_Eof(WBXML * pWbxml); +uint8_t WBXML_DOM_GetTag(WBXML * pWbxml); +uint8_t WBXML_DOM_GetChar(WBXML * pWbxml); +uint8_t WBXML_DOM_GetUIntVar(WBXML * pWbxml); +void WBXML_DOM_Rewind(WBXML * pWbxml); +void WBXML_DOM_Seek(WBXML * pWbxml, int32_t offset); +int32_t WBXML_GetUintVar(const uint8_t *const buffer, int32_t *len); + +#endif /* WBXML_DOM_PARSER */ + +#ifdef XML_TREE_STRUCTURE + +typedef struct _XML_TREE_ATTR XML_TREE_ATTR; +struct _XML_TREE_ATTR { + uint8_t name[XML_MAX_ATTR_VALUE_LEN]; + uint8_t value[XML_MAX_ATTR_VALUE_LEN]; + XML_TREE_ATTR *next; +}; + +typedef struct _XML_TREE XML_TREE; +struct _XML_TREE { + uint8_t tag[XML_MAX_PROPERTY_LEN]; + uint8_t value[XML_MAX_VALUE_LEN]; + XML_TREE_ATTR *attr; + XML_TREE_ATTR *last_attr; + XML_TREE *brother; + XML_TREE *last_brother; + XML_TREE *child; +}; + +XML_TREE *XML_makeTree(uint8_t **buf); +void XML_freeTree(XML_TREE * pTree); + +#endif /* XML_TREE_STRUCTURE */ + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_TINYPARSER_H__ */ diff --git a/media/libdrm/mobile1/src/jni/drm1_jni.c b/media/libdrm/mobile1/src/jni/drm1_jni.c new file mode 100644 index 0000000..d0fca54 --- /dev/null +++ b/media/libdrm/mobile1/src/jni/drm1_jni.c @@ -0,0 +1,1175 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file drm1_jni.c + * + * This file implement the Java Native Interface + * for supporting OMA DRM 1.0 + */ + +#include <jni/drm1_jni.h> +#include <objmng/svc_drm.h> +#include "log.h" + + +#define MS_PER_SECOND 1000 /* Milliseconds per second */ +#define MS_PER_MINUTE 60 * MS_PER_SECOND /* Milliseconds per minute */ +#define MS_PER_HOUR 60 * MS_PER_MINUTE /* Milliseconds per hour */ +#define MS_PER_DAY 24 * MS_PER_HOUR /* Milliseconds per day */ + +#define SECONDS_PER_MINUTE 60 /* Seconds per minute*/ +#define SECONDS_PER_HOUR 60 * SECONDS_PER_MINUTE /* Seconds per hour */ +#define SECONDS_PER_DAY 24 * SECONDS_PER_HOUR /* Seconds per day */ + +#define DAY_PER_MONTH 30 /* Days per month */ +#define DAY_PER_YEAR 365 /* Days per year */ + +/** Nonzero if 'y' is a leap year, else zero. */ +#define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0) + +/** Number of leap years from 1970 to 'y' (not including 'y' itself). */ +#define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400) + +/** Accumulated number of days from 01-Jan up to start of current month. */ +static const int32_t ydays[] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 +}; + +#define int64_const(s) (s) +#define int64_add(dst, s1, s2) ((void)((dst) = (s1) + (s2))) +#define int64_mul(dst, s1, s2) ((void)((dst) = (int64_t)(s1) * (int64_t)(s2))) + +/** + * DRM data structure + */ +typedef struct _DrmData { + /** + * The id of the DRM content. + */ + int32_t id; + + /** + * The pointer of JNI interface. + */ + JNIEnv* env; + + /** + * The pointer of DRM raw content InputStream object. + */ + jobject* pInData; + + /** + * The len of the InputStream object. + */ + int32_t len; + + /** + * The next DRM data. + */ + struct _DrmData *next; +} DrmData; + +/** The table to hold all the DRM data. */ +static DrmData *drmTable = NULL; + +/** + * Allocate a new item of DrmData. + * + * \return a pointer to a DrmData item if allocate successfully, + * otherwise return NULL + */ +static DrmData * newItem(void) +{ + DrmData *d = (DrmData *)malloc(sizeof(DrmData)); + + if (d != NULL) { + d->id = -1; + d->next = NULL; + } + + return d; +} + +/** + * Free the memory of the specified DrmData item <code>d</code>. + * + * \param d - a pointer to DrmData + */ +static void freeItem(DrmData *d) +{ + assert(d != NULL); + + free(d); +} + +/** + * Insert a DrmData item with given <code>name</code> into the head of + * the DrmData list. + * + * @param d - the pointer of the JNI interface + * @param pInData - the pointer of the DRM content InputStream object. + * + * @return <code>JNI_DRM_SUCCESS</code> if insert successfully, otherwise + * return <code>JNI_DRM_FAILURE</code> + */ +static int32_t addItem(DrmData* d) +{ + if (NULL == d) + return JNI_DRM_FAILURE; + + if (NULL == drmTable) { + drmTable = d; + return JNI_DRM_SUCCESS; + } + + d->next = drmTable; + drmTable = d; + + return JNI_DRM_SUCCESS; +} + +/** + * Get the item from the DrmData list by the specified <code> + * id</code>. + * + * @param p - the pointer of the DRM content InputStream object. + * + * @return a pointer to the DrmData item if find it successfuly, + * otherwise return NULL + */ +static DrmData * getItem(int32_t id) +{ + DrmData *d; + + if (NULL == drmTable) + return NULL; + + for (d = drmTable; d != NULL; d = d->next) { + if (id == d->id) + return d; + } + + return NULL; +} + +/** + * Remove the specified DrmData item <code>d</code>. + * + * @param p - the pointer of the DRM content InputStream object. + * + * @return <code>JNI_DRM_SUCCESS</code> if remove successfuly, + * otherwise return <code>JNI_DRM_FAILURE</code> + */ +static int32_t removeItem(int32_t id) +{ + DrmData *curItem, *preItem, *dstItem; + + if (NULL == drmTable) + return JNI_DRM_FAILURE; + + preItem = NULL; + for (curItem = drmTable; curItem != NULL; curItem = curItem->next) { + if (id == curItem->id) { + if (curItem == drmTable) + drmTable = curItem->next; + else + preItem->next = curItem->next; + + freeItem(curItem); + + return JNI_DRM_SUCCESS; + } + + preItem = curItem; + } + + return JNI_DRM_FAILURE; +} + + +static int32_t getInputStreamDataLength(int32_t handle) +{ + JNIEnv* env; + jobject* pInputStream; + int32_t len; + DrmData* p; + jclass cls; + jmethodID mid; + + p = (DrmData *)handle; + + if (NULL == p) + return 0; + + env = p->env; + pInputStream = p->pInData; + len = p->len; + + if (NULL == env || p->len <= 0 || NULL == pInputStream) + return 0; + + /* check the original InputStream is available or not */ + cls = (*env)->GetObjectClass(env, *pInputStream); + mid = (*env)->GetMethodID(env, cls, "available", "()I"); + (*env)->DeleteLocalRef(env, cls); + + if (NULL == mid) + return 0; + + if (0 > (*env)->CallIntMethod(env, *pInputStream, mid)) + return 0; + + return len; +} + +static int32_t readInputStreamData(int32_t handle, uint8_t* buf, int32_t bufLen) +{ + JNIEnv* env; + jobject* pInputStream; + int32_t len; + DrmData* p; + jclass cls; + jmethodID mid; + jbyteArray tmp; + int tmpLen; + jbyte* pNativeBuf; + + p = (DrmData *)handle; + + if (NULL == p || NULL == buf || bufLen <- 0) + return 0; + + env = p->env; + pInputStream = p->pInData; + len = p->len; + + if (NULL == env || p->len <= 0 || NULL == pInputStream) + return 0; + + cls = (*env)->GetObjectClass(env, *pInputStream); + mid = (*env)->GetMethodID(env, cls, "read", "([BII)I"); + tmp = (*env)->NewByteArray(env, bufLen); + bufLen = (*env)->CallIntMethod(env, *pInputStream, mid, tmp, 0, bufLen); + + (*env)->DeleteLocalRef(env, cls); + + if (-1 == bufLen) + return -1; + + pNativeBuf = (*env)->GetByteArrayElements(env, tmp, NULL); + memcpy(buf, pNativeBuf, bufLen); + (*env)->ReleaseByteArrayElements(env, tmp, pNativeBuf, 0); + (*env)->DeleteLocalRef(env, tmp); + + return bufLen; +} + +static const T_DRM_Rights_Info_Node *searchRightsObject(const jbyte* roId, const T_DRM_Rights_Info_Node* pRightsList) +{ + const T_DRM_Rights_Info_Node *pTmp; + + if (NULL == roId || NULL == pRightsList) + return NULL; + + pTmp = pRightsList; + + while (NULL != pTmp) { + if(0 == strcmp((char *)roId, (char *)pTmp->roInfo.roId)) + break; + pTmp = pTmp->next; + } + + return pTmp; +} + +/** + * Returns the difference in seconds between the given GMT time + * and 1970-01-01 00:00:00 GMT. + * + * \param year the year (since 1970) + * \param month the month (1 - 12) + * \param day the day (1 - 31) + * \param hour the hour (0 - 23) + * \param minute the minute (0 - 59) + * \param second the second (0 - 59) + * + * \return the difference in seconds between the given GMT time + * and 1970-01-01 00:00:00 GMT. + */ +static int64_t mkgmtime( + uint32_t year, uint32_t month, uint32_t day, + uint32_t hour, uint32_t minute, uint32_t second) +{ + int64_t result; + + /* + * FIXME: It does not check whether the specified days + * is valid based on the specified months. + */ + assert(year >= 1970 + && month > 0 && month <= 12 + && day > 0 && day <= 31 + && hour < 24 && minute < 60 + && second < 60); + + /* Set 'day' to the number of days into the year. */ + day += ydays[month - 1] + (month > 2 && leap (year)) - 1; + + /* Now calculate 'day' to the number of days since Jan 1, 1970. */ + day = day + 365 * (year - 1970) + nleap(year); + + int64_mul(result, int64_const(day), int64_const(SECONDS_PER_DAY)); + int64_add(result, result, int64_const( + SECONDS_PER_HOUR * hour + SECONDS_PER_MINUTE * minute + second)); + + return result; +} + +/** + * Compute the milliseconds by the specified <code>date</code> + * and <code>time</code>. + * + * @param date - the specified date, + * <code>date = year * 10000 + month * 100 + day</code> + * @param time - the specified time, + * <code>time = hour * 10000 + minute * 100 + second</code> + * + * @return the related milliseconds + */ +static int64_t computeTime(int32_t date, int32_t time) +{ + int32_t year, month, day, hour, minute, second; + + year = date / 10000; + month = (date / 100) % 100; + day = date % 100; + hour = time / 10000; + minute = (time / 100) % 100; + second = time % 100; + + /* Adjust the invalid parameters. */ + if (year < 1970) year = 1970; + if (month < 1) month = 1; + if (month > 12) month = 12; + if (day < 1) day = 1; + if (day > 31) day = 31; + if (hour < 0) hour = 0; + if (hour > 23) hour = 23; + if (minute < 0) minute = 0; + if (minute > 59) minute = 59; + if (second < 0) second = 0; + if (second > 59) second = 59; + + return mkgmtime(year, month, day, hour, minute, second) * 1000; +} + +/** + * Compute the milliseconds by the specified <code>date</code> + * and <code>time</code>. + * Note that here we always treat 1 year as 365 days and 1 month as 30 days + * that is not precise. But it should not be a problem since OMA DRM 2.0 + * already restricts the interval representation to be day-based, + * i.e. there will not be an interval with year or month any more in the + * future. + * + * @param date - the specified date, + * <code>date = year * 10000 + month * 100 + day</code> + * @param time - the specified time, + * <code>time = hour * 10000 + minute * 100 + second</code> + * + * @return the related milliseconds + */ +static int64_t computeInterval(int32_t date, int32_t time) +{ + int32_t year, month, day, hour, minute, second; + int64_t milliseconds; + + year = date / 10000; + month = (date / 100) % 100; + day = date % 100; + hour = time / 10000; + minute = (time / 100) % 100; + second = time % 100; + + /* milliseconds = ((((year * 365 + month * 30 + day) * 24 + * + hour) * 60 + minute) * 60 + second) * 1000; + */ + int64_mul(milliseconds, + int64_const(year * DAY_PER_YEAR + month * DAY_PER_MONTH + day), + int64_const(MS_PER_DAY)); + int64_add(milliseconds, milliseconds, + int64_const(hour * MS_PER_HOUR + minute * MS_PER_MINUTE + + second * MS_PER_SECOND)); + + return milliseconds; +} + +static jint getObjectIntField(JNIEnv * env, jobject obj, const char *name, jint * value) +{ + jclass clazz; + jfieldID field; + + clazz = (*env)->GetObjectClass(env, obj); + if (NULL == clazz) + return JNI_DRM_FAILURE; + + field = (*env)->GetFieldID(env, clazz, name, "I"); + (*env)->DeleteLocalRef(env, clazz); + + if (NULL == field) + return JNI_DRM_FAILURE; + + *value = (*env)->GetIntField(env, obj, field); + + return JNI_DRM_SUCCESS; +} + +static jint setObjectIntField(JNIEnv * env, jobject obj, const char *name, jint value) +{ + jclass clazz; + jfieldID field; + + clazz = (*env)->GetObjectClass(env, obj); + if (NULL == clazz) + return JNI_DRM_FAILURE; + + field = (*env)->GetFieldID(env, clazz, name, "I"); + (*env)->DeleteLocalRef(env, clazz); + + if (NULL == field) + return JNI_DRM_FAILURE; + + (*env)->SetIntField(env, obj, field, value); + + return JNI_DRM_SUCCESS; +} + +static jint setObjectLongField(JNIEnv * env, jobject obj, const char *name, jlong value) +{ + jclass clazz; + jfieldID field; + + clazz = (*env)->GetObjectClass(env, obj); + if (NULL == clazz) + return JNI_DRM_FAILURE; + + field = (*env)->GetFieldID(env, clazz, name, "J"); + (*env)->DeleteLocalRef(env, clazz); + + if (NULL == field) + return JNI_DRM_FAILURE; + + (*env)->SetLongField(env, obj, field, value); + + return JNI_DRM_SUCCESS; +} + +static jint setConstraintFields(JNIEnv * env, jobject constraint, T_DRM_Constraint_Info * pConstraint) +{ + /* if no this permission */ + if (pConstraint->indicator == (uint8_t)DRM_NO_RIGHTS) { + if (JNI_DRM_FAILURE == setObjectIntField(env, constraint, "count", 0)) + return JNI_DRM_FAILURE; + + return JNI_DRM_SUCCESS; + } + + /* set count field */ + if (pConstraint->indicator & DRM_COUNT_CONSTRAINT) { + if (JNI_DRM_FAILURE == setObjectIntField(env, constraint, "count", pConstraint->count)) + return JNI_DRM_FAILURE; + } + + /* set start time field */ + if (pConstraint->indicator & DRM_START_TIME_CONSTRAINT) { + int64_t startTime; + + startTime = computeTime(pConstraint->startDate, pConstraint->startTime); + + if (JNI_DRM_FAILURE == setObjectLongField(env, constraint, "startDate", startTime)) + return JNI_DRM_FAILURE; + } + + /* set end time field */ + if (pConstraint->indicator & DRM_END_TIME_CONSTRAINT) { + int64_t endTime; + + endTime = computeTime(pConstraint->endDate, pConstraint->endTime); + + if (JNI_DRM_FAILURE == setObjectLongField(env, constraint, "endDate", endTime)) + return JNI_DRM_FAILURE; + } + + /* set interval field */ + if (pConstraint->indicator & DRM_INTERVAL_CONSTRAINT) { + int64_t interval; + + interval = computeInterval(pConstraint->intervalDate, pConstraint->intervalTime); + + if (JNI_DRM_FAILURE == setObjectLongField(env, constraint, "interval", interval)) + return JNI_DRM_FAILURE; + } + + return JNI_DRM_SUCCESS; +} + +static jint setRightsFields(JNIEnv * env, jobject rights, T_DRM_Rights_Info* pRoInfo) +{ + jclass clazz; + jfieldID field; + jstring str; + jint index; + + clazz = (*env)->GetObjectClass(env, rights); + if (NULL == clazz) + return JNI_DRM_FAILURE; + + /* set roId field */ + field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;"); + (*env)->DeleteLocalRef(env, clazz); + + if (NULL == field) + return JNI_DRM_FAILURE; + + str = (*env)->NewStringUTF(env, (char *)pRoInfo->roId); + if (NULL == str) + return JNI_DRM_FAILURE; + + (*env)->SetObjectField(env, rights, field, str); + (*env)->DeleteLocalRef(env, str); + + return JNI_DRM_SUCCESS; +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRawContent_nativeConstructDrmContent + (JNIEnv * env, jobject rawContent, jobject data, jint len, jint mimeType) +{ + int32_t id; + T_DRM_Input_Data inData; + DrmData* drmInData; + + switch (mimeType) { + case JNI_DRM_MIMETYPE_MESSAGE: + mimeType = TYPE_DRM_MESSAGE; + break; + case JNI_DRM_MIMETYPE_CONTENT: + mimeType = TYPE_DRM_CONTENT; + break; + default: + return JNI_DRM_FAILURE; + } + + drmInData = newItem(); + if (NULL == drmInData) + return JNI_DRM_FAILURE; + + drmInData->env = env; + drmInData->pInData = &data; + drmInData->len = len; + + if (JNI_DRM_FAILURE == addItem(drmInData)) + return JNI_DRM_FAILURE; + + inData.inputHandle = (int32_t)drmInData; + inData.mimeType = mimeType; + inData.getInputDataLength = getInputStreamDataLength; + inData.readInputData = readInputStreamData; + + id = SVC_drm_openSession(inData); + if (id < 0) + return JNI_DRM_FAILURE; + + drmInData->id = id; + + return id; +} + +/* native interface */ +JNIEXPORT jstring JNICALL +Java_android_drm_mobile1_DrmRawContent_nativeGetRightsAddress + (JNIEnv * env, jobject rawContent) +{ + jint id; + uint8_t rightsIssuer[256] = {0}; + jstring str = NULL; + + if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) + return NULL; + + if (DRM_SUCCESS == SVC_drm_getRightsIssuer(id, rightsIssuer)) + str = (*env)->NewStringUTF(env, (char *)rightsIssuer); + + return str; +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRawContent_nativeGetDeliveryMethod + (JNIEnv * env, jobject rawContent) +{ + jint id; + int32_t res; + + if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) + return JNI_DRM_FAILURE; + + res = SVC_drm_getDeliveryMethod(id); + + switch (res) { + case FORWARD_LOCK: + return JNI_DRM_FORWARD_LOCK; + case COMBINED_DELIVERY: + return JNI_DRM_COMBINED_DELIVERY; + case SEPARATE_DELIVERY: + return JNI_DRM_SEPARATE_DELIVERY; + case SEPARATE_DELIVERY_FL: + return JNI_DRM_SEPARATE_DELIVERY_DM; + default: + return JNI_DRM_FAILURE; + } +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRawContent_nativeReadContent + (JNIEnv * env, jobject rawContent, jbyteArray buf, jint bufOff, jint len, jint mediaOff) +{ + jint id; + jbyte *nativeBuf; + jclass cls; + jmethodID mid; + DrmData* p; + jobject inputStream; + jfieldID field; + + if (NULL == buf) { + jclass newExcCls = (*env)->FindClass(env, "java.lang.NullPointerException"); + + if (newExcCls == NULL) + /* Unable to find the exception class, give up. */ + return JNI_DRM_FAILURE; + + (*env)->ThrowNew(env, newExcCls, "b is null"); + } + + if (len < 0 || bufOff < 0 || len + bufOff > (*env)->GetArrayLength(env, buf)) { + jclass newExcCls = (*env)->FindClass(env, "java/lang/IndexOutOfBoundsException"); + + if (newExcCls == NULL) + /* Unable to find the exception class, give up. */ + return JNI_DRM_FAILURE; + + (*env)->ThrowNew(env, newExcCls, NULL); + } + + if (mediaOff < 0 || len == 0) + return JNI_DRM_FAILURE; + + if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) + return JNI_DRM_FAILURE; + + p = getItem(id); + if (NULL == p) + return JNI_DRM_FAILURE; + + cls = (*env)->GetObjectClass(env, rawContent); + if (NULL == cls) + return JNI_DRM_FAILURE; + + field = (*env)->GetFieldID(env, cls, "inData", "Ljava/io/BufferedInputStream;"); + (*env)->DeleteLocalRef(env, cls); + + if (NULL == field) + return JNI_DRM_FAILURE; + + inputStream = (*env)->GetObjectField(env, rawContent, field); + + p->env = env; + p->pInData = &inputStream; + + nativeBuf = (*env)->GetByteArrayElements(env, buf, NULL); + + len = SVC_drm_getContent(id, mediaOff, (uint8_t *)nativeBuf + bufOff, len); + + (*env)->ReleaseByteArrayElements(env, buf, nativeBuf, 0); + + if (DRM_MEDIA_EOF == len) + return JNI_DRM_EOF; + if (len <= 0) + return JNI_DRM_FAILURE; + + return len; +} + +/* native interface */ +JNIEXPORT jstring JNICALL +Java_android_drm_mobile1_DrmRawContent_nativeGetContentType + (JNIEnv * env, jobject rawContent) +{ + jint id; + uint8_t contentType[64] = {0}; + jstring str = NULL; + + if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) + return NULL; + + if (DRM_SUCCESS == SVC_drm_getContentType(id, contentType)) + str = (*env)->NewStringUTF(env, (char *)contentType); + + return str; +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRawContent_nativeGetContentLength + (JNIEnv * env, jobject rawContent) +{ + jint id; + int32_t len; + + if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) + return JNI_DRM_FAILURE; + + len = SVC_drm_getContentLength(id); + + if (DRM_UNKNOWN_DATA_LEN == len) + return JNI_DRM_UNKNOWN_DATA_LEN; + + if (0 > len) + return JNI_DRM_FAILURE; + + return len; +} + +/* native interface */ +JNIEXPORT void JNICALL +Java_android_drm_mobile1_DrmRawContent_finalize + (JNIEnv * env, jobject rawContent) +{ + jint id; + + if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) + return; + + removeItem(id); + + SVC_drm_closeSession(id); +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRights_nativeGetConstraintInfo + (JNIEnv * env, jobject rights, jint permission, jobject constraint) +{ + jclass clazz; + jfieldID field; + jstring str; + uint8_t *nativeStr; + T_DRM_Rights_Info_Node *pRightsList; + T_DRM_Rights_Info_Node *pCurNode; + T_DRM_Constraint_Info *pConstraint; + + clazz = (*env)->GetObjectClass(env, rights); + if (NULL == clazz) + return JNI_DRM_FAILURE; + + field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;"); + (*env)->DeleteLocalRef(env, clazz); + + if (NULL == field) + return JNI_DRM_FAILURE; + + str = (*env)->GetObjectField(env, rights, field); + + nativeStr = (uint8_t *)(*env)->GetStringUTFChars(env, str, NULL); + if (NULL == nativeStr) + return JNI_DRM_FAILURE; + + /* this means forward-lock rights */ + if (0 == strcmp((char *)nativeStr, "ForwardLock")) { + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + return JNI_DRM_SUCCESS; + } + + if (DRM_FAILURE == SVC_drm_viewAllRights(&pRightsList)) { + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + return JNI_DRM_FAILURE; + } + + pCurNode = searchRightsObject((jbyte *)nativeStr, pRightsList); + if (NULL == pCurNode) { + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + SVC_drm_freeRightsInfoList(pRightsList); + return JNI_DRM_FAILURE; + } + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + + switch (permission) { + case JNI_DRM_PERMISSION_PLAY: + pConstraint = &(pCurNode->roInfo.playRights); + break; + case JNI_DRM_PERMISSION_DISPLAY: + pConstraint = &(pCurNode->roInfo.displayRights); + break; + case JNI_DRM_PERMISSION_EXECUTE: + pConstraint = &(pCurNode->roInfo.executeRights); + break; + case JNI_DRM_PERMISSION_PRINT: + pConstraint = &(pCurNode->roInfo.printRights); + break; + default: + SVC_drm_freeRightsInfoList(pRightsList); + return JNI_DRM_FAILURE; + } + + /* set constraint field */ + if (JNI_DRM_FAILURE == setConstraintFields(env, constraint, pConstraint)) { + SVC_drm_freeRightsInfoList(pRightsList); + return JNI_DRM_FAILURE; + } + + SVC_drm_freeRightsInfoList(pRightsList); + + return JNI_DRM_SUCCESS; +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRights_nativeConsumeRights + (JNIEnv * env, jobject rights, jint permission) +{ + jclass clazz; + jfieldID field; + jstring str; + uint8_t *nativeStr; + int32_t id; + + switch (permission) { + case JNI_DRM_PERMISSION_PLAY: + permission = DRM_PERMISSION_PLAY; + break; + case JNI_DRM_PERMISSION_DISPLAY: + permission = DRM_PERMISSION_DISPLAY; + break; + case JNI_DRM_PERMISSION_EXECUTE: + permission = DRM_PERMISSION_EXECUTE; + break; + case JNI_DRM_PERMISSION_PRINT: + permission = DRM_PERMISSION_PRINT; + break; + default: + return JNI_DRM_FAILURE; + } + + clazz = (*env)->GetObjectClass(env, rights); + if (NULL == clazz) + return JNI_DRM_FAILURE; + + field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;"); + (*env)->DeleteLocalRef(env, clazz); + + if (NULL == field) + return JNI_DRM_FAILURE; + + str = (*env)->GetObjectField(env, rights, field); + + nativeStr = (uint8_t *)(*env)->GetStringUTFChars(env, str, NULL); + if (NULL == nativeStr) + return JNI_DRM_FAILURE; + + if (0 == strcmp("ForwardLock", (char *)nativeStr)) { + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + return JNI_DRM_SUCCESS; + } + + if (DRM_SUCCESS != SVC_drm_updateRights(nativeStr, permission)) { + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + return JNI_DRM_FAILURE; + } + + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + + return JNI_DRM_SUCCESS; +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRightsManager_nativeInstallDrmRights + (JNIEnv * env, jobject rightsManager, jobject data, jint len, jint mimeType, jobject rights) +{ + int32_t id; + T_DRM_Input_Data inData; + DrmData* drmInData; + jclass cls; + jmethodID mid; + T_DRM_Rights_Info rightsInfo; + + switch (mimeType) { + case JNI_DRM_MIMETYPE_RIGHTS_XML: + mimeType = TYPE_DRM_RIGHTS_XML; + break; + case JNI_DRM_MIMETYPE_RIGHTS_WBXML: + mimeType = TYPE_DRM_RIGHTS_WBXML; + break; + case JNI_DRM_MIMETYPE_MESSAGE: + mimeType = TYPE_DRM_MESSAGE; + break; + default: + return JNI_DRM_FAILURE; + } + + drmInData = newItem(); + if (NULL == drmInData) + return JNI_DRM_FAILURE; + + drmInData->env = env; + drmInData->pInData = &data; + drmInData->len = len; + + inData.inputHandle = (int32_t)drmInData; + inData.mimeType = mimeType; + inData.getInputDataLength = getInputStreamDataLength; + inData.readInputData = readInputStreamData; + + memset(&rightsInfo, 0, sizeof(T_DRM_Rights_Info)); + if (DRM_FAILURE == SVC_drm_installRights(inData, &rightsInfo)) + return JNI_DRM_FAILURE; + + freeItem(drmInData); + + return setRightsFields(env, rights, &rightsInfo); +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRightsManager_nativeQueryRights + (JNIEnv * env, jobject rightsManager, jobject rawContent, jobject rights) +{ + jint id; + T_DRM_Rights_Info rightsInfo; + + if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) + return JNI_DRM_FAILURE; + + memset(&rightsInfo, 0, sizeof(T_DRM_Rights_Info)); + if (DRM_SUCCESS != SVC_drm_getRightsInfo(id, &rightsInfo)) + return JNI_DRM_FAILURE; + + return setRightsFields(env, rights, &rightsInfo); +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRightsManager_nativeGetNumOfRights + (JNIEnv * env, jobject rightsManager) +{ + T_DRM_Rights_Info_Node *pRightsList; + T_DRM_Rights_Info_Node *pCurNode; + int32_t num = 0; + + if (DRM_FAILURE == SVC_drm_viewAllRights(&pRightsList)) + return JNI_DRM_FAILURE; + + pCurNode = pRightsList; + while (pCurNode != NULL) { + num++; + pCurNode = pCurNode->next; + } + + SVC_drm_freeRightsInfoList(pRightsList); + + return num; +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRightsManager_nativeGetRightsList + (JNIEnv * env, jobject rightsManager, jobjectArray rightsArray, jint num) +{ + T_DRM_Rights_Info_Node *pRightsList; + T_DRM_Rights_Info_Node *pCurNode; + int32_t index; + + if (DRM_FAILURE == SVC_drm_viewAllRights(&pRightsList)) + return JNI_DRM_FAILURE; + + pCurNode = pRightsList; + for (index = 0; NULL != pCurNode; index++) { + jobject rights = (*env)->GetObjectArrayElement(env, rightsArray, index); + if (NULL == rights) + break; + + if (JNI_DRM_FAILURE == setRightsFields(env, rights, &(pCurNode->roInfo))) + break; + + (*env)->SetObjectArrayElement(env, rightsArray, index, rights); + + pCurNode = pCurNode->next; + } + + SVC_drm_freeRightsInfoList(pRightsList); + + return index; +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRightsManager_nativeDeleteRights + (JNIEnv * env, jobject rightsManager, jobject rights) +{ + jclass clazz; + jfieldID field; + jstring str; + uint8_t *nativeStr; + + clazz = (*env)->GetObjectClass(env, rights); + if (NULL == clazz) + return JNI_DRM_FAILURE; + + field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;"); + if (NULL == field) + return JNI_DRM_FAILURE; + + str = (*env)->GetObjectField(env, rights, field); + + nativeStr = (uint8_t *)(*env)->GetStringUTFChars(env, str, NULL); + if (NULL == nativeStr) + return JNI_DRM_FAILURE; + + if (0 == strcmp("ForwardLock", (char *)nativeStr)) + return JNI_DRM_SUCCESS; + + if (DRM_SUCCESS != SVC_drm_deleteRights(nativeStr)) { + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + return JNI_DRM_FAILURE; + } + + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + return JNI_DRM_SUCCESS; +} + +/* + * Table of methods associated with the DrmRawContent class. + */ +static JNINativeMethod gDrmRawContentMethods[] = { + /* name, signature, funcPtr */ + {"nativeConstructDrmContent", "(Ljava/io/InputStream;II)I", + (void*)Java_android_drm_mobile1_DrmRawContent_nativeConstructDrmContent}, + {"nativeGetRightsAddress", "()Ljava/lang/String;", + (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetRightsAddress}, + {"nativeGetDeliveryMethod", "()I", + (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetDeliveryMethod}, + {"nativeReadContent", "([BIII)I", + (void*)Java_android_drm_mobile1_DrmRawContent_nativeReadContent}, + {"nativeGetContentType", "()Ljava/lang/String;", + (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetContentType}, + {"nativeGetContentLength", "()I", + (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetContentLength}, + {"finalize", "()V", + (void*)Java_android_drm_mobile1_DrmRawContent_finalize}, +}; + +/* + * Table of methods associated with the DrmRights class. + */ +static JNINativeMethod gDrmRightsMethods[] = { + /* name, signature, funcPtr */ + {"nativeGetConstraintInfo", "(ILandroid/drm/mobile1/DrmConstraintInfo;)I", + (void*)Java_android_drm_mobile1_DrmRights_nativeGetConstraintInfo}, + {"nativeConsumeRights", "(I)I", + (void*)Java_android_drm_mobile1_DrmRights_nativeConsumeRights}, +}; + +/* + * Table of methods associated with the DrmRightsManager class. + */ +static JNINativeMethod gDrmRightsManagerMethods[] = { + /* name, signature, funcPtr */ + {"nativeInstallDrmRights", "(Ljava/io/InputStream;IILandroid/drm/mobile1/DrmRights;)I", + (void*)Java_android_drm_mobile1_DrmRightsManager_nativeInstallDrmRights}, + {"nativeQueryRights", "(Landroid/drm/mobile1/DrmRawContent;Landroid/drm/mobile1/DrmRights;)I", + (void*)Java_android_drm_mobile1_DrmRightsManager_nativeQueryRights}, + {"nativeGetNumOfRights", "()I", + (void*)Java_android_drm_mobile1_DrmRightsManager_nativeGetNumOfRights}, + {"nativeGetRightsList", "([Landroid/drm/mobile1/DrmRights;I)I", + (void*)Java_android_drm_mobile1_DrmRightsManager_nativeGetRightsList}, + {"nativeDeleteRights", "(Landroid/drm/mobile1/DrmRights;)I", + (void*)Java_android_drm_mobile1_DrmRightsManager_nativeDeleteRights}, +}; + +/* + * Register several native methods for one class. + */ +static int registerNativeMethods(JNIEnv* env, const char* className, + JNINativeMethod* gMethods, int numMethods) +{ + jclass clazz; + + clazz = (*env)->FindClass(env, className); + if (clazz == NULL) + return JNI_FALSE; + + if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) + return JNI_FALSE; + + return JNI_TRUE; +} + +/* + * Register native methods for all classes we know about. + */ +static int registerNatives(JNIEnv* env) +{ + if (!registerNativeMethods(env, "android/drm/mobile1/DrmRawContent", + gDrmRawContentMethods, sizeof(gDrmRawContentMethods) / sizeof(gDrmRawContentMethods[0]))) + return JNI_FALSE; + + if (!registerNativeMethods(env, "android/drm/mobile1/DrmRights", + gDrmRightsMethods, sizeof(gDrmRightsMethods) / sizeof(gDrmRightsMethods[0]))) + return JNI_FALSE; + + if (!registerNativeMethods(env, "android/drm/mobile1/DrmRightsManager", + gDrmRightsManagerMethods, sizeof(gDrmRightsManagerMethods) / sizeof(gDrmRightsManagerMethods[0]))) + return JNI_FALSE; + + return JNI_TRUE; +} + +jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + JNIEnv* env = NULL; + jint result = -1; + + printf("Entering JNI_OnLoad\n"); + + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) + goto bail; + + assert(env != NULL); + + if (!registerNatives(env)) + goto bail; + + /* success -- return valid version number */ + result = JNI_VERSION_1_4; + +bail: + printf("Leaving JNI_OnLoad (result=0x%x)\n", result); + return result; +} diff --git a/media/libdrm/mobile1/src/objmng/drm_api.c b/media/libdrm/mobile1/src/objmng/drm_api.c new file mode 100644 index 0000000..0e453de --- /dev/null +++ b/media/libdrm/mobile1/src/objmng/drm_api.c @@ -0,0 +1,1944 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <svc_drm.h> +#include <drm_inner.h> +#include <parser_dm.h> +#include <parser_dcf.h> +#include <parser_rel.h> +#include <drm_rights_manager.h> +#include <drm_time.h> +#include <drm_decoder.h> +#include <aes.h> +#include "log.h" + +/** + * Current id. + */ +static int32_t curID = 0; + +/** + * The header pointer for the session list. + */ +static T_DRM_Session_Node* sessionTable = NULL; + +/** + * New a session. + */ +static T_DRM_Session_Node* newSession(T_DRM_Input_Data data) +{ + T_DRM_Session_Node* s = (T_DRM_Session_Node *)malloc(sizeof(T_DRM_Session_Node)); + + if (NULL != s) { + memset(s, 0, sizeof(T_DRM_Session_Node)); + + s->sessionId = curID++; + s->inputHandle = data.inputHandle; + s->mimeType = data.mimeType; + s->getInputDataLengthFunc = data.getInputDataLength; + s->readInputDataFunc = data.readInputData; + s->seekInputDataFunc = data.seekInputData; + } + + return s; +} + +/** + * Free a session. + */ +static void freeSession(T_DRM_Session_Node* s) +{ + if (NULL == s) + return; + + if (NULL != s->rawContent) + free(s->rawContent); + + if (NULL != s->readBuf) + free(s->readBuf); + + if (NULL != s->infoStruct) + free(s->infoStruct); + + free(s); +} + +/** + * Add a session to list. + */ +static int32_t addSession(T_DRM_Session_Node* s) +{ + if (NULL == s) + return -1; + + s->next = sessionTable; + sessionTable = s; + + return s->sessionId; +} + +/** + * Get a session from the list. + */ +static T_DRM_Session_Node* getSession(int32_t sessionId) +{ + T_DRM_Session_Node* s; + + if (sessionId < 0 || NULL == sessionTable) + return NULL; + + for (s = sessionTable; s != NULL; s = s->next) { + if (sessionId == s->sessionId) + return s; + } + + return NULL; +} + +/** + * Remove a session from the list. + */ +static void removeSession(int32_t sessionId) +{ + T_DRM_Session_Node *curS, *preS; + + if (sessionId < 0 || NULL == sessionTable) + return; + + if (sessionId == sessionTable->sessionId) { + curS = sessionTable; + sessionTable = curS->next; + freeSession(curS); + return; + } + + for (preS = sessionTable; preS->next != NULL; preS = preS->next) { + if (preS->next->sessionId == sessionId) + curS = preS->next; + } + + if (NULL == preS->next) + return; + + preS->next = curS->next; + freeSession(curS); +} + +/** + * Try to identify the mimetype according the input DRM data. + */ +static int32_t getMimeType(const uint8_t *buf, int32_t bufLen) +{ + const uint8_t *p; + + if (NULL == buf || bufLen <= 0) + return TYPE_DRM_UNKNOWN; + + p = buf; + + /* check if it is DRM Content Format, only check the first field of Version, it must be "0x01" */ + if (0x01 == *p) + return TYPE_DRM_CONTENT; + + /* check if it is DRM Message, only check the first two bytes, it must be the start flag of boundary: "--" */ + if (bufLen >= 2 && '-' == *p && '-' == *(p + 1)) + return TYPE_DRM_MESSAGE; + + /* check if it is DRM Rights XML format, only check the first several bytes, it must be: "<o-ex:rights" */ + if (bufLen >= 12 && 0 == strncmp("<o-ex:rights", (char *)p, 12)) + return TYPE_DRM_RIGHTS_XML; + + /* check if it is DRM Rights WBXML format, only check the first two bytes, it must be: 0x03, 0x0e */ + if (bufLen >= 2 && 0x03 == *p && 0x0e == *(p + 1)) + return TYPE_DRM_RIGHTS_WBXML; + + return TYPE_DRM_UNKNOWN; +} + +static int32_t drm_skipCRLFinB64(const uint8_t* b64Data, int32_t len) +{ + const uint8_t* p; + int32_t skipLen = 0; + + if (NULL == b64Data || len <= 0) + return -1; + + p = b64Data; + while (p - b64Data < len) { + if ('\r' == *p || '\n'== *p) + skipLen++; + p++; + } + + return skipLen; +} + +static int32_t drm_scanEndBoundary(const uint8_t* pBuf, int32_t len, uint8_t* const boundary) +{ + const uint8_t* p; + int32_t leftLen; + int32_t boundaryLen; + + if (NULL == pBuf || len <=0 || NULL == boundary) + return -1; + + p = pBuf; + boundaryLen = strlen((char *)boundary) + 2; /* 2 means: '\r' and '\n' */ + leftLen = len - (p - pBuf); + while (leftLen > 0) { + if (NULL == (p = memchr(p, '\r', leftLen))) + break; + + leftLen = len - (p - pBuf); + if (leftLen < boundaryLen) + return -2; /* here means may be the boundary has been split */ + + if (('\n' == *(p + 1)) && (0 == memcmp(p + 2, boundary, strlen((char *)boundary)))) + return p - pBuf; /* find the boundary here */ + + p++; + leftLen--; + } + + return len; /* no boundary found */ +} + +static int32_t drm_getLicenseInfo(T_DRM_Rights* pRights, T_DRM_Rights_Info* licenseInfo) +{ + if (NULL != licenseInfo && NULL != pRights) { + strcpy((char *)licenseInfo->roId, (char *)pRights->uid); + + if (1 == pRights->bIsDisplayable) { + licenseInfo->displayRights.indicator = pRights->DisplayConstraint.Indicator; + licenseInfo->displayRights.count = + pRights->DisplayConstraint.Count; + licenseInfo->displayRights.startDate = + pRights->DisplayConstraint.StartTime.date; + licenseInfo->displayRights.startTime = + pRights->DisplayConstraint.StartTime.time; + licenseInfo->displayRights.endDate = + pRights->DisplayConstraint.EndTime.date; + licenseInfo->displayRights.endTime = + pRights->DisplayConstraint.EndTime.time; + licenseInfo->displayRights.intervalDate = + pRights->DisplayConstraint.Interval.date; + licenseInfo->displayRights.intervalTime = + pRights->DisplayConstraint.Interval.time; + } + if (1 == pRights->bIsPlayable) { + licenseInfo->playRights.indicator = pRights->PlayConstraint.Indicator; + licenseInfo->playRights.count = pRights->PlayConstraint.Count; + licenseInfo->playRights.startDate = + pRights->PlayConstraint.StartTime.date; + licenseInfo->playRights.startTime = + pRights->PlayConstraint.StartTime.time; + licenseInfo->playRights.endDate = + pRights->PlayConstraint.EndTime.date; + licenseInfo->playRights.endTime = + pRights->PlayConstraint.EndTime.time; + licenseInfo->playRights.intervalDate = + pRights->PlayConstraint.Interval.date; + licenseInfo->playRights.intervalTime = + pRights->PlayConstraint.Interval.time; + } + if (1 == pRights->bIsExecuteable) { + licenseInfo->executeRights.indicator = pRights->ExecuteConstraint.Indicator; + licenseInfo->executeRights.count = + pRights->ExecuteConstraint.Count; + licenseInfo->executeRights.startDate = + pRights->ExecuteConstraint.StartTime.date; + licenseInfo->executeRights.startTime = + pRights->ExecuteConstraint.StartTime.time; + licenseInfo->executeRights.endDate = + pRights->ExecuteConstraint.EndTime.date; + licenseInfo->executeRights.endTime = + pRights->ExecuteConstraint.EndTime.time; + licenseInfo->executeRights.intervalDate = + pRights->ExecuteConstraint.Interval.date; + licenseInfo->executeRights.intervalTime = + pRights->ExecuteConstraint.Interval.time; + } + if (1 == pRights->bIsPrintable) { + licenseInfo->printRights.indicator = pRights->PrintConstraint.Indicator; + licenseInfo->printRights.count = + pRights->PrintConstraint.Count; + licenseInfo->printRights.startDate = + pRights->PrintConstraint.StartTime.date; + licenseInfo->printRights.startTime = + pRights->PrintConstraint.StartTime.time; + licenseInfo->printRights.endDate = + pRights->PrintConstraint.EndTime.date; + licenseInfo->printRights.endTime = + pRights->PrintConstraint.EndTime.time; + licenseInfo->printRights.intervalDate = + pRights->PrintConstraint.Interval.date; + licenseInfo->printRights.intervalTime = + pRights->PrintConstraint.Interval.time; + } + return TRUE; + } + return FALSE; +} + +static int32_t drm_addRightsNodeToList(T_DRM_Rights_Info_Node **ppRightsHeader, + T_DRM_Rights_Info_Node *pInputRightsNode) +{ + T_DRM_Rights_Info_Node *pRightsNode; + + if (NULL == ppRightsHeader || NULL == pInputRightsNode) + return FALSE; + + pRightsNode = (T_DRM_Rights_Info_Node *)malloc(sizeof(T_DRM_Rights_Info_Node)); + if (NULL == pRightsNode) + return FALSE; + + memcpy(pRightsNode, pInputRightsNode, sizeof(T_DRM_Rights_Info_Node)); + pRightsNode->next = NULL; + + /* this means it is the first node */ + if (NULL == *ppRightsHeader) + *ppRightsHeader = pRightsNode; + else { + T_DRM_Rights_Info_Node *pTmp; + + pTmp = *ppRightsHeader; + while (NULL != pTmp->next) + pTmp = pTmp->next; + + pTmp->next = pRightsNode; + } + return TRUE; +} + +static int32_t drm_startConsumeRights(int32_t * bIsXXable, + T_DRM_Rights_Constraint * XXConstraint, + int32_t * writeFlag) +{ + T_DB_TIME_SysTime curDateTime; + T_DRM_DATETIME CurrentTime; + uint8_t countFlag = 0; + + memset(&CurrentTime, 0, sizeof(T_DRM_DATETIME)); + + if (NULL == bIsXXable || 0 == *bIsXXable || NULL == XXConstraint || NULL == writeFlag) + return DRM_FAILURE; + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_NO_CONSTRAINT)) /* Have utter right? */ + return DRM_SUCCESS; + + *bIsXXable = 0; /* Assume have invalid rights at first */ + *writeFlag = 0; + + if (0 != (XXConstraint->Indicator & (DRM_START_TIME_CONSTRAINT | DRM_END_TIME_CONSTRAINT | DRM_INTERVAL_CONSTRAINT))) { + DRM_time_getSysTime(&curDateTime); + + if (-1 == drm_checkDate(curDateTime.year, curDateTime.month, curDateTime.day, + curDateTime.hour, curDateTime.min, curDateTime.sec)) + return DRM_FAILURE; + + YMD_HMS_2_INT(curDateTime.year, curDateTime.month, curDateTime.day, + CurrentTime.date, curDateTime.hour, curDateTime.min, + curDateTime.sec, CurrentTime.time); + } + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_COUNT_CONSTRAINT)) { /* Have count restrict? */ + *writeFlag = 1; + /* If it has only one time for use, after use this function, we will delete this rights */ + if (XXConstraint->Count <= 0) { + XXConstraint->Indicator &= ~DRM_COUNT_CONSTRAINT; + return DRM_RIGHTS_EXPIRED; + } + + if (XXConstraint->Count-- <= 1) { + XXConstraint->Indicator &= ~DRM_COUNT_CONSTRAINT; + countFlag = 1; + } + } + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_START_TIME_CONSTRAINT)) { + if (XXConstraint->StartTime.date > CurrentTime.date || + (XXConstraint->StartTime.date == CurrentTime.date && + XXConstraint->StartTime.time >= CurrentTime.time)) { + *bIsXXable = 1; + return DRM_RIGHTS_PENDING; + } + } + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_END_TIME_CONSTRAINT)) { /* Have end time restrict? */ + if (XXConstraint->EndTime.date < CurrentTime.date || + (XXConstraint->EndTime.date == CurrentTime.date && + XXConstraint->EndTime.time <= CurrentTime.time)) { + *writeFlag = 1; + XXConstraint->Indicator &= ~DRM_END_TIME_CONSTRAINT; + return DRM_RIGHTS_EXPIRED; + } + } + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_INTERVAL_CONSTRAINT)) { /* Have interval time restrict? */ + int32_t year, mon, day, hour, min, sec, date, time; + int32_t ret; + + XXConstraint->Indicator |= DRM_END_TIME_CONSTRAINT; + XXConstraint->Indicator &= ~DRM_INTERVAL_CONSTRAINT; /* Write off interval right */ + *writeFlag = 1; + + if (XXConstraint->Interval.date == 0 + && XXConstraint->Interval.time == 0) { + return DRM_RIGHTS_EXPIRED; + } + date = CurrentTime.date + XXConstraint->Interval.date; + time = CurrentTime.time + XXConstraint->Interval.time; + INT_2_YMD_HMS(year, mon, day, date, hour, min, sec, time); + + if (sec > 59) { + min += sec / 60; + sec %= 60; + } + if (min > 59) { + hour += min / 60; + min %= 60; + } + if (hour > 23) { + day += hour / 24; + hour %= 24; + } + if (day > 31) { + mon += day / 31; + day %= 31; + } + if (mon > 12) { + year += mon / 12; + mon %= 12; + } + if (day > (ret = drm_monthDays(year, mon))) { + day -= ret; + mon++; + if (mon > 12) { + mon -= 12; + year++; + } + } + YMD_HMS_2_INT(year, mon, day, XXConstraint->EndTime.date, hour, + min, sec, XXConstraint->EndTime.time); + } + + if (1 != countFlag) + *bIsXXable = 1; /* Can go here ,so right must be valid */ + return DRM_SUCCESS; +} + +static int32_t drm_startCheckRights(int32_t * bIsXXable, + T_DRM_Rights_Constraint * XXConstraint) +{ + T_DB_TIME_SysTime curDateTime; + T_DRM_DATETIME CurrentTime; + + memset(&CurrentTime, 0, sizeof(T_DRM_DATETIME)); + + if (NULL == bIsXXable || 0 == *bIsXXable || NULL == XXConstraint) + return DRM_FAILURE; + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_NO_CONSTRAINT)) /* Have utter right? */ + return DRM_SUCCESS; + + *bIsXXable = 0; /* Assume have invalid rights at first */ + + if (0 != (XXConstraint->Indicator & (DRM_START_TIME_CONSTRAINT | DRM_END_TIME_CONSTRAINT))) { + DRM_time_getSysTime(&curDateTime); + + if (-1 == drm_checkDate(curDateTime.year, curDateTime.month, curDateTime.day, + curDateTime.hour, curDateTime.min, curDateTime.sec)) + return DRM_FAILURE; + + YMD_HMS_2_INT(curDateTime.year, curDateTime.month, curDateTime.day, + CurrentTime.date, curDateTime.hour, curDateTime.min, + curDateTime.sec, CurrentTime.time); + } + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_COUNT_CONSTRAINT)) { /* Have count restrict? */ + if (XXConstraint->Count <= 0) { + XXConstraint->Indicator &= ~DRM_COUNT_CONSTRAINT; + return DRM_RIGHTS_EXPIRED; + } + } + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_START_TIME_CONSTRAINT)) { + if (XXConstraint->StartTime.date > CurrentTime.date || + (XXConstraint->StartTime.date == CurrentTime.date && + XXConstraint->StartTime.time >= CurrentTime.time)) { + *bIsXXable = 1; + return DRM_RIGHTS_PENDING; + } + } + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_END_TIME_CONSTRAINT)) { /* Have end time restrict? */ + if (XXConstraint->EndTime.date < CurrentTime.date || + (XXConstraint->EndTime.date == CurrentTime.date && + XXConstraint->EndTime.time <= CurrentTime.time)) { + XXConstraint->Indicator &= ~DRM_END_TIME_CONSTRAINT; + return DRM_RIGHTS_EXPIRED; + } + } + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_INTERVAL_CONSTRAINT)) { /* Have interval time restrict? */ + if (XXConstraint->Interval.date == 0 && XXConstraint->Interval.time == 0) { + XXConstraint->Indicator &= ~DRM_INTERVAL_CONSTRAINT; + return DRM_RIGHTS_EXPIRED; + } + } + + *bIsXXable = 1; + return DRM_SUCCESS; +} + +int32_t drm_checkRoAndUpdate(int32_t id, int32_t permission) +{ + int32_t writeFlag = 0; + int32_t roAmount; + int32_t validRoAmount = 0; + int32_t flag = DRM_FAILURE; + int32_t i, j; + T_DRM_Rights *pRo; + T_DRM_Rights *pCurRo; + int32_t * pNumOfPriority; + int32_t iNum; + T_DRM_Rights_Constraint * pCurConstraint; + T_DRM_Rights_Constraint * pCompareConstraint; + int priority[8] = {1, 2, 4, 3, 8, 6, 7, 5}; + + if (FALSE == drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT)) + return DRM_FAILURE; + + validRoAmount = roAmount; + if (roAmount < 1) + return DRM_NO_RIGHTS; + + pRo = malloc(roAmount * sizeof(T_DRM_Rights)); + pCurRo = pRo; + if (NULL == pRo) + return DRM_FAILURE; + + if (FALSE == drm_writeOrReadInfo(id, pRo, &roAmount, GET_ALL_RO)) { + free(pRo); + return DRM_FAILURE; + } + + /** check the right priority */ + pNumOfPriority = malloc(sizeof(int32_t) * roAmount); + for(i = 0; i < roAmount; i++) { + iNum = roAmount - 1; + for(j = 0; j < roAmount; j++) { + if(i == j) + continue; + switch(permission) { + case DRM_PERMISSION_PLAY: + pCurConstraint = &pRo[i].PlayConstraint; + pCompareConstraint = &pRo[j].PlayConstraint; + break; + case DRM_PERMISSION_DISPLAY: + pCurConstraint = &pRo[i].DisplayConstraint; + pCompareConstraint = &pRo[j].DisplayConstraint; + break; + case DRM_PERMISSION_EXECUTE: + pCurConstraint = &pRo[i].ExecuteConstraint; + pCompareConstraint = &pRo[j].ExecuteConstraint; + break; + case DRM_PERMISSION_PRINT: + pCurConstraint = &pRo[i].PrintConstraint; + pCompareConstraint = &pRo[j].PrintConstraint; + break; + default: + free(pRo); + free(pNumOfPriority); + return DRM_FAILURE; + } + + /**get priority by Indicator*/ + if(0 == (pCurConstraint->Indicator & DRM_NO_CONSTRAINT) && + 0 == (pCompareConstraint->Indicator & DRM_NO_CONSTRAINT)) { + int num1, num2; + num1 = (pCurConstraint->Indicator & 0x0e) >> 1; + num2 = (pCompareConstraint->Indicator & 0x0e) >> 1; + if(priority[num1] > priority[num2]) { + iNum--; + continue; + } else if(priority[pCurConstraint->Indicator] < priority[pCompareConstraint->Indicator]) + continue; + } else if(pCurConstraint->Indicator > pCompareConstraint->Indicator) { + iNum--; + continue; + } else if(pCurConstraint->Indicator < pCompareConstraint->Indicator) + continue; + + if(0 != (pCurConstraint->Indicator & DRM_END_TIME_CONSTRAINT)) { + if(pCurConstraint->EndTime.date < pCompareConstraint->EndTime.date) { + iNum--; + continue; + } else if(pCurConstraint->EndTime.date > pCompareConstraint->EndTime.date) + continue; + + if(pCurConstraint->EndTime.time < pCompareConstraint->EndTime.time) { + iNum--; + continue; + } else if(pCurConstraint->EndTime.date > pCompareConstraint->EndTime.date) + continue; + } + + if(0 != (pCurConstraint->Indicator & DRM_INTERVAL_CONSTRAINT)) { + if(pCurConstraint->Interval.date < pCompareConstraint->Interval.date) { + iNum--; + continue; + } else if(pCurConstraint->Interval.date > pCompareConstraint->Interval.date) + continue; + + if(pCurConstraint->Interval.time < pCompareConstraint->Interval.time) { + iNum--; + continue; + } else if(pCurConstraint->Interval.time > pCompareConstraint->Interval.time) + continue; + } + + if(0 != (pCurConstraint->Indicator & DRM_COUNT_CONSTRAINT)) { + if(pCurConstraint->Count < pCompareConstraint->Count) { + iNum--; + continue; + } else if(pCurConstraint->Count > pCompareConstraint->Count) + continue; + } + + if(i < j) + iNum--; + } + pNumOfPriority[iNum] = i; + } + + for (i = 0; i < validRoAmount; i++) { + /** check the right priority */ + if (pNumOfPriority[i] >= validRoAmount) + break; + + pCurRo = pRo + pNumOfPriority[i]; + + switch (permission) { + case DRM_PERMISSION_PLAY: + flag = + drm_startConsumeRights(&pCurRo->bIsPlayable, + &pCurRo->PlayConstraint, &writeFlag); + break; + case DRM_PERMISSION_DISPLAY: + flag = + drm_startConsumeRights(&pCurRo->bIsDisplayable, + &pCurRo->DisplayConstraint, + &writeFlag); + break; + case DRM_PERMISSION_EXECUTE: + flag = + drm_startConsumeRights(&pCurRo->bIsExecuteable, + &pCurRo->ExecuteConstraint, + &writeFlag); + break; + case DRM_PERMISSION_PRINT: + flag = + drm_startConsumeRights(&pCurRo->bIsPrintable, + &pCurRo->PrintConstraint, &writeFlag); + break; + default: + free(pNumOfPriority); + free(pRo); + return DRM_FAILURE; + } + + /* Here confirm the valid RO amount and set the writeFlag */ + if (0 == pCurRo->bIsPlayable && 0 == pCurRo->bIsDisplayable && + 0 == pCurRo->bIsExecuteable && 0 == pCurRo->bIsPrintable) { + int32_t iCurPri; + + /** refresh the right priority */ + iCurPri = pNumOfPriority[i]; + for(j = i; j < validRoAmount - 1; j++) + pNumOfPriority[j] = pNumOfPriority[j + 1]; + + if(iCurPri != validRoAmount - 1) { + memcpy(pCurRo, pRo + validRoAmount - 1, + sizeof(T_DRM_Rights)); + for(j = 0; j < validRoAmount -1; j++) { + if(validRoAmount - 1 == pNumOfPriority[j]) + pNumOfPriority[j] = iCurPri; + } + } + + /* Here means it is not the last one RO, so the invalid RO should be deleted */ + writeFlag = 1; + validRoAmount--; /* If current right is invalid */ + i--; + } + + /* If the flag is TRUE, this means: we have found a valid RO, so break, no need to check other RO */ + if (DRM_SUCCESS == flag) + break; + } + + if (1 == writeFlag) { + /* Delete the *.info first */ + //drm_removeIdInfoFile(id); + + if (FALSE == drm_writeOrReadInfo(id, pRo, &validRoAmount, SAVE_ALL_RO)) + flag = DRM_FAILURE; + } + + free(pNumOfPriority); + free(pRo); + return flag; +} + + +/* see svc_drm.h */ +int32_t SVC_drm_installRights(T_DRM_Input_Data data, T_DRM_Rights_Info* pRightsInfo) +{ + uint8_t *buf; + int32_t dataLen, bufLen; + T_DRM_Rights rights; + + if (0 == data.inputHandle) + return DRM_RIGHTS_DATA_INVALID; + + /* Get input rights data length */ + dataLen = data.getInputDataLength(data.inputHandle); + if (dataLen <= 0) + return DRM_RIGHTS_DATA_INVALID; + + /* Check if the length is larger than DRM max malloc length */ + if (dataLen > DRM_MAX_MALLOC_LEN) + bufLen = DRM_MAX_MALLOC_LEN; + else + bufLen = dataLen; + + buf = (uint8_t *)malloc(bufLen); + if (NULL == buf) + return DRM_FAILURE; + + /* Read input data to buffer */ + if (0 >= data.readInputData(data.inputHandle, buf, bufLen)) { + free(buf); + return DRM_RIGHTS_DATA_INVALID; + } + + /* if the input mime type is unknown, DRM engine will try to recognize it. */ + if (TYPE_DRM_UNKNOWN == data.mimeType) + data.mimeType = getMimeType(buf, bufLen); + + switch(data.mimeType) { + case TYPE_DRM_MESSAGE: /* in case of Combined Delivery, extract the rights part to install */ + { + T_DRM_DM_Info dmInfo; + + memset(&dmInfo, 0, sizeof(T_DRM_DM_Info)); + if (FALSE == drm_parseDM(buf, bufLen, &dmInfo)) { + free(buf); + return DRM_RIGHTS_DATA_INVALID; + } + + /* if it is not Combined Delivery, it can not use to "SVC_drm_installRights" */ + if (COMBINED_DELIVERY != dmInfo.deliveryType || dmInfo.rightsOffset <= 0 || dmInfo.rightsLen <= 0) { + free(buf); + return DRM_RIGHTS_DATA_INVALID; + } + + memset(&rights, 0, sizeof(T_DRM_Rights)); + if (FALSE == drm_relParser(buf + dmInfo.rightsOffset, dmInfo.rightsLen, TYPE_DRM_RIGHTS_XML, &rights)) { + free(buf); + return DRM_RIGHTS_DATA_INVALID; + } + } + break; + case TYPE_DRM_RIGHTS_XML: + case TYPE_DRM_RIGHTS_WBXML: + memset(&rights, 0, sizeof(T_DRM_Rights)); + if (FALSE == drm_relParser(buf, bufLen, data.mimeType, &rights)) { + free(buf); + return DRM_RIGHTS_DATA_INVALID; + } + break; + case TYPE_DRM_CONTENT: /* DCF should not using "SVC_drm_installRights", it should be used to open a session. */ + case TYPE_DRM_UNKNOWN: + default: + free(buf); + return DRM_MEDIA_DATA_INVALID; + } + + free(buf); + + /* append the rights information to DRM engine storage */ + if (FALSE == drm_appendRightsInfo(&rights)) + return DRM_FAILURE; + + memset(pRightsInfo, 0, sizeof(T_DRM_Rights_Info)); + drm_getLicenseInfo(&rights, pRightsInfo); + + return DRM_SUCCESS; +} + +/* see svc_drm.h */ +int32_t SVC_drm_openSession(T_DRM_Input_Data data) +{ + int32_t session; + int32_t dataLen; + T_DRM_Session_Node* s; + + if (0 == data.inputHandle) + return DRM_MEDIA_DATA_INVALID; + + /* Get input data length */ + dataLen = data.getInputDataLength(data.inputHandle); + if (dataLen <= 0) + return DRM_MEDIA_DATA_INVALID; + + s = newSession(data); + if (NULL == s) + return DRM_FAILURE; + + /* Check if the length is larger than DRM max malloc length */ + if (dataLen > DRM_MAX_MALLOC_LEN) + s->rawContentLen = DRM_MAX_MALLOC_LEN; + else + s->rawContentLen = dataLen; + + s->rawContent = (uint8_t *)malloc(s->rawContentLen); + if (NULL == s->rawContent) + return DRM_FAILURE; + + /* Read input data to buffer */ + if (0 >= data.readInputData(data.inputHandle, s->rawContent, s->rawContentLen)) { + freeSession(s); + return DRM_MEDIA_DATA_INVALID; + } + + /* if the input mime type is unknown, DRM engine will try to recognize it. */ + if (TYPE_DRM_UNKNOWN == data.mimeType) + data.mimeType = getMimeType(s->rawContent, s->rawContentLen); + + switch(data.mimeType) { + case TYPE_DRM_MESSAGE: + { + T_DRM_DM_Info dmInfo; + + memset(&dmInfo, 0, sizeof(T_DRM_DM_Info)); + if (FALSE == drm_parseDM(s->rawContent, s->rawContentLen, &dmInfo)) { + freeSession(s); + return DRM_MEDIA_DATA_INVALID; + } + + s->deliveryMethod = dmInfo.deliveryType; + + if (SEPARATE_DELIVERY_FL == s->deliveryMethod) + s->contentLength = DRM_UNKNOWN_DATA_LEN; + else + s->contentLength = dmInfo.contentLen; + + s->transferEncoding = dmInfo.transferEncoding; + s->contentOffset = dmInfo.contentOffset; + s->bEndData = FALSE; + strcpy((char *)s->contentType, (char *)dmInfo.contentType); + strcpy((char *)s->contentID, (char *)dmInfo.contentID); + + if (SEPARATE_DELIVERY_FL == s->deliveryMethod) { + s->infoStruct = (T_DRM_Dcf_Node *)malloc(sizeof(T_DRM_Dcf_Node)); + if (NULL == s->infoStruct) + return DRM_FAILURE; + memset(s->infoStruct, 0, sizeof(T_DRM_Dcf_Node)); + + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength = dmInfo.contentLen; + strcpy((char *)((T_DRM_Dcf_Node *)(s->infoStruct))->rightsIssuer, (char *)dmInfo.rightsIssuer); + break; + } + + if (DRM_MESSAGE_CODING_BASE64 == s->transferEncoding) { + s->infoStruct = (T_DRM_DM_Base64_Node *)malloc(sizeof(T_DRM_DM_Base64_Node)); + if (NULL == s->infoStruct) + return DRM_FAILURE; + memset(s->infoStruct, 0, sizeof(T_DRM_DM_Base64_Node)); + + strcpy((char *)((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary, (char *)dmInfo.boundary); + } else { + s->infoStruct = (T_DRM_DM_Binary_Node *)malloc(sizeof(T_DRM_DM_Binary_Node)); + if (NULL == s->infoStruct) + return DRM_FAILURE; + memset(s->infoStruct, 0, sizeof(T_DRM_DM_Binary_Node)); + + strcpy((char *)((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary, (char *)dmInfo.boundary); + } + + + if (DRM_MESSAGE_CODING_BASE64 == s->transferEncoding) { + if (s->contentLength > 0) { + int32_t encLen, decLen; + + encLen = s->contentLength; + decLen = encLen / DRM_B64_ENC_BLOCK * DRM_B64_DEC_BLOCK; + + decLen = drm_decodeBase64(s->rawContent, decLen, s->rawContent + s->contentOffset, &encLen); + s->contentLength = decLen; + } else { + int32_t encLen = DRM_MAX_MALLOC_LEN - s->contentOffset, decLen; + int32_t skipLen, needBytes, i; + uint8_t *pStart; + int32_t res, bFoundBoundary = FALSE; + + pStart = s->rawContent + s->contentOffset; + if (-1 == (skipLen = drm_skipCRLFinB64(pStart, encLen))) { + freeSession(s); + return DRM_FAILURE; + } + + needBytes = DRM_B64_ENC_BLOCK - ((encLen - skipLen) % DRM_B64_ENC_BLOCK); + if (needBytes < DRM_B64_ENC_BLOCK) { + s->rawContent = (uint8_t *)realloc(s->rawContent, DRM_MAX_MALLOC_LEN + needBytes); + if (NULL == s->rawContent) { + freeSession(s); + return DRM_FAILURE; + } + + i = 0; + while (i < needBytes) { + if (-1 != data.readInputData(data.inputHandle, s->rawContent + DRM_MAX_MALLOC_LEN + i, 1)) { + if ('\r' == *(s->rawContent + DRM_MAX_MALLOC_LEN + i) || '\n' == *(s->rawContent + DRM_MAX_MALLOC_LEN + i)) + continue; + i++; + } else + break; + } + encLen += i; + } + + res = drm_scanEndBoundary(pStart, encLen, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary); + if (-1 == res) { + freeSession(s); + return DRM_FAILURE; + } + if (-2 == res) { /* may be there is a boundary */ + int32_t boundaryLen, leftLen, readBytes; + char* pTmp = memrchr(pStart, '\r', encLen); + + if (NULL == pTmp) { + freeSession(s); + return DRM_FAILURE; /* conflict */ + } + boundaryLen = strlen((char *)((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary) + 2; /* 2 means: '\r''\n' */ + s->readBuf = (uint8_t *)malloc(boundaryLen); + if (NULL == s->readBuf) { + freeSession(s); + return DRM_FAILURE; + } + s->readBufOff = encLen - ((uint8_t *)pTmp - pStart); + s->readBufLen = boundaryLen - s->readBufOff; + memcpy(s->readBuf, pTmp, s->readBufOff); + readBytes = data.readInputData(data.inputHandle, s->readBuf + s->readBufOff, s->readBufLen); + if (-1 == readBytes || readBytes < s->readBufLen) { + freeSession(s); + return DRM_MEDIA_DATA_INVALID; + } + + if (0 == drm_scanEndBoundary(s->readBuf, boundaryLen, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary)) { + encLen = (uint8_t *)pTmp - pStart; /* yes, it is the end boundary */ + bFoundBoundary = TRUE; + } + } else { + if (res >= 0 && res < encLen) { + encLen = res; + bFoundBoundary = TRUE; + } + } + + decLen = encLen / DRM_B64_ENC_BLOCK * DRM_B64_DEC_BLOCK; + decLen = drm_decodeBase64(s->rawContent, decLen, s->rawContent + s->contentOffset, &encLen); + ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen = decLen; + if (bFoundBoundary) + s->contentLength = decLen; + } + } else { + /* binary data */ + if (DRM_UNKNOWN_DATA_LEN == s->contentLength) { + /* try to check whether there is boundary may be split */ + int32_t res, binContentLen; + uint8_t* pStart; + int32_t bFoundBoundary = FALSE; + + pStart = s->rawContent + s->contentOffset; + binContentLen = s->rawContentLen - s->contentOffset; + res = drm_scanEndBoundary(pStart, binContentLen, ((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary); + + if (-1 == res) { + freeSession(s); + return DRM_FAILURE; + } + + if (-2 == res) { /* may be the boundary is split */ + int32_t boundaryLen, leftLen, readBytes; + char* pTmp = memrchr(pStart, '\r', binContentLen); + + if (NULL == pTmp) { + freeSession(s); + return DRM_FAILURE; /* conflict */ + } + + boundaryLen = strlen((char *)((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary) + 2; /* 2 means: '\r''\n' */ + s->readBuf = (uint8_t *)malloc(boundaryLen); + if (NULL == s->readBuf) { + freeSession(s); + return DRM_FAILURE; + } + s->readBufOff = binContentLen - ((uint8_t *)pTmp - pStart); + s->readBufLen = boundaryLen - s->readBufOff; + memcpy(s->readBuf, pTmp, s->readBufOff); + readBytes = data.readInputData(data.inputHandle, s->readBuf + s->readBufOff, s->readBufLen); + if (-1 == readBytes || readBytes < s->readBufLen) { + freeSession(s); + return DRM_MEDIA_DATA_INVALID; + } + + if (0 == drm_scanEndBoundary(s->readBuf, boundaryLen, ((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary)) { + binContentLen = (uint8_t *)pTmp - pStart; /* yes, it is the end boundary */ + bFoundBoundary = TRUE; + } + } else { + if (res >= 0 && res < binContentLen) { + binContentLen = res; + bFoundBoundary = TRUE; + } + } + + if (bFoundBoundary) + s->contentLength = binContentLen; + } + } + } + break; + case TYPE_DRM_CONTENT: + { + T_DRM_DCF_Info dcfInfo; + uint8_t* pEncData = NULL; + + memset(&dcfInfo, 0, sizeof(T_DRM_DCF_Info)); + if (FALSE == drm_dcfParser(s->rawContent, s->rawContentLen, &dcfInfo, &pEncData)) { + freeSession(s); + return DRM_MEDIA_DATA_INVALID; + } + + s->infoStruct = (T_DRM_Dcf_Node *)malloc(sizeof(T_DRM_Dcf_Node)); + if (NULL == s->infoStruct) + return DRM_FAILURE; + memset(s->infoStruct, 0, sizeof(T_DRM_Dcf_Node)); + + s->deliveryMethod = SEPARATE_DELIVERY; + s->contentLength = dcfInfo.DecryptedDataLen; + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength = dcfInfo.EncryptedDataLen; + s->contentOffset = pEncData - s->rawContent; + strcpy((char *)s->contentType, (char *)dcfInfo.ContentType); + strcpy((char *)s->contentID, (char *)dcfInfo.ContentURI); + strcpy((char *)((T_DRM_Dcf_Node *)(s->infoStruct))->rightsIssuer, (char *)dcfInfo.Rights_Issuer); + } + break; + case TYPE_DRM_RIGHTS_XML: /* rights object should using "SVC_drm_installRights", it can not open a session */ + case TYPE_DRM_RIGHTS_WBXML: /* rights object should using "SVC_drm_installRights", it can not open a session */ + case TYPE_DRM_UNKNOWN: + default: + freeSession(s); + return DRM_MEDIA_DATA_INVALID; + } + + if ((SEPARATE_DELIVERY_FL == s->deliveryMethod || SEPARATE_DELIVERY == s->deliveryMethod) && + s->contentOffset + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength <= DRM_MAX_MALLOC_LEN) { + uint8_t keyValue[DRM_KEY_LEN]; + uint8_t lastDcfBuf[DRM_TWO_AES_BLOCK_LEN]; + int32_t seekPos, moreBytes; + + if (TRUE == drm_getKey(s->contentID, keyValue)) { + seekPos = s->contentOffset + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength - DRM_TWO_AES_BLOCK_LEN; + memcpy(lastDcfBuf, s->rawContent + seekPos, DRM_TWO_AES_BLOCK_LEN); + + if (TRUE == drm_updateDcfDataLen(lastDcfBuf, keyValue, &moreBytes)) { + s->contentLength = ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength; + s->contentLength -= moreBytes; + } + } + } + + session = addSession(s); + if (-1 == session) + return DRM_FAILURE; + + return session; +} + +/* see svc_drm.h */ +int32_t SVC_drm_getDeliveryMethod(int32_t session) +{ + T_DRM_Session_Node* s; + + if (session < 0) + return DRM_FAILURE; + + s = getSession(session); + if (NULL == s) + return DRM_SESSION_NOT_OPENED; + + return s->deliveryMethod; +} + +/* see svc_drm.h */ +int32_t SVC_drm_getContentType(int32_t session, uint8_t* mediaType) +{ + T_DRM_Session_Node* s; + + if (session < 0 || NULL == mediaType) + return DRM_FAILURE; + + s = getSession(session); + if (NULL == s) + return DRM_SESSION_NOT_OPENED; + + strcpy((char *)mediaType, (char *)s->contentType); + + return DRM_SUCCESS; +} + +/* see svc_drm.h */ +int32_t SVC_drm_checkRights(int32_t session, int32_t permission) +{ + T_DRM_Session_Node* s; + int32_t id; + T_DRM_Rights *pRo, *pCurRo; + int32_t roAmount; + int32_t i; + int32_t res = DRM_FAILURE; + + if (session < 0) + return DRM_FAILURE; + + s = getSession(session); + if (NULL == s) + return DRM_SESSION_NOT_OPENED; + + /* if it is Forward-Lock cases, check it and return directly */ + if (FORWARD_LOCK == s->deliveryMethod) { + if (DRM_PERMISSION_PLAY == permission || + DRM_PERMISSION_DISPLAY == permission || + DRM_PERMISSION_EXECUTE == permission || + DRM_PERMISSION_PRINT == permission) + return DRM_SUCCESS; + + return DRM_FAILURE; + } + + /* if try to forward, only DCF can be forwarded */ + if (DRM_PERMISSION_FORWARD == permission) { + if (SEPARATE_DELIVERY == s->deliveryMethod) + return DRM_SUCCESS; + + return DRM_FAILURE; + } + + /* The following will check CD or SD other permissions */ + if (FALSE == drm_readFromUidTxt(s->contentID, &id, GET_ID)) + return DRM_FAILURE; + + drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT); + if (roAmount <= 0) + return DRM_FAILURE; + + pRo = malloc(roAmount * sizeof(T_DRM_Rights)); + if (NULL == pRo) + return DRM_FAILURE; + + drm_writeOrReadInfo(id, pRo, &roAmount, GET_ALL_RO); + + pCurRo = pRo; + for (i = 0; i < roAmount; i++) { + switch (permission) { + case DRM_PERMISSION_PLAY: + res = drm_startCheckRights(&(pCurRo->bIsPlayable), &(pCurRo->PlayConstraint)); + break; + case DRM_PERMISSION_DISPLAY: + res = drm_startCheckRights(&(pCurRo->bIsDisplayable), &(pCurRo->DisplayConstraint)); + break; + case DRM_PERMISSION_EXECUTE: + res = drm_startCheckRights(&(pCurRo->bIsExecuteable), &(pCurRo->ExecuteConstraint)); + break; + case DRM_PERMISSION_PRINT: + res = drm_startCheckRights(&(pCurRo->bIsPrintable), &(pCurRo->PrintConstraint)); + break; + default: + free(pRo); + return DRM_FAILURE; + } + + if (DRM_SUCCESS == res) { + free(pRo); + return DRM_SUCCESS; + } + pCurRo++; + } + + free(pRo); + return res; +} + +/* see svc_drm.h */ +int32_t SVC_drm_consumeRights(int32_t session, int32_t permission) +{ + T_DRM_Session_Node* s; + int32_t id; + + if (session < 0) + return DRM_FAILURE; + + s = getSession(session); + if (NULL == s) + return DRM_SESSION_NOT_OPENED; + + if (DRM_PERMISSION_FORWARD == permission) { + if (SEPARATE_DELIVERY == s->deliveryMethod) + return DRM_SUCCESS; + + return DRM_FAILURE; + } + + if (FORWARD_LOCK == s->deliveryMethod) /* Forwardlock type have utter rights */ + return DRM_SUCCESS; + + if (FALSE == drm_readFromUidTxt(s->contentID, &id, GET_ID)) + return DRM_FAILURE; + + return drm_checkRoAndUpdate(id, permission); +} + +/* see svc_drm.h */ +int32_t SVC_drm_getContentLength(int32_t session) +{ + T_DRM_Session_Node* s; + + if (session < 0) + return DRM_FAILURE; + + s = getSession(session); + if (NULL == s) + return DRM_SESSION_NOT_OPENED; + + if (DRM_UNKNOWN_DATA_LEN == s->contentLength && s->contentOffset + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength <= DRM_MAX_MALLOC_LEN && + (SEPARATE_DELIVERY == s->deliveryMethod || SEPARATE_DELIVERY_FL == s->deliveryMethod)) { + uint8_t keyValue[DRM_KEY_LEN]; + uint8_t lastDcfBuf[DRM_TWO_AES_BLOCK_LEN]; + int32_t seekPos, moreBytes; + + if (TRUE == drm_getKey(s->contentID, keyValue)) { + seekPos = s->contentOffset + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength - DRM_TWO_AES_BLOCK_LEN; + memcpy(lastDcfBuf, s->rawContent + seekPos, DRM_TWO_AES_BLOCK_LEN); + + if (TRUE == drm_updateDcfDataLen(lastDcfBuf, keyValue, &moreBytes)) { + s->contentLength = ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength; + s->contentLength -= moreBytes; + } + } + } + + return s->contentLength; +} + +static int32_t drm_readAesData(uint8_t* buf, T_DRM_Session_Node* s, int32_t aesStart, int32_t bufLen) +{ + if (NULL == buf || NULL == s || aesStart < 0 || bufLen < 0) + return -1; + + if (aesStart - s->contentOffset + bufLen > ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength) + return -2; + + if (aesStart < DRM_MAX_MALLOC_LEN) { + if (aesStart + bufLen <= DRM_MAX_MALLOC_LEN) { /* read from buffer */ + memcpy(buf, s->rawContent + aesStart, bufLen); + return bufLen; + } else { /* first read from buffer and then from InputStream */ + int32_t point = DRM_MAX_MALLOC_LEN - aesStart; + int32_t res; + + if (((T_DRM_Dcf_Node *)(s->infoStruct))->bAesBackupBuf) { + memcpy(buf, ((T_DRM_Dcf_Node *)(s->infoStruct))->aesBackupBuf, DRM_ONE_AES_BLOCK_LEN); + res = s->readInputDataFunc(s->inputHandle, buf + DRM_ONE_AES_BLOCK_LEN, DRM_ONE_AES_BLOCK_LEN); + if (0 == res || -1 == res) + return -1; + + res += DRM_ONE_AES_BLOCK_LEN; + } else { + memcpy(buf, s->rawContent + aesStart, point); + res = s->readInputDataFunc(s->inputHandle, buf + point, bufLen - point); + if (0 == res || -1 == res) + return -1; + + res += point; + } + + memcpy(((T_DRM_Dcf_Node *)(s->infoStruct))->aesBackupBuf, buf + DRM_ONE_AES_BLOCK_LEN, DRM_ONE_AES_BLOCK_LEN); + ((T_DRM_Dcf_Node *)(s->infoStruct))->bAesBackupBuf = TRUE; + + return res; + } + } else { /* read from InputStream */ + int32_t res; + + memcpy(buf, ((T_DRM_Dcf_Node *)(s->infoStruct))->aesBackupBuf, DRM_ONE_AES_BLOCK_LEN); + res = s->readInputDataFunc(s->inputHandle, buf + DRM_ONE_AES_BLOCK_LEN, DRM_ONE_AES_BLOCK_LEN); + + if (0 == res || -1 == res) + return -1; + + memcpy(((T_DRM_Dcf_Node *)(s->infoStruct))->aesBackupBuf, buf + DRM_ONE_AES_BLOCK_LEN, DRM_ONE_AES_BLOCK_LEN); + + return DRM_ONE_AES_BLOCK_LEN + res; + } +} + +static int32_t drm_readContentFromBuf(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen) +{ + int32_t readBytes; + + if (offset > s->contentLength) + return DRM_FAILURE; + + if (offset == s->contentLength) + return DRM_MEDIA_EOF; + + if (offset + mediaBufLen > s->contentLength) + readBytes = s->contentLength - offset; + else + readBytes = mediaBufLen; + + if (DRM_MESSAGE_CODING_BASE64 == s->transferEncoding) + memcpy(mediaBuf, s->rawContent + offset, readBytes); + else + memcpy(mediaBuf, s->rawContent + s->contentOffset + offset, readBytes); + + return readBytes; +} + +static int32_t drm_readB64ContentFromInputStream(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen) +{ + uint8_t encBuf[DRM_B64_ENC_BLOCK], decBuf[DRM_B64_DEC_BLOCK]; + int32_t encLen, decLen; + int32_t i, j, piece, leftLen, firstBytes; + int32_t readBytes = 0; + + if (offset < ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen) { + readBytes = ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen - offset; + memcpy(mediaBuf, s->rawContent + offset, readBytes); + } else { + if (s->bEndData) + return DRM_MEDIA_EOF; + + firstBytes = offset % DRM_B64_DEC_BLOCK; + if (firstBytes > 0) { + if (DRM_B64_DEC_BLOCK - firstBytes >= mediaBufLen) { + readBytes = mediaBufLen; + memcpy(mediaBuf, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeData + firstBytes, readBytes); + return readBytes; + } + + readBytes = DRM_B64_DEC_BLOCK - firstBytes; + memcpy(mediaBuf, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeData + firstBytes, readBytes); + } + } + + leftLen = mediaBufLen - readBytes; + encLen = (leftLen - 1) / DRM_B64_DEC_BLOCK * DRM_B64_ENC_BLOCK + DRM_B64_ENC_BLOCK; + piece = encLen / DRM_B64_ENC_BLOCK; + + for (i = 0; i < piece; i++) { + j = 0; + while (j < DRM_B64_ENC_BLOCK) { + if (NULL != s->readBuf && s->readBufLen > 0) { /* read from backup buffer */ + *(encBuf + j) = s->readBuf[s->readBufOff]; + s->readBufOff++; + s->readBufLen--; + } else { /* read from InputStream */ + if (0 == s->readInputDataFunc(s->inputHandle, encBuf + j, 1)) + return DRM_MEDIA_DATA_INVALID; + } + + if ('\r' == *(encBuf + j) || '\n' == *(encBuf + j)) + continue; /* skip CRLF */ + + if ('-' == *(encBuf + j)) { + int32_t k, len; + + /* invalid base64 data, it comes to end boundary */ + if (0 != j) + return DRM_MEDIA_DATA_INVALID; + + /* check whether it is really the boundary */ + len = strlen((char *)((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary); + if (NULL == s->readBuf) { + s->readBuf = (uint8_t *)malloc(len); + if (NULL == s->readBuf) + return DRM_FAILURE; + } + + s->readBuf[0] = '-'; + for (k = 0; k < len - 1; k++) { + if (NULL != s->readBuf && s->readBufLen > 0) { /* read from backup buffer */ + *(s->readBuf + k + 1) = s->readBuf[s->readBufOff]; + s->readBufOff++; + s->readBufLen--; + } else { /* read from InputStream */ + if (-1 == s->readInputDataFunc(s->inputHandle, s->readBuf + k + 1, 1)) + return DRM_MEDIA_DATA_INVALID; + } + } + if (0 == memcmp(s->readBuf, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary, len)) + s->bEndData = TRUE; + else + return DRM_MEDIA_DATA_INVALID; + + break; + } + j++; + } + + if (TRUE == s->bEndData) { /* it means come to the end of base64 data */ + if (0 == readBytes) + return DRM_MEDIA_EOF; + + break; + } + + encLen = DRM_B64_ENC_BLOCK; + decLen = DRM_B64_DEC_BLOCK; + if (-1 == (decLen = drm_decodeBase64(decBuf, decLen, encBuf, &encLen))) + return DRM_MEDIA_DATA_INVALID; + + if (leftLen >= decLen) { + memcpy(mediaBuf + readBytes, decBuf, decLen); + readBytes += decLen; + leftLen -= decLen; + } else { + if (leftLen > 0) { + memcpy(mediaBuf + readBytes, decBuf, leftLen); + readBytes += leftLen; + } + break; + } + } + memcpy(((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeData, decBuf, DRM_B64_DEC_BLOCK); + + return readBytes; +} + +static int32_t drm_readBase64Content(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen) +{ + int32_t readBytes; + + /* when the content length has been well-known */ + if (s->contentLength >= 0) + readBytes = drm_readContentFromBuf(s, offset, mediaBuf, mediaBufLen); + else /* else when the content length has not been well-known yet */ + if (offset < ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen) + if (offset + mediaBufLen <= ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen) { + readBytes = mediaBufLen; + memcpy(mediaBuf, s->rawContent + offset, readBytes); + } else + readBytes = drm_readB64ContentFromInputStream(s, offset, mediaBuf, mediaBufLen); + else + readBytes = drm_readB64ContentFromInputStream(s, offset, mediaBuf, mediaBufLen); + + return readBytes; +} + +static int32_t drm_readBinaryContentFromInputStream(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen) +{ + int32_t res = 0, readBytes = 0; + int32_t leftLen; + + if (s->contentOffset + offset < DRM_MAX_MALLOC_LEN) { + readBytes = DRM_MAX_MALLOC_LEN - s->contentOffset - offset; + memcpy(mediaBuf, s->rawContent + s->contentOffset + offset, readBytes); + } else + if (s->bEndData) + return DRM_MEDIA_EOF; + + leftLen = mediaBufLen - readBytes; + + if (NULL != s->readBuf && s->readBufLen > 0) { /* read from backup buffer */ + if (leftLen <= s->readBufLen) { + memcpy(mediaBuf, s->readBuf + s->readBufOff, leftLen); + s->readBufOff += leftLen; + s->readBufLen -= leftLen; + readBytes += leftLen; + leftLen = 0; + } else { + memcpy(mediaBuf, s->readBuf + s->readBufOff, s->readBufLen); + s->readBufOff += s->readBufLen; + leftLen -= s->readBufLen; + readBytes += s->readBufLen; + s->readBufLen = 0; + } + } + + if (leftLen > 0) { + res = s->readInputDataFunc(s->inputHandle, mediaBuf + readBytes, mediaBufLen - readBytes); + if (-1 == res) + return DRM_MEDIA_DATA_INVALID; + } + + readBytes += res; + res = drm_scanEndBoundary(mediaBuf, readBytes, ((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary); + if (-1 == res) + return DRM_MEDIA_DATA_INVALID; + if (-2 == res) { /* may be the boundary is split */ + int32_t boundaryLen, len, off, k; + char* pTmp = memrchr(mediaBuf, '\r', readBytes); + + if (NULL == pTmp) + return DRM_FAILURE; /* conflict */ + + boundaryLen = strlen((char *)((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary) + 2; /* 2 means: '\r''\n' */ + if (NULL == s->readBuf) { + s->readBuf = (uint8_t *)malloc(boundaryLen); + if (NULL == s->readBuf) + return DRM_FAILURE; + } + + off = readBytes - ((uint8_t *)pTmp - mediaBuf); + len = boundaryLen - off; + memcpy(s->readBuf, pTmp, off); + for (k = 0; k < boundaryLen - off; k++) { + if (NULL != s->readBuf && s->readBufLen > 0) { /* read from backup buffer */ + *(s->readBuf + k + off) = s->readBuf[s->readBufOff]; + s->readBufOff++; + s->readBufLen--; + } else { /* read from InputStream */ + if (-1 == s->readInputDataFunc(s->inputHandle, s->readBuf + k + off, 1)) + return DRM_MEDIA_DATA_INVALID; + } + } + s->readBufOff = off; + s->readBufLen = len; + + if (0 == drm_scanEndBoundary(s->readBuf, boundaryLen, ((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary)) { + readBytes = (uint8_t *)pTmp - mediaBuf; /* yes, it is the end boundary */ + s->bEndData = TRUE; + } + } else { + if (res >= 0 && res < readBytes) { + readBytes = res; + s->bEndData = TRUE; + } + } + + if (s->bEndData) { + if (0 == readBytes) + return DRM_MEDIA_EOF; + } + + return readBytes; +} + +static int32_t drm_readBinaryContent(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen) +{ + int32_t readBytes; + + if (s->contentLength >= 0) + readBytes = drm_readContentFromBuf(s, offset, mediaBuf, mediaBufLen); + else /* else when the content length has not been well-known yet */ + if (s->contentOffset + offset < DRM_MAX_MALLOC_LEN) + if (s->contentOffset + offset + mediaBufLen <= DRM_MAX_MALLOC_LEN) { + readBytes = mediaBufLen; + memcpy(mediaBuf, s->rawContent + s->contentOffset + offset, readBytes); + } else + readBytes = drm_readBinaryContentFromInputStream(s, offset, mediaBuf, mediaBufLen); + else + readBytes = drm_readBinaryContentFromInputStream(s, offset, mediaBuf, mediaBufLen); + + return readBytes; +} + +static int32_t drm_readAesContent(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen) +{ + uint8_t keyValue[DRM_KEY_LEN]; + uint8_t buf[DRM_TWO_AES_BLOCK_LEN]; + int32_t readBytes = 0; + int32_t bufLen, piece, i, copyBytes, leftBytes; + int32_t aesStart, mediaStart, mediaBufOff; + aes_decrypt_ctx ctx[1]; + + if (FALSE == drm_getKey(s->contentID, keyValue)) + return DRM_NO_RIGHTS; + + /* when the content length has been well-known */ + if (s->contentLength > 0) { + if (offset > s->contentLength) + return DRM_FAILURE; + + if (offset == s->contentLength) + return DRM_MEDIA_EOF; + + if (offset + mediaBufLen > s->contentLength) + readBytes = s->contentLength - offset; + else + readBytes = mediaBufLen; + + aesStart = s->contentOffset + (offset / DRM_ONE_AES_BLOCK_LEN * DRM_ONE_AES_BLOCK_LEN); + piece = (offset + readBytes - 1) / DRM_ONE_AES_BLOCK_LEN - offset / DRM_ONE_AES_BLOCK_LEN + 2; + mediaStart = offset % DRM_ONE_AES_BLOCK_LEN; + + aes_decrypt_key128(keyValue, ctx); + mediaBufOff = 0; + leftBytes = readBytes; + + for (i = 0; i < piece - 1; i++) { + memcpy(buf, s->rawContent + aesStart + i * DRM_ONE_AES_BLOCK_LEN, DRM_TWO_AES_BLOCK_LEN); + bufLen = DRM_TWO_AES_BLOCK_LEN; + + if (drm_aesDecBuffer(buf, &bufLen, ctx) < 0) + return DRM_MEDIA_DATA_INVALID; + + if (0 != i) + mediaStart = 0; + + if (bufLen - mediaStart <= leftBytes) + copyBytes = bufLen - mediaStart; + else + copyBytes = leftBytes; + + memcpy(mediaBuf + mediaBufOff, buf + mediaStart, copyBytes); + leftBytes -= copyBytes; + mediaBufOff += copyBytes; + } + } else { + int32_t res; + + if (s->bEndData) + return DRM_MEDIA_EOF; + + if (((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen > ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff) { + if (mediaBufLen < ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen - ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff) + copyBytes = mediaBufLen; + else + copyBytes = ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen - ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff; + + memcpy(mediaBuf, ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecData + ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff, copyBytes); + ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff += copyBytes; + readBytes += copyBytes; + } + + leftBytes = mediaBufLen - readBytes; + if (0 == leftBytes) + return readBytes; + if (leftBytes < 0) + return DRM_FAILURE; + + offset += readBytes; + aesStart = s->contentOffset + (offset / DRM_ONE_AES_BLOCK_LEN * DRM_ONE_AES_BLOCK_LEN); + piece = (offset + leftBytes - 1) / DRM_ONE_AES_BLOCK_LEN - offset / DRM_ONE_AES_BLOCK_LEN + 2; + mediaBufOff = readBytes; + + aes_decrypt_key128(keyValue, ctx); + + for (i = 0; i < piece - 1; i++) { + if (-1 == (res = drm_readAesData(buf, s, aesStart, DRM_TWO_AES_BLOCK_LEN))) + return DRM_MEDIA_DATA_INVALID; + + if (-2 == res) + break; + + bufLen = DRM_TWO_AES_BLOCK_LEN; + aesStart += DRM_ONE_AES_BLOCK_LEN; + + if (drm_aesDecBuffer(buf, &bufLen, ctx) < 0) + return DRM_MEDIA_DATA_INVALID; + + drm_discardPaddingByte(buf, &bufLen); + + if (bufLen <= leftBytes) + copyBytes = bufLen; + else + copyBytes = leftBytes; + + memcpy(mediaBuf + mediaBufOff, buf, copyBytes); + leftBytes -= copyBytes; + mediaBufOff += copyBytes; + readBytes += copyBytes; + } + + memcpy(((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecData, buf, DRM_ONE_AES_BLOCK_LEN); + ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen = bufLen; + ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff = copyBytes; + + if (aesStart - s->contentOffset > ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength - DRM_TWO_AES_BLOCK_LEN && ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff == ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen) { + s->bEndData = TRUE; + if (0 == readBytes) + return DRM_MEDIA_EOF; + } + } + + return readBytes; +} + +/* see svc_drm.h */ +int32_t SVC_drm_getContent(int32_t session, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen) +{ + T_DRM_Session_Node* s; + int32_t readBytes; + + if (session < 0 || offset < 0 || NULL == mediaBuf || mediaBufLen <= 0) + return DRM_FAILURE; + + s = getSession(session); + if (NULL == s) + return DRM_SESSION_NOT_OPENED; + + if (0 >= s->getInputDataLengthFunc(s->inputHandle)) + return DRM_MEDIA_DATA_INVALID; + + switch(s->deliveryMethod) { + case FORWARD_LOCK: + case COMBINED_DELIVERY: + if (DRM_MESSAGE_CODING_BASE64 == s->transferEncoding) + readBytes = drm_readBase64Content(s, offset, mediaBuf, mediaBufLen); + else /* binary */ + readBytes = drm_readBinaryContent(s, offset, mediaBuf, mediaBufLen); + break; + case SEPARATE_DELIVERY: + case SEPARATE_DELIVERY_FL: + readBytes = drm_readAesContent(s, offset, mediaBuf, mediaBufLen); + break; + default: + return DRM_FAILURE; + } + + return readBytes; +} + +/* see svc_drm.h */ +int32_t SVC_drm_getRightsIssuer(int32_t session, uint8_t* rightsIssuer) +{ + T_DRM_Session_Node* s; + + if (session < 0 || NULL == rightsIssuer) + return DRM_FAILURE; + + s = getSession(session); + if (NULL == s) + return DRM_SESSION_NOT_OPENED; + + if (SEPARATE_DELIVERY == s->deliveryMethod || SEPARATE_DELIVERY_FL == s->deliveryMethod) { + strcpy((char *)rightsIssuer, (char *)((T_DRM_Dcf_Node *)(s->infoStruct))->rightsIssuer); + return DRM_SUCCESS; + } + + return DRM_NOT_SD_METHOD; +} + +/* see svc_drm.h */ +int32_t SVC_drm_getRightsInfo(int32_t session, T_DRM_Rights_Info* rights) +{ + T_DRM_Session_Node* s; + T_DRM_Rights rightsInfo; + int32_t roAmount, id; + + if (session < 0 || NULL == rights) + return DRM_FAILURE; + + s = getSession(session); + if (NULL == s) + return DRM_SESSION_NOT_OPENED; + + if (FORWARD_LOCK == s->deliveryMethod) { + strcpy((char *)rights->roId, "ForwardLock"); + rights->displayRights.indicator = DRM_NO_CONSTRAINT; + rights->playRights.indicator = DRM_NO_CONSTRAINT; + rights->executeRights.indicator = DRM_NO_CONSTRAINT; + rights->printRights.indicator = DRM_NO_CONSTRAINT; + return DRM_SUCCESS; + } + + if (FALSE == drm_readFromUidTxt(s->contentID, &id, GET_ID)) + return DRM_NO_RIGHTS; + + if (FALSE == drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT)) + return DRM_FAILURE; + + if (roAmount < 0) + return DRM_NO_RIGHTS; + + /* some rights has been installed, but now there is no valid rights */ + if (0 == roAmount) { + strcpy((char *)rights->roId, s->contentID); + rights->displayRights.indicator = DRM_NO_PERMISSION; + rights->playRights.indicator = DRM_NO_PERMISSION; + rights->executeRights.indicator = DRM_NO_PERMISSION; + rights->printRights.indicator = DRM_NO_PERMISSION; + return DRM_SUCCESS; + } + + roAmount = 1; + memset(&rightsInfo, 0, sizeof(T_DRM_Rights)); + if (FALSE == drm_writeOrReadInfo(id, &rightsInfo, &roAmount, GET_A_RO)) + return DRM_FAILURE; + + memset(rights, 0, sizeof(T_DRM_Rights_Info)); + drm_getLicenseInfo(&rightsInfo, rights); + return DRM_SUCCESS; +} + +/* see svc_drm.h */ +int32_t SVC_drm_closeSession(int32_t session) +{ + if (session < 0) + return DRM_FAILURE; + + if (NULL == getSession(session)) + return DRM_SESSION_NOT_OPENED; + + removeSession(session); + + return DRM_SUCCESS; +} + +/* see svc_drm.h */ +int32_t SVC_drm_updateRights(uint8_t* contentID, int32_t permission) +{ + int32_t id; + + if (NULL == contentID) + return DRM_FAILURE; + + if (FALSE == drm_readFromUidTxt(contentID, &id, GET_ID)) + return DRM_FAILURE; + + return drm_checkRoAndUpdate(id, permission); +} + +/* see svc_drm.h */ +int32_t SVC_drm_viewAllRights(T_DRM_Rights_Info_Node **ppRightsInfo) +{ + T_DRM_Rights_Info_Node rightsNode; + int32_t maxId, id, roAmount, j; + T_DRM_Rights rights; + + memset(&rights, 0, sizeof(T_DRM_Rights)); + + if (NULL == ppRightsInfo) + return DRM_FAILURE; + + *ppRightsInfo = NULL; + + maxId = drm_getMaxIdFromUidTxt(); + if (-1 == maxId) + return DRM_FAILURE; + + for (id = 1; id <= maxId; id++) { + drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT); + if (roAmount <= 0) /* this means there is not any rights */ + continue; + + for (j = 1; j <= roAmount; j++) { + if (FALSE == drm_writeOrReadInfo(id, &rights, &j, GET_A_RO)) + continue; + + memset(&rightsNode, 0, sizeof(T_DRM_Rights_Info_Node)); + + drm_getLicenseInfo(&rights, &(rightsNode.roInfo)); + + if (FALSE == drm_addRightsNodeToList(ppRightsInfo, &rightsNode)) + continue; + } + } + return DRM_SUCCESS; +} + +/* see svc_drm.h */ +int32_t SVC_drm_freeRightsInfoList(T_DRM_Rights_Info_Node *pRightsHeader) +{ + T_DRM_Rights_Info_Node *pNode, *pTmp; + + if (NULL == pRightsHeader) + return DRM_FAILURE; + + pNode = pRightsHeader; + + while (NULL != pNode) { + pTmp = pNode; + pNode = pNode->next; + free(pTmp); + } + return DRM_SUCCESS; +} + +/* see svc_drm.h */ +int32_t SVC_drm_deleteRights(uint8_t* roId) +{ + int32_t maxId, id, roAmount, j; + T_DRM_Rights rights; + + memset(&rights, 0, sizeof(T_DRM_Rights)); + + if (NULL == roId) + return DRM_FAILURE; + + maxId = drm_getMaxIdFromUidTxt(); + if (-1 == maxId) + return DRM_NO_RIGHTS; + + for (id = 1; id <= maxId; id++) { + drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT); + if (roAmount <= 0) /* this means there is not any rights */ + continue; + + for (j = 1; j <= roAmount; j++) { + if (FALSE == drm_writeOrReadInfo(id, &rights, &j, GET_A_RO)) + continue; + + /* here find the RO which will be deleted */ + if (0 == strcmp((char *)rights.uid, (char *)roId)) { + T_DRM_Rights *pAllRights; + + pAllRights = (T_DRM_Rights *)malloc(roAmount * sizeof(T_DRM_Rights)); + if (NULL == pAllRights) + return DRM_FAILURE; + + drm_writeOrReadInfo(id, pAllRights, &roAmount, GET_ALL_RO); + roAmount--; + if (0 == roAmount) { /* this means it is the last one rights */ + drm_removeIdInfoFile(id); /* delete the id.info file first */ + drm_updateUidTxtWhenDelete(id); /* update uid.txt file */ + free(pAllRights); + return DRM_SUCCESS; + } else /* using the last one rights instead of the deleted one */ + memcpy(pAllRights + (j - 1), pAllRights + roAmount, sizeof(T_DRM_Rights)); + + /* delete the id.info file first */ +// drm_removeIdInfoFile(id); + + if (FALSE == drm_writeOrReadInfo(id, pAllRights, &roAmount, SAVE_ALL_RO)) { + free(pAllRights); + return DRM_FAILURE; + } + + free(pAllRights); + return DRM_SUCCESS; + } + } + } + + return DRM_FAILURE; +} diff --git a/media/libdrm/mobile1/src/objmng/drm_decoder.c b/media/libdrm/mobile1/src/objmng/drm_decoder.c new file mode 100644 index 0000000..82c7efb --- /dev/null +++ b/media/libdrm/mobile1/src/objmng/drm_decoder.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <objmng/drm_decoder.h> + +/* global variables */ +static const uint8_t * base64_alphabet = (const uint8_t *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +#define SKIP_CRLF(p) while('\r' == *(p) || '\n' == *(p)) \ + p++ + +static int8_t get_alphabet_index(int8_t ch) +{ + uint8_t * tmp; + + if ('=' == ch) + return 64; + + tmp = (uint8_t *)strchr((const char *)base64_alphabet, ch); + if (NULL == tmp) + return -1; + + return (int8_t)(tmp - base64_alphabet); +} + +/* See drm_decoder.h */ +int32_t drm_decodeBase64(uint8_t * dest, int32_t destLen, uint8_t * src, int32_t * srcLen) +{ + int32_t maxDestSize, i, maxGroup; + uint8_t *pDest, *pSrc; + int8_t tpChar; + + if (NULL == src || NULL == srcLen || *srcLen <= 0 || destLen < 0) + return -1; + + maxDestSize = (*srcLen) * 3/4; + if (NULL == dest || 0 == destLen) + return maxDestSize; + + if (destLen < maxDestSize) + maxDestSize = destLen; + maxGroup = maxDestSize/3; + + pDest = dest; /* start to decode src to dest */ + pSrc = src; + for (i = 0; i < maxGroup && *srcLen - (pSrc - src) >= 4; i++) { + SKIP_CRLF(pSrc); + if (pSrc - src >= *srcLen) + break; + tpChar = get_alphabet_index(*pSrc); /* to first byte */ + if (-1 == tpChar || 64 == tpChar) + return -1; + pDest[0] = tpChar << 2; + pSrc++; + SKIP_CRLF(pSrc); + tpChar = get_alphabet_index(*pSrc); + if (-1 == tpChar || 64 == tpChar) + return -1; + pDest[0] |= (tpChar >> 4); + pDest[1] = tpChar << 4; /* to second byte */ + pSrc++; + SKIP_CRLF(pSrc); + tpChar = get_alphabet_index(*pSrc); + if (-1 == tpChar) + return -1; + if (64 == tpChar) /* end */ + return pDest - dest + 1; + pDest[1] |= (tpChar >> 2); + pDest[2] = tpChar << 6; /* to third byte */ + pSrc++; + SKIP_CRLF(pSrc); + tpChar = get_alphabet_index(*pSrc); + if (-1 == tpChar) + return -1; + if (64 == tpChar) /* end */ + return pDest - dest + 2; + pDest[2] |= tpChar; + pDest += 3; + pSrc++; + } + *srcLen = pSrc - src; + return pDest - dest; +} diff --git a/media/libdrm/mobile1/src/objmng/drm_file.c b/media/libdrm/mobile1/src/objmng/drm_file.c new file mode 100644 index 0000000..e6c303e --- /dev/null +++ b/media/libdrm/mobile1/src/objmng/drm_file.c @@ -0,0 +1,694 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <objmng/drm_file.h> + +#include <unistd.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <stdio.h> +#include <fcntl.h> +#include <dirent.h> +#include <errno.h> +#include <string.h> + +/** + * Fails on zaurus? + #define DEVICE_FILESYSTEM +*/ +#define DEFAULT_TOTAL_SPACE (4L * 1024L * 1024L) /* 4 Meg. */ + +#ifndef DEVICE_FILESYSTEM +/* Store the total space on FS VM can use. */ +static int32_t totalSpace; +/* how many remain space can VM use. */ +static int32_t availableSize; +#endif + +extern char* getStorageRoot(void); + +static char tmpPathBuf1[MAX_FILENAME_LEN]; +static char tmpPathBuf2[MAX_FILENAME_LEN]; + +static int32_t +convertFilename(const uint16_t *strData, int32_t strLength, char *buffer); + +static int calcDirSize(char *path, int len, uint8_t includeSubdirs); + +#ifndef DEVICE_FILESYSTEM +static void initFsVariables(void); +#endif + +/** + * Convert a Java string into a nul terminated ascii string to pass to posix + * @param strData first character of name + * @param strLength number of characters in name + * @param buffer Buffer to store terminated string in (at least MAXPATHLEN) + * @return Length of filename in characters (excl. nul), or -1 on failure. + */ +static int32_t +convertFilename(const uint16_t *strData, int32_t strLength, char *buffer) +{ + int idx; + + if (strLength >= (MAXPATHLEN-1)) + { + Trace("convertFilename '%.*S' too long", strLength, strData); + return -1; + } + + for (idx = 0; idx < strLength; ++idx) + *buffer++ = (char)*strData++; + + *buffer = 0; + return strLength; +} + + +/** + * Perform a stat() call on the given filename. + * Helper for getFileLength and exists + * @param name unicode name + * @param nameLen number of unicode characters in name + * @param sbuf stat buffer + * @return TRUE on success, FALSE on failure + */ +static int32_t +getFileStat(const uint16_t *name, int32_t nameLen, struct stat *sbuf) +{ + Trace("getFileStat: %.*S", nameLen, name); + + if (convertFilename(name, nameLen, tmpPathBuf1) <= 0) + { + Trace("getFileStat: bad filename"); + } + else if (stat(tmpPathBuf1, sbuf) != 0) + { + Trace("getFileStat %s: stat() errno=%d", tmpPathBuf1, errno); + } + else /* Successful */ + { + return TRUE; + } + + return FALSE; +} + +#ifndef DEVICE_FILESYSTEM +/** + * initial the variables like totalSpace, availableSize... + */ +static void initFsVariables(void) +{ + totalSpace = DEFAULT_TOTAL_SPACE; + + availableSize = totalSpace; +} +#endif /* DEVICE_FILESYSTEM */ + +/** + * calculate the size of everything inside path pointed directory + * this function will use path pointed buffer to store some extra info + * so param len is needed. + * @param path the directory path need to calculate + * @param len length of the path buffer, not the path string length + * @param includeSubdirs also calculate all the subdirs in path holds? + * @return the calculated size, DRM_FILE_FAILURE on failure. + */ +static int calcDirSize(char *path, int len, uint8_t includeSubdirs) +{ + struct dirent *ent; + struct stat stat_buf; + + DIR *dir = NULL; + int size = 0; + int exists = -1; + int dirPathLen = strlen(path); + + /* Ensure space for wildcard */ + if((dirPathLen + 2) >= MAXPATHLEN || (dirPathLen + 2) >= len) + { + return DRM_FILE_FAILURE; + } + + if(path[dirPathLen - 1] != '/') + { + path[dirPathLen++] = '/'; + path[dirPathLen] = '\0'; + } + + dir = opendir(path); + if (dir == NULL) + { + return DRM_FILE_FAILURE; + } + + while ((ent = readdir(dir)) != NULL ) + { + if (strcmp(ent->d_name, ".") == 0 || + strcmp(ent->d_name, "..") == 0) + { + continue; + } + + path[dirPathLen] = '\0'; + if ((int)(strlen(ent->d_name) + dirPathLen + 1) < len) + { + strcat(path, ent->d_name); + } + else + { + continue; + } + + exists = stat(path, &stat_buf); + if (exists != -1) + { + /* exclude the storage occupied by directory itself */ + if (stat_buf.st_mode & S_IFDIR) + { + if(includeSubdirs) + { + /* calculate the size recursively */ + int ret; + ret = calcDirSize(path, len, includeSubdirs); + /* ignore failure in subdirs */ + if( DRM_FILE_FAILURE != ret ) + { + size += ret; + } + } + } + else + { + size += stat_buf.st_size; + } + } + } + + closedir(dir); + return size; +} + +/* see drm_file.h */ +int32_t DRM_file_startup(void) +{ + Trace("DRM_file_startup"); + +#ifndef DEVICE_FILESYSTEM + availableSize = -1; + + initFsVariables(); +#endif + + return DRM_FILE_SUCCESS; /* Nothing to do */ +} + +/* see drm_file.h */ +int32_t +DRM_file_listOpen(const uint16_t *prefix, + int32_t prefixLen, + int32_t* session, + int32_t* iteration) +{ + Trace("DRM_file_listOpen: %.*S", prefixLen, prefix); + + if (convertFilename(prefix, prefixLen, tmpPathBuf1) <= 0) + { + Trace("DRM_file_listOpen: bad filename"); + } + else + { + DIR *dir; + + /* find the last /, and store the offset to the leaf prefix in + * *iteration + */ + + char *sep = strrchr(tmpPathBuf1, '/'); + /* Root "/" is a leaf */ + if (sep == NULL || ((sep != NULL) && (sep == tmpPathBuf1))) + { + *iteration = prefixLen; + +#ifdef TRACE_ON + sep = " <empty>"; /* trace will show sep+1 */ +#endif + } + else + { + *iteration = sep - tmpPathBuf1 + 1; + *sep = 0; + } + + dir = opendir(tmpPathBuf1); + + if (dir == NULL) + { + Trace("DRM_file_listOpen: opendir %s: errno=%d", tmpPathBuf1, errno); + } + else + { + Trace("DRM_file_listOpen: dir %s, filter %s", tmpPathBuf1, sep+1); + *session = (int32_t)dir; + return DRM_FILE_SUCCESS; + } + } + + return DRM_FILE_FAILURE; +} + +/* see drm_file.h */ +int32_t +DRM_file_listNextEntry(const uint16_t *prefix, int32_t prefixLen, + uint16_t* entry, int32_t entrySize, + int32_t *session, int32_t* iteration) +{ + struct dirent *ent; + + /* We stored the offset of the leaf part of the prefix (if any) + * in *iteration + */ + const uint16_t* strData = prefix + *iteration; + int32_t strLength = prefixLen - *iteration; + + /* entrySize is bytes for some reason. Convert to ucs chars */ + entrySize /= 2; + + /* Now we want to filter for files which start with the (possibly empty) + * sequence at strData. We have to return fully-qualified filenames, + * which means *iteration characters from prefix, plus the + * leaf name. + */ + + while ( (ent = readdir((DIR *)*session)) != NULL) + { + int len = strlen(ent->d_name); + + if ( (len + *iteration) > entrySize) + { + Trace("DRM_file_listNextEntry: %s too long", ent->d_name); + } + else if (strcmp(ent->d_name, ".") != 0 && + strcmp(ent->d_name, "..") != 0) + { + int idx; + struct stat sinfo; + + /* check against the filter */ + + for (idx = 0; idx < strLength; ++idx) + { + if (ent->d_name[idx] != strData[idx]) + goto next_name; + } + + Trace("DRM_file_listNextEntry: matched %s", ent->d_name); + + /* Now generate the fully-qualified name */ + + for (idx = 0; idx < *iteration; ++idx) + entry[idx] = prefix[idx]; + + for (idx = 0; idx < len; ++idx) + entry[*iteration + idx] = (unsigned char)ent->d_name[idx]; + + /*add "/" at the end of a DIR file entry*/ + if (getFileStat(entry, idx + *iteration, &sinfo)){ + if (S_ISDIR(sinfo.st_mode) && + (idx + 1 + *iteration) < entrySize) { + entry[*iteration + idx] = '/'; + ++idx; + } + } + else + { + Trace("DRM_file_listNextEntry: stat FAILURE on %.*S", + idx + *iteration, entry); + } + Trace("DRM_file_listNextEntry: got %.*S", idx + *iteration, entry); + + return idx + *iteration; + } + + next_name: + Trace("DRM_file_listNextEntry: rejected %s", ent->d_name); + } + + Trace("DRM_file_listNextEntry: end of list"); + return 0; +} + +/* see drm_file.h */ +int32_t +DRM_file_listClose(int32_t session, int32_t iteration) +{ + closedir( (DIR *)session); + return DRM_FILE_SUCCESS; +} + +/* see drm_file.h */ +int32_t +DRM_file_getFileLength(const uint16_t *name, int32_t nameLen) +{ + struct stat sbuf; + + if (getFileStat(name, nameLen, &sbuf)) + { + if (sbuf.st_size >= INT32_MAX) + { + Trace("DRM_file_getFileLength: file too big"); + } + else /* Successful */ + { + Trace("DRM_file_getFileLength: %.*S -> %d", + nameLen, name, (int32_t)sbuf.st_size); + return (int32_t)sbuf.st_size; + } + } + + return DRM_FILE_FAILURE; +} + +/* see drm_file.h */ +int32_t +DRM_file_delete(const uint16_t *name, int32_t nameLen) +{ + Trace("DRM_file_delete: %.*S", nameLen, name); + + if (convertFilename(name, nameLen, tmpPathBuf1) <= 0) + { + Trace("DRM_file_delete: bad filename"); + return DRM_FILE_FAILURE; + } + else + { + struct stat sinfo; + if (stat(tmpPathBuf1, &sinfo) != 0){ + Trace("DRM_file_delete: stat failed, errno=%d", errno); + return DRM_FILE_FAILURE; + } +#ifndef DEVICE_FILESYSTEM + if (S_ISDIR(sinfo.st_mode)){ + /* it's a dir */ + if (rmdir(tmpPathBuf1) != 0){ + Trace("DRM_file_delete: dir remove failed, errno=%d", errno); + return DRM_FILE_FAILURE; + } + else + { + return DRM_FILE_SUCCESS; + } + } +#endif + /* it's a file */ + if (unlink(tmpPathBuf1) != 0) + { + Trace("DRM_file_delete: file remove failed, errno=%d", errno); + return DRM_FILE_FAILURE; + } + else + { +#ifndef DEVICE_FILESYSTEM + availableSize += sinfo.st_size; +#endif + return DRM_FILE_SUCCESS; + } + } + return DRM_FILE_FAILURE; +} + +/* see drm_file.h */ +int32_t +DRM_file_rename(const uint16_t *oldName, int32_t oldNameLen, + const uint16_t *newName, int32_t newNameLen) +{ + Trace("DRM_file_rename %.*S -> %.*S", + oldNameLen, oldName, newNameLen, newName); + if (DRM_file_exists(newName, newNameLen) != DRM_FILE_FAILURE) + { + Trace("DRM_file_rename: filename:%s exist",newName); + return DRM_FILE_FAILURE; + } + + if (convertFilename(oldName, oldNameLen, tmpPathBuf1) <= 0 || + convertFilename(newName, newNameLen, tmpPathBuf2) <= 0) + { + Trace("DRM_file_rename: bad filename"); + } + else if (rename(tmpPathBuf1, tmpPathBuf2) != 0) + { + Trace("DRM_file_rename: failed errno=%d", errno); + } + else /* Success */ + { + return DRM_FILE_SUCCESS; + } + + return DRM_FILE_FAILURE; +} + +/* see drm_file.h */ +int32_t +DRM_file_exists(const uint16_t *name, int32_t nameLen) +{ + struct stat sbuf; + + Trace("DRM_file_exists: %.*S", nameLen, name); + + /*remove trailing "/" separators, except the first "/" standing for root*/ + while ((nameLen > 1) && (name[nameLen -1] == '/')) + --nameLen; + + if (getFileStat(name, nameLen, &sbuf)) + { + Trace("DRM_file_exists: stat returns mode 0x%x", sbuf.st_mode); + + if (S_ISDIR(sbuf.st_mode)) + return DRM_FILE_ISDIR; + if (S_ISREG(sbuf.st_mode)) + return DRM_FILE_ISREG; + } + + return DRM_FILE_FAILURE; +} + +/* see drm_file.h */ +int32_t +DRM_file_open(const uint16_t *name, int32_t nameLen, int32_t mode, + int32_t* handle) +{ + int res; + +#if DRM_FILE_MODE_READ != 1 || DRM_FILE_MODE_WRITE != 2 +#error constants changed +#endif + + /* Convert DRM file modes to posix modes */ + static const int modes[4] = + { 0, + O_RDONLY, + O_WRONLY | O_CREAT, + O_RDWR | O_CREAT + }; + + Trace("DRM_file_open %.*S mode 0x%x", nameLen, name, mode); + + assert((mode & ~(DRM_FILE_MODE_READ|DRM_FILE_MODE_WRITE)) == 0); + + if (convertFilename(name, nameLen, tmpPathBuf1) <= 0) + { + Trace("DRM_file_open: bad filename"); + return DRM_FILE_FAILURE; + } + + if ((res = open(tmpPathBuf1, modes[mode], 0777)) == -1) + { + Trace("DRM_file_open: open failed errno=%d", errno); + return DRM_FILE_FAILURE; + } + + Trace("DRM_file_open: open '%s; returned %d", tmpPathBuf1, res); + *handle = res; + + return DRM_FILE_SUCCESS; +} + +/* see drm_file.h */ +int32_t +DRM_file_read(int32_t handle, uint8_t* dst, int32_t length) +{ + int n; + + assert(length > 0); + + /* TODO: Make dst a void *? */ + + n = read((int)handle, dst, (size_t)length); + if (n > 0) + { + Trace("DRM_file_read handle=%d read %d bytes", handle, n); + return n; + } + else if (n == 0) + { + Trace("DRM_file_read read EOF: handle=%d", handle); + return DRM_FILE_EOF; + } + else + { + Trace("DRM_file_read failed handle=%d, errno=%d", handle, errno); + return DRM_FILE_FAILURE; + } +} + +/* see drm_file.h */ +int32_t +DRM_file_write(int32_t handle, const uint8_t* src, int32_t length) +{ + /* TODO: Make dst a void *? */ + int n; +#ifndef DEVICE_FILESYSTEM + int delta; + off_t prevPos; + struct stat sbuf; + int prevFileSize; +#endif + + assert(length >= 0); + +#ifndef DEVICE_FILESYSTEM + if ( -1 == fstat((int)handle, &sbuf) ) + { + Trace("DRM_file_write: fstat error %d", errno); + return DRM_FILE_FAILURE; + } + prevFileSize = (int)(sbuf.st_size); + prevPos = lseek( (int)handle, 0, SEEK_CUR); + if ( (off_t)-1 == prevPos ) + { + Trace("DRM_file_write: get current pos error %d", errno); + return DRM_FILE_FAILURE; + } + delta = (int)prevPos + length - prevFileSize; + if (delta > availableSize) + { + Trace("DRM_file_write: not enough size!"); + return DRM_FILE_FAILURE; + } +#endif + n = write((int)handle, src, (size_t)length); + if (n < 0) + { + Trace("DRM_file_write failed errno=%d", errno); + return DRM_FILE_FAILURE; + } +#ifndef DEVICE_FILESYSTEM + delta = prevPos + n - prevFileSize; + + if ( delta > 0 ) + { + availableSize -= delta; + } +#endif + Trace("DRM_file_write handle=%d wrote %d/%d bytes", handle, n, length); + + return n; +} + +/* see drm_file.h */ +int32_t DRM_file_close(int32_t handle) +{ + if (close((int)handle) == 0) + { + Trace("DRM_file_close handle=%d success", handle); + return DRM_FILE_SUCCESS; + } + + Trace("DRM_file_close handle=%d failed", handle); + return DRM_FILE_FAILURE; +} + +/* see drm_file.h */ +int32_t +DRM_file_setPosition(int32_t handle, int32_t value) +{ +#ifndef DEVICE_FILESYSTEM + struct stat sbuf; +#endif + off_t newPos; + + if (value < 0) + { + Trace("DRM_file_setPosition: handle=%d negative value (%d)", + handle, value); + return DRM_FILE_FAILURE; + } + +#ifndef DEVICE_FILESYSTEM + if ( fstat((int)handle, &sbuf) == -1 ) + { + Trace("DRM_file_setPosition: fstat fail errno=%d", errno); + return DRM_FILE_FAILURE; + } + + if ( ((off_t)value > sbuf.st_size) && + (availableSize < (value - (int)(sbuf.st_size))) ) + { + Trace("DRM_file_setPosition: not enough space"); + return DRM_FILE_FAILURE; + } +#endif + + newPos = lseek( (int)handle, (off_t)value, SEEK_SET); + if ( newPos == (off_t)-1 ) + { + Trace("DRM_file_setPosition: seek failed: errno=%d", errno); + } + else + { +#ifndef DEVICE_FILESYSTEM + if ( newPos > sbuf.st_size ) + { + availableSize -= (int)(newPos - sbuf.st_size); + } +#endif + return DRM_FILE_SUCCESS; + } + + return DRM_FILE_FAILURE; +} + +/* see drm_file.h */ +int32_t +DRM_file_mkdir(const uint16_t* name, int32_t nameChars) +{ + Trace("DRM_file_mkdir started!.."); + + if (convertFilename(name, nameChars, tmpPathBuf1) <= 0) + { + Trace("DRM_file_mkdir: bad filename"); + return DRM_FILE_FAILURE; + } + + if (mkdir(tmpPathBuf1,0777) != 0) + { + Trace("DRM_file_mkdir failed!errno=%d",errno); + return DRM_FILE_FAILURE; + } + + return DRM_FILE_SUCCESS; +} diff --git a/media/libdrm/mobile1/src/objmng/drm_i18n.c b/media/libdrm/mobile1/src/objmng/drm_i18n.c new file mode 100644 index 0000000..b1118a9 --- /dev/null +++ b/media/libdrm/mobile1/src/objmng/drm_i18n.c @@ -0,0 +1,444 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <objmng/drm_i18n.h> + +#define IS_GB2312_HIGH_BYTE(c) ((c) >= 0xA1 && (c) <= 0xF7) +#define IS_GB2312_LOW_BYTE(c) ((c) >= 0xA1 && (c) <= 0xFE) +#define IS_GBK_HIGH_BYTE(c) ((c) >= 0x81 && (c) <= 0xFE) +#define IS_GBK_LOW_BYTE(c) ((c) >= 0x40 && (c) <= 0xFE && (c) != 0x7F) +#define IS_BIG5_HIGH_BYTE(c) ((c) >= 0xA1 && (c) <= 0xF9) +#define IS_BIG5_LOW_BYTE(c) (((c) >= 0x40 && (c) <= 0x7E) \ + || ((c) >= 0xA1 && (c) <= 0xFE)) +#define IS_ASCII(c) ((c) <= 127) + +#define INVALID_UNICODE 0xFFFD + +#define I18N_LATIN1_SUPPORT +#define I18N_UTF8_UTF16_SUPPORT + + +/** + * Simply convert ISO 8859-1 (latin1) to unicode + */ +static int32_t latin1ToWcs(const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed); + +/** + * Convert one unicode char to ISO 8859-1 (latin1) byte + */ +static int32_t wcToLatin1(uint16_t wc, uint8_t * mbs, int32_t bufSize); + +/** + * Convert UTF-8 to unicode + */ +static int32_t utf8ToWcs(const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed); + +/** + * Convert one unicode char to UTF-8 bytes + */ +static int32_t wcToUtf8(uint16_t wc, uint8_t * mbs, int32_t bufSize); + +/** + * Convert UTF-16 BE to unicode + */ +static int32_t utf16beToWcs(const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed); + +/** + * Convert one unicode char to UTF-16 BE bytes + */ +static int32_t wcToUtf16be(uint16_t wc, uint8_t * mbs, int32_t bufSize); + +/** + * Convert UTF-16 LE to unicode + */ +static int32_t utf16leToWcs(const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed); + +/** + * Convert one unicode char to UTF-16 LE bytes + */ +static int32_t wcToUtf16le(uint16_t wc, uint8_t * mbs, int32_t bufSize); + +/* + * see drm_i18n.h + */ +int32_t DRM_i18n_mbsToWcs(DRM_Charset_t charset, + const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed) +{ + switch (charset) + { +#ifdef I18N_GB2312_SUPPORT + case DRM_CHARSET_GB2312: + return gb2312ToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed); +#endif +#ifdef I18N_GBK_SUPPORT + case DRM_CHARSET_GBK: + return gbkToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed); +#endif +#ifdef I18N_BIG5_SUPPORT + case DRM_CHARSET_BIG5: + return big5ToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed); +#endif +#ifdef I18N_LATIN1_SUPPORT + case DRM_CHARSET_LATIN1: + return latin1ToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed); +#endif +#ifdef I18N_ISO8859X_SUPPORT + case DRM_CHARSET_LATIN2: + case DRM_CHARSET_LATIN3: + case DRM_CHARSET_LATIN4: + case DRM_CHARSET_CYRILLIC: + case DRM_CHARSET_ARABIC: + case DRM_CHARSET_GREEK: + case DRM_CHARSET_HEBREW: + case DRM_CHARSET_LATIN5: + case DRM_CHARSET_LATIN6: + case DRM_CHARSET_THAI: + case DRM_CHARSET_LATIN7: + case DRM_CHARSET_LATIN8: + case DRM_CHARSET_LATIN9: + case DRM_CHARSET_LATIN10: + return iso8859xToWcs(charset, mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed); +#endif +#ifdef I18N_UTF8_UTF16_SUPPORT + case DRM_CHARSET_UTF8: + return utf8ToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed); + case DRM_CHARSET_UTF16BE: + return utf16beToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed); + case DRM_CHARSET_UTF16LE: + return utf16leToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed); +#endif + default: + return -1; + } +} + +/* + * see drm_i18n.h + */ +int32_t DRM_i18n_wcsToMbs(DRM_Charset_t charset, + const uint16_t *wcs, int32_t wcsLen, + uint8_t *mbsBuf, int32_t bufSizeInByte) +{ + int32_t (* wcToMbFunc)(uint16_t, uint8_t *, int32_t); + int32_t charIndex = 0; + int32_t numMultiBytes = 0; + + switch (charset) + { +#ifdef I18N_LATIN1_SUPPORT + case DRM_CHARSET_LATIN1: + wcToMbFunc = wcToLatin1; + break; +#endif +#ifdef I18N_UTF8_UTF16_SUPPORT + case DRM_CHARSET_UTF8: + wcToMbFunc = wcToUtf8; + break; + case DRM_CHARSET_UTF16BE: + wcToMbFunc = wcToUtf16be; + break; + case DRM_CHARSET_UTF16LE: + wcToMbFunc = wcToUtf16le; + break; +#endif +#ifdef I18N_ISO8859X_SUPPORT + case DRM_CHARSET_LATIN2: + case DRM_CHARSET_LATIN3: + case DRM_CHARSET_LATIN4: + case DRM_CHARSET_CYRILLIC: + case DRM_CHARSET_ARABIC: + case DRM_CHARSET_GREEK: + case DRM_CHARSET_HEBREW: + case DRM_CHARSET_LATIN5: + case DRM_CHARSET_LATIN6: + case DRM_CHARSET_THAI: + case DRM_CHARSET_LATIN7: + case DRM_CHARSET_LATIN8: + case DRM_CHARSET_LATIN9: + case DRM_CHARSET_LATIN10: + return wcsToIso8859x(charset, wcs, wcsLen, mbsBuf, bufSizeInByte); +#endif + default: + return -1; + } + + if (mbsBuf) { + while (numMultiBytes < bufSizeInByte && charIndex < wcsLen) { + /* TODO: handle surrogate pair values here */ + int32_t mbLen = wcToMbFunc(wcs[charIndex], + &mbsBuf[numMultiBytes], bufSizeInByte - numMultiBytes); + + if (numMultiBytes + mbLen > bufSizeInByte) { + /* Insufficient buffer. Don't update numMultiBytes */ + break; + } + charIndex++; + numMultiBytes += mbLen; + } + } else { + while (charIndex < wcsLen) { + /* TODO: handle surrogate pair values here */ + numMultiBytes += wcToMbFunc(wcs[charIndex], NULL, 0); + charIndex++; + } + } + + return numMultiBytes; +} + + +#ifdef I18N_LATIN1_SUPPORT + +int32_t latin1ToWcs(const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed) +{ + int32_t charsToConvert; + int32_t len; + + if (wcsBuf == NULL) { + return mbsLen; + } + + len = charsToConvert = mbsLen > bufSizeInWideChar ? bufSizeInWideChar : mbsLen; + if (len < 0) + return 0; + while (len--) { + *wcsBuf++ = *mbs++; + } + + if (bytesConsumed) + *bytesConsumed = charsToConvert; + + return charsToConvert; +} + +int32_t wcToLatin1(uint16_t wc, uint8_t * mbs, int32_t bufSize) +{ + uint8_t ch; + + if (wc < 0x100) { + ch = (uint8_t)(wc & 0xff); + } else { + ch = '?'; + } + if (mbs && bufSize > 0) + *mbs = ch; + return 1; +} + +#endif /* I18N_LATIN1_SUPPORT */ + +#ifdef I18N_UTF8_UTF16_SUPPORT + +int32_t utf8ToWcs(const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed) +{ + int32_t charsConverted = 0; + int32_t i = 0; + int32_t wideChar; + + if (wcsBuf == NULL) { + /* No conversion but we're still going to calculate bytesConsumed */ + bufSizeInWideChar = mbsLen * 2; + } + + while((i < mbsLen) && (charsConverted < bufSizeInWideChar)) { + uint8_t ch = mbs[i]; + uint8_t ch2, ch3, ch4; + + wideChar = -1; + + if(IS_ASCII(ch)) { + wideChar = ch; + i++; + } else if ((ch & 0xc0) == 0xc0) { + int utfStart = i; + if ((ch & 0xe0) == 0xc0) { + /* 2 byte sequence */ + if (i + 1 < mbsLen && ((ch2 = mbs[i + 1]) & 0xc0) == 0x80) { + wideChar = (uint16_t)(((ch & 0x1F) << 6) | (ch2 & 0x3F)); + i += 2; + } else { + /* skip incomplete sequence */ + i++; + } + } else if ((ch & 0xf0) == 0xe0) { + /* 3 byte sequence */ + if (i + 2 < mbsLen + && ((ch2 = mbs[i + 1]) & 0xc0) == 0x80 + && ((ch3 = mbs[i + 2]) & 0xc0) == 0x80) { + wideChar = (uint16_t)(((ch & 0x0F) << 12) | ((ch2 & 0x3F) << 6) | (ch3 & 0x3F)); + i += 3; + } else { + /* skip incomplete sequence (up to 2 bytes) */ + i++; + if (i < mbsLen && (mbs[i] & 0xc0) == 0x80) + i++; + } + } else if ((ch & 0xf8) == 0xf0) { + /* 4 byte sequence */ + if (i + 3 < mbsLen + && ((ch2 = mbs[i + 1]) & 0xc0) == 0x80 + && ((ch3 = mbs[i + 2]) & 0xc0) == 0x80 + && ((ch4 = mbs[i + 3]) & 0xc0) == 0x80) { + /* FIXME: we do NOT support U+10000 - U+10FFFF for now. + * leave it as 0xFFFD. */ + wideChar = INVALID_UNICODE; + i += 4; + } else { + /* skip incomplete sequence (up to 3 bytes) */ + i++; + if (i < mbsLen && (mbs[i] & 0xc0) == 0x80) { + i++; + if (i < mbsLen && (mbs[i] & 0xc0) == 0x80) { + i++; + } + } + } + } else { + /* invalid */ + i++; + } + if (i >= mbsLen && wideChar == -1) { + /* Possible incomplete UTF-8 sequence at the end of mbs. + * Leave it to the caller. + */ + i = utfStart; + break; + } + } else { + /* invalid */ + i++; + } + if(wcsBuf) { + if (wideChar == -1) + wideChar = INVALID_UNICODE; + wcsBuf[charsConverted] = (uint16_t)wideChar; + } + charsConverted++; + } + + if (bytesConsumed) + *bytesConsumed = i; + + return charsConverted; +} + +int32_t wcToUtf8(uint16_t wc, uint8_t * mbs, int32_t bufSize) +{ + if (wc <= 0x7f) { + if (mbs && (bufSize >= 1)) { + *mbs = (uint8_t)wc; + } + return 1; + } else if (wc <= 0x7ff) { + if (mbs && (bufSize >= 2)) { + *mbs++ = (uint8_t)((wc >> 6) | 0xc0); + *mbs = (uint8_t)((wc & 0x3f) | 0x80); + } + return 2; + } else { + if (mbs && (bufSize >= 3)) { + *mbs++ = (uint8_t)((wc >> 12) | 0xe0); + *mbs++ = (uint8_t)(((wc >> 6) & 0x3f)| 0x80); + *mbs = (uint8_t)((wc & 0x3f) | 0x80); + } + return 3; + } +} + +int32_t utf16beToWcs(const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed) +{ + int32_t charsToConvert; + int32_t len; + + if (wcsBuf == NULL) { + return mbsLen / 2; + } + + len = charsToConvert = (mbsLen / 2) > bufSizeInWideChar ? bufSizeInWideChar : (mbsLen / 2); + while (len--) { + /* TODO: handle surrogate pair values */ + *wcsBuf++ = (uint16_t)((*mbs << 8) | *(mbs + 1)); + mbs += 2; + } + + if (bytesConsumed) + *bytesConsumed = charsToConvert * 2; + + return charsToConvert; +} + +int32_t wcToUtf16be(uint16_t wc, uint8_t * mbs, int32_t bufSize) +{ + if (mbs && bufSize >= 2) { + /* TODO: handle surrogate pair values */ + *mbs = (uint8_t)(wc >> 8); + *(mbs + 1) = (uint8_t)(wc & 0xff); + } + return 2; +} + +int32_t utf16leToWcs(const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed) +{ + int32_t charsToConvert; + int32_t len; + + if (wcsBuf == NULL) { + return mbsLen / 2; + } + + len = charsToConvert = (mbsLen / 2) > bufSizeInWideChar ? bufSizeInWideChar : (mbsLen / 2); + while (len--) { + /* TODO: handle surrogate pair values */ + *wcsBuf++ = (uint16_t)(*mbs | (*(mbs + 1) << 8)); + mbs += 2; + } + + if (bytesConsumed) + *bytesConsumed = charsToConvert * 2; + + return charsToConvert; +} + +int32_t wcToUtf16le(uint16_t wc, uint8_t * mbs, int32_t bufSize) +{ + if (mbs && bufSize >= 2) { + /* TODO: handle surrogate pair values */ + *mbs = (uint8_t)(wc & 0xff); + *(mbs + 1) = (uint8_t)(wc >> 8); + } + return 2; +} + +#endif /* I18N_UTF8_UTF16_SUPPORT */ + diff --git a/media/libdrm/mobile1/src/objmng/drm_rights_manager.c b/media/libdrm/mobile1/src/objmng/drm_rights_manager.c new file mode 100644 index 0000000..80901f5 --- /dev/null +++ b/media/libdrm/mobile1/src/objmng/drm_rights_manager.c @@ -0,0 +1,688 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <drm_rights_manager.h> +#include <drm_inner.h> +#include <drm_file.h> +#include <drm_i18n.h> + +static int32_t drm_getString(uint8_t* string, int32_t len, int32_t handle) +{ + int32_t i; + + for (i = 0; i < len; i++) { + if (DRM_FILE_FAILURE == DRM_file_read(handle, &string[i], 1)) + return FALSE; + if (string[i] == '\n') { + string[i + 1] = '\0'; + break; + } + } + return TRUE; +} + +static int32_t drm_putString(uint8_t* string, int32_t handle) +{ + int32_t i = 0; + + for (i = 0;; i++) { + if (string[i] == '\0') + break; + if (DRM_FILE_FAILURE == DRM_file_write(handle, &string[i], 1)) + return FALSE; + } + return TRUE; +} + +static int32_t drm_writeToUidTxt(uint8_t* Uid, int32_t* id) +{ + int32_t length; + int32_t i; + uint8_t idStr[8]; + int32_t idMax; + uint8_t(*uidStr)[256]; + uint16_t nameUcs2[MAX_FILENAME_LEN]; + int32_t nameLen; + int32_t bytesConsumed; + int32_t handle; + int32_t fileRes; + + if (*id < 1) + return FALSE; + + /* convert in ucs2 */ + nameLen = strlen(DRM_UID_FILE_PATH); + nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8, + (uint8_t *)DRM_UID_FILE_PATH, + nameLen, + nameUcs2, + MAX_FILENAME_LEN, + &bytesConsumed); + fileRes = DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_READ, + &handle); + if (DRM_FILE_SUCCESS != fileRes) { + DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_WRITE, + &handle); + DRM_file_write(handle, (uint8_t *)"0\n", 2); + DRM_file_close(handle); + DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_READ, + &handle); + } + + if (!drm_getString(idStr, 8, handle)) { + DRM_file_close(handle); + return FALSE; + } + idMax = atoi((char *)idStr); + + if (idMax < *id) + uidStr = malloc((idMax + 1) * 256); + else + uidStr = malloc(idMax * 256); + + for (i = 0; i < idMax; i++) { + if (!drm_getString(uidStr[i], 256, handle)) { + DRM_file_close(handle); + free(uidStr); + return FALSE; + } + } + length = strlen((char *)Uid); + strcpy((char *)uidStr[*id - 1], (char *)Uid); + uidStr[*id - 1][length] = '\n'; + uidStr[*id - 1][length + 1] = '\0'; + if (idMax < (*id)) + idMax++; + DRM_file_close(handle); + + DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_WRITE, + &handle); + sprintf((char *)idStr, "%d", idMax); + + if (!drm_putString(idStr, handle)) { + DRM_file_close(handle); + free(uidStr); + return FALSE; + } + if (DRM_FILE_FAILURE == DRM_file_write(handle, (uint8_t *)"\n", 1)) { + DRM_file_close(handle); + free(uidStr); + return FALSE; + } + for (i = 0; i < idMax; i++) { + if (!drm_putString(uidStr[i], handle)) { + DRM_file_close(handle); + free(uidStr); + return FALSE; + } + } + if (DRM_FILE_FAILURE == DRM_file_write(handle, (uint8_t *)"\n", 1)) { + DRM_file_close(handle); + free(uidStr); + return FALSE; + } + DRM_file_close(handle); + free(uidStr); + return TRUE; +} + +/* See objmng_files.h */ +int32_t drm_readFromUidTxt(uint8_t* Uid, int32_t* id, int32_t option) +{ + int32_t i; + uint8_t p[256] = { 0 }; + uint8_t idStr[8]; + int32_t idMax = 0; + uint16_t nameUcs2[MAX_FILENAME_LEN]; + int32_t nameLen = 0; + int32_t bytesConsumed; + int32_t handle; + int32_t fileRes; + + if (NULL == id || NULL == Uid) + return FALSE; + + DRM_file_startup(); + + /* convert in ucs2 */ + nameLen = strlen(DRM_UID_FILE_PATH); + nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8, + (uint8_t *)DRM_UID_FILE_PATH, + nameLen, + nameUcs2, + MAX_FILENAME_LEN, + &bytesConsumed); + fileRes = DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_READ, + &handle); + if (DRM_FILE_SUCCESS != fileRes) { + DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_WRITE, + &handle); + DRM_file_write(handle, (uint8_t *)"0\n", 2); + DRM_file_close(handle); + DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_READ, + &handle); + } + + if (!drm_getString(idStr, 8, handle)) { + DRM_file_close(handle); + return FALSE; + } + idMax = atoi((char *)idStr); + + if (option == GET_UID) { + if (*id < 1 || *id > idMax) { + DRM_file_close(handle); + return FALSE; + } + for (i = 1; i <= *id; i++) { + if (!drm_getString(Uid, 256, handle)) { + DRM_file_close(handle); + return FALSE; + } + } + DRM_file_close(handle); + return TRUE; + } + if (option == GET_ID) { + *id = -1; + for (i = 1; i <= idMax; i++) { + if (!drm_getString(p, 256, handle)) { + DRM_file_close(handle); + return FALSE; + } + if (strstr((char *)p, (char *)Uid) != NULL + && strlen((char *)p) == strlen((char *)Uid) + 1) { + *id = i; + DRM_file_close(handle); + return TRUE; + } + if ((*id == -1) && (strlen((char *)p) < 3)) + *id = i; + } + if (*id != -1) { + DRM_file_close(handle); + return FALSE; + } + *id = idMax + 1; + DRM_file_close(handle); + return FALSE; + } + DRM_file_close(handle); + return FALSE; +} + +static int32_t drm_acquireId(uint8_t* uid, int32_t* id) +{ + if (TRUE == drm_readFromUidTxt(uid, id, GET_ID)) + return TRUE; + + drm_writeToUidTxt(uid, id); + + return FALSE; /* The Uid is not exit, then return FALSE indicate it */ +} + +int32_t drm_writeOrReadInfo(int32_t id, T_DRM_Rights* Ro, int32_t* RoAmount, int32_t option) +{ + uint8_t fullname[MAX_FILENAME_LEN] = {0}; + int32_t tmpRoAmount; + uint16_t nameUcs2[MAX_FILENAME_LEN]; + int32_t nameLen = 0; + int32_t bytesConsumed; + int32_t handle; + int32_t fileRes; + + sprintf((char *)fullname, ANDROID_DRM_CORE_PATH"%d"EXTENSION_NAME_INFO, id); + + /* convert in ucs2 */ + nameLen = strlen((char *)fullname); + nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8, + fullname, + nameLen, + nameUcs2, + MAX_FILENAME_LEN, + &bytesConsumed); + fileRes = DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_READ, + &handle); + if (DRM_FILE_SUCCESS != fileRes) { + if (GET_ALL_RO == option || GET_A_RO == option) + return FALSE; + + if (GET_ROAMOUNT == option) { + *RoAmount = -1; + return TRUE; + } + } + + DRM_file_close(handle); + DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_READ | DRM_FILE_MODE_WRITE, + &handle); + + switch(option) { + case GET_ROAMOUNT: + if (DRM_FILE_FAILURE == DRM_file_read(handle, (uint8_t*)RoAmount, sizeof(int32_t))) { + DRM_file_close(handle); + return FALSE; + } + break; + case GET_ALL_RO: + DRM_file_setPosition(handle, sizeof(int32_t)); + + if (DRM_FILE_FAILURE == DRM_file_read(handle, (uint8_t*)Ro, (*RoAmount) * sizeof(T_DRM_Rights))) { + DRM_file_close(handle); + return FALSE; + } + break; + case SAVE_ALL_RO: + if (DRM_FILE_FAILURE == DRM_file_write(handle, (uint8_t*)RoAmount, sizeof(int32_t))) { + DRM_file_close(handle); + return FALSE; + } + + if (NULL != Ro && *RoAmount >= 1) { + if (DRM_FILE_FAILURE == DRM_file_write(handle, (uint8_t*) Ro, (*RoAmount) * sizeof(T_DRM_Rights))) { + DRM_file_close(handle); + return FALSE; + } + } + break; + case GET_A_RO: + DRM_file_setPosition(handle, sizeof(int32_t) + (*RoAmount - 1) * sizeof(T_DRM_Rights)); + + if (DRM_FILE_FAILURE == DRM_file_read(handle, (uint8_t*)Ro, sizeof(T_DRM_Rights))) { + DRM_file_close(handle); + return FALSE; + } + break; + case SAVE_A_RO: + DRM_file_setPosition(handle, sizeof(int32_t) + (*RoAmount - 1) * sizeof(T_DRM_Rights)); + + if (DRM_FILE_FAILURE == DRM_file_write(handle, (uint8_t*)Ro, sizeof(T_DRM_Rights))) { + DRM_file_close(handle); + return FALSE; + } + + DRM_file_setPosition(handle, 0); + if (DRM_FILE_FAILURE == DRM_file_read(handle, (uint8_t*)&tmpRoAmount, sizeof(int32_t))) { + DRM_file_close(handle); + return FALSE; + } + if (tmpRoAmount < *RoAmount) { + DRM_file_setPosition(handle, 0); + DRM_file_write(handle, (uint8_t*)RoAmount, sizeof(int32_t)); + } + break; + default: + DRM_file_close(handle); + return FALSE; + } + + DRM_file_close(handle); + return TRUE; +} + +int32_t drm_appendRightsInfo(T_DRM_Rights* rights) +{ + int32_t id; + int32_t roAmount; + + if (NULL == rights) + return FALSE; + + drm_acquireId(rights->uid, &id); + + if (FALSE == drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT)) + return FALSE; + + if (-1 == roAmount) + roAmount = 0; + + /* The RO amount increase */ + roAmount++; + + /* Save the rights information */ + if (FALSE == drm_writeOrReadInfo(id, rights, &roAmount, SAVE_A_RO)) + return FALSE; + + return TRUE; +} + +int32_t drm_getMaxIdFromUidTxt() +{ + uint8_t idStr[8]; + int32_t idMax = 0; + uint16_t nameUcs2[MAX_FILENAME_LEN] = {0}; + int32_t nameLen = 0; + int32_t bytesConsumed; + int32_t handle; + int32_t fileRes; + + /* convert in ucs2 */ + nameLen = strlen(DRM_UID_FILE_PATH); + nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8, + (uint8_t *)DRM_UID_FILE_PATH, + nameLen, + nameUcs2, + MAX_FILENAME_LEN, + &bytesConsumed); + fileRes = DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_READ, + &handle); + + /* this means the uid.txt file is not exist, so there is not any DRM object */ + if (DRM_FILE_SUCCESS != fileRes) + return 0; + + if (!drm_getString(idStr, 8, handle)) { + DRM_file_close(handle); + return -1; + } + DRM_file_close(handle); + + idMax = atoi((char *)idStr); + return idMax; +} + +int32_t drm_removeIdInfoFile(int32_t id) +{ + uint8_t filename[MAX_FILENAME_LEN] = {0}; + uint16_t nameUcs2[MAX_FILENAME_LEN]; + int32_t nameLen = 0; + int32_t bytesConsumed; + + if (id <= 0) + return FALSE; + + sprintf((char *)filename, ANDROID_DRM_CORE_PATH"%d"EXTENSION_NAME_INFO, id); + + /* convert in ucs2 */ + nameLen = strlen((char *)filename); + nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8, + filename, + nameLen, + nameUcs2, + MAX_FILENAME_LEN, + &bytesConsumed); + if (DRM_FILE_SUCCESS != DRM_file_delete(nameUcs2, nameLen)) + return FALSE; + + return TRUE; +} + +int32_t drm_updateUidTxtWhenDelete(int32_t id) +{ + uint16_t nameUcs2[MAX_FILENAME_LEN]; + int32_t nameLen = 0; + int32_t bytesConsumed; + int32_t handle; + int32_t fileRes; + int32_t bufferLen; + uint8_t *buffer; + uint8_t idStr[8]; + int32_t idMax; + + if (id <= 0) + return FALSE; + + nameLen = strlen(DRM_UID_FILE_PATH); + nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8, + (uint8_t *)DRM_UID_FILE_PATH, + nameLen, + nameUcs2, + MAX_FILENAME_LEN, + &bytesConsumed); + bufferLen = DRM_file_getFileLength(nameUcs2, nameLen); + if (bufferLen <= 0) + return FALSE; + + buffer = (uint8_t *)malloc(bufferLen); + if (NULL == buffer) + return FALSE; + + fileRes = DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_READ, + &handle); + if (DRM_FILE_SUCCESS != fileRes) { + free(buffer); + return FALSE; + } + + drm_getString(idStr, 8, handle); + idMax = atoi((char *)idStr); + + bufferLen -= strlen((char *)idStr); + fileRes = DRM_file_read(handle, buffer, bufferLen); + buffer[bufferLen] = '\0'; + DRM_file_close(handle); + + /* handle this buffer */ + { + uint8_t *pStart, *pEnd; + int32_t i, movLen; + + pStart = buffer; + pEnd = pStart; + for (i = 0; i < id; i++) { + if (pEnd != pStart) + pStart = ++pEnd; + while ('\n' != *pEnd) + pEnd++; + if (pStart == pEnd) + pStart--; + } + movLen = bufferLen - (pEnd - buffer); + memmove(pStart, pEnd, movLen); + bufferLen -= (pEnd - pStart); + } + + if (DRM_FILE_SUCCESS != DRM_file_delete(nameUcs2, nameLen)) { + free(buffer); + return FALSE; + } + + fileRes = DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_WRITE, + &handle); + if (DRM_FILE_SUCCESS != fileRes) { + free(buffer); + return FALSE; + } + sprintf((char *)idStr, "%d", idMax); + drm_putString(idStr, handle); + DRM_file_write(handle, (uint8_t*)"\n", 1); + DRM_file_write(handle, buffer, bufferLen); + free(buffer); + DRM_file_close(handle); + return TRUE; +} + +int32_t drm_getKey(uint8_t* uid, uint8_t* KeyValue) +{ + T_DRM_Rights ro; + int32_t id, roAmount; + + if (NULL == uid || NULL == KeyValue) + return FALSE; + + if (FALSE == drm_readFromUidTxt(uid, &id, GET_ID)) + return FALSE; + + if (FALSE == drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT)) + return FALSE; + + if (roAmount <= 0) + return FALSE; + + memset(&ro, 0, sizeof(T_DRM_Rights)); + roAmount = 1; + if (FALSE == drm_writeOrReadInfo(id, &ro, &roAmount, GET_A_RO)) + return FALSE; + + memcpy(KeyValue, ro.KeyValue, DRM_KEY_LEN); + return TRUE; +} + +void drm_discardPaddingByte(uint8_t *decryptedBuf, int32_t *decryptedBufLen) +{ + int32_t tmpLen = *decryptedBufLen; + int32_t i; + + if (NULL == decryptedBuf || *decryptedBufLen < 0) + return; + + /* Check whether the last several bytes are padding or not */ + for (i = 1; i < decryptedBuf[tmpLen - 1]; i++) { + if (decryptedBuf[tmpLen - 1 - i] != decryptedBuf[tmpLen - 1]) + break; /* Not the padding bytes */ + } + if (i == decryptedBuf[tmpLen - 1]) /* They are padding bytes */ + *decryptedBufLen = tmpLen - i; + return; +} + +int32_t drm_aesDecBuffer(uint8_t * Buffer, int32_t * BufferLen, aes_decrypt_ctx ctx[1]) +{ + uint8_t dbuf[3 * DRM_ONE_AES_BLOCK_LEN], buf[DRM_ONE_AES_BLOCK_LEN]; + uint64_t i, len, wlen = DRM_ONE_AES_BLOCK_LEN, curLen, restLen; + uint8_t *pTarget, *pTargetHead; + + pTargetHead = Buffer; + pTarget = Buffer; + curLen = 0; + restLen = *BufferLen; + + if (restLen > 2 * DRM_ONE_AES_BLOCK_LEN) { + len = 2 * DRM_ONE_AES_BLOCK_LEN; + } else { + len = restLen; + } + memcpy(dbuf, Buffer, (size_t)len); + restLen -= len; + Buffer += len; + + if (len < 2 * DRM_ONE_AES_BLOCK_LEN) { /* The original file is less than one block in length */ + len -= DRM_ONE_AES_BLOCK_LEN; + /* Decrypt from position len to position len + DRM_ONE_AES_BLOCK_LEN */ + aes_decrypt((dbuf + len), (dbuf + len), ctx); + + /* Undo the CBC chaining */ + for (i = 0; i < len; ++i) + dbuf[i] ^= dbuf[i + DRM_ONE_AES_BLOCK_LEN]; + + /* Output the decrypted bytes */ + memcpy(pTarget, dbuf, (size_t)len); + pTarget += len; + } else { + uint8_t *b1 = dbuf, *b2 = b1 + DRM_ONE_AES_BLOCK_LEN, *b3 = b2 + DRM_ONE_AES_BLOCK_LEN, *bt; + + for (;;) { /* While some ciphertext remains, prepare to decrypt block b2 */ + /* Read in the next block to see if ciphertext stealing is needed */ + b3 = Buffer; + if (restLen > DRM_ONE_AES_BLOCK_LEN) { + len = DRM_ONE_AES_BLOCK_LEN; + } else { + len = restLen; + } + restLen -= len; + Buffer += len; + + /* Decrypt the b2 block */ + aes_decrypt((uint8_t *)b2, buf, ctx); + + if (len == 0 || len == DRM_ONE_AES_BLOCK_LEN) { /* No ciphertext stealing */ + /* Unchain CBC using the previous ciphertext block in b1 */ + for (i = 0; i < DRM_ONE_AES_BLOCK_LEN; ++i) + buf[i] ^= b1[i]; + } else { /* Partial last block - use ciphertext stealing */ + wlen = len; + /* Produce last 'len' bytes of plaintext by xoring with */ + /* The lowest 'len' bytes of next block b3 - C[N-1] */ + for (i = 0; i < len; ++i) + buf[i] ^= b3[i]; + + /* Reconstruct the C[N-1] block in b3 by adding in the */ + /* Last (DRM_ONE_AES_BLOCK_LEN - len) bytes of C[N-2] in b2 */ + for (i = len; i < DRM_ONE_AES_BLOCK_LEN; ++i) + b3[i] = buf[i]; + + /* Decrypt the C[N-1] block in b3 */ + aes_decrypt((uint8_t *)b3, (uint8_t *)b3, ctx); + + /* Produce the last but one plaintext block by xoring with */ + /* The last but two ciphertext block */ + for (i = 0; i < DRM_ONE_AES_BLOCK_LEN; ++i) + b3[i] ^= b1[i]; + + /* Write decrypted plaintext blocks */ + memcpy(pTarget, b3, DRM_ONE_AES_BLOCK_LEN); + pTarget += DRM_ONE_AES_BLOCK_LEN; + } + + /* Write the decrypted plaintext block */ + memcpy(pTarget, buf, (size_t)wlen); + pTarget += wlen; + + if (len != DRM_ONE_AES_BLOCK_LEN) { + *BufferLen = pTarget - pTargetHead; + return 0; + } + + /* Advance the buffer pointers */ + bt = b1, b1 = b2, b2 = b3, b3 = bt; + } + } + return 0; +} + +int32_t drm_updateDcfDataLen(uint8_t* pDcfLastData, uint8_t* keyValue, int32_t* moreBytes) +{ + aes_decrypt_ctx ctx[1]; + int32_t len = DRM_TWO_AES_BLOCK_LEN; + + if (NULL == pDcfLastData || NULL == keyValue) + return FALSE; + + aes_decrypt_key128(keyValue, ctx); + + if (drm_aesDecBuffer(pDcfLastData, &len, ctx) < 0) + return FALSE; + + drm_discardPaddingByte(pDcfLastData, &len); + + *moreBytes = DRM_TWO_AES_BLOCK_LEN - len; + + return TRUE; +} diff --git a/media/libdrm/mobile1/src/objmng/drm_time.c b/media/libdrm/mobile1/src/objmng/drm_time.c new file mode 100644 index 0000000..fceb4952 --- /dev/null +++ b/media/libdrm/mobile1/src/objmng/drm_time.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * DRM 1.0 Reference Port: linux implementation of drm_time.c. + */ + +#include <objmng/drm_time.h> +#include <unistd.h> + +/* See drm_time.h */ +uint32_t DRM_time_getElapsedSecondsFrom1970(void) +{ + return time(NULL); +} + +/* See drm_time.h */ +void DRM_time_sleep(uint32_t ms) +{ + usleep(ms * 1000); +} + +/* See drm_time.h */ +void DRM_time_getSysTime(T_DB_TIME_SysTime *time_ptr) +{ + time_t t; + struct tm *tm_t; + + time(&t); + tm_t = gmtime(&t); + + time_ptr->year = tm_t->tm_year + 1900; + time_ptr->month = tm_t->tm_mon + 1; + time_ptr->day = tm_t->tm_mday; + time_ptr->hour = tm_t->tm_hour; + time_ptr->min = tm_t->tm_min; + time_ptr->sec = tm_t->tm_sec; +} diff --git a/media/libdrm/mobile1/src/parser/parser_dcf.c b/media/libdrm/mobile1/src/parser/parser_dcf.c new file mode 100644 index 0000000..06aa830 --- /dev/null +++ b/media/libdrm/mobile1/src/parser/parser_dcf.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <parser_dcf.h> +#include <svc_drm.h> + +static int32_t drm_parseUintVar(uint8_t * buffer, uint8_t * len) +{ + int32_t i; + int32_t byteLen; + int32_t sum; + + if (NULL == buffer) + return DRM_UINT_VAR_ERR; + + byteLen = 0; + while ((buffer[byteLen] & UINT_VAR_FLAG) > 0 && byteLen < MAX_UINT_VAR_BYTE) /* UINT_VAR_FLAG == 0x80 */ + byteLen++; + + if (byteLen >= MAX_UINT_VAR_BYTE) /* MAX_UINT_VAR_BYTE == 5 */ + return DRM_UINT_VAR_ERR; /* The var int is too large, and that is impossible */ + + *len = (uint8_t)(byteLen + 1); + sum = buffer[byteLen]; + for (i = byteLen - 1; i >= 0; i--) + sum += ((buffer[i] & UINT_VAR_DATA) << 7 * (byteLen - i)); /* UINT_VAR_DATA == 0x7F */ + + return sum; +} + +/* See parser_dcf.h */ +int32_t drm_dcfParser(uint8_t *buffer, int32_t bufferLen, T_DRM_DCF_Info *pDcfInfo, + uint8_t **ppEncryptedData) +{ + uint8_t *tmpBuf; + uint8_t *pStart, *pEnd; + uint8_t *pHeader, *pData; + uint8_t varLen; + + if (NULL == buffer || bufferLen <= 0 || NULL == pDcfInfo) + return FALSE; + + tmpBuf = buffer; + /* 1. Parse the version, content-type and content-url */ + pDcfInfo->Version = *(tmpBuf++); + if (0x01 != pDcfInfo->Version) /* Because it is OMA DRM v1.0, the vension must be 1 */ + return FALSE; + pDcfInfo->ContentTypeLen = *(tmpBuf++); + pDcfInfo->ContentURILen = *(tmpBuf++); + strncpy((char *)pDcfInfo->ContentType, (char *)tmpBuf, pDcfInfo->ContentTypeLen); + tmpBuf += pDcfInfo->ContentTypeLen; + strncpy((char *)pDcfInfo->ContentURI, (char *)tmpBuf, pDcfInfo->ContentURILen); + tmpBuf += pDcfInfo->ContentURILen; + + /* 2. Get the headers length and data length */ + pDcfInfo->HeadersLen = drm_parseUintVar(tmpBuf, &varLen); + if (DRM_UINT_VAR_ERR == pDcfInfo->HeadersLen) + return FALSE; + tmpBuf += varLen; + pDcfInfo->DecryptedDataLen = DRM_UNKNOWN_DATA_LEN; + pDcfInfo->EncryptedDataLen = drm_parseUintVar(tmpBuf, &varLen); + if (DRM_UINT_VAR_ERR == pDcfInfo->EncryptedDataLen) + return FALSE; + tmpBuf += varLen; + pHeader = tmpBuf; + tmpBuf += pDcfInfo->HeadersLen; + pData = tmpBuf; + + /* 3. Parse the headers */ + pStart = pHeader; + while (pStart < pData) { + pEnd = pStart; + while ('\r' != *pEnd && pEnd < pData) + pEnd++; + + if (0 == strncmp((char *)pStart, HEADER_ENCRYPTION_METHOD, HEADER_ENCRYPTION_METHOD_LEN)) + strncpy((char *)pDcfInfo->Encryption_Method, + (char *)(pStart + HEADER_ENCRYPTION_METHOD_LEN), + pEnd - pStart - HEADER_ENCRYPTION_METHOD_LEN); + else if (0 == strncmp((char *)pStart, HEADER_RIGHTS_ISSUER, HEADER_RIGHTS_ISSUER_LEN)) + strncpy((char *)pDcfInfo->Rights_Issuer, + (char *)(pStart + HEADER_RIGHTS_ISSUER_LEN), + pEnd - pStart - HEADER_RIGHTS_ISSUER_LEN); + else if (0 == strncmp((char *)pStart, HEADER_CONTENT_NAME, HEADER_CONTENT_NAME_LEN)) + strncpy((char *)pDcfInfo->Content_Name, + (char *)(pStart + HEADER_CONTENT_NAME_LEN), + pEnd - pStart - HEADER_CONTENT_NAME_LEN); + else if (0 == strncmp((char *)pStart, HEADER_CONTENT_DESCRIPTION, HEADER_CONTENT_DESCRIPTION_LEN)) + strncpy((char *)pDcfInfo->ContentDescription, + (char *)(pStart + HEADER_CONTENT_DESCRIPTION_LEN), + pEnd - pStart - HEADER_CONTENT_DESCRIPTION_LEN); + else if (0 == strncmp((char *)pStart, HEADER_CONTENT_VENDOR, HEADER_CONTENT_VENDOR_LEN)) + strncpy((char *)pDcfInfo->ContentVendor, + (char *)(pStart + HEADER_CONTENT_VENDOR_LEN), + pEnd - pStart - HEADER_CONTENT_VENDOR_LEN); + else if (0 == strncmp((char *)pStart, HEADER_ICON_URI, HEADER_ICON_URI_LEN)) + strncpy((char *)pDcfInfo->Icon_URI, + (char *)(pStart + HEADER_ICON_URI_LEN), + pEnd - pStart - HEADER_ICON_URI_LEN); + + if ('\n' == *(pEnd + 1)) + pStart = pEnd + 2; /* Two bytes: a '\r' and a '\n' */ + else + pStart = pEnd + 1; + } + + /* 4. Give out the location of encrypted data */ + if (NULL != ppEncryptedData) + *ppEncryptedData = pData; + + return TRUE; +} diff --git a/media/libdrm/mobile1/src/parser/parser_dm.c b/media/libdrm/mobile1/src/parser/parser_dm.c new file mode 100644 index 0000000..567e650 --- /dev/null +++ b/media/libdrm/mobile1/src/parser/parser_dm.c @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <parser_dm.h> +#include <parser_dcf.h> +#include <svc_drm.h> +#include "log.h" + +#define DRM_SKIP_SPACE_TAB(p) while( (*(p) == ' ') || (*(p) == '\t') ) \ + p++ + +typedef enum _DM_PARSE_STATUS { + DM_PARSE_START, + DM_PARSING_RIGHTS, + DM_PARSING_CONTENT, + DM_PARSE_END +} DM_PARSE_STATUS; + +static int drm_strnicmp(const uint8_t* s1, const uint8_t* s2, int32_t n) +{ + if (n < 0 || NULL == s1 || NULL == s2) + return -1; + + if (n == 0) + return 0; + + while (n-- != 0 && tolower(*s1) == tolower(*s2)) + { + if (n == 0 || *s1 == '\0' || *s2 == '\0') + break; + s1++; + s2++; + } + + return tolower(*s1) - tolower(*s2); +} + +const uint8_t * drm_strnstr(const uint8_t * str, const uint8_t * strSearch, int32_t len) +{ + int32_t i, stringLen; + + if (NULL == str || NULL == strSearch || len <= 0) + return NULL; + + stringLen = strlen((char *)strSearch); + for (i = 0; i < len - stringLen + 1; i++) { + if (str[i] == *strSearch && 0 == memcmp(str + i, strSearch, stringLen)) + return str + i; + } + return NULL; +} + +/* See parser_dm.h */ +int32_t drm_parseDM(const uint8_t *buffer, int32_t bufferLen, T_DRM_DM_Info *pDmInfo) +{ + const uint8_t *pStart = NULL, *pEnd = NULL; + const uint8_t *pBufferEnd; + int32_t contentLen, leftLen; + DM_PARSE_STATUS status = DM_PARSE_START; + int32_t boundaryLen; + + if (NULL == buffer || bufferLen <= 0 || NULL == pDmInfo) + return FALSE; + + /* Find the end of the input buffer */ + pBufferEnd = buffer + bufferLen; + leftLen = bufferLen; + + /* Find out the boundary */ + pStart = drm_strnstr(buffer, (uint8_t *)"--", bufferLen); + if (NULL == pStart) + return FALSE; /* No boundary error */ + pEnd = pStart; + + /* Record the boundary */ + pEnd = drm_strnstr(pStart, (uint8_t *)DRM_NEW_LINE_CRLF, leftLen); + /* if can not find the CRLF, return FALSE */ + if (NULL == pEnd) + return FALSE; + strncpy((char *)pDmInfo->boundary, (char *)pStart, pEnd - pStart); + boundaryLen = strlen((char *)pDmInfo->boundary) + 2; /* 2 means: '\r' and '\n' */ + + pEnd += 2; /* skip the '\r' and '\n' */ + pStart = pEnd; + leftLen = pBufferEnd - pStart; + do { + pDmInfo->transferEncoding = DRM_MESSAGE_CODING_7BIT; /* According RFC2045 chapter 6.1, the default value should be 7bit.*/ + strcpy((char *)pDmInfo->contentType, "text/plain"); /* According RFC2045 chapter 5.2, the default value should be "text/plain". */ + + /* Deal the header information */ + while ((('\r' != *pStart) || ('\n' != *(pStart + 1))) && pStart < pBufferEnd) { + pEnd = drm_strnstr(pStart, (uint8_t *)DRM_NEW_LINE_CRLF, leftLen); + if (NULL == pEnd) + return FALSE; + + if (0 != pDmInfo->deliveryType) { /* This means the delivery type has been confirmed */ + if (0 == strncmp((char *)pStart, HEADERS_TRANSFER_CODING, HEADERS_TRANSFER_CODING_LEN)) { + pStart += HEADERS_TRANSFER_CODING_LEN; + DRM_SKIP_SPACE_TAB(pStart); + + if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_7BIT, pEnd - pStart)) + pDmInfo->transferEncoding = DRM_MESSAGE_CODING_7BIT; + else if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_8BIT, pEnd - pStart)) + pDmInfo->transferEncoding = DRM_MESSAGE_CODING_8BIT; + else if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_BINARY, pEnd - pStart)) + pDmInfo->transferEncoding = DRM_MESSAGE_CODING_BINARY; + else if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_BASE64, pEnd - pStart)) + pDmInfo->transferEncoding = DRM_MESSAGE_CODING_BASE64; + else + return FALSE; /* Unknown transferCoding error */ + } else if (0 == drm_strnicmp(pStart, (uint8_t *)HEADERS_CONTENT_TYPE, HEADERS_CONTENT_TYPE_LEN)) { + pStart += HEADERS_CONTENT_TYPE_LEN; + DRM_SKIP_SPACE_TAB(pStart); + + if (pEnd - pStart > 0) { + strncpy((char *)pDmInfo->contentType, (char *)pStart, pEnd - pStart); + pDmInfo->contentType[pEnd - pStart] = '\0'; + } + } else if (0 == drm_strnicmp(pStart, (uint8_t *)HEADERS_CONTENT_ID, HEADERS_CONTENT_ID_LEN)) { + uint8_t tmpBuf[MAX_CONTENT_ID] = {0}; + uint8_t *pTmp; + + pStart += HEADERS_CONTENT_ID_LEN; + DRM_SKIP_SPACE_TAB(pStart); + + /* error: more than one content id */ + if(drm_strnstr(pStart, (uint8_t*)HEADERS_CONTENT_ID, pBufferEnd - pStart)){ + LOGD("drm_dmParser: error: more than one content id\r\n"); + return FALSE; + } + + status = DM_PARSING_CONTENT; /* can go here means that the rights object has been parsed. */ + + /* Change the format from <...> to cid:... */ + if (NULL != (pTmp = (uint8_t *)memchr((char *)pStart, '<', pEnd - pStart))) { + strncpy((char *)tmpBuf, (char *)(pTmp + 1), pEnd - pTmp - 1); + + if (NULL != (pTmp = (uint8_t *)memchr((char *)tmpBuf, '>', pEnd - pTmp - 1))) { + *pTmp = '\0'; + + memset(pDmInfo->contentID, 0, MAX_CONTENT_ID); + sprintf((char *)pDmInfo->contentID, "%s%s", "cid:", (int8_t *)tmpBuf); + } + } + } + } else { /* First confirm delivery type, Forward_Lock, Combined Delivery or Separate Delivery */ + if (0 == drm_strnicmp(pStart, (uint8_t *)HEADERS_CONTENT_TYPE, HEADERS_CONTENT_TYPE_LEN)) { + pStart += HEADERS_CONTENT_TYPE_LEN; + DRM_SKIP_SPACE_TAB(pStart); + + if (pEnd - pStart > 0) { + strncpy((char *)pDmInfo->contentType, (char *)pStart, pEnd - pStart); + pDmInfo->contentType[pEnd - pStart] = '\0'; + } + + if (0 == strcmp((char *)pDmInfo->contentType, DRM_MIME_TYPE_RIGHTS_XML)) { + pDmInfo->deliveryType = COMBINED_DELIVERY; + status = DM_PARSING_RIGHTS; + } + else if (0 == strcmp((char *)pDmInfo->contentType, DRM_MIME_TYPE_CONTENT)) { + pDmInfo->deliveryType = SEPARATE_DELIVERY_FL; + status = DM_PARSING_CONTENT; + } + else if (0 == pDmInfo->deliveryType) { + pDmInfo->deliveryType = FORWARD_LOCK; + status = DM_PARSING_CONTENT; + } + } + } + pEnd += 2; /* skip the '\r' and '\n' */ + pStart = pEnd; + leftLen = pBufferEnd - pStart; + } + pStart += 2; /* skip the second CRLF: "\r\n" */ + pEnd = pStart; + + /* Deal the content part, including rel or real content */ + while (leftLen > 0) { + if (NULL == (pEnd = memchr(pEnd, '\r', leftLen))) { + pEnd = pBufferEnd; + break; /* no boundary found */ + } + + leftLen = pBufferEnd - pEnd; + if (leftLen < boundaryLen) { + pEnd = pBufferEnd; + break; /* here means may be the boundary has been split */ + } + + if (('\n' == *(pEnd + 1)) && (0 == memcmp(pEnd + 2, pDmInfo->boundary, strlen((char *)pDmInfo->boundary)))) + break; /* find the boundary here */ + + pEnd++; + leftLen--; + } + + if (pEnd >= pBufferEnd) + contentLen = DRM_UNKNOWN_DATA_LEN; + else + contentLen = pEnd - pStart; + + switch(pDmInfo->deliveryType) { + case FORWARD_LOCK: + pDmInfo->contentLen = contentLen; + pDmInfo->contentOffset = pStart - buffer; + status = DM_PARSE_END; + break; + case COMBINED_DELIVERY: + if (DM_PARSING_RIGHTS == status) { + pDmInfo->rightsLen = contentLen; + pDmInfo->rightsOffset = pStart - buffer; + } else { + pDmInfo->contentLen = contentLen; + pDmInfo->contentOffset = pStart - buffer; + status = DM_PARSE_END; + } + break; + case SEPARATE_DELIVERY_FL: + { + T_DRM_DCF_Info dcfInfo; + uint8_t* pEncData = NULL; + + memset(&dcfInfo, 0, sizeof(T_DRM_DCF_Info)); + if (DRM_UNKNOWN_DATA_LEN == contentLen) + contentLen = pEnd - pStart; + if (FALSE == drm_dcfParser(pStart, contentLen, &dcfInfo, &pEncData)) + return FALSE; + + pDmInfo->contentLen = dcfInfo.EncryptedDataLen; + pDmInfo->contentOffset = pEncData - buffer; + strcpy((char *)pDmInfo->contentType, (char *)dcfInfo.ContentType); + strcpy((char *)pDmInfo->contentID, (char *)dcfInfo.ContentURI); + strcpy((char *)pDmInfo->rightsIssuer, (char *)dcfInfo.Rights_Issuer); + status = DM_PARSE_END; + } + break; + default: + return FALSE; + } + + if (DM_PARSING_RIGHTS == status) { + /* Here means the rights object data has been completed, boundary must exist */ + leftLen = pBufferEnd - pEnd; + pStart = drm_strnstr(pEnd, pDmInfo->boundary, leftLen); + if (NULL == pStart) + return FALSE; + leftLen = pBufferEnd - pStart; + pEnd = drm_strnstr(pStart, (uint8_t *)DRM_NEW_LINE_CRLF, leftLen); + if (NULL == pEnd) + return FALSE; /* only rights object, no media object, error */ + + pEnd += 2; /* skip the "\r\n" */ + pStart = pEnd; + } + } while (DM_PARSE_END != status); + + return TRUE; +} diff --git a/media/libdrm/mobile1/src/parser/parser_rel.c b/media/libdrm/mobile1/src/parser/parser_rel.c new file mode 100644 index 0000000..537fa9c --- /dev/null +++ b/media/libdrm/mobile1/src/parser/parser_rel.c @@ -0,0 +1,663 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <parser_rel.h> +#include <parser_dm.h> +#include <xml_tinyParser.h> +#include <wbxml_tinyparser.h> +#include <drm_decoder.h> +#include <svc_drm.h> + +/* See parser_rel.h */ +int32_t drm_monthDays(int32_t year, int32_t month) +{ + switch (month) { + case 1: + case 3: + case 5: + case 7: + case 8: + case 10: + case 12: + return 31; + case 4: + case 6: + case 9: + case 11: + return 30; + case 2: + if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) + return 29; + else + return 28; + default: + return -1; + } +} + +int32_t drm_checkDate(int32_t year, int32_t month, int32_t day, + int32_t hour, int32_t min, int32_t sec) +{ + if (month >= 1 && month <= 12 && + day >= 1 && day <= drm_monthDays(year, month) && + hour >= 0 && hour <= 23 && + min >= 0 && min <= 59 && sec >= 0 && sec <= 59) + return 0; + else + return -1; +} + +static int32_t drm_getStartEndTime(uint8_t * pValue, int32_t valueLen, + T_DRM_DATETIME * dateTime) +{ + int32_t year, mon, day, hour, min, sec; + uint8_t pTmp[64] = {0}; + + strncpy((char *)pTmp, (char *)pValue, valueLen); + { + uint8_t * pHead = pTmp; + uint8_t * pEnd = NULL; + uint8_t tmpByte; + + /** get year */ + pEnd = (uint8_t *)strstr((char *)pHead, "-"); + if(NULL == pEnd) + return FALSE; + tmpByte = *pEnd; + *pEnd = '\0'; + year = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpByte; + + /** get month */ + pEnd = (uint8_t *)strstr((char *)pHead, "-"); + if(NULL == pEnd) + return FALSE; + tmpByte = *pEnd; + *pEnd = '\0'; + mon = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpByte; + + /** get day */ + pEnd = (uint8_t *)strstr((char *)pHead, "T"); + if(NULL == pEnd) + return FALSE; + tmpByte = *pEnd; + *pEnd = '\0'; + day = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpByte; + + /** get hour */ + pEnd = (uint8_t *)strstr((char *)pHead, ":"); + if(NULL == pEnd) + return FALSE; + tmpByte = *pEnd; + *pEnd = '\0'; + hour = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpByte; + + /** get minute */ + pEnd = (uint8_t *)strstr((char *)pHead, ":"); + if(NULL == pEnd) + return FALSE; + tmpByte = *pEnd; + *pEnd = '\0'; + min = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpByte; + + /** get second */ + sec = atoi((char *)pHead); + } + if (0 != drm_checkDate(year, mon, day, hour, min, sec)) + return FALSE; + + YMD_HMS_2_INT(year, mon, day, dateTime->date, hour, min, sec, + dateTime->time); + return TRUE; +} + +static int32_t drm_checkWhetherHasUnknowConstraint(uint8_t* drm_constrain) +{ + char* begin_constrain = "<o-ex:constraint>"; + char* end_constrain = "</o-ex:constraint>"; + char* constrain_begin = strstr((char*)drm_constrain,begin_constrain); + char* constrain_end = strstr((char*)drm_constrain,end_constrain); + uint32_t constrain_len = 0; + + if(NULL == constrain_begin) + return FALSE; + + if(NULL == constrain_end) + return TRUE; + + /* compute valid characters length */ + { + uint32_t constrain_begin_len = strlen(begin_constrain); + char* cur_pos = constrain_begin + constrain_begin_len; + + constrain_len = (constrain_end - constrain_begin) - constrain_begin_len; + + while(cur_pos < constrain_end){ + if(isspace(*cur_pos)) + constrain_len--; + + cur_pos++; + } + } + + /* check all constraints */ + { + #define DRM_ALL_CONSTRAINT_COUNT 5 + + int32_t i = 0; + int32_t has_datetime = FALSE; + int32_t has_start_or_end = FALSE; + + char* all_vaild_constraints[DRM_ALL_CONSTRAINT_COUNT][2] = { + {"<o-dd:count>","</o-dd:count>"}, + {"<o-dd:interval>","</o-dd:interval>"}, + {"<o-dd:datetime>","</o-dd:datetime>"}, + {"<o-dd:start>","</o-dd:start>"}, + {"<o-dd:end>","</o-dd:end>"} + }; + + for(i = 0; i < DRM_ALL_CONSTRAINT_COUNT; i++){ + char*start = strstr((char*)drm_constrain,all_vaild_constraints[i][0]); + + if(start && (start < constrain_end)){ + char* end = strstr((char*)drm_constrain,all_vaild_constraints[i][1]); + + if(end && (end < constrain_end)){ + if(0 == strncmp(all_vaild_constraints[i][0],"<o-dd:datetime>",strlen("<o-dd:datetime>"))){ + constrain_len -= strlen(all_vaild_constraints[i][0]); + constrain_len -= strlen(all_vaild_constraints[i][1]); + + if(0 == constrain_len) + return TRUE; + + has_datetime = TRUE; + continue; + } + + if((0 == strncmp(all_vaild_constraints[i][0],"<o-dd:start>",strlen("<o-dd:start>"))) + || (0 == strncmp(all_vaild_constraints[i][0],"<o-dd:end>",strlen("<o-dd:end>")))){ + if(FALSE == has_datetime) + return TRUE; + else + has_start_or_end = TRUE; + } + + constrain_len -= (end - start); + constrain_len -= strlen(all_vaild_constraints[i][1]); + + if(0 == constrain_len) + if(has_datetime != has_start_or_end) + return TRUE; + else + return FALSE; + } + else + return TRUE; + } + } + + if(has_datetime != has_start_or_end) + return TRUE; + + if(constrain_len) + return TRUE; + else + return FALSE; + } +} + +static int32_t drm_getRightValue(uint8_t * buffer, int32_t bufferLen, + T_DRM_Rights * ro, uint8_t * operation, + uint8_t oper_char) +{ + uint8_t *pBuf, *pValue; + uint8_t sProperty[256]; + int32_t valueLen; + int32_t year, mon, day, hour, min, sec; + T_DRM_Rights_Constraint *pConstraint; + int32_t *bIsAble; + uint8_t *ret = NULL; + int32_t flag = 0; + + if (operation == NULL) { + switch (oper_char) { + case REL_TAG_PLAY: + pConstraint = &(ro->PlayConstraint); + bIsAble = &(ro->bIsPlayable); + break; + case REL_TAG_DISPLAY: + pConstraint = &(ro->DisplayConstraint); + bIsAble = &(ro->bIsDisplayable); + break; + case REL_TAG_EXECUTE: + pConstraint = &(ro->ExecuteConstraint); + bIsAble = &(ro->bIsExecuteable); + break; + case REL_TAG_PRINT: + pConstraint = &(ro->PrintConstraint); + bIsAble = &(ro->bIsPrintable); + break; + default: + return FALSE; /* The input parm is err */ + } + } else { + if (strcmp((char *)operation, "play") == 0) { + pConstraint = &(ro->PlayConstraint); + bIsAble = &(ro->bIsPlayable); + } else if (strcmp((char *)operation, "display") == 0) { + pConstraint = &(ro->DisplayConstraint); + bIsAble = &(ro->bIsDisplayable); + } else if (strcmp((char *)operation, "execute") == 0) { + pConstraint = &(ro->ExecuteConstraint); + bIsAble = &(ro->bIsExecuteable); + } else if (strcmp((char *)operation, "print") == 0) { + pConstraint = &(ro->PrintConstraint); + bIsAble = &(ro->bIsPrintable); + } else + return FALSE; /* The input parm is err */ + } + + if (operation == NULL) { + sprintf((char *)sProperty, "%c%c%c%c", REL_TAG_RIGHTS, + REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char); + ret = WBXML_DOM_getNode(buffer, bufferLen, sProperty); + } else { + sprintf((char *)sProperty, + "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s", + operation); + ret = XML_DOM_getNode(buffer, sProperty); + } + CHECK_VALIDITY(ret); + if (NULL == ret) + return TRUE; + WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_NO_CONSTRAINT); /* If exit first assume have utter rights */ + flag = 1; + + if (operation == NULL) { /* If father element node is not exit then return */ + sprintf((char *)sProperty, "%c%c%c%c%c", REL_TAG_RIGHTS, + REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char, + REL_TAG_CONSTRAINT); + ret = WBXML_DOM_getNode(buffer, bufferLen, sProperty); + } else { + sprintf((char *)sProperty, + "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint", + operation); + ret = XML_DOM_getNode(buffer, sProperty); + } + + CHECK_VALIDITY(ret); + if (ret == NULL) + return TRUE; + + if(TRUE == drm_checkWhetherHasUnknowConstraint(ret)) + return FALSE; + + *bIsAble = 0; + pConstraint->Indicator = DRM_NO_PERMISSION; /* If exit constraint assume have no rights */ + flag = 2; + + if (operation == NULL) { + sprintf((char *)sProperty, "%c%c%c%c%c%c", REL_TAG_RIGHTS, + REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char, + REL_TAG_CONSTRAINT, REL_TAG_INTERVAL); + pBuf = + WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue, + &valueLen); + } else { + sprintf((char *)sProperty, + "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint\\o-dd:interval", + operation); + pBuf = XML_DOM_getNodeValue(buffer, sProperty, &pValue, &valueLen); + } + CHECK_VALIDITY(pBuf); + if (pBuf) { /* If interval element exit then get the value */ + uint8_t pTmp[64] = {0}; + + strncpy((char *)pTmp, (char *)pValue, valueLen); + { + uint8_t * pHead = pTmp + 1; + uint8_t * pEnd = NULL; + uint8_t tmpChar; + + /** get year */ + pEnd = (uint8_t *)strstr((char *)pHead, "Y"); + if(NULL == pEnd) + return FALSE; + tmpChar = *pEnd; + *pEnd = '\0'; + year = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpChar; + + /** get month */ + pEnd = (uint8_t *)strstr((char *)pHead, "M"); + if(NULL == pEnd) + return FALSE; + tmpChar = *pEnd; + *pEnd = '\0'; + mon = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpChar; + + /** get day */ + pEnd = (uint8_t *)strstr((char *)pHead, "D"); + if(NULL == pEnd) + return FALSE; + tmpChar = *pEnd; + *pEnd = '\0'; + day = atoi((char *)pHead); + pHead = pEnd + 2; + *pEnd = tmpChar; + + /** get hour */ + pEnd = (uint8_t *)strstr((char *)pHead, "H"); + if(NULL == pEnd) + return FALSE; + tmpChar = *pEnd; + *pEnd = '\0'; + hour = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpChar; + + /** get minute */ + pEnd = (uint8_t *)strstr((char *)pHead, "M"); + if(NULL == pEnd) + return FALSE; + tmpChar = *pEnd; + *pEnd = '\0'; + min = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpChar; + + /** get second */ + pEnd = (uint8_t *)strstr((char *)pHead, "S"); + if(NULL == pEnd) + return FALSE; + tmpChar = *pEnd; + *pEnd = '\0'; + sec = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpChar; + } + + if (year < 0 || mon < 0 || day < 0 || hour < 0 + || min < 0 || sec < 0) + return FALSE; + YMD_HMS_2_INT(year, mon, day, pConstraint->Interval.date, hour, + min, sec, pConstraint->Interval.time); + WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, + DRM_INTERVAL_CONSTRAINT); + flag = 3; + } + + if (operation == NULL) { + sprintf((char *)sProperty, "%c%c%c%c%c%c", REL_TAG_RIGHTS, + REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char, + REL_TAG_CONSTRAINT, REL_TAG_COUNT); + pBuf = + WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue, + &valueLen); + } else { + sprintf((char *)sProperty, + "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint\\o-dd:count", + operation); + pBuf = XML_DOM_getNodeValue(buffer, sProperty, &pValue, &valueLen); + } + CHECK_VALIDITY(pBuf); + if (pBuf) { /* If count element exit the get the value */ + uint8_t pTmp[16] = {0}; + int32_t i; + + for (i = 0; i < valueLen; i++) { /* Check the count format */ + if (0 == isdigit(*(pValue + i))) + return FALSE; + } + + strncpy((char *)pTmp, (char *)pValue, valueLen); + pConstraint->Count = atoi((char *)pTmp); + + if(0 == pConstraint->Count) + { + WRITE_RO_FLAG(*bIsAble, 0, pConstraint->Indicator, DRM_NO_PERMISSION); + } + else if( pConstraint->Count > 0) + { + WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_COUNT_CONSTRAINT); + } + else /* < 0 */ + { + return FALSE; + } + + flag = 3; + } + + if (operation == NULL) { + sprintf((char *)sProperty, "%c%c%c%c%c%c%c", REL_TAG_RIGHTS, + REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char, + REL_TAG_CONSTRAINT, REL_TAG_DATETIME, REL_TAG_START); + pBuf = + WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue, + &valueLen); + } else { + sprintf((char *)sProperty, + "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint\\o-dd:datetime\\o-dd:start", + operation); + pBuf = XML_DOM_getNodeValue(buffer, sProperty, &pValue, &valueLen); + } + CHECK_VALIDITY(pBuf); + if (pBuf) { /* If start element exit then get the value */ + if (FALSE == + drm_getStartEndTime(pValue, valueLen, &pConstraint->StartTime)) + return FALSE; + WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_START_TIME_CONSTRAINT); + flag = 3; + } + + if (operation == NULL) { + sprintf((char *)sProperty, "%c%c%c%c%c%c%c", REL_TAG_RIGHTS, + REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char, + REL_TAG_CONSTRAINT, REL_TAG_DATETIME, REL_TAG_END); + pBuf = + WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue, + &valueLen); + } else { + sprintf((char *)sProperty, + "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint\\o-dd:datetime\\o-dd:end", + operation); + pBuf = XML_DOM_getNodeValue(buffer, sProperty, &pValue, &valueLen); + } + CHECK_VALIDITY(pBuf); + if (pBuf) { + if (FALSE == + drm_getStartEndTime(pValue, valueLen, &pConstraint->EndTime)) + return FALSE; + WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_END_TIME_CONSTRAINT); + flag = 3; + } + + if (2 == flag) + WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_NO_CONSTRAINT); /* If exit first assume have utter rights */ + return TRUE; +} + +/* See parser_rel.h */ +int32_t drm_relParser(uint8_t* buffer, int32_t bufferLen, int32_t Format, T_DRM_Rights* pRights) +{ + uint8_t *pBuf, *pValue; + uint8_t sProperty[256]; + int32_t valueLen; + + if (TYPE_DRM_RIGHTS_WBXML != Format && TYPE_DRM_RIGHTS_XML != Format) /* It is not the support parse format */ + return FALSE; + + if (TYPE_DRM_RIGHTS_XML == Format) { + /* Check whether it is a CD, and parse it using TYPE_DRM_RIGHTS_XML */ + if (NULL != drm_strnstr(buffer, (uint8_t *)HEADERS_CONTENT_ID, bufferLen)) + return FALSE; + + pBuf = + XML_DOM_getNodeValue(buffer, + (uint8_t *)"o-ex:rights\\o-ex:context\\o-dd:version", + &pValue, &valueLen); + CHECK_VALIDITY(pBuf); + + if (pBuf) { + if (valueLen > 8) /* Check version lenth */ + return FALSE; + + /* error version */ + if(strncmp(pValue,"1.0",valueLen)) + return FALSE; + + strncpy((char *)pRights->Version, (char *)pValue, valueLen); + } else + return FALSE; + + /* this means there is more than one version label in rights */ + if(strstr((char*)pBuf, "<o-dd:version>")) + return FALSE; + + pBuf = + XML_DOM_getNodeValue(buffer, + (uint8_t *)"o-ex:rights\\o-ex:agreement\\o-ex:asset\\ds:KeyInfo\\ds:KeyValue", + &pValue, &valueLen); + CHECK_VALIDITY(pBuf); + if (pBuf) { /* Get keyvalue */ + int32_t keyLen; + + if (24 != valueLen) + return FALSE; + + keyLen = drm_decodeBase64(NULL, 0, pValue, &valueLen); + if (keyLen < 0) + return FALSE; + + if (DRM_KEY_LEN != drm_decodeBase64(pRights->KeyValue, keyLen, pValue, &valueLen)) + return FALSE; + } + + pBuf = + XML_DOM_getNodeValue(buffer, + (uint8_t *)"o-ex:rights\\o-ex:agreement\\o-ex:asset\\o-ex:context\\o-dd:uid", + &pValue, &valueLen); + CHECK_VALIDITY(pBuf); + if (pBuf) { + if (valueLen > DRM_UID_LEN) + return FALSE; + strncpy((char *)pRights->uid, (char *)pValue, valueLen); + pRights->uid[valueLen] = '\0'; + } else + return FALSE; + + /* this means there is more than one uid label in rights */ + if(strstr((char*)pBuf, "<o-dd:uid>")) + return FALSE; + + if (FALSE == + drm_getRightValue(buffer, bufferLen, pRights, (uint8_t *)"play", 0)) + return FALSE; + + if (FALSE == + drm_getRightValue(buffer, bufferLen, pRights, (uint8_t *)"display", 0)) + return FALSE; + + if (FALSE == + drm_getRightValue(buffer, bufferLen, pRights, (uint8_t *)"execute", 0)) + return FALSE; + + if (FALSE == + drm_getRightValue(buffer, bufferLen, pRights, (uint8_t *)"print", 0)) + return FALSE; + } else if (TYPE_DRM_RIGHTS_WBXML == Format) { + if (!REL_CHECK_WBXML_HEADER(buffer)) + return FALSE; + + sprintf((char *)sProperty, "%c%c%c", REL_TAG_RIGHTS, REL_TAG_CONTEXT, + REL_TAG_VERSION); + pBuf = + WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue, + &valueLen); + CHECK_VALIDITY(pBuf); + + if (pBuf) { + if (valueLen > 8) /* Check version lenth */ + return FALSE; + strncpy((char *)pRights->Version, (char *)pValue, valueLen); + } else + return FALSE; + + sprintf((char *)sProperty, "%c%c%c%c%c", + REL_TAG_RIGHTS, REL_TAG_AGREEMENT, REL_TAG_ASSET, + REL_TAG_KEYINFO, REL_TAG_KEYVALUE); + pBuf = + WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue, + &valueLen); + CHECK_VALIDITY(pBuf); + if (pBuf) { + if (DRM_KEY_LEN != valueLen) + return FALSE; + memcpy(pRights->KeyValue, pValue, DRM_KEY_LEN); + memset(pValue, 0, DRM_KEY_LEN); /* Clean the KeyValue */ + } + + sprintf((char *)sProperty, "%c%c%c%c%c", + REL_TAG_RIGHTS, REL_TAG_AGREEMENT, REL_TAG_ASSET, + REL_TAG_CONTEXT, REL_TAG_UID); + pBuf = + WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue, + &valueLen); + CHECK_VALIDITY(pBuf); + if (pBuf) { + if (valueLen > DRM_UID_LEN) + return FALSE; + strncpy((char *)pRights->uid, (char *)pValue, valueLen); + pRights->uid[valueLen] = '\0'; + } else + return FALSE; + + if (FALSE == + drm_getRightValue(buffer, bufferLen, pRights, NULL, + REL_TAG_PLAY)) + return FALSE; + + if (FALSE == + drm_getRightValue(buffer, bufferLen, pRights, NULL, + REL_TAG_DISPLAY)) + return FALSE; + + if (FALSE == + drm_getRightValue(buffer, bufferLen, pRights, NULL, + REL_TAG_EXECUTE)) + return FALSE; + + if (FALSE == + drm_getRightValue(buffer, bufferLen, pRights, NULL, + REL_TAG_PRINT)) + return FALSE; + } + + return TRUE; +} diff --git a/media/libdrm/mobile1/src/xml/xml_tinyparser.c b/media/libdrm/mobile1/src/xml/xml_tinyparser.c new file mode 100644 index 0000000..7580312 --- /dev/null +++ b/media/libdrm/mobile1/src/xml/xml_tinyparser.c @@ -0,0 +1,834 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <xml/xml_tinyParser.h> + +int32_t xml_errno; + +#ifdef XML_DOM_PARSER + +#define XML_IS_WHITESPACE(x) ((x) == '\t' || (x) == '\n' || (x) == ' ' || (x) == '\r') +#define XML_IS_NAMECHAR(ch) (isalpha(ch) || isdigit(ch) || ch ==':' || \ + ch == '_' || ch == '-' || ch =='.') + +static uint8_t *xml_ignore_blank(uint8_t *buffer) +{ + if (NULL == buffer) + return NULL; + + while (XML_IS_WHITESPACE(*buffer)) + buffer++; + + return buffer; +} + +static uint8_t *xml_goto_tagend(uint8_t *buffer) +{ + int32_t nameLen, valueLen; + uint8_t *name, *value; + + if (NULL == buffer) + return NULL; + + /* Ignore the start-tag */ + if (*buffer == '<') { + buffer++; + while (buffer != NULL && XML_IS_NAMECHAR(*buffer)) + buffer++; + if (NULL == buffer) + return NULL; + } + + do { + if (NULL == (buffer = xml_ignore_blank(buffer))) + return NULL; + + if (*buffer == '>' || (*buffer == '/' && *(buffer + 1) == '>')) + return buffer; + + if (NULL == + XML_DOM_getAttr(buffer, &name, &nameLen, &value, &valueLen)) + return NULL; + + buffer = value + valueLen + 1; + } while (*buffer != '\0'); + + return NULL; +} + +static uint8_t *xml_match_tag(uint8_t *buffer) +{ + int32_t tagLen, tagType, bal; + + if (NULL == buffer) + return NULL; + + bal = 0; + do { + if (NULL == (buffer = XML_DOM_getTag(buffer, &tagLen, &tagType))) + return NULL; + + switch (tagType) { + case XML_TAG_SELF: + case XML_TAG_START: + if (NULL == (buffer = xml_goto_tagend(buffer + tagLen + 1))) + return NULL; + if (strncmp((char *)buffer, "/>", 2) == 0) { + buffer += 2; + } else { + bal++; + } + break; + + case XML_TAG_END: + if (bal <= 0) + return NULL; + buffer = buffer + tagLen + 2; + bal--; + break; + } + } while (bal != 0); + + return buffer; +} + +uint8_t *XML_DOM_getAttr(uint8_t *buffer, uint8_t **pName, int32_t *nameLen, + uint8_t **pValue, int32_t *valueLen) +{ + uint8_t charQuoted; + + if (NULL == buffer) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + /* Ignore the tag */ + if (*buffer == '<') { + buffer++; + /* Ignore the STag */ + while (buffer != NULL && XML_IS_NAMECHAR(*buffer)) + buffer++; + if (NULL == buffer) + return NULL; + } + + if (NULL == (buffer = xml_ignore_blank(buffer))) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + /* Name */ + *pName = buffer; + while (buffer != NULL && XML_IS_NAMECHAR(*buffer)) + buffer++; + if (NULL == buffer) { + XML_ERROR(XML_ERROR_ATTR_NAME); + return NULL; + } + *nameLen = buffer - *pName; + if (*nameLen <= 0) { + XML_ERROR(XML_ERROR_ATTR_NAME); + return NULL; + } + + /* '=' */ + buffer = xml_ignore_blank(buffer); + if (NULL == buffer || *buffer != '=') { + XML_ERROR(XML_ERROR_ATTR_MISSED_EQUAL); + return NULL; + } + + /* Value */ + buffer++; + buffer = xml_ignore_blank(buffer); + if (NULL == buffer || (*buffer != '"' && *buffer != '\'')) { + XML_ERROR(XML_ERROR_ATTR_VALUE); + return NULL; + } + charQuoted = *buffer++; + *pValue = buffer; + while (*buffer != '\0' && *buffer != charQuoted) + buffer++; + if (*buffer != charQuoted) { + XML_ERROR(XML_ERROR_ATTR_VALUE); + return NULL; + } + *valueLen = buffer - *pValue; + + XML_ERROR(XML_ERROR_OK); + + return buffer + 1; +} + +uint8_t *XML_DOM_getValue(uint8_t *buffer, uint8_t **pValue, int32_t *valueLen) +{ + uint8_t *pEnd; + + if (NULL == buffer) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + /* Ignore the STag */ + if (*buffer == '<') { + buffer++; + /* If it's an end_tag, no value should be returned */ + if (*buffer == '/') { + *valueLen = 0; + XML_ERROR(XML_ERROR_NOVALUE); + return NULL; + } + + while (buffer != NULL && XML_IS_NAMECHAR(*buffer)) + buffer++; + if (NULL == buffer) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + if (NULL == (buffer = xml_goto_tagend(buffer))) { + XML_ERROR(XML_ERROR_PROPERTY_END); + return NULL; + } + } + + /* <test/> node found */ + if (*buffer == '/') { + if (*(buffer + 1) != '>') { + XML_ERROR(XML_ERROR_PROPERTY_END); + return NULL; + } + XML_ERROR(XML_ERROR_OK); + *valueLen = 0; + return buffer; + } + + if (*buffer == '>') + buffer++; + + if (NULL == (buffer = xml_ignore_blank(buffer))) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + /* the following is a tag instead of the value */ + if (*buffer == '<') { /* nono value, such as <test></test> */ + buffer++; + if (*buffer != '/') { + XML_ERROR(XML_ERROR_ENDTAG); + return NULL; + } + *valueLen = 0; + XML_ERROR(XML_ERROR_OK); + return NULL; + } + + *pValue = buffer; + pEnd = NULL; + while (*buffer != '\0' && *buffer != '<') { + if (!XML_IS_WHITESPACE(*buffer)) + pEnd = buffer; + buffer++; + } + if (*buffer != '<' || pEnd == NULL) { + XML_ERROR(XML_ERROR_VALUE); + return NULL; + } + + *valueLen = pEnd - *pValue + 1; + + buffer++; + if (*buffer != '/') { + XML_ERROR(XML_ERROR_ENDTAG); + return NULL; + } + + XML_ERROR(XML_ERROR_OK); + + return buffer - 1; +} + +uint8_t *XML_DOM_getTag(uint8_t *buffer, int32_t *tagLen, int32_t *tagType) +{ + uint8_t *pStart; + + /* WARNING: <!-- --> comment is not supported in this verison */ + if (NULL == buffer) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + do { + while (*buffer != '<') { + if (*buffer == '\0') { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + if (*buffer == '\"' || *buffer == '\'') { + uint8_t charQuoted = *buffer; + buffer++; + while (*buffer != '\0' && *buffer != charQuoted) + buffer++; + if (*buffer == '\0') { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + } + buffer++; + } + buffer++; + } while (*buffer == '!' || *buffer == '?'); + + pStart = buffer - 1; + + if (*buffer == '/') { + buffer++; + *tagType = XML_TAG_END; + } else { + /* check here if it is self-end-tag */ + uint8_t *pCheck = xml_goto_tagend(pStart); + if (pCheck == NULL) { + XML_ERROR(XML_ERROR_PROPERTY_END); + return NULL; + } + + if (*pCheck == '>') + *tagType = XML_TAG_START; + else if (strncmp((char *)pCheck, "/>", 2) == 0) + *tagType = XML_TAG_SELF; + else { + XML_ERROR(XML_ERROR_PROPERTY_END); + return NULL; + } + } + + while (buffer != NULL && XML_IS_NAMECHAR(*buffer)) + buffer++; + if (NULL == buffer) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + if (*tagType == XML_TAG_END) + *tagLen = buffer - pStart - 2; + else + *tagLen = buffer - pStart - 1; + + XML_ERROR(XML_ERROR_OK); + + return pStart; +} + +uint8_t *XML_DOM_getNode(uint8_t *buffer, const uint8_t *const node) +{ + uint8_t *pStart; + uint8_t buf[XML_MAX_PROPERTY_LEN + 2]; + uint8_t *nodeStr = buf; + uint8_t *retPtr = NULL; + int32_t tagLen, tagType; + uint8_t *lastNode = (uint8_t *)""; + + if (NULL == buffer) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + strncpy((char *)nodeStr, (char *)node, XML_MAX_PROPERTY_LEN); + strcat((char *)nodeStr, "\\"); + pStart = (uint8_t *)strchr((char *)nodeStr, '\\'); + + while (pStart != NULL) { + *pStart = '\0'; + + /* get the first start_tag from buffer */ + if (NULL == (buffer = XML_DOM_getTag(buffer, &tagLen, &tagType))) { + XML_ERROR(XML_ERROR_NO_SUCH_NODE); + return NULL; + } + + if (tagType == XML_TAG_END) { + if (0 == + strncmp((char *)lastNode, (char *)(buffer + 2), strlen((char *)lastNode))) + XML_ERROR(XML_ERROR_NO_SUCH_NODE); + else + XML_ERROR(XML_ERROR_NO_START_TAG); + return NULL; + } + + /* wrong node, contiue to fetch the next node */ + if ((int32_t) strlen((char *)nodeStr) != tagLen + || strncmp((char *)nodeStr, (char *)(buffer + 1), tagLen) != 0) { + /* we should ignore all the middle code */ + buffer = xml_match_tag(buffer); + continue; + } + + retPtr = buffer; /* retPtr starts with '<xxx>' */ + buffer += (tagLen + 1); + + if (tagType == XML_TAG_SELF) { + nodeStr = pStart + 1; + break; + } + + lastNode = nodeStr; + nodeStr = pStart + 1; + pStart = (uint8_t *)strchr((char *)nodeStr, '\\'); + } + + /* Check 5: nodeStr should be empty here */ + if (*nodeStr != '\0') { + XML_ERROR(XML_ERROR_NO_SUCH_NODE); + return NULL; + } + + XML_ERROR(XML_ERROR_OK); + + return retPtr; +} + +uint8_t *XML_DOM_getNodeValue(uint8_t *buffer, uint8_t *node, + uint8_t **value, int32_t *valueLen) +{ + uint8_t *pStart; + uint8_t *lastTag; + + if (NULL == node || NULL == buffer) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + lastTag = node + strlen((char *)node) - 1; + while (lastTag >= node && *lastTag != '\\') + lastTag--; + lastTag++; + + if (NULL == (pStart = XML_DOM_getNode(buffer, node))) + return NULL; + + pStart += (strlen((char *)lastTag) + 1); + + if (NULL == (pStart = xml_goto_tagend(pStart))) { + XML_ERROR(XML_ERROR_PROPERTY_END); + return NULL; + } + + if (NULL == (pStart = XML_DOM_getValue(pStart, value, valueLen))) + return NULL; + + /* Check the end tag */ +#ifdef XML_DOM_CHECK_ENDTAG + if (strncmp((char *)pStart, "/>", 2) == 0) { + + } else if (strncmp((char *)lastTag, (char *)(pStart + 2), strlen((char *)lastTag)) != + 0) { + XML_ERROR(XML_ERROR_ENDTAG); + return NULL; + } +#endif + + XML_ERROR(XML_ERROR_OK); + + return *value; +} + +uint8_t *XML_DOM_getNextNode(uint8_t *buffer, uint8_t **pNodeName, int32_t *nodenameLen) +{ + int32_t tagType; + + if (NULL == buffer) + return NULL; + + do { + if (NULL == + (buffer = XML_DOM_getTag(buffer + 1, nodenameLen, &tagType))) { + XML_ERROR(XML_ERROR_NO_SUCH_NODE); + return NULL; + } + } while (tagType == XML_TAG_END); + + *pNodeName = buffer + 1; + + XML_ERROR(XML_ERROR_OK); + + return buffer; +} + +#endif /* XML_DOM_PARSER */ + +#ifdef WBXML_DOM_PARSER + +#ifdef WBXML_OLD_VERSION +uint8_t *WBXML_DOM_getNode(uint8_t *buffer, int32_t bufferLen, + uint8_t *node) +{ + int32_t i = 0, j = 0; + + if (NULL == buffer || node == NULL) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + while (i < bufferLen) { + if (WBXML_GET_TAG(buffer[i]) == WBXML_GET_TAG(node[j])) { + j++; + if (node[j] == '\0') + break; + + /* Check if there is the content(it should have content) */ + if (!WBXML_HAS_CONTENT(buffer[i])) { + /*XML_ERROR(WBXML_ERROR_MISSED_CONTENT); */ + XML_ERROR(XML_ERROR_NO_SUCH_NODE); + return NULL; + } + + /* Ignore the attrib filed */ + if (WBXML_HAS_ATTR(buffer[i])) { + while (i < bufferLen && buffer[i] != WBXML_ATTR_END) + i++; + if (i >= bufferLen) + break; + } + } + i++; + + /* Ignore the content filed */ + if (buffer[i] == WBXML_STR_I) { + while (i < bufferLen && buffer[i] != WBXML_END) + i++; + if (i >= bufferLen) + break; + i++; + } + } + + if (i >= bufferLen) { + XML_ERROR(XML_ERROR_NO_SUCH_NODE); + return NULL; + } + + XML_ERROR(XML_ERROR_OK); + + return buffer + i + 1; +} + +uint8_t *WBXML_DOM_getNodeValue(uint8_t *buffer, int32_t bufferLen, + uint8_t *node, + uint8_t **value, int32_t *valueLen) +{ + int32_t i; + uint8_t *pEnd; + + *value = NULL; + *valueLen = 0; + + pEnd = buffer + bufferLen; + buffer = WBXML_DOM_getNode(buffer, bufferLen, node); + if (NULL == buffer) { + XML_ERROR(XML_ERROR_NO_SUCH_NODE); + return NULL; + } + + if (*buffer == WBXML_OPAUE) { + buffer++; + *valueLen = WBXML_GetUintVar(buffer, &i); + if (*valueLen < 0) { + XML_ERROR(WBXML_ERROR_MBUINT32); + return NULL; + } + buffer += i; + *value = buffer; + return *value; + } + + if (*buffer != WBXML_STR_I) { + XML_ERROR(WBXML_ERROR_MISSED_STARTTAG); + return NULL; + } + + buffer++; + + i = 0; + while ((buffer + i) < pEnd && buffer[i] != WBXML_END) + i++; + + if (buffer[i] != WBXML_END) { + XML_ERROR(WBXML_ERROR_MISSED_ENDTAG); + return NULL; + } + + *value = buffer; + *valueLen = i; + XML_ERROR(XML_ERROR_OK); + + return *value; +} +#endif /* WBXML_OLD_VERSION */ + +#define MAX_UINT_VAR_BYTE 4 +#define UINTVAR_INVALID -1 +int32_t WBXML_GetUintVar(const uint8_t *const buffer, int32_t *len) +{ + int32_t i, byteLen; + int32_t sum; + + byteLen = 0; + while ((buffer[byteLen] & 0x80) > 0 && byteLen < MAX_UINT_VAR_BYTE) + byteLen++; + + if (byteLen > MAX_UINT_VAR_BYTE) + return UINTVAR_INVALID; + + *len = byteLen + 1; + sum = buffer[byteLen]; + for (i = byteLen - 1; i >= 0; i--) + sum += ((buffer[i] & 0x7F) << 7 * (byteLen - i)); + + return sum; +} + +XML_BOOL WBXML_DOM_Init(WBXML * pWbxml, uint8_t *buffer, + int32_t bufferLen) +{ + int32_t num, len; + + pWbxml->End = buffer + bufferLen; + pWbxml->version = *buffer++; + if (UINTVAR_INVALID == (num = WBXML_GetUintVar(buffer, &len))) + return XML_FALSE; + buffer += len; + pWbxml->publicid = num; + if (UINTVAR_INVALID == (num = WBXML_GetUintVar(buffer, &len))) + return XML_FALSE; + buffer += len; + pWbxml->charset = num; + if (UINTVAR_INVALID == (num = WBXML_GetUintVar(buffer, &len))) + return XML_FALSE; + buffer += len; + pWbxml->strTable = buffer; + pWbxml->strTableLen = num; + buffer += num; + pWbxml->curPtr = pWbxml->Content = buffer; + pWbxml->depth = 0; + + return XML_TRUE; +} + +void WBXML_DOM_Rewind(WBXML * pWbxml) +{ + pWbxml->curPtr = pWbxml->Content; +} + +XML_BOOL WBXML_DOM_Eof(WBXML * pWbxml) +{ + if (pWbxml->curPtr > pWbxml->End) + return XML_TRUE; + + return XML_FALSE; +} + +uint8_t WBXML_DOM_GetTag(WBXML * pWbxml) +{ + uint8_t tagChar; + + if (pWbxml->curPtr > pWbxml->End) + return XML_EOF; + + tagChar = *pWbxml->curPtr; + pWbxml->curPtr++; + + if (WBXML_GET_TAG(tagChar) == WBXML_CONTENT_END) + pWbxml->depth--; + else + pWbxml->depth++; + + return tagChar; +} + +uint8_t WBXML_DOM_GetChar(WBXML * pWbxml) +{ + return *pWbxml->curPtr++; +} + +void WBXML_DOM_Seek(WBXML * pWbxml, int32_t offset) +{ + pWbxml->curPtr += offset; +} + +uint8_t WBXML_DOM_GetUIntVar(WBXML * pWbxml) +{ + int32_t num, len; + + num = WBXML_GetUintVar(pWbxml->curPtr, &len); + pWbxml->curPtr += len; + + return (uint8_t)num; +} + +#ifdef XML_TREE_STRUCTURE + +#ifdef DEBUG_MODE +static int32_t malloc_times = 0; +static int32_t free_times = 0; +void XML_PrintMallocInfo() +{ + printf("====XML_PrintMallocInfo====\n"); + printf(" Total malloc times:%d\n", malloc_times); + printf(" Total free times:%d\n", free_times); + printf("===========================\n"); +} +#endif + +void *xml_malloc(int32_t size) +{ +#ifdef DEBUG_MODE + malloc_times++; +#endif + return malloc(size); +} + +void xml_free(void *buffer) +{ +#ifdef DEBUG_MODE + free_times++; +#endif + free(buffer); +} + +XML_TREE *xml_tree_fillnode(uint8_t **buf, int32_t tagLen) +{ + XML_TREE *Tree; + uint8_t *pAttr, *pName, *pValue; + int32_t nameLen, valueLen; + uint8_t *buffer = *buf; + + if (NULL == (Tree = (XML_TREE *) xml_malloc(sizeof(XML_TREE)))) + return NULL; + memset(Tree, 0, sizeof(XML_TREE)); + + strncpy((char *)Tree->tag, (char *)++buffer, tagLen); + buffer += tagLen; + pAttr = buffer; + + /* attribute */ + while (NULL != + (pAttr = + XML_DOM_getAttr(pAttr, &pName, &nameLen, &pValue, + &valueLen))) { + XML_TREE_ATTR *attr; + if (NULL == + (attr = (XML_TREE_ATTR *) xml_malloc(sizeof(XML_TREE_ATTR)))) + return NULL; + memset(attr, 0, sizeof(XML_TREE_ATTR)); + strncpy((char *)attr->name, (char *)pName, nameLen); + strncpy((char *)attr->value, (char *)pValue, valueLen); + buffer = pValue + valueLen + 1; + + if (NULL != Tree->attr) // no attribute now + Tree->last_attr->next = attr; + else + Tree->attr = attr; + Tree->last_attr = attr; + } + + /* value */ + pAttr = XML_DOM_getValue(buffer, &pValue, &valueLen); + if (pAttr != NULL && valueLen > 0) { + strncpy((char *)Tree->value, (char *)pValue, valueLen); + buffer = pValue + valueLen; + } + + *buf = buffer; + return Tree; +} + +XML_TREE *XML_makeTree(uint8_t **buf) +{ + uint8_t *pBuf; + int32_t valueLen, tagType; + uint8_t *buffer = *buf; + XML_TREE *TreeHead = NULL; + + if (NULL == (buffer = XML_DOM_getTag(buffer, &valueLen, &tagType))) + return NULL; + if (XML_TAG_END == tagType) + return NULL; + if (NULL == (TreeHead = xml_tree_fillnode(&buffer, valueLen))) + return NULL; + if (XML_TAG_SELF == tagType) { + *buf = buffer; + return TreeHead; + } + + do { + if (NULL == (pBuf = XML_DOM_getTag(buffer, &valueLen, &tagType))) + return NULL; + + switch (tagType) { + case XML_TAG_SELF: + case XML_TAG_START: + if (NULL == TreeHead->child) + TreeHead->child = XML_makeTree(&buffer); + else if (NULL == TreeHead->child->last_brother) { + TreeHead->child->brother = XML_makeTree(&buffer); + TreeHead->child->last_brother = TreeHead->child->brother; + } else { + TreeHead->child->last_brother->brother = + XML_makeTree(&buffer); + TreeHead->child->last_brother = + TreeHead->child->last_brother->brother; + } + break; + case XML_TAG_END: + *buf = pBuf; + return TreeHead; + } + buffer++; + } while (1); +} + +void XML_freeTree(XML_TREE * pTree) +{ + XML_TREE *p, *pNext; + XML_TREE_ATTR *pa, *lastpa; + + if (NULL == pTree) + return; + + p = pTree->brother; + while (NULL != p) { + pNext = p->brother; + p->brother = NULL; + XML_freeTree(p); + p = pNext; + } + + if (NULL != pTree->child) + XML_freeTree(pTree->child); + + pa = pTree->attr; + while (NULL != pa) { + lastpa = pa; + pa = pa->next; + xml_free(lastpa); + } + xml_free(pTree); +} + +#endif /* XML_TREE_STRUCTURE */ + +#endif /* WBXML_DOM_PARSER */ |