# HG changeset patch
# User Michael Stahl <mst@openoffice.org>
# Date 1303140562 0
# Node ID 414c34ef3984cc11b259821f49c474c6f80d8705
# Parent  aa5f5a7a9c3064ea1e8eecc3d3fe1431b669cc82
rtftok01: writerfilter: support for a destination stack

diff --git a/writerfilter/source/rtftok/RTFDocumentImpl.cxx b/writerfilter/source/rtftok/RTFDocumentImpl.cxx
--- a/writerfilter/source/rtftok/RTFDocumentImpl.cxx
+++ b/writerfilter/source/rtftok/RTFDocumentImpl.cxx
@@ -28,6 +28,7 @@
 #include <RTFDocumentImpl.hxx>
 
 #include <map>
+#include <stack>
 #include <algorithm>
 
 #include <rtl/strbuf.hxx>
@@ -36,6 +37,7 @@
 #include <comphelper/stlunosequence.hxx>
 
 #include <resourcemodel/TagLogger.hxx>
+#include <doctok/resourceids.hxx>
 #include <rtftok/RTFScanner.hxx>
 #include <rtftok/RTFScannerHandler.hxx>
 #include <rtftok/RTFInputSource.hxx>
@@ -241,6 +243,54 @@
     uno::Reference<io::XInputStream> m_xInputStream;
 };
 
