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