1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-06-15 11:44:07 +03:00
occt/src/BinLDrivers/BinLDrivers_DocumentStorageDriver.cxx
asuraven 9f45d35b6b 0031136: Modeling Data - BinXCAF persistence loses normals from triangulation-only Faces
Information about normals are stored in BinOCAF, XmlOCAF, BRep and BBRep (in case of triangulation-only Faces).
Versions of formats have been changed (11 for TDocStd, 4 for BRep Shape and 3 for Binary BRep Shape)
theWithNormals parameter added to BRepTools::Write()
IsWithNormals()/SetWithNormals() function added to BRepTools_ShapeSet
-normals/-noNormals option added to StoreTriangulation DRAW command
-normals/-noNormals option added to writebrep DRAW command
Tests for writing to brep/binary brep/BinXCaf/XmlXCaf added
Test for StoreTriangulation options -normals/-noNormals added
2021-01-20 21:20:43 +03:00

556 lines
18 KiB
C++

// Created on: 2002-10-29
// Created by: Michael SAZONOV
// Copyright (c) 2002-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <BinLDrivers.hxx>
#include <BinLDrivers_DocumentSection.hxx>
#include <BinLDrivers_DocumentStorageDriver.hxx>
#include <BinLDrivers_Marker.hxx>
#include <BinMDF_ADriver.hxx>
#include <BinMDF_ADriverTable.hxx>
#include <BinObjMgt_Persistent.hxx>
#include <CDM_Application.hxx>
#include <CDM_Document.hxx>
#include <Message_Messenger.hxx>
#include <FSD_BinaryFile.hxx>
#include <FSD_FileHeader.hxx>
#include <OSD_OpenFile.hxx>
#include <PCDM_ReadWriter.hxx>
#include <Standard_ErrorHandler.hxx>
#include <Standard_Type.hxx>
#include <Storage_Schema.hxx>
#include <TCollection_AsciiString.hxx>
#include <TCollection_ExtendedString.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <TColStd_ListIteratorOfListOfInteger.hxx>
#include <TColStd_ListOfInteger.hxx>
#include <TDF_AttributeIterator.hxx>
#include <TDF_ChildIterator.hxx>
#include <TDF_Data.hxx>
#include <TDF_Label.hxx>
#include <TDF_Tool.hxx>
#include <TDocStd_Document.hxx>
#include <Message_ProgressScope.hxx>
IMPLEMENT_STANDARD_RTTIEXT(BinLDrivers_DocumentStorageDriver,PCDM_StorageDriver)
#define SHAPESECTION_POS (Standard_CString)"SHAPE_SECTION_POS:"
//=======================================================================
//function : BinLDrivers_DocumentStorageDriver
//purpose : Constructor
//=======================================================================
BinLDrivers_DocumentStorageDriver::BinLDrivers_DocumentStorageDriver ()
{
}
//=======================================================================
//function : Write
//purpose :
//=======================================================================
void BinLDrivers_DocumentStorageDriver::Write
(const Handle(CDM_Document)& theDocument,
const TCollection_ExtendedString& theFileName,
const Message_ProgressRange& theRange)
{
SetIsError(Standard_False);
SetStoreStatus(PCDM_SS_OK);
myFileName = theFileName;
std::ofstream aFileStream;
OSD_OpenStream (aFileStream, theFileName, std::ios::out | std::ios::binary);
if (aFileStream.is_open() && aFileStream.good())
{
Write(theDocument, aFileStream, theRange);
}
else
{
SetIsError (Standard_True);
SetStoreStatus(PCDM_SS_WriteFailure);
}
}
//=======================================================================
//function : Write
//purpose :
//=======================================================================
void BinLDrivers_DocumentStorageDriver::Write (const Handle(CDM_Document)& theDoc,
Standard_OStream& theOStream,
const Message_ProgressRange& theRange)
{
myMsgDriver = theDoc->Application()->MessageDriver();
myMapUnsupported.Clear();
Handle(TDocStd_Document) aDoc =
Handle(TDocStd_Document)::DownCast(theDoc);
if (aDoc.IsNull()) {
SetIsError(Standard_True);
SetStoreStatus(PCDM_SS_Doc_IsNull);
}
else {
// First pass: collect empty labels, assign IDs to the types
if (myDrivers.IsNull())
myDrivers = AttributeDrivers (myMsgDriver);
Handle(TDF_Data) aData = aDoc->GetData();
FirstPass (aData->Root());
if(aDoc->EmptyLabelsSavingMode())
myEmptyLabels.Clear(); //
// 1. Write info section (including types table)
WriteInfoSection (aDoc, theOStream);
myTypesMap.Clear();
if (IsError())
{
SetStoreStatus(PCDM_SS_Info_Section_Error);
return;
}
// 2. Write the Table of Contents of Sections
const TDocStd_FormatVersion aDocVer = aDoc->StorageFormatVersion();
BinLDrivers_VectorOfDocumentSection::Iterator anIterS (mySections);
for (; anIterS.More(); anIterS.Next())
anIterS.ChangeValue().WriteTOC (theOStream, aDocVer);
// Shapes Section is the last one, it indicates the end of the table.
BinLDrivers_DocumentSection aShapesSection (SHAPESECTION_POS,
Standard_False);
aShapesSection.WriteTOC (theOStream, aDocVer);
// 3. Write document contents
// (Storage data to the stream)
myRelocTable.Clear();
myPAtt.Init();
Message_ProgressScope aPS(theRange, "Writing document", 3);
// Write Doc structure
WriteSubTree (aData->Root(), theOStream, aPS.Next()); // Doc is written
if (!aPS.More())
{
SetIsError(Standard_True);
SetStoreStatus(PCDM_SS_UserBreak);
return;
}
// 4. Write Shapes section
WriteShapeSection (aShapesSection, theOStream, aDocVer, aPS.Next());
if (!aPS.More())
{
SetIsError(Standard_True);
SetStoreStatus(PCDM_SS_UserBreak);
return;
}
// Write application-defined sections
for (anIterS.Init (mySections); anIterS.More(); anIterS.Next()) {
BinLDrivers_DocumentSection& aSection = anIterS.ChangeValue();
const Standard_Size aSectionOffset = (Standard_Size) theOStream.tellp();
WriteSection (aSection.Name(), aDoc, theOStream);
aSection.Write (theOStream, aSectionOffset, aDocVer);
}
// End of processing: close structures and check the status
myPAtt.Destroy(); // free buffer
myEmptyLabels.Clear();
myMapUnsupported.Clear();
if (!myRelocTable.Extent()) {
// No objects written
#ifdef OCCT_DEBUG
myMsgDriver->Send ("BinLDrivers_DocumentStorageDriver, no objects written", Message_Info);
#endif
SetIsError(Standard_True);
SetStoreStatus(PCDM_SS_No_Obj);
}
myRelocTable.Clear();
if (!aPS.More())
{
SetIsError(Standard_True);
SetStoreStatus(PCDM_SS_UserBreak);
return;
}
aPS.Next();
if (!theOStream) {
// A problem with the stream
#ifdef OCCT_DEBUG
TCollection_ExtendedString anErrorStr ("BinLDrivers_DocumentStorageDriver, Problem with the file stream, rdstate = ");
myMsgDriver->Send (anErrorStr + (Standard_Integer )theOStream.rdstate(), Message_Info);
#endif
SetIsError(Standard_True);
SetStoreStatus(PCDM_SS_WriteFailure);
}
}
}
//=======================================================================
//function : UnsupportedAttrMsg
//purpose :
//=======================================================================
void BinLDrivers_DocumentStorageDriver::UnsupportedAttrMsg
(const Handle(Standard_Type)& theType)
{
#ifdef OCCT_DEBUG
TCollection_ExtendedString aMsg
("BinDrivers_DocumentStorageDriver: warning: attribute driver for type ");
#endif
if (!myMapUnsupported.Contains(theType)) {
myMapUnsupported.Add(theType);
#ifdef OCCT_DEBUG
myMsgDriver->Send (aMsg + theType->Name() + " not found", Message_Info);
#endif
}
}
//=======================================================================
//function : WriteSubTree
//purpose :
//=======================================================================
void BinLDrivers_DocumentStorageDriver::WriteSubTree
(const TDF_Label& theLabel,
Standard_OStream& theOS,
const Message_ProgressRange& theRange)
{
// Skip empty labels
if (!myEmptyLabels.IsEmpty() && myEmptyLabels.First() == theLabel) {
myEmptyLabels.RemoveFirst();
return;
}
Message_ProgressScope aPS(theRange, "Writing sub tree", 2, true);
// Write label header: tag
Standard_Integer aTag = theLabel.Tag();
#if DO_INVERSE
aTag = InverseInt (aTag);
#endif
theOS.write ((char*)&aTag, sizeof(Standard_Integer));
// Write attributes
TDF_AttributeIterator itAtt (theLabel);
for ( ; itAtt.More() && theOS && aPS.More(); itAtt.Next()) {
const Handle(TDF_Attribute) tAtt = itAtt.Value();
const Handle(Standard_Type)& aType = tAtt->DynamicType();
// Get type ID and driver
Handle(BinMDF_ADriver) aDriver;
const Standard_Integer aTypeId = myDrivers->GetDriver (aType,aDriver);
if (aTypeId > 0) {
// Add source to relocation table
const Standard_Integer anId = myRelocTable.Add (tAtt);
// Create and fill data item
myPAtt.SetTypeId (aTypeId);
myPAtt.SetId (anId);
aDriver->Paste (tAtt, myPAtt, myRelocTable);
// Write data to the stream -->!!!
theOS << myPAtt;
}
#ifdef OCCT_DEBUG
else
UnsupportedAttrMsg (aType);
#endif
}
if (!theOS) {
// Problem with the stream
return;
}
if (!aPS.More())
{
SetIsError(Standard_True);
SetStoreStatus(PCDM_SS_UserBreak);
return;
}
// Write the end attributes list marker
BinLDrivers_Marker anEndAttr = BinLDrivers_ENDATTRLIST;
#if DO_INVERSE
anEndAttr = (BinLDrivers_Marker) InverseInt (anEndAttr);
#endif
theOS.write ((char*)&anEndAttr, sizeof(anEndAttr));
// Process sub-labels
TDF_ChildIterator itChld (theLabel);
for ( ; itChld.More(); itChld.Next())
{
const TDF_Label& aChildLab = itChld.Value();
if (!aPS.More())
{
SetIsError(Standard_True);
SetStoreStatus(PCDM_SS_UserBreak);
return;
}
WriteSubTree (aChildLab, theOS, aPS.Next());
}
// Write the end label marker
BinLDrivers_Marker anEndLabel = BinLDrivers_ENDLABEL;
#if DO_INVERSE
anEndLabel = (BinLDrivers_Marker) InverseInt (anEndLabel);
#endif
theOS.write ((char*)&anEndLabel, sizeof(anEndLabel));
}
//=======================================================================
//function : AttributeDrivers
//purpose :
//=======================================================================
Handle(BinMDF_ADriverTable) BinLDrivers_DocumentStorageDriver::AttributeDrivers
(const Handle(Message_Messenger)& theMessageDriver)
{
return BinLDrivers::AttributeDrivers (theMessageDriver);
}
//=======================================================================
//function : FirstPassSubTree
//purpose :
//=======================================================================
Standard_Boolean BinLDrivers_DocumentStorageDriver::FirstPassSubTree
(const TDF_Label& L,
TDF_LabelList& ListOfEmptyL)
{
// are there writable attributes on L ?
Standard_Boolean hasAttr = Standard_False;
TDF_AttributeIterator itAtt (L);
for ( ; itAtt.More(); itAtt.Next()) {
const Handle(Standard_Type)& aType = itAtt.Value()->DynamicType();
Handle(BinMDF_ADriver) aDriver;
// do not rely on a value returned by GetDriver here, because
// the IDs have not yet been assigned to the types
myDrivers->GetDriver (aType, aDriver);
if (!aDriver.IsNull()) {
hasAttr = Standard_True;
myTypesMap.Add (aType);
}
#ifdef OCCT_DEBUG
else
UnsupportedAttrMsg (aType);
#endif
}
// are there writable attributes on sub-labels ?
Standard_Boolean hasChildAttr = Standard_False;
TDF_LabelList emptyChildrenList;
TDF_ChildIterator itChld (L);
for ( ; itChld.More(); itChld.Next())
{
if (FirstPassSubTree (itChld.Value(), emptyChildrenList))
emptyChildrenList.Append( itChld.Value() );
else
hasChildAttr = Standard_True;
}
Standard_Boolean isEmpty = !(hasAttr || hasChildAttr);
if (!isEmpty)
ListOfEmptyL.Append( emptyChildrenList );
return isEmpty;
}
//=======================================================================
//function : FirstPass
//purpose :
//=======================================================================
void BinLDrivers_DocumentStorageDriver::FirstPass
(const TDF_Label& theRoot)
{
myTypesMap.Clear();
myEmptyLabels.Clear();
if (FirstPassSubTree( theRoot, myEmptyLabels))
myEmptyLabels.Append( theRoot );
myDrivers->AssignIds (myTypesMap);
}
//=======================================================================
//function : WriteInfoSection
//purpose : Write info section using FSD_BinaryFile driver
//=======================================================================
#define START_TYPES "START_TYPES"
#define END_TYPES "END_TYPES"
void BinLDrivers_DocumentStorageDriver::WriteInfoSection
(const Handle(CDM_Document)& theDoc,
Standard_OStream& theOStream)
{
// Magic number
theOStream.write (FSD_BinaryFile::MagicNumber(), strlen(FSD_BinaryFile::MagicNumber()));
FSD_FileHeader aHeader;
{
aHeader.testindian = -1;
aHeader.binfo = -1;
aHeader.einfo = -1;
aHeader.bcomment = -1;
aHeader.ecomment = -1;
aHeader.btype = -1;
aHeader.etype = -1;
aHeader.broot = -1;
aHeader.eroot = -1;
aHeader.bref = -1;
aHeader.eref = -1;
aHeader.bdata = -1;
aHeader.edata = -1;
}
// aHeader.testindian
{
union {
char ti2[4];
Standard_Integer aResult;
} aWrapUnion;
aWrapUnion.ti2[0] = 1;
aWrapUnion.ti2[1] = 2;
aWrapUnion.ti2[2] = 3;
aWrapUnion.ti2[3] = 4;
aHeader.testindian = aWrapUnion.aResult;
}
// info section
aHeader.binfo = (Standard_Integer)theOStream.tellp();
// header section
aHeader.einfo = aHeader.binfo + FSD_BinaryFile::WriteHeader (theOStream, aHeader, Standard_True);
// add format
Handle(Storage_Data) theData = new Storage_Data;
PCDM_ReadWriter::WriteFileFormat (theData, theDoc);
PCDM_ReadWriter::Writer()->WriteReferenceCounter (theData, theDoc);
PCDM_ReadWriter::Writer()->WriteReferences (theData, theDoc, myFileName);
PCDM_ReadWriter::Writer()->WriteExtensions (theData, theDoc);
PCDM_ReadWriter::Writer()->WriteVersion (theData, theDoc);
// add the types table
theData->AddToUserInfo(START_TYPES);
for (Standard_Integer i = 1; i <= myTypesMap.Extent(); i++)
{
Handle(BinMDF_ADriver) aDriver = myDrivers->GetDriver(i);
if (!aDriver.IsNull())
{
const TCollection_AsciiString& aTypeName = aDriver->TypeName();
theData->AddToUserInfo (aTypeName);
}
}
theData->AddToUserInfo(END_TYPES);
Standard_Integer aObjNb = 1;
Standard_Integer aShemaVer = 1;
// Store the name and version of the application that has created the
// document.
theData->SetApplicationVersion(theDoc->Application()->Version());
theData->SetApplicationName(theDoc->Application()->Name());
Handle(TDocStd_Document) aDoc = Handle(TDocStd_Document)::DownCast(theDoc);
const Standard_Integer aDocVer = aDoc->StorageFormatVersion();
aHeader.einfo += FSD_BinaryFile::WriteInfo (theOStream,
aObjNb,
aDocVer,
Storage_Schema::ICreationDate(),
"", // schema name
aShemaVer,
theData->ApplicationName(),
theData->ApplicationVersion(),
theData->DataType(),
theData->UserInfo(),
Standard_True); // only count the size of the section
// calculate comment section
TColStd_SequenceOfExtendedString aComments;
theDoc->Comments(aComments);
for (Standard_Integer i = 1; i <= aComments.Length(); i++)
{
theData->AddToComments (aComments(i));
}
aHeader.bcomment = aHeader.einfo;
aHeader.ecomment = aHeader.bcomment + FSD_BinaryFile::WriteComment(theOStream, theData->Comments(), Standard_True);
aHeader.edata = aHeader.ecomment;
// write header information
FSD_BinaryFile::WriteHeader (theOStream, aHeader);
// write info section
FSD_BinaryFile::WriteInfo (theOStream,
aObjNb,
aDocVer,
Storage_Schema::ICreationDate(),
"", // schema name
aShemaVer,
theData->ApplicationName(),
theData->ApplicationVersion(),
theData->DataType(),
theData->UserInfo());
// write the comments
FSD_BinaryFile::WriteComment(theOStream, theData->Comments());
}
//=======================================================================
//function : AddSection
//purpose :
//=======================================================================
void BinLDrivers_DocumentStorageDriver::AddSection
(const TCollection_AsciiString& theName,
const Standard_Boolean isPostRead)
{
mySections.Append (BinLDrivers_DocumentSection (theName, isPostRead));
}
//=======================================================================
//function : WriteSection
//purpose :
//=======================================================================
void BinLDrivers_DocumentStorageDriver::WriteSection
(const TCollection_AsciiString& /*theName*/,
const Handle(CDM_Document)& /*theDocument*/,
Standard_OStream& /*theOS*/)
{
// empty; should be redefined in subclasses
}
//=======================================================================
//function : WriteShapeSection
//purpose : defines WriteShapeSection
//=======================================================================
void BinLDrivers_DocumentStorageDriver::WriteShapeSection
(BinLDrivers_DocumentSection& theSection,
Standard_OStream& theOS,
const TDocStd_FormatVersion theDocVer,
const Message_ProgressRange& /*theRange*/)
{
const Standard_Size aShapesSectionOffset = (Standard_Size) theOS.tellp();
theSection.Write (theOS, aShapesSectionOffset, theDocVer);
}