Home | History | Annotate | Download | only in parser
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <parser_dm.h>
     18 #include <parser_dcf.h>
     19 #include <svc_drm.h>
     20 #include "log.h"
     21 
     22 #define DRM_SKIP_SPACE_TAB(p) while( (*(p) == ' ') || (*(p) == '\t') ) \
     23                                   p++
     24 
     25 typedef enum _DM_PARSE_STATUS {
     26     DM_PARSE_START,
     27     DM_PARSING_RIGHTS,
     28     DM_PARSING_CONTENT,
     29     DM_PARSE_END
     30 } DM_PARSE_STATUS;
     31 
     32 static int drm_strnicmp(const uint8_t* s1, const uint8_t* s2, int32_t n)
     33 {
     34     if (n < 0 || NULL == s1 || NULL == s2)
     35         return -1;
     36 
     37     if (n == 0)
     38         return 0;
     39 
     40     while (n-- != 0 && tolower(*s1) == tolower(*s2))
     41     {
     42         if (n == 0 || *s1 == '\0' || *s2 == '\0')
     43             break;
     44         s1++;
     45         s2++;
     46     }
     47 
     48     return tolower(*s1) - tolower(*s2);
     49 }
     50 
     51 const uint8_t * drm_strnstr(const uint8_t * str, const uint8_t * strSearch, int32_t len)
     52 {
     53     int32_t i, stringLen;
     54 
     55     if (NULL == str || NULL == strSearch || len <= 0)
     56         return NULL;
     57 
     58     stringLen = strlen((char *)strSearch);
     59     for (i = 0; i < len - stringLen + 1; i++) {
     60         if (str[i] == *strSearch && 0 == memcmp(str + i, strSearch, stringLen))
     61             return str + i;
     62     }
     63     return NULL;
     64 }
     65 
     66 /* See parser_dm.h */
     67 int32_t drm_parseDM(const uint8_t *buffer, int32_t bufferLen, T_DRM_DM_Info *pDmInfo)
     68 {
     69     const uint8_t *pStart = NULL, *pEnd = NULL;
     70     const uint8_t *pBufferEnd;
     71     int32_t contentLen, leftLen;
     72     DM_PARSE_STATUS status = DM_PARSE_START;
     73     int32_t boundaryLen;
     74 
     75     if (NULL == buffer || bufferLen <= 0 || NULL == pDmInfo)
     76         return FALSE;
     77 
     78     /* Find the end of the input buffer */
     79     pBufferEnd = buffer + bufferLen;
     80     leftLen = bufferLen;
     81 
     82     /* Find out the boundary */
     83     pStart = drm_strnstr(buffer, (uint8_t *)"--", bufferLen);
     84     if (NULL == pStart)
     85         return FALSE; /* No boundary error */
     86     pEnd = pStart;
     87 
     88     /* Record the boundary */
     89     pEnd = drm_strnstr(pStart, (uint8_t *)DRM_NEW_LINE_CRLF, leftLen);
     90     /* if can not find the CRLF, return FALSE */
     91     if (NULL == pEnd)
     92         return FALSE;
     93     strncpy((char *)pDmInfo->boundary, (char *)pStart, pEnd - pStart);
     94     boundaryLen = strlen((char *)pDmInfo->boundary) + 2; /* 2 means: '\r' and '\n' */
     95 
     96     pEnd += 2; /* skip the '\r' and '\n' */
     97     pStart = pEnd;
     98     leftLen = pBufferEnd - pStart;
     99     do {
    100         pDmInfo->transferEncoding = DRM_MESSAGE_CODING_7BIT; /* According RFC2045 chapter 6.1, the default value should be 7bit.*/
    101         strcpy((char *)pDmInfo->contentType, "text/plain");  /* According RFC2045 chapter 5.2, the default value should be "text/plain". */
    102 
    103         /* Deal the header information */
    104         while ((('\r' != *pStart) || ('\n' != *(pStart + 1))) && pStart < pBufferEnd) {
    105             pEnd = drm_strnstr(pStart, (uint8_t *)DRM_NEW_LINE_CRLF, leftLen);
    106             if (NULL == pEnd)
    107                 return FALSE;
    108 
    109             if (0 != pDmInfo->deliveryType) { /* This means the delivery type has been confirmed */
    110                 if (0 == strncmp((char *)pStart, HEADERS_TRANSFER_CODING, HEADERS_TRANSFER_CODING_LEN)) {
    111                     pStart += HEADERS_TRANSFER_CODING_LEN;
    112                     DRM_SKIP_SPACE_TAB(pStart);
    113 
    114                     if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_7BIT, pEnd - pStart))
    115                         pDmInfo->transferEncoding = DRM_MESSAGE_CODING_7BIT;
    116                     else if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_8BIT, pEnd - pStart))
    117                         pDmInfo->transferEncoding = DRM_MESSAGE_CODING_8BIT;
    118                     else if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_BINARY, pEnd - pStart))
    119                         pDmInfo->transferEncoding = DRM_MESSAGE_CODING_BINARY;
    120                     else if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_BASE64, pEnd - pStart))
    121                         pDmInfo->transferEncoding = DRM_MESSAGE_CODING_BASE64;
    122                     else
    123                         return FALSE; /* Unknown transferCoding error */
    124                 } else if (0 == drm_strnicmp(pStart, (uint8_t *)HEADERS_CONTENT_TYPE, HEADERS_CONTENT_TYPE_LEN)) {
    125                     pStart += HEADERS_CONTENT_TYPE_LEN;
    126                     DRM_SKIP_SPACE_TAB(pStart);
    127 
    128                     if (pEnd - pStart > 0) {
    129                         strncpy((char *)pDmInfo->contentType, (char *)pStart, pEnd - pStart);
    130                         pDmInfo->contentType[pEnd - pStart] = '\0';
    131                     }
    132                 } else if (0 == drm_strnicmp(pStart, (uint8_t *)HEADERS_CONTENT_ID, HEADERS_CONTENT_ID_LEN)) {
    133                     uint8_t tmpBuf[MAX_CONTENT_ID] = {0};
    134                     uint8_t *pTmp;
    135 
    136                     pStart += HEADERS_CONTENT_ID_LEN;
    137                     DRM_SKIP_SPACE_TAB(pStart);
    138 
    139                     /* error: more than one content id */
    140                     if(drm_strnstr(pStart, (uint8_t*)HEADERS_CONTENT_ID, pBufferEnd - pStart)){
    141                         LOGD("drm_dmParser: error: more than one content id\r\n");
    142                         return FALSE;
    143                     }
    144 
    145                     status = DM_PARSING_CONTENT; /* can go here means that the rights object has been parsed. */
    146 
    147                     /* Change the format from <...> to cid:... */
    148                     if (NULL != (pTmp = (uint8_t *)memchr((char *)pStart, '<', pEnd - pStart))) {
    149                         strncpy((char *)tmpBuf, (char *)(pTmp + 1), pEnd - pTmp - 1);
    150 
    151                         if (NULL != (pTmp = (uint8_t *)memchr((char *)tmpBuf, '>', pEnd - pTmp - 1))) {
    152                             *pTmp = '\0';
    153 
    154                             memset(pDmInfo->contentID, 0, MAX_CONTENT_ID);
    155                             sprintf((char *)pDmInfo->contentID, "%s%s", "cid:", (int8_t *)tmpBuf);
    156                         }
    157                     }
    158                 }
    159             } else { /* First confirm delivery type, Forward_Lock, Combined Delivery or Separate Delivery */
    160                 if (0 == drm_strnicmp(pStart, (uint8_t *)HEADERS_CONTENT_TYPE, HEADERS_CONTENT_TYPE_LEN)) {
    161                     pStart += HEADERS_CONTENT_TYPE_LEN;
    162                     DRM_SKIP_SPACE_TAB(pStart);
    163 
    164                     if (pEnd - pStart > 0) {
    165                         strncpy((char *)pDmInfo->contentType, (char *)pStart, pEnd - pStart);
    166                         pDmInfo->contentType[pEnd - pStart] = '\0';
    167                     }
    168 
    169                     if (0 == strcmp((char *)pDmInfo->contentType, DRM_MIME_TYPE_RIGHTS_XML)) {
    170                         pDmInfo->deliveryType = COMBINED_DELIVERY;
    171                         status = DM_PARSING_RIGHTS;
    172                     }
    173                     else if (0 == strcmp((char *)pDmInfo->contentType, DRM_MIME_TYPE_CONTENT)) {
    174                         pDmInfo->deliveryType = SEPARATE_DELIVERY_FL;
    175                         status = DM_PARSING_CONTENT;
    176                     }
    177                     else if (0 == pDmInfo->deliveryType) {
    178                         pDmInfo->deliveryType = FORWARD_LOCK;
    179                         status = DM_PARSING_CONTENT;
    180                     }
    181                 }
    182             }
    183             pEnd += 2; /* skip the '\r' and '\n' */
    184             pStart = pEnd;
    185             leftLen = pBufferEnd - pStart;
    186         }
    187         pStart += 2; /* skip the second CRLF: "\r\n" */
    188         pEnd = pStart;
    189 
    190         /* Deal the content part, including rel or real content */
    191         while (leftLen > 0) {
    192             if (NULL == (pEnd = memchr(pEnd, '\r', leftLen))) {
    193                 pEnd = pBufferEnd;
    194                 break; /* no boundary found */
    195             }
    196 
    197             leftLen = pBufferEnd - pEnd;
    198             if (leftLen < boundaryLen) {
    199                 pEnd = pBufferEnd;
    200                 break; /* here means may be the boundary has been split */
    201             }
    202 
    203             if (('\n' == *(pEnd + 1)) && (0 == memcmp(pEnd + 2, pDmInfo->boundary, strlen((char *)pDmInfo->boundary))))
    204                 break; /* find the boundary here */
    205 
    206             pEnd++;
    207             leftLen--;
    208         }
    209 
    210         if (pEnd >= pBufferEnd)
    211             contentLen = DRM_UNKNOWN_DATA_LEN;
    212         else
    213             contentLen = pEnd - pStart;
    214 
    215         switch(pDmInfo->deliveryType) {
    216         case FORWARD_LOCK:
    217             pDmInfo->contentLen = contentLen;
    218             pDmInfo->contentOffset = pStart - buffer;
    219             status = DM_PARSE_END;
    220             break;
    221         case COMBINED_DELIVERY:
    222             if (DM_PARSING_RIGHTS == status) {
    223                 pDmInfo->rightsLen = contentLen;
    224                 pDmInfo->rightsOffset = pStart - buffer;
    225             } else {
    226                 pDmInfo->contentLen = contentLen;
    227                 pDmInfo->contentOffset = pStart - buffer;
    228                 status = DM_PARSE_END;
    229             }
    230             break;
    231         case SEPARATE_DELIVERY_FL:
    232             {
    233                 T_DRM_DCF_Info dcfInfo;
    234                 uint8_t* pEncData = NULL;
    235 
    236                 memset(&dcfInfo, 0, sizeof(T_DRM_DCF_Info));
    237                 if (DRM_UNKNOWN_DATA_LEN == contentLen)
    238                     contentLen = pEnd - pStart;
    239                 if (FALSE == drm_dcfParser(pStart, contentLen, &dcfInfo, &pEncData))
    240                     return FALSE;
    241 
    242                 pDmInfo->contentLen = dcfInfo.EncryptedDataLen;
    243                 pDmInfo->contentOffset = pEncData - buffer;
    244                 strcpy((char *)pDmInfo->contentType, (char *)dcfInfo.ContentType);
    245                 strcpy((char *)pDmInfo->contentID, (char *)dcfInfo.ContentURI);
    246                 strcpy((char *)pDmInfo->rightsIssuer, (char *)dcfInfo.Rights_Issuer);
    247                 status = DM_PARSE_END;
    248             }
    249             break;
    250         default:
    251             return FALSE;
    252         }
    253 
    254         if (DM_PARSING_RIGHTS == status) {
    255             /* Here means the rights object data has been completed, boundary must exist */
    256             leftLen = pBufferEnd - pEnd;
    257             pStart = drm_strnstr(pEnd, pDmInfo->boundary, leftLen);
    258             if (NULL == pStart)
    259                 return FALSE;
    260             leftLen = pBufferEnd - pStart;
    261             pEnd = drm_strnstr(pStart, (uint8_t *)DRM_NEW_LINE_CRLF, leftLen);
    262             if (NULL == pEnd)
    263                 return FALSE; /* only rights object, no media object, error */
    264 
    265             pEnd += 2; /* skip the "\r\n" */
    266             pStart = pEnd;
    267         }
    268     } while (DM_PARSE_END != status);
    269 
    270     return TRUE;
    271 }
    272