diff options
Diffstat (limited to 'source/blender/blenkernel/intern/packedFile.c')
-rw-r--r-- | source/blender/blenkernel/intern/packedFile.c | 638 |
1 files changed, 638 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c new file mode 100644 index 00000000000..991b4a8c840 --- /dev/null +++ b/source/blender/blenkernel/intern/packedFile.c @@ -0,0 +1,638 @@ +/** + * blenkernel/packedFile.c - (cleaned up mar-01 nzc) + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include <stdio.h> +#include <fcntl.h> +#include <sys/stat.h> +#ifndef WIN32 +#include <unistd.h> +#else +#include <io.h> +#endif +#include <string.h> +#include "MEM_guardedalloc.h" + +#include "DNA_image_types.h" +#include "DNA_sound_types.h" +#include "DNA_vfont_types.h" +#include "DNA_packedFile_types.h" + + +#include "BLI_blenlib.h" + +#include "BKE_utildefines.h" +#include "BKE_bad_level_calls.h" + +#include "BKE_global.h" +#include "BKE_main.h" + +#include "BKE_screen.h" + +#include "BKE_sound.h" +//#include "sound.h" + +#include "BKE_image.h" +#include "BKE_font.h" +#include "BKE_packedFile.h" + +int seekPackedFile(PackedFile * pf, int offset, int whence) +{ + int oldseek = -1, seek = 0; + + if (pf) { + oldseek = pf->seek; + switch(whence) { + case SEEK_CUR: + seek = oldseek + offset; + break; + case SEEK_END: + seek = pf->size + offset; + break; + case SEEK_SET: + seek = offset; + break; + default: + oldseek = -1; + } + if (seek < 0) { + seek = 0; + } else if (seek > pf->size) { + seek = pf->size; + } + pf->seek = seek; + } + + return(oldseek); +} + +void rewindPackedFile(PackedFile * pf) +{ + seekPackedFile(pf, 0, SEEK_SET); +} + +int readPackedFile(PackedFile * pf, void * data, int size) +{ + if ((pf != NULL) && (size >= 0) && (data != NULL)) { + if (size + pf->seek > pf->size) { + size = pf->size - pf->seek; + } + + if (size > 0) { + memcpy(data, ((char *) pf->data) + pf->seek, size); + } else { + size = 0; + } + + pf->seek += size; + } else { + size = -1; + } + + return(size); +} + +int countPackedFiles() +{ + int count = 0; + Image *ima; + VFont *vf; + bSample *sample; + + // let's check if there are packed files... + ima = G.main->image.first; + while (ima) { + if (ima->packedfile) { + count++; + } + ima= ima->id.next; + } + + vf = G.main->vfont.first; + while (vf) { + if (vf->packedfile) { + count++; + } + vf = vf->id.next; + } + + sample = samples->first; + while (sample) { + if (sample->packedfile) { + count++; + } + sample = sample->id.next; + } + + return(count); +} + +void freePackedFile(PackedFile * pf) +{ + if (pf) { + MEM_freeN(pf->data); + MEM_freeN(pf); + } else { + printf("freePackedFile: Trying to free a NULL pointer\n"); + } +} + +PackedFile * newPackedFileMemory(void *mem, int memlen) +{ + PackedFile * pf = MEM_callocN(sizeof(*pf), "PackedFile"); + pf->data = mem; + pf->size = memlen; + + return pf; +} + +PackedFile * newPackedFile(char * filename) +{ + PackedFile * pf = NULL; + int file, filelen; + char name[FILE_MAXDIR+FILE_MAXFILE]; + void * data; + + waitcursor(1); + + // convert relative filenames to absolute filenames + + strcpy(name, filename); + BLI_convertstringcode(name, G.sce, G.scene->r.cfra); + + // open the file + // and create a PackedFile structure + + file= open(name, O_BINARY|O_RDONLY); + if (file <= 0) { + // error("Can't open file: %s", name); + } else { + filelen = BLI_filesize(file); + + if (filelen == 0) { + // MEM_mallocN complains about MEM_mallocN(0, "bla"); + // we don't care.... + data = MEM_mallocN(1, "packFile"); + } else { + data = MEM_mallocN(filelen, "packFile"); + } + if (read(file, data, filelen) == filelen) { + pf = newPackedFileMemory(data, filelen); + } + + close(file); + } + + waitcursor(0); + + return (pf); +} + +void packAll() +{ + Image *ima; + VFont *vf; + bSample *sample; + + ima = G.main->image.first; + while (ima) { + if (ima->packedfile == NULL) { + ima->packedfile = newPackedFile(ima->name); + } + ima= ima->id.next; + } + + vf = G.main->vfont.first; + while (vf) { + if (vf->packedfile == NULL) { + vf->packedfile = newPackedFile(vf->name); + } + vf = vf->id.next; + } + + + sample = samples->first; + while (sample) { + if (sample->packedfile == NULL) { + sound_set_packedfile(sample, newPackedFile(sample->name)); + } + sample = sample->id.next; + } +} + + +/* + +// attempt to create a function that generates an unique filename +// this will work when all funtions in fileops.c understand relative filenames... + +char * find_new_name(char * name) +{ + char tempname[FILE_MAXDIR + FILE_MAXFILE]; + char * newname; + + if (fop_exists(name)) { + for (number = 1; number <= 999; number++) { + sprintf(tempname, "%s.%03d", name, number); + if (! fop_exists(tempname)) { + break; + } + } + } + + newname = mallocN(strlen(tempname) + 1, "find_new_name"); + strcpy(newname, tempname); + + return(newname); +} + +*/ + +int writePackedFile(char * filename, PackedFile *pf) +{ + int file, number, remove_tmp = FALSE; + int ret_value = RET_OK; + char name[FILE_MAXDIR + FILE_MAXFILE]; + char tempname[FILE_MAXDIR + FILE_MAXFILE]; +/* void * data; */ + + waitcursor(1); + + strcpy(name, filename); + BLI_convertstringcode(name, G.sce, G.scene->r.cfra); + + if (BLI_exists(name)) { + for (number = 1; number <= 999; number++) { + sprintf(tempname, "%s.%03d_", name, number); + if (! BLI_exists(tempname)) { + if (BLI_copy_fileops(name, tempname) == RET_OK) { + remove_tmp = TRUE; + } + break; + } + } + } + + // make sure the path to the file exists... + RE_make_existing_file(name); + + file = open(name, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666); + if (file >= 0) { + if (write(file, pf->data, pf->size) != pf->size) { + error("Error writing file: %s", name); + ret_value = RET_ERROR; + } + close(file); + } else { + error("Error creating file: %s", name); + ret_value = RET_ERROR; + } + + if (remove_tmp) { + if (ret_value == RET_ERROR) { + if (BLI_rename(tempname, name) == RET_ERROR) { + error("Error restoring tempfile. Check files: '%s' '%s'", tempname, name); + } + } else { + if (BLI_delete(tempname, 0, 0) == RET_ERROR) { + error("Error deleting '%s' (ignored)"); + } + } + } + + waitcursor(0); + + return (ret_value); +} + +/* + +This function compares a packed file to a 'real' file. +It returns an integer indicating if: + +PF_EQUAL - the packed file and original file are identical +PF_DIFFERENT - the packed file and original file differ +PF_NOFILE - the original file doens't exist + +*/ + +int checkPackedFile(char * filename, PackedFile * pf) +{ + struct stat st; + int ret_val, i, len, file; + char buf[4096]; + char name[FILE_MAXDIR + FILE_MAXFILE]; + + strcpy(name, filename); + BLI_convertstringcode(name, G.sce, G.scene->r.cfra); + + if (stat(name, &st)) { + ret_val = PF_NOFILE; + } else if (st.st_size != pf->size) { + ret_val = PF_DIFFERS; + } else { + // we'll have to compare the two... + + file = open(name, O_BINARY | O_RDONLY); + if (file < 0) { + ret_val = PF_NOFILE; + } else { + ret_val = PF_EQUAL; + + for (i = 0; i < pf->size; i += sizeof(buf)) { + len = pf->size - i; + if (len > sizeof(buf)) { + len = sizeof(buf); + } + + if (read(file, buf, len) != len) { + // read error ... + ret_val = PF_DIFFERS; + break; + } else { + if (memcmp(buf, ((char *)pf->data) + i, len)) { + ret_val = PF_DIFFERS; + break; + } + } + } + } + } + + return(ret_val); +} + +/* + +unpackFile() looks at the existing files (abs_name, local_name) and a packed file. +If how == PF_ASK it offers the user a couple of options what to do with the packed file. + +It returns a char * to the existing file name / new file name or NULL when +there was an error or when the user desides to cancel the operation. + +*/ + +char * unpackFile(char * abs_name, char * local_name, PackedFile * pf, int how) +{ + char menu[6 * (FILE_MAXDIR + FILE_MAXFILE + 100)]; + char line[FILE_MAXDIR + FILE_MAXFILE + 100]; + char * newname = NULL, * temp = NULL; + + // char newabs[FILE_MAXDIR + FILE_MAXFILE]; + // char newlocal[FILE_MAXDIR + FILE_MAXFILE]; + + if (pf != NULL) { + if (how == PF_ASK) { + strcpy(menu, "UnPack file%t"); + + if (strcmp(abs_name, local_name)) { + switch (checkPackedFile(local_name, pf)) { + case PF_NOFILE: + sprintf(line, "|Create %s%%x%d", local_name, PF_WRITE_LOCAL); + strcat(menu, line); + break; + case PF_EQUAL: + sprintf(line, "|Use %s (identical)%%x%d", local_name, PF_USE_LOCAL); + strcat(menu, line); + break; + case PF_DIFFERS: + sprintf(line, "|Use %s (differs)%%x%d", local_name, PF_USE_LOCAL); + strcat(menu, line); + sprintf(line, "|Overwrite %s%%x%d", local_name, PF_WRITE_LOCAL); + strcat(menu, line); + break; + } + // sprintf(line, "|%%x%d", PF_INVALID); + // strcat(menu, line); + } + + switch (checkPackedFile(abs_name, pf)) { + case PF_NOFILE: + sprintf(line, "|Create %s%%x%d", abs_name, PF_WRITE_ORIGINAL); + strcat(menu, line); + break; + case PF_EQUAL: + sprintf(line, "|Use %s (identical)%%x%d", abs_name, PF_USE_ORIGINAL); + strcat(menu, line); + break; + case PF_DIFFERS: + sprintf(line, "|Use %s (differs)%%x%d", abs_name, PF_USE_ORIGINAL); + strcat(menu, line); + sprintf(line, "|Overwrite %s%%x%d", abs_name, PF_WRITE_ORIGINAL); + strcat(menu, line); + break; + } + + how = pupmenu(menu); + } + + switch (how) { + case -1: + case PF_KEEP: + break; + case PF_USE_LOCAL: + // if file exists use it + if (BLI_exists(local_name)) { + temp = local_name; + break; + } + // else fall through and create it + case PF_WRITE_LOCAL: + if (writePackedFile(local_name, pf) == RET_OK) { + temp = local_name; + } + break; + case PF_USE_ORIGINAL: + // if file exists use it + if (BLI_exists(abs_name)) { + temp = abs_name; + break; + } + // else fall through and create it + case PF_WRITE_ORIGINAL: + if (writePackedFile(abs_name, pf) == RET_OK) { + temp = abs_name; + } + break; + default: + printf("unpackFile: unknown return_value %d\n", how); + break; + } + + if (temp) { + newname = MEM_mallocN(strlen(temp) + 1, "unpack_file newname"); + strcpy(newname, temp); + } + } + + return (newname); +} + + +int unpackVFont(VFont * vfont, int how) +{ + char localname[FILE_MAXDIR + FILE_MAXFILE], fi[FILE_MAXFILE]; + char * newname; + int ret_value = RET_ERROR; + + if (vfont != NULL) { + strcpy(localname, vfont->name); + BLI_splitdirstring(localname, fi); + + sprintf(localname, "//fonts/%s", fi); + + newname = unpackFile(vfont->name, localname, vfont->packedfile, how); + if (newname != NULL) { + ret_value = RET_OK; + freePackedFile(vfont->packedfile); + vfont->packedfile = 0; + strcpy(vfont->name, newname); + MEM_freeN(newname); + } + } + + return (ret_value); +} + +/* +create_local_name() creates a relative (starting with //) name. +Because it is allowed to have /'s and \'s in blenderobject names +we have to remove these first. +*/ + + +void create_local_name(char *localname, char *prefix, char *filename) +{ + char tempname[FILE_MAXDIR + FILE_MAXFILE]; + int i, len; + + strcpy(tempname, filename); + len = strlen(tempname); + + for (i = 0; i < len ; i++) { + switch (tempname[i]) + { + case '/': + case '\\': + case ' ': + tempname[i] = '_'; + break; + } + } + + strcpy(localname, prefix); + strcat(localname, tempname); +} + + +int unpackSample(bSample *sample, int how) +{ + char localname[FILE_MAXDIR + FILE_MAXFILE]; + char * newname; + int ret_value = RET_ERROR; + PackedFile *pf; + + if (sample != NULL) { + create_local_name(localname, "//samples/", sample->id.name + 2); + + newname = unpackFile(sample->name, localname, sample->packedfile, how); + if (newname != NULL) { + strcpy(sample->name, newname); + MEM_freeN(newname); + + pf = sample->packedfile; + // because samples and sounds can point to the + // same packedfile we have to check them all + sound_set_packedfile(sample, NULL); + freePackedFile(pf); + + ret_value = RET_OK; + } + } + + return(ret_value); +} + +int unpackImage(Image * ima, int how) +{ + char localname[FILE_MAXDIR + FILE_MAXFILE]; + char * newname; + int ret_value = RET_ERROR; + + if (ima != NULL) { + create_local_name(localname, "//textures/", ima->id.name + 2); + + newname = unpackFile(ima->name, localname, ima->packedfile, how); + if (newname != NULL) { + ret_value = RET_OK; + freePackedFile(ima->packedfile); + ima->packedfile = 0; + strcpy(ima->name, newname); + MEM_freeN(newname); + free_image_buffers(ima); + } + } + + return(ret_value); +} + +void unpackAll(int how) +{ + Image *ima; + VFont *vf; + bSample *sample; + + ima = G.main->image.first; + while (ima) { + if (ima->packedfile) { + unpackImage(ima, how); + } + ima= ima->id.next; + } + + vf = G.main->vfont.first; + while (vf) { + if (vf->packedfile) { + unpackVFont(vf, how); + } + vf = vf->id.next; + } + + sample = samples->first; + while (sample) { + if (sample->packedfile) { + unpackSample(sample, how); + } + sample = sample->id.next; + } +} |