refactor: 管道截面统一存 SAT,曲线写路径退役

SectionRegionDwgOutFields 不再 explode 后按曲线写,改为固定写 nLen=0 +
RegionAcisoutDwgOutFields。读取端 nLen==0 本来就识别 SAT 通道,因此
kCurrentVersionNumber 保持 7,新图在老插件上仍可还原。

同时修 SAT 通道自身缺陷:
- RegionAcisoutDwgOutFields:临时文件名加进程号;new char[nLen] 补 +1 并
  清零;检查短读,短读或空文件退回原生写法,不再把未初始化内存写进 DWG;
  acisOut/Open 失败分支补 DeleteFile;两个重复的 errorfile 分支合并为
  WriteRegionNativeFallback,顺带修掉 7 字节泄漏
- RegionAcisInDwgInFields:临时文件名只取纯文件名,拒绝 DWG 里夹带的路径
  成分和盘符;errorfile 分支补 delete[];create/dwgInFields/acisIn 失败
  分支加日志并正确释放;acisIn 返回的非 region 实体不再泄漏
- 删除 RegionExplodeDwgOutFields(写路径退役后无调用者)
This commit is contained in:
company-desktop-computer committed 2026-10-21 22:15:49 +08:00
1 parent 5692d9010b
commit 8941246b16
2 files changed
+168 -167

No files matched your search

