diff options
Diffstat (limited to 'rbutil/ibassoboot/jni')
-rw-r--r-- | rbutil/ibassoboot/jni/Android.mk | 6 | ||||
-rw-r--r-- | rbutil/ibassoboot/jni/chooser.bmp | bin | 0 -> 230454 bytes | |||
-rw-r--r-- | rbutil/ibassoboot/jni/ibassodualboot.c | 439 | ||||
-rw-r--r-- | rbutil/ibassoboot/jni/qdbmp.c | 798 | ||||
-rw-r--r-- | rbutil/ibassoboot/jni/qdbmp.h | 133 |
5 files changed, 1376 insertions, 0 deletions
diff --git a/rbutil/ibassoboot/jni/Android.mk b/rbutil/ibassoboot/jni/Android.mk new file mode 100644 index 0000000000..1d1566d8c0 --- /dev/null +++ b/rbutil/ibassoboot/jni/Android.mk | |||
@@ -0,0 +1,6 @@ | |||
1 | LOCAL_PATH := $(call my-dir) | ||
2 | include $(CLEAR_VARS) | ||
3 | |||
4 | LOCAL_MODULE := MangoPlayer | ||
5 | LOCAL_SRC_FILES := ibassodualboot.c qdbmp.c | ||
6 | include $(BUILD_EXECUTABLE) | ||
diff --git a/rbutil/ibassoboot/jni/chooser.bmp b/rbutil/ibassoboot/jni/chooser.bmp new file mode 100644 index 0000000000..3e6742d600 --- /dev/null +++ b/rbutil/ibassoboot/jni/chooser.bmp | |||
Binary files differ | |||
diff --git a/rbutil/ibassoboot/jni/ibassodualboot.c b/rbutil/ibassoboot/jni/ibassodualboot.c new file mode 100644 index 0000000000..3f20bbeecf --- /dev/null +++ b/rbutil/ibassoboot/jni/ibassodualboot.c | |||
@@ -0,0 +1,439 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2014 by Ilia Sergachev | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include <dirent.h> | ||
23 | #include <errno.h> | ||
24 | #include <fcntl.h> | ||
25 | |||
26 | #include <linux/fb.h> | ||
27 | #include <linux/input.h> | ||
28 | #include <linux/reboot.h> | ||
29 | |||
30 | #include <stdbool.h> | ||
31 | #include <string.h> | ||
32 | #include <stdint.h> | ||
33 | #include <stdio.h> | ||
34 | #include <stdlib.h> | ||
35 | |||
36 | #include <time.h> | ||
37 | |||
38 | #include <sys/limits.h> | ||
39 | #include <sys/mman.h> | ||
40 | #include <sys/inotify.h> | ||
41 | #include <sys/ioctl.h> | ||
42 | #include <sys/poll.h> | ||
43 | #include <sys/stat.h> | ||
44 | #include <sys/time.h> | ||
45 | #include <sys/types.h> | ||
46 | |||
47 | #include <unistd.h> | ||
48 | |||
49 | #include "qdbmp.h" | ||
50 | |||
51 | |||
52 | #define MIN_TIME 1395606821 | ||
53 | #define TIME_FILE "/data/time_store" | ||
54 | #define TIME_CHECK_PERIOD 60 /* seconds */ | ||
55 | #define VOLD_LINK "/data/vold" | ||
56 | #define PLAYER_FILE "/data/chosen_player" | ||
57 | #define NOASK_FLAG "/data/no_ask_once" | ||
58 | #define POLL_MS 10 | ||
59 | |||
60 | |||
61 | #define KEYCODE_HEADPHONES 114 | ||
62 | #define KEYCODE_HOLD 115 | ||
63 | #define KEYCODE_PWR 116 | ||
64 | #define KEYCODE_PWR_LONG 117 | ||
65 | #define KEYCODE_SD 143 | ||
66 | #define KEYCODE_VOLPLUS 158 | ||
67 | #define KEYCODE_VOLMINUS 159 | ||
68 | #define KEYCODE_PREV 160 | ||
69 | #define KEYCODE_NEXT 162 | ||
70 | #define KEYCODE_PLAY 161 | ||
71 | |||
72 | #define KEY_HOLD_OFF 16 | ||
73 | |||
74 | void checktime() | ||
75 | { | ||
76 | time_t t_stored=0, t_current=time(NULL); | ||
77 | |||
78 | FILE *f = fopen(TIME_FILE, "r"); | ||
79 | if(f!=NULL) | ||
80 | { | ||
81 | fscanf(f, "%ld", &t_stored); | ||
82 | fclose(f); | ||
83 | } | ||
84 | |||
85 | printf("stored time: %ld, current time: %ld\n", t_stored, t_current); | ||
86 | |||
87 | if(t_stored<MIN_TIME) | ||
88 | t_stored=MIN_TIME; | ||
89 | |||
90 | if(t_stored<t_current) | ||
91 | { | ||
92 | f = fopen(TIME_FILE, "w"); | ||
93 | fprintf(f, "%ld", t_current); | ||
94 | fclose(f); | ||
95 | } | ||
96 | else | ||
97 | { | ||
98 | t_stored += TIME_CHECK_PERIOD; | ||
99 | struct tm *t = localtime(&t_stored); | ||
100 | struct timeval tv = {mktime(t), 0}; | ||
101 | settimeofday(&tv, 0); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | |||
106 | static struct pollfd *ufds; | ||
107 | static char **device_names; | ||
108 | static int nfds; | ||
109 | |||
110 | |||
111 | |||
112 | static int open_device(const char *device, int print_flags) | ||
113 | { | ||
114 | int fd; | ||
115 | struct pollfd *new_ufds; | ||
116 | char **new_device_names; | ||
117 | |||
118 | fd = open(device, O_RDWR); | ||
119 | if(fd < 0) | ||
120 | { | ||
121 | fprintf(stderr, "could not open %s, %s\n", device, strerror(errno)); | ||
122 | return -1; | ||
123 | } | ||
124 | |||
125 | new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1)); | ||
126 | if(new_ufds == NULL) | ||
127 | { | ||
128 | fprintf(stderr, "out of memory\n"); | ||
129 | return -1; | ||
130 | } | ||
131 | ufds = new_ufds; | ||
132 | new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1)); | ||
133 | if(new_device_names == NULL) | ||
134 | { | ||
135 | fprintf(stderr, "out of memory\n"); | ||
136 | return -1; | ||
137 | } | ||
138 | device_names = new_device_names; | ||
139 | |||
140 | ufds[nfds].fd = fd; | ||
141 | ufds[nfds].events = POLLIN; | ||
142 | device_names[nfds] = strdup(device); | ||
143 | nfds++; | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | |||
149 | |||
150 | static int scan_dir(const char *dirname, int print_flags) | ||
151 | { | ||
152 | char devname[PATH_MAX]; | ||
153 | char *filename; | ||
154 | DIR *dir; | ||
155 | struct dirent *de; | ||
156 | dir = opendir(dirname); | ||
157 | if(dir == NULL) | ||
158 | return -1; | ||
159 | strcpy(devname, dirname); | ||
160 | filename = devname + strlen(devname); | ||
161 | *filename++ = '/'; | ||
162 | while((de = readdir(dir))) | ||
163 | { | ||
164 | if(de->d_name[0] == '.' && | ||
165 | (de->d_name[1] == '\0' || | ||
166 | (de->d_name[1] == '.' && de->d_name[2] == '\0'))) | ||
167 | continue; | ||
168 | strcpy(filename, de->d_name); | ||
169 | open_device(devname, print_flags); | ||
170 | } | ||
171 | closedir(dir); | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | |||
176 | |||
177 | void button_init_device(void) | ||
178 | { | ||
179 | int res; | ||
180 | int print_flags = 0; | ||
181 | const char *device = NULL; | ||
182 | const char *device_path = "/dev/input"; | ||
183 | |||
184 | nfds = 1; | ||
185 | ufds = calloc(1, sizeof(ufds[0])); | ||
186 | ufds[0].fd = inotify_init(); | ||
187 | ufds[0].events = POLLIN; | ||
188 | if(device) | ||
189 | { | ||
190 | res = open_device(device, print_flags); | ||
191 | if(res < 0) { | ||
192 | fprintf(stderr, "open device failed\n"); | ||
193 | } | ||
194 | } | ||
195 | else | ||
196 | { | ||
197 | res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE); | ||
198 | if(res < 0) | ||
199 | { | ||
200 | fprintf(stderr, "could not add watch for %s, %s\n", device_path, strerror(errno)); | ||
201 | } | ||
202 | res = scan_dir(device_path, print_flags); | ||
203 | if(res < 0) | ||
204 | { | ||
205 | fprintf(stderr, "scan dir failed for %s\n", device_path); | ||
206 | } | ||
207 | } | ||
208 | } | ||
209 | |||
210 | |||
211 | int draw() | ||
212 | { | ||
213 | int fbfd = 0; | ||
214 | struct fb_var_screeninfo vinfo; | ||
215 | struct fb_fix_screeninfo finfo; | ||
216 | long int screensize = 0; | ||
217 | char *fbp = 0; | ||
218 | int x = 0, y = 0; | ||
219 | long int location = 0; | ||
220 | |||
221 | /* Open the file for reading and writing */ | ||
222 | fbfd = open("/dev/graphics/fb0", O_RDWR); | ||
223 | if (fbfd == -1) | ||
224 | { | ||
225 | perror("Error: cannot open framebuffer device"); | ||
226 | exit(1); | ||
227 | } | ||
228 | /* Get fixed screen information */ | ||
229 | if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) | ||
230 | { | ||
231 | perror("Error reading fixed information"); | ||
232 | exit(2); | ||
233 | } | ||
234 | |||
235 | /* Get variable screen information */ | ||
236 | if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) | ||
237 | { | ||
238 | perror("Error reading variable information"); | ||
239 | exit(3); | ||
240 | } | ||
241 | |||
242 | /* Figure out the size of the screen in bytes */ | ||
243 | screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; | ||
244 | |||
245 | vinfo.xres = vinfo.xres_virtual = vinfo.width = 320; | ||
246 | vinfo.yres = vinfo.yres_virtual = vinfo.height = 240; | ||
247 | vinfo.xoffset = vinfo.yoffset = vinfo.sync = vinfo.vmode = 0; | ||
248 | vinfo.pixclock = 104377; | ||
249 | vinfo.left_margin = 20; | ||
250 | vinfo.right_margin = 50; | ||
251 | vinfo.upper_margin = 2; | ||
252 | vinfo.lower_margin = 4; | ||
253 | vinfo.hsync_len = 10; | ||
254 | vinfo.vsync_len = 2; | ||
255 | vinfo.red.offset = 11; | ||
256 | vinfo.red.length = 5; | ||
257 | vinfo.red.msb_right = 0; | ||
258 | vinfo.green.offset = 5; | ||
259 | vinfo.green.length = 6; | ||
260 | vinfo.green.msb_right = 0; | ||
261 | vinfo.blue.offset = 0; | ||
262 | vinfo.blue.length = 5; | ||
263 | vinfo.blue.msb_right = 0; | ||
264 | vinfo.transp.offset = vinfo.transp.length = vinfo.transp.msb_right = 0; | ||
265 | vinfo.nonstd = 4; | ||
266 | |||
267 | if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo)) | ||
268 | { | ||
269 | perror("fbset(ioctl)"); | ||
270 | exit(4); | ||
271 | } | ||
272 | |||
273 | |||
274 | /* Map the device to memory */ | ||
275 | fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, | ||
276 | fbfd, 0); | ||
277 | if ((int)fbp == -1) | ||
278 | { | ||
279 | perror("Error: failed to map framebuffer device to memory"); | ||
280 | exit(4); | ||
281 | } | ||
282 | |||
283 | BMP* bmp = BMP_ReadFile("/system/rockbox/chooser.bmp"); | ||
284 | BMP_CHECK_ERROR( stderr, -1 ); | ||
285 | |||
286 | UCHAR r, g, b; | ||
287 | unsigned short int t; | ||
288 | |||
289 | for (y = 0; y < 240; y++) | ||
290 | for (x = 0; x < 320; x++) | ||
291 | { | ||
292 | location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) + | ||
293 | (y+vinfo.yoffset) * finfo.line_length; | ||
294 | |||
295 | BMP_GetPixelRGB(bmp, x, y, &r, &g, &b); | ||
296 | t = (r>>3)<<11 | (g>>2) << 5 | (b>>3); | ||
297 | *((unsigned short int*)(fbp + location)) = t; | ||
298 | } | ||
299 | |||
300 | BMP_Free( bmp ); | ||
301 | |||
302 | munmap(fbp, screensize); | ||
303 | close(fbfd); | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | |||
308 | int choose_player() | ||
309 | { | ||
310 | int i; | ||
311 | int res; | ||
312 | struct input_event event; | ||
313 | |||
314 | while(true) | ||
315 | { | ||
316 | poll(ufds, nfds, POLL_MS); | ||
317 | for(i = 1; i < nfds; i++) | ||
318 | { | ||
319 | if(ufds[i].revents & POLLIN) | ||
320 | { | ||
321 | res = read(ufds[i].fd, &event, sizeof(event)); | ||
322 | if(res < (int)sizeof(event)) | ||
323 | { | ||
324 | fprintf(stderr, "could not get event\n"); | ||
325 | } | ||
326 | if(event.type==1) | ||
327 | { | ||
328 | if(event.code==KEYCODE_NEXT) | ||
329 | { | ||
330 | puts("rockbox!"); | ||
331 | return 1; | ||
332 | } | ||
333 | else if(event.code==KEYCODE_PREV) | ||
334 | { | ||
335 | puts("mango!"); | ||
336 | return 0; | ||
337 | } | ||
338 | else if(event.code==KEYCODE_PWR || event.code==KEYCODE_PWR_LONG) | ||
339 | { | ||
340 | reboot(LINUX_REBOOT_CMD_POWER_OFF); | ||
341 | } | ||
342 | } | ||
343 | else if(event.type==3) | ||
344 | { | ||
345 | if(event.code==53) //x coord | ||
346 | { | ||
347 | if(event.value<160) | ||
348 | { | ||
349 | puts("mango!"); | ||
350 | return 0; | ||
351 | } | ||
352 | else | ||
353 | { | ||
354 | puts("rockbox!"); | ||
355 | return 1; | ||
356 | } | ||
357 | } | ||
358 | } | ||
359 | } | ||
360 | } | ||
361 | } | ||
362 | return true; | ||
363 | } | ||
364 | |||
365 | bool check_for_hold() | ||
366 | { | ||
367 | FILE *f = fopen("/sys/class/axppower/holdkey", "r"); | ||
368 | char x; | ||
369 | fscanf(f, "%c", &x); | ||
370 | fclose(f); | ||
371 | |||
372 | if(x & KEY_HOLD_OFF) | ||
373 | return false; | ||
374 | else | ||
375 | return true; | ||
376 | } | ||
377 | |||
378 | int main(int argc, char **argv) | ||
379 | { | ||
380 | FILE *f; | ||
381 | int last_chosen_player = -1; | ||
382 | |||
383 | f = fopen(PLAYER_FILE, "r"); | ||
384 | if(f!=NULL) | ||
385 | { | ||
386 | fscanf(f, "%d", &last_chosen_player); | ||
387 | fclose(f); | ||
388 | } | ||
389 | bool ask = (access(VOLD_LINK, F_OK) == -1) || ((access(NOASK_FLAG, F_OK) == -1) && check_for_hold()) || (last_chosen_player==-1); | ||
390 | |||
391 | if(ask) | ||
392 | { | ||
393 | draw(); | ||
394 | button_init_device(); | ||
395 | int player_chosen_now = choose_player(); | ||
396 | |||
397 | if(last_chosen_player!=player_chosen_now) | ||
398 | { | ||
399 | f = fopen(PLAYER_FILE, "w"); | ||
400 | fprintf(f, "%d", player_chosen_now); | ||
401 | fclose(f); | ||
402 | } | ||
403 | |||
404 | if(last_chosen_player!=player_chosen_now || (access(VOLD_LINK, F_OK) == -1)) | ||
405 | { | ||
406 | system("rm "VOLD_LINK); | ||
407 | |||
408 | if(player_chosen_now) | ||
409 | system("ln -s /system/bin/vold_rockbox "VOLD_LINK); | ||
410 | else | ||
411 | system("ln -s /system/bin/vold_original "VOLD_LINK); | ||
412 | |||
413 | system("touch "NOASK_FLAG); | ||
414 | system("reboot"); | ||
415 | } | ||
416 | last_chosen_player = player_chosen_now; | ||
417 | } | ||
418 | |||
419 | system("rm "NOASK_FLAG); | ||
420 | |||
421 | while(1) | ||
422 | { | ||
423 | if(last_chosen_player) | ||
424 | { | ||
425 | // system("/system/bin/openadb"); | ||
426 | system("/system/rockbox/lib/rockbox"); | ||
427 | } | ||
428 | else | ||
429 | // system("/system/bin/closeadb"); | ||
430 | system("/system/bin/MangoPlayer_original"); | ||
431 | |||
432 | sleep(1); | ||
433 | } | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | |||
439 | |||
diff --git a/rbutil/ibassoboot/jni/qdbmp.c b/rbutil/ibassoboot/jni/qdbmp.c new file mode 100644 index 0000000000..fd1337277d --- /dev/null +++ b/rbutil/ibassoboot/jni/qdbmp.c | |||
@@ -0,0 +1,798 @@ | |||
1 | #include "qdbmp.h" | ||
2 | #include <stdlib.h> | ||
3 | #include <string.h> | ||
4 | |||
5 | |||
6 | /* Bitmap header */ | ||
7 | typedef struct _BMP_Header | ||
8 | { | ||
9 | USHORT Magic; /* Magic identifier: "BM" */ | ||
10 | UINT FileSize; /* Size of the BMP file in bytes */ | ||
11 | USHORT Reserved1; /* Reserved */ | ||
12 | USHORT Reserved2; /* Reserved */ | ||
13 | UINT DataOffset; /* Offset of image data relative to the file's start */ | ||
14 | UINT HeaderSize; /* Size of the header in bytes */ | ||
15 | UINT Width; /* Bitmap's width */ | ||
16 | UINT Height; /* Bitmap's height */ | ||
17 | USHORT Planes; /* Number of color planes in the bitmap */ | ||
18 | USHORT BitsPerPixel; /* Number of bits per pixel */ | ||
19 | UINT CompressionType; /* Compression type */ | ||
20 | UINT ImageDataSize; /* Size of uncompressed image's data */ | ||
21 | UINT HPixelsPerMeter; /* Horizontal resolution (pixels per meter) */ | ||
22 | UINT VPixelsPerMeter; /* Vertical resolution (pixels per meter) */ | ||
23 | UINT ColorsUsed; /* Number of color indexes in the color table that are actually used by the bitmap */ | ||
24 | UINT ColorsRequired; /* Number of color indexes that are required for displaying the bitmap */ | ||
25 | } BMP_Header; | ||
26 | |||
27 | |||
28 | /* Private data structure */ | ||
29 | struct _BMP | ||
30 | { | ||
31 | BMP_Header Header; | ||
32 | UCHAR* Palette; | ||
33 | UCHAR* Data; | ||
34 | }; | ||
35 | |||
36 | |||
37 | /* Holds the last error code */ | ||
38 | static BMP_STATUS BMP_LAST_ERROR_CODE = 0; | ||
39 | |||
40 | |||
41 | /* Error description strings */ | ||
42 | static const char* BMP_ERROR_STRING[] = | ||
43 | { | ||
44 | "", | ||
45 | "General error", | ||
46 | "Could not allocate enough memory to complete the operation", | ||
47 | "File input/output error", | ||
48 | "File not found", | ||
49 | "File is not a supported BMP variant (must be uncompressed 8, 24 or 32 BPP)", | ||
50 | "File is not a valid BMP image", | ||
51 | "An argument is invalid or out of range", | ||
52 | "The requested action is not compatible with the BMP's type" | ||
53 | }; | ||
54 | |||
55 | |||
56 | /* Size of the palette data for 8 BPP bitmaps */ | ||
57 | #define BMP_PALETTE_SIZE ( 256 * 4 ) | ||
58 | |||
59 | |||
60 | |||
61 | /*********************************** Forward declarations **********************************/ | ||
62 | int ReadHeader ( BMP* bmp, FILE* f ); | ||
63 | int WriteHeader ( BMP* bmp, FILE* f ); | ||
64 | |||
65 | int ReadUINT ( UINT* x, FILE* f ); | ||
66 | int ReadUSHORT ( USHORT *x, FILE* f ); | ||
67 | |||
68 | int WriteUINT ( UINT x, FILE* f ); | ||
69 | int WriteUSHORT ( USHORT x, FILE* f ); | ||
70 | |||
71 | |||
72 | |||
73 | |||
74 | |||
75 | |||
76 | /*********************************** Public methods **********************************/ | ||
77 | |||
78 | |||
79 | /************************************************************** | ||
80 | Creates a blank BMP image with the specified dimensions | ||
81 | and bit depth. | ||
82 | **************************************************************/ | ||
83 | BMP* BMP_Create( UINT width, UINT height, USHORT depth ) | ||
84 | { | ||
85 | BMP* bmp; | ||
86 | int bytes_per_pixel = depth >> 3; | ||
87 | UINT bytes_per_row; | ||
88 | |||
89 | if ( height <= 0 || width <= 0 ) | ||
90 | { | ||
91 | BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; | ||
92 | return NULL; | ||
93 | } | ||
94 | |||
95 | if ( depth != 8 && depth != 24 && depth != 32 ) | ||
96 | { | ||
97 | BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED; | ||
98 | return NULL; | ||
99 | } | ||
100 | |||
101 | |||
102 | /* Allocate the bitmap data structure */ | ||
103 | bmp = calloc( 1, sizeof( BMP ) ); | ||
104 | if ( bmp == NULL ) | ||
105 | { | ||
106 | BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; | ||
107 | return NULL; | ||
108 | } | ||
109 | |||
110 | |||
111 | /* Set header' default values */ | ||
112 | bmp->Header.Magic = 0x4D42; | ||
113 | bmp->Header.Reserved1 = 0; | ||
114 | bmp->Header.Reserved2 = 0; | ||
115 | bmp->Header.HeaderSize = 40; | ||
116 | bmp->Header.Planes = 1; | ||
117 | bmp->Header.CompressionType = 0; | ||
118 | bmp->Header.HPixelsPerMeter = 0; | ||
119 | bmp->Header.VPixelsPerMeter = 0; | ||
120 | bmp->Header.ColorsUsed = 0; | ||
121 | bmp->Header.ColorsRequired = 0; | ||
122 | |||
123 | |||
124 | /* Calculate the number of bytes used to store a single image row. This is always | ||
125 | rounded up to the next multiple of 4. */ | ||
126 | bytes_per_row = width * bytes_per_pixel; | ||
127 | bytes_per_row += ( bytes_per_row % 4 ? 4 - bytes_per_row % 4 : 0 ); | ||
128 | |||
129 | |||
130 | /* Set header's image specific values */ | ||
131 | bmp->Header.Width = width; | ||
132 | bmp->Header.Height = height; | ||
133 | bmp->Header.BitsPerPixel = depth; | ||
134 | bmp->Header.ImageDataSize = bytes_per_row * height; | ||
135 | bmp->Header.FileSize = bmp->Header.ImageDataSize + 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 ); | ||
136 | bmp->Header.DataOffset = 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 ); | ||
137 | |||
138 | |||
139 | /* Allocate palette */ | ||
140 | if ( bmp->Header.BitsPerPixel == 8 ) | ||
141 | { | ||
142 | bmp->Palette = (UCHAR*) calloc( BMP_PALETTE_SIZE, sizeof( UCHAR ) ); | ||
143 | if ( bmp->Palette == NULL ) | ||
144 | { | ||
145 | BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; | ||
146 | free( bmp ); | ||
147 | return NULL; | ||
148 | } | ||
149 | } | ||
150 | else | ||
151 | { | ||
152 | bmp->Palette = NULL; | ||
153 | } | ||
154 | |||
155 | |||
156 | /* Allocate pixels */ | ||
157 | bmp->Data = (UCHAR*) calloc( bmp->Header.ImageDataSize, sizeof( UCHAR ) ); | ||
158 | if ( bmp->Data == NULL ) | ||
159 | { | ||
160 | BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; | ||
161 | free( bmp->Palette ); | ||
162 | free( bmp ); | ||
163 | return NULL; | ||
164 | } | ||
165 | |||
166 | |||
167 | BMP_LAST_ERROR_CODE = BMP_OK; | ||
168 | |||
169 | return bmp; | ||
170 | } | ||
171 | |||
172 | |||
173 | /************************************************************** | ||
174 | Frees all the memory used by the specified BMP image. | ||
175 | **************************************************************/ | ||
176 | void BMP_Free( BMP* bmp ) | ||
177 | { | ||
178 | if ( bmp == NULL ) | ||
179 | { | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | if ( bmp->Palette != NULL ) | ||
184 | { | ||
185 | free( bmp->Palette ); | ||
186 | } | ||
187 | |||
188 | if ( bmp->Data != NULL ) | ||
189 | { | ||
190 | free( bmp->Data ); | ||
191 | } | ||
192 | |||
193 | free( bmp ); | ||
194 | |||
195 | BMP_LAST_ERROR_CODE = BMP_OK; | ||
196 | } | ||
197 | |||
198 | |||
199 | /************************************************************** | ||
200 | Reads the specified BMP image file. | ||
201 | **************************************************************/ | ||
202 | BMP* BMP_ReadFile( const char* filename ) | ||
203 | { | ||
204 | BMP* bmp; | ||
205 | FILE* f; | ||
206 | |||
207 | if ( filename == NULL ) | ||
208 | { | ||
209 | BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; | ||
210 | return NULL; | ||
211 | } | ||
212 | |||
213 | |||
214 | /* Allocate */ | ||
215 | bmp = calloc( 1, sizeof( BMP ) ); | ||
216 | if ( bmp == NULL ) | ||
217 | { | ||
218 | BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; | ||
219 | return NULL; | ||
220 | } | ||
221 | |||
222 | |||
223 | /* Open file */ | ||
224 | f = fopen( filename, "rb" ); | ||
225 | if ( f == NULL ) | ||
226 | { | ||
227 | BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND; | ||
228 | free( bmp ); | ||
229 | return NULL; | ||
230 | } | ||
231 | |||
232 | |||
233 | /* Read header */ | ||
234 | if ( ReadHeader( bmp, f ) != BMP_OK || bmp->Header.Magic != 0x4D42 ) | ||
235 | { | ||
236 | BMP_LAST_ERROR_CODE = BMP_FILE_INVALID; | ||
237 | fclose( f ); | ||
238 | free( bmp ); | ||
239 | return NULL; | ||
240 | } | ||
241 | |||
242 | |||
243 | /* Verify that the bitmap variant is supported */ | ||
244 | if ( ( bmp->Header.BitsPerPixel != 32 && bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 8 ) | ||
245 | || bmp->Header.CompressionType != 0 || bmp->Header.HeaderSize != 40 ) | ||
246 | { | ||
247 | BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED; | ||
248 | fclose( f ); | ||
249 | free( bmp ); | ||
250 | return NULL; | ||
251 | } | ||
252 | |||
253 | |||
254 | /* Allocate and read palette */ | ||
255 | if ( bmp->Header.BitsPerPixel == 8 ) | ||
256 | { | ||
257 | bmp->Palette = (UCHAR*) malloc( BMP_PALETTE_SIZE * sizeof( UCHAR ) ); | ||
258 | if ( bmp->Palette == NULL ) | ||
259 | { | ||
260 | BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; | ||
261 | fclose( f ); | ||
262 | free( bmp ); | ||
263 | return NULL; | ||
264 | } | ||
265 | |||
266 | if ( fread( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE ) | ||
267 | { | ||
268 | BMP_LAST_ERROR_CODE = BMP_FILE_INVALID; | ||
269 | fclose( f ); | ||
270 | free( bmp->Palette ); | ||
271 | free( bmp ); | ||
272 | return NULL; | ||
273 | } | ||
274 | } | ||
275 | else /* Not an indexed image */ | ||
276 | { | ||
277 | bmp->Palette = NULL; | ||
278 | } | ||
279 | |||
280 | |||
281 | /* Allocate memory for image data */ | ||
282 | bmp->Data = (UCHAR*) malloc( bmp->Header.ImageDataSize ); | ||
283 | if ( bmp->Data == NULL ) | ||
284 | { | ||
285 | BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; | ||
286 | fclose( f ); | ||
287 | free( bmp->Palette ); | ||
288 | free( bmp ); | ||
289 | return NULL; | ||
290 | } | ||
291 | |||
292 | |||
293 | /* Read image data */ | ||
294 | if ( fread( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize ) | ||
295 | { | ||
296 | BMP_LAST_ERROR_CODE = BMP_FILE_INVALID; | ||
297 | fclose( f ); | ||
298 | free( bmp->Data ); | ||
299 | free( bmp->Palette ); | ||
300 | free( bmp ); | ||
301 | return NULL; | ||
302 | } | ||
303 | |||
304 | |||
305 | fclose( f ); | ||
306 | |||
307 | BMP_LAST_ERROR_CODE = BMP_OK; | ||
308 | |||
309 | return bmp; | ||
310 | } | ||
311 | |||
312 | |||
313 | /************************************************************** | ||
314 | Writes the BMP image to the specified file. | ||
315 | **************************************************************/ | ||
316 | void BMP_WriteFile( BMP* bmp, const char* filename ) | ||
317 | { | ||
318 | FILE* f; | ||
319 | |||
320 | if ( filename == NULL ) | ||
321 | { | ||
322 | BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; | ||
323 | return; | ||
324 | } | ||
325 | |||
326 | |||
327 | /* Open file */ | ||
328 | f = fopen( filename, "wb" ); | ||
329 | if ( f == NULL ) | ||
330 | { | ||
331 | BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND; | ||
332 | return; | ||
333 | } | ||
334 | |||
335 | |||
336 | /* Write header */ | ||
337 | if ( WriteHeader( bmp, f ) != BMP_OK ) | ||
338 | { | ||
339 | BMP_LAST_ERROR_CODE = BMP_IO_ERROR; | ||
340 | fclose( f ); | ||
341 | return; | ||
342 | } | ||
343 | |||
344 | |||
345 | /* Write palette */ | ||
346 | if ( bmp->Palette ) | ||
347 | { | ||
348 | if ( fwrite( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE ) | ||
349 | { | ||
350 | BMP_LAST_ERROR_CODE = BMP_IO_ERROR; | ||
351 | fclose( f ); | ||
352 | return; | ||
353 | } | ||
354 | } | ||
355 | |||
356 | |||
357 | /* Write data */ | ||
358 | if ( fwrite( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize ) | ||
359 | { | ||
360 | BMP_LAST_ERROR_CODE = BMP_IO_ERROR; | ||
361 | fclose( f ); | ||
362 | return; | ||
363 | } | ||
364 | |||
365 | |||
366 | BMP_LAST_ERROR_CODE = BMP_OK; | ||
367 | fclose( f ); | ||
368 | } | ||
369 | |||
370 | |||
371 | /************************************************************** | ||
372 | Returns the image's width. | ||
373 | **************************************************************/ | ||
374 | UINT BMP_GetWidth( BMP* bmp ) | ||
375 | { | ||
376 | if ( bmp == NULL ) | ||
377 | { | ||
378 | BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; | ||
379 | return -1; | ||
380 | } | ||
381 | |||
382 | BMP_LAST_ERROR_CODE = BMP_OK; | ||
383 | |||
384 | return ( bmp->Header.Width ); | ||
385 | } | ||
386 | |||
387 | |||
388 | /************************************************************** | ||
389 | Returns the image's height. | ||
390 | **************************************************************/ | ||
391 | UINT BMP_GetHeight( BMP* bmp ) | ||
392 | { | ||
393 | if ( bmp == NULL ) | ||
394 | { | ||
395 | BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; | ||
396 | return -1; | ||
397 | } | ||
398 | |||
399 | BMP_LAST_ERROR_CODE = BMP_OK; | ||
400 | |||
401 | return ( bmp->Header.Height ); | ||
402 | } | ||
403 | |||
404 | |||
405 | /************************************************************** | ||
406 | Returns the image's color depth (bits per pixel). | ||
407 | **************************************************************/ | ||
408 | USHORT BMP_GetDepth( BMP* bmp ) | ||
409 | { | ||
410 | if ( bmp == NULL ) | ||
411 | { | ||
412 | BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; | ||
413 | return -1; | ||
414 | } | ||
415 | |||
416 | BMP_LAST_ERROR_CODE = BMP_OK; | ||
417 | |||
418 | return ( bmp->Header.BitsPerPixel ); | ||
419 | } | ||
420 | |||
421 | |||
422 | /************************************************************** | ||
423 | Populates the arguments with the specified pixel's RGB | ||
424 | values. | ||
425 | **************************************************************/ | ||
426 | void BMP_GetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR* r, UCHAR* g, UCHAR* b ) | ||
427 | { | ||
428 | UCHAR* pixel; | ||
429 | UINT bytes_per_row; | ||
430 | UCHAR bytes_per_pixel; | ||
431 | |||
432 | if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height ) | ||
433 | { | ||
434 | BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; | ||
435 | } | ||
436 | else | ||
437 | { | ||
438 | BMP_LAST_ERROR_CODE = BMP_OK; | ||
439 | |||
440 | bytes_per_pixel = bmp->Header.BitsPerPixel >> 3; | ||
441 | |||
442 | /* Row's size is rounded up to the next multiple of 4 bytes */ | ||
443 | bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height; | ||
444 | |||
445 | /* Calculate the location of the relevant pixel (rows are flipped) */ | ||
446 | pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel ); | ||
447 | |||
448 | |||
449 | /* In indexed color mode the pixel's value is an index within the palette */ | ||
450 | if ( bmp->Header.BitsPerPixel == 8 ) | ||
451 | { | ||
452 | pixel = bmp->Palette + *pixel * 4; | ||
453 | } | ||
454 | |||
455 | /* Note: colors are stored in BGR order */ | ||
456 | if ( r ) *r = *( pixel + 2 ); | ||
457 | if ( g ) *g = *( pixel + 1 ); | ||
458 | if ( b ) *b = *( pixel + 0 ); | ||
459 | } | ||
460 | } | ||
461 | |||
462 | |||
463 | /************************************************************** | ||
464 | Sets the specified pixel's RGB values. | ||
465 | **************************************************************/ | ||
466 | void BMP_SetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR r, UCHAR g, UCHAR b ) | ||
467 | { | ||
468 | UCHAR* pixel; | ||
469 | UINT bytes_per_row; | ||
470 | UCHAR bytes_per_pixel; | ||
471 | |||
472 | if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height ) | ||
473 | { | ||
474 | BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; | ||
475 | } | ||
476 | |||
477 | else if ( bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 32 ) | ||
478 | { | ||
479 | BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH; | ||
480 | } | ||
481 | |||
482 | else | ||
483 | { | ||
484 | BMP_LAST_ERROR_CODE = BMP_OK; | ||
485 | |||
486 | bytes_per_pixel = bmp->Header.BitsPerPixel >> 3; | ||
487 | |||
488 | /* Row's size is rounded up to the next multiple of 4 bytes */ | ||
489 | bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height; | ||
490 | |||
491 | /* Calculate the location of the relevant pixel (rows are flipped) */ | ||
492 | pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel ); | ||
493 | |||
494 | /* Note: colors are stored in BGR order */ | ||
495 | *( pixel + 2 ) = r; | ||
496 | *( pixel + 1 ) = g; | ||
497 | *( pixel + 0 ) = b; | ||
498 | } | ||
499 | } | ||
500 | |||
501 | |||
502 | /************************************************************** | ||
503 | Gets the specified pixel's color index. | ||
504 | **************************************************************/ | ||
505 | void BMP_GetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR* val ) | ||
506 | { | ||
507 | UCHAR* pixel; | ||
508 | UINT bytes_per_row; | ||
509 | |||
510 | if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height ) | ||
511 | { | ||
512 | BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; | ||
513 | } | ||
514 | |||
515 | else if ( bmp->Header.BitsPerPixel != 8 ) | ||
516 | { | ||
517 | BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH; | ||
518 | } | ||
519 | |||
520 | else | ||
521 | { | ||
522 | BMP_LAST_ERROR_CODE = BMP_OK; | ||
523 | |||
524 | /* Row's size is rounded up to the next multiple of 4 bytes */ | ||
525 | bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height; | ||
526 | |||
527 | /* Calculate the location of the relevant pixel */ | ||
528 | pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x ); | ||
529 | |||
530 | |||
531 | if ( val ) *val = *pixel; | ||
532 | } | ||
533 | } | ||
534 | |||
535 | |||
536 | /************************************************************** | ||
537 | Sets the specified pixel's color index. | ||
538 | **************************************************************/ | ||
539 | void BMP_SetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR val ) | ||
540 | { | ||
541 | UCHAR* pixel; | ||
542 | UINT bytes_per_row; | ||
543 | |||
544 | if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height ) | ||
545 | { | ||
546 | BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; | ||
547 | } | ||
548 | |||
549 | else if ( bmp->Header.BitsPerPixel != 8 ) | ||
550 | { | ||
551 | BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH; | ||
552 | } | ||
553 | |||
554 | else | ||
555 | { | ||
556 | BMP_LAST_ERROR_CODE = BMP_OK; | ||
557 | |||
558 | /* Row's size is rounded up to the next multiple of 4 bytes */ | ||
559 | bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height; | ||
560 | |||
561 | /* Calculate the location of the relevant pixel */ | ||
562 | pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x ); | ||
563 | |||
564 | *pixel = val; | ||
565 | } | ||
566 | } | ||
567 | |||
568 | |||
569 | /************************************************************** | ||
570 | Gets the color value for the specified palette index. | ||
571 | **************************************************************/ | ||
572 | void BMP_GetPaletteColor( BMP* bmp, UCHAR index, UCHAR* r, UCHAR* g, UCHAR* b ) | ||
573 | { | ||
574 | if ( bmp == NULL ) | ||
575 | { | ||
576 | BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; | ||
577 | } | ||
578 | |||
579 | else if ( bmp->Header.BitsPerPixel != 8 ) | ||
580 | { | ||
581 | BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH; | ||
582 | } | ||
583 | |||
584 | else | ||
585 | { | ||
586 | if ( r ) *r = *( bmp->Palette + index * 4 + 2 ); | ||
587 | if ( g ) *g = *( bmp->Palette + index * 4 + 1 ); | ||
588 | if ( b ) *b = *( bmp->Palette + index * 4 + 0 ); | ||
589 | |||
590 | BMP_LAST_ERROR_CODE = BMP_OK; | ||
591 | } | ||
592 | } | ||
593 | |||
594 | |||
595 | /************************************************************** | ||
596 | Sets the color value for the specified palette index. | ||
597 | **************************************************************/ | ||
598 | void BMP_SetPaletteColor( BMP* bmp, UCHAR index, UCHAR r, UCHAR g, UCHAR b ) | ||
599 | { | ||
600 | if ( bmp == NULL ) | ||
601 | { | ||
602 | BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; | ||
603 | } | ||
604 | |||
605 | else if ( bmp->Header.BitsPerPixel != 8 ) | ||
606 | { | ||
607 | BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH; | ||
608 | } | ||
609 | |||
610 | else | ||
611 | { | ||
612 | *( bmp->Palette + index * 4 + 2 ) = r; | ||
613 | *( bmp->Palette + index * 4 + 1 ) = g; | ||
614 | *( bmp->Palette + index * 4 + 0 ) = b; | ||
615 | |||
616 | BMP_LAST_ERROR_CODE = BMP_OK; | ||
617 | } | ||
618 | } | ||
619 | |||
620 | |||
621 | /************************************************************** | ||
622 | Returns the last error code. | ||
623 | **************************************************************/ | ||
624 | BMP_STATUS BMP_GetError() | ||
625 | { | ||
626 | return BMP_LAST_ERROR_CODE; | ||
627 | } | ||
628 | |||
629 | |||
630 | /************************************************************** | ||
631 | Returns a description of the last error code. | ||
632 | **************************************************************/ | ||
633 | const char* BMP_GetErrorDescription() | ||
634 | { | ||
635 | if ( BMP_LAST_ERROR_CODE > 0 && BMP_LAST_ERROR_CODE < BMP_ERROR_NUM ) | ||
636 | { | ||
637 | return BMP_ERROR_STRING[ BMP_LAST_ERROR_CODE ]; | ||
638 | } | ||
639 | else | ||
640 | { | ||
641 | return NULL; | ||
642 | } | ||
643 | } | ||
644 | |||
645 | |||
646 | |||
647 | |||
648 | |||
649 | /*********************************** Private methods **********************************/ | ||
650 | |||
651 | |||
652 | /************************************************************** | ||
653 | Reads the BMP file's header into the data structure. | ||
654 | Returns BMP_OK on success. | ||
655 | **************************************************************/ | ||
656 | int ReadHeader( BMP* bmp, FILE* f ) | ||
657 | { | ||
658 | if ( bmp == NULL || f == NULL ) | ||
659 | { | ||
660 | return BMP_INVALID_ARGUMENT; | ||
661 | } | ||
662 | |||
663 | /* The header's fields are read one by one, and converted from the format's | ||
664 | little endian to the system's native representation. */ | ||
665 | if ( !ReadUSHORT( &( bmp->Header.Magic ), f ) ) return BMP_IO_ERROR; | ||
666 | if ( !ReadUINT( &( bmp->Header.FileSize ), f ) ) return BMP_IO_ERROR; | ||
667 | if ( !ReadUSHORT( &( bmp->Header.Reserved1 ), f ) ) return BMP_IO_ERROR; | ||
668 | if ( !ReadUSHORT( &( bmp->Header.Reserved2 ), f ) ) return BMP_IO_ERROR; | ||
669 | if ( !ReadUINT( &( bmp->Header.DataOffset ), f ) ) return BMP_IO_ERROR; | ||
670 | if ( !ReadUINT( &( bmp->Header.HeaderSize ), f ) ) return BMP_IO_ERROR; | ||
671 | if ( !ReadUINT( &( bmp->Header.Width ), f ) ) return BMP_IO_ERROR; | ||
672 | if ( !ReadUINT( &( bmp->Header.Height ), f ) ) return BMP_IO_ERROR; | ||
673 | if ( !ReadUSHORT( &( bmp->Header.Planes ), f ) ) return BMP_IO_ERROR; | ||
674 | if ( !ReadUSHORT( &( bmp->Header.BitsPerPixel ), f ) ) return BMP_IO_ERROR; | ||
675 | if ( !ReadUINT( &( bmp->Header.CompressionType ), f ) ) return BMP_IO_ERROR; | ||
676 | if ( !ReadUINT( &( bmp->Header.ImageDataSize ), f ) ) return BMP_IO_ERROR; | ||
677 | if ( !ReadUINT( &( bmp->Header.HPixelsPerMeter ), f ) ) return BMP_IO_ERROR; | ||
678 | if ( !ReadUINT( &( bmp->Header.VPixelsPerMeter ), f ) ) return BMP_IO_ERROR; | ||
679 | if ( !ReadUINT( &( bmp->Header.ColorsUsed ), f ) ) return BMP_IO_ERROR; | ||
680 | if ( !ReadUINT( &( bmp->Header.ColorsRequired ), f ) ) return BMP_IO_ERROR; | ||
681 | |||
682 | return BMP_OK; | ||
683 | } | ||
684 | |||
685 | |||
686 | /************************************************************** | ||
687 | Writes the BMP file's header into the data structure. | ||
688 | Returns BMP_OK on success. | ||
689 | **************************************************************/ | ||
690 | int WriteHeader( BMP* bmp, FILE* f ) | ||
691 | { | ||
692 | if ( bmp == NULL || f == NULL ) | ||
693 | { | ||
694 | return BMP_INVALID_ARGUMENT; | ||
695 | } | ||
696 | |||
697 | /* The header's fields are written one by one, and converted to the format's | ||
698 | little endian representation. */ | ||
699 | if ( !WriteUSHORT( bmp->Header.Magic, f ) ) return BMP_IO_ERROR; | ||
700 | if ( !WriteUINT( bmp->Header.FileSize, f ) ) return BMP_IO_ERROR; | ||
701 | if ( !WriteUSHORT( bmp->Header.Reserved1, f ) ) return BMP_IO_ERROR; | ||
702 | if ( !WriteUSHORT( bmp->Header.Reserved2, f ) ) return BMP_IO_ERROR; | ||
703 | if ( !WriteUINT( bmp->Header.DataOffset, f ) ) return BMP_IO_ERROR; | ||
704 | if ( !WriteUINT( bmp->Header.HeaderSize, f ) ) return BMP_IO_ERROR; | ||
705 | if ( !WriteUINT( bmp->Header.Width, f ) ) return BMP_IO_ERROR; | ||
706 | if ( !WriteUINT( bmp->Header.Height, f ) ) return BMP_IO_ERROR; | ||
707 | if ( !WriteUSHORT( bmp->Header.Planes, f ) ) return BMP_IO_ERROR; | ||
708 | if ( !WriteUSHORT( bmp->Header.BitsPerPixel, f ) ) return BMP_IO_ERROR; | ||
709 | if ( !WriteUINT( bmp->Header.CompressionType, f ) ) return BMP_IO_ERROR; | ||
710 | if ( !WriteUINT( bmp->Header.ImageDataSize, f ) ) return BMP_IO_ERROR; | ||
711 | if ( !WriteUINT( bmp->Header.HPixelsPerMeter, f ) ) return BMP_IO_ERROR; | ||
712 | if ( !WriteUINT( bmp->Header.VPixelsPerMeter, f ) ) return BMP_IO_ERROR; | ||
713 | if ( !WriteUINT( bmp->Header.ColorsUsed, f ) ) return BMP_IO_ERROR; | ||
714 | if ( !WriteUINT( bmp->Header.ColorsRequired, f ) ) return BMP_IO_ERROR; | ||
715 | |||
716 | return BMP_OK; | ||
717 | } | ||
718 | |||
719 | |||
720 | /************************************************************** | ||
721 | Reads a little-endian unsigned int from the file. | ||
722 | Returns non-zero on success. | ||
723 | **************************************************************/ | ||
724 | int ReadUINT( UINT* x, FILE* f ) | ||
725 | { | ||
726 | UCHAR little[ 4 ]; /* BMPs use 32 bit ints */ | ||
727 | |||
728 | if ( x == NULL || f == NULL ) | ||
729 | { | ||
730 | return 0; | ||
731 | } | ||
732 | |||
733 | if ( fread( little, 4, 1, f ) != 1 ) | ||
734 | { | ||
735 | return 0; | ||
736 | } | ||
737 | |||
738 | *x = ( little[ 3 ] << 24 | little[ 2 ] << 16 | little[ 1 ] << 8 | little[ 0 ] ); | ||
739 | |||
740 | return 1; | ||
741 | } | ||
742 | |||
743 | |||
744 | /************************************************************** | ||
745 | Reads a little-endian unsigned short int from the file. | ||
746 | Returns non-zero on success. | ||
747 | **************************************************************/ | ||
748 | int ReadUSHORT( USHORT *x, FILE* f ) | ||
749 | { | ||
750 | UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */ | ||
751 | |||
752 | if ( x == NULL || f == NULL ) | ||
753 | { | ||
754 | return 0; | ||
755 | } | ||
756 | |||
757 | if ( fread( little, 2, 1, f ) != 1 ) | ||
758 | { | ||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | *x = ( little[ 1 ] << 8 | little[ 0 ] ); | ||
763 | |||
764 | return 1; | ||
765 | } | ||
766 | |||
767 | |||
768 | /************************************************************** | ||
769 | Writes a little-endian unsigned int to the file. | ||
770 | Returns non-zero on success. | ||
771 | **************************************************************/ | ||
772 | int WriteUINT( UINT x, FILE* f ) | ||
773 | { | ||
774 | UCHAR little[ 4 ]; /* BMPs use 32 bit ints */ | ||
775 | |||
776 | little[ 3 ] = (UCHAR)( ( x & 0xff000000 ) >> 24 ); | ||
777 | little[ 2 ] = (UCHAR)( ( x & 0x00ff0000 ) >> 16 ); | ||
778 | little[ 1 ] = (UCHAR)( ( x & 0x0000ff00 ) >> 8 ); | ||
779 | little[ 0 ] = (UCHAR)( ( x & 0x000000ff ) >> 0 ); | ||
780 | |||
781 | return ( f && fwrite( little, 4, 1, f ) == 1 ); | ||
782 | } | ||
783 | |||
784 | |||
785 | /************************************************************** | ||
786 | Writes a little-endian unsigned short int to the file. | ||
787 | Returns non-zero on success. | ||
788 | **************************************************************/ | ||
789 | int WriteUSHORT( USHORT x, FILE* f ) | ||
790 | { | ||
791 | UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */ | ||
792 | |||
793 | little[ 1 ] = (UCHAR)( ( x & 0xff00 ) >> 8 ); | ||
794 | little[ 0 ] = (UCHAR)( ( x & 0x00ff ) >> 0 ); | ||
795 | |||
796 | return ( f && fwrite( little, 2, 1, f ) == 1 ); | ||
797 | } | ||
798 | |||
diff --git a/rbutil/ibassoboot/jni/qdbmp.h b/rbutil/ibassoboot/jni/qdbmp.h new file mode 100644 index 0000000000..d6c0e6c452 --- /dev/null +++ b/rbutil/ibassoboot/jni/qdbmp.h | |||
@@ -0,0 +1,133 @@ | |||
1 | #ifndef _BMP_H_ | ||
2 | #define _BMP_H_ | ||
3 | |||
4 | |||
5 | /************************************************************** | ||
6 | |||
7 | QDBMP - Quick n' Dirty BMP | ||
8 | |||
9 | v1.0.0 - 2007-04-07 | ||
10 | http://qdbmp.sourceforge.net | ||
11 | |||
12 | |||
13 | The library supports the following BMP variants: | ||
14 | 1. Uncompressed 32 BPP (alpha values are ignored) | ||
15 | 2. Uncompressed 24 BPP | ||
16 | 3. Uncompressed 8 BPP (indexed color) | ||
17 | |||
18 | QDBMP is free and open source software, distributed | ||
19 | under the MIT licence. | ||
20 | |||
21 | Copyright (c) 2007 Chai Braudo (braudo@users.sourceforge.net) | ||
22 | |||
23 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
24 | of this software and associated documentation files (the "Software"), to deal | ||
25 | in the Software without restriction, including without limitation the rights | ||
26 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
27 | copies of the Software, and to permit persons to whom the Software is | ||
28 | furnished to do so, subject to the following conditions: | ||
29 | |||
30 | The above copyright notice and this permission notice shall be included in | ||
31 | all copies or substantial portions of the Software. | ||
32 | |||
33 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
34 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
35 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
36 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
37 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
38 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
39 | THE SOFTWARE. | ||
40 | |||
41 | **************************************************************/ | ||
42 | |||
43 | #include <stdio.h> | ||
44 | |||
45 | |||
46 | |||
47 | /* Type definitions */ | ||
48 | #ifndef UINT | ||
49 | #define UINT unsigned long int | ||
50 | #endif | ||
51 | |||
52 | #ifndef USHORT | ||
53 | #define USHORT unsigned short | ||
54 | #endif | ||
55 | |||
56 | #ifndef UCHAR | ||
57 | #define UCHAR unsigned char | ||
58 | #endif | ||
59 | |||
60 | |||
61 | /* Version */ | ||
62 | #define QDBMP_VERSION_MAJOR 1 | ||
63 | #define QDBMP_VERSION_MINOR 0 | ||
64 | #define QDBMP_VERSION_PATCH 1 | ||
65 | |||
66 | |||
67 | /* Error codes */ | ||
68 | typedef enum | ||
69 | { | ||
70 | BMP_OK = 0, /* No error */ | ||
71 | BMP_ERROR, /* General error */ | ||
72 | BMP_OUT_OF_MEMORY, /* Could not allocate enough memory to complete the operation */ | ||
73 | BMP_IO_ERROR, /* General input/output error */ | ||
74 | BMP_FILE_NOT_FOUND, /* File not found */ | ||
75 | BMP_FILE_NOT_SUPPORTED, /* File is not a supported BMP variant */ | ||
76 | BMP_FILE_INVALID, /* File is not a BMP image or is an invalid BMP */ | ||
77 | BMP_INVALID_ARGUMENT, /* An argument is invalid or out of range */ | ||
78 | BMP_TYPE_MISMATCH, /* The requested action is not compatible with the BMP's type */ | ||
79 | BMP_ERROR_NUM | ||
80 | } BMP_STATUS; | ||
81 | |||
82 | |||
83 | /* Bitmap image */ | ||
84 | typedef struct _BMP BMP; | ||
85 | |||
86 | |||
87 | |||
88 | |||
89 | /*********************************** Public methods **********************************/ | ||
90 | |||
91 | |||
92 | /* Construction/destruction */ | ||
93 | BMP* BMP_Create ( UINT width, UINT height, USHORT depth ); | ||
94 | void BMP_Free ( BMP* bmp ); | ||
95 | |||
96 | |||
97 | /* I/O */ | ||
98 | BMP* BMP_ReadFile ( const char* filename ); | ||
99 | void BMP_WriteFile ( BMP* bmp, const char* filename ); | ||
100 | |||
101 | |||
102 | /* Meta info */ | ||
103 | UINT BMP_GetWidth ( BMP* bmp ); | ||
104 | UINT BMP_GetHeight ( BMP* bmp ); | ||
105 | USHORT BMP_GetDepth ( BMP* bmp ); | ||
106 | |||
107 | |||
108 | /* Pixel access */ | ||
109 | void BMP_GetPixelRGB ( BMP* bmp, UINT x, UINT y, UCHAR* r, UCHAR* g, UCHAR* b ); | ||
110 | void BMP_SetPixelRGB ( BMP* bmp, UINT x, UINT y, UCHAR r, UCHAR g, UCHAR b ); | ||
111 | void BMP_GetPixelIndex ( BMP* bmp, UINT x, UINT y, UCHAR* val ); | ||
112 | void BMP_SetPixelIndex ( BMP* bmp, UINT x, UINT y, UCHAR val ); | ||
113 | |||
114 | |||
115 | /* Palette handling */ | ||
116 | void BMP_GetPaletteColor ( BMP* bmp, UCHAR index, UCHAR* r, UCHAR* g, UCHAR* b ); | ||
117 | void BMP_SetPaletteColor ( BMP* bmp, UCHAR index, UCHAR r, UCHAR g, UCHAR b ); | ||
118 | |||
119 | |||
120 | /* Error handling */ | ||
121 | BMP_STATUS BMP_GetError (); | ||
122 | const char* BMP_GetErrorDescription (); | ||
123 | |||
124 | |||
125 | /* Useful macro that may be used after each BMP operation to check for an error */ | ||
126 | #define BMP_CHECK_ERROR( output_file, return_value ) \ | ||
127 | if ( BMP_GetError() != BMP_OK ) \ | ||
128 | { \ | ||
129 | fprintf( ( output_file ), "BMP error: %s\n", BMP_GetErrorDescription() ); \ | ||
130 | return( return_value ); \ | ||
131 | } \ | ||
132 | |||
133 | #endif | ||