diff --git a/develop/global/src/dwf/whiptk/file.cpp b/develop/global/src/dwf/whiptk/file.cpp index daf23a0..19a79a9 100644 --- a/develop/global/src/dwf/whiptk/file.cpp +++ b/develop/global/src/dwf/whiptk/file.cpp @@ -1772,15 +1772,29 @@ WT_Result WT_File::read(WT_Byte & a_byte) ////////////////////////////////////////////////////////////////////////////////// WT_Result WT_File::read(WT_Integer32 & a_word) { + // W2D format always stores this as a 4-byte little-endian or big-endian field. + // sizeof(WT_Integer32)==sizeof(long)==8 on LP64 (macOS arm64/x86_64), so we + // must read exactly 4 bytes. Crucially: assemble into uint32_t first, then + // cast to int32_t (which properly reinterprets the sign bit), then assign to + // the long (which sign-extends 32-bit → 64-bit). Without the intermediate + // int32_t cast, a uint32_t like 0xF8E35A4F would become +4175958607 instead + // of -118950833, corrupting the running current_point accumulation. + WT_Byte buf[4]; + WD_CHECK(read(4, buf)); #if WD_BIGENDIAN - WT_Integer32 tmp_word; - - WD_CHECK (read(sizeof(WT_Integer32), (WT_Byte *) &tmp_word)); - a_word = WT_Endian::adjust(tmp_word); - return WT_Result::Success; + { + uint32_t u = ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | + ((uint32_t)buf[2] << 8) | (uint32_t)buf[3]; + a_word = (WT_Integer32)(int32_t)u; + } #else - return read(sizeof(WT_Integer32), (WT_Byte *) &a_word); + { + uint32_t u = (uint32_t)buf[0] | ((uint32_t)buf[1] << 8) | + ((uint32_t)buf[2] << 16) | ((uint32_t)buf[3] << 24); + a_word = (WT_Integer32)(int32_t)u; + } #endif + return WT_Result::Success; } ////////////////////////////////////////////////////////////////////////////////// @@ -1814,13 +1828,21 @@ WT_Result WT_File::read(WT_Unsigned_Integer16 & a_word) ////////////////////////////////////////////////////////////////////////////////// WT_Result WT_File::read(WT_Unsigned_Integer32 & a_dword) { + // Always read exactly 4 bytes — sizeof(WT_Unsigned_Integer32)==8 on LP64. + WT_Byte buf[4]; + WD_CHECK(read(4, buf)); #if WD_BIGENDIAN - WD_CHECK (read(sizeof(WT_Unsigned_Integer32), (WT_Byte *) &a_dword)); - a_dword = WT_Endian::adjust(a_dword); - return WT_Result::Success; + a_dword = ((WT_Unsigned_Integer32)buf[0] << 24) | + ((WT_Unsigned_Integer32)buf[1] << 16) | + ((WT_Unsigned_Integer32)buf[2] << 8) | + (WT_Unsigned_Integer32)buf[3]; #else - return read(sizeof(WT_Unsigned_Integer32), (WT_Byte *) &a_dword); + a_dword = (WT_Unsigned_Integer32)buf[0] | + (((WT_Unsigned_Integer32)buf[1]) << 8) | + (((WT_Unsigned_Integer32)buf[2]) << 16) | + (((WT_Unsigned_Integer32)buf[3]) << 24); #endif + return WT_Result::Success; } ////////////////////////////////////////////////////////////////////////////////// @@ -2405,48 +2427,15 @@ WT_Result WT_File::read(int count, WT_Logical_Point * points) WD_Assert(points); WD_Assert(count > 0); - WT_Logical_Point * pos = NULL; - WT_Integer32 arrCoords[8]; - int i = 0; - while (i <= count - 4) - { - WD_CHECK (read(sizeof(arrCoords), (WT_Byte *)arrCoords)); - - WT_Integer32 *p = arrCoords; - pos = &points[i]; - pos[0].m_x = *p++; - pos[0].m_y = *p++; - - pos[1].m_x = *p++; - pos[1].m_y = *p++; - - pos[2].m_x = *p++; - pos[2].m_y = *p++; - - pos[3].m_x = *p++; - pos[3].m_y = *p; - - i += 4; - } - while (i < count) - { - WD_CHECK (read(points[i].m_x)); - WD_CHECK (read(points[i].m_y)); - pos++; - i++; - } - -#if WD_BIGENDIAN - pos = points; - for (int loop = 0; loop < count; loop++) + // Each WT_Logical_Point is 2 x 4-byte integers in the W2D binary format. + // sizeof(WT_Integer32)==sizeof(long)==8 on LP64, so the old sizeof-based bulk + // read consumed twice as many bytes as needed. Use our fixed read(WT_Integer32&) + // for every coordinate to guarantee exactly 4 bytes per component. + for (int i = 0; i < count; i++) { - pos->m_x = WT_Endian::adjust(pos->m_x); - pos->m_y = WT_Endian::adjust(pos->m_y); - pos++; + WD_CHECK(read(points[i].m_x)); + WD_CHECK(read(points[i].m_y)); } -#else - // NOP -#endif return WT_Result::Success; } diff --git a/develop/global/src/dwf/whiptk/image.cpp b/develop/global/src/dwf/whiptk/image.cpp index a2f7772..11d44cb 100644 --- a/develop/global/src/dwf/whiptk/image.cpp +++ b/develop/global/src/dwf/whiptk/image.cpp @@ -354,7 +354,6 @@ WT_Result WT_Image::materialize(WT_Opcode const & opcode, WT_File & file) case Getting_Max_Corner: WD_CHECK (file.read(1, &m_max_corner)); m_stage = Getting_Identifier; - m_relativized = WD_True; de_relativize(file); diff --git a/develop/global/src/dwf/whiptk/lweight.cpp b/develop/global/src/dwf/whiptk/lweight.cpp index 21df555..48d551a 100644 --- a/develop/global/src/dwf/whiptk/lweight.cpp +++ b/develop/global/src/dwf/whiptk/lweight.cpp @@ -151,7 +151,7 @@ WT_Result WT_Line_Weight::skip_operand( WT_Opcode const & opcode, WT_File& file break; case WT_Opcode::Single_Byte: - WD_CHECK( file.skip(sizeof(WT_Integer32)) ); + WD_CHECK( file.skip(4) ); // W2D format: always 4 bytes, not sizeof(long) break; case WT_Opcode::Extended_Binary: diff --git a/develop/global/src/dwf/whiptk/whipcore.h b/develop/global/src/dwf/whiptk/whipcore.h index a38e12e..064005d 100644 --- a/develop/global/src/dwf/whiptk/whipcore.h +++ b/develop/global/src/dwf/whiptk/whipcore.h @@ -101,7 +101,12 @@ #elif defined (macintosh) || (defined (__MACH__) && defined (__APPLE__)) #define WD_MAC_SYSTEM - #define WD_BIGENDIAN 1 + // Old PowerPC Macs were big-endian; Apple Silicon (arm64) and Intel Macs are little-endian. + #if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + #define WD_BIGENDIAN 1 + #else + #define WD_BIGENDIAN 0 + #endif // // GNU macros messing with class methods... strange diff --git a/develop/global/src/dwfcore/Exception.cpp b/develop/global/src/dwfcore/Exception.cpp index 7990bae..63551f4 100644 --- a/develop/global/src/dwfcore/Exception.cpp +++ b/develop/global/src/dwfcore/Exception.cpp @@ -1,128 +1,140 @@ -// -// Copyright (c) 2003-2006 by Autodesk, Inc. -// -// By using this code, you are agreeing to the terms and conditions of -// the License Agreement included in the documentation for this code. -// -// AUTODESK MAKES NO WARRANTIES, EXPRESS OR IMPLIED, -// AS TO THE CORRECTNESS OF THIS CODE OR ANY DERIVATIVE -// WORKS WHICH INCORPORATE IT. -// -// AUTODESK PROVIDES THE CODE ON AN "AS-IS" BASIS -// AND EXPLICITLY DISCLAIMS ANY LIABILITY, INCLUDING -// CONSEQUENTIAL AND INCIDENTAL DAMAGES FOR ERRORS, -// OMISSIONS, AND OTHER PROBLEMS IN THE CODE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer Software -// Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) (Rights in Technical -// Data and Computer Software), as applicable. -// - - -#include "dwfcore/Core.h" -#include "dwfcore/Exception.h" -using namespace DWFCore; - - - -_DWFCORE_API -DWFException::DWFException( const wchar_t* zMessage, - const char* zFunction, - const wchar_t* zFile, - unsigned int nLine ) -throw() - : _zFunction( zFunction ) - , _zFile( zFile ) - , _nLine( nLine ) -{ - _zMessage[0] = 0; - - if (zMessage) - { - size_t nBytes = min( 511*sizeof(wchar_t), DWFCORE_WIDE_STRING_LENGTH_IN_BYTES(zMessage) ); - - DWFCORE_ZERO_MEMORY( _zMessage, nBytes + 2 ); - DWFCORE_COPY_MEMORY( _zMessage, zMessage, nBytes ); - } -} - -_DWFCORE_API -DWFException::~DWFException() -throw() -{ - ; -} - -_DWFCORE_API -DWFException::DWFException( const DWFException& rEx ) -throw() - : _zFunction( rEx._zFunction ) - , _zFile( rEx._zFile ) - , _nLine( rEx._nLine ) -{ - _zMessage[0] = 0; - - if (rEx._zMessage) - { - size_t nBytes = min( 511*sizeof(wchar_t), DWFCORE_WIDE_STRING_LENGTH_IN_BYTES(rEx._zMessage) ); - - DWFCORE_ZERO_MEMORY( _zMessage, nBytes + 2 ); - DWFCORE_COPY_MEMORY( _zMessage, rEx._zMessage, nBytes ); - } -} - -_DWFCORE_API -DWFException& -DWFException::operator=( const DWFException& rEx ) -throw() -{ - _zFunction = rEx._zFunction; - _zFile = rEx._zFile; - _nLine = rEx._nLine; - - _zMessage[0] = 0; - - if (rEx._zMessage) - { - size_t nBytes = min( 511*sizeof(wchar_t), DWFCORE_WIDE_STRING_LENGTH_IN_BYTES(rEx._zMessage) ); - - DWFCORE_ZERO_MEMORY( _zMessage, nBytes + 2 ); - DWFCORE_COPY_MEMORY( _zMessage, rEx._zMessage, nBytes ); - } - - return *this; -} - -_DWFCORE_API -const wchar_t* -DWFException::message() const -throw() -{ - return _zMessage; -} - -_DWFCORE_API -const char* -DWFException::function() const -throw() -{ - return _zFunction; -} - -_DWFCORE_API -const wchar_t* -DWFException::file() const -throw() -{ - return _zFile; -} - -_DWFCORE_API -unsigned int -DWFException::line() const -throw() -{ - return _nLine; -} - +// +// Copyright (c) 2003-2006 by Autodesk, Inc. +// +// By using this code, you are agreeing to the terms and conditions of +// the License Agreement included in the documentation for this code. +// +// AUTODESK MAKES NO WARRANTIES, EXPRESS OR IMPLIED, +// AS TO THE CORRECTNESS OF THIS CODE OR ANY DERIVATIVE +// WORKS WHICH INCORPORATE IT. +// +// AUTODESK PROVIDES THE CODE ON AN "AS-IS" BASIS +// AND EXPLICITLY DISCLAIMS ANY LIABILITY, INCLUDING +// CONSEQUENTIAL AND INCIDENTAL DAMAGES FOR ERRORS, +// OMISSIONS, AND OTHER PROBLEMS IN THE CODE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer Software +// Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) (Rights in Technical +// Data and Computer Software), as applicable. +// + + +#include "dwfcore/Core.h" +#include "dwfcore/Exception.h" +using namespace DWFCore; + + + +_DWFCORE_API +DWFException::DWFException( const wchar_t* zMessage, + const char* zFunction, + const wchar_t* zFile, + unsigned int nLine ) +throw() + : _zFunction( zFunction ) + , _zFile( zFile ) + , _nLine( nLine ) +{ + _zMessage[0] = 0; + + if (zMessage) + { + size_t nBytes = min( 511*sizeof(wchar_t), DWFCORE_WIDE_STRING_LENGTH_IN_BYTES(zMessage) ); + + // The "+ 2" here assumed a 2-byte wchar_t (Windows). On macOS wchar_t is 4 bytes, + // so only half the terminator was cleared and the rest stayed as whatever the + // buffer already held: messages came back with binary garbage glued on, and + // wcslen then ran past the end looking for a zero. Clear a whole character. + DWFCORE_ZERO_MEMORY( _zMessage, nBytes + sizeof(wchar_t) ); + DWFCORE_COPY_MEMORY( _zMessage, zMessage, nBytes ); + } +} + +_DWFCORE_API +DWFException::~DWFException() +throw() +{ + ; +} + +_DWFCORE_API +DWFException::DWFException( const DWFException& rEx ) +throw() + : _zFunction( rEx._zFunction ) + , _zFile( rEx._zFile ) + , _nLine( rEx._nLine ) +{ + _zMessage[0] = 0; + + if (rEx._zMessage) + { + size_t nBytes = min( 511*sizeof(wchar_t), DWFCORE_WIDE_STRING_LENGTH_IN_BYTES(rEx._zMessage) ); + + // The "+ 2" here assumed a 2-byte wchar_t (Windows). On macOS wchar_t is 4 bytes, + // so only half the terminator was cleared and the rest stayed as whatever the + // buffer already held: messages came back with binary garbage glued on, and + // wcslen then ran past the end looking for a zero. Clear a whole character. + DWFCORE_ZERO_MEMORY( _zMessage, nBytes + sizeof(wchar_t) ); + DWFCORE_COPY_MEMORY( _zMessage, rEx._zMessage, nBytes ); + } +} + +_DWFCORE_API +DWFException& +DWFException::operator=( const DWFException& rEx ) +throw() +{ + _zFunction = rEx._zFunction; + _zFile = rEx._zFile; + _nLine = rEx._nLine; + + _zMessage[0] = 0; + + if (rEx._zMessage) + { + size_t nBytes = min( 511*sizeof(wchar_t), DWFCORE_WIDE_STRING_LENGTH_IN_BYTES(rEx._zMessage) ); + + // The "+ 2" here assumed a 2-byte wchar_t (Windows). On macOS wchar_t is 4 bytes, + // so only half the terminator was cleared and the rest stayed as whatever the + // buffer already held: messages came back with binary garbage glued on, and + // wcslen then ran past the end looking for a zero. Clear a whole character. + DWFCORE_ZERO_MEMORY( _zMessage, nBytes + sizeof(wchar_t) ); + DWFCORE_COPY_MEMORY( _zMessage, rEx._zMessage, nBytes ); + } + + return *this; +} + +_DWFCORE_API +const wchar_t* +DWFException::message() const +throw() +{ + return _zMessage; +} + +_DWFCORE_API +const char* +DWFException::function() const +throw() +{ + return _zFunction; +} + +_DWFCORE_API +const wchar_t* +DWFException::file() const +throw() +{ + return _zFile; +} + +_DWFCORE_API +unsigned int +DWFException::line() const +throw() +{ + return _nLine; +} + diff --git a/develop/global/src/dwfcore/Vector.h b/develop/global/src/dwfcore/Vector.h index cb780f9..5ca2382 100644 --- a/develop/global/src/dwfcore/Vector.h +++ b/develop/global/src/dwfcore/Vector.h @@ -560,7 +560,7 @@ public: _tSTLConstIterator iter = this->_oVector.begin(); for (; iter!=this->_oVector.end(); ++iter) { - if (_tEquals(*iter, oValue)) + if (this->_tEquals(*iter, oValue)) { ++nCount; } @@ -588,7 +588,7 @@ public: _tSTLConstIterator iter = this->_oVector.begin(); for (; iter!=this->_oVector.end(); ++iter) { - if (_tEquals( oValue, *iter )) + if (this->_tEquals( oValue, *iter )) { return true; } @@ -619,7 +619,7 @@ public: unsigned int i = 0; for (; it != this->_oVector.end(); ++it, ++i) { - if (_tEquals( oValue, *it )) + if (this->_tEquals( oValue, *it )) { oIndices.push_back( i ); } @@ -882,7 +882,7 @@ public: else { // Insert only if the value was not found - if ( iter==this->_oVector.end() || _tCompares( oValue, *iter) ) + if ( iter==this->_oVector.end() || this->_tCompares( oValue, *iter) ) { this->_oVector.insert( iter, oValue ); } @@ -1017,7 +1017,7 @@ public: // for this method. _tSTLConstIterator iter = std::lower_bound( this->_oVector.begin(), this->_oVector.end(), oValue, this->_tCompares ); - if ( iter==this->_oVector.end() || _tCompares( oValue, *iter) ) + if ( iter==this->_oVector.end() || this->_tCompares( oValue, *iter) ) { // The value was not found return false; diff --git a/develop/global/src/dwfcore/mac/Core.cpp b/develop/global/src/dwfcore/mac/Core.cpp index dd3cb8e..236a366 100644 --- a/develop/global/src/dwfcore/mac/Core.cpp +++ b/develop/global/src/dwfcore/mac/Core.cpp @@ -30,14 +30,8 @@ // // Carbon API with atomic operations // -#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) -#include -#define OTAtomicAdd32 OSAtomicAdd32 -typedef int32_t _SInt32; -#else -#include -typedef SInt32 _SInt32; -#endif +// Patched: OSAtomic is deprecated since macOS 10.12; use C11 atomics via stdatomic.h +#include namespace DWFCore { @@ -47,22 +41,14 @@ int AtomicIncrement( volatile int* pValue ) throw() { - // - // /usr/include/ppc/types.h defines int32_t with int - // so this cast feels safe - // - return ::OTAtomicAdd32( 1, (_SInt32*)pValue ); + return atomic_fetch_add((_Atomic(int)*)pValue, 1) + 1; } int AtomicDecrement( volatile int* pValue ) throw() { - // - // /usr/include/ppc/types.h defines int32_t with int - // so this cast feels safe - // - return ::OTAtomicAdd32( -1, (_SInt32*)pValue ); + return atomic_fetch_sub((_Atomic(int)*)pValue, 1) - 1; } // diff --git a/develop/global/src/dwfcore/mac/Core.h b/develop/global/src/dwfcore/mac/Core.h index 0623baf..1e6a9de 100644 --- a/develop/global/src/dwfcore/mac/Core.h +++ b/develop/global/src/dwfcore/mac/Core.h @@ -46,14 +46,43 @@ #include #include -// -// include stl's min and max definitions -// if we are on gcc 4.0 or greater -// -#if __GNUC__ > 3 -#include -using namespace std; -#endif +// Patched for modern clang/libc++ on macOS: +// libc++ // rely on namespace std for ::strcpy etc., +// so pull them into global namespace which the toolkit's macros expect. +#include +#include +#include +#include +#include +#include +using std::min; +using std::max; +using std::strcpy; +using std::strncpy; +using std::strcmp; +using std::strncmp; +using std::strlen; +using std::strcat; +using std::strchr; +using std::strstr; +using std::memcpy; +using std::memmove; +using std::memset; +using std::memcmp; +using std::wcscpy; +using std::wcsncpy; +using std::wcscmp; +using std::wcsncmp; +using std::wcslen; +using std::wcschr; +using std::wcsstr; +using std::tolower; +using std::toupper; +using std::isalpha; +using std::isdigit; +using std::isspace; +using std::sprintf; +using std::sscanf; // diff --git a/develop/global/src/dwfcore/mac/Timer.cpp b/develop/global/src/dwfcore/mac/Timer.cpp index 8784c4a..05c84f7 100644 --- a/develop/global/src/dwfcore/mac/Timer.cpp +++ b/develop/global/src/dwfcore/mac/Timer.cpp @@ -33,8 +33,16 @@ using namespace DWFCore; // // Carbon API with absolute timer operations // -//#include -#include +// Patched: CoreServices/Carbon UpTime() not available on modern macOS; use mach_absolute_time +#include + +static unsigned long long _dwf_mach_uptime_ns() +{ + static mach_timebase_info_data_t tb = {0, 0}; + if (tb.denom == 0) mach_timebase_info(&tb); + uint64_t t = mach_absolute_time(); + return (unsigned long long)(t * tb.numer / tb.denom); +} DWFTimer::DWFTimer() throw() @@ -67,16 +75,14 @@ unsigned long DWFTimer::Tick32() throw() { - AbsoluteTime tTime = ::UpTime(); - return *(unsigned long*)&tTime; + return (unsigned long)(_dwf_mach_uptime_ns() & 0xFFFFFFFFULL); } unsigned long long DWFTimer::Tick64() throw() { - AbsoluteTime tTime = ::UpTime(); - return *(unsigned long long *)&tTime; + return _dwf_mach_uptime_ns(); } void diff --git a/develop/global/src/dwfcore/paging/MemoryManager.cpp b/develop/global/src/dwfcore/paging/MemoryManager.cpp index bd521b1..effc8ee 100644 --- a/develop/global/src/dwfcore/paging/MemoryManager.cpp +++ b/develop/global/src/dwfcore/paging/MemoryManager.cpp @@ -21,9 +21,14 @@ #include "dwfcore/paging/MemoryManager.h" #include "dwfcore/paging/PagingStrategy.h" #include "dwfcore/paging/SqlAdapter.h" +#include "dwfcore/paging/FileAdapter.h" +#include "dwfcore/File.h" #include #include "dwfcore/Synchronization.h" #include +#include +#include +#include namespace DWFCore { @@ -52,8 +57,19 @@ namespace DWFCore _oInfo._nBlockSize = kDefaultBlockSize; - // DWFSqliteAdapter is faster than DWFFileAdapter - static DWFCore::DWFSqliteAdapter oAdapter; + // DWFSqliteAdapter (in-memory sqlite b-tree) is faster than DWFFileAdapter, but its + // sqlite3BtreeOpen() call fails on real iOS hardware (reproduced on a physical + // iPad — works fine in the Simulator and on macOS with the identical source) and + // throws DWFIOException right here, on whatever thread first pages a property + // object in; nothing in the calling app can catch that. DWFFileAdapter is the + // toolkit's own working fallback, backed by a real temp file instead. + const char* tmpdir = getenv("TMPDIR"); + if (!tmpdir || !*tmpdir) tmpdir = "/tmp"; + char zPathBuf[1024]; + snprintf(zPathBuf, sizeof(zPathBuf), "%s%sdwfpaging_%d.tmp", + tmpdir, (tmpdir[strlen(tmpdir) - 1] == '/') ? "" : "/", (int)getpid()); + static DWFCore::DWFFile oPagingFile(zPathBuf); + static DWFCore::DWFFileAdapter oAdapter(oPagingFile); static DWFCore::DWFNruStrategy oStrategy(oAdapter); oStrategy.highWater(kDefaultHighWater); oStrategy.lowWater(kDefaultLowWater); diff --git a/develop/global/src/dwfcore/zlib/zconf.h b/develop/global/src/dwfcore/zlib/zconf.h index e927c5c..3c02d69 100644 --- a/develop/global/src/dwfcore/zlib/zconf.h +++ b/develop/global/src/dwfcore/zlib/zconf.h @@ -231,9 +231,8 @@ # define FAR #endif -#if !defined(MACOS) && !defined(TARGET_OS_MAC) +/* Patched: always typedef Byte; on modern macOS we don't pull MacTypes.h */ typedef unsigned char Byte; /* 8 bits */ -#endif typedef unsigned int uInt; /* 16 bits or more */ typedef unsigned long uLong; /* 32 bits or more */ diff --git a/develop/global/src/dwf/opc/RelationshipContainer.cpp b/develop/global/src/dwf/opc/RelationshipContainer.cpp index 77bb0e3..85c0b6b 100644 --- a/develop/global/src/dwf/opc/RelationshipContainer.cpp +++ b/develop/global/src/dwf/opc/RelationshipContainer.cpp @@ -388,6 +388,12 @@ throw( DWFException ) _DWFCORE_THROW( DWFUnexpectedException, /*NOXLATE*/L"This RelationshipsContainer already contains Relationships." ); } + // DWF View: a damaged package returns no stream for its relationships part. + if (pRelsInputStream == NULL) + { + _DWFCORE_THROW( DWFDoesNotExistException, /*NOXLATE*/L"The relationships part could not be read" ); + } + DWFXMLParser manifestRelsParser( this ); manifestRelsParser.parseDocument( *pRelsInputStream ); } diff --git a/develop/global/src/dwfcore/XMLParser.cpp b/develop/global/src/dwfcore/XMLParser.cpp index 20c0693..f603b40 100644 --- a/develop/global/src/dwfcore/XMLParser.cpp +++ b/develop/global/src/dwfcore/XMLParser.cpp @@ -141,6 +141,17 @@ void DWFXMLParser::parseDocument( DWFInputStream& rDocumentStream) throw( DWFException ) { + // + // DWF View: a damaged package can hand over a part that could not be extracted + // (a null stream behind the reference). Reading it crashed the app on iOS, where + // this code runs in-process; refuse it so the caller reports an unreadable file. + // + DWFInputStream* volatile pDocumentStream = &rDocumentStream; + if (pDocumentStream == NULL) + { + _DWFCORE_THROW( DWFNullPointerException, /*NOXLATE*/L"No stream to parse: the package part could not be read" ); + } + bool bAdvance = false; XML_Status retCode = XML_STATUS_OK; XML_ParsingStatus status; diff --git a/develop/global/src/dwf/package/Manifest.cpp b/develop/global/src/dwf/package/Manifest.cpp index 1e986a6..75ca33e 100644 --- a/develop/global/src/dwf/package/Manifest.cpp +++ b/develop/global/src/dwf/package/Manifest.cpp @@ -290,8 +290,18 @@ throw() // // key object by it's own name for fast look up // - _oSectionsByName.insert( pSection->name(), pSection ); - _oSectionsByType.insert( DWFSection::tMultiMap::value_type(pSection->type(), pSection) ); + // + // Alteração byn: uma secção sem nome (manifesto mal formado) daria uma chave NULL, + // que partia a lista por nome. Fica só nas listas por ordem e por tipo. + // + if (pSection->name().chars() > 0) + { + _oSectionsByName.insert( pSection->name(), pSection ); + } + if (pSection->type().chars() > 0) // Alteração byn: chave NULL, como no nome + { + _oSectionsByType.insert( DWFSection::tMultiMap::value_type(pSection->type(), pSection) ); + } // // if unowned, claim ownership @@ -350,6 +360,10 @@ DWFSection* DWFManifest::findSectionByName( const DWFString& zName ) throw() { + if (zName.chars() == 0) // Alteração byn: chave vazia, ver provideSection + { + return NULL; + } DWFSection** ppSection = _oSectionsByName.find( (const wchar_t*)zName ); return (ppSection ? *ppSection : NULL); } @@ -359,6 +373,10 @@ DWFManifest::SectionIterator* DWFManifest::findSectionsByType( const DWFString& zType ) throw() { + if (zType.chars() == 0) // Alteração byn: chave vazia, ver provideSection + { + return DWFCORE_ALLOC_OBJECT( SectionIterator(_oSectionsByType.end(), _oSectionsByType.end()) ); + } return DWFCORE_ALLOC_OBJECT( SectionIterator(_oSectionsByType.lower_bound((const wchar_t*)zType), _oSectionsByType.upper_bound((const wchar_t*)zType)) ); } @@ -549,7 +567,10 @@ throw( DWFException ) // // try removing it from the sections-by-name list // - _oSectionsByName.erase( pSection->name() ); + if (pSection->name().chars() > 0) // Alteração byn: ver provideSection + { + _oSectionsByName.erase( pSection->name() ); + } // // try removing it from the sections-in-order list diff --git a/develop/global/src/dwf/package/Paper.cpp b/develop/global/src/dwf/package/Paper.cpp index f5924bc..27d6343 100644 --- a/develop/global/src/dwf/package/Paper.cpp +++ b/develop/global/src/dwf/package/Paper.cpp @@ -210,16 +210,22 @@ throw( DWFException ) { nFound |= 0x10; + // + // Alteração byn: a cor deve ser "R G B". Com menos números o tokenizador + // devolve NULL e o atoi(NULL) deitava a app abaixo. Uma cor incompleta ignora-se. + // char* pColor = (char*)ppAttributeList[iAttrib+1]; char* pSavePtr; - char* pToken = DWFCORE_ASCII_STRING_TOKENIZE( pColor, /*NOXLATE*/" ", &pSavePtr ); - _nColorARGB = ((unsigned char)::atoi(pToken) << 16); - - pToken = DWFCORE_ASCII_STRING_TOKENIZE( NULL, /*NOXLATE*/" ", &pSavePtr ); - _nColorARGB |= ((unsigned char)::atoi(pToken) << 8); - - pToken = DWFCORE_ASCII_STRING_TOKENIZE( NULL, /*NOXLATE*/" ", &pSavePtr ); - _nColorARGB |= (unsigned char)::atoi(pToken); + char* apToken[3]; + apToken[0] = DWFCORE_ASCII_STRING_TOKENIZE( pColor, /*NOXLATE*/" ", &pSavePtr ); + apToken[1] = apToken[0] ? DWFCORE_ASCII_STRING_TOKENIZE( NULL, /*NOXLATE*/" ", &pSavePtr ) : NULL; + apToken[2] = apToken[1] ? DWFCORE_ASCII_STRING_TOKENIZE( NULL, /*NOXLATE*/" ", &pSavePtr ) : NULL; + if (apToken[2]) + { + _nColorARGB = ((unsigned char)::atoi(apToken[0]) << 16); + _nColorARGB |= ((unsigned char)::atoi(apToken[1]) << 8); + _nColorARGB |= (unsigned char)::atoi(apToken[2]); + } } // // set the clip region diff --git a/develop/global/src/dwf/package/SectionBuilder.cpp b/develop/global/src/dwf/package/SectionBuilder.cpp index e2ed7b6..1284c6d 100644 --- a/develop/global/src/dwf/package/SectionBuilder.cpp +++ b/develop/global/src/dwf/package/SectionBuilder.cpp @@ -170,7 +170,9 @@ throw( DWFException ) // // acquire a specific factory for this section type // - DWFSection::Factory** ppFactory = _oFactories.find( zType ); + // Alteração byn: uma secção sem tipo (manifesto mal formado) daria uma chave NULL, + // que partia a procura. Sem tipo, fica a secção "regular". + DWFSection::Factory** ppFactory = (zType.chars() > 0) ? _oFactories.find( zType ) : NULL; // // don't have one? no problem, build a "regular" section diff --git a/develop/global/src/dwf/package/reader/EPlotSectionDescriptorReader.cpp b/develop/global/src/dwf/package/reader/EPlotSectionDescriptorReader.cpp index ae60b2c..6e610c8 100644 --- a/develop/global/src/dwf/package/reader/EPlotSectionDescriptorReader.cpp +++ b/develop/global/src/dwf/package/reader/EPlotSectionDescriptorReader.cpp @@ -237,18 +237,24 @@ throw() { nFound |= eProvideColor; + // + // Alteração byn: a cor deve ser "R G B". Com menos números o tokenizador + // devolve NULL e o atoi(NULL) deitava a app abaixo. Uma cor incompleta ignora-se. + // char* pColor = (char*)ppAttributeList[iAttrib+1]; char* pSavePtr; - char* pToken = DWFCORE_ASCII_STRING_TOKENIZE( pColor, /*NOXLATE*/" ", &pSavePtr ); - unsigned int nColorARGB = ((unsigned char)::atoi(pToken) << 16); - - pToken = DWFCORE_ASCII_STRING_TOKENIZE( NULL, /*NOXLATE*/" ", &pSavePtr ); - nColorARGB |= ((unsigned char)::atoi(pToken) << 8); - - pToken = DWFCORE_ASCII_STRING_TOKENIZE( NULL, /*NOXLATE*/" ", &pSavePtr ); - nColorARGB |= (unsigned char)::atoi(pToken); + char* apToken[3]; + apToken[0] = DWFCORE_ASCII_STRING_TOKENIZE( pColor, /*NOXLATE*/" ", &pSavePtr ); + apToken[1] = apToken[0] ? DWFCORE_ASCII_STRING_TOKENIZE( NULL, /*NOXLATE*/" ", &pSavePtr ) : NULL; + apToken[2] = apToken[1] ? DWFCORE_ASCII_STRING_TOKENIZE( NULL, /*NOXLATE*/" ", &pSavePtr ) : NULL; + if (apToken[2]) + { + unsigned int nColorARGB = ((unsigned char)::atoi(apToken[0]) << 16); + nColorARGB |= ((unsigned char)::atoi(apToken[1]) << 8); + nColorARGB |= (unsigned char)::atoi(apToken[2]); - _provideColor( nColorARGB ); + _provideColor( nColorARGB ); + } } // // provide the object id diff --git a/develop/global/src/dwf/package/utility/ResourceContainer.cpp b/develop/global/src/dwf/package/utility/ResourceContainer.cpp index e32ef67..089b82e 100644 --- a/develop/global/src/dwf/package/utility/ResourceContainer.cpp +++ b/develop/global/src/dwf/package/utility/ResourceContainer.cpp @@ -103,6 +103,15 @@ DWFResource* DWFResourceContainer::findResourceByHREF( const DWFString& zHRef ) throw() { + // + // Alteração byn: um href vazio dá um ponteiro NULL, que as listas não aceitam como + // chave (caía no wcscmp). Num ficheiro mal formado o recurso pode não ter href. + // + if (zHRef.chars() == 0) + { + return NULL; + } + DWFResource** ppResource = _oResourcesByHREF.find( (const wchar_t*)zHRef ); return (ppResource ? *ppResource : NULL); } @@ -112,6 +121,12 @@ DWFResource* DWFResourceContainer::findResourceByObjectID( const DWFString& zObjectID ) throw() { + // Alteração byn: chave vazia, como no href. + if (zObjectID.chars() == 0) + { + return NULL; + } + DWFResource** ppResource = _oResourcesByObjectID.find( (const wchar_t*)zObjectID ); return (ppResource ? *ppResource : NULL); } @@ -173,6 +188,11 @@ throw( DWFException ) // // look up and remove by HREF // + // Alteração byn: um recurso sem href não está na lista por href. + if (rResource.href().chars() == 0) + { + return NULL; + } DWFResource** ppResource = _oResourcesByHREF.find( (const wchar_t*)rResource.href() ); if (ppResource) @@ -344,7 +364,10 @@ throw() // // remove from href list // - _oResourcesByHREF.erase( (const wchar_t*)pResource->href() ); + if (pResource->href().chars() > 0) // Alteração byn: sem href não entrou na lista + { + _oResourcesByHREF.erase( (const wchar_t*)pResource->href() ); + } // // remove from ObjectID list @@ -358,7 +381,9 @@ throw() // // remove from the role list // - DWFResource::tMultiMap::iterator iResource = _oResourcesByRole.lower_bound( pResource->role() ); + // Alteração byn: sem papel não entrou na lista (ver addResource). + DWFResource::tMultiMap::iterator iResource = (pResource->role().chars() > 0) ? + _oResourcesByRole.lower_bound( pResource->role() ) : _oResourcesByRole.end(); DWFResource::tMultiMap::iterator iLast; if (iResource != _oResourcesByRole.end()) @@ -378,7 +403,8 @@ throw() // // remove from the MIME list // - iResource = _oResourcesByMIME.lower_bound( pResource->mime() ); + iResource = (pResource->mime().chars() > 0) ? // Alteração byn: idem + _oResourcesByMIME.lower_bound( pResource->mime() ) : _oResourcesByMIME.end(); if (iResource != _oResourcesByMIME.end()) { @@ -479,7 +505,7 @@ throw( DWFException ) // // check for previous // - if (bReplace) + if (bReplace && zHREF.chars() > 0) // Alteração byn: sem href não há chave { DWFResource** ppFind = _oResourcesByHREF.find( (const wchar_t*)zHREF ); if (ppFind) @@ -500,7 +526,12 @@ throw( DWFException ) // // insert new resource // - _oResourcesByHREF.insert( (const wchar_t*)pResource->href(), pResource, bReplace ); + // Alteração byn: um recurso sem href (ficheiro mal formado) fica só nas listas + // por papel e por tipo: a chave NULL partia a lista por href. + if (zHREF.chars() > 0) + { + _oResourcesByHREF.insert( (const wchar_t*)pResource->href(), pResource, bReplace ); + } // // store in aux lists @@ -511,8 +542,15 @@ throw( DWFException ) _oResourcesByObjectID.insert( (const wchar_t*)zObjectID, pResource, bReplace ); } - _oResourcesByRole.insert( DWFResource::tMultiMap::value_type(pResource->role(), pResource) ); - _oResourcesByMIME.insert( DWFResource::tMultiMap::value_type(pResource->mime(), pResource) ); + // Alteração byn: sem papel ou sem tipo MIME, a chave NULL partia a comparação. + if (pResource->role().chars() > 0) + { + _oResourcesByRole.insert( DWFResource::tMultiMap::value_type(pResource->role(), pResource) ); + } + if (pResource->mime().chars() > 0) + { + _oResourcesByMIME.insert( DWFResource::tMultiMap::value_type(pResource->mime(), pResource) ); + } // // capture the structure @@ -541,7 +579,7 @@ throw( DWFException ) { DWFResource* pResource = dynamic_cast(&rOwnable); - if (pResource && _oResourcesByHREF.find(pResource->href())) + if (pResource && pResource->href().chars() > 0 && _oResourcesByHREF.find(pResource->href())) { removeResource( *pResource, false ); } diff --git a/develop/global/src/dwfcore/ansi/String.cpp b/develop/global/src/dwfcore/ansi/String.cpp index 8dc90db..02cadf5 100644 --- a/develop/global/src/dwfcore/ansi/String.cpp +++ b/develop/global/src/dwfcore/ansi/String.cpp @@ -2396,6 +2396,15 @@ throw( DWFException ) double nScale = 1.0; char* pIn = (char*)zString; + // + // Alteração byn: num ficheiro mal formado, um atributo pode ter menos números do + // que os esperados e o tokenizador devolve NULL. Vale 0, em vez de cair. + // + if (pIn == NULL) + { + return 0.0; + } + if (*pIn == '-') { *pIn++; @@ -2511,6 +2520,14 @@ throw( DWFException ) double nScale = 1.0; wchar_t* pIn = (wchar_t*)zString; + // + // Alteração byn: texto em falta vale 0, como na versão de char. + // + if (pIn == NULL) + { + return 0.0; + } + if (*pIn == L'-') { *pIn++; diff --git a/develop/global/src/dwfcore/paging/MemoryManager.cpp b/develop/global/src/dwfcore/paging/MemoryManager.cpp index effc8ee..befc7d4 100644 --- a/develop/global/src/dwfcore/paging/MemoryManager.cpp +++ b/develop/global/src/dwfcore/paging/MemoryManager.cpp @@ -70,6 +70,11 @@ namespace DWFCore tmpdir, (tmpdir[strlen(tmpdir) - 1] == '/') ? "" : "/", (int)getpid()); static DWFCore::DWFFile oPagingFile(zPathBuf); static DWFCore::DWFFileAdapter oAdapter(oPagingFile); + // Alteração byn: o adaptador já abriu o ficheiro (no construtor). Apagá-lo do disco + // logo aqui evita deixar um dwfpaging_.tmp na pasta temporária por cada + // processo: no Mac e no iOS o ficheiro aberto continua a servir até ao fim. Onde o + // sistema não deixa apagar um ficheiro aberto, falha sem consequências. + std::remove(zPathBuf); static DWFCore::DWFNruStrategy oStrategy(oAdapter); oStrategy.highWater(kDefaultHighWater); oStrategy.lowWater(kDefaultLowWater); diff --git a/develop/global/src/dwfcore/paging/MemoryManager.cpp b/develop/global/src/dwfcore/paging/MemoryManager.cpp index befc7d4..135a0d2 100644 --- a/develop/global/src/dwfcore/paging/MemoryManager.cpp +++ b/develop/global/src/dwfcore/paging/MemoryManager.cpp @@ -28,7 +28,13 @@ #include #include #include +// Alteração byn: getpid() vem do unistd.h no Mac, no iOS e no Android, e do process.h no Windows. +#ifdef _WIN32 +#include +#define getpid _getpid +#else #include +#endif namespace DWFCore { @@ -63,11 +69,25 @@ namespace DWFCore // throws DWFIOException right here, on whatever thread first pages a property // object in; nothing in the calling app can catch that. DWFFileAdapter is the // toolkit's own working fallback, backed by a real temp file instead. + // Alteração byn: no Windows a pasta temporária vem de TEMP (ou TMP) e o separador é "\". +#ifdef _WIN32 + const char* tmpdir = getenv("TEMP"); + if (!tmpdir || !*tmpdir) tmpdir = getenv("TMP"); + if (!tmpdir || !*tmpdir) tmpdir = "."; + const char cSep = '\\'; +#else const char* tmpdir = getenv("TMPDIR"); if (!tmpdir || !*tmpdir) tmpdir = "/tmp"; - char zPathBuf[1024]; + const char cSep = '/'; +#endif + static char zPathBuf[1024]; + const char zSep[2] = { cSep, 0 }; snprintf(zPathBuf, sizeof(zPathBuf), "%s%sdwfpaging_%d.tmp", - tmpdir, (tmpdir[strlen(tmpdir) - 1] == '/') ? "" : "/", (int)getpid()); + tmpdir, (tmpdir[strlen(tmpdir) - 1] == cSep) ? "" : zSep, (int)getpid()); + // Alteração byn: onde o sistema não deixa apagar um ficheiro aberto (Windows), o + // ficheiro apaga-se à saída do processo. Os objetos estáticos destroem-se pela ordem + // inversa da construção: este, criado antes do ficheiro e do adaptador, é o último. + static struct _ApagarNoFim { ~_ApagarNoFim() { std::remove(zPathBuf); } } oApagarNoFim; static DWFCore::DWFFile oPagingFile(zPathBuf); static DWFCore::DWFFileAdapter oAdapter(oPagingFile); // Alteração byn: o adaptador já abriu o ficheiro (no construtor). Apagá-lo do disco diff --git a/develop/global/src/dwfcore/paging/Archive.h b/develop/global/src/dwfcore/paging/Archive.h index 803327b..8c7d8cc 100644 --- a/develop/global/src/dwfcore/paging/Archive.h +++ b/develop/global/src/dwfcore/paging/Archive.h @@ -26,6 +26,9 @@ #include "dwfcore/paging/Adapter.h" #include +// Alteração byn: o MSVC não traz nem por outros cabeçalhos (std::basic_string, memcpy). +#include +#include /// ///\file dwfcore/paging/Archive.h diff --git a/develop/global/src/dwf/package/XML.cpp b/develop/global/src/dwf/package/XML.cpp index 94b59b7..c321a14 100644 --- a/develop/global/src/dwf/package/XML.cpp +++ b/develop/global/src/dwf/package/XML.cpp @@ -400,8 +400,15 @@ DWFContentPresentationModelViewNode* DWFXMLElementBuilder::buildContentPresentationModelViewNode( const char** ppAttributeList ) throw( DWFException ) { +#ifdef DWFTK_SEM_W3D + // Alteração byn: sem o w3dtk (3D) não há nós de vista 3D; o leitor de apresentações lê-os + // como nós de referência e nunca chama este método. + (void)ppAttributeList; + return NULL; +#else DWFContentPresentationModelViewNode* pElement = _build( pElement, ppAttributeList ); return pElement; +#endif } DWFCoordinateSystem* diff --git a/develop/global/src/dwf/presentation/reader/ContentPresentationReader.cpp b/develop/global/src/dwf/presentation/reader/ContentPresentationReader.cpp index 748e4e3..191ac6c 100644 --- a/develop/global/src/dwf/presentation/reader/ContentPresentationReader.cpp +++ b/develop/global/src/dwf/presentation/reader/ContentPresentationReader.cpp @@ -328,7 +328,13 @@ throw() // // Create a new Presentation Model View Node object. // +#ifdef DWFTK_SEM_W3D + // Alteração byn: sem o w3dtk (3D), o nó de vista 3D lê-se como um nó de referência + // (a classe de que deriva), sem câmara, matrizes, cores nem cortes. + DWFContentPresentationReferenceNode *pModelViewNode = _pElementBuilder->buildContentPresentationReferenceNode( ppAttributeList ); +#else DWFContentPresentationModelViewNode *pModelViewNode = _pElementBuilder->buildContentPresentationModelViewNode( ppAttributeList ); +#endif // // Add it to the active node container. @@ -339,6 +345,7 @@ throw() _pCurrentNodeContainer = dynamic_cast( _pCurrentNode ); _oNodeContainerStack.push_back(_pCurrentNodeContainer); } +#ifndef DWFTK_SEM_W3D // Alteração byn: os elementos 3D do nó de vista 3D ficam por ler else if (DWFCORE_COMPARE_ASCII_STRINGS(zName, DWFXML::kzElement_ModelScene) == 0) { @@ -904,6 +911,7 @@ throw() } } } +#endif break; } @@ -1109,11 +1117,13 @@ throw() if ((_nProviderFlags & eProvideModelViewNodes) && DWFCORE_COMPARE_ASCII_STRINGS(zName, DWFXML::kzElement_ModelViewNode) == 0) { +#ifndef DWFTK_SEM_W3D // Alteração byn: ver notifyStartElement DWFContentPresentationModelViewNode *pModelViewNode = dynamic_cast(_pCurrentNode); if(pModelViewNode != NULL) { pModelViewNode->close(); } +#endif // // When the Node ends, re-establish any pre-existing node container. @@ -1128,11 +1138,20 @@ throw() // if (_pCurrentNode) { +#ifdef DWFTK_SEM_W3D + // Alteração byn: lido como nó de referência (ver notifyStartElement). + DWFContentPresentationReferenceNode* pReferenceNode = dynamic_cast(_pCurrentNode); + if (pReferenceNode) + { + _pCurrentNode = _provideReferenceNode( pReferenceNode ); + } +#else DWFContentPresentationModelViewNode* pNewModelViewNode = dynamic_cast(_pCurrentNode); if (pNewModelViewNode) { _pCurrentNode = _provideModelViewNode( pNewModelViewNode ); } +#endif _pCurrentNodeContainer->addNode(_pCurrentNode); } @@ -1144,6 +1163,7 @@ throw() _pCurrentNodeContainer = NULL; } } +#ifndef DWFTK_SEM_W3D // Alteração byn: ver notifyStartElement if (DWFCORE_COMPARE_ASCII_STRINGS(zName, DWFXML::kzElement_ModelScene) == 0) { } @@ -1250,6 +1270,7 @@ throw() if (DWFCORE_COMPARE_ASCII_STRINGS(zName, DWFXML::kzElement_AttributeUnlock) == 0) { } +#endif break; } }