| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 PDFium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
| 6 | |
| 7 #include "xfa/src/fxfa/app/xfa_ffdoc.h" | |
| 8 | |
| 9 #include "core/include/fpdfapi/cpdf_array.h" | |
| 10 #include "core/include/fpdfapi/cpdf_document.h" | |
| 11 #include "core/include/fpdfdoc/fpdf_doc.h" | |
| 12 #include "core/include/fxcrt/fx_ext.h" | |
| 13 #include "xfa/include/fwl/core/fwl_note.h" | |
| 14 #include "xfa/src/fgas/crt/fgas_algorithm.h" | |
| 15 #include "xfa/src/fxfa/app/xfa_ffapp.h" | |
| 16 #include "xfa/src/fxfa/app/xfa_ffdocview.h" | |
| 17 #include "xfa/src/fxfa/app/xfa_ffnotify.h" | |
| 18 #include "xfa/src/fxfa/app/xfa_ffwidget.h" | |
| 19 #include "xfa/src/fxfa/app/xfa_fontmgr.h" | |
| 20 #include "xfa/src/fxfa/parser/xfa_docdata.h" | |
| 21 #include "xfa/src/fxfa/parser/xfa_parser.h" | |
| 22 | |
| 23 CXFA_FFDoc::CXFA_FFDoc(CXFA_FFApp* pApp, IXFA_DocProvider* pDocProvider) | |
| 24 : m_pDocProvider(pDocProvider), | |
| 25 m_pDocument(nullptr), | |
| 26 m_pStream(nullptr), | |
| 27 m_pApp(pApp), | |
| 28 m_pNotify(nullptr), | |
| 29 m_pPDFDoc(nullptr), | |
| 30 m_dwDocType(XFA_DOCTYPE_Static), | |
| 31 m_bOwnStream(TRUE) {} | |
| 32 CXFA_FFDoc::~CXFA_FFDoc() { | |
| 33 CloseDoc(); | |
| 34 } | |
| 35 FX_DWORD CXFA_FFDoc::GetDocType() { | |
| 36 return m_dwDocType; | |
| 37 } | |
| 38 int32_t CXFA_FFDoc::StartLoad() { | |
| 39 m_pNotify = new CXFA_FFNotify(this); | |
| 40 IXFA_DocParser* pDocParser = IXFA_DocParser::Create(m_pNotify); | |
| 41 int32_t iStatus = pDocParser->StartParse(m_pStream); | |
| 42 m_pDocument = pDocParser->GetDocument(); | |
| 43 return iStatus; | |
| 44 } | |
| 45 FX_BOOL XFA_GetPDFContentsFromPDFXML(IFDE_XMLNode* pPDFElement, | |
| 46 uint8_t*& pByteBuffer, | |
| 47 int32_t& iBufferSize) { | |
| 48 IFDE_XMLElement* pDocumentElement = NULL; | |
| 49 for (IFDE_XMLNode* pXMLNode = | |
| 50 pPDFElement->GetNodeItem(IFDE_XMLNode::FirstChild); | |
| 51 pXMLNode; pXMLNode = pXMLNode->GetNodeItem(IFDE_XMLNode::NextSibling)) { | |
| 52 if (pXMLNode->GetType() == FDE_XMLNODE_Element) { | |
| 53 CFX_WideString wsTagName; | |
| 54 IFDE_XMLElement* pXMLElement = (IFDE_XMLElement*)pXMLNode; | |
| 55 pXMLElement->GetTagName(wsTagName); | |
| 56 if (wsTagName.Equal(FX_WSTRC(L"document"))) { | |
| 57 pDocumentElement = pXMLElement; | |
| 58 break; | |
| 59 } | |
| 60 } | |
| 61 } | |
| 62 if (!pDocumentElement) { | |
| 63 return FALSE; | |
| 64 } | |
| 65 IFDE_XMLElement* pChunkElement = NULL; | |
| 66 for (IFDE_XMLNode* pXMLNode = | |
| 67 pDocumentElement->GetNodeItem(IFDE_XMLNode::FirstChild); | |
| 68 pXMLNode; pXMLNode = pXMLNode->GetNodeItem(IFDE_XMLNode::NextSibling)) { | |
| 69 if (pXMLNode->GetType() == FDE_XMLNODE_Element) { | |
| 70 CFX_WideString wsTagName; | |
| 71 IFDE_XMLElement* pXMLElement = (IFDE_XMLElement*)pXMLNode; | |
| 72 pXMLElement->GetTagName(wsTagName); | |
| 73 if (wsTagName.Equal(FX_WSTRC(L"chunk"))) { | |
| 74 pChunkElement = pXMLElement; | |
| 75 break; | |
| 76 } | |
| 77 } | |
| 78 } | |
| 79 if (!pChunkElement) { | |
| 80 return FALSE; | |
| 81 } | |
| 82 CFX_WideString wsPDFContent; | |
| 83 pChunkElement->GetTextData(wsPDFContent); | |
| 84 iBufferSize = FX_Base64DecodeW(wsPDFContent, wsPDFContent.GetLength(), NULL); | |
| 85 pByteBuffer = FX_Alloc(uint8_t, iBufferSize + 1); | |
| 86 pByteBuffer[iBufferSize] = '0'; // FIXME: I bet this is wrong. | |
| 87 FX_Base64DecodeW(wsPDFContent, wsPDFContent.GetLength(), pByteBuffer); | |
| 88 return TRUE; | |
| 89 } | |
| 90 void XFA_XPDPacket_MergeRootNode(CXFA_Node* pOriginRoot, CXFA_Node* pNewRoot) { | |
| 91 CXFA_Node* pChildNode = pNewRoot->GetNodeItem(XFA_NODEITEM_FirstChild); | |
| 92 while (pChildNode) { | |
| 93 CXFA_Node* pOriginChild = | |
| 94 pOriginRoot->GetFirstChildByName(pChildNode->GetNameHash()); | |
| 95 if (pOriginChild) { | |
| 96 pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling); | |
| 97 } else { | |
| 98 CXFA_Node* pNextSibling = | |
| 99 pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling); | |
| 100 pNewRoot->RemoveChild(pChildNode); | |
| 101 pOriginRoot->InsertChild(pChildNode); | |
| 102 pChildNode = pNextSibling; | |
| 103 pNextSibling = NULL; | |
| 104 } | |
| 105 } | |
| 106 } | |
| 107 int32_t CXFA_FFDoc::DoLoad(IFX_Pause* pPause) { | |
| 108 int32_t iStatus = m_pDocument->GetParser()->DoParse(pPause); | |
| 109 if (iStatus == XFA_PARSESTATUS_Done && !m_pPDFDoc) { | |
| 110 CXFA_Node* pPDFNode = ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Pdf)); | |
| 111 if (!pPDFNode) { | |
| 112 return XFA_PARSESTATUS_SyntaxErr; | |
| 113 } | |
| 114 IFDE_XMLNode* pPDFXML = pPDFNode->GetXMLMappingNode(); | |
| 115 if (pPDFXML->GetType() != FDE_XMLNODE_Element) { | |
| 116 return XFA_PARSESTATUS_SyntaxErr; | |
| 117 } | |
| 118 int32_t iBufferSize = 0; | |
| 119 uint8_t* pByteBuffer = NULL; | |
| 120 IFX_FileRead* pXFAReader = NULL; | |
| 121 if (XFA_GetPDFContentsFromPDFXML(pPDFXML, pByteBuffer, iBufferSize)) { | |
| 122 pXFAReader = FX_CreateMemoryStream(pByteBuffer, iBufferSize, TRUE); | |
| 123 } else { | |
| 124 CFX_WideString wsHref; | |
| 125 ((IFDE_XMLElement*)pPDFXML)->GetString(L"href", wsHref); | |
| 126 if (!wsHref.IsEmpty()) { | |
| 127 pXFAReader = GetDocProvider()->OpenLinkedFile(this, wsHref); | |
| 128 } | |
| 129 } | |
| 130 if (!pXFAReader) { | |
| 131 return XFA_PARSESTATUS_SyntaxErr; | |
| 132 } | |
| 133 CPDF_Document* pPDFDocument = | |
| 134 GetDocProvider()->OpenPDF(this, pXFAReader, TRUE); | |
| 135 FXSYS_assert(!m_pPDFDoc); | |
| 136 if (!OpenDoc(pPDFDocument)) { | |
| 137 return XFA_PARSESTATUS_SyntaxErr; | |
| 138 } | |
| 139 IXFA_Parser* pParser = IXFA_Parser::Create(m_pDocument, TRUE); | |
| 140 if (!pParser) { | |
| 141 return XFA_PARSESTATUS_SyntaxErr; | |
| 142 } | |
| 143 CXFA_Node* pRootNode = NULL; | |
| 144 if (pParser->StartParse(m_pStream) == XFA_PARSESTATUS_Ready && | |
| 145 pParser->DoParse(NULL) == XFA_PARSESTATUS_Done) { | |
| 146 pRootNode = pParser->GetRootNode(); | |
| 147 } | |
| 148 if (pRootNode && m_pDocument->GetRoot()) { | |
| 149 XFA_XPDPacket_MergeRootNode(m_pDocument->GetRoot(), pRootNode); | |
| 150 iStatus = XFA_PARSESTATUS_Done; | |
| 151 } else { | |
| 152 iStatus = XFA_PARSESTATUS_StatusErr; | |
| 153 } | |
| 154 pParser->Release(); | |
| 155 pParser = NULL; | |
| 156 } | |
| 157 return iStatus; | |
| 158 } | |
| 159 void CXFA_FFDoc::StopLoad() { | |
| 160 m_pApp->GetXFAFontMgr()->LoadDocFonts(this); | |
| 161 m_dwDocType = XFA_DOCTYPE_Static; | |
| 162 CXFA_Node* pConfig = ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Config)); | |
| 163 if (!pConfig) { | |
| 164 return; | |
| 165 } | |
| 166 CXFA_Node* pAcrobat = pConfig->GetFirstChildByClass(XFA_ELEMENT_Acrobat); | |
| 167 if (!pAcrobat) { | |
| 168 return; | |
| 169 } | |
| 170 CXFA_Node* pAcrobat7 = pAcrobat->GetFirstChildByClass(XFA_ELEMENT_Acrobat7); | |
| 171 if (!pAcrobat7) { | |
| 172 return; | |
| 173 } | |
| 174 CXFA_Node* pDynamicRender = | |
| 175 pAcrobat7->GetFirstChildByClass(XFA_ELEMENT_DynamicRender); | |
| 176 if (!pDynamicRender) { | |
| 177 return; | |
| 178 } | |
| 179 CFX_WideString wsType; | |
| 180 if (pDynamicRender->TryContent(wsType) && wsType == FX_WSTRC(L"required")) { | |
| 181 m_dwDocType = XFA_DOCTYPE_Dynamic; | |
| 182 } | |
| 183 } | |
| 184 IXFA_DocView* CXFA_FFDoc::CreateDocView(FX_DWORD dwView) { | |
| 185 CXFA_FFDocView* pDocView = | |
| 186 (CXFA_FFDocView*)m_mapTypeToDocView.GetValueAt((void*)(uintptr_t)dwView); | |
| 187 if (!pDocView) { | |
| 188 pDocView = new CXFA_FFDocView(this); | |
| 189 m_mapTypeToDocView.SetAt((void*)(uintptr_t)dwView, pDocView); | |
| 190 } | |
| 191 return pDocView; | |
| 192 } | |
| 193 CXFA_FFDocView* CXFA_FFDoc::GetDocView(IXFA_DocLayout* pLayout) { | |
| 194 FX_POSITION ps = m_mapTypeToDocView.GetStartPosition(); | |
| 195 while (ps) { | |
| 196 void* pType; | |
| 197 CXFA_FFDocView* pDocView; | |
| 198 m_mapTypeToDocView.GetNextAssoc(ps, pType, (void*&)pDocView); | |
| 199 if (pDocView->GetXFALayout() == pLayout) { | |
| 200 return pDocView; | |
| 201 } | |
| 202 } | |
| 203 return NULL; | |
| 204 } | |
| 205 CXFA_FFDocView* CXFA_FFDoc::GetDocView() { | |
| 206 FX_POSITION ps = m_mapTypeToDocView.GetStartPosition(); | |
| 207 if (ps) { | |
| 208 void* pType; | |
| 209 CXFA_FFDocView* pDocView; | |
| 210 m_mapTypeToDocView.GetNextAssoc(ps, pType, (void*&)pDocView); | |
| 211 return pDocView; | |
| 212 } | |
| 213 return NULL; | |
| 214 } | |
| 215 FX_BOOL CXFA_FFDoc::OpenDoc(IFX_FileRead* pStream, FX_BOOL bTakeOverFile) { | |
| 216 m_bOwnStream = bTakeOverFile; | |
| 217 m_pStream = pStream; | |
| 218 return TRUE; | |
| 219 } | |
| 220 FX_BOOL CXFA_FFDoc::OpenDoc(CPDF_Document* pPDFDoc) { | |
| 221 if (pPDFDoc == NULL) { | |
| 222 return FALSE; | |
| 223 } | |
| 224 CPDF_Dictionary* pRoot = pPDFDoc->GetRoot(); | |
| 225 if (pRoot == NULL) { | |
| 226 return FALSE; | |
| 227 } | |
| 228 CPDF_Dictionary* pAcroForm = pRoot->GetDictBy("AcroForm"); | |
| 229 if (pAcroForm == NULL) { | |
| 230 return FALSE; | |
| 231 } | |
| 232 CPDF_Object* pElementXFA = pAcroForm->GetElementValue("XFA"); | |
| 233 if (pElementXFA == NULL) { | |
| 234 return FALSE; | |
| 235 } | |
| 236 CFX_ArrayTemplate<CPDF_Stream*> xfaStreams; | |
| 237 if (pElementXFA->IsArray()) { | |
| 238 CPDF_Array* pXFAArray = (CPDF_Array*)pElementXFA; | |
| 239 FX_DWORD count = pXFAArray->GetCount() / 2; | |
| 240 for (FX_DWORD i = 0; i < count; i++) { | |
| 241 if (CPDF_Stream* pStream = pXFAArray->GetStreamAt(i * 2 + 1)) | |
| 242 xfaStreams.Add(pStream); | |
| 243 } | |
| 244 } else if (pElementXFA->IsStream()) { | |
| 245 xfaStreams.Add((CPDF_Stream*)pElementXFA); | |
| 246 } | |
| 247 if (xfaStreams.GetSize() < 1) { | |
| 248 return FALSE; | |
| 249 } | |
| 250 IFX_FileRead* pFileRead = new CXFA_FileRead(xfaStreams); | |
| 251 m_pPDFDoc = pPDFDoc; | |
| 252 if (m_pStream) { | |
| 253 m_pStream->Release(); | |
| 254 m_pStream = NULL; | |
| 255 } | |
| 256 m_pStream = pFileRead; | |
| 257 m_bOwnStream = TRUE; | |
| 258 return TRUE; | |
| 259 } | |
| 260 FX_BOOL CXFA_FFDoc::CloseDoc() { | |
| 261 FX_POSITION psClose = m_mapTypeToDocView.GetStartPosition(); | |
| 262 while (psClose) { | |
| 263 void* pType; | |
| 264 CXFA_FFDocView* pDocView; | |
| 265 m_mapTypeToDocView.GetNextAssoc(psClose, pType, (void*&)pDocView); | |
| 266 pDocView->RunDocClose(); | |
| 267 } | |
| 268 if (m_pDocument) { | |
| 269 m_pDocument->ClearLayoutData(); | |
| 270 } | |
| 271 FX_POSITION ps = m_mapTypeToDocView.GetStartPosition(); | |
| 272 while (ps) { | |
| 273 void* pType; | |
| 274 CXFA_FFDocView* pDocView; | |
| 275 m_mapTypeToDocView.GetNextAssoc(ps, pType, (void*&)pDocView); | |
| 276 delete pDocView; | |
| 277 } | |
| 278 m_mapTypeToDocView.RemoveAll(); | |
| 279 if (m_pDocument) { | |
| 280 IXFA_Parser* pParser = m_pDocument->GetParser(); | |
| 281 pParser->Release(); | |
| 282 m_pDocument = NULL; | |
| 283 } | |
| 284 if (m_pNotify) { | |
| 285 delete m_pNotify; | |
| 286 m_pNotify = NULL; | |
| 287 } | |
| 288 m_pApp->GetXFAFontMgr()->ReleaseDocFonts(this); | |
| 289 if (m_dwDocType != XFA_DOCTYPE_XDP && m_pStream && m_bOwnStream) { | |
| 290 m_pStream->Release(); | |
| 291 m_pStream = NULL; | |
| 292 } | |
| 293 ps = m_mapNamedImages.GetStartPosition(); | |
| 294 while (ps) { | |
| 295 void* pName; | |
| 296 FX_IMAGEDIB_AND_DPI* pImage = NULL; | |
| 297 m_mapNamedImages.GetNextAssoc(ps, pName, (void*&)pImage); | |
| 298 if (pImage) { | |
| 299 delete pImage->pDibSource; | |
| 300 pImage->pDibSource = NULL; | |
| 301 FX_Free(pImage); | |
| 302 pImage = NULL; | |
| 303 } | |
| 304 } | |
| 305 m_mapNamedImages.RemoveAll(); | |
| 306 IFWL_NoteDriver* pNoteDriver = FWL_GetApp()->GetNoteDriver(); | |
| 307 pNoteDriver->ClearEventTargets(FALSE); | |
| 308 return TRUE; | |
| 309 } | |
| 310 void CXFA_FFDoc::SetDocType(FX_DWORD dwType) { | |
| 311 m_dwDocType = dwType; | |
| 312 } | |
| 313 CPDF_Document* CXFA_FFDoc::GetPDFDoc() { | |
| 314 return m_pPDFDoc; | |
| 315 } | |
| 316 | |
| 317 CFX_DIBitmap* CXFA_FFDoc::GetPDFNamedImage(const CFX_WideStringC& wsName, | |
| 318 int32_t& iImageXDpi, | |
| 319 int32_t& iImageYDpi) { | |
| 320 if (!m_pPDFDoc) | |
| 321 return nullptr; | |
| 322 | |
| 323 FX_DWORD dwHash = | |
| 324 FX_HashCode_String_GetW(wsName.GetPtr(), wsName.GetLength(), FALSE); | |
| 325 FX_IMAGEDIB_AND_DPI* imageDIBDpi = nullptr; | |
| 326 if (m_mapNamedImages.Lookup((void*)(uintptr_t)dwHash, (void*&)imageDIBDpi)) { | |
| 327 iImageXDpi = imageDIBDpi->iImageXDpi; | |
| 328 iImageYDpi = imageDIBDpi->iImageYDpi; | |
| 329 return static_cast<CFX_DIBitmap*>(imageDIBDpi->pDibSource); | |
| 330 } | |
| 331 | |
| 332 CPDF_Dictionary* pRoot = m_pPDFDoc->GetRoot(); | |
| 333 if (!pRoot) | |
| 334 return nullptr; | |
| 335 | |
| 336 CPDF_Dictionary* pNames = pRoot->GetDictBy("Names"); | |
| 337 if (!pNames) | |
| 338 return nullptr; | |
| 339 | |
| 340 CPDF_Dictionary* pXFAImages = pNames->GetDictBy("XFAImages"); | |
| 341 if (!pXFAImages) | |
| 342 return nullptr; | |
| 343 | |
| 344 CPDF_NameTree nametree(pXFAImages); | |
| 345 CFX_ByteString bsName = PDF_EncodeText(wsName.GetPtr(), wsName.GetLength()); | |
| 346 CPDF_Object* pObject = nametree.LookupValue(bsName); | |
| 347 if (!pObject) { | |
| 348 int32_t iCount = nametree.GetCount(); | |
| 349 for (int32_t i = 0; i < iCount; i++) { | |
| 350 CFX_ByteString bsTemp; | |
| 351 CPDF_Object* pTempObject = nametree.LookupValue(i, bsTemp); | |
| 352 if (bsTemp == bsName) { | |
| 353 pObject = pTempObject; | |
| 354 break; | |
| 355 } | |
| 356 } | |
| 357 } | |
| 358 | |
| 359 if (!pObject || !pObject->IsStream()) | |
| 360 return nullptr; | |
| 361 | |
| 362 if (!imageDIBDpi) { | |
| 363 imageDIBDpi = FX_Alloc(FX_IMAGEDIB_AND_DPI, 1); | |
| 364 imageDIBDpi->pDibSource = nullptr; | |
| 365 imageDIBDpi->iImageXDpi = 0; | |
| 366 imageDIBDpi->iImageYDpi = 0; | |
| 367 CPDF_StreamAcc streamAcc; | |
| 368 streamAcc.LoadAllData((CPDF_Stream*)pObject); | |
| 369 IFX_FileRead* pImageFileRead = FX_CreateMemoryStream( | |
| 370 (uint8_t*)streamAcc.GetData(), streamAcc.GetSize()); | |
| 371 imageDIBDpi->pDibSource = XFA_LoadImageFromBuffer( | |
| 372 pImageFileRead, FXCODEC_IMAGE_UNKNOWN, iImageXDpi, iImageYDpi); | |
| 373 imageDIBDpi->iImageXDpi = iImageXDpi; | |
| 374 imageDIBDpi->iImageYDpi = iImageYDpi; | |
| 375 pImageFileRead->Release(); | |
| 376 } | |
| 377 m_mapNamedImages.SetAt((void*)(uintptr_t)dwHash, imageDIBDpi); | |
| 378 return (CFX_DIBitmap*)imageDIBDpi->pDibSource; | |
| 379 } | |
| 380 | |
| 381 IFDE_XMLElement* CXFA_FFDoc::GetPackageData(const CFX_WideStringC& wsPackage) { | |
| 382 FX_DWORD packetHash = | |
| 383 FX_HashCode_String_GetW(wsPackage.GetPtr(), wsPackage.GetLength()); | |
| 384 CXFA_Node* pNode = ToNode(m_pDocument->GetXFAObject(packetHash)); | |
| 385 if (!pNode) { | |
| 386 return NULL; | |
| 387 } | |
| 388 IFDE_XMLNode* pXMLNode = pNode->GetXMLMappingNode(); | |
| 389 return (pXMLNode && pXMLNode->GetType() == FDE_XMLNODE_Element) | |
| 390 ? (IFDE_XMLElement*)pXMLNode | |
| 391 : NULL; | |
| 392 } | |
| 393 FX_BOOL CXFA_FFDoc::SavePackage(const CFX_WideStringC& wsPackage, | |
| 394 IFX_FileWrite* pFile, | |
| 395 IXFA_ChecksumContext* pCSContext) { | |
| 396 IXFA_PacketExport* pExport = IXFA_PacketExport::Create(m_pDocument); | |
| 397 if (!pExport) { | |
| 398 return FALSE; | |
| 399 } | |
| 400 FX_DWORD packetHash = | |
| 401 FX_HashCode_String_GetW(wsPackage.GetPtr(), wsPackage.GetLength()); | |
| 402 CXFA_Node* pNode = NULL; | |
| 403 if (packetHash == XFA_HASHCODE_Xfa) { | |
| 404 pNode = m_pDocument->GetRoot(); | |
| 405 } else { | |
| 406 pNode = ToNode(m_pDocument->GetXFAObject(packetHash)); | |
| 407 } | |
| 408 FX_BOOL bFlags = FALSE; | |
| 409 if (pNode) { | |
| 410 CFX_ByteString bsChecksum; | |
| 411 if (pCSContext) { | |
| 412 pCSContext->GetChecksum(bsChecksum); | |
| 413 } | |
| 414 bFlags = pExport->Export(pFile, pNode, 0, bsChecksum.GetLength() | |
| 415 ? (const FX_CHAR*)bsChecksum | |
| 416 : NULL); | |
| 417 } else { | |
| 418 bFlags = pExport->Export(pFile); | |
| 419 } | |
| 420 pExport->Release(); | |
| 421 return bFlags; | |
| 422 } | |
| 423 FX_BOOL CXFA_FFDoc::ImportData(IFX_FileRead* pStream, FX_BOOL bXDP) { | |
| 424 FX_BOOL bRet = FALSE; | |
| 425 IXFA_PacketImport* pImport = IXFA_PacketImport::Create(m_pDocument); | |
| 426 if (pImport) { | |
| 427 bRet = pImport->ImportData(pStream); | |
| 428 pImport->Release(); | |
| 429 } | |
| 430 return bRet; | |
| 431 } | |
| OLD | NEW |