Commits

Lenard Lindstrom  committed 2978031

merge fsencoding branch back into trunk, correcting Unicode file path encoding

  • Participants
  • Parent commits 43a8850

Comments (0)

Files changed (28)

 # BREAK = change breaks existing code
 # BUG    = fixed a bug that was (or could have been) crashing
 
+[SVN 2921] September 15, 2010
+    Merge fsencoding branch back into trunk. This adds corrected Unicode file path
+    handling to Pygame. File paths can contain any UTF-32 character, except \x00,
+    provided the file system encoding can handle it. It is also one more step
+    towards a full Python 3.1 port of Pygame.
+
 [SVN 2914, 2916] September 15, 2010
     Preparation for merge with fsencoding branch
 

File docs/filepaths.html

+<html>
+<title>Pygame Documentation</title>
+<body bgcolor="#aaeebb" text="#000000" link="#331111" vlink="#331111">
+
+  <table cellpadding="0" cellspacing="0" border="0" style="border: 3px solid black;" width="100%">
+    <tr><td bgcolor="#c2fc20" style="padding: 6px;" align="center"
+            valign="center">
+      <a href="http://www.pygame.org/"><img src="pygame_tiny.gif" border="0"
+                                            width="200" height="60"></a><br>
+      <b>pygame documentation</b>
+    </td>
+    <td bgcolor="#6aee28" style="border-left: 3px solid black; padding: 6px;"
+        align="center" valign="center">
+      ||&nbsp;
+      <a href="http://www.pygame.org">Pygame Home</a> &nbsp;||&nbsp;
+      <a href="index.html">Help Contents</a> &nbsp;||
+      <a href="ref/index.html">Reference Index</a> &nbsp;||
+      <br>&nbsp;<br>
+	
+      <h1>File Path Function Arguments</h1>
+      
+    </td>
+  </tr>
+</table>
+<br>
+
+<p>
+A Pygame function or method which takes a file path argument
+will accept either a Unicode or an 8-bit character (byte) string.
+Unicode strings are translated to Python's default file system encoding,
+as returned by sys.getfilesystemencoding().
+An Unicode code point above U+FFFF&thinsp;&mdash;&thinsp;'\uFFFF'&thinsp;&mdash;&thinsp;can
+be coded directly with a 32-bit escape
+sequences&thinsp;&mdash;&thinsp;'\Uxxxxxxxx'&thinsp;&mdash;&thinsp;,
+even for Python interpreters built with an UCS-2 (16-bit character) unicode type.
+8-bit character (byte) strings are passed to the operating system unchanged.
+</p>
+
+<p>
+Null characters&thinsp;&mdash;&thinsp;'\x00'&thinsp;&mdash;&thinsp;
+are not permitted in the path, raising an exception.
+An exception is also raised if a Unicode file path cannot be encoded.
+How UTF-16 surrogate codes are handled is Python interpreter dependent.
+Use UTF-32 code points and 32-bit escape sequences instead.
+The exception types are function dependent.
+</p>
+
+</body></html>

File docs/index.html

 Pygame on several platforms. Also help on finding and installing
 prebuilt binaries for your systems.</dd>
 
+<dt><a href="./filepaths.html">File Path Function Arguments</a></dt><dd> 
+How Pygame handles file system paths.</dd>
+
 <dt><a href="../LGPL">LGPL License</a></dt><dd> This is the license Pygame is
 distributed under. It provides for Pygame to be distributed with open
 source and commercial software. Generally, if Pygame is not changed, it

File docs/ref/font.html

   <i>draw text on a new Surface</i><br>
   <tt>Font.render(text, antialias, color, background=None): return Surface</tt><br>
 <p>This creates a new Surface with the specified text rendered on it. Pygame provides no way to directly draw text on an existing Surface: instead you must use <tt><a href="freetype.html#Font.render">Font.render</a> - <font size=-1>Renders text on a surface</font></tt> to create an image (Surface) of the text, then blit this image onto another Surface. </p>
-<p>The text can only be a single line: newline characters are not rendered. Null characters ('\x00') are treated as end-of-text. Both Unicode and char (byte) strings are accepted. For Unicode strings only <tt>UCS-2</tt> characters ('\u0001' to '\uFFFF') are recognized. Behavior is undefined for anything greater. For char strings a <tt>LATIN1</tt> encoding is assumed. The antialias argument is a boolean: if true the characters will have smooth edges. The color argument is the color of the text <tt>[e.g.:</tt> (0,0,255) for blue]. The optional background argument is a color to use for the text background. If no background is passed the area outside the text will be transparent. </p>
+<p>The text can only be a single line: newline characters are not rendered. Null characters ('\x00') raise a TypeError. Both Unicode and char (byte) strings are accepted. For Unicode strings only <tt>UCS-2</tt> characters ('\u0001' to '\uFFFF') are recognized. Anything greater raises a UnicodeError. For char strings a <tt>LATIN1</tt> encoding is assumed. The antialias argument is a boolean: if true the characters will have smooth edges. The color argument is the color of the text <tt>[e.g.:</tt> (0,0,255) for blue]. The optional background argument is a color to use for the text background. If no background is passed the area outside the text will be transparent. </p>
 <p>The Surface returned will be of the dimensions required to hold the text. (the same as those returned by <tt>Font.size())</tt>. If an empty string is passed for the text, a blank surface will be returned that is one pixel wide and the height of the font. </p>
 <p>Depending on the type of background and antialiasing used, this returns different types of Surfaces. For performance reasons, it is good to know what type of image will be used. If antialiasing is not used, the return image will always be an 8bit image with a two color palette. If the background is transparent a colorkey will be set. Antialiased images are rendered to 24-bit <tt>RGB</tt> images. If the background is transparent a pixel alpha will be included. </p>
 <p>Optimization: if you know that the final destination for the text (on the screen) will always have a solid background, and the text is antialiased, you can improve performance by specifying the background color. This will cause the resulting image to maintain transparency information by colorkey rather than (much less efficient) alpha values. </p>

File docs/ref/index.html

 <li><a href="draw.html#pygame.draw.polygon">pygame.draw.polygon</a> - <font size=-1>draw a shape with any number of sides</font></li>
 <li><a href="draw.html#pygame.draw.rect">pygame.draw.rect</a> - <font size=-1>draw a rectangle shape</font></li>
 </ul>
+<li><a href="pygame.html#pygame.encode_file_path">pygame.encode_file_path</a> - <font size=-1>Encode a unicode or bytes object as a file system path</font></li>
+<li><a href="pygame.html#pygame.encode_string">pygame.encode_string</a> - <font size=-1>Encode a unicode or bytes object</font></li>
 <li><a href="pygame.html#pygame.error">pygame.error</a> - <font size=-1>standard pygame exception</font></li>
 <li><a href="event.html#pygame.event">pygame.event</a> - <font size=-1>pygame module for interacting with events and queues</font></li>
 <ul>

File docs/ref/pygame.html

   <tr><td><a href="pygame.html#pygame.get_sdl_version">pygame.get_sdl_version</a> - <font size=-1>get the version number of SDL</font></td><td>get the version number of SDL</td></tr>
   <tr><td><a href="pygame.html#pygame.get_sdl_byteorder">pygame.get_sdl_byteorder</a> - <font size=-1>get the byte order of SDL</font></td><td>get the byte order of SDL</td></tr>
   <tr><td><a href="pygame.html#pygame.register_quit">pygame.register_quit</a> - <font size=-1>register a function to be called when pygame quits</font></td><td>register a function to be called when pygame quits</td></tr>
+  <tr><td><a href="pygame.html#pygame.encode_string">pygame.encode_string</a> - <font size=-1>Encode a unicode or bytes object</font></td><td>Encode a unicode or bytes object</td></tr>
+  <tr><td><a href="pygame.html#pygame.encode_file_path">pygame.encode_file_path</a> - <font size=-1>Encode a unicode or bytes object as a file system path</font></td><td>Encode a unicode or bytes object as a file system path</td></tr>
   <tr><td><a href="pygame.html#pygame.version">pygame.version</a> - <font size=-1>small module containing version information</font></td><td>small module containing version information</td></tr>
 </table></small></ul>
 <p>The pygame package represents the top-level package for others to use. Pygame itself is broken into many submodules, but this does not affect programs that use Pygame. </p>
 <br></ul>
 
 
+<a name="pygame.encode_string">
+<big><b>pygame.encode_string</big></b><br><ul>
+  <i>Encode a unicode or bytes object</i><br>
+  <tt>encode_string([obj [, encoding [, errors [, etype]]]]) => bytes or None</tt><br>
+<p>obj: If unicode, encode; if bytes, return unaltered; if anything else, </p>
+<pre>  return None; if not given, raise SyntaxError.
+  encoding (string): If present, encoding to use. The default is
+  'unicode_escape'.
+</pre><p>errors (string): If given, how to handle unencodable characters. </p>
+<pre>  The default is 'backslashreplace'.
+</pre><p>etype (exception type): If given, the exception type to raise for </p>
+<pre>  an encoding error. The default is UnicodeEncodeError, as returned
+  by PyUnicode_AsEncodedString(). For the default encoding and
+  errors values there should be no encoding errors.
+</pre><p>This function is used in encoding file paths. Keyword arguments are supported. </p>
+<p>Added in Pygame <tt>1.9.2</tt> (primarily for use in unit tests) </p>
+<!--COMMENTS:pygame.encode_string--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="pygame.encode_file_path">
+<big><b>pygame.encode_file_path</big></b><br><ul>
+  <i>Encode a unicode or bytes object as a file system path</i><br>
+  <tt>encode_file_path([obj [, etype]]) => bytes or None</tt><br>
+<p>obj: If unicode, encode; if bytes, return unaltered; if anything else, </p>
+<pre>  return None; if not given, raise SyntaxError.
+</pre><p>etype (exception type): If given, the exception type to raise for </p>
+<pre>  an encoding error. The default is UnicodeEncodeError, as returned
+  by PyUnicode_AsEncodedString().
+</pre><p>This function is used to encode file paths in Pygame. Encoding is to the codec as returned by <tt>sys.getfilesystemencoding()</tt>. Keyword arguments are supported. </p>
+<p>Added in Pygame <tt>1.9.2</tt> (primarily for use in unit tests) </p>
+<!--COMMENTS:pygame.encode_file_path--> &nbsp;<br> 
+<br></ul>
+
+
 <a name="pygame.version">
 <big><b>pygame.version</big></b><br><ul>
   <i>small module containing version information</i><br>

