| @@ -287,7 +287,7 @@ private: | |||||
| { | { | ||||
| XmlElement* proj = new XmlElement ("project"); | XmlElement* proj = new XmlElement ("project"); | ||||
| proj->setAttribute ("name", project.getProjectName().toString()); | proj->setAttribute ("name", project.getProjectName().toString()); | ||||
| proj->setAttribute ("default", "help"); | |||||
| proj->setAttribute ("default", "debug"); | |||||
| proj->createNewChildElement ("property")->setAttribute ("file", "local.properties"); | proj->createNewChildElement ("property")->setAttribute ("file", "local.properties"); | ||||
| proj->createNewChildElement ("property")->setAttribute ("file", "build.properties"); | proj->createNewChildElement ("property")->setAttribute ("file", "build.properties"); | ||||
| @@ -8984,10 +8984,10 @@ END_JUCE_NAMESPACE | |||||
| #include <netdb.h> | #include <netdb.h> | ||||
| #include <arpa/inet.h> | #include <arpa/inet.h> | ||||
| #include <netinet/tcp.h> | #include <netinet/tcp.h> | ||||
| #endif | |||||
| #ifndef AI_NUMERICSERV // (missing in older Mac SDKs) | |||||
| #define AI_NUMERICSERV 0x1000 | |||||
| #endif | |||||
| #ifndef AI_NUMERICSERV // (missing in older Mac SDKs) | |||||
| #define AI_NUMERICSERV 0x1000 | |||||
| #endif | #endif | ||||
| BEGIN_JUCE_NAMESPACE | BEGIN_JUCE_NAMESPACE | ||||
| @@ -10759,9 +10759,9 @@ public: | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| #if JUCE_DEBUG | |||||
| #if JUCE_DEBUG | |||||
| file_.numOpenStreams++; | file_.numOpenStreams++; | ||||
| #endif | |||||
| #endif | |||||
| } | } | ||||
| char buffer [30]; | char buffer [30]; | ||||
| @@ -10778,10 +10778,10 @@ public: | |||||
| ~ZipInputStream() | ~ZipInputStream() | ||||
| { | { | ||||
| #if JUCE_DEBUG | |||||
| #if JUCE_DEBUG | |||||
| if (inputStream != 0 && inputStream == file.inputStream) | if (inputStream != 0 && inputStream == file.inputStream) | ||||
| file.numOpenStreams--; | file.numOpenStreams--; | ||||
| #endif | |||||
| #endif | |||||
| } | } | ||||
| int64 getTotalLength() | int64 getTotalLength() | ||||
| @@ -10847,9 +10847,9 @@ private: | |||||
| ZipFile::ZipFile (InputStream* const source_, const bool deleteStreamWhenDestroyed) | ZipFile::ZipFile (InputStream* const source_, const bool deleteStreamWhenDestroyed) | ||||
| : inputStream (source_) | : inputStream (source_) | ||||
| #if JUCE_DEBUG | |||||
| #if JUCE_DEBUG | |||||
| , numOpenStreams (0) | , numOpenStreams (0) | ||||
| #endif | |||||
| #endif | |||||
| { | { | ||||
| if (deleteStreamWhenDestroyed) | if (deleteStreamWhenDestroyed) | ||||
| streamToDelete = inputStream; | streamToDelete = inputStream; | ||||
| @@ -10859,9 +10859,9 @@ ZipFile::ZipFile (InputStream* const source_, const bool deleteStreamWhenDestroy | |||||
| ZipFile::ZipFile (const File& file) | ZipFile::ZipFile (const File& file) | ||||
| : inputStream (0) | : inputStream (0) | ||||
| #if JUCE_DEBUG | |||||
| #if JUCE_DEBUG | |||||
| , numOpenStreams (0) | , numOpenStreams (0) | ||||
| #endif | |||||
| #endif | |||||
| { | { | ||||
| inputSource = new FileInputSource (file); | inputSource = new FileInputSource (file); | ||||
| init(); | init(); | ||||
| @@ -10870,16 +10870,16 @@ ZipFile::ZipFile (const File& file) | |||||
| ZipFile::ZipFile (InputSource* const inputSource_) | ZipFile::ZipFile (InputSource* const inputSource_) | ||||
| : inputStream (0), | : inputStream (0), | ||||
| inputSource (inputSource_) | inputSource (inputSource_) | ||||
| #if JUCE_DEBUG | |||||
| #if JUCE_DEBUG | |||||
| , numOpenStreams (0) | , numOpenStreams (0) | ||||
| #endif | |||||
| #endif | |||||
| { | { | ||||
| init(); | init(); | ||||
| } | } | ||||
| ZipFile::~ZipFile() | ZipFile::~ZipFile() | ||||
| { | { | ||||
| #if JUCE_DEBUG | |||||
| #if JUCE_DEBUG | |||||
| entries.clear(); | entries.clear(); | ||||
| /* If you hit this assertion, it means you've created a stream to read one of the items in the | /* If you hit this assertion, it means you've created a stream to read one of the items in the | ||||
| @@ -10888,7 +10888,7 @@ ZipFile::~ZipFile() | |||||
| stream that the file uses to read itself. | stream that the file uses to read itself. | ||||
| */ | */ | ||||
| jassert (numOpenStreams == 0); | jassert (numOpenStreams == 0); | ||||
| #endif | |||||
| #endif | |||||
| } | } | ||||
| int ZipFile::getNumEntries() const throw() | int ZipFile::getNumEntries() const throw() | ||||
| @@ -11114,6 +11114,155 @@ bool ZipFile::uncompressEntry (const int index, | |||||
| return false; | return false; | ||||
| } | } | ||||
| extern unsigned long juce_crc32 (unsigned long crc, const unsigned char* buf, unsigned len); | |||||
| class ZipFile::Builder::Item | |||||
| { | |||||
| public: | |||||
| Item (const File& file_, const int compressionLevel_, const String& storedPathName_) | |||||
| : file (file_), | |||||
| storedPathname (storedPathName_.isEmpty() ? file_.getFileName() : storedPathName_), | |||||
| compressionLevel (compressionLevel_), | |||||
| compressedSize (0), | |||||
| headerStart (0) | |||||
| { | |||||
| } | |||||
| bool writeData (OutputStream& target, const int64 overallStartPosition) | |||||
| { | |||||
| MemoryOutputStream compressedData; | |||||
| if (compressionLevel > 0) | |||||
| { | |||||
| GZIPCompressorOutputStream compressor (&compressedData, compressionLevel, false, | |||||
| GZIPCompressorOutputStream::windowBitsRaw); | |||||
| if (! writeSource (compressor)) | |||||
| return false; | |||||
| } | |||||
| else | |||||
| { | |||||
| if (! writeSource (compressedData)) | |||||
| return false; | |||||
| } | |||||
| compressedSize = compressedData.getDataSize(); | |||||
| headerStart = (int) (target.getPosition() - overallStartPosition); | |||||
| target.writeInt (0x04034b50); | |||||
| writeFlagsAndSizes (target); | |||||
| target << storedPathname | |||||
| << compressedData; | |||||
| return true; | |||||
| } | |||||
| bool writeDirectoryEntry (OutputStream& target) | |||||
| { | |||||
| target.writeInt (0x02014b50); | |||||
| target.writeShort (20); // version written | |||||
| writeFlagsAndSizes (target); | |||||
| target.writeShort (0); // comment length | |||||
| target.writeShort (0); // start disk num | |||||
| target.writeShort (0); // internal attributes | |||||
| target.writeInt (0); // external attributes | |||||
| target.writeInt (headerStart); | |||||
| target << storedPathname; | |||||
| return true; | |||||
| } | |||||
| private: | |||||
| const File file; | |||||
| String storedPathname; | |||||
| int compressionLevel, compressedSize, headerStart; | |||||
| uint32 checksum; | |||||
| void writeTimeAndDate (OutputStream& target) const | |||||
| { | |||||
| const Time t (file.getLastModificationTime()); | |||||
| target.writeShort ((short) (t.getSeconds() + (t.getMinutes() << 5) + (t.getHours() << 11))); | |||||
| target.writeShort ((short) (t.getDayOfMonth() + ((t.getMonth() + 1) << 5) + ((t.getYear() - 1980) << 9))); | |||||
| } | |||||
| bool writeSource (OutputStream& target) | |||||
| { | |||||
| checksum = 0; | |||||
| ScopedPointer<FileInputStream> input (file.createInputStream()); | |||||
| if (input == 0) | |||||
| return false; | |||||
| const int bufferSize = 2048; | |||||
| HeapBlock<unsigned char> buffer (bufferSize); | |||||
| while (! input->isExhausted()) | |||||
| { | |||||
| const int bytesRead = input->read (buffer, bufferSize); | |||||
| if (bytesRead < 0) | |||||
| return false; | |||||
| checksum = juce_crc32 (checksum, buffer, bytesRead); | |||||
| target.write (buffer, bytesRead); | |||||
| } | |||||
| return true; | |||||
| } | |||||
| void writeFlagsAndSizes (OutputStream& target) const | |||||
| { | |||||
| target.writeShort (10); // version needed | |||||
| target.writeShort (0); // flags | |||||
| target.writeShort (compressionLevel > 0 ? (short) 8 : (short) 0); | |||||
| writeTimeAndDate (target); | |||||
| target.writeInt (checksum); | |||||
| target.writeInt (compressedSize); | |||||
| target.writeInt ((int) file.getSize()); | |||||
| target.writeShort ((short) storedPathname.toUTF8().sizeInBytes() - 1); | |||||
| target.writeShort (0); // extra field length | |||||
| } | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Item); | |||||
| }; | |||||
| ZipFile::Builder::Builder() {} | |||||
| ZipFile::Builder::~Builder() {} | |||||
| void ZipFile::Builder::addFile (const File& fileToAdd, const int compressionLevel, const String& storedPathName) | |||||
| { | |||||
| items.add (new Item (fileToAdd, compressionLevel, storedPathName)); | |||||
| } | |||||
| bool ZipFile::Builder::writeToStream (OutputStream& target) const | |||||
| { | |||||
| const int64 fileStart = target.getPosition(); | |||||
| int i; | |||||
| for (i = 0; i < items.size(); ++i) | |||||
| if (! items.getUnchecked (i)->writeData (target, fileStart)) | |||||
| return false; | |||||
| const int64 directoryStart = target.getPosition(); | |||||
| for (i = 0; i < items.size(); ++i) | |||||
| if (! items.getUnchecked (i)->writeDirectoryEntry (target)) | |||||
| return false; | |||||
| const int64 directoryEnd = target.getPosition(); | |||||
| target.writeInt (0x06054b50); | |||||
| target.writeShort (0); | |||||
| target.writeShort (0); | |||||
| target.writeShort ((short) items.size()); | |||||
| target.writeShort ((short) items.size()); | |||||
| target.writeInt ((int) (directoryEnd - directoryStart)); | |||||
| target.writeInt ((int) (directoryStart - fileStart)); | |||||
| target.writeShort (0); | |||||
| target.flush(); | |||||
| return true; | |||||
| } | |||||
| END_JUCE_NAMESPACE | END_JUCE_NAMESPACE | ||||
| /*** End of inlined file: juce_ZipFile.cpp ***/ | /*** End of inlined file: juce_ZipFile.cpp ***/ | ||||
| @@ -61264,6 +61413,9 @@ public: | |||||
| { | { | ||||
| component->setAlpha ((float) destAlpha); | component->setAlpha ((float) destAlpha); | ||||
| component->setBounds (destination); | component->setBounds (destination); | ||||
| if (proxy != 0) | |||||
| component->setVisible (destAlpha > 0); | |||||
| } | } | ||||
| } | } | ||||
| @@ -106086,6 +106238,12 @@ bool GZIPDecompressorInputStream::setPosition (int64 newPos) | |||||
| return true; | return true; | ||||
| } | } | ||||
| // (This is used as a way for the zip file code to use the crc32 function without including zlib) | |||||
| unsigned long juce_crc32 (unsigned long crc, const unsigned char* buf, unsigned len) | |||||
| { | |||||
| return zlibNamespace::crc32 (crc, buf, len); | |||||
| } | |||||
| END_JUCE_NAMESPACE | END_JUCE_NAMESPACE | ||||
| /*** End of inlined file: juce_GZIPDecompressorInputStream.cpp ***/ | /*** End of inlined file: juce_GZIPDecompressorInputStream.cpp ***/ | ||||
| @@ -256374,11 +256532,15 @@ private: | |||||
| { | { | ||||
| sessionEventCallback = new SessionEventCallback (*this); | sessionEventCallback = new SessionEventCallback (*this); | ||||
| audioSessionControl->RegisterAudioSessionNotification (sessionEventCallback); | audioSessionControl->RegisterAudioSessionNotification (sessionEventCallback); | ||||
| sessionEventCallback->Release(); // (required because ComBaseClassHelper objects are constructed with a ref count of 1) | |||||
| } | } | ||||
| } | } | ||||
| void deleteSessionEventCallback() | void deleteSessionEventCallback() | ||||
| { | { | ||||
| if (audioSessionControl != 0 && sessionEventCallback != 0) | |||||
| audioSessionControl->UnregisterAudioSessionNotification (sessionEventCallback); | |||||
| audioSessionControl = 0; | audioSessionControl = 0; | ||||
| sessionEventCallback = 0; | sessionEventCallback = 0; | ||||
| } | } | ||||
| @@ -262011,7 +262173,7 @@ class LinuxComponentPeer : public ComponentPeer | |||||
| { | { | ||||
| public: | public: | ||||
| LinuxComponentPeer (Component* const component, const int windowStyleFlags, Window parentToAddTo)) | |||||
| LinuxComponentPeer (Component* const component, const int windowStyleFlags, Window parentToAddTo) | |||||
| : ComponentPeer (component, windowStyleFlags), | : ComponentPeer (component, windowStyleFlags), | ||||
| windowH (0), parentWindow (0), | windowH (0), parentWindow (0), | ||||
| wx (0), wy (0), ww (0), wh (0), | wx (0), wy (0), ww (0), wh (0), | ||||
| @@ -280566,6 +280728,11 @@ public: | |||||
| messageQueue.post (m); | messageQueue.post (m); | ||||
| } | } | ||||
| static NSString* getBroacastEventName() | |||||
| { | |||||
| return juceStringToNS ("juce_" + String::toHexString (File::getSpecialLocation (File::currentExecutableFile).hashCode64())); | |||||
| } | |||||
| private: | private: | ||||
| CFRunLoopRef runLoop; | CFRunLoopRef runLoop; | ||||
| CFRunLoopSourceRef runLoopSource; | CFRunLoopSourceRef runLoopSource; | ||||
| @@ -280605,6 +280772,7 @@ using namespace JUCE_NAMESPACE; | |||||
| - (void) applicationDidResignActive: (NSNotification*) aNotification; | - (void) applicationDidResignActive: (NSNotification*) aNotification; | ||||
| - (void) applicationWillUnhide: (NSNotification*) aNotification; | - (void) applicationWillUnhide: (NSNotification*) aNotification; | ||||
| - (void) performCallback: (id) info; | - (void) performCallback: (id) info; | ||||
| - (void) broadcastMessageCallback: (NSNotification*) info; | |||||
| - (void) dummyMethod; | - (void) dummyMethod; | ||||
| @end | @end | ||||
| @@ -280622,6 +280790,11 @@ using namespace JUCE_NAMESPACE; | |||||
| { | { | ||||
| oldDelegate = [NSApp delegate]; | oldDelegate = [NSApp delegate]; | ||||
| [NSApp setDelegate: self]; | [NSApp setDelegate: self]; | ||||
| [[NSDistributedNotificationCenter defaultCenter] addObserver: self | |||||
| selector: @selector (broadcastMessageCallback:) | |||||
| name: AppDelegateRedirector::getBroacastEventName() | |||||
| object: nil]; | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -280644,6 +280817,10 @@ using namespace JUCE_NAMESPACE; | |||||
| if (oldDelegate != 0) | if (oldDelegate != 0) | ||||
| [NSApp setDelegate: oldDelegate]; | [NSApp setDelegate: oldDelegate]; | ||||
| [[NSDistributedNotificationCenter defaultCenter] removeObserver: self | |||||
| name: AppDelegateRedirector::getBroacastEventName() | |||||
| object: nil]; | |||||
| redirector->deleteSelf(); | redirector->deleteSelf(); | ||||
| [super dealloc]; | [super dealloc]; | ||||
| } | } | ||||
| @@ -280706,6 +280883,13 @@ using namespace JUCE_NAMESPACE; | |||||
| } | } | ||||
| } | } | ||||
| - (void) broadcastMessageCallback: (NSNotification*) n | |||||
| { | |||||
| NSDictionary* dict = (NSDictionary*) [n userInfo]; | |||||
| const String messageString (nsStringToJuce ((NSString*) [dict valueForKey: @"message"])); | |||||
| MessageManager::getInstance()->deliverBroadcastMessage (messageString); | |||||
| } | |||||
| - (void) dummyMethod {} // (used as a way of running a dummy thread) | - (void) dummyMethod {} // (used as a way of running a dummy thread) | ||||
| @end | @end | ||||
| @@ -280723,7 +280907,7 @@ void MessageManager::runDispatchLoop() | |||||
| // must only be called by the message thread! | // must only be called by the message thread! | ||||
| jassert (isThisTheMessageThread()); | jassert (isThisTheMessageThread()); | ||||
| #if JUCE_CATCH_UNHANDLED_EXCEPTIONS | |||||
| #if JUCE_CATCH_UNHANDLED_EXCEPTIONS | |||||
| @try | @try | ||||
| { | { | ||||
| [NSApp run]; | [NSApp run]; | ||||
| @@ -280737,9 +280921,9 @@ void MessageManager::runDispatchLoop() | |||||
| @finally | @finally | ||||
| { | { | ||||
| } | } | ||||
| #else | |||||
| #else | |||||
| [NSApp run]; | [NSApp run]; | ||||
| #endif | |||||
| #endif | |||||
| } | } | ||||
| } | } | ||||
| @@ -280897,8 +281081,14 @@ bool juce_postMessageToSystemQueue (Message* message) | |||||
| return true; | return true; | ||||
| } | } | ||||
| void MessageManager::broadcastMessage (const String&) | |||||
| void MessageManager::broadcastMessage (const String& message) | |||||
| { | { | ||||
| NSDictionary* info = [NSDictionary dictionaryWithObject: juceStringToNS (message) | |||||
| forKey: @"message"]; | |||||
| [[NSDistributedNotificationCenter defaultCenter] postNotificationName: AppDelegateRedirector::getBroacastEventName() | |||||
| object: nil | |||||
| userInfo: info]; | |||||
| } | } | ||||
| void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, void* data) | void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, void* data) | ||||
| @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} | |||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 53 | #define JUCE_MINOR_VERSION 53 | ||||
| #define JUCE_BUILDNUMBER 49 | |||||
| #define JUCE_BUILDNUMBER 50 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -19001,6 +19001,42 @@ public: | |||||
| const File& targetDirectory, | const File& targetDirectory, | ||||
| bool shouldOverwriteFiles = true); | bool shouldOverwriteFiles = true); | ||||
| /** Used to create a new zip file. | |||||
| Create a ZipFile::Builder object, and call its addFile() method to add some files, | |||||
| then you can write it to a stream with write(). | |||||
| Currently this just stores the files with no compression.. That will be added | |||||
| soon! | |||||
| */ | |||||
| class Builder | |||||
| { | |||||
| public: | |||||
| Builder(); | |||||
| ~Builder(); | |||||
| /** Adds a file while should be added to the archive. | |||||
| The file isn't read immediately, all the files will be read later when the writeToStream() | |||||
| method is called. | |||||
| The compressionLevel can be between 0 (no compression), and 9 (maximum compression). | |||||
| If the storedPathName parameter is specified, you can customise the partial pathname that | |||||
| will be stored for this file. | |||||
| */ | |||||
| void addFile (const File& fileToAdd, int compressionLevel, | |||||
| const String& storedPathName = String::empty); | |||||
| /** Generates the zip file, writing it to the specified stream. */ | |||||
| bool writeToStream (OutputStream& target) const; | |||||
| private: | |||||
| class Item; | |||||
| friend class OwnedArray<Item>; | |||||
| OwnedArray<Item> items; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Builder); | |||||
| }; | |||||
| private: | private: | ||||
| class ZipInputStream; | class ZipInputStream; | ||||
| @@ -59899,7 +59935,7 @@ public: | |||||
| virtual const Rectangle<int> getPropertyComponentContentPosition (PropertyComponent& component); | virtual const Rectangle<int> getPropertyComponentContentPosition (PropertyComponent& component); | ||||
| void drawCallOutBoxBackground (CallOutBox& box, Graphics& g, const Path& path); | |||||
| virtual void drawCallOutBoxBackground (CallOutBox& box, Graphics& g, const Path& path); | |||||
| virtual void drawLevelMeter (Graphics& g, int width, int height, float level); | virtual void drawLevelMeter (Graphics& g, int width, int height, float level); | ||||
| @@ -63522,7 +63558,6 @@ private: | |||||
| Image background; | Image background; | ||||
| void refreshPath(); | void refreshPath(); | ||||
| void drawCallOutBoxBackground (Graphics& g, const Path& outline, int width, int height); | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallOutBox); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallOutBox); | ||||
| }; | }; | ||||
| @@ -33,7 +33,7 @@ | |||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 53 | #define JUCE_MINOR_VERSION 53 | ||||
| #define JUCE_BUILDNUMBER 49 | |||||
| #define JUCE_BUILDNUMBER 50 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -138,6 +138,9 @@ public: | |||||
| { | { | ||||
| component->setAlpha ((float) destAlpha); | component->setAlpha ((float) destAlpha); | ||||
| component->setBounds (destination); | component->setBounds (destination); | ||||
| if (proxy != 0) | |||||
| component->setVisible (destAlpha > 0); | |||||
| } | } | ||||
| } | } | ||||
| @@ -602,7 +602,7 @@ public: | |||||
| virtual const Rectangle<int> getPropertyComponentContentPosition (PropertyComponent& component); | virtual const Rectangle<int> getPropertyComponentContentPosition (PropertyComponent& component); | ||||
| //============================================================================== | //============================================================================== | ||||
| void drawCallOutBoxBackground (CallOutBox& box, Graphics& g, const Path& path); | |||||
| virtual void drawCallOutBoxBackground (CallOutBox& box, Graphics& g, const Path& path); | |||||
| //============================================================================== | //============================================================================== | ||||
| virtual void drawLevelMeter (Graphics& g, int width, int height, float level); | virtual void drawLevelMeter (Graphics& g, int width, int height, float level); | ||||
| @@ -119,7 +119,6 @@ private: | |||||
| Image background; | Image background; | ||||
| void refreshPath(); | void refreshPath(); | ||||
| void drawCallOutBoxBackground (Graphics& g, const Path& outline, int width, int height); | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallOutBox); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallOutBox); | ||||
| }; | }; | ||||
| @@ -31,6 +31,8 @@ BEGIN_JUCE_NAMESPACE | |||||
| #include "../streams/juce_GZIPDecompressorInputStream.h" | #include "../streams/juce_GZIPDecompressorInputStream.h" | ||||
| #include "../streams/juce_BufferedInputStream.h" | #include "../streams/juce_BufferedInputStream.h" | ||||
| #include "../streams/juce_FileInputSource.h" | #include "../streams/juce_FileInputSource.h" | ||||
| #include "../streams/juce_MemoryOutputStream.h" | |||||
| #include "../streams/juce_GZIPCompressorOutputStream.h" | |||||
| #include "juce_FileInputStream.h" | #include "juce_FileInputStream.h" | ||||
| #include "juce_FileOutputStream.h" | #include "juce_FileOutputStream.h" | ||||
| #include "../../threads/juce_ScopedLock.h" | #include "../../threads/juce_ScopedLock.h" | ||||
| @@ -66,9 +68,9 @@ public: | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| #if JUCE_DEBUG | |||||
| #if JUCE_DEBUG | |||||
| file_.numOpenStreams++; | file_.numOpenStreams++; | ||||
| #endif | |||||
| #endif | |||||
| } | } | ||||
| char buffer [30]; | char buffer [30]; | ||||
| @@ -85,10 +87,10 @@ public: | |||||
| ~ZipInputStream() | ~ZipInputStream() | ||||
| { | { | ||||
| #if JUCE_DEBUG | |||||
| #if JUCE_DEBUG | |||||
| if (inputStream != 0 && inputStream == file.inputStream) | if (inputStream != 0 && inputStream == file.inputStream) | ||||
| file.numOpenStreams--; | file.numOpenStreams--; | ||||
| #endif | |||||
| #endif | |||||
| } | } | ||||
| int64 getTotalLength() | int64 getTotalLength() | ||||
| @@ -157,9 +159,9 @@ private: | |||||
| //============================================================================== | //============================================================================== | ||||
| ZipFile::ZipFile (InputStream* const source_, const bool deleteStreamWhenDestroyed) | ZipFile::ZipFile (InputStream* const source_, const bool deleteStreamWhenDestroyed) | ||||
| : inputStream (source_) | : inputStream (source_) | ||||
| #if JUCE_DEBUG | |||||
| #if JUCE_DEBUG | |||||
| , numOpenStreams (0) | , numOpenStreams (0) | ||||
| #endif | |||||
| #endif | |||||
| { | { | ||||
| if (deleteStreamWhenDestroyed) | if (deleteStreamWhenDestroyed) | ||||
| streamToDelete = inputStream; | streamToDelete = inputStream; | ||||
| @@ -169,9 +171,9 @@ ZipFile::ZipFile (InputStream* const source_, const bool deleteStreamWhenDestroy | |||||
| ZipFile::ZipFile (const File& file) | ZipFile::ZipFile (const File& file) | ||||
| : inputStream (0) | : inputStream (0) | ||||
| #if JUCE_DEBUG | |||||
| #if JUCE_DEBUG | |||||
| , numOpenStreams (0) | , numOpenStreams (0) | ||||
| #endif | |||||
| #endif | |||||
| { | { | ||||
| inputSource = new FileInputSource (file); | inputSource = new FileInputSource (file); | ||||
| init(); | init(); | ||||
| @@ -180,16 +182,16 @@ ZipFile::ZipFile (const File& file) | |||||
| ZipFile::ZipFile (InputSource* const inputSource_) | ZipFile::ZipFile (InputSource* const inputSource_) | ||||
| : inputStream (0), | : inputStream (0), | ||||
| inputSource (inputSource_) | inputSource (inputSource_) | ||||
| #if JUCE_DEBUG | |||||
| #if JUCE_DEBUG | |||||
| , numOpenStreams (0) | , numOpenStreams (0) | ||||
| #endif | |||||
| #endif | |||||
| { | { | ||||
| init(); | init(); | ||||
| } | } | ||||
| ZipFile::~ZipFile() | ZipFile::~ZipFile() | ||||
| { | { | ||||
| #if JUCE_DEBUG | |||||
| #if JUCE_DEBUG | |||||
| entries.clear(); | entries.clear(); | ||||
| /* If you hit this assertion, it means you've created a stream to read one of the items in the | /* If you hit this assertion, it means you've created a stream to read one of the items in the | ||||
| @@ -198,7 +200,7 @@ ZipFile::~ZipFile() | |||||
| stream that the file uses to read itself. | stream that the file uses to read itself. | ||||
| */ | */ | ||||
| jassert (numOpenStreams == 0); | jassert (numOpenStreams == 0); | ||||
| #endif | |||||
| #endif | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -427,4 +429,156 @@ bool ZipFile::uncompressEntry (const int index, | |||||
| } | } | ||||
| //============================================================================= | |||||
| extern unsigned long juce_crc32 (unsigned long crc, const unsigned char* buf, unsigned len); | |||||
| class ZipFile::Builder::Item | |||||
| { | |||||
| public: | |||||
| Item (const File& file_, const int compressionLevel_, const String& storedPathName_) | |||||
| : file (file_), | |||||
| storedPathname (storedPathName_.isEmpty() ? file_.getFileName() : storedPathName_), | |||||
| compressionLevel (compressionLevel_), | |||||
| compressedSize (0), | |||||
| headerStart (0) | |||||
| { | |||||
| } | |||||
| bool writeData (OutputStream& target, const int64 overallStartPosition) | |||||
| { | |||||
| MemoryOutputStream compressedData; | |||||
| if (compressionLevel > 0) | |||||
| { | |||||
| GZIPCompressorOutputStream compressor (&compressedData, compressionLevel, false, | |||||
| GZIPCompressorOutputStream::windowBitsRaw); | |||||
| if (! writeSource (compressor)) | |||||
| return false; | |||||
| } | |||||
| else | |||||
| { | |||||
| if (! writeSource (compressedData)) | |||||
| return false; | |||||
| } | |||||
| compressedSize = compressedData.getDataSize(); | |||||
| headerStart = (int) (target.getPosition() - overallStartPosition); | |||||
| target.writeInt (0x04034b50); | |||||
| writeFlagsAndSizes (target); | |||||
| target << storedPathname | |||||
| << compressedData; | |||||
| return true; | |||||
| } | |||||
| bool writeDirectoryEntry (OutputStream& target) | |||||
| { | |||||
| target.writeInt (0x02014b50); | |||||
| target.writeShort (20); // version written | |||||
| writeFlagsAndSizes (target); | |||||
| target.writeShort (0); // comment length | |||||
| target.writeShort (0); // start disk num | |||||
| target.writeShort (0); // internal attributes | |||||
| target.writeInt (0); // external attributes | |||||
| target.writeInt (headerStart); | |||||
| target << storedPathname; | |||||
| return true; | |||||
| } | |||||
| private: | |||||
| const File file; | |||||
| String storedPathname; | |||||
| int compressionLevel, compressedSize, headerStart; | |||||
| uint32 checksum; | |||||
| void writeTimeAndDate (OutputStream& target) const | |||||
| { | |||||
| const Time t (file.getLastModificationTime()); | |||||
| target.writeShort ((short) (t.getSeconds() + (t.getMinutes() << 5) + (t.getHours() << 11))); | |||||
| target.writeShort ((short) (t.getDayOfMonth() + ((t.getMonth() + 1) << 5) + ((t.getYear() - 1980) << 9))); | |||||
| } | |||||
| bool writeSource (OutputStream& target) | |||||
| { | |||||
| checksum = 0; | |||||
| ScopedPointer<FileInputStream> input (file.createInputStream()); | |||||
| if (input == 0) | |||||
| return false; | |||||
| const int bufferSize = 2048; | |||||
| HeapBlock<unsigned char> buffer (bufferSize); | |||||
| while (! input->isExhausted()) | |||||
| { | |||||
| const int bytesRead = input->read (buffer, bufferSize); | |||||
| if (bytesRead < 0) | |||||
| return false; | |||||
| checksum = juce_crc32 (checksum, buffer, bytesRead); | |||||
| target.write (buffer, bytesRead); | |||||
| } | |||||
| return true; | |||||
| } | |||||
| void writeFlagsAndSizes (OutputStream& target) const | |||||
| { | |||||
| target.writeShort (10); // version needed | |||||
| target.writeShort (0); // flags | |||||
| target.writeShort (compressionLevel > 0 ? (short) 8 : (short) 0); | |||||
| writeTimeAndDate (target); | |||||
| target.writeInt (checksum); | |||||
| target.writeInt (compressedSize); | |||||
| target.writeInt ((int) file.getSize()); | |||||
| target.writeShort ((short) storedPathname.toUTF8().sizeInBytes() - 1); | |||||
| target.writeShort (0); // extra field length | |||||
| } | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Item); | |||||
| }; | |||||
| //============================================================================= | |||||
| ZipFile::Builder::Builder() {} | |||||
| ZipFile::Builder::~Builder() {} | |||||
| void ZipFile::Builder::addFile (const File& fileToAdd, const int compressionLevel, const String& storedPathName) | |||||
| { | |||||
| items.add (new Item (fileToAdd, compressionLevel, storedPathName)); | |||||
| } | |||||
| bool ZipFile::Builder::writeToStream (OutputStream& target) const | |||||
| { | |||||
| const int64 fileStart = target.getPosition(); | |||||
| int i; | |||||
| for (i = 0; i < items.size(); ++i) | |||||
| if (! items.getUnchecked (i)->writeData (target, fileStart)) | |||||
| return false; | |||||
| const int64 directoryStart = target.getPosition(); | |||||
| for (i = 0; i < items.size(); ++i) | |||||
| if (! items.getUnchecked (i)->writeDirectoryEntry (target)) | |||||
| return false; | |||||
| const int64 directoryEnd = target.getPosition(); | |||||
| target.writeInt (0x06054b50); | |||||
| target.writeShort (0); | |||||
| target.writeShort (0); | |||||
| target.writeShort ((short) items.size()); | |||||
| target.writeShort ((short) items.size()); | |||||
| target.writeInt ((int) (directoryEnd - directoryStart)); | |||||
| target.writeInt ((int) (directoryStart - fileStart)); | |||||
| target.writeShort (0); | |||||
| target.flush(); | |||||
| return true; | |||||
| } | |||||
| END_JUCE_NAMESPACE | END_JUCE_NAMESPACE | ||||
| @@ -165,6 +165,45 @@ public: | |||||
| const File& targetDirectory, | const File& targetDirectory, | ||||
| bool shouldOverwriteFiles = true); | bool shouldOverwriteFiles = true); | ||||
| //============================================================================== | |||||
| /** Used to create a new zip file. | |||||
| Create a ZipFile::Builder object, and call its addFile() method to add some files, | |||||
| then you can write it to a stream with write(). | |||||
| Currently this just stores the files with no compression.. That will be added | |||||
| soon! | |||||
| */ | |||||
| class Builder | |||||
| { | |||||
| public: | |||||
| Builder(); | |||||
| ~Builder(); | |||||
| /** Adds a file while should be added to the archive. | |||||
| The file isn't read immediately, all the files will be read later when the writeToStream() | |||||
| method is called. | |||||
| The compressionLevel can be between 0 (no compression), and 9 (maximum compression). | |||||
| If the storedPathName parameter is specified, you can customise the partial pathname that | |||||
| will be stored for this file. | |||||
| */ | |||||
| void addFile (const File& fileToAdd, int compressionLevel, | |||||
| const String& storedPathName = String::empty); | |||||
| /** Generates the zip file, writing it to the specified stream. */ | |||||
| bool writeToStream (OutputStream& target) const; | |||||
| //============================================================================== | |||||
| private: | |||||
| class Item; | |||||
| friend class OwnedArray<Item>; | |||||
| OwnedArray<Item> items; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Builder); | |||||
| }; | |||||
| private: | private: | ||||
| //============================================================================== | //============================================================================== | ||||
| class ZipInputStream; | class ZipInputStream; | ||||
| @@ -47,10 +47,10 @@ | |||||
| #include <netdb.h> | #include <netdb.h> | ||||
| #include <arpa/inet.h> | #include <arpa/inet.h> | ||||
| #include <netinet/tcp.h> | #include <netinet/tcp.h> | ||||
| #endif | |||||
| #ifndef AI_NUMERICSERV // (missing in older Mac SDKs) | |||||
| #define AI_NUMERICSERV 0x1000 | |||||
| #endif | |||||
| #ifndef AI_NUMERICSERV // (missing in older Mac SDKs) | |||||
| #define AI_NUMERICSERV 0x1000 | |||||
| #endif | #endif | ||||
| #include "../../core/juce_StandardHeader.h" | #include "../../core/juce_StandardHeader.h" | ||||
| @@ -41,7 +41,6 @@ BEGIN_JUCE_NAMESPACE | |||||
| #include "juce_GZIPCompressorOutputStream.h" | #include "juce_GZIPCompressorOutputStream.h" | ||||
| //============================================================================== | //============================================================================== | ||||
| class GZIPCompressorOutputStream::GZIPCompressorHelper | class GZIPCompressorOutputStream::GZIPCompressorHelper | ||||
| { | { | ||||
| @@ -277,4 +277,10 @@ bool GZIPDecompressorInputStream::setPosition (int64 newPos) | |||||
| return true; | return true; | ||||
| } | } | ||||
| // (This is used as a way for the zip file code to use the crc32 function without including zlib) | |||||
| unsigned long juce_crc32 (unsigned long crc, const unsigned char* buf, unsigned len) | |||||
| { | |||||
| return zlibNamespace::crc32 (crc, buf, len); | |||||
| } | |||||
| END_JUCE_NAMESPACE | END_JUCE_NAMESPACE | ||||
| @@ -747,7 +747,7 @@ class LinuxComponentPeer : public ComponentPeer | |||||
| { | { | ||||
| public: | public: | ||||
| //============================================================================== | //============================================================================== | ||||
| LinuxComponentPeer (Component* const component, const int windowStyleFlags, Window parentToAddTo)) | |||||
| LinuxComponentPeer (Component* const component, const int windowStyleFlags, Window parentToAddTo) | |||||
| : ComponentPeer (component, windowStyleFlags), | : ComponentPeer (component, windowStyleFlags), | ||||
| windowH (0), parentWindow (0), | windowH (0), parentWindow (0), | ||||
| wx (0), wy (0), ww (0), wh (0), | wx (0), wy (0), ww (0), wh (0), | ||||
| @@ -118,6 +118,11 @@ public: | |||||
| messageQueue.post (m); | messageQueue.post (m); | ||||
| } | } | ||||
| static NSString* getBroacastEventName() | |||||
| { | |||||
| return juceStringToNS ("juce_" + String::toHexString (File::getSpecialLocation (File::currentExecutableFile).hashCode64())); | |||||
| } | |||||
| private: | private: | ||||
| CFRunLoopRef runLoop; | CFRunLoopRef runLoop; | ||||
| CFRunLoopSourceRef runLoopSource; | CFRunLoopSourceRef runLoopSource; | ||||
| @@ -159,6 +164,7 @@ using namespace JUCE_NAMESPACE; | |||||
| - (void) applicationDidResignActive: (NSNotification*) aNotification; | - (void) applicationDidResignActive: (NSNotification*) aNotification; | ||||
| - (void) applicationWillUnhide: (NSNotification*) aNotification; | - (void) applicationWillUnhide: (NSNotification*) aNotification; | ||||
| - (void) performCallback: (id) info; | - (void) performCallback: (id) info; | ||||
| - (void) broadcastMessageCallback: (NSNotification*) info; | |||||
| - (void) dummyMethod; | - (void) dummyMethod; | ||||
| @end | @end | ||||
| @@ -176,6 +182,11 @@ using namespace JUCE_NAMESPACE; | |||||
| { | { | ||||
| oldDelegate = [NSApp delegate]; | oldDelegate = [NSApp delegate]; | ||||
| [NSApp setDelegate: self]; | [NSApp setDelegate: self]; | ||||
| [[NSDistributedNotificationCenter defaultCenter] addObserver: self | |||||
| selector: @selector (broadcastMessageCallback:) | |||||
| name: AppDelegateRedirector::getBroacastEventName() | |||||
| object: nil]; | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -198,6 +209,10 @@ using namespace JUCE_NAMESPACE; | |||||
| if (oldDelegate != 0) | if (oldDelegate != 0) | ||||
| [NSApp setDelegate: oldDelegate]; | [NSApp setDelegate: oldDelegate]; | ||||
| [[NSDistributedNotificationCenter defaultCenter] removeObserver: self | |||||
| name: AppDelegateRedirector::getBroacastEventName() | |||||
| object: nil]; | |||||
| redirector->deleteSelf(); | redirector->deleteSelf(); | ||||
| [super dealloc]; | [super dealloc]; | ||||
| } | } | ||||
| @@ -260,6 +275,13 @@ using namespace JUCE_NAMESPACE; | |||||
| } | } | ||||
| } | } | ||||
| - (void) broadcastMessageCallback: (NSNotification*) n | |||||
| { | |||||
| NSDictionary* dict = (NSDictionary*) [n userInfo]; | |||||
| const String messageString (nsStringToJuce ((NSString*) [dict valueForKey: @"message"])); | |||||
| MessageManager::getInstance()->deliverBroadcastMessage (messageString); | |||||
| } | |||||
| - (void) dummyMethod {} // (used as a way of running a dummy thread) | - (void) dummyMethod {} // (used as a way of running a dummy thread) | ||||
| @end | @end | ||||
| @@ -278,7 +300,7 @@ void MessageManager::runDispatchLoop() | |||||
| // must only be called by the message thread! | // must only be called by the message thread! | ||||
| jassert (isThisTheMessageThread()); | jassert (isThisTheMessageThread()); | ||||
| #if JUCE_CATCH_UNHANDLED_EXCEPTIONS | |||||
| #if JUCE_CATCH_UNHANDLED_EXCEPTIONS | |||||
| @try | @try | ||||
| { | { | ||||
| [NSApp run]; | [NSApp run]; | ||||
| @@ -292,9 +314,9 @@ void MessageManager::runDispatchLoop() | |||||
| @finally | @finally | ||||
| { | { | ||||
| } | } | ||||
| #else | |||||
| #else | |||||
| [NSApp run]; | [NSApp run]; | ||||
| #endif | |||||
| #endif | |||||
| } | } | ||||
| } | } | ||||
| @@ -453,8 +475,14 @@ bool juce_postMessageToSystemQueue (Message* message) | |||||
| return true; | return true; | ||||
| } | } | ||||
| void MessageManager::broadcastMessage (const String&) | |||||
| void MessageManager::broadcastMessage (const String& message) | |||||
| { | { | ||||
| NSDictionary* info = [NSDictionary dictionaryWithObject: juceStringToNS (message) | |||||
| forKey: @"message"]; | |||||
| [[NSDistributedNotificationCenter defaultCenter] postNotificationName: AppDelegateRedirector::getBroacastEventName() | |||||
| object: nil | |||||
| userInfo: info]; | |||||
| } | } | ||||
| void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, void* data) | void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, void* data) | ||||
| @@ -301,11 +301,15 @@ private: | |||||
| { | { | ||||
| sessionEventCallback = new SessionEventCallback (*this); | sessionEventCallback = new SessionEventCallback (*this); | ||||
| audioSessionControl->RegisterAudioSessionNotification (sessionEventCallback); | audioSessionControl->RegisterAudioSessionNotification (sessionEventCallback); | ||||
| sessionEventCallback->Release(); // (required because ComBaseClassHelper objects are constructed with a ref count of 1) | |||||
| } | } | ||||
| } | } | ||||
| void deleteSessionEventCallback() | void deleteSessionEventCallback() | ||||
| { | { | ||||
| if (audioSessionControl != 0 && sessionEventCallback != 0) | |||||
| audioSessionControl->UnregisterAudioSessionNotification (sessionEventCallback); | |||||
| audioSessionControl = 0; | audioSessionControl = 0; | ||||
| sessionEventCallback = 0; | sessionEventCallback = 0; | ||||
| } | } | ||||