Avoid potential negative array index access to cached text.
[LibreOffice.git] / tools / source / inet / inetstrm.cxx
blobac33f5eda4a3054adbef6d36a311a4b6b4065ce0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <cassert>
24 #include <sal/types.h>
25 #include <tools/inetmsg.hxx>
26 #include <tools/inetstrm.hxx>
28 int INetMIMEMessageStream::GetHeaderLine(char* pData, sal_uInt32 nSize)
30 char* pWBuf = pData;
32 sal_uInt32 i, n;
34 if (maMsgBuffer.Tell() == 0)
36 // Insert formatted header into buffer.
37 n = pSourceMsg->GetHeaderCount();
38 for (i = 0; i < n; i++)
40 INetMessageHeader aHeader (pSourceMsg->GetHeaderField(i));
41 if (aHeader.GetValue().getLength())
43 // NYI: Folding long lines.
44 maMsgBuffer.WriteOString( aHeader.GetName() );
45 maMsgBuffer.WriteOString( ": " );
46 maMsgBuffer.WriteOString( aHeader.GetValue() );
47 maMsgBuffer.WriteOString( "\r\n" );
51 pMsgWrite = const_cast<char *>(static_cast<char const *>(maMsgBuffer.GetData()));
52 pMsgRead = pMsgWrite + maMsgBuffer.Tell();
55 n = pMsgRead - pMsgWrite;
56 if (n > 0)
58 // Move to caller.
59 if (nSize < n) n = nSize;
60 for (i = 0; i < n; i++) *pWBuf++ = *pMsgWrite++;
62 else
64 // Reset buffer.
65 maMsgBuffer.Seek(STREAM_SEEK_TO_BEGIN);
68 return (pWBuf - pData);
71 int INetMIMEMessageStream::GetBodyLine(char* pData, sal_uInt32 nSize)
73 char* pWBuf = pData;
74 char* pWEnd = pData + nSize;
76 if (pSourceMsg->GetDocumentLB())
78 if (pMsgStrm == nullptr)
79 pMsgStrm.reset(new SvStream (pSourceMsg->GetDocumentLB()));
81 sal_uInt32 nRead = pMsgStrm->ReadBytes(pWBuf, (pWEnd - pWBuf));
82 pWBuf += nRead;
85 return (pWBuf - pData);
88 int INetMIMEMessageStream::GetMsgLine(char* pData, sal_uInt32 nSize)
90 // Check for header or body.
91 if (!bHeaderGenerated)
93 if (!done)
95 // Prepare special header fields.
96 if (pSourceMsg->GetParent())
98 OUString aPCT(pSourceMsg->GetParent()->GetContentType());
99 if (aPCT.startsWithIgnoreAsciiCase("message/rfc822"))
100 pSourceMsg->SetMIMEVersion("1.0");
101 else
102 pSourceMsg->SetMIMEVersion(OUString());
104 else
106 pSourceMsg->SetMIMEVersion("1.0");
109 // Check ContentType.
110 OUString aContentType(pSourceMsg->GetContentType());
111 if (!aContentType.isEmpty())
113 // Determine default Content-Type.
114 OUString aDefaultType = pSourceMsg->GetDefaultContentType();
116 if (aDefaultType.equalsIgnoreAsciiCase(aContentType))
118 // No need to specify default.
119 pSourceMsg->SetContentType(OUString());
123 // No need to specify default.
124 pSourceMsg->SetContentTransferEncoding(OUString());
126 // Mark we're done.
127 done = true;
130 // Generate the message header.
131 int nRead = GetHeaderLine(pData, nSize);
132 if (nRead <= 0)
134 // Reset state.
135 done = false;
137 return nRead;
139 else
141 // Generate the message body.
142 if (pSourceMsg->IsContainer())
144 // Encapsulated message body.
145 while (!done)
147 if (pChildStrm == nullptr)
149 INetMIMEMessage *pChild = pSourceMsg->GetChild(nChildIndex);
150 if (pChild)
152 // Increment child index.
153 nChildIndex++;
155 // Create child stream.
156 pChildStrm.reset(new INetMIMEMessageStream(pChild, false));
158 if (pSourceMsg->IsMultipart())
160 // Insert multipart delimiter.
161 OString aDelim = "--" +
162 pSourceMsg->GetMultipartBoundary() +
163 "\r\n";
165 memcpy(pData, aDelim.getStr(),
166 aDelim.getLength());
167 return aDelim.getLength();
170 else
172 // No more parts. Mark we're done.
173 done = true;
174 nChildIndex = 0;
176 if (pSourceMsg->IsMultipart())
178 // Insert close delimiter.
179 OString aDelim = "--" +
180 pSourceMsg->GetMultipartBoundary() +
181 "--\r\n";
183 memcpy(pData, aDelim.getStr(),
184 aDelim.getLength());
185 return aDelim.getLength();
189 else
191 // Read current child stream.
192 int nRead = pChildStrm->Read(pData, nSize);
193 if (nRead > 0)
195 return nRead;
197 else
199 // Cleanup exhausted child stream.
200 pChildStrm.reset();
204 return 0;
206 else
208 // Single part message body.
209 if (pSourceMsg->GetDocumentLB() == nullptr)
211 // Empty message body.
212 return 0;
215 // No Encoding.
216 return GetBodyLine(pData, nSize);
221 namespace
224 const int BUFFER_SIZE = 2048;
228 INetMIMEMessageStream::INetMIMEMessageStream(
229 INetMIMEMessage *pMsg, bool headerGenerated):
230 pSourceMsg(pMsg),
231 bHeaderGenerated(headerGenerated),
232 mvBuffer(BUFFER_SIZE),
233 pMsgRead(nullptr),
234 pMsgWrite(nullptr),
235 done(false),
236 nChildIndex(0)
238 assert(pMsg != nullptr);
239 maMsgBuffer.SetStreamCharSet(RTL_TEXTENCODING_ASCII_US);
240 pRead = pWrite = mvBuffer.data();
243 INetMIMEMessageStream::~INetMIMEMessageStream()
245 pChildStrm.reset();
248 int INetMIMEMessageStream::Read(char* pData, sal_uInt32 nSize)
250 char* pWBuf = pData;
251 char* pWEnd = pData + nSize;
253 while (pWBuf < pWEnd)
255 // Caller's buffer not yet filled.
256 sal_uInt32 n = pRead - pWrite;
257 if (n > 0)
259 // Bytes still in buffer.
260 sal_uInt32 m = pWEnd - pWBuf;
261 if (m < n) n = m;
262 for (sal_uInt32 i = 0; i < n; i++) *pWBuf++ = *pWrite++;
264 else
266 // Buffer empty. Reset to <Begin-of-Buffer>.
267 pRead = pWrite = mvBuffer.data();
269 // Read next message line.
270 int nRead = GetMsgLine(mvBuffer.data(), mvBuffer.size());
271 if (nRead > 0)
273 // Set read pointer.
274 pRead = mvBuffer.data() + nRead;
276 else
278 if (!bHeaderGenerated)
280 // Header generated. Insert empty line.
281 bHeaderGenerated = true;
282 *pRead++ = '\r';
283 *pRead++ = '\n';
285 else
287 // Body generated.
288 return (pWBuf - pData);
293 return (pWBuf - pData);
296 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */