/*
//
//   ADOBE SYSTEMS INCORPORATED
//   Copyright (C) 2000-2003 Adobe Systems Incorporated
//   All rights reserved.
//
//   NOTICE: Adobe permits you to use, modify, and distribute this file
//   in accordance with the terms of the Adobe license agreement
//   accompanying it. If you have received this file from a source other
//   than Adobe, then your use, modification, or distribution of it
//   requires the prior written permission of Adobe.
//
*/
/*
// 
// Description:
//     This file contains several externally visible functions:
//         _ Get a PDF file's base URI (if any)
//         - Enumerate weblinks in a PDF file
//         - Get a URI from a PDAction
//         - Set a PDAction's URI
//         - Get an annotation's PDAction
// 
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "CosCalls.h"
#include "CorCalls.h"
#include "ASCalls.h"
#include "PDCalls.h"
#include "NSelExpT.h"
#include "extrURI.h"
#include "PIExcept.h"

/* Line endings - lineend is defined so that it is correct for Mac, Win, UNIX */
#ifdef WIN_ENV
#define lineend "\r\n"
#elif MAC_ENV
#define lineend "\r"
#else
#define lineend "\n"
#endif

#define MAX_URI_SIZE 2048

/* Static Function Declarations */
static   char  *CosCStringValue( char  *cBuf,  CosObj  coValue,  int  nLen);
static   ASBool   CosObjIsValid(CosObj  co,  CosType  ct);


/**************************************************************************
   Function name: 
       PDDocGetBaseURI
   
   Description:
       Gets the base URL, if any, from a specified PDF file.
       
   Input parameters:
       pdd - The document whose base URI is to be obtained
       cBase - Buffer into which base URI will be written
       nLen - Length of buffer (in bytes)into which URI is written
       
   Output parameters:
       cBase - Buffer containing base URI
       
   Return value:
       true if the document has a base URI 
       false if the document has no base URL, if cBase is NULL, or nLen is 0.

****************************************************************************/
ASBool   PDDocGetBaseURI(PDDoc  pdd,  char  *cBase,  Uns16  nLen)
{
                CosObj  coDict, coBase;

                /* Get the catalog. */
               coDict =  CosDocGetRoot(PDDocGetCosDoc(pdd));
                if  (!CosObjIsValid(coDict,  CosDict))
                                return   false ;

                /* Get the URI dictionary. */
               coDict =  CosDictGet(coDict,  ASAtomFromString( "URI" ));
                if  (!CosObjIsValid(coDict,  CosDict))
                                return   false ;

                /* Get the Base key. */
               coBase =  CosDictGet(coDict,  ASAtomFromString( "Base" )); 
                if  (!CosObjIsValid(coBase,  CosString))
                                return   false ;

                CosCStringValue(cBase, coBase, nLen);
                return   true ;
}


