Making updateTextureSubImage more robust

Our development group has been been bitten by invalid calls to updateTextureSubImage.  The following changes are intended to make that method more robust in the handling of error conditions in order to avoid getting the application into a bad state.


### Eclipse Workspace Patch 1.0
Index: src/com/jme/renderer/jogl/JOGLRenderer.java
===================================================================
--- src/com/jme/renderer/jogl/JOGLRenderer.java   (revision 4480)
+++ src/com/jme/renderer/jogl/JOGLRenderer.java   (working copy)
@@ -1834,6 +1834,12 @@
             throws JmeException {
         GL gl = GLU.getCurrentGL();
 
+        // We can't update a non-existent texture.
+        if (dstTexture.getTextureId() <= 0) {
+            logger.warning("Attempting to update a non-existent texture");
+            return;
+        }
+
         // Check that the texture type is supported.
         if (dstTexture.getType() != Texture.Type.TwoDimensional)
             throw new UnsupportedOperationException(
@@ -1880,25 +1886,58 @@
             gl.glPixelStorei(GL.GL_UNPACK_SKIP_ROWS, srcY);
 
         // Upload the image region into the texture.
-        gl.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, dstX, dstY, width, height,
-                pixelFormat, GL.GL_UNSIGNED_BYTE, data);
+        try {
+            gl.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, dstX, dstY, width, height,
+                    pixelFormat, GL.GL_UNSIGNED_BYTE, data);
+        } catch (GLException updateFailure) {
+            // Attempt to determine the root cause of the problem.
+            final Image dstImage = dstTexture.getImage();
+            final int b = (dstTexture.hasBorder()) ? 1 : 0;
+            if (srcX < -b || (srcX + width) > (dstImage.getWidth() - b)) {
+                throw new JmeException("Invalid Parameters: Source X=" + srcX
+                        + " and width=" + width + ": Texture width="
+                        + dstImage.getWidth());
+            }
+            if (srcY < -b || (srcY + height) > (dstImage.getHeight() - b)) {
+                throw new JmeException("Invalid Parameters: Source Y=" + srcY
+                        + " and height=" + height + ": Texture height="
+                        + dstImage.getHeight());
+            }
+            if (dstX < -b || (dstX + width) > (dstImage.getWidth() - b)) {
+                throw new JmeException("Invalid Parameters: Source X=" + dstX
+                        + " and width=" + width + ": Texture width="
+                        + dstImage.getWidth());
+            }
+            if (dstY < -b || (dstY + height) > (dstImage.getHeight() - b)) {
+                throw new JmeException("Invalid Parameters: Source Y=" + dstY
+                        + " and height=" + height + ": Texture height="
+                        + dstImage.getHeight());
+            }
 
-        // Restore the texture configuration (when necessary).
-        // Restore the texture binding.
-        if (origTexBinding[0] != dstTexture.getTextureId())
-            gl.glBindTexture(GL.GL_TEXTURE_2D, origTexBinding[0]);
-        // Restore alignment.
-        if (origAlignment[0] != alignment)
-            gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, origAlignment[0]);
-        // Restore row length.
-        if (origRowLength != rowLength)
-            gl.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, origRowLength);
-        // Restore skip pixels.
-        if (origSkipPixels != srcX)
-            gl.glPixelStorei(GL.GL_UNPACK_SKIP_PIXELS, origSkipPixels);
-        // Restore skip rows.
-        if (origSkipRows != srcY)
-            gl.glPixelStorei(GL.GL_UNPACK_SKIP_ROWS, origSkipRows);
+            // As a default case, simply throw a generic exception.
+            throw new JmeException("Unable to update the texture",
+                    updateFailure);
+        }
+        // Try to clean up any changes in a safe way so that the caller can
+        // recover gracefully.
+        finally {
+            // Restore the texture configuration (when necessary).
+            // Restore the texture binding.
+            if (origTexBinding[0] != dstTexture.getTextureId())
+                gl.glBindTexture(GL.GL_TEXTURE_2D, origTexBinding[0]);
+            // Restore alignment.
+            if (origAlignment[0] != alignment)
+                gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, origAlignment[0]);
+            // Restore row length.
+            if (origRowLength != rowLength)
+                gl.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, origRowLength);
+            // Restore skip pixels.
+            if (origSkipPixels != srcX)
+                gl.glPixelStorei(GL.GL_UNPACK_SKIP_PIXELS, origSkipPixels);
+            // Restore skip rows.
+            if (origSkipRows != srcY)
+                gl.glPixelStorei(GL.GL_UNPACK_SKIP_ROWS, origSkipRows);
+        }
     }
 
     @Override