file.c revision 7914d74b
1/* 2 * $Id: file.c,v 1.1.1.1 2008/07/30 02:45:53 mrg Exp $ 3 * 4 * Copyright © 2002 Keith Packard 5 * 6 * Permission to use, copy, modify, distribute, and sell this software and its 7 * documentation for any purpose is hereby granted without fee, provided that 8 * the above copyright notice appear in all copies and that both that 9 * copyright notice and this permission notice appear in supporting 10 * documentation, and that the name of Keith Packard not be used in 11 * advertising or publicity pertaining to distribution of the software without 12 * specific, written prior permission. Keith Packard makes no 13 * representations about the suitability of this software for any purpose. It 14 * is provided "as is" without express or implied warranty. 15 * 16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22 * PERFORMANCE OF THIS SOFTWARE. 23 */ 24 25#include "xcursorint.h" 26#include <stdlib.h> 27#include <string.h> 28 29XcursorImage * 30XcursorImageCreate (int width, int height) 31{ 32 XcursorImage *image; 33 34 image = malloc (sizeof (XcursorImage) + 35 width * height * sizeof (XcursorPixel)); 36 if (!image) 37 return NULL; 38 image->version = XCURSOR_IMAGE_VERSION; 39 image->pixels = (XcursorPixel *) (image + 1); 40 image->size = width > height ? width : height; 41 image->width = width; 42 image->height = height; 43 image->delay = 0; 44 return image; 45} 46 47void 48XcursorImageDestroy (XcursorImage *image) 49{ 50 free (image); 51} 52 53XcursorImages * 54XcursorImagesCreate (int size) 55{ 56 XcursorImages *images; 57 58 images = malloc (sizeof (XcursorImages) + 59 size * sizeof (XcursorImage *)); 60 if (!images) 61 return NULL; 62 images->nimage = 0; 63 images->images = (XcursorImage **) (images + 1); 64 images->name = NULL; 65 return images; 66} 67 68void 69XcursorImagesDestroy (XcursorImages *images) 70{ 71 int n; 72 73 if (!images) 74 return; 75 76 for (n = 0; n < images->nimage; n++) 77 XcursorImageDestroy (images->images[n]); 78 if (images->name) 79 free (images->name); 80 free (images); 81} 82 83void 84XcursorImagesSetName (XcursorImages *images, const char *name) 85{ 86 char *new; 87 88 if (!images || !name) 89 return; 90 91 new = malloc (strlen (name) + 1); 92 93 if (!new) 94 return; 95 96 strcpy (new, name); 97 if (images->name) 98 free (images->name); 99 images->name = new; 100} 101 102XcursorComment * 103XcursorCommentCreate (XcursorUInt comment_type, int length) 104{ 105 XcursorComment *comment; 106 107 if (length > XCURSOR_COMMENT_MAX_LEN) 108 return NULL; 109 110 comment = malloc (sizeof (XcursorComment) + length + 1); 111 if (!comment) 112 return NULL; 113 comment->version = XCURSOR_COMMENT_VERSION; 114 comment->comment_type = comment_type; 115 comment->comment = (char *) (comment + 1); 116 comment->comment[0] = '\0'; 117 return comment; 118} 119 120void 121XcursorCommentDestroy (XcursorComment *comment) 122{ 123 free (comment); 124} 125 126XcursorComments * 127XcursorCommentsCreate (int size) 128{ 129 XcursorComments *comments; 130 131 comments = malloc (sizeof (XcursorComments) + 132 size * sizeof (XcursorComment *)); 133 if (!comments) 134 return NULL; 135 comments->ncomment = 0; 136 comments->comments = (XcursorComment **) (comments + 1); 137 return comments; 138} 139 140void 141XcursorCommentsDestroy (XcursorComments *comments) 142{ 143 int n; 144 145 if (!comments) 146 return; 147 148 for (n = 0; n < comments->ncomment; n++) 149 XcursorCommentDestroy (comments->comments[n]); 150 free (comments); 151} 152 153static XcursorBool 154_XcursorReadUInt (XcursorFile *file, XcursorUInt *u) 155{ 156 unsigned char bytes[4]; 157 158 if (!file || !u) 159 return XcursorFalse; 160 161 if ((*file->read) (file, bytes, 4) != 4) 162 return XcursorFalse; 163 *u = ((bytes[0] << 0) | 164 (bytes[1] << 8) | 165 (bytes[2] << 16) | 166 (bytes[3] << 24)); 167 return XcursorTrue; 168} 169 170static XcursorBool 171_XcursorReadBytes (XcursorFile *file, char *bytes, int length) 172{ 173 if (!file || !bytes || (*file->read) (file, (unsigned char *) bytes, length) != length) 174 return XcursorFalse; 175 return XcursorTrue; 176} 177 178static XcursorBool 179_XcursorWriteUInt (XcursorFile *file, XcursorUInt u) 180{ 181 unsigned char bytes[4]; 182 183 if (!file) 184 return XcursorFalse; 185 186 bytes[0] = u; 187 bytes[1] = u >> 8; 188 bytes[2] = u >> 16; 189 bytes[3] = u >> 24; 190 if ((*file->write) (file, bytes, 4) != 4) 191 return XcursorFalse; 192 return XcursorTrue; 193} 194 195static XcursorBool 196_XcursorWriteBytes (XcursorFile *file, char *bytes, int length) 197{ 198 if (!file || !bytes || (*file->write) (file, (unsigned char *) bytes, length) != length) 199 return XcursorFalse; 200 return XcursorTrue; 201} 202 203static void 204_XcursorFileHeaderDestroy (XcursorFileHeader *fileHeader) 205{ 206 free (fileHeader); 207} 208 209static XcursorFileHeader * 210_XcursorFileHeaderCreate (int ntoc) 211{ 212 XcursorFileHeader *fileHeader; 213 214 if (ntoc > 0x10000) 215 return NULL; 216 fileHeader = malloc (sizeof (XcursorFileHeader) + 217 ntoc * sizeof (XcursorFileToc)); 218 if (!fileHeader) 219 return NULL; 220 fileHeader->magic = XCURSOR_MAGIC; 221 fileHeader->header = XCURSOR_FILE_HEADER_LEN; 222 fileHeader->version = XCURSOR_FILE_VERSION; 223 fileHeader->ntoc = ntoc; 224 fileHeader->tocs = (XcursorFileToc *) (fileHeader + 1); 225 return fileHeader; 226} 227 228static XcursorFileHeader * 229_XcursorReadFileHeader (XcursorFile *file) 230{ 231 XcursorFileHeader head, *fileHeader; 232 XcursorUInt skip; 233 int n; 234 235 if (!file) 236 return NULL; 237 238 if (!_XcursorReadUInt (file, &head.magic)) 239 return NULL; 240 if (head.magic != XCURSOR_MAGIC) 241 return NULL; 242 if (!_XcursorReadUInt (file, &head.header)) 243 return NULL; 244 if (!_XcursorReadUInt (file, &head.version)) 245 return NULL; 246 if (!_XcursorReadUInt (file, &head.ntoc)) 247 return NULL; 248 skip = head.header - XCURSOR_FILE_HEADER_LEN; 249 if (skip) 250 if ((*file->seek) (file, skip, SEEK_CUR) == EOF) 251 return NULL; 252 fileHeader = _XcursorFileHeaderCreate (head.ntoc); 253 if (!fileHeader) 254 return NULL; 255 fileHeader->magic = head.magic; 256 fileHeader->header = head.header; 257 fileHeader->version = head.version; 258 fileHeader->ntoc = head.ntoc; 259 for (n = 0; n < fileHeader->ntoc; n++) 260 { 261 if (!_XcursorReadUInt (file, &fileHeader->tocs[n].type)) 262 break; 263 if (!_XcursorReadUInt (file, &fileHeader->tocs[n].subtype)) 264 break; 265 if (!_XcursorReadUInt (file, &fileHeader->tocs[n].position)) 266 break; 267 } 268 if (n != fileHeader->ntoc) 269 { 270 _XcursorFileHeaderDestroy (fileHeader); 271 return NULL; 272 } 273 return fileHeader; 274} 275 276static XcursorUInt 277_XcursorFileHeaderLength (XcursorFileHeader *fileHeader) 278{ 279 return (XCURSOR_FILE_HEADER_LEN + 280 fileHeader->ntoc * XCURSOR_FILE_TOC_LEN); 281} 282 283static XcursorBool 284_XcursorWriteFileHeader (XcursorFile *file, XcursorFileHeader *fileHeader) 285{ 286 int toc; 287 288 if (!file || !fileHeader) 289 return XcursorFalse; 290 291 if (!_XcursorWriteUInt (file, fileHeader->magic)) 292 return XcursorFalse; 293 if (!_XcursorWriteUInt (file, fileHeader->header)) 294 return XcursorFalse; 295 if (!_XcursorWriteUInt (file, fileHeader->version)) 296 return XcursorFalse; 297 if (!_XcursorWriteUInt (file, fileHeader->ntoc)) 298 return XcursorFalse; 299 for (toc = 0; toc < fileHeader->ntoc; toc++) 300 { 301 if (!_XcursorWriteUInt (file, fileHeader->tocs[toc].type)) 302 return XcursorFalse; 303 if (!_XcursorWriteUInt (file, fileHeader->tocs[toc].subtype)) 304 return XcursorFalse; 305 if (!_XcursorWriteUInt (file, fileHeader->tocs[toc].position)) 306 return XcursorFalse; 307 } 308 return XcursorTrue; 309} 310 311static XcursorBool 312_XcursorSeekToToc (XcursorFile *file, 313 XcursorFileHeader *fileHeader, 314 int toc) 315{ 316 if (!file || !fileHeader || \ 317 (*file->seek) (file, fileHeader->tocs[toc].position, SEEK_SET) == EOF) 318 return XcursorFalse; 319 return XcursorTrue; 320} 321 322static XcursorBool 323_XcursorFileReadChunkHeader (XcursorFile *file, 324 XcursorFileHeader *fileHeader, 325 int toc, 326 XcursorChunkHeader *chunkHeader) 327{ 328 if (!file || !fileHeader || !chunkHeader) 329 return XcursorFalse; 330 if (!_XcursorSeekToToc (file, fileHeader, toc)) 331 return XcursorFalse; 332 if (!_XcursorReadUInt (file, &chunkHeader->header)) 333 return XcursorFalse; 334 if (!_XcursorReadUInt (file, &chunkHeader->type)) 335 return XcursorFalse; 336 if (!_XcursorReadUInt (file, &chunkHeader->subtype)) 337 return XcursorFalse; 338 if (!_XcursorReadUInt (file, &chunkHeader->version)) 339 return XcursorFalse; 340 /* sanity check */ 341 if (chunkHeader->type != fileHeader->tocs[toc].type || 342 chunkHeader->subtype != fileHeader->tocs[toc].subtype) 343 return XcursorFalse; 344 return XcursorTrue; 345} 346 347static XcursorBool 348_XcursorFileWriteChunkHeader (XcursorFile *file, 349 XcursorFileHeader *fileHeader, 350 int toc, 351 XcursorChunkHeader *chunkHeader) 352{ 353 if (!file || !fileHeader || !chunkHeader) 354 return XcursorFalse; 355 if (!_XcursorSeekToToc (file, fileHeader, toc)) 356 return XcursorFalse; 357 if (!_XcursorWriteUInt (file, chunkHeader->header)) 358 return XcursorFalse; 359 if (!_XcursorWriteUInt (file, chunkHeader->type)) 360 return XcursorFalse; 361 if (!_XcursorWriteUInt (file, chunkHeader->subtype)) 362 return XcursorFalse; 363 if (!_XcursorWriteUInt (file, chunkHeader->version)) 364 return XcursorFalse; 365 return XcursorTrue; 366} 367 368#define dist(a,b) ((a) > (b) ? (a) - (b) : (b) - (a)) 369 370static XcursorDim 371_XcursorFindBestSize (XcursorFileHeader *fileHeader, 372 XcursorDim size, 373 int *nsizesp) 374{ 375 int n; 376 int nsizes = 0; 377 XcursorDim bestSize = 0; 378 XcursorDim thisSize; 379 380 if (!fileHeader || !nsizesp) 381 return 0; 382 383 for (n = 0; n < fileHeader->ntoc; n++) 384 { 385 if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE) 386 continue; 387 thisSize = fileHeader->tocs[n].subtype; 388 if (!bestSize || dist (thisSize, size) < dist (bestSize, size)) 389 { 390 bestSize = thisSize; 391 nsizes = 1; 392 } 393 else if (thisSize == bestSize) 394 nsizes++; 395 } 396 *nsizesp = nsizes; 397 return bestSize; 398} 399 400static int 401_XcursorFindImageToc (XcursorFileHeader *fileHeader, 402 XcursorDim size, 403 int count) 404{ 405 int toc; 406 XcursorDim thisSize; 407 408 if (!fileHeader) 409 return 0; 410 411 for (toc = 0; toc < fileHeader->ntoc; toc++) 412 { 413 if (fileHeader->tocs[toc].type != XCURSOR_IMAGE_TYPE) 414 continue; 415 thisSize = fileHeader->tocs[toc].subtype; 416 if (thisSize != size) 417 continue; 418 if (!count) 419 break; 420 count--; 421 } 422 if (toc == fileHeader->ntoc) 423 return -1; 424 return toc; 425} 426 427static XcursorImage * 428_XcursorReadImage (XcursorFile *file, 429 XcursorFileHeader *fileHeader, 430 int toc) 431{ 432 XcursorChunkHeader chunkHeader; 433 XcursorImage head; 434 XcursorImage *image; 435 int n; 436 XcursorPixel *p; 437 438 if (!file || !fileHeader) 439 return NULL; 440 441 if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader)) 442 return NULL; 443 if (!_XcursorReadUInt (file, &head.width)) 444 return NULL; 445 if (!_XcursorReadUInt (file, &head.height)) 446 return NULL; 447 if (!_XcursorReadUInt (file, &head.xhot)) 448 return NULL; 449 if (!_XcursorReadUInt (file, &head.yhot)) 450 return NULL; 451 if (!_XcursorReadUInt (file, &head.delay)) 452 return NULL; 453 /* sanity check data */ 454 if (head.width >= 0x10000 || head.height > 0x10000) 455 return NULL; 456 if (head.width == 0 || head.height == 0) 457 return NULL; 458 if (head.xhot > head.width || head.yhot > head.height) 459 return NULL; 460 461 /* Create the image and initialize it */ 462 image = XcursorImageCreate (head.width, head.height); 463 if (chunkHeader.version < image->version) 464 image->version = chunkHeader.version; 465 image->size = chunkHeader.subtype; 466 image->xhot = head.xhot; 467 image->yhot = head.yhot; 468 image->delay = head.delay; 469 n = image->width * image->height; 470 p = image->pixels; 471 while (n--) 472 { 473 if (!_XcursorReadUInt (file, p)) 474 { 475 XcursorImageDestroy (image); 476 return NULL; 477 } 478 p++; 479 } 480 return image; 481} 482 483static XcursorUInt 484_XcursorImageLength (XcursorImage *image) 485{ 486 if (!image) 487 return 0; 488 489 return XCURSOR_IMAGE_HEADER_LEN + (image->width * image->height) * 4; 490} 491 492static XcursorBool 493_XcursorWriteImage (XcursorFile *file, 494 XcursorFileHeader *fileHeader, 495 int toc, 496 XcursorImage *image) 497{ 498 XcursorChunkHeader chunkHeader; 499 int n; 500 XcursorPixel *p; 501 502 if (!file || !fileHeader || !image) 503 return XcursorFalse; 504 505 /* sanity check data */ 506 if (image->width > XCURSOR_IMAGE_MAX_SIZE || 507 image->height > XCURSOR_IMAGE_MAX_SIZE) 508 return XcursorFalse; 509 if (image->width == 0 || image->height == 0) 510 return XcursorFalse; 511 if (image->xhot > image->width || image->yhot > image->height) 512 return XcursorFalse; 513 514 /* write chunk header */ 515 chunkHeader.header = XCURSOR_IMAGE_HEADER_LEN; 516 chunkHeader.type = XCURSOR_IMAGE_TYPE; 517 chunkHeader.subtype = image->size; 518 chunkHeader.version = XCURSOR_IMAGE_VERSION; 519 520 if (!_XcursorFileWriteChunkHeader (file, fileHeader, toc, &chunkHeader)) 521 return XcursorFalse; 522 523 /* write extra image header fields */ 524 if (!_XcursorWriteUInt (file, image->width)) 525 return XcursorFalse; 526 if (!_XcursorWriteUInt (file, image->height)) 527 return XcursorFalse; 528 if (!_XcursorWriteUInt (file, image->xhot)) 529 return XcursorFalse; 530 if (!_XcursorWriteUInt (file, image->yhot)) 531 return XcursorFalse; 532 if (!_XcursorWriteUInt (file, image->delay)) 533 return XcursorFalse; 534 535 /* write the image */ 536 n = image->width * image->height; 537 p = image->pixels; 538 while (n--) 539 { 540 if (!_XcursorWriteUInt (file, *p)) 541 return XcursorFalse; 542 p++; 543 } 544 return XcursorTrue; 545} 546 547static XcursorComment * 548_XcursorReadComment (XcursorFile *file, 549 XcursorFileHeader *fileHeader, 550 int toc) 551{ 552 XcursorChunkHeader chunkHeader; 553 XcursorUInt length; 554 XcursorComment *comment; 555 556 if (!file || !fileHeader) 557 return NULL; 558 559 /* read chunk header */ 560 if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader)) 561 return NULL; 562 /* read extra comment header fields */ 563 if (!_XcursorReadUInt (file, &length)) 564 return NULL; 565 comment = XcursorCommentCreate (chunkHeader.subtype, length); 566 if (!comment) 567 return NULL; 568 if (!_XcursorReadBytes (file, comment->comment, length)) 569 { 570 XcursorCommentDestroy (comment); 571 return NULL; 572 } 573 comment->comment[length] = '\0'; 574 return comment; 575} 576 577static XcursorUInt 578_XcursorCommentLength (XcursorComment *comment) 579{ 580 return XCURSOR_COMMENT_HEADER_LEN + strlen (comment->comment); 581} 582 583static XcursorBool 584_XcursorWriteComment (XcursorFile *file, 585 XcursorFileHeader *fileHeader, 586 int toc, 587 XcursorComment *comment) 588{ 589 XcursorChunkHeader chunkHeader; 590 XcursorUInt length; 591 592 if (!file || !fileHeader || !comment || !comment->comment) 593 return XcursorFalse; 594 595 length = strlen (comment->comment); 596 597 /* sanity check data */ 598 if (length > XCURSOR_COMMENT_MAX_LEN) 599 return XcursorFalse; 600 601 /* read chunk header */ 602 chunkHeader.header = XCURSOR_COMMENT_HEADER_LEN; 603 chunkHeader.type = XCURSOR_COMMENT_TYPE; 604 chunkHeader.subtype = comment->comment_type; 605 chunkHeader.version = XCURSOR_COMMENT_VERSION; 606 607 if (!_XcursorFileWriteChunkHeader (file, fileHeader, toc, &chunkHeader)) 608 return XcursorFalse; 609 610 /* write extra comment header fields */ 611 if (!_XcursorWriteUInt (file, length)) 612 return XcursorFalse; 613 614 if (!_XcursorWriteBytes (file, comment->comment, length)) 615 return XcursorFalse; 616 return XcursorTrue; 617} 618 619XcursorImage * 620XcursorXcFileLoadImage (XcursorFile *file, int size) 621{ 622 XcursorFileHeader *fileHeader; 623 XcursorDim bestSize; 624 int nsize; 625 int toc; 626 XcursorImage *image; 627 628 if (size < 0) 629 return NULL; 630 fileHeader = _XcursorReadFileHeader (file); 631 if (!fileHeader) 632 return NULL; 633 bestSize = _XcursorFindBestSize (fileHeader, (XcursorDim) size, &nsize); 634 if (!bestSize) 635 return NULL; 636 toc = _XcursorFindImageToc (fileHeader, bestSize, 0); 637 if (toc < 0) 638 return NULL; 639 image = _XcursorReadImage (file, fileHeader, toc); 640 _XcursorFileHeaderDestroy (fileHeader); 641 return image; 642} 643 644XcursorImages * 645XcursorXcFileLoadImages (XcursorFile *file, int size) 646{ 647 XcursorFileHeader *fileHeader; 648 XcursorDim bestSize; 649 int nsize; 650 XcursorImages *images; 651 int n; 652 int toc; 653 654 if (!file || size < 0) 655 return NULL; 656 fileHeader = _XcursorReadFileHeader (file); 657 if (!fileHeader) 658 return NULL; 659 bestSize = _XcursorFindBestSize (fileHeader, (XcursorDim) size, &nsize); 660 if (!bestSize) 661 { 662 _XcursorFileHeaderDestroy (fileHeader); 663 return NULL; 664 } 665 images = XcursorImagesCreate (nsize); 666 if (!images) 667 { 668 _XcursorFileHeaderDestroy (fileHeader); 669 return NULL; 670 } 671 for (n = 0; n < nsize; n++) 672 { 673 toc = _XcursorFindImageToc (fileHeader, bestSize, n); 674 if (toc < 0) 675 break; 676 images->images[images->nimage] = _XcursorReadImage (file, fileHeader, 677 toc); 678 if (!images->images[images->nimage]) 679 break; 680 images->nimage++; 681 } 682 _XcursorFileHeaderDestroy (fileHeader); 683 if (images->nimage != nsize) 684 { 685 XcursorImagesDestroy (images); 686 images = NULL; 687 } 688 return images; 689} 690 691XcursorImages * 692XcursorXcFileLoadAllImages (XcursorFile *file) 693{ 694 XcursorFileHeader *fileHeader; 695 XcursorImage *image; 696 XcursorImages *images; 697 int nimage; 698 int n; 699 int toc; 700 701 if (!file) 702 return NULL; 703 704 fileHeader = _XcursorReadFileHeader (file); 705 if (!fileHeader) 706 return NULL; 707 nimage = 0; 708 for (n = 0; n < fileHeader->ntoc; n++) 709 { 710 switch (fileHeader->tocs[n].type) { 711 case XCURSOR_IMAGE_TYPE: 712 nimage++; 713 break; 714 } 715 } 716 images = XcursorImagesCreate (nimage); 717 if (!images) 718 return NULL; 719 for (toc = 0; toc < fileHeader->ntoc; toc++) 720 { 721 switch (fileHeader->tocs[toc].type) { 722 case XCURSOR_IMAGE_TYPE: 723 image = _XcursorReadImage (file, fileHeader, toc); 724 if (image) 725 { 726 images->images[images->nimage] = image; 727 images->nimage++; 728 } 729 break; 730 } 731 } 732 _XcursorFileHeaderDestroy (fileHeader); 733 if (images->nimage != nimage) 734 { 735 XcursorImagesDestroy (images); 736 images = NULL; 737 } 738 return images; 739} 740 741XcursorBool 742XcursorXcFileLoad (XcursorFile *file, 743 XcursorComments **commentsp, 744 XcursorImages **imagesp) 745{ 746 XcursorFileHeader *fileHeader; 747 int nimage; 748 int ncomment; 749 XcursorImages *images; 750 XcursorImage *image; 751 XcursorComment *comment; 752 XcursorComments *comments; 753 int toc; 754 755 if (!file) 756 return 0; 757 fileHeader = _XcursorReadFileHeader (file); 758 if (!fileHeader) 759 return 0; 760 nimage = 0; 761 ncomment = 0; 762 for (toc = 0; toc < fileHeader->ntoc; toc++) 763 { 764 switch (fileHeader->tocs[toc].type) { 765 case XCURSOR_COMMENT_TYPE: 766 ncomment++; 767 break; 768 case XCURSOR_IMAGE_TYPE: 769 nimage++; 770 break; 771 } 772 } 773 images = XcursorImagesCreate (nimage); 774 if (!images) 775 return 0; 776 comments = XcursorCommentsCreate (ncomment); 777 if (!comments) 778 { 779 XcursorImagesDestroy (images); 780 return 0; 781 } 782 for (toc = 0; toc < fileHeader->ntoc; toc++) 783 { 784 switch (fileHeader->tocs[toc].type) { 785 case XCURSOR_COMMENT_TYPE: 786 comment = _XcursorReadComment (file, fileHeader, toc); 787 if (comment) 788 { 789 comments->comments[comments->ncomment] = comment; 790 comments->ncomment++; 791 } 792 break; 793 case XCURSOR_IMAGE_TYPE: 794 image = _XcursorReadImage (file, fileHeader, toc); 795 if (image) 796 { 797 images->images[images->nimage] = image; 798 images->nimage++; 799 } 800 break; 801 } 802 } 803 _XcursorFileHeaderDestroy (fileHeader); 804 if (images->nimage != nimage || comments->ncomment != ncomment) 805 { 806 XcursorImagesDestroy (images); 807 XcursorCommentsDestroy (comments); 808 images = NULL; 809 comments = NULL; 810 return XcursorFalse; 811 } 812 *imagesp = images; 813 *commentsp = comments; 814 return XcursorTrue; 815} 816 817XcursorBool 818XcursorXcFileSave (XcursorFile *file, 819 const XcursorComments *comments, 820 const XcursorImages *images) 821{ 822 XcursorFileHeader *fileHeader; 823 XcursorUInt position; 824 int n; 825 int toc; 826 827 if (!file || !comments || !images) 828 return XcursorFalse; 829 830 fileHeader = _XcursorFileHeaderCreate (comments->ncomment + images->nimage); 831 if (!fileHeader) 832 return XcursorFalse; 833 834 position = _XcursorFileHeaderLength (fileHeader); 835 836 /* 837 * Compute the toc. Place the images before the comments 838 * as they're more often read 839 */ 840 841 toc = 0; 842 for (n = 0; n < images->nimage; n++) 843 { 844 fileHeader->tocs[toc].type = XCURSOR_IMAGE_TYPE; 845 fileHeader->tocs[toc].subtype = images->images[n]->size; 846 fileHeader->tocs[toc].position = position; 847 position += _XcursorImageLength (images->images[n]); 848 toc++; 849 } 850 851 for (n = 0; n < comments->ncomment; n++) 852 { 853 fileHeader->tocs[toc].type = XCURSOR_COMMENT_TYPE; 854 fileHeader->tocs[toc].subtype = comments->comments[n]->comment_type; 855 fileHeader->tocs[toc].position = position; 856 position += _XcursorCommentLength (comments->comments[n]); 857 toc++; 858 } 859 860 /* 861 * Write the header and the toc 862 */ 863 if (!_XcursorWriteFileHeader (file, fileHeader)) 864 goto bail; 865 866 /* 867 * Write the images 868 */ 869 toc = 0; 870 for (n = 0; n < images->nimage; n++) 871 { 872 if (!_XcursorWriteImage (file, fileHeader, toc, images->images[n])) 873 goto bail; 874 toc++; 875 } 876 877 /* 878 * Write the comments 879 */ 880 for (n = 0; n < comments->ncomment; n++) 881 { 882 if (!_XcursorWriteComment (file, fileHeader, toc, comments->comments[n])) 883 goto bail; 884 toc++; 885 } 886 887 _XcursorFileHeaderDestroy (fileHeader); 888 return XcursorTrue; 889bail: 890 _XcursorFileHeaderDestroy (fileHeader); 891 return XcursorFalse; 892} 893 894static int 895_XcursorStdioFileRead (XcursorFile *file, unsigned char *buf, int len) 896{ 897 FILE *f = file->closure; 898 return fread (buf, 1, len, f); 899} 900 901static int 902_XcursorStdioFileWrite (XcursorFile *file, unsigned char *buf, int len) 903{ 904 FILE *f = file->closure; 905 return fwrite (buf, 1, len, f); 906} 907 908static int 909_XcursorStdioFileSeek (XcursorFile *file, long offset, int whence) 910{ 911 FILE *f = file->closure; 912 return fseek (f, offset, whence); 913} 914 915static void 916_XcursorStdioFileInitialize (FILE *stdfile, XcursorFile *file) 917{ 918 file->closure = stdfile; 919 file->read = _XcursorStdioFileRead; 920 file->write = _XcursorStdioFileWrite; 921 file->seek = _XcursorStdioFileSeek; 922} 923 924XcursorImage * 925XcursorFileLoadImage (FILE *file, int size) 926{ 927 XcursorFile f; 928 929 if (!file) 930 return NULL; 931 932 _XcursorStdioFileInitialize (file, &f); 933 return XcursorXcFileLoadImage (&f, size); 934} 935 936XcursorImages * 937XcursorFileLoadImages (FILE *file, int size) 938{ 939 XcursorFile f; 940 941 if (!file) 942 return NULL; 943 944 _XcursorStdioFileInitialize (file, &f); 945 return XcursorXcFileLoadImages (&f, size); 946} 947 948XcursorImages * 949XcursorFileLoadAllImages (FILE *file) 950{ 951 XcursorFile f; 952 953 if (!file) 954 return NULL; 955 956 _XcursorStdioFileInitialize (file, &f); 957 return XcursorXcFileLoadAllImages (&f); 958} 959 960XcursorBool 961XcursorFileLoad (FILE *file, 962 XcursorComments **commentsp, 963 XcursorImages **imagesp) 964{ 965 XcursorFile f; 966 967 if (!file || !commentsp || !imagesp) 968 return XcursorFalse; 969 970 _XcursorStdioFileInitialize (file, &f); 971 return XcursorXcFileLoad (&f, commentsp, imagesp); 972} 973 974XcursorBool 975XcursorFileSaveImages (FILE *file, const XcursorImages *images) 976{ 977 XcursorComments *comments = XcursorCommentsCreate (0); 978 XcursorFile f; 979 XcursorBool ret; 980 if (!comments || !file || !images) 981 return 0; 982 _XcursorStdioFileInitialize (file, &f); 983 ret = XcursorXcFileSave (&f, comments, images) && fflush (file) != EOF; 984 XcursorCommentsDestroy (comments); 985 return ret; 986} 987 988XcursorBool 989XcursorFileSave (FILE * file, 990 const XcursorComments *comments, 991 const XcursorImages *images) 992{ 993 XcursorFile f; 994 995 if (!file || !comments || !images) 996 return XcursorFalse; 997 998 _XcursorStdioFileInitialize (file, &f); 999 return XcursorXcFileSave (&f, comments, images) && fflush (file) != EOF; 1000} 1001 1002XcursorImage * 1003XcursorFilenameLoadImage (const char *file, int size) 1004{ 1005 FILE *f; 1006 XcursorImage *image; 1007 1008 if (!file || size < 0) 1009 return NULL; 1010 1011 f = fopen (file, "r"); 1012 if (!f) 1013 return NULL; 1014 image = XcursorFileLoadImage (f, size); 1015 fclose (f); 1016 return image; 1017} 1018 1019XcursorImages * 1020XcursorFilenameLoadImages (const char *file, int size) 1021{ 1022 FILE *f; 1023 XcursorImages *images; 1024 1025 if (!file || size < 0) 1026 return NULL; 1027 1028 f = fopen (file, "r"); 1029 if (!f) 1030 return NULL; 1031 images = XcursorFileLoadImages (f, size); 1032 fclose (f); 1033 return images; 1034} 1035 1036XcursorImages * 1037XcursorFilenameLoadAllImages (const char *file) 1038{ 1039 FILE *f; 1040 XcursorImages *images; 1041 1042 if (!file) 1043 return NULL; 1044 1045 f = fopen (file, "r"); 1046 if (!f) 1047 return NULL; 1048 images = XcursorFileLoadAllImages (f); 1049 fclose (f); 1050 return images; 1051} 1052 1053XcursorBool 1054XcursorFilenameLoad (const char *file, 1055 XcursorComments **commentsp, 1056 XcursorImages **imagesp) 1057{ 1058 FILE *f; 1059 XcursorBool ret; 1060 1061 if (!file) 1062 return XcursorFalse; 1063 1064 f = fopen (file, "r"); 1065 if (!f) 1066 return 0; 1067 ret = XcursorFileLoad (f, commentsp, imagesp); 1068 fclose (f); 1069 return ret; 1070} 1071 1072XcursorBool 1073XcursorFilenameSaveImages (const char *file, const XcursorImages *images) 1074{ 1075 FILE *f; 1076 XcursorBool ret; 1077 1078 if (!file || !images) 1079 return XcursorFalse; 1080 1081 f = fopen (file, "w"); 1082 if (!f) 1083 return 0; 1084 ret = XcursorFileSaveImages (f, images); 1085 return fclose (f) != EOF && ret; 1086} 1087 1088XcursorBool 1089XcursorFilenameSave (const char *file, 1090 const XcursorComments *comments, 1091 const XcursorImages *images) 1092{ 1093 FILE *f; 1094 XcursorBool ret; 1095 1096 if (!file || !comments || !images) 1097 return XcursorFalse; 1098 1099 f = fopen (file, "w"); 1100 if (!f) 1101 return 0; 1102 ret = XcursorFileSave (f, comments, images); 1103 return fclose (f) != EOF && ret; 1104} 1105