diff options
Diffstat (limited to 'src/generator.c')
-rw-r--r-- | src/generator.c | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/src/generator.c b/src/generator.c new file mode 100644 index 0000000..b4bec9d --- /dev/null +++ b/src/generator.c @@ -0,0 +1,199 @@ +/* + * generator.c: dictionary generator + * + * Copyright (c) 2013, Přemysl Janouch <p.janouch@gmail.com> + * All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <glib.h> +#include <gio/gio.h> + +#include "stardict.h" +#include "stardict-private.h" +#include "generator.h" + + +/** Creates an output stream for a path plus suffix. */ +static GFileOutputStream * +replace_file_by_suffix (const gchar *base, const gchar *suffix, GError **error) +{ + gchar *full_path = g_strconcat (base, suffix, NULL); + GFile *file = g_file_new_for_path (full_path); + g_free (full_path); + + GFileOutputStream *stream = g_file_replace (file, + NULL, FALSE, G_FILE_CREATE_NONE, NULL, error); + g_object_unref (file); + return stream; +} + +/** Creates a Stardict dictionary generator for the specified base. */ +Generator * +generator_new (const gchar *base, GError **error) +{ + Generator *self = g_malloc0 (sizeof *self); + self->info = g_malloc0 (sizeof *self->info); + self->info->path = g_strconcat (base, ".ifo", NULL); + + self->dict_stream = replace_file_by_suffix (base, ".dict", error); + if (!self->dict_stream) + goto error_dict; + + self->idx_stream = replace_file_by_suffix (base, ".idx", error); + if (!self->idx_stream) + goto error_idx; + + self->dict_data = g_data_output_stream_new + (G_OUTPUT_STREAM (self->dict_stream)); + g_data_output_stream_set_byte_order + (self->dict_data, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN); + + self->idx_data = g_data_output_stream_new + (G_OUTPUT_STREAM (self->idx_stream)); + g_data_output_stream_set_byte_order + (self->idx_data, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN); + + return self; + +error_idx: + g_object_unref (self->dict_stream); +error_dict: + stardict_info_free (self->info); + g_free (self); + return NULL; +} + +/** Finishes the dictionary and writes the .ifo file. */ +gboolean +generator_finish (Generator *self, GError **error) +{ + GString *ifo_contents = g_string_new ("StarDict's dict ifo file\n"); + + if (self->info->version == SD_VERSION_3_0_0) + g_string_append (ifo_contents, "version=3.0.0\n"); + else + g_string_append (ifo_contents, "version=2.4.2\n"); + + self->info->idx_filesize = g_seekable_tell (G_SEEKABLE (self->idx_stream)); + self->info->idx_offset_bits = 32; + + if (!g_output_stream_close + (G_OUTPUT_STREAM (self->dict_stream), NULL, error) + || !g_output_stream_close + (G_OUTPUT_STREAM (self->idx_stream), NULL, error)) + return FALSE; + + guint i; + for (i = 0; i < _stardict_ifo_keys_length; i++) + { + const struct stardict_ifo_key *key = &_stardict_ifo_keys[i]; + if (key->type == IFO_STRING) + { + const gchar *value = G_STRUCT_MEMBER (const gchar *, + self->info, key->offset); + if (value) + g_string_append_printf (ifo_contents, "%s=%s\n", + key->name, value); + } + else + { + gulong value = G_STRUCT_MEMBER (gulong, + self->info, key->offset); + if (value) + g_string_append_printf (ifo_contents, "%s=%lu\n", + key->name, value); + } + } + + gboolean success = g_file_set_contents (self->info->path, + ifo_contents->str, -1, error); + g_string_free (ifo_contents, TRUE); + return success; +} + +/** Start writing a dictionary entry. */ +void +generator_begin_entry (Generator *self) +{ + self->entry_mark = g_seekable_tell (G_SEEKABLE (self->dict_stream)); +} + +/** Write the data type of an entry field, when there's no sametypesequence. */ +gboolean +generator_write_type (Generator *self, gchar type, GError **error) +{ + return g_data_output_stream_put_byte (self->dict_data, type, NULL, error); +} + +/** Write a raw binary field. */ +gboolean +generator_write_raw (Generator *self, + gpointer data, gsize data_size, gboolean mark_end, GError **error) +{ + gsize written; + if ((mark_end && !g_data_output_stream_put_uint32 + (self->dict_data, data_size, NULL, error)) + || !g_output_stream_write_all (G_OUTPUT_STREAM (self->dict_stream), + data, data_size, &written, NULL, error)) + return FALSE; + return TRUE; +} + +/** Write a text string. */ +gboolean +generator_write_string (Generator *self, + const gchar *s, gboolean mark_end, GError **error) +{ + if (!g_data_output_stream_put_string (self->dict_data, s, NULL, error) + || (mark_end && !g_data_output_stream_put_byte + (self->dict_data, '\0', NULL, error))) + return FALSE; + return TRUE; +} + +/** Finishes the current entry and writes it into the index. */ +gboolean +generator_finish_entry (Generator *self, const gchar *word, GError **error) +{ + if (!g_data_output_stream_put_string (self->idx_data, word, NULL, error) + || !g_data_output_stream_put_byte (self->idx_data, '\0', NULL, error) + || !g_data_output_stream_put_uint32 (self->idx_data, + self->entry_mark, NULL, error) + || !g_data_output_stream_put_uint32 (self->idx_data, + g_seekable_tell (G_SEEKABLE (self->dict_stream)) - + self->entry_mark, NULL, error)) + return FALSE; + + self->info->word_count++; + return TRUE; +} + +/** Destroys the generator object, freeing up system resources. */ +void +generator_free (Generator *self) +{ + stardict_info_free (self->info); + + g_object_unref (self->dict_data); + g_object_unref (self->idx_data); + + g_object_unref (self->dict_stream); + g_object_unref (self->idx_stream); +} |