text: /**
   * libpsd - Photoshop file formats (*.psd) decode library
   * Copyright (C) 2004-2007 Graphest Software.
   *
   * libpsd is the legal property of its developers, whose names are too numerous
   * to list here.  Please refer to the COPYRIGHT file distributed with this
   * source distribution.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU Library 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 Library 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
   *
   * $Id: psd.c, created by Patrick in 2006.05.18, libpsd@graphest.com Exp $
   */
  
  #include "libpsd.h"
  #include "psd_config.h"
  #include "psd_system.h"
  #include "psd_stream.h"
  
  
  enum {
  	PSD_FILE_HEADER,
  	PSD_COLOR_MODE_DATA,
  	PSD_IMAGE_RESOURCE,
  	PSD_LAYER_AND_MASK_INFORMATION,
  	PSD_IMAGE_DATA,
  	PSD_DONE
  };
  
  extern psd_status psd_get_file_header(psd_context * context);
  extern psd_status psd_get_color_mode_data(psd_context * context);
  extern psd_status psd_get_image_resource(psd_context * context);
  extern psd_status psd_get_layer_and_mask(psd_context * context);
  extern psd_status psd_get_image_data(psd_context * context);
  extern void psd_color_mode_data_free(psd_context * context);
  extern void psd_image_resource_free(psd_context * context);
  extern void psd_layer_and_mask_free(psd_context * context);
  extern void psd_image_data_free(psd_context * context);
  extern void psd_image_blend_free(psd_context * context);
  
  static psd_file_ops psd_std_fileops = {
  	psd_std_size,
  	psd_std_seek,
  	psd_std_read,
  //	psd_std_write,
  //	psd_std_close,
  //	psd_std_gets,
  //	psd_std_eof,
  //	psd_std_tell,
  //	psd_std_getc,
  //	psd_std_scanf
  };
  
  static psd_status psd_image_load_tag(psd_context ** dst_context, psd_char * file_name, psd_load_tag load_tag)
  {
  	psd_context * context;
  	psd_status status;
  
  	if(dst_context == NULL)
  		return psd_status_invalid_context;
  	if(file_name == NULL)
  		return psd_status_invalid_file;
  
  	context = (psd_context *)psd_malloc(sizeof(psd_context));
  	if(context == NULL)
  		return psd_status_malloc_failed;
  	memset(context, 0, sizeof(psd_context));
  
  	context->ops_ = &psd_std_fileops;
  	context->file_name = file_name;
  	context->file = psd_fopen(file_name);
  	if (context->file == NULL)
  	{
  		psd_free(context);
  		return psd_status_invalid_file;
  	}
  	
  	context->state = PSD_FILE_HEADER;
  	context->stream.file_length = psd_fsize(context->file);
  	context->load_tag = load_tag;
  	status = psd_main_loop(context);
  	
  	if(status != psd_status_done)
  	{
  		psd_image_free(context);
  		context = NULL;
  	}
  	else
  	{
  		psd_stream_free(context);
  	}
  	
  	*dst_context = context;
  
  	return status;
  }
  
  psd_status psd_image_load(psd_context ** dst_context, psd_char * file_name)
  {
  	return psd_image_load_tag(dst_context, file_name, psd_load_tag_all);
  }
  
  psd_status psd_image_load_header(psd_context ** dst_context, psd_char * file_name)
  {
  	return psd_image_load_tag(dst_context, file_name, psd_load_tag_header);
  }
  
  psd_status psd_image_load_layer(psd_context ** dst_context, psd_char * file_name)
  {
  	return psd_image_load_tag(dst_context, file_name, psd_load_tag_layer);
  }
  
  psd_status psd_image_load_merged(psd_context ** dst_context, psd_char * file_name)
  {
  	return psd_image_load_tag(dst_context, file_name, psd_load_tag_merged);
  }
  
  psd_status psd_image_load_thumbnail(psd_context ** dst_context, psd_char * file_name)
  {
  	return psd_image_load_tag(dst_context, file_name, psd_load_tag_thumbnail);
  }
  
  psd_status psd_image_load_exif(psd_context ** dst_context, psd_char * file_name)
  {
  #ifdef PSD_INCLUDE_LIBXML
  	return psd_image_load_tag(dst_context, file_name, psd_load_tag_exif);
  #else
  	return psd_status_unsupport_yet;
  #endif
  }
  
  psd_status psd_image_free(psd_context * context)
  {
  	if(context == NULL)
  		return psd_status_invalid_context;
  	
  	psd_color_mode_data_free(context);
  	psd_image_resource_free(context);
  	psd_layer_and_mask_free(context);
  	psd_image_data_free(context);
  	
  	psd_image_blend_free(context);
  	psd_stream_free(context);
  	
  	//psd_free(context); //[DP] the application is responsible for this
  
  	return psd_status_done;
  }
  
  psd_static psd_status psd_main_loop(psd_context * context)
  {
  	psd_status status = psd_status_done;
  
  	while(status == psd_status_done)
  	{
  		if(context->stream.file_length <= 0)
  		{
  			status = psd_status_fread_error;
  			break;
  		}
  		
  		switch(context->state)
  		{
  			case PSD_FILE_HEADER:
  				status = psd_get_file_header(context);
  				if(status == psd_status_done)
  				{
  					if (context->load_tag == psd_load_tag_header)
  						context->state = PSD_DONE;
  					else
  						context->state = PSD_COLOR_MODE_DATA;
  				}
  				else if(status == psd_status_unkown_error)
  					status = psd_status_file_header_error;
  				break;
  				
  			case PSD_COLOR_MODE_DATA:
  				status = psd_get_color_mode_data(context);
  				if(status == psd_status_done)
  					context->state = PSD_IMAGE_RESOURCE;
  				else if(status == psd_status_unkown_error)
  					status = psd_status_color_mode_data_error;
  				break;
  				
  			case PSD_IMAGE_RESOURCE:
  				status = psd_get_image_resource(context);
  				if(status == psd_status_done)
  					context->state = PSD_LAYER_AND_MASK_INFORMATION;
  				else if(status == psd_status_unkown_error)
  					status = psd_status_image_resource_error;
  				break;
  				
  			case PSD_LAYER_AND_MASK_INFORMATION:
  				status = psd_get_layer_and_mask(context);
  				if(status == psd_status_done)
  					context->state = PSD_IMAGE_DATA;
  				else if(status == psd_status_unkown_error)
  					status = psd_status_layer_and_mask_error;
  				break;
  				
  			case PSD_IMAGE_DATA:
  				status = psd_get_image_data(context);
  				if(status == psd_status_done)
  					context->state = PSD_DONE;
  				else if(status == psd_status_unkown_error)
  					status = psd_status_image_data_error;
  				break;
  
  			case PSD_DONE:
  				return psd_status_done;
  
  			default:
  				psd_assert(0);
  				return psd_status_unkown_error;
  		}
  	}
  
  	return status;
  }
  
  