@@ -658,6 +658,40 @@ namespace
return es != Acad::eOk;
}
// 读端只接受纯文件名:DWG 里存的名字不可信,去掉路径成分防止写到临时目录之外
CString SanitizeRegionTempName(const CString& sFileName)
{
CString sName = sFileName;
int nSlash = sName.ReverseFind(_T('\\'));
int nSlash2 = sName.ReverseFind(_T('/'));
if (nSlash2 > nSlash)
nSlash = nSlash2;
if (nSlash >= 0)
sName = sName.Mid(nSlash + 1);
// 空名、上跳目录、盘符一律丢弃,退回固定名
if (sName.IsEmpty() || sName.Find(_T("..")) >= 0 || sName.Find(_T(':')) >= 0)
sName = _T("region_tmp.dat");
return sName;
}
// acisOut 不可用时的兜底:写 errorfile 标记,再让 region 自己写原生数据
Acad::ErrorStatus WriteRegionNativeFallback(AcDbDwgFiler* pFiler, AcDbRegion* pRegion)
{
pFiler->writeString(_T("errorfile"));
char pszTxt[7];
::memset(pszTxt, 0, sizeof(pszTxt));
pFiler->writeUInt32(7);
pFiler->writeBytes(pszTxt, 7);
return pRegion->dwgOutFields(pFiler);
}
}
AcDbRegion *AecDbEwPipeBase::RegionFromCurvesDwgInFields(AcDbDwgFiler *pFiler, Adesk::UInt32 nLen)
@@ -760,66 +794,92 @@ AcDbRegion* AecDbEwPipeBase::RegionAcisInDwgInFields(AcDbDwgFiler* pFiler)
//高版本acis方式
CString sFileName;
TCHAR* pszFileName = NULL;
pFiler->readString(&pszFileName);
if (pszFileName != NULL)
if (pFiler->readString(&pszFileName) != Acad::eOk || pszFileName == NULL)
{
//Region_%s.dat
sFileName = pszFileName;
acutDelString(pszFileName);
Adesk::UInt32 nLen = 0;
pFiler->readUInt32(&nLen);
if (nLen > 0)
{
char* pszTxt = new char[nLen];
pFiler->readBytes(pszTxt,nLen);
if (sFileName.CompareNoCase(_T("errorfile")) == 0)
{
//原生写法
AcDbRegion* pRegion = (AcDbRegion*)AcDbRegion::desc()->create();
Acad::ErrorStatus es = pRegion->dwgInFields(pFiler);
return pRegion;
}
else
{
CString sFullPath = FilePath::getSystemTemporaryFolder();
sFullPath += _T("\\");
sFullPath += sFileName;
CFile file;
if (file.Open(sFullPath, CFile::modeCreate | CFile::modeWrite))
{
file.Write(pszTxt,nLen);
file.Close();
AcDbVoidPtrArray arBodyPtrs;
Acad::ErrorStatus es;
if ( Acad::eOk == (es = AcDbBody::acisIn(sFullPath,arBodyPtrs) ) )
{
if (arBodyPtrs.length() > 0)
{
AcDbEntity* pEnt = (AcDbEntity*)arBodyPtrs.first();
AcDbRegion* pRegion = AcDbRegion::cast(pEnt);
if (pRegion != NULL)
{
::DeleteFile(sFullPath);
delete[] pszTxt;
return pRegion;
}
//可能其他的合成或boolsubstract...
}
}
::DeleteFile(sFullPath);
}
}
delete[] pszTxt;
}
acutPrintf(_T("\nAecDbEwPipeBase: 截面读文件名失败。"));
return NULL;
}
return NULL;
//Region_%s.dat
sFileName = pszFileName;
acutDelString(pszFileName);
Adesk::UInt32 nLen = 0;
pFiler->readUInt32(&nLen);
if (nLen == 0)
return NULL;
char* pszTxt = new char[nLen + 1];
::memset(pszTxt, 0, nLen + 1);
pFiler->readBytes(pszTxt,nLen);
if (sFileName.CompareNoCase(_T("errorfile")) == 0)
{
//原生写法
delete[] pszTxt;
AcDbRegion* pRegion = (AcDbRegion*)AcDbRegion::desc()->create();
if (pRegion == NULL)
{
acutPrintf(_T("\nAecDbEwPipeBase: 截面原生读取时创建 region 失败。"));
return NULL;
}
Acad::ErrorStatus es = pRegion->dwgInFields(pFiler);
if (es != Acad::eOk)
{
acutPrintf(_T("\nAecDbEwPipeBase: 截面原生 dwgInFields 失败,err=%d。"),es);
delete pRegion;
return NULL;
}
return pRegion;
}
CString sFullPath = FilePath::getSystemTemporaryFolder();
sFullPath += _T("\\");
sFullPath += SanitizeRegionTempName(sFileName);
CFile file;
if (!file.Open(sFullPath, CFile::modeCreate | CFile::modeWrite))
{
acutPrintf(_T("\nAecDbEwPipeBase: 截面临时文件创建失败:%s"),(LPCTSTR)sFullPath);
delete[] pszTxt;
return NULL;
}
file.Write(pszTxt,nLen);
file.Close();
delete[] pszTxt;
AcDbVoidPtrArray arBodyPtrs;
Acad::ErrorStatus es = AcDbBody::acisIn(sFullPath,arBodyPtrs);
if (es != Acad::eOk)
{
acutPrintf(_T("\nAecDbEwPipeBase: 截面 acisIn 失败,len=%u,err=%d。"),nLen,es);
::DeleteFile(sFullPath);
return NULL;
}
// acisIn 返回的实体未入库,由调用方负责释放;只留第一个 region,其余丢弃
AcDbRegion* pRegion = NULL;
for (int i = 0;i < arBodyPtrs.length();i++)
{
AcDbEntity* pEnt = (AcDbEntity*)arBodyPtrs.at(i);
if (pRegion == NULL)
{
pRegion = AcDbRegion::cast(pEnt);
if (pRegion != NULL)
continue;
}
delete pEnt;
}
if (pRegion == NULL)
acutPrintf(_T("\nAecDbEwPipeBase: 截面 acisIn 未返回 region,len=%u。"),nLen);
::DeleteFile(sFullPath);
return pRegion;
}
AcDbRegion* AecDbEwPipeBase::SectionRegionDwgInFields(AcDbDwgFiler* pFiler,int nVer)
@@ -1132,34 +1192,19 @@ Acad::ErrorStatus AecDbEwPipeBase::BaseCurveDwgOutFields(AcDbCurve* pBaseCurve,A
return Acad::eOk;
}
Acad::ErrorStatus AecDbEwPipeBase::RegionExplodeDwgOutFields(AcDbDwgFiler* pFiler,AcDbVoidPtrArray& arCurPtrs) const
{
Adesk::UInt32 nCurs = arCurPtrs.length();
pFiler->writeUInt32(nCurs);
AcDbCurve* pCurve = NULL;
for (int i = 0;i < arCurPtrs.length();i++)
{
pCurve = (AcDbCurve*)arCurPtrs.at(i);
BaseCurveDwgOutFields(pCurve,pFiler);
delete pCurve;
}
return Acad::eOk;
}
Acad::ErrorStatus AecDbEwPipeBase::RegionAcisoutDwgOutFields(AcDbDwgFiler* pFiler) const
{
if (m_pRegion == NULL)
return Acad::eInvalidInput;
//开始写acis方式
//避免多文档crash
//避免多文档crash:文件名带进程号,同一张图在两个 CAD 实例里同时打开不会互相覆盖
TCHAR szHandleStr[19];
memset(szHandleStr,0,sizeof(szHandleStr) );
objectId().handle().getIntoAsciiBuffer(szHandleStr);
CString sFileName;
sFileName.Format(_T("Region_%s.dat"),szHandleStr);
sFileName.Format(_T("Region_%lu_%s.dat"),(unsigned long)::GetCurrentProcessId(),szHandleStr);
CString sFullPath = FilePath::getSystemTemporaryFolder();
sFullPath += _T("\\");
@@ -1168,110 +1213,67 @@ Acad::ErrorStatus AecDbEwPipeBase::RegionAcisoutDwgOutFields(AcDbDwgFiler* pFile
AcDbVoidPtrArray arBodyPtrs;
arBodyPtrs.append(m_pRegion);
Acad::ErrorStatus es;
if (Acad::eOk == (es = AcDbBody::acisOut(sFullPath, arBodyPtrs)))
Acad::ErrorStatus es = AcDbBody::acisOut(sFullPath, arBodyPtrs);
if (Acad::eOk != es)
{
CFile file;
if (file.Open(sFullPath, CFile::modeRead))
{
//确认REGION不会超过32位数量级字节
//强制转换兼容可能的07-09CAD
ULONGLONG dwFileLength = file.GetLength();
Adesk::UInt32 nLen = (Adesk::UInt32)dwFileLength;
char* pszTxt = new char[nLen];
file.Read(pszTxt, nLen);
file.Close();
pFiler->writeString((LPCTSTR)sFileName);
pFiler->writeUInt32(nLen);
pFiler->writeBytes(pszTxt,nLen);
::DeleteFile(sFullPath);
delete[] pszTxt;
return Acad::eOk;
}
else
{
pFiler->writeString(_T("errorfile"));
char* pszTxt = new char[7];
memset(pszTxt,0,7);
pFiler->writeUInt32(7);
pFiler->writeBytes(pszTxt,7);
//原生写法
es = m_pRegion->dwgOutFields(pFiler);
return es;
}
acutPrintf(_T("\nAecDbEwPipeBase: 截面 acisOut 失败,handle=%s,err=%d,改用原生写法。"),szHandleStr,es);
::DeleteFile(sFullPath);
return WriteRegionNativeFallback(pFiler, m_pRegion);
}
else
CFile file;
if (!file.Open(sFullPath, CFile::modeRead))
{
pFiler->writeString(_T("errorfile"));
char* pszTxt = new char[7];
memset(pszTxt,0,7);
pFiler->writeUInt32(7);
pFiler->writeBytes(pszTxt,7);
//原生写法
es = m_pRegion->dwgOutFields(pFiler);
return es;
acutPrintf(_T("\nAecDbEwPipeBase: 截面临时文件打开失败,handle=%s,改用原生写法。"),szHandleStr);
::DeleteFile(sFullPath);
return WriteRegionNativeFallback(pFiler, m_pRegion);
}
return Acad::eOutOfMemory;
//确认REGION不会超过32位数量级字节
//强制转换兼容可能的07-09CAD
ULONGLONG dwFileLength = file.GetLength();
Adesk::UInt32 nLen = (Adesk::UInt32)dwFileLength;
char* pszTxt = new char[nLen + 1];
::memset(pszTxt, 0, nLen + 1);
UINT nRead = file.Read(pszTxt, nLen);
file.Close();
if (nLen == 0 || nRead != nLen)
{
// 空文件或短读:尾部是未初始化内存,不能写进 DWG
acutPrintf(_T("\nAecDbEwPipeBase: 截面临时文件异常,handle=%s,期望%u字节实读%u字节,改用原生写法。")
,szHandleStr,nLen,nRead);
::DeleteFile(sFullPath);
delete[] pszTxt;
return WriteRegionNativeFallback(pFiler, m_pRegion);
}
pFiler->writeString((LPCTSTR)sFileName);
pFiler->writeUInt32(nLen);
pFiler->writeBytes(pszTxt,nLen);
::DeleteFile(sFullPath);
delete[] pszTxt;
return Acad::eOk;
}
Acad::ErrorStatus AecDbEwPipeBase::SectionRegionDwgOutFields(AcDbDwgFiler* pFiler,int nVer) const
{
assertReadEnabled();
if (m_pRegion != NULL)
{
if (nVer < 4)//旧版本,保持原样,有错误漏洞
{
AcDbVoidPtrArray arCurPtrs;
m_pRegion->explode(arCurPtrs);
UNREFERENCED_PARAMETER(nVer);
if (!arCurPtrs.isEmpty())
{
return RegionExplodeDwgOutFields(pFiler,arCurPtrs);
}
else
{
//旧版本错误漏洞
//旧版本不考虑 nVer已经升级
//...
}
}
else
{
AcDbVoidPtrArray arCurPtrs;
m_pRegion->explode(arCurPtrs);
if (m_pRegion == NULL)
return Acad::eOk;
//如果炸碎成功
if (!arCurPtrs.isEmpty())
{
//轻量化写法
return RegionExplodeDwgOutFields(pFiler,arCurPtrs);
}
else
{
//补救措施,重量化写法
//写入长度0 旧版本<4 情况不考虑 nVer已经升级
Adesk::UInt32 nCurs = 0;
pFiler->writeUInt32(nCurs);
// 统一写 SAT:nLen = 0 是读取端识别 SAT 通道的标志,旧版本插件同样识别。
// 曲线通道只用于读老图纸,写路径已退役,不再按截面类型分流
Adesk::UInt32 nCurs = 0;
pFiler->writeUInt32(nCurs);
return RegionAcisoutDwgOutFields(pFiler);
}
}
}
return Acad::eOk;
return RegionAcisoutDwgOutFields(pFiler);
}
Acad::ErrorStatus AecDbEwPipeBase::DefaultNo()
@@ -149,7 +149,6 @@ protected:
Acad::ErrorStatus BaseCurveDwgOutFields(AcDbCurve* pBaseCurve,AcDbDwgFiler* pFiler) const;
Acad::ErrorStatus RegionAcisoutDwgOutFields(AcDbDwgFiler* pFiler) const;
Acad::ErrorStatus RegionExplodeDwgOutFields(AcDbDwgFiler* pFiler,AcDbVoidPtrArray& arCurPtrs) const;
Acad::ErrorStatus SectionRegionDwgOutFields(AcDbDwgFiler* pFiler,int nVer) const;
Acad::ErrorStatus AddDimPoints(AcDbGripDataPtrArray& grips,const AcGeVector3d& curViewDir,