Notes about using xrefs
March 02, 2017
Xref (short for eXternal REFerence) is, as the name suggests, a reference to an external .dwg file. External references are often used to split big files into smaller ones; the smaller files are referenced by one “host” file, and the smaller files can be processed by different engineers independently and simultaneously. Other uses of external references are to make block libraries or underlays.
In the host database, an xref is represented as a block with a name corresponding to the name of the referenced file (without a .dwg file extension). An xref block does not contain entities from the xref database; instead it returns an iterator to the xref model space in OdDbBlockTableRecord::newIterator.
Xref management functions are bundled in two namespaces: OdDbXRefMan and OdDbXRefManExt. The most important function is OdDbXRefMan::load(OdDbBlockTableRecord*). It loads the external reference attached to the given block. The loading process is rather complicated. First, the saved xref path (OdDbBlockTableRecord::pathname()) is passed to OdDbHostAppServices::findFile() with a hint FindFileHint::kXRefDrawing findFile() that should return a resolved path, which will be passed to OdDbHostAppServices::readFile(). If the file was not found, the block xrefStatus() is set to kXrfUnresolved. If the file was found, xref symbol tables are merged into the host database as follows:
- Some symbols, such as blocks, linetypes and dimension styles, are copied to the host tables as is — by reference, they even retain xref tables as their owners. Other symbols, such as layers and text styles, are cloned into the host. Symbol names have xref block names prepended (with ‘|’ as a separator). Cloned symbols keep the reference to the xref block, which can be obtained via OdDbXRefManExt::getSymbolTableRecordXrefBlockId().
- Annotation scales are cloned and have “_XREF” appended to their names.
- Layer states are cloned and have the xref block name and “__” prepended.
- Materials and plot styles are cloned if there are no such objects with the same name in the host.
ID mapping created while cloning is saved in the xref database, and the cloned objects get the “redirected” status, so that opening an object ID of the cloned object (e.g., a layer), will return the corresponding layer from the host database. To get an original object, use OdDbObjectId::convertToRedirectedId() or OdDbObjectId::getNonForwardedHandle(). The reason for this redirection is to make the xref block look more native in the host database (also for list scripts). This way, when asking for a layer of some entity from the xref block you get a layer from the host database, which is what is usually expected.
The xref database also keeps a reference to the host xref block, accessible via OdDbDatabase::xrefBlockId().
To temporarily restore an xref database to its original state (e.g., in REFEDIT-like scenarios), use the OdDbDatabase::restoreOriginalXrefSymbols() function. OdDbDatabase::restoreForwardingXrefSymbols() does the opposite.
When referencing a database which in turn references other files (nested xrefs), you have an option to skip these nested files using the “overlay” xref status: OdDbXRefMan::setOverlaid.
The OdDbXrefGraph::findCycles() function is used while loading to detect circular references of the nested xrefs. Use OdDbXrefGraph::getFrom to inspect nested xref graph structure.
To create a new xref block, use OdDbXRefManExt::addNewXRefDefBlock(). After that, either explicitly load it via OdDbXRefMan::load() or it will be automatically loaded when the block insert is rendered. (Yes, you will also need an insert, just like with the normal block.)
After saving, the path to the xref file is saved in an OdDbBlockBegin object in the xref block. Layers and other cloned symbols are saved with the host database if the “VISRETAIN” database variable is true. Blocks and symbols copied without cloning are, of course, never saved with the host.
The external reference is one of the dependencies maintained by the OdFileDependencyManager.
OdDbXRefMan::detach erases all traces of the xref from the host.
OdDbXRefMan::bind merges the xref into the host, cloning all the missing data (model space contents) and changing symbols by mangling to “xref$n$name” from the usual “xref|name”. It converts the xref block to a normal block, and releases the xref database. Bind is somewhat like OdDbXRefMan::detach() followed by OdDbDatabase::insert(). Bind is irreversible; you won’t be able to detach the bound drawing because it is not “attached” anymore.