/**************************************************************************
   Function name: 
       PDDocEnumURILinks
   
   Description:
       Enumerates weblinks on a specific page, or on all pages, of 
       a specified PDF file.
       
   Input parameters:
       pdd - The document whose whose weblinks are to be enumerated
       nPageNum - Page number for which to enumerate wseblinks. The first page in
           a PDF file has page number zero. Pass PDAllPages to enumerate weblinks 
           on all pages.
       linkProc - User-supplied procedure that is called for each weblink found
       vClientData - User-supplied data that is passed to linkProc each time that 
           it is called.
       
   Output parameters:
       None
       
   Return value:
       None

****************************************************************************/
void   PDDocEnumURILinks(PDDoc  pdd,  Int32  nPageNum,
                PDURILinkEnumProc  linkProc,  void  *vClientData)
{
                Int32  nNumPages, nStartPage, nEndPage;
                Int32  nError;
                register   Int32  i;
               
                if  (linkProc ==  NULL) {
                ASRaise(GenError(genErrBadParm));
               }
               
               nError = 0;         
                DURING
                       nNumPages =  PDDocGetNumPages(pdd);
                       nStartPage = 0;
                       nEndPage = nNumPages;

                                /* Determine the start and end page numbers. */
                        if  (nPageNum !=  PDAllPages)
                               {
                                                if  (nPageNum >= nNumPages || nPageNum < 0)
                                                ASRaise(GenError(genErrBadParm));
                                               
                                               nStartPage = nPageNum;
                                               nEndPage = nStartPage + 1;
                               }

                                /* Loop over each requested page. */
                                for  (i = nStartPage; i < nEndPage; i++){
                                                PDPage  pdp =  PDDocAcquirePage(pdd, i);
                                                Int32  nNumAnnots;
                                                register   Int32  j;
                                                char  cURI[MAX_URI_SIZE];
                                                PDAction  pdac;
                                               
                                               fprintf( stdout,  "." );
                                               fflush(stdout);
                                               
                                                /* Loop over all annotations on the page. */
                                               nNumAnnots =  PDPageGetNumAnnots(pdp);
                                                for  (j = 0; j < nNumAnnots; j++){
                                                                /* Get the annotation and check to see if it's a link. */
                                                                PDAnnot  pdan;
                                                               pdan =  PDPageGetAnnot(pdp, j);
                                                                if  (!PDAnnotIsValid(pdan) || 
                                                                    PDAnnotGetSubtype(pdan) !=    ASAtomFromString( "Link" ))
                                                                                continue ;
                                                               
                                                                /* Try to get the action dictionary. */
                                                               pdac =  PDAnnotGetAction(pdan);
                                                                if  (PDActionGetURI(pdac, cURI,  sizeof (cURI))){
                                                                                if  (!linkProc(pdp, pdan, cURI, vClientData)){
                                                                                                /* linkProc has asked us to stop. */
                                                                                                PDPageRelease(pdp);
                                                                                                E_RTRN_VOID;
                                                                               }
                                                               }
                                               }

                                                PDPageRelease(pdp);
                               }

                HANDLER
                               nError =  ERRORCODE;
                END_HANDLER
                if  (nError)
                        ASRaise(nError);
}

/**************************************************************************
   Function name: 
       PDActionGetURI
   
   Description:
       Gets the URI from a specified action.
       
   Input parameters:
       pdac - The action whose URI is to be obtained
       cURI - buffer into which the URI is to be written
       nLen - Maximum number of bytes that cURI can hold
       
   Output parameters:
       cURI - The action's URI. If the URI will not fit, the URI is truncated
               
   Return value:
       true if the URI was successfully obtained, false otherwise

****************************************************************************/
ASBool   PDActionGetURI(PDAction  pdac,  char  *cURI,  Uns16  nLen)
{
                CosObj  coAction, coURI;
                PDFileSpec  filespec;
                char  buf[MAX_URI_SIZE  + 10];


                /* Make sure we have a valid action. */
                if  (!PDActionIsValid(pdac))
                                return   false ;
               
                /* Make sure that the subtype is URI. */
                if  (PDActionGetSubtype(pdac) ==  ASAtomFromString( "URI" )){
               coAction =  PDActionGetCosObj(pdac);
               
                /* Get the value of the URI key.*/
               coURI =  CosDictGet(coAction,  ASAtomFromString( "URI" ));
                if  (!CosObjIsValid(coURI,  CosString))
                                return   false ;
               
                CosCStringValue(cURI, coURI, nLen);
               
                if  (!strstr(cURI, "http://" )){
                               strcpy(buf, "http://" );
                               strcat(buf, cURI);
                               strcpy(cURI, buf);
                               }
                return   true ;
               }
               
                if  (PDActionGetSubtype(pdac) ==  ASAtomFromString( "GoToR" ) ||  PDActionGetSubtype(pdac) ==  ASAtomFromString( "Launch" )){
                               filespec =  PDActionGetFileSpec(pdac);
                                PDFileSpecGetDIPath(filespec, cURI,MAX_URI_SIZE);
                               
                               strcpy(buf,  ASAtomGetString(PDActionGetSubtype(pdac)));
                               strcat(buf,  ": " );
                               strcat(buf, cURI);
                               strcpy(cURI, buf);
                                return   true ;
               }
                return   false ;
               
               
}


