[armedbear-cvs] r12321 - trunk/abcl/src/org/armedbear/lisp/util

Erik Huelsmann ehuelsmann at common-lisp.net
Fri Jan 1 18:26:31 UTC 2010


Author: ehuelsmann
Date: Fri Jan  1 13:26:24 2010
New Revision: 12321

Log:
Fix ticket #75: infinite loop while writing unmappable
  characters to an output stream - while at it,
  fix the input side too.

Added:
   trunk/abcl/src/org/armedbear/lisp/util/RACFMalformedInputException.java   (contents, props changed)
   trunk/abcl/src/org/armedbear/lisp/util/RACFUnmappableCharacterException.java   (contents, props changed)
Modified:
   trunk/abcl/src/org/armedbear/lisp/util/RandomAccessCharacterFile.java

Added: trunk/abcl/src/org/armedbear/lisp/util/RACFMalformedInputException.java
==============================================================================
--- (empty file)
+++ trunk/abcl/src/org/armedbear/lisp/util/RACFMalformedInputException.java	Fri Jan  1 13:26:24 2010
@@ -0,0 +1,68 @@
+/*
+ * RACFMalformedInputException.java
+ *
+ * Copyright (C) 2009 Erik Huelsmann
+ * $Id$
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * As a special exception, the copyright holders of this library give you
+ * permission to link this library with independent modules to produce an
+ * executable, regardless of the license terms of these independent
+ * modules, and to copy and distribute the resulting executable under
+ * terms of your choice, provided that you also meet, for each linked
+ * independent module, the terms and conditions of the license of that
+ * module.  An independent module is a module which is not derived from
+ * or based on this library.  If you modify this library, you may extend
+ * this exception to your version of the library, but you are not
+ * obligated to do so.  If you do not wish to do so, delete this
+ * exception statement from your version.
+ */
+
+package org.armedbear.lisp.util;
+
+import java.nio.charset.MalformedInputException;
+
+
+/** Class - derived from MalformedInputException -
+ * which holds information required to allow higher level
+ * systems to invoke a lisp restart function to set replacement characters.
+ */
+public class RACFMalformedInputException
+    extends MalformedInputException {
+
+    final int position;
+    final char character;
+    final String charsetName;
+
+    public RACFMalformedInputException(int position, char character,
+                                       String charsetName) {
+        super(1); // 1 == fake length
+        this.position = position;
+        this.character = character;
+        this.charsetName = charsetName;
+    }
+
+    @Override
+    public String getMessage() {
+        return "Input value 0x" + Integer.toHexString(character)
+            + " is malformed while recoding with charset " + charsetName;
+    }
+
+    public int getPosition() {
+        return position;
+    }
+
+}
\ No newline at end of file

Added: trunk/abcl/src/org/armedbear/lisp/util/RACFUnmappableCharacterException.java
==============================================================================
--- (empty file)
+++ trunk/abcl/src/org/armedbear/lisp/util/RACFUnmappableCharacterException.java	Fri Jan  1 13:26:24 2010
@@ -0,0 +1,68 @@
+/*
+ * RACFUnmappableCharacterException.java
+ *
+ * Copyright (C) 2009 Erik Huelsmann
+ * $Id$
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * As a special exception, the copyright holders of this library give you
+ * permission to link this library with independent modules to produce an
+ * executable, regardless of the license terms of these independent
+ * modules, and to copy and distribute the resulting executable under
+ * terms of your choice, provided that you also meet, for each linked
+ * independent module, the terms and conditions of the license of that
+ * module.  An independent module is a module which is not derived from
+ * or based on this library.  If you modify this library, you may extend
+ * this exception to your version of the library, but you are not
+ * obligated to do so.  If you do not wish to do so, delete this
+ * exception statement from your version.
+ */
+
+package org.armedbear.lisp.util;
+
+import java.nio.charset.UnmappableCharacterException;
+
+
+/** Class - derived from UnmappableCharacterException -
+ * which holds information required to allow higher level
+ * systems to invoke a lisp restart function to set replacement characters.
+ */
+public class RACFUnmappableCharacterException
+    extends UnmappableCharacterException {
+
+    final int position;
+    final char character;
+    final String charsetName;
+
+    public RACFUnmappableCharacterException(int position, char character,
+                                            String charsetName) {
+        super(1); // 1 == fake length
+        this.position = position;
+        this.character = character;
+        this.charsetName = charsetName;
+    }
+
+    @Override
+    public String getMessage() {
+        return "Character \\U" + Integer.toHexString(character)
+            + " can't be recoded using charset " + charsetName;
+    }
+
+    public int getPosition() {
+        return position;
+    }
+
+}
\ No newline at end of file