+
+class RTFScannerHandlerImpl;
+
+/** Base class for destinations.
+ */
+class RTFDestination
+{
+public:
+    typedef ::boost::shared_ptr<RTFDestination> Pointer_t;
+    explicit RTFDestination(RTFScannerHandlerImpl & rHandler)
+        : m_rHandler(rHandler)
+    { }
+    virtual ~RTFDestination() { }
+
+    virtual Pointer_t dest(char const*const token, char const*const /*value*/)
+    {
+fprintf(stderr, "RTFDestination::dest: creating default context for %s\n", token);
+        return Pointer_t(new RTFDestination(m_rHandler));
+    }
+    virtual void ctrl(char const*const token, char const*const /*value*/)
+    {
+fprintf(stderr, "RTFDestination::ctrl: ignoring control %s\n", token);
+    }
+    virtual void lbrace()
+    {
+    }
+    virtual void rbrace()
+    {
+    }
+    virtual void HandleString (::rtl::OStringBuffer  & /*rBuf*/)
+    {
+fprintf(stderr, "RTFDestination::HandleString: ignoring string\n");
+    }
+    virtual void HandleStringU(::rtl::OUStringBuffer & /*rBuf*/)
+    {
+fprintf(stderr, "RTFDestination::HandleStringU: ignoring stringU\n");
+    }
+
+protected:
+    RTFScannerHandlerImpl & GetHandler() { return m_rHandler; }
+private:
+    RTFScannerHandlerImpl & m_rHandler;
+};
+
+static RTFDestination::Pointer_t
+createRootDestination(RTFScannerHandlerImpl &);
+
+
 static char
 lcl_HexDigit(char const c)
 {
@@ -261,27 +311,43 @@
 public:
     explicit RTFScannerHandlerImpl(Stream & rStream)
         : m_rStream(rStream)
-    { }
+    {
+        m_Destinations.push( ::std::make_pair(0,
+            RTFDestination::Pointer_t(createRootDestination(*this))) );
+    }
     virtual ~RTFScannerHandlerImpl() { }
     virtual void dest(char const*const token, char const*const value)
     {
         checkStrings();
+        RTFDestination::Pointer_t const pDestination(
+            m_Destinations.top().second->dest(token, value) );
+        OSL_ASSERT(pDestination);
+        if (pDestination) {
+            m_Destinations.push(::std::make_pair(1, pDestination));
+        }
     }
     virtual void ctrl(char const*const token, char const*const value)
     {
         checkStrings();
-        if (!strcasecmp(token, "par")) {
-            sal_uInt8 const nl(0x0d);
-            m_rStream.text(& nl, sizeof(nl));
-        }
+        m_Destinations.top().second->ctrl(token, value);
     }
     virtual void lbrace()
     {
         checkStrings();
+        m_Destinations.top().second->lbrace();
+        ++m_Destinations.top().first;
     }
     virtual void rbrace()
     {
         checkStrings();
+        m_Destinations.top().second->rbrace();
+        --m_Destinations.top().first;
+        if (0 == m_Destinations.top().first) {
+            if (m_Destinations.size() > 1) {
+fprintf(stderr, "RTFScannerHandlerImpl::rbrace: end destination\n");
+                m_Destinations.pop();
+            }
+        }
     }
     virtual void addSpaces(unsigned int const count)
     {
@@ -321,18 +387,14 @@
     void checkString()
     {
         if (m_String.getLength()) {
-            m_rStream.text(
-                reinterpret_cast<sal_uInt8 const*>(m_String.getStr()),
-                m_String.getLength());
+            m_Destinations.top().second->HandleString(m_String);
             m_String.makeStringAndClear();
         }
     }
     void checkUString()
     {
         if (m_UString.getLength()) {
-            m_rStream.utext(
-                reinterpret_cast<sal_uInt8 const*>(m_UString.getStr()),
-                m_UString.getLength());
+            m_Destinations.top().second->HandleStringU(m_UString);
             m_UString.makeStringAndClear();
         }
     }
@@ -341,9 +403,173 @@
        to unicode individually (could be mult-byte enconding!) */
     ::rtl::OStringBuffer m_String;
     ::rtl::OUStringBuffer m_UString;
+    ::std::stack< ::std::pair<int, RTFDestination::Pointer_t> > m_Destinations;
 };
 
 
+
+
+class RTFDestinationFontTable
+    : public RTFDestination
+{
+public:
+    explicit RTFDestinationFontTable(RTFScannerHandlerImpl & rHandler)
+        : RTFDestination(rHandler)
+        , m_Level(1)
+    { }
+    virtual ~RTFDestinationFontTable() { }
+
+    virtual void ctrl(char const*const token, char const*const value)
+    {
+        if (2 <= m_Level) {// nested group
+            if (!strcasecmp(token, "f")) {
+                m_Entry.m_Index = ::rtl::OString(value).toInt32();
+fprintf(stderr, "read: \\f with: %d\n", m_Entry.m_Index);
+            }
+        }
+    }
+    virtual void lbrace()
+    {
+        ++m_Level;
+    }
+    virtual void rbrace()
+    {
+        if (1 == m_Level) // end of font table
+        {
+fprintf(stderr, "RTFDestinationFontTable::rbrace: pushing font table\n");
+            writerfilter::Reference<Table>::Pointer_t const pTable(
+                    new RTFRefTable(m_Properties) );
+            GetHandler().GetStream().table(NS_rtf::LN_FONTTABLE, pTable);
+        }
+        else if (2 == m_Level) // end of font entry
+        {
+            ::rtl::OUString name(
+                ::rtl::OStringToOUString(m_Entry.m_Name,
+            //FIXME encoding?
+                    RTL_TEXTENCODING_ASCII_US).trim() );
+            if (name.endsWithAsciiL(";", 1)) { // strip trailing ;
+                name = name.copy(0, name.getLength() - 1);
+            }
+            if ((m_Entry.m_Index >= 0) && (name.getLength())) // valid?
+            {
+fprintf(stderr, "RTFDestinationFontTable::rbrace: adding entry\n");
+                RTFRefProperties::Attributes_t attrmap;
+                {
+                    RTFRefProperties::Attributes_t::mapped_type const
+                        pName( new RTFValueString(name) );
+//                attrmap.insert(NS_ooxml::LN_CT_Font_name, pName);
+                    attrmap.insert(::std::make_pair(NS_rtf::LN_XSZFFN, pName));
+                }
+
+                writerfilter::Reference<Properties>::Pointer_t const pProperties(
+                        new RTFRefProperties(attrmap) );
+                m_Properties.insert(
+                        ::std::make_pair(m_Entry.m_Index, pProperties));
+            }
+            m_Entry = Entry(); // reset
+        }
+        --m_Level;
+        OSL_ASSERT(m_Level >= 0);
+    }
+    virtual void HandleString (::rtl::OStringBuffer  & rBuf)
+    {
+        if (2 <= m_Level) { // nested group
+            m_Entry.m_Name += rBuf.makeStringAndClear();
+        }
+    }
+    virtual void HandleStringU(::rtl::OUStringBuffer & /*rBuf*/)
+    {
+    }
+
+private:
+    RTFRefTable::Properties_t m_Properties;
+    int m_Level;
+    struct Entry {
+        ::rtl::OString m_Name;
+        int m_Index;
+        explicit Entry() : m_Index(-1) { }
+    } m_Entry;
+};
+
+
+
+class RTFDestinationRTF
+    : public RTFDestination
+{
+public:
+    explicit RTFDestinationRTF(RTFScannerHandlerImpl & rHandler)
+        : RTFDestination(rHandler)
+    { }
+    virtual ~RTFDestinationRTF() { }
+
+    virtual Pointer_t dest(char const*const token, char const*const value)
+    {
+        if (!strcasecmp(token, "fonttbl")) {
+fprintf(stderr, "create RTFDestinationFontTable\n");
+            return Pointer_t(new RTFDestinationFontTable(GetHandler()));
+        }
+        return RTFDestination::dest(token, value);
+    }
+    virtual void ctrl(char const*const token, char const*const /*value*/)
+    {
+        if (!strcasecmp(token, "par")) {
+            sal_uInt8 const nl(0x0d);
+            GetHandler().GetStream().text(& nl, sizeof(nl));
+        }
+else fprintf(stderr, "RTFDestinationRTF::ctrl: ignoring control %s\n", token);
+    }
+#if 0
+    virtual Pointer_t lbrace()
+    {
+    }
+    virtual void rbrace()
+    {
+    }
+#endif
+    virtual void HandleString (::rtl::OStringBuffer  & rBuf)
+    {
+        GetHandler().GetStream().text(
+            reinterpret_cast<sal_uInt8 const*>(rBuf.getStr()),
+            rBuf.getLength());
+    }
+    virtual void HandleStringU(::rtl::OUStringBuffer & rBuf)
+    {
+        GetHandler().GetStream().utext(
+            reinterpret_cast<sal_uInt8 const*>(rBuf.getStr()),
+            rBuf.getLength());
+    }
+
+private:
+};
+
+
+class RTFDestinationRoot
+    : public RTFDestination
+{
+public:
+    explicit RTFDestinationRoot(RTFScannerHandlerImpl & rHandler)
+        : RTFDestination(rHandler)
+    { }
+    virtual ~RTFDestinationRoot() { }
+
+    virtual Pointer_t dest(char const*const token, char const*const value)
+    {
+        if (!strcasecmp(token, "rtf")) {
+fprintf(stderr, "create RTFDestinationRTF\n");
+            return Pointer_t(new RTFDestinationRTF(GetHandler()));
+        }
+        return RTFDestination::dest(token, value);
+    }
+};
+
+static RTFDestination::Pointer_t
+createRootDestination(RTFScannerHandlerImpl & rHandler)
+{
+    return RTFDestination::Pointer_t(new RTFDestinationRoot(rHandler));
+}
+
+
+
 class RTFDocumentImpl::Impl
 {
     friend class RTFDocumentImpl;
