text: /*
   * This file is part of the Simutrans-Extended project under the Artistic License.
   * (see LICENSE.txt)
   */
  
  #include <stdio.h>
  #include <string.h>
  
  #include "../../display/simgraph.h"
  #include "../../simdebug.h"
  #include "../../display/simimg.h"
  
  #include "../image.h"
  #include "image_reader.h"
  #include "../obj_node_info.h"
  
  #include <zlib.h>
  #include "../../tpl/inthashtable_tpl.h"
  
  // if without graphics backend, do not copy any pixel
  #if COLOUR_DEPTH != 0
  #define skip_reading_pixels_if_no_graphics
  #else
  #define skip_reading_pixels_if_no_graphics goto adjust_image
  #endif
  
  obj_desc_t *image_reader_t::read_node(FILE *fp, obj_node_info_t &node)
  {
  	ALLOCA(char, desc_buf, node.size);
  	image_t* desc=NULL;
  
  	// Hajo: Read data
  	fread(desc_buf, node.size, 1, fp);
  	char * p = desc_buf+6;
  
  	// always zero in old version, since length was always less than 65535
  	// because a node could not hold more data
  	uint8 version = decode_uint8(p);
  	p = desc_buf;
  
  #if COLOUR_DEPTH != 0
  	desc = new image_t();
  #else
  	// reserve space for one single pixel and initialize data
  	desc = image_t::create_single_pixel();
  #endif
  
  	if(version==0) {
  		desc->x = decode_uint8(p);
  		desc->w = decode_uint8(p);
  		desc->y = decode_uint8(p);
  		desc->h = decode_uint8(p);
  		desc->alloc(decode_uint32(p)); // len
  		desc->imageid = IMG_EMPTY;
  		p += 2;	// dummys
  		desc->zoomable = decode_uint8(p);
  
  		skip_reading_pixels_if_no_graphics;
  		//DBG_DEBUG("image_t::read_node()","x,y=%d,%d  w,h=%d,%d, len=%i",desc->x,desc->y,desc->w,desc->h, desc->len);
  
  		uint16* dest = desc->data;
  		p = desc_buf+12;
  
  		if (desc->h > 0) {
  			for (uint i = 0; i < desc->len; i++) {
  				uint16 data = decode_uint16(p);
  				if(data>=0x8000u  &&  data<=0x800Fu) {
  					// player color offset changed
  					data ++;
  				}
  				*dest++ = data;
  			}
  		}
  	}
  	else if(version<=2) {
  		desc->x = decode_sint16(p);
  		desc->y = decode_sint16(p);
  		desc->w = decode_uint8(p);
  		desc->h = decode_uint8(p);
  		p++; // skip version information
  		desc->alloc(decode_uint16(p)); // len
  		desc->zoomable = decode_uint8(p);
  		desc->imageid = IMG_EMPTY;
  
  		skip_reading_pixels_if_no_graphics;
  		uint16* dest = desc->data;
  		if (desc->h > 0) {
  			for (uint i = 0; i < desc->len; i++) {
  				*dest++ = decode_uint16(p);
  			}
  		}
  	}
  	else if(version==3) {
  		desc->x = decode_sint16(p);
  		desc->y = decode_sint16(p);
  		desc->w = decode_sint16(p);
  		p++; // skip version information
  		desc->h = decode_sint16(p);
  		desc->alloc((node.size - 10) / 2); // len
  		desc->zoomable = decode_uint8(p);
  		desc->imageid = IMG_EMPTY;
  
  		skip_reading_pixels_if_no_graphics;
  		uint16* dest = desc->data;
  		if (desc->h > 0) {
  			for (uint i = 0; i < desc->len; i++) {
  				*dest++ = decode_uint16(p);
  			}
  		}
  	}
  	else {
  		dbg->fatal("image_reader_t::read_node()","illegal versions %d", version );
  	}
  
  #if COLOUR_DEPTH == 0
  adjust_image:
  	// reset image parameters, but only for non-empty images
  	if(  desc->h > 0  ) {
  		desc->h = 1;
  	}
  	if(  desc->w > 0  ) {
  		desc->w = 1;
  	}
  	if(  desc->len > 0  ) {
  		desc->len = 4;
  	}
  	desc->x = 0;
  	desc->y = 0;
  #endif
  
  	// check for left corner
  	if(version<2  &&  desc->h>0) {
  		// find left border
  		uint16 left = 255;
  		uint16 *dest = desc->data;
  		for( uint8 y=0;  y<desc->h;  y++  ) {
  			if(*dest<left) {
  				left = *dest;
  			}
  			// skip rest of the line
  			do {
  				dest++;
  				dest += *dest + 1;
  			} while (*dest);
  			dest++;	// skip trailing zero
  		}
  
  		if(left<desc->x) {
  			dbg->warning( "image_reader_t::read_node()","left(%i)<x(%i) (may be intended)", left, desc->x );
  		}
  
  		dest = desc->data;
  		for( uint8 y=0;  y<desc->h;  y++  ) {
  			*dest -= left;
  			// skip rest of the line
  			do {
  				dest++;
  				dest += *dest + 1;
  			} while (*dest);
  			dest++;	// skip trailing zero
  		}
  	}
  
  	if (desc->len != 0) {
  		// get the adler hash (since we have zlib on board anyway ... )
  		bool do_register_image = true;
  		uint32 adler = adler32(0L, NULL, 0 );
  		// remember len is sizeof(uint16)!
  		adler = adler32(adler, (const Bytef *)(desc->data), desc->len * 2);
  		static inthashtable_tpl<uint32, image_t *> images_adlers;
  		image_t *same = images_adlers.get(adler);
  		if (same) {
  			// same checksum => if same then skip!
  			image_t const& a = *desc;
  			image_t const& b = *same;
  			do_register_image =
  				a.x        != b.x        ||
  				a.y        != b.y        ||
  				a.w        != b.w        ||
  				a.h        != b.h        ||
  				a.zoomable != b.zoomable ||
  				a.len      != b.len      ||
  				memcmp(a.data, b.data, sizeof(*a.data) * a.len) != 0;
  		}
  		// unique image here
  		if(  do_register_image  ) {
  			if(!same) {
  				images_adlers.put(adler,desc);	// still with imageid == IMG_EMPTY!
  			}
  			// register image adds this image to the internal array maintained by simgraph??.cc
  			register_image(desc);
  		}
  		else {
  			// no need to load doubles ...
  			delete desc;
  			desc = same;
  		}
  	}
  
  	return desc;
  }
  