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