Mercurial > sdl-ios-xcode
view src/timer/os2/SDL_systimer.c @ 4388:1524d3237820 SDL-1.2
Fixed bug #896
John Popplewell 2009-12-08 23:05:50 PST
Originally reported by AKFoerster on the mailing list.
Error decoding UTF8 Russian text to UTF-16LE on Windows, but specifically on
platforms without iconv support (the default on Windows).
Valid UTF8 characters are flagged as being overlong and then substituted by the
UNKNOWN_UNICODE character.
After studying the testiconv.c example program, reading the RFCs and putting
some printf statements in SDL_iconv.c the problem is in a test for 'Maximum
overlong sequences', specifically 4.2.1, which is carried out by the following
code:
} else if ( p[0] >= 0xC0 ) {
if ( (p[0] & 0xE0) != 0xC0 ) {
/* Skip illegal sequences
return SDL_ICONV_EILSEQ;
*/
ch = UNKNOWN_UNICODE;
} else {
if ( (p[0] & 0xCE) == 0xC0 ) { <<<<<<<< here
overlong = SDL_TRUE;
}
ch = (Uint32)(p[0] & 0x1F);
left = 1;
}
} else {
Here is the 2-byte encoding of a character in range 00000080 - 000007FF
110xxxxx 10xxxxxx
The line in question is supposed to be checking for an overlong sequence which
would be less than
11000001 10111111
which should be represented as a single byte.
BUT, the mask value (0xCE) is wrong, it isn't checking the top-most bit:
11000001 value
11001110 mask (incorrect)
^
and should be (0xDE):
11000001 value
11011110 mask (correct)
making the above code:
} else if ( p[0] >= 0xC0 ) {
if ( (p[0] & 0xE0) != 0xC0 ) {
/* Skip illegal sequences
return SDL_ICONV_EILSEQ;
*/
ch = UNKNOWN_UNICODE;
} else {
if ( (p[0] & 0xDE) == 0xC0 ) { <<<<<<<< here
overlong = SDL_TRUE;
}
ch = (Uint32)(p[0] & 0x1F);
left = 1;
}
} else {
I can supply a test program and/or a patch if required,
best regards,
John Popplewell
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Fri, 11 Dec 2009 08:00:57 +0000 |
parents | a1b03ba2fcd0 |
children |
line wrap: on
line source
/* SDL - Simple DirectMedia Layer Copyright (C) 1997-2009 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Sam Lantinga slouken@libsdl.org */ #include "SDL_config.h" #ifdef SDL_TIMER_OS2 #define INCL_DOSMISC #define INCL_DOSERRORS #define INCL_DOSSEMAPHORES #define INCL_DOSDATETIME #define INCL_DOSPROCESS #define INCL_DOSPROFILE #define INCL_DOSEXCEPTIONS #include <os2.h> #include "SDL_thread.h" #include "SDL_timer.h" #include "../SDL_timer_c.h" #define TIME_WRAP_VALUE (~(DWORD)0) /* The first high-resolution ticks value of the application */ static long long hires_start_ticks; /* The number of ticks per second of the high-resolution performance counter */ static ULONG hires_ticks_per_second; void SDL_StartTicks(void) { DosTmrQueryFreq(&hires_ticks_per_second); DosTmrQueryTime((PQWORD)&hires_start_ticks); } DECLSPEC Uint32 SDLCALL SDL_GetTicks(void) { long long hires_now; ULONG ticks = ticks; DosTmrQueryTime((PQWORD)&hires_now); /* hires_now -= hires_start_ticks; hires_now *= 1000; hires_now /= hires_ticks_per_second; */ /* inline asm to avoid runtime inclusion */ _asm { push edx push eax mov eax, dword ptr hires_now mov edx, dword ptr hires_now+4 sub eax, dword ptr hires_start_ticks sbb edx, dword ptr hires_start_ticks+4 mov ebx,1000 mov ecx,edx mul ebx push eax push edx mov eax,ecx mul ebx pop eax add edx,eax pop eax mov ebx, dword ptr hires_ticks_per_second div ebx mov dword ptr ticks, eax pop edx pop eax } return ticks; } /* High resolution sleep, originally made by Ilya Zakharevich */ DECLSPEC void SDLCALL SDL_Delay(Uint32 ms) { /* This is similar to DosSleep(), but has 8ms granularity in time-critical threads even on Warp3. */ HEV hevEvent1 = 0; /* Event semaphore handle */ HTIMER htimerEvent1 = 0; /* Timer handle */ APIRET rc = NO_ERROR; /* Return code */ int ret = 1; ULONG priority = 0, nesting; /* Shut down the warnings */ PPIB pib; PTIB tib; char *e = NULL; APIRET badrc; int switch_priority = 50; DosCreateEventSem(NULL, /* Unnamed */ &hevEvent1, /* Handle of semaphore returned */ DC_SEM_SHARED, /* Shared needed for DosAsyncTimer */ FALSE); /* Semaphore is in RESET state */ if (ms >= switch_priority) switch_priority = 0; if (switch_priority) { if (DosGetInfoBlocks(&tib, &pib)!=NO_ERROR) switch_priority = 0; else { /* In Warp3, to switch scheduling to 8ms step, one needs to do DosAsyncTimer() in time-critical thread. On laters versions, more and more cases of wait-for-something are covered. It turns out that on Warp3fp42 it is the priority at the time of DosAsyncTimer() which matters. Let's hope that this works with later versions too... XXXX */ priority = (tib->tib_ptib2->tib2_ulpri); if ((priority & 0xFF00) == 0x0300) /* already time-critical */ switch_priority = 0; /* Make us time-critical. Just modifying TIB is not enough... */ /* tib->tib_ptib2->tib2_ulpri = 0x0300;*/ /* We do not want to run at high priority if a signal causes us to longjmp() out of this section... */ if (DosEnterMustComplete(&nesting)) switch_priority = 0; else DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0); } } if ((badrc = DosAsyncTimer(ms, (HSEM) hevEvent1, /* Semaphore to post */ &htimerEvent1))) /* Timer handler (returned) */ e = "DosAsyncTimer"; if (switch_priority && tib->tib_ptib2->tib2_ulpri == 0x0300) { /* Nobody switched priority while we slept... Ignore errors... */ /* tib->tib_ptib2->tib2_ulpri = priority; */ /* Get back... */ if (!(rc = DosSetPriority(PRTYS_THREAD, (priority>>8) & 0xFF, 0, 0))) rc = DosSetPriority(PRTYS_THREAD, 0, priority & 0xFF, 0); } if (switch_priority) rc = DosExitMustComplete(&nesting); /* Ignore errors */ /* The actual blocking call is made with "normal" priority. This way we should not bother with DosSleep(0) etc. to compensate for us interrupting higher-priority threads. The goal is to prohibit the system spending too much time halt()ing, not to run us "no matter what". */ if (!e) /* Wait for AsyncTimer event */ badrc = DosWaitEventSem(hevEvent1, SEM_INDEFINITE_WAIT); if (e) ; /* Do nothing */ else if (badrc == ERROR_INTERRUPT) ret = 0; else if (badrc) e = "DosWaitEventSem"; if ((rc = DosCloseEventSem(hevEvent1)) && !e) { /* Get rid of semaphore */ e = "DosCloseEventSem"; badrc = rc; } if (e) { SDL_SetError("[SDL_Delay] : Had error in %s(), rc is 0x%x\n", e, badrc); } } /* Data to handle a single periodic alarm */ static int timer_alive = 0; static SDL_Thread *timer = NULL; static int SDLCALL RunTimer(void *unused) { DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0); while ( timer_alive ) { if ( SDL_timer_running ) { SDL_ThreadedTimerCheck(); } SDL_Delay(10); } return(0); } /* This is only called if the event thread is not running */ int SDL_SYS_TimerInit(void) { timer_alive = 1; timer = SDL_CreateThread(RunTimer, NULL); if ( timer == NULL ) return(-1); return(SDL_SetTimerThreaded(1)); } void SDL_SYS_TimerQuit(void) { timer_alive = 0; if ( timer ) { SDL_WaitThread(timer, NULL); timer = NULL; } } int SDL_SYS_StartTimer(void) { SDL_SetError("Internal logic error: OS/2 uses threaded timer"); return(-1); } void SDL_SYS_StopTimer(void) { return; } #endif /* SDL_TIMER_OS2 */