OSDN Git Service

0139831d7577cee4bd2088ad58d633d02056cf24
[csp-qt/common_source_project-fm7.git] / source / src / common.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2013.01.17-
6
7         [ common ]
8 */
9
10 #if defined(_USE_QT)
11         #include <string.h>
12         #include <fcntl.h>
13         #if !defined(__WIN32) && !defined(__WIN64)
14                 #include <unistd.h>
15         #else
16                 #include <io.h>
17                 #include <direct.h>
18         #endif
19         #include <sys/types.h>
20         #include <sys/stat.h>
21         #include "agar_logger.h"
22         #include <string>
23         #include <algorithm>
24         #include <cctype>
25         #include <QDir>
26 #elif defined(_WIN32)
27         #include <shlwapi.h>
28         #pragma comment(lib, "shlwapi.lib")
29 #else
30         #include <time.h>
31 #endif
32 #include <math.h>
33 #include "common.h"
34 #include "fileio.h"
35
36 #if defined(__MINGW32__) || defined(__MINGW64__)
37         extern DWORD GetLongPathName(LPCTSTR lpszShortPath, LPTSTR lpszLongPath, DWORD cchBuffer);
38 #endif
39 #if defined(_USE_QT)
40         extern std::string cpp_homedir;
41         extern std::string my_procname;
42 #endif
43
44 uint32_t EndianToLittle_DWORD(uint32_t x)
45 {
46 #if defined(__LITTLE_ENDIAN__)
47         return x;
48 #else
49         uint32_t y;
50         y = ((x & 0x000000ff) << 24) | ((x & 0x0000ff00) << 8) |
51             ((x & 0x00ff0000) >> 8)  | ((x & 0xff000000) >> 24);
52         return y;
53 #endif
54 }
55
56 uint16_t EndianToLittle_WORD(uint16_t x)
57 {
58 #if defined(__LITTLE_ENDIAN__)
59         return x;
60 #else
61         uint16_t y;
62         y = ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
63         return y;
64 #endif
65 }
66
67 #ifndef _MSC_VER
68 int max(int a, int b)
69 {
70         if(a > b) {
71                 return a;
72         } else {
73                 return b;
74         }
75 }
76
77 unsigned int max(unsigned int a, unsigned int b)
78 {
79         if(a > b) {
80                 return a;
81         } else {
82                 return b;
83         }
84 }
85
86 int min(int a, int b)
87 {
88         if(a < b) {
89                 return a;
90         } else {
91                 return b;
92         }
93 }
94
95 unsigned int min(unsigned int a, unsigned int b)
96 {
97         if(a < b) {
98                 return a;
99         } else {
100                 return b;
101         }
102 }
103 #endif
104
105 #ifndef SUPPORT_SECURE_FUNCTIONS
106 //errno_t my_tfopen_s(FILE** pFile, const _TCHAR *filename, const _TCHAR *mode)
107 //{
108 //      if((*pFile = _tfopen(filename, mode)) != NULL) {
109 //              return 0;
110 //      } else {
111 //              return errno;
112 //      }
113 //}
114
115 errno_t my_strcpy_s(char *strDestination, size_t numberOfElements, const char *strSource)
116 {
117         strcpy(strDestination, strSource);
118         return 0;
119 }
120
121 errno_t my_tcscpy_s(_TCHAR *strDestination, size_t numberOfElements, const _TCHAR *strSource)
122 {
123         _tcscpy(strDestination, strSource);
124         return 0;
125 }
126
127 errno_t my_strncpy_s(char *strDestination, size_t numberOfElements, const char *strSource, size_t count)
128 {
129         strncpy(strDestination, strSource, count);
130         return 0;
131 }
132
133 errno_t my_tcsncpy_s(_TCHAR *strDestination, size_t numberOfElements, const _TCHAR *strSource, size_t count)
134 {
135         _tcsncpy(strDestination, strSource, count);
136         return 0;
137 }
138
139 char *my_strtok_s(char *strToken, const char *strDelimit, char **context)
140 {
141         return strtok(strToken, strDelimit);
142 }
143
144 _TCHAR *my_tcstok_s(_TCHAR *strToken, const char *strDelimit, _TCHAR **context)
145 {
146         return _tcstok(strToken, strDelimit);
147 }
148
149 int my_sprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, ...)
150 {
151         va_list ap;
152         va_start(ap, format);
153         int result = vsprintf(buffer, format, ap);
154         va_end(ap);
155         return result;
156 }
157
158 int my_stprintf_s(_TCHAR *buffer, size_t sizeOfBuffer, const _TCHAR *format, ...)
159 {
160         va_list ap;
161         va_start(ap, format);
162         int result = _vstprintf(buffer, format, ap);
163         va_end(ap);
164         return result;
165 }
166
167 int my_vsprintf_s(char *buffer, size_t numberOfElements, const char *format, va_list argptr)
168 {
169         return vsprintf(buffer, format, argptr);
170 }
171
172 int my_vstprintf_s(_TCHAR *buffer, size_t numberOfElements, const _TCHAR *format, va_list argptr)
173 {
174         return _vstprintf(buffer, format, argptr);
175 }
176 #endif
177
178 #ifndef _WIN32
179 BOOL MyWritePrivateProfileString(LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpString, LPCTSTR lpFileName)
180 {
181         BOOL result = FALSE;
182         FILEIO* fio_i = new FILEIO();
183         if(fio_i->Fopen(lpFileName, FILEIO_READ_ASCII)) {
184                 char tmp_path[_MAX_PATH];
185                 my_sprintf_s(tmp_path, _MAX_PATH, "%s.$$$", lpFileName);
186                 FILEIO* fio_o = new FILEIO();
187                 if(fio_o->Fopen(tmp_path, FILEIO_WRITE_ASCII)) {
188                         bool in_section = false;
189                         char section[1024], line[1024], *equal;
190                         my_sprintf_s(section, 1024, "[%s]", lpAppName);
191                         while(fio_i->Fgets(line, 1024) != NULL && strlen(line) > 0) {
192                                 if(line[strlen(line) - 1] == '\n') {
193                                         line[strlen(line) - 1] = '\0';
194                                 }
195                                 if(!result) {
196                                         if(line[0] == '[') {
197                                                 if(in_section) {
198                                                         fio_o->Fprintf("%s=%s\n", lpKeyName, lpString);
199                                                         result = TRUE;
200                                                 } else if(strcmp(line, section) == 0) {
201                                                         in_section = true;
202                                                 }
203                                         } else if(in_section && (equal = strstr(line, "=")) != NULL) {
204                                                 *equal = '\0';
205                                                 if(strcmp(line, lpKeyName) == 0) {
206                                                         fio_o->Fprintf("%s=%s\n", lpKeyName, lpString);
207                                                         result = TRUE;
208                                                         continue;
209                                                 }
210                                                 *equal = '=';
211                                         }
212                                 }
213                                 fio_o->Fprintf("%s\n", line);
214                         }
215                         if(!result) {
216                                 if(!in_section) {
217                                         fio_o->Fprintf("[%s]\n", lpAppName);
218                                 }
219                                 fio_o->Fprintf("%s=%s\n", lpKeyName, lpString);
220                                 result = TRUE;
221                         }
222                         fio_o->Fclose();
223                 }
224                 delete fio_o;
225                 fio_i->Fclose();
226                 if(result) {
227                         if(!(FILEIO::RemoveFile(lpFileName) && FILEIO::RenameFile(tmp_path, lpFileName))) {
228                                 result = FALSE;
229                         }
230                 }
231         } else {
232                 FILEIO* fio_o = new FILEIO();
233                 if(fio_o->Fopen(lpFileName, FILEIO_WRITE_ASCII)) {
234                         fio_o->Fprintf("[%s]\n", lpAppName);
235                         fio_o->Fprintf("%s=%s\n", lpKeyName, lpString);
236                         fio_o->Fclose();
237                 }
238                 delete fio_o;
239         }
240         delete fio_i;
241         return result;
242 }
243
244 static std::string MyGetPrivateProfileStr(const _TCHAR *lpAppName, const _TCHAR *lpKeyName, _TCHAR *lpFileName)
245 {
246         std::string key;
247         char ibuf[4096 + 102];
248         int64_t i;
249         int l_len;
250         int c = '\0';
251         std::string::size_type  pos;
252         std::string key_str;
253         std::string got_str;
254         FILEIO *pf = new FILEIO;
255         
256         key = lpAppName;
257         key = key + ".";
258         key = key + lpKeyName;
259         got_str = "";
260         if(pf->Fopen(lpFileName, FILEIO_READ_ASCII) != true) {
261                 delete pf;
262                 return got_str;
263         }
264         AGAR_DebugLog(AGAR_LOG_DEBUG, "Try App: %s Key: %s", lpAppName, lpKeyName);
265         pf->Fseek(0, FILEIO_SEEK_SET);
266         do {
267                 key_str = key;
268                 ibuf[0] = '\0';
269                 i = 0;
270                 l_len = 0;
271                 while(1) {
272                         if(l_len > (4096 + 100)) { // Too long, read dummy.
273                                 c = (char)pf->Fgetc();
274                                 if((c != EOF) && (c != '\n') && (c != '\0')) continue;
275                                 break;
276                         }
277                         c = (char)pf->Fgetc();
278                         if((c == EOF) || (c == '\n') || (c == '\0')) break;
279                         ibuf[i] = (char)c;
280                         i++;
281                         l_len++;
282                 }
283                 l_len = 0;
284                 ibuf[i] = '\0';
285                 got_str = ibuf;
286                 key_str = key_str + "=";
287                 pos = got_str.find(key_str);
288                 if(pos != std::string::npos) break;
289                 if(c == EOF) return "";
290         } while(c != EOF);
291         pf->Fclose();
292         delete pf;
293         
294         got_str.erase(0, pos + key_str.length());
295         AGAR_DebugLog(AGAR_LOG_DEBUG, "Got: %s Length: %d", got_str.c_str(), got_str.length());
296         return got_str;
297 }
298
299 DWORD MyGetPrivateProfileString(LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize, LPCTSTR lpFileName)
300 {
301         _TCHAR *lpp = (_TCHAR *)lpReturnedString;
302         if(lpDefault != NULL) {
303                 my_strcpy_s(lpp, nSize, lpDefault);
304         } else {
305                 lpp[0] = '\0';
306         }
307         FILEIO* fio = new FILEIO();
308         if(fio->Fopen(lpFileName, FILEIO_READ_ASCII)) {
309                 bool in_section = false;
310                 char section[1024], line[1024], *equal;
311                 my_sprintf_s(section, 1024, "[%s]", lpAppName);
312                 while(fio->Fgets(line, 1024) != NULL && strlen(line) > 0) {
313                         if(line[strlen(line) - 1] == '\n') {
314                                 line[strlen(line) - 1] = '\0';
315                         }
316                         if(line[0] == '[') {
317                                 if(in_section) {
318                                         break;
319                                 } else if(strcmp(line, section) == 0) {
320                                         in_section = true;
321                                 }
322                         } else if(in_section && (equal = strstr(line, "=")) != NULL) {
323                                 *equal = '\0';
324                                 if(strcmp(line, lpKeyName) == 0) {
325                                         my_strcpy_s(lpp, nSize, equal + 1);
326                                         break;
327                                 }
328                         }
329                 }
330                 fio->Fclose();
331         }
332         delete fio;
333         return strlen(lpp);
334 }
335
336 UINT MyGetPrivateProfileInt(LPCTSTR lpAppName, LPCTSTR lpKeyName, INT nDefault, LPCTSTR lpFileName)
337 {
338         int i;
339         char sstr[128];
340         char sval[128];
341         std::string s;
342         memset(sstr, 0x00, sizeof(sstr));
343         memset(sval, 0x00, sizeof(sval));
344         snprintf(sval, 128, "%d", nDefault); 
345         MyGetPrivateProfileString(lpAppName,lpKeyName, sval, sstr, 128, lpFileName);
346         s = sstr;
347         
348         if(s.empty()) {
349                 i = nDefault;
350         } else {
351                 i = strtol(s.c_str(), NULL, 10);
352         }
353         //AGAR_DebugLog(AGAR_LOG_DEBUG, "Got Int: %d\n", i);
354         return i;
355 }
356 #endif
357
358 #if defined(_RGB555)
359 scrntype_t RGB_COLOR(uint32_t r, uint32_t g, uint32_t b)
360 {
361         scrntype_t rr = ((scrntype_t)r * 0x1f) / 0xff;
362         scrntype_t gg = ((scrntype_t)g * 0x1f) / 0xff;
363         scrntype_t bb = ((scrntype_t)b * 0x1f) / 0xff;
364         return (rr << 10) | (gg << 5) | bb;
365 }
366
367 scrntype_t RGBA_COLOR(uint32_t r, uint32_t g, uint b, uint32_t a)
368 {
369         return RGB_COLOR(r, g, b);
370 }
371
372 uint8_t R_OF_COLOR(scrntype_t c)
373 {
374         c = (c >> 10) & 0x1f;
375         c = (c * 0xff) / 0x1f;
376         return (uint8_t)c;
377 }
378
379 uint8_t G_OF_COLOR(scrntype_t c)
380 {
381         c = (c >>  5) & 0x1f;
382         c = (c * 0xff) / 0x1f;
383         return (uint8_t)c;
384 }
385
386 uint8_t B_OF_COLOR(scrntype_t c)
387 {
388         c = (c >>  0) & 0x1f;
389         c = (c * 0xff) / 0x1f;
390         return (uint8_t)c;
391 }
392
393 uint8_t A_OF_COLOR(scrntype_t c)
394 {
395         return 0;
396 }
397 #elif defined(_RGB565)
398 scrntype_t RGB_COLOR(uint32_t r, uint32_t g, uint32_t b)
399 {
400         scrntype_t rr = ((scrntype_t)r * 0x1f) / 0xff;
401         scrntype_t gg = ((scrntype_t)g * 0x3f) / 0xff;
402         scrntype_t bb = ((scrntype_t)b * 0x1f) / 0xff;
403         return (rr << 11) | (gg << 5) | bb;
404 }
405
406 scrntype_t RGBA_COLOR(uint32_t r, uint32_t g, uint32_t b, uint32_t a)
407 {
408         return RGB_COLOR(r, g, b);
409 }
410
411 uint8_t R_OF_COLOR(scrntype_t c)
412 {
413         c = (c >> 11) & 0x1f;
414         c = (c * 0xff) / 0x1f;
415         return (uint8_t)c;
416 }
417
418 uint8_t G_OF_COLOR(scrntype_t c)
419 {
420         c = (c >>  5) & 0x3f;
421         c = (c * 0xff) / 0x3f;
422         return (uint8_t)c;
423 }
424
425 uint8_t B_OF_COLOR(scrntype_t c)
426 {
427         c = (c >>  0) & 0x1f;
428         c = (c * 0xff) / 0x1f;
429         return (uint8_t)c;
430 }
431
432 uint8_t A_OF_COLOR(scrntype_t c)
433 {
434         return 0;
435 }
436 #endif
437
438 #ifndef _MSC_VER
439 struct to_upper {  // Refer from documentation of libstdc++, GCC5.
440         char operator() (char c) const { return std::toupper(c); }
441 };
442 #endif
443
444 const _TCHAR *get_application_path()
445 {
446         static _TCHAR app_path[_MAX_PATH];
447         static bool initialized = false;
448         
449         if(!initialized) {
450 #if defined(_WIN32) && !defined(_USE_QT)
451                 _TCHAR tmp_path[_MAX_PATH], *ptr = NULL;
452                 if(GetModuleFileName(NULL, tmp_path, _MAX_PATH) != 0 && GetFullPathName(tmp_path, _MAX_PATH, app_path, &ptr) != 0 && ptr != NULL) {
453                         *ptr = _T('\0');
454                 } else {
455                         my_tcscpy_s(app_path, _MAX_PATH, _T(".\\"));
456                 }
457 #else
458 #if defined(Q_OS_WIN)
459                 std::string delim = "\\";
460 #else
461                 std::string delim = "/";
462 #endif
463                 std::string cpath = cpp_homedir + my_procname + delim;
464                 strncpy(app_path, cpath.c_str(), _MAX_PATH);
465                 {
466                         struct stat st;
467 #if !defined(__WIN32) && !defined(__WIN64)
468                         if(fstatat(AT_FDCWD, app_path, &st, 0) != 0) {
469                                 mkdirat(AT_FDCWD, app_path, 0700); // Not found
470                         }
471 #elif defined(_USE_QT)
472                         if(stat(app_path, &st) != 0) {
473                                 QDir dir = QDir::current();
474                                 dir.mkdir(QString::fromUtf8(app_path));
475                         }
476 #else
477                         if(stat(app_path, &st) != 0) {
478                                 _mkdir(app_path); // Not found
479                         }
480 #endif
481                 }
482 #endif
483                 initialized = true;
484         }
485         return (const _TCHAR *)app_path;
486 }
487
488 const _TCHAR *create_local_path(const _TCHAR *format, ...)
489 {
490         static _TCHAR file_path[8][_MAX_PATH];
491         static unsigned int table_index = 0;
492         unsigned int output_index = (table_index++) & 7;
493         _TCHAR file_name[_MAX_PATH];
494         va_list ap;
495         
496         va_start(ap, format);
497         my_vstprintf_s(file_name, _MAX_PATH, format, ap);
498         va_end(ap);
499         my_stprintf_s(file_path[output_index], _MAX_PATH, _T("%s%s"), get_application_path(), file_name);
500         return (const _TCHAR *)file_path[output_index];
501 }
502
503 void create_local_path(_TCHAR *file_path, int length, const _TCHAR *format, ...)
504 {
505         _TCHAR file_name[_MAX_PATH];
506         va_list ap;
507         
508         va_start(ap, format);
509         my_vstprintf_s(file_name, _MAX_PATH, format, ap);
510         va_end(ap);
511         my_stprintf_s(file_path, length, _T("%s%s"), get_application_path(), file_name);
512 }
513
514 const _TCHAR *create_date_file_path(const _TCHAR *extension)
515 {
516         cur_time_t cur_time;
517         
518         get_host_time(&cur_time);
519         return create_local_path(_T("%d-%0.2d-%0.2d_%0.2d-%0.2d-%0.2d.%s"), cur_time.year, cur_time.month, cur_time.day, cur_time.hour, cur_time.minute, cur_time.second, extension);
520 }
521
522 void create_date_file_path(_TCHAR *file_path, int length, const _TCHAR *extension)
523 {
524         my_tcscpy_s(file_path, length, create_date_file_path(extension));
525 }
526
527 bool check_file_extension(const _TCHAR *file_path, const _TCHAR *ext)
528 {
529 #if defined(_USE_QT)
530         std::string s_fpath = file_path;
531         std::string s_ext = ext;
532         bool f = false;
533         int pos;
534         std::transform(s_fpath.begin(), s_fpath.end(), s_fpath.begin(), to_upper());
535         std::transform(s_ext.begin(), s_ext.end(), s_ext.begin(), to_upper());
536         if(s_fpath.length() < s_ext.length()) return false;
537         pos = s_fpath.rfind(s_ext.c_str(), s_fpath.length());
538         if((pos != std::string::npos) && (pos >= (s_fpath.length() - s_ext.length()))) return true; 
539         return false;
540 #else
541         int nam_len = _tcslen(file_path);
542         int ext_len = _tcslen(ext);
543         
544         return (nam_len >= ext_len && _tcsncicmp(&file_path[nam_len - ext_len], ext, ext_len) == 0);
545 #endif
546 }
547
548 const _TCHAR *get_file_path_without_extensiton(const _TCHAR *file_path)
549 {
550         static _TCHAR path[8][_MAX_PATH];
551         static unsigned int table_index = 0;
552         unsigned int output_index = (table_index++) & 7;
553         
554         my_tcscpy_s(path[output_index], _MAX_PATH, file_path);
555 #if defined(_WIN32) && defined(_MSC_VER)
556         PathRemoveExtension(path[output_index]);
557 #else
558         _TCHAR *p = _tcsrchr(path[output_index], _T('.'));
559         if(p != NULL) {
560                 *p = _T('\0');
561         }
562 #endif
563         return (const _TCHAR *)path[output_index];
564 }
565
566 void get_long_full_path_name(const _TCHAR* src, _TCHAR* dst, size_t dst_len)
567 {
568         _TCHAR tmp[_MAX_PATH];
569         
570 #ifdef _WIN32
571         if(GetFullPathName(src, _MAX_PATH, tmp, NULL) == 0) {
572                 my_tcscpy_s(dst, dst_len, src);
573         } else if(GetLongPathName(tmp, dst, _MAX_PATH) == 0) {
574                 my_tcscpy_s(dst, dst_len, tmp);
575         }
576 #else
577         // write code for your environment
578 #endif
579 }
580
581 const _TCHAR* get_parent_dir(const _TCHAR* file)
582 {
583         static _TCHAR path[8][_MAX_PATH];
584         static unsigned int table_index = 0;
585         unsigned int output_index = (table_index++) & 7;
586         
587 #ifdef _WIN32
588         _TCHAR *ptr;
589         GetFullPathName(file, _MAX_PATH, path[output_index], &ptr);
590         if(ptr != NULL) {
591                 *ptr = _T('\0');
592         }
593 #else
594         // write code for your environment
595 #endif
596         return path[output_index];
597 }
598
599 const _TCHAR *create_string(const _TCHAR* format, ...)
600 {
601         static _TCHAR buffer[8][1024];
602         static unsigned int table_index = 0;
603         unsigned int output_index = (table_index++) & 7;
604         va_list ap;
605         
606         va_start(ap, format);
607         my_vstprintf_s(buffer[output_index], 1024, format, ap);
608         va_end(ap);
609         return (const _TCHAR *)buffer[output_index];
610 }
611
612 uint32_t get_crc32(uint8_t data[], int size)
613 {
614         static bool initialized = false;
615         static uint32_t table[256];
616         
617         if(!initialized) {
618                 for(int i = 0; i < 256; i++) {
619                         uint32_t c = i;
620                         for(int j = 0; j < 8; j++) {
621                                 if(c & 1) {
622                                         c = (c >> 1) ^ 0xedb88320;
623                                 } else {
624                                         c >>= 1;
625                                 }
626                         }
627                         table[i] = c;
628                 }
629                 initialized = true;
630         }
631         
632         uint32_t c = ~0;
633         for(int i = 0; i < size; i++) {
634                 c = table[(c ^ data[i]) & 0xff] ^ (c >> 8);
635         }
636         return ~c;
637 }
638
639 uint16_t jis_to_sjis(uint16_t jis)
640 {
641         pair_t tmp;
642         
643         tmp.w.l = jis - 0x2121;
644         if(tmp.w.l & 0x100) {
645                 tmp.w.l += 0x9e;
646         } else {
647                 tmp.w.l += 0x40;
648         }
649         if(tmp.b.l > 0x7f) {
650                 tmp.w.l += 0x01;
651         }
652         tmp.b.h = (tmp.b.h >> 1) + 0x81;
653         if(tmp.w.l >= 0xa000) {
654                 tmp.w.l += 0x4000;
655         }
656         return tmp.w.l;
657 }
658
659 int decibel_to_volume(int decibel)
660 {
661         // +1 equals +0.5dB (same as fmgen)
662         return (int)(1024.0 * pow(10.0, decibel / 40.0) + 0.5);
663 }
664
665 int32_t apply_volume(int32_t sample, int volume)
666 {
667 //      int64_t output;
668         int32_t output;
669         if(sample < 0) {
670                 output = -sample;
671                 output *= volume;
672                 output >>= 10;
673                 output = -output;
674         } else {
675                 output = sample;
676                 output *= volume;
677                 output >>= 10;
678         }
679 //      if(output > 2147483647) {
680 //              return 2147483647;
681 //      } else if(output < (-2147483647 - 1)) {
682 //              return (-2147483647 - 1);
683 //      } else {
684 //              return (int32_t)output;
685 //      }
686         return output;
687 }
688
689 void get_host_time(cur_time_t* cur_time)
690 {
691 #ifdef _WIN32
692         SYSTEMTIME sTime;
693         GetLocalTime(&sTime);
694         cur_time->year = sTime.wYear;
695         cur_time->month = sTime.wMonth;
696         cur_time->day = sTime.wDay;
697         cur_time->day_of_week = sTime.wDayOfWeek;
698         cur_time->hour = sTime.wHour;
699         cur_time->minute = sTime.wMinute;
700         cur_time->second = sTime.wSecond;
701 #else
702         time_t timer = time(NULL);
703         struct tm *local = localtime(&timer);
704         cur_time->year = local->tm_year + 1900;
705         cur_time->month = local->tm_mon + 1;
706         cur_time->day = local->tm_mday;
707         cur_time->day_of_week = local->tm_wday;
708         cur_time->hour = local->tm_hour;
709         cur_time->minute = local->tm_min;
710         cur_time->second = local->tm_sec;
711 #endif
712 }
713
714 void cur_time_t::increment()
715 {
716         if(++second >= 60) {
717                 second = 0;
718                 if(++minute >= 60) {
719                         minute = 0;
720                         if(++hour >= 24) {
721                                 hour = 0;
722                                 // days in this month
723                                 int days = 31;
724                                 if(month == 2) {
725                                         days = LEAP_YEAR(year) ? 29 : 28;
726                                 } else if(month == 4 || month == 6 || month == 9 || month == 11) {
727                                         days = 30;
728                                 }
729                                 if(++day > days) {
730                                         day = 1;
731                                         if(++month > 12) {
732                                                 month = 1;
733                                                 year++;
734                                         }
735                                 }
736                                 if(++day_of_week >= 7) {
737                                         day_of_week = 0;
738                                 }
739                         }
740                 }
741         }
742 }
743
744 void cur_time_t::update_year()
745 {
746         // 1970-2069
747         if(year < 70) {
748                 year += 2000;
749         } else if(year < 100) {
750                 year += 1900;
751         }
752 }
753
754 void cur_time_t::update_day_of_week()
755 {
756         static const int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
757         int y = year - (month < 3);
758         day_of_week = (y + y / 4 - y / 100 + y / 400 + t[month - 1] + day) % 7;
759 }
760
761 #define STATE_VERSION   1
762
763 void cur_time_t::save_state(void *f)
764 {
765         FILEIO *state_fio = (FILEIO *)f;
766         
767         state_fio->FputUint32(STATE_VERSION);
768         
769         state_fio->FputInt32(year);
770         state_fio->FputInt32(month);
771         state_fio->FputInt32(day);
772         state_fio->FputInt32(day_of_week);
773         state_fio->FputInt32(hour);
774         state_fio->FputInt32(minute);
775         state_fio->FputInt32(second);
776         state_fio->FputBool(initialized);
777 }
778
779 bool cur_time_t::load_state(void *f)
780 {
781         FILEIO *state_fio = (FILEIO *)f;
782         
783         if(state_fio->FgetUint32() != STATE_VERSION) {
784                 return false;
785         }
786         year = state_fio->FgetInt32();
787         month = state_fio->FgetInt32();
788         day = state_fio->FgetInt32();
789         day_of_week = state_fio->FgetInt32();
790         hour = state_fio->FgetInt32();
791         minute = state_fio->FgetInt32();
792         second = state_fio->FgetInt32();
793         initialized = state_fio->FgetBool();
794         return true;
795 }
796