update dev300-m57
[ooovba.git] / sal / osl / all / readline.c
blobe5baa4f965d5e3e73c3b242ab05b2878a5755468
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: readline.c,v $
10 * $Revision: 1.9 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include <osl/diagnose.h>
32 #include <osl/file.h>
33 #include <rtl/byteseq.h>
34 #include <rtl/alloc.h>
37 /* Test cases:
39 1. A file without line ends
40 2. A file with lines longer than the initial buffer size
41 3. An empty file
42 4.
45 /** Some defines
47 #define CR 0x0D
48 #define LF 0x0A
50 #define INITIAL_BUFF_SIZE 80
51 #define BUFFER_GROW_FACTOR 2
52 #define READ_BLOCK_SIZE (INITIAL_BUFF_SIZE - 1)
54 /** Helper data and function
55 */
57 struct _Buffer
59 sal_Char* m_pMem;
60 sal_uInt64 m_Capacity; /* elements possible in buffer */
61 sal_uInt64 m_Size; /* elements actually in buffer */
62 sal_uInt64 m_ActiveSectionStart; /* buffer was lastly filled from here to
63 (m_Size - 1) */
66 typedef struct _Buffer Buffer;
69 /** Allocate the memory of the buffer
70 @Returns sal_True on succes
72 static sal_Bool AllocateBuffer(Buffer* pBuffer, sal_uInt64 Capacity)
74 sal_Bool rc = sal_False;
76 OSL_ASSERT(pBuffer);
78 pBuffer->m_pMem = (sal_Char*)rtl_allocateZeroMemory((sal_uInt32)Capacity);
79 if (pBuffer->m_pMem)
81 pBuffer->m_Capacity = Capacity;
82 pBuffer->m_Size = 0;
83 pBuffer->m_ActiveSectionStart = 0;
84 rc = sal_True;
87 return rc;
90 /** Release the memory occupied by the buffer
92 static void FreeBuffer(Buffer* pBuffer)
94 OSL_ASSERT(pBuffer);
96 rtl_freeMemory(pBuffer->m_pMem);
97 pBuffer->m_pMem = 0;
98 pBuffer->m_Capacity = 0;
99 pBuffer->m_Size = 0;
100 pBuffer->m_ActiveSectionStart = 0;
103 /** Grow the buffer by the specified factor (usually doubling
104 the buffer size)
105 In case of failure, growing the buffer, the original buffer
106 stays untouched
108 @Returns sal_True on success
110 static sal_Bool GrowBuffer(Buffer* pBuffer, size_t factor)
112 sal_Bool rc = sal_False;
113 void* p;
115 OSL_ASSERT(pBuffer);
117 p = rtl_reallocateMemory(
118 pBuffer->m_pMem, (sal_uInt32)(pBuffer->m_Capacity * factor));
119 if (p)
121 pBuffer->m_pMem = (sal_Char*)p;
122 pBuffer->m_Capacity *= factor;
123 rc = sal_True;
126 return rc;
129 /** Read n bytes from file into buffer,
130 grow the buffer if necessary
132 @Returns osl_File_E_None on success else
133 an error code
135 static oslFileError ReadFromFile(oslFileHandle hFile, Buffer* pBuffer, sal_uInt64 Requested, sal_uInt64* pRead)
137 oslFileError rc;
139 OSL_ASSERT(pBuffer);
140 OSL_ASSERT(hFile);
141 OSL_ASSERT(pRead);
143 if (((pBuffer->m_Size + Requested) > pBuffer->m_Capacity) &&
144 !GrowBuffer(pBuffer, BUFFER_GROW_FACTOR))
145 return osl_File_E_NOMEM;
147 pBuffer->m_ActiveSectionStart = pBuffer->m_Size;
149 rc = osl_readFile(
150 hFile,
151 pBuffer->m_pMem + pBuffer->m_ActiveSectionStart,
152 Requested,
153 pRead);
155 if (osl_File_E_None == rc)
156 pBuffer->m_Size += *pRead;
158 return rc;
161 /** Makes a sequence from the given buffer and release the memory
162 occupied by the buffer
164 static void MakeSequenceFreeBuffer(sal_Sequence** ppSequence, Buffer* pBuffer, sal_uInt64 Length)
166 OSL_ASSERT(ppSequence);
167 OSL_ASSERT(pBuffer);
168 OSL_ASSERT(Length <= pBuffer->m_Capacity);
170 rtl_byte_sequence_constructFromArray(ppSequence, (sal_Int8*)pBuffer->m_pMem, (sal_Int32)Length);
171 FreeBuffer(pBuffer);
174 /** Handle occurence of LF character:
175 construct a sequence from buffer
176 correct file pointer (maybe we have read more than necessary)
178 @Returns osl_File_E_None on success else
179 an error code
181 static oslFileError HandleLFFreeBuffer(oslFileHandle hFile, sal_Sequence** ppSequence, Buffer* pBuffer, sal_uInt64 Pos)
183 sal_Int64 offset = 0;
184 oslFileError rc = osl_File_E_None;
186 OSL_ASSERT(hFile);
187 OSL_ASSERT(pBuffer);
188 OSL_ASSERT(LF == pBuffer->m_pMem[Pos]);
190 /* correct file pointer pos in case we have read to far */
191 offset = pBuffer->m_Size - (Pos + 1);
192 rc = osl_setFilePos(hFile, osl_Pos_Current, -offset);
194 if (osl_File_E_None == rc)
195 MakeSequenceFreeBuffer(ppSequence, pBuffer, Pos);
196 else
197 FreeBuffer(pBuffer);
199 return rc;
202 /** Handle occurence of CR character
203 construct a sequence from buffer
204 correct file pointer (maybe we have read more than necessary)
206 @Returns osl_File_E_None on success else
207 an error code
209 static oslFileError HandleCRFreeBuffer(oslFileHandle hFile, sal_Sequence** ppSequence, Buffer* pBuffer, sal_uInt64 Pos)
211 sal_Int64 offset = 0;
212 sal_uInt64 nread = 0;
213 oslFileError rc = osl_File_E_None;
215 OSL_ASSERT(hFile);
216 OSL_ASSERT(pBuffer);
217 OSL_ASSERT(CR == pBuffer->m_pMem[Pos]);
219 if (Pos == (pBuffer->m_Size - 1))
221 /* only need to check if the next byte is a LF
222 that's why reading only one byte from file */
223 rc = ReadFromFile(hFile, pBuffer, 1, &nread);
225 if (osl_File_E_None != rc)
227 FreeBuffer(pBuffer);
228 return rc;
230 else if (0 == nread)
232 MakeSequenceFreeBuffer(ppSequence, pBuffer, Pos);
233 return osl_File_E_None;
237 if (LF == pBuffer->m_pMem[Pos + 1])
238 Pos++;
240 /* correct the file pointer */
241 offset = pBuffer->m_Size - (Pos + 1);
242 rc = osl_setFilePos(hFile, osl_Pos_Current, -offset);
244 if (osl_File_E_None == rc)
245 MakeSequenceFreeBuffer(ppSequence, pBuffer, Pos - 1);
246 else
247 FreeBuffer(pBuffer);
249 return rc;
252 /***************************************************************************
253 osl_readLine (platform independent)
254 Reads a line from given file. The new line delimiter(s) are NOT returned!
255 Valid line ends: \n, \r\n or \r
257 @param Handle [in] Handle to an open file.
258 @param ppSequence [in/out] a pointer to a valid sequence.
260 @return osl_File_E_None on success otherwise one of the following errorcodes:<p>
262 osl_File_E_INVAL the format of the parameters was not valid<br>
263 osl_File_E_NOMEM the necessary memory could not be allocated
264 ****************************************************************************/
266 oslFileError SAL_CALL osl_readLine(oslFileHandle Handle, sal_Sequence** ppSeq)
268 oslFileError rc;
269 sal_uInt64 nread = 0;
270 Buffer line_buffer;
271 sal_uInt64 pos;
273 OSL_PRECOND(Handle, "invalid handle");
274 OSL_PRECOND(ppSeq, "invalid parameter detected");
276 if (!AllocateBuffer(&line_buffer, INITIAL_BUFF_SIZE))
277 return osl_File_E_NOMEM;
279 for(;;)
281 rc = ReadFromFile(Handle, &line_buffer, READ_BLOCK_SIZE, &nread);
283 if (osl_File_E_None != rc)
285 FreeBuffer(&line_buffer);
286 return rc;
288 else if (0 == nread)
290 /* EOF */
291 nread = line_buffer.m_Size;
292 MakeSequenceFreeBuffer(ppSeq, &line_buffer, nread);
293 if (0 < nread)
294 return osl_File_E_None;
295 else
296 return osl_File_E_AGAIN;
299 /* scan buffer for line end */
300 for (pos = line_buffer.m_ActiveSectionStart; pos < line_buffer.m_Size; pos++)
302 switch(line_buffer.m_pMem[pos])
304 case LF:
305 return HandleLFFreeBuffer(Handle, ppSeq, &line_buffer, pos);
306 case CR:
307 return HandleCRFreeBuffer(Handle, ppSeq, &line_buffer, pos);
310 } /* end for */