/////////////////////////////////////////////////////////////////////////////// // 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. /////////////////////////////////////////////////////////////////////////////// // ODA SDK includes #include #include #include // System includes #include #include // SDAI includes #include #include #include // IFC SDK includes #include #include enum AppResult { arOk = 0, arIncorrectUsage, arFileOpenError, arEmptySectionHeader, arUnsupportedSchema, arEmptyModel, arOdError, arUnexpectedError }; unsigned int inverse_aggregates = 0; unsigned int empty_inverse_aggregates = 0; void dumpEntity(OdIfc::OdIfcInstance *inst, OdDAI::Entity *entityDef) { if (inst == nullptr) return; /* OdDAIObjectId instId = inst->id(); if (instId.getHandle() == (OdUInt64)10) { throw OdError("Just stop"); } */ const OdDAI::List& superEntities = entityDef->supertypes(); OdDAI::ConstIteratorPtr it_super = superEntities.createConstIterator(); for (; it_super->next();) { OdDAI::Entity* pEntity; it_super->getCurrentMember() >> pEntity; dumpEntity(inst, pEntity); } OdString entName = entityDef->name(); OdString strAbstract = entityDef->instantiable() ? OD_T("INSTANTIABLE") : OD_T("ABSTRACT"); odPrintConsoleString(OD_T("\t%s %s\n"), strAbstract.c_str(), entName.c_str()); for (OdDAI::ConstIteratorPtr it = entityDef->attributes().createConstIterator(); it->next();) { OdDAI::AttributePtr pAttr; it->getCurrentMember() >> pAttr; OdString strAttrType = OD_T("UNKNOWN"); switch (pAttr->getAttributeType()) { case OdDAI::AttributeType::Explicit: { strAttrType = OD_T("EXPLICIT"); } break; case OdDAI::AttributeType::Inverse: { strAttrType = OD_T("INVERSE"); } break; case OdDAI::AttributeType::Derived: { strAttrType = OD_T("DERIVED"); } break; } const OdAnsiString &attrName = pAttr->name(); odPrintConsoleString(OD_T("\t\t%s .%hs"), strAttrType.c_str(), attrName.c_str()); // #define _DUMP_DERIVED_ATTRIBUTES #ifndef _DUMP_DERIVED_ATTRIBUTES if (pAttr->getAttributeType() == OdDAI::AttributeType::Derived) { odPrintConsoleString(OD_T(" = \n")); continue; } #endif OdRxValue val; #ifndef _DUMP_DERIVED_ATTRIBUTES val = inst->getAttr(attrName); #else val = pDerived.isNull() ? inst->getAttr(attrName) : inst->getDerivedAttr(attrName); #endif bool unset = false; const OdRxValueType &vt = val.type(); if (vt == OdRxValueType::Desc::value()) { OdDAIObjectId idVal; if (val >> idVal) { unset = OdDAI::Utils::isUnset(idVal); if (!unset) { OdUInt64 int64 = idVal.getHandle(); odPrintConsoleString(OD_T(" = #%d"), int64); } } } else if (vt == OdRxValueType::Desc::value()) { OdDAI::CompressedGUID guidVal; if (val >> guidVal) { unset = OdDAI::Utils::isUnset(guidVal); if (!unset) { odPrintConsoleString(OD_T(" = '%s'"), OdString(guidVal).c_str()); } } } else if (vt == OdRxValueType::Desc::value()) { int intVal; if (val >> intVal) { unset = OdDAI::Utils::isUnset(intVal); if (!unset) odPrintConsoleString(OD_T(" = %i"), intVal); } } else if (vt == OdRxValueType::Desc::value()) { double dblVal; if (val >> dblVal) { unset = OdDAI::Utils::isUnset(dblVal); if (!unset) odPrintConsoleString(OD_T(" = %.6f"), dblVal); } } else if (vt == OdRxValueType::Desc::value()) { const char *strVal; if (val >> strVal) { unset = OdDAI::Utils::isUnset(strVal); if (!unset) { OdString strW = strVal; odPrintConsoleString(OD_T(" = '%hs'"), strW.c_str()); } } } else if (vt.isEnum()) { const char *strVal = nullptr; if (val >> strVal) { unset = (strVal == nullptr); if (!unset) { odPrintConsoleString(OD_T(" = .%hs."), strVal); } } // or: //OdDAI::EnumValueInfo enumVal; //if (val >> enumVal) //{ // unset = (enumVal.value == NULL); // if (!unset) // { // odPrintConsoleString(L" = .%hs.", enumVal.value); // } //} } else if (vt.isSelect()) { OdTCKind selectKind; if (val >> selectKind) { unset = (selectKind == tkNull); if (!unset) { OdString typePath = val.typePath(); odPrintConsoleString(OD_T(" = %s("), typePath.c_str()); switch (selectKind) { case tkObjectId: // An object identifier's value. { OdDAIObjectId idVal; if (val >> idVal) { OdUInt64 int64; int64 = idVal.getHandle(); odPrintConsoleString(OD_T("#%d"), int64); } break; } case tkLong: // An unsigned 32-bit integer value. { int intVal; if (val >> intVal) odPrintConsoleString(OD_T("%i"), intVal); break; } case tkBoolean: // A boolean value. { bool boolVal; if (val >> boolVal) { OdString strBool; strBool = boolVal ? OD_T("true") : OD_T("false"); odPrintConsoleString(OD_T("%s"), strBool.c_str()); } break; } case tkDouble: // A double value. { double dVal; if (val >> dVal) odPrintConsoleString(OD_T("%.6f"), dVal); break; } case tkBinary: // A binary value. case tkLogical: // A logical value. break; case tkString: { OdAnsiString strVal; if (val >> strVal) { OdString wcsVal = strVal; odPrintConsoleString(OD_T("'%s'"), wcsVal.c_str()); } break; } case tkSequence: { odPrintConsoleString(OD_T("TODO: kSequence not implemented yet")); break; } default: odPrintConsoleString(OD_T("Not implemented yet.")); } odPrintConsoleString(OD_T(")")); } } } else //if (vt == OdRxValueType::Desc::value() // || vt == OdRxValueType::Desc* >::value()) if (vt.isAggregate()) { OdDAI::Aggr *aggr = NULL; if (val >> aggr) { unset = aggr->isNil(); if (!unset) { odPrintConsoleString(OD_T(" = ")); OdDAI::AggrType aggrType = aggr->aggrType(); switch (aggrType) { case OdDAI::aggrTypeArray: odPrintConsoleString(OD_T("ARRAY")); break; case OdDAI::aggrTypeBag: odPrintConsoleString(OD_T("BAG")); break; case OdDAI::aggrTypeList: odPrintConsoleString(OD_T("LIST")); break; case OdDAI::aggrTypeSet: odPrintConsoleString(OD_T("SET")); break; } odPrintConsoleString(OD_T("[")); OdDAI::IteratorPtr iterator = aggr->createIterator(); for (iterator->beginning(); iterator->next();) { OdRxValue val = iterator->getCurrentMember(); OdString strVal = val.toString(); odPrintConsoleString(OD_T(" %s "), strVal.c_str()); } odPrintConsoleString(OD_T("]")); } } } else { // // Deprecated: OdArray instead of Aggregate // OdDAIObjectIds idsVal; if (val >> idsVal) { ++inverse_aggregates; unset = (idsVal.size() == 0); if (!unset) { OdUInt64 int64; int64 = idsVal[0].getHandle(); odPrintConsoleString(OD_T(" = (#%d"), int64); for (unsigned int i = 1; i < idsVal.size(); ++i) { int64 = idsVal[i].getHandle(); odPrintConsoleString(OD_T(", #%d"), int64); } odPrintConsoleString(OD_T(")")); } else ++empty_inverse_aggregates; } } if (unset) odPrintConsoleString(OD_T(" = UNSET")); odPrintConsoleString(OD_T("\n")); } } int dumpFile(OdIfcHostAppServices &svcs, const OdString fileName) { odPrintConsoleString(OD_T("\nDump %s.\n"), fileName.c_str()); OdIfcFilePtr pFile = svcs.createDatabase(); OdResult res = pFile->readFile(fileName); if (res == eOk) { odPrintConsoleString(OD_T("\nFile opened successfully.\n")); } else { odPrintConsoleString(OD_T("\nFile open error.")); return arFileOpenError; } OdDAI::OdHeaderSectionPtr headerSection = pFile->getHeaderSection(); if (headerSection.isNull()) { odPrintConsoleString(OD_T("\nError getting header section from the %s file!")); return arEmptySectionHeader; } OdSmartPtr pFileSchema = headerSection->getEntityByType(OdDAI::kFileSchema); OdAnsiStringArray schemaIdentifiers; pFileSchema->getSchemaIdentifiers(schemaIdentifiers); //or: pFileSchema->getAttr("schema_identifiers") >> schemaIdentifiers; OdString schemaName = schemaIdentifiers[0]; if (!schemaName.iCompare(OD_T("IFC2X3")) && !schemaName.iCompare(OD_T("IFC4"))) { odPrintConsoleString(OD_T("\nUnsupported file schema: %s!"), schemaName.c_str()); return arUnsupportedSchema; } OdIfcModelPtr pModel = pFile->getModel(); if (pModel.isNull()) { odPrintConsoleString(OD_T("\nAn unexpected error occurred while opening the IFC file!")); return arEmptyModel; } odPrintConsoleString(OD_T("Model entities (schema name is \"%s\"): \n"), schemaName.c_str()); OdDAI::InstanceIteratorPtr it = pModel->newIterator(); OdIfc::OdIfcInstancePtr pInst; unsigned int entIdx; for (entIdx = 0; !it->done(); it->step(), ++entIdx) { // Opens an instance pInst = it->id().openObject(); if (!pInst.isNull()) { OdUInt64 id; pInst->getAttr("_id") >> id; OdString typeNameW = pInst->typeName(); OdDAI::EntityPtr pEntityDef = pInst->getInstanceType(); odPrintConsoleString(OD_T("Entity %d: \n"), entIdx); odPrintConsoleString(OD_T("\tEntity handle (corresponds to the STEP-id) = %d\n"), id); odPrintConsoleString(OD_T("\tEntity type name = %s (enum = %d)\n"), typeNameW.c_str(), pInst->type()); dumpEntity(pInst, pEntityDef); if (pInst->isKindOf("ifcroot")) odPrintConsoleString(OD_T("\tDerived from IfcRoot!\n")); } } odPrintConsoleString(OD_T("Found entities: %d\n"), entIdx); odPrintConsoleString(OD_T("Inverse aggregates: %d\n"), inverse_aggregates); odPrintConsoleString(OD_T("Empty inverse aggregates: %d\n"), empty_inverse_aggregates); //Finalize the process, OdIfcFile and underlying header section and Model will be released. return arOk; } #ifndef _TOOLKIT_IN_DLL_ INIT_IFC_STATIC_MODULES_NO_GEOM; #endif int main(int argc, char* argv[]) { setlocale(LC_TIME, ""); // set current user locale (not OD_T("C")), for strftime OdStaticRxObject< MyServices > svcs; // In current documentation <> together // with inner code is empty as it looks as html tag odrxInitialize(&svcs); odIfcInitialize(false /* No CDA */, false /* No geometry calculation needed */); OdArray intArr; int arrSize = sizeof(intArr); int arrBufSize = sizeof(OdArrayBuffer); odPrintConsoleString(OD_T("\nIFC SDK Extract Data Application. Copyright (c) 2025, Open Design Alliance\n")); odPrintConsoleString(OD_T("\nExIfcExtractData application developed using %ls ver %ls"), svcs.product().c_str(), svcs.versionString().c_str()); const OdString noWaitKeyword = OD_T("-noWait"); if (argc < 2 || argc > 3) { odPrintConsoleString(OD_T("\n\nusage: ExIfcExtractData [%s]\n"), noWaitKeyword.c_str()); odPrintConsoleString(OD_T("\n - a full path to the input IFC file\n")); odPrintConsoleString(OD_T("\n[%s] - optional disable \"Press ENTER to continue\" on finish\n"), noWaitKeyword.c_str()); return arIncorrectUsage; } #ifndef _TOOLKIT_IN_DLL_ ODRX_INIT_STATIC_MODULE_MAP(); #endif int result = arOk; bool noWait = false; try { OdString ifcFileName(argv[1]); for (int argIndex = 2; argIndex < argc; ++argIndex) { if (noWaitKeyword == argv[argIndex]) { noWait = true; continue; } } result = dumpFile(svcs, ifcFileName); } catch (OdError& e) { odPrintConsoleString(OD_T("\nError occurred: %ls!"), e.description().c_str()); result = arOdError; } catch (...) { odPrintConsoleString(OD_T("\n\nUnexpected error.")); result = arUnexpectedError; } odIfcUninitialize(); ::odrxUninitialize(); if (!noWait) { odPrintConsoleString(OD_T("\nPress ENTER to continue.\n")); getchar(); } return result; }