File lib/__init__.py

 from pygame.version import *
 from pygame.rect import Rect
 from pygame.compat import geterror
-import pygame.rwobject
+from pygame.rwobject import encode_string, encode_file_path
 import pygame.surflock
 import pygame.color
 Color = color.Color
 
 
 #cleanup namespace
-del pygame, os, sys, rwobject, surflock, MissingModule, copy_reg, geterror
+del pygame, os, sys, surflock, MissingModule, copy_reg, geterror

File lib/compat.py

 except NameError:
     raw_input_ = input
 
+if sys.version_info >= (3, 0, 0):
+    filesystem_errors = "surrogateescape"
+else:
+    filesystem_errors = "strict"
+    
+def filesystem_encode(u):
+    return u.encode(sys.getfilesystemencoding(), filesystem_errors)
+
 # Represent escaped bytes and strings in a portable way.
 #
 # as_bytes: Allow a Python 3.x string to represent a bytes object.

File src/doc/math_doc.h

 
 #define DOC_ ""
 
+#define DOC_ ""
+
 
 
 /* Docs in a comments... slightly easier to read. */
 
 
 
+
+ 
+
+
+
 */
 

File src/doc/midi_doc.h

 
 #define DOC_PYGAMEMIDITIME "pygame.midi.time(): return time\nreturns the current time in ms of the PortMidi timer"
 
+#define DOC_ ""
+
 
 
 /* Docs in a comments... slightly easier to read. */
 
 
 
+
+ 
+
+
+
 */
 

File src/doc/pygame_doc.h

 
 #define DOC_PYGAMEREGISTERQUIT "register_quit(callable): return None\nregister a function to be called when pygame quits"
 
+#define DOC_PYGAMEENCODESTRING "encode_string([obj [, encoding [, errors [, etype]]]]) => bytes or None\nEncode a unicode or bytes object"
+
+#define DOC_PYGAMEENCODEFILEPATH "encode_file_path([obj [, etype]]) => bytes or None\nEncode a unicode or bytes object as a file system path"
+
 #define DOC_PYGAMEVERSION "module pygame.version\nsmall module containing version information"
 
 #define DOC_PYGAMEVERSIONVER "pygame.version.ver = '1.2'\nversion number as a string"
 
 
 
+pygame.encode_string
+ encode_string([obj [, encoding [, errors [, etype]]]]) => bytes or None
+Encode a unicode or bytes object
+
+
+
+pygame.encode_file_path
+ encode_file_path([obj [, etype]]) => bytes or None
+Encode a unicode or bytes object as a file system path
+
+
+
 pygame.version
  module pygame.version
 small module containing version information
 #include "doc/font_doc.h"
 #include "structmember.h"
 
+/* Do we need to support anything before 2006? */
+#if !defined(TTF_MAJOR_VERSION)
+#error Require SDL_ttf 1.2.6 or later
+#endif
+
 #if PY3
 #define RAISE_TEXT_TYPE_ERROR() \
     RAISE(PyExc_TypeError, "text must be a unicode or bytes");
 #endif
 
 
