#include "main.h" GList *error_lines = NULL; /* Saves a subtitle of format 'filetype' to file 'filename' and eventually * stops after 'max_rows' (set to -1 to disable */ int gse_fl_write_file (char *filename, gint filetype, gint max_rows) { FILE *fl; gchar line[BUF_LEN], msg[100], *tmp[4], converted[4][20]; GtkWidget *msgbox; gint i, col, hr, min, sec, msec; gdouble tot_sec; if (*filename == '\0' || (fl = fopen (filename, "w")) == NULL) { g_snprintf (msg, 100, _("Unable to open file '%s' for writing!\nTry 'Save As..' and select another filename"), current_open_file); msgbox = gnome_message_box_new (msg, GNOME_MESSAGE_BOX_ERROR, GNOME_STOCK_BUTTON_OK, NULL); gnome_dialog_run_and_close (GNOME_DIALOG (msgbox)); return GSE_FILE_ERROR_OPEN_W; } if (filetype == GSE_SUBT_MICRODVD) { if (max_rows == GSE_NO_SPLIT) max_rows = GTK_CLIST (mwin_clist)->rows; for (i = 0; i < max_rows; i++) { for (col = 1; col < 4; col++) { gtk_clist_get_text (GTK_CLIST (mwin_clist), i, col, &(tmp[col])); /* We might need to convert from time-mode to frame-mode */ if (cur_open_file.filetype == GSE_SUBT_SUBRIPPER && (col == 1 || col == 2)) { if (gse_str_to_time (tmp[col], &hr, &min, &sec, &msec) < 0) return -1; g_snprintf (converted[col], BUF_LEN, "%ld", (glong) gse_time_to_frame (glob_fps, hr, min, sec, msec)); tmp[col] = converted[col]; } } g_snprintf (line, BUF_LEN, "{%s}{%s}%s\n", tmp[1], tmp[2], tmp[3]); fputs (line, fl); } } else if (filetype == GSE_SUBT_SUBRIPPER) /* Damn stupid file format! */ { if (max_rows == GSE_NO_SPLIT) max_rows = GTK_CLIST (mwin_clist)->rows; for (i = 0; i < max_rows; i++) { for (col = 0; col < 4; col++) { gtk_clist_get_text (GTK_CLIST (mwin_clist), i, col, &(tmp[col])); /* Merge column 1 and 2 into one string */ if (col == 1) { gtk_clist_get_text (GTK_CLIST (mwin_clist), i, col + 1, &(tmp[col + 1])); /* We might need to convert from frame-mode to time-mode */ if (cur_open_file.filetype == GSE_SUBT_MICRODVD) { tot_sec = gse_frame_to_time (glob_fps, atoi (tmp[1])); gse_parse_time (tot_sec, &hr, &min, &sec, &msec); g_snprintf (converted[1], BUF_LEN, "%.2d:%.2d:%.2d,%.3d", hr, min, sec, msec); tot_sec = gse_frame_to_time (glob_fps, atoi (tmp[2])); gse_parse_time (tot_sec, &hr, &min, &sec, &msec); g_snprintf (converted[2], BUF_LEN, "%.2d:%.2d:%.2d,%.3d", hr, min, sec, msec); g_snprintf (converted[0], BUF_LEN, "%s --> %s", converted[1], converted[2]); } else g_snprintf (converted[0], BUF_LEN, "%s --> %s", tmp[1], tmp[2]); col++; tmp[col] = converted[0]; } else if (col == 3) { g_snprintf (converted[0], BUF_LEN, "%s", tmp[col]); g_strdelimit (converted[0], "|", '\n'); tmp[col] = converted[0]; } fprintf (fl, "%s\n", tmp[col]); } fputc ('\n', fl); } } fclose (fl); if (cur_open_file.filename != filename) /* We don't want to free cur_open_file.filename if it points to the same as 'filename' */ { g_free (cur_open_file.filename); cur_open_file.filename = g_strdup (filename); cur_open_file.filetype = filetype; } cur_open_file.changed = FALSE; gse_set_title_changed (FALSE); return 1; } /* Opens the file 'filename' of the type 'filetype' and add all its content to the main clist * If 'append' is true, then the contents will be appended to the currently opened file */ gint gse_fl_open_file (gchar *filename, gint filetype, gboolean append) { gchar line[BUF_LEN], *entry[4], **str_v, *buf; gint i, width, n_lines; gint hr, min, sec, msec; gdouble offset = 0, tot; GString *srt_entry; FILE *sub_fl; gboolean something_went_wrong = FALSE; if (*filename == '\0' || (sub_fl = fopen (filename, "r")) == NULL) { g_warning ("GSubEdit: Failed to open file '%s' for reading. Do you have the correct permissions?", filename); return GSE_FILE_ERROR_OPEN_R; } if (append && cur_open_file.filetype != filetype) { g_warning ("GSubEdit: Unable to append file '%s'. Filetype is not the same as current open file!", filename); return GSE_FILE_ERROR_APPEND_FTYPE; } for (i = 0; i < 4; i++) entry[i] = NULL; if (!append) gtk_clist_clear (GTK_CLIST (mwin_clist)); else { gtk_clist_get_text (GTK_CLIST (mwin_clist), GTK_CLIST (mwin_clist)->rows - 1, 2, &buf); if (cur_open_file.filetype == GSE_SUBT_MICRODVD) offset = atoi (buf); else if (cur_open_file.filetype == GSE_SUBT_SUBRIPPER) { gse_str_to_time (buf, &hr, &min, &sec, &msec); offset = (hr * 3600) + (min * 60) + (sec); offset += (gdouble) msec / 1000; } else g_warning ("GSubEdit: Error when appending, unknown fileformat of current open file!"); } if (!append) n_lines = 0; else n_lines = GTK_CLIST (mwin_clist)->rows; gtk_clist_freeze (GTK_CLIST (mwin_clist)); if (filetype == GSE_SUBT_MICRODVD) { while (gse_str_only_spaces (fgets (line, BUF_LEN, sub_fl)) && !feof (sub_fl)); while (!feof (sub_fl)) { n_lines++; /* The first entry is the index of the current sub (i.e. the line number read) */ entry[0] = g_malloc0 (6); g_snprintf (entry[0], 6, "%d", n_lines); for (i = 1; i < 4; i++) { entry[i] = gse_fl_get_item_microdvd (line, i - 1, &something_went_wrong, n_lines - 1); if (append && i < 3) { tot = atoi (entry[i]); tot += offset; g_free (entry[i]); entry[i] = g_strdup_printf ("%d", (int) tot); } } gtk_clist_append (GTK_CLIST (mwin_clist), (gchar **) entry); for (i = 0; i < 4; i++) { g_free (entry[i]); entry[i] = NULL; } while (gse_str_only_spaces (fgets (line, BUF_LEN, sub_fl)) && !feof (sub_fl)); } } else if (filetype == GSE_SUBT_SUBRIPPER) { while (!feof (sub_fl)) { srt_entry = gse_fl_get_item_subripper (sub_fl); if (srt_entry == NULL) break; str_v = g_strsplit (srt_entry->str, "|", 3); g_string_free (srt_entry, TRUE); for (i = 0; str_v[i] != NULL; i++) { entry[i] = g_strdup (str_v[i]); /* If we're appending, add 'offset' to the time */ if (i == 0 && append) { tot = atoi (entry[i]); tot+= n_lines; g_free (entry[i]); entry[i] = g_strdup_printf ("%d", (gint) tot); } else if (i < 3 && append) { /* Add 'offset' seconds */ gse_str_to_time (entry[i], &hr, &min, &sec, &msec); gse_add_to_time (offset, &hr, &min, &sec, &msec); g_free (entry[i]); entry[i] = gse_time_to_str (hr, min, sec, msec); } } if (!something_went_wrong) something_went_wrong = gse_fl_check_entry_for_errors_srt (entry, atoi (entry[0]) - 1); else gse_fl_check_entry_for_errors_srt (entry, atoi (entry[0]) - 1); gtk_clist_append (GTK_CLIST (mwin_clist), (gchar **) entry); for (i = 0; str_v[i] != NULL; i++) { g_free (entry[i]); entry[i] = NULL; } } } else { g_warning ("gsubedit: failed to open file '%s'. Unknown format!\n", filename); fclose (sub_fl); return GSE_FILE_UNKNOWN_TYPE; } fclose (sub_fl); if (cur_open_file.filename != filename) { g_free (cur_open_file.filename); cur_open_file.filename = g_strdup (filename); } cur_open_file.filetype = filetype; cur_open_file.changed = FALSE; cur_open_file.lines = GTK_CLIST (mwin_clist)->rows; gse_fl_get_subtitle_info (filename); gse_gui_set_infobox_values (); gse_set_title_changed (FALSE); gse_set_menu_toolbar_state (GSE_FILE_OPEN | cur_open_file.filetype); for (i = 0; i < 4; i++) { width = gtk_clist_optimal_column_width (GTK_CLIST (mwin_clist), i); gtk_clist_set_column_width (GTK_CLIST (mwin_clist), i, width); } gtk_clist_thaw (GTK_CLIST (mwin_clist)); if (something_went_wrong) { while (error_lines) { gtk_clist_set_background (GTK_CLIST (mwin_clist), GPOINTER_TO_INT (error_lines->data), &light_red); error_lines = g_list_next (error_lines); } g_list_free (error_lines); return GSE_FILE_CORRECTED_VALUES; } else return GSE_FILE_NO_ERRORS; } /* Tries to determine the file-format of the file 'fname'. * If force_mode is set to something else than 0, then that detect-mode will be used, * otherwise it uses the mode configured by the user */ int gse_fl_get_subtitle_format (gchar *fname, gint force_mode) { gchar *ext, line[BUF_LEN]; FILE *fl; if ((force_mode == CFG_DETECT_BY_CONTENT) || (cfg.detect_file_by == CFG_DETECT_BY_CONTENT && force_mode != CFG_DETECT_BY_EXT)) { if ((fl = fopen (fname, "r")) == NULL) return GSE_SUBT_UNKNOWN; while (gse_str_only_spaces ((fgets (line, BUF_LEN, fl)))); fclose (fl); if (*line == '{') return GSE_SUBT_MICRODVD; /* First char of a srt file is a number (1) and the second should be a newline (or space of some kind) */ else if (gse_str_only_digits (line)) return GSE_SUBT_SUBRIPPER; else return GSE_SUBT_UNKNOWN; } else { /* Detect by file-extension */ ext = strrchr (fname, '.') + 1; if (g_strncasecmp (ext, "srt", 3) == 0) return GSE_SUBT_SUBRIPPER; else if (g_strncasecmp (ext, "sub", 3) == 0) return GSE_SUBT_MICRODVD; else return GSE_SUBT_UNKNOWN; } } /* Microdvd subtitles comes in the format: * {startframe}{endframe}text_to_display_on_screen|next_line_of_text * returns the apropriate text depending on 'col' (col = 1 returns 'startframe' etc.) */ gchar *gse_fl_get_item_microdvd (gchar *ptr, gint col, gboolean *error, gint cur_line) { gchar *ret, *orig = ptr; gint i = 0; switch (col) { case 0: ret = g_malloc0 (20); ptr = strchr (ptr, '{') + 1; if (ptr != (void *) 0x01) while (*ptr != '}' && i < 19) /* The part between the first {} */ { ret[i] = *ptr; ptr++; i++; } else { *error = TRUE; error_lines = g_list_append (error_lines, GINT_TO_POINTER (cur_line)); *ret = '0'; } break; case 1: ptr = strchr (ptr, '{') + 1; if (ptr != (void *) 0x01) ptr = strchr (ptr, '{') + 1; ret = g_malloc0 (20); if (ptr != (void *) 0x01) while (*ptr != '}' && i < 19) /* The part between the second {} */ { ret[i] = *ptr; ptr++; i++; } else { *error = TRUE; if (error_lines) { if (GPOINTER_TO_INT (g_list_last (error_lines)->data) != cur_line) error_lines = g_list_append (error_lines, GINT_TO_POINTER (cur_line)); } else error_lines = g_list_append (error_lines, GINT_TO_POINTER (cur_line)); *ret = '0'; } break; case 2: ptr = strchr (ptr, '}') + 1; if (ptr != (void *) 0x01) { orig = ptr; ptr = strchr (ptr, '}') + 1; } if (ptr != (void *) 0x01) ret = g_strdup (ptr); /* The remaining string duplicated.. */ else { ret = g_strdup (orig); /* ..or if something went wrong, from where error occurred! */ *error = TRUE; if (error_lines) { if (GPOINTER_TO_INT (g_list_last (error_lines)->data) != cur_line) error_lines = g_list_append (error_lines, GINT_TO_POINTER (cur_line)); } else error_lines = g_list_append (error_lines, GINT_TO_POINTER (cur_line)); } break; default: g_warning ("GSubEdit: get_item_microdvd: Unknown column!\n"); ret = NULL; break; } if (ret) g_strchomp (ret); return ret; } /* SubRip files are a bit harder to parse: * First row is the number of the subtitle, the second row contains start- and end-time in the format: * HH:MM:SS,msec --> HH:MM:SS,msec * The remaining rows contains the actual text, terminated by an empty line followed by a new subtitlenumber */ GString *gse_fl_get_item_subripper (FILE *fl) { GString *str; gchar line[BUF_LEN]; gchar **tmp_v; str = g_string_new (""); /* Step line by line until a line is reached that contains _only_ digits */ while (!feof (fl) && (!gse_str_only_digits (fgets (line, BUF_LEN, fl)))); if (!feof (fl)) { do { g_strchomp (line); if (strstr (line, " --> ")) { tmp_v = g_strsplit (line, " --> ", 2); /* Split the "start --> end" into two strings.. */ g_string_append (str, g_strjoinv ("|", tmp_v)); /* .. and join them together again w/ '|'as a separator */ g_strfreev (tmp_v); } else g_string_append (str, line); g_string_append (str, "|"); /* Used to keep track of the different strings, and as an indikator of a newline */ } while (!feof (fl) && (!gse_str_only_spaces (fgets (line, BUF_LEN, fl)))); } if (*(str->str) == '\0') return NULL; else { str->str[strlen (str->str) - 1] = '\0'; return str; } } /* Checks an subrip entry for errors and returns TRUE if anything was * needed to be corrected (i.e. if one or more of entry[?] was NULL) */ gboolean gse_fl_check_entry_for_errors_srt (gchar *entry[4], gint cur_line) { gboolean ret = FALSE; if (entry[0] == NULL) { entry[0] = g_strdup ("0"); ret = TRUE; } if (entry[1] == NULL) { entry[1] = g_strdup ("00:00:00,000"); ret = TRUE; } if (entry[2] == NULL) { entry[2] = g_strdup ("00:00:00,000"); ret = TRUE; } if (entry[3] == NULL) { entry[3] = g_strdup (""); ret = TRUE; } if (ret) error_lines = g_list_append (error_lines, GINT_TO_POINTER (cur_line)); return ret; } /* Currently only gets the filesize of the open subtitle */ void gse_fl_get_subtitle_info (gchar *filename) { struct stat *buf; int ret; buf = (struct stat *) g_malloc (sizeof (struct stat)); ret = stat (filename, buf); if (ret > -1) cur_open_file.size = buf->st_size / 1024; g_free (buf); }