diff --git a/build/macosx/Juce.xcodeproj/project.pbxproj b/build/macosx/Juce.xcodeproj/project.pbxproj index 9ae71bffe9..dc6a4c61a6 100644 --- a/build/macosx/Juce.xcodeproj/project.pbxproj +++ b/build/macosx/Juce.xcodeproj/project.pbxproj @@ -659,6 +659,8 @@ 84B2053F10D535EC008B4A79 /* juce_ValueTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 843D4A3910D3C54500624BA6 /* juce_ValueTree.cpp */; }; 84BA604010F2017A001D9D70 /* juce_Value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84BA603E10F2017A001D9D70 /* juce_Value.cpp */; }; 84BA604110F2017A001D9D70 /* juce_Value.h in Headers */ = {isa = PBXBuildFile; fileRef = 84BA603F10F2017A001D9D70 /* juce_Value.h */; }; + 84CABF691101292D0088D64D /* juce_TemporaryFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84CABF671101292D0088D64D /* juce_TemporaryFile.cpp */; }; + 84CABF6A1101292D0088D64D /* juce_TemporaryFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 84CABF681101292D0088D64D /* juce_TemporaryFile.h */; }; 84D0F00C109B1546007F73A3 /* juce_mac_CoreGraphicsContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84D0F00B109B1546007F73A3 /* juce_mac_CoreGraphicsContext.mm */; }; 84DEDD9F10EE496500909D01 /* juce_HeapBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 84DEDD9E10EE496500909D01 /* juce_HeapBlock.h */; }; 84F1E6E710403605006A1807 /* juce_Application.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84F1E6DC10403605006A1807 /* juce_Application.cpp */; }; @@ -1270,6 +1272,8 @@ 84AF3FE710EF9FF30035D74F /* juce_ScopedPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = juce_ScopedPointer.h; sourceTree = ""; }; 84BA603E10F2017A001D9D70 /* juce_Value.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = juce_Value.cpp; sourceTree = ""; }; 84BA603F10F2017A001D9D70 /* juce_Value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = juce_Value.h; sourceTree = ""; }; + 84CABF671101292D0088D64D /* juce_TemporaryFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = juce_TemporaryFile.cpp; sourceTree = ""; }; + 84CABF681101292D0088D64D /* juce_TemporaryFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = juce_TemporaryFile.h; sourceTree = ""; }; 84D0F00B109B1546007F73A3 /* juce_mac_CoreGraphicsContext.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = juce_mac_CoreGraphicsContext.mm; sourceTree = ""; }; 84DEDD9E10EE496500909D01 /* juce_HeapBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = juce_HeapBlock.h; sourceTree = ""; }; 84F1E6DC10403605006A1807 /* juce_Application.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Application.cpp; path = ../../src/application/juce_Application.cpp; sourceTree = SOURCE_ROOT; }; @@ -2325,6 +2329,8 @@ 84F1E993104036D6006A1807 /* juce_FileSearchPath.h */, 84F1E994104036D6006A1807 /* juce_NamedPipe.cpp */, 84F1E995104036D6006A1807 /* juce_NamedPipe.h */, + 84CABF671101292D0088D64D /* juce_TemporaryFile.cpp */, + 84CABF681101292D0088D64D /* juce_TemporaryFile.h */, 84F1E996104036D6006A1807 /* juce_ZipFile.cpp */, 84F1E997104036D6006A1807 /* juce_ZipFile.h */, ); @@ -3550,6 +3556,7 @@ 84AF3FE810EF9FF30035D74F /* juce_ScopedPointer.h in Headers */, 84BA604110F2017A001D9D70 /* juce_Value.h in Headers */, 848432C310F933B800490977 /* juce_ByteOrder.h in Headers */, + 84CABF6A1101292D0088D64D /* juce_TemporaryFile.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4190,6 +4197,7 @@ 84F29A9F10C2EFA5005014DF /* juce_FillType.cpp in Sources */, 843D4A3B10D3C54500624BA6 /* juce_ValueTree.cpp in Sources */, 84BA604010F2017A001D9D70 /* juce_Value.cpp in Sources */, + 84CABF691101292D0088D64D /* juce_TemporaryFile.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/build/win32/vc8/JUCE.vcproj b/build/win32/vc8/JUCE.vcproj index b05a0b490d..53de7db406 100644 --- a/build/win32/vc8/JUCE.vcproj +++ b/build/win32/vc8/JUCE.vcproj @@ -2604,6 +2604,14 @@ RelativePath="..\..\..\src\io\files\juce_NamedPipe.h" > + + + + diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index b0f7e516d2..25ccf9527b 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -1333,7 +1333,7 @@ void JUCE_PUBLIC_FUNCTION initialiseJuce_NonGUI() // Some simple test code to keep an eye on things and make sure these functions // work ok on all platforms. Let me know if any of these assertions fail! - jassert (sizeof (pointer_sized_int) == sizeof (void*)); + static_jassert (sizeof (pointer_sized_int) == sizeof (void*)); char a1[7]; jassert (numElementsInArray(a1) == 7); @@ -6664,16 +6664,9 @@ bool File::replaceWithData (const void* const dataToWrite, if (numberOfBytes <= 0) return deleteFile(); - const File tempFile (getSiblingFile (T(".") + getFileName()).getNonexistentSibling (false)); - - if (tempFile.appendData (dataToWrite, numberOfBytes) - && tempFile.moveFileTo (*this)) - { - return true; - } - - tempFile.deleteFile(); - return false; + TemporaryFile tempFile (*this, TemporaryFile::useHiddenFile); + tempFile.getFile().appendData (dataToWrite, numberOfBytes); + return tempFile.overwriteTargetFileWithTemporary(); } bool File::appendText (const String& text, @@ -6695,16 +6688,9 @@ bool File::replaceWithText (const String& textToWrite, const bool asUnicode, const bool writeUnicodeHeaderBytes) const { - const File tempFile (getSiblingFile (T(".") + getFileName()).getNonexistentSibling (false)); - - if (tempFile.appendText (textToWrite, asUnicode, writeUnicodeHeaderBytes) - && tempFile.moveFileTo (*this)) - { - return true; - } - - tempFile.deleteFile(); - return false; + TemporaryFile tempFile (*this, TemporaryFile::useHiddenFile); + tempFile.getFile().appendText (textToWrite, asUnicode, writeUnicodeHeaderBytes); + return tempFile.overwriteTargetFileWithTemporary(); } const String File::createLegalPathName (const String& original) @@ -6832,12 +6818,9 @@ int File::getVolumeSerialNumber() const const File File::createTempFile (const String& fileNameEnding) { - String tempName (T("temp")); - static int tempNum = 0; - tempName << tempNum++ << fileNameEnding; - const File tempFile (getSpecialLocation (tempDirectory) - .getChildFile (tempName)); + .getChildFile (T("temp_") + String (Random::getSystemRandom().nextInt())) + .withFileExtension (fileNameEnding)); if (tempFile.exists()) return createTempFile (fileNameEnding); @@ -7219,6 +7202,90 @@ const String NamedPipe::getName() const END_JUCE_NAMESPACE /********* End of inlined file: juce_NamedPipe.cpp *********/ +/********* Start of inlined file: juce_TemporaryFile.cpp *********/ + +BEGIN_JUCE_NAMESPACE + +TemporaryFile::TemporaryFile (const String& suffix, const int optionFlags) +{ + createTempFile (File::getSpecialLocation (File::tempDirectory), + T("temp_") + String (Random::getSystemRandom().nextInt()), + suffix, + optionFlags); +} + +TemporaryFile::TemporaryFile (const File& targetFile_, const int optionFlags) + : targetFile (targetFile_) +{ + // If you use this constructor, you need to give it a valid target file! + jassert (targetFile != File::nonexistent); + + createTempFile (targetFile.getParentDirectory(), + targetFile.getFileNameWithoutExtension() + T("_temp") + String (Random::getSystemRandom().nextInt()), + targetFile.getFileExtension(), + optionFlags); +} + +void TemporaryFile::createTempFile (const File& parentDirectory, String name, + const String& suffix, const int optionFlags) +{ + if ((optionFlags & useHiddenFile) != 0) + name = T(".") + name; + + temporaryFile = parentDirectory.getNonexistentChildFile (name, targetFile.getFileExtension(), + (optionFlags & putNumbersInBrackets) != 0); +} + +TemporaryFile::~TemporaryFile() +{ + // Have a few attempts at deleting the file before giving up.. + for (int i = 5; --i >= 0;) + { + if (temporaryFile.deleteFile()) + return; + + Thread::sleep (50); + } + + // Failed to delete our temporary file! Check that you've deleted all the + // file output streams that were using it! + jassertfalse; +} + +bool TemporaryFile::overwriteTargetFileWithTemporary() const +{ + // This method only works if you created this object with the constructor + // that takes a target file! + jassert (targetFile != File::nonexistent); + + if (temporaryFile.exists()) + { + // Have a few attempts at overwriting the file before giving up.. + for (int i = 5; --i >= 0;) + { + if (temporaryFile.moveFileTo (targetFile)) + return true; + + Thread::sleep (100); + } + + // Failed to overwrite the new file! Make sure you've not left any + // file streams hanging around when you call this method! + jassertfalse + } + else + { + // There's no temporary file to use. If your write failed, you should + // probably check, and not bother calling this method. + jassertfalse + } + + return false; +} + +END_JUCE_NAMESPACE +/********* End of inlined file: juce_TemporaryFile.cpp *********/ + /********* Start of inlined file: juce_Socket.cpp *********/ #if JUCE_WINDOWS @@ -14418,34 +14485,15 @@ bool XmlElement::writeToFile (const File& file, { if (file.hasWriteAccess()) { - const File tempFile (file.getNonexistentSibling()); - - ScopedPointer out (tempFile.createOutputStream()); + TemporaryFile tempFile (file); + ScopedPointer out (tempFile.getFile().createOutputStream()); if (out != 0) { writeToStream (*out, dtdToUse, false, true, encodingType, lineWrapLength); out = 0; - if (! tempFile.exists()) - return false; - - int i; - for (i = 5; --i >= 0;) - { - if (tempFile.moveFileTo (file)) - return true; - - Thread::sleep (100); - } - - for (i = 5; --i >= 0;) - { - if (tempFile.deleteFile()) - break; - - Thread::sleep (100); - } + return tempFile.overwriteTargetFileWithTemporary(); } } @@ -18173,8 +18221,9 @@ bool PropertiesFile::save() } else { - const File tempFile (file.getNonexistentSibling (false)); - ScopedPointer out (tempFile.createOutputStream()); + TemporaryFile tempFile (file); + + ScopedPointer out (tempFile.getFile().createOutputStream()); if (out != 0) { @@ -18203,16 +18252,13 @@ bool PropertiesFile::save() out->writeString (getAllProperties().getAllValues() [i]); } - out->flush(); out = 0; - if (tempFile.moveFileTo (file)) + if (tempFile.overwriteTargetFileWithTemporary()) { needsWriting = false; return true; } - - tempFile.deleteFile(); } } @@ -22398,40 +22444,34 @@ AudioFormatWriter* WavAudioFormat::createWriterFor (OutputStream* out, static bool juce_slowCopyOfWavFileWithNewMetadata (const File& file, const StringPairArray& metadata) { - bool ok = false; - WavAudioFormat wav; + TemporaryFile tempFile (file); - const File dest (file.getNonexistentSibling()); + WavAudioFormat wav; + ScopedPointer reader (wav.createReaderFor (file.createInputStream(), true)); + if (reader != 0) { - ScopedPointer outStream (dest.createOutputStream()); + ScopedPointer outStream (tempFile.getFile().createOutputStream()); if (outStream != 0) { - ScopedPointer reader (wav.createReaderFor (file.createInputStream(), true)); + ScopedPointer writer (wav.createWriterFor (outStream, reader->sampleRate, + reader->numChannels, reader->bitsPerSample, + metadata, 0)); - if (reader != 0) + if (writer != 0) { - ScopedPointer writer (wav.createWriterFor (outStream, reader->sampleRate, - reader->numChannels, reader->bitsPerSample, - metadata, 0)); + outStream.release(); - if (writer != 0) - { - ok = writer->writeFromAudioReader (*reader, 0, -1); - outStream.release(); - } + bool ok = writer->writeFromAudioReader (*reader, 0, -1); + writer = 0; + + return ok && tempFile.overwriteTargetFileWithTemporary(); } } } - if (ok) - ok = dest.moveFileTo (file); - - if (! ok) - dest.deleteFile(); - - return ok; + return false; } bool WavAudioFormat::replaceMetadataInFile (const File& wavFile, const StringPairArray& newMetadata) @@ -47073,7 +47113,7 @@ Label::Label (const String& componentName, font (15.0f), justification (Justification::centredLeft), ownerComponent (0), - horizontalBorderSize (3), + horizontalBorderSize (5), verticalBorderSize (1), minimumHorizontalScale (0.7f), editSingleClick (false), @@ -81065,10 +81105,6 @@ END_JUCE_NAMESPACE BEGIN_JUCE_NAMESPACE -#if JUCE_MSVC - #pragma warning (disable: 4996) // deprecated sprintf warning -#endif - // this will throw an assertion if you try to draw something that's not // possible in postscript #define WARN_ABOUT_NON_POSTSCRIPT_OPERATIONS 0 @@ -213263,11 +213299,10 @@ const String File::getVersion() const if (VerQueryValue (buffer, _T("\\"), (LPVOID*) &vffi, &len)) { - result.printf (T("%d.%d.%d.%d"), - HIWORD (vffi->dwFileVersionMS), - LOWORD (vffi->dwFileVersionMS), - HIWORD (vffi->dwFileVersionLS), - LOWORD (vffi->dwFileVersionLS)); + result << (int) HIWORD (vffi->dwFileVersionMS) << "." + << (int) LOWORD (vffi->dwFileVersionMS) << "." + << (int) HIWORD (vffi->dwFileVersionLS) << "." + << (int) LOWORD (vffi->dwFileVersionLS); } } @@ -213905,6 +213940,12 @@ static int getMACAddressViaGetAdaptersInfo (int64* addresses, int maxNum, const return numFound; } +struct ASTAT +{ + ADAPTER_STATUS adapt; + NAME_BUFFER NameBuff [30]; +}; + static int getMACAddressesViaNetBios (int64* addresses, int maxNum, const bool littleEndian) throw() { int numFound = 0; @@ -213917,12 +213958,6 @@ static int getMACAddressesViaNetBios (int64* addresses, int maxNum, const bool l NCB ncb; zerostruct (ncb); - typedef struct _ASTAT_ - { - ADAPTER_STATUS adapt; - NAME_BUFFER NameBuff [30]; - } ASTAT; - ASTAT astat; zerostruct (astat); diff --git a/juce_amalgamated.h b/juce_amalgamated.h index e6d44e4f18..f762d5665f 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -7601,6 +7601,55 @@ private: #endif // __JUCE_NAMEDPIPE_JUCEHEADER__ /********* End of inlined file: juce_NamedPipe.h *********/ +#endif +#ifndef __JUCE_TEMPORARYFILE_JUCEHEADER__ + +/********* Start of inlined file: juce_TemporaryFile.h *********/ +#ifndef __JUCE_TEMPORARYFILE_JUCEHEADER__ +#define __JUCE_TEMPORARYFILE_JUCEHEADER__ + +class JUCE_API TemporaryFile +{ +public: + + enum OptionFlags + { + useHiddenFile = 1, /**< Indicates that the temporary file should be hidden - + i.e. its name should start with a dot. */ + putNumbersInBrackets = 2 /**< Indicates that when numbers are appended to make sure + the file is unique, they should go in brackets rather + than just being appended (see File::getNonexistentSibling() )*/ + }; + + TemporaryFile (const String& suffix = String::empty, + const int optionFlags = 0); + + TemporaryFile (const File& targetFile, + const int optionFlags = 0); + + ~TemporaryFile(); + + const File getFile() const { return temporaryFile; } + + const File getTargetFile() const { return targetFile; } + + bool overwriteTargetFileWithTemporary() const; + + juce_UseDebuggingNewOperator + +private: + + File temporaryFile, targetFile; + + void createTempFile (const File& parentDirectory, String name, const String& suffix, const int optionFlags); + + TemporaryFile (const TemporaryFile&); + const TemporaryFile& operator= (const TemporaryFile&); +}; + +#endif // __JUCE_TEMPORARYFILE_JUCEHEADER__ +/********* End of inlined file: juce_TemporaryFile.h *********/ + #endif #ifndef __JUCE_ZIPFILE_JUCEHEADER__ @@ -25100,6 +25149,9 @@ private: String onText, offText; void createButton(); + + BooleanPropertyComponent (const BooleanPropertyComponent&); + const BooleanPropertyComponent& operator= (const BooleanPropertyComponent&); }; #endif // __JUCE_BOOLEANPROPERTYCOMPONENT_JUCEHEADER__ @@ -25176,6 +25228,9 @@ private: ComboBox* comboBox; void createComboBox(); + + ChoicePropertyComponent (const ChoicePropertyComponent&); + const ChoicePropertyComponent& operator= (const ChoicePropertyComponent&); }; #endif // __JUCE_CHOICEPROPERTYCOMPONENT_JUCEHEADER__ @@ -25229,6 +25284,9 @@ public: protected: Slider* slider; + + SliderPropertyComponent (const SliderPropertyComponent&); + const SliderPropertyComponent& operator= (const SliderPropertyComponent&); }; #endif // __JUCE_SLIDERPROPERTYCOMPONENT_JUCEHEADER__ @@ -25270,6 +25328,9 @@ private: Label* textEditor; void createEditor (const int maxNumChars, const bool isMultiLine); + + TextPropertyComponent (const TextPropertyComponent&); + const TextPropertyComponent& operator= (const TextPropertyComponent&); }; #endif // __JUCE_TEXTPROPERTYCOMPONENT_JUCEHEADER__ diff --git a/src/audio/audio_file_formats/juce_WavAudioFormat.cpp b/src/audio/audio_file_formats/juce_WavAudioFormat.cpp index 751b8d39ad..faa2916048 100644 --- a/src/audio/audio_file_formats/juce_WavAudioFormat.cpp +++ b/src/audio/audio_file_formats/juce_WavAudioFormat.cpp @@ -31,7 +31,7 @@ BEGIN_JUCE_NAMESPACE #include "../../io/streams/juce_BufferedInputStream.h" #include "../../text/juce_LocalisedStrings.h" #include "../../io/files/juce_FileInputStream.h" -#include "../../io/files/juce_FileOutputStream.h" +#include "../../io/files/juce_TemporaryFile.h" //============================================================================== @@ -793,40 +793,34 @@ AudioFormatWriter* WavAudioFormat::createWriterFor (OutputStream* out, static bool juce_slowCopyOfWavFileWithNewMetadata (const File& file, const StringPairArray& metadata) { - bool ok = false; - WavAudioFormat wav; + TemporaryFile tempFile (file); - const File dest (file.getNonexistentSibling()); + WavAudioFormat wav; + ScopedPointer reader (wav.createReaderFor (file.createInputStream(), true)); + if (reader != 0) { - ScopedPointer outStream (dest.createOutputStream()); + ScopedPointer outStream (tempFile.getFile().createOutputStream()); if (outStream != 0) { - ScopedPointer reader (wav.createReaderFor (file.createInputStream(), true)); + ScopedPointer writer (wav.createWriterFor (outStream, reader->sampleRate, + reader->numChannels, reader->bitsPerSample, + metadata, 0)); - if (reader != 0) + if (writer != 0) { - ScopedPointer writer (wav.createWriterFor (outStream, reader->sampleRate, - reader->numChannels, reader->bitsPerSample, - metadata, 0)); + outStream.release(); - if (writer != 0) - { - ok = writer->writeFromAudioReader (*reader, 0, -1); - outStream.release(); - } + bool ok = writer->writeFromAudioReader (*reader, 0, -1); + writer = 0; + + return ok && tempFile.overwriteTargetFileWithTemporary(); } } } - if (ok) - ok = dest.moveFileTo (file); - - if (! ok) - dest.deleteFile(); - - return ok; + return false; } bool WavAudioFormat::replaceMetadataInFile (const File& wavFile, const StringPairArray& newMetadata) diff --git a/src/core/juce_SystemStats.cpp b/src/core/juce_SystemStats.cpp index b92370262d..ffd8e4fbc2 100644 --- a/src/core/juce_SystemStats.cpp +++ b/src/core/juce_SystemStats.cpp @@ -63,7 +63,7 @@ void JUCE_PUBLIC_FUNCTION initialiseJuce_NonGUI() // Some simple test code to keep an eye on things and make sure these functions // work ok on all platforms. Let me know if any of these assertions fail! - jassert (sizeof (pointer_sized_int) == sizeof (void*)); + static_jassert (sizeof (pointer_sized_int) == sizeof (void*)); char a1[7]; jassert (numElementsInArray(a1) == 7); diff --git a/src/gui/components/controls/juce_Label.cpp b/src/gui/components/controls/juce_Label.cpp index 6308450912..9edd7264ff 100644 --- a/src/gui/components/controls/juce_Label.cpp +++ b/src/gui/components/controls/juce_Label.cpp @@ -40,7 +40,7 @@ Label::Label (const String& componentName, font (15.0f), justification (Justification::centredLeft), ownerComponent (0), - horizontalBorderSize (3), + horizontalBorderSize (5), verticalBorderSize (1), minimumHorizontalScale (0.7f), editSingleClick (false), diff --git a/src/gui/components/properties/juce_BooleanPropertyComponent.h b/src/gui/components/properties/juce_BooleanPropertyComponent.h index 3e66e9e77e..655028c1e8 100644 --- a/src/gui/components/properties/juce_BooleanPropertyComponent.h +++ b/src/gui/components/properties/juce_BooleanPropertyComponent.h @@ -93,6 +93,9 @@ private: String onText, offText; void createButton(); + + BooleanPropertyComponent (const BooleanPropertyComponent&); + const BooleanPropertyComponent& operator= (const BooleanPropertyComponent&); }; diff --git a/src/gui/components/properties/juce_ChoicePropertyComponent.h b/src/gui/components/properties/juce_ChoicePropertyComponent.h index c693f85ced..1658caa7cd 100644 --- a/src/gui/components/properties/juce_ChoicePropertyComponent.h +++ b/src/gui/components/properties/juce_ChoicePropertyComponent.h @@ -114,6 +114,9 @@ private: ComboBox* comboBox; void createComboBox(); + + ChoicePropertyComponent (const ChoicePropertyComponent&); + const ChoicePropertyComponent& operator= (const ChoicePropertyComponent&); }; diff --git a/src/gui/components/properties/juce_SliderPropertyComponent.h b/src/gui/components/properties/juce_SliderPropertyComponent.h index db087aaea1..1cb7491430 100644 --- a/src/gui/components/properties/juce_SliderPropertyComponent.h +++ b/src/gui/components/properties/juce_SliderPropertyComponent.h @@ -103,6 +103,9 @@ protected: Your subclass has access to this in case it needs to customise it in some way. */ Slider* slider; + + SliderPropertyComponent (const SliderPropertyComponent&); + const SliderPropertyComponent& operator= (const SliderPropertyComponent&); }; diff --git a/src/gui/components/properties/juce_TextPropertyComponent.h b/src/gui/components/properties/juce_TextPropertyComponent.h index 3e029a9b8c..5cdafef4a5 100644 --- a/src/gui/components/properties/juce_TextPropertyComponent.h +++ b/src/gui/components/properties/juce_TextPropertyComponent.h @@ -92,6 +92,9 @@ private: Label* textEditor; void createEditor (const int maxNumChars, const bool isMultiLine); + + TextPropertyComponent (const TextPropertyComponent&); + const TextPropertyComponent& operator= (const TextPropertyComponent&); }; diff --git a/src/gui/graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp b/src/gui/graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp index d3783a8485..7201b7872c 100644 --- a/src/gui/graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp +++ b/src/gui/graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp @@ -34,11 +34,6 @@ BEGIN_JUCE_NAMESPACE #include "../geometry/juce_Rectangle.h" #include "../../../containers/juce_SparseSet.h" -#if JUCE_MSVC - #pragma warning (disable: 4996) // deprecated sprintf warning -#endif - - // this will throw an assertion if you try to draw something that's not // possible in postscript #define WARN_ABOUT_NON_POSTSCRIPT_OPERATIONS 0 diff --git a/src/io/files/juce_File.cpp b/src/io/files/juce_File.cpp index 9df4cd4fb3..8570957daa 100644 --- a/src/io/files/juce_File.cpp +++ b/src/io/files/juce_File.cpp @@ -39,8 +39,9 @@ BEGIN_JUCE_NAMESPACE #include "juce_File.h" #include "juce_FileInputStream.h" -#include "juce_FileOutputStream.h" +#include "juce_TemporaryFile.h" #include "../../core/juce_SystemStats.h" +#include "../../core/juce_Random.h" #ifdef _MSC_VER #pragma warning (pop) @@ -958,16 +959,9 @@ bool File::replaceWithData (const void* const dataToWrite, if (numberOfBytes <= 0) return deleteFile(); - const File tempFile (getSiblingFile (T(".") + getFileName()).getNonexistentSibling (false)); - - if (tempFile.appendData (dataToWrite, numberOfBytes) - && tempFile.moveFileTo (*this)) - { - return true; - } - - tempFile.deleteFile(); - return false; + TemporaryFile tempFile (*this, TemporaryFile::useHiddenFile); + tempFile.getFile().appendData (dataToWrite, numberOfBytes); + return tempFile.overwriteTargetFileWithTemporary(); } bool File::appendText (const String& text, @@ -989,16 +983,9 @@ bool File::replaceWithText (const String& textToWrite, const bool asUnicode, const bool writeUnicodeHeaderBytes) const { - const File tempFile (getSiblingFile (T(".") + getFileName()).getNonexistentSibling (false)); - - if (tempFile.appendText (textToWrite, asUnicode, writeUnicodeHeaderBytes) - && tempFile.moveFileTo (*this)) - { - return true; - } - - tempFile.deleteFile(); - return false; + TemporaryFile tempFile (*this, TemporaryFile::useHiddenFile); + tempFile.getFile().appendText (textToWrite, asUnicode, writeUnicodeHeaderBytes); + return tempFile.overwriteTargetFileWithTemporary(); } //============================================================================== @@ -1130,12 +1117,9 @@ int File::getVolumeSerialNumber() const //============================================================================== const File File::createTempFile (const String& fileNameEnding) { - String tempName (T("temp")); - static int tempNum = 0; - tempName << tempNum++ << fileNameEnding; - const File tempFile (getSpecialLocation (tempDirectory) - .getChildFile (tempName)); + .getChildFile (T("temp_") + String (Random::getSystemRandom().nextInt())) + .withFileExtension (fileNameEnding)); if (tempFile.exists()) return createTempFile (fileNameEnding); diff --git a/src/io/files/juce_FileOutputStream.h b/src/io/files/juce_FileOutputStream.h index b55508c54a..84452d3a53 100644 --- a/src/io/files/juce_FileOutputStream.h +++ b/src/io/files/juce_FileOutputStream.h @@ -53,6 +53,8 @@ public: It's better to use File::createOutputStream() to create one of these, rather than using the class directly. + + @see TemporaryFile */ FileOutputStream (const File& fileToWriteTo, const int bufferSizeToUse = 16384); diff --git a/src/io/files/juce_TemporaryFile.cpp b/src/io/files/juce_TemporaryFile.cpp new file mode 100644 index 0000000000..bac9c75edf --- /dev/null +++ b/src/io/files/juce_TemporaryFile.cpp @@ -0,0 +1,115 @@ +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-9 by Raw Material Software Ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the GNU General + Public License (Version 2), as published by the Free Software Foundation. + A copy of the license is included in the JUCE distribution, or can be found + online at www.gnu.org/licenses. + + 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. + + ------------------------------------------------------------------------------ + + To release a closed-source product which uses JUCE, commercial licenses are + available: visit www.rawmaterialsoftware.com/juce for more information. + + ============================================================================== +*/ + +#include "../../core/juce_StandardHeader.h" + +BEGIN_JUCE_NAMESPACE + +#include "juce_TemporaryFile.h" +#include "../../core/juce_Random.h" +#include "../../threads/juce_Thread.h" + + +//============================================================================== +TemporaryFile::TemporaryFile (const String& suffix, const int optionFlags) +{ + createTempFile (File::getSpecialLocation (File::tempDirectory), + T("temp_") + String (Random::getSystemRandom().nextInt()), + suffix, + optionFlags); +} + +TemporaryFile::TemporaryFile (const File& targetFile_, const int optionFlags) + : targetFile (targetFile_) +{ + // If you use this constructor, you need to give it a valid target file! + jassert (targetFile != File::nonexistent); + + createTempFile (targetFile.getParentDirectory(), + targetFile.getFileNameWithoutExtension() + T("_temp") + String (Random::getSystemRandom().nextInt()), + targetFile.getFileExtension(), + optionFlags); +} + +void TemporaryFile::createTempFile (const File& parentDirectory, String name, + const String& suffix, const int optionFlags) +{ + if ((optionFlags & useHiddenFile) != 0) + name = T(".") + name; + + temporaryFile = parentDirectory.getNonexistentChildFile (name, targetFile.getFileExtension(), + (optionFlags & putNumbersInBrackets) != 0); +} + +TemporaryFile::~TemporaryFile() +{ + // Have a few attempts at deleting the file before giving up.. + for (int i = 5; --i >= 0;) + { + if (temporaryFile.deleteFile()) + return; + + Thread::sleep (50); + } + + // Failed to delete our temporary file! Check that you've deleted all the + // file output streams that were using it! + jassertfalse; +} + +//============================================================================== +bool TemporaryFile::overwriteTargetFileWithTemporary() const +{ + // This method only works if you created this object with the constructor + // that takes a target file! + jassert (targetFile != File::nonexistent); + + if (temporaryFile.exists()) + { + // Have a few attempts at overwriting the file before giving up.. + for (int i = 5; --i >= 0;) + { + if (temporaryFile.moveFileTo (targetFile)) + return true; + + Thread::sleep (100); + } + + // Failed to overwrite the new file! Make sure you've not left any + // file streams hanging around when you call this method! + jassertfalse + } + else + { + // There's no temporary file to use. If your write failed, you should + // probably check, and not bother calling this method. + jassertfalse + } + + return false; +} + + +END_JUCE_NAMESPACE diff --git a/src/io/files/juce_TemporaryFile.h b/src/io/files/juce_TemporaryFile.h new file mode 100644 index 0000000000..9bfbdca68b --- /dev/null +++ b/src/io/files/juce_TemporaryFile.h @@ -0,0 +1,159 @@ +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-9 by Raw Material Software Ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the GNU General + Public License (Version 2), as published by the Free Software Foundation. + A copy of the license is included in the JUCE distribution, or can be found + online at www.gnu.org/licenses. + + 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. + + ------------------------------------------------------------------------------ + + To release a closed-source product which uses JUCE, commercial licenses are + available: visit www.rawmaterialsoftware.com/juce for more information. + + ============================================================================== +*/ + +#ifndef __JUCE_TEMPORARYFILE_JUCEHEADER__ +#define __JUCE_TEMPORARYFILE_JUCEHEADER__ + +#include "juce_FileOutputStream.h" + + +//============================================================================== +/** + Manages a temporary file, which will be deleted when this object is deleted. + + This object is intended to be used as a stack based object, using its scope + to make sure the temporary file isn't left lying around. + + For example: + + @code + { + File myTargetFile ("~/myfile.txt"); + + // this will choose a file called something like "~/myfile_temp239348.txt" + // which definitely doesn't exist at the time the constructor is called. + TemporaryFile temp (myTargetFile); + + // create a stream to the temporary file, and write some data to it... + ScopedPointer out (temp.getFile().createOutputStream()); + + if (out != 0) + { + out->write ( ...etc ) + out->flush(); + out = 0; // (deletes the stream) + + // ..now we've finished writing, this will rename the temp file to + // make it replace the target file we specified above. + bool succeeded = temp.overwriteTargetFileWithTemporary(); + } + + // ..and even if something went wrong and our overwrite failed, + // as the TemporaryFile object goes out of scope here, it'll make sure + // that the temp file gets deleted. + } + @endcode + + @see File, FileOutputStream +*/ +class JUCE_API TemporaryFile +{ +public: + //============================================================================== + enum OptionFlags + { + useHiddenFile = 1, /**< Indicates that the temporary file should be hidden - + i.e. its name should start with a dot. */ + putNumbersInBrackets = 2 /**< Indicates that when numbers are appended to make sure + the file is unique, they should go in brackets rather + than just being appended (see File::getNonexistentSibling() )*/ + }; + + //============================================================================== + /** Creates a randomly-named temporary file in the default temp directory. + + @param suffix a file suffix to use for the file + @param optionFlags a combination of the values listed in the OptionFlags enum + The file will not be created until you write to it. And remember that when + this object is deleted, the file will also be deleted! + */ + TemporaryFile (const String& suffix = String::empty, + const int optionFlags = 0); + + /** Creates a temporary file in the same directory as a specified file. + + This is useful if you have a file that you want to overwrite, but don't + want to harm the original file if the write operation fails. You can + use this to create a temporary file next to the target file, then + write to the temporary file, and finally use overwriteTargetFileWithTemporary() + to replace the target file with the one you've just written. + + This class won't create any files until you actually write to them. And remember + that when this object is deleted, the temporary file will also be deleted! + + @param targetFile the file that you intend to overwrite - the temporary + file will be created in the same directory as this + @param optionFlags a combination of the values listed in the OptionFlags enum + */ + TemporaryFile (const File& targetFile, + const int optionFlags = 0); + + /** Destructor. + + When this object is deleted it will make sure that its temporary file is + also deleted! If the operation fails, it'll throw an assertion in debug + mode. + */ + ~TemporaryFile(); + + //============================================================================== + /** Returns the temporary file. */ + const File getFile() const { return temporaryFile; } + + /** Returns the target file that was specified in the constructor. */ + const File getTargetFile() const { return targetFile; } + + /** Tries to move the temporary file to overwrite the target file that was + specified in the constructor. + + If you used the constructor that specified a target file, this will attempt + to replace that file with the temporary one. + + Before calling this, make sure: + - that you've actually written to the temporary file + - that you've closed any open streams that you were using to write to it + - and that you don't have any streams open to the target file, which would + prevent it being overwritten + + If the file move succeeds, this returns false, and the temporary file will + have disappeared. If it fails, the temporary file will probably still exist, + but will be deleted when this object is destroyed. + */ + bool overwriteTargetFileWithTemporary() const; + + //============================================================================== + juce_UseDebuggingNewOperator + +private: + //============================================================================== + File temporaryFile, targetFile; + + void createTempFile (const File& parentDirectory, String name, const String& suffix, const int optionFlags); + + TemporaryFile (const TemporaryFile&); + const TemporaryFile& operator= (const TemporaryFile&); +}; + +#endif // __JUCE_TEMPORARYFILE_JUCEHEADER__ diff --git a/src/juce_amalgamated_template.cpp b/src/juce_amalgamated_template.cpp index de8310032e..9333e28e32 100644 --- a/src/juce_amalgamated_template.cpp +++ b/src/juce_amalgamated_template.cpp @@ -94,6 +94,7 @@ #include "io/files/juce_FileOutputStream.cpp" #include "io/files/juce_FileSearchPath.cpp" #include "io/files/juce_NamedPipe.cpp" +#include "io/files/juce_TemporaryFile.cpp" #include "io/network/juce_Socket.cpp" #include "io/network/juce_URL.cpp" #include "io/streams/juce_BufferedInputStream.cpp" diff --git a/src/juce_core_includes.h b/src/juce_core_includes.h index bd5d7610a3..5fc6d73ee3 100644 --- a/src/juce_core_includes.h +++ b/src/juce_core_includes.h @@ -161,6 +161,9 @@ #ifndef __JUCE_NAMEDPIPE_JUCEHEADER__ #include "io/files/juce_NamedPipe.h" #endif +#ifndef __JUCE_TEMPORARYFILE_JUCEHEADER__ + #include "io/files/juce_TemporaryFile.h" +#endif #ifndef __JUCE_ZIPFILE_JUCEHEADER__ #include "io/files/juce_ZipFile.h" #endif diff --git a/src/native/windows/juce_win32_Files.cpp b/src/native/windows/juce_win32_Files.cpp index 530ac0595a..e68da9f53b 100644 --- a/src/native/windows/juce_win32_Files.cpp +++ b/src/native/windows/juce_win32_Files.cpp @@ -540,11 +540,10 @@ const String File::getVersion() const if (VerQueryValue (buffer, _T("\\"), (LPVOID*) &vffi, &len)) { - result.printf (T("%d.%d.%d.%d"), - HIWORD (vffi->dwFileVersionMS), - LOWORD (vffi->dwFileVersionMS), - HIWORD (vffi->dwFileVersionLS), - LOWORD (vffi->dwFileVersionLS)); + result << (int) HIWORD (vffi->dwFileVersionMS) << "." + << (int) LOWORD (vffi->dwFileVersionMS) << "." + << (int) HIWORD (vffi->dwFileVersionLS) << "." + << (int) LOWORD (vffi->dwFileVersionLS); } } diff --git a/src/native/windows/juce_win32_Network.cpp b/src/native/windows/juce_win32_Network.cpp index b6522f2251..f70639c527 100644 --- a/src/native/windows/juce_win32_Network.cpp +++ b/src/native/windows/juce_win32_Network.cpp @@ -289,6 +289,12 @@ static int getMACAddressViaGetAdaptersInfo (int64* addresses, int maxNum, const return numFound; } +struct ASTAT +{ + ADAPTER_STATUS adapt; + NAME_BUFFER NameBuff [30]; +}; + static int getMACAddressesViaNetBios (int64* addresses, int maxNum, const bool littleEndian) throw() { int numFound = 0; @@ -301,12 +307,6 @@ static int getMACAddressesViaNetBios (int64* addresses, int maxNum, const bool l NCB ncb; zerostruct (ncb); - typedef struct _ASTAT_ - { - ADAPTER_STATUS adapt; - NAME_BUFFER NameBuff [30]; - } ASTAT; - ASTAT astat; zerostruct (astat); diff --git a/src/text/juce_XmlElement.cpp b/src/text/juce_XmlElement.cpp index d44f53ec10..3773280788 100644 --- a/src/text/juce_XmlElement.cpp +++ b/src/text/juce_XmlElement.cpp @@ -30,7 +30,7 @@ BEGIN_JUCE_NAMESPACE #include "juce_XmlElement.h" #include "../io/streams/juce_MemoryOutputStream.h" -#include "../io/files/juce_FileOutputStream.h" +#include "../io/files/juce_TemporaryFile.h" #include "../threads/juce_Thread.h" #include "../containers/juce_ScopedPointer.h" @@ -429,34 +429,15 @@ bool XmlElement::writeToFile (const File& file, { if (file.hasWriteAccess()) { - const File tempFile (file.getNonexistentSibling()); - - ScopedPointer out (tempFile.createOutputStream()); + TemporaryFile tempFile (file); + ScopedPointer out (tempFile.getFile().createOutputStream()); if (out != 0) { writeToStream (*out, dtdToUse, false, true, encodingType, lineWrapLength); out = 0; - if (! tempFile.exists()) - return false; - - int i; - for (i = 5; --i >= 0;) - { - if (tempFile.moveFileTo (file)) - return true; - - Thread::sleep (100); - } - - for (i = 5; --i >= 0;) - { - if (tempFile.deleteFile()) - break; - - Thread::sleep (100); - } + return tempFile.overwriteTargetFileWithTemporary(); } } diff --git a/src/utilities/juce_PropertiesFile.cpp b/src/utilities/juce_PropertiesFile.cpp index bd4a840f2b..e1da8f3430 100644 --- a/src/utilities/juce_PropertiesFile.cpp +++ b/src/utilities/juce_PropertiesFile.cpp @@ -29,6 +29,7 @@ BEGIN_JUCE_NAMESPACE #include "juce_PropertiesFile.h" +#include "../io/files/juce_TemporaryFile.h" #include "../io/files/juce_FileInputStream.h" #include "../io/files/juce_FileOutputStream.h" #include "../io/streams/juce_BufferedInputStream.h" @@ -182,8 +183,9 @@ bool PropertiesFile::save() } else { - const File tempFile (file.getNonexistentSibling (false)); - ScopedPointer out (tempFile.createOutputStream()); + TemporaryFile tempFile (file); + + ScopedPointer out (tempFile.getFile().createOutputStream()); if (out != 0) { @@ -212,16 +214,13 @@ bool PropertiesFile::save() out->writeString (getAllProperties().getAllValues() [i]); } - out->flush(); out = 0; - if (tempFile.moveFileTo (file)) + if (tempFile.overwriteTargetFileWithTemporary()) { needsWriting = false; return true; } - - tempFile.deleteFile(); } }