+/*
+ */
+static int
+utf_8_needs_UCS_4(const char *str)
+{
+    static const Uint8 first = 0xF0;
+    
+    while (*str) {
+        if ((Uint8)*str >= first) {
+            return 1;
+        }
+        ++str;
+    }
+    return 0;
+}
+
+/* Return an encoded file path, a file-like object or a NULL pointer.
+ * May raise a Python error. Use PyErr_Occurred to check.
+ */
 static PyObject*
 font_resource (const char *filename)
 {
-    PyObject* load_basicfunc = NULL;
     PyObject* pkgdatamodule = NULL;
     PyObject* resourcefunc = NULL;
     PyObject* result = NULL;
-#if PY3
     PyObject* tmp;
-#endif
 
-    pkgdatamodule = PyImport_ImportModule (pkgdatamodule_name);
-    if (!pkgdatamodule)
-        goto font_resource_end;
+    pkgdatamodule = PyImport_ImportModule(pkgdatamodule_name);
+    if (pkgdatamodule == NULL) {
+        return NULL;
+    }
 
-    resourcefunc = PyObject_GetAttrString (pkgdatamodule, resourcefunc_name);
-    if (!resourcefunc)
-        goto font_resource_end;
+    resourcefunc = PyObject_GetAttrString(pkgdatamodule, resourcefunc_name);
+    Py_DECREF(pkgdatamodule);
+    if (resourcefunc == NULL) {
+        return NULL;
+    }
 
-    result = PyObject_CallFunction (resourcefunc, "s", filename);
-    if (!result)
-        goto font_resource_end;
+    result = PyObject_CallFunction(resourcefunc, "s", filename);
+    Py_DECREF(resourcefunc);
+    if (result == NULL) {
+        return NULL;
+    }
 
 #if PY3
-    tmp = PyObject_GetAttrString (result, "name");
+    tmp = PyObject_GetAttrString(result, "name");
     if (tmp != NULL) {
-        Py_DECREF (result);
+        Py_DECREF(result);
         result = tmp;
     }
-    else {
-        PyErr_Clear ();
+    else if (!PyErr_ExceptionMatches(PyExc_MemoryError)) {
+        PyErr_Clear();
     }
 #else
-    if (PyFile_Check (result))
+    if (PyFile_Check(result))
     {		
-        PyObject *tmp = PyFile_Name (result);        
-        Py_INCREF (tmp);
-        Py_DECREF (result);
+        tmp = PyFile_Name(result);        
+        Py_INCREF(tmp);
+        Py_DECREF(result);
         result = tmp;
     }
 #endif
 
-font_resource_end:
-    Py_XDECREF (pkgdatamodule);
-    Py_XDECREF (resourcefunc);
-    Py_XDECREF (load_basicfunc);
+    tmp = RWopsEncodeFilePath(result, NULL);
+    if (tmp == NULL) {
+        Py_DECREF(result);
+        return NULL;
+    }
+    else if (tmp != Py_None) {
+        Py_DECREF(result);
+        result = tmp;
+    }
+    else {
+        Py_DECREF(tmp);
+    }
+
     return result;
 }
 
     }
 
     if (!RGBAFromColorObj(fg_rgba_obj, rgba)) {
-        return RAISE (PyExc_TypeError, "Invalid foreground RGBA argument");
+        return RAISE(PyExc_TypeError, "Invalid foreground RGBA argument");
     }
     foreg.r = rgba[0];
     foreg.g = rgba[1];
     foreg.b = rgba[2];
     if (bg_rgba_obj != NULL) {
         if (!RGBAFromColorObj(bg_rgba_obj, rgba)) {
-            return RAISE (PyExc_TypeError, "Invalid background RGBA argument");
+            return RAISE(PyExc_TypeError, "Invalid background RGBA argument");
         }
         backg.r = rgba[0];
         backg.g = rgba[1];
         surf = SDL_CreateRGBSurface(SDL_SWSURFACE, 1, height, 32,
                                     0xff<<16, 0xff<<8, 0xff, 0);
         if (surf == NULL) {
-            return RAISE (PyExc_SDLError, SDL_GetError());
+            return RAISE(PyExc_SDLError, SDL_GetError());
         }
         if (bg_rgba_obj != NULL) {
             Uint32 c = SDL_MapRGB(surf->format, backg.r, backg.g, backg.b);
         if (!bytes) {
             return NULL;
         }
-        astring = Bytes_AsString (bytes);
+        astring = Bytes_AsString(bytes);
+        if (strlen(astring) != Bytes_GET_SIZE(bytes)) {
+            Py_DECREF(bytes);
+            return RAISE(PyExc_ValueError,
+                         "A null character was found in the text");
+        }
+        if (utf_8_needs_UCS_4(astring)) {
+            Py_DECREF(bytes);
+            return RAISE(PyExc_UnicodeError,
+                         "A Unicode character above '\\uFFFF' was found;"
+                         " not supported");
+        }
         if (aa) {
             if (bg_rgba_obj == NULL) {
                 surf = TTF_RenderUTF8_Blended(font, astring, foreg);
         else {
             surf = TTF_RenderUTF8_Solid(font, astring, foreg);
         }
-        Py_DECREF (bytes);
+        Py_DECREF(bytes);
     }
     else if (Bytes_Check(text)) {
         const char *astring = Bytes_AsString(text);
 
+        if (strlen(astring) != Bytes_GET_SIZE(text)) {
+            return RAISE(PyExc_ValueError,
+                         "A null character was found in the text");
+        }
         if (aa) {
             if (bg_rgba_obj == NULL) {
                 surf = TTF_RenderText_Blended(font, astring, foreg);
         return RAISE_TEXT_TYPE_ERROR();
     }
     if (surf == NULL) {
-        return RAISE (PyExc_SDLError, TTF_GetError());
+        return RAISE(PyExc_SDLError, TTF_GetError());
     }
     if (!aa && (bg_rgba_obj != NULL) && !just_return) {
         /* turn off transparancy */
 
     if (PyUnicode_Check(text))
     {
-        PyObject* bytes = PyUnicode_AsEncodedString(text, "utf-8", "replace");
+        PyObject* bytes = PyUnicode_AsEncodedString(text, "utf-8", "strict");
         int ecode;
         
         if (!bytes) {
 }
 
 static int
-font_init (PyFontObject *self, PyObject *args, PyObject *kwds)
+font_init(PyFontObject *self, PyObject *args, PyObject *kwds)
 {
     int fontsize;
-    TTF_Font* font = NULL;
-    PyObject* fileobj;
+    TTF_Font *font = NULL;
+    PyObject *obj;
+    PyObject *oencoded;
     
     self->font = NULL;
-    if (!PyArg_ParseTuple (args, "Oi", &fileobj, &fontsize))
-        return -1;
-
-    if (!font_initialized)
-    {
-        RAISE (PyExc_SDLError, "font not initialized");
+    if (!PyArg_ParseTuple(args, "Oi", &obj, &fontsize)) {
         return -1;
     }
 
-    Py_INCREF (fileobj);
+    if (!font_initialized) {
+        RAISE(PyExc_SDLError, "font not initialized");
+        return -1;
+    }
 
-    if (fontsize <= 1)
+    Py_INCREF(obj);
+
+    if (fontsize <= 1) {
         fontsize = 1;
+    }
 
-    if (fileobj == Py_None)
-    {
-        Py_DECREF(fileobj);
-        fileobj = font_resource (font_defaultname);
-        if (fileobj == NULL)
-        {
-            char error[1024];
-            PyOS_snprintf (error, 1024, "default font not found '%s'",
-                      font_defaultname);
-            RAISE (PyExc_RuntimeError, error);
+    if (obj == Py_None) {
+        Py_DECREF(obj);
+        obj = font_resource(font_defaultname);
+        if (obj == NULL) {
+            if (PyErr_Occurred() == NULL) {
+                PyErr_Format(PyExc_RuntimeError,
+                             "default font '%.1024s' not found",
+                             font_defaultname);
+            }
             goto error;
         }
-        fontsize = (int) (fontsize * .6875);
-        if (fontsize <= 1)
+        fontsize = (int)(fontsize * .6875);
+        if (fontsize <= 1) {
             fontsize = 1;
+        }
     }
-     
-    if (PyUnicode_Check (fileobj)) {
-        PyObject* tmp = PyUnicode_AsASCIIString (fileobj);
-
-        if (tmp == NULL) {
+    else {
+        oencoded = RWopsEncodeFilePath(obj, NULL);
+        if (oencoded == NULL) {
             goto error;
         }
-        Py_DECREF(fileobj);
-        fileobj = tmp;
+        if (oencoded == Py_None) {
+            Py_DECREF(oencoded);
+        }
+        else {
+            Py_DECREF(obj);
+            obj = oencoded;
+        }
     }
-
-    if (Bytes_Check (fileobj))
-    {
-        FILE* test;        
-        char* filename = Bytes_AsString (fileobj);
+    if (Bytes_Check(obj)) {
+        const char *filename = Bytes_AS_STRING(obj);
+        FILE *test;        
        		
-        if (!filename) {
-            goto error;
-        }
-                
         /*check if it is a valid file, else SDL_ttf segfaults*/
-        test = fopen (filename, "rb");
-        if(!test)
-        {
+        test = fopen(filename, "rb");
+        if(test == NULL) {
             PyObject *tmp = NULL;
 
-            if (!strcmp (filename, font_defaultname)) {
-                tmp = font_resource (font_defaultname);
+            if (!strcmp(filename, font_defaultname)) {
+                /* filename is the default font; get it's file-like resource
+                 */
+                tmp = font_resource(font_defaultname);
             }
-            if (!tmp)
-            {
-                PyErr_SetString (PyExc_IOError,
-                                 "unable to read font filename");
+            if (tmp == NULL) {
+                if (PyErr_Occurred() == NULL) {
+                    PyErr_Format(PyExc_IOError,
+                                 "unable to read font file '%.1024s'",
+                                 filename);
+                }
                 goto error;
             }
-            Py_DECREF (fileobj);
-            fileobj = tmp;
+            Py_DECREF(obj);
+            obj = tmp;
         }
-        else
-        {
-            fclose (test);
+        else {
+            fclose(test);
             Py_BEGIN_ALLOW_THREADS;
             font = TTF_OpenFont(filename, fontsize);
             Py_END_ALLOW_THREADS;
         }	
     }
-    if (!font)
-    {
-#ifdef TTF_MAJOR_VERSION
-        SDL_RWops *rw;
-        rw = RWopsFromPython (fileobj);
-        if (!rw)
-        {
+    if (font == NULL)  {
+        SDL_RWops *rw = RWopsFromFileObject(obj);
+
+        if (rw == NULL) {
             goto error;
         }
 
-
-
-        if (RWopsCheckPython (rw)) {
-            font = TTF_OpenFontIndexRW (rw, 1, fontsize, 0);
+        if (RWopsCheckObject(rw)) {
+            font = TTF_OpenFontIndexRW(rw, 1, fontsize, 0);
         }
-        else
-        {
-         Py_BEGIN_ALLOW_THREADS;
-         font = TTF_OpenFontIndexRW (rw, 1, fontsize, 0);
-         Py_END_ALLOW_THREADS;
+        else {
+             Py_BEGIN_ALLOW_THREADS;
+             font = TTF_OpenFontIndexRW(rw, 1, fontsize, 0);
+             Py_END_ALLOW_THREADS;
         }
- #else
-         RAISE (PyExc_NotImplementedError,
-                "nonstring fonts require SDL_ttf-2.0.6");
-        goto error;
-#endif
     }
 
-    if (!font)
-    {
-        RAISE (PyExc_RuntimeError, SDL_GetError ());
+    if (font == NULL) {
+        RAISE(PyExc_RuntimeError, SDL_GetError());
         goto error;
     }
 
-    Py_DECREF (fileobj);
+    Py_DECREF(obj);
     self->font = font;
     return 0;
 
 error:
-    Py_DECREF (fileobj);
+    Py_DECREF(obj);
     return -1;
 }
 

File src/font.doc

 the text, then blit this image onto another Surface.
 
 The text can only be a single line: newline characters are not rendered.
-Null characters ('\x00') are treated as end-of-text.
+Null characters ('\x00') raise a TypeError.
 Both Unicode and char (byte) strings are accepted.
 For Unicode strings only UCS-2 characters ('\u0001' to '\uFFFF') are recognized.
-Behavior is undefined for anything greater.
+Anything greater raises a UnicodeError.
 For char strings a LATIN1 encoding is assumed.
 The antialias argument is a boolean: if true the characters will have
 smooth edges. The color argument is the color of the text
 #define GETSTATE(m) PY2_GETSTATE (_state)
 #endif
 
-static int SaveTGA (SDL_Surface *surface, char *file, int rle);
+static int SaveTGA (SDL_Surface *surface, const char *file, int rle);
 static int SaveTGA_RW (SDL_Surface *surface, SDL_RWops *out, int rle);
 static SDL_Surface* opengltosdl (void);
 
      (((char*) data) + row * width))
 
 static PyObject*
-image_load_basic (PyObject* self, PyObject* arg)
+image_load_basic(PyObject *self, PyObject *arg)
 {
-    PyObject* file, *final;
-    char* name = NULL;
+    PyObject *obj;
+    PyObject *final;
+    PyObject *oencoded;
+    const char *name = NULL;
     SDL_Surface* surf;
     SDL_RWops *rw;
-    if (!PyArg_ParseTuple (arg, "O|s", &file, &name))
+
+    if (!PyArg_ParseTuple(arg, "O|s", &obj, &name)) {
         return NULL;
+    }
 
-#if PY3
-    if (PyUnicode_Check (file)) {
-        if (!PyArg_ParseTuple (arg, "s|O", &name, &file))
+    oencoded = RWopsEncodeFilePath(obj, PyExc_SDLError);
+    if (oencoded == NULL) {
+        return NULL;
+    }
+    if (oencoded != Py_None) {
+        Py_BEGIN_ALLOW_THREADS;
+        surf = SDL_LoadBMP(Bytes_AS_STRING(oencoded));
+        Py_END_ALLOW_THREADS;
+        Py_DECREF(oencoded);
+    }
+    else {
+        Py_DECREF(oencoded);
+        rw = RWopsFromFileObject(obj);
+        if (rw == NULL) {
             return NULL;
-        Py_BEGIN_ALLOW_THREADS;
-        surf = SDL_LoadBMP (name);
-        Py_END_ALLOW_THREADS;
-    }
-    else if (PyBytes_Check (file)) {
-        if (!PyArg_ParseTuple (arg, "y|O", &name, &file))
-            return NULL;
-        Py_BEGIN_ALLOW_THREADS;
-        surf = SDL_LoadBMP (name);
-        Py_END_ALLOW_THREADS;
-    }
-#else
-    if (PyString_Check (file) || PyUnicode_Check (file))
-    {
-        if (!PyArg_ParseTuple (arg, "s|O", &name, &file))
-            return NULL;
-        Py_BEGIN_ALLOW_THREADS;
-        surf = SDL_LoadBMP (name);
-        Py_END_ALLOW_THREADS;
-    }
-#endif
-    else
-    {
-        if (!(rw = RWopsFromPython (file)))
-            return NULL;
-        if (RWopsCheckPython (rw))
+        }
+        if (RWopsCheckObject(rw)) {
             surf = SDL_LoadBMP_RW (rw, 1);
-        else
-        {
+        }
+        else {
             Py_BEGIN_ALLOW_THREADS;
-            surf = SDL_LoadBMP_RW (rw, 1);
+            surf = SDL_LoadBMP_RW(rw, 1);
             Py_END_ALLOW_THREADS;
         }
     }
-    if (!surf)
-        return RAISE (PyExc_SDLError, SDL_GetError ());
+            
+    if (surf == NULL) {
+        return RAISE(PyExc_SDLError, SDL_GetError());
+    }
 
-    final = PySurface_New (surf);
-    if (!final)
-        SDL_FreeSurface (surf);
+    final = PySurface_New(surf);
+    if (final == NULL) {
+        SDL_FreeSurface(surf);
+    }
     return final;
 }
 
 }
 
 PyObject*
-image_save (PyObject* self, PyObject* arg)
+image_save(PyObject *self, PyObject *arg)
 {
-    PyObject* surfobj, *file;
+    PyObject *surfobj;
+    PyObject *obj;
+    PyObject *oencoded;
     PyObject *imgext = NULL;
     SDL_Surface *surf;
     SDL_Surface *temp = NULL;
-    int result = 0;
+    int result = 1;
 
-    if (!PyArg_ParseTuple (arg, "O!O", &PySurface_Type, &surfobj, &file))
+    if (!PyArg_ParseTuple(arg, "O!O", &PySurface_Type, &surfobj, &obj)) {
         return NULL;
-    surf = PySurface_AsSurface (surfobj);
+    }
+    
+    surf = PySurface_AsSurface(surfobj);
+    if (surf->flags & SDL_OPENGL) {
+        temp = surf = opengltosdl();
+        if (surf == NULL) {
+            return NULL;
+        }
+    }
+    else {
+        PySurface_Prep(surfobj);
+    }
 
-    if (surf->flags & SDL_OPENGL)
-    {
-        temp = surf = opengltosdl ();
-        if (!surf)
-            return NULL;
+    oencoded = RWopsEncodeFilePath(obj, PyExc_SDLError);
+    if (oencoded == Py_None) {
+        SDL_RWops *rw = RWopsFromFileObject(obj);
+        if (rw != NULL) {
+            result = SaveTGA_RW(surf, rw, 1);
+        }
+        else {
+            result = -2;
+        }
     }
-    else
-        PySurface_Prep (surfobj);
-
-#if PY3
-    if (PyBytes_Check (file) || PyUnicode_Check (file))
-#else
-    if (PyString_Check (file) || PyUnicode_Check (file))
-#endif
-    {
-        int namelen;
-        char* name;
+    else if (oencoded != NULL) {
+        const char *name = Bytes_AS_STRING(oencoded);
+        Py_ssize_t namelen = Bytes_GET_SIZE(oencoded);
         int written = 0;
 
-#if PY3
-        if (PyUnicode_Check (file)) {
-            if (!PyArg_ParseTuple (arg, "O|s", &file, &name)) {
-                return NULL;
-            }
-        }
-        else {
-            if (!PyArg_ParseTuple (arg, "O|y", &file, &name)) {
-                return NULL;
-            }
-        }
-#else
-        if (!PyArg_ParseTuple (arg, "O|s", &file, &name))
-            return NULL;
-#endif
-        namelen = strlen (name);
-        if (namelen > 3)
-        {
+        if (namelen > 3) {
             if ((name[namelen - 1]=='p' || name[namelen - 1]=='P') &&
                 (name[namelen - 2]=='m' || name[namelen - 2]=='M') &&
-                (name[namelen - 3]=='b' || name[namelen - 3]=='B'))
-            {
+                (name[namelen - 3]=='b' || name[namelen - 3]=='B'))   {
                 Py_BEGIN_ALLOW_THREADS;
-                result = SDL_SaveBMP (surf, name);
+                result = SDL_SaveBMP(surf, name);
                 Py_END_ALLOW_THREADS;
                 written = 1;
             }
             else if (((name[namelen - 1]=='g' || name[namelen - 1]=='G') &&
-                    (name[namelen - 2]=='n' || name[namelen - 2]=='N') &&
-                    (name[namelen - 3]=='p' || name[namelen - 3]=='P')) ||
-                ((name[namelen - 1]=='g' || name[namelen - 1]=='G') &&
-                    (name[namelen - 2]=='e' || name[namelen - 2]=='E') &&
-                    (name[namelen - 3]=='p' || name[namelen - 3]=='P') &&
-                    (name[namelen - 4]=='j' || name[namelen - 4]=='J')) ||
-                ((name[namelen - 1]=='g' || name[namelen - 1]=='G') &&
-                    (name[namelen - 2]=='p' || name[namelen - 2]=='P') &&
-                    (name[namelen - 3]=='j' || name[namelen - 3]=='J')))
-            {
+                      (name[namelen - 2]=='n' || name[namelen - 2]=='N') &&
+                      (name[namelen - 3]=='p' || name[namelen - 3]=='P')) ||
+                     ((name[namelen - 1]=='g' || name[namelen - 1]=='G') &&
+                      (name[namelen - 2]=='e' || name[namelen - 2]=='E') &&
+                      (name[namelen - 3]=='p' || name[namelen - 3]=='P') &&
+                      (name[namelen - 4]=='j' || name[namelen - 4]=='J')) ||
+                     ((name[namelen - 1]=='g' || name[namelen - 1]=='G') &&
+                      (name[namelen - 2]=='p' || name[namelen - 2]=='P') &&
+                      (name[namelen - 3]=='j' || name[namelen - 3]=='J')))  {
                 /* If it is .png .jpg .jpeg use the extended module. */
                 /* try to get extended formats */
-                imgext = PyImport_ImportModule (IMPPREFIX "imageext");
-                if (imgext)
+                imgext = PyImport_ImportModule(IMPPREFIX "imageext");
+                if (imgext != NULL)
                 {
-                    PyObject *extdict = PyModule_GetDict (imgext);
-                    PyObject* extsave = PyDict_GetItemString (extdict,
-                        "save_extended");
-                    PyObject* data = PyObject_CallObject (extsave, arg);
-                    if (!data)
-                        result = -1;
-                    Py_DECREF (imgext);
-                    /* Data must be decremented here, not? */
-                    if (data)
-		    {
-                    	Py_DECREF (data);
-		    }
+                    PyObject *extsave = 
+                        PyObject_GetAttrString(imgext, "save_extended");
+                    PyObject *data;
+                    
+                    Py_DECREF(imgext);
+                    if (extsave != NULL) {
+                        data = PyObject_CallObject(extsave, arg);
+                        Py_DECREF(extsave);
+                        if (data == NULL) {
+                            result = -2;
+                        }
+                        else {
+                            Py_DECREF(data);
+                            result = 0;
+                        }
+                    }
+                    else {
+                        result = -2;
+                    }
                 }
-                else
-		{
+                else {
                     result = -2;
-		}
+                }
                 written = 1;
             }
         }
 
-        if (!written)
-        {
+        if (!written) {
             Py_BEGIN_ALLOW_THREADS;
-            result = SaveTGA (surf, name, 1);
+            result = SaveTGA(surf, name, 1);
             Py_END_ALLOW_THREADS;
         }
     }
-    else
-    {
-        SDL_RWops* rw;
-        if (!(rw = RWopsFromPython (file)))
-            return NULL;
-        result = SaveTGA_RW (surf, rw, 1);
+    else {
+        result = -2;
     }
+    Py_XDECREF(oencoded);
 
-    if (temp)
+    if (temp) {
         SDL_FreeSurface (temp);
-    else
+    }
+    else {
         PySurface_Unprep (surfobj);
+    }
         
-    if (result == -2)
-        return imgext;
-    if (result == -1)
-        return RAISE (PyExc_SDLError, SDL_GetError ());
+    if (result == -2) {
+        /* Python error raised elsewhere */
+        return NULL;
+    }
+    if (result == -1) {
+        /* SDL error: translate to Python error */
+        return RAISE(PyExc_SDLError, SDL_GetError());
+    }
+    if (result == 1) {
+        /* Should never get here */
+        return RAISE(PyExc_SDLError, "Unrecognized image type");
+    }
 
     Py_RETURN_NONE;
 }
 /*******************************************************/
 struct TGAheader
 {
-    Uint8 infolen;		/* length of info field */
-    Uint8 has_cmap;		/* 1 if image has colormap, 0 otherwise */
+    Uint8 infolen;                /* length of info field */
+    Uint8 has_cmap;                /* 1 if image has colormap, 0 otherwise */
     Uint8 type;
 
-    Uint8 cmap_start[2];	/* index of first colormap entry */
-    Uint8 cmap_len[2];		/* number of entries in colormap */
-    Uint8 cmap_bits;		/* bits per colormap entry */
+    Uint8 cmap_start[2];        /* index of first colormap entry */
+    Uint8 cmap_len[2];                /* number of entries in colormap */
+    Uint8 cmap_bits;                /* bits per colormap entry */
 
-    Uint8 yorigin[2];		/* image origin (ignored here) */
+    Uint8 yorigin[2];                /* image origin (ignored here) */
     Uint8 xorigin[2];
-    Uint8 width[2];		/* image size */
+    Uint8 width[2];                /* image size */
     Uint8 height[2];
-    Uint8 pixel_bits;		/* bits/pixel */
+    Uint8 pixel_bits;                /* bits/pixel */
     Uint8 flags;
 };
 
     TGA_TYPE_INDEXED = 1,
     TGA_TYPE_RGB = 2,
     TGA_TYPE_BW = 3,
-    TGA_TYPE_RLE = 8		/* additive */
+    TGA_TYPE_RLE = 8                /* additive */
 };
 
-#define TGA_INTERLEAVE_MASK	0xc0
-#define TGA_INTERLEAVE_NONE	0x00
-#define TGA_INTERLEAVE_2WAY	0x40
-#define TGA_INTERLEAVE_4WAY	0x80
+#define TGA_INTERLEAVE_MASK        0xc0
+#define TGA_INTERLEAVE_NONE        0x00
+#define TGA_INTERLEAVE_2WAY        0x40
+#define TGA_INTERLEAVE_4WAY        0x80
 
-#define TGA_ORIGIN_MASK		0x30
-#define TGA_ORIGIN_LEFT		0x00
-#define TGA_ORIGIN_RIGHT	0x10
-#define TGA_ORIGIN_LOWER	0x00
-#define TGA_ORIGIN_UPPER	0x20
+#define TGA_ORIGIN_MASK                0x30
+#define TGA_ORIGIN_LEFT                0x00
+#define TGA_ORIGIN_RIGHT        0x10
+#define TGA_ORIGIN_LOWER        0x00
+#define TGA_ORIGIN_UPPER        0x20
 
 /* read/write unaligned little-endian 16-bit ints */
 #define LE16(p) ((p)[0] + ((p)[1] << 8))
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 #endif
 
-#define TGA_RLE_MAX 128		/* max length of a TGA RLE chunk */
+#define TGA_RLE_MAX 128                /* max length of a TGA RLE chunk */
 /* return the number of bytes in the resulting buffer after RLE-encoding
    a line of TGA data */
 static int
     int raw = 0;
     while (x < w)
     {
-	Uint32 pix;
-	int x0 = x;
-	memcpy (&pix, src + x * bpp, bpp);
-	x++;
-	while (x < w && memcmp (&pix, src + x * bpp, bpp) == 0
+        Uint32 pix;
+        int x0 = x;
+        memcpy (&pix, src + x * bpp, bpp);
+        x++;
+        while (x < w && memcmp (&pix, src + x * bpp, bpp) == 0
                && x - x0 < TGA_RLE_MAX)
-	    x++;
-	/* use a repetition chunk iff the repeated pixels would consume
-	   two bytes or more */
-	if ((x - x0 - 1) * bpp >= 2 || x == w)
+            x++;
+        /* use a repetition chunk iff the repeated pixels would consume
+           two bytes or more */
+        if ((x - x0 - 1) * bpp >= 2 || x == w)
         {
-	    /* output previous raw chunks */
-	    while (raw < x0)
+            /* output previous raw chunks */
+            while (raw < x0)
             {
-		int n = MIN (TGA_RLE_MAX, x0 - raw);
-		dst[out++] = n - 1;
-		memcpy (dst + out, src + raw * bpp, n * bpp);
-		out += n * bpp;
-		raw += n;
-	    }
+                int n = MIN (TGA_RLE_MAX, x0 - raw);
+                dst[out++] = n - 1;
+                memcpy (dst + out, src + raw * bpp, n * bpp);
+                out += n * bpp;
+                raw += n;
+            }
 
-	    if (x - x0 > 0)
+            if (x - x0 > 0)
             {
-		/* output new repetition chunk */
-		dst[out++] = 0x7f + x - x0;
-		memcpy (dst + out, &pix, bpp);
-		out += bpp;
-	    }
-	    raw = x;
-	}
+                /* output new repetition chunk */
+                dst[out++] = 0x7f + x - x0;
+                memcpy (dst + out, &pix, bpp);
+                out += bpp;
+            }
+            raw = x;
+        }
     }
     return out;
 }
     srcbpp = surface->format->BitsPerPixel;
     if (srcbpp < 8)
     {
-	SDL_SetError ("cannot save <8bpp images as TGA");
-	return -1;
+        SDL_SetError ("cannot save <8bpp images as TGA");
+        return -1;
     }
 
     if (srcbpp == 8)
     {
-	h.has_cmap = 1;
-	h.type = TGA_TYPE_INDEXED;
-	if (surface->flags & SDL_SRCCOLORKEY)
+        h.has_cmap = 1;
+        h.type = TGA_TYPE_INDEXED;
+        if (surface->flags & SDL_SRCCOLORKEY)
         {
-	    ckey = surface->format->colorkey;
-	    h.cmap_bits = 32;
-	}
+            ckey = surface->format->colorkey;
+            h.cmap_bits = 32;
+        }
         else
-	    h.cmap_bits = 24;
-	SETLE16 (h.cmap_len, surface->format->palette->ncolors);
-	h.pixel_bits = 8;
-	rmask = gmask = bmask = amask = 0;
+            h.cmap_bits = 24;
+        SETLE16 (h.cmap_len, surface->format->palette->ncolors);
+        h.pixel_bits = 8;
+        rmask = gmask = bmask = amask = 0;
     }
     else
     {
-	h.has_cmap = 0;
-	h.type = TGA_TYPE_RGB;
-	h.cmap_bits = 0;
-	SETLE16 (h.cmap_len, 0);
-	if (surface->format->Amask)
+        h.has_cmap = 0;
+        h.type = TGA_TYPE_RGB;
+        h.cmap_bits = 0;
+        SETLE16 (h.cmap_len, 0);
+        if (surface->format->Amask)
         {
-	    alpha = 1;
-	    h.pixel_bits = 32;
-	}
+            alpha = 1;
+            h.pixel_bits = 32;
+        }
         else
-	    h.pixel_bits = 24;
-	if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
+            h.pixel_bits = 24;
+        if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
         {
-	    int s = alpha ? 0 : 8;
-	    amask = 0x000000ff >> s;
-	    rmask = 0x0000ff00 >> s;
-	    gmask = 0x00ff0000 >> s;
-	    bmask = 0xff000000 >> s;
-	}
+            int s = alpha ? 0 : 8;
+            amask = 0x000000ff >> s;
+            rmask = 0x0000ff00 >> s;
+            gmask = 0x00ff0000 >> s;
+            bmask = 0xff000000 >> s;
+        }
         else
         {
-	    amask = alpha ? 0xff000000 : 0;
-	    rmask = 0x00ff0000;
-	    gmask = 0x0000ff00;
-	    bmask = 0x000000ff;
-	}
+            amask = alpha ? 0xff000000 : 0;
+            rmask = 0x00ff0000;
+            gmask = 0x0000ff00;
+            bmask = 0x000000ff;
+        }
     }
     bpp = h.pixel_bits >> 3;
     if (rle)
     h.flags = TGA_ORIGIN_UPPER | (alpha ? 8 : 0);
 
     if (!SDL_RWwrite (out, &h, sizeof (h), 1))
-	return -1;
+        return -1;
 
     if (h.has_cmap)
     {
-	int i;
-	SDL_Palette *pal = surface->format->palette;
-	Uint8 entry[4];
-	for (i = 0; i < pal->ncolors; i++)
+        int i;
+        SDL_Palette *pal = surface->format->palette;
+        Uint8 entry[4];
+        for (i = 0; i < pal->ncolors; i++)
         {
-	    entry[0] = pal->colors[i].b;
-	    entry[1] = pal->colors[i].g;
-	    entry[2] = pal->colors[i].r;
-	    entry[3] = (i == ckey) ? 0 : 0xff;
-	    if (!SDL_RWwrite (out, entry, h.cmap_bits >> 3, 1))
-		return -1;
-	}
+            entry[0] = pal->colors[i].b;
+            entry[1] = pal->colors[i].g;
+            entry[2] = pal->colors[i].r;
+            entry[3] = (i == ckey) ? 0 : 0xff;
+            if (!SDL_RWwrite (out, entry, h.cmap_bits >> 3, 1))
+                return -1;
+        }
     }
 
     linebuf = SDL_CreateRGBSurface (SDL_SWSURFACE, surface->w, 1, h.pixel_bits,
                                     rmask, gmask, bmask, amask);
     if (!linebuf)
-	return -1;
+        return -1;
     if (h.has_cmap)
-	SDL_SetColors (linebuf, surface->format->palette->colors, 0,
+        SDL_SetColors (linebuf, surface->format->palette->colors, 0,
                        surface->format->palette->ncolors);
     if (rle)
     {
-	rlebuf = malloc (bpp * surface->w + 1 + surface->w / TGA_RLE_MAX);
-	if (!rlebuf)
+        rlebuf = malloc (bpp * surface->w + 1 + surface->w / TGA_RLE_MAX);
+        if (!rlebuf)
         {
-	    SDL_SetError ("out of memory");
-	    goto error;
-	}
+            SDL_SetError ("out of memory");
+            goto error;
+        }
     }
 
     /* Temporarily remove colourkey and alpha from surface so copies are
     surf_flags = surface->flags & (SDL_SRCALPHA | SDL_SRCCOLORKEY);
     surf_alpha = surface->format->alpha;
     if (surf_flags & SDL_SRCALPHA)
-	SDL_SetAlpha (surface, 0, 255);
+        SDL_SetAlpha (surface, 0, 255);
     if (surf_flags & SDL_SRCCOLORKEY)
-	SDL_SetColorKey (surface, 0, surface->format->colorkey);
+        SDL_SetColorKey (surface, 0, surface->format->colorkey);
 
     r.x = 0;
     r.w = surface->w;
     r.h = 1;
     for (r.y = 0; r.y < surface->h; r.y++)
     {
-	int n;
-	void *buf;
-	if (SDL_BlitSurface (surface, &r, linebuf, NULL) < 0)
-	    break;
-	if (rle)
+        int n;
+        void *buf;
+        if (SDL_BlitSurface (surface, &r, linebuf, NULL) < 0)
+            break;
+        if (rle)
         {
-	    buf = rlebuf;
-	    n = rle_line (linebuf->pixels, rlebuf, surface->w, bpp);
-	}
+            buf = rlebuf;
+            n = rle_line (linebuf->pixels, rlebuf, surface->w, bpp);
+        }
         else
         {
-	    buf = linebuf->pixels;
-	    n = surface->w * bpp;
-	}
-	if (!SDL_RWwrite (out, buf, n, 1))
-	    break;
+            buf = linebuf->pixels;
+            n = surface->w * bpp;
+        }
+        if (!SDL_RWwrite (out, buf, n, 1))
+            break;
     }
 
     /* restore flags */
     if (surf_flags & SDL_SRCALPHA)
-	SDL_SetAlpha (surface, SDL_SRCALPHA, (Uint8)surf_alpha);
+        SDL_SetAlpha (surface, SDL_SRCALPHA, (Uint8)surf_alpha);
     if (surf_flags & SDL_SRCCOLORKEY)
-	SDL_SetColorKey (surface, SDL_SRCCOLORKEY, surface->format->colorkey);
+        SDL_SetColorKey (surface, SDL_SRCCOLORKEY, surface->format->colorkey);
 
 error:
     free (rlebuf);
 }
 
 static int
-SaveTGA (SDL_Surface *surface, char *file, int rle)
+SaveTGA (SDL_Surface *surface, const char *file, int rle)
 {
     SDL_RWops *out = SDL_RWFromFile (file, "wb");
     int ret;
     if (!out)
-	return -1;
+        return -1;
     ret = SaveTGA_RW (surface, out, rle);
     SDL_RWclose (out);
     return ret;

File src/imageext.c

 #include "pgopengl.h"
 #include <SDL_image.h>
 
-static char*
-find_extension (char* fullname)
+static const char*
+find_extension(const char *fullname)
 {
-    char* dot;
+    const char *dot;
 
-    if (!fullname)
+    if (fullname == NULL) {
         return NULL;
+    }
 
-    dot = strrchr (fullname, '.');
-    if (!dot)
+    dot = strrchr(fullname, '.');
+    if (dot == NULL) {
         return fullname;
+    }
     return dot + 1;
 }
 
 static PyObject*
-image_load_ext (PyObject* self, PyObject* arg)
+image_load_ext(PyObject *self, PyObject *arg)
 {
-    PyObject *file, *final;
-#if PY3
-    PyObject *oname, *odecoded = NULL;
+    PyObject *obj;
+    PyObject *final;
+    PyObject *oencoded;
+    PyObject *oname;
+    const char *name = NULL;
+    const char *cext;
+    char *ext = NULL;
+    SDL_Surface *surf;
+    SDL_RWops *rw;
+    
+    if (!PyArg_ParseTuple(arg, "O|s", &obj, &name)) {
+        return NULL;
+    }
+    
+    oencoded = RWopsEncodeFilePath(obj, PyExc_SDLError);
+    if (oencoded == NULL) {
+        return NULL;
+    }
+    if (oencoded != Py_None) {
+        Py_BEGIN_ALLOW_THREADS;
+        surf = IMG_Load(Bytes_AS_STRING(oencoded));
+        Py_END_ALLOW_THREADS;
+        Py_DECREF(oencoded);
+    }
+    else {
+        Py_DECREF(oencoded);
+        oencoded = NULL;
+#if PY2
+        if (name == NULL && PyFile_Check(obj)) {
+            oencoded = PyFile_Name(obj);
+            if (oencoded == NULL) {
+                /* This should never happen */
+                return NULL;
+            }
+            Py_INCREF(oencoded);
+            name = Bytes_AS_STRING(oencoded);
+        }
 #endif
-    char* name = NULL;
-    SDL_Surface* surf;
-    SDL_RWops *rw;
-    if (!PyArg_ParseTuple (arg, "O|s", &file, &name))
-        return NULL;
-#if PY3
-    if (PyUnicode_Check (file))
-#else
-    if (PyString_Check (file) || PyUnicode_Check (file))
-#endif
-    {
-        if (!PyArg_ParseTuple (arg, "s|O", &name, &file))
-            return NULL;
-        Py_BEGIN_ALLOW_THREADS;
-        surf = IMG_Load (name);
-        Py_END_ALLOW_THREADS;
-    }
-#if PY3
-    else if (PyBytes_Check (file)) {
-        name = PyBytes_AsString (file);
-	if (name == NULL) {
-	    return NULL;
-	}
-        Py_BEGIN_ALLOW_THREADS;
-        surf = IMG_Load (name);
-        Py_END_ALLOW_THREADS;
-    }
-#endif
-    else
-    {
-#if PY3
         if (name == NULL) {
-            oname = PyObject_GetAttrString (file, "name");
-            if (oname == NULL) {
-	        PyErr_Clear ();
+            oname = PyObject_GetAttrString(obj, "name");
+            if (oname != NULL) {
+                oencoded = RWopsEncodeFilePath(oname, NULL);
+                Py_DECREF(oname);
+                if (oencoded == NULL) {
+                    return NULL;
+                }
+                if (oencoded != Py_None) {
+                    name = Bytes_AS_STRING(oencoded);
+                }
             }
             else {
-	        if (PyUnicode_Check (oname)) {
-	            odecoded = PyUnicode_AsASCIIString (oname);
-	            Py_DECREF (oname);
-	            if (odecoded == NULL) {
-	                return NULL;
-		    }
-	  	    name = PyBytes_AsString (odecoded);
-	        }
-		else if (PyBytes_Check (oname)) {
-		    name = PyBytes_AsString (oname);
-		}
-	    }
+                PyErr_Clear();
+            }
         }
-#else
-        if (!name && PyFile_Check (file))
-            name = PyString_AsString (PyFile_Name (file));
-#endif
-        if (!(rw = RWopsFromPython (file))) {
-#if PY3
-	    Py_XDECREF (odecoded);
-#endif
+        rw = RWopsFromFileObject(obj);
+        if (rw == NULL) {
+            Py_XDECREF(oencoded);
             return NULL;
-	}
-        if (RWopsCheckPython (rw))
-        {
-            surf = IMG_LoadTyped_RW (rw, 1, find_extension (name));
         }
-        else
-        {
+        
+        cext = find_extension(name);
+        if (cext != NULL) {
+            ext = PyMem_Malloc(strlen(cext) + 1);
+            if (ext == NULL) {
+                Py_XDECREF(oencoded);
+                return PyErr_NoMemory();
+            }
+            strcpy(ext, cext);
+        }
+        Py_XDECREF(oencoded);
+        if (RWopsCheckObject(rw)) {
+            surf = IMG_LoadTyped_RW(rw, 1, ext);
+        }
+        else {
             Py_BEGIN_ALLOW_THREADS;
-            surf = IMG_LoadTyped_RW (rw, 1, find_extension (name));
+            surf = IMG_LoadTyped_RW(rw, 1, ext);
             Py_END_ALLOW_THREADS;
         }
-#if PY3
-	Py_XDECREF (odecoded);
-#endif
+        PyMem_Free(ext);
     }
 
-    if (!surf)
-        return RAISE (PyExc_SDLError, IMG_GetError ());
-    final = PySurface_New (surf);
-    if (!final)
-        SDL_FreeSurface (surf);
+    if (surf == NULL) {
+        return RAISE(PyExc_SDLError, IMG_GetError());
+    }
+    final = PySurface_New(surf);
+    if (final == NULL) {
+        SDL_FreeSurface(surf);
+    }
     return final;
 }
 
 #ifdef PNG_H
 
 static int
-write_png (char *file_name, png_bytep *rows, int w, int h, int colortype,
-           int bitdepth)
+write_png (const char *file_name, png_bytep *rows, int w, int h,
+           int colortype, int bitdepth)
 {
     png_structp png_ptr;
     png_infop info_ptr;
 }
 
 static int
-SavePNG (SDL_Surface *surface, char *file)
+SavePNG (SDL_Surface *surface, const char *file)
 {
     static unsigned char** ss_rows;
     static int ss_size;
 #define NUM_LINES_TO_WRITE 500
 
 
-int write_jpeg (char *file_name, unsigned char** image_buffer,  int image_width,
-            int image_height, int quality) {
+int write_jpeg (const char *file_name, unsigned char** image_buffer,
+                int image_width, int image_height, int quality) {
 
     struct jpeg_compress_struct cinfo;
     struct jpeg_error_mgr jerr;
 
 
 
-int SaveJPEG (SDL_Surface *surface, char *file) {
+int SaveJPEG (SDL_Surface *surface, const char *file) {
 
     static unsigned char** ss_rows;
     static int ss_size;
 
 
 static PyObject*
-image_save_ext (PyObject* self, PyObject* arg)
+image_save_ext(PyObject *self, PyObject *arg)
 {
-    PyObject* surfobj, *file;
+    PyObject *surfobj;
+    PyObject *obj;
+    PyObject *oencoded;
     SDL_Surface *surf;
     SDL_Surface *temp = NULL;
-    int result;
+    int result = 1;
 
-    if (!PyArg_ParseTuple (arg, "O!O", &PySurface_Type, &surfobj, &file))
+    if (!PyArg_ParseTuple(arg, "O!O", &PySurface_Type, &surfobj, &obj)) {
         return NULL;
-    surf = PySurface_AsSurface (surfobj);
+    }
+    surf = PySurface_AsSurface(surfobj);
 
-    if (surf->flags & SDL_OPENGL)
-    {
-        temp = surf = opengltosdl ();
-        if (!surf)
+    surf = PySurface_AsSurface(surfobj);
+    if (surf->flags & SDL_OPENGL) {
+        temp = surf = opengltosdl();
+        if (surf == NULL) {
             return NULL;
+        }
     }
-    else
-        PySurface_Prep (surfobj);
+    else {
+        PySurface_Prep(surfobj);
+    }
 
-#if PY3
-    if (PyUnicode_Check (file) || PyBytes_Check (file))
-#else
-    if (PyString_Check (file) || PyUnicode_Check (file))
-#endif
-    {
-        int namelen;
-        char* name;
-#if PY3
-        if (PyBytes_Check (file)) {
-	    if (!PyArg_ParseTuple (arg, "0|y", &file, &name)) {
-	        return NULL;
-	    }
-	}
-	else
-#endif
-        if (!PyArg_ParseTuple (arg, "O|s", &file, &name))
-            return NULL;
-        namelen = strlen (name);
+    oencoded = RWopsEncodeFilePath(obj, PyExc_SDLError);
+    if (oencoded == Py_None) {
+        PyErr_Format(PyExc_TypeError,
+                     "Expected a string for the file argument: got %.1024s",
+                     Py_TYPE(obj)->tp_name);
+        result = -2;
+    }
+    else if (oencoded != NULL) {
+        const char *name = Bytes_AS_STRING(oencoded);
+        Py_ssize_t namelen = Bytes_GET_SIZE(oencoded);
+
         if ((namelen >= 4) &&
             (((name[namelen - 1]=='g' || name[namelen - 1]=='G') &&
               (name[namelen - 2]=='e' || name[namelen - 2]=='E') &&
               (name[namelen - 4]=='j' || name[namelen - 4]=='J')) ||
              ((name[namelen - 1]=='g' || name[namelen - 1]=='G') &&
               (name[namelen - 2]=='p' || name[namelen - 2]=='P') &&
-              (name[namelen - 3]=='j' || name[namelen - 3]=='J'))))
-        {
+              (name[namelen - 3]=='j' || name[namelen - 3]=='J'))))  {
 #ifdef JPEGLIB_H
             /* jpg save functions seem *NOT* thread safe at least on windows. */
             /*
             Py_BEGIN_ALLOW_THREADS;
             */
-            result = SaveJPEG (surf, name);
+            result = SaveJPEG(surf, name);
             /*
             Py_END_ALLOW_THREADS;
             */
 #else
-            return RAISE (PyExc_SDLError, "No support for jpg compiled in.");
+            RAISE(PyExc_SDLError, "No support for jpg compiled in.");
+            result = -2;
 #endif
 
         }
         else if ((namelen >= 3) &&
                  ((name[namelen - 1]=='g' || name[namelen - 1]=='G') &&
                   (name[namelen - 2]=='n' || name[namelen - 2]=='N') &&
-                  (name[namelen - 3]=='p' || name[namelen - 3]=='P')))
-        {
+                  (name[namelen - 3]=='p' || name[namelen - 3]=='P')))  {
 #ifdef PNG_H
             /*Py_BEGIN_ALLOW_THREADS; */
-            result = SavePNG (surf, name);
+            result = SavePNG(surf, name);
             /*Py_END_ALLOW_THREADS; */
 #else
-            return RAISE (PyExc_SDLError, "No support for png compiled in.");
+            RAISE(PyExc_SDLError, "No support for png compiled in.");
+            result = -2;
 #endif
         }
+    }
+    else {
+        result = -2;
+    }
 
-        else
-            result = -1;
+    if (temp != NULL) {
+        SDL_FreeSurface(temp);
     }
-    else
+    else {
+        PySurface_Unprep(surfobj);
+    }
+
+    if (result == -2) {
+        /* Python error raised elsewhere */
         return NULL;
-
-    if(temp)
-        SDL_FreeSurface (temp);
-    else
-        PySurface_Unprep (surfobj);
-
-    if (result == -1)
-        return RAISE (PyExc_SDLError, SDL_GetError ());
+    }
+    if (result == -1) {
+        /* SDL error: translate to Python error */
+        return RAISE(PyExc_SDLError, SDL_GetError());
+    }
+    if (result == 1) {
+        return RAISE(PyExc_SDLError, "Unrecognized image type");
+    }
 
     Py_RETURN_NONE;
 }
 static PyTypeObject PyChannel_Type;
 static PyObject* PySound_New (Mix_Chunk*);
 static PyObject* PyChannel_New (int);
-#define PySound_Check(x) ((x)->ob_type == &PySound_Type)
-#define PyChannel_Check(x) ((x)->ob_type == &PyChannel_Type)
+#define PySound_Check(x) (Py_TYPE(x) == &PySound_Type)
+#define PyChannel_Check(x) (Py_TYPE(x) == &PyChannel_Type)
 
 static int request_frequency = PYGAME_MIXER_DEFAULT_FREQUENCY;
 static int request_size = PYGAME_MIXER_DEFAULT_SIZE;
 }
 
 static int
-sound_init (PyObject* self, PyObject* arg, PyObject* kwarg)
+sound_init(PyObject *self, PyObject *arg, PyObject *kwarg)
 {
     static const char arg_cnt_err_msg[] =
         "Sound takes either 1 positional or 1 keyword argument";
     PyObject *obj = NULL;
     PyObject *file = NULL;
     PyObject *buffer = NULL;
+    PyObject *keys;
+    PyObject *kencoded;
+    SDL_RWops *rw;
+    const void *buf = NULL;
+    Py_ssize_t buflen = 0;
     Mix_Chunk *chunk = NULL;
     Uint8 *mem;
     
     /* Process arguments, returning cleaner error messages than
        PyArg_ParseTupleAndKeywords would.
     */
-    if (arg && PyTuple_GET_SIZE (arg))
-    {
-        if ((kwarg && PyDict_Size (kwarg)) || PyTuple_GET_SIZE (arg) != 1)
-        {
-            RAISE (PyExc_TypeError, arg_cnt_err_msg);
+    if (arg != NULL && PyTuple_GET_SIZE(arg)) {
+        if ((kwarg != NULL && PyDict_Size(kwarg)) || /* conditional and */
+            PyTuple_GET_SIZE(arg) != 1)              {
+            RAISE(PyExc_TypeError, arg_cnt_err_msg);
             return -1;
         }
-        obj = PyTuple_GET_ITEM (arg, 0);
+        obj = PyTuple_GET_ITEM(arg, 0);
         
-        if (PyUnicode_Check (obj))
-        {
+        if (PyUnicode_Check(obj)) {
             file = obj;
             obj = NULL;
         }
-        else
-        {
+        else {
             file = obj;
             buffer = obj;
         }
     }
-    else if (kwarg)
-    {
-        if (PyDict_Size (kwarg) != 1)
-        {
-            RAISE (PyExc_TypeError, arg_cnt_err_msg);
+    else if (kwarg != NULL) {
+        if (PyDict_Size(kwarg) != 1) {
+            RAISE(PyExc_TypeError, arg_cnt_err_msg);
             return -1;
         }
-        if (!(file = PyDict_GetItemString (kwarg, "file")) &&
-            !(buffer = PyDict_GetItemString (kwarg, "buffer")))
-        {
-            PyObject *keys;
-            PyObject *key;
-            const char *keystr;
-#if PY3
-            PyObject *tmp;
-#endif
-            if (!(keys = PyDict_Keys (kwarg)))
-            {
+        if ((file = PyDict_GetItemString(kwarg, "file")) == NULL &&
+            (buffer = PyDict_GetItemString(kwarg, "buffer")) == NULL) {
+            keys = PyDict_Keys(kwarg);
+            if (keys == NULL) {
                 return -1;
             }
-            key = PyList_GET_ITEM (keys, 0);
-            Py_INCREF (key);
-#if PY3
-            tmp = PyUnicode_AsASCIIString (key);
-            Py_DECREF (key);
-            key = tmp;
-            if (!key)
-            {
-                Py_DECREF (keys);
+            kencoded = RWopsEncodeString(PyList_GET_ITEM(keys, 0),
+                                         NULL, NULL, NULL);
+            Py_DECREF(keys);
+            if (kencoded == NULL) {
                 return -1;
             }
-#endif
-            keystr = Bytes_AsString (key);
             PyErr_Format(PyExc_TypeError,
-                         "Unrecognized keyword argument '%s'",
-                         keystr);
-            Py_DECREF (key);
-            Py_DECREF (keys);
+                         "Unrecognized keyword argument '%.1024s'",
+                         Bytes_AS_STRING(kencoded));
+            Py_DECREF(kencoded);
             return -1;
         }
-        if (buffer && PyUnicode_Check (buffer))
-        {
-            RAISE (PyExc_TypeError,
-                   "Unicode object not allowed as buffer object");
+        if (buffer != NULL && PyUnicode_Check(buffer)) { /* conditional and */
+            RAISE(PyExc_TypeError,
+                  "Unicode object not allowed as buffer object");
             return -1;
         }
     }
-    else
-    {
-        RAISE (PyExc_TypeError, arg_cnt_err_msg);
+    else {
+        RAISE(PyExc_TypeError, arg_cnt_err_msg);
         return -1;
     }  
 
-    if (file)
-    {
-        SDL_RWops *rw = RWopsFromPython (file);
-        if (!rw)
-        {
-            /* RWopsFromPython only raises critical Python exceptions,
+    if (file != NULL) {
+        rw = RWopsFromObject(file);
+        if (rw == NULL) {
+            /* RWopsFromObject only raises critical Python exceptions,
                so automatically pass them on.
             */
             return -1;
         }
-        if (RWopsCheckPython (rw))
-        {
-            chunk = Mix_LoadWAV_RW (rw, 1);
+        if (RWopsCheckObject(rw)) {
+            chunk = Mix_LoadWAV_RW(rw, 1);
         }
-        else
-        {
+        else {
             Py_BEGIN_ALLOW_THREADS;
-            chunk = Mix_LoadWAV_RW (rw, 1);
+            chunk = Mix_LoadWAV_RW(rw, 1);
             Py_END_ALLOW_THREADS;
         }
-        if (!chunk && !obj)
-        {
-            if (PyUnicode_Check (file))
-            {
-                const char *name = NULL;
-                PyObject *tmp =
-                    PyUnicode_AsEncodedString(file,
-                                              "unicode_escape",
-                                              "backslashreplace");
-                if (!tmp)
-                {
-                    return -1;
+        if (chunk == NULL && obj == NULL) {
+            obj = RWopsEncodeString(file, NULL, NULL, NULL);
+            if (obj != NULL) {
+                if (obj == Py_None) {
+                    RAISE(PyExc_SDLError, SDL_GetError());
                 }
-                name = Bytes_AS_STRING (tmp);
-                PyErr_Format (PyExc_SDLError,
-                              "Unable to open file '%s'", name);
-                Py_DECREF (tmp);
-            }
-            else if (Bytes_Check (file))
-            {
-                const char *name = Bytes_AS_STRING (file);
-                PyErr_Format (PyExc_SDLError,
-                              "Unable to open file '%s'", name);
-            }
-            else
-            {
-                RAISE (PyExc_SDLError, SDL_GetError ());
+                else {
+                    PyErr_Format(PyExc_SDLError,
+                                 "Unable to open file '%s'",
+                                 Bytes_AS_STRING(obj));
+                }
+                Py_XDECREF(obj);
             }
             return -1;
         }
     }
 
-    if (!chunk && buffer)
-    {
-        const void *buf = NULL;
-        Py_ssize_t buflen = 0;
-
-        if (PyObject_AsReadBuffer (buffer, &buf, &buflen))
-        {
-            if (obj)
-            {
-                PyErr_Clear ();
+    if (chunk == NULL && buffer != NULL) {
+        if (PyObject_AsReadBuffer(buffer, &buf, &buflen)) {
+            if (obj != NULL) {
+                PyErr_Clear();
             }
-            else
-            {
-                PyErr_Format (PyExc_TypeError,
-                              "Expected object with buffer interface: got a %s",
-                              buffer->ob_type->tp_name);
+            else {
+                PyErr_Format(PyExc_TypeError,
+                             "Expected object with buffer interface: got a %s",
+                             Py_TYPE(buffer)->tp_name);
                 return -1;
             }
         }
-        else
-        {
-            mem = PyMem_Malloc ((size_t)buflen);
+        else {
+            mem = PyMem_Malloc((size_t)buflen);
             if (mem == NULL)
             {
                 PyErr_NoMemory ();
                 return -1;
             }
-            chunk = Mix_QuickLoad_RAW (mem, (Uint32)buflen);
-            if (!chunk)
-            {
-                SDL_ClearError ();
-                PyMem_Free (mem);
-                PyErr_NoMemory ();
+            chunk = Mix_QuickLoad_RAW(mem, (Uint32)buflen);
+            if (chunk == NULL) {
+                SDL_ClearError();
+                PyMem_Free(mem);
+                PyErr_NoMemory();
                 return -1;
             }
             ((PySoundObject *)self)->mem = mem;
-            memcpy (mem, buf, (size_t)buflen);
+            memcpy(mem, buf, (size_t)buflen);
         }
     }
-    
-    if (!chunk)
-    {
-        PyErr_Format (PyExc_TypeError,
-                      "Unrecognized argument (type %s)",
-                      obj->ob_type->tp_name);
+
+    if (chunk == NULL) {
+        PyErr_Format(PyExc_TypeError,
+                     "Unrecognized argument (type %s)",
+                     Py_TYPE(obj)->tp_name);
         return -1;
     }
         
-    ((PySoundObject*)self)->chunk = chunk;
+    ((PySoundObject *)self)->chunk = chunk;
     return 0;
 }
 
 Movie (PyObject* self, PyObject* arg)
 {
     PyObject* file, *final, *filesource=NULL;
-    char* name = NULL;
+    PyObject* oencoded;
     SMPEG* movie=NULL;
     SMPEG_Info info;
     SDL_Surface* screen;
     if (!SDL_WasInit (SDL_INIT_AUDIO))
         audioavail = 1;
 
-    if (Bytes_Check (file) || PyUnicode_Check (file))
-    {
-        if (!PyArg_ParseTuple (arg, "s", &name))
-            return NULL;
+    oencoded = RWopsEncodeFilePath (file, PyExc_SDLError);
+    if (oencoded == NULL) {
+        return NULL;
+    }
+    if (oencoded != Py_None) {
+        const char *name = Bytes_AS_STRING(oencoded);
+
         movie = SMPEG_new (name, &info, audioavail);
+        Py_DECREF(oencoded);
     }
-#if !PY3
+#if PY2
     else if (PyFile_Check (file))
     {
+        Py_DECREF(oencoded);
         SDL_RWops *rw = SDL_RWFromFP (PyFile_AsFile (file), 0);
         movie = SMPEG_new_rwops (rw, &info, audioavail);
         filesource = file;
 #endif
     else
     {
-        SDL_RWops *rw;
-        if (!(rw = RWopsFromPythonThreaded (file)))
+        SDL_RWops *rw = RWopsFromFileObjectThreaded (file);
+        
+        Py_DECREF(oencoded);
+        if (!rw)
             return NULL;
         Py_BEGIN_ALLOW_THREADS;
         movie = SMPEG_new_rwops (rw, &info, audioavail);
 #include "doc/music_doc.h"
 #include "mixer.h"
 
+/* Need at least SDL_mixer 1.2.8 (released in 2007) */
+#if (MIX_MAJOR_VERSION*100*100 + MIX_MINOR_VERSION*100 + MIX_PATCHLEVEL) < 10208
+#error Need at least SDL_mixer 1.2.8
+#endif
+
 static Mix_Music* current_music = NULL;
 static Mix_Music* queue_music = NULL;
 static int endmusic_event = SDL_NOEVENT;
     music_pos = 0;
     music_pos_time = SDL_GetTicks ();
 
-#if MIX_MAJOR_VERSION>=1 && MIX_MINOR_VERSION>=2 && MIX_PATCHLEVEL>=3
     Py_BEGIN_ALLOW_THREADS
     volume = Mix_VolumeMusic (-1);
     val = Mix_FadeInMusicPos (current_music, loops, 0, startpos);
     Mix_VolumeMusic (volume);
     Py_END_ALLOW_THREADS
-#else
-    if (startpos)
-        return RAISE (PyExc_NotImplementedError,
-                      "music start position requires SDL_mixer-1.2.4");
-    Py_BEGIN_ALLOW_THREADS
-    val = Mix_PlayMusic (current_music, loops);
-    Py_END_ALLOW_THREADS
-#endif
     if (val == -1)
         return RAISE (PyExc_SDLError, SDL_GetError ());
 
 }
 
 static PyObject*
-music_load (PyObject* self, PyObject* args)
+music_load(PyObject *self, PyObject *args)
 {
-    char* name = NULL;
-    PyObject* file;
-    Mix_Music* new_music;
+    PyObject *obj;
+    PyObject *oencoded;
+    Mix_Music *new_music = NULL;
+    const char *name;
     SDL_RWops *rw;
-    if(!PyArg_ParseTuple(args, "O", &file))
+
+    if(!PyArg_ParseTuple(args, "O", &obj)) {
         return NULL;
+    }
 
-    MIXER_INIT_CHECK ();
+    MIXER_INIT_CHECK();
 
-    #if (MIX_MAJOR_VERSION*100*100 + MIX_MINOR_VERSION*100 + MIX_PATCHLEVEL) >= 10208
-    if(!Bytes_Check(file) && !PyUnicode_Check(file))
-    {
-        rw = RWopsFromPythonThreaded(file);
-        if(!rw)
+    oencoded = RWopsEncodeFilePath(obj, PyExc_SDLError);
+    if (oencoded == Py_None) {
+        Py_DECREF(oencoded);
+        rw = RWopsFromFileObjectThreaded(obj);
+        if(rw == NULL) {
             return NULL;
+        }
         Py_BEGIN_ALLOW_THREADS
         new_music = Mix_LoadMUS_RW(rw);
         Py_END_ALLOW_THREADS
     }
-    else
-    #endif
-    {
-#if PY3
-        if (PyUnicode_Check(file)) {
-            if (!PyArg_ParseTuple(args, "s", &name)) {
-                return NULL;
-            }
-        }
-        else {
-            if (!PyArg_ParseTuple(args, "y", &name)) {
-                return NULL;
-            }
-        }
-#else
-        if(!PyArg_ParseTuple(args, "s", &name))
-            return NULL;
-#endif
+    else if (oencoded != NULL) {
+        name = Bytes_AS_STRING(oencoded);
         Py_BEGIN_ALLOW_THREADS
         new_music = Mix_LoadMUS(name);