Audacity 3.2.0
MultipartData.cpp
Go to the documentation of this file.
1/*!********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 @file MultipartData.cpp
6
7 Dmitry Vedenko
8 **********************************************************************/
9
10#include "MultipartData.h"
11
12#include <algorithm>
13#include <cstring>
14
15#include "AudacityException.h"
16
17namespace audacity
18{
19namespace network_manager
20{
21namespace
22{
24{
25public:
26 ByteBufferPart(const void* data, size_t size)
27 {
28 mData.resize(size);
29 std::memcpy(mData.data(), data, size);
30 }
31
32 int64_t GetSize() const override
33 {
34 return static_cast<int64_t>(mData.size());
35 }
36
37 size_t GetOffset() const override
38 {
39 return mOffset;
40 }
41
42 size_t Read(void* buffer, size_t maxBytes) override
43 {
44 const size_t availableBytes = mData.size() - mOffset;
45
46 maxBytes = std::min(maxBytes, availableBytes);
47
48 std::memcpy(buffer, mData.data() + mOffset, maxBytes);
49
50 mOffset += maxBytes;
51
52 return maxBytes;
53 }
54
55 bool Seek(int64_t offset, int origin) override
56 {
57 switch (origin)
58 {
59 case SEEK_SET:
60 if (offset <= GetSize())
61 {
62 mOffset = offset;
63 return true;
64 }
65 break;
66 case SEEK_CUR:
67 {
68 const int64_t targetOffset = offset + mOffset;
69
70 if (targetOffset >= 0 && targetOffset < GetSize())
71 {
72 mOffset = targetOffset;
73 return true;
74 }
75 }
76 break;
77 case SEEK_END:
78 {
79 const int64_t targetOffset = GetSize() + offset;
80
81 if (targetOffset >= 0 && targetOffset < GetSize())
82 {
83 mOffset = targetOffset;
84 return true;
85 }
86 }
87 break;
88 default:
89 break;
90 }
91
92 return false;
93 }
94
95private:
96 std::vector<uint8_t> mData;
97 size_t mOffset { 0 };
98};
99
100class FilePart final : public MultipartData::Part
101{
102public:
103 explicit FilePart(const wxFileName& fileName)
104 : mFileName(fileName)
105 {
106 if (!fileName.FileExists())
107 {
109 XO("Failed to open the file for upload: %s")
110 .Format(fileName.GetFullPath()));
111 }
112
113 if (!mFile.Open(fileName.GetFullPath()))
114 {
117 XO("Failed to open the file for upload: %s")
118 .Format(fileName.GetFullPath()));
119 }
120 }
121
122 int64_t GetSize() const override
123 {
124 return static_cast<int64_t>(mFileName.GetSize().GetValue());
125 }
126
127 size_t GetOffset() const override
128 {
129 return static_cast<size_t>(mFile.Tell());
130 }
131
132 size_t Read(void* buffer, size_t maxBytes) override
133 {
134 const auto bytesRead = mFile.Read(buffer, maxBytes);
135
136 if (bytesRead == wxInvalidOffset)
137 return 0;
138
139 return static_cast<size_t>(bytesRead);
140 }
141
142 bool Seek(int64_t offset, int origin = SEEK_SET) override
143 {
144 static constexpr wxSeekMode map[] = { wxFromStart, wxFromCurrent,
145 wxFromEnd };
146
147 if (origin < SEEK_SET || origin > SEEK_END)
148 return false;
149
150 return wxInvalidOffset != mFile.Seek(offset, map[origin]);
151 }
152
153private:
154 wxFile mFile;
155 wxFileName mFileName;
156};
157}
158
160 const std::string& headerName, const std::string& headerValue)
161{
162 mHeaders.setHeader(headerName, headerValue);
163}
164
165void MultipartData::Part::SetContentType(const std::string& mimeType)
166{
167 SetHeader(common_headers::ContentType, mimeType);
168}
169
170void MultipartData::Part::SetContentDisposition(const std::string& disposition)
171{
172 SetHeader(common_headers::ContentDisposition, disposition);
173}
174
176{
177 return mHeaders;
178}
179
180void MultipartData::Add(std::string_view name, std::string_view value)
181{
182 Add(name, {}, value.data(), value.length());
183}
184
186 std::string_view name, std::string_view contentType, const void* value,
187 size_t size)
188{
189 mParts.emplace_back(std::make_unique<ByteBufferPart>(value, size));
190
191 mParts.back()->SetContentDisposition("form-data; name=\"" + std::string(name) + "\"");
192
193 if (!contentType.empty())
194 mParts.back()->SetContentType(std::string(contentType));
195}
196
198 std::string_view name, std::string_view contentType,
199 const wxFileName& fileName)
200{
201 mParts.emplace_back(std::make_unique<FilePart>(fileName));
202
203 mParts.back()->SetContentDisposition(
204 "form-data; name=\"" + std::string(name) + "\"; filename=\"" +
205 fileName.GetFullName().ToUTF8().data() + "\"");
206
207 if (!contentType.empty())
208 mParts.back()->SetContentType(std::string(contentType));
209}
210
212{
213 return mParts.size();
214}
215
217{
218 if (idx < mParts.size())
219 return mParts[idx].get();
220
221 return nullptr;
222}
223
225{
226 if (idx < mParts.size())
227 return mParts[idx].get();
228
229 return nullptr;
230}
231
233{
234 return mParts.empty();
235}
236
237}
238}
Declare abstract class AudacityException, some often-used subclasses, and GuardedCall.
@ BadUserAction
Indicates that the user performed an action that is not allowed.
int min(int a, int b)
const TranslatableString name
Definition: Distortion.cpp:76
XO("Cut/Copy/Paste")
Abstract base class used in importing a file.
A MessageBoxException that shows a given, unvarying string.
void setHeader(const Header &header)
Definition: HeadersList.cpp:92
void SetContentType(const std::string &mimeType)
void SetContentDisposition(const std::string &disposition)
void SetHeader(const std::string &headerName, const std::string &headerValue)
void Add(std::string_view name, std::string_view value)
void AddFile(std::string_view name, std::string_view contentType, const wxFileName &fileName)
std::vector< std::unique_ptr< Part > > mParts
Definition: MultipartData.h:68