/* * Copyright (C) 2004-2005 Vadim Berezniker * http://www.kryptolus.com * * This Program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This Program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * http://www.gnu.org/copyleft/gpl.html * */ #include "stdafx.h" #include "common.h" #include "sabbu.h" #include "stringutils.h" #include "kryTextFileReader.h" #include "krySubReader.h" extern struct sabbu app; /* * Converts miliseconds into a a string in the format HH:MM:SS.MS * * The returned string must be freed. */ char *time_mili_to_string(long mili, gboolean is_srt_format, gboolean is_srt_write) { struct time_parts time_parts; time_mili_to_parts(mili, &time_parts); char *rv; if(is_srt_format) { if(is_srt_write) { rv = kry_strdup_printf(KRY_LOC "%s%02d:%02d:%02d,%03d", time_parts.negative ? "-" : "", time_parts.hours, time_parts.minutes, time_parts.seconds, time_parts.mili); } else { rv = kry_strdup_printf(KRY_LOC "%s%02d:%02d:%02d.%03d", time_parts.negative ? "-" : "", time_parts.hours, time_parts.minutes, time_parts.seconds, time_parts.mili); } } else { rv = kry_strdup_printf(KRY_LOC "%s%d:%02d:%02d.%02d", time_parts.negative ? "-" : "", time_parts.hours, time_parts.minutes, time_parts.seconds, (int) (time_parts.mili / 10.0)); } return rv; } /* * Converts miliseconds into a string in the forat HH:MM:SS.MS * If any leading fields are 0, they are left out. * * The returned string must be freed. */ char *time_mili_to_string_compact(long time) { char *rv; struct time_parts time_parts; time_mili_to_parts(time, &time_parts); if(time_parts.hours == 0 && time_parts.minutes == 0) rv = kry_strdup_printf(KRY_LOC "%02d.%02d", time_parts.seconds, (int) (time_parts.mili / 10.0)); else if(time_parts.hours == 0) rv = kry_strdup_printf(KRY_LOC "%02d:%02d.%02d", time_parts.minutes, time_parts.seconds, (int) (time_parts.mili / 10.0)); else rv = kry_strdup_printf(KRY_LOC "%d:%02d:%02d.%02d", time_parts.hours, time_parts.minutes, time_parts.seconds, (int) (time_parts.mili / 10.0)); return rv; } /* * Calculates Hours/Minutes/Seconds/Miliseconds from the given milisecond total and stores it in the * structure pointed to by time_parts. */ void time_mili_to_parts(long time, struct time_parts *time_parts) { int minutes, hours, seconds, mili; if(time < 0) { time = 0 - time; time_parts->negative = TRUE; } else { time_parts->negative = FALSE; } mili = time % 1000; time -= mili; seconds = time / 1000; minutes = seconds / 60; seconds -= minutes * 60; hours = minutes / 60; minutes -= hours * 60; time_parts->hours = hours; time_parts->minutes = minutes; time_parts->seconds = seconds; time_parts->mili = mili; } /* * Converts the given string (which should be in the HH:MM:SS.MS format) into miliseconds. * If the given string is not valid, the function returns err_val. */ long time_string_to_mili(const char *time_str, int err_val, gboolean is_srt_format, gboolean is_srt_separator) { char *time_str_ptr = kry_strdup(time_str); char *time_str_orig = time_str_ptr; char *val; long numval; gboolean negative = FALSE; if(time_str_ptr[0] == '-') { negative = TRUE; time_str_ptr++; } // read hours val = string_read_token(&time_str_ptr, ':'); if(!val) { kry_free(time_str_orig); return err_val; } numval = atoi(val) * 60 * 60 * 1000; kry_free(val); // read minutes val = string_read_token(&time_str_ptr, ':'); if(!val) { kry_free(time_str_orig); return err_val; } numval += atoi(val) * 60 * 1000; kry_free(val); // read seconds val = string_read_token(&time_str_ptr, is_srt_format && is_srt_separator ? ',' : '.'); if(!val) { kry_free(time_str_orig); return err_val; } numval += atoi(val) * 1000; kry_free(val); // read miliseconds val = string_read_token_end(&time_str_ptr); if(!val) { kry_free(time_str_orig); return err_val; } numval += atoi(val) * (is_srt_format ? 1 : 10); kry_free(val); kry_free(time_str_orig); if(negative) numval = 0 - numval; return numval; } /* * Returns the path to the application configuration directory. * The returned string must be freed. */ char *sabbu_get_config_dir() { char *rv = KRY_TS(g_build_filename(g_get_home_dir(), ".sabbu", NULL)); return rv; } /* * Returns the path to the application configuration file. * The returned string must be freed. */ char *sabbu_get_config_file() { char *dir = sabbu_get_config_dir(); char *filename = KRY_TS(g_build_filename(dir, "config.ini", NULL)); kry_free(dir); return filename; } FILE *sabbu_log_fh = NULL; gboolean sabbu_log_check() { if(!app.opts.enable_logging) return FALSE; if(!sabbu_log_fh) { #ifdef _WINDOWS char app_path[_MAX_PATH]; if(!GetModuleFileName(NULL, app_path, _MAX_PATH)) app_path[0] = NULL; #else char app_path[1] = { 0 }; #endif char *app_path_base = g_path_get_dirname(app_path); char *log_path = g_strdup_printf("%s\\debug.log", app_path_base); sabbu_log_fh = fopen(log_path, "w"); g_free(app_path_base); g_free(log_path); } if(!sabbu_log_fh) return FALSE; return TRUE; } void sabbu_log_endl() { if(!sabbu_log_check()) return; char *buff = g_strdup("\n"); fwrite(buff, strlen(buff), 1, sabbu_log_fh); g_free(buff); } void sabbu_log_real(int type, char *file, int line, char *text) { if(type == LOG_SOUND) return; if(!sabbu_log_check()) return; char *file_short = g_path_get_basename(file); char *buff = g_strdup_printf("%30s: %5d - %s\n", file_short, line, text); fwrite(buff, strlen(buff), 1, sabbu_log_fh); g_free(buff); g_free(file_short); fflush(sabbu_log_fh); } void sabbu_log_close() { if(!sabbu_log_fh) return; fclose(sabbu_log_fh); } int sabbu_clamp_value_real(int val, int min, int max, char *file, int line) { if(min > max) { g_warning("%s: %d - Given minimum(%d) is less than the given maximum(%d). Are you crazy?", file, line, min, max); return val; } else if(val < min) { g_warning("%s: %d - Value(%d) is lower than the allowed minimum (%d). Setting to minimum.", file, line, val, min); return min; } else if(val > max) { g_warning("%s: %d - Value(%d) is higher than the allowed maximum (%d). Setting to maximum.", file, line, val, max); return max; } return val; } /* * Returns the number of characters are required to display the given integer. */ int integer_calculate_width(int num) { int width = 0; if(num == 0) return 1; if(num < 0) { width++; num = -num; } while(num) { num /= 10; width++; } return width; } char *sabbu_iconv_get_charset(int code) { switch(code) { case 186: // BALTIC_CHARSET return "CP1257"; case 136: //CHINESEBIG5_CHARSET return "CP950"; case 238: // EASTEUROPE_CHARSET return "CP1250"; case 134: // GB2312_CHARSET return "CP936"; case 161: // GREEK_CHARSET return "CP1253"; case 129: // HANGUL_CHARSET return "CP949"; case 204: // RUSSIAN_CHARSET return "CP1251"; case 128: // SHIFTJIS_CHARSET return "CP932"; case 162: // TURKISH_CHARSET return "CP1254"; case 163: // VIETNAMESE_CHARSET return "CP1258"; default: return NULL; } } void sabbu_style_iconv_map_free(struct style_iconv_map *map) { if(map->present) iconv_close(map->iconv_h); kry_free(map); } gboolean sabbu_iconv_get_mapping(kryScript *script, kryEventDetailed *event, kryHash *hash, struct style_iconv_map **map_param, gboolean backward = FALSE) { gboolean unknown_charset = FALSE; struct style_iconv_map *map = hash->Lookup(event->GetStyle()); if(map == NULL) { map = kry_new0(struct style_iconv_map); kryStyle *style = script->GetStyle(event->GetStyle()); if(style && style->GetCharset() != 0) { char *charset = sabbu_iconv_get_charset(style->GetCharset()); if(charset) { map->present = TRUE; if(backward) { map->iconv_h = iconv_open(charset, "UTF-8"); map->src_encoding = "UTF-8"; } else { map->iconv_h = iconv_open("UTF-8", charset); map->src_encoding = charset; } } else { unknown_charset = TRUE; } } hash->Insert(kry_strdup(event->GetStyle()), map); } *map_param = map; return !unknown_charset; } void fwrite_custom(char *buffer, int len, int count, FILE *fh, gboolean utf16) { if(utf16) { gboolean free_buffer = FALSE; if(strlen(buffer) == 1 && buffer[0] == 10 || strlen(buffer) > 1 && buffer[strlen(buffer) - 1] == 10 && buffer[strlen(buffer) - 2] != 13) { char *buffer_new = (char *) kry_malloc(strlen(buffer) + 2); strcpy(buffer_new, buffer); buffer_new[strlen(buffer) - 1] = 13; buffer_new[strlen(buffer)] = 10; buffer_new[strlen(buffer) + 1] = 0; buffer = buffer_new; free_buffer = TRUE; } GError *error = NULL; glong items_written = 0; void *utf16str = g_utf8_to_utf16(buffer, -1, NULL, &items_written, &error); fwrite(utf16str, items_written * 2, 1, fh); g_free(utf16str); if(free_buffer) kry_free(buffer); return; } fwrite(buffer, len, count, fh); } /* * Removes the file extension from the given path. */ void kry_path_remove_ext(char *path) { int len = strlen(path); for(int i = len - 1; i >= 0; i--) { if(path[i] == '\\' || path[i] == '/') break; if(path[i] == '.') { path[i] = 0; break; } } } char *kry_path_replace_ext(char *path, char *new_ext) { int i = 0; int len = strlen(path); for(i = len - 1; i >= 0; i--) { if(path[i] == '\\' || path[i] == '/') break; if(path[i] == '.') { path[i] = 0; break; } } char *new_file = kry_strdup_printf(KRY_LOC "%s.%s", path, new_ext); if(i >= 0 && path[i] == 0) path[i] = '.'; return new_file; } #ifdef _WINDOWS FILE *fopen_win32(char *filename, char *flags) { gunichar2 *filename_utf16 = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL); gunichar2 *flags_utf16 = g_utf8_to_utf16(flags, -1, NULL, NULL, NULL); FILE *fh = _wfopen(filename_utf16, flags_utf16); g_free(filename_utf16); g_free(flags_utf16); return fh; } int open_win32(char *filename, int flags) { gunichar2 *filename_utf16 = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL); int rv = _wopen(filename_utf16, flags, S_IREAD | S_IWRITE); g_free(filename_utf16); return rv; } int stat_win32(char *filename, struct _stat *props) { gunichar2 *filename_utf16 = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL); int rv = _wstat(filename_utf16, props); g_free(filename_utf16); return rv; } int mkdir_win32(char *filename) { gunichar2 *filename_utf16 = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL); int rv = _wmkdir(filename_utf16); g_free(filename_utf16); return rv; } int chdir_win32(char *filename) { gunichar2 *filename_utf16 = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL); int rv = _wchdir(filename_utf16); g_free(filename_utf16); return rv; } #endif #ifndef DISABLE_GETTEXT char *sgettext (const char *msgid) { char *msgval = gettext (msgid); if (msgval == msgid) { msgval = strrchr (msgid, '|'); if(!msgval) msgval = (char *) msgid; else msgval++; } return msgval; } #endif char *sgettext_strip(const char *msgid) { char *msgval = strrchr(msgid, '|'); if(!msgval) return (char *) msgid; return msgval + 1; } void kry_recent_list_add(GList **list, char *string) { GList *match = g_list_find_custom(*list, string, (GCompareFunc) strcmp); char *filename_copy = kry_strdup(string); *list = g_list_prepend(*list, filename_copy); if(match) { *list = g_list_remove_link(*list, match); kry_free(match->data); g_list_free_1(match); } if(g_list_length(*list) > 10) { GList *last = g_list_last(*list); *list = g_list_remove_link(*list, last); kry_free(last->data); g_list_free_1(last); } } GList *kry_recent_list_load(char *key) { GList *file_list = NULL; GList *recent_files = app.prefs->GetList(key); while(recent_files) { kryPrefValue *pref = (kryPrefValue *) recent_files->data; char *val_copy = kry_strdup((const gchar *) pref->GetData()); file_list = g_list_append(file_list, val_copy); recent_files = recent_files->next; } return file_list; } void kry_recent_list_save(GList *list, char *key) { app.prefs->Remove(key); while(list) { app.prefs->SetListAddString(key, (char *) list->data); list = list->next; } } int time_mili_to_frames(int time, double fps) { double framesfloat = ((time / 1000.0) * fps); int frames = (int) framesfloat; if(framesfloat - (int) framesfloat >= 0.5) frames ++; return frames; }