465 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			465 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * 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.
 | 
						|
 */
 | 
						|
 | 
						|
/** \file
 | 
						|
 * \ingroup bke
 | 
						|
 */
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
#include "MEM_guardedalloc.h"
 | 
						|
 | 
						|
#include "BLI_endian_switch.h"
 | 
						|
#include "BLI_fileops.h"
 | 
						|
#include "BLI_string.h"
 | 
						|
#include "BLI_utildefines.h"
 | 
						|
 | 
						|
#include "BKE_customdata_file.h"
 | 
						|
#include "BKE_global.h"
 | 
						|
 | 
						|
/************************* File Format Definitions ***************************/
 | 
						|
 | 
						|
#define CDF_ENDIAN_LITTLE 0
 | 
						|
#define CDF_ENDIAN_BIG 1
 | 
						|
 | 
						|
#define CDF_DATA_FLOAT 0
 | 
						|
 | 
						|
typedef struct CDataFileHeader {
 | 
						|
  char ID[4];      /* "BCDF" */
 | 
						|
  char endian;     /* little, big */
 | 
						|
  char version;    /* non-compatible versions */
 | 
						|
  char subversion; /* compatible sub versions */
 | 
						|
  char pad;        /* padding */
 | 
						|
 | 
						|
  int structbytes; /* size of this struct in bytes */
 | 
						|
  int type;        /* image, mesh */
 | 
						|
  int totlayer;    /* number of layers in the file */
 | 
						|
} CDataFileHeader;
 | 
						|
 | 
						|
typedef struct CDataFileImageHeader {
 | 
						|
  int structbytes; /* size of this struct in bytes */
 | 
						|
  int width;       /* image width */
 | 
						|
  int height;      /* image height */
 | 
						|
  int tile_size;   /* tile size (required power of 2) */
 | 
						|
} CDataFileImageHeader;
 | 
						|
 | 
						|
typedef struct CDataFileMeshHeader {
 | 
						|
  int structbytes; /* size of this struct in bytes */
 | 
						|
} CDataFileMeshHeader;
 | 
						|
 | 
						|
struct CDataFileLayer {
 | 
						|
  int structbytes;               /* size of this struct in bytes */
 | 
						|
  int datatype;                  /* only float for now */
 | 
						|
  uint64_t datasize;             /* size of data in layer */
 | 
						|
  int type;                      /* layer type */
 | 
						|
  char name[CDF_LAYER_NAME_MAX]; /* layer name */
 | 
						|
};
 | 
						|
 | 
						|
/**************************** Other Definitions ******************************/
 | 
						|
 | 
						|
#define CDF_VERSION 0
 | 
						|
#define CDF_SUBVERSION 0
 | 
						|
#define CDF_TILE_SIZE 64
 | 
						|
 | 
						|
struct CDataFile {
 | 
						|
  int type;
 | 
						|
 | 
						|
  CDataFileHeader header;
 | 
						|
  union {
 | 
						|
    CDataFileImageHeader image;
 | 
						|
    CDataFileMeshHeader mesh;
 | 
						|
  } btype;
 | 
						|
 | 
						|
  CDataFileLayer *layer;
 | 
						|
  int totlayer;
 | 
						|
 | 
						|
  FILE *readf;
 | 
						|
  FILE *writef;
 | 
						|
  int switchendian;
 | 
						|
  size_t dataoffset;
 | 
						|
};
 | 
						|
 | 
						|
/********************************* Create/Free *******************************/
 | 
						|
 | 
						|