Modified: trunk/abcl/src/org/armedbear/lisp/util/RandomAccessCharacterFile.java
==============================================================================
--- trunk/abcl/src/org/armedbear/lisp/util/RandomAccessCharacterFile.java	(original)
+++ trunk/abcl/src/org/armedbear/lisp/util/RandomAccessCharacterFile.java	Fri Jan  1 13:26:24 2010
@@ -280,12 +280,7 @@
 
         fcn = raf.getChannel();
 
-        cset = (encoding == null) ? Charset.defaultCharset() : Charset.forName(encoding);
-        cdec = cset.newDecoder();
-        cdec.onMalformedInput(CodingErrorAction.REPLACE);
-        cdec.onUnmappableCharacter(CodingErrorAction.REPLACE);
-        cenc = cset.newEncoder();
-
+        setEncoding(encoding);
         bbuf = ByteBuffer.allocate(BUFSIZ);
 
         // there is no readable data available in the buffers.
@@ -304,6 +299,15 @@
         outputStream = new RandomAccessOutputStream();
     }
 
+    public void setEncoding(String encoding) {
+        cset = (encoding == null)
+            ? Charset.defaultCharset() : Charset.forName(encoding);
+        cdec = cset.newDecoder();
+        cdec.onMalformedInput(CodingErrorAction.REPLACE);
+        cdec.onUnmappableCharacter(CodingErrorAction.REPLACE);
+        cenc = cset.newEncoder();
+    }
+
     public Writer getWriter() {
         return writer;
     }
@@ -365,6 +369,18 @@
             atEof = ! ensureReadBbuf(decodeWasUnderflow);
             CoderResult r = cdec.decode(bbuf, cbuf, atEof );
             decodeWasUnderflow = (CoderResult.UNDERFLOW == r);
+            if (r.isMalformed())
+                // When reading encoded Unicode, we'd expect to require
+                // catching MalformedInput
+                throw new RACFMalformedInputException(bbuf.position(),
+                                                      bbuf.get(bbuf.position()),
+                                                      cset.name());
+            if (r.isUnmappable())
+                // Since we're mapping TO unicode, we'd expect to be able
+                // to map all characters
+                Debug.assertTrue(false);
+            if (CoderResult.OVERFLOW == r)
+                Debug.assertTrue(false);
         }
         if (cbuf.remaining() == len) {
             return -1;
@@ -387,7 +403,8 @@
         }
     }
 
-    private final void encodeAndWrite(CharBuffer cbuf, boolean flush, boolean endOfFile) throws IOException {
+    private final void encodeAndWrite(CharBuffer cbuf, boolean flush,
+                                      boolean endOfFile) throws IOException {
         while (cbuf.remaining() > 0) {
             CoderResult r = cenc.encode(cbuf, bbuf, endOfFile);
             bbufIsDirty = true;
@@ -395,6 +412,20 @@
                 flushBbuf(false);
                 bbuf.clear();
             }
+            if (r.isUnmappable()) {
+                throw new RACFUnmappableCharacterException(cbuf.position(),
+                                                           cbuf.charAt(cbuf.position()),
+                                                           cset.name());
+            }
+            if (r.isMalformed()) {
+                // We don't really expect Malformed, but not handling it
+                // will cause an infinite loop if we don't...
+                throw new RACFMalformedInputException(cbuf.position(),
+                                                      cbuf.charAt(cbuf.position()),
+                                                      cset.name());
+            }
+            if (CoderResult.UNDERFLOW == r)
+                Debug.assertTrue(false);
         }
         if (bbuf.position() > 0 && bbufIsDirty && flush) {
             flushBbuf(false);




More information about the armedbear-cvs mailing list