Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle Unicode objects properly #656

Merged
merged 17 commits into from Dec 6, 2018

font: use Python to open the file

SDL expects UTF8 strings
  • Loading branch information...
dlon committed Dec 1, 2018
commit de5b152e222c8d786d59e88311154eb1db7ba870
@@ -192,7 +192,7 @@ pg_SetDefaultWindowSurface(PyObject *);
static FILE*
pg_Fopen(const char *filename, const char *mode) {
FILE *fp = NULL;
static wchar_t modebuf[32];
static wchar_t modebuf[24];
size_t nameInputSize = strlen(filename) + 1;
size_t namebuf_chars = MultiByteToWideChar(CP_UTF8, 0, filename, nameInputSize, 0, 0);
wchar_t* namebuf;
@@ -85,6 +85,24 @@ utf_8_needs_UCS_4(const char *str)
return 0;
}

static PyObject *
pg_open_obj(PyObject *obj, const char *mode)
{
PyObject *result;
PyObject *open;
PyObject *bltins = PyImport_ImportModule(BUILTINS_MODULE);
if (!bltins)
return NULL;
open = PyObject_GetAttrString(bltins, "open");
Py_DECREF(bltins);
if (!open)
return NULL;

result = PyObject_CallFunction(open, "Os", obj, mode);
Py_DECREF(open);
return result;
}

/* Return an encoded file path, a file-like object or a NULL pointer.
* May raise a Python error. Use PyErr_Occurred to check.
*/
@@ -624,7 +642,9 @@ font_init(PyFontObject *self, PyObject *args, PyObject *kwds)
int fontsize;
TTF_Font *font = NULL;
PyObject *obj;
PyObject *oencoded;
PyObject *test;
PyObject *oencoded = NULL;
const char *filename;

