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