mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-18 00:54:19 +00:00
This commit is contained in:
parent
27ff7115db
commit
78f413bf50
1 changed files with 469 additions and 439 deletions
|
|
@ -1,439 +1,469 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified under the terms of the
|
||||
GNU General Public License, as published by the Free Software Foundation;
|
||||
either version 2 of the License, or (at your option) any later version.
|
||||
|
||||
JUCE is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "juce_mac_NativeHeaders.h"
|
||||
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/network/IOEthernetInterface.h>
|
||||
#include <IOKit/network/IONetworkInterface.h>
|
||||
#include <IOKit/network/IOEthernetController.h>
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "../../../src/juce_core/text/juce_String.h"
|
||||
#include "../../../src/juce_core/basics/juce_Time.h"
|
||||
#include "../../../src/juce_core/basics/juce_SystemStats.h"
|
||||
#include "../../../src/juce_core/basics/juce_Logger.h"
|
||||
#include "../../../src/juce_core/threads/juce_ScopedLock.h"
|
||||
#include "../../../src/juce_core/threads/juce_WaitableEvent.h"
|
||||
#include "../../../src/juce_core/threads/juce_Thread.h"
|
||||
#include "../../../src/juce_core/containers/juce_MemoryBlock.h"
|
||||
#include "../../../src/juce_core/text/juce_StringArray.h"
|
||||
#include "../../../src/juce_core/misc/juce_PlatformUtilities.h"
|
||||
#include "../../../src/juce_core/io/network/juce_URL.h"
|
||||
|
||||
//#include "juce_mac_HTTPStream.h"
|
||||
|
||||
//==============================================================================
|
||||
static bool GetEthernetIterator (io_iterator_t* matchingServices) throw()
|
||||
{
|
||||
mach_port_t masterPort;
|
||||
|
||||
if (IOMasterPort (MACH_PORT_NULL, &masterPort) == KERN_SUCCESS)
|
||||
{
|
||||
CFMutableDictionaryRef dict = IOServiceMatching (kIOEthernetInterfaceClass);
|
||||
|
||||
if (dict != 0)
|
||||
{
|
||||
CFMutableDictionaryRef propDict = CFDictionaryCreateMutable (kCFAllocatorDefault,
|
||||
0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
if (propDict != 0)
|
||||
{
|
||||
CFDictionarySetValue (propDict, CFSTR (kIOPrimaryInterface), kCFBooleanTrue);
|
||||
|
||||
CFDictionarySetValue (dict, CFSTR (kIOPropertyMatchKey), propDict);
|
||||
CFRelease (propDict);
|
||||
}
|
||||
}
|
||||
|
||||
return IOServiceGetMatchingServices (masterPort, dict, matchingServices) == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian) throw()
|
||||
{
|
||||
int numResults = 0;
|
||||
io_iterator_t it;
|
||||
|
||||
if (GetEthernetIterator (&it))
|
||||
{
|
||||
io_object_t i;
|
||||
|
||||
while ((i = IOIteratorNext (it)) != 0)
|
||||
{
|
||||
io_object_t controller;
|
||||
|
||||
if (IORegistryEntryGetParentEntry (i, kIOServicePlane, &controller) == KERN_SUCCESS)
|
||||
{
|
||||
CFTypeRef data = IORegistryEntryCreateCFProperty (controller,
|
||||
CFSTR (kIOMACAddress),
|
||||
kCFAllocatorDefault,
|
||||
0);
|
||||
if (data != 0)
|
||||
{
|
||||
UInt8 addr [kIOEthernetAddressSize];
|
||||
zeromem (addr, sizeof (addr));
|
||||
|
||||
CFDataGetBytes ((CFDataRef) data, CFRangeMake (0, sizeof (addr)), addr);
|
||||
CFRelease (data);
|
||||
|
||||
int64 a = 0;
|
||||
for (int i = 6; --i >= 0;)
|
||||
a = (a << 8) | addr[i];
|
||||
|
||||
if (! littleEndian)
|
||||
a = (int64) swapByteOrder ((uint64) a);
|
||||
|
||||
if (numResults < maxNum)
|
||||
{
|
||||
*addresses++ = a;
|
||||
++numResults;
|
||||
}
|
||||
}
|
||||
|
||||
IOObjectRelease (controller);
|
||||
}
|
||||
|
||||
IOObjectRelease (i);
|
||||
}
|
||||
|
||||
IOObjectRelease (it);
|
||||
}
|
||||
|
||||
return numResults;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAddress,
|
||||
const String& emailSubject,
|
||||
const String& bodyText,
|
||||
const StringArray& filesToAttach)
|
||||
{
|
||||
const AutoPool pool;
|
||||
|
||||
String script;
|
||||
script << "tell application \"Mail\"\r\n"
|
||||
"set newMessage to make new outgoing message with properties {subject:\""
|
||||
<< emailSubject.replace (T("\""), T("\\\""))
|
||||
<< "\", content:\""
|
||||
<< bodyText.replace (T("\""), T("\\\""))
|
||||
<< "\" & return & return}\r\n"
|
||||
"tell newMessage\r\n"
|
||||
"set visible to true\r\n"
|
||||
"set sender to \"sdfsdfsdfewf\"\r\n"
|
||||
"make new to recipient at end of to recipients with properties {address:\""
|
||||
<< targetEmailAddress
|
||||
<< "\"}\r\n";
|
||||
|
||||
for (int i = 0; i < filesToAttach.size(); ++i)
|
||||
{
|
||||
script << "tell content\r\n"
|
||||
"make new attachment with properties {file name:\""
|
||||
<< filesToAttach[i].replace (T("\""), T("\\\""))
|
||||
<< "\"} at after the last paragraph\r\n"
|
||||
"end tell\r\n";
|
||||
}
|
||||
|
||||
script << "end tell\r\n"
|
||||
"end tell\r\n";
|
||||
|
||||
NSAppleScript* s = [[NSAppleScript alloc]
|
||||
initWithSource: [NSString stringWithUTF8String: (const char*) script.toUTF8()]];
|
||||
NSDictionary* error = 0;
|
||||
const bool ok = [s executeAndReturnError: &error] != nil;
|
||||
[s release];
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
END_JUCE_NAMESPACE
|
||||
|
||||
using namespace JUCE_NAMESPACE;
|
||||
|
||||
@interface JuceURLConnection : NSInputStream
|
||||
{
|
||||
NSURLConnection* connection;
|
||||
NSMutableData* data;
|
||||
NSThread* runLoopThread;
|
||||
NSRunLoop* runLoop;
|
||||
bool initialised, hasFailed, hasFinished;
|
||||
int position;
|
||||
NSLock* dataLock;
|
||||
}
|
||||
|
||||
- (JuceURLConnection*) initWithRequest: (NSURLRequest*) req;
|
||||
- (void) dealloc;
|
||||
- (void) connection: (NSURLConnection*) connection didReceiveResponse: (NSURLResponse*) response;
|
||||
- (void) connection: (NSURLConnection*) connection didFailWithError: (NSError*) error;
|
||||
- (void) connection: (NSURLConnection*) connection didReceiveData: (NSData*) data;
|
||||
- (void) connectionDidFinishLoading: (NSURLConnection*) connection;
|
||||
|
||||
- (BOOL) isOpen;
|
||||
- (int) read: (char*) dest numBytes: (int) num;
|
||||
- (int) readPosition;
|
||||
|
||||
- (void) runThread: (id) dummyParam;
|
||||
|
||||
@end
|
||||
|
||||
@implementation JuceURLConnection
|
||||
|
||||
- (JuceURLConnection*) initWithRequest: (NSURLRequest*) req
|
||||
{
|
||||
[super init];
|
||||
data = [[NSMutableData data] retain];
|
||||
dataLock = [[NSLock alloc] init];
|
||||
connection = 0;
|
||||
initialised = false;
|
||||
hasFailed = false;
|
||||
hasFinished = false;
|
||||
|
||||
runLoopThread = [[NSThread alloc] initWithTarget: self
|
||||
selector: @selector (runThread:)
|
||||
object: req];
|
||||
|
||||
[runLoopThread start];
|
||||
|
||||
while (! [runLoopThread isExecuting])
|
||||
Thread::sleep (1);
|
||||
|
||||
while ([runLoopThread isExecuting] && ! initialised)
|
||||
Thread::sleep (1);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[connection cancel];
|
||||
[runLoopThread cancel];
|
||||
|
||||
while ([runLoopThread isExecuting])
|
||||
[NSThread sleepForTimeInterval: 0.001];
|
||||
|
||||
[runLoopThread release];
|
||||
[connection release];
|
||||
[data release];
|
||||
[dataLock release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) runThread: (id) request
|
||||
{
|
||||
AutoPool pool;
|
||||
|
||||
runLoop = [NSRunLoop currentRunLoop];
|
||||
|
||||
connection = [[NSURLConnection alloc] initWithRequest: request
|
||||
delegate: self
|
||||
startImmediately: YES];
|
||||
|
||||
if (connection == nil)
|
||||
{
|
||||
hasFailed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
initialised = true;
|
||||
|
||||
while (! ([[NSThread currentThread] isCancelled] || hasFailed || hasFinished))
|
||||
{
|
||||
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) connection: (NSURLConnection*) connection didReceiveResponse: (NSURLResponse*) response
|
||||
{
|
||||
[dataLock lock];
|
||||
[data setLength: 0];
|
||||
[dataLock unlock];
|
||||
}
|
||||
|
||||
- (void) connection: (NSURLConnection*) connection didFailWithError: (NSError*) error
|
||||
{
|
||||
NSLog ([error description]);
|
||||
hasFailed = true;
|
||||
}
|
||||
|
||||
- (void) connection: (NSURLConnection*) connection didReceiveData: (NSData*) newData
|
||||
{
|
||||
[dataLock lock];
|
||||
[data appendData: newData];
|
||||
[dataLock unlock];
|
||||
}
|
||||
|
||||
- (void) connectionDidFinishLoading: (NSURLConnection*) connection
|
||||
{
|
||||
hasFinished = true;
|
||||
}
|
||||
|
||||
- (BOOL) isOpen
|
||||
{
|
||||
return connection != 0 && ! hasFailed;
|
||||
}
|
||||
|
||||
- (int) readPosition
|
||||
{
|
||||
return position;
|
||||
}
|
||||
|
||||
- (int) read: (char*) dest numBytes: (int) numNeeded
|
||||
{
|
||||
int numDone = 0;
|
||||
|
||||
while (numNeeded > 0)
|
||||
{
|
||||
int available = jmin (numNeeded, [data length]);
|
||||
|
||||
if (available > 0)
|
||||
{
|
||||
[dataLock lock];
|
||||
[data getBytes: dest length: available];
|
||||
[data replaceBytesInRange: NSMakeRange (0, available) withBytes: nil length: 0];
|
||||
[dataLock unlock];
|
||||
|
||||
numDone += available;
|
||||
numNeeded -= available;
|
||||
dest += available;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasFailed || hasFinished)
|
||||
break;
|
||||
|
||||
Thread::sleep (1);
|
||||
}
|
||||
}
|
||||
|
||||
position += numDone;
|
||||
return numDone;
|
||||
}
|
||||
|
||||
@end
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
|
||||
bool juce_isOnLine()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void* juce_openInternetFile (const String& url,
|
||||
const String& headers,
|
||||
const MemoryBlock& postData,
|
||||
const bool isPost,
|
||||
URL::OpenStreamProgressCallback* callback,
|
||||
void* callbackContext,
|
||||
int timeOutMs)
|
||||
{
|
||||
AutoPool pool;
|
||||
|
||||
NSMutableURLRequest* req = [NSMutableURLRequest
|
||||
requestWithURL: [NSURL URLWithString: juceStringToNS (url)]
|
||||
cachePolicy: NSURLRequestUseProtocolCachePolicy
|
||||
timeoutInterval: timeOutMs <= 0 ? 60.0 : (timeOutMs / 1000.0)];
|
||||
|
||||
if (req == nil)
|
||||
return 0;
|
||||
|
||||
[req setHTTPMethod: isPost ? @"POST" : @"GET"];
|
||||
//[req setCachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData];
|
||||
|
||||
StringArray headerLines;
|
||||
headerLines.addLines (headers);
|
||||
headerLines.removeEmptyStrings (true);
|
||||
|
||||
for (int i = 0; i < headerLines.size(); ++i)
|
||||
{
|
||||
const String key (headerLines[i].upToFirstOccurrenceOf (T(":"), false, false).trim());
|
||||
const String value (headerLines[i].fromFirstOccurrenceOf (T(":"), false, false).trim());
|
||||
|
||||
if (key.isNotEmpty() && value.isNotEmpty())
|
||||
[req addValue: juceStringToNS (value) forHTTPHeaderField: juceStringToNS (key)];
|
||||
}
|
||||
|
||||
if (isPost && postData.getSize() > 0)
|
||||
{
|
||||
[req setHTTPBody: [NSData dataWithBytes: postData.getData()
|
||||
length: postData.getSize()]];
|
||||
}
|
||||
|
||||
JuceURLConnection* const s = [[JuceURLConnection alloc] initWithRequest: req];
|
||||
|
||||
if ([s isOpen])
|
||||
return s;
|
||||
|
||||
delete s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void juce_closeInternetFile (void* handle)
|
||||
{
|
||||
JuceURLConnection* const s = (JuceURLConnection*) handle;
|
||||
|
||||
if (s != 0)
|
||||
{
|
||||
AutoPool pool;
|
||||
[s release];
|
||||
}
|
||||
}
|
||||
|
||||
int juce_readFromInternetFile (void* handle, void* buffer, int bytesToRead)
|
||||
{
|
||||
JuceURLConnection* const s = (JuceURLConnection*) handle;
|
||||
|
||||
if (s != 0)
|
||||
{
|
||||
AutoPool pool;
|
||||
return [s read: (char*) buffer numBytes: bytesToRead];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int juce_seekInInternetFile (void* handle, int newPosition)
|
||||
{
|
||||
JuceURLConnection* const s = (JuceURLConnection*) handle;
|
||||
|
||||
if (s != 0)
|
||||
return [s readPosition];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified under the terms of the
|
||||
GNU General Public License, as published by the Free Software Foundation;
|
||||
either version 2 of the License, or (at your option) any later version.
|
||||
|
||||
JUCE is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "juce_mac_NativeHeaders.h"
|
||||
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/network/IOEthernetInterface.h>
|
||||
#include <IOKit/network/IONetworkInterface.h>
|
||||
#include <IOKit/network/IOEthernetController.h>
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "../../../src/juce_core/text/juce_String.h"
|
||||
#include "../../../src/juce_core/basics/juce_Time.h"
|
||||
#include "../../../src/juce_core/basics/juce_SystemStats.h"
|
||||
#include "../../../src/juce_core/basics/juce_Logger.h"
|
||||
#include "../../../src/juce_core/threads/juce_ScopedLock.h"
|
||||
#include "../../../src/juce_core/threads/juce_WaitableEvent.h"
|
||||
#include "../../../src/juce_core/threads/juce_Thread.h"
|
||||
#include "../../../src/juce_core/containers/juce_MemoryBlock.h"
|
||||
#include "../../../src/juce_core/text/juce_StringArray.h"
|
||||
#include "../../../src/juce_core/misc/juce_PlatformUtilities.h"
|
||||
#include "../../../src/juce_core/io/network/juce_URL.h"
|
||||
|
||||
//#include "juce_mac_HTTPStream.h"
|
||||
|
||||
//==============================================================================
|
||||
static bool GetEthernetIterator (io_iterator_t* matchingServices) throw()
|
||||
{
|
||||
mach_port_t masterPort;
|
||||
|
||||
if (IOMasterPort (MACH_PORT_NULL, &masterPort) == KERN_SUCCESS)
|
||||
{
|
||||
CFMutableDictionaryRef dict = IOServiceMatching (kIOEthernetInterfaceClass);
|
||||
|
||||
if (dict != 0)
|
||||
{
|
||||
CFMutableDictionaryRef propDict = CFDictionaryCreateMutable (kCFAllocatorDefault,
|
||||
0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
if (propDict != 0)
|
||||
{
|
||||
CFDictionarySetValue (propDict, CFSTR (kIOPrimaryInterface), kCFBooleanTrue);
|
||||
|
||||
CFDictionarySetValue (dict, CFSTR (kIOPropertyMatchKey), propDict);
|
||||
CFRelease (propDict);
|
||||
}
|
||||
}
|
||||
|
||||
return IOServiceGetMatchingServices (masterPort, dict, matchingServices) == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian) throw()
|
||||
{
|
||||
int numResults = 0;
|
||||
io_iterator_t it;
|
||||
|
||||
if (GetEthernetIterator (&it))
|
||||
{
|
||||
io_object_t i;
|
||||
|
||||
while ((i = IOIteratorNext (it)) != 0)
|
||||
{
|
||||
io_object_t controller;
|
||||
|
||||
if (IORegistryEntryGetParentEntry (i, kIOServicePlane, &controller) == KERN_SUCCESS)
|
||||
{
|
||||
CFTypeRef data = IORegistryEntryCreateCFProperty (controller,
|
||||
CFSTR (kIOMACAddress),
|
||||
kCFAllocatorDefault,
|
||||
0);
|
||||
if (data != 0)
|
||||
{
|
||||
UInt8 addr [kIOEthernetAddressSize];
|
||||
zeromem (addr, sizeof (addr));
|
||||
|
||||
CFDataGetBytes ((CFDataRef) data, CFRangeMake (0, sizeof (addr)), addr);
|
||||
CFRelease (data);
|
||||
|
||||
int64 a = 0;
|
||||
for (int i = 6; --i >= 0;)
|
||||
a = (a << 8) | addr[i];
|
||||
|
||||
if (! littleEndian)
|
||||
a = (int64) swapByteOrder ((uint64) a);
|
||||
|
||||
if (numResults < maxNum)
|
||||
{
|
||||
*addresses++ = a;
|
||||
++numResults;
|
||||
}
|
||||
}
|
||||
|
||||
IOObjectRelease (controller);
|
||||
}
|
||||
|
||||
IOObjectRelease (i);
|
||||
}
|
||||
|
||||
IOObjectRelease (it);
|
||||
}
|
||||
|
||||
return numResults;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAddress,
|
||||
const String& emailSubject,
|
||||
const String& bodyText,
|
||||
const StringArray& filesToAttach)
|
||||
{
|
||||
const AutoPool pool;
|
||||
|
||||
String script;
|
||||
script << "tell application \"Mail\"\r\n"
|
||||
"set newMessage to make new outgoing message with properties {subject:\""
|
||||
<< emailSubject.replace (T("\""), T("\\\""))
|
||||
<< "\", content:\""
|
||||
<< bodyText.replace (T("\""), T("\\\""))
|
||||
<< "\" & return & return}\r\n"
|
||||
"tell newMessage\r\n"
|
||||
"set visible to true\r\n"
|
||||
"set sender to \"sdfsdfsdfewf\"\r\n"
|
||||
"make new to recipient at end of to recipients with properties {address:\""
|
||||
<< targetEmailAddress
|
||||
<< "\"}\r\n";
|
||||
|
||||
for (int i = 0; i < filesToAttach.size(); ++i)
|
||||
{
|
||||
script << "tell content\r\n"
|
||||
"make new attachment with properties {file name:\""
|
||||
<< filesToAttach[i].replace (T("\""), T("\\\""))
|
||||
<< "\"} at after the last paragraph\r\n"
|
||||
"end tell\r\n";
|
||||
}
|
||||
|
||||
script << "end tell\r\n"
|
||||
"end tell\r\n";
|
||||
|
||||
NSAppleScript* s = [[NSAppleScript alloc]
|
||||
initWithSource: [NSString stringWithUTF8String: (const char*) script.toUTF8()]];
|
||||
NSDictionary* error = 0;
|
||||
const bool ok = [s executeAndReturnError: &error] != nil;
|
||||
[s release];
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
END_JUCE_NAMESPACE
|
||||
|
||||
using namespace JUCE_NAMESPACE;
|
||||
|
||||
//==============================================================================
|
||||
@interface JuceURLConnection : NSObject
|
||||
{
|
||||
NSURLRequest* request;
|
||||
NSURLConnection* connection;
|
||||
NSMutableData* data;
|
||||
Thread* runLoopThread;
|
||||
bool initialised, hasFailed, hasFinished;
|
||||
int position;
|
||||
NSLock* dataLock;
|
||||
}
|
||||
|
||||
- (JuceURLConnection*) initWithRequest: (NSURLRequest*) req withCallback: (URL::OpenStreamProgressCallback*) callback withContext: (void*) context;
|
||||
- (void) dealloc;
|
||||
- (void) connection: (NSURLConnection*) connection didReceiveResponse: (NSURLResponse*) response;
|
||||
- (void) connection: (NSURLConnection*) connection didFailWithError: (NSError*) error;
|
||||
- (void) connection: (NSURLConnection*) connection didReceiveData: (NSData*) data;
|
||||
- (void) connectionDidFinishLoading: (NSURLConnection*) connection;
|
||||
|
||||
- (BOOL) isOpen;
|
||||
- (int) read: (char*) dest numBytes: (int) num;
|
||||
- (int) readPosition;
|
||||
- (void) stop;
|
||||
- (void) createConnection;
|
||||
|
||||
@end
|
||||
|
||||
class JuceURLConnectionMessageThread : public Thread
|
||||
{
|
||||
JuceURLConnection* owner;
|
||||
|
||||
public:
|
||||
JuceURLConnectionMessageThread (JuceURLConnection* owner_)
|
||||
: Thread (T("http connection")),
|
||||
owner (owner_)
|
||||
{
|
||||
startThread();
|
||||
}
|
||||
|
||||
~JuceURLConnectionMessageThread()
|
||||
{
|
||||
stopThread (5000);
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
AutoPool pool;
|
||||
[owner createConnection];
|
||||
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
AutoPool pool;
|
||||
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@implementation JuceURLConnection
|
||||
|
||||
- (JuceURLConnection*) initWithRequest: (NSURLRequest*) req
|
||||
withCallback: (URL::OpenStreamProgressCallback*) callback
|
||||
withContext: (void*) context;
|
||||
{
|
||||
[super init];
|
||||
request = req;
|
||||
[request retain];
|
||||
data = [[NSMutableData data] retain];
|
||||
dataLock = [[NSLock alloc] init];
|
||||
connection = 0;
|
||||
initialised = false;
|
||||
hasFailed = false;
|
||||
hasFinished = false;
|
||||
|
||||
runLoopThread = new JuceURLConnectionMessageThread (self);
|
||||
|
||||
while (runLoopThread->isThreadRunning() && ! initialised)
|
||||
{
|
||||
if (callback != 0)
|
||||
callback (context, -1, [[request HTTPBody] length]);
|
||||
|
||||
Thread::sleep (1);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[self stop];
|
||||
|
||||
delete runLoopThread;
|
||||
[connection release];
|
||||
[data release];
|
||||
[dataLock release];
|
||||
[request release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) createConnection
|
||||
{
|
||||
connection = [[NSURLConnection alloc] initWithRequest: request
|
||||
delegate: self];
|
||||
|
||||
if (connection == nil)
|
||||
runLoopThread->signalThreadShouldExit();
|
||||
}
|
||||
|
||||
- (void) connection: (NSURLConnection*) connection didReceiveResponse: (NSURLResponse*) response
|
||||
{
|
||||
[dataLock lock];
|
||||
[data setLength: 0];
|
||||
[dataLock unlock];
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
- (void) connection: (NSURLConnection*) connection didFailWithError: (NSError*) error
|
||||
{
|
||||
NSLog ([error description]);
|
||||
hasFailed = true;
|
||||
initialised = true;
|
||||
runLoopThread->signalThreadShouldExit();
|
||||
}
|
||||
|
||||
- (void) connection: (NSURLConnection*) connection didReceiveData: (NSData*) newData
|
||||
{
|
||||
[dataLock lock];
|
||||
[data appendData: newData];
|
||||
[dataLock unlock];
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
- (void) connectionDidFinishLoading: (NSURLConnection*) connection
|
||||
{
|
||||
hasFinished = true;
|
||||
initialised = true;
|
||||
runLoopThread->signalThreadShouldExit();
|
||||
}
|
||||
|
||||
- (BOOL) isOpen
|
||||
{
|
||||
return connection != 0 && ! hasFailed;
|
||||
}
|
||||
|
||||
- (int) readPosition
|
||||
{
|
||||
return position;
|
||||
}
|
||||
|
||||
- (int) read: (char*) dest numBytes: (int) numNeeded
|
||||
{
|
||||
int numDone = 0;
|
||||
|
||||
while (numNeeded > 0)
|
||||
{
|
||||
int available = jmin (numNeeded, [data length]);
|
||||
|
||||
if (available > 0)
|
||||
{
|
||||
[dataLock lock];
|
||||
[data getBytes: dest length: available];
|
||||
[data replaceBytesInRange: NSMakeRange (0, available) withBytes: nil length: 0];
|
||||
[dataLock unlock];
|
||||
|
||||
numDone += available;
|
||||
numNeeded -= available;
|
||||
dest += available;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasFailed || hasFinished)
|
||||
break;
|
||||
|
||||
Thread::sleep (1);
|
||||
}
|
||||
}
|
||||
|
||||
position += numDone;
|
||||
return numDone;
|
||||
}
|
||||
|
||||
- (void) stop
|
||||
{
|
||||
[connection cancel];
|
||||
runLoopThread->stopThread (5000);
|
||||
}
|
||||
|
||||
@end
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
|
||||
bool juce_isOnLine()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void* juce_openInternetFile (const String& url,
|
||||
const String& headers,
|
||||
const MemoryBlock& postData,
|
||||
const bool isPost,
|
||||
URL::OpenStreamProgressCallback* callback,
|
||||
void* callbackContext,
|
||||
int timeOutMs)
|
||||
{
|
||||
AutoPool pool;
|
||||
|
||||
NSMutableURLRequest* req = [NSMutableURLRequest
|
||||
requestWithURL: [NSURL URLWithString: juceStringToNS (url)]
|
||||
cachePolicy: NSURLRequestUseProtocolCachePolicy
|
||||
timeoutInterval: timeOutMs <= 0 ? 60.0 : (timeOutMs / 1000.0)];
|
||||
|
||||
if (req == nil)
|
||||
return 0;
|
||||
|
||||
[req setHTTPMethod: isPost ? @"POST" : @"GET"];
|
||||
//[req setCachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData];
|
||||
|
||||
StringArray headerLines;
|
||||
headerLines.addLines (headers);
|
||||
headerLines.removeEmptyStrings (true);
|
||||
|
||||
for (int i = 0; i < headerLines.size(); ++i)
|
||||
{
|
||||
const String key (headerLines[i].upToFirstOccurrenceOf (T(":"), false, false).trim());
|
||||
const String value (headerLines[i].fromFirstOccurrenceOf (T(":"), false, false).trim());
|
||||
|
||||
if (key.isNotEmpty() && value.isNotEmpty())
|
||||
[req addValue: juceStringToNS (value) forHTTPHeaderField: juceStringToNS (key)];
|
||||
}
|
||||
|
||||
if (isPost && postData.getSize() > 0)
|
||||
{
|
||||
[req setHTTPBody: [NSData dataWithBytes: postData.getData()
|
||||
length: postData.getSize()]];
|
||||
}
|
||||
|
||||
JuceURLConnection* const s = [[JuceURLConnection alloc] initWithRequest: req
|
||||
withCallback: callback
|
||||
withContext: callbackContext];
|
||||
|
||||
if ([s isOpen])
|
||||
return s;
|
||||
|
||||
[s release];
|
||||
return 0;
|
||||
}
|
||||
|
||||
void juce_closeInternetFile (void* handle)
|
||||
{
|
||||
JuceURLConnection* const s = (JuceURLConnection*) handle;
|
||||
|
||||
if (s != 0)
|
||||
{
|
||||
AutoPool pool;
|
||||
[s stop];
|
||||
[s release];
|
||||
}
|
||||
}
|
||||
|
||||
int juce_readFromInternetFile (void* handle, void* buffer, int bytesToRead)
|
||||
{
|
||||
JuceURLConnection* const s = (JuceURLConnection*) handle;
|
||||
|
||||
if (s != 0)
|
||||
{
|
||||
AutoPool pool;
|
||||
return [s read: (char*) buffer numBytes: bytesToRead];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int juce_seekInInternetFile (void* handle, int newPosition)
|
||||
{
|
||||
JuceURLConnection* const s = (JuceURLConnection*) handle;
|
||||
|
||||
if (s != 0)
|
||||
return [s readPosition];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue