1bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber/*
2bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber * Copyright 2012, The Android Open Source Project
3bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber *
4bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
5bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber * you may not use this file except in compliance with the License.
6bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber * You may obtain a copy of the License at
7bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber *
8bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber *     http://www.apache.org/licenses/LICENSE-2.0
9bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber *
10bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber * Unless required by applicable law or agreed to in writing, software
11bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
12bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber * See the License for the specific language governing permissions and
14bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber * limitations under the License.
15bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber */
16bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
17bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber#include "ParsedMessage.h"
18bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
19bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber#include <ctype.h>
20bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber#include <media/stagefright/foundation/ABuffer.h>
21bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber#include <media/stagefright/foundation/ADebug.h>
228060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber#include <media/stagefright/foundation/hexdump.h>
23bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
24bb197f84c4119651e5face418285688ddaf08ea3Andreas Hubernamespace android {
25bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
26bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber// static
27bb197f84c4119651e5face418285688ddaf08ea3Andreas Hubersp<ParsedMessage> ParsedMessage::Parse(
28bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        const char *data, size_t size, bool noMoreData, size_t *length) {
29bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    sp<ParsedMessage> msg = new ParsedMessage;
30bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    ssize_t res = msg->parse(data, size, noMoreData);
31bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
32bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    if (res < 0) {
33bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        *length = 0;
34bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        return NULL;
35bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    }
36bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
37bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    *length = res;
38bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    return msg;
39bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber}
40bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
41bb197f84c4119651e5face418285688ddaf08ea3Andreas HuberParsedMessage::ParsedMessage() {
42bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber}
43bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
44bb197f84c4119651e5face418285688ddaf08ea3Andreas HuberParsedMessage::~ParsedMessage() {
45bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber}
46bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
47bb197f84c4119651e5face418285688ddaf08ea3Andreas Huberbool ParsedMessage::findString(const char *name, AString *value) const {
48bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    AString key = name;
49bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    key.tolower();
50bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
51bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    ssize_t index = mDict.indexOfKey(key);
52bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
53bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    if (index < 0) {
54bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        value->clear();
55bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
56bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        return false;
57bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    }
58bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
59bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    *value = mDict.valueAt(index);
60bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    return true;
61bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber}
62bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
63bb197f84c4119651e5face418285688ddaf08ea3Andreas Huberbool ParsedMessage::findInt32(const char *name, int32_t *value) const {
64bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    AString stringValue;
65bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
66bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    if (!findString(name, &stringValue)) {
67bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        return false;
68bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    }
69bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
70bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    char *end;
71bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    *value = strtol(stringValue.c_str(), &end, 10);
72bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
73bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    if (end == stringValue.c_str() || *end != '\0') {
74bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        *value = 0;
75bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        return false;
76bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    }
77bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
78bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    return true;
79bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber}
80bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
81bb197f84c4119651e5face418285688ddaf08ea3Andreas Huberconst char *ParsedMessage::getContent() const {
82bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    return mContent.c_str();
83bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber}
84bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
85bb197f84c4119651e5face418285688ddaf08ea3Andreas Huberssize_t ParsedMessage::parse(const char *data, size_t size, bool noMoreData) {
86bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    if (size == 0) {
87bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        return -1;
88bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    }
89bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
90bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    ssize_t lastDictIndex = -1;
91bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
92bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    size_t offset = 0;
938060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber    bool headersComplete = false;
94bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    while (offset < size) {
95bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        size_t lineEndOffset = offset;
96bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        while (lineEndOffset + 1 < size
97bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber                && (data[lineEndOffset] != '\r'
98bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber                        || data[lineEndOffset + 1] != '\n')) {
99bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            ++lineEndOffset;
100bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        }
101bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
102bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        if (lineEndOffset + 1 >= size) {
103bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            return -1;
104bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        }
105bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
106bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        AString line(&data[offset], lineEndOffset - offset);
107bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
108bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        if (offset == 0) {
109bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            // Special handling for the request/status line.
110bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
111bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            mDict.add(AString("_"), line);
112bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            offset = lineEndOffset + 2;
113bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
114bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            continue;
115bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        }
116bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
117bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        if (lineEndOffset == offset) {
1188060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber            // An empty line separates headers from body.
1198060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber            headersComplete = true;
120bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            offset += 2;
121bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            break;
122bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        }
123bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
124bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        if (line.c_str()[0] == ' ' || line.c_str()[0] == '\t') {
125bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            // Support for folded header values.
126bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
127bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            if (lastDictIndex >= 0) {
128bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber                // Otherwise it's malformed since the first header line
129bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber                // cannot continue anything...
130bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
131bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber                AString &value = mDict.editValueAt(lastDictIndex);
132bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber                value.append(line);
133bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            }
134bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
135bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            offset = lineEndOffset + 2;
136bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            continue;
137bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        }
138bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
139bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        ssize_t colonPos = line.find(":");
140bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        if (colonPos >= 0) {
141bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            AString key(line, 0, colonPos);
142bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            key.trim();
143bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            key.tolower();
144bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
145bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            line.erase(0, colonPos + 1);
146bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
147bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            lastDictIndex = mDict.add(key, line);
148bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        }
149bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
150bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        offset = lineEndOffset + 2;
151bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    }
152bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
1538060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber    if (!headersComplete && (!noMoreData || offset == 0)) {
1548060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber        // We either saw the empty line separating headers from body
1558060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber        // or we saw at least the status line and know that no more data
1568060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber        // is going to follow.
1578060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber        return -1;
1588060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber    }
1598060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber
160bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    for (size_t i = 0; i < mDict.size(); ++i) {
161bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        mDict.editValueAt(i).trim();
162bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    }
163bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
164bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    int32_t contentLength;
165bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    if (!findInt32("content-length", &contentLength) || contentLength < 0) {
166bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        contentLength = 0;
167bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    }
168bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
169bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    size_t totalLength = offset + contentLength;
170bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
171bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    if (size < totalLength) {
172bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        return -1;
173bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    }
174bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
175bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    mContent.setTo(&data[offset], contentLength);
176bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
177bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    return totalLength;
178bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber}
179bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
1808060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huberbool ParsedMessage::getRequestField(size_t index, AString *field) const {
181bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    AString line;
182bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    CHECK(findString("_", &line));
183bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
184bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    size_t prevOffset = 0;
185bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    size_t offset = 0;
186bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    for (size_t i = 0; i <= index; ++i) {
1878060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber        if (offset >= line.size()) {
1888060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber            return false;
1898060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber        }
1908060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber
191bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        ssize_t spacePos = line.find(" ", offset);
192bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
193bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        if (spacePos < 0) {
194bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            spacePos = line.size();
195bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        }
196bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
197bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        prevOffset = offset;
198bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        offset = spacePos + 1;
199bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    }
200bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
201bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    field->setTo(line, prevOffset, offset - prevOffset - 1);
2028060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber
2038060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber    return true;
204bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber}
205bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
206bb197f84c4119651e5face418285688ddaf08ea3Andreas Huberbool ParsedMessage::getStatusCode(int32_t *statusCode) const {
207bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    AString statusCodeString;
2088060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber    if (!getRequestField(1, &statusCodeString)) {
2098060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber        *statusCode = 0;
2108060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber        return false;
2118060060217ff16cd67c8f6a15c649f44c343acf0Andreas Huber    }
212bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
213bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    char *end;
214bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    *statusCode = strtol(statusCodeString.c_str(), &end, 10);
215bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
216bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    if (*end != '\0' || end == statusCodeString.c_str()
217bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            || (*statusCode) < 100 || (*statusCode) > 999) {
218bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        *statusCode = 0;
219bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        return false;
220bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    }
221bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
222bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    return true;
223bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber}
224bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
225bb197f84c4119651e5face418285688ddaf08ea3Andreas HuberAString ParsedMessage::debugString() const {
226bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    AString line;
227bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    CHECK(findString("_", &line));
228bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
229bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    line.append("\n");
230bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
231bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    for (size_t i = 0; i < mDict.size(); ++i) {
232bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        const AString &key = mDict.keyAt(i);
233bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        const AString &value = mDict.valueAt(i);
234bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
235bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        if (key == AString("_")) {
236bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            continue;
237bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        }
238bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
239bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        line.append(key);
240bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        line.append(": ");
241bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        line.append(value);
242bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        line.append("\n");
243bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    }
244bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
245bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    line.append("\n");
246bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    line.append(mContent);
247bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
248bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    return line;
249bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber}
250bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
251bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber// static
252bb197f84c4119651e5face418285688ddaf08ea3Andreas Huberbool ParsedMessage::GetAttribute(
253bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        const char *s, const char *key, AString *value) {
254bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    value->clear();
255bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
256bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    size_t keyLen = strlen(key);
257bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
258bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    for (;;) {
259bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        while (isspace(*s)) {
260bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            ++s;
261bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        }
262bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
263bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        const char *colonPos = strchr(s, ';');
264bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
265bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        size_t len =
266bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            (colonPos == NULL) ? strlen(s) : colonPos - s;
267bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
268bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
269bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            value->setTo(&s[keyLen + 1], len - keyLen - 1);
270bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            return true;
271bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        }
272bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
273bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        if (colonPos == NULL) {
274bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber            return false;
275bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        }
276bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
277bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        s = colonPos + 1;
278bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    }
279bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber}
280bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
281bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber// static
282bb197f84c4119651e5face418285688ddaf08ea3Andreas Huberbool ParsedMessage::GetInt32Attribute(
283bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        const char *s, const char *key, int32_t *value) {
284bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    AString stringValue;
285bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    if (!GetAttribute(s, key, &stringValue)) {
286bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        *value = 0;
287bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        return false;
288bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    }
289bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
290bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    char *end;
291bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    *value = strtol(stringValue.c_str(), &end, 10);
292bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
293bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    if (end == stringValue.c_str() || *end != '\0') {
294bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        *value = 0;
295bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber        return false;
296bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    }
297bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
298bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber    return true;
299bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber}
300bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
301bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber}  // namespace android
302bb197f84c4119651e5face418285688ddaf08ea3Andreas Huber
303