blob: f5b7aaf65025d44d8f4e9209dd7290669d7bd5e3 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
25typedef 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
32static 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
51const 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 */
67int32_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)){
Steve Block5baa3a62011-12-20 16:23:08 +0000141 ALOGD("drm_dmParser: error: more than one content id\r\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 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}