This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/blenkernel/intern/packedFile.c
Campbell Barton 51dcbdde03 use 'const char *' by default with RNA functions except when the value is flagged as PROP_THICK_WRAP.
Also use const char in many other parts of blenders code.

Currently this gives warnings for setting operator id, label and description since these are an exception and allocated beforehand.
2010-11-17 09:45:45 +00:00

542 lines
12 KiB
C

/**
* blenkernel/packedFile.c - (cleaned up mar-01 nzc)
*
* $Id$
*
* ***** BEGIN GPL 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.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 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_global.h"
#include "BKE_main.h"
#include "BKE_sound.h"
#include "BKE_image.h"
#include "BKE_packedFile.h"
#include "BKE_report.h"
#ifdef _WIN32
#define open _open
#define close _close
#define read _read
#define write _write
#endif
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(Main *bmain)
{
Image *ima;
VFont *vf;
bSound *sound;
int count = 0;
// let's check if there are packed files...
for(ima=bmain->image.first; ima; ima=ima->id.next)
if(ima->packedfile)
count++;
for(vf=bmain->vfont.first; vf; vf=vf->id.next)
if(vf->packedfile)
count++;
for(sound=bmain->sound.first; sound; sound=sound->id.next)
if(sound->packedfile)
count++;
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(ReportList *reports, const char *filename)
{
PackedFile *pf = NULL;
int file, filelen;
char name[FILE_MAXDIR+FILE_MAXFILE];
void *data;
/* render result has no filename and can be ignored
* any other files with no name can be ignored too */
if(filename[0]=='\0')
return NULL;
//XXX waitcursor(1);
// convert relative filenames to absolute filenames
strcpy(name, filename);
BLI_path_abs(name, G.main->name);
// open the file
// and create a PackedFile structure
file= open(name, O_BINARY|O_RDONLY);
if (file <= 0) {
BKE_reportf(reports, RPT_ERROR, "Unable to pack file, source path not found: \"%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);
}
//XXX waitcursor(0);
return (pf);
}
void packAll(Main *bmain, ReportList *reports)
{
Image *ima;
VFont *vf;
bSound *sound;
for(ima=bmain->image.first; ima; ima=ima->id.next) {
if(ima->packedfile == NULL && ima->id.lib==NULL) {
if(ima->source==IMA_SRC_FILE) {
ima->packedfile = newPackedFile(reports, ima->name);
}
else if(ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) {
BKE_reportf(reports, RPT_WARNING, "Image '%s' skipped, movies and image sequences not supported.", ima->id.name+2);
}
}
}
for(vf=bmain->vfont.first; vf; vf=vf->id.next)
if(vf->packedfile == NULL && vf->id.lib==NULL && strcmp(vf->name, FO_BUILTIN_NAME) != 0)
vf->packedfile = newPackedFile(reports, vf->name);
for(sound=bmain->sound.first; sound; sound=sound->id.next)
if(sound->packedfile == NULL && sound->id.lib==NULL)
sound->packedfile = newPackedFile(reports, sound->name);
}
/*
// attempt to create a function that generates an unique filename
// this will work when all funtions in fileops.c understand relative filenames...
static 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(ReportList *reports, char *filename, PackedFile *pf, int guimode)
{
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; */
if (guimode) {} //XXX waitcursor(1);
strcpy(name, filename);
BLI_path_abs(name, G.main->name);
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...
BLI_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) {
BKE_reportf(reports, RPT_ERROR, "Error writing file: %s", name);
ret_value = RET_ERROR;
}
close(file);
} else {
BKE_reportf(reports, RPT_ERROR, "Error creating file: %s", name);
ret_value = RET_ERROR;
}
if (remove_tmp) {
if (ret_value == RET_ERROR) {
if (BLI_rename(tempname, name) != 0) {
BKE_reportf(reports, RPT_ERROR, "Error restoring tempfile. Check files: '%s' '%s'", tempname, name);
}
} else {
if (BLI_delete(tempname, 0, 0) != 0) {
BKE_reportf(reports, RPT_ERROR, "Error deleting '%s' (ignored)", tempname);
}
}
}
if(guimode) {} //XXX 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_path_abs(name, G.main->name);
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;
}
}
}
close(file);
}
}
return(ret_val);
}
/*
unpackFile() looks at the existing files (abs_name, local_name) and a 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(ReportList *reports, char *abs_name, char *local_name, PackedFile *pf, int how)
{
char *newname = NULL, *temp = NULL;
// char newabs[FILE_MAXDIR + FILE_MAXFILE];
// char newlocal[FILE_MAXDIR + FILE_MAXFILE];
if (pf != NULL) {
switch (how) {
case -1:
case PF_KEEP:
break;
case PF_REMOVE:
temp= abs_name;
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(reports, local_name, pf, 1) == 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(reports, abs_name, pf, 1) == 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(ReportList *reports, 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(reports, 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);
}
int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how)
{
char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
char *newname;
int ret_value = RET_ERROR;
if (sound != NULL) {
strcpy(localname, sound->name);
BLI_splitdirstring(localname, fi);
sprintf(localname, "//sounds/%s", fi);
newname = unpackFile(reports, sound->name, localname, sound->packedfile, how);
if (newname != NULL) {
strcpy(sound->name, newname);
MEM_freeN(newname);
freePackedFile(sound->packedfile);
sound->packedfile = 0;
sound_load(bmain, sound);
ret_value = RET_OK;
}
}
return(ret_value);
}
int unpackImage(ReportList *reports, Image *ima, int how)
{
char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
char *newname;
int ret_value = RET_ERROR;
if (ima != NULL) {
strcpy(localname, ima->name);
BLI_splitdirstring(localname, fi);
sprintf(localname, "//textures/%s", fi);
newname = unpackFile(reports, ima->name, localname, ima->packedfile, how);
if (newname != NULL) {
ret_value = RET_OK;
freePackedFile(ima->packedfile);
ima->packedfile = NULL;
strcpy(ima->name, newname);
MEM_freeN(newname);
BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
}
}
return(ret_value);
}
void unpackAll(Main *bmain, ReportList *reports, int how)
{
Image *ima;
VFont *vf;
bSound *sound;
for(ima=bmain->image.first; ima; ima=ima->id.next)
if(ima->packedfile)
unpackImage(reports, ima, how);
for(vf=bmain->vfont.first; vf; vf=vf->id.next)
if(vf->packedfile)
unpackVFont(reports, vf, how);
for(sound=bmain->sound.first; sound; sound=sound->id.next)
if(sound->packedfile)
unpackSound(bmain, reports, sound, how);
}