1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: readline.c,v $
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>
33 #include <rtl/byteseq.h>
34 #include <rtl/alloc.h>
39 1. A file without line ends
40 2. A file with lines longer than the initial buffer size
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
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
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
;
78 pBuffer
->m_pMem
= (sal_Char
*)rtl_allocateZeroMemory((sal_uInt32
)Capacity
);
81 pBuffer
->m_Capacity
= Capacity
;
83 pBuffer
->m_ActiveSectionStart
= 0;
90 /** Release the memory occupied by the buffer
92 static void FreeBuffer(Buffer
* pBuffer
)
96 rtl_freeMemory(pBuffer
->m_pMem
);
98 pBuffer
->m_Capacity
= 0;
100 pBuffer
->m_ActiveSectionStart
= 0;
103 /** Grow the buffer by the specified factor (usually doubling
105 In case of failure, growing the buffer, the original buffer
108 @Returns sal_True on success
110 static sal_Bool
GrowBuffer(Buffer
* pBuffer
, size_t factor
)
112 sal_Bool rc
= sal_False
;
117 p
= rtl_reallocateMemory(
118 pBuffer
->m_pMem
, (sal_uInt32
)(pBuffer
->m_Capacity
* factor
));
121 pBuffer
->m_pMem
= (sal_Char
*)p
;
122 pBuffer
->m_Capacity
*= factor
;
129 /** Read n bytes from file into buffer,
130 grow the buffer if necessary
132 @Returns osl_File_E_None on success else
135 static oslFileError
ReadFromFile(oslFileHandle hFile
, Buffer
* pBuffer
, sal_uInt64 Requested
, sal_uInt64
* 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
;
151 pBuffer
->m_pMem
+ pBuffer
->m_ActiveSectionStart
,
155 if (osl_File_E_None
== rc
)
156 pBuffer
->m_Size
+= *pRead
;
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
);
168 OSL_ASSERT(Length
<= pBuffer
->m_Capacity
);
170 rtl_byte_sequence_constructFromArray(ppSequence
, (sal_Int8
*)pBuffer
->m_pMem
, (sal_Int32
)Length
);
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
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
;
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
);
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
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
;
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
)
232 MakeSequenceFreeBuffer(ppSequence
, pBuffer
, Pos
);
233 return osl_File_E_None
;
237 if (LF
== pBuffer
->m_pMem
[Pos
+ 1])
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);
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
)
269 sal_uInt64 nread
= 0;
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
;
281 rc
= ReadFromFile(Handle
, &line_buffer
, READ_BLOCK_SIZE
, &nread
);
283 if (osl_File_E_None
!= rc
)
285 FreeBuffer(&line_buffer
);
291 nread
= line_buffer
.m_Size
;
292 MakeSequenceFreeBuffer(ppSeq
, &line_buffer
, nread
);
294 return osl_File_E_None
;
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
])
305 return HandleLFFreeBuffer(Handle
, ppSeq
, &line_buffer
, pos
);
307 return HandleCRFreeBuffer(Handle
, ppSeq
, &line_buffer
, pos
);