self->font = NULL;
if (!PyArg_ParseTuple(args, "Oi", &obj, &fontsize)) {
@@ -657,65 +677,57 @@ font_init(PyFontObject *self, PyObject *args, PyObject *kwds)
if (fontsize <= 1) {
fontsize = 1;
}
}
else {
oencoded = pgRWopsEncodeFilePath(obj, NULL);
if (oencoded == NULL) {
goto error;
}
if (oencoded == Py_None) {
Py_DECREF(oencoded);
}
else {
Py_DECREF(obj);
obj = oencoded;

oencoded = obj;
Py_INCREF(oencoded);
filename = Bytes_AS_STRING(oencoded);
} else {
/* SDL accepts UTF8 */
oencoded = pgRWopsEncodeString(obj, "UTF8", NULL, NULL);
if (!oencoded || oencoded == Py_None) {
Py_XDECREF(oencoded);
oencoded = NULL;
PyErr_Clear();
goto fileobject;
}
filename = Bytes_AS_STRING(oencoded);
}
if (Bytes_Check(obj)) {
FILE *test;
const char *filename = Bytes_AS_STRING(obj);
if (filename == NULL)
goto error;

/*check if it is a valid file, else SDL_ttf segfaults*/
test = pg_Fopen(filename, "rb");
if (test == NULL) {
PyObject *tmp = NULL;
/*check if it is a valid file, else SDL_ttf segfaults*/
test = pg_open_obj(obj, "rb");
if (test == NULL) {
if (strcmp(filename, font_defaultname) == 0) {
PyObject *tmp;
PyErr_Clear();

if (strcmp(filename, font_defaultname) == 0) {
/* filename is the default font; get it's resource
*/
tmp = font_resource(font_defaultname);
if (tmp == NULL) {
if (PyErr_Occurred() == NULL) {
PyErr_Format(PyExc_IOError,
"unable to read font file '%.1024s'",
filename);
}
goto error;
}
Py_DECREF(obj);
obj = tmp;
if (Bytes_Check(obj)) {
filename = Bytes_AS_STRING(obj);
test = fopen(filename, "rb");
tmp = font_resource(font_defaultname);
if (tmp == NULL) {
if (!PyErr_Occurred()) {
PyErr_Format(PyExc_IOError,
"unable to read font file '%.1024s'",
filename);
}
goto error;
}
if (test == NULL) {
Py_DECREF(obj);
obj = tmp;
filename = Bytes_AS_STRING(obj);
test = pg_open_obj(obj, "rb");
}
if (test == NULL) {
if (!PyErr_Occurred()) {
PyErr_Format(PyExc_IOError,
"unable to read font file '%.1024s'",
filename);
goto error;
}
}
if (test != NULL) {
fclose(test);
Py_BEGIN_ALLOW_THREADS;
font = TTF_OpenFont(filename, fontsize);
Py_END_ALLOW_THREADS;
goto error;
}
}
Py_DECREF(test);
Py_BEGIN_ALLOW_THREADS;
font = TTF_OpenFont(filename, fontsize);
Py_END_ALLOW_THREADS;

fileobject:
if (font == NULL) {
#if FONT_HAVE_RWOPS
SDL_RWops *rw = pgRWopsFromFileObject(obj);
@@ -744,11 +756,13 @@ font_init(PyFontObject *self, PyObject *args, PyObject *kwds)
goto error;
}

Py_XDECREF(oencoded);
Py_DECREF(obj);
self->font = font;
return 0;

error:
Py_XDECREF(oencoded);
Py_DECREF(obj);
return -1;
}
@@ -96,7 +96,8 @@ image_load_ext(PyObject *self, PyObject *arg)
return NULL;
}

oencoded = pgRWopsEncodeFilePath(obj, pgExc_SDLError);
/*oencoded = pgRWopsEncodeFilePath(obj, pgExc_SDLError);*/
oencoded = pgRWopsEncodeString(obj, "UTF-8", NULL, pgExc_SDLError);
if (oencoded == NULL) {
return NULL;
}
@@ -123,7 +124,8 @@ image_load_ext(PyObject *self, PyObject *arg)
if (name == NULL) {
oname = PyObject_GetAttrString(obj, "name");
if (oname != NULL) {
oencoded = pgRWopsEncodeFilePath(oname, NULL);
/*oencoded = pgRWopsEncodeFilePath(oname, NULL);*/
oencoded = pgRWopsEncodeString(oname, "UTF-8", NULL, NULL);
Py_DECREF(oname);
if (oencoded == NULL) {
return NULL;
@@ -173,6 +175,24 @@ image_load_ext(PyObject *self, PyObject *arg)
return final;
}

static PyObject *
pg_open(const char *filename, const char *mode)
{
PyObject *result;
PyObject *open;
PyObject *bltins = PyImport_ImportModule(BUILTINS_MODULE);
if (!bltins)
return NULL;
open = PyObject_GetAttrString(bltins, "open");
Py_DECREF(bltins);
if (!open)
return NULL;

result = PyObject_CallFunction(open, "ss", filename, mode);
Py_DECREF(open);
return result;
}

#ifdef PNG_H

static void
@@ -201,7 +221,7 @@ write_png(const char *file_name, png_bytep *rows, int w, int h, int colortype,
{
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
FILE *fp = NULL;
FILE *fp;
char *doing = "open for writing";

if (!(fp = pg_Fopen(file_name, "wb")))
@@ -495,7 +515,7 @@ write_jpeg(const char *file_name, unsigned char **image_buffer,
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);

if ((outfile = pg_Fopen(file_name, "wb")) == NULL) {
if (!(outfile = pg_Fopen(file_name, "wb"))) {
SDL_SetError("SaveJPEG: could not open %s", file_name);
return -1;
}
@@ -752,7 +772,7 @@ image_save_ext(PyObject *self, PyObject *arg)
pgSurface_Prep(surfobj);
#endif /* IS_SDLv2 */

oencoded = pgRWopsEncodeFilePath(obj, pgExc_SDLError);
oencoded = pgRWopsEncodeString(obj, "UTF-8", NULL, pgExc_SDLError);
if (oencoded == Py_None) {
PyErr_Format(PyExc_TypeError,
"Expected a string for the file argument: got %.1024s",
@@ -406,15 +406,17 @@ def test_load_default_font_filename(self):

def test_load_from_file_unicode(self):
import shutil
import tempfile
tmpdirname = tempfile.mkdtemp().encode('utf8')
if sys.version_info.major < 3:
fdir = FONTDIR.encode()
else:
fdir = FONTDIR
temp = os.path.join(fdir, u'给中国人的秘密信息.ttf')
pgfont = os.path.join(fdir, u'test_sans.ttf')
shutil.copy(pgfont, temp)
try:
newfontpath = os.path.join(tmpdirname, u'给中国人的秘密信息.ttf'.encode('utf8'))
pgfont = os.path.join(FONTDIR, u'test_sans.ttf').encode('utf8')
shutil.copy(pgfont, newfontpath)
pygame_font.Font(newfontpath, 20)
pygame_font.Font(temp, 20)
finally:
shutil.rmtree(tmpdirname)
os.remove(temp)

def test_load_from_file_bytes(self):
font_path = os.path.join(os.path.split(pygame.__file__)[0],
@@ -19,13 +19,15 @@ def test_save_non_string_file(self):
def test_load_non_string_file(self):
self.assertRaises(pygame.error, imageext.load_extended, [])

@unittest.skip("SDL silently removes invalid characters")
def test_save_bad_filename(self):
im = pygame.Surface((10, 10), 0, 32)
u = as_unicode(r"a\x00b\x00c.png")
u = u"a\x00b\x00c.png"
self.assertRaises(pygame.error, imageext.save_extended, im, u)

@unittest.skip("SDL silently removes invalid characters")
def test_load_bad_filename(self):
u = as_unicode(r"a\x00b\x00c.png")
u = u"a\x00b\x00c.png"
self.assertRaises(pygame.error, imageext.load_extended, u)

def test_save_unknown_extension(self):
@@ -37,12 +39,16 @@ def test_load_unknown_extension(self):
s = "foo.bar"
self.assertRaises(pygame.error, imageext.load_extended, s)

def test_load_unknown_file(self):
s = "nonexistent.png"
self.assertRaises(pygame.error, imageext.load_extended, s)

def test_load_unicode_path(self):
u = unicode_(example_path("data/alien1.png"))
im = imageext.load_extended(u)

def test_save_unicode_path(self):
temp_file = u"你好.png".encode('utf8')
temp_file = u"你好.png"
im = pygame.Surface((10, 10), 0, 32)
try:
os.remove(temp_file)
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.