/*
*
* $Author: philipp $
* $Revision: 1.1 $
* $Log: pdfchinfo.c,v $
* Revision 1.1  2002/10/17 19:37:51  philipp
* File name was changed.
*
* Revision 1.1  2002/10/17 19:37:42  philipp
* *** Empty log message ***
*
*/

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

#define progversion "1.0a"
#define producer "pdfchinfo (c) 2002 by Philipp Dunkel <philipp@dunkel.org> (GPL)"

#define chunksize 1024

typedef struct hashitem {
 unsigned char *key;
 char *val;
 struct hashitem *next;
} hashitem;

hashitem *infohash=NULL;
char *filename=NULL;

void usage(const char* program)
{
 fprintf(stderr,"Usage: %s <filename> <key>=<value> [<key>=<value> ...]\nTry \"%s –help\" for more information.\n",program,program);
}

void version(const char *program)
{
 fprintf(stderr,"%s version %s\n(c) 2002 by Philipp Dunkel <philipp@dunkel.org>\nReleased under General Public License\n",program,progversion);
}

void help(const char *program)
{
 fprintf(stderr,"pdfchinfo can change the values of the PDF Info-Dictionary.\nThis program is designed to post-process PDF-Files created with GhostScript.\nIt can handle PDF version 1.0 – 1.4.\nAnd don’t try this on encrypted stuff you might have to fix your file by cutting of the stuff that was added.\nThis does conform to the specs by simply adding stuff to the end of the file.\n");
 version(program);
}

