1 /*
2  *   skinedit - a skin editor for the TiEmu emulator
3  *   Copyright (C) 2002 Julien BLACHE <jb@tilp.info>
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 
20 /*
21 contra-sh :
22    This file is a (quasi) perfect copy of the tiemu skinops.c file ...
23    Thank's to rom's and JB for this wonderful work.
24 */
25 
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29 
30 #include <stdio.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdint.h>
35 #include <math.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <errno.h>
39 #include "skinops.h"
40 
41 #include <gtk/gtk.h>
42 #include <glib/gstdio.h>
43 
44 #define SKIN_ERROR g_quark_from_static_string("skin-error")
45 enum {
46 	SKIN_ERROR_INVALID
47 };
48 
49 /*
50 	Determine skin type
51 */
skin_get_type(SKIN_INFOS * si,const char * filename)52 int skin_get_type(SKIN_INFOS *si, const char *filename)
53 {
54 	FILE *fp;
55 	char str[17];
56 
57 	fp = g_fopen(filename, "rb");
58 	if (fp == NULL) {
59 		fprintf(stderr, "Unable to open this file: <%s>\n", filename);
60 		return -1;
61 	}
62 
63 	memset(str, 0, sizeof(str));
64 	fread(str, 16, 1, fp);
65 
66 	if(!strncmp(str, "TiEmu v2.00", 16))
67 		si->type = SKIN_TYPE_TIEMU;
68 	else if(!strncmp(str, "TilEm v2.00 ", 16))
69 		si->type = SKIN_TYPE_TIEMU;
70 	else if(!strncmp(str, "VTIv2.1 ", 8))
71 		si->type = SKIN_TYPE_OLD_VTI;
72 	else if(!strncmp(str, "VTIv2.5 ", 8))
73 		si->type = SKIN_TYPE_VTI;
74 	else {
75 		fprintf(stderr, "Bad skin format\n");
76 		return -1;
77 	}
78 
79 	return 0;
80 }
81 
82 /*
83   Read TilEm skin informations (header)
84 */
skin_read_header(SKIN_INFOS * si,FILE * fp)85 int skin_read_header(SKIN_INFOS *si, FILE *fp)
86 {
87 	int i;
88 	uint32_t endian;
89 	uint32_t jpeg_offset;
90 	uint32_t length;
91 	char str[17];
92 
93 	/* signature & offsets */
94 	fread(str, 16, 1, fp);
95 	if ((strncmp(str, "TilEm v2.00", 16))
96 	    && (strncmp(str, "TiEmu v2.00", 16))) {
97 		return -1;
98 	}
99 	fread(&endian, 4, 1, fp);
100 	fread(&jpeg_offset, 4, 1, fp);
101 
102 	if (endian != ENDIANNESS_FLAG)
103 		jpeg_offset = GUINT32_SWAP_LE_BE(jpeg_offset);
104 
105 	/* Skin name */
106 	fread(&length, 4, 1, fp);
107 	if (endian != ENDIANNESS_FLAG)
108 		length = GUINT32_SWAP_LE_BE(length);
109 
110 	if (length > 0) {
111 		si->name = (char *)malloc(length + 1);
112 		if (si->name == NULL)
113 			return -1;
114 
115 		memset(si->name, 0, length + 1);
116 		fread(si->name, length, 1, fp);
117 	}
118 
119 	/* Skin author */
120 	fread(&length, 4, 1, fp);
121 	if (endian != ENDIANNESS_FLAG)
122 		length = GUINT32_SWAP_LE_BE(length);
123 
124 	if (length > 0) {
125 		si->author = (char *)malloc(length + 1);
126 		if (si->author == NULL)
127 			return -1;
128 
129 		memset(si->author, 0, length + 1);
130 		fread(si->author, length, 1, fp);
131 	}
132 
133 	/* LCD colors */
134 	fread(&si->colortype, 4, 1, fp);
135 	fread(&si->lcd_white, 4, 1, fp);
136 	fread(&si->lcd_black, 4, 1, fp);
137 
138 	/* Calc type */
139 	fread(si->calc, 8, 1, fp);
140 
141 	/* LCD position */
142 	fread(&si->lcd_pos.left, 4, 1, fp);
143 	fread(&si->lcd_pos.top, 4, 1, fp);
144 	fread(&si->lcd_pos.right, 4, 1, fp);
145 	fread(&si->lcd_pos.bottom, 4, 1, fp);
146 
147 	/* Number of RECT struct to read */
148 	fread(&length, 4, 1, fp);
149 	if (endian != ENDIANNESS_FLAG)
150 		length = GUINT32_SWAP_LE_BE(length);
151 
152 	if (length > SKIN_KEYS)
153 		return -1;
154 
155 	for (i = 0; i < (int)length; i++) {
156 		fread(&si->keys_pos[i].left, 4, 1, fp);
157 		fread(&si->keys_pos[i].top, 4, 1, fp);
158 		fread(&si->keys_pos[i].right, 4, 1, fp);
159 		fread(&si->keys_pos[i].bottom, 4, 1, fp);
160 	}
161 
162 	if (endian != ENDIANNESS_FLAG) {
163 		si->colortype = GUINT32_SWAP_LE_BE(si->colortype);
164 		si->lcd_white = GUINT32_SWAP_LE_BE(si->lcd_white);
165 		si->lcd_black = GUINT32_SWAP_LE_BE(si->lcd_black);
166 
167 		si->lcd_pos.top = GUINT32_SWAP_LE_BE(si->lcd_pos.top);
168 		si->lcd_pos.left = GUINT32_SWAP_LE_BE(si->lcd_pos.left);
169 		si->lcd_pos.bottom = GUINT32_SWAP_LE_BE(si->lcd_pos.bottom);
170 		si->lcd_pos.right = GUINT32_SWAP_LE_BE(si->lcd_pos.right);
171 
172 		for (i = 0; i < (int)length; i++) {
173 			si->keys_pos[i].top = GUINT32_SWAP_LE_BE(si->keys_pos[i].top);
174 			si->keys_pos[i].bottom = GUINT32_SWAP_LE_BE(si->keys_pos[i].bottom);
175 			si->keys_pos[i].left = GUINT32_SWAP_LE_BE(si->keys_pos[i].left);
176 			si->keys_pos[i].right = GUINT32_SWAP_LE_BE(si->keys_pos[i].right);
177 		}
178 	}
179 
180 	si->jpeg_offset = ftell(fp);
181 
182 	return 0;
183 }
184 
185 /*
186   Read skin image (pure jpeg data)
187 */
skin_read_image(SKIN_INFOS * si,FILE * fp,GError ** err)188 int skin_read_image(SKIN_INFOS *si, FILE *fp, GError **err)
189 {
190 	GdkPixbufLoader *loader;
191 	gboolean result;
192 	guchar *buf;
193 	gsize count;
194 	struct stat st;
195 
196 	// Extract image from skin
197 	fseek(fp, si->jpeg_offset, SEEK_SET);
198 	fstat(fileno(fp), &st);
199 	count = st.st_size - si->jpeg_offset;
200 
201 	buf = g_malloc(count * sizeof(guchar));
202 	count = fread(buf, sizeof(guchar), count, fp);
203 
204 	// Feed the pixbuf loader with our jpeg data
205 	loader = gdk_pixbuf_loader_new();
206 	result = gdk_pixbuf_loader_write(loader, buf, count, err);
207 	g_free(buf);
208 
209 	if(result == FALSE) {
210 		g_object_unref(loader);
211 		return -1;
212 	}
213 
214 	result = gdk_pixbuf_loader_close(loader, err);
215 	if(result == FALSE) {
216 		g_object_unref(loader);
217 		return -1;
218 	}
219 
220 	// and get the pixbuf
221 	si->raw = gdk_pixbuf_loader_get_pixbuf(loader);
222 	if(si->raw == NULL) {
223 		g_set_error(err, SKIN_ERROR, SKIN_ERROR_INVALID,
224 		            "Unable to load background image");
225 		g_object_unref(loader);
226 		return -1;
227 	}
228 
229 	si->sx = si->sy = 1.0;
230 	si->image = g_object_ref(si->raw);
231 	g_object_ref(si->raw);
232 
233 	// Get new skin size
234 	si->width = gdk_pixbuf_get_width(si->image);
235 	si->height = gdk_pixbuf_get_height(si->image);
236 
237 	g_object_unref(loader);
238 
239 	return 0;
240 }
241 
242 /* Load a skin (TilEm v2.00 only) */
skin_load(SKIN_INFOS * si,const char * filename,GError ** err)243 int skin_load(SKIN_INFOS *si, const char *filename, GError **err)
244 {
245 	FILE *fp;
246 	int ret = 0, errnum;
247 	char *dname;
248 
249 	g_return_val_if_fail(err == NULL || *err == NULL, -1);
250 
251 	fp = g_fopen(filename, "rb");
252 	if (fp == NULL) {
253 		errnum = errno;
254 		dname = g_filename_display_basename(filename);
255 		g_set_error(err, G_FILE_ERROR, g_file_error_from_errno(errnum),
256 		            "Unable to open %s for reading: %s",
257 		            dname, g_strerror(errnum));
258 		g_free(dname);
259 		return -1;
260 	}
261 
262 	ret = skin_read_header(si, fp);
263 	if (ret) {
264 		fclose(fp);
265 		dname = g_filename_display_basename(filename);
266 		g_set_error(err, SKIN_ERROR, SKIN_ERROR_INVALID,
267 		            "The file %s is not a valid skin.", dname);
268 		g_free(dname);
269 		return -1;
270 	}
271 
272 	ret = skin_read_image(si, fp, err);
273 
274 	fclose(fp);
275 
276 	return ret;
277 }
278 
279 /* Unload skin by freeing allocated memory */
skin_unload(SKIN_INFOS * si)280 int skin_unload(SKIN_INFOS *si)
281 {
282 	if (si->image != NULL) {
283 		g_object_unref(si->image);
284 		si->image = NULL;
285 	}
286 
287 	if (si->raw) {
288 		g_object_unref(si->raw);
289 		si->raw = NULL;
290 	}
291 
292 	free(si->name);
293 	free(si->author);
294 
295 	memset(si, 0, sizeof(SKIN_INFOS));
296 
297 	return 0;
298 }
299 
300