1 /*
2 * Copyright (C) 2004-2005 Vadim Berezniker
3 * http://www.kryptolus.com
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21 #include "stdafx.h"
22
23 #include "common.h"
24
25 #include "sabbu.h"
26 #include "stringutils.h"
27
28 #include "kryTextFileReader.h"
29
30 #include "krySubReader.h"
31
32 extern struct sabbu app;
33
34 /*
35 * Converts miliseconds into a a string in the format HH:MM:SS.MS
36 *
37 * The returned string must be freed.
38 */
time_mili_to_string(long mili,gboolean is_srt_format,gboolean is_srt_write)39 char *time_mili_to_string(long mili, gboolean is_srt_format, gboolean is_srt_write)
40 {
41 struct time_parts time_parts;
42 time_mili_to_parts(mili, &time_parts);
43 char *rv;
44 if(is_srt_format)
45 {
46 if(is_srt_write)
47 {
48 rv = kry_strdup_printf(KRY_LOC "%s%02d:%02d:%02d,%03d", time_parts.negative ? "-" : "",
49 time_parts.hours, time_parts.minutes, time_parts.seconds, time_parts.mili);
50 }
51 else
52 {
53 rv = kry_strdup_printf(KRY_LOC "%s%02d:%02d:%02d.%03d", time_parts.negative ? "-" : "",
54 time_parts.hours, time_parts.minutes, time_parts.seconds, time_parts.mili);
55 }
56 }
57 else
58 {
59 rv = kry_strdup_printf(KRY_LOC "%s%d:%02d:%02d.%02d", time_parts.negative ? "-" : "",
60 time_parts.hours, time_parts.minutes, time_parts.seconds, (int) (time_parts.mili / 10.0));
61 }
62 return rv;
63 }
64
65 /*
66 * Converts miliseconds into a string in the forat HH:MM:SS.MS
67 * If any leading fields are 0, they are left out.
68 *
69 * The returned string must be freed.
70 */
time_mili_to_string_compact(long time)71 char *time_mili_to_string_compact(long time)
72 {
73 char *rv;
74 struct time_parts time_parts;
75 time_mili_to_parts(time, &time_parts);
76
77 if(time_parts.hours == 0 && time_parts.minutes == 0)
78 rv = kry_strdup_printf(KRY_LOC "%02d.%02d", time_parts.seconds, (int) (time_parts.mili / 10.0));
79 else if(time_parts.hours == 0)
80 rv = kry_strdup_printf(KRY_LOC "%02d:%02d.%02d", time_parts.minutes, time_parts.seconds, (int) (time_parts.mili / 10.0));
81 else
82 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));
83
84 return rv;
85 }
86
87 /*
88 * Calculates Hours/Minutes/Seconds/Miliseconds from the given milisecond total and stores it in the
89 * structure pointed to by time_parts.
90 */
time_mili_to_parts(long time,struct time_parts * time_parts)91 void time_mili_to_parts(long time, struct time_parts *time_parts)
92 {
93 int minutes, hours, seconds, mili;
94
95 if(time < 0)
96 {
97 time = 0 - time;
98 time_parts->negative = TRUE;
99 }
100 else
101 {
102 time_parts->negative = FALSE;
103 }
104
105 mili = time % 1000;
106 time -= mili;
107
108 seconds = time / 1000;
109 minutes = seconds / 60;
110 seconds -= minutes * 60;
111
112 hours = minutes / 60;
113 minutes -= hours * 60;
114
115 time_parts->hours = hours;
116 time_parts->minutes = minutes;
117 time_parts->seconds = seconds;
118 time_parts->mili = mili;
119 }
120
121 /*
122 * Converts the given string (which should be in the HH:MM:SS.MS format) into miliseconds.
123 * If the given string is not valid, the function returns err_val.
124 */
time_string_to_mili(const char * time_str,int err_val,gboolean is_srt_format,gboolean is_srt_separator)125 long time_string_to_mili(const char *time_str, int err_val, gboolean is_srt_format, gboolean is_srt_separator)
126 {
127 char *time_str_ptr = kry_strdup(time_str);
128 char *time_str_orig = time_str_ptr;
129 char *val;
130 long numval;
131 gboolean negative = FALSE;
132
133 if(time_str_ptr[0] == '-')
134 {
135 negative = TRUE;
136 time_str_ptr++;
137 }
138
139 // read hours
140 val = string_read_token(&time_str_ptr, ':');
141 if(!val)
142 {
143 kry_free(time_str_orig);
144 return err_val;
145 }
146 numval = atoi(val) * 60 * 60 * 1000;
147 kry_free(val);
148
149 // read minutes
150 val = string_read_token(&time_str_ptr, ':');
151 if(!val)
152 {
153 kry_free(time_str_orig);
154 return err_val;
155 }
156 numval += atoi(val) * 60 * 1000;
157 kry_free(val);
158
159 // read seconds
160 val = string_read_token(&time_str_ptr, is_srt_format && is_srt_separator ? ',' : '.');
161 if(!val)
162 {
163 kry_free(time_str_orig);
164 return err_val;
165 }
166 numval += atoi(val) * 1000;
167 kry_free(val);
168
169 // read miliseconds
170 val = string_read_token_end(&time_str_ptr);
171 if(!val)
172 {
173 kry_free(time_str_orig);
174 return err_val;
175 }
176 numval += atoi(val) * (is_srt_format ? 1 : 10);
177
178 kry_free(val);
179 kry_free(time_str_orig);
180
181 if(negative)
182 numval = 0 - numval;
183
184 return numval;
185 }
186
187 /*
188 * Returns the path to the application configuration directory.
189 * The returned string must be freed.
190 */
sabbu_get_config_dir()191 char *sabbu_get_config_dir()
192 {
193 char *rv = KRY_TS(g_build_filename(g_get_home_dir(), ".sabbu", NULL));
194 return rv;
195 }
196
197 /*
198 * Returns the path to the application configuration file.
199 * The returned string must be freed.
200 */
sabbu_get_config_file()201 char *sabbu_get_config_file()
202 {
203 char *dir = sabbu_get_config_dir();
204 char *filename = KRY_TS(g_build_filename(dir, "config.ini", NULL));
205
206 kry_free(dir);
207
208 return filename;
209 }
210
211 FILE *sabbu_log_fh = NULL;
sabbu_log_check()212 gboolean sabbu_log_check()
213 {
214 if(!app.opts.enable_logging)
215 return FALSE;
216
217 if(!sabbu_log_fh)
218 {
219 #ifdef _WINDOWS
220 char app_path[_MAX_PATH];
221 if(!GetModuleFileName(NULL, app_path, _MAX_PATH))
222 app_path[0] = NULL;
223 #else
224 char app_path[1] = { 0 };
225 #endif
226
227 char *app_path_base = g_path_get_dirname(app_path);
228 char *log_path = g_strdup_printf("%s\\debug.log", app_path_base);
229
230 sabbu_log_fh = fopen(log_path, "w");
231 g_free(app_path_base);
232 g_free(log_path);
233 }
234
235 if(!sabbu_log_fh)
236 return FALSE;
237
238 return TRUE;
239
240 }
241
sabbu_log_endl()242 void sabbu_log_endl()
243 {
244 if(!sabbu_log_check())
245 return;
246
247 char *buff = g_strdup("\n");
248 fwrite(buff, strlen(buff), 1, sabbu_log_fh);
249 g_free(buff);
250 }
251
sabbu_log_real(int type,char * file,int line,char * text)252 void sabbu_log_real(int type, char *file, int line, char *text)
253 {
254 if(type == LOG_SOUND)
255 return;
256
257 if(!sabbu_log_check())
258 return;
259
260 char *file_short = g_path_get_basename(file);
261 char *buff = g_strdup_printf("%30s: %5d - %s\n", file_short, line, text);
262 fwrite(buff, strlen(buff), 1, sabbu_log_fh);
263 g_free(buff);
264 g_free(file_short);
265 fflush(sabbu_log_fh);
266 }
267
sabbu_log_close()268 void sabbu_log_close()
269 {
270 if(!sabbu_log_fh)
271 return;
272
273 fclose(sabbu_log_fh);
274 }
275
sabbu_clamp_value_real(int val,int min,int max,char * file,int line)276 int sabbu_clamp_value_real(int val, int min, int max, char *file, int line)
277 {
278 if(min > max)
279 {
280 g_warning("%s: %d - Given minimum(%d) is less than the given maximum(%d). Are you crazy?", file, line, min, max);
281 return val;
282 }
283 else if(val < min)
284 {
285 g_warning("%s: %d - Value(%d) is lower than the allowed minimum (%d). Setting to minimum.", file, line, val, min);
286 return min;
287 }
288 else if(val > max)
289 {
290 g_warning("%s: %d - Value(%d) is higher than the allowed maximum (%d). Setting to maximum.", file, line, val, max);
291 return max;
292 }
293
294 return val;
295 }
296
297 /*
298 * Returns the number of characters are required to display the given integer.
299 */
integer_calculate_width(int num)300 int integer_calculate_width(int num)
301 {
302 int width = 0;
303 if(num == 0)
304 return 1;
305
306 if(num < 0)
307 {
308 width++;
309 num = -num;
310 }
311
312 while(num)
313 {
314 num /= 10;
315 width++;
316 }
317
318 return width;
319 }
320
sabbu_iconv_get_charset(int code)321 char *sabbu_iconv_get_charset(int code)
322 {
323 switch(code)
324 {
325 case 186: // BALTIC_CHARSET
326 return "CP1257";
327 case 136: //CHINESEBIG5_CHARSET
328 return "CP950";
329 case 238: // EASTEUROPE_CHARSET
330 return "CP1250";
331 case 134: // GB2312_CHARSET
332 return "CP936";
333 case 161: // GREEK_CHARSET
334 return "CP1253";
335 case 129: // HANGUL_CHARSET
336 return "CP949";
337 case 204: // RUSSIAN_CHARSET
338 return "CP1251";
339 case 128: // SHIFTJIS_CHARSET
340 return "CP932";
341 case 162: // TURKISH_CHARSET
342 return "CP1254";
343 case 163: // VIETNAMESE_CHARSET
344 return "CP1258";
345 default:
346 return NULL;
347 }
348 }
349
sabbu_style_iconv_map_free(struct style_iconv_map * map)350 void sabbu_style_iconv_map_free(struct style_iconv_map *map)
351 {
352 if(map->present)
353 iconv_close(map->iconv_h);
354
355 kry_free(map);
356 }
357
358
sabbu_iconv_get_mapping(kryScript * script,kryEventDetailed * event,kryHash<char *,struct style_iconv_map * > * hash,struct style_iconv_map ** map_param,gboolean backward=FALSE)359 gboolean sabbu_iconv_get_mapping(kryScript *script, kryEventDetailed *event, kryHash<char *, struct style_iconv_map *> *hash, struct style_iconv_map **map_param, gboolean backward = FALSE)
360 {
361 gboolean unknown_charset = FALSE;
362 struct style_iconv_map *map = hash->Lookup(event->GetStyle());
363 if(map == NULL)
364 {
365 map = kry_new0(struct style_iconv_map);
366 kryStyle *style = script->GetStyle(event->GetStyle());
367 if(style && style->GetCharset() != 0)
368 {
369 char *charset = sabbu_iconv_get_charset(style->GetCharset());
370 if(charset)
371 {
372 map->present = TRUE;
373 if(backward)
374 {
375 map->iconv_h = iconv_open(charset, "UTF-8");
376 map->src_encoding = "UTF-8";
377 }
378 else
379 {
380 map->iconv_h = iconv_open("UTF-8", charset);
381 map->src_encoding = charset;
382 }
383 }
384 else
385 {
386 unknown_charset = TRUE;
387 }
388 }
389
390 hash->Insert(kry_strdup(event->GetStyle()), map);
391 }
392
393 *map_param = map;
394
395 return !unknown_charset;
396 }
397
fwrite_custom(char * buffer,int len,int count,FILE * fh,gboolean utf16)398 void fwrite_custom(char *buffer, int len, int count, FILE *fh, gboolean utf16)
399 {
400 if(utf16)
401 {
402 gboolean free_buffer = FALSE;
403 if(strlen(buffer) == 1 && buffer[0] == 10 || strlen(buffer) > 1 && buffer[strlen(buffer) - 1] == 10 && buffer[strlen(buffer) - 2] != 13)
404 {
405 char *buffer_new = (char *) kry_malloc(strlen(buffer) + 2);
406 strcpy(buffer_new, buffer);
407 buffer_new[strlen(buffer) - 1] = 13;
408 buffer_new[strlen(buffer)] = 10;
409 buffer_new[strlen(buffer) + 1] = 0;
410 buffer = buffer_new;
411 free_buffer = TRUE;
412 }
413
414 GError *error = NULL;
415 glong items_written = 0;
416 void *utf16str = g_utf8_to_utf16(buffer, -1, NULL, &items_written, &error);
417 fwrite(utf16str, items_written * 2, 1, fh);
418 g_free(utf16str);
419
420 if(free_buffer)
421 kry_free(buffer);
422
423 return;
424 }
425
426 fwrite(buffer, len, count, fh);
427 }
428
429 /*
430 * Removes the file extension from the given path.
431 */
kry_path_remove_ext(char * path)432 void kry_path_remove_ext(char *path)
433 {
434 int len = strlen(path);
435 for(int i = len - 1; i >= 0; i--)
436 {
437 if(path[i] == '\\' || path[i] == '/')
438 break;
439
440 if(path[i] == '.')
441 {
442 path[i] = 0;
443 break;
444 }
445 }
446 }
447
kry_path_replace_ext(char * path,char * new_ext)448 char *kry_path_replace_ext(char *path, char *new_ext)
449 {
450 int i = 0;
451 int len = strlen(path);
452 for(i = len - 1; i >= 0; i--)
453 {
454 if(path[i] == '\\' || path[i] == '/')
455 break;
456
457 if(path[i] == '.')
458 {
459 path[i] = 0;
460 break;
461 }
462 }
463
464 char *new_file = kry_strdup_printf(KRY_LOC "%s.%s", path, new_ext);
465 if(i >= 0 && path[i] == 0)
466 path[i] = '.';
467
468 return new_file;
469 }
470
471 #ifdef _WINDOWS
fopen_win32(char * filename,char * flags)472 FILE *fopen_win32(char *filename, char *flags)
473 {
474 gunichar2 *filename_utf16 = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL);
475 gunichar2 *flags_utf16 = g_utf8_to_utf16(flags, -1, NULL, NULL, NULL);
476 FILE *fh = _wfopen(filename_utf16, flags_utf16);
477 g_free(filename_utf16);
478 g_free(flags_utf16);
479
480 return fh;
481 }
482
open_win32(char * filename,int flags)483 int open_win32(char *filename, int flags)
484 {
485 gunichar2 *filename_utf16 = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL);
486 int rv = _wopen(filename_utf16, flags, S_IREAD | S_IWRITE);
487 g_free(filename_utf16);
488
489 return rv;
490 }
491
stat_win32(char * filename,struct _stat * props)492 int stat_win32(char *filename, struct _stat *props)
493 {
494 gunichar2 *filename_utf16 = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL);
495 int rv = _wstat(filename_utf16, props);
496 g_free(filename_utf16);
497
498 return rv;
499 }
500
mkdir_win32(char * filename)501 int mkdir_win32(char *filename)
502 {
503 gunichar2 *filename_utf16 = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL);
504 int rv = _wmkdir(filename_utf16);
505 g_free(filename_utf16);
506
507 return rv;
508 }
509
chdir_win32(char * filename)510 int chdir_win32(char *filename)
511 {
512 gunichar2 *filename_utf16 = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL);
513 int rv = _wchdir(filename_utf16);
514 g_free(filename_utf16);
515
516 return rv;
517 }
518 #endif
519
520 #ifndef DISABLE_GETTEXT
sgettext(const char * msgid)521 char *sgettext (const char *msgid)
522 {
523 char *msgval = gettext (msgid);
524 if (msgval == msgid)
525 {
526 msgval = strrchr ((char *) msgid, '|');
527 if(!msgval)
528 msgval = (char *) msgid;
529 else
530 msgval++;
531 }
532 return msgval;
533 }
534
535 #endif
536
sgettext_strip(const char * msgid)537 char *sgettext_strip(const char *msgid)
538 {
539 char *msgval = strrchr((char *) msgid, '|');
540 if(!msgval)
541 return (char *) msgid;
542
543 return msgval + 1;
544 }
545
kry_recent_list_add(GList ** list,char * string)546 void kry_recent_list_add(GList **list, char *string)
547 {
548 GList *match = g_list_find_custom(*list, string, (GCompareFunc) strcmp);
549 char *filename_copy = kry_strdup(string);
550 *list = g_list_prepend(*list, filename_copy);
551 if(match)
552 {
553 *list = g_list_remove_link(*list, match);
554 kry_free(match->data);
555 g_list_free_1(match);
556 }
557
558 if(g_list_length(*list) > 10)
559 {
560 GList *last = g_list_last(*list);
561 *list = g_list_remove_link(*list, last);
562 kry_free(last->data);
563 g_list_free_1(last);
564 }
565 }
566
kry_recent_list_load(char * key)567 GList *kry_recent_list_load(char *key)
568 {
569 GList *file_list = NULL;
570 GList *recent_files = app.prefs->GetList(key);
571 while(recent_files)
572 {
573 kryPrefValue *pref = (kryPrefValue *) recent_files->data;
574 char *val_copy = kry_strdup((const gchar *) pref->GetData());
575 file_list = g_list_append(file_list, val_copy);
576
577 recent_files = recent_files->next;
578 }
579
580 return file_list;
581 }
582
kry_recent_list_save(GList * list,char * key)583 void kry_recent_list_save(GList *list, char *key)
584 {
585 app.prefs->Remove(key);
586 while(list)
587 {
588 app.prefs->SetListAddString(key, (char *) list->data);
589 list = list->next;
590 }
591 }
592
time_mili_to_frames(int time,double fps)593 int time_mili_to_frames(int time, double fps)
594 {
595 double framesfloat = ((time / 1000.0) * fps);
596 int frames = (int) framesfloat;
597 if(framesfloat - (int) framesfloat >= 0.5)
598 frames ++;
599
600 return frames;
601 }
602
603
604