1/*---------------------------------------------------------------------------* 2 | PDFlib - A library for generating PDF on the fly | 3 +---------------------------------------------------------------------------+ 4 | Copyright (c) 1997-2004 Thomas Merz and PDFlib GmbH. All rights reserved. | 5 +---------------------------------------------------------------------------+ 6 | | 7 | This software is subject to the PDFlib license. It is NOT in the | 8 | public domain. Extended versions and commercial licenses are | 9 | available, please check http://www.pdflib.com. | 10 | | 11 *---------------------------------------------------------------------------*/ 12 13/* $Id: pc_file.c 14574 2005-10-29 16:27:43Z bonefish $ 14 * 15 * Various file routines 16 * 17 */ 18 19#include <errno.h> 20 21#include "pc_config.h" 22#include "pc_util.h" 23#include "pc_md5.h" 24#include "pc_file.h" 25 26/* headers for getpid() or _getpid(). 27*/ 28#if defined(WIN32) 29#define WIN32_LEAN_AND_MEAN 30#include <windows.h> 31#include <process.h> 32#else 33#if !defined(MAC) 34 #include <sys/types.h> 35 #include <unistd.h> 36#endif 37#endif 38 39#ifndef WINCE 40#include <time.h> 41#else 42#include <winbase.h> 43#endif 44 45struct pdc_file_s 46{ 47 pdc_core *pdc; /* pdcore struct */ 48 char *filename; /* file name */ 49 FILE *fp; /* file struct or NULL. Then data != NULL: */ 50 const pdc_byte *data; /* file data or NULL. Then fp != NULL */ 51 const pdc_byte *end; /* first byte above data buffer */ 52 const pdc_byte *pos; /* current file position in data buffer */ 53 pdc_byte *tdata; /* temporary buffer filled up by ungetc */ 54 int number; /* next available entry in tdata buffer */ 55 int capacity; /* currently allocated size of tdata buffer */ 56}; 57 58#if defined(_MSC_VER) && defined(_MANAGED) 59#pragma unmanaged 60#endif 61int 62pdc_get_fopen_errnum(pdc_core *pdc, int errnum) 63{ 64 int outnum = errnum, isread; 65 66 (void) pdc; 67 68 isread = (errnum == PDC_E_IO_RDOPEN); 69 70#if defined(MVS) 71 72 switch (errno) 73 { 74 case 49: 75 outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NF; 76 } 77 return outnum; 78 79#elif defined(WIN32) 80 { 81 DWORD lasterror = GetLastError(); 82 switch (lasterror) 83 { 84 case ERROR_ACCESS_DENIED: 85 outnum = isread ? PDC_E_IO_RDOPEN_PD : PDC_E_IO_WROPEN_PD; 86 break; 87 88 case ERROR_FILE_NOT_FOUND: 89 case ERROR_INVALID_DRIVE: 90 case ERROR_BAD_UNIT: 91 outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NF; 92 break; 93 94 case ERROR_INVALID_NAME: 95 outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_IS; 96 break; 97 98 case ERROR_PATH_NOT_FOUND: 99 outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NP; 100 break; 101 102 case ERROR_TOO_MANY_OPEN_FILES: 103 case ERROR_SHARING_BUFFER_EXCEEDED: 104 outnum = isread ? PDC_E_IO_RDOPEN_TM : PDC_E_IO_WROPEN_TM; 105 break; 106 107 case ERROR_FILE_EXISTS: 108 outnum = PDC_E_IO_WROPEN_AE; 109 break; 110 111 case ERROR_BUFFER_OVERFLOW: 112 outnum = PDC_E_IO_WROPEN_TL; 113 break; 114 115 case ERROR_WRITE_FAULT: 116 case ERROR_CANNOT_MAKE: 117 outnum = PDC_E_IO_WROPEN_NC; 118 break; 119 120 case ERROR_HANDLE_DISK_FULL: 121 outnum = PDC_E_IO_WROPEN_NS; 122 break; 123 } 124 125 if (lasterror) 126 return outnum; 127 128 /* if lasterror == 0 we must look for errno (see .NET) */ 129 } 130 131#endif /* WIN32 */ 132 133 switch (errno) 134 { 135#ifdef EACCES 136 case EACCES: 137 outnum = isread ? PDC_E_IO_RDOPEN_PD : PDC_E_IO_WROPEN_PD; 138 break; 139#endif 140#ifdef ENOENT 141 case ENOENT: 142 outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NF; 143 break; 144#endif 145#ifdef EMFILE 146 case EMFILE: 147 outnum = isread ? PDC_E_IO_RDOPEN_TM : PDC_E_IO_WROPEN_TM; 148 break; 149#endif 150#ifdef ENFILE 151 case ENFILE: 152 outnum = isread ? PDC_E_IO_RDOPEN_TM : PDC_E_IO_WROPEN_TM; 153 break; 154#endif 155#ifdef EISDIR 156 case EISDIR: 157 outnum = isread ? PDC_E_IO_RDOPEN_ID : PDC_E_IO_WROPEN_ID; 158 break; 159#endif 160#ifdef EEXIST 161 case EEXIST: 162 outnum = PDC_E_IO_WROPEN_AE; 163 break; 164#endif 165#ifdef ENAMETOOLONG 166 case ENAMETOOLONG: 167 outnum = PDC_E_IO_WROPEN_TL; 168 break; 169#endif 170#ifdef ENOSPC 171 case ENOSPC: 172 outnum = PDC_E_IO_WROPEN_NS; 173 break; 174#endif 175 default: 176 outnum = errnum; 177 break; 178 } 179 180 return outnum; 181} 182#if defined(_MSC_VER) && defined(_MANAGED) 183#pragma managed 184#endif 185 186void * 187pdc_read_file(pdc_core *pdc, FILE *fp, size_t *o_filelen, int incore) 188{ 189 static const char *fn = "pdc_read_file"; 190 size_t filelen, len; 191 char *content = NULL; 192 193#if defined(MVS) && defined(I370) 194#define PDC_READ_CHUNKSIZE 64000 195 196 while (!feof(fp)) 197 { 198 if (!content) 199 { 200 len = 0; 201 filelen = PDC_READ_CHUNKSIZE; 202 content = (char *) pdc_malloc(pdc, filelen + 1, fn); 203 } 204 else if (incore) 205 { 206 len = filelen; 207 filelen += PDC_READ_CHUNKSIZE; 208 content = (char *) pdc_realloc(pdc, content, filelen + 1, fn); 209 } 210 len = fread(&content[len], 1, PDC_READ_CHUNKSIZE, fp); 211 } 212 filelen += len - PDC_READ_CHUNKSIZE; 213 if (incore && filelen) 214 { 215 content = (char *) pdc_realloc(pdc, content, filelen + 1, fn); 216 } 217 else 218 { 219 pdc_free(pdc, content); 220 content = NULL; 221 } 222 223#else 224 225 fseek(fp, 0L, SEEK_END); 226 filelen = (size_t) ftell(fp); 227 fseek(fp, 0L, SEEK_SET); 228 if (incore && filelen) 229 { 230 content = (char *) pdc_malloc(pdc, filelen + 1, fn); 231 len = fread(content, 1, filelen, fp); 232 if (len != filelen) 233 { 234 pdc_free(pdc, content); 235 filelen = 0; 236 content = NULL; 237 } 238 } 239 240#endif 241 242 if (content) content[filelen] = 0; 243 *o_filelen = filelen; 244 return (void *) content; 245} 246 247pdc_file * 248pdc_fopen(pdc_core *pdc, const char *filename, const char *qualifier, 249 const pdc_byte *data, size_t size, int flags) 250{ 251 static const char fn[] = "pdc_fopen"; 252 pdc_file *sfile; 253 254 sfile = (pdc_file *) pdc_calloc(pdc, sizeof(pdc_file), fn); 255 if (data) 256 { 257 sfile->data = data; 258 sfile->pos = sfile->data; 259 sfile->end = sfile->data + size; 260 } 261 else 262 { 263 sfile->fp = fopen(filename, 264 (flags & PDC_FILE_BINARY) ? READBMODE : READTMODE); 265 if (sfile->fp == NULL) 266 { 267 pdc_free(pdc, sfile); 268 if (qualifier) 269 { 270 pdc_set_errmsg(pdc, pdc_get_fopen_errnum(pdc, PDC_E_IO_RDOPEN), 271 qualifier, filename, 0, 0); 272 } 273 return NULL; 274 } 275 } 276 277 sfile->pdc = pdc; 278 sfile->filename = pdc_strdup(pdc, filename); 279 280 281 return sfile; 282} 283 284 285pdc_bool 286pdc_file_isvirtual(pdc_file *sfp) 287{ 288 return sfp->fp ? pdc_false : pdc_true; 289} 290 291char * 292pdc_file_name(pdc_file *sfp) 293{ 294 return sfp->filename; 295} 296 297pdc_core * 298pdc_file_getpdc(pdc_file *sfp) 299{ 300 return sfp->pdc; 301} 302 303size_t 304pdc_file_size(pdc_file *sfp) 305{ 306 size_t filelen; 307 308 if (sfp->fp) 309 { 310 long pos = ftell(sfp->fp); 311 pdc_read_file(sfp->pdc, sfp->fp, &filelen, 0); 312 fseek(sfp->fp, pos, SEEK_SET); 313 } 314 else 315 filelen = (size_t) (sfp->end - sfp->data); 316 return filelen; 317} 318 319const void * 320pdc_freadall(pdc_file *sfp, size_t *filelen, pdc_bool *ismem) 321{ 322 if (sfp->fp) 323 { 324 if (ismem) *ismem = pdc_false; 325 return (const void *) pdc_read_file(sfp->pdc, sfp->fp, filelen, 1); 326 } 327 328 if (ismem) *ismem = pdc_true; 329 *filelen = (size_t) (sfp->end - sfp->data); 330 return sfp->data; 331} 332 333static int 334pdc_fgetc_e(pdc_file *sfp) 335{ 336 int c = pdc_fgetc(sfp); 337 return c; 338} 339 340char * 341pdc_fgets_comp(char *s, int size, pdc_file *sfp) 342{ 343 int i, c; 344 345 c = pdc_fgetc_e(sfp); 346 if (c == EOF) 347 return NULL; 348 349 size--; 350 for (i = 0; i < size; i++) 351 { 352 if (c == '\n' || c == '\r' || c == EOF) break; 353 s[i] = (char) c; 354 c = pdc_fgetc_e(sfp); 355 } 356 s[i] = 0; 357 358 /* Skip windows line end \r\n */ 359 if (c == '\r') 360 { 361 c = pdc_fgetc_e(sfp); 362 if (c != '\n') 363 { 364 pdc_ungetc(c, sfp); 365 } 366 } 367 return s; 368} 369 370/* 371 * Emulation of C file functions - relevant for PDFlib 372 */ 373 374long 375pdc_ftell(pdc_file *sfp) 376{ 377 if (sfp->fp) 378 return ftell(sfp->fp); 379 380 return (long) (sfp->pos - sfp->data); 381} 382 383int 384pdc_fseek(pdc_file *sfp, long offset, int whence) 385{ 386 if (sfp->fp) 387 return fseek(sfp->fp, offset, whence); 388 389 sfp->number = 0; 390 391 switch (whence) 392 { 393 case SEEK_SET: 394 if (sfp->data + offset > sfp->end) 395 return -1; 396 sfp->pos = sfp->data + offset; 397 break; 398 399 case SEEK_CUR: 400 if (sfp->pos + offset > sfp->end) 401 return -1; 402 sfp->pos += offset; 403 break; 404 405 case SEEK_END: 406 if (sfp->end + offset > sfp->end) 407 return -1; 408 sfp->pos = sfp->end + offset; 409 break; 410 } 411 return 0; 412} 413 414size_t 415pdc_fread(void *ptr, size_t size, size_t nmemb, pdc_file *sfp) 416{ 417 size_t nbytes = 0; 418 419 if (sfp->fp) 420 return fread(ptr, size, nmemb, sfp->fp); 421 422 nbytes = size * nmemb; 423 if (sfp->pos + nbytes > sfp->end) 424 { 425 nbytes = (size_t) (sfp->end - sfp->pos); 426 nmemb = nbytes / size; 427 nbytes = nmemb *size; 428 } 429 memcpy(ptr, sfp->pos, nbytes); 430 sfp->pos += nbytes; 431 432 return nmemb; 433} 434 435#define UNGETC_CHUNKSIZE 16 436 437int 438pdc_ungetc(int c, pdc_file *sfp) 439{ 440 static const char fn[] = "pdc_ungetc"; 441 442 if (sfp->fp) 443 return ungetc(c, sfp->fp); 444 445 if (!sfp->capacity) 446 { 447 sfp->capacity = UNGETC_CHUNKSIZE; 448 sfp->tdata = (pdc_byte *) pdc_malloc(sfp->pdc, 449 sfp->capacity * sizeof(pdc_byte), fn); 450 } 451 else if (sfp->number == sfp->capacity) 452 { 453 sfp->capacity += UNGETC_CHUNKSIZE; 454 sfp->tdata = (pdc_byte *) pdc_realloc(sfp->pdc, sfp->tdata, 455 sfp->capacity * sizeof(pdc_byte), fn); 456 } 457 458 sfp->tdata[sfp->number] = (pdc_byte) c; 459 sfp->number++; 460 return c; 461} 462 463int 464pdc_fgetc(pdc_file *sfp) 465{ 466 int ch = 0; 467 468 if (sfp->fp) 469 return fgetc(sfp->fp); 470 471 if (sfp->tdata && sfp->number > 0) 472 { 473 sfp->number--; 474 ch = (int) sfp->tdata[sfp->number]; 475 } 476 else 477 { 478 if (sfp->pos < sfp->end) 479 { 480 ch = (int) *sfp->pos; 481 sfp->pos++; 482 } 483 else 484 { 485 ch = EOF; 486 } 487 } 488 return ch; 489} 490 491char * 492pdc_fgets(char *s, int size, pdc_file *sfp) 493{ 494 int i; 495 int ch, chp; 496 497 if (sfp->fp) 498 return fgets(s, size, sfp->fp); 499 500 chp = 0; 501 for (i = 0; i < size ; i++) 502 { 503 ch = 0; 504 if (i < size - 1 && chp != '\n') 505 { 506 if (sfp->number > 0) 507 { 508 sfp->number--; 509 ch = (int) sfp->tdata[sfp->number]; 510 } 511 else if (sfp->pos < sfp->end) 512 { 513 ch = (int) *sfp->pos; 514 sfp->pos++; 515 } 516 if (ch == EOF) ch = 0; 517 } 518 s[i] = (char) ch; 519 if (!ch) 520 break; 521 chp = (int) s[i]; 522 } 523 524 return (i > 1) ? s : NULL; 525} 526 527int 528pdc_feof(pdc_file *sfp) 529{ 530 if (sfp->fp) 531 return feof(sfp->fp); 532 533 return (sfp->pos >= sfp->end) ? 1 : 0; 534} 535 536void 537pdc_fclose(pdc_file *sfp) 538{ 539 if (sfp) 540 { 541 if (sfp->fp) 542 { 543 fclose(sfp->fp); 544 sfp->fp = NULL; 545 } 546 if (sfp->tdata) 547 { 548 pdc_free(sfp->pdc, sfp->tdata); 549 sfp->tdata = NULL; 550 } 551 if (sfp->filename) 552 { 553 pdc_free(sfp->pdc, sfp->filename); 554 sfp->filename = NULL; 555 } 556 pdc_free(sfp->pdc, sfp); 557 } 558} 559 560/* 561 * Concatenating a directory name with a file base name to a full valid 562 * file name. On MVS platforms an extension at the end of basename 563 * will be discarded. 564 */ 565void 566pdc_file_fullname(const char *dirname, const char *basename, char *fullname) 567{ 568 int ib; 569 size_t len = strlen(basename); 570#ifdef MVS 571 pdc_bool lastterm = pdc_false; 572#endif 573 574 for (ib = 0; ib < (int) len; ib++) 575 if (!isspace(basename[ib])) 576 break; 577 578 if (!dirname || !dirname[0]) 579 { 580 strcpy(fullname, &basename[ib]); 581 } 582 else 583 { 584 fullname[0] = 0; 585#ifdef MVS 586 if (strncmp(dirname, PDC_FILEQUOT, 1)) 587 strcat(fullname, PDC_FILEQUOT); 588#endif 589 strcat(fullname, dirname); 590 strcat(fullname, PDC_PATHSEP); 591 strcat(fullname, &basename[ib]); 592#ifdef MVS 593 lastterm = pdc_true; 594#endif 595 } 596 597#ifdef MVS 598 { 599 int ie; 600 601 len = strlen(fullname); 602 for (ie = len; ie >= 0; ie--) 603 { 604 if (!strncmp(&fullname[ie], PDC_PATHSEP, 1)) 605 break; 606 if (fullname[ie] == '.') 607 { 608 fullname[ie] = 0; 609 break; 610 } 611 } 612 if (lastterm) 613 { 614 strcat(fullname, PDC_PATHTERM); 615 strcat(fullname, PDC_FILEQUOT); 616 } 617 } 618#endif 619} 620 621/* 622 * Function reads a text file and creates a string list 623 * of all no-empty and no-comment lines. The strings are stripped 624 * by leading and trailing white space characters. 625 * 626 * The caller is responsible for freeing the resultated string list 627 * by calling the function pdc_cleanup_stringlist. 628 * 629 * Not for unicode strings. 630 * 631 * Return value: Number of strings 632 */ 633 634#define PDC_BUFSIZE 1024 635#define PDC_ARGV_CHUNKSIZE 256 636 637int 638pdc_read_textfile(pdc_core *pdc, pdc_file *sfp, char ***linelist) 639{ 640 static const char *fn = "pdc_read_textfile"; 641 char buf[PDC_BUFSIZE]; 642 char *content = NULL; 643 char **argv = NULL; 644 int nlines = 0; 645 size_t filelen; 646 size_t len, maxl = 0; 647 int tocont, incont = 0; 648 int i, is = 0; 649 650 /* Get file length and allocate content array */ 651 filelen = pdc_file_size(sfp); 652 content = (char *) pdc_malloc(pdc, filelen, fn); 653 654 /* Read loop */ 655 while (pdc_fgets_comp(buf, PDC_BUFSIZE, sfp) != NULL) 656 { 657 /* Strip blank and comment lines */ 658 pdc_str2trim(buf); 659 if (buf[0] == 0 || buf[0] == '%') 660 continue; 661 662 /* Strip inline comments */ 663 len = strlen(buf); 664 for (i = 1; i < (int) len; i++) 665 { 666 if (buf[i] == '%' && buf[i-1] != '\\') 667 { 668 buf[i] = 0; 669 pdc_strtrim(buf); 670 len = strlen(buf); 671 break; 672 } 673 } 674 675 /* Continuation line */ 676 tocont = (buf[len-1] == '\\') ? 1:0; 677 if (tocont) 678 { 679 buf[len-1] = '\0'; 680 len--; 681 } 682 683 /* Copy line */ 684 strcpy(&content[is], buf); 685 686 /* Save whole line */ 687 if (!incont) 688 { 689 if (nlines >= (int) maxl) 690 { 691 maxl += PDC_ARGV_CHUNKSIZE; 692 argv = (argv == NULL) ? 693 (char **)pdc_malloc(pdc, maxl * sizeof(char *), fn): 694 (char **)pdc_realloc(pdc, argv, maxl * 695 sizeof(char *), fn); 696 } 697 argv[nlines] = &content[is]; 698 nlines++; 699 } 700 701 /* Next index */ 702 incont = tocont; 703 is += (int) (len + 1 - incont); 704 } 705 706 if (!argv) pdc_free(pdc, content); 707 *linelist = argv; 708 return nlines; 709} 710 711 712/* generate a temporary file name from the current time, pid, and the 713** data in inbuf using MD5. 714*/ 715void 716pdc_tempname(char *outbuf, int outlen, const char *inbuf, int inlen) 717{ 718 MD5_CTX md5; 719 time_t timer; 720 unsigned char digest[MD5_DIGEST_LENGTH]; 721 int i; 722 723#if defined(WIN32) 724 int pid = _getpid(); 725#else 726#if !defined(MAC) 727 pid_t pid = getpid(); 728#endif 729#endif 730 731 time(&timer); 732 733 MD5_Init(&md5); 734#if !defined(MAC) 735 MD5_Update(&md5, (unsigned char *) &pid, sizeof pid); 736#endif 737 MD5_Update(&md5, (unsigned char *) &timer, sizeof timer); 738 MD5_Update(&md5, (unsigned char *) inbuf, (unsigned int) inlen); 739 MD5_Final(digest, &md5); 740 741 for (i = 0; i < outlen - 1; ++i) 742 outbuf[i] = (char) ('A' + digest[i % MD5_DIGEST_LENGTH] % 26); 743 744 outbuf[i] = 0; 745} 746 747#ifdef PDF_TARGET_API_MAC_CARBON 748 749/* Construct an FSSpec from a Posix path name. Only required for 750 * Carbon (host font support and file type/creator). 751 */ 752 753OSStatus 754FSPathMakeFSSpec(const UInt8 *path, FSSpec *spec) 755{ 756 OSStatus result; 757 FSRef ref; 758 759 /* convert the POSIX path to an FSRef */ 760 result = FSPathMakeRef(path, &ref, NULL); 761 762 if (result != noErr) 763 return result; 764 765 /* and then convert the FSRef to an FSSpec */ 766 result = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL); 767 768 return result; 769} 770 771#endif /* PDF_TARGET_API_MAC_CARBON */ 772 773