/**************************************************************************
   Function name: 
       PDAnnotGetAction
   
   Description:
       Gets the action from a specified PDAnnot.
       
   Input parameters:
       pdan - The PDAnnot whose action is to be obtained
       
   Output parameters:
       None
               
   Return value:
       The action associated with the specified PDAnnot. Returns a NULL Cos object
       if the PDAnnot does not have an action (i.e., does not have an "A" key)

****************************************************************************/
PDAction   PDAnnotGetAction(PDAnnot  pdan)
{
                CosObj  coAction;
                CosObj  coAnnot =  PDAnnotGetCosObj(pdan);
                CosObj  coNull =  CosNewNull();
               
                if  (!CosObjIsValid(coAnnot,  CosDict))
                                return  (*(PDAction  *) &(coNull));

                /* Get the Action dict. */
               coAction =  CosDictGet(coAnnot,  ASAtomFromString( "Action" ));
                if  (CosObjGetType(coAction) !=  CosDict) {
                               coAction =  CosDictGet(coAnnot,  ASAtomFromString( "A" ));
                                if  (CosObjGetType(coAction) !=  CosDict)
                                                return  (*(PDAction  *) &(coNull));
               }

                return   PDActionFromCosObj(coAction);
}

/* ---- Static Function Definitions ---- */


/**************************************************************************
   Function name: 
       CosObjIsValid
   
   Description:
       Tests whether or not a specified COS Object is valid. Note that this test
       is minimal; the object is valid if it is not a NULL object, and if it is
       of the specified type.
       
   Input parameters:
       obj - The COS object whose validity is to be tested
       objType - The object type (boolean, string, dictionary...) that obj is 
           supposed to be
       
   Output parameters:
       None
       
   Return value:
       true if the object is valid, falce otherwise

****************************************************************************/
static   ASBool   CosObjIsValid(CosObj  obj,  CosType  objType)
{
                return  !((CosObjGetType(obj) ==  CosNull) ||  CosObjGetType(obj) != objType);
}


/**************************************************************************
   Function name: 
       CosCStringValue
   
   Description:
       Gets the value of a specified COS string as a C-style string.
       
   Input parameters:
       cBuf - Buffer into which the COS string's value is to be placed
       objType - The object type (boolean, string, dictionary...) that obj is 
           supposed to be
       nLen - Maximum number of bytes that cBuf can hold
       
   Output parameters:
       cBuf - The value of the COS string. If the string's value is longer than
           nLen, the string is truncated to fit into cBuf.
       
   Return value:
       The value of the COS string.

****************************************************************************/
static   char  *CosCStringValue( char  *cBuf,  CosObj  coValue,  int  nLen)
{
                Int32  nCount;
                char  *c =  CosStringValue(coValue, &nCount);

                if  (nCount > nLen - 1)
                               nCount = nLen - 1;

                while (nCount--)
                               *cBuf++ = *c++;
               *cBuf =  '\0' ;

                return  cBuf;
}



/**************************************************************************
   Function name: 
       getURI
   
   Description:
       Extracts the URL from the first weblink annotation on the first page of a 
       specified document. Prints the URL to a specified file.
   
   Input parameters:
         docP - PDDoc from which URL is to be extracted
         outf - file into which output is to be written (NULL if none)
   
   Output parameters:
       None
   
   Return value:
       None
**************************************************************************/
void   getURI(PDDoc  docP, FILE *outf)
{
                PDAction  action;
                PDPage  page;
                char  buf[32];
                PDAnnot  annot;
               
                DURING
                   strcpy(buf,  "thisisit" );
                   page =  PDDocAcquirePage(docP, 0);
                   annot =  PDPageGetAnnot(page, 0);
                   action =  PDAnnotGetAction(annot);
                    PDActionGetURI(action, ( char  *)&buf,  sizeof (buf));
                   fprintf(outf,  "%s\n" , buf);
                    PDPageRelease(page);
                HANDLER
                END_HANDLER
}