void addhashitem(struct hashitem** hash, const char *nkey, const char *nval)
{
 int i=0;
 char hexbuf[3];
 struct hashitem *temp = (struct hashitem*)malloc(sizeof(struct hashitem));
 temp->next=*hash;
 *hash=temp;

 if (strchr(nkey,’\n’)!=NULL) { return; }
 if (strchr(nkey,’\r’)!=NULL) { return; }
 if (strchr(nkey,’\t’)!=NULL) { return; }
 if (strchr(nkey,’/')!=NULL) { return; }
 if (strchr(nkey,’\\’)!=NULL) { return; }
 if (strchr(nkey,’ ‘)!=NULL) { return; }
 if (strchr(nkey,’\”)!=NULL) { return; }
 if (strchr(nkey,’\"’)!=NULL) { return; }
 if (strchr(nkey,’>’)!=NULL) { return; }
 if (strchr(nkey,’<’)!=NULL) { return; }
 if (strchr(nkey,’(‘)!=NULL) { return; }
 if (strchr(nkey,’)')!=NULL) { return; }
 if (strchr(nkey,’[')!=NULL) { return; }
 if (strchr(nkey,']‘)!=NULL) { return; }

 (*hash)->key=(char*)malloc(strlen(nkey)+2);
 strcpy((*hash)->key,"/");
 strcat((*hash)->key,nkey);

 (*hash)->val=(char*)malloc((strlen(nval) * 2)+3);
 strcpy((*hash)->val,"<");
 for (i=0;i<strlen(nval);i++) {
  hexbuf[0]=0;
  snprintf(hexbuf,3,"%X",nval[i]);
  strcat((*hash)->val,hexbuf);
 }
 strcat((*hash)->val,">");
}

int initialize(int argc, char* argv[])
{
 int i=1;
 char *cur=NULL;
 for(i=1;i<argc;i++) {
  if (strcmp(argv[i],"-V") == 0) {
   version(argv[0]);
   return 1;
  } else if ((strcmp(argv[i],"-h") == 0)||(strcmp(argv[i],"–help") == 0)) {
   usage(argv[0]);
   help(argv[0]);
   return 1;
  } else if (*argv[i]==’-') {
   usage(argv[0]);
   return 1;
  } else if (strchr(argv[i],’=') != NULL) {
   cur=strdup(argv[i]);
   *(strchr(cur,’='))=0;
   addhashitem(&infohash,cur,strchr(cur,0)+1);
   free(cur);
  } else {
   if (filename != NULL) {
    free(filename);
   }
   filename=strdup(argv[i]);
  }
 }
 if (infohash == NULL) {
  usage("pdfchinfo");
  return 1;
 }
 addhashitem(&infohash,"Producer",producer);
 return 0;
}

void finalize(void)
{
 struct hashitem *temp=NULL;
 while (infohash != NULL) {
  temp=infohash;
  infohash=infohash->next;
  free(temp);
  temp=NULL;
 }
 if (filename != NULL) {
  free(filename);
  filename=NULL;
 }
}


struct filedef {
 long size;
 long trailer;
 long xref;
 int objects;
 int rootid;
 int rootgen;
 int infoid;
 int infogen;
};

void nullnorm(struct filedef *fd)
{
 fd->size=0;
 fd->trailer=0;
 fd->xref=0;
 fd->objects=0;
 fd->rootid=0;
 fd->rootgen=0;
 fd->infoid=0;
 fd->infogen=0;
}

int writedict(FILE *stream, const int id, const int gen)
{
 long result=0;
 int err=0;
 struct hashitem *mover=infohash;
 err=fprintf(stream, "%d %d obj\n<<\n",id,gen);
 if (err < 0) {
  fprintf(stderr,"Error: Could not write to file!\n");
  return -1;
 }
 result += err;
 while (mover != NULL) {
  err=fprintf(stream, "%s%s\n",mover->key,mover->val);
  if (err < 0) {
   fprintf(stderr,"Error: Could not write to file!\n");
   return -1;
  }
  result += err;
  mover=mover->next;
 }
 err=fprintf(stream, ">>\nendobj\n");
 if (err < 0) {
  fprintf(stderr,"Error: Could not write to file!\n");
  return -1;
 }
 result += err;
 return result;
}

char *strrstr(char *haystack, const char *needle, const int haylength)
{
 char *mover=haystack+haylength;
 if (haylength == 0) {
  mover=strchr(haystack,’\0′);
 }
 while ((mover >= haystack) && (strncmp(mover,needle,strlen(needle)) != 0)) {
  mover–;
 }
 return mover>=haystack?mover:NULL;
}

int treatfile(void)
{
 char buffer[chunksize+1];
 FILE *infile = fopen(filename,"r");
 memset(buffer,0,chunksize+1);
 char *t1=NULL;
 char *t2=NULL;
 long offset=0;
 struct filedef input;
 long newxref=0;

 nullnorm(&input);

 if (infile == NULL) {
  fprintf(stderr,"Error: Cannot open file!\n");
  fclose(infile);
  return 1;
 }
 if (fread(buffer,1,chunksize,infile) == 0) {
  if (ferror(infile)) {
   fprintf(stderr,"Error: Cannot read from file!\n");
   fclose(infile);
   return 1;
  }
 }
 t1=strstr(buffer,"%PDF");
 if (t1 == NULL) {
  fprintf(stderr,"Error: This is not a PDF-file!\n");
  fclose(infile);
  return 1;
 }
 if (fseek(infile,t1-buffer,SEEK_SET)==-1) {
  fprintf(stderr,"Error: Cannot seek file!\n");
  fclose(infile);
  return 1;
 }
 if (fread(buffer,1,chunksize,infile) == 0) {
  if (ferror(infile)) {
   fprintf(stderr,"Error: Cannot read from file!\n");
   fclose(infile);
   return 1;
  }
 }
 t1=strstr(buffer,"/Linearized 1");
 if (t1 != NULL) {
  fprintf(stderr,"Error: This PDF-file has been Linearized! It should not be updated.\nIf you really want to do it convert to PS with pdftops and back to PDF with ps2pdf.\nAfter that use pdfchinfo again.\nIf you then want, you can then linearize it again with pdfopt.\n");
  fclose(infile);
  return 1;
 }

 if (fseek(infile,0,SEEK_END)==-1) {
  fprintf(stderr,"Error: Cannot seek file!\n");
  fclose(infile);
  return 1;
 }
 input.size=ftell(infile);

 offset=0;
 while ((input.trailer == 0) && (offset < input.size)) {
  offset+=(offset+chunksize-7)>input.size?input.size-offset:chunksize-7;
  if(fseek(infile,-1 * offset,SEEK_END) == -1) {
   fprintf(stderr,"Error: Cannot seek file!\n");
   fclose(infile);
   return 1;
  }
  memset(buffer,0,chunksize+1);
  if (fread(buffer,1,chunksize,infile) == 0) {
   if (ferror(infile)) {
    fprintf(stderr,"Error: Cannot read from file!\n");
    fclose(infile);
    return 1;
   }
  }
  t1=strrstr(buffer,"trailer",chunksize);
  if (t1 != NULL) {
   offset-=(t1-buffer);
   input.trailer=input.size-offset;
   t1=NULL;
  }
 }
 if (input.trailer == 0) {
  fprintf(stderr,"Error: This file does not have a trailer anywhere!\n");
  fclose(infile);
  return 0;
 }
 if (fseek(infile,input.trailer,SEEK_SET)==-1) {
  fprintf(stderr,"Error: Cannot seek file!\n");
  fclose(infile);
  return 1;
 }
 memset(buffer,1,chunksize+1);
 if(fread(buffer,1,chunksize,infile)==0) {
  if (ferror(infile)) {
   fprintf(stderr,"Error: Cannot read from file!\n");
   fclose(infile);
   return 1;
  }
 }

 t1=strstr(buffer,"/Size");
 if (t1 == NULL) {
  fprintf(stderr,"Error: This file does not specify an object count!\n");
  fclose(infile);
  return 0;
 }
 t1+=6;
 input.objects=atoi(t1);
 if (input.objects < 1) {
  fprintf(stderr,"Error: This file has no objects!\n");
  fclose(infile);
  return 0;
 }

 t1=strstr(buffer,"/Root");
 if (t1 == NULL) {
  fprintf(stderr,"Error: This file does not specify a root object!\n");
  fclose(infile);
  return 0;
 }
 t1+=6;
 input.rootid=atoi(t1);
 if (input.rootid < 1) {
  fprintf(stderr,"Error: This file has no root object!\n");
  fclose(infile);
  return 0;
 }
 t1=strchr(t1,’ ‘);
 if (t1 == NULL) {
  fprintf(stderr,"Error: This file does not specify a root with a generation object!\n");
  fclose(infile);
  return 0;
 }
 t1++;
 input.rootgen=atoi(t1);
 t1=NULL;

 do {
  t1=strstr(buffer,"startxref");
  if (t1 != NULL) {
   t1+=9;
   while (((*t1 == ‘\n’)||(*t1 == ‘\r’))&&(*t1 != 0)) {
    t1++;
   }
   input.xref=strtol(t1,NULL,0);
   t1=NULL;
  } else {
   offset=offset-chunksize+9;
   offset=offset<0?0:offset;
   memset(buffer,0,chunksize+1);
   if (fseek(infile,-1 * offset,SEEK_END)==-1) {
    fprintf(stderr,"Error: Cannot seek file!\n");
    fclose(infile);
    return 1; 
   }
  }
  if (fread(buffer,1,chunksize,infile) == 0) {
   if (ferror(infile)) {
    fprintf(stderr,"Error: Cannot read from file!\n");
    fclose(infile);
    return 1;
   }
  }
 } while ((input.xref == 0) && (offset-chunksize>0));

 offset=input.size>chunksize?chunksize:input.size;
 do {
  if (fseek(infile,-1 * offset,SEEK_END) == -1) {
   fprintf(stderr,"Error: Cannot seek file!\n");
   fclose(infile);
   return 1;
  }
  if (fread(buffer,1,chunksize,infile) == 0) {
   if (ferror(infile)) {
    fprintf(stderr,"Error: Cannot read from file!\n");
    fclose(infile);
    return 1;
   }
  }
  t1=strstr(buffer,"trailer");
  if (t1 != NULL) {
   if (fseek(infile,-1 * (offset-(t1-buffer)),SEEK_END) == -1) {
    fprintf(stderr,"Error: Cannot read from file!\n");
    fclose(infile);
    return 1;
   }
   if (fread(buffer,1,chunksize,infile) == 0) {
    if (ferror(infile)) {
     fprintf(stderr,"Error: Cannot read from file!\n");
     fclose(infile);
     return 1;
    }
   }
   t1=strstr(buffer,"/Info");
   if (t1 != NULL) {
    t1+=5;
    while (((*t1 == ‘\n’)||(*t1 == ‘\r’))&&(*t1 != 0)) {
     t1++;
    }
    input.infoid=atoi(t1);
    while ((*t1 != ‘\n’)&&(*t1 != ‘\r’)&&(*t1 != 0)) {
     t1++;
    }
    while (((*t1 == ‘\n’)||(*t1 == ‘\r’))&&(*t1 != 0)) {
     t1++;
    }
    input.infogen=atoi(t1);
    input.infoid=input.infoid<1?0:input.infoid;
    t1=NULL;
   } else {
    t1=offset==input.size?buffer:NULL;
    offset=offset+chunksize;
    offset=offset>input.size?input.size:offset;
   }
  } else {
   t1=offset==input.size?buffer:NULL;
   offset=offset+chunksize-7;
   offset=offset>input.size?input.size:offset;
  }
 } while ((input.infoid == 0)&&(t1==NULL));

 fclose(infile);
 infile=fopen(filename,"a");
 if (infile == NULL) {
  fprintf(stderr,"Error: Cannot open file!\n");
  return 1;
 }
 newxref=writedict(infile,input.objects,0);
 if (newxref < 0) {
  if (ferror(infile)) {
   fprintf(stderr,"Error: Cannot write to file!\n");
   fclose(infile);
   return 1;
  }
 }
 newxref += input.size;
 if (fprintf(infile,"xref\n0 1\n%010d 65535 f\r\n",input.infoid) < 0) {
  if (ferror(infile)) {
   fprintf(stderr,"Error: Cannot write to file!\n");
   fclose(infile);
   return 1;
  }
 }
 if (input.infoid != 0) {
  if(fprintf(infile,"\n%d 1\n%010d %05d f\r\n",input.infoid,0,input.infogen+1) < 0) {
   if (ferror(infile)) {
    fprintf(stderr,"Error: Cannot write to file!\n");
    fclose(infile);
    return 1;
   }

  }
 }
 if (fprintf(infile,"\n%d 1\n%010d %05d n\r\n",input.objects,input.size,0) < 0) {
  if (ferror(infile)) {
   fprintf(stderr,"Error: Cannot write to file!\n");
   fclose(infile);
   return 1;
  }
 }
 if (fprintf(infile,"trailer\n<<\n/Size %d\n/Root %d %d R\n/Prev %d\n/Info %d %d R\n>>\nstartxref\n%d\n%%%%EOF\n",input.objects+1,input.rootid,input.rootgen,input.xref,input.objects,0,newxref) < 0) {
  if (ferror(infile)) {
   fprintf(stderr,"Error: Cannot write to file!\n");
   fclose(infile);
   return 1;
  }
 }
 return 0;
}

int main(int argc, char* argv[])
{
 int result=0;
 if (initialize(argc,argv) == 0) {
  if (filename != NULL) {
   if (result=treatfile() != 0) {
    fprintf(stderr,"Error processing file \"%s\"!\n",filename);
    usage(argv[0]);
   }
  } else {
   usage(argv[0]);
  }
 }
 finalize();
 return 0;
}


评论

该日志第一篇评论

发表评论

评论也有版权!