summaryrefslogtreecommitdiff
path: root/sw/source/filter/html/htmlreqifreader.cxx
blob: 34199d8a613f53d3d245b59313d1e4bd520c2d64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "htmlreqifreader.hxx"

#include <rtl/character.hxx>
#include <rtl/strbuf.hxx>
#include <svtools/parrtf.hxx>
#include <svtools/rtftoken.h>
#include <tools/stream.hxx>

namespace
{
int AsHex(char ch)
{
    int ret = 0;
    if (rtl::isAsciiDigit(static_cast<unsigned char>(ch)))
        ret = ch - '0';
    else
    {
        if (ch >= 'a' && ch <= 'f')
            ret = ch - 'a';
        else if (ch >= 'A' && ch <= 'F')
            ret = ch - 'A';
        else
            return -1;
        ret += 10;
    }
    return ret;
}

/// RTF parser that just extracts a single OLE2 object from a file.
class ReqIfRtfReader : public SvRTFParser
{
public:
    ReqIfRtfReader(SvStream& rStream);
    void NextToken(int nToken) override;
    bool WriteObjectData(SvStream& rStream);

private:
    bool m_bInObjData = false;
    OStringBuffer m_aHex;
};

ReqIfRtfReader::ReqIfRtfReader(SvStream& rStream)
    : SvRTFParser(rStream)
{
}

void ReqIfRtfReader::NextToken(int nToken)
{
    switch (nToken)
    {
        case '}':
            m_bInObjData = false;
            break;
        case RTF_TEXTTOKEN:
            if (m_bInObjData)
                m_aHex.append(OUStringToOString(aToken, RTL_TEXTENCODING_ASCII_US));
            break;
        case RTF_OBJDATA:
            m_bInObjData = true;
            break;
    }
}

bool ReqIfRtfReader::WriteObjectData(SvStream& rOLE)
{
    int b = 0, count = 2;

    SvMemoryStream aBuf;
    for (int i = 0; i < m_aHex.getLength(); ++i)
    {
        char ch = m_aHex[i];
        if (ch != 0x0d && ch != 0x0a)
        {
            b = b << 4;
            sal_Int8 parsed = AsHex(ch);
            if (parsed == -1)
                return false;
            b += parsed;
            count--;
            if (!count)
            {
                aBuf.WriteChar(b);
                count = 2;
                b = 0;
            }
        }
    }

    // Skip ObjectHeader, see [MS-OLEDS] 2.2.4.
    if (aBuf.Tell())
    {
        aBuf.Seek(0);
        sal_uInt32 nData;
        aBuf.ReadUInt32(nData); // OLEVersion
        aBuf.ReadUInt32(nData); // FormatID
        aBuf.ReadUInt32(nData); // ClassName
        aBuf.SeekRel(nData);
        aBuf.ReadUInt32(nData); // TopicName
        aBuf.SeekRel(nData);
        aBuf.ReadUInt32(nData); // ItemName
        aBuf.SeekRel(nData);
        aBuf.ReadUInt32(nData); // NativeDataSize

        if (nData)
        {
            rOLE.WriteStream(aBuf);
            rOLE.Seek(0);
        }
    }

    return true;
}
}

namespace SwReqIfReader
{
bool ExtractOleFromRtf(SvStream& rRtf, SvStream& rOle)
{
    // Add missing header/footer.
    SvMemoryStream aRtf;
    aRtf.WriteOString("{\\rtf1");
    aRtf.WriteStream(rRtf);
    aRtf.WriteOString("}");
    aRtf.Seek(0);

    // Read the RTF markup.
    tools::SvRef<ReqIfRtfReader> xReader(new ReqIfRtfReader(aRtf));
    SvParserState eState = xReader->CallParser();
    if (eState == SvParserState::Error)
        return false;

    // Write the OLE2 data.
    return xReader->WriteObjectData(rOle);
}
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */