Home | History | Annotate | Download | only in wifi-display
      1 /*
      2  * Copyright 2012, 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 "ParsedMessage.h"
     18 
     19 #include <ctype.h>
     20 #include <media/stagefright/foundation/ABuffer.h>
     21 #include <media/stagefright/foundation/ADebug.h>
     22 
     23 namespace android {
     24 
     25 // static
     26 sp<ParsedMessage> ParsedMessage::Parse(
     27         const char *data, size_t size, bool noMoreData, size_t *length) {
     28     sp<ParsedMessage> msg = new ParsedMessage;
     29     ssize_t res = msg->parse(data, size, noMoreData);
     30 
     31     if (res < 0) {
     32         *length = 0;
     33         return NULL;
     34     }
     35 
     36     *length = res;
     37     return msg;
     38 }
     39 
     40 ParsedMessage::ParsedMessage() {
     41 }
     42 
     43 ParsedMessage::~ParsedMessage() {
     44 }
     45 
     46 bool ParsedMessage::findString(const char *name, AString *value) const {
     47     AString key = name;
     48     key.tolower();
     49 
     50     ssize_t index = mDict.indexOfKey(key);
     51 
     52     if (index < 0) {
     53         value->clear();
     54 
     55         return false;
     56     }
     57 
     58     *value = mDict.valueAt(index);
     59     return true;
     60 }
     61 
     62 bool ParsedMessage::findInt32(const char *name, int32_t *value) const {
     63     AString stringValue;
     64 
     65     if (!findString(name, &stringValue)) {
     66         return false;
     67     }
     68 
     69     char *end;
     70     *value = strtol(stringValue.c_str(), &end, 10);
     71 
     72     if (end == stringValue.c_str() || *end != '\0') {
     73         *value = 0;
     74         return false;
     75     }
     76 
     77     return true;
     78 }
     79 
     80 const char *ParsedMessage::getContent() const {
     81     return mContent.c_str();
     82 }
     83 
     84 ssize_t ParsedMessage::parse(const char *data, size_t size, bool noMoreData) {
     85     if (size == 0) {
     86         return -1;
     87     }
     88 
     89     ssize_t lastDictIndex = -1;
     90 
     91     size_t offset = 0;
     92     while (offset < size) {
     93         size_t lineEndOffset = offset;
     94         while (lineEndOffset + 1 < size
     95                 && (data[lineEndOffset] != '\r'
     96                         || data[lineEndOffset + 1] != '\n')) {
     97             ++lineEndOffset;
     98         }
     99 
    100         if (lineEndOffset + 1 >= size) {
    101             return -1;
    102         }
    103 
    104         AString line(&data[offset], lineEndOffset - offset);
    105 
    106         if (offset == 0) {
    107             // Special handling for the request/status line.
    108 
    109             mDict.add(AString("_"), line);
    110             offset = lineEndOffset + 2;
    111 
    112             continue;
    113         }
    114 
    115         if (lineEndOffset == offset) {
    116             offset += 2;
    117             break;
    118         }
    119 
    120         if (line.c_str()[0] == ' ' || line.c_str()[0] == '\t') {
    121             // Support for folded header values.
    122 
    123             if (lastDictIndex >= 0) {
    124                 // Otherwise it's malformed since the first header line
    125                 // cannot continue anything...
    126 
    127                 AString &value = mDict.editValueAt(lastDictIndex);
    128                 value.append(line);
    129             }
    130 
    131             offset = lineEndOffset + 2;
    132             continue;
    133         }
    134 
    135         ssize_t colonPos = line.find(":");
    136         if (colonPos >= 0) {
    137             AString key(line, 0, colonPos);
    138             key.trim();
    139             key.tolower();
    140 
    141             line.erase(0, colonPos + 1);
    142 
    143             lastDictIndex = mDict.add(key, line);
    144         }
    145 
    146         offset = lineEndOffset + 2;
    147     }
    148 
    149     for (size_t i = 0; i < mDict.size(); ++i) {
    150         mDict.editValueAt(i).trim();
    151     }
    152 
    153     // Found the end of headers.
    154 
    155     int32_t contentLength;
    156     if (!findInt32("content-length", &contentLength) || contentLength < 0) {
    157         contentLength = 0;
    158     }
    159 
    160     size_t totalLength = offset + contentLength;
    161 
    162     if (size < totalLength) {
    163         return -1;
    164     }
    165 
    166     mContent.setTo(&data[offset], contentLength);
    167 
    168     return totalLength;
    169 }
    170 
    171 void ParsedMessage::getRequestField(size_t index, AString *field) const {
    172     AString line;
    173     CHECK(findString("_", &line));
    174 
    175     size_t prevOffset = 0;
    176     size_t offset = 0;
    177     for (size_t i = 0; i <= index; ++i) {
    178         ssize_t spacePos = line.find(" ", offset);
    179 
    180         if (spacePos < 0) {
    181             spacePos = line.size();
    182         }
    183 
    184         prevOffset = offset;
    185         offset = spacePos + 1;
    186     }
    187 
    188     field->setTo(line, prevOffset, offset - prevOffset - 1);
    189 }
    190 
    191 bool ParsedMessage::getStatusCode(int32_t *statusCode) const {
    192     AString statusCodeString;
    193     getRequestField(1, &statusCodeString);
    194 
    195     char *end;
    196     *statusCode = strtol(statusCodeString.c_str(), &end, 10);
    197 
    198     if (*end != '\0' || end == statusCodeString.c_str()
    199             || (*statusCode) < 100 || (*statusCode) > 999) {
    200         *statusCode = 0;
    201         return false;
    202     }
    203 
    204     return true;
    205 }
    206 
    207 AString ParsedMessage::debugString() const {
    208     AString line;
    209     CHECK(findString("_", &line));
    210 
    211     line.append("\n");
    212 
    213     for (size_t i = 0; i < mDict.size(); ++i) {
    214         const AString &key = mDict.keyAt(i);
    215         const AString &value = mDict.valueAt(i);
    216 
    217         if (key == AString("_")) {
    218             continue;
    219         }
    220 
    221         line.append(key);
    222         line.append(": ");
    223         line.append(value);
    224         line.append("\n");
    225     }
    226 
    227     line.append("\n");
    228     line.append(mContent);
    229 
    230     return line;
    231 }
    232 
    233 // static
    234 bool ParsedMessage::GetAttribute(
    235         const char *s, const char *key, AString *value) {
    236     value->clear();
    237 
    238     size_t keyLen = strlen(key);
    239 
    240     for (;;) {
    241         while (isspace(*s)) {
    242             ++s;
    243         }
    244 
    245         const char *colonPos = strchr(s, ';');
    246 
    247         size_t len =
    248             (colonPos == NULL) ? strlen(s) : colonPos - s;
    249 
    250         if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
    251             value->setTo(&s[keyLen + 1], len - keyLen - 1);
    252             return true;
    253         }
    254 
    255         if (colonPos == NULL) {
    256             return false;
    257         }
    258 
    259         s = colonPos + 1;
    260     }
    261 }
    262 
    263 // static
    264 bool ParsedMessage::GetInt32Attribute(
    265         const char *s, const char *key, int32_t *value) {
    266     AString stringValue;
    267     if (!GetAttribute(s, key, &stringValue)) {
    268         *value = 0;
    269         return false;
    270     }
    271 
    272     char *end;
    273     *value = strtol(stringValue.c_str(), &end, 10);
    274 
    275     if (end == stringValue.c_str() || *end != '\0') {
    276         *value = 0;
    277         return false;
    278     }
    279 
    280     return true;
    281 }
    282 
    283 }  // namespace android
    284 
    285