1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <webrtc/SDP.h>
18
19 #include "Utils.h"
20
21 #include <android-base/logging.h>
22
23 #include <cerrno>
24 #include <iostream>
25
SDP()26 SDP::SDP()
27 : mInitCheck(-ENODEV),
28 mNewSectionEditorActive(false) {
29 }
30
initCheck() const31 int SDP::initCheck() const {
32 return mInitCheck;
33 }
34
countSections() const35 size_t SDP::countSections() const {
36 CHECK(!mInitCheck);
37 return mLineIndexBySection.size();
38 }
39
clear()40 void SDP::clear() {
41 mInitCheck = -ENODEV;
42 mLines.clear();
43 mLineIndexBySection.clear();
44 }
45
setTo(const std::string & data)46 int SDP::setTo(const std::string &data) {
47 clear();
48
49 mLines = SplitString(data, "\r\n");
50
51 LOG(VERBOSE) << "SDP contained " << mLines.size() << " lines.";
52
53 mLineIndexBySection.push_back(0);
54
55 mInitCheck = 0;
56
57 for (size_t i = 0; i < mLines.size(); ++i) {
58 const auto &line = mLines[i];
59
60 LOG(VERBOSE) << "Line #" << i << ": " << line;
61
62 if (i == 0 && line != "v=0") {
63 mInitCheck = -EINVAL;
64 break;
65 }
66
67 if (line.size() < 2 || line[1] != '=') {
68 mInitCheck = -EINVAL;
69 break;
70 }
71
72 if (line[0] == 'm') {
73 mLineIndexBySection.push_back(i);
74 }
75 }
76
77 return mInitCheck;
78 }
79
getSectionRange(size_t section,size_t * lineStartIndex,size_t * lineStopIndex) const80 void SDP::getSectionRange(
81 size_t section, size_t *lineStartIndex, size_t *lineStopIndex) const {
82 CHECK(!mInitCheck);
83 CHECK_LT(section, mLineIndexBySection.size());
84
85 if (lineStartIndex) {
86 *lineStartIndex = mLineIndexBySection[section];
87 }
88
89 if (lineStopIndex) {
90 if (section + 1 < mLineIndexBySection.size()) {
91 *lineStopIndex = mLineIndexBySection[section + 1];
92 } else {
93 *lineStopIndex = mLines.size();
94 }
95 }
96 }
97
section_begin(size_t section) const98 std::vector<std::string>::const_iterator SDP::section_begin(
99 size_t section) const {
100
101 size_t startLineIndex;
102 getSectionRange(section, &startLineIndex, nullptr /* lineStopIndex */);
103
104 return mLines.cbegin() + startLineIndex;
105 }
106
section_end(size_t section) const107 std::vector<std::string>::const_iterator SDP::section_end(
108 size_t section) const {
109
110 size_t stopLineIndex;
111 getSectionRange(section, nullptr /* lineStartIndex */, &stopLineIndex);
112
113 return mLines.cbegin() + stopLineIndex;
114 }
115
createSection()116 SDP::SectionEditor SDP::createSection() {
117 CHECK(!mNewSectionEditorActive);
118 mNewSectionEditorActive = true;
119
120 if (mInitCheck) {
121 clear();
122 mInitCheck = 0;
123 }
124
125 return SectionEditor(this, countSections());
126 }
127
appendToSection(size_t section)128 SDP::SectionEditor SDP::appendToSection(size_t section) {
129 CHECK_LT(section, countSections());
130 return SectionEditor(this, section);
131 }
132
commitSectionEdit(size_t section,const std::vector<std::string> & lines)133 void SDP::commitSectionEdit(
134 size_t section, const std::vector<std::string> &lines) {
135
136 CHECK_LE(section, countSections());
137
138 if (section == countSections()) {
139 // This was an edit creating a new section.
140 mLineIndexBySection.push_back(mLines.size());
141
142 mLines.insert(mLines.end(), lines.begin(), lines.end());
143
144 mNewSectionEditorActive = false;
145 return;
146 }
147
148 mLines.insert(section_end(section), lines.begin(), lines.end());
149
150 if (section + 1 < countSections()) {
151 mLineIndexBySection[section + 1] += lines.size();
152 }
153 }
154
155 ////////////////////////////////////////////////////////////////////////////////
156
SectionEditor(SDP * sdp,size_t section)157 SDP::SectionEditor::SectionEditor(SDP *sdp, size_t section)
158 : mSDP(sdp),
159 mSection(section) {
160 }
161
~SectionEditor()162 SDP::SectionEditor::~SectionEditor() {
163 commit();
164 }
165
operator <<(std::string_view s)166 SDP::SectionEditor &SDP::SectionEditor::operator<<(std::string_view s) {
167 mBuffer.append(s);
168
169 return *this;
170 }
171
commit()172 void SDP::SectionEditor::commit() {
173 if (mSDP) {
174 auto lines = SplitString(mBuffer, "\r\n");
175
176 mSDP->commitSectionEdit(mSection, lines);
177 mSDP = nullptr;
178 }
179 }
180