OpenShot Audio Library | OpenShotAudio 0.3.2

Loading...
Searching...
No Matches
juce_URL.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23 namespace juce
24{
25
26 struct FallbackDownloadTask : public URL::DownloadTask,
27 public Thread
28{
29 FallbackDownloadTask (FileOutputStream* outputStreamToUse,
30 size_t bufferSizeToUse,
31 WebInputStream* streamToUse,
32 URL::DownloadTask::Listener* listenerToUse)
33 : Thread ("DownloadTask thread"),
34 fileStream (outputStreamToUse),
35 stream (streamToUse),
36 bufferSize (bufferSizeToUse),
37 buffer (bufferSize),
38 listener (listenerToUse)
39 {
40 jassert (fileStream != nullptr);
41 jassert (stream != nullptr);
42
43 targetLocation = fileStream->getFile();
44 contentLength = stream->getTotalLength();
45 httpCode = stream->getStatusCode();
46
47 startThread();
48 }
49
50 ~FallbackDownloadTask() override
51 {
52 signalThreadShouldExit();
53 stream->cancel();
54 waitForThreadToExit (-1);
55 }
56
57 //==============================================================================
58 void run() override
59 {
60 while (! (stream->isExhausted() || stream->isError() || threadShouldExit()))
61 {
62 if (listener != nullptr)
63 listener->progress (this, downloaded, contentLength);
64
65 auto max = (int) jmin ((int64) bufferSize, contentLength < 0 ? std::numeric_limits<int64>::max()
66 : static_cast<int64> (contentLength - downloaded));
67
68 auto actual = stream->read (buffer.get(), max);
69
70 if (actual < 0 || threadShouldExit() || stream->isError())
71 break;
72
73 if (! fileStream->write (buffer.get(), static_cast<size_t> (actual)))
74 {
75 error = true;
76 break;
77 }
78
79 downloaded += actual;
80
81 if (downloaded == contentLength)
82 break;
83 }
84
85 fileStream.reset();
86
87 if (threadShouldExit() || stream->isError())
88 error = true;
89
90 if (contentLength > 0 && downloaded < contentLength)
91 error = true;
92
93 finished = true;
94
95 if (listener != nullptr && ! threadShouldExit())
96 listener->finished (this, ! error);
97 }
98
99 //==============================================================================
100 std::unique_ptr<FileOutputStream> fileStream;
101 const std::unique_ptr<WebInputStream> stream;
102 const size_t bufferSize;
103 HeapBlock<char> buffer;
104 URL::DownloadTask::Listener* const listener;
105
106 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FallbackDownloadTask)
107};
108
109 void URL::DownloadTask::Listener::progress (DownloadTask*, int64, int64) {}
110URL::DownloadTask::Listener::~Listener() {}
111
112//==============================================================================
113 URL::DownloadTask* URL::DownloadTask::createFallbackDownloader (const URL& urlToUse,
114 const File& targetFileToUse,
115 const String& extraHeadersToUse,
116 Listener* listenerToUse,
117 bool usePostRequest)
118{
119 const size_t bufferSize = 0x8000;
120 targetFileToUse.deleteFile();
121
122 if (auto outputStream = std::unique_ptr<FileOutputStream> (targetFileToUse.createOutputStream (bufferSize)))
123 {
124 std::unique_ptr<WebInputStream> stream (new WebInputStream (urlToUse, usePostRequest));
125 stream->withExtraHeaders (extraHeadersToUse);
126
127 if (stream->connect (nullptr))
128 return new FallbackDownloadTask (outputStream.release(), bufferSize, stream.release(), listenerToUse);
129 }
130
131 return nullptr;
132}
133
134URL::DownloadTask::DownloadTask() {}
135 URL::DownloadTask::~DownloadTask() {}
136
137//==============================================================================
138 URL::URL() {}
139
140 URL::URL (const String& u) : url (u)
141{
142 init();
143}
144
145 URL::URL (File localFile)
146{
147 if (localFile == File())
148 return;
149
150 #if JUCE_WINDOWS
151 bool isUncPath = localFile.getFullPathName().startsWith ("\\\\");
152 #endif
153
154 while (! localFile.isRoot())
155 {
156 url = "/" + addEscapeChars (localFile.getFileName(), false) + url;
157 localFile = localFile.getParentDirectory();
158 }
159
160 url = addEscapeChars (localFile.getFileName(), false) + url;
161
162 #if JUCE_WINDOWS
163 if (isUncPath)
164 {
165 url = url.fromFirstOccurrenceOf ("/", false, false);
166 }
167 else
168 #endif
169 {
170 if (! url.startsWithChar (L'/'))
171 url = "/" + url;
172 }
173
174 url = "file://" + url;
175
176 jassert (isWellFormed());
177}
178
179 void URL::init()
180{
181 auto i = url.indexOfChar ('?');
182
183 if (i >= 0)
184 {
185 do
186 {
187 auto nextAmp = url.indexOfChar (i + 1, '&');
188 auto equalsPos = url.indexOfChar (i + 1, '=');
189
190 if (nextAmp < 0)
191 {
192 addParameter (removeEscapeChars (equalsPos < 0 ? url.substring (i + 1) : url.substring (i + 1, equalsPos)),
193 equalsPos < 0 ? String() : removeEscapeChars (url.substring (equalsPos + 1)));
194 }
195 else if (nextAmp > 0 && equalsPos < nextAmp)
196 {
197 addParameter (removeEscapeChars (equalsPos < 0 ? url.substring (i + 1, nextAmp) : url.substring (i + 1, equalsPos)),
198 equalsPos < 0 ? String() : removeEscapeChars (url.substring (equalsPos + 1, nextAmp)));
199 }
200
201 i = nextAmp;
202 }
203 while (i >= 0);
204
205 url = url.upToFirstOccurrenceOf ("?", false, false);
206 }
207}
208
209 URL::URL (const String& u, int) : url (u) {}
210
211 URL URL::createWithoutParsing (const String& u)
212{
213 return URL (u, 0);
214}
215
216 bool URL::operator== (const URL& other) const
217{
218 return url == other.url
219 && postData == other.postData
220 && parameterNames == other.parameterNames
221 && parameterValues == other.parameterValues
222 && filesToUpload == other.filesToUpload;
223}
224
225 bool URL::operator!= (const URL& other) const
226{
227 return ! operator== (other);
228}
229
230 namespace URLHelpers
231{
232 static String getMangledParameters (const URL& url)
233 {
234 jassert (url.getParameterNames().size() == url.getParameterValues().size());
235 String p;
236
237 for (int i = 0; i < url.getParameterNames().size(); ++i)
238 {
239 if (i > 0)
240 p << '&';
241
242 auto val = url.getParameterValues()[i];
243
244 p << URL::addEscapeChars (url.getParameterNames()[i], true);
245
246 if (val.isNotEmpty())
247 p << '=' << URL::addEscapeChars (val, true);
248 }
249
250 return p;
251 }
252
253 static int findEndOfScheme (const String& url)
254 {
255 int i = 0;
256
257 while (CharacterFunctions::isLetterOrDigit (url[i])
258 || url[i] == '+' || url[i] == '-' || url[i] == '.')
259 ++i;
260
261 return url.substring (i).startsWith ("://") ? i + 1 : 0;
262 }
263
264 static int findStartOfNetLocation (const String& url)
265 {
266 int start = findEndOfScheme (url);
267
268 while (url[start] == '/')
269 ++start;
270
271 return start;
272 }
273
274 static int findStartOfPath (const String& url)
275 {
276 return url.indexOfChar (findStartOfNetLocation (url), '/') + 1;
277 }
278
279 static void concatenatePaths (String& path, const String& suffix)
280 {
281 if (! path.endsWithChar ('/'))
282 path << '/';
283
284 if (suffix.startsWithChar ('/'))
285 path += suffix.substring (1);
286 else
287 path += suffix;
288 }
289
290 static String removeLastPathSection (const String& url)
291 {
292 auto startOfPath = findStartOfPath (url);
293 auto lastSlash = url.lastIndexOfChar ('/');
294
295 if (lastSlash > startOfPath && lastSlash == url.length() - 1)
296 return removeLastPathSection (url.dropLastCharacters (1));
297
298 if (lastSlash < 0)
299 return url;
300
301 return url.substring (0, std::max (startOfPath, lastSlash));
302 }
303}
304
305 void URL::addParameter (const String& name, const String& value)
306{
307 parameterNames.add (name);
308 parameterValues.add (value);
309}
310
311 String URL::toString (bool includeGetParameters) const
312{
313 if (includeGetParameters)
314 return url + getQueryString();
315
316 return url;
317}
318
319 bool URL::isEmpty() const noexcept
320{
321 return url.isEmpty();
322}
323
324 bool URL::isWellFormed() const
325{
326 //xxx TODO
327 return url.isNotEmpty();
328}
329
330 String URL::getDomain() const
331{
332 return getDomainInternal (false);
333}
334
335 String URL::getSubPath (bool includeGetParameters) const
336{
337 auto startOfPath = URLHelpers::findStartOfPath (url);
338 auto subPath = startOfPath <= 0 ? String()
339 : url.substring (startOfPath);
340
341 if (includeGetParameters)
342 subPath += getQueryString();
343
344 return subPath;
345}
346
347 String URL::getQueryString() const
348{
349 if (parameterNames.size() > 0)
350 return "?" + URLHelpers::getMangledParameters (*this);
351
352 return {};
353}
354
355 String URL::getScheme() const
356{
357 return url.substring (0, URLHelpers::findEndOfScheme (url) - 1);
358}
359
360#if ! JUCE_ANDROID
361 bool URL::isLocalFile() const
362{
363 return getScheme() == "file";
364}
365
366 File URL::getLocalFile() const
367{
368 return fileFromFileSchemeURL (*this);
369}
370
371 String URL::getFileName() const
372{
373 return toString (false).fromLastOccurrenceOf ("/", false, true);
374}
375#endif
376
377 File URL::fileFromFileSchemeURL (const URL& fileURL)
378{
379 if (! fileURL.isLocalFile())
380 {
381 jassertfalse;
382 return {};
383 }
384
385 auto path = removeEscapeChars (fileURL.getDomainInternal (true)).replace ("+", "%2B");
386
387 #if JUCE_WINDOWS
388 bool isUncPath = (! fileURL.url.startsWith ("file:///"));
389 #else
390 path = File::getSeparatorString() + path;
391 #endif
392
393 auto urlElements = StringArray::fromTokens (fileURL.getSubPath(), "/", "");
394
395 for (auto urlElement : urlElements)
396 path += File::getSeparatorString() + removeEscapeChars (urlElement.replace ("+", "%2B"));
397
398 #if JUCE_WINDOWS
399 if (isUncPath)
400 path = "\\\\" + path;
401 #endif
402
403 return path;
404}
405
406 int URL::getPort() const
407{
408 auto colonPos = url.indexOfChar (URLHelpers::findStartOfNetLocation (url), ':');
409
410 return colonPos > 0 ? url.substring (colonPos + 1).getIntValue() : 0;
411}
412
413 URL URL::withNewDomainAndPath (const String& newURL) const
414{
415 URL u (*this);
416 u.url = newURL;
417 return u;
418}
419
420 URL URL::withNewSubPath (const String& newPath) const
421{
422 URL u (*this);
423
424 auto startOfPath = URLHelpers::findStartOfPath (url);
425
426 if (startOfPath > 0)
427 u.url = url.substring (0, startOfPath);
428
429 URLHelpers::concatenatePaths (u.url, newPath);
430 return u;
431}
432
433 URL URL::getParentURL() const
434{
435 URL u (*this);
436 u.url = URLHelpers::removeLastPathSection (u.url);
437 return u;
438}
439
440 URL URL::getChildURL (const String& subPath) const
441{
442 URL u (*this);
443 URLHelpers::concatenatePaths (u.url, subPath);
444 return u;
445}
446
447 void URL::createHeadersAndPostData (String& headers, MemoryBlock& postDataToWrite) const
448{
449 MemoryOutputStream data (postDataToWrite, false);
450
451 if (filesToUpload.size() > 0)
452 {
453 // (this doesn't currently support mixing custom post-data with uploads..)
454 jassert (postData.getSize() == 0);
455
456 auto boundary = String::toHexString (Random::getSystemRandom().nextInt64());
457
458 headers << "Content-Type: multipart/form-data; boundary=" << boundary << "\r\n";
459
460 data << "--" << boundary;
461
462 for (int i = 0; i < parameterNames.size(); ++i)
463 {
464 data << "\r\nContent-Disposition: form-data; name=\"" << parameterNames[i]
465 << "\"\r\n\r\n" << parameterValues[i]
466 << "\r\n--" << boundary;
467 }
468
469 for (auto* f : filesToUpload)
470 {
471 data << "\r\nContent-Disposition: form-data; name=\"" << f->parameterName
472 << "\"; filename=\"" << f->filename << "\"\r\n";
473
474 if (f->mimeType.isNotEmpty())
475 data << "Content-Type: " << f->mimeType << "\r\n";
476
477 data << "Content-Transfer-Encoding: binary\r\n\r\n";
478
479 if (f->data != nullptr)
480 data << *f->data;
481 else
482 data << f->file;
483
484 data << "\r\n--" << boundary;
485 }
486
487 data << "--\r\n";
488 }
489 else
490 {
491 data << URLHelpers::getMangledParameters (*this)
492 << postData;
493
494 // if the user-supplied headers didn't contain a content-type, add one now..
495 if (! headers.containsIgnoreCase ("Content-Type"))
496 headers << "Content-Type: application/x-www-form-urlencoded\r\n";
497
498 headers << "Content-length: " << (int) data.getDataSize() << "\r\n";
499 }
500}
501
502//==============================================================================
503 bool URL::isProbablyAWebsiteURL (const String& possibleURL)
504{
505 for (auto* protocol : { "http:", "https:", "ftp:" })
506 if (possibleURL.startsWithIgnoreCase (protocol))
507 return true;
508
509 if (possibleURL.containsChar ('@') || possibleURL.containsChar (' '))
510 return false;
511
512 auto topLevelDomain = possibleURL.upToFirstOccurrenceOf ("/", false, false)
513 .fromLastOccurrenceOf (".", false, false);
514
515 return topLevelDomain.isNotEmpty() && topLevelDomain.length() <= 3;
516}
517
518 bool URL::isProbablyAnEmailAddress (const String& possibleEmailAddress)
519{
520 auto atSign = possibleEmailAddress.indexOfChar ('@');
521
522 return atSign > 0
523 && possibleEmailAddress.lastIndexOfChar ('.') > (atSign + 1)
524 && ! possibleEmailAddress.endsWithChar ('.');
525}
526
527 String URL::getDomainInternal (bool ignorePort) const
528{
529 auto start = URLHelpers::findStartOfNetLocation (url);
530 auto end1 = url.indexOfChar (start, '/');
531 auto end2 = ignorePort ? -1 : url.indexOfChar (start, ':');
532
533 auto end = (end1 < 0 && end2 < 0) ? std::numeric_limits<int>::max()
534 : ((end1 < 0 || end2 < 0) ? jmax (end1, end2)
535 : jmin (end1, end2));
536 return url.substring (start, end);
537}
538
539#if JUCE_IOS
540URL::Bookmark::Bookmark (void* bookmarkToUse) : data (bookmarkToUse)
541{
542}
543
544URL::Bookmark::~Bookmark()
545{
546 [(NSData*) data release];
547}
548
549 void setURLBookmark (URL& u, void* bookmark)
550{
551 u.bookmark = new URL::Bookmark (bookmark);
552}
553
554 void* getURLBookmark (URL& u)
555{
556 if (u.bookmark.get() == nullptr)
557 return nullptr;
558
559 return u.bookmark.get()->data;
560}
561
562 template <typename Stream> struct iOSFileStreamWrapperFlush { static void flush (Stream*) {} };
563 template <> struct iOSFileStreamWrapperFlush<FileOutputStream> { static void flush (OutputStream* o) { o->flush(); } };
564
565 template <typename Stream>
566 class iOSFileStreamWrapper : public Stream
567{
568 public:
569 iOSFileStreamWrapper (URL& urlToUse)
570 : Stream (getLocalFileAccess (urlToUse)),
571 url (urlToUse)
572 {}
573
574 ~iOSFileStreamWrapper()
575 {
576 iOSFileStreamWrapperFlush<Stream>::flush (this);
577
578 if (NSData* bookmark = (NSData*) getURLBookmark (url))
579 {
580 BOOL isBookmarkStale = false;
581 NSError* error = nil;
582
583 auto nsURL = [NSURL URLByResolvingBookmarkData: bookmark
584 options: 0
585 relativeToURL: nil
586 bookmarkDataIsStale: &isBookmarkStale
587 error: &error];
588
589 if (error == nil)
590 {
591 if (isBookmarkStale)
592 updateStaleBookmark (nsURL, url);
593
594 [nsURL stopAccessingSecurityScopedResource];
595 }
596 else
597 {
598 auto desc = [error localizedDescription];
599 ignoreUnused (desc);
600 jassertfalse;
601 }
602 }
603 }
604
605 private:
606 URL url;
607 bool securityAccessSucceeded = false;
608
609 File getLocalFileAccess (URL& urlToUse)
610 {
611 if (NSData* bookmark = (NSData*) getURLBookmark (urlToUse))
612 {
613 BOOL isBookmarkStale = false;
614 NSError* error = nil;
615
616 auto nsURL = [NSURL URLByResolvingBookmarkData: bookmark
617 options: 0
618 relativeToURL: nil
619 bookmarkDataIsStale: &isBookmarkStale
620 error: &error];
621
622 if (error == nil)
623 {
624 securityAccessSucceeded = [nsURL startAccessingSecurityScopedResource];
625
626 if (isBookmarkStale)
627 updateStaleBookmark (nsURL, urlToUse);
628
629 return urlToUse.getLocalFile();
630 }
631
632 auto desc = [error localizedDescription];
633 ignoreUnused (desc);
634 jassertfalse;
635 }
636
637 return urlToUse.getLocalFile();
638 }
639
640 void updateStaleBookmark (NSURL* nsURL, URL& juceUrl)
641 {
642 NSError* error = nil;
643
644 NSData* bookmark = [nsURL bookmarkDataWithOptions: NSURLBookmarkCreationSuitableForBookmarkFile
645 includingResourceValuesForKeys: nil
646 relativeToURL: nil
647 error: &error];
648
649 if (error == nil)
650 setURLBookmark (juceUrl, (void*) bookmark);
651 else
652 jassertfalse;
653 }
654};
655#endif
656
657//==============================================================================
658 InputStream* URL::createInputStream (bool usePostCommand,
659 OpenStreamProgressCallback* progressCallback,
660 void* progressCallbackContext,
661 String headers,
662 int timeOutMs,
663 StringPairArray* responseHeaders,
664 int* statusCode,
665 int numRedirectsToFollow,
666 String httpRequestCmd) const
667{
668 if (isLocalFile())
669 {
670 #if JUCE_IOS
671 // We may need to refresh the embedded bookmark.
672 return new iOSFileStreamWrapper<FileInputStream> (const_cast<URL&>(*this));
673 #else
674 return getLocalFile().createInputStream();
675 #endif
676 }
677
678 auto wi = std::make_unique<WebInputStream> (*this, usePostCommand);
679
680 struct ProgressCallbackCaller : public WebInputStream::Listener
681 {
682 ProgressCallbackCaller (OpenStreamProgressCallback* progressCallbackToUse, void* progressCallbackContextToUse)
683 : callback (progressCallbackToUse), data (progressCallbackContextToUse)
684 {}
685
686 bool postDataSendProgress (WebInputStream&, int bytesSent, int totalBytes) override
687 {
688 return callback (data, bytesSent, totalBytes);
689 }
690
691 OpenStreamProgressCallback* callback;
692 void* const data;
693 };
694
695 std::unique_ptr<ProgressCallbackCaller> callbackCaller
696 (progressCallback != nullptr ? new ProgressCallbackCaller (progressCallback, progressCallbackContext) : nullptr);
697
698 if (headers.isNotEmpty())
699 wi->withExtraHeaders (headers);
700
701 if (timeOutMs != 0)
702 wi->withConnectionTimeout (timeOutMs);
703
704 if (httpRequestCmd.isNotEmpty())
705 wi->withCustomRequestCommand (httpRequestCmd);
706
707 wi->withNumRedirectsToFollow (numRedirectsToFollow);
708
709 bool success = wi->connect (callbackCaller.get());
710
711 if (statusCode != nullptr)
712 *statusCode = wi->getStatusCode();
713
714 if (responseHeaders != nullptr)
715 *responseHeaders = wi->getResponseHeaders();
716
717 if (! success || wi->isError())
718 return nullptr;
719
720 return wi.release();
721}
722
723#if JUCE_ANDROID
724 OutputStream* juce_CreateContentURIOutputStream (const URL&);
725#endif
726
727 OutputStream* URL::createOutputStream() const
728{
729 if (isLocalFile())
730 {
731 #if JUCE_IOS
732 // We may need to refresh the embedded bookmark.
733 return new iOSFileStreamWrapper<FileOutputStream> (const_cast<URL&> (*this));
734 #else
735 return new FileOutputStream (getLocalFile());
736 #endif
737 }
738
739 #if JUCE_ANDROID
740 return juce_CreateContentURIOutputStream (*this);
741 #else
742 return nullptr;
743 #endif
744}
745
746//==============================================================================
747 bool URL::readEntireBinaryStream (MemoryBlock& destData, bool usePostCommand) const
748{
749 const std::unique_ptr<InputStream> in (isLocalFile() ? getLocalFile().createInputStream()
750 : createInputStream (usePostCommand));
751
752 if (in != nullptr)
753 {
754 in->readIntoMemoryBlock (destData);
755 return true;
756 }
757
758 return false;
759}
760
761 String URL::readEntireTextStream (bool usePostCommand) const
762{
763 const std::unique_ptr<InputStream> in (isLocalFile() ? getLocalFile().createInputStream()
764 : createInputStream (usePostCommand));
765
766 if (in != nullptr)
767 return in->readEntireStreamAsString();
768
769 return {};
770}
771
772std::unique_ptr<XmlElement> URL::readEntireXmlStream (bool usePostCommand) const
773{
774 return parseXML (readEntireTextStream (usePostCommand));
775}
776
777//==============================================================================
778 URL URL::withParameter (const String& parameterName,
779 const String& parameterValue) const
780{
781 auto u = *this;
782 u.addParameter (parameterName, parameterValue);
783 return u;
784}
785
786 URL URL::withParameters (const StringPairArray& parametersToAdd) const
787{
788 auto u = *this;
789
790 for (int i = 0; i < parametersToAdd.size(); ++i)
791 u.addParameter (parametersToAdd.getAllKeys()[i],
792 parametersToAdd.getAllValues()[i]);
793
794 return u;
795}
796
797 URL URL::withPOSTData (const String& newPostData) const
798{
799 return withPOSTData (MemoryBlock (newPostData.toRawUTF8(), newPostData.getNumBytesAsUTF8()));
800}
801
802 URL URL::withPOSTData (const MemoryBlock& newPostData) const
803{
804 auto u = *this;
805 u.postData = newPostData;
806 return u;
807}
808
809URL::Upload::Upload (const String& param, const String& name,
810 const String& mime, const File& f, MemoryBlock* mb)
811 : parameterName (param), filename (name), mimeType (mime), file (f), data (mb)
812{
813 jassert (mimeType.isNotEmpty()); // You need to supply a mime type!
814}
815
816URL URL::withUpload (Upload* const f) const
817{
818 auto u = *this;
819
820 for (int i = u.filesToUpload.size(); --i >= 0;)
821 if (u.filesToUpload.getObjectPointerUnchecked(i)->parameterName == f->parameterName)
822 u.filesToUpload.remove (i);
823
824 u.filesToUpload.add (f);
825 return u;
826}
827
828 URL URL::withFileToUpload (const String& parameterName, const File& fileToUpload,
829 const String& mimeType) const
830{
831 return withUpload (new Upload (parameterName, fileToUpload.getFileName(),
832 mimeType, fileToUpload, nullptr));
833}
834
835 URL URL::withDataToUpload (const String& parameterName, const String& filename,
836 const MemoryBlock& fileContentToUpload, const String& mimeType) const
837{
838 return withUpload (new Upload (parameterName, filename, mimeType, File(),
839 new MemoryBlock (fileContentToUpload)));
840}
841
842//==============================================================================
843 String URL::removeEscapeChars (const String& s)
844{
845 auto result = s.replaceCharacter ('+', ' ');
846
847 if (! result.containsChar ('%'))
848 return result;
849
850 // We need to operate on the string as raw UTF8 chars, and then recombine them into unicode
851 // after all the replacements have been made, so that multi-byte chars are handled.
852 Array<char> utf8 (result.toRawUTF8(), (int) result.getNumBytesAsUTF8());
853
854 for (int i = 0; i < utf8.size(); ++i)
855 {
856 if (utf8.getUnchecked(i) == '%')
857 {
858 auto hexDigit1 = CharacterFunctions::getHexDigitValue ((juce_wchar) (uint8) utf8 [i + 1]);
859 auto hexDigit2 = CharacterFunctions::getHexDigitValue ((juce_wchar) (uint8) utf8 [i + 2]);
860
861 if (hexDigit1 >= 0 && hexDigit2 >= 0)
862 {
863 utf8.set (i, (char) ((hexDigit1 << 4) + hexDigit2));
864 utf8.removeRange (i + 1, 2);
865 }
866 }
867 }
868
869 return String::fromUTF8 (utf8.getRawDataPointer(), utf8.size());
870}
871
872 String URL::addEscapeChars (const String& s, bool isParameter, bool roundBracketsAreLegal)
873{
874 String legalChars (isParameter ? "_-.~"
875 : ",$_-.*!'");
876
877 if (roundBracketsAreLegal)
878 legalChars += "()";
879
880 Array<char> utf8 (s.toRawUTF8(), (int) s.getNumBytesAsUTF8());
881
882 for (int i = 0; i < utf8.size(); ++i)
883 {
884 auto c = utf8.getUnchecked(i);
885
886 if (! (CharacterFunctions::isLetterOrDigit (c)
887 || legalChars.containsChar ((juce_wchar) c)))
888 {
889 utf8.set (i, '%');
890 utf8.insert (++i, "0123456789ABCDEF" [((uint8) c) >> 4]);
891 utf8.insert (++i, "0123456789ABCDEF" [c & 15]);
892 }
893 }
894
895 return String::fromUTF8 (utf8.getRawDataPointer(), utf8.size());
896}
897
898//==============================================================================
899 bool URL::launchInDefaultBrowser() const
900{
901 auto u = toString (true);
902
903 if (u.containsChar ('@') && ! u.containsChar (':'))
904 u = "mailto:" + u;
905
906 return Process::openDocument (u, {});
907}
908
909} // namespace juce
juce::Array
Definition: juce_Array.h:56
juce::Array::getUnchecked
ElementType getUnchecked(int index) const
Definition: juce_Array.h:252
juce::Array::size
int size() const noexcept
Definition: juce_Array.h:215
juce::Array::removeRange
void removeRange(int startIndex, int numberToRemove)
Definition: juce_Array.h:916
juce::Array::insert
void insert(int indexToInsertAt, ParameterType newElement)
Definition: juce_Array.h:462
juce::Array::getRawDataPointer
ElementType * getRawDataPointer() noexcept
Definition: juce_Array.h:310
juce::Array::set
void set(int indexToChange, ParameterType newValue)
Definition: juce_Array.h:542
juce::CharacterFunctions::getHexDigitValue
static int getHexDigitValue(juce_wchar digit) noexcept
Definition: juce_CharacterFunctions.cpp:117
juce::CharacterFunctions::isLetterOrDigit
static bool isLetterOrDigit(char character) noexcept
Definition: juce_CharacterFunctions.cpp:95
juce::FileOutputStream
Definition: juce_FileOutputStream.h:35
juce::File
Definition: juce_File.h:41
juce::File::createOutputStream
FileOutputStream * createOutputStream(size_t bufferSize=0x8000) const
Definition: juce_File.cpp:739
juce::File::getFullPathName
const String & getFullPathName() const noexcept
Definition: juce_File.h:149
juce::File::getFileName
String getFileName() const
Definition: juce_File.cpp:366
juce::File::isRoot
bool isRoot() const
Definition: juce_File.cpp:127
juce::File::createInputStream
FileInputStream * createInputStream() const
Definition: juce_File.cpp:729
juce::File::getParentDirectory
File getParentDirectory() const
Definition: juce_File.cpp:360
juce::File::deleteFile
bool deleteFile() const
juce::File::getSeparatorString
static StringRef getSeparatorString()
juce::InputStream
Definition: juce_InputStream.h:37
juce::MemoryBlock
Definition: juce_MemoryBlock.h:33
juce::MemoryBlock::getSize
size_t getSize() const noexcept
Definition: juce_MemoryBlock.h:124
juce::MemoryOutputStream
Definition: juce_MemoryOutputStream.h:36
juce::OutputStream
Definition: juce_OutputStream.h:38
juce::Process::openDocument
static bool JUCE_CALLTYPE openDocument(const String &documentURL, const String &parameters)
juce::Random::getSystemRandom
static Random & getSystemRandom() noexcept
Definition: juce_Random.cpp:71
juce::ReferenceCountedArray::size
int size() const noexcept
Definition: juce_ReferenceCountedArray.h:150
juce::StringArray::fromTokens
static StringArray fromTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
Definition: juce_StringArray.cpp:386
juce::StringArray::size
int size() const noexcept
Definition: juce_StringArray.h:135
juce::StringArray::add
void add(String stringToAdd)
Definition: juce_StringArray.cpp:135
juce::StringPairArray
Definition: juce_StringPairArray.h:35
juce::StringPairArray::getAllValues
const StringArray & getAllValues() const noexcept
Definition: juce_StringPairArray.h:90
juce::StringPairArray::size
int size() const noexcept
Definition: juce_StringPairArray.h:93
juce::StringPairArray::getAllKeys
const StringArray & getAllKeys() const noexcept
Definition: juce_StringPairArray.h:87
juce::String
Definition: juce_String.h:39
juce::String::indexOfChar
int indexOfChar(juce_wchar characterToLookFor) const noexcept
Definition: juce_String.cpp:885
juce::String::upToFirstOccurrenceOf
String upToFirstOccurrenceOf(StringRef substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const
Definition: juce_String.cpp:1596
juce::String::endsWithChar
bool endsWithChar(juce_wchar character) const noexcept
Definition: juce_String.cpp:1421
juce::String::toRawUTF8
const char * toRawUTF8() const
Definition: juce_String.cpp:2077
juce::String::containsIgnoreCase
bool containsIgnoreCase(StringRef text) const noexcept
Definition: juce_String.cpp:1056
juce::String::startsWithChar
bool startsWithChar(juce_wchar character) const noexcept
Definition: juce_String.cpp:1414
juce::String::startsWith
bool startsWith(StringRef text) const noexcept
Definition: juce_String.cpp:1404
juce::String::containsChar
bool containsChar(juce_wchar character) const noexcept
Definition: juce_String.cpp:1051
juce::String::startsWithIgnoreCase
bool startsWithIgnoreCase(StringRef text) const noexcept
Definition: juce_String.cpp:1409
juce::String::getNumBytesAsUTF8
size_t getNumBytesAsUTF8() const noexcept
Definition: juce_String.cpp:2123
juce::String::toHexString
static String toHexString(IntegerType number)
Definition: juce_String.h:1053
juce::String::lastIndexOfChar
int lastIndexOfChar(juce_wchar character) const noexcept
Definition: juce_String.cpp:910
juce::String::replace
String replace(StringRef stringToReplace, StringRef stringToInsertInstead, bool ignoreCase=false) const
Definition: juce_String.cpp:1290
juce::String::replaceCharacter
String replaceCharacter(juce_wchar characterToReplace, juce_wchar characterToInsertInstead) const
Definition: juce_String.cpp:1355
juce::String::substring
String substring(int startIndex, int endIndex) const
Definition: juce_String.cpp:1509
juce::String::fromLastOccurrenceOf
String fromLastOccurrenceOf(StringRef substringToFind, bool includeSubStringInResult, bool ignoreCase) const
Definition: juce_String.cpp:1586
juce::String::fromUTF8
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
Definition: juce_String.cpp:2128
juce::String::isNotEmpty
bool isNotEmpty() const noexcept
Definition: juce_String.h:302
juce::String::fromFirstOccurrenceOf
String fromFirstOccurrenceOf(StringRef substringToStartFrom, bool includeSubStringInResult, bool ignoreCase) const
Definition: juce_String.cpp:1576
juce::Thread::startThread
void startThread()
Definition: juce_Thread.cpp:122
juce::Thread::waitForThreadToExit
bool waitForThreadToExit(int timeOutMilliseconds) const
Definition: juce_Thread.cpp:195
juce::Thread::Thread
Thread(const String &threadName, size_t threadStackSize=0)
Definition: juce_Thread.cpp:26
juce::Thread::threadShouldExit
bool threadShouldExit() const
Definition: juce_Thread.cpp:182
juce::Thread::signalThreadShouldExit
void signalThreadShouldExit()
Definition: juce_Thread.cpp:176
juce::URL::DownloadTask
Definition: juce_URL.h:365
juce::URL::DownloadTask::~DownloadTask
virtual ~DownloadTask()
Definition: juce_URL.cpp:135
juce::URL
Definition: juce_URL.h:38
juce::URL::withParameter
URL withParameter(const String &parameterName, const String &parameterValue) const
Definition: juce_URL.cpp:778
juce::URL::createWithoutParsing
static URL createWithoutParsing(const String &url)
Definition: juce_URL.cpp:211
juce::URL::getLocalFile
File getLocalFile() const
Definition: juce_URL.cpp:366
juce::URL::isWellFormed
bool isWellFormed() const
Definition: juce_URL.cpp:324
juce::URL::readEntireBinaryStream
bool readEntireBinaryStream(MemoryBlock &destData, bool usePostCommand=false) const
Definition: juce_URL.cpp:747
juce::URL::getPort
int getPort() const
Definition: juce_URL.cpp:406
juce::URL::createOutputStream
OutputStream * createOutputStream() const
Definition: juce_URL.cpp:727
juce::URL::withDataToUpload
URL withDataToUpload(const String &parameterName, const String &filename, const MemoryBlock &fileContentToUpload, const String &mimeType) const
Definition: juce_URL.cpp:835
juce::URL::getFileName
String getFileName() const
Definition: juce_URL.cpp:371
juce::URL::getChildURL
URL getChildURL(const String &subPath) const
Definition: juce_URL.cpp:440
juce::URL::removeEscapeChars
static String removeEscapeChars(const String &stringToRemoveEscapeCharsFrom)
Definition: juce_URL.cpp:843
juce::URL::addEscapeChars
static String addEscapeChars(const String &stringToAddEscapeCharsTo, bool isParameter, bool roundBracketsAreLegal=true)
Definition: juce_URL.cpp:872
juce::URL::toString
String toString(bool includeGetParameters) const
Definition: juce_URL.cpp:311
juce::URL::getSubPath
String getSubPath(bool includeGetParameters=false) const
Definition: juce_URL.cpp:335
juce::URL::getParentURL
URL getParentURL() const
Definition: juce_URL.cpp:433
juce::URL::getQueryString
String getQueryString() const
Definition: juce_URL.cpp:347
juce::URL::withNewSubPath
URL withNewSubPath(const String &newPath) const
Definition: juce_URL.cpp:420
juce::URL::isProbablyAnEmailAddress
static bool isProbablyAnEmailAddress(const String &possibleEmailAddress)
Definition: juce_URL.cpp:518
juce::URL::withNewDomainAndPath
URL withNewDomainAndPath(const String &newFullPath) const
Definition: juce_URL.cpp:413
juce::URL::createInputStream
InputStream * createInputStream(bool doPostLikeRequest, OpenStreamProgressCallback *progressCallback=nullptr, void *progressCallbackContext=nullptr, String extraHeaders={}, int connectionTimeOutMs=0, StringPairArray *responseHeaders=nullptr, int *statusCode=nullptr, int numRedirectsToFollow=5, String httpRequestCmd={}) const
Definition: juce_URL.cpp:658
juce::URL::readEntireTextStream
String readEntireTextStream(bool usePostCommand=false) const
Definition: juce_URL.cpp:761
juce::URL::isEmpty
bool isEmpty() const noexcept
Definition: juce_URL.cpp:319
juce::URL::isProbablyAWebsiteURL
static bool isProbablyAWebsiteURL(const String &possibleURL)
Definition: juce_URL.cpp:503
juce::URL::OpenStreamProgressCallback
bool(void *context, int bytesSent, int totalBytes) OpenStreamProgressCallback
Definition: juce_URL.h:299
juce::URL::getDomain
String getDomain() const
Definition: juce_URL.cpp:330
juce::URL::isLocalFile
bool isLocalFile() const
Definition: juce_URL.cpp:361
juce::URL::withFileToUpload
URL withFileToUpload(const String &parameterName, const File &fileToUpload, const String &mimeType) const
Definition: juce_URL.cpp:828
juce::URL::withPOSTData
URL withPOSTData(const String &postData) const
Definition: juce_URL.cpp:797
juce::URL::withParameters
URL withParameters(const StringPairArray &parametersToAdd) const
Definition: juce_URL.cpp:786
juce::URL::readEntireXmlStream
std::unique_ptr< XmlElement > readEntireXmlStream(bool usePostCommand=false) const
Definition: juce_URL.cpp:772
juce::URL::getScheme
String getScheme() const
Definition: juce_URL.cpp:355
juce::URL::operator==
bool operator==(const URL &) const
Definition: juce_URL.cpp:216
juce::URL::launchInDefaultBrowser
bool launchInDefaultBrowser() const
Definition: juce_URL.cpp:899
juce::URL::URL
URL()
Definition: juce_URL.cpp:138
juce::WebInputStream::Listener
Definition: juce_WebInputStream.h:37
juce::WebInputStream
Definition: juce_WebInputStream.h:33
juce::URL::DownloadTask::Listener::progress
virtual void progress(URL::DownloadTask *task, int64 bytesDownloaded, int64 totalLength)
Definition: juce_URL.cpp:109