static int cdf_endian(void)
 | 
						|
{
 | 
						|
  if (ENDIAN_ORDER == L_ENDIAN) {
 | 
						|
    return CDF_ENDIAN_LITTLE;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    return CDF_ENDIAN_BIG;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
CDataFile *cdf_create(int type)
 | 
						|
{
 | 
						|
  CDataFile *cdf = MEM_callocN(sizeof(CDataFile), "CDataFile");
 | 
						|
 | 
						|
  cdf->type = type;
 | 
						|
 | 
						|
  return cdf;
 | 
						|
}
 | 
						|
 | 
						|
void cdf_free(CDataFile *cdf)
 | 
						|
{
 | 
						|
  cdf_read_close(cdf);
 | 
						|
  cdf_write_close(cdf);
 | 
						|
 | 
						|
  if (cdf->layer) {
 | 
						|
    MEM_freeN(cdf->layer);
 | 
						|
  }
 | 
						|
 | 
						|
  MEM_freeN(cdf);
 | 
						|
}
 | 
						|
 | 
						|
/********************************* Read/Write ********************************/
 | 
						|
 | 
						|
static int cdf_read_header(CDataFile *cdf)
 | 
						|
{
 | 
						|
  CDataFileHeader *header;
 | 
						|
  CDataFileImageHeader *image;
 | 
						|
  CDataFileMeshHeader *mesh;
 | 
						|
  CDataFileLayer *layer;
 | 
						|
  FILE *f = cdf->readf;
 | 
						|
  size_t offset = 0;
 | 
						|
  int a;
 | 
						|
 | 
						|
  header = &cdf->header;
 | 
						|
 | 
						|
  if (!fread(header, sizeof(CDataFileHeader), 1, cdf->readf)) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (memcmp(header->ID, "BCDF", sizeof(header->ID)) != 0) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
  if (header->version > CDF_VERSION) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  cdf->switchendian = header->endian != cdf_endian();
 | 
						|
  header->endian = cdf_endian();
 | 
						|
 | 
						|
  if (cdf->switchendian) {
 | 
						|
    BLI_endian_switch_int32(&header->type);
 | 
						|
    BLI_endian_switch_int32(&header->totlayer);
 | 
						|
    BLI_endian_switch_int32(&header->structbytes);
 | 
						|
  }
 | 
						|
 | 
						|
  if (!ELEM(header->type, CDF_TYPE_IMAGE, CDF_TYPE_MESH)) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  offset += header->structbytes;
 | 
						|
  header->structbytes = sizeof(CDataFileHeader);
 | 
						|
 | 
						|
  if (fseek(f, offset, SEEK_SET) != 0) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (header->type == CDF_TYPE_IMAGE) {
 | 
						|
    image = &cdf->btype.image;
 | 
						|
    if (!fread(image, sizeof(CDataFileImageHeader), 1, f)) {
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    if (cdf->switchendian) {
 | 
						|
      BLI_endian_switch_int32(&image->width);
 | 
						|
      BLI_endian_switch_int32(&image->height);
 | 
						|
      BLI_endian_switch_int32(&image->tile_size);
 | 
						|
      BLI_endian_switch_int32(&image->structbytes);
 | 
						|
    }
 | 
						|
 | 
						|
    offset += image->structbytes;
 | 
						|
    image->structbytes = sizeof(CDataFileImageHeader);
 | 
						|
  }
 | 
						|
  else if (header->type == CDF_TYPE_MESH) {
 | 
						|
    mesh = &cdf->btype.mesh;
 | 
						|
    if (!fread(mesh, sizeof(CDataFileMeshHeader), 1, f)) {
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    if (cdf->switchendian) {
 | 
						|
      BLI_endian_switch_int32(&mesh->structbytes);
 | 
						|
    }
 | 
						|
 | 
						|
    offset += mesh->structbytes;
 | 
						|
    mesh->structbytes = sizeof(CDataFileMeshHeader);
 | 
						|
  }
 | 
						|
 | 
						|
  if (fseek(f, offset, SEEK_SET) != 0) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  cdf->layer = MEM_calloc_arrayN(header->totlayer, sizeof(CDataFileLayer), "CDataFileLayer");
 | 
						|
  cdf->totlayer = header->totlayer;
 | 
						|
 | 
						|
  if (!cdf->layer) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  for (a = 0; a < header->totlayer; a++) {
 | 
						|
    layer = &cdf->layer[a];
 | 
						|
 | 
						|
    if (!fread(layer, sizeof(CDataFileLayer), 1, f)) {
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    if (cdf->switchendian) {
 | 
						|
      BLI_endian_switch_int32(&layer->type);
 | 
						|
      BLI_endian_switch_int32(&layer->datatype);
 | 
						|
      BLI_endian_switch_uint64(&layer->datasize);
 | 
						|
      BLI_endian_switch_int32(&layer->structbytes);
 | 
						|
    }
 | 
						|
 | 
						|
    if (layer->datatype != CDF_DATA_FLOAT) {
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    offset += layer->structbytes;
 | 
						|
    layer->structbytes = sizeof(CDataFileLayer);
 | 
						|
 | 
						|
    if (fseek(f, offset, SEEK_SET) != 0) {
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  cdf->dataoffset = offset;
 | 
						|
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
static int cdf_write_header(CDataFile *cdf)
 | 
						|
{
 | 
						|
  CDataFileHeader *header;
 | 
						|
  CDataFileImageHeader *image;
 | 
						|
  CDataFileMeshHeader *mesh;
 | 
						|
  CDataFileLayer *layer;
 | 
						|
  FILE *f = cdf->writef;
 | 
						|
  int a;
 | 
						|
 | 
						|
  header = &cdf->header;
 | 
						|
 | 
						|
  if (!fwrite(header, sizeof(CDataFileHeader), 1, f)) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (header->type == CDF_TYPE_IMAGE) {
 | 
						|
    image = &cdf->btype.image;
 | 
						|
    if (!fwrite(image, sizeof(CDataFileImageHeader), 1, f)) {
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else if (header->type == CDF_TYPE_MESH) {
 | 
						|
    mesh = &cdf->btype.mesh;
 | 
						|
    if (!fwrite(mesh, sizeof(CDataFileMeshHeader), 1, f)) {
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  for (a = 0; a < header->totlayer; a++) {
 | 
						|
    layer = &cdf->layer[a];
 | 
						|
 | 
						|
    if (!fwrite(layer, sizeof(CDataFileLayer), 1, f)) {
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
bool cdf_read_open(CDataFile *cdf, const char *filename)
 | 
						|
{
 | 
						|
  FILE *f;
 | 
						|
 | 
						|
  f = BLI_fopen(filename, "rb");
 | 
						|
  if (!f) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  cdf->readf = f;
 | 
						|
 | 
						|
  if (!cdf_read_header(cdf)) {
 | 
						|
    cdf_read_close(cdf);
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (cdf->header.type != cdf->type) {
 | 
						|
    cdf_read_close(cdf);
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
bool cdf_read_layer(CDataFile *cdf, CDataFileLayer *blay)
 | 
						|
{
 | 
						|
  size_t offset;
 | 
						|
  int a;
 | 
						|
 | 
						|
  /* seek to right location in file */
 | 
						|
  offset = cdf->dataoffset;
 | 
						|
  for (a = 0; a < cdf->totlayer; a++) {
 | 
						|
    if (&cdf->layer[a] == blay) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      offset += cdf->layer[a].datasize;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return (fseek(cdf->readf, offset, SEEK_SET) == 0);
 | 
						|
}
 | 
						|
 | 
						|
bool cdf_read_data(CDataFile *cdf, unsigned int size, void *data)
 | 
						|
{
 | 
						|
  /* read data */
 | 
						|
  if (!fread(data, size, 1, cdf->readf)) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  /* switch endian if necessary */
 | 
						|
  if (cdf->switchendian) {
 | 
						|
    BLI_endian_switch_float_array(data, size / sizeof(float));
 | 
						|
  }
 | 
						|
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
void cdf_read_close(CDataFile *cdf)
 | 
						|
{
 | 
						|
  if (cdf->readf) {
 | 
						|
    fclose(cdf->readf);
 | 
						|
    cdf->readf = NULL;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool cdf_write_open(CDataFile *cdf, const char *filename)
 | 
						|
{
 | 
						|
  CDataFileHeader *header;
 | 
						|
  CDataFileImageHeader *image;
 | 
						|
  CDataFileMeshHeader *mesh;
 | 
						|
  FILE *f;
 | 
						|
 | 
						|
  f = BLI_fopen(filename, "wb");
 | 
						|
  if (!f) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  cdf->writef = f;
 | 
						|
 | 
						|
  /* fill header */
 | 
						|
  header = &cdf->header;
 | 
						|
  /* strcpy(, "BCDF"); // terminator out of range */
 | 
						|
  header->ID[0] = 'B';
 | 
						|
  header->ID[1] = 'C';
 | 
						|
  header->ID[2] = 'D';
 | 
						|
  header->ID[3] = 'F';
 | 
						|
  header->endian = cdf_endian();
 | 
						|
  header->version = CDF_VERSION;
 | 
						|
  header->subversion = CDF_SUBVERSION;
 | 
						|
 | 
						|
  header->structbytes = sizeof(CDataFileHeader);
 | 
						|
  header->type = cdf->type;
 | 
						|
  header->totlayer = cdf->totlayer;
 | 
						|
 | 
						|
  if (cdf->type == CDF_TYPE_IMAGE) {
 | 
						|
    /* fill image header */
 | 
						|
    image = &cdf->btype.image;
 | 
						|
    image->structbytes = sizeof(CDataFileImageHeader);
 | 
						|
    image->tile_size = CDF_TILE_SIZE;
 | 
						|
  }
 | 
						|
  else if (cdf->type == CDF_TYPE_MESH) {
 | 
						|
    /* fill mesh header */
 | 
						|
    mesh = &cdf->btype.mesh;
 | 
						|
    mesh->structbytes = sizeof(CDataFileMeshHeader);
 | 
						|
  }
 | 
						|
 | 
						|
  cdf_write_header(cdf);
 | 
						|
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
bool cdf_write_layer(CDataFile *UNUSED(cdf), CDataFileLayer *UNUSED(blay))
 | 
						|
{
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
bool cdf_write_data(CDataFile *cdf, unsigned int size, void *data)
 | 
						|
{
 | 
						|
  /* write data */
 | 
						|
  if (!fwrite(data, size, 1, cdf->writef)) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
void cdf_write_close(CDataFile *cdf)
 | 
						|
{
 | 
						|
  if (cdf->writef) {
 | 
						|
    fclose(cdf->writef);
 | 
						|
    cdf->writef = NULL;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void cdf_remove(const char *filename)
 | 
						|
{
 | 
						|
  BLI_delete(filename, false, false);
 | 
						|
}
 | 
						|
 | 
						|
/********************************** Layers ***********************************/
 | 
						|
 | 
						|
CDataFileLayer *cdf_layer_find(CDataFile *cdf, int type, const char *name)
 | 
						|
{
 | 
						|
  CDataFileLayer *layer;
 | 
						|
  int a;
 | 
						|
 | 
						|
  for (a = 0; a < cdf->totlayer; a++) {
 | 
						|
    layer = &cdf->layer[a];
 | 
						|
 | 
						|
    if (layer->type == type && STREQ(layer->name, name)) {
 | 
						|
      return layer;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
CDataFileLayer *cdf_layer_add(CDataFile *cdf, int type, const char *name, size_t datasize)
 | 
						|
{
 | 
						|
  CDataFileLayer *newlayer, *layer;
 | 
						|
 | 
						|
  /* expand array */
 | 
						|
  newlayer = MEM_calloc_arrayN((cdf->totlayer + 1), sizeof(CDataFileLayer), "CDataFileLayer");
 | 
						|
  memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
 | 
						|
  cdf->layer = newlayer;
 | 
						|
 | 
						|
  cdf->totlayer++;
 | 
						|
 | 
						|
  /* fill in new layer */
 | 
						|
  layer = &cdf->layer[cdf->totlayer - 1];
 | 
						|
  layer->structbytes = sizeof(CDataFileLayer);
 | 
						|
  layer->datatype = CDF_DATA_FLOAT;
 | 
						|
  layer->datasize = datasize;
 | 
						|
  layer->type = type;
 | 
						|
  BLI_strncpy(layer->name, name, CDF_LAYER_NAME_MAX);
 | 
						|
 | 
						|
  return layer;
 | 
						|
}
 |