GDS-Render v1.2.1
layer-settings.c
Go to the documentation of this file.
1/*
2 * GDSII-Converter
3 * Copyright (C) 2019 Mario Hüttel <mario.huettel@gmx.net>
4 *
5 * This file is part of GDSII-Converter.
6 *
7 * GDSII-Converter is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * GDSII-Converter 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
17 * along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
18 */
19
27#include <stdlib.h>
28
30 GObject parent;
32 gpointer padding[12];
33};
34
35G_DEFINE_TYPE(LayerSettings, layer_settings, G_TYPE_OBJECT)
36
37static void layer_settings_init(LayerSettings *self)
38{
39 self->layer_infos = NULL;
40}
41
42static void layer_info_delete_with_name(struct layer_info *const info)
43{
44 if (!info)
45 return;
46
47 if (info->name)
48 free(info->name);
49 free(info);
50}
51
52static void layer_settings_dispose(GObject *obj)
53{
54 LayerSettings *self;
55
56 self = GDS_RENDER_LAYER_SETTINGS(obj);
57
58 if (self->layer_infos) {
59 g_list_free_full(self->layer_infos, (GDestroyNotify)layer_info_delete_with_name);
60 self->layer_infos = NULL;
61 }
62
63 G_OBJECT_CLASS(layer_settings_parent_class)->dispose(obj);
64}
65
66static void layer_settings_class_init(LayerSettingsClass *klass)
67{
68 GObjectClass *oclass;
69
70 oclass = G_OBJECT_CLASS(klass);
71 oclass->dispose = layer_settings_dispose;
72
73 return;
74}
75
86static struct layer_info *layer_info_copy(const struct layer_info * const info)
87{
88 struct layer_info *copy;
89
90 if (!info)
91 return 0;
92
93 copy = (struct layer_info *)malloc(sizeof(struct layer_info));
94 if (!copy)
95 return 0;
96
97 /* Copy data */
98 memcpy(copy, info, sizeof(struct layer_info));
99 /* Duplicate string */
100 if (info->name)
101 copy->name = strdup(info->name);
102
103 return copy;
104}
105
106LayerSettings *layer_settings_new()
107{
108 return g_object_new(GDS_RENDER_TYPE_LAYER_SETTINGS, NULL);
109}
110
111int layer_settings_append_layer_info(LayerSettings *settings, struct layer_info *info)
112{
113 struct layer_info *info_copy;
114
115 g_return_val_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings), -1);
116 if (!info)
117 return -2;
118
119 /* Copy layer info */
120 info_copy = layer_info_copy(info);
121
122 /* Append to list */
123 settings->layer_infos = g_list_append(settings->layer_infos, info_copy);
124
125 return (settings->layer_infos ? 0 : -3);
126}
127
128void layer_settings_clear(LayerSettings *settings)
129{
130 g_return_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings));
131
132 /* Clear list and delete layer_info structs including the name field */
133 g_list_free_full(settings->layer_infos, (GDestroyNotify)layer_info_delete_with_name);
134 settings->layer_infos = NULL;
135}
136
137int layer_settings_remove_layer(LayerSettings *settings, int layer)
138{
139 GList *list_iter;
140 GList *found = NULL;
141 struct layer_info *inf;
142
143 g_return_val_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings), -1);
144
145 /* Find in list */
146 for (list_iter = settings->layer_infos; list_iter; list_iter = list_iter->next) {
147 inf = (struct layer_info *)list_iter->data;
148
149 if (!inf)
150 continue;
151 if (inf->layer == layer)
152 found = list_iter;
153 }
154
155 if (found) {
156 /* Free the layer_info struct */
157 layer_info_delete_with_name((struct layer_info *)found->data);
158 /* Delete the list element */
159 settings->layer_infos = g_list_delete_link(settings->layer_infos, found);
160 return 0;
161 }
162
163 return -2;
164}
165
166GList *layer_settings_get_layer_info_list(LayerSettings *settings)
167{
168 g_return_val_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings), NULL);
169 return settings->layer_infos;
170}
171
177static void layer_settings_gen_csv_line(GString *string, struct layer_info *linfo)
178{
179 int i;
180
181 g_string_printf(string, "%d:%lf:%lf:%lf:%lf:%d:%s\n",
182 linfo->layer, linfo->color.red, linfo->color.green,
183 linfo->color.blue, linfo->color.alpha, (linfo->render ? 1 : 0), linfo->name);
184 /* Fix broken locale settings */
185 for (i = 0; string->str[i]; i++) {
186 if (string->str[i] == ',')
187 string->str[i] = '.';
188 }
189
190 for (i = 0; string->str[i]; i++) {
191 if (string->str[i] == ':')
192 string->str[i] = ',';
193 }
194}
195
196int layer_settings_to_csv(LayerSettings *settings, const char *path)
197{
198 GFile *file;
199 GOutputStream *w_fstream;
200 GString *string;
201 GList *info_iter;
202 struct layer_info *linfo;
203 int ret = 0;
204
205 file = g_file_new_for_path(path);
206 w_fstream = G_OUTPUT_STREAM(g_file_replace(file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL));
207 if (!w_fstream) {
208 ret = -1;
209 goto ret_unref_file;
210 }
211
212 /* Allocate new working buffer string. A size bigger than 200 is unexpected, but possible
213 * 200 is a tradeoff between memory usage and preventing the necessity of realloc'ing the string
214 */
215 string = g_string_new_len(NULL, 200);
216 if (!string) {
217 ret = -2;
218 goto ret_close_file;
219 }
220
221 /* Loop over layers and write CSV lines */
222 for (info_iter = settings->layer_infos; info_iter; info_iter = info_iter->next) {
223 linfo = (struct layer_info *)info_iter->data;
224
225 layer_settings_gen_csv_line(string, linfo);
226 g_output_stream_write(w_fstream, string->str, string->len * sizeof(gchar), NULL, NULL);
227 }
228
229 /* Delete string */
230 g_string_free(string, TRUE);
231ret_close_file:
232 g_output_stream_flush(w_fstream, NULL, NULL);
233 g_output_stream_close(w_fstream, NULL, NULL);
234 g_object_unref(w_fstream);
235ret_unref_file:
236 g_object_unref(file);
237
238 return ret;
239}
240
247static int layer_settings_load_csv_line_from_stream(GDataInputStream *stream, struct layer_info *linfo)
248{
249 int ret;
250 gsize len;
251 gchar *line;
252 GRegex *regex;
253 GMatchInfo *mi;
254 char *match;
255
256 if (!linfo) {
257 ret = 1;
258 goto ret_direct;
259 }
260
261 regex = g_regex_new("^(?<layer>[0-9]+),(?<r>[0-9\\.]+),(?<g>[0-9\\.]+),(?<b>[0-9\\.]+),(?<a>[0-9\\.]+),(?<export>[01]),(?<name>.*)$", 0, 0, NULL);
262
263 line = g_data_input_stream_read_line(stream, &len, NULL, NULL);
264 if (!line) {
265 ret = -1;
266 goto destroy_regex;
267 }
268
269 /* Match line in CSV */
270 g_regex_match(regex, line, 0, &mi);
271 if (g_match_info_matches(mi)) {
272 /* Line is valid */
273 match = g_match_info_fetch_named(mi, "layer");
274 linfo->layer = (int)g_ascii_strtoll(match, NULL, 10);
275 g_free(match);
276 match = g_match_info_fetch_named(mi, "r");
277 linfo->color.red = g_ascii_strtod(match, NULL);
278 g_free(match);
279 match = g_match_info_fetch_named(mi, "g");
280 linfo->color.green = g_ascii_strtod(match, NULL);
281 g_free(match);
282 match = g_match_info_fetch_named(mi, "b");
283 linfo->color.blue = g_ascii_strtod(match, NULL);
284 g_free(match);
285 match = g_match_info_fetch_named(mi, "a");
286 linfo->color.alpha = g_ascii_strtod(match, NULL);
287 g_free(match);
288 match = g_match_info_fetch_named(mi, "export");
289 linfo->render = ((!strcmp(match, "1")) ? 1 : 0);
290 g_free(match);
291 match = g_match_info_fetch_named(mi, "name");
292 linfo->name = match;
293
294 ret = 0;
295 } else {
296 /* Line is malformatted */
297 printf("Could not recognize line in CSV as valid entry: %s\n", line);
298 ret = 1;
299 }
300
301 g_match_info_free(mi);
302 g_free(line);
303destroy_regex:
304 g_regex_unref(regex);
305ret_direct:
306 return ret;
307
308}
309
310int layer_settings_load_from_csv(LayerSettings *settings, const char *path)
311{
312 GFile *file;
313 int ret = 0;
314 GInputStream *in_stream;
315 GDataInputStream *data_stream;
316 int parser_ret;
317 int stacked_pos;
318 struct layer_info linfo;
319
320 file = g_file_new_for_path(path);
321 in_stream = G_INPUT_STREAM(g_file_read(file, NULL, NULL));
322
323 g_return_val_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings), -2);
324
325 if (!in_stream) {
326 ret = -1;
327 goto ret_destroy_file;
328 }
329 /* Delete old settings */
330 layer_settings_clear(settings);
331
332 data_stream = g_data_input_stream_new(in_stream);
333
334 stacked_pos = 0;
335 while ((parser_ret = layer_settings_load_csv_line_from_stream(data_stream, &linfo)) >= 0) {
336 /* Line broken */
337 if (parser_ret == 1)
338 continue;
339
340 linfo.stacked_position = stacked_pos++;
341
342 layer_settings_append_layer_info(settings, &linfo);
343 /* Clear name to prevent memory leak */
344 if (linfo.name)
345 g_free(linfo.name);
346 }
347
348 g_object_unref(data_stream);
349 g_object_unref(in_stream);
350ret_destroy_file:
351 g_object_unref(file);
352
353 return ret;
354}
void layer_settings_clear(LayerSettings *settings)
Clear all layers in this settings object.
int layer_settings_to_csv(LayerSettings *settings, const char *path)
Write layer settings to a CSV file.
static struct layer_info * layer_info_copy(const struct layer_info *const info)
Copy layer_info struct.
LayerSettings * layer_settings_new()
New LayerSettings object.
static void layer_settings_class_init(LayerSettingsClass *klass)
static int layer_settings_load_csv_line_from_stream(GDataInputStream *stream, struct layer_info *linfo)
Load a line from stream and parse try to parse it as layer information.
GList * layer_settings_get_layer_info_list(LayerSettings *settings)
Get a GList with layer_info structs.
int layer_settings_load_from_csv(LayerSettings *settings, const char *path)
Load new layer Settings from CSV.
static void layer_settings_gen_csv_line(GString *string, struct layer_info *linfo)
Generate a layer mapping CSV line for a given layer_info struct.
int layer_settings_remove_layer(LayerSettings *settings, int layer)
Remove a specific layer number from the layer settings.
static void layer_settings_init(LayerSettings *self)
static void layer_info_delete_with_name(struct layer_info *const info)
int layer_settings_append_layer_info(LayerSettings *settings, struct layer_info *info)
layer_settings_append_layer_info
static void layer_settings_dispose(GObject *obj)
LayerSettings class header file.
#define GDS_RENDER_TYPE_LAYER_SETTINGS
GList * layer_infos
gpointer padding[12]
Layer information.
int render
true: Render to output
char * name
Layer name.
int stacked_position
Position of layer in output.
GdkRGBA color
RGBA color used to render this layer.
int layer
Layer number.