1 /* vim:expandtab:ts=2 sw=2:
2 */
3 /* Grafx2 - The Ultimate 256-color bitmap paint program
4
5 Copyright owned by various GrafX2 authors, see COPYRIGHT.txt for details.
6
7 Grafx2 is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; version 2
10 of the License.
11
12 Grafx2 is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Grafx2; if not, see <http://www.gnu.org/licenses/>
19 */
20 //////////////////////////////////////////////////////////////////////////////
21 ///@file loadsavefuncs.c
22 /// helper functions for load/save
23 //////////////////////////////////////////////////////////////////////////////
24
25 #include <stdlib.h>
26 #include <string.h>
27 #ifndef _MSC_VER
28 #include <strings.h>
29 #include <unistd.h>
30 #endif
31 #if defined(WIN32)
32 #include <windows.h>
33 #if defined(_MSC_VER)
34 #define strdup _strdup
35 #if _MSC_VER < 1900
36 #define snprintf _snprintf
37 #endif
38 #endif
39 #endif
40 #include "struct.h"
41 #include "global.h"
42 #include "loadsave.h"
43 #include "loadsavefuncs.h"
44 #include "io.h"
45 #include "unicode.h"
46 #include "gfx2mem.h"
47 #include "gfx2log.h"
48
49 /// For use by Save_XXX() functions
Open_file_write(T_IO_Context * context)50 FILE * Open_file_write(T_IO_Context *context)
51 {
52 FILE * f;
53 char * filename; // filename with full path
54 #if defined(WIN32)
55 if (context->File_name_unicode != NULL && context->File_name_unicode[0] != 0)
56 {
57 size_t len;
58 WCHAR * filename_unicode;
59
60 len = strlen(context->File_directory) + strlen(PATH_SEPARATOR)
61 + Unicode_strlen(context->File_name_unicode) + 1;
62 filename_unicode = (WCHAR *)GFX2_malloc(sizeof(WCHAR) * len);
63 if (filename_unicode == NULL)
64 return NULL;
65
66 Unicode_char_strlcpy((word *)filename_unicode, context->File_directory, len);
67 Unicode_char_strlcat((word *)filename_unicode, PATH_SEPARATOR, len);
68 Unicode_strlcat((word *)filename_unicode, context->File_name_unicode, len);
69
70 f = _wfopen(filename_unicode, L"wb");
71 if (f != NULL)
72 {
73 // Now the file has been created, retrieve its short (ASCII) name
74 len = GetShortPathNameW(filename_unicode, NULL, 0);
75 if (len > 0)
76 {
77 WCHAR * shortpath = (WCHAR *)GFX2_malloc(sizeof(WCHAR) * len);
78 if (shortpath != NULL)
79 {
80 len = GetShortPathNameW(filename_unicode, shortpath, len);
81 if (len > 0)
82 {
83 DWORD start, index;
84 for (start = len; start > 0 && shortpath[start-1] != '\\'; start--);
85 free(context->File_name);
86 context->File_name = (char *)GFX2_malloc(len + 1 - start);
87 if (context->File_name != NULL)
88 {
89 for (index = 0; index < len - start; index++)
90 context->File_name[index] = shortpath[start + index];
91 context->File_name[index] = '\0';
92 }
93 }
94 else
95 {
96 GFX2_Log(GFX2_ERROR, "GetShortPathNameW(%p, %p, %u) failed !\n", filename_unicode, shortpath, len);
97 }
98 }
99 }
100 else
101 {
102 GFX2_Log(GFX2_ERROR, "GetShortPathNameW(%p, NULL, 0) failed !\n", filename_unicode);
103 }
104 }
105 free(filename_unicode);
106 return f;
107 }
108 #endif
109
110 filename = Filepath_append_to_dir(context->File_directory, context->File_name);
111 if (filename == NULL)
112 return NULL;
113 f = fopen(filename, "wb");
114 free(filename);
115 return f;
116 }
117
Open_file_write_with_alternate_ext(T_IO_Context * context,const char * ext)118 FILE * Open_file_write_with_alternate_ext(T_IO_Context *context, const char * ext)
119 {
120 FILE * f;
121 char *p;
122 char * filename; // filename with full path
123 #if defined(WIN32)
124 if (context->File_name_unicode != NULL && context->File_name_unicode[0] != 0)
125 {
126 size_t len;
127 WCHAR * filename_unicode;
128 WCHAR * pw;
129
130 len = strlen(context->File_directory) + strlen(PATH_SEPARATOR)
131 + Unicode_strlen(context->File_name_unicode) + strlen(ext) + 1 + 1;
132 filename_unicode = (WCHAR *)GFX2_malloc(len * sizeof(WCHAR));
133 if (filename_unicode == NULL)
134 return NULL;
135 Unicode_char_strlcpy((word *)filename_unicode, context->File_directory, len);
136 Unicode_char_strlcat((word *)filename_unicode, PATH_SEPARATOR, len);
137 Unicode_strlcat((word *)filename_unicode, context->File_name_unicode, len);
138 pw = wcschr(filename_unicode, (WCHAR)'.');
139 if (pw != NULL)
140 *pw = 0;
141 Unicode_char_strlcat((word *)filename_unicode, ".", len);
142 Unicode_char_strlcat((word *)filename_unicode, ext, len);
143
144 f = _wfopen(filename_unicode, L"wb");
145 free(filename_unicode);
146 return f;
147 }
148 #endif
149 filename = Filepath_append_to_dir(context->File_directory, context->File_name);
150 // TODO: fix ! (realloc if not enough space)
151 p = strrchr(filename, '.');
152 if (p != NULL)
153 *p = '\0';
154 strcat(filename, ".");
155 strcat(filename, ext);
156
157 f = fopen(filename, "wb");
158 free(filename);
159 return f;
160 }
161
162 /// For use by Load_XXX() and Test_XXX() functions
Open_file_read(T_IO_Context * context)163 FILE * Open_file_read(T_IO_Context *context)
164 {
165 FILE * f;
166 char * filename; // filename with full path
167
168 filename = Filepath_append_to_dir(context->File_directory, context->File_name);
169 f = fopen(filename, "rb");
170 free(filename);
171 return f;
172 }
173
174 struct T_Find_alternate_ext_data
175 {
176 const char * ext;
177 char * basename;
178 word * basename_unicode;
179 char * foundname;
180 word * foundname_unicode;
181 };
182
Look_for_alternate_ext(void * pdata,const char * filename,const word * filename_unicode,byte is_file,byte is_directory,byte is_hidden)183 static void Look_for_alternate_ext(void * pdata, const char * filename, const word * filename_unicode, byte is_file, byte is_directory, byte is_hidden)
184 {
185 size_t base_len;
186 struct T_Find_alternate_ext_data * params = (struct T_Find_alternate_ext_data *)pdata;
187 (void)is_hidden;
188 (void)is_directory;
189
190 if (!is_file)
191 return;
192
193 if (filename_unicode != NULL && params->basename_unicode != NULL)
194 {
195 if (params->foundname_unicode != NULL)
196 return; // We already have found a file
197 base_len = Unicode_strlen(params->basename_unicode);
198 if (Unicode_strlen(filename_unicode) <= base_len)
199 return; // No match.
200 if (filename_unicode[base_len] != '.')
201 return; // No match.
202 #if defined(WIN32)
203 {
204 int cmp;
205 WCHAR * temp_string = (WCHAR *)GFX2_malloc((base_len + 1) * sizeof(WCHAR));
206 if (temp_string == NULL)
207 return;
208 memcpy(temp_string, filename_unicode, base_len * sizeof(word));
209 temp_string[base_len] = 0;
210 cmp = _wcsicmp((const WCHAR *)params->basename_unicode, temp_string);
211 free(temp_string);
212 if (cmp != 0)
213 return; // No match.
214 }
215 #else
216 if (memcmp(params->basename_unicode, filename_unicode, base_len * sizeof(word)) != 0)
217 return; // No match.
218 #endif
219 if (Unicode_char_strcasecmp(filename_unicode + base_len + 1, params->ext) != 0)
220 return; // No match.
221 // it is a match !
222 free(params->foundname);
223 params->foundname_unicode = Unicode_strdup(filename_unicode);
224 params->foundname = strdup(filename);
225 }
226 else
227 {
228 if (params->foundname != NULL)
229 return; // We already have found a file
230 base_len = strlen(params->basename);
231 if (filename[base_len] != '.')
232 return; // No match.
233 #if defined(WIN32)
234 if (_memicmp(params->basename, filename, base_len) != 0) // Not case sensitive
235 return; // No match.
236 #else
237 if (memcmp(params->basename, filename, base_len) != 0)
238 return; // No match.
239 #endif
240 if (strcasecmp(filename + base_len + 1, params->ext) != 0)
241 return; // No match.
242 params->foundname_unicode = NULL;
243 params->foundname = strdup(filename);
244 }
245 }
246
Open_file_read_with_alternate_ext(T_IO_Context * context,const char * ext)247 FILE * Open_file_read_with_alternate_ext(T_IO_Context *context, const char * ext)
248 {
249 FILE * f = NULL;
250 char * p;
251 struct T_Find_alternate_ext_data params;
252
253 memset(¶ms, 0, sizeof(params));
254 params.ext = ext;
255 params.basename = strdup(context->File_name);
256 if (params.basename == NULL)
257 {
258 GFX2_Log(GFX2_ERROR, "Open_file_read_with_alternate_ext() strdup() failed\n");
259 return NULL;
260 }
261 p = strrchr(params.basename, '.');
262 if (p != NULL)
263 *p = '\0';
264 if (context->File_name_unicode != NULL)
265 {
266 size_t i = Unicode_strlen(context->File_name_unicode);
267 params.basename_unicode = GFX2_malloc(sizeof(word) * (i + 1));
268 if (params.basename_unicode != NULL)
269 {
270 memcpy(params.basename_unicode, context->File_name_unicode, (i + 1) * sizeof(word));
271 while (i-- > 0)
272 if (params.basename_unicode[i] == (word)'.')
273 {
274 params.basename_unicode[i] = 0;
275 break;
276 }
277 }
278 }
279
280 For_each_directory_entry(context->File_directory, ¶ms, Look_for_alternate_ext);
281 if (params.foundname != NULL)
282 {
283 char * filename; // filename with full path
284
285 filename = Filepath_append_to_dir(context->File_directory, params.foundname);
286 f = fopen(filename, "rb");
287 free(filename);
288 }
289 free(params.basename);
290 free(params.basename_unicode);
291 free(params.foundname);
292 free(params.foundname_unicode);
293 return f;
294 }
295
296 /// For use by Save_XXX() functions
Remove_file(T_IO_Context * context)297 void Remove_file(T_IO_Context *context)
298 {
299 char * filename; // filename with full path
300
301 filename = Filepath_append_to_dir(context->File_directory, context->File_name);
302 Remove_path(filename);
303 free(filename);
304 }
305
Palette_256_to_64(T_Palette palette)306 void Palette_256_to_64(T_Palette palette)
307 {
308 int i;
309 for(i=0;i<256;i++)
310 {
311 palette[i].R = palette[i].R >> 2;
312 palette[i].G = palette[i].G >> 2;
313 palette[i].B = palette[i].B >> 2;
314 }
315 }
316
Palette_64_to_256(T_Palette palette)317 void Palette_64_to_256(T_Palette palette)
318 {
319 int i;
320 for(i=0;i<256;i++)
321 {
322 palette[i].R = (palette[i].R << 2)|(palette[i].R >> 4);
323 palette[i].G = (palette[i].G << 2)|(palette[i].G >> 4);
324 palette[i].B = (palette[i].B << 2)|(palette[i].B >> 4);
325 }
326 }
327
Current_layer_count_used_colors(T_IO_Context * context,dword * usage)328 word Current_layer_count_used_colors(T_IO_Context *context, dword *usage)
329 {
330 dword nb_colors = 0;
331 int i;
332 word x, y;
333
334 for (i = 0; i < 256; i++) usage[i] = 0;
335
336 for (y = 0; y < context->Height; y++)
337 {
338 for (x = 0; x < context->Width; x++)
339 usage[Get_pixel(context, x, y)]++;
340 }
341
342 // count the total number of unique used colors
343 for (i = 0; i < 256; i++)
344 {
345 if (usage[i] != 0)
346 nb_colors++;
347 }
348
349 return nb_colors;
350 }
351