Bug fix: Run-time errors when removing a toolbar icon
[geeqie.git] / src / image-load-zxscr.cc
1 /*
2  * Copyright (C) 2021 - The Geeqie Team
3  *
4  * Author: Dusan Gallo
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "main.h"
22
23 #include "image-load.h"
24 #include "image-load-zxscr.h"
25
26 struct ImageLoaderZXSCR {
27         ImageLoaderBackendCbAreaUpdated area_updated_cb;
28         ImageLoaderBackendCbSize size_cb;
29         ImageLoaderBackendCbAreaPrepared area_prepared_cb;
30         gpointer data;
31         GdkPixbuf *pixbuf;
32         guint requested_width;
33         guint requested_height;
34         gboolean abort;
35 };
36
37 const guchar palette[2][8][3] = {
38         {
39                 {0x00, 0x00, 0x00},
40                 {0x00, 0x00, 0xbf},
41                 {0xbf, 0x00, 0x00},
42                 {0xbf, 0x00, 0xbf},
43                 {0x00, 0xbf, 0x00},
44                 {0x00, 0xbf, 0xbf},
45                 {0xbf, 0xbf, 0x00},
46                 {0xbf, 0xbf, 0xbf}
47         }, {
48                 {0x00, 0x00, 0x00},
49                 {0x00, 0x00, 0xff},
50                 {0xff, 0x00, 0x00},
51                 {0xff, 0x00, 0xff},
52                 {0x00, 0xff, 0x00},
53                 {0x00, 0xff, 0xff},
54                 {0xff, 0xff, 0x00},
55                 {0xff, 0xff, 0xff}
56         }
57 };
58
59 static void free_buffer(guchar *pixels, gpointer)
60 {
61         g_free(pixels);
62 }
63
64 static gboolean image_loader_zxscr_load(gpointer loader, const guchar *buf, gsize count, GError **)
65 {
66         auto ld = static_cast<ImageLoaderZXSCR *>(loader);
67         guint8 *pixels;
68         gint width, height;
69         gint row, col, mrow, pxs, i;
70         guint8 attr, bright, ink, paper;
71         guint8 *ptr;
72
73         if (count != 6144 && count != 6912)
74                 {
75                 log_printf("Error: zxscr reader error\n");
76                 return FALSE;
77                 }
78
79         width = 256;
80         height = 192;
81
82         pixels = static_cast<guint8 *>(g_try_malloc(width * height * 3));
83
84         if (!pixels)
85                 {
86                 log_printf("Error: zxscr reader error\n");
87                 return FALSE;
88                 }
89
90         ld->pixbuf = gdk_pixbuf_new_from_data(pixels, GDK_COLORSPACE_RGB, FALSE, 8, width, height, width * 3, free_buffer, nullptr);
91
92         if (!ld->pixbuf)
93                 {
94                 g_free(pixels);
95                 DEBUG_1("Insufficient memory to open ZXSCR file");
96                 return FALSE;
97                 }
98         //let's decode screen
99         for (row = 0; row < 24; row++)
100                 for (col = 0; col < 32; col++)
101                         {
102                         if (count == 6144)
103                                 {
104                                 //if we have pixels only, make default white ink on black paper
105                                 bright = 0x01;
106                                 ink = 0x07;
107                                 paper = 0x00;
108                                 }
109                         else
110                                 {
111                                 attr = buf[6144 + row * 32 + col];
112                                 bright = (attr >> 6) & 0x01;
113                                 ink = attr & 0x07;
114                                 paper = ((attr >> 3) & 0x07);
115                                 }
116                         ptr = pixels + (row * 256 + col) * 8 * 3;
117
118                         for (mrow = 0; mrow < 8; mrow ++)
119                                 {
120                                 pxs = buf[(row / 8) * 2048 + mrow * 256 + (row % 8) * 32 + col];
121                                 for (i = 0; i < 8; i++)
122                                         {
123                                         if (pxs & 0x80)
124                                                 {
125                                                 *ptr++ = palette[bright][ink][0];       //r
126                                                 *ptr++ = palette[bright][ink][1];       //g
127                                                 *ptr++ = palette[bright][ink][2];       //b
128                                                 }
129                                         else
130                                                 {
131                                                 *ptr++ = palette[bright][paper][0];
132                                                 *ptr++ = palette[bright][paper][1];
133                                                 *ptr++ = palette[bright][paper][2];
134                                                 }
135                                         pxs <<= 1;
136                                         }
137                                 ptr += (31 * 8 * 3);
138                                 }
139                         }
140
141         ld->area_updated_cb(loader, 0, 0, width, height, ld->data);
142
143         return TRUE;
144 }
145
146 static gpointer image_loader_zxscr_new(ImageLoaderBackendCbAreaUpdated area_updated_cb, ImageLoaderBackendCbSize size_cb, ImageLoaderBackendCbAreaPrepared area_prepared_cb, gpointer data)
147 {
148         auto loader = g_new0(ImageLoaderZXSCR, 1);
149         loader->area_updated_cb = area_updated_cb;
150         loader->size_cb = size_cb;
151         loader->area_prepared_cb = area_prepared_cb;
152         loader->data = data;
153         return loader;
154 }
155
156 static void image_loader_zxscr_set_size(gpointer loader, int width, int height)
157 {
158         auto ld = static_cast<ImageLoaderZXSCR *>(loader);
159         ld->requested_width = width;
160         ld->requested_height = height;
161 }
162
163 static GdkPixbuf *image_loader_zxscr_get_pixbuf(gpointer loader)
164 {
165         auto ld = static_cast<ImageLoaderZXSCR *>(loader);
166         return ld->pixbuf;
167 }
168
169 static gchar *image_loader_zxscr_get_format_name(gpointer)
170 {
171         return g_strdup("zxscr");
172 }
173
174 static gchar **image_loader_zxscr_get_format_mime_types(gpointer)
175 {
176         static const gchar *mime[] = {"application/octet-stream", nullptr};
177         return g_strdupv(const_cast<gchar **>(mime));
178 }
179
180 static gboolean image_loader_zxscr_close(gpointer, GError **)
181 {
182         return TRUE;
183 }
184
185 static void image_loader_zxscr_abort(gpointer loader)
186 {
187         auto ld = static_cast<ImageLoaderZXSCR *>(loader);
188         ld->abort = TRUE;
189 }
190
191 static void image_loader_zxscr_free(gpointer loader)
192 {
193         auto ld = static_cast<ImageLoaderZXSCR *>(loader);
194         if (ld->pixbuf) g_object_unref(ld->pixbuf);
195         g_free(ld);
196 }
197
198 void image_loader_backend_set_zxscr(ImageLoaderBackend *funcs)
199 {
200         funcs->loader_new = image_loader_zxscr_new;
201         funcs->set_size = image_loader_zxscr_set_size;
202         funcs->load = image_loader_zxscr_load;
203         funcs->write = nullptr;
204         funcs->get_pixbuf = image_loader_zxscr_get_pixbuf;
205         funcs->close = image_loader_zxscr_close;
206         funcs->abort = image_loader_zxscr_abort;
207         funcs->free = image_loader_zxscr_free;
208         funcs->get_format_name = image_loader_zxscr_get_format_name;
209         funcs->get_format_mime_types = image_loader_zxscr_get_format_mime_types;
210 }
211 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */