- Library code update
- project update (added Eigen) git-svn-id: http://moon:8086/svn/software/trunk/projects/mpsk_rx_gui@94 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
@@ -35,7 +35,7 @@ AbstractFifo::AbstractFifo (const int capacity) noexcept
|
||||
AbstractFifo::~AbstractFifo() {}
|
||||
|
||||
int AbstractFifo::getTotalSize() const noexcept { return bufferSize; }
|
||||
int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady(); }
|
||||
int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady() - 1; }
|
||||
|
||||
int AbstractFifo::getNumReady() const noexcept
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
- it must be able to be relocated in memory by a memcpy without this causing any problems - so
|
||||
objects whose functionality relies on external pointers or references to themselves can not be used.
|
||||
|
||||
You can of course have an array of pointers to any kind of object, e.g. Array <MyClass*>, but if
|
||||
You can of course have an array of pointers to any kind of object, e.g. Array<MyClass*>, but if
|
||||
you do this, the array doesn't take any ownership of the objects - see the OwnedArray class or the
|
||||
ReferenceCountedArray class for more powerful ways of holding lists of objects.
|
||||
|
||||
@@ -65,8 +65,7 @@ private:
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty array. */
|
||||
Array() noexcept
|
||||
: numUsed (0)
|
||||
Array() noexcept : numUsed (0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ DynamicObject::DynamicObject()
|
||||
}
|
||||
|
||||
DynamicObject::DynamicObject (const DynamicObject& other)
|
||||
: properties (other.properties)
|
||||
: ReferenceCountedObject(), properties (other.properties)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -85,16 +85,9 @@ void DynamicObject::clear()
|
||||
|
||||
void DynamicObject::cloneAllProperties()
|
||||
{
|
||||
for (LinkedListPointer<NamedValueSet::NamedValue>* i = &(properties.values);;)
|
||||
{
|
||||
if (NamedValueSet::NamedValue* const v = i->get())
|
||||
{
|
||||
v->value = v->value.clone();
|
||||
i = &(v->nextListItem);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
for (int i = properties.size(); --i >= 0;)
|
||||
if (var* v = properties.getVarPointerAt (i))
|
||||
*v = v->clone();
|
||||
}
|
||||
|
||||
DynamicObject::Ptr DynamicObject::clone()
|
||||
@@ -110,32 +103,27 @@ void DynamicObject::writeAsJSON (OutputStream& out, const int indentLevel, const
|
||||
if (! allOnOneLine)
|
||||
out << newLine;
|
||||
|
||||
for (LinkedListPointer<NamedValueSet::NamedValue>* i = &(properties.values);;)
|
||||
const int numValues = properties.size();
|
||||
|
||||
for (int i = 0; i < numValues; ++i)
|
||||
{
|
||||
if (NamedValueSet::NamedValue* const v = i->get())
|
||||
if (! allOnOneLine)
|
||||
JSONFormatter::writeSpaces (out, indentLevel + JSONFormatter::indentSize);
|
||||
|
||||
out << '"';
|
||||
JSONFormatter::writeString (out, properties.getName (i));
|
||||
out << "\": ";
|
||||
JSONFormatter::write (out, properties.getValueAt (i), indentLevel + JSONFormatter::indentSize, allOnOneLine);
|
||||
|
||||
if (i < numValues - 1)
|
||||
{
|
||||
if (! allOnOneLine)
|
||||
JSONFormatter::writeSpaces (out, indentLevel + JSONFormatter::indentSize);
|
||||
|
||||
out << '"';
|
||||
JSONFormatter::writeString (out, v->name);
|
||||
out << "\": ";
|
||||
JSONFormatter::write (out, v->value, indentLevel + JSONFormatter::indentSize, allOnOneLine);
|
||||
|
||||
if (v->nextListItem.get() != nullptr)
|
||||
{
|
||||
if (allOnOneLine)
|
||||
out << ", ";
|
||||
else
|
||||
out << ',' << newLine;
|
||||
}
|
||||
else if (! allOnOneLine)
|
||||
out << newLine;
|
||||
|
||||
i = &(v->nextListItem);
|
||||
if (allOnOneLine)
|
||||
out << ", ";
|
||||
else
|
||||
out << ',' << newLine;
|
||||
}
|
||||
else
|
||||
break;
|
||||
else if (! allOnOneLine)
|
||||
out << newLine;
|
||||
}
|
||||
|
||||
if (! allOnOneLine)
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
virtual bool hasProperty (const Identifier& propertyName) const;
|
||||
|
||||
/** Returns a named property.
|
||||
This returns a void if no such property exists.
|
||||
This returns var::null if no such property exists.
|
||||
*/
|
||||
virtual var getProperty (const Identifier& propertyName) const;
|
||||
|
||||
|
||||
@@ -26,53 +26,37 @@
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
NamedValueSet::NamedValue::NamedValue() noexcept
|
||||
struct NamedValueSet::NamedValue
|
||||
{
|
||||
}
|
||||
NamedValue() noexcept {}
|
||||
NamedValue (Identifier n, const var& v) : name (n), value (v) {}
|
||||
NamedValue (const NamedValue& other) : name (other.name), value (other.value) {}
|
||||
|
||||
inline NamedValueSet::NamedValue::NamedValue (Identifier n, const var& v)
|
||||
: name (n), value (v)
|
||||
{
|
||||
}
|
||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
NamedValue (NamedValue&& other) noexcept
|
||||
: name (static_cast<Identifier&&> (other.name)),
|
||||
value (static_cast<var&&> (other.value))
|
||||
{
|
||||
}
|
||||
|
||||
NamedValueSet::NamedValue::NamedValue (const NamedValue& other)
|
||||
: name (other.name), value (other.value)
|
||||
{
|
||||
}
|
||||
NamedValue (Identifier n, var&& v) : name (n), value (static_cast<var&&> (v))
|
||||
{
|
||||
}
|
||||
|
||||
NamedValueSet::NamedValue& NamedValueSet::NamedValue::operator= (const NamedValueSet::NamedValue& other)
|
||||
{
|
||||
name = other.name;
|
||||
value = other.value;
|
||||
return *this;
|
||||
}
|
||||
NamedValue& operator= (NamedValue&& other) noexcept
|
||||
{
|
||||
name = static_cast<Identifier&&> (other.name);
|
||||
value = static_cast<var&&> (other.value);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
NamedValueSet::NamedValue::NamedValue (NamedValue&& other) noexcept
|
||||
: nextListItem (static_cast<LinkedListPointer<NamedValue>&&> (other.nextListItem)),
|
||||
name (static_cast<Identifier&&> (other.name)),
|
||||
value (static_cast<var&&> (other.value))
|
||||
{
|
||||
}
|
||||
bool operator== (const NamedValue& other) const noexcept { return name == other.name && value == other.value; }
|
||||
bool operator!= (const NamedValue& other) const noexcept { return ! operator== (other); }
|
||||
|
||||
inline NamedValueSet::NamedValue::NamedValue (Identifier n, var&& v)
|
||||
: name (n), value (static_cast<var&&> (v))
|
||||
{
|
||||
}
|
||||
|
||||
NamedValueSet::NamedValue& NamedValueSet::NamedValue::operator= (NamedValue&& other) noexcept
|
||||
{
|
||||
nextListItem = static_cast<LinkedListPointer<NamedValue>&&> (other.nextListItem);
|
||||
name = static_cast<Identifier&&> (other.name);
|
||||
value = static_cast<var&&> (other.value);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool NamedValueSet::NamedValue::operator== (const NamedValueSet::NamedValue& other) const noexcept
|
||||
{
|
||||
return name == other.name && value == other.value;
|
||||
}
|
||||
Identifier name;
|
||||
var value;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
NamedValueSet::NamedValueSet() noexcept
|
||||
@@ -80,20 +64,20 @@ NamedValueSet::NamedValueSet() noexcept
|
||||
}
|
||||
|
||||
NamedValueSet::NamedValueSet (const NamedValueSet& other)
|
||||
: values (other.values)
|
||||
{
|
||||
values.addCopyOfList (other.values);
|
||||
}
|
||||
|
||||
NamedValueSet& NamedValueSet::operator= (const NamedValueSet& other)
|
||||
{
|
||||
clear();
|
||||
values.addCopyOfList (other.values);
|
||||
values = other.values;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
NamedValueSet::NamedValueSet (NamedValueSet&& other) noexcept
|
||||
: values (static_cast <LinkedListPointer<NamedValue>&&> (other.values))
|
||||
: values (static_cast <Array<NamedValue>&&> (other.values))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -104,31 +88,18 @@ NamedValueSet& NamedValueSet::operator= (NamedValueSet&& other) noexcept
|
||||
}
|
||||
#endif
|
||||
|
||||
NamedValueSet::~NamedValueSet()
|
||||
NamedValueSet::~NamedValueSet() noexcept
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void NamedValueSet::clear()
|
||||
{
|
||||
values.deleteAll();
|
||||
values.clear();
|
||||
}
|
||||
|
||||
bool NamedValueSet::operator== (const NamedValueSet& other) const
|
||||
{
|
||||
const NamedValue* i1 = values;
|
||||
const NamedValue* i2 = other.values;
|
||||
|
||||
while (i1 != nullptr && i2 != nullptr)
|
||||
{
|
||||
if (! (*i1 == *i2))
|
||||
return false;
|
||||
|
||||
i1 = i1->nextListItem;
|
||||
i2 = i2->nextListItem;
|
||||
}
|
||||
|
||||
return true;
|
||||
return values == other.values;
|
||||
}
|
||||
|
||||
bool NamedValueSet::operator!= (const NamedValueSet& other) const
|
||||
@@ -141,16 +112,15 @@ int NamedValueSet::size() const noexcept
|
||||
return values.size();
|
||||
}
|
||||
|
||||
const var& NamedValueSet::operator[] (Identifier name) const
|
||||
const var& NamedValueSet::operator[] (const Identifier& name) const noexcept
|
||||
{
|
||||
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
|
||||
if (i->name == name)
|
||||
return i->value;
|
||||
if (const var* v = getVarPointer (name))
|
||||
return *v;
|
||||
|
||||
return var::null;
|
||||
}
|
||||
|
||||
var NamedValueSet::getWithDefault (Identifier name, const var& defaultReturnValue) const
|
||||
var NamedValueSet::getWithDefault (const Identifier& name, const var& defaultReturnValue) const
|
||||
{
|
||||
if (const var* const v = getVarPointer (name))
|
||||
return *v;
|
||||
@@ -158,9 +128,9 @@ var NamedValueSet::getWithDefault (Identifier name, const var& defaultReturnValu
|
||||
return defaultReturnValue;
|
||||
}
|
||||
|
||||
var* NamedValueSet::getVarPointer (Identifier name) const noexcept
|
||||
var* NamedValueSet::getVarPointer (const Identifier& name) const noexcept
|
||||
{
|
||||
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
|
||||
for (NamedValue* e = values.end(), *i = values.begin(); i != e; ++i)
|
||||
if (i->name == name)
|
||||
return &(i->value);
|
||||
|
||||
@@ -170,145 +140,121 @@ var* NamedValueSet::getVarPointer (Identifier name) const noexcept
|
||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
bool NamedValueSet::set (Identifier name, var&& newValue)
|
||||
{
|
||||
LinkedListPointer<NamedValue>* i = &values;
|
||||
|
||||
while (i->get() != nullptr)
|
||||
if (var* const v = getVarPointer (name))
|
||||
{
|
||||
NamedValue* const v = i->get();
|
||||
if (v->equalsWithSameType (newValue))
|
||||
return false;
|
||||
|
||||
if (v->name == name)
|
||||
{
|
||||
if (v->value.equalsWithSameType (newValue))
|
||||
return false;
|
||||
|
||||
v->value = static_cast <var&&> (newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
i = &(v->nextListItem);
|
||||
*v = static_cast<var&&> (newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
i->insertNext (new NamedValue (name, static_cast <var&&> (newValue)));
|
||||
values.add (NamedValue (name, static_cast<var&&> (newValue)));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool NamedValueSet::set (Identifier name, const var& newValue)
|
||||
{
|
||||
LinkedListPointer<NamedValue>* i = &values;
|
||||
|
||||
while (i->get() != nullptr)
|
||||
if (var* const v = getVarPointer (name))
|
||||
{
|
||||
NamedValue* const v = i->get();
|
||||
if (v->equalsWithSameType (newValue))
|
||||
return false;
|
||||
|
||||
if (v->name == name)
|
||||
{
|
||||
if (v->value.equalsWithSameType (newValue))
|
||||
return false;
|
||||
|
||||
v->value = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
i = &(v->nextListItem);
|
||||
*v = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
i->insertNext (new NamedValue (name, newValue));
|
||||
values.add (NamedValue (name, newValue));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NamedValueSet::contains (Identifier name) const
|
||||
bool NamedValueSet::contains (const Identifier& name) const noexcept
|
||||
{
|
||||
return getVarPointer (name) != nullptr;
|
||||
}
|
||||
|
||||
int NamedValueSet::indexOf (Identifier name) const noexcept
|
||||
int NamedValueSet::indexOf (const Identifier& name) const noexcept
|
||||
{
|
||||
int index = 0;
|
||||
const int numValues = values.size();
|
||||
|
||||
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
|
||||
{
|
||||
if (i->name == name)
|
||||
return index;
|
||||
|
||||
++index;
|
||||
}
|
||||
for (int i = 0; i < numValues; ++i)
|
||||
if (values.getReference(i).name == name)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool NamedValueSet::remove (Identifier name)
|
||||
bool NamedValueSet::remove (const Identifier& name)
|
||||
{
|
||||
LinkedListPointer<NamedValue>* i = &values;
|
||||
const int numValues = values.size();
|
||||
|
||||
for (;;)
|
||||
for (int i = 0; i < numValues; ++i)
|
||||
{
|
||||
NamedValue* const v = i->get();
|
||||
|
||||
if (v == nullptr)
|
||||
break;
|
||||
|
||||
if (v->name == name)
|
||||
if (values.getReference(i).name == name)
|
||||
{
|
||||
delete i->removeNext();
|
||||
values.remove (i);
|
||||
return true;
|
||||
}
|
||||
|
||||
i = &(v->nextListItem);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Identifier NamedValueSet::getName (const int index) const
|
||||
Identifier NamedValueSet::getName (const int index) const noexcept
|
||||
{
|
||||
const NamedValue* const v = values[index];
|
||||
jassert (v != nullptr);
|
||||
return v->name;
|
||||
if (isPositiveAndBelow (index, values.size()))
|
||||
return values.getReference (index).name;
|
||||
|
||||
jassertfalse;
|
||||
return Identifier();
|
||||
}
|
||||
|
||||
const var& NamedValueSet::getValueAt (const int index) const
|
||||
const var& NamedValueSet::getValueAt (const int index) const noexcept
|
||||
{
|
||||
const NamedValue* const v = values[index];
|
||||
jassert (v != nullptr);
|
||||
return v->value;
|
||||
if (isPositiveAndBelow (index, values.size()))
|
||||
return values.getReference (index).value;
|
||||
|
||||
jassertfalse;
|
||||
return var::null;
|
||||
}
|
||||
|
||||
var* NamedValueSet::getVarPointerAt (int index) const noexcept
|
||||
{
|
||||
if (isPositiveAndBelow (index, values.size()))
|
||||
return &(values.getReference (index).value);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void NamedValueSet::setFromXmlAttributes (const XmlElement& xml)
|
||||
{
|
||||
clear();
|
||||
LinkedListPointer<NamedValue>::Appender appender (values);
|
||||
values.clearQuick();
|
||||
|
||||
const int numAtts = xml.getNumAttributes(); // xxx inefficient - should write an att iterator..
|
||||
|
||||
for (int i = 0; i < numAtts; ++i)
|
||||
for (const XmlElement::XmlAttributeNode* att = xml.attributes; att != nullptr; att = att->nextListItem)
|
||||
{
|
||||
const String& name = xml.getAttributeName (i);
|
||||
const String& value = xml.getAttributeValue (i);
|
||||
|
||||
if (name.startsWith ("base64:"))
|
||||
if (att->name.toString().startsWith ("base64:"))
|
||||
{
|
||||
MemoryBlock mb;
|
||||
|
||||
if (mb.fromBase64Encoding (value))
|
||||
if (mb.fromBase64Encoding (att->value))
|
||||
{
|
||||
appender.append (new NamedValue (name.substring (7), var (mb)));
|
||||
values.add (NamedValue (att->name.toString().substring (7), var (mb)));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
appender.append (new NamedValue (name, var (value)));
|
||||
values.add (NamedValue (att->name, var (att->value)));
|
||||
}
|
||||
}
|
||||
|
||||
void NamedValueSet::copyToXmlAttributes (XmlElement& xml) const
|
||||
{
|
||||
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
|
||||
for (NamedValue* e = values.end(), *i = values.begin(); i != e; ++i)
|
||||
{
|
||||
if (const MemoryBlock* mb = i->value.getBinaryData())
|
||||
{
|
||||
xml.setAttribute ("base64:" + i->name.toString(),
|
||||
mb->toBase64Encoding());
|
||||
xml.setAttribute ("base64:" + i->name.toString(), mb->toBase64Encoding());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
#endif
|
||||
|
||||
/** Destructor. */
|
||||
~NamedValueSet();
|
||||
~NamedValueSet() noexcept;
|
||||
|
||||
bool operator== (const NamedValueSet&) const;
|
||||
bool operator!= (const NamedValueSet&) const;
|
||||
@@ -67,12 +67,12 @@ public:
|
||||
If the name isn't found, this will return a void variant.
|
||||
@see getProperty
|
||||
*/
|
||||
const var& operator[] (Identifier name) const;
|
||||
const var& operator[] (const Identifier& name) const noexcept;
|
||||
|
||||
/** Tries to return the named value, but if no such value is found, this will
|
||||
instead return the supplied default value.
|
||||
*/
|
||||
var getWithDefault (Identifier name, const var& defaultReturnValue) const;
|
||||
var getWithDefault (const Identifier& name, const var& defaultReturnValue) const;
|
||||
|
||||
/** Changes or adds a named value.
|
||||
@returns true if a value was changed or added; false if the
|
||||
@@ -89,38 +89,42 @@ public:
|
||||
#endif
|
||||
|
||||
/** Returns true if the set contains an item with the specified name. */
|
||||
bool contains (Identifier name) const;
|
||||
bool contains (const Identifier& name) const noexcept;
|
||||
|
||||
/** Removes a value from the set.
|
||||
@returns true if a value was removed; false if there was no value
|
||||
with the name that was given.
|
||||
*/
|
||||
bool remove (Identifier name);
|
||||
bool remove (const Identifier& name);
|
||||
|
||||
/** Returns the name of the value at a given index.
|
||||
The index must be between 0 and size() - 1.
|
||||
*/
|
||||
Identifier getName (int index) const;
|
||||
Identifier getName (int index) const noexcept;
|
||||
|
||||
/** Returns the value of the item at a given index.
|
||||
The index must be between 0 and size() - 1.
|
||||
*/
|
||||
const var& getValueAt (int index) const;
|
||||
|
||||
/** Returns the index of the given name, or -1 if it's not found. */
|
||||
int indexOf (Identifier name) const noexcept;
|
||||
|
||||
/** Removes all values. */
|
||||
void clear();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a pointer to the var that holds a named value, or null if there is
|
||||
no value with this name.
|
||||
|
||||
Do not use this method unless you really need access to the internal var object
|
||||
for some reason - for normal reading and writing always prefer operator[]() and set().
|
||||
*/
|
||||
var* getVarPointer (Identifier name) const noexcept;
|
||||
var* getVarPointer (const Identifier& name) const noexcept;
|
||||
|
||||
/** Returns the value of the item at a given index.
|
||||
The index must be between 0 and size() - 1.
|
||||
*/
|
||||
const var& getValueAt (int index) const noexcept;
|
||||
|
||||
/** Returns the value of the item at a given index.
|
||||
The index must be between 0 and size() - 1, or this will return a nullptr
|
||||
*/
|
||||
var* getVarPointerAt (int index) const noexcept;
|
||||
|
||||
/** Returns the index of the given name, or -1 if it's not found. */
|
||||
int indexOf (const Identifier& name) const noexcept;
|
||||
|
||||
/** Removes all values. */
|
||||
void clear();
|
||||
|
||||
//==============================================================================
|
||||
/** Sets properties to the values of all of an XML element's attributes. */
|
||||
@@ -133,32 +137,8 @@ public:
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class NamedValue
|
||||
{
|
||||
public:
|
||||
NamedValue() noexcept;
|
||||
NamedValue (const NamedValue&);
|
||||
NamedValue (Identifier, const var&);
|
||||
NamedValue& operator= (const NamedValue&);
|
||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
NamedValue (NamedValue&&) noexcept;
|
||||
NamedValue (Identifier, var&&);
|
||||
NamedValue& operator= (NamedValue&&) noexcept;
|
||||
#endif
|
||||
bool operator== (const NamedValue&) const noexcept;
|
||||
|
||||
LinkedListPointer<NamedValue> nextListItem;
|
||||
Identifier name;
|
||||
var value;
|
||||
|
||||
private:
|
||||
JUCE_LEAK_DETECTOR (NamedValue)
|
||||
};
|
||||
|
||||
friend class LinkedListPointer<NamedValue>;
|
||||
LinkedListPointer<NamedValue> values;
|
||||
|
||||
friend class DynamicObject;
|
||||
struct NamedValue;
|
||||
Array<NamedValue> values;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -830,7 +830,7 @@ public:
|
||||
This will use a comparator object to sort the elements into order. The object
|
||||
passed must have a method of the form:
|
||||
@code
|
||||
int compareElements (ElementType first, ElementType second);
|
||||
int compareElements (ElementType* first, ElementType* second);
|
||||
@endcode
|
||||
|
||||
..and this method must return:
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
The template parameter specifies the class of the object you want to point to - the easiest
|
||||
way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject
|
||||
or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable
|
||||
class by implementing a set of mathods called incReferenceCount(), decReferenceCount(), and
|
||||
class by implementing a set of methods called incReferenceCount(), decReferenceCount(), and
|
||||
decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods
|
||||
should behave.
|
||||
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
const ScopedLockType lock (other.getLock());
|
||||
numUsed = other.size();
|
||||
data.setAllocatedSize (numUsed);
|
||||
memcpy (data.elements, other.getRawDataPointer(), numUsed * sizeof (ObjectClass*));
|
||||
memcpy (data.elements, other.getRawDataPointer(), (size_t) numUsed * sizeof (ObjectClass*));
|
||||
|
||||
for (int i = numUsed; --i >= 0;)
|
||||
if (ObjectClass* o = data.elements[i])
|
||||
|
||||
@@ -476,7 +476,7 @@ bool File::loadFileAsData (MemoryBlock& destBlock) const
|
||||
return false;
|
||||
|
||||
FileInputStream in (*this);
|
||||
return in.openedOk() && getSize() == in.readIntoMemoryBlock (destBlock);
|
||||
return in.openedOk() && getSize() == (int64) in.readIntoMemoryBlock (destBlock);
|
||||
}
|
||||
|
||||
String File::loadFileAsString() const
|
||||
|
||||
@@ -361,6 +361,14 @@ public:
|
||||
*/
|
||||
File getLinkedTarget() const;
|
||||
|
||||
/** Returns a unique identifier for the file, if one is available.
|
||||
|
||||
Depending on the OS and file-system, this may be a unix inode number or
|
||||
a win32 file identifier, or 0 if it fails to find one. The number will
|
||||
be unique on the filesystem, but not globally.
|
||||
*/
|
||||
uint64 getFileIdentifier() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the last modification time of this file.
|
||||
|
||||
@@ -836,6 +844,11 @@ public:
|
||||
/** In a plugin, this will return the path of the host executable. */
|
||||
hostApplicationPath,
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
/** On a Windows machine, returns the location of the Windows/System32 folder. */
|
||||
windowsSystemDirectory,
|
||||
#endif
|
||||
|
||||
/** The directory in which applications normally get installed.
|
||||
So on windows, this would be something like "c:\program files", on the
|
||||
Mac "/Applications", or "/usr" on linux.
|
||||
|
||||
@@ -28,41 +28,34 @@
|
||||
|
||||
int64 juce_fileSetPosition (void* handle, int64 pos);
|
||||
|
||||
|
||||
//==============================================================================
|
||||
FileInputStream::FileInputStream (const File& f)
|
||||
: file (f),
|
||||
fileHandle (nullptr),
|
||||
currentPosition (0),
|
||||
status (Result::ok()),
|
||||
needToSeek (true)
|
||||
status (Result::ok())
|
||||
{
|
||||
openHandle();
|
||||
}
|
||||
|
||||
FileInputStream::~FileInputStream()
|
||||
{
|
||||
closeHandle();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int64 FileInputStream::getTotalLength()
|
||||
{
|
||||
// You should always check that a stream opened successfully before using it!
|
||||
jassert (openedOk());
|
||||
|
||||
return file.getSize();
|
||||
}
|
||||
|
||||
int FileInputStream::read (void* buffer, int bytesToRead)
|
||||
{
|
||||
// You should always check that a stream opened successfully before using it!
|
||||
jassert (openedOk());
|
||||
|
||||
// The buffer should never be null, and a negative size is probably a
|
||||
// sign that something is broken!
|
||||
jassert (buffer != nullptr && bytesToRead >= 0);
|
||||
|
||||
if (needToSeek)
|
||||
{
|
||||
if (juce_fileSetPosition (fileHandle, currentPosition) < 0)
|
||||
return 0;
|
||||
|
||||
needToSeek = false;
|
||||
}
|
||||
|
||||
const size_t num = readInternal (buffer, (size_t) bytesToRead);
|
||||
currentPosition += num;
|
||||
|
||||
@@ -81,15 +74,11 @@ int64 FileInputStream::getPosition()
|
||||
|
||||
bool FileInputStream::setPosition (int64 pos)
|
||||
{
|
||||
// You should always check that a stream opened successfully before using it!
|
||||
jassert (openedOk());
|
||||
|
||||
if (pos != currentPosition)
|
||||
{
|
||||
pos = jlimit ((int64) 0, getTotalLength(), pos);
|
||||
currentPosition = juce_fileSetPosition (fileHandle, pos);
|
||||
|
||||
needToSeek |= (currentPosition != pos);
|
||||
currentPosition = pos;
|
||||
}
|
||||
|
||||
return true;
|
||||
return currentPosition == pos;
|
||||
}
|
||||
|
||||
@@ -40,10 +40,11 @@ class JUCE_API FileInputStream : public InputStream
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a FileInputStream.
|
||||
/** Creates a FileInputStream to read from the given file.
|
||||
|
||||
@param fileToRead the file to read from - if the file can't be accessed for some
|
||||
reason, then the stream will just contain no data
|
||||
After creating a FileInputStream, you should use openedOk() or failedToOpen()
|
||||
to make sure that it's OK before trying to read from it! If it failed, you
|
||||
can call getStatus() to get more error information.
|
||||
*/
|
||||
explicit FileInputStream (const File& fileToRead);
|
||||
|
||||
@@ -73,24 +74,23 @@ public:
|
||||
|
||||
//==============================================================================
|
||||
int64 getTotalLength() override;
|
||||
int read (void* destBuffer, int maxBytesToRead) override;
|
||||
int read (void*, int) override;
|
||||
bool isExhausted() override;
|
||||
int64 getPosition() override;
|
||||
bool setPosition (int64 pos) override;
|
||||
bool setPosition (int64) override;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
File file;
|
||||
const File file;
|
||||
void* fileHandle;
|
||||
int64 currentPosition;
|
||||
Result status;
|
||||
bool needToSeek;
|
||||
|
||||
void openHandle();
|
||||
void closeHandle();
|
||||
size_t readInternal (void* buffer, size_t numBytes);
|
||||
size_t readInternal (void*, size_t);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileInputStream)
|
||||
};
|
||||
|
||||
|
||||
#endif // JUCE_FILEINPUTSTREAM_H_INCLUDED
|
||||
|
||||
@@ -26,32 +26,7 @@
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
WildcardFileFilter::WildcardFileFilter (const String& fileWildcardPatterns,
|
||||
const String& directoryWildcardPatterns,
|
||||
const String& desc)
|
||||
: FileFilter (desc.isEmpty() ? fileWildcardPatterns
|
||||
: (desc + " (" + fileWildcardPatterns + ")"))
|
||||
{
|
||||
parse (fileWildcardPatterns, fileWildcards);
|
||||
parse (directoryWildcardPatterns, directoryWildcards);
|
||||
}
|
||||
|
||||
WildcardFileFilter::~WildcardFileFilter()
|
||||
{
|
||||
}
|
||||
|
||||
bool WildcardFileFilter::isFileSuitable (const File& file) const
|
||||
{
|
||||
return match (file, fileWildcards);
|
||||
}
|
||||
|
||||
bool WildcardFileFilter::isDirectorySuitable (const File& file) const
|
||||
{
|
||||
return match (file, directoryWildcards);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void WildcardFileFilter::parse (const String& pattern, StringArray& result)
|
||||
static void parseWildcard (const String& pattern, StringArray& result)
|
||||
{
|
||||
result.addTokens (pattern.toLowerCase(), ";,", "\"'");
|
||||
|
||||
@@ -65,7 +40,7 @@ void WildcardFileFilter::parse (const String& pattern, StringArray& result)
|
||||
result.set (i, "*");
|
||||
}
|
||||
|
||||
bool WildcardFileFilter::match (const File& file, const StringArray& wildcards)
|
||||
static bool matchWildcard (const File& file, const StringArray& wildcards)
|
||||
{
|
||||
const String filename (file.getFileName());
|
||||
|
||||
@@ -75,3 +50,27 @@ bool WildcardFileFilter::match (const File& file, const StringArray& wildcards)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
WildcardFileFilter::WildcardFileFilter (const String& fileWildcardPatterns,
|
||||
const String& directoryWildcardPatterns,
|
||||
const String& desc)
|
||||
: FileFilter (desc.isEmpty() ? fileWildcardPatterns
|
||||
: (desc + " (" + fileWildcardPatterns + ")"))
|
||||
{
|
||||
parseWildcard (fileWildcardPatterns, fileWildcards);
|
||||
parseWildcard (directoryWildcardPatterns, directoryWildcards);
|
||||
}
|
||||
|
||||
WildcardFileFilter::~WildcardFileFilter()
|
||||
{
|
||||
}
|
||||
|
||||
bool WildcardFileFilter::isFileSuitable (const File& file) const
|
||||
{
|
||||
return matchWildcard (file, fileWildcards);
|
||||
}
|
||||
|
||||
bool WildcardFileFilter::isDirectorySuitable (const File& file) const
|
||||
{
|
||||
return matchWildcard (file, directoryWildcards);
|
||||
}
|
||||
|
||||
@@ -75,12 +75,8 @@ private:
|
||||
//==============================================================================
|
||||
StringArray fileWildcards, directoryWildcards;
|
||||
|
||||
static void parse (const String& pattern, StringArray& result);
|
||||
static bool match (const File& file, const StringArray& wildcards);
|
||||
|
||||
JUCE_LEAK_DETECTOR (WildcardFileFilter)
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // JUCE_WILDCARDFILEFILTER_H_INCLUDED
|
||||
|
||||
@@ -243,9 +243,9 @@ private:
|
||||
if (r.failed())
|
||||
return r;
|
||||
|
||||
const String propertyName (propertyNameVar.toString());
|
||||
const Identifier propertyName (propertyNameVar.toString());
|
||||
|
||||
if (propertyName.isNotEmpty())
|
||||
if (propertyName.isValid())
|
||||
{
|
||||
t = t.findEndOfWhitespace();
|
||||
oldT = t;
|
||||
|
||||
@@ -102,6 +102,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
static bool isNumericOrUndefined (const var& v) { return v.isInt() || v.isDouble() || v.isInt64() || v.isBool() || v.isUndefined(); }
|
||||
static int64 getOctalValue (const String& s) { BigInteger b; b.parseString (s, 8); return b.toInt64(); }
|
||||
static Identifier getPrototypeIdentifier() { static const Identifier i ("prototype"); return i; }
|
||||
static var* getPropertyPointer (DynamicObject* o, Identifier i) { return o->getProperties().getVarPointer (i); }
|
||||
|
||||
//==============================================================================
|
||||
struct CodeLocation
|
||||
@@ -139,13 +140,13 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
{
|
||||
if (DynamicObject* o = targetObject.getDynamicObject())
|
||||
{
|
||||
if (var* prop = o->getProperties().getVarPointer (functionName))
|
||||
if (const var* prop = getPropertyPointer (o, functionName))
|
||||
return *prop;
|
||||
|
||||
for (DynamicObject* p = o->getProperty (getPrototypeIdentifier()).getDynamicObject(); p != nullptr;
|
||||
p = p->getProperty (getPrototypeIdentifier()).getDynamicObject())
|
||||
{
|
||||
if (var* prop = p->getProperties().getVarPointer (functionName))
|
||||
if (const var* prop = getPropertyPointer (p, functionName))
|
||||
return *prop;
|
||||
}
|
||||
}
|
||||
@@ -168,14 +169,14 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
var* findRootClassProperty (Identifier className, Identifier propName) const
|
||||
{
|
||||
if (DynamicObject* cls = root->getProperty (className).getDynamicObject())
|
||||
return cls->getProperties().getVarPointer (propName);
|
||||
return getPropertyPointer (cls, propName);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
var findSymbolInParentScopes (Identifier name) const
|
||||
{
|
||||
if (var* v = scope->getProperties().getVarPointer (name))
|
||||
if (const var* v = getPropertyPointer (scope, name))
|
||||
return *v;
|
||||
|
||||
return parent != nullptr ? parent->findSymbolInParentScopes (name)
|
||||
@@ -184,13 +185,11 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
|
||||
bool findAndInvokeMethod (Identifier function, const var::NativeFunctionArgs& args, var& result) const
|
||||
{
|
||||
const NamedValueSet& props = scope->getProperties();
|
||||
|
||||
DynamicObject* target = args.thisObject.getDynamicObject();
|
||||
|
||||
if (target == nullptr || target == scope)
|
||||
{
|
||||
if (const var* m = props.getVarPointer (function))
|
||||
if (const var* m = getPropertyPointer (scope, function))
|
||||
{
|
||||
if (FunctionObject* fo = dynamic_cast<FunctionObject*> (m->getObject()))
|
||||
{
|
||||
@@ -200,6 +199,8 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
}
|
||||
}
|
||||
|
||||
const NamedValueSet& props = scope->getProperties();
|
||||
|
||||
for (int i = 0; i < props.size(); ++i)
|
||||
if (DynamicObject* o = props.getValueAt (i).getDynamicObject())
|
||||
if (Scope (this, root, o).findAndInvokeMethod (function, args, result))
|
||||
@@ -353,7 +354,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
|
||||
void assign (const Scope& s, const var& newValue) const override
|
||||
{
|
||||
if (var* v = s.scope->getProperties().getVarPointer (name))
|
||||
if (var* v = getPropertyPointer (s.scope, name))
|
||||
*v = newValue;
|
||||
else
|
||||
s.root->setProperty (name, newValue);
|
||||
@@ -378,7 +379,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
}
|
||||
|
||||
if (DynamicObject* o = p.getDynamicObject())
|
||||
if (var* v = o->getProperties().getVarPointer (child))
|
||||
if (const var* v = getPropertyPointer (o, child))
|
||||
return *v;
|
||||
|
||||
return var::undefined();
|
||||
@@ -543,14 +544,14 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
struct DivideOp : public BinaryOperator
|
||||
{
|
||||
DivideOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::divide) {}
|
||||
var getWithDoubles (double a, double b) const override { return a / b; }
|
||||
var getWithInts (int64 a, int64 b) const override { return a / b; }
|
||||
var getWithDoubles (double a, double b) const override { return b != 0 ? a / b : std::numeric_limits<double>::infinity(); }
|
||||
var getWithInts (int64 a, int64 b) const override { return b != 0 ? var (a / (double) b) : var (std::numeric_limits<double>::infinity()); }
|
||||
};
|
||||
|
||||
struct ModuloOp : public BinaryOperator
|
||||
{
|
||||
ModuloOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::modulo) {}
|
||||
var getWithInts (int64 a, int64 b) const override { return a % b; }
|
||||
var getWithInts (int64 a, int64 b) const override { return b != 0 ? var (a % b) : var (std::numeric_limits<double>::infinity()); }
|
||||
};
|
||||
|
||||
struct BitwiseOrOp : public BinaryOperator
|
||||
@@ -768,7 +769,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
{
|
||||
FunctionObject() noexcept {}
|
||||
|
||||
FunctionObject (const FunctionObject& other) : functionCode (other.functionCode)
|
||||
FunctionObject (const FunctionObject& other) : DynamicObject(), functionCode (other.functionCode)
|
||||
{
|
||||
ExpressionTreeBuilder tb (functionCode);
|
||||
tb.parseFunctionParamsAndBody (*this);
|
||||
@@ -843,7 +844,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
String::CharPointerType end (p);
|
||||
while (isIdentifierBody (*++end)) {}
|
||||
|
||||
const size_t len = end - p;
|
||||
const size_t len = (size_t) (end - p);
|
||||
#define JUCE_JS_COMPARE_KEYWORD(name, str) if (len == sizeof (str) - 1 && matchToken (TokenTypes::name, len)) return TokenTypes::name;
|
||||
JUCE_JS_KEYWORDS (JUCE_JS_COMPARE_KEYWORD)
|
||||
|
||||
@@ -1145,8 +1146,14 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
match (TokenTypes::semicolon);
|
||||
}
|
||||
|
||||
s->iterator = parseExpression();
|
||||
match (TokenTypes::closeParen);
|
||||
if (matchIf (TokenTypes::closeParen))
|
||||
s->iterator = new Statement (location);
|
||||
else
|
||||
{
|
||||
s->iterator = parseExpression();
|
||||
match (TokenTypes::closeParen);
|
||||
}
|
||||
|
||||
s->body = parseStatement();
|
||||
return s.release();
|
||||
}
|
||||
@@ -1555,6 +1562,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
setMethod ("log", Math_log); setMethod ("log10", Math_log10);
|
||||
setMethod ("exp", Math_exp); setMethod ("pow", Math_pow);
|
||||
setMethod ("sqr", Math_sqr); setMethod ("sqrt", Math_sqrt);
|
||||
setMethod ("ceil", Math_ceil); setMethod ("floor", Math_floor);
|
||||
}
|
||||
|
||||
static var Math_pi (Args) { return double_Pi; }
|
||||
@@ -1587,6 +1595,8 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
static var Math_pow (Args a) { return pow (getDouble (a, 0), getDouble (a, 1)); }
|
||||
static var Math_sqr (Args a) { double x = getDouble (a, 0); return x * x; }
|
||||
static var Math_sqrt (Args a) { return std::sqrt (getDouble (a, 0)); }
|
||||
static var Math_ceil (Args a) { return std::ceil (getDouble (a, 0)); }
|
||||
static var Math_floor (Args a) { return std::floor (getDouble (a, 0)); }
|
||||
|
||||
static Identifier getClassName() { static const Identifier i ("Math"); return i; }
|
||||
template <typename Type> static Type sign (Type n) noexcept { return n > 0 ? (Type) 1 : (n < 0 ? (Type) -1 : 0); }
|
||||
@@ -1649,7 +1659,7 @@ JavascriptEngine::JavascriptEngine() : maximumExecutionTime (15.0), root (new R
|
||||
|
||||
JavascriptEngine::~JavascriptEngine() {}
|
||||
|
||||
void JavascriptEngine::prepareTimeout() const { root->timeout = Time::getCurrentTime() + maximumExecutionTime; }
|
||||
void JavascriptEngine::prepareTimeout() const noexcept { root->timeout = Time::getCurrentTime() + maximumExecutionTime; }
|
||||
|
||||
void JavascriptEngine::registerNativeObject (Identifier name, DynamicObject* object)
|
||||
{
|
||||
@@ -1705,6 +1715,11 @@ var JavascriptEngine::callFunction (Identifier function, const var::NativeFuncti
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
const NamedValueSet& JavascriptEngine::getRootObjectProperties() const noexcept
|
||||
{
|
||||
return root->getProperties();
|
||||
}
|
||||
|
||||
#if JUCE_MSVC
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
@@ -96,10 +96,13 @@ public:
|
||||
*/
|
||||
RelativeTime maximumExecutionTime;
|
||||
|
||||
/** Provides access to the set of properties of the root namespace object. */
|
||||
const NamedValueSet& getRootObjectProperties() const noexcept;
|
||||
|
||||
private:
|
||||
JUCE_PUBLIC_IN_DLL_BUILD (struct RootObject)
|
||||
ReferenceCountedObjectPtr<RootObject> root;
|
||||
void prepareTimeout() const;
|
||||
const ReferenceCountedObjectPtr<RootObject> root;
|
||||
void prepareTimeout() const noexcept;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JavascriptEngine)
|
||||
};
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
#include <ctime>
|
||||
|
||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS 1
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
@@ -79,6 +81,7 @@
|
||||
|
||||
#if JUCE_LINUX
|
||||
#include <langinfo.h>
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#include <pwd.h>
|
||||
|
||||
@@ -194,6 +194,7 @@ extern JUCE_API void JUCE_CALLTYPE logAssertion (const char* file, int line) noe
|
||||
#include "threads/juce_ScopedLock.h"
|
||||
#include "threads/juce_CriticalSection.h"
|
||||
#include "maths/juce_Range.h"
|
||||
#include "maths/juce_NormalisableRange.h"
|
||||
#include "containers/juce_ElementComparator.h"
|
||||
#include "containers/juce_ArrayAllocationBase.h"
|
||||
#include "containers/juce_Array.h"
|
||||
@@ -244,6 +245,7 @@ extern JUCE_API void JUCE_CALLTYPE logAssertion (const char* file, int line) noe
|
||||
#include "misc/juce_Uuid.h"
|
||||
#include "misc/juce_WindowsRegistry.h"
|
||||
#include "system/juce_PlatformDefs.h"
|
||||
#include "system/juce_CompilerSupport.h"
|
||||
#include "system/juce_SystemStats.h"
|
||||
#include "threads/juce_ChildProcess.h"
|
||||
#include "threads/juce_DynamicLibrary.h"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "juce_core",
|
||||
"name": "JUCE core classes",
|
||||
"version": "3.0.5",
|
||||
"version": "3.0.8",
|
||||
"description": "The essential set of basic JUCE classes, as required by all the other JUCE modules. Includes text, container, memory, threading and i/o functionality.",
|
||||
"website": "http://www.juce.com/juce",
|
||||
"license": "ISC Permissive",
|
||||
|
||||
@@ -307,41 +307,28 @@ void BigInteger::negate() noexcept
|
||||
negative = (! negative) && ! isZero();
|
||||
}
|
||||
|
||||
#if JUCE_USE_INTRINSICS && ! defined (__INTEL_COMPILER)
|
||||
#if JUCE_USE_MSVC_INTRINSICS && ! defined (__INTEL_COMPILER)
|
||||
#pragma intrinsic (_BitScanReverse)
|
||||
#endif
|
||||
|
||||
namespace BitFunctions
|
||||
inline static int highestBitInInt (uint32 n) noexcept
|
||||
{
|
||||
inline int countBitsInInt32 (uint32 n) noexcept
|
||||
{
|
||||
n -= ((n >> 1) & 0x55555555);
|
||||
n = (((n >> 2) & 0x33333333) + (n & 0x33333333));
|
||||
n = (((n >> 4) + n) & 0x0f0f0f0f);
|
||||
n += (n >> 8);
|
||||
n += (n >> 16);
|
||||
return (int) (n & 0x3f);
|
||||
}
|
||||
jassert (n != 0); // (the built-in functions may not work for n = 0)
|
||||
|
||||
inline int highestBitInInt (uint32 n) noexcept
|
||||
{
|
||||
jassert (n != 0); // (the built-in functions may not work for n = 0)
|
||||
|
||||
#if JUCE_GCC
|
||||
return 31 - __builtin_clz (n);
|
||||
#elif JUCE_USE_INTRINSICS
|
||||
unsigned long highest;
|
||||
_BitScanReverse (&highest, n);
|
||||
return (int) highest;
|
||||
#else
|
||||
n |= (n >> 1);
|
||||
n |= (n >> 2);
|
||||
n |= (n >> 4);
|
||||
n |= (n >> 8);
|
||||
n |= (n >> 16);
|
||||
return countBitsInInt32 (n >> 1);
|
||||
#endif
|
||||
}
|
||||
#if JUCE_GCC
|
||||
return 31 - __builtin_clz (n);
|
||||
#elif JUCE_USE_MSVC_INTRINSICS
|
||||
unsigned long highest;
|
||||
_BitScanReverse (&highest, n);
|
||||
return (int) highest;
|
||||
#else
|
||||
n |= (n >> 1);
|
||||
n |= (n >> 2);
|
||||
n |= (n >> 4);
|
||||
n |= (n >> 8);
|
||||
n |= (n >> 16);
|
||||
return countBitsInInt32 (n >> 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int BigInteger::countNumberOfSetBits() const noexcept
|
||||
@@ -349,7 +336,7 @@ int BigInteger::countNumberOfSetBits() const noexcept
|
||||
int total = 0;
|
||||
|
||||
for (int i = (int) bitToIndex (highestBit) + 1; --i >= 0;)
|
||||
total += BitFunctions::countBitsInInt32 (values[i]);
|
||||
total += countNumberOfBits (values[i]);
|
||||
|
||||
return total;
|
||||
}
|
||||
@@ -361,7 +348,7 @@ int BigInteger::getHighestBit() const noexcept
|
||||
const uint32 n = values[i];
|
||||
|
||||
if (n != 0)
|
||||
return BitFunctions::highestBitInInt (n) + (i << 5);
|
||||
return highestBitInInt (n) + (i << 5);
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
@@ -364,6 +364,11 @@ inline int roundToInt (const FloatType value) noexcept
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int roundToInt (int value) noexcept
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
#if JUCE_MSVC
|
||||
#ifndef __INTEL_COMPILER
|
||||
#pragma float_control (pop)
|
||||
@@ -438,6 +443,23 @@ inline int nextPowerOfTwo (int n) noexcept
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
/** Returns the number of bits in a 32-bit integer. */
|
||||
inline int countNumberOfBits (uint32 n) noexcept
|
||||
{
|
||||
n -= ((n >> 1) & 0x55555555);
|
||||
n = (((n >> 2) & 0x33333333) + (n & 0x33333333));
|
||||
n = (((n >> 4) + n) & 0x0f0f0f0f);
|
||||
n += (n >> 8);
|
||||
n += (n >> 16);
|
||||
return (int) (n & 0x3f);
|
||||
}
|
||||
|
||||
/** Returns the number of bits in a 64-bit integer. */
|
||||
inline int countNumberOfBits (uint64 n) noexcept
|
||||
{
|
||||
return countNumberOfBits ((uint32) n) + countNumberOfBits ((uint32) (n >> 32));
|
||||
}
|
||||
|
||||
/** Performs a modulo operation, but can cope with the dividend being negative.
|
||||
The divisor must be greater than zero.
|
||||
*/
|
||||
|
||||
@@ -77,6 +77,13 @@ public:
|
||||
: Range (position2, position1);
|
||||
}
|
||||
|
||||
/** Returns a range with a given start and length. */
|
||||
static Range withStartAndLength (const ValueType startValue, const ValueType length) noexcept
|
||||
{
|
||||
jassert (length >= ValueType());
|
||||
return Range (startValue, startValue + length);
|
||||
}
|
||||
|
||||
/** Returns a range with the specified start position and a length of zero. */
|
||||
static Range emptyRange (const ValueType start) noexcept
|
||||
{
|
||||
|
||||
@@ -218,7 +218,7 @@ private:
|
||||
#else
|
||||
#define JUCE_ATOMICS_WINDOWS 1 // Windows with intrinsics
|
||||
|
||||
#if JUCE_USE_INTRINSICS
|
||||
#if JUCE_USE_MSVC_INTRINSICS
|
||||
#ifndef __INTEL_COMPILER
|
||||
#pragma intrinsic (_InterlockedExchange, _InterlockedIncrement, _InterlockedDecrement, _InterlockedCompareExchange, \
|
||||
_InterlockedCompareExchange64, _InterlockedExchangeAdd, _ReadWriteBarrier)
|
||||
|
||||
@@ -87,16 +87,16 @@ public:
|
||||
|
||||
//==============================================================================
|
||||
/** Converts 3 little-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
|
||||
static int littleEndian24Bit (const char* bytes) noexcept;
|
||||
static int littleEndian24Bit (const void* bytes) noexcept;
|
||||
|
||||
/** Converts 3 big-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
|
||||
static int bigEndian24Bit (const char* bytes) noexcept;
|
||||
static int bigEndian24Bit (const void* bytes) noexcept;
|
||||
|
||||
/** Copies a 24-bit number to 3 little-endian bytes. */
|
||||
static void littleEndian24BitToChars (int value, char* destBytes) noexcept;
|
||||
static void littleEndian24BitToChars (int value, void* destBytes) noexcept;
|
||||
|
||||
/** Copies a 24-bit number to 3 big-endian bytes. */
|
||||
static void bigEndian24BitToChars (int value, char* destBytes) noexcept;
|
||||
static void bigEndian24BitToChars (int value, void* destBytes) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the current CPU is big-endian. */
|
||||
@@ -110,16 +110,16 @@ private:
|
||||
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_USE_INTRINSICS && ! defined (__INTEL_COMPILER)
|
||||
#if JUCE_USE_MSVC_INTRINSICS && ! defined (__INTEL_COMPILER)
|
||||
#pragma intrinsic (_byteswap_ulong)
|
||||
#endif
|
||||
|
||||
inline uint16 ByteOrder::swap (uint16 n) noexcept
|
||||
{
|
||||
#if JUCE_USE_INTRINSICSxxx // agh - the MS compiler has an internal error when you try to use this intrinsic!
|
||||
return static_cast <uint16> (_byteswap_ushort (n));
|
||||
#if JUCE_USE_MSVC_INTRINSICSxxx // agh - the MS compiler has an internal error when you try to use this intrinsic!
|
||||
return static_cast<uint16> (_byteswap_ushort (n));
|
||||
#else
|
||||
return static_cast <uint16> ((n << 8) | (n >> 8));
|
||||
return static_cast<uint16> ((n << 8) | (n >> 8));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ inline uint32 ByteOrder::swap (uint32 n) noexcept
|
||||
#elif JUCE_GCC && JUCE_INTEL && ! JUCE_NO_INLINE_ASM
|
||||
asm("bswap %%eax" : "=a"(n) : "a"(n));
|
||||
return n;
|
||||
#elif JUCE_USE_INTRINSICS
|
||||
#elif JUCE_USE_MSVC_INTRINSICS
|
||||
return _byteswap_ulong (n);
|
||||
#elif JUCE_MSVC && ! JUCE_NO_INLINE_ASM
|
||||
__asm {
|
||||
@@ -150,7 +150,7 @@ inline uint64 ByteOrder::swap (uint64 value) noexcept
|
||||
{
|
||||
#if JUCE_MAC || JUCE_IOS
|
||||
return OSSwapInt64 (value);
|
||||
#elif JUCE_USE_INTRINSICS
|
||||
#elif JUCE_USE_MSVC_INTRINSICS
|
||||
return _byteswap_uint64 (value);
|
||||
#else
|
||||
return (((int64) swap ((uint32) value)) << 32) | swap ((uint32) (value >> 32));
|
||||
@@ -164,12 +164,12 @@ inline uint64 ByteOrder::swap (uint64 value) noexcept
|
||||
inline uint16 ByteOrder::swapIfLittleEndian (const uint16 v) noexcept { return swap (v); }
|
||||
inline uint32 ByteOrder::swapIfLittleEndian (const uint32 v) noexcept { return swap (v); }
|
||||
inline uint64 ByteOrder::swapIfLittleEndian (const uint64 v) noexcept { return swap (v); }
|
||||
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) noexcept { return *static_cast <const uint32*> (bytes); }
|
||||
inline uint64 ByteOrder::littleEndianInt64 (const void* const bytes) noexcept { return *static_cast <const uint64*> (bytes); }
|
||||
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) noexcept { return *static_cast <const uint16*> (bytes); }
|
||||
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) noexcept { return swap (*static_cast <const uint32*> (bytes)); }
|
||||
inline uint64 ByteOrder::bigEndianInt64 (const void* const bytes) noexcept { return swap (*static_cast <const uint64*> (bytes)); }
|
||||
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) noexcept { return swap (*static_cast <const uint16*> (bytes)); }
|
||||
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) noexcept { return *static_cast<const uint32*> (bytes); }
|
||||
inline uint64 ByteOrder::littleEndianInt64 (const void* const bytes) noexcept { return *static_cast<const uint64*> (bytes); }
|
||||
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) noexcept { return *static_cast<const uint16*> (bytes); }
|
||||
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) noexcept { return swap (*static_cast<const uint32*> (bytes)); }
|
||||
inline uint64 ByteOrder::bigEndianInt64 (const void* const bytes) noexcept { return swap (*static_cast<const uint64*> (bytes)); }
|
||||
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) noexcept { return swap (*static_cast<const uint16*> (bytes)); }
|
||||
inline bool ByteOrder::isBigEndian() noexcept { return false; }
|
||||
#else
|
||||
inline uint16 ByteOrder::swapIfBigEndian (const uint16 v) noexcept { return swap (v); }
|
||||
@@ -178,19 +178,19 @@ inline uint64 ByteOrder::swap (uint64 value) noexcept
|
||||
inline uint16 ByteOrder::swapIfLittleEndian (const uint16 v) noexcept { return v; }
|
||||
inline uint32 ByteOrder::swapIfLittleEndian (const uint32 v) noexcept { return v; }
|
||||
inline uint64 ByteOrder::swapIfLittleEndian (const uint64 v) noexcept { return v; }
|
||||
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) noexcept { return swap (*static_cast <const uint32*> (bytes)); }
|
||||
inline uint64 ByteOrder::littleEndianInt64 (const void* const bytes) noexcept { return swap (*static_cast <const uint64*> (bytes)); }
|
||||
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) noexcept { return swap (*static_cast <const uint16*> (bytes)); }
|
||||
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) noexcept { return *static_cast <const uint32*> (bytes); }
|
||||
inline uint64 ByteOrder::bigEndianInt64 (const void* const bytes) noexcept { return *static_cast <const uint64*> (bytes); }
|
||||
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) noexcept { return *static_cast <const uint16*> (bytes); }
|
||||
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) noexcept { return swap (*static_cast<const uint32*> (bytes)); }
|
||||
inline uint64 ByteOrder::littleEndianInt64 (const void* const bytes) noexcept { return swap (*static_cast<const uint64*> (bytes)); }
|
||||
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) noexcept { return swap (*static_cast<const uint16*> (bytes)); }
|
||||
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) noexcept { return *static_cast<const uint32*> (bytes); }
|
||||
inline uint64 ByteOrder::bigEndianInt64 (const void* const bytes) noexcept { return *static_cast<const uint64*> (bytes); }
|
||||
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) noexcept { return *static_cast<const uint16*> (bytes); }
|
||||
inline bool ByteOrder::isBigEndian() noexcept { return true; }
|
||||
#endif
|
||||
|
||||
inline int ByteOrder::littleEndian24Bit (const char* const bytes) noexcept { return (((int) bytes[2]) << 16) | (((int) (uint8) bytes[1]) << 8) | ((int) (uint8) bytes[0]); }
|
||||
inline int ByteOrder::bigEndian24Bit (const char* const bytes) noexcept { return (((int) bytes[0]) << 16) | (((int) (uint8) bytes[1]) << 8) | ((int) (uint8) bytes[2]); }
|
||||
inline void ByteOrder::littleEndian24BitToChars (const int value, char* const destBytes) noexcept { destBytes[0] = (char)(value & 0xff); destBytes[1] = (char)((value >> 8) & 0xff); destBytes[2] = (char)((value >> 16) & 0xff); }
|
||||
inline void ByteOrder::bigEndian24BitToChars (const int value, char* const destBytes) noexcept { destBytes[0] = (char)((value >> 16) & 0xff); destBytes[1] = (char)((value >> 8) & 0xff); destBytes[2] = (char)(value & 0xff); }
|
||||
inline int ByteOrder::littleEndian24Bit (const void* const bytes) noexcept { return (((int) static_cast<const int8*> (bytes)[2]) << 16) | (((int) static_cast<const uint8*> (bytes)[1]) << 8) | ((int) static_cast<const uint8*> (bytes)[0]); }
|
||||
inline int ByteOrder::bigEndian24Bit (const void* const bytes) noexcept { return (((int) static_cast<const int8*> (bytes)[0]) << 16) | (((int) static_cast<const uint8*> (bytes)[1]) << 8) | ((int) static_cast<const uint8*> (bytes)[2]); }
|
||||
inline void ByteOrder::littleEndian24BitToChars (const int value, void* const destBytes) noexcept { static_cast<uint8*> (destBytes)[0] = (uint8) value; static_cast<uint8*> (destBytes)[1] = (uint8) (value >> 8); static_cast<uint8*> (destBytes)[2] = (uint8) (value >> 16); }
|
||||
inline void ByteOrder::bigEndian24BitToChars (const int value, void* const destBytes) noexcept { static_cast<uint8*> (destBytes)[0] = (uint8) (value >> 16); static_cast<uint8*> (destBytes)[1] = (uint8) (value >> 8); static_cast<uint8*> (destBytes)[2] = (uint8) value; }
|
||||
|
||||
|
||||
#endif // JUCE_BYTEORDER_H_INCLUDED
|
||||
|
||||
@@ -88,14 +88,14 @@ MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other)
|
||||
|
||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
MemoryBlock::MemoryBlock (MemoryBlock&& other) noexcept
|
||||
: data (static_cast <HeapBlock<char>&&> (other.data)),
|
||||
: data (static_cast<HeapBlock<char>&&> (other.data)),
|
||||
size (other.size)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryBlock& MemoryBlock::operator= (MemoryBlock&& other) noexcept
|
||||
{
|
||||
data = static_cast <HeapBlock<char>&&> (other.data);
|
||||
data = static_cast<HeapBlock<char>&&> (other.data);
|
||||
size = other.size;
|
||||
return *this;
|
||||
}
|
||||
@@ -346,7 +346,7 @@ void MemoryBlock::loadFromHexString (StringRef hex)
|
||||
|
||||
if (c == 0)
|
||||
{
|
||||
setSize (static_cast <size_t> (dest - data));
|
||||
setSize (static_cast<size_t> (dest - data));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ private:
|
||||
The template parameter specifies the class of the object you want to point to - the easiest
|
||||
way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject
|
||||
or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable
|
||||
class by implementing a set of mathods called incReferenceCount(), decReferenceCount(), and
|
||||
class by implementing a set of methods called incReferenceCount(), decReferenceCount(), and
|
||||
decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods
|
||||
should behave.
|
||||
|
||||
|
||||
@@ -182,11 +182,11 @@ public:
|
||||
/** Swaps this object with that of another ScopedPointer.
|
||||
The two objects simply exchange their pointers.
|
||||
*/
|
||||
void swapWith (ScopedPointer <ObjectType>& other) noexcept
|
||||
void swapWith (ScopedPointer<ObjectType>& other) noexcept
|
||||
{
|
||||
// Two ScopedPointers should never be able to refer to the same object - if
|
||||
// this happens, you must have done something dodgy!
|
||||
jassert (object != other.object || this == other.getAddress());
|
||||
jassert (object != other.object || this == other.getAddress() || object == nullptr);
|
||||
|
||||
std::swap (object, other.object);
|
||||
}
|
||||
@@ -231,7 +231,7 @@ private:
|
||||
template <class ObjectType>
|
||||
bool operator== (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
|
||||
{
|
||||
return static_cast <ObjectType*> (pointer1) == pointer2;
|
||||
return static_cast<ObjectType*> (pointer1) == pointer2;
|
||||
}
|
||||
|
||||
/** Compares a ScopedPointer with another pointer.
|
||||
@@ -240,7 +240,7 @@ bool operator== (const ScopedPointer<ObjectType>& pointer1, ObjectType* const po
|
||||
template <class ObjectType>
|
||||
bool operator!= (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
|
||||
{
|
||||
return static_cast <ObjectType*> (pointer1) != pointer2;
|
||||
return static_cast<ObjectType*> (pointer1) != pointer2;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
@@ -139,7 +139,7 @@ private:
|
||||
|
||||
static SharedObjectHolder& getSharedObjectHolder() noexcept
|
||||
{
|
||||
static char holder [sizeof (SharedObjectHolder)] = { 0 };
|
||||
static void* holder [(sizeof (SharedObjectHolder) + sizeof(void*) - 1) / sizeof(void*)] = { 0 };
|
||||
return *reinterpret_cast<SharedObjectHolder*> (holder);
|
||||
}
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ public:
|
||||
public:
|
||||
Master() noexcept {}
|
||||
|
||||
~Master()
|
||||
~Master() noexcept
|
||||
{
|
||||
// You must remember to call clear() in your source object's destructor! See the notes
|
||||
// for the WeakReference class for an example of how to do this.
|
||||
@@ -187,7 +187,7 @@ public:
|
||||
to zero all the references to this object that may be out there. See the WeakReference
|
||||
class notes for an example of how to do this.
|
||||
*/
|
||||
void clear()
|
||||
void clear() noexcept
|
||||
{
|
||||
if (sharedPointer != nullptr)
|
||||
sharedPointer->clearPointer();
|
||||
|
||||
@@ -399,16 +399,21 @@ public final class JuceAppActivity extends Activity
|
||||
private native void handleKeyDown (long host, int keycode, int textchar);
|
||||
private native void handleKeyUp (long host, int keycode, int textchar);
|
||||
|
||||
public void showKeyboard (boolean shouldShow)
|
||||
public void showKeyboard (String type)
|
||||
{
|
||||
InputMethodManager imm = (InputMethodManager) getSystemService (Context.INPUT_METHOD_SERVICE);
|
||||
|
||||
if (imm != null)
|
||||
{
|
||||
if (shouldShow)
|
||||
imm.showSoftInput (this, InputMethodManager.SHOW_FORCED);
|
||||
if (type.length() > 0)
|
||||
{
|
||||
imm.showSoftInput (this, android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT);
|
||||
imm.setInputMethod (getWindowToken(), type);
|
||||
}
|
||||
else
|
||||
{
|
||||
imm.hideSoftInputFromWindow (getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -271,26 +271,33 @@ public:
|
||||
|
||||
JNIEnv* attach() noexcept
|
||||
{
|
||||
if (JNIEnv* env = attachToCurrentThread())
|
||||
if (android.activity != nullptr)
|
||||
{
|
||||
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||
return addEnv (env);
|
||||
if (JNIEnv* env = attachToCurrentThread())
|
||||
{
|
||||
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||
return addEnv (env);
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void detach() noexcept
|
||||
{
|
||||
jvm->DetachCurrentThread();
|
||||
if (android.activity != nullptr)
|
||||
{
|
||||
jvm->DetachCurrentThread();
|
||||
|
||||
const pthread_t thisThread = pthread_self();
|
||||
const pthread_t thisThread = pthread_self();
|
||||
|
||||
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||
for (int i = 0; i < maxThreads; ++i)
|
||||
if (threads[i] == thisThread)
|
||||
threads[i] = 0;
|
||||
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||
for (int i = 0; i < maxThreads; ++i)
|
||||
if (threads[i] == thisThread)
|
||||
threads[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEnv* getOrAttach() noexcept
|
||||
@@ -355,6 +362,12 @@ private:
|
||||
|
||||
extern ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder;
|
||||
|
||||
struct AndroidThreadScope
|
||||
{
|
||||
AndroidThreadScope() { threadLocalJNIEnvHolder.attach(); }
|
||||
~AndroidThreadScope() { threadLocalJNIEnvHolder.detach(); }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
METHOD (createNewView, "createNewView", "(ZJ)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;") \
|
||||
|
||||
@@ -166,7 +166,7 @@ public:
|
||||
int numBytes = stream.callIntMethod (HTTPStream.read, javaArray, (jint) bytesToRead);
|
||||
|
||||
if (numBytes > 0)
|
||||
env->GetByteArrayRegion (javaArray, 0, numBytes, static_cast <jbyte*> (buffer));
|
||||
env->GetByteArrayRegion (javaArray, 0, numBytes, static_cast<jbyte*> (buffer));
|
||||
|
||||
env->DeleteLocalRef (javaArray);
|
||||
return numBytes;
|
||||
|
||||
@@ -179,6 +179,16 @@ namespace AndroidStatsHelpers
|
||||
JuceAppActivity.getLocaleValue,
|
||||
isRegion)));
|
||||
}
|
||||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD)
|
||||
DECLARE_JNI_CLASS (BuildClass, "android/os/Build");
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
String getAndroidOsBuildValue (const char* fieldName)
|
||||
{
|
||||
return juceString (LocalRef<jstring> ((jstring) getEnv()->GetStaticObjectField (
|
||||
BuildClass, getEnv()->GetStaticFieldID (BuildClass, fieldName, "Ljava/lang/String;"))));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
@@ -194,7 +204,8 @@ String SystemStats::getOperatingSystemName()
|
||||
|
||||
String SystemStats::getDeviceDescription()
|
||||
{
|
||||
return String::empty;
|
||||
return AndroidStatsHelpers::getAndroidOsBuildValue ("MODEL")
|
||||
+ "-" + AndroidStatsHelpers::getAndroidOsBuildValue ("SERIAL");
|
||||
}
|
||||
|
||||
bool SystemStats::isOperatingSystem64Bit()
|
||||
@@ -262,7 +273,7 @@ String SystemStats::getComputerName()
|
||||
|
||||
String SystemStats::getUserLanguage() { return AndroidStatsHelpers::getLocaleValue (false); }
|
||||
String SystemStats::getUserRegion() { return AndroidStatsHelpers::getLocaleValue (true); }
|
||||
String SystemStats::getDisplayLanguage() { return getUserLanguage(); }
|
||||
String SystemStats::getDisplayLanguage() { return getUserLanguage() + "-" + getUserRegion(); }
|
||||
|
||||
//==============================================================================
|
||||
void CPUInformation::initialise() noexcept
|
||||
|
||||
@@ -31,23 +31,26 @@ void MACAddress::findAllAddresses (Array<MACAddress>& result)
|
||||
const int s = socket (AF_INET, SOCK_DGRAM, 0);
|
||||
if (s != -1)
|
||||
{
|
||||
char buf [1024];
|
||||
struct ifconf ifc;
|
||||
ifc.ifc_len = sizeof (buf);
|
||||
ifc.ifc_buf = buf;
|
||||
ioctl (s, SIOCGIFCONF, &ifc);
|
||||
struct ifaddrs* addrs = nullptr;
|
||||
|
||||
for (unsigned int i = 0; i < ifc.ifc_len / sizeof (struct ifreq); ++i)
|
||||
if (getifaddrs (&addrs) != -1)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
strcpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name);
|
||||
|
||||
if (ioctl (s, SIOCGIFFLAGS, &ifr) == 0
|
||||
&& (ifr.ifr_flags & IFF_LOOPBACK) == 0
|
||||
&& ioctl (s, SIOCGIFHWADDR, &ifr) == 0)
|
||||
for (struct ifaddrs* i = addrs; i != nullptr; i = i->ifa_next)
|
||||
{
|
||||
result.addIfNotAlreadyThere (MACAddress ((const uint8*) ifr.ifr_hwaddr.sa_data));
|
||||
struct ifreq ifr;
|
||||
strcpy (ifr.ifr_name, i->ifa_name);
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
|
||||
if (ioctl (s, SIOCGIFHWADDR, &ifr) == 0)
|
||||
{
|
||||
MACAddress ma ((const uint8*) ifr.ifr_hwaddr.sa_data);
|
||||
|
||||
if (! ma.isNull())
|
||||
result.addIfNotAlreadyThere (ma);
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs (addrs);
|
||||
}
|
||||
|
||||
close (s);
|
||||
@@ -260,7 +263,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
String responseHeader (readResponse (socketHandle, timeOutTime));
|
||||
String responseHeader (readResponse (timeOutTime));
|
||||
position = 0;
|
||||
|
||||
if (responseHeader.isNotEmpty())
|
||||
@@ -299,7 +302,7 @@ private:
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String readResponse (const int socketHandle, const uint32 timeOutTime)
|
||||
String readResponse (const uint32 timeOutTime)
|
||||
{
|
||||
int numConsecutiveLFs = 0;
|
||||
MemoryOutputStream buffer;
|
||||
@@ -335,7 +338,8 @@ private:
|
||||
dest << "\r\n" << key << ' ' << value;
|
||||
}
|
||||
|
||||
static void writeHost (MemoryOutputStream& dest, const bool isPost, const String& path, const String& host, const int port)
|
||||
static void writeHost (MemoryOutputStream& dest, const bool isPost,
|
||||
const String& path, const String& host, int /*port*/)
|
||||
{
|
||||
dest << (isPost ? "POST " : "GET ") << path << " HTTP/1.0\r\nHost: " << host;
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ static String getLocaleValue (nl_item key)
|
||||
|
||||
String SystemStats::getUserLanguage() { return getLocaleValue (_NL_IDENTIFICATION_LANGUAGE); }
|
||||
String SystemStats::getUserRegion() { return getLocaleValue (_NL_IDENTIFICATION_TERRITORY); }
|
||||
String SystemStats::getDisplayLanguage() { return getUserLanguage(); }
|
||||
String SystemStats::getDisplayLanguage() { return getUserLanguage() + "-" + getUserRegion(); }
|
||||
|
||||
//==============================================================================
|
||||
void CPUInformation::initialise() noexcept
|
||||
|
||||
@@ -79,10 +79,11 @@ JUCE_API bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
|
||||
return juce_isRunningUnderDebugger();
|
||||
}
|
||||
|
||||
static void swapUserAndEffectiveUser()
|
||||
static bool swapUserAndEffectiveUser()
|
||||
{
|
||||
(void) setreuid (geteuid(), getuid());
|
||||
(void) setregid (getegid(), getgid());
|
||||
int result1 = setreuid (geteuid(), getuid());
|
||||
int result2 = setregid (getegid(), getgid());
|
||||
return result1 == 0 && result2 == 0;
|
||||
}
|
||||
|
||||
JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() { if (geteuid() != 0 && getuid() == 0) swapUserAndEffectiveUser(); }
|
||||
|
||||
@@ -39,12 +39,17 @@ void MACAddress::findAllAddresses (Array<MACAddress>& result)
|
||||
{
|
||||
const sockaddr_dl* const sadd = (const sockaddr_dl*) cursor->ifa_addr;
|
||||
|
||||
#ifndef IFT_ETHER
|
||||
#define IFT_ETHER 6
|
||||
#endif
|
||||
#ifndef IFT_ETHER
|
||||
enum { IFT_ETHER = 6 };
|
||||
#endif
|
||||
|
||||
if (sadd->sdl_type == IFT_ETHER)
|
||||
result.addIfNotAlreadyThere (MACAddress (((const uint8*) sadd->sdl_data) + sadd->sdl_nlen));
|
||||
{
|
||||
MACAddress ma (MACAddress (((const uint8*) sadd->sdl_data) + sadd->sdl_nlen));
|
||||
|
||||
if (! ma.isNull())
|
||||
result.addIfNotAlreadyThere (ma);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||
return iOS;
|
||||
#else
|
||||
StringArray parts;
|
||||
parts.addTokens (getOSXVersion(), ".", String());
|
||||
parts.addTokens (getOSXVersion(), ".", StringRef());
|
||||
|
||||
jassert (parts[0].getIntValue() == 10);
|
||||
const int major = parts[1].getIntValue();
|
||||
@@ -241,35 +241,41 @@ String SystemStats::getDisplayLanguage()
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class HiResCounterHandler
|
||||
/* NB: these are kept outside the HiResCounterInfo struct and initialised to 1 to avoid
|
||||
division-by-zero errors if some other static constructor calls us before this file's
|
||||
static constructors have had a chance to fill them in correctly..
|
||||
*/
|
||||
static uint64 hiResCounterNumerator = 0, hiResCounterDenominator = 1;
|
||||
|
||||
class HiResCounterInfo
|
||||
{
|
||||
public:
|
||||
HiResCounterHandler()
|
||||
HiResCounterInfo()
|
||||
{
|
||||
mach_timebase_info_data_t timebase;
|
||||
(void) mach_timebase_info (&timebase);
|
||||
|
||||
if (timebase.numer % 1000000 == 0)
|
||||
{
|
||||
numerator = timebase.numer / 1000000;
|
||||
denominator = timebase.denom;
|
||||
hiResCounterNumerator = timebase.numer / 1000000;
|
||||
hiResCounterDenominator = timebase.denom;
|
||||
}
|
||||
else
|
||||
{
|
||||
numerator = timebase.numer;
|
||||
denominator = timebase.denom * (uint64) 1000000;
|
||||
hiResCounterNumerator = timebase.numer;
|
||||
hiResCounterDenominator = timebase.denom * (uint64) 1000000;
|
||||
}
|
||||
|
||||
highResTimerFrequency = (timebase.denom * (uint64) 1000000000) / timebase.numer;
|
||||
highResTimerToMillisecRatio = numerator / (double) denominator;
|
||||
highResTimerToMillisecRatio = hiResCounterNumerator / (double) hiResCounterDenominator;
|
||||
}
|
||||
|
||||
inline uint32 millisecondsSinceStartup() const noexcept
|
||||
uint32 millisecondsSinceStartup() const noexcept
|
||||
{
|
||||
return (uint32) ((mach_absolute_time() * numerator) / denominator);
|
||||
return (uint32) ((mach_absolute_time() * hiResCounterNumerator) / hiResCounterDenominator);
|
||||
}
|
||||
|
||||
inline double getMillisecondCounterHiRes() const noexcept
|
||||
double getMillisecondCounterHiRes() const noexcept
|
||||
{
|
||||
return mach_absolute_time() * highResTimerToMillisecRatio;
|
||||
}
|
||||
@@ -277,15 +283,14 @@ public:
|
||||
int64 highResTimerFrequency;
|
||||
|
||||
private:
|
||||
uint64 numerator, denominator;
|
||||
double highResTimerToMillisecRatio;
|
||||
};
|
||||
|
||||
static HiResCounterHandler hiResCounterHandler;
|
||||
static HiResCounterInfo hiResCounterInfo;
|
||||
|
||||
uint32 juce_millisecondsSinceStartup() noexcept { return hiResCounterHandler.millisecondsSinceStartup(); }
|
||||
double Time::getMillisecondCounterHiRes() noexcept { return hiResCounterHandler.getMillisecondCounterHiRes(); }
|
||||
int64 Time::getHighResolutionTicksPerSecond() noexcept { return hiResCounterHandler.highResTimerFrequency; }
|
||||
uint32 juce_millisecondsSinceStartup() noexcept { return hiResCounterInfo.millisecondsSinceStartup(); }
|
||||
double Time::getMillisecondCounterHiRes() noexcept { return hiResCounterInfo.getMillisecondCounterHiRes(); }
|
||||
int64 Time::getHighResolutionTicksPerSecond() noexcept { return hiResCounterInfo.highResTimerFrequency; }
|
||||
int64 Time::getHighResolutionTicks() noexcept { return (int64) mach_absolute_time(); }
|
||||
|
||||
bool Time::setSystemTimeToThisTime() const
|
||||
|
||||
@@ -223,6 +223,12 @@ namespace
|
||||
return statfs (f.getFullPathName().toUTF8(), &result) == 0;
|
||||
}
|
||||
|
||||
#if (JUCE_MAC && MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || JUCE_IOS
|
||||
static int64 getCreationTime (const juce_statStruct& s) noexcept { return (int64) s.st_birthtime; }
|
||||
#else
|
||||
static int64 getCreationTime (const juce_statStruct& s) noexcept { return (int64) s.st_ctime; }
|
||||
#endif
|
||||
|
||||
void updateStatInfoForFile (const String& path, bool* const isDir, int64* const fileSize,
|
||||
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||
{
|
||||
@@ -232,9 +238,9 @@ namespace
|
||||
const bool statOk = juce_stat (path, info);
|
||||
|
||||
if (isDir != nullptr) *isDir = statOk && ((info.st_mode & S_IFDIR) != 0);
|
||||
if (fileSize != nullptr) *fileSize = statOk ? info.st_size : 0;
|
||||
if (modTime != nullptr) *modTime = Time (statOk ? (int64) info.st_mtime * 1000 : 0);
|
||||
if (creationTime != nullptr) *creationTime = Time (statOk ? (int64) info.st_ctime * 1000 : 0);
|
||||
if (fileSize != nullptr) *fileSize = statOk ? (int64) info.st_size : 0;
|
||||
if (modTime != nullptr) *modTime = Time (statOk ? (int64) info.st_mtime * 1000 : 0);
|
||||
if (creationTime != nullptr) *creationTime = Time (statOk ? getCreationTime (info) * 1000 : 0);
|
||||
}
|
||||
|
||||
if (isReadOnly != nullptr)
|
||||
@@ -280,6 +286,12 @@ int64 File::getSize() const
|
||||
return juce_stat (fullPath, info) ? info.st_size : 0;
|
||||
}
|
||||
|
||||
uint64 File::getFileIdentifier() const
|
||||
{
|
||||
juce_statStruct info;
|
||||
return juce_stat (fullPath, info) ? (uint64) info.st_ino : 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool File::hasWriteAccess() const
|
||||
{
|
||||
@@ -391,13 +403,10 @@ void FileInputStream::openHandle()
|
||||
status = getResultForErrno();
|
||||
}
|
||||
|
||||
void FileInputStream::closeHandle()
|
||||
FileInputStream::~FileInputStream()
|
||||
{
|
||||
if (fileHandle != 0)
|
||||
{
|
||||
close (getFD (fileHandle));
|
||||
fileHandle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t FileInputStream::readInternal (void* const buffer, const size_t numBytes)
|
||||
@@ -661,6 +670,7 @@ int File::getVolumeSerialNumber() const
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if ! JUCE_IOS
|
||||
void juce_runSystemCommand (const String&);
|
||||
void juce_runSystemCommand (const String& command)
|
||||
{
|
||||
@@ -681,7 +691,7 @@ String juce_getOutputFromCommand (const String& command)
|
||||
tempFile.deleteFile();
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_IOS
|
||||
@@ -834,12 +844,6 @@ extern "C" void* threadEntryProc (void* userData)
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
#if JUCE_ANDROID
|
||||
struct AndroidThreadScope
|
||||
{
|
||||
AndroidThreadScope() { threadLocalJNIEnvHolder.attach(); }
|
||||
~AndroidThreadScope() { threadLocalJNIEnvHolder.detach(); }
|
||||
};
|
||||
|
||||
const AndroidThreadScope androidEnv;
|
||||
#endif
|
||||
|
||||
@@ -1017,12 +1021,12 @@ public:
|
||||
// we're the child process..
|
||||
close (pipeHandles[0]); // close the read handle
|
||||
|
||||
if ((streamFlags | wantStdOut) != 0)
|
||||
if ((streamFlags & wantStdOut) != 0)
|
||||
dup2 (pipeHandles[1], 1); // turns the pipe into stdout
|
||||
else
|
||||
close (STDOUT_FILENO);
|
||||
|
||||
if ((streamFlags | wantStdErr) != 0)
|
||||
if ((streamFlags & wantStdErr) != 0)
|
||||
dup2 (pipeHandles[1], 2);
|
||||
else
|
||||
close (STDERR_FILENO);
|
||||
@@ -1032,7 +1036,7 @@ public:
|
||||
Array<char*> argv;
|
||||
for (int i = 0; i < arguments.size(); ++i)
|
||||
if (arguments[i].isNotEmpty())
|
||||
argv.add (arguments[i].toUTF8().getAddress());
|
||||
argv.add (const_cast<char*> (arguments[i].toUTF8().getAddress()));
|
||||
|
||||
argv.add (nullptr);
|
||||
|
||||
@@ -1147,16 +1151,25 @@ struct HighResolutionTimer::Pimpl
|
||||
|
||||
void start (int newPeriod)
|
||||
{
|
||||
periodMs = newPeriod;
|
||||
|
||||
if (thread == 0)
|
||||
if (periodMs != newPeriod)
|
||||
{
|
||||
shouldStop = false;
|
||||
if (thread != pthread_self())
|
||||
{
|
||||
stop();
|
||||
|
||||
if (pthread_create (&thread, nullptr, timerThread, this) == 0)
|
||||
setThreadToRealtime (thread, (uint64) newPeriod);
|
||||
periodMs = newPeriod;
|
||||
shouldStop = false;
|
||||
|
||||
if (pthread_create (&thread, nullptr, timerThread, this) == 0)
|
||||
setThreadToRealtime (thread, (uint64) newPeriod);
|
||||
else
|
||||
jassertfalse;
|
||||
}
|
||||
else
|
||||
jassertfalse;
|
||||
{
|
||||
periodMs = newPeriod;
|
||||
shouldStop = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1180,7 +1193,9 @@ private:
|
||||
|
||||
static void* timerThread (void* param)
|
||||
{
|
||||
#if ! JUCE_ANDROID
|
||||
#if JUCE_ANDROID
|
||||
const AndroidThreadScope androidEnv;
|
||||
#else
|
||||
int dummy;
|
||||
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &dummy);
|
||||
#endif
|
||||
@@ -1191,12 +1206,19 @@ private:
|
||||
|
||||
void timerThread()
|
||||
{
|
||||
Clock clock (periodMs);
|
||||
int lastPeriod = periodMs;
|
||||
Clock clock (lastPeriod);
|
||||
|
||||
while (! shouldStop)
|
||||
{
|
||||
clock.wait();
|
||||
owner.hiResTimerCallback();
|
||||
|
||||
if (lastPeriod != periodMs)
|
||||
{
|
||||
lastPeriod = periodMs;
|
||||
clock = Clock (lastPeriod);
|
||||
}
|
||||
}
|
||||
|
||||
periodMs = 0;
|
||||
@@ -1210,7 +1232,7 @@ private:
|
||||
{
|
||||
mach_timebase_info_data_t timebase;
|
||||
(void) mach_timebase_info (&timebase);
|
||||
delta = (((uint64_t) (millis * 1000000.0)) * timebase.numer) / timebase.denom;
|
||||
delta = (((uint64_t) (millis * 1000000.0)) * timebase.denom) / timebase.numer;
|
||||
time = mach_absolute_time();
|
||||
}
|
||||
|
||||
|
||||
@@ -234,7 +234,7 @@ void FileInputStream::openHandle()
|
||||
status = WindowsFileHelpers::getResultForLastError();
|
||||
}
|
||||
|
||||
void FileInputStream::closeHandle()
|
||||
FileInputStream::~FileInputStream()
|
||||
{
|
||||
CloseHandle ((HANDLE) fileHandle);
|
||||
}
|
||||
@@ -474,6 +474,28 @@ int64 File::getVolumeTotalSize() const
|
||||
return WindowsFileHelpers::getDiskSpaceInfo (getFullPathName(), true);
|
||||
}
|
||||
|
||||
uint64 File::getFileIdentifier() const
|
||||
{
|
||||
uint64 result = 0;
|
||||
|
||||
HANDLE h = CreateFile (getFullPathName().toWideCharPointer(),
|
||||
GENERIC_READ, FILE_SHARE_READ, nullptr,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
|
||||
if (h != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
BY_HANDLE_FILE_INFORMATION info;
|
||||
zerostruct (info);
|
||||
|
||||
if (GetFileInformationByHandle (h, &info))
|
||||
result = (((uint64) info.nFileIndexHigh) << 32) | info.nFileIndexLow;
|
||||
|
||||
CloseHandle (h);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool File::isOnCDRomDrive() const
|
||||
{
|
||||
@@ -532,6 +554,14 @@ File JUCE_CALLTYPE File::getSpecialLocation (const SpecialLocationType type)
|
||||
return File (String (dest));
|
||||
}
|
||||
|
||||
case windowsSystemDirectory:
|
||||
{
|
||||
WCHAR dest [2048];
|
||||
dest[0] = 0;
|
||||
GetSystemDirectoryW (dest, (UINT) numElementsInArray (dest));
|
||||
return File (String (dest));
|
||||
}
|
||||
|
||||
case invokedExecutableFile:
|
||||
case currentExecutableFile:
|
||||
case currentApplicationFile:
|
||||
|
||||
@@ -45,13 +45,14 @@ public:
|
||||
address (address_), headers (headers_), postData (postData_), position (0),
|
||||
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
|
||||
{
|
||||
createConnection (progressCallback, progressCallbackContext);
|
||||
|
||||
if (! isError())
|
||||
for (int maxRedirects = 10; --maxRedirects >= 0;)
|
||||
{
|
||||
if (responseHeaders != nullptr)
|
||||
createConnection (progressCallback, progressCallbackContext);
|
||||
|
||||
if (! isError())
|
||||
{
|
||||
DWORD bufferSizeBytes = 4096;
|
||||
StringPairArray headers (false);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@@ -65,11 +66,10 @@ public:
|
||||
for (int i = 0; i < headersArray.size(); ++i)
|
||||
{
|
||||
const String& header = headersArray[i];
|
||||
const String key (header.upToFirstOccurrenceOf (": ", false, false));
|
||||
const String key (header.upToFirstOccurrenceOf (": ", false, false));
|
||||
const String value (header.fromFirstOccurrenceOf (": ", false, false));
|
||||
const String previousValue ((*responseHeaders) [key]);
|
||||
|
||||
responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
|
||||
const String previousValue (headers[key]);
|
||||
headers.set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -77,14 +77,34 @@ public:
|
||||
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
break;
|
||||
|
||||
bufferSizeBytes += 4096;
|
||||
}
|
||||
|
||||
DWORD status = 0;
|
||||
DWORD statusSize = sizeof (status);
|
||||
|
||||
if (HttpQueryInfo (request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &statusSize, 0))
|
||||
{
|
||||
statusCode = (int) status;
|
||||
|
||||
if (status == 301 || status == 302 || status == 303 || status == 307)
|
||||
{
|
||||
const String newLocation (headers["Location"]);
|
||||
|
||||
if (newLocation.isNotEmpty() && newLocation != address)
|
||||
{
|
||||
address = newLocation;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (responseHeaders != nullptr)
|
||||
responseHeaders->addArray (headers);
|
||||
}
|
||||
|
||||
DWORD status = 0;
|
||||
DWORD statusSize = sizeof (status);
|
||||
|
||||
if (HttpQueryInfo (request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &statusSize, 0))
|
||||
statusCode = (int) status;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,7 +279,8 @@ private:
|
||||
{
|
||||
const TCHAR* mimeTypes[] = { _T("*/*"), nullptr };
|
||||
|
||||
DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES;
|
||||
DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES
|
||||
| INTERNET_FLAG_NO_AUTO_REDIRECT | SECURITY_SET_MASK;
|
||||
|
||||
if (address.startsWithIgnoreCase ("https:"))
|
||||
flags |= INTERNET_FLAG_SECURE; // (this flag only seems necessary if the OS is running IE6 -
|
||||
@@ -270,6 +291,8 @@ private:
|
||||
|
||||
if (request != 0)
|
||||
{
|
||||
setSecurityFlags();
|
||||
|
||||
INTERNET_BUFFERS buffers = { 0 };
|
||||
buffers.dwStructSize = sizeof (INTERNET_BUFFERS);
|
||||
buffers.lpcszHeader = headers.toWideCharPointer();
|
||||
@@ -287,7 +310,7 @@ private:
|
||||
|
||||
if (bytesToDo > 0
|
||||
&& ! InternetWriteFile (request,
|
||||
static_cast <const char*> (postData.getData()) + bytesSent,
|
||||
static_cast<const char*> (postData.getData()) + bytesSent,
|
||||
(DWORD) bytesToDo, &bytesDone))
|
||||
{
|
||||
break;
|
||||
@@ -313,6 +336,14 @@ private:
|
||||
close();
|
||||
}
|
||||
|
||||
void setSecurityFlags()
|
||||
{
|
||||
DWORD dwFlags = 0, dwBuffLen = sizeof (DWORD);
|
||||
InternetQueryOption (request, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, &dwBuffLen);
|
||||
dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_SET_MASK;
|
||||
InternetSetOption (request, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags));
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
|
||||
};
|
||||
|
||||
@@ -342,7 +373,13 @@ struct GetAdaptersInfoHelper
|
||||
|
||||
namespace MACAddressHelpers
|
||||
{
|
||||
void getViaGetAdaptersInfo (Array<MACAddress>& result)
|
||||
static void addAddress (Array<MACAddress>& result, const MACAddress& ma)
|
||||
{
|
||||
if (! ma.isNull())
|
||||
result.addIfNotAlreadyThere (ma);
|
||||
}
|
||||
|
||||
static void getViaGetAdaptersInfo (Array<MACAddress>& result)
|
||||
{
|
||||
GetAdaptersInfoHelper gah;
|
||||
|
||||
@@ -350,11 +387,11 @@ namespace MACAddressHelpers
|
||||
{
|
||||
for (PIP_ADAPTER_INFO adapter = gah.adapterInfo; adapter != nullptr; adapter = adapter->Next)
|
||||
if (adapter->AddressLength >= 6)
|
||||
result.addIfNotAlreadyThere (MACAddress (adapter->Address));
|
||||
addAddress (result, MACAddress (adapter->Address));
|
||||
}
|
||||
}
|
||||
|
||||
void getViaNetBios (Array<MACAddress>& result)
|
||||
static void getViaNetBios (Array<MACAddress>& result)
|
||||
{
|
||||
DynamicLibrary dll ("netapi32.dll");
|
||||
JUCE_LOAD_WINAPI_FUNCTION (dll, Netbios, NetbiosCall, UCHAR, (PNCB))
|
||||
@@ -396,7 +433,7 @@ namespace MACAddressHelpers
|
||||
ncb.ncb_length = sizeof (ASTAT);
|
||||
|
||||
if (NetbiosCall (&ncb) == 0 && astat.adapt.adapter_type == 0xfe)
|
||||
result.addIfNotAlreadyThere (MACAddress (astat.adapt.adapter_address));
|
||||
addAddress (result, MACAddress (astat.adapt.adapter_address));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ void Logger::outputDebugString (const String& text)
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_USE_INTRINSICS
|
||||
#if JUCE_USE_MSVC_INTRINSICS
|
||||
|
||||
// CPU info functions using intrinsics...
|
||||
|
||||
@@ -137,10 +137,11 @@ static bool isWindowsVersionOrLater (SystemStats::OperatingSystemType target)
|
||||
|
||||
switch (target)
|
||||
{
|
||||
case SystemStats::WinVista: info.dwMinorVersion = 0; break;
|
||||
case SystemStats::Windows7: info.dwMinorVersion = 1; break;
|
||||
case SystemStats::Windows8: info.dwMinorVersion = 2; break;
|
||||
default: jassertfalse; break;
|
||||
case SystemStats::WinVista: break;
|
||||
case SystemStats::Windows7: info.dwMinorVersion = 1; break;
|
||||
case SystemStats::Windows8_0: info.dwMinorVersion = 2; break;
|
||||
case SystemStats::Windows8_1: info.dwMinorVersion = 3; break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -165,7 +166,7 @@ static bool isWindowsVersionOrLater (SystemStats::OperatingSystemType target)
|
||||
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||
{
|
||||
const SystemStats::OperatingSystemType types[]
|
||||
= { Windows8, Windows7, WinVista, WinXP, Win2000 };
|
||||
= { Windows8_1, Windows8_0, Windows7, WinVista, WinXP, Win2000 };
|
||||
|
||||
for (int i = 0; i < numElementsInArray (types); ++i)
|
||||
if (isWindowsVersionOrLater (types[i]))
|
||||
@@ -181,8 +182,9 @@ String SystemStats::getOperatingSystemName()
|
||||
|
||||
switch (getOperatingSystemType())
|
||||
{
|
||||
case Windows8_1: name = "Windows 8.1"; break;
|
||||
case Windows8_0: name = "Windows 8.0"; break;
|
||||
case Windows7: name = "Windows 7"; break;
|
||||
case Windows8: name = "Windows 8"; break;
|
||||
case WinVista: name = "Windows Vista"; break;
|
||||
case WinXP: name = "Windows XP"; break;
|
||||
case Win2000: name = "Windows 2000"; break;
|
||||
@@ -194,7 +196,7 @@ String SystemStats::getOperatingSystemName()
|
||||
|
||||
String SystemStats::getDeviceDescription()
|
||||
{
|
||||
return String::empty;
|
||||
return String();
|
||||
}
|
||||
|
||||
bool SystemStats::isOperatingSystem64Bit()
|
||||
@@ -251,9 +253,23 @@ public:
|
||||
HiResCounterHandler()
|
||||
: hiResTicksOffset (0)
|
||||
{
|
||||
const MMRESULT res = timeBeginPeriod (1);
|
||||
// This macro allows you to override the default timer-period
|
||||
// used on Windows. By default this is set to 1, because that has
|
||||
// always been the value used in JUCE apps, and changing it could
|
||||
// affect the behaviour of existing code, but you may wish to make
|
||||
// it larger (or set it to 0 to use the system default) to make your
|
||||
// app less demanding on the CPU.
|
||||
// For more info, see win32 documentation about the timeBeginPeriod
|
||||
// function.
|
||||
#ifndef JUCE_WIN32_TIMER_PERIOD
|
||||
#define JUCE_WIN32_TIMER_PERIOD 1
|
||||
#endif
|
||||
|
||||
#if JUCE_WIN32_TIMER_PERIOD > 0
|
||||
const MMRESULT res = timeBeginPeriod (JUCE_WIN32_TIMER_PERIOD);
|
||||
(void) res;
|
||||
jassert (res == TIMERR_NOERROR);
|
||||
#endif
|
||||
|
||||
LARGE_INTEGER f;
|
||||
QueryPerformanceFrequency (&f);
|
||||
@@ -297,7 +313,7 @@ double Time::getMillisecondCounterHiRes() noexcept { return hiResCounterHa
|
||||
//==============================================================================
|
||||
static int64 juce_getClockCycleCounter() noexcept
|
||||
{
|
||||
#if JUCE_USE_INTRINSICS
|
||||
#if JUCE_USE_MSVC_INTRINSICS
|
||||
// MS intrinsics version...
|
||||
return (int64) __rdtsc();
|
||||
|
||||
@@ -428,8 +444,16 @@ String SystemStats::getDisplayLanguage()
|
||||
DynamicLibrary dll ("kernel32.dll");
|
||||
JUCE_LOAD_WINAPI_FUNCTION (dll, GetUserDefaultUILanguage, getUserDefaultUILanguage, LANGID, (void))
|
||||
|
||||
if (getUserDefaultUILanguage != nullptr)
|
||||
return getLocaleValue (MAKELCID (getUserDefaultUILanguage(), SORT_DEFAULT), LOCALE_SISO639LANGNAME, "en");
|
||||
if (getUserDefaultUILanguage == nullptr)
|
||||
return "en";
|
||||
|
||||
return "en";
|
||||
const DWORD langID = MAKELCID (getUserDefaultUILanguage(), SORT_DEFAULT);
|
||||
|
||||
String mainLang (getLocaleValue (langID, LOCALE_SISO639LANGNAME, "en"));
|
||||
String region (getLocaleValue (langID, LOCALE_SISO3166CTRYNAME, nullptr));
|
||||
|
||||
if (region.isNotEmpty())
|
||||
mainLang << '-' << region;
|
||||
|
||||
return mainLang;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ void* getUser32Function (const char* functionName)
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if ! JUCE_USE_INTRINSICS
|
||||
#if ! JUCE_USE_MSVC_INTRINSICS
|
||||
// In newer compilers, the inline versions of these are used (in juce_Atomic.h), but in
|
||||
// older ones we have to actually call the ops as win32 functions..
|
||||
long juce_InterlockedExchange (volatile long* a, long b) noexcept { return InterlockedExchange (a, b); }
|
||||
|
||||
@@ -263,6 +263,12 @@ namespace SocketHelpers
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void makeReusable (int handle) noexcept
|
||||
{
|
||||
const int reuse = 1;
|
||||
setsockopt (handle, SOL_SOCKET, SO_REUSEADDR, (const char*) &reuse, sizeof (reuse));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
@@ -378,7 +384,7 @@ void StreamingSocket::close()
|
||||
{
|
||||
// need to do this to interrupt the accept() function..
|
||||
StreamingSocket temp;
|
||||
temp.connect ("localhost", portNumber, 1000);
|
||||
temp.connect (IPAddress::local().toString(), portNumber, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,8 +424,9 @@ bool StreamingSocket::createListener (const int newPortNumber, const String& loc
|
||||
if (handle < 0)
|
||||
return false;
|
||||
|
||||
const int reuse = 1;
|
||||
setsockopt (handle, SOL_SOCKET, SO_REUSEADDR, (const char*) &reuse, sizeof (reuse));
|
||||
#if ! JUCE_WINDOWS // on windows, adding this option produces behaviour different to posix
|
||||
SocketHelpers::makeReusable (handle);
|
||||
#endif
|
||||
|
||||
if (bind (handle, (struct sockaddr*) &servTmpAddr, sizeof (struct sockaddr_in)) < 0
|
||||
|| listen (handle, SOMAXCONN) < 0)
|
||||
@@ -470,6 +477,7 @@ DatagramSocket::DatagramSocket (const int localPortNumber, const bool canBroadca
|
||||
SocketHelpers::initSockets();
|
||||
|
||||
handle = (int) socket (AF_INET, SOCK_DGRAM, 0);
|
||||
SocketHelpers::makeReusable (handle);
|
||||
bindToPort (localPortNumber);
|
||||
}
|
||||
|
||||
|
||||
@@ -179,6 +179,11 @@ String URL::toString (const bool includeGetParameters) const
|
||||
return url;
|
||||
}
|
||||
|
||||
bool URL::isEmpty() const noexcept
|
||||
{
|
||||
return url.isEmpty();
|
||||
}
|
||||
|
||||
bool URL::isWellFormed() const
|
||||
{
|
||||
//xxx TODO
|
||||
@@ -241,8 +246,6 @@ void URL::createHeadersAndPostData (String& headers, MemoryBlock& headersAndPost
|
||||
{
|
||||
MemoryOutputStream data (headersAndPostData, false);
|
||||
|
||||
data << URLHelpers::getMangledParameters (*this);
|
||||
|
||||
if (filesToUpload.size() > 0)
|
||||
{
|
||||
// (this doesn't currently support mixing custom post-data with uploads..)
|
||||
@@ -285,7 +288,8 @@ void URL::createHeadersAndPostData (String& headers, MemoryBlock& headersAndPost
|
||||
}
|
||||
else
|
||||
{
|
||||
data << postData;
|
||||
data << URLHelpers::getMangledParameters (*this)
|
||||
<< postData;
|
||||
|
||||
// if the user-supplied headers didn't contain a content-type, add one now..
|
||||
if (! headers.containsIgnoreCase ("Content-Type"))
|
||||
|
||||
@@ -76,6 +76,9 @@ public:
|
||||
*/
|
||||
String toString (bool includeGetParameters) const;
|
||||
|
||||
/** Returns true if the URL is an empty string. */
|
||||
bool isEmpty() const noexcept;
|
||||
|
||||
/** True if it seems to be valid. */
|
||||
bool isWellFormed() const;
|
||||
|
||||
|
||||
@@ -209,10 +209,10 @@ String InputStream::readNextLine()
|
||||
return String::fromUTF8 (data, (int) i);
|
||||
}
|
||||
|
||||
int InputStream::readIntoMemoryBlock (MemoryBlock& block, ssize_t numBytes)
|
||||
size_t InputStream::readIntoMemoryBlock (MemoryBlock& block, ssize_t numBytes)
|
||||
{
|
||||
MemoryOutputStream mo (block, true);
|
||||
return mo.writeFromInputStream (*this, numBytes);
|
||||
return (size_t) mo.writeFromInputStream (*this, numBytes);
|
||||
}
|
||||
|
||||
String InputStream::readEntireStreamAsString()
|
||||
|
||||
@@ -211,7 +211,7 @@ public:
|
||||
/** Tries to read the whole stream and turn it into a string.
|
||||
|
||||
This will read from the stream's current position until the end-of-stream.
|
||||
It can read from either UTF-16 or UTF-8 formats.
|
||||
It can read from UTF-8 data, or UTF-16 if it detects suitable header-bytes.
|
||||
*/
|
||||
virtual String readEntireStreamAsString();
|
||||
|
||||
@@ -223,8 +223,8 @@ public:
|
||||
will be read until the stream is exhausted.
|
||||
@returns the number of bytes that were added to the memory block
|
||||
*/
|
||||
virtual int readIntoMemoryBlock (MemoryBlock& destBlock,
|
||||
ssize_t maxNumBytesToRead = -1);
|
||||
virtual size_t readIntoMemoryBlock (MemoryBlock& destBlock,
|
||||
ssize_t maxNumBytesToRead = -1);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the offset of the next byte that will be read from the stream.
|
||||
|
||||
@@ -60,7 +60,7 @@ MemoryInputStream::~MemoryInputStream()
|
||||
|
||||
int64 MemoryInputStream::getTotalLength()
|
||||
{
|
||||
return dataSize;
|
||||
return (int64) dataSize;
|
||||
}
|
||||
|
||||
int MemoryInputStream::read (void* const buffer, const int howMany)
|
||||
@@ -89,7 +89,7 @@ bool MemoryInputStream::setPosition (const int64 pos)
|
||||
|
||||
int64 MemoryInputStream::getPosition()
|
||||
{
|
||||
return position;
|
||||
return (int64) position;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -175,14 +175,14 @@ bool MemoryOutputStream::setPosition (int64 newPosition)
|
||||
return false;
|
||||
}
|
||||
|
||||
int MemoryOutputStream::writeFromInputStream (InputStream& source, int64 maxNumBytesToWrite)
|
||||
int64 MemoryOutputStream::writeFromInputStream (InputStream& source, int64 maxNumBytesToWrite)
|
||||
{
|
||||
// before writing from an input, see if we can preallocate to make it more efficient..
|
||||
int64 availableData = source.getTotalLength() - source.getPosition();
|
||||
|
||||
if (availableData > 0)
|
||||
{
|
||||
if (maxNumBytesToWrite > availableData)
|
||||
if (maxNumBytesToWrite > availableData || maxNumBytesToWrite < 0)
|
||||
maxNumBytesToWrite = availableData;
|
||||
|
||||
if (blockToUse != nullptr)
|
||||
|
||||
@@ -114,9 +114,9 @@ public:
|
||||
void flush();
|
||||
|
||||
bool write (const void*, size_t) override;
|
||||
int64 getPosition() override { return position; }
|
||||
int64 getPosition() override { return (int64) position; }
|
||||
bool setPosition (int64) override;
|
||||
int writeFromInputStream (InputStream&, int64 maxNumBytesToWrite) override;
|
||||
int64 writeFromInputStream (InputStream&, int64 maxNumBytesToWrite) override;
|
||||
bool writeRepeatedByte (uint8 byte, size_t numTimesToRepeat) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -252,12 +252,12 @@ bool OutputStream::writeText (const String& text, const bool asUTF16,
|
||||
return true;
|
||||
}
|
||||
|
||||
int OutputStream::writeFromInputStream (InputStream& source, int64 numBytesToWrite)
|
||||
int64 OutputStream::writeFromInputStream (InputStream& source, int64 numBytesToWrite)
|
||||
{
|
||||
if (numBytesToWrite < 0)
|
||||
numBytesToWrite = std::numeric_limits<int64>::max();
|
||||
|
||||
int numWritten = 0;
|
||||
int64 numWritten = 0;
|
||||
|
||||
while (numBytesToWrite > 0)
|
||||
{
|
||||
|
||||
@@ -221,7 +221,7 @@ public:
|
||||
is exhausted)
|
||||
@returns the number of bytes written
|
||||
*/
|
||||
virtual int writeFromInputStream (InputStream& source, int64 maxNumBytesToWrite);
|
||||
virtual int64 writeFromInputStream (InputStream& source, int64 maxNumBytesToWrite);
|
||||
|
||||
//==============================================================================
|
||||
/** Sets the string that will be written to the stream when the writeNewLine()
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
@see jassert()
|
||||
*/
|
||||
#define juce_breakDebugger { ::kill (0, SIGTRAP); }
|
||||
#elif JUCE_USE_INTRINSICS
|
||||
#elif JUCE_USE_MSVC_INTRINSICS
|
||||
#ifndef __INTEL_COMPILER
|
||||
#pragma intrinsic (__debugbreak)
|
||||
#endif
|
||||
@@ -94,20 +94,34 @@
|
||||
#define JUCE_ANALYZER_NORETURN
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_MSVC && ! DOXYGEN
|
||||
#define MACRO_WITH_FORCED_SEMICOLON(x) \
|
||||
__pragma(warning(push)) \
|
||||
__pragma(warning(disable:4127)) \
|
||||
do { x } while (false) \
|
||||
__pragma(warning(pop))
|
||||
#else
|
||||
/** This is the good old C++ trick for creating a macro that forces the user to put
|
||||
a semicolon after it when they use it.
|
||||
*/
|
||||
#define MACRO_WITH_FORCED_SEMICOLON(x) do { x } while (false)
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_DEBUG || DOXYGEN
|
||||
/** Writes a string to the standard error stream.
|
||||
This is only compiled in a debug build.
|
||||
@see Logger::outputDebugString
|
||||
*/
|
||||
#define DBG(dbgtext) { juce::String tempDbgBuf; tempDbgBuf << dbgtext; juce::Logger::outputDebugString (tempDbgBuf); }
|
||||
#define DBG(dbgtext) MACRO_WITH_FORCED_SEMICOLON (juce::String tempDbgBuf; tempDbgBuf << dbgtext; juce::Logger::outputDebugString (tempDbgBuf);)
|
||||
|
||||
//==============================================================================
|
||||
/** This will always cause an assertion failure.
|
||||
It is only compiled in a debug build, (unless JUCE_LOG_ASSERTIONS is enabled for your build).
|
||||
@see jassert
|
||||
*/
|
||||
#define jassertfalse { juce_LogCurrentAssertion; if (juce::juce_isRunningUnderDebugger()) juce_breakDebugger; JUCE_ANALYZER_NORETURN }
|
||||
#define jassertfalse MACRO_WITH_FORCED_SEMICOLON (juce_LogCurrentAssertion; if (juce::juce_isRunningUnderDebugger()) juce_breakDebugger; JUCE_ANALYZER_NORETURN)
|
||||
|
||||
//==============================================================================
|
||||
/** Platform-independent assertion macro.
|
||||
@@ -117,19 +131,19 @@
|
||||
correct behaviour of your program!
|
||||
@see jassertfalse
|
||||
*/
|
||||
#define jassert(expression) { if (! (expression)) jassertfalse; }
|
||||
#define jassert(expression) MACRO_WITH_FORCED_SEMICOLON (if (! (expression)) jassertfalse;)
|
||||
|
||||
#else
|
||||
//==============================================================================
|
||||
// If debugging is disabled, these dummy debug and assertion macros are used..
|
||||
|
||||
#define DBG(dbgtext)
|
||||
#define jassertfalse { juce_LogCurrentAssertion }
|
||||
#define jassertfalse MACRO_WITH_FORCED_SEMICOLON (juce_LogCurrentAssertion)
|
||||
|
||||
#if JUCE_LOG_ASSERTIONS
|
||||
#define jassert(expression) { if (! (expression)) jassertfalse; }
|
||||
#define jassert(expression) MACRO_WITH_FORCED_SEMICOLON (if (! (expression)) jassertfalse;)
|
||||
#else
|
||||
#define jassert(a) {}
|
||||
#define jassert(a) MACRO_WITH_FORCED_SEMICOLON ( ; )
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -139,7 +153,7 @@
|
||||
namespace juce
|
||||
{
|
||||
template <bool b> struct JuceStaticAssert;
|
||||
template <> struct JuceStaticAssert <true> { static void dummy() {} };
|
||||
template <> struct JuceStaticAssert<true> { static void dummy() {} };
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -211,6 +225,26 @@ namespace juce
|
||||
#define JUCE_STRINGIFY(item) JUCE_STRINGIFY_MACRO_HELPER (item)
|
||||
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_MSVC && ! defined (DOXYGEN)
|
||||
#define JUCE_WARNING_HELPER(file, line, mess) message(file "(" JUCE_STRINGIFY (line) ") : Warning: " #mess)
|
||||
#define JUCE_COMPILER_WARNING(message) __pragma(JUCE_WARNING_HELPER (__FILE__, __LINE__, message));
|
||||
#else
|
||||
#ifndef DOXYGEN
|
||||
#define JUCE_WARNING_HELPER(mess) message(#mess)
|
||||
#endif
|
||||
|
||||
/** This macro allows you to emit a custom compiler warning message.
|
||||
Very handy for marking bits of code as "to-do" items, or for shaming
|
||||
code written by your co-workers in a way that's hard to ignore.
|
||||
|
||||
GCC and Clang provide the \#warning directive, but MSVC doesn't, so this macro
|
||||
is a cross-compiler way to get the same functionality as \#warning.
|
||||
*/
|
||||
#define JUCE_COMPILER_WARNING(message) _Pragma(JUCE_STRINGIFY (JUCE_WARNING_HELPER (message)));
|
||||
#endif
|
||||
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_CATCH_UNHANDLED_EXCEPTIONS
|
||||
|
||||
@@ -302,84 +336,4 @@ namespace juce
|
||||
#define JUCE_PACKED
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
// Here, we'll check for C++11 compiler support, and if it's not available, define
|
||||
// a few workarounds, so that we can still use some of the newer language features.
|
||||
#if (__cplusplus >= 201103L || defined (__GXX_EXPERIMENTAL_CXX0X__)) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
|
||||
#define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1
|
||||
#define JUCE_COMPILER_SUPPORTS_NULLPTR 1
|
||||
#define JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS 1
|
||||
|
||||
#if (__GNUC__ * 100 + __GNUC_MINOR__) >= 407 && ! defined (JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL)
|
||||
#define JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL 1
|
||||
#endif
|
||||
|
||||
#if (__GNUC__ * 100 + __GNUC_MINOR__) >= 407 && ! defined (JUCE_DELETED_FUNCTION)
|
||||
#define JUCE_DELETED_FUNCTION = delete
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if JUCE_CLANG && defined (__has_feature)
|
||||
#if __has_feature (cxx_nullptr)
|
||||
#define JUCE_COMPILER_SUPPORTS_NULLPTR 1
|
||||
#endif
|
||||
|
||||
#if __has_feature (cxx_noexcept)
|
||||
#define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1
|
||||
#endif
|
||||
|
||||
#if __has_feature (cxx_rvalue_references)
|
||||
#define JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS 1
|
||||
#endif
|
||||
|
||||
#if __has_feature (cxx_deleted_functions)
|
||||
#define JUCE_DELETED_FUNCTION = delete
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL
|
||||
#define JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_COMPILER_SUPPORTS_ARC
|
||||
#define JUCE_COMPILER_SUPPORTS_ARC 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined (_MSC_VER) && _MSC_VER >= 1600
|
||||
#define JUCE_COMPILER_SUPPORTS_NULLPTR 1
|
||||
#define JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS 1
|
||||
#endif
|
||||
|
||||
#if defined (_MSC_VER) && _MSC_VER >= 1700
|
||||
#define JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_DELETED_FUNCTION
|
||||
#define JUCE_DELETED_FUNCTION
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
// Declare some fake versions of nullptr and noexcept, for older compilers:
|
||||
#if ! (DOXYGEN || JUCE_COMPILER_SUPPORTS_NOEXCEPT)
|
||||
#ifdef noexcept
|
||||
#undef noexcept
|
||||
#endif
|
||||
#define noexcept throw()
|
||||
#if defined (_MSC_VER) && _MSC_VER > 1600
|
||||
#define _ALLOW_KEYWORD_MACROS 1 // (to stop VC2012 complaining)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ! (DOXYGEN || JUCE_COMPILER_SUPPORTS_NULLPTR)
|
||||
#ifdef nullptr
|
||||
#undef nullptr
|
||||
#endif
|
||||
#define nullptr (0)
|
||||
#endif
|
||||
|
||||
#if ! (DOXYGEN || JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL)
|
||||
#undef override
|
||||
#define override
|
||||
#endif
|
||||
|
||||
#endif // JUCE_PLATFORMDEFS_H_INCLUDED
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
*/
|
||||
#define JUCE_MAJOR_VERSION 3
|
||||
#define JUCE_MINOR_VERSION 0
|
||||
#define JUCE_BUILDNUMBER 5
|
||||
#define JUCE_BUILDNUMBER 8
|
||||
|
||||
/** Current Juce version number.
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
|
||||
//==============================================================================
|
||||
#include "juce_PlatformDefs.h"
|
||||
#include "juce_CompilerSupport.h"
|
||||
|
||||
//==============================================================================
|
||||
// Now we'll include some common OS headers..
|
||||
@@ -72,8 +73,9 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#if JUCE_USE_INTRINSICS
|
||||
#if JUCE_USE_MSVC_INTRINSICS
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -64,7 +64,8 @@ public:
|
||||
WinXP = 0x4106,
|
||||
WinVista = 0x4107,
|
||||
Windows7 = 0x4108,
|
||||
Windows8 = 0x4109,
|
||||
Windows8_0 = 0x4109,
|
||||
Windows8_1 = 0x410a,
|
||||
|
||||
Windows = 0x4000, /**< To test whether any version of Windows is running,
|
||||
you can use the expression ((getOperatingSystemType() & Windows) != 0). */
|
||||
@@ -118,7 +119,9 @@ public:
|
||||
static String getUserRegion();
|
||||
|
||||
/** Returns the user's display language.
|
||||
The return value is a 2 or 3 letter language code (ISO 639-1 or ISO 639-2)
|
||||
The return value is a 2 or 3 letter language code (ISO 639-1 or ISO 639-2).
|
||||
Note that depending on the OS and region, this may also be followed by a dash
|
||||
and a sub-region code, e.g "en-GB"
|
||||
*/
|
||||
static String getDisplayLanguage();
|
||||
|
||||
|
||||
@@ -155,13 +155,13 @@
|
||||
#define JUCE_BIG_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#if defined (__LP64__) || defined (_LP64)
|
||||
#if defined (__LP64__) || defined (_LP64) || defined (__arm64__)
|
||||
#define JUCE_64BIT 1
|
||||
#else
|
||||
#define JUCE_32BIT 1
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
#if defined (__arm__) || defined (__arm64__)
|
||||
#define JUCE_ARM 1
|
||||
#elif __MMX__ || __SSE__ || __amd64__
|
||||
#define JUCE_INTEL 1
|
||||
@@ -192,7 +192,7 @@
|
||||
#endif
|
||||
|
||||
#if JUCE_64BIT || ! JUCE_VC7_OR_EARLIER
|
||||
#define JUCE_USE_INTRINSICS 1
|
||||
#define JUCE_USE_MSVC_INTRINSICS 1
|
||||
#endif
|
||||
#else
|
||||
#error unknown compiler
|
||||
|
||||
@@ -26,21 +26,10 @@
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
StringPool& Identifier::getPool()
|
||||
{
|
||||
static StringPool pool;
|
||||
return pool;
|
||||
}
|
||||
Identifier::Identifier() noexcept {}
|
||||
Identifier::~Identifier() noexcept {}
|
||||
|
||||
Identifier::Identifier() noexcept
|
||||
: name (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Identifier::Identifier (const Identifier& other) noexcept
|
||||
: name (other.name)
|
||||
{
|
||||
}
|
||||
Identifier::Identifier (const Identifier& other) noexcept : name (other.name) {}
|
||||
|
||||
Identifier& Identifier::operator= (const Identifier other) noexcept
|
||||
{
|
||||
@@ -49,20 +38,27 @@ Identifier& Identifier::operator= (const Identifier other) noexcept
|
||||
}
|
||||
|
||||
Identifier::Identifier (const String& nm)
|
||||
: name (Identifier::getPool().getPooledString (nm))
|
||||
{
|
||||
}
|
||||
|
||||
Identifier::Identifier (const char* const nm)
|
||||
: name (Identifier::getPool().getPooledString (nm))
|
||||
: name (StringPool::getGlobalPool().getPooledString (nm))
|
||||
{
|
||||
/* An Identifier string must be suitable for use as a script variable or XML
|
||||
attribute, so it can only contain this limited set of characters.. */
|
||||
jassert (isValidIdentifier (toString()));
|
||||
}
|
||||
|
||||
Identifier::~Identifier()
|
||||
Identifier::Identifier (const char* nm)
|
||||
: name (StringPool::getGlobalPool().getPooledString (nm))
|
||||
{
|
||||
/* An Identifier string must be suitable for use as a script variable or XML
|
||||
attribute, so it can only contain this limited set of characters.. */
|
||||
jassert (isValidIdentifier (toString()));
|
||||
}
|
||||
|
||||
Identifier::Identifier (String::CharPointerType start, String::CharPointerType end)
|
||||
: name (StringPool::getGlobalPool().getPooledString (start, end))
|
||||
{
|
||||
/* An Identifier string must be suitable for use as a script variable or XML
|
||||
attribute, so it can only contain this limited set of characters.. */
|
||||
jassert (isValidIdentifier (toString()));
|
||||
}
|
||||
|
||||
Identifier Identifier::null;
|
||||
|
||||
@@ -34,9 +34,9 @@
|
||||
/**
|
||||
Represents a string identifier, designed for accessing properties by name.
|
||||
|
||||
Identifier objects are very light and fast to copy, but slower to initialise
|
||||
from a string, so it's much faster to keep a static identifier object to refer
|
||||
to frequently-used names, rather than constructing them each time you need it.
|
||||
Comparing two Identifier objects is very fast (an O(1) operation), but creating
|
||||
them can be slower than just using a String directly, so the optimal way to use them
|
||||
is to keep some static Identifier objects for the things you use often.
|
||||
|
||||
@see NamedValueSet, ValueTree
|
||||
*/
|
||||
@@ -58,6 +58,12 @@ public:
|
||||
*/
|
||||
Identifier (const String& name);
|
||||
|
||||
/** Creates an identifier with a specified name.
|
||||
Because this name may need to be used in contexts such as script variables or XML
|
||||
tags, it must only contain ascii letters and digits, or the underscore character.
|
||||
*/
|
||||
Identifier (String::CharPointerType nameStart, String::CharPointerType nameEnd);
|
||||
|
||||
/** Creates a copy of another identifier. */
|
||||
Identifier (const Identifier& other) noexcept;
|
||||
|
||||
@@ -65,37 +71,37 @@ public:
|
||||
Identifier& operator= (const Identifier other) noexcept;
|
||||
|
||||
/** Destructor */
|
||||
~Identifier();
|
||||
~Identifier() noexcept;
|
||||
|
||||
/** Compares two identifiers. This is a very fast operation. */
|
||||
inline bool operator== (Identifier other) const noexcept { return name == other.name; }
|
||||
inline bool operator== (Identifier other) const noexcept { return name.getCharPointer() == other.name.getCharPointer(); }
|
||||
|
||||
/** Compares two identifiers. This is a very fast operation. */
|
||||
inline bool operator!= (Identifier other) const noexcept { return name != other.name; }
|
||||
inline bool operator!= (Identifier other) const noexcept { return name.getCharPointer() != other.name.getCharPointer(); }
|
||||
|
||||
/** Compares the identifier with a string. */
|
||||
inline bool operator== (StringRef other) const noexcept { return name.compare (other.text) == 0; }
|
||||
inline bool operator== (StringRef other) const noexcept { return name == other; }
|
||||
|
||||
/** Compares the identifier with a string. */
|
||||
inline bool operator!= (StringRef other) const noexcept { return name.compare (other.text) != 0; }
|
||||
inline bool operator!= (StringRef other) const noexcept { return name != other; }
|
||||
|
||||
/** Returns this identifier as a string. */
|
||||
String toString() const { return name; }
|
||||
const String& toString() const noexcept { return name; }
|
||||
|
||||
/** Returns this identifier's raw string pointer. */
|
||||
operator String::CharPointerType() const noexcept { return name; }
|
||||
operator String::CharPointerType() const noexcept { return name.getCharPointer(); }
|
||||
|
||||
/** Returns this identifier's raw string pointer. */
|
||||
String::CharPointerType getCharPointer() const noexcept { return name; }
|
||||
String::CharPointerType getCharPointer() const noexcept { return name.getCharPointer(); }
|
||||
|
||||
/** Returns this identifier as a StringRef. */
|
||||
operator StringRef() const noexcept { return name; }
|
||||
|
||||
/** Returns true if this Identifier is not null */
|
||||
bool isValid() const noexcept { return name.getAddress() != nullptr; }
|
||||
bool isValid() const noexcept { return name.isNotEmpty(); }
|
||||
|
||||
/** Returns true if this Identifier is null */
|
||||
bool isNull() const noexcept { return name.getAddress() == nullptr; }
|
||||
bool isNull() const noexcept { return name.isEmpty(); }
|
||||
|
||||
/** A null identifier. */
|
||||
static Identifier null;
|
||||
@@ -106,12 +112,8 @@ public:
|
||||
*/
|
||||
static bool isValidIdentifier (const String& possibleIdentifier) noexcept;
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
String::CharPointerType name;
|
||||
|
||||
static StringPool& getPool();
|
||||
String name;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -194,11 +194,11 @@ LocalisedStrings* LocalisedStrings::getCurrentMappings()
|
||||
String LocalisedStrings::translateWithCurrentMappings (const String& text) { return juce::translate (text); }
|
||||
String LocalisedStrings::translateWithCurrentMappings (const char* text) { return juce::translate (text); }
|
||||
|
||||
String translate (const String& text) { return juce::translate (text, text); }
|
||||
String translate (const char* text) { return juce::translate (String (text)); }
|
||||
String translate (CharPointer_UTF8 text) { return juce::translate (String (text)); }
|
||||
JUCE_API String translate (const String& text) { return juce::translate (text, text); }
|
||||
JUCE_API String translate (const char* text) { return juce::translate (String (text)); }
|
||||
JUCE_API String translate (CharPointer_UTF8 text) { return juce::translate (String (text)); }
|
||||
|
||||
String translate (const String& text, const String& resultIfNotFound)
|
||||
JUCE_API String translate (const String& text, const String& resultIfNotFound)
|
||||
{
|
||||
const SpinLock::ScopedLockType sl (currentMappingsLock);
|
||||
|
||||
|
||||
@@ -226,22 +226,22 @@ private:
|
||||
/** Uses the LocalisedStrings class to translate the given string literal.
|
||||
@see LocalisedStrings
|
||||
*/
|
||||
String translate (const String& stringLiteral);
|
||||
JUCE_API String translate (const String& stringLiteral);
|
||||
|
||||
/** Uses the LocalisedStrings class to translate the given string literal.
|
||||
@see LocalisedStrings
|
||||
*/
|
||||
String translate (const char* stringLiteral);
|
||||
JUCE_API String translate (const char* stringLiteral);
|
||||
|
||||
/** Uses the LocalisedStrings class to translate the given string literal.
|
||||
@see LocalisedStrings
|
||||
*/
|
||||
String translate (CharPointer_UTF8 stringLiteral);
|
||||
JUCE_API String translate (CharPointer_UTF8 stringLiteral);
|
||||
|
||||
/** Uses the LocalisedStrings class to translate the given string literal.
|
||||
@see LocalisedStrings
|
||||
*/
|
||||
String translate (const String& stringLiteral, const String& resultIfNotFound);
|
||||
JUCE_API String translate (const String& stringLiteral, const String& resultIfNotFound);
|
||||
|
||||
|
||||
#endif // JUCE_LOCALISEDSTRINGS_H_INCLUDED
|
||||
|
||||
@@ -180,6 +180,11 @@ public:
|
||||
release (bufferFromText (text));
|
||||
}
|
||||
|
||||
static inline int getReferenceCount (const CharPointerType text) noexcept
|
||||
{
|
||||
return bufferFromText (text)->refCount.get() + 1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static CharPointerType makeUniqueWithByteSize (const CharPointerType text, size_t numBytes)
|
||||
{
|
||||
@@ -216,8 +221,8 @@ private:
|
||||
static inline StringHolder* bufferFromText (const CharPointerType text) noexcept
|
||||
{
|
||||
// (Can't use offsetof() here because of warnings about this not being a POD)
|
||||
return reinterpret_cast <StringHolder*> (reinterpret_cast <char*> (text.getAddress())
|
||||
- (reinterpret_cast <size_t> (reinterpret_cast <StringHolder*> (1)->text) - 1));
|
||||
return reinterpret_cast<StringHolder*> (reinterpret_cast<char*> (text.getAddress())
|
||||
- (reinterpret_cast<size_t> (reinterpret_cast<StringHolder*> (1)->text) - 1));
|
||||
}
|
||||
|
||||
void compileTimeChecks()
|
||||
@@ -285,7 +290,7 @@ String& String::operator= (String&& other) noexcept
|
||||
}
|
||||
#endif
|
||||
|
||||
inline String::PreallocationBytes::PreallocationBytes (const size_t numBytes_) : numBytes (numBytes_) {}
|
||||
inline String::PreallocationBytes::PreallocationBytes (const size_t num) noexcept : numBytes (num) {}
|
||||
|
||||
String::String (const PreallocationBytes& preallocationSize)
|
||||
: text (StringHolder::createUninitialisedBytes (preallocationSize.numBytes + sizeof (CharPointerType::CharType)))
|
||||
@@ -297,6 +302,11 @@ void String::preallocateBytes (const size_t numBytesNeeded)
|
||||
text = StringHolder::makeUniqueWithByteSize (text, numBytesNeeded + sizeof (CharPointerType::CharType));
|
||||
}
|
||||
|
||||
int String::getReferenceCount() const noexcept
|
||||
{
|
||||
return StringHolder::getReferenceCount (text);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String::String (const char* const t)
|
||||
: text (StringHolder::createFromCharPointer (CharPointer_ASCII (t)))
|
||||
@@ -548,7 +558,7 @@ struct HashGenerator
|
||||
Type result = Type();
|
||||
|
||||
while (! t.isEmpty())
|
||||
result = multiplier * result + t.getAndAdvance();
|
||||
result = ((Type) multiplier) * result + (Type) t.getAndAdvance();
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -608,19 +618,103 @@ int String::compare (const char* const other) const noexcept { return text
|
||||
int String::compare (const wchar_t* const other) const noexcept { return text.compare (castToCharPointer_wchar_t (other)); }
|
||||
int String::compareIgnoreCase (const String& other) const noexcept { return (text == other.text) ? 0 : text.compareIgnoreCase (other.text); }
|
||||
|
||||
int String::compareLexicographically (const String& other) const noexcept
|
||||
static int stringCompareRight (String::CharPointerType s1, String::CharPointerType s2) noexcept
|
||||
{
|
||||
CharPointerType s1 (text);
|
||||
for (int bias = 0;;)
|
||||
{
|
||||
const juce_wchar c1 = s1.getAndAdvance();
|
||||
const bool isDigit1 = CharacterFunctions::isDigit (c1);
|
||||
|
||||
while (! (s1.isEmpty() || s1.isLetterOrDigit()))
|
||||
++s1;
|
||||
const juce_wchar c2 = s2.getAndAdvance();
|
||||
const bool isDigit2 = CharacterFunctions::isDigit (c2);
|
||||
|
||||
CharPointerType s2 (other.text);
|
||||
if (! (isDigit1 || isDigit2)) return bias;
|
||||
if (! isDigit1) return -1;
|
||||
if (! isDigit2) return 1;
|
||||
|
||||
while (! (s2.isEmpty() || s2.isLetterOrDigit()))
|
||||
++s2;
|
||||
if (c1 != c2 && bias == 0)
|
||||
bias = c1 < c2 ? -1 : 1;
|
||||
|
||||
return s1.compareIgnoreCase (s2);
|
||||
jassert (c1 != 0 && c2 != 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int stringCompareLeft (String::CharPointerType s1, String::CharPointerType s2) noexcept
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
const juce_wchar c1 = s1.getAndAdvance();
|
||||
const bool isDigit1 = CharacterFunctions::isDigit (c1);
|
||||
|
||||
const juce_wchar c2 = s2.getAndAdvance();
|
||||
const bool isDigit2 = CharacterFunctions::isDigit (c2);
|
||||
|
||||
if (! (isDigit1 || isDigit2)) return 0;
|
||||
if (! isDigit1) return -1;
|
||||
if (! isDigit2) return 1;
|
||||
if (c1 < c2) return -1;
|
||||
if (c1 > c2) return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int naturalStringCompare (String::CharPointerType s1, String::CharPointerType s2) noexcept
|
||||
{
|
||||
bool firstLoop = true;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const bool hasSpace1 = s1.isWhitespace();
|
||||
const bool hasSpace2 = s2.isWhitespace();
|
||||
|
||||
if ((! firstLoop) && (hasSpace1 ^ hasSpace2))
|
||||
return hasSpace2 ? 1 : -1;
|
||||
|
||||
firstLoop = false;
|
||||
|
||||
if (hasSpace1) s1 = s1.findEndOfWhitespace();
|
||||
if (hasSpace2) s2 = s2.findEndOfWhitespace();
|
||||
|
||||
if (s1.isDigit() && s2.isDigit())
|
||||
{
|
||||
const int result = (*s1 == '0' || *s2 == '0') ? stringCompareLeft (s1, s2)
|
||||
: stringCompareRight (s1, s2);
|
||||
|
||||
if (result != 0)
|
||||
return result;
|
||||
}
|
||||
|
||||
juce_wchar c1 = s1.getAndAdvance();
|
||||
juce_wchar c2 = s2.getAndAdvance();
|
||||
|
||||
if (c1 != c2)
|
||||
{
|
||||
c1 = CharacterFunctions::toUpperCase (c1);
|
||||
c2 = CharacterFunctions::toUpperCase (c2);
|
||||
}
|
||||
|
||||
if (c1 == c2)
|
||||
{
|
||||
if (c1 == 0)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool isAlphaNum1 = CharacterFunctions::isLetterOrDigit (c1);
|
||||
const bool isAlphaNum2 = CharacterFunctions::isLetterOrDigit (c2);
|
||||
|
||||
if (isAlphaNum2 && ! isAlphaNum1) return -1;
|
||||
if (isAlphaNum1 && ! isAlphaNum2) return 1;
|
||||
|
||||
return c1 < c2 ? -1 : 1;
|
||||
}
|
||||
|
||||
jassert (c1 != 0 && c2 != 0);
|
||||
}
|
||||
}
|
||||
|
||||
int String::compareNatural (StringRef other) const noexcept
|
||||
{
|
||||
return naturalStringCompare (getCharPointer(), other.text);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
@@ -1750,13 +1844,13 @@ String String::formatted (const String pf, ... )
|
||||
va_start (args, pf);
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
HeapBlock <wchar_t> temp (bufferSize);
|
||||
HeapBlock<wchar_t> temp (bufferSize);
|
||||
const int num = (int) _vsnwprintf (temp.getData(), bufferSize - 1, pf.toWideCharPointer(), args);
|
||||
#elif JUCE_ANDROID
|
||||
HeapBlock <char> temp (bufferSize);
|
||||
HeapBlock<char> temp (bufferSize);
|
||||
const int num = (int) vsnprintf (temp.getData(), bufferSize - 1, pf.toUTF8(), args);
|
||||
#else
|
||||
HeapBlock <wchar_t> temp (bufferSize);
|
||||
HeapBlock<wchar_t> temp (bufferSize);
|
||||
const int num = (int) vswprintf (temp.getData(), bufferSize - 1, pf.toWideCharPointer(), args);
|
||||
#endif
|
||||
|
||||
@@ -1911,12 +2005,12 @@ struct StringEncodingConverter
|
||||
{
|
||||
static CharPointerType_Dest convert (const String& s)
|
||||
{
|
||||
String& source = const_cast <String&> (s);
|
||||
String& source = const_cast<String&> (s);
|
||||
|
||||
typedef typename CharPointerType_Dest::CharType DestChar;
|
||||
|
||||
if (source.isEmpty())
|
||||
return CharPointerType_Dest (reinterpret_cast <const DestChar*> (&emptyChar));
|
||||
return CharPointerType_Dest (reinterpret_cast<const DestChar*> (&emptyChar));
|
||||
|
||||
CharPointerType_Src text (source.getCharPointer());
|
||||
const size_t extraBytesNeeded = CharPointerType_Dest::getBytesRequiredFor (text) + sizeof (typename CharPointerType_Dest::CharType);
|
||||
@@ -1926,7 +2020,7 @@ struct StringEncodingConverter
|
||||
text = source.getCharPointer();
|
||||
|
||||
void* const newSpace = addBytesToPointer (text.getAddress(), (int) endOffset);
|
||||
const CharPointerType_Dest extraSpace (static_cast <DestChar*> (newSpace));
|
||||
const CharPointerType_Dest extraSpace (static_cast<DestChar*> (newSpace));
|
||||
|
||||
#if JUCE_DEBUG // (This just avoids spurious warnings from valgrind about the uninitialised bytes at the end of the buffer..)
|
||||
const size_t bytesToClear = (size_t) jmin ((int) extraBytesNeeded, 4);
|
||||
@@ -2179,6 +2273,12 @@ public:
|
||||
expect (s.compare (String ("012345678")) == 0);
|
||||
expect (s.compare (String ("012345679")) < 0);
|
||||
expect (s.compare (String ("012345676")) > 0);
|
||||
expect (String("a").compareNatural ("A") == 0);
|
||||
expect (String("A").compareNatural ("B") < 0);
|
||||
expect (String("a").compareNatural ("B") < 0);
|
||||
expect (String("10").compareNatural ("2") > 0);
|
||||
expect (String("Abc 10").compareNatural ("aBC 2") > 0);
|
||||
expect (String("Abc 1").compareNatural ("aBC 2") < 0);
|
||||
expect (s.substring (2, 3) == String::charToString (s[2]));
|
||||
expect (s.substring (0, 1) == String::charToString (s[0]));
|
||||
expect (s.getLastCharacter() == s [s.length() - 1]);
|
||||
|
||||
@@ -167,7 +167,7 @@ public:
|
||||
typedef CharPointer_UTF32 CharPointerType;
|
||||
#elif (JUCE_STRING_UTF_TYPE == 16)
|
||||
typedef CharPointer_UTF16 CharPointerType;
|
||||
#elif (JUCE_STRING_UTF_TYPE == 8)
|
||||
#elif (DOXYGEN || JUCE_STRING_UTF_TYPE == 8)
|
||||
typedef CharPointer_UTF8 CharPointerType;
|
||||
#else
|
||||
#error "You must set the value of JUCE_STRING_UTF_TYPE to be either 8, 16, or 32!"
|
||||
@@ -346,15 +346,15 @@ public:
|
||||
*/
|
||||
int compareIgnoreCase (const String& other) const noexcept;
|
||||
|
||||
/** Lexicographic comparison with another string.
|
||||
/** Compares two strings, taking into account textual characteristics like numbers and spaces.
|
||||
|
||||
The comparison used here is case-insensitive and ignores leading non-alphanumeric
|
||||
characters, making it good for sorting human-readable strings.
|
||||
This comparison is case-insensitive and can detect words and embedded numbers in the
|
||||
strings, making it good for sorting human-readable lists of things like filenames.
|
||||
|
||||
@returns 0 if the two strings are identical; negative if this string comes before
|
||||
the other one alphabetically, or positive if it comes after it.
|
||||
*/
|
||||
int compareLexicographically (const String& other) const noexcept;
|
||||
int compareNatural (StringRef other) const noexcept;
|
||||
|
||||
/** Tests whether the string begins with another string.
|
||||
If the parameter is an empty string, this will always return true.
|
||||
@@ -1204,20 +1204,25 @@ public:
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_MAC || JUCE_IOS || DOXYGEN
|
||||
/** MAC ONLY - Creates a String from an OSX CFString. */
|
||||
/** OSX ONLY - Creates a String from an OSX CFString. */
|
||||
static String fromCFString (CFStringRef cfString);
|
||||
|
||||
/** MAC ONLY - Converts this string to a CFString.
|
||||
/** OSX ONLY - Converts this string to a CFString.
|
||||
Remember that you must use CFRelease() to free the returned string when you're
|
||||
finished with it.
|
||||
*/
|
||||
CFStringRef toCFString() const;
|
||||
|
||||
/** MAC ONLY - Returns a copy of this string in which any decomposed unicode characters have
|
||||
/** OSX ONLY - Returns a copy of this string in which any decomposed unicode characters have
|
||||
been converted to their precomposed equivalents. */
|
||||
String convertToPrecomposedUnicode() const;
|
||||
#endif
|
||||
|
||||
/** Returns the number of String objects which are currently sharing the same internal
|
||||
data as this one.
|
||||
*/
|
||||
int getReferenceCount() const noexcept;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
CharPointerType text;
|
||||
@@ -1225,7 +1230,7 @@ private:
|
||||
//==============================================================================
|
||||
struct PreallocationBytes
|
||||
{
|
||||
explicit PreallocationBytes (size_t);
|
||||
explicit PreallocationBytes (size_t) noexcept;
|
||||
size_t numBytes;
|
||||
};
|
||||
|
||||
|
||||
@@ -199,6 +199,11 @@ int StringArray::indexOf (StringRef stringToLookFor, const bool ignoreCase, int
|
||||
return -1;
|
||||
}
|
||||
|
||||
void StringArray::move (const int currentIndex, const int newIndex) noexcept
|
||||
{
|
||||
strings.move (currentIndex, newIndex);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void StringArray::remove (const int index)
|
||||
{
|
||||
@@ -255,12 +260,17 @@ void StringArray::trim()
|
||||
//==============================================================================
|
||||
struct InternalStringArrayComparator_CaseSensitive
|
||||
{
|
||||
static int compareElements (String& first, String& second) { return first.compare (second); }
|
||||
static int compareElements (String& s1, String& s2) noexcept { return s1.compare (s2); }
|
||||
};
|
||||
|
||||
struct InternalStringArrayComparator_CaseInsensitive
|
||||
{
|
||||
static int compareElements (String& first, String& second) { return first.compareIgnoreCase (second); }
|
||||
static int compareElements (String& s1, String& s2) noexcept { return s1.compareIgnoreCase (s2); }
|
||||
};
|
||||
|
||||
struct InternalStringArrayComparator_Natural
|
||||
{
|
||||
static int compareElements (String& s1, String& s2) noexcept { return s1.compareNatural (s2); }
|
||||
};
|
||||
|
||||
void StringArray::sort (const bool ignoreCase)
|
||||
@@ -277,12 +287,12 @@ void StringArray::sort (const bool ignoreCase)
|
||||
}
|
||||
}
|
||||
|
||||
void StringArray::move (const int currentIndex, int newIndex) noexcept
|
||||
void StringArray::sortNatural()
|
||||
{
|
||||
strings.move (currentIndex, newIndex);
|
||||
InternalStringArrayComparator_Natural comp;
|
||||
strings.sort (comp);
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
String StringArray::joinIntoString (StringRef separator, int start, int numberToJoin) const
|
||||
{
|
||||
|
||||
@@ -134,18 +134,12 @@ public:
|
||||
/** Returns a pointer to the first String in the array.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline String* begin() const noexcept
|
||||
{
|
||||
return strings.begin();
|
||||
}
|
||||
inline String* begin() const noexcept { return strings.begin(); }
|
||||
|
||||
/** Returns a pointer to the String which follows the last element in the array.
|
||||
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||
*/
|
||||
inline String* end() const noexcept
|
||||
{
|
||||
return strings.end();
|
||||
}
|
||||
inline String* end() const noexcept { return strings.end(); }
|
||||
|
||||
/** Searches for a string in the array.
|
||||
|
||||
@@ -387,11 +381,16 @@ public:
|
||||
|
||||
//==============================================================================
|
||||
/** Sorts the array into alphabetical order.
|
||||
|
||||
@param ignoreCase if true, the comparisons used will be case-sensitive.
|
||||
*/
|
||||
void sort (bool ignoreCase);
|
||||
|
||||
/** Sorts the array using extra language-aware rules to do a better job of comparing
|
||||
words containing spaces and numbers.
|
||||
@see String::compareNatural()
|
||||
*/
|
||||
void sortNatural();
|
||||
|
||||
//==============================================================================
|
||||
/** Increases the array's internal storage to hold a minimum number of elements.
|
||||
|
||||
|
||||
@@ -26,88 +26,141 @@
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
StringPool::StringPool() noexcept {}
|
||||
StringPool::~StringPool() {}
|
||||
static const int minNumberOfStringsForGarbageCollection = 300;
|
||||
static const uint32 garbageCollectionInterval = 30000;
|
||||
|
||||
namespace StringPoolHelpers
|
||||
|
||||
StringPool::StringPool() noexcept : lastGarbageCollectionTime (0) {}
|
||||
StringPool::~StringPool() {}
|
||||
|
||||
struct StartEndString
|
||||
{
|
||||
template <class StringType>
|
||||
String::CharPointerType getPooledStringFromArray (Array<String>& strings,
|
||||
StringType newString,
|
||||
const CriticalSection& lock)
|
||||
StartEndString (String::CharPointerType s, String::CharPointerType e) noexcept : start (s), end (e) {}
|
||||
operator String() const { return String (start, end); }
|
||||
|
||||
String::CharPointerType start, end;
|
||||
};
|
||||
|
||||
static int compareStrings (const String& s1, const String& s2) noexcept { return s1.compare (s2); }
|
||||
static int compareStrings (CharPointer_UTF8 s1, const String& s2) noexcept { return s1.compare (s2.getCharPointer()); }
|
||||
|
||||
static int compareStrings (const StartEndString& string1, const String& string2) noexcept
|
||||
{
|
||||
String::CharPointerType s1 (string1.start), s2 (string2.getCharPointer());
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
int start = 0;
|
||||
int end = strings.size();
|
||||
const int c1 = s1 < string1.end ? (int) s1.getAndAdvance() : 0;
|
||||
const int c2 = (int) s2.getAndAdvance();
|
||||
const int diff = c1 - c2;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (start >= end)
|
||||
{
|
||||
jassert (start <= end);
|
||||
strings.insert (start, newString);
|
||||
return strings.getReference (start).getCharPointer();
|
||||
}
|
||||
|
||||
const String& startString = strings.getReference (start);
|
||||
|
||||
if (startString == newString)
|
||||
return startString.getCharPointer();
|
||||
|
||||
const int halfway = (start + end) >> 1;
|
||||
|
||||
if (halfway == start)
|
||||
{
|
||||
if (startString.compare (newString) < 0)
|
||||
++start;
|
||||
|
||||
strings.insert (start, newString);
|
||||
return strings.getReference (start).getCharPointer();
|
||||
}
|
||||
|
||||
const int comp = strings.getReference (halfway).compare (newString);
|
||||
|
||||
if (comp == 0)
|
||||
return strings.getReference (halfway).getCharPointer();
|
||||
|
||||
if (comp < 0)
|
||||
start = halfway;
|
||||
else
|
||||
end = halfway;
|
||||
}
|
||||
if (diff != 0) return diff < 0 ? -1 : 1;
|
||||
if (c1 == 0) break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
String::CharPointerType StringPool::getPooledString (const String& s)
|
||||
template <typename NewStringType>
|
||||
static String addPooledString (Array<String>& strings, const NewStringType& newString)
|
||||
{
|
||||
if (s.isEmpty())
|
||||
return String().getCharPointer();
|
||||
int start = 0;
|
||||
int end = strings.size();
|
||||
|
||||
return StringPoolHelpers::getPooledStringFromArray (strings, s, lock);
|
||||
while (start < end)
|
||||
{
|
||||
const String& startString = strings.getReference (start);
|
||||
const int startComp = compareStrings (newString, startString);
|
||||
|
||||
if (startComp == 0)
|
||||
return startString;
|
||||
|
||||
const int halfway = (start + end) / 2;
|
||||
|
||||
if (halfway == start)
|
||||
{
|
||||
if (startComp > 0)
|
||||
++start;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
const String& halfwayString = strings.getReference (halfway);
|
||||
const int halfwayComp = compareStrings (newString, halfwayString);
|
||||
|
||||
if (halfwayComp == 0)
|
||||
return halfwayString;
|
||||
|
||||
if (halfwayComp > 0)
|
||||
start = halfway;
|
||||
else
|
||||
end = halfway;
|
||||
}
|
||||
|
||||
strings.insert (start, newString);
|
||||
return strings.getReference (start);
|
||||
}
|
||||
|
||||
String::CharPointerType StringPool::getPooledString (const char* const s)
|
||||
String StringPool::getPooledString (const char* const newString)
|
||||
{
|
||||
if (s == nullptr || *s == 0)
|
||||
return String().getCharPointer();
|
||||
if (newString == nullptr || *newString == 0)
|
||||
return String();
|
||||
|
||||
return StringPoolHelpers::getPooledStringFromArray (strings, s, lock);
|
||||
const ScopedLock sl (lock);
|
||||
garbageCollectIfNeeded();
|
||||
return addPooledString (strings, CharPointer_UTF8 (newString));
|
||||
}
|
||||
|
||||
String::CharPointerType StringPool::getPooledString (const wchar_t* const s)
|
||||
String StringPool::getPooledString (String::CharPointerType start, String::CharPointerType end)
|
||||
{
|
||||
if (s == nullptr || *s == 0)
|
||||
return String().getCharPointer();
|
||||
if (start.isEmpty() || start == end)
|
||||
return String();
|
||||
|
||||
return StringPoolHelpers::getPooledStringFromArray (strings, s, lock);
|
||||
const ScopedLock sl (lock);
|
||||
garbageCollectIfNeeded();
|
||||
return addPooledString (strings, StartEndString (start, end));
|
||||
}
|
||||
|
||||
int StringPool::size() const noexcept
|
||||
String StringPool::getPooledString (StringRef newString)
|
||||
{
|
||||
return strings.size();
|
||||
if (newString.isEmpty())
|
||||
return String();
|
||||
|
||||
const ScopedLock sl (lock);
|
||||
garbageCollectIfNeeded();
|
||||
return addPooledString (strings, newString.text);
|
||||
}
|
||||
|
||||
String::CharPointerType StringPool::operator[] (const int index) const noexcept
|
||||
String StringPool::getPooledString (const String& newString)
|
||||
{
|
||||
return strings [index].getCharPointer();
|
||||
if (newString.isEmpty())
|
||||
return String();
|
||||
|
||||
const ScopedLock sl (lock);
|
||||
garbageCollectIfNeeded();
|
||||
return addPooledString (strings, newString);
|
||||
}
|
||||
|
||||
void StringPool::garbageCollectIfNeeded()
|
||||
{
|
||||
if (strings.size() > minNumberOfStringsForGarbageCollection
|
||||
&& Time::getApproximateMillisecondCounter() > lastGarbageCollectionTime + garbageCollectionInterval)
|
||||
garbageCollect();
|
||||
}
|
||||
|
||||
void StringPool::garbageCollect()
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
for (int i = strings.size(); --i >= 0;)
|
||||
if (strings.getReference(i).getReferenceCount() == 1)
|
||||
strings.remove (i);
|
||||
|
||||
lastGarbageCollectionTime = Time::getApproximateMillisecondCounter();
|
||||
}
|
||||
|
||||
StringPool& StringPool::getGlobalPool() noexcept
|
||||
{
|
||||
static StringPool pool;
|
||||
return pool;
|
||||
}
|
||||
|
||||
@@ -52,40 +52,42 @@ public:
|
||||
~StringPool();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a pointer to a copy of the string that is passed in.
|
||||
|
||||
The pool will always return the same pointer when asked for a string that matches it.
|
||||
The pool will own all the pointers that it returns, deleting them when the pool itself
|
||||
is deleted.
|
||||
/** Returns a pointer to a shared copy of the string that is passed in.
|
||||
The pool will always return the same String object when asked for a string that matches it.
|
||||
*/
|
||||
String::CharPointerType getPooledString (const String& original);
|
||||
String getPooledString (const String& original);
|
||||
|
||||
/** Returns a pointer to a copy of the string that is passed in.
|
||||
|
||||
The pool will always return the same pointer when asked for a string that matches it.
|
||||
The pool will own all the pointers that it returns, deleting them when the pool itself
|
||||
is deleted.
|
||||
The pool will always return the same String object when asked for a string that matches it.
|
||||
*/
|
||||
String::CharPointerType getPooledString (const char* original);
|
||||
String getPooledString (const char* original);
|
||||
|
||||
/** Returns a pointer to a shared copy of the string that is passed in.
|
||||
The pool will always return the same String object when asked for a string that matches it.
|
||||
*/
|
||||
String getPooledString (StringRef original);
|
||||
|
||||
/** Returns a pointer to a copy of the string that is passed in.
|
||||
|
||||
The pool will always return the same pointer when asked for a string that matches it.
|
||||
The pool will own all the pointers that it returns, deleting them when the pool itself
|
||||
is deleted.
|
||||
The pool will always return the same String object when asked for a string that matches it.
|
||||
*/
|
||||
String::CharPointerType getPooledString (const wchar_t* original);
|
||||
String getPooledString (String::CharPointerType start, String::CharPointerType end);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the number of strings in the pool. */
|
||||
int size() const noexcept;
|
||||
/** Scans the pool, and removes any strings that are unreferenced.
|
||||
You don't generally need to call this - it'll be called automatically when the pool grows
|
||||
large enough to warrant it.
|
||||
*/
|
||||
void garbageCollect();
|
||||
|
||||
/** Returns one of the strings in the pool, by index. */
|
||||
String::CharPointerType operator[] (int index) const noexcept;
|
||||
/** Returns a shared global pool which is used for things like Identifiers, XML parsing. */
|
||||
static StringPool& getGlobalPool() noexcept;
|
||||
|
||||
private:
|
||||
Array <String> strings;
|
||||
Array<String> strings;
|
||||
CriticalSection lock;
|
||||
uint32 lastGarbageCollectionTime;
|
||||
|
||||
void garbageCollectIfNeeded();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -407,11 +407,11 @@ String Time::getWeekdayName (const bool threeLetterVersion) const
|
||||
return getWeekdayName (getDayOfWeek(), threeLetterVersion);
|
||||
}
|
||||
|
||||
static const char* const shortMonthNames[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
||||
static const char* const longMonthNames[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
|
||||
|
||||
String Time::getMonthName (int monthNumber, const bool threeLetterVersion)
|
||||
{
|
||||
static const char* const shortMonthNames[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
||||
static const char* const longMonthNames[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
|
||||
|
||||
monthNumber %= 12;
|
||||
|
||||
return TRANS (threeLetterVersion ? shortMonthNames [monthNumber]
|
||||
@@ -430,17 +430,40 @@ String Time::getWeekdayName (int day, const bool threeLetterVersion)
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Time& Time::operator+= (RelativeTime delta) { millisSinceEpoch += delta.inMilliseconds(); return *this; }
|
||||
Time& Time::operator-= (RelativeTime delta) { millisSinceEpoch -= delta.inMilliseconds(); return *this; }
|
||||
Time& Time::operator+= (RelativeTime delta) noexcept { millisSinceEpoch += delta.inMilliseconds(); return *this; }
|
||||
Time& Time::operator-= (RelativeTime delta) noexcept { millisSinceEpoch -= delta.inMilliseconds(); return *this; }
|
||||
|
||||
Time operator+ (Time time, RelativeTime delta) { Time t (time); return t += delta; }
|
||||
Time operator- (Time time, RelativeTime delta) { Time t (time); return t -= delta; }
|
||||
Time operator+ (RelativeTime delta, Time time) { Time t (time); return t += delta; }
|
||||
const RelativeTime operator- (Time time1, Time time2) { return RelativeTime::milliseconds (time1.toMilliseconds() - time2.toMilliseconds()); }
|
||||
Time operator+ (Time time, RelativeTime delta) noexcept { Time t (time); return t += delta; }
|
||||
Time operator- (Time time, RelativeTime delta) noexcept { Time t (time); return t -= delta; }
|
||||
Time operator+ (RelativeTime delta, Time time) noexcept { Time t (time); return t += delta; }
|
||||
const RelativeTime operator- (Time time1, Time time2) noexcept { return RelativeTime::milliseconds (time1.toMilliseconds() - time2.toMilliseconds()); }
|
||||
|
||||
bool operator== (Time time1, Time time2) { return time1.toMilliseconds() == time2.toMilliseconds(); }
|
||||
bool operator!= (Time time1, Time time2) { return time1.toMilliseconds() != time2.toMilliseconds(); }
|
||||
bool operator< (Time time1, Time time2) { return time1.toMilliseconds() < time2.toMilliseconds(); }
|
||||
bool operator> (Time time1, Time time2) { return time1.toMilliseconds() > time2.toMilliseconds(); }
|
||||
bool operator<= (Time time1, Time time2) { return time1.toMilliseconds() <= time2.toMilliseconds(); }
|
||||
bool operator>= (Time time1, Time time2) { return time1.toMilliseconds() >= time2.toMilliseconds(); }
|
||||
bool operator== (Time time1, Time time2) noexcept { return time1.toMilliseconds() == time2.toMilliseconds(); }
|
||||
bool operator!= (Time time1, Time time2) noexcept { return time1.toMilliseconds() != time2.toMilliseconds(); }
|
||||
bool operator< (Time time1, Time time2) noexcept { return time1.toMilliseconds() < time2.toMilliseconds(); }
|
||||
bool operator> (Time time1, Time time2) noexcept { return time1.toMilliseconds() > time2.toMilliseconds(); }
|
||||
bool operator<= (Time time1, Time time2) noexcept { return time1.toMilliseconds() <= time2.toMilliseconds(); }
|
||||
bool operator>= (Time time1, Time time2) noexcept { return time1.toMilliseconds() >= time2.toMilliseconds(); }
|
||||
|
||||
static int getMonthNumberForCompileDate (const String& m) noexcept
|
||||
{
|
||||
for (int i = 0; i < 12; ++i)
|
||||
if (m.equalsIgnoreCase (shortMonthNames[i]))
|
||||
return i;
|
||||
|
||||
// If you hit this because your compiler has a non-standard __DATE__ format,
|
||||
// let me know so we can add support for it!
|
||||
jassertfalse;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Time Time::getCompilationDate()
|
||||
{
|
||||
StringArray dateTokens;
|
||||
dateTokens.addTokens (__DATE__, true);
|
||||
dateTokens.removeEmptyStrings (true);
|
||||
|
||||
return Time (dateTokens[2].getIntValue(),
|
||||
getMonthNumberForCompileDate (dateTokens[0]),
|
||||
dateTokens[1].getIntValue(), 12, 0);
|
||||
}
|
||||
|
||||
@@ -253,9 +253,9 @@ public:
|
||||
|
||||
//==============================================================================
|
||||
/** Adds a RelativeTime to this time. */
|
||||
Time& operator+= (RelativeTime delta);
|
||||
Time& operator+= (RelativeTime delta) noexcept;
|
||||
/** Subtracts a RelativeTime from this time. */
|
||||
Time& operator-= (RelativeTime delta);
|
||||
Time& operator-= (RelativeTime delta) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Tries to set the computer's clock.
|
||||
@@ -272,8 +272,7 @@ public:
|
||||
@param threeLetterVersion if true, it'll return a 3-letter abbreviation, e.g. "Tue"; if
|
||||
false, it'll return the full version, e.g. "Tuesday".
|
||||
*/
|
||||
static String getWeekdayName (int dayNumber,
|
||||
bool threeLetterVersion);
|
||||
static String getWeekdayName (int dayNumber, bool threeLetterVersion);
|
||||
|
||||
/** Returns the name of one of the months.
|
||||
|
||||
@@ -281,8 +280,7 @@ public:
|
||||
@param threeLetterVersion if true, it'll be a 3-letter abbreviation, e.g. "Jan"; if false
|
||||
it'll return the long form, e.g. "January"
|
||||
*/
|
||||
static String getMonthName (int monthNumber,
|
||||
bool threeLetterVersion);
|
||||
static String getMonthName (int monthNumber, bool threeLetterVersion);
|
||||
|
||||
//==============================================================================
|
||||
// Static methods for getting system timers directly..
|
||||
@@ -370,6 +368,8 @@ public:
|
||||
*/
|
||||
static int64 secondsToHighResolutionTicks (double seconds) noexcept;
|
||||
|
||||
/** Returns a Time based on the value of the __DATE__ macro when this module was compiled */
|
||||
static Time getCompilationDate();
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
@@ -378,27 +378,27 @@ private:
|
||||
|
||||
//==============================================================================
|
||||
/** Adds a RelativeTime to a Time. */
|
||||
JUCE_API Time operator+ (Time time, RelativeTime delta);
|
||||
JUCE_API Time operator+ (Time time, RelativeTime delta) noexcept;
|
||||
/** Adds a RelativeTime to a Time. */
|
||||
JUCE_API Time operator+ (RelativeTime delta, Time time);
|
||||
JUCE_API Time operator+ (RelativeTime delta, Time time) noexcept;
|
||||
|
||||
/** Subtracts a RelativeTime from a Time. */
|
||||
JUCE_API Time operator- (Time time, RelativeTime delta);
|
||||
JUCE_API Time operator- (Time time, RelativeTime delta) noexcept;
|
||||
/** Returns the relative time difference between two times. */
|
||||
JUCE_API const RelativeTime operator- (Time time1, Time time2);
|
||||
JUCE_API const RelativeTime operator- (Time time1, Time time2) noexcept;
|
||||
|
||||
/** Compares two Time objects. */
|
||||
JUCE_API bool operator== (Time time1, Time time2);
|
||||
JUCE_API bool operator== (Time time1, Time time2) noexcept;
|
||||
/** Compares two Time objects. */
|
||||
JUCE_API bool operator!= (Time time1, Time time2);
|
||||
JUCE_API bool operator!= (Time time1, Time time2) noexcept;
|
||||
/** Compares two Time objects. */
|
||||
JUCE_API bool operator< (Time time1, Time time2);
|
||||
JUCE_API bool operator< (Time time1, Time time2) noexcept;
|
||||
/** Compares two Time objects. */
|
||||
JUCE_API bool operator<= (Time time1, Time time2);
|
||||
JUCE_API bool operator<= (Time time1, Time time2) noexcept;
|
||||
/** Compares two Time objects. */
|
||||
JUCE_API bool operator> (Time time1, Time time2);
|
||||
JUCE_API bool operator> (Time time1, Time time2) noexcept;
|
||||
/** Compares two Time objects. */
|
||||
JUCE_API bool operator>= (Time time1, Time time2);
|
||||
JUCE_API bool operator>= (Time time1, Time time2) noexcept;
|
||||
|
||||
|
||||
#endif // JUCE_TIME_H_INCLUDED
|
||||
|
||||
@@ -408,7 +408,7 @@ XmlElement* XmlDocument::readNextElement (const bool alsoParseSubElements)
|
||||
}
|
||||
}
|
||||
|
||||
node = new XmlElement (String (input, endOfToken));
|
||||
node = new XmlElement (input, endOfToken);
|
||||
input = endOfToken;
|
||||
LinkedListPointer<XmlElement::XmlAttributeNode>::Appender attributeAppender (node->attributes);
|
||||
|
||||
@@ -458,8 +458,7 @@ XmlElement* XmlDocument::readNextElement (const bool alsoParseSubElements)
|
||||
if (nextChar == '"' || nextChar == '\'')
|
||||
{
|
||||
XmlElement::XmlAttributeNode* const newAtt
|
||||
= new XmlElement::XmlAttributeNode (String (attNameStart, attNameEnd),
|
||||
String::empty);
|
||||
= new XmlElement::XmlAttributeNode (attNameStart, attNameEnd);
|
||||
|
||||
readQuotedString (newAtt->value);
|
||||
attributeAppender.append (newAtt);
|
||||
|
||||
@@ -32,7 +32,7 @@ XmlElement::XmlAttributeNode::XmlAttributeNode (const XmlAttributeNode& other) n
|
||||
{
|
||||
}
|
||||
|
||||
XmlElement::XmlAttributeNode::XmlAttributeNode (const String& n, const String& v) noexcept
|
||||
XmlElement::XmlAttributeNode::XmlAttributeNode (const Identifier& n, const String& v) noexcept
|
||||
: name (n), value (v)
|
||||
{
|
||||
#if JUCE_DEBUG
|
||||
@@ -42,22 +42,53 @@ XmlElement::XmlAttributeNode::XmlAttributeNode (const String& n, const String& v
|
||||
#endif
|
||||
}
|
||||
|
||||
bool XmlElement::XmlAttributeNode::hasName (StringRef nameToMatch) const noexcept
|
||||
XmlElement::XmlAttributeNode::XmlAttributeNode (String::CharPointerType nameStart, String::CharPointerType nameEnd)
|
||||
: name (nameStart, nameEnd)
|
||||
{
|
||||
return name.equalsIgnoreCase (nameToMatch);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
XmlElement::XmlElement (const String& tag) noexcept
|
||||
: tagName (tag)
|
||||
static void sanityCheckTagName (const String& tag)
|
||||
{
|
||||
(void) tag;
|
||||
|
||||
// the tag name mustn't be empty, or it'll look like a text element!
|
||||
jassert (tag.containsNonWhitespaceChars())
|
||||
jassert (tag.containsNonWhitespaceChars());
|
||||
|
||||
// The tag can't contain spaces or other characters that would create invalid XML!
|
||||
jassert (! tag.containsAnyOf (" <>/&(){}"));
|
||||
}
|
||||
|
||||
XmlElement::XmlElement (const String& tag)
|
||||
: tagName (StringPool::getGlobalPool().getPooledString (tag))
|
||||
{
|
||||
sanityCheckTagName (tagName);
|
||||
}
|
||||
|
||||
XmlElement::XmlElement (const char* tag)
|
||||
: tagName (StringPool::getGlobalPool().getPooledString (tag))
|
||||
{
|
||||
sanityCheckTagName (tagName);
|
||||
}
|
||||
|
||||
XmlElement::XmlElement (StringRef tag)
|
||||
: tagName (StringPool::getGlobalPool().getPooledString (tag))
|
||||
{
|
||||
sanityCheckTagName (tagName);
|
||||
}
|
||||
|
||||
XmlElement::XmlElement (const Identifier& tag)
|
||||
: tagName (tag.toString())
|
||||
{
|
||||
sanityCheckTagName (tagName);
|
||||
}
|
||||
|
||||
XmlElement::XmlElement (String::CharPointerType tagNameStart, String::CharPointerType tagNameEnd)
|
||||
: tagName (StringPool::getGlobalPool().getPooledString (tagNameStart, tagNameEnd))
|
||||
{
|
||||
sanityCheckTagName (tagName);
|
||||
}
|
||||
|
||||
XmlElement::XmlElement (int /*dummy*/) noexcept
|
||||
{
|
||||
}
|
||||
@@ -407,7 +438,7 @@ int XmlElement::getNumAttributes() const noexcept
|
||||
const String& XmlElement::getAttributeName (const int index) const noexcept
|
||||
{
|
||||
if (const XmlAttributeNode* const att = attributes [index])
|
||||
return att->name;
|
||||
return att->name.toString();
|
||||
|
||||
return String::empty;
|
||||
}
|
||||
@@ -423,7 +454,7 @@ const String& XmlElement::getAttributeValue (const int index) const noexcept
|
||||
XmlElement::XmlAttributeNode* XmlElement::getAttribute (StringRef attributeName) const noexcept
|
||||
{
|
||||
for (XmlAttributeNode* att = attributes; att != nullptr; att = att->nextListItem)
|
||||
if (att->hasName (attributeName))
|
||||
if (att->name == attributeName)
|
||||
return att;
|
||||
|
||||
return nullptr;
|
||||
@@ -495,7 +526,7 @@ bool XmlElement::compareAttribute (StringRef attributeName,
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void XmlElement::setAttribute (const String& attributeName, const String& value)
|
||||
void XmlElement::setAttribute (const Identifier& attributeName, const String& value)
|
||||
{
|
||||
if (attributes == nullptr)
|
||||
{
|
||||
@@ -505,7 +536,7 @@ void XmlElement::setAttribute (const String& attributeName, const String& value)
|
||||
{
|
||||
for (XmlAttributeNode* att = attributes; ; att = att->nextListItem)
|
||||
{
|
||||
if (att->hasName (attributeName))
|
||||
if (att->name == attributeName)
|
||||
{
|
||||
att->value = value;
|
||||
break;
|
||||
@@ -520,23 +551,23 @@ void XmlElement::setAttribute (const String& attributeName, const String& value)
|
||||
}
|
||||
}
|
||||
|
||||
void XmlElement::setAttribute (const String& attributeName, const int number)
|
||||
void XmlElement::setAttribute (const Identifier& attributeName, const int number)
|
||||
{
|
||||
setAttribute (attributeName, String (number));
|
||||
}
|
||||
|
||||
void XmlElement::setAttribute (const String& attributeName, const double number)
|
||||
void XmlElement::setAttribute (const Identifier& attributeName, const double number)
|
||||
{
|
||||
setAttribute (attributeName, String (number, 20));
|
||||
}
|
||||
|
||||
void XmlElement::removeAttribute (const String& attributeName) noexcept
|
||||
void XmlElement::removeAttribute (const Identifier& attributeName) noexcept
|
||||
{
|
||||
for (LinkedListPointer<XmlAttributeNode>* att = &attributes;
|
||||
att->get() != nullptr;
|
||||
att = &(att->get()->nextListItem))
|
||||
{
|
||||
if (att->get()->hasName (attributeName))
|
||||
if (att->get()->name == attributeName)
|
||||
{
|
||||
delete att->removeNext();
|
||||
break;
|
||||
@@ -615,7 +646,7 @@ void XmlElement::prependChildElement (XmlElement* newNode) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
XmlElement* XmlElement::createNewChildElement (const String& childTagName)
|
||||
XmlElement* XmlElement::createNewChildElement (StringRef childTagName)
|
||||
{
|
||||
XmlElement* const newElement = new XmlElement (childTagName);
|
||||
addChildElement (newElement);
|
||||
@@ -683,7 +714,7 @@ bool XmlElement::isEquivalentTo (const XmlElement* const other,
|
||||
{
|
||||
if (thisAtt == nullptr || otherAtt == nullptr)
|
||||
{
|
||||
if (thisAtt == otherAtt) // both 0, so it's a match
|
||||
if (thisAtt == otherAtt) // both nullptr, so it's a match
|
||||
break;
|
||||
|
||||
return false;
|
||||
|
||||
@@ -144,20 +144,32 @@ class JUCE_API XmlElement
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an XmlElement with this tag name. */
|
||||
explicit XmlElement (const String& tagName) noexcept;
|
||||
explicit XmlElement (const String& tagName);
|
||||
|
||||
/** Creates an XmlElement with this tag name. */
|
||||
explicit XmlElement (const char* tagName);
|
||||
|
||||
/** Creates an XmlElement with this tag name. */
|
||||
explicit XmlElement (const Identifier& tagName);
|
||||
|
||||
/** Creates an XmlElement with this tag name. */
|
||||
explicit XmlElement (StringRef tagName);
|
||||
|
||||
/** Creates an XmlElement with this tag name. */
|
||||
XmlElement (String::CharPointerType tagNameBegin, String::CharPointerType tagNameEnd);
|
||||
|
||||
/** Creates a (deep) copy of another element. */
|
||||
XmlElement (const XmlElement& other);
|
||||
XmlElement (const XmlElement&);
|
||||
|
||||
/** Creates a (deep) copy of another element. */
|
||||
XmlElement& operator= (const XmlElement& other);
|
||||
XmlElement& operator= (const XmlElement&);
|
||||
|
||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
XmlElement (XmlElement&& other) noexcept;
|
||||
XmlElement& operator= (XmlElement&& other) noexcept;
|
||||
XmlElement (XmlElement&&) noexcept;
|
||||
XmlElement& operator= (XmlElement&&) noexcept;
|
||||
#endif
|
||||
|
||||
/** Deleting an XmlElement will also delete all its child elements. */
|
||||
/** Deleting an XmlElement will also delete all of its child elements. */
|
||||
~XmlElement() noexcept;
|
||||
|
||||
//==============================================================================
|
||||
@@ -303,13 +315,11 @@ public:
|
||||
bool hasAttribute (StringRef attributeName) const noexcept;
|
||||
|
||||
/** Returns the value of a named attribute.
|
||||
|
||||
@param attributeName the name of the attribute to look up
|
||||
*/
|
||||
const String& getStringAttribute (StringRef attributeName) const noexcept;
|
||||
|
||||
/** Returns the value of a named attribute.
|
||||
|
||||
@param attributeName the name of the attribute to look up
|
||||
@param defaultReturnValue a value to return if the element doesn't have an attribute
|
||||
with this name
|
||||
@@ -377,7 +387,7 @@ public:
|
||||
@param newValue the value to set it to
|
||||
@see removeAttribute
|
||||
*/
|
||||
void setAttribute (const String& attributeName, const String& newValue);
|
||||
void setAttribute (const Identifier& attributeName, const String& newValue);
|
||||
|
||||
/** Adds a named attribute to the element, setting it to an integer value.
|
||||
|
||||
@@ -391,7 +401,7 @@ public:
|
||||
@param attributeName the name of the attribute to set
|
||||
@param newValue the value to set it to
|
||||
*/
|
||||
void setAttribute (const String& attributeName, int newValue);
|
||||
void setAttribute (const Identifier& attributeName, int newValue);
|
||||
|
||||
/** Adds a named attribute to the element, setting it to a floating-point value.
|
||||
|
||||
@@ -405,14 +415,14 @@ public:
|
||||
@param attributeName the name of the attribute to set
|
||||
@param newValue the value to set it to
|
||||
*/
|
||||
void setAttribute (const String& attributeName, double newValue);
|
||||
void setAttribute (const Identifier& attributeName, double newValue);
|
||||
|
||||
/** Removes a named attribute from the element.
|
||||
|
||||
@param attributeName the name of the attribute to remove
|
||||
@see removeAllAttributes
|
||||
*/
|
||||
void removeAttribute (const String& attributeName) noexcept;
|
||||
void removeAttribute (const Identifier& attributeName) noexcept;
|
||||
|
||||
/** Removes all attributes from this element. */
|
||||
void removeAllAttributes() noexcept;
|
||||
@@ -555,7 +565,7 @@ public:
|
||||
XmlElement* newElement = myParentElement->createNewChildElement ("foobar");
|
||||
@endcode
|
||||
*/
|
||||
XmlElement* createNewChildElement (const String& tagName);
|
||||
XmlElement* createNewChildElement (StringRef tagName);
|
||||
|
||||
/** Replaces one of this element's children with another node.
|
||||
|
||||
@@ -589,10 +599,17 @@ public:
|
||||
/** Returns true if the given element is a child of this one. */
|
||||
bool containsChildElement (const XmlElement* possibleChild) const noexcept;
|
||||
|
||||
/** Recursively searches all sub-elements to find one that contains the specified
|
||||
child element.
|
||||
/** Recursively searches all sub-elements of this one, looking for an element
|
||||
which is the direct parent of the specified element.
|
||||
|
||||
Because elements don't store a pointer to their parent, if you have one
|
||||
and need to find its parent, the only way to do so is to exhaustively
|
||||
search the whole tree for it.
|
||||
|
||||
If the given child is found somewhere in this element's hierarchy, then
|
||||
this method will return its parent. If not, it will return nullptr.
|
||||
*/
|
||||
XmlElement* findParentElementOf (const XmlElement* elementToLookFor) noexcept;
|
||||
XmlElement* findParentElementOf (const XmlElement* childToSearchFor) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Sorts the child elements using a comparator.
|
||||
@@ -712,25 +729,26 @@ private:
|
||||
struct XmlAttributeNode
|
||||
{
|
||||
XmlAttributeNode (const XmlAttributeNode&) noexcept;
|
||||
XmlAttributeNode (const String& name, const String& value) noexcept;
|
||||
XmlAttributeNode (const Identifier&, const String&) noexcept;
|
||||
XmlAttributeNode (String::CharPointerType, String::CharPointerType);
|
||||
|
||||
LinkedListPointer<XmlAttributeNode> nextListItem;
|
||||
String name, value;
|
||||
|
||||
bool hasName (StringRef) const noexcept;
|
||||
Identifier name;
|
||||
String value;
|
||||
|
||||
private:
|
||||
XmlAttributeNode& operator= (const XmlAttributeNode&);
|
||||
XmlAttributeNode& operator= (const XmlAttributeNode&) JUCE_DELETED_FUNCTION;
|
||||
};
|
||||
|
||||
friend class XmlDocument;
|
||||
friend class LinkedListPointer <XmlAttributeNode>;
|
||||
friend class LinkedListPointer <XmlElement>;
|
||||
friend class LinkedListPointer <XmlElement>::Appender;
|
||||
friend class LinkedListPointer<XmlAttributeNode>;
|
||||
friend class LinkedListPointer<XmlElement>;
|
||||
friend class LinkedListPointer<XmlElement>::Appender;
|
||||
friend class NamedValueSet;
|
||||
|
||||
LinkedListPointer <XmlElement> nextListItem;
|
||||
LinkedListPointer <XmlElement> firstChildElement;
|
||||
LinkedListPointer <XmlAttributeNode> attributes;
|
||||
LinkedListPointer<XmlElement> nextListItem;
|
||||
LinkedListPointer<XmlElement> firstChildElement;
|
||||
LinkedListPointer<XmlAttributeNode> attributes;
|
||||
String tagName;
|
||||
|
||||
XmlElement (int) noexcept;
|
||||
@@ -740,6 +758,11 @@ private:
|
||||
void reorderChildElements (XmlElement**, int) noexcept;
|
||||
XmlAttributeNode* getAttribute (StringRef) const noexcept;
|
||||
|
||||
// Sigh.. L"" or _T("") string literals are problematic in general, and really inappropriate
|
||||
// for XML tags. Use a UTF-8 encoded literal instead, or if you're really determined to use
|
||||
// UTF-16, cast it to a String and use the other constructor.
|
||||
XmlElement (const wchar_t*) JUCE_DELETED_FUNCTION;
|
||||
|
||||
JUCE_LEAK_DETECTOR (XmlElement)
|
||||
};
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ public:
|
||||
char buffer [30];
|
||||
|
||||
if (inputStream != nullptr
|
||||
&& inputStream->setPosition (zei.streamOffset)
|
||||
&& inputStream->setPosition ((int64) zei.streamOffset)
|
||||
&& inputStream->read (buffer, 30) == 30
|
||||
&& ByteOrder::littleEndianInt (buffer) == 0x04034b50)
|
||||
{
|
||||
@@ -154,7 +154,7 @@ public:
|
||||
|
||||
int64 getTotalLength()
|
||||
{
|
||||
return zipEntryHolder.compressedSize;
|
||||
return (int64) zipEntryHolder.compressedSize;
|
||||
}
|
||||
|
||||
int read (void* buffer, int howMany)
|
||||
@@ -162,7 +162,7 @@ public:
|
||||
if (headerSize <= 0)
|
||||
return 0;
|
||||
|
||||
howMany = (int) jmin ((int64) howMany, (int64) (zipEntryHolder.compressedSize - pos));
|
||||
howMany = (int) jmin ((int64) howMany, ((int64) zipEntryHolder.compressedSize) - pos);
|
||||
|
||||
if (inputStream == nullptr)
|
||||
return 0;
|
||||
@@ -172,12 +172,12 @@ public:
|
||||
if (inputStream == file.inputStream)
|
||||
{
|
||||
const ScopedLock sl (file.lock);
|
||||
inputStream->setPosition (pos + zipEntryHolder.streamOffset + headerSize);
|
||||
inputStream->setPosition (pos + (int64) zipEntryHolder.streamOffset + headerSize);
|
||||
num = inputStream->read (buffer, howMany);
|
||||
}
|
||||
else
|
||||
{
|
||||
inputStream->setPosition (pos + zipEntryHolder.streamOffset + headerSize);
|
||||
inputStream->setPosition (pos + (int64) zipEntryHolder.streamOffset + headerSize);
|
||||
num = inputStream->read (buffer, howMany);
|
||||
}
|
||||
|
||||
@@ -298,8 +298,7 @@ InputStream* ZipFile::createStreamForEntry (const int index)
|
||||
|
||||
if (zei->compressed)
|
||||
{
|
||||
stream = new GZIPDecompressorInputStream (stream, true, true,
|
||||
zei->entry.uncompressedSize);
|
||||
stream = new GZIPDecompressorInputStream (stream, true, true, (int64) zei->entry.uncompressedSize);
|
||||
|
||||
// (much faster to unzip in big blocks using a buffer..)
|
||||
stream = new BufferedInputStream (stream, 32768, true);
|
||||
@@ -348,7 +347,7 @@ void ZipFile::init()
|
||||
in->setPosition (pos);
|
||||
MemoryBlock headerData;
|
||||
|
||||
if (in->readIntoMemoryBlock (headerData, size) == size)
|
||||
if (in->readIntoMemoryBlock (headerData, size) == (size_t) size)
|
||||
{
|
||||
pos = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user