#include "stdafx.h" #include #include #include "MemoryUtils.h" #include "StringExt.h" #include "Object.h" #include "Array.h" #include "Dict.h" #include "Link.h" //------------------------------------------------------------------------------------------------------------------------------- // LinkAction //------------------------------------------------------------------------------------------------------------------------------- LinkAction *LinkAction::ParseDestination(Object *pObject) { LinkAction *pAction = new LinkGoTo( pObject ); if ( !pAction->CheckValidate() ) { delete pAction; return NULL; } return pAction; } LinkAction *LinkAction::ParseAction(Object *pObject, StringExt *seBaseURI) { LinkAction *pAction = NULL; if ( !pObject->IsDict() ) { // TO DO: Error "Bad annotation action" return NULL; } // S (тип Action) Object oType; pObject->DictLookup("S", &oType); // GoTo action if ( oType.IsName("GoTo") ) { Object oD; pObject->DictLookup("D", &oD); pAction = new LinkGoTo(&oD); oD.Free(); } else if ( oType.IsName("GoToR") ) // GoToR action { Object oF, oD; pObject->DictLookup("F", &oF); pObject->DictLookup("D", &oD); pAction = new LinkGoToR( &oF, &oD ); oF.Free(); oD.Free(); } else if ( oType.IsName("Launch") ) // Launch action { pAction = new LinkLaunch(pObject); } else if ( oType.IsName("URI") ) // URI action { Object oURI; pObject->DictLookup("URI", &oURI); pAction = new LinkURI( &oURI, seBaseURI ); oURI.Free(); } else if ( oType.IsName("Named") ) // Named action { Object oN; pObject->DictLookup("N", &oN); pAction = new LinkNamed(&oN); oN.Free(); } else if ( oType.IsName("Movie") ) // Movie action { Object oAnnot, oT; pObject->DictLookupAndCopy("Annot", &oAnnot); pObject->DictLookup("T", &oT); pAction = new LinkMovie( &oAnnot, &oT ); oAnnot.Free(); oT.Free(); } else if ( oType.IsName() ) // unknown action { pAction = new LinkUnknown(oType.GetName()); } else { // TO DO: Error "Bad annotation action" pAction = NULL; } oType.Free(); if ( pAction && !pAction->CheckValidate() ) { delete pAction; return NULL; } return pAction; } StringExt *LinkAction::GetFileSpecName(Object *pFileSpecObject) { StringExt *seName = NULL; if ( pFileSpecObject->IsString() ) { seName = pFileSpecObject->GetString()->Copy(); } else if ( pFileSpecObject->IsDict() ) { Object oTemp; if ( !pFileSpecObject->DictLookup("DOS", &oTemp)->IsString() ) { oTemp.Free(); pFileSpecObject->DictLookup("F", &oTemp); } if ( oTemp.IsString() ) { seName = oTemp.GetString()->Copy(); } else { // TO DO: Error "Illegal file spec in link" } oTemp.Free(); } else { // TO DO: Error "Illegal file spec in link" } if ( seName ) { // Производим преобразования, связанные с формой записи путей // "//...." --> "\...." // "/x/...." --> "x:\...." // "/server/share/...." --> "\\server\share\...." int nCurIndex = 0; if ( seName->GetAt(0) == '/' ) { if ( seName->GetLength() >= 2 && seName->GetAt(1) == '/' ) { seName->Delete(0); nCurIndex = 0; } else if ( seName->GetLength() >= 2 && ((seName->GetAt(1) >= 'a' && seName->GetAt(1) <= 'z') || (seName->GetAt(1) >= 'A' && seName->GetAt(1) <= 'Z')) && (seName->GetLength() == 2 || seName->GetAt(2) == '/') ) { seName->SetAt( 0, seName->GetAt(1) ); seName->SetAt( 1, ':' ); nCurIndex = 2; } else { int nJ; for ( nJ = 2; nJ < seName->GetLength(); ++nJ ) { if ( seName->GetAt(nJ - 1) != '\\' && seName->GetAt(nJ) == '/' ) { break; } } if ( nJ < seName->GetLength() ) { seName->SetAt(0, '\\'); seName->Insert(0, '\\'); nCurIndex = 2; } } } for (; nCurIndex < seName->GetLength(); ++nCurIndex) { if ( seName->GetAt(nCurIndex) == '/' ) { seName->SetAt(nCurIndex, '\\'); } else if ( seName->GetAt(nCurIndex) == '\\' && nCurIndex + 1 < seName->GetLength() && seName->GetAt(nCurIndex + 1) == '/' ) { seName->Delete(nCurIndex); } } } return seName; } //------------------------------------------------------------------------------------------------------------------------------- // LinkDest //------------------------------------------------------------------------------------------------------------------------------- LinkDestination::LinkDestination(Array *pArray) { m_dLeft = m_dBottom = m_dRight = m_dTop = m_dZoom = 0; m_bValidate = FALSE; if ( pArray->GetCount() < 2 ) { // TO DO: Error "Annotation destination array is too short" return; } Object oArrayItem; pArray->GetCopy( 0, &oArrayItem ); if ( oArrayItem.IsInt() ) { m_nPageNum = oArrayItem.GetInt() + 1; m_bPageIsRef = FALSE; } else if ( oArrayItem.IsRef() ) { m_oPageRef.nNum = oArrayItem.GetRefNum(); m_oPageRef.nGen = oArrayItem.GetRefGen(); m_bPageIsRef = TRUE; } else { // TO DO: Error "Bad annotation destination" oArrayItem.Free(); return; } oArrayItem.Free(); // Destination type pArray->Get( 1, &oArrayItem ); if ( oArrayItem.IsName("XYZ") ) { m_eType = destXYZ; Object oTemp; if ( pArray->GetCount() < 3 ) { m_bChangeLeft = FALSE; } else { pArray->Get( 2, &oTemp ); if ( oTemp.IsNull() ) { m_bChangeLeft = FALSE; } else if ( oTemp.IsNum() ) { m_bChangeLeft = TRUE; m_dLeft = oTemp.GetNum(); } else { // TO DO: Error "Bad annotation destination position" oTemp.Free(); oArrayItem.Free(); return; } oTemp.Free(); } if ( pArray->GetCount() < 4 ) { m_bChangeTop = FALSE; } else { pArray->Get( 3, &oTemp ); if ( oTemp.IsNull() ) { m_bChangeTop = FALSE; } else if ( oTemp.IsNum() ) { m_bChangeTop = TRUE; m_dTop = oTemp.GetNum(); } else { // TO DO: Error "Bad annotation destination position" oTemp.Free(); oArrayItem.Free(); return; } oTemp.Free(); } if ( pArray->GetCount() < 5 ) { m_bChangeZoom = FALSE; } else { pArray->Get( 4, &oTemp ); if ( oTemp.IsNull() ) { m_bChangeZoom = FALSE; } else if ( oTemp.IsNum() ) { m_bChangeZoom = TRUE; m_dZoom = oTemp.GetNum(); } else { // TO DO: Error "Bad annotation destination position" oTemp.Free(); oArrayItem.Free(); return; } oTemp.Free(); } } else if ( oArrayItem.IsName("Fit") ) { if ( pArray->GetCount() < 2 ) { // TO DO: Error "Annotation destination array is too short" oArrayItem.Free(); return; } m_eType = destFit; } else if ( oArrayItem.IsName("FitH") ) { if ( pArray->GetCount() < 3 ) { // TO DO: Error "Annotation destination array is too short" oArrayItem.Free(); return; } m_eType = destFitH; Object oTemp; if ( !pArray->Get(2, &oTemp)->IsNum() ) { // TO DO: Error "Bad annotation destination position" m_eType = destFit; } m_dTop = oTemp.GetNum(); oTemp.Free(); } else if ( oArrayItem.IsName("FitV") ) { if ( pArray->GetCount() < 3 ) { // TO DO: Error "Annotation destination array is too short" oArrayItem.Free(); return; } m_eType = destFitV; Object oTemp; if ( !pArray->Get(2, &oTemp)->IsNum() ) { // TO DO: Error "Bad annotation destination position" m_eType = destFit; } m_dLeft = oTemp.GetNum(); oTemp.Free(); } else if ( oArrayItem.IsName("FitR") ) { if ( pArray->GetCount() < 6 ) { // TO DO: Error "Annotation destination array is too short" oArrayItem.Free(); return; } m_eType = destFitR; Object oTemp; if ( !pArray->Get(2, &oTemp)->IsNum() ) { // TO DO: Error "Bad annotation destination position" m_eType = destFit; } m_dLeft = oTemp.GetNum(); oTemp.Free(); if ( !pArray->Get(3, &oTemp)->IsNum() ) { // TO DO: Error "Bad annotation destination position" m_eType = destFit; } m_dBottom = oTemp.GetNum(); oTemp.Free(); if ( !pArray->Get(4, &oTemp)->IsNum() ) { // TO DO: Error "Bad annotation destination position" m_eType = destFit; } m_dRight = oTemp.GetNum(); oTemp.Free(); if ( !pArray->Get(5, &oTemp)->IsNum() ) { // TO DO: Error "Bad annotation destination position" m_eType = destFit; } m_dTop = oTemp.GetNum(); oTemp.Free(); } else if ( oArrayItem.IsName("FitB") ) { if ( pArray->GetCount() < 2 ) { // TO DO: Error "Annotation destination array is too short" oArrayItem.Free(); return; } m_eType = destFitB; } else if ( oArrayItem.IsName("FitBH") ) { if ( pArray->GetCount() < 3 ) { // TO DO: Error "Annotation destination array is too short" oArrayItem.Free(); return; } m_eType = destFitBH; Object oTemp; if ( !pArray->Get(2, &oTemp)->IsNum() ) { // TO DO: Error "Bad annotation destination position" m_eType = destFit; } m_dTop = oTemp.GetNum(); oTemp.Free(); } else if ( oArrayItem.IsName("FitBV") ) { if ( pArray->GetCount() < 3 ) { // TO DO: Error "Annotation destination array is too short" oArrayItem.Free(); return; } m_eType = destFitBV; Object oTemp; if ( !pArray->Get(2, &oTemp)->IsNum() ) { // TO DO: Error "Bad annotation destination position" m_eType = destFit; } m_dLeft = oTemp.GetNum(); oTemp.Free(); } else { // TO DO: Error "Unknown annotation destination type" oArrayItem.Free(); return; } oArrayItem.Free(); m_bValidate = TRUE; return; } LinkDestination::LinkDestination(LinkDestination *pDest) { m_eType = pDest->m_eType; m_bPageIsRef = pDest->m_bPageIsRef; if ( m_bPageIsRef ) m_oPageRef = pDest->m_oPageRef; else m_nPageNum = pDest->m_nPageNum; m_dLeft = pDest->m_dLeft; m_dBottom = pDest->m_dBottom; m_dRight = pDest->m_dRight; m_dTop = pDest->m_dTop; m_dZoom = pDest->m_dZoom; m_bChangeLeft = pDest->m_bChangeLeft; m_bChangeTop = pDest->m_bChangeTop; m_bChangeZoom = pDest->m_bChangeZoom; m_bValidate = TRUE; } //------------------------------------------------------------------------------------------------------------------------------- // LinkGoTo //------------------------------------------------------------------------------------------------------------------------------- LinkGoTo::LinkGoTo(Object *pDestObject) { m_pDestination = NULL; m_pNamedDestination = NULL; if ( pDestObject->IsName() ) { m_pNamedDestination = new StringExt( pDestObject->GetName() ); } else if ( pDestObject->IsString() ) { m_pNamedDestination = pDestObject->GetString()->Copy(); } else if ( pDestObject->IsArray() ) { m_pDestination = new LinkDestination( pDestObject->GetArray() ); if ( !m_pDestination->CheckValidate() ) { delete m_pDestination; m_pDestination = NULL; } } else { // TO DO: Error "Illegal annotation destination" } } LinkGoTo::~LinkGoTo() { if ( m_pDestination ) delete m_pDestination; if ( m_pNamedDestination ) delete m_pNamedDestination; } //------------------------------------------------------------------------------------------------------------------------------- // LinkGoToR //------------------------------------------------------------------------------------------------------------------------------- LinkGoToR::LinkGoToR(Object *pFileSpecObject, Object *pDestObject) { m_pDestination = NULL; m_pNamedDestination = NULL; m_seFileName = GetFileSpecName( pFileSpecObject ); if ( pDestObject->IsName() ) { m_pNamedDestination = new StringExt( pDestObject->GetName() ); } else if ( pDestObject->IsString() ) { m_pNamedDestination = pDestObject->GetString()->Copy(); } else if ( pDestObject->IsArray() ) { m_pDestination = new LinkDestination( pDestObject->GetArray() ); if ( !m_pDestination->CheckValidate() ) { delete m_pDestination; m_pDestination = NULL; } } else { // TO DO: Error "Illegal annotation destination" } } LinkGoToR::~LinkGoToR() { if ( m_seFileName ) delete m_seFileName; if ( m_pDestination ) delete m_pDestination; if ( m_pNamedDestination ) delete m_pNamedDestination; } //------------------------------------------------------------------------------------------------------------------------------- // LinkLaunch //------------------------------------------------------------------------------------------------------------------------------- LinkLaunch::LinkLaunch(Object *pActionObject) { m_seFileName = NULL; m_pParameters = NULL; if ( pActionObject->IsDict() ) { Object oSpecObject; if ( !pActionObject->DictLookup("F", &oSpecObject)->IsNull() ) { m_seFileName = GetFileSpecName(&oSpecObject); } else { oSpecObject.Free(); if ( pActionObject->DictLookup("Win", &oSpecObject)->IsDict() ) { Object oTemp; oSpecObject.DictLookup("F", &oTemp); m_seFileName = GetFileSpecName(&oTemp); oTemp.Free(); if ( oSpecObject.DictLookup("P", &oTemp)->IsString() ) { m_pParameters = oTemp.GetString()->Copy(); } oTemp.Free(); } else { // TO DO: Error "Bad launch-type link action" } } oSpecObject.Free(); } } LinkLaunch::~LinkLaunch() { if ( m_seFileName ) delete m_seFileName; if ( m_pParameters ) delete m_pParameters; } //------------------------------------------------------------------------------------------------------------------------------- // LinkURI //------------------------------------------------------------------------------------------------------------------------------- LinkURI::LinkURI(Object *pUriObject, StringExt *seBaseURI) { m_seURI = NULL; if ( pUriObject->IsString() ) { StringExt *seTempURI = pUriObject->GetString()->Copy(); if ( seBaseURI && seBaseURI->GetLength() > 0 ) { int nCount = strcspn( seTempURI->GetBuffer(), "/:" ); if ( nCount == seTempURI->GetLength() || seTempURI->GetAt(nCount) == '/' ) { m_seURI = seBaseURI->Copy(); int nChar = m_seURI->GetAt( m_seURI->GetLength() - 1); if ( nChar == '/' || nChar == '?' ) { if ( seTempURI->GetAt(0) == '/' ) { seTempURI->Delete(0); } } else { if ( seTempURI->GetAt(0) != '/' ) { m_seURI->Append('/'); } } m_seURI->Append( seTempURI ); delete seTempURI; } else { m_seURI = seTempURI; } } else { m_seURI = seTempURI; } } else { // TO DO: Error "Illegal URI-type link" } } LinkURI::~LinkURI() { if ( m_seURI ) delete m_seURI; } //------------------------------------------------------------------------------------------------------------------------------- // LinkNamed //------------------------------------------------------------------------------------------------------------------------------- LinkNamed::LinkNamed(Object *pNameObject) { m_seName = NULL; if ( pNameObject->IsName() ) { m_seName = new StringExt(pNameObject->GetName()); } } LinkNamed::~LinkNamed() { if ( m_seName ) { delete m_seName; } } //------------------------------------------------------------------------------------------------------------------------------- // LinkMovie //------------------------------------------------------------------------------------------------------------------------------- LinkMovie::LinkMovie(Object *pAnnotObject, Object *pTitleObject) { m_oAnnotRef.nNum = -1; m_seTitle = NULL; if ( pAnnotObject->IsRef() ) { m_oAnnotRef = pAnnotObject->GetRef(); } else if ( pTitleObject->IsString() ) { m_seTitle = pTitleObject->GetString()->Copy(); } else { // TO DO: Error "Movie action is missing both the Annot and T keys" } } LinkMovie::~LinkMovie() { if ( m_seTitle ) { delete m_seTitle; } } //------------------------------------------------------------------------------------------------------------------------------- // LinkUnknown //------------------------------------------------------------------------------------------------------------------------------- LinkUnknown::LinkUnknown(char *sAction) { m_seAction = new StringExt( sAction ); } LinkUnknown::~LinkUnknown() { if ( m_seAction ) delete m_seAction; } //------------------------------------------------------------------------------------------------------------------------------- // Link //------------------------------------------------------------------------------------------------------------------------------- Link::Link(Dict *pDict, StringExt *seBaseURI) { m_pAction = NULL; m_bValid = FALSE; // Rect Object oDictItem; if ( !pDict->Search("Rect", &oDictItem)->IsArray() ) { // TO DO: Error "Annotation rectangle is wrong type" oDictItem.Free(); return; } Object oTemp; if ( !oDictItem.ArrayGet( 0, &oTemp )->IsNum() ) { // TO DO: Error "Bad annotation rectangle" oTemp.Free(); oDictItem.Free(); return; } m_dLeft = oTemp.GetNum(); oTemp.Free(); if ( !oDictItem.ArrayGet( 1, &oTemp )->IsNum() ) { // TO DO: Error "Bad annotation rectangle" oTemp.Free(); oDictItem.Free(); return; } m_dBottom = oTemp.GetNum(); oTemp.Free(); if ( !oDictItem.ArrayGet( 2, &oTemp )->IsNum() ) { // TO DO: Error "Bad annotation rectangle" oTemp.Free(); oDictItem.Free(); return; } m_dRight = oTemp.GetNum(); oTemp.Free(); if ( !oDictItem.ArrayGet( 3, &oTemp )->IsNum() ) { // TO DO: Error "Bad annotation rectangle" oTemp.Free(); oDictItem.Free(); return; } m_dTop = oTemp.GetNum(); oTemp.Free(); oDictItem.Free(); if ( m_dLeft > m_dRight ) { double dTemp = m_dLeft; m_dLeft = m_dRight; m_dRight = dTemp; } if ( m_dBottom > m_dTop ) { double dTemp = m_dBottom; m_dBottom = m_dTop; m_dTop = dTemp; } // Dest if ( !pDict->Search("Dest", &oDictItem)->IsNull() ) { m_pAction = LinkAction::ParseDestination(&oDictItem); } else // A (Action) { oDictItem.Free(); if ( pDict->Search("A", &oDictItem)->IsDict() ) { m_pAction = LinkAction::ParseAction(&oDictItem, seBaseURI); } } oDictItem.Free(); if ( m_pAction ) { m_bValid = TRUE; } return; } Link::~Link() { if ( m_pAction ) { delete m_pAction; } } //------------------------------------------------------------------------------------------------------------------------------- // Links //------------------------------------------------------------------------------------------------------------------------------- Links::Links(Object *pAnnots, StringExt *seBaseURI) { m_ppLinks = NULL; m_nLinksCount = 0; int nSize = 0; if ( pAnnots->IsArray() ) { for ( int nIndex = 0; nIndex < pAnnots->ArrayGetLength(); ++nIndex ) { Object oArrayItem; if ( pAnnots->ArrayGet( nIndex, &oArrayItem )->IsDict() ) { Object oTemp; if ( oArrayItem.DictLookup("Subtype", &oTemp)->IsName("Link") ) { Link *pLink = new Link( oArrayItem.GetDict(), seBaseURI ); if ( pLink->CheckValidate() ) { if ( m_nLinksCount >= nSize ) { nSize += 16; m_ppLinks = (Link **)MemUtilsReallocArray( m_ppLinks, nSize, sizeof(Link *)); } m_ppLinks[m_nLinksCount++] = pLink; } else { if ( pLink ) delete pLink; } } oTemp.Free(); } oArrayItem.Free(); } } } Links::~Links() { for ( int nIndex = 0; nIndex < m_nLinksCount; ++nIndex ) { if ( m_ppLinks[nIndex] ) delete m_ppLinks[nIndex]; } MemUtilsFree(m_ppLinks); } LinkAction *Links::Find(double dX, double dY) { for ( int nIndex = m_nLinksCount - 1; nIndex >= 0; --nIndex ) { if ( m_ppLinks[nIndex]->InRect(dX, dY) ) { return m_ppLinks[nIndex]->GetAction(); } } return NULL; } BOOL Links::OnLink(double dX, double dY) { for ( int nIndex = 0; nIndex < m_nLinksCount; ++nIndex ) { if ( m_ppLinks[nIndex]->InRect(dX, dY) ) return TRUE; } return FALSE; }