/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #define STL_USING_IOSTREAM #include "OdaSTL.h" #define STD(a) std:: a #include "DbFDumper.h" #include "toString.h" #define _T(x) L##x void DbFDumper::tokenize(OdDbObjectIdArray& outarr, const OdString& input, const OdChar& delim, bool remap) { if (input.isEmpty()) return; const OdChar *pbuf = input.c_str(); int npos(0), nprevpos(0), nlen = input.getLength(); while (npos <= nlen) { if (pbuf[npos] == delim || pbuf[npos] == 0) { if (npos != nprevpos) { // skip empty strings OdString sHandle(OdString(pbuf + nprevpos, npos - nprevpos)); OdDbHandle h(sHandle); if(h.isNull()) { if(remap) remapHandle(h); outarr.push_back(m_pDb->objectId()); } else { OdDbObjectId id = m_pDb->getOdDbObjectId(h); if(id.isNull()) odPrintConsoleString(L"Invalid handle specified in option: %s\n", sHandle.c_str()); else { if(remap) remapHandle(h); outarr.push_back(id); } } } nprevpos = npos + 1; } ++npos; } } OdString DbFDumper::objectIdAndClassName(const OdDbObject* pObj) { if (pObj) { OdDbHandle h = pObj->objectId().getHandle(); return OdString().format(_T("%02I64X : < %ls >"), OdUInt64(remapHandle(h)), pObj->isA()->name().c_str() ); } return OdString(_T("00 : < >")); } OdString DbFDumper::objectIdAndClassName(OdDbObjectId id) { return objectIdAndClassName(id.openObject()); } DbFDumper::DbFDumper() : m_pDb(nullptr) , m_indent(0) , m_numDumpedObjects(0) , m_nEmbeddedSubobjectFollowState(0) , m_hasSchema(false) , m_savedAssertFunc(nullptr) , m_dumpRefs(false) , m_remap(false) { } void DbFDumper::fdump(OdDbDatabase* pDb, const OdString& sset, const OdString& blist, bool dumpRefs, bool remap) { m_pDb = pDb; m_numDumpedObjects = 0; m_remaphash.clear(); m_remaphash.insert(std::pair(0,0)); m_remap = remap; OdDbObjectIdArray blstids; tokenize(blstids, blist, L',', false); for (OdUInt32 i = 0; i < blstids.size(); ++i) { m_blist.insert(blstids[i]); } if(sset.isEmpty()) { // dump all m_dumpRefs = true; // forced ::odPrintConsoleString(L"Dump in ODA format all objects in drawing.\n\n"); fdumpObject(pDb->objectId()); dumpReferences(); } else { // dump specified only m_dumpRefs = dumpRefs; ::odPrintConsoleString(L"Dump in ODA format selected objects: %s\n\n", sset.c_str()); OdDbObjectIdArray ssids; tokenize(ssids, sset, L',', true); for(OdUInt32 i=0; i handles(OdUInt32(m_remaphash.size()), 1); handles.resize(OdUInt32(m_remaphash.size())); auto it = m_remaphash.begin(), end = m_remaphash.end(); for(; it!=end; ++it) { handles[static_cast(it->second)] = it->first; } for(OdUInt32 i=1; i\n", i, handles[i].ascii().c_str(), database()->getOdDbObjectId(handles[i]).safeOpenObject(OdDb::kForRead, true)->isA()->name().c_str()); } ::odPrintConsoleString(L"\n"); } if(m_numDumpedObjects==1) ::odPrintConsoleString(L"1 object was dumped in total\n\n"); else ::odPrintConsoleString(L"%d objects were dumped in total\n\n", m_numDumpedObjects); } void DbFDumper::dumpReferences() { while (!m_refQueue.empty()) { fdumpObject(m_refQueue.front()); m_refQueue.pop(); } } void DbFDumper::listDwgFields(const OdDbObject* obj) { seekObjectSchema(obj); // substituteAssertFunc(); try { obj->dwgOutFields(this); // restoreAssertFunc(); } catch (const OdError& e) { ::odPrintConsoleString(e.description()); ::odPrintConsoleString(L"\n"); } /* catch (...) { restoreAssertFunc(); throw; } */ } void DbFDumper::fdumpObject(const OdDbObjectId& id, int indent) { if(!m_blist.empty() && m_blist.find(id)!= m_blist.end()) // check black list return; m_blist.insert(id); // dump only once m_pDb = id.database(); /**********************************************************************/ /* Get a SmartPointer to the object */ /**********************************************************************/ OdDbObjectPtr pObject = id.openObject(); if (pObject.isNull()) { writeLine(indent, id.getHandle().ascii(), L"*Erased*"); return; } ++m_numDumpedObjects; m_indent = indent = 0; /**********************************************************************/ /* Dump object's handle */ /**********************************************************************/ writeLine(5, _T("HANDLE"), remapHandle(id.getHandle()).ascii()); /**********************************************************************/ /* Dump object's class name */ /**********************************************************************/ writeLine(5, _T("CLASS"), OdString().format(_T("< %ls >"), pObject->isA()->name().c_str()) ); /********************************************************************/ /* Dump the object */ /********************************************************************/ listDwgFields(pObject); /********************************************************************/ /* Dump Xrecord Data expanded to set of group-codes */ /********************************************************************/ if (pObject->isKindOf(OdDbXrecord::desc())) { OdDbXrecordPtr pXRec = pObject; dumpResBuf(pXRec->rbChain(), L"XRecord Data", indent); } /********************************************************************/ /* Dump Object's XData */ /********************************************************************/ dumpXdata(pObject->xData(), indent); writeLine(); } void DbFDumper::insertSubclassMarkers(OdString& /*curFieldName*/) { OdString curSubclass = m_pSchemaIterator->currentSubClass(); OdString curSubobject = m_pSchemaIterator->currentSubObject(); OdString curSubobjectName = m_pSchemaIterator->currentSubObjectName(); bool atSubclass = false; if (m_subclass != curSubclass) { atSubclass = true; m_subclass = curSubclass; writeLine(m_indent, L"........ SUBCLASS", "< " + m_subclass + L" >"); } if (m_subobject != curSubobject || m_subobjectName != curSubobjectName) { if (m_subobject.isEmpty() || m_subobjectName != curSubobjectName) { m_subobjectName = curSubobjectName; writeLine(m_indent, L". . . . . " + curSubobjectName, L"{ " + curSubobject + L" }"); } else if (!atSubclass && curSubobject.isEmpty() && !m_subobject.isEmpty()) { writeLine(m_indent, OdString::kEmpty, L"."); } m_subobject = curSubobject; } // if (!subobject.isEmpty()) // curFieldName = OdString("-> ") + curFieldName; } OdDbHandle DbFDumper::remapHandle(OdDbHandle h) { if(!m_remap || h.isNull()) return h; auto f = m_remaphash.find(h); if(f!= m_remaphash.end()) return f->second; OdDbHandle m = (OdUInt64)m_remaphash.size(); m_remaphash.insert(std::pair(h, m)); return m; } void DbFDumper::wrBool(bool b) { writeLine(m_indent, _T("Bool ") + seekFieldGetName((OdInt64)b), b ? _T("true") : _T("false")); } void DbFDumper::wrString(const OdString &string) { writeLine(m_indent, _T("String ") + seekFieldGetName(string), OdString().format(_T("\"%s\""), string.c_str())); } void DbFDumper::wrBytes(const void* /*buffer*/, OdUInt32 nLen) { OdString str; str.format(_T("(%i) { ... }"), nLen); writeLine(m_indent, _T("Binary ") + seekFieldGetName_onBinaryChunk(), str); } void DbFDumper::wrInt8(OdInt8 val) { OdString str; if(val >= 0 && val < 10) str.format(_T("%i"), int(val)); else str.format(_T("%i : %02X"), int(val), int(OdUInt8(val))); writeLine(m_indent, _T("Int8 ") + seekFieldGetName((OdInt64)val), str); } void DbFDumper::wrUInt8(OdUInt8 val) { OdString str; if(val<10) str.format(_T("%u"), int(val)); else str.format(_T("%u : %02X"), int(val), int(OdUInt8(val))); writeLine(m_indent, _T("UInt8 ") + seekFieldGetName((OdInt64)val), str); } void DbFDumper::wrInt16(OdInt16 val) { OdString str; if (val >= 0 && val < 10) str.format(_T("%i"), int(val)); else str.format(_T("%i : %04X"), int(val), int(OdUInt16(val))); writeLine(m_indent, _T("Int16 ") + seekFieldGetName((OdInt64)val), str); } void DbFDumper::wrInt32(OdInt32 val) { OdString str; if (val >= 0 && val < 10) str.format(_T("%li"), val); else str.format(_T("%li : %08X"), val, val); writeLine(m_indent, _T("Int32 ") + seekFieldGetName((OdInt64)val), str); } void DbFDumper::wrInt64(OdInt64 val) { OdString str; if (val >= 0 && val < 10) str.format(_T("%I64i"), val); else str.format(_T("%I64i : %02I64X"), val, val); writeLine(m_indent, _T("Int64 ") + seekFieldGetName(val), str); } void DbFDumper::wrDouble(double val) { OdString str; str.format(_T("%g"), val); if(str.getLength()==1) str.format(_T("%.1f"), val); writeLine(m_indent, _T("double ") + seekFieldGetName(val), str); } void DbFDumper::wrDbHandle(const OdDbHandle& val) { writeLine(m_indent, _T("Handle ") + seekFieldGetName((OdInt64)val), val.ascii()); } void DbFDumper::wrSoftOwnershipId(const OdDbObjectId& id) { writeLine(m_indent, _T("SoftOwn ") + seekFieldGetName(((OdInt64)id.getHandle())), objectIdAndClassName(id)); if (m_dumpRefs && !id.isErased() && m_dumped.find(id) == m_dumped.end()) { m_refQueue.push(id); m_dumped.insert(id); } } void DbFDumper::wrHardOwnershipId(const OdDbObjectId& id) { writeLine(m_indent, _T("HardOwn ") + seekFieldGetName(((OdInt64)id.getHandle())), objectIdAndClassName(id)); if (m_dumpRefs && !id.isErased() && m_dumped.find(id) == m_dumped.end()) { m_refQueue.push(id); m_dumped.insert(id); } } void DbFDumper::wrSoftPointerId(const OdDbObjectId& id) { writeLine(m_indent, _T("SoftPtr ") + seekFieldGetName(((OdInt64)id.getHandle())), objectIdAndClassName(id)); /* if (m_dumpRefs && !id.isErased() && m_dumped.find(id) == m_dumped.end()) { m_refQueue.push(id); m_dumped.insert(id); } */ } void DbFDumper::wrHardPointerId(const OdDbObjectId& id) { writeLine(m_indent, _T("HardPtr ") + seekFieldGetName(((OdInt64)id.getHandle())), objectIdAndClassName(id)); if (m_dumpRefs && !id.isErased() && m_dumped.find(id) == m_dumped.end()) { m_refQueue.push(id); m_dumped.insert(id); } } void DbFDumper::wrPoint2d(const OdGePoint2d& pt) { OdString str, format, format1; format = _T("%g"); format1 = "(" + format + _T(", ") + format + ")"; str.format(format1.c_str(), pt.x, pt.y); writeLine(m_indent, _T("Point2d ") + seekFieldGetName(pt.x, pt.y), str); } void DbFDumper::wrPoint3d(const OdGePoint3d& pt) { OdString str, format, format1; format = _T("%g"); format1 = "(" + format + _T(", ") + format + _T(", ") + format + ")"; str.format(format1.c_str(), pt.x, pt.y, pt.z); writeLine(m_indent, _T("Point3d ") + seekFieldGetName(pt.x, pt.y, pt.z), str); } void DbFDumper::wrVector2d(const OdGeVector2d& vec) { OdString str, format, format1; format = _T("%g"); format1 = "(" + format + _T(", ") + format + ")"; str.format(format1.c_str(), vec.x, vec.y); writeLine(m_indent, _T("Vector2d ") + seekFieldGetName(vec.x, vec.y), str); } void DbFDumper::wrVector3d(const OdGeVector3d& vec) { OdString str, format, format1; format = _T("%g"); format1 = "(" + format + _T(", ") + format + _T(", ") + format + ")"; str.format(format1.c_str(), vec.x, vec.y, vec.z); writeLine(m_indent, _T("Vector3d ") + seekFieldGetName(vec.x, vec.y, vec.z), str); } void DbFDumper::wrScale3d(const OdGeScale3d& point) { OdString str, format, format1; format = _T("%g"); format1 = "(" + format + _T(", ") + format + _T(", ") + format + ")"; str.format(format1.c_str(), point.sx, point.sy, point.sz); writeLine(m_indent, _T("Scale3d ") + seekFieldGetName(point.sx, point.sy, point.sz), str); } bool DbFDumper::seekObjectSchema(const OdDbObject* pObj) { if (pObj) { if (m_pSchemaIterator.isNull()) m_pSchemaIterator = ::odrxSafeCreateObject(L"OdDbObjectSchemaIterator", L"TD_Tf"); const OdRxClass* c = pObj->isA(); const OdRxClass* d = OdGiDrawable::desc(); do { m_hasSchema = m_pSchemaIterator->seekClass(c, m_pDb->appServices()); c = c->myParent(); } while (!m_hasSchema && c != d); } else { m_hasSchema = false; } m_subclass.empty(); m_subobject.empty(); return m_hasSchema; } void DbFDumper::wrAddress(const void*) { ODA_FAIL(); } OdString DbFDumper::seekFieldGetName() { if (m_hasSchema) { OdString fieldName = m_pSchemaIterator->seekFieldGetName(); insertSubclassMarkers(fieldName); return fieldName; } return OdString::kEmpty; } OdString DbFDumper::seekFieldGetName(const OdString& sValue) { if (m_hasSchema) { OdString fieldName = m_pSchemaIterator->seekFieldGetName(sValue); insertSubclassMarkers(fieldName); return fieldName; } return OdString::kEmpty; } OdString DbFDumper::seekFieldGetName(const OdInt64& data) { if (m_hasSchema) { OdString fieldName = m_pSchemaIterator->seekFieldGetName(data); insertSubclassMarkers(fieldName); return fieldName; } return OdString::kEmpty; } OdString DbFDumper::seekFieldGetName(const double& value) { if (m_hasSchema) { OdString fieldName = m_pSchemaIterator->seekFieldGetName(value); insertSubclassMarkers(fieldName); return fieldName; } return OdString::kEmpty; } OdString DbFDumper::seekFieldGetName(const double& valueX, const double& valueY) { if (m_hasSchema) { OdString fieldName = m_pSchemaIterator->seekFieldGetName(valueX, valueY); insertSubclassMarkers(fieldName); return fieldName; } return OdString::kEmpty; } OdString DbFDumper::seekFieldGetName(const double& valueX, const double& valueY, const double& valueZ) { if (m_hasSchema) { OdString fieldName = m_pSchemaIterator->seekFieldGetName(valueX, valueY, valueZ); insertSubclassMarkers(fieldName); return fieldName; } return OdString::kEmpty; } OdString DbFDumper::seekFieldGetName_onBinaryChunk() { if (m_hasSchema) { OdString fieldName = m_pSchemaIterator->seekFieldGetName_onBinaryChunk(); insertSubclassMarkers(fieldName); return fieldName; } return OdString::kEmpty; } OdUInt64 DbFDumper::tell() const { return 0; } OdAssertFunc DbFDumper::g_savedAssertFunc = 0; void DbFDumper::substituteAssertFunc() { ODA_ASSERT_ONCE(!m_savedAssertFunc); if(!m_savedAssertFunc) g_savedAssertFunc = m_savedAssertFunc = ::odSetAssertFunc(&DbFDumper::myAssert); } void DbFDumper::restoreAssertFunc() { ODA_ASSERT_ONCE(m_savedAssertFunc); if (m_savedAssertFunc) ::odSetAssertFunc(m_savedAssertFunc); g_savedAssertFunc = m_savedAssertFunc = nullptr; } void DbFDumper::myAssert(const char* expr, const char* fileName, int nLine) { if(OdString(fileName).right(23)==L"TfSchemaManagerImpl.cpp" && nLine==237) { ; // suppress assertion dialog box } else { g_savedAssertFunc(expr, fileName, nLine); } } void DbFDumper::wrThickness(double val) { if (dwgVersion() > OdDb::vAC14) { if (OdNonZero(val)) { wrBool(false); wrDouble(val); } else wrBool(true); } else wrDouble(val); } void DbFDumper::wrExtrusion(const OdGeVector3d& v) { bool defaultExtrusion = (v.x == 0.0 && v.y == 0.0 && v.z == 1.0); wrBool(defaultExtrusion); if (!defaultExtrusion) wrVector3d(v); }