1e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber/*
2e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * Copyright (C) 2010 The Android Open Source Project
3e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber *
4e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
5e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * you may not use this file except in compliance with the License.
6e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * You may obtain a copy of the License at
7e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber *
8e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
9e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber *
10e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * Unless required by applicable law or agreed to in writing, software
11e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
12e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * See the License for the specific language governing permissions and
14e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * limitations under the License.
15e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber */
16e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
17ac13b81c590386b3a42e381b31d7614ca53b79c5Andreas Huber//#define LOG_NDEBUG 0
18ac13b81c590386b3a42e381b31d7614ca53b79c5Andreas Huber#define LOG_TAG "M3UParser"
19ac13b81c590386b3a42e381b31d7614ca53b79c5Andreas Huber#include <utils/Log.h>
20ac13b81c590386b3a42e381b31d7614ca53b79c5Andreas Huber
21e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber#include "include/M3UParser.h"
22e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
230a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber#include <media/stagefright/foundation/ADebug.h>
24e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber#include <media/stagefright/foundation/AMessage.h>
25e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber#include <media/stagefright/MediaErrors.h>
26e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
27e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Hubernamespace android {
28e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
29e71d10e7ad55ccbcb0756c007caef1c959090384Andreas HuberM3UParser::M3UParser(
30e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        const char *baseURI, const void *data, size_t size)
31e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    : mInitCheck(NO_INIT),
32e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber      mBaseURI(baseURI),
33e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber      mIsExtM3U(false),
34bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber      mIsVariantPlaylist(false),
35bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber      mIsComplete(false) {
36e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    mInitCheck = parse(data, size);
37e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
38e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
39e71d10e7ad55ccbcb0756c007caef1c959090384Andreas HuberM3UParser::~M3UParser() {
40e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
41e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
42e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::initCheck() const {
43e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return mInitCheck;
44e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
45e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
46e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberbool M3UParser::isExtM3U() const {
47e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return mIsExtM3U;
48e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
49e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
50e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberbool M3UParser::isVariantPlaylist() const {
51e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return mIsVariantPlaylist;
52e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
53e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
54bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huberbool M3UParser::isComplete() const {
55bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber    return mIsComplete;
56bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber}
57bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber
58e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Hubersp<AMessage> M3UParser::meta() {
59e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return mMeta;
60e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
61e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
62e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Hubersize_t M3UParser::size() {
63e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return mItems.size();
64e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
65e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
66e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberbool M3UParser::itemAt(size_t index, AString *uri, sp<AMessage> *meta) {
670f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber    if (uri) {
680f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber        uri->clear();
690f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber    }
700f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber
710f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber    if (meta) {
720f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber        *meta = NULL;
730f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber    }
74e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
75e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (index >= mItems.size()) {
76e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return false;
77e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
78e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
790f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber    if (uri) {
800f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber        *uri = mItems.itemAt(index).mURI;
810f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber    }
82e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
83e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (meta) {
84e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        *meta = mItems.itemAt(index).mMeta;
85e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
86e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
87e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return true;
88e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
89e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
90e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatic bool MakeURL(const char *baseURL, const char *url, AString *out) {
91e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    out->clear();
92e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
932a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    if (strncasecmp("http://", baseURL, 7)
94df42f949c8bd05b81d94633767514fff88f52062Andreas Huber            && strncasecmp("https://", baseURL, 8)
952a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            && strncasecmp("file://", baseURL, 7)) {
96e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        // Base URL must be absolute
97e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return false;
98e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
99e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
100df42f949c8bd05b81d94633767514fff88f52062Andreas Huber    if (!strncasecmp("http://", url, 7) || !strncasecmp("https://", url, 8)) {
101e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        // "url" is already an absolute URL, ignore base URL.
102e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        out->setTo(url);
103ac13b81c590386b3a42e381b31d7614ca53b79c5Andreas Huber
1043856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("base:'%s', url:'%s' => '%s'", baseURL, url, out->c_str());
105ac13b81c590386b3a42e381b31d7614ca53b79c5Andreas Huber
106e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return true;
107e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
108e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
109d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber    if (url[0] == '/') {
110d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber        // URL is an absolute path.
111d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber
112d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber        char *protocolEnd = strstr(baseURL, "//") + 2;
113d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber        char *pathStart = strchr(protocolEnd, '/');
114e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
115d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber        if (pathStart != NULL) {
116d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber            out->setTo(baseURL, pathStart - baseURL);
117e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        } else {
118e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            out->setTo(baseURL);
119e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
120e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
121e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        out->append(url);
122d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber    } else {
123d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber        // URL is a relative path
124d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber
125d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber        size_t n = strlen(baseURL);
126d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber        if (baseURL[n - 1] == '/') {
127d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber            out->setTo(baseURL);
128d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber            out->append(url);
129d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber        } else {
130d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber            const char *slashPos = strrchr(baseURL, '/');
131d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber
132d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber            if (slashPos > &baseURL[6]) {
133d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber                out->setTo(baseURL, slashPos - baseURL);
134d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber            } else {
135d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber                out->setTo(baseURL);
136d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber            }
137d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber
138d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber            out->append("/");
139d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber            out->append(url);
140d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber        }
141e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
142e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
1433856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("base:'%s', url:'%s' => '%s'", baseURL, url, out->c_str());
144ac13b81c590386b3a42e381b31d7614ca53b79c5Andreas Huber
145e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return true;
146e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
147e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
148e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::parse(const void *_data, size_t size) {
149e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    int32_t lineNo = 0;
150e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
151e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    sp<AMessage> itemMeta;
152e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
153e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    const char *data = (const char *)_data;
154e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    size_t offset = 0;
1552aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    uint64_t segmentRangeOffset = 0;
156e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    while (offset < size) {
157e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        size_t offsetLF = offset;
158e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        while (offsetLF < size && data[offsetLF] != '\n') {
159e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            ++offsetLF;
160e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
161e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        if (offsetLF >= size) {
162e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            break;
163e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
164e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
165e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        AString line;
166e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        if (offsetLF > offset && data[offsetLF - 1] == '\r') {
167e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            line.setTo(&data[offset], offsetLF - offset - 1);
168e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        } else {
169e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            line.setTo(&data[offset], offsetLF - offset);
170e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
171e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
172df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block        // ALOGI("#%s#", line.c_str());
1732a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
1742a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        if (line.empty()) {
1752a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            offset = offsetLF + 1;
1762a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            continue;
1772a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        }
178e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
179e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        if (lineNo == 0 && line == "#EXTM3U") {
180e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            mIsExtM3U = true;
181e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
182e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
183e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        if (mIsExtM3U) {
184e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            status_t err = OK;
185e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
186e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            if (line.startsWith("#EXT-X-TARGETDURATION")) {
187e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                if (mIsVariantPlaylist) {
188e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                    return ERROR_MALFORMED;
189e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                }
190e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                err = parseMetaData(line, &mMeta, "target-duration");
191e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            } else if (line.startsWith("#EXT-X-MEDIA-SEQUENCE")) {
192e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                if (mIsVariantPlaylist) {
193e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                    return ERROR_MALFORMED;
194e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                }
195e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                err = parseMetaData(line, &mMeta, "media-sequence");
196e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            } else if (line.startsWith("#EXT-X-KEY")) {
197e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber                if (mIsVariantPlaylist) {
198e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber                    return ERROR_MALFORMED;
199e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber                }
200decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                err = parseCipherInfo(line, &itemMeta, mBaseURI);
201bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber            } else if (line.startsWith("#EXT-X-ENDLIST")) {
202bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber                mIsComplete = true;
203e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            } else if (line.startsWith("#EXTINF")) {
204e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                if (mIsVariantPlaylist) {
205e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                    return ERROR_MALFORMED;
206e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                }
2079067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber                err = parseMetaDataDuration(line, &itemMeta, "durationUs");
2082a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            } else if (line.startsWith("#EXT-X-DISCONTINUITY")) {
2092a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                if (mIsVariantPlaylist) {
2102a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                    return ERROR_MALFORMED;
2112a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                }
2122a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                if (itemMeta == NULL) {
2132a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                    itemMeta = new AMessage;
2142a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                }
2152a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                itemMeta->setInt32("discontinuity", true);
216e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            } else if (line.startsWith("#EXT-X-STREAM-INF")) {
217e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                if (mMeta != NULL) {
218e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                    return ERROR_MALFORMED;
219e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                }
220e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                mIsVariantPlaylist = true;
2212a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                err = parseStreamInf(line, &itemMeta);
2222aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber            } else if (line.startsWith("#EXT-X-BYTERANGE")) {
2232aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                if (mIsVariantPlaylist) {
2242aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    return ERROR_MALFORMED;
2252aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                }
2262aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
2272aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                uint64_t length, offset;
2282aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                err = parseByteRange(line, segmentRangeOffset, &length, &offset);
2292aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
2302aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                if (err == OK) {
2312aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    if (itemMeta == NULL) {
2322aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                        itemMeta = new AMessage;
2332aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    }
2342aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
2352aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    itemMeta->setInt64("range-offset", offset);
2362aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    itemMeta->setInt64("range-length", length);
2372aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
2382aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    segmentRangeOffset = offset + length;
2392aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                }
240e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            }
241e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
242e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            if (err != OK) {
243e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                return err;
244e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            }
245e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
246e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
247e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        if (!line.startsWith("#")) {
248e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            if (!mIsVariantPlaylist) {
2499067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber                int64_t durationUs;
250e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                if (itemMeta == NULL
2519067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber                        || !itemMeta->findInt64("durationUs", &durationUs)) {
252e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                    return ERROR_MALFORMED;
253e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                }
254e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            }
255e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
256e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            mItems.push();
257e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            Item *item = &mItems.editItemAt(mItems.size() - 1);
258e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
259e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            CHECK(MakeURL(mBaseURI.c_str(), line.c_str(), &item->mURI));
260e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
261e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            item->mMeta = itemMeta;
262e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
263e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            itemMeta.clear();
264e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
265e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
266e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        offset = offsetLF + 1;
267e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        ++lineNo;
268e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
269e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
270e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return OK;
271e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
272e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
273e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber// static
274e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::parseMetaData(
275e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        const AString &line, sp<AMessage> *meta, const char *key) {
276e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    ssize_t colonPos = line.find(":");
277e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
278e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (colonPos < 0) {
279e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return ERROR_MALFORMED;
280e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
281e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
282e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    int32_t x;
283e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    status_t err = ParseInt32(line.c_str() + colonPos + 1, &x);
284e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
285e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (err != OK) {
286e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return err;
287e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
288e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
289e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (meta->get() == NULL) {
290e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        *meta = new AMessage;
291e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
292e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    (*meta)->setInt32(key, x);
293e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
294e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return OK;
295e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
296e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
297e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber// static
2989067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huberstatus_t M3UParser::parseMetaDataDuration(
2999067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber        const AString &line, sp<AMessage> *meta, const char *key) {
3009067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    ssize_t colonPos = line.find(":");
3019067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
3029067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    if (colonPos < 0) {
3039067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber        return ERROR_MALFORMED;
3049067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    }
3059067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
3069067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    double x;
3079067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    status_t err = ParseDouble(line.c_str() + colonPos + 1, &x);
3089067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
3099067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    if (err != OK) {
3109067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber        return err;
3119067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    }
3129067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
3139067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    if (meta->get() == NULL) {
3149067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber        *meta = new AMessage;
3159067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    }
3169067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    (*meta)->setInt64(key, (int64_t)x * 1E6);
3179067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
3189067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    return OK;
3199067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber}
3209067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
3219067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber// static
3222a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huberstatus_t M3UParser::parseStreamInf(
3232a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        const AString &line, sp<AMessage> *meta) {
3242a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    ssize_t colonPos = line.find(":");
3252a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
3262a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    if (colonPos < 0) {
3272a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        return ERROR_MALFORMED;
3282a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    }
3292a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
3302a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    size_t offset = colonPos + 1;
3312a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
3322a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    while (offset < line.size()) {
3332a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        ssize_t end = line.find(",", offset);
3342a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        if (end < 0) {
3352a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            end = line.size();
3362a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        }
3372a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
3382a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        AString attr(line, offset, end - offset);
3392a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        attr.trim();
3402a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
3412a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        offset = end + 1;
3422a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
3432a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        ssize_t equalPos = attr.find("=");
3442a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        if (equalPos < 0) {
3452a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            continue;
3462a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        }
3472a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
3482a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        AString key(attr, 0, equalPos);
3492a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        key.trim();
3502a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
3512a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        AString val(attr, equalPos + 1, attr.size() - equalPos - 1);
3522a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        val.trim();
3532a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
3543856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("key=%s value=%s", key.c_str(), val.c_str());
3552a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
3562a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        if (!strcasecmp("bandwidth", key.c_str())) {
3572a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            const char *s = val.c_str();
3582a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            char *end;
3592a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            unsigned long x = strtoul(s, &end, 10);
3602a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
3612a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            if (end == s || *end != '\0') {
3622a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                // malformed
3632a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                continue;
3642a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            }
3652a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
3662a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            if (meta->get() == NULL) {
3672a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                *meta = new AMessage;
3682a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            }
3692a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            (*meta)->setInt32("bandwidth", x);
3702a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        }
3712a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    }
3722a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
3732a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    return OK;
3742a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber}
3752a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
3760a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber// Find the next occurence of the character "what" at or after "offset",
3770a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber// but ignore occurences between quotation marks.
3780a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber// Return the index of the occurrence or -1 if not found.
3790a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huberstatic ssize_t FindNextUnquoted(
3800a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber        const AString &line, char what, size_t offset) {
3810a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber    CHECK_NE((int)what, (int)'"');
3820a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber
3830a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber    bool quoted = false;
3840a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber    while (offset < line.size()) {
3850a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber        char c = line.c_str()[offset];
3860a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber
3870a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber        if (c == '"') {
3880a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber            quoted = !quoted;
3890a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber        } else if (c == what && !quoted) {
3900a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber            return offset;
3910a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber        }
3920a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber
3930a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber        ++offset;
3940a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber    }
3950a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber
3960a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber    return -1;
3970a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber}
3980a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber
3992a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber// static
400e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huberstatus_t M3UParser::parseCipherInfo(
401decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber        const AString &line, sp<AMessage> *meta, const AString &baseURI) {
402e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    ssize_t colonPos = line.find(":");
403e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
404e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    if (colonPos < 0) {
405e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        return ERROR_MALFORMED;
406e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    }
407e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
408e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    size_t offset = colonPos + 1;
409e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
410e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    while (offset < line.size()) {
4110a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber        ssize_t end = FindNextUnquoted(line, ',', offset);
412e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        if (end < 0) {
413e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            end = line.size();
414e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        }
415e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
416e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        AString attr(line, offset, end - offset);
417e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        attr.trim();
418e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
419e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        offset = end + 1;
420e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
421e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        ssize_t equalPos = attr.find("=");
422e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        if (equalPos < 0) {
423e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            continue;
424e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        }
425e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
426e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        AString key(attr, 0, equalPos);
427e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        key.trim();
428e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
429e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        AString val(attr, equalPos + 1, attr.size() - equalPos - 1);
430e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        val.trim();
431e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
4323856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("key=%s value=%s", key.c_str(), val.c_str());
433e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
434e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        key.tolower();
435e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
436e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        if (key == "method" || key == "uri" || key == "iv") {
437e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            if (meta->get() == NULL) {
438e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber                *meta = new AMessage;
439e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            }
440e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
441decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber            if (key == "uri") {
442decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                if (val.size() >= 2
443decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                        && val.c_str()[0] == '"'
444decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                        && val.c_str()[val.size() - 1] == '"') {
445decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                    // Remove surrounding quotes.
446decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                    AString tmp(val, 1, val.size() - 2);
447decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                    val = tmp;
448decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                }
449decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber
450decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                AString absURI;
451decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                if (MakeURL(baseURI.c_str(), val.c_str(), &absURI)) {
452decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                    val = absURI;
453decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                } else {
45429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("failed to make absolute url for '%s'.",
455decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                         val.c_str());
456decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                }
457decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber            }
458decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber
459e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            key.insert(AString("cipher-"), 0);
460e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
461e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            (*meta)->setString(key.c_str(), val.c_str(), val.size());
462e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        }
463e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    }
464e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
465e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    return OK;
466e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber}
467e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
468e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber// static
4692aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huberstatus_t M3UParser::parseByteRange(
4702aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        const AString &line, uint64_t curOffset,
4712aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        uint64_t *length, uint64_t *offset) {
4722aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    ssize_t colonPos = line.find(":");
4732aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
4742aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    if (colonPos < 0) {
4752aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        return ERROR_MALFORMED;
4762aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    }
4772aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
4782aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    ssize_t atPos = line.find("@", colonPos + 1);
4792aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
4802aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    AString lenStr;
4812aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    if (atPos < 0) {
4822aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        lenStr = AString(line, colonPos + 1, line.size() - colonPos - 1);
4832aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    } else {
4842aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        lenStr = AString(line, colonPos + 1, atPos - colonPos - 1);
4852aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    }
4862aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
4872aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    lenStr.trim();
4882aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
4892aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    const char *s = lenStr.c_str();
4902aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    char *end;
4912aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    *length = strtoull(s, &end, 10);
4922aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
4932aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    if (s == end || *end != '\0') {
4942aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        return ERROR_MALFORMED;
4952aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    }
4962aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
4972aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    if (atPos >= 0) {
4982aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        AString offStr = AString(line, atPos + 1, line.size() - atPos - 1);
4992aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        offStr.trim();
5002aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
5012aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        const char *s = offStr.c_str();
5022aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        *offset = strtoull(s, &end, 10);
5032aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
5042aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        if (s == end || *end != '\0') {
5052aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber            return ERROR_MALFORMED;
5062aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        }
5072aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    } else {
5082aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        *offset = curOffset;
5092aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    }
5102aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
5112aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    return OK;
5122aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber}
5132aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
5142aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber// static
515e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::ParseInt32(const char *s, int32_t *x) {
516e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    char *end;
517e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    long lval = strtol(s, &end, 10);
518e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
519e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (end == s || (*end != '\0' && *end != ',')) {
520e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return ERROR_MALFORMED;
521e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
522e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
523e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    *x = (int32_t)lval;
524e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
525e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return OK;
526e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
527e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
5289067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber// static
5299067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huberstatus_t M3UParser::ParseDouble(const char *s, double *x) {
5309067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    char *end;
5319067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    double dval = strtod(s, &end);
5329067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
5339067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    if (end == s || (*end != '\0' && *end != ',')) {
5349067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber        return ERROR_MALFORMED;
5359067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    }
5369067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
5379067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    *x = dval;
5389067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
5399067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    return OK;
5409067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber}
5419067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
542e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}  // namespace android
543