United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-5042704 : RTFEditorKit wrongly parses rtf if fontname has unicode characters

Details
Type:
Bug
Submit Date:
2004-05-05
Status:
Resolved
Updated Date:
2004-08-17
Project Name:
JDK
Resolved Date:
2004-08-10
Component:
client-libs
OS:
windows_2000
Sub-Component:
javax.swing
CPU:
x86
Priority:
P4
Resolution:
Fixed
Affected Versions:
1.4.2
Fixed Versions:
1.4.2_06 (06)

Related Reports
Backport:

Sub Tasks

Description

Name: gm110360			Date: 05/05/2004


FULL PRODUCT VERSION :
Reproducible with 1.4.2 also
java version "1.5.0-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta-b32c)
Java HotSpot(TM) Client VM (build 1.5.0-beta-b32c, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
I have created a text editor using JTextPane. I have set the StyledDocument as
the DefaultStyledDocument. If I use some locale specific fontname suitable for
multibyte characters, say a fontname which contains Japanese language
characters , to format the text , on reopening the editor,  the font name
information is lost.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1.Create a JTextPane and attach a DefaultStyledDocument to it.
2.Create a RTFEditorKit  and set some rtf text on JTextPane.
3.Use the read/write API's of RTFEditorKit and write this DefaultStyledDocument into RTF2.rtf  file.
4. Compare the original rtf text set on textpane with RTF2.rtf.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The rtf generated should be same as the rtf set on the JTextPane.
ACTUAL -
Both rtfs are different.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
/**
* This is a Demo application created
*/
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.rtf.*;

public class RTFTest extends JApplet implements ActionListener
{

  public static void main(String args[])
  {
    JFrame frame = new JFrame("Test");
    frame.setSize(300, 200);
    frame.setLocation(50, 50);
    RTFTest test = new RTFTest();
    test.init();
    frame.getContentPane().add("Center", test);

    frame.show();
    frame.addWindowListener(new java.awt.event.WindowAdapter()
    {
      public void windowClosing(java.awt.event.WindowEvent event)
      {
        System.exit(0); // close the application
      }
    });
  }

  /**
   * constructor
   */
  public RTFTest()
  {
  }

  public void init()
  {
    super.init();

    getContentPane().setLayout(new BorderLayout());

    // xxxxx main part of UI
    JPanel common = new JPanel(new BorderLayout());

    JTextPane jtp = new JTextPane();
    String rtftext = "{\\rtf1\\ansi{\\fonttbl\\f0\\fnil Monospaced;\\f1\\fnil\\u26032 ?\\u32048 ?\\u26126 ?\\u39636 ?;\\f2\\fnil\\u65325?\\u65331 ? \\u12468 ?\\u12471 ?\\u12483 ?\\u12463 ?;}\\ql\\f1\\fs60\\cf0 Test\\f2 \\par\\ql\\f2\\fs60\\cf0 \\par}";
    char[] buf = rtftext.toCharArray();
    std = new DefaultStyledDocument();

    RTFEditorKit kit = new RTFEditorKit();
    try
    {
       CharArrayReader read = new CharArrayReader(buf);
       kit.read(read, std, 0);
       jtp.setStyledDocument(std);
       read.close();
    }
    catch (Exception streamException)
    {
        System.out.println("Failed to Read from file: " +
                                               streamException.toString());
        streamException.printStackTrace();
    }

    common.add("Center", jtp);

    getContentPane().add("Center", common);

    // xxxxx buttons of UI
    _buttonPanel = new JPanel();
    _buttonPanel.setLayout(new GridLayout(0, 1));
    common.add("East", _buttonPanel);

    _buttonToRTF = new JButton("Save RTF");
    _buttonPanel.add(_buttonToRTF);

    _buttonToRTF.addActionListener(this);

  }

  public void actionPerformed(ActionEvent e)
  {

    if (e.getSource() == _buttonToRTF)
    {
      StyledDocument doc = std;
      int length = doc.getLength();
      RTFEditorKit kit = new RTFEditorKit();

      try
      {
        // Write the Document's content into the RTF file
        FileOutputStream outStream = new FileOutputStream("D:\\RTF2.rtf");
        kit.write(outStream,std,0,length);
        outStream.close();

        ////////////////Print out the Document's content i.e. RTF ///////////
        PipedOutputStream pos = new PipedOutputStream();

        PipedInputStream pis = new PipedInputStream(pos);

        InputStreamReader isr = new InputStreamReader(pis, "UTF8");

        kit.write(pos, doc, 0, length);
        pos.flush();
        pos.close();

        StringBuffer buffer = new StringBuffer();
        Reader in = new BufferedReader(isr);
        int ch;
        while ((ch = in.read()) > -1)
        {
           buffer.append((char)ch);
        }
        in.close();
        System.out.println("RTF O/P::"+buffer.toString());
        ///////////////////////////////////////////////////////////////
      }
      catch (Exception streamException)
      {
        System.out.println("Failed to write to file: " +
                                                  streamException.toString());
        streamException.printStackTrace();
      }
    }
  }


  private JPanel _buttonPanel = null;
  private JButton _buttonToRTF = null;
  private StyledDocument std = null;

}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
No workaround available
(Incident Review ID: 261044) 
======================================================================

                                    

Comments
EVALUATION

unfortunately it is too late to get this bug fixed for the current release.
Postopned for the next one.
(If you feel that this problem should be addressed sooner please contact me)

###@###.### 2004-05-11
swing-rtf handles unicode characters in a different way than ascii
characters. They get handled one by one that is why the font name was only one
character long. (In fact we create new entry in the font table for every
character. They all created with the same key Integer(-1) though.)
 

To work around this I suggest to collect characters in  RTFReader.FonttblDestination.handleText(String text)

---- javax.swing.text.rtf.RTFReader

*** /tmp/geta4197	Mon Aug  2 19:22:38 2004
--- RTFReader.java	Mon Aug  2 19:19:50 2004
***************
*** 668,673 ****
--- 668,674 ----
  class FonttblDestination implements Destination
  {
      int nextFontNumber;
+     int lastFontNumber;
      String nextFontFamily;
      
      public void handleBinaryBlob(byte[] data)
***************
*** 679,695 ****
      {
          int semicolon = text.indexOf(';');
          String fontName;
-         Object fontNum;  /* an Integer, but we don't care */
  
!         if (semicolon > 0)
              fontName = text.substring(0, semicolon);
          else
              fontName = text;
  
          /* TODO: do something with the font family. */
  
!         fontTable.put(new Integer(nextFontNumber), fontName);
  
  	nextFontNumber = -1;
  	nextFontFamily = null;
          return;
--- 680,706 ----
      {
          int semicolon = text.indexOf(';');
          String fontName;
  
!         if (semicolon > -1)
              fontName = text.substring(0, semicolon);
          else
              fontName = text;
  
          /* TODO: do something with the font family. */
  
!         int fontNumber = nextFontNumber;
  
+         if (nextFontNumber == -1
+             && ! " ".equals(fontName)) {
+             fontNumber = lastFontNumber;
+             fontName = fontTable.get(new Integer(fontNumber)) + fontName;
+         }
+ 
+         fontTable.put(new Integer(fontNumber), fontName);
+ 
+         if (nextFontNumber != -1) {
+             lastFontNumber = nextFontNumber;
+         }
  	nextFontNumber = -1;
  	nextFontFamily = null;
          return;

----
###@###.### 2004-08-02
--from the review request---
RTFParser handles unicode character as keywords. As such each of them get
handled individually.

RTFReader.FonttblDestination.handleText was not implemented to handle font names
split across multiple calls.

Usual calling sequence  for RTFReader.FonttblDestination is:

handleKeyword(String keyword, int parameter) [ font index in the table ]
handleKeyword(String keyword)                [ font family             ]
handleText(String text)                      [ font name               ]

For unicode charactes and for the case when write buffer divides font
name picture is like:

handleKeyword(String keyword, int parameter)
handleKeyword(String keyword)
handleText(String text)
handleText(String text)
handleText(String text)
handleText(String text)
handleText(String text)
handleText(String text)
handleText(String text)
...


The fix is to append new pieces to stored font name.

###@###.### 2004-08-07
                                     
2004-08-07
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
1.4.2_06
generic
tiger-rc

FIXED IN:
1.4.2_06
tiger-rc

INTEGRATED IN:
1.4.2_06
tiger-b63
tiger-rc


                                     
2004-08-18



Hardware and Software, Engineered to Work Together