WORDWRAP *wordwrap_new_wrapper(size_t line_length, void (*wrapped_text_output_destination)(z_ucs *output, void *parameter), void *destination_parameter, bool add_newline_after_full_line, int left_side_padding, bool flush_after_newline, bool enable_hyphenation) { WORDWRAP *result = fizmo_malloc(sizeof(WORDWRAP)); int i; result->line_length = line_length; result->wrapped_text_output_destination = wrapped_text_output_destination; result->destination_parameter = destination_parameter; result->add_newline_after_full_line = add_newline_after_full_line; result->left_side_padding = left_side_padding; if (left_side_padding > 0) { result->padding_buffer = fizmo_malloc((left_side_padding + 1) * sizeof(z_ucs)); for (i=0; i<left_side_padding; i++) result->padding_buffer[i] = Z_UCS_SPACE; result->padding_buffer[i] = 0; } else result->padding_buffer = NULL; result->flush_after_newline = flush_after_newline; result->enable_hyphenation = enable_hyphenation; result->input_buffer_size = line_length * 4; result->input_buffer = fizmo_malloc(sizeof(z_ucs)*result->input_buffer_size); result->input_index = 0; result->chars_already_on_line = 0; result->metadata = NULL; result->metadata_size = 0; result->metadata_index = 0; return result; }
true_type_wordwrapper *create_true_type_wordwrapper(true_type_font *font, int line_length, void (*wrapped_text_output_destination)(z_ucs *output, void *parameter), void *destination_parameter, bool hyphenation_enabled) { true_type_wordwrapper *result = fizmo_malloc(sizeof(true_type_wordwrapper)); result->line_length = line_length; result->input_buffer = NULL; result->input_buffer_size = 0; result->current_buffer_index = 0; freetype_wordwrap_reset_position(result); result->wrapped_text_output_destination = wrapped_text_output_destination; result->destination_parameter = destination_parameter; result->enable_hyphenation = hyphenation_enabled; result->metadata = NULL; result->metadata_size = 0; result->metadata_index = 0; result->font_at_buffer_start = font; set_font(result, font); TRACE_LOG("Created new wordwrapper %p with line length %d.\n", result, line_length); return result; }
true_type_factory *create_true_type_factory(char *font_search_path) { true_type_factory *result; int ft_error; result = (true_type_factory*)fizmo_malloc(sizeof(true_type_factory)); if ((ft_error = FT_Init_FreeType(&result->ftlibrary))) { i18n_translate_and_exit( libpixelif_module_name, i18n_libpixelif_FUNCTION_CALL_P0S_ABORTED_DUE_TO_ERROR, -1, "FT_Init_FreeType"); } if ((ft_error = FT_Library_SetLcdFilter( result->ftlibrary, FT_LCD_FILTER_DEFAULT))) { result->render_mode = FT_RENDER_MODE_NORMAL; } else { result->render_mode = FT_RENDER_MODE_LCD; } result->font_search_path = strdup(font_search_path); TRACE_LOG("factory path: %s\n", result->font_search_path); return result; }
struct babel_info *load_babel_info_from_blorb(z_file *infile, int length, char *filename, time_t last_mod_timestamp) { struct babel_info *result; char *xmlData = (char*)fizmo_malloc(length + 1); xmlDocPtr babel_doc; if (fsi->readchars(xmlData, length, infile) != (size_t)length) { free(xmlData); return NULL; } xmlData[length] = '\0'; babel_doc = xmlReadDoc( (xmlChar*)xmlData, NULL, NULL, XML_PARSE_NOWARNING | XML_PARSE_NOERROR); free(xmlData); if (babel_doc == NULL) return NULL; result = (struct babel_info*)fizmo_malloc(sizeof(struct babel_info)); result->entries = NULL; result->entries_allocated = 0; result->nof_entries = 0; if (add_doc_to_babel_info(babel_doc, result, last_mod_timestamp, filename) != 0) { xmlFreeDoc(babel_doc); free(result); return NULL; } return result; }
int append_path_value(char *key, char *value_to_append) { char *str, *str2; int result; if ((str = get_configuration_value(key)) != NULL) { str2 = fizmo_malloc(strlen(str) + strlen(value_to_append) + 2); strcpy(str2, str); strcat(str2, ":"); strcat(str2, value_to_append); TRACE_LOG("Appended path: %s.\n", str2); result = set_configuration_value(key, str2); free(str2); return result; } else return set_configuration_value(key, value_to_append); }
true_type_font *create_true_type_font(true_type_factory *factory, char *font_filename, int pixel_size, int line_height) { int ft_error; z_file *fontfile; char *token, *filename, *path_copy; FT_Open_Args *openArgs; FT_Stream stream; long filesize; true_type_font *result; if (factory->font_search_path == NULL) return NULL; TRACE_LOG("Loading font %s\n", font_filename); path_copy = strdup(factory->font_search_path); token = strtok(path_copy, ":"); fontfile = NULL; while (token) { if ((filename = find_file_recursively(token, font_filename)) != NULL) { fontfile = fsi->openfile(filename, FILETYPE_DATA, FILEACCESS_READ); free(filename); if (fontfile != NULL) { break; } } /* filename = fizmo_malloc(strlen(token) + strlen(font_filename) + 2); strcpy(filename, token); strcat(filename, "/"); strcat(filename, font_filename); if ((fontfile = fsi->openfile(filename, FILETYPE_DATA, FILEACCESS_READ)) != NULL) { free(filename); break; } free(filename); */ token = strtok(NULL, ":"); } free(path_copy); if (fontfile == NULL) { TRACE_LOG("Font %s not found.\n", font_filename); return NULL; } fsi->setfilepos(fontfile, 0, SEEK_END); filesize = fsi->getfilepos(fontfile); fsi->setfilepos(fontfile, 0, SEEK_SET); openArgs = (FT_Open_Args *)fizmo_malloc(sizeof(FT_Open_Args)); stream = (FT_Stream)fizmo_malloc(sizeof(FT_StreamRec)); openArgs->flags = FT_OPEN_STREAM; openArgs->stream = stream; openArgs->stream->base = NULL; openArgs->stream->size = filesize; openArgs->stream->pos = 0; openArgs->stream->descriptor.pointer = fontfile; openArgs->stream->pathname.pointer = NULL; openArgs->stream->read = read_ft_stream; openArgs->stream->close = close_ft_stream; result = (true_type_font*)fizmo_malloc(sizeof(true_type_font)); ft_error = FT_Open_Face(factory->ftlibrary, openArgs, 0, &result->face); if ( ft_error == FT_Err_Unknown_File_Format ) { // ... the font file could be opened and read, but it appears // ... that its font format is unsupported return NULL; } else if ( ft_error ) { // ... another ft_error code means that the font file could not // ... be opened or read, or simply that it is broken... return NULL; } //free(stream), //free(openArgs); result->font_height_in_pixel = pixel_size; result->line_height = line_height; result->render_mode = factory->render_mode; result->glyph_size_cache = NULL; result->glyph_size_cache_size = 0; ft_error = FT_Set_Pixel_Sizes( result->face, 0, pixel_size); //result->has_kerning = FT_HAS_KERNING(result->face); return result; }
static int detect_and_add_z_file(char *filename, char *blorb_filename, struct babel_info *babel, struct z_story_list *story_list) { z_file *infile; uint8_t buf[30]; uint32_t val; char serial[7]; int version; uint16_t checksum; uint16_t release; struct babel_story_info *b_info = NULL; char *title; char *author; char *language; char *description; char *ptr, *ptr2; int length; time_t storyfile_timestamp; char *empty_string = ""; struct z_story_list_entry *entry; int chunk_length = -1; struct babel_info *file_babel = NULL; bool file_is_zblorb; char *cwd = NULL; char *abs_filename = NULL; if (filename == NULL) return -1; if (filename[0] != '/') { cwd = fsi->get_cwd(); abs_filename = fizmo_malloc(strlen(cwd) + strlen(filename) + 2); sprintf(abs_filename, "%s/%s", cwd, filename); } else abs_filename = filename; if ((infile = fsi->openfile(abs_filename, FILETYPE_DATA, FILEACCESS_READ)) == NULL) { if (cwd != NULL) { free(cwd); free(abs_filename); } return -1; } if ((storyfile_timestamp = fsi->get_last_file_mod_timestamp(infile)) < 0) { fsi->closefile(infile); if (cwd != NULL) { free(cwd); free(abs_filename); } return -1; } if (fsi->readchars(buf, 30, infile) != 30) { fsi->closefile(infile); if (cwd != NULL) { free(cwd); free(abs_filename); } return -1; } if (memcmp(buf, "FORM", 4) == 0) { // IFF file. if ( (is_form_type(infile, "IFRS") != true) || (find_chunk("ZCOD", infile) == -1) ) { fsi->closefile(infile); if (cwd != NULL) { free(cwd); free(abs_filename); } return -1; } file_is_zblorb = true; if (find_chunk("IFmd", infile) == 0) { read_chunk_length(infile); chunk_length = get_last_chunk_length(); file_babel = load_babel_info_from_blorb( infile, chunk_length, abs_filename, storyfile_timestamp); babel = file_babel; } find_chunk("ZCOD", infile); read_chunk_length(infile); length = get_last_chunk_length(); if (fsi->readchars(buf, 30, infile) != 30) { fsi->closefile(infile); if (cwd != NULL) { free(cwd); free(abs_filename); } return -1; } } else { fsi->setfilepos(infile, 0, SEEK_END); length = fsi->getfilepos(infile); file_is_zblorb = false; } fsi->closefile(infile); val = (buf[16] << 24) | (buf[17] << 16) | (buf[18] << 8) | (buf[19]); if ( ((val & 0xbe00f0f0) != 0x3030) || (*buf < 1) || (*buf > 8) ) { if (cwd != NULL) { free(cwd); free(abs_filename); } return -2; } version = *buf; memcpy(serial, buf + 0x12, 6); serial[6] = '\0'; checksum = (buf[0x1c] << 8) | buf[0x1d]; release = (buf[2] << 8) | buf[3]; if ((entry = get_z_story_entry(serial, release, length, story_list)) != NULL) { // We already have the story in our story-list. If we have a raw file // we can just quit if the support-blorbfilename is the same (raw files // don't contain metadata which might have changed). if ( (file_is_zblorb == false) && ( ( (entry->blorbfile == NULL) && (blorb_filename != NULL) ) // || (Don't delete blorb file) // ( (blorb_filename == NULL) && (entry->blorbfile != NULL) ) || ( (entry->blorbfile != NULL) && (blorb_filename != NULL) && (strcmp(blorb_filename, entry->blorbfile) == 0) ) ) ) { if (cwd != NULL) { free(cwd); free(abs_filename); } return -3; } //printf("%ld / %ld\n", storyfile_timestamp, entry->storyfile_timestamp); // In case new file is a zblorb and we have save a raw file, remove the // raw and keep the blorb (so we can get images and sound). We'll also // re-read the file contents if the file has changed (metadata might // have been altered). if ( (strcmp(entry->filetype, filetype_raw) == 0) || (storyfile_timestamp > entry->storyfile_timestamp) ) { remove_entry_from_list(story_list, entry); //printf("%s...\n", abs_filename); } else { if (cwd != NULL) { free(cwd); free(abs_filename); } return -4; } } ptr2 = NULL; if ((b_info = get_babel_story_info( release, serial, checksum, babel, file_is_zblorb)) != NULL) { title = (b_info->title == NULL ? empty_string : b_info->title); author = (b_info->author == NULL ? empty_string : b_info->author); language = (b_info->language == NULL ? empty_string : b_info->language); description = (b_info->description != NULL) ? b_info->description : empty_string; } else { if ((title = strrchr(abs_filename, '/')) == NULL) title = abs_filename; else title++; if ((ptr = strrchr(title, '.')) != NULL) { TRACE_LOG("strdup: %s\n", title); ptr2 = fizmo_strdup(title); ptr = strrchr(ptr2, '.'); if ( ( (strlen(ptr) == 3) && (ptr[1] == 'z') && (isdigit(ptr[2]) != 0) ) || (strcasecmp(ptr, ".dat") == 0) || (strcasecmp(ptr, ".zblorb") == 0) ) *ptr = '\0'; *ptr2 = toupper(*ptr2); title = ptr2; } author = empty_string; language = empty_string; description = empty_string; } add_entry_to_story_list( story_list, title, author, language, description, serial, version, length, checksum, release, abs_filename, file_is_zblorb ? NULL : blorb_filename, file_is_zblorb ? filetype_zblorb : filetype_raw, storyfile_timestamp); if (b_info != NULL) free_babel_story_info(b_info); if (ptr2 != NULL) free(ptr2); if (file_babel != NULL) free_babel_info(file_babel); if (cwd != NULL) { free(cwd); free(abs_filename); } return 0; }
struct babel_info *load_babel_info() { struct babel_info *result = NULL; #ifndef DISABLE_BABEL char *cwd = NULL; char *config_dir_name = NULL; z_dir *config_dir; struct z_dir_ent z_dir_entry; time_t last_mod_timestamp; z_file *new_babel_doc_file; xmlDocPtr new_babel_doc; #ifndef DISABLE_CONFIGFILES config_dir_name = get_fizmo_config_dir_name(); #endif // DISABLE_CONFIGFILES if ((config_dir = fsi->open_dir(config_dir_name)) == NULL) return NULL; cwd = fsi->get_cwd(); if (fsi->ch_dir(config_dir_name) != 0) { fsi->close_dir(config_dir); free(cwd); return NULL; } result = (struct babel_info*)fizmo_malloc(sizeof(struct babel_info)); result->entries = NULL; result->entries_allocated = 0; result->nof_entries = 0; while (fsi->read_dir(&z_dir_entry, config_dir) == 0) { if ( (fsi->is_filename_directory(z_dir_entry.d_name) == false) && (strlen(z_dir_entry.d_name) >= 9) && (strcasecmp( z_dir_entry.d_name + strlen(z_dir_entry.d_name) - 9, ".iFiction") == 0) ) { if ((new_babel_doc = xmlReadFile( z_dir_entry.d_name, NULL, XML_PARSE_NOWARNING | XML_PARSE_NOERROR)) != NULL) { if ((new_babel_doc_file = fsi->openfile( z_dir_entry.d_name, FILETYPE_DATA, FILEACCESS_READ)) == NULL) { free_babel_info(result); fsi->ch_dir(cwd); free(cwd); fsi->close_dir(config_dir); return NULL; } last_mod_timestamp = fsi->get_last_file_mod_timestamp(new_babel_doc_file); fsi->closefile(new_babel_doc_file); if ((add_doc_to_babel_info( new_babel_doc, result, last_mod_timestamp, z_dir_entry.d_name)) != 0) { xmlFreeDoc(new_babel_doc); free_babel_info(result); fsi->ch_dir(cwd); free(cwd); fsi->close_dir(config_dir); return NULL; } } } } fsi->ch_dir(cwd); free(cwd); fsi->close_dir(config_dir); #endif return result; }
static int add_doc_to_babel_info(xmlDocPtr new_babel_doc, struct babel_info *babel, time_t last_mod_timestamp, char *filename) { xmlXPathContextPtr xpathCtx; xmlXPathObjectPtr xpathObj; char *xmlExpr = "/ifindex"; char *xmlNamespacedExpr = "/if:ifindex"; bool uses_if_namespace; struct babel_doc_entry *new_entry; // Check contents xpathCtx = xmlXPathNewContext(new_babel_doc); if(xpathCtx == NULL) { fprintf(stderr,"Error: unable to create new XPath context\n"); return -1; } if (xmlXPathRegisterNs( xpathCtx, (xmlChar*)"if", (xmlChar*)"http://babel.ifarchive.org/protocol/iFiction/") == -1) { fprintf(stderr,"Error: unable to create new namespace\n"); xmlXPathFreeContext(xpathCtx); return -1; } xpathObj = xmlXPathEvalExpression((xmlChar*)xmlExpr, xpathCtx); if (xpathObj == NULL) { xmlXPathFreeContext(xpathCtx); fprintf( stderr, "Error: unable to evaluate xpath expression \"%s\"\n", xmlExpr); return -1; } if (xmlXPathNodeSetGetLength(xpathObj->nodesetval) != 1) { // "/ifindex" was not found. Try "/if:ifindex". xmlXPathFreeObject(xpathObj); xpathObj = xmlXPathEvalExpression( (xmlChar*)xmlNamespacedExpr, xpathCtx); if (xpathObj == NULL) { xmlXPathFreeContext(xpathCtx); fprintf( stderr, "Error: unable to evaluate xpath expression \"%s\"\n", xmlNamespacedExpr); return -1; } if (xmlXPathNodeSetGetLength(xpathObj->nodesetval) != 1) { // Neither "/ifindex" nor "/if:ifindex" found. Skip this file. xmlXPathFreeObject(xpathObj); xmlXPathFreeContext(xpathCtx); return -1; } else uses_if_namespace = true; } else uses_if_namespace = false; xmlXPathFreeObject(xpathObj); xmlXPathFreeContext(xpathCtx); if (babel->nof_entries == babel->entries_allocated) { babel->entries = (struct babel_doc_entry**)fizmo_realloc( babel->entries, sizeof(struct babel_doc_entry*) * (babel->entries_allocated+10)); babel->entries_allocated += 10; } new_entry = (struct babel_doc_entry*)fizmo_malloc( sizeof(struct babel_doc_entry)); new_entry->babel_doc = new_babel_doc; new_entry->uses_if_namespace = uses_if_namespace; new_entry->timestamp = last_mod_timestamp; new_entry->filename = fizmo_strdup(filename); babel->entries[babel->nof_entries] = new_entry; babel->nof_entries++; return 0; }
static z_blorb_map *fizmo_blorb_init(z_file *blorb_file) { z_blorb_map *result_wrapper; fizmo_blorb_map *result; fizmo_blorb *blorb; int resource_chunk_size; char buf[5]; int nof_resources, nof_loops, blorb_index, resource_number; if (find_chunk("RIdx", blorb_file) == -1) { fsi->closefile(blorb_file); return NULL; } if (read_chunk_length(blorb_file) == -1) i18n_translate_and_exit( libfizmo_module_name, i18n_libfizmo_FUNCTION_CALL_P0S_RETURNED_ERROR_CODE_P1D, -0x0101, "read_chunk_length", errno); result = fizmo_malloc(sizeof(fizmo_blorb_map)); result->blorb_file = blorb_file; result_wrapper = fizmo_malloc(sizeof(z_blorb_map)); result_wrapper->blorb_map_implementation = result; resource_chunk_size = get_last_chunk_length(); nof_resources = (resource_chunk_size - 4) / 12; // Skip next number of resources. if ((fsi->setfilepos(result->blorb_file, 4, SEEK_CUR)) != 0) i18n_translate_and_exit( libfizmo_module_name, i18n_libfizmo_FUNCTION_CALL_P0S_RETURNED_ERROR_CODE_P1D, -0x0101, "setfilepos", errno); TRACE_LOG("Number of resources in blorb file: %d.\n", nof_resources); // Count number of images and sounds. result->blorbs = fizmo_malloc(sizeof(fizmo_blorb*) * (nof_resources+1)); buf[4] = '\0'; blorb_index = 0; while (nof_resources > 0) { blorb = fizmo_malloc(sizeof(fizmo_blorb)); if (fsi->readchars(buf, 4, result->blorb_file) != 4) i18n_translate_and_exit( libfizmo_module_name, i18n_libfizmo_FUNCTION_CALL_P0S_ABORTED_DUE_TO_ERROR, -0x0106, "readchars"); TRACE_LOG("Type descriptor: %s\n", buf); if (strcmp(buf, "Pict") == 0) blorb->type = Z_BLORB_TYPE_PICT; else if (strcmp(buf, "Snd ") == 0) blorb->type = Z_BLORB_TYPE_SOUND; else if (strcmp(buf, "Exec") == 0) blorb->type = Z_BLORB_TYPE_EXEC; else // Unknown resource. i18n_translate_and_exit( libfizmo_module_name, i18n_libfizmo_UNKNOWN_ERROR_CASE, -1); blorb->resource_number = read_four_byte_number(result->blorb_file); blorb->offset = read_four_byte_number(result->blorb_file) + 8; blorb->v3_number_of_loops = -1; result->blorbs[blorb_index++] = blorb; nof_resources--; } result->blorbs[blorb_index] = NULL; if (find_chunk("Fspc", result->blorb_file) == 0) { if ((fsi->setfilepos(result->blorb_file, 4, SEEK_CUR)) != 0) i18n_translate_and_exit( libfizmo_module_name, i18n_libfizmo_FUNCTION_CALL_P0S_RETURNED_ERROR_CODE_P1D, -0x0101, "setfilepos", errno); result->frontispiece_image_no = read_four_byte_number(result->blorb_file); } else result->frontispiece_image_no = -1; if (ver < 5) { if (find_chunk("Loop", result->blorb_file) == 0) { nof_resources = read_four_byte_number(result->blorb_file) / 8; TRACE_LOG("Number of loop entries: %d.\n", nof_resources); while (nof_resources > 0) { resource_number = read_four_byte_number(result->blorb_file); nof_loops = read_four_byte_number(result->blorb_file); TRACE_LOG("Trying to find resource #%d.\n", resource_number); if ((blorb = fizmo_get_blorb( result_wrapper, Z_BLORB_TYPE_SOUND, resource_number)) != NULL) { TRACE_LOG("Resource found, setting nof_loops to %d.\n", nof_loops); blorb->v3_number_of_loops = nof_loops; } nof_resources--; } } } return result_wrapper; }
static char *expand_configuration_value(char *unexpanded_value) { static char *homedir; static int homedir_len; char *ptr = unexpanded_value; int resultlen; char *result, *resultindex; char *var_name; char buf; if (unexpanded_value == NULL) return NULL; if ((homedir = get_user_homedir()) == NULL) homedir = empty_string; homedir_len = strlen(homedir); TRACE_LOG("Value to expand: \"%s\".\n", unexpanded_value); resultlen = 0; while (*ptr != 0) { if (*ptr == '$') { ptr++; if (*ptr == '(') { ptr++; var_name = ptr; while ( (*ptr != 0) && (*ptr != ')') ) ptr++; if (*ptr != ')') return NULL; buf = *ptr; *ptr = 0; if (strcmp(var_name, "HOME") == 0) { resultlen += strlen(homedir); } else { *ptr = buf; return NULL; } *ptr = buf; ptr++; } else return NULL; } else { ptr++; resultlen++; } } TRACE_LOG("result len: %d.\n", resultlen); result = fizmo_malloc(resultlen + 1); resultindex = result; ptr = unexpanded_value; while (*ptr != 0) { if (*ptr == '$') { ptr++; if (*ptr == '(') { ptr++; var_name = ptr; while ( (*ptr != 0) && (*ptr != ')') ) ptr++; if (*ptr != ')') { free(result); return NULL; } buf = *ptr; *ptr = 0; if (strcmp(var_name, "HOME") == 0) { strcpy(resultindex, homedir); resultindex += homedir_len; } else { *ptr = buf; // Can't ever reach this point due to loop 1. } *ptr = buf; ptr++; } } else { *resultindex = *ptr; ptr++; resultindex++; } } *resultindex = 0; TRACE_LOG("result expanded value: %s / %p.\n", result, result); return result; }