src/lib/util/corefile.c
| r3191 | r3192 | |
| 133 | 133 | |
| 134 | 134 | |
| 135 | 135 | /*------------------------------------------------- |
| 136 | | core_fopen_ram - open a RAM-based buffer for |
| 137 | | file-like access and return an error code |
| 136 | core_fopen_ram_internal - open a RAM-based buffer |
| 137 | for file-like access, possibly copying the data, |
| 138 | and return an error code |
| 138 | 139 | -------------------------------------------------*/ |
| 139 | 140 | |
| 140 | | file_error core_fopen_ram(const void *data, size_t length, UINT32 openflags, core_file **file) |
| 141 | static file_error core_fopen_ram_internal(const void *data, size_t length, int copy_buffer, UINT32 openflags, core_file **file) |
| 141 | 142 | { |
| 142 | 143 | /* can only do this for read access */ |
| 143 | 144 | if ((openflags & OPEN_FLAG_WRITE) != 0) |
| r3191 | r3192 | |
| 146 | 147 | return FILERR_INVALID_ACCESS; |
| 147 | 148 | |
| 148 | 149 | /* allocate the file itself */ |
| 149 | | *file = malloc(sizeof(**file)); |
| 150 | *file = malloc(sizeof(**file) + (copy_buffer ? length : 0)); |
| 150 | 151 | if (*file == NULL) |
| 151 | 152 | return FILERR_OUT_OF_MEMORY; |
| 152 | 153 | memset(*file, 0, sizeof(**file)); |
| 153 | 154 | |
| 155 | /* copy the buffer, if we're asked to */ |
| 156 | if (copy_buffer) |
| 157 | { |
| 158 | void *dest = ((UINT8 *) *file) + sizeof(**file); |
| 159 | memcpy(dest, data, length); |
| 160 | data = dest; |
| 161 | } |
| 162 | |
| 154 | 163 | /* claim the buffer */ |
| 155 | 164 | (*file)->data = (UINT8 *)data; |
| 156 | 165 | (*file)->length = length; |
| r3191 | r3192 | |
| 161 | 170 | |
| 162 | 171 | |
| 163 | 172 | /*------------------------------------------------- |
| 173 | core_fopen_ram - open a RAM-based buffer for |
| 174 | file-like access and return an error code |
| 175 | -------------------------------------------------*/ |
| 176 | |
| 177 | file_error core_fopen_ram(const void *data, size_t length, UINT32 openflags, core_file **file) |
| 178 | { |
| 179 | return core_fopen_ram_internal(data, length, FALSE, openflags, file); |
| 180 | } |
| 181 | |
| 182 | |
| 183 | /*------------------------------------------------- |
| 184 | core_fopen_ram_copy - open a copy of a RAM-based |
| 185 | buffer for file-like access and return an error code |
| 186 | -------------------------------------------------*/ |
| 187 | |
| 188 | file_error core_fopen_ram_copy(const void *data, size_t length, UINT32 openflags, core_file **file) |
| 189 | { |
| 190 | return core_fopen_ram_internal(data, length, TRUE, openflags, file); |
| 191 | } |
| 192 | |
| 193 | |
| 194 | /*------------------------------------------------- |
| 164 | 195 | core_fclose - closes a file |
| 165 | 196 | -------------------------------------------------*/ |
| 166 | 197 | |
src/mess/image.c
| r3191 | r3192 | |
| 54 | 54 | |
| 55 | 55 | /* variables that are only non-zero when an image is mounted */ |
| 56 | 56 | core_file *file; |
| 57 | | char *name; |
| 57 | astring *name; |
| 58 | 58 | char *dir; |
| 59 | 59 | char *hash; |
| 60 | 60 | char *basename_noext; |
| r3191 | r3192 | |
| 72 | 72 | char *extrainfo; |
| 73 | 73 | |
| 74 | 74 | /* working directory; persists across mounts */ |
| 75 | | char *working_directory; |
| 75 | astring *working_directory; |
| 76 | 76 | |
| 77 | 77 | /* pointer */ |
| 78 | 78 | void *ptr; |
| r3191 | r3192 | |
| 220 | 220 | { |
| 221 | 221 | slot = &machine->images_data->slots[indx]; |
| 222 | 222 | |
| 223 | | /* create a memory pool */ |
| 223 | /* create a memory pool, and allocated strings */ |
| 224 | 224 | slot->mempool = pool_alloc(memory_error); |
| 225 | slot->name = astring_alloc(); |
| 226 | slot->working_directory = astring_alloc(); |
| 225 | 227 | |
| 226 | 228 | /* setup the device */ |
| 227 | 229 | slot->dev = dev; |
| r3191 | r3192 | |
| 298 | 300 | /* free the memory pool */ |
| 299 | 301 | pool_free(slot->mempool); |
| 300 | 302 | slot->mempool = NULL; |
| 303 | |
| 304 | /* free the allocated strings */ |
| 305 | astring_free(slot->name); |
| 306 | astring_free(slot->working_directory); |
| 307 | slot->name = NULL; |
| 308 | slot->working_directory = NULL; |
| 301 | 309 | } |
| 302 | 310 | |
| 303 | 311 | machine->images_data = NULL; |
| r3191 | r3192 | |
| 668 | 676 | an image |
| 669 | 677 | -------------------------------------------------*/ |
| 670 | 678 | |
| 671 | | static image_error_t set_image_filename(image_slot_data *image, const char *filename, const char *zippath) |
| 679 | static image_error_t set_image_filename(image_slot_data *image, const char *filename) |
| 672 | 680 | { |
| 673 | | image_error_t err = IMAGE_ERROR_SUCCESS; |
| 674 | | astring *alloc_filename = NULL; |
| 675 | | char *full_filename = NULL; |
| 676 | | char *new_name; |
| 677 | | char *new_dir; |
| 678 | | char *new_working_directory; |
| 679 | | int pos; |
| 680 | | |
| 681 | | /* get the full path */ |
| 682 | | if (osd_get_full_path(&full_filename, filename) == FILERR_NONE) |
| 683 | | filename = full_filename; |
| 684 | | |
| 685 | | /* create the directory string */ |
| 686 | | new_dir = filename ? image_strdup(image->dev, filename) : NULL; |
| 687 | | for (pos = strlen(new_dir); (pos > 0); pos--) |
| 688 | | { |
| 689 | | if (strchr(":\\/", new_dir[pos - 1])) |
| 690 | | { |
| 691 | | new_dir[pos] = '\0'; |
| 692 | | break; |
| 693 | | } |
| 694 | | } |
| 695 | | |
| 696 | | /* do we have to concatenate the names? */ |
| 697 | | if (zippath) |
| 698 | | { |
| 699 | | alloc_filename = astring_assemble_3(astring_alloc(), filename, PATH_SEPARATOR, zippath); |
| 700 | | filename = astring_c(alloc_filename); |
| 701 | | } |
| 702 | | |
| 703 | | /* copy the string */ |
| 704 | | new_name = image_strdup(image->dev, filename); |
| 705 | | if (!new_name) |
| 706 | | { |
| 707 | | err = IMAGE_ERROR_OUTOFMEMORY; |
| 708 | | goto done; |
| 709 | | } |
| 710 | | |
| 711 | | /* copy the working directory */ |
| 712 | | new_working_directory = mame_strdup(new_dir); |
| 713 | | if (!new_working_directory) |
| 714 | | { |
| 715 | | err = IMAGE_ERROR_OUTOFMEMORY; |
| 716 | | goto done; |
| 717 | | } |
| 718 | | |
| 719 | | /* set the new name and dir */ |
| 720 | | if (image->name != NULL) |
| 721 | | image_freeptr(image->dev, image->name); |
| 722 | | if (image->dir != NULL) |
| 723 | | image_freeptr(image->dev, image->dir); |
| 724 | | if (image->working_directory != NULL) |
| 725 | | free(image->working_directory); |
| 726 | | image->name = new_name; |
| 727 | | image->dir = new_dir; |
| 728 | | image->working_directory = new_working_directory; |
| 729 | | |
| 730 | | done: |
| 731 | | if (alloc_filename != NULL) |
| 732 | | astring_free(alloc_filename); |
| 733 | | if (full_filename != NULL) |
| 734 | | free(full_filename); |
| 735 | | return err; |
| 681 | astring_cpyc(image->name, filename); |
| 682 | zippath_parent(image->working_directory, filename); |
| 683 | return IMAGE_ERROR_SUCCESS; |
| 736 | 684 | } |
| 737 | 685 | |
| 738 | 686 | |
| r3191 | r3192 | |
| 750 | 698 | |
| 751 | 699 | |
| 752 | 700 | /*------------------------------------------------- |
| 753 | | load_zip_path - loads a ZIP file with a |
| 754 | | specific path |
| 755 | | -------------------------------------------------*/ |
| 756 | | |
| 757 | | static image_error_t load_zip_path(image_slot_data *image, const char *path) |
| 758 | | { |
| 759 | | image_error_t err = IMAGE_ERROR_FILENOTFOUND; |
| 760 | | zip_file *zip = NULL; |
| 761 | | zip_error ziperr; |
| 762 | | const zip_file_header *header; |
| 763 | | const char *zip_extension = ".zip"; |
| 764 | | char *path_copy; |
| 765 | | const char *zip_entry; |
| 766 | | void *ptr; |
| 767 | | int pos; |
| 768 | | |
| 769 | | /* create our own copy of the path */ |
| 770 | | path_copy = mame_strdup(path); |
| 771 | | if (!path_copy) |
| 772 | | { |
| 773 | | err = IMAGE_ERROR_OUTOFMEMORY; |
| 774 | | goto done; |
| 775 | | } |
| 776 | | |
| 777 | | /* loop through the path and try opening zip files */ |
| 778 | | ziperr = ZIPERR_FILE_ERROR; |
| 779 | | zip_entry = NULL; |
| 780 | | pos = strlen(path_copy); |
| 781 | | while(pos > strlen(zip_extension)) |
| 782 | | { |
| 783 | | /* is this a potential zip path? */ |
| 784 | | if ((path_copy[pos] == '\0') || !strncmp(&path_copy[pos], PATH_SEPARATOR, strlen(PATH_SEPARATOR))) |
| 785 | | { |
| 786 | | /* parse out the zip path */ |
| 787 | | if (path_copy[pos] == '\0') |
| 788 | | { |
| 789 | | /* no zip path */ |
| 790 | | zip_entry = NULL; |
| 791 | | } |
| 792 | | else |
| 793 | | { |
| 794 | | /* we are at a zip path */ |
| 795 | | path_copy[pos] = '\0'; |
| 796 | | zip_entry = &path_copy[pos + strlen(PATH_SEPARATOR)]; |
| 797 | | } |
| 798 | | |
| 799 | | /* try to open the zip file */ |
| 800 | | ziperr = zip_file_open(path_copy, &zip); |
| 801 | | if (ziperr != ZIPERR_FILE_ERROR) |
| 802 | | break; |
| 803 | | |
| 804 | | /* restore the path if we changed */ |
| 805 | | if (zip_entry) |
| 806 | | path_copy[pos] = PATH_SEPARATOR[0]; |
| 807 | | } |
| 808 | | pos--; |
| 809 | | } |
| 810 | | |
| 811 | | /* did we succeed in opening up a zip file? */ |
| 812 | | if (ziperr == ZIPERR_NONE) |
| 813 | | { |
| 814 | | /* iterate through the zip file */ |
| 815 | | header = zippath_find_sub_path(zip, zip_entry, NULL); |
| 816 | | |
| 817 | | /* were we successful? */ |
| 818 | | if (header != NULL) |
| 819 | | { |
| 820 | | /* if no zip path was specified, we have to change the name */ |
| 821 | | if (!zip_entry) |
| 822 | | { |
| 823 | | /* use the first entry; tough part is we have to change the name */ |
| 824 | | err = set_image_filename(image, image->name, header->filename); |
| 825 | | if (err) |
| 826 | | goto done; |
| 827 | | } |
| 828 | | |
| 829 | | /* allocate space for this zip file */ |
| 830 | | ptr = image_malloc(image->dev, header->uncompressed_length); |
| 831 | | if (!ptr) |
| 832 | | { |
| 833 | | err = IMAGE_ERROR_OUTOFMEMORY; |
| 834 | | goto done; |
| 835 | | } |
| 836 | | |
| 837 | | ziperr = zip_file_decompress(zip, ptr, header->uncompressed_length); |
| 838 | | if (ziperr == ZIPERR_NONE) |
| 839 | | { |
| 840 | | /* success! */ |
| 841 | | err = IMAGE_ERROR_SUCCESS; |
| 842 | | core_fopen_ram(ptr, header->uncompressed_length, OPEN_FLAG_READ, &image->file); |
| 843 | | } |
| 844 | | } |
| 845 | | } |
| 846 | | |
| 847 | | done: |
| 848 | | if (path_copy) |
| 849 | | free(path_copy); |
| 850 | | if (zip) |
| 851 | | zip_file_close(zip); |
| 852 | | return err; |
| 853 | | } |
| 854 | | |
| 855 | | |
| 856 | | |
| 857 | | /*------------------------------------------------- |
| 858 | 701 | load_image_by_path - loads an image with a |
| 859 | 702 | specific path |
| 860 | 703 | -------------------------------------------------*/ |
| r3191 | r3192 | |
| 863 | 706 | { |
| 864 | 707 | file_error filerr = FILERR_NOT_FOUND; |
| 865 | 708 | image_error_t err = IMAGE_ERROR_FILENOTFOUND; |
| 866 | | astring *full_path = NULL; |
| 867 | | const char *file_extension; |
| 709 | astring *revised_path = astring_alloc(); |
| 868 | 710 | |
| 869 | | /* quick check to see if the file is a ZIP file */ |
| 870 | | file_extension = strrchr(path, '.'); |
| 871 | | if (!file_extension || mame_stricmp(file_extension, ".zip")) |
| 711 | /* attempt to read the file */ |
| 712 | filerr = zippath_fopen(path, open_flags, &image->file, revised_path); |
| 713 | |
| 714 | /* did the open succeed? */ |
| 715 | switch(filerr) |
| 872 | 716 | { |
| 873 | | filerr = core_fopen(path, open_flags, &image->file); |
| 717 | case FILERR_NONE: |
| 718 | /* success! */ |
| 719 | image->writeable = (open_flags & OPEN_FLAG_WRITE) ? 1 : 0; |
| 720 | image->created = (open_flags & OPEN_FLAG_CREATE) ? 1 : 0; |
| 721 | err = IMAGE_ERROR_SUCCESS; |
| 722 | break; |
| 874 | 723 | |
| 875 | | /* did the open succeed? */ |
| 876 | | switch(filerr) |
| 877 | | { |
| 878 | | case FILERR_NONE: |
| 879 | | /* success! */ |
| 880 | | image->writeable = (open_flags & OPEN_FLAG_WRITE) ? 1 : 0; |
| 881 | | image->created = (open_flags & OPEN_FLAG_CREATE) ? 1 : 0; |
| 882 | | err = IMAGE_ERROR_SUCCESS; |
| 883 | | break; |
| 724 | case FILERR_NOT_FOUND: |
| 725 | case FILERR_ACCESS_DENIED: |
| 726 | /* file not found (or otherwise cannot open); continue */ |
| 727 | err = IMAGE_ERROR_FILENOTFOUND; |
| 728 | break; |
| 884 | 729 | |
| 885 | | case FILERR_NOT_FOUND: |
| 886 | | case FILERR_ACCESS_DENIED: |
| 887 | | /* file not found (or otherwise cannot open); continue */ |
| 888 | | err = IMAGE_ERROR_FILENOTFOUND; |
| 889 | | break; |
| 730 | case FILERR_OUT_OF_MEMORY: |
| 731 | /* out of memory */ |
| 732 | err = IMAGE_ERROR_OUTOFMEMORY; |
| 733 | break; |
| 890 | 734 | |
| 891 | | case FILERR_OUT_OF_MEMORY: |
| 892 | | /* out of memory */ |
| 893 | | err = IMAGE_ERROR_OUTOFMEMORY; |
| 894 | | break; |
| 735 | case FILERR_ALREADY_OPEN: |
| 736 | /* this shouldn't happen */ |
| 737 | err = IMAGE_ERROR_ALREADYOPEN; |
| 738 | break; |
| 895 | 739 | |
| 896 | | case FILERR_ALREADY_OPEN: |
| 897 | | /* this shouldn't happen */ |
| 898 | | err = IMAGE_ERROR_ALREADYOPEN; |
| 899 | | break; |
| 900 | | |
| 901 | | case FILERR_FAILURE: |
| 902 | | case FILERR_TOO_MANY_FILES: |
| 903 | | case FILERR_INVALID_DATA: |
| 904 | | default: |
| 905 | | /* other errors */ |
| 906 | | err = IMAGE_ERROR_INTERNAL; |
| 907 | | break; |
| 908 | | } |
| 740 | case FILERR_FAILURE: |
| 741 | case FILERR_TOO_MANY_FILES: |
| 742 | case FILERR_INVALID_DATA: |
| 743 | default: |
| 744 | /* other errors */ |
| 745 | err = IMAGE_ERROR_INTERNAL; |
| 746 | break; |
| 909 | 747 | } |
| 910 | 748 | |
| 911 | | /* special case for ZIP files */ |
| 912 | | if ((err == IMAGE_ERROR_FILENOTFOUND) && (open_flags == OPEN_FLAG_READ)) |
| 913 | | err = load_zip_path(image, path); |
| 749 | /* if successful, set the file name */ |
| 750 | if (filerr == FILERR_NONE) |
| 751 | set_image_filename(image, astring_c(revised_path)); |
| 914 | 752 | |
| 915 | | /* check to make sure that our reported error is reflective of the actual status */ |
| 916 | | if (err) |
| 917 | | assert(!is_loaded(image)); |
| 918 | | else |
| 919 | | assert(is_loaded(image)); |
| 920 | | |
| 921 | | /* free up memory, and exit */ |
| 922 | | if (full_path != NULL) |
| 923 | | astring_free(full_path); |
| 753 | astring_free(revised_path); |
| 924 | 754 | return err; |
| 925 | 755 | } |
| 926 | 756 | |
| r3191 | r3192 | |
| 996 | 826 | image_unload(image); |
| 997 | 827 | |
| 998 | 828 | /* record the filename */ |
| 999 | | slot->err = set_image_filename(slot, path, NULL); |
| 829 | slot->err = set_image_filename(slot, path); |
| 1000 | 830 | if (slot->err) |
| 1001 | 831 | goto done; |
| 1002 | 832 | |
| r3191 | r3192 | |
| 1395 | 1225 | const char *image_filename(const device_config *image) |
| 1396 | 1226 | { |
| 1397 | 1227 | image_slot_data *slot = find_image_slot(image); |
| 1398 | | return slot->name; |
| 1228 | const char *name = astring_c(slot->name); |
| 1229 | return (name[0] != '\0') ? name : NULL; |
| 1399 | 1230 | } |
| 1400 | 1231 | |
| 1401 | 1232 | |
| r3191 | r3192 | |
| 1688 | 1519 | const osd_directory_entry *entry; |
| 1689 | 1520 | int success = FALSE; |
| 1690 | 1521 | int done = FALSE; |
| 1691 | | char *new_working_directory; |
| 1692 | 1522 | |
| 1693 | | directory = osd_opendir(image->working_directory); |
| 1523 | directory = osd_opendir(astring_c(image->working_directory)); |
| 1694 | 1524 | if (directory != NULL) |
| 1695 | 1525 | { |
| 1696 | 1526 | while(!done && (entry = osd_readdir(directory)) != NULL) |
| r3191 | r3192 | |
| 1707 | 1537 | |
| 1708 | 1538 | /* did we successfully identify the directory? */ |
| 1709 | 1539 | if (success) |
| 1710 | | { |
| 1711 | | new_working_directory = malloc_or_die(strlen(image->working_directory) |
| 1712 | | + strlen(PATH_SEPARATOR) + strlen(subdir) + strlen(PATH_SEPARATOR) + 1); |
| 1713 | | strcpy(new_working_directory, image->working_directory); |
| 1540 | zippath_combine(image->working_directory, astring_c(image->working_directory), subdir); |
| 1714 | 1541 | |
| 1715 | | /* remove final path separator, if present */ |
| 1716 | | if ((strlen(new_working_directory) >= strlen(PATH_SEPARATOR)) |
| 1717 | | && !strcmp(new_working_directory + strlen(new_working_directory) - strlen(PATH_SEPARATOR), PATH_SEPARATOR)) |
| 1718 | | { |
| 1719 | | new_working_directory[strlen(new_working_directory) - strlen(PATH_SEPARATOR)] = '\0'; |
| 1720 | | } |
| 1721 | | |
| 1722 | | strcat(new_working_directory, PATH_SEPARATOR); |
| 1723 | | strcat(new_working_directory, subdir); |
| 1724 | | strcat(new_working_directory, PATH_SEPARATOR); |
| 1725 | | |
| 1726 | | free(image->working_directory); |
| 1727 | | image->working_directory = new_working_directory; |
| 1728 | | } |
| 1729 | 1542 | return success; |
| 1730 | 1543 | } |
| 1731 | 1544 | |
| r3191 | r3192 | |
| 1743 | 1556 | |
| 1744 | 1557 | /* first set up the working directory to be the MESS directory */ |
| 1745 | 1558 | osd_get_emulator_directory(mess_directory, ARRAY_LENGTH(mess_directory)); |
| 1746 | | image->working_directory = mame_strdup(mess_directory); |
| 1559 | astring_cpyc(image->working_directory, mess_directory); |
| 1747 | 1560 | |
| 1748 | 1561 | /* now try browsing down to "software" */ |
| 1749 | 1562 | if (try_change_working_directory(image, "software")) |
| r3191 | r3192 | |
| 1770 | 1583 | image_slot_data *slot = find_image_slot(image); |
| 1771 | 1584 | |
| 1772 | 1585 | /* check to see if we've never initialized the working directory */ |
| 1773 | | if (slot->working_directory == NULL) |
| 1586 | if (astring_len(slot->working_directory) == 0) |
| 1774 | 1587 | setup_working_directory(slot); |
| 1775 | 1588 | |
| 1776 | | return slot->working_directory; |
| 1589 | return astring_c(slot->working_directory); |
| 1777 | 1590 | } |
| 1778 | 1591 | |
| 1779 | 1592 | |
| r3191 | r3192 | |
| 1786 | 1599 | void image_set_working_directory(const device_config *image, const char *working_directory) |
| 1787 | 1600 | { |
| 1788 | 1601 | image_slot_data *slot = find_image_slot(image); |
| 1789 | | |
| 1790 | | char *new_working_directory = (working_directory != NULL) ? mame_strdup(working_directory) : NULL; |
| 1791 | | if (slot->working_directory != NULL) |
| 1792 | | free(slot->working_directory); |
| 1793 | | slot->working_directory = new_working_directory; |
| 1602 | astring_cpyc(slot->working_directory, (working_directory != NULL) ? working_directory : ""); |
| 1794 | 1603 | } |
| 1795 | 1604 | |
| 1796 | 1605 | |
src/mess/zippath.c
| r3191 | r3192 | |
| 43 | 43 | }; |
| 44 | 44 | |
| 45 | 45 | |
| 46 | /*************************************************************************** |
| 47 | FUNCTION PROTOTYPES |
| 48 | ***************************************************************************/ |
| 46 | 49 | |
| 50 | static const zip_file_header *zippath_find_sub_path(zip_file *zipfile, const char *subpath, osd_dir_entry_type *type); |
| 51 | static int is_zip_file(const char *path); |
| 52 | static int is_zip_file_separator(char c); |
| 53 | |
| 54 | |
| 47 | 55 | /*************************************************************************** |
| 48 | 56 | PATH OPERATIONS |
| 49 | 57 | ***************************************************************************/ |
| r3191 | r3192 | |
| 141 | 149 | |
| 142 | 150 | |
| 143 | 151 | /*************************************************************************** |
| 152 | FILE OPERATIONS |
| 153 | ***************************************************************************/ |
| 154 | |
| 155 | /*------------------------------------------------- |
| 156 | file_error_from_zip_error - translates a |
| 157 | file_error to a zip_error |
| 158 | -------------------------------------------------*/ |
| 159 | |
| 160 | static file_error file_error_from_zip_error(zip_error ziperr) |
| 161 | { |
| 162 | file_error filerr; |
| 163 | switch(ziperr) |
| 164 | { |
| 165 | case ZIPERR_NONE: |
| 166 | filerr = FILERR_NONE; |
| 167 | break; |
| 168 | case ZIPERR_OUT_OF_MEMORY: |
| 169 | filerr = FILERR_OUT_OF_MEMORY; |
| 170 | break; |
| 171 | case ZIPERR_BAD_SIGNATURE: |
| 172 | case ZIPERR_DECOMPRESS_ERROR: |
| 173 | case ZIPERR_FILE_TRUNCATED: |
| 174 | case ZIPERR_FILE_CORRUPT: |
| 175 | case ZIPERR_UNSUPPORTED: |
| 176 | case ZIPERR_FILE_ERROR: |
| 177 | filerr = FILERR_INVALID_DATA; |
| 178 | break; |
| 179 | case ZIPERR_BUFFER_TOO_SMALL: |
| 180 | default: |
| 181 | filerr = FILERR_FAILURE; |
| 182 | break; |
| 183 | } |
| 184 | return filerr; |
| 185 | } |
| 186 | |
| 187 | |
| 188 | /*------------------------------------------------- |
| 189 | create_core_file_from_zip - creates a core_file |
| 190 | from a zip file entry |
| 191 | -------------------------------------------------*/ |
| 192 | |
| 193 | static file_error create_core_file_from_zip(zip_file *zip, const zip_file_header *header, core_file **file) |
| 194 | { |
| 195 | file_error filerr; |
| 196 | zip_error ziperr; |
| 197 | void *ptr; |
| 198 | |
| 199 | ptr = malloc(header->uncompressed_length); |
| 200 | if (ptr == NULL) |
| 201 | { |
| 202 | filerr = FILERR_OUT_OF_MEMORY; |
| 203 | goto done; |
| 204 | } |
| 205 | |
| 206 | ziperr = zip_file_decompress(zip, ptr, header->uncompressed_length); |
| 207 | if (ziperr != ZIPERR_NONE) |
| 208 | { |
| 209 | filerr = file_error_from_zip_error(ziperr); |
| 210 | goto done; |
| 211 | } |
| 212 | |
| 213 | filerr = core_fopen_ram_copy(ptr, header->uncompressed_length, OPEN_FLAG_READ, file); |
| 214 | if (filerr != FILERR_NONE) |
| 215 | goto done; |
| 216 | |
| 217 | done: |
| 218 | if (ptr != NULL) |
| 219 | free(ptr); |
| 220 | return filerr; |
| 221 | } |
| 222 | |
| 223 | |
| 224 | /*------------------------------------------------- |
| 225 | zippath_fopen - opens a zip path file |
| 226 | -------------------------------------------------*/ |
| 227 | |
| 228 | file_error zippath_fopen(const char *filename, UINT32 openflags, core_file **file, astring *revised_path) |
| 229 | { |
| 230 | file_error filerr = FILERR_NOT_FOUND; |
| 231 | zip_error ziperr; |
| 232 | zip_file *zip = NULL; |
| 233 | const zip_file_header *header; |
| 234 | osd_dir_entry_type entry_type; |
| 235 | astring *mainpath; |
| 236 | astring *subpath; |
| 237 | astring *temp; |
| 238 | astring *temp2; |
| 239 | char *alloc_fullpath = NULL; |
| 240 | int len; |
| 241 | |
| 242 | /* first, set up the two types of paths */ |
| 243 | mainpath = astring_cpyc(astring_alloc(), filename); |
| 244 | subpath = astring_alloc(); |
| 245 | temp = astring_alloc(); |
| 246 | temp2 = astring_alloc(); |
| 247 | *file = NULL; |
| 248 | |
| 249 | /* loop through */ |
| 250 | while((*file == NULL) && (astring_len(mainpath) > 0) |
| 251 | && ((openflags == OPEN_FLAG_READ) || (astring_len(subpath) == 0))) |
| 252 | { |
| 253 | /* is the mainpath a ZIP path? */ |
| 254 | if (is_zip_file(astring_c(mainpath))) |
| 255 | { |
| 256 | /* this file might be a zip file - lets take a look */ |
| 257 | ziperr = zip_file_open(astring_c(mainpath), &zip); |
| 258 | if (ziperr == ZIPERR_NONE) |
| 259 | { |
| 260 | /* it is a zip file - error if we're not opening for reading */ |
| 261 | if (openflags != OPEN_FLAG_READ) |
| 262 | { |
| 263 | filerr = FILERR_ACCESS_DENIED; |
| 264 | goto done; |
| 265 | } |
| 266 | |
| 267 | if (astring_len(subpath) > 0) |
| 268 | header = zippath_find_sub_path(zip, astring_c(subpath), &entry_type); |
| 269 | else |
| 270 | header = zip_file_first_file(zip); |
| 271 | |
| 272 | if (header == NULL) |
| 273 | { |
| 274 | filerr = FILERR_NOT_FOUND; |
| 275 | goto done; |
| 276 | } |
| 277 | |
| 278 | /* attempt to read the file */ |
| 279 | filerr = create_core_file_from_zip(zip, header, file); |
| 280 | if (filerr != FILERR_NONE) |
| 281 | goto done; |
| 282 | |
| 283 | /* update subpath, if appropriate */ |
| 284 | if (astring_len(subpath) == 0) |
| 285 | astring_cpyc(subpath, header->filename); |
| 286 | |
| 287 | /* we're done */ |
| 288 | goto done; |
| 289 | } |
| 290 | } |
| 291 | |
| 292 | if (astring_len(subpath) == 0) |
| 293 | filerr = core_fopen(filename, openflags, file); |
| 294 | else |
| 295 | filerr = FILERR_NOT_FOUND; |
| 296 | |
| 297 | /* if we errored, then go up a directory */ |
| 298 | if (filerr != FILERR_NONE) |
| 299 | { |
| 300 | /* go up a directory */ |
| 301 | zippath_parent(temp, astring_c(mainpath)); |
| 302 | |
| 303 | /* append to the sub path */ |
| 304 | if (astring_len(subpath) > 0) |
| 305 | { |
| 306 | astring_assemble_3(temp2, astring_c(mainpath) + astring_len(temp), PATH_SEPARATOR, astring_c(subpath)); |
| 307 | astring_cpy(subpath, temp2); |
| 308 | } |
| 309 | else |
| 310 | { |
| 311 | astring_cpyc(subpath, astring_c(mainpath) + astring_len(temp)); |
| 312 | } |
| 313 | |
| 314 | /* get the new main path, truncating path separators */ |
| 315 | len = astring_len(temp); |
| 316 | while((len > 0) && is_zip_file_separator(astring_c(temp)[len - 1])) |
| 317 | len--; |
| 318 | astring_cpych(mainpath, astring_c(temp), len); |
| 319 | } |
| 320 | } |
| 321 | |
| 322 | done: |
| 323 | /* store the revised path if appropriate */ |
| 324 | if (revised_path != NULL) |
| 325 | { |
| 326 | astring_cpyc(revised_path, ""); |
| 327 | if (filerr == FILERR_NONE) |
| 328 | { |
| 329 | /* cannonicalize mainpath */ |
| 330 | filerr = osd_get_full_path(&alloc_fullpath, astring_c(mainpath)); |
| 331 | if (filerr == FILERR_NONE) |
| 332 | { |
| 333 | if (astring_len(subpath) > 0) |
| 334 | astring_assemble_3(revised_path, alloc_fullpath, PATH_SEPARATOR, astring_c(subpath)); |
| 335 | else |
| 336 | astring_cpyc(revised_path, alloc_fullpath); |
| 337 | } |
| 338 | } |
| 339 | } |
| 340 | |
| 341 | if (zip != NULL) |
| 342 | zip_file_close(zip); |
| 343 | if (mainpath != NULL) |
| 344 | astring_free(mainpath); |
| 345 | if (subpath != NULL) |
| 346 | astring_free(subpath); |
| 347 | if (temp != NULL) |
| 348 | astring_free(temp); |
| 349 | if (temp2 != NULL) |
| 350 | astring_free(temp2); |
| 351 | if (alloc_fullpath != NULL) |
| 352 | free(alloc_fullpath); |
| 353 | return filerr; |
| 354 | } |
| 355 | |
| 356 | |
| 357 | /*************************************************************************** |
| 144 | 358 | DIRECTORY OPERATIONS |
| 145 | 359 | ***************************************************************************/ |
| 146 | 360 | |
| r3191 | r3192 | |
| 249 | 463 | type of a sub path in a zip file |
| 250 | 464 | -------------------------------------------------*/ |
| 251 | 465 | |
| 252 | | const zip_file_header *zippath_find_sub_path(zip_file *zipfile, const char *subpath, osd_dir_entry_type *type) |
| 466 | static const zip_file_header *zippath_find_sub_path(zip_file *zipfile, const char *subpath, osd_dir_entry_type *type) |
| 253 | 467 | { |
| 254 | 468 | int i, j; |
| 255 | 469 | char c1, c2, last_char; |