1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#include "linereader.h"
4
5#include <base/system.h>
6
7CLineReader::CLineReader()
8{
9 m_pBuffer = nullptr;
10}
11
12CLineReader::~CLineReader()
13{
14 free(ptr: m_pBuffer);
15}
16
17bool CLineReader::OpenFile(IOHANDLE File)
18{
19 if(!File)
20 {
21 return false;
22 }
23 char *pBuffer = io_read_all_str(io: File);
24 io_close(io: File);
25 if(pBuffer == nullptr)
26 {
27 return false;
28 }
29 OpenBuffer(pBuffer);
30 return true;
31}
32
33void CLineReader::OpenBuffer(char *pBuffer)
34{
35 dbg_assert(pBuffer != nullptr, "Line reader initialized without valid buffer");
36
37 m_pBuffer = pBuffer;
38 m_BufferPos = 0;
39 m_ReadLastLine = false;
40
41 // Skip UTF-8 BOM
42 if(m_pBuffer[0] == '\xEF' && m_pBuffer[1] == '\xBB' && m_pBuffer[2] == '\xBF')
43 {
44 m_BufferPos += 3;
45 }
46}
47
48const char *CLineReader::Get()
49{
50 dbg_assert(m_pBuffer != nullptr, "Line reader not initialized");
51 if(m_ReadLastLine)
52 {
53 return nullptr;
54 }
55
56 unsigned LineStart = m_BufferPos;
57 while(true)
58 {
59 if(m_pBuffer[m_BufferPos] == '\0' || m_pBuffer[m_BufferPos] == '\n' || (m_pBuffer[m_BufferPos] == '\r' && m_pBuffer[m_BufferPos + 1] == '\n'))
60 {
61 if(m_pBuffer[m_BufferPos] == '\0')
62 {
63 m_ReadLastLine = true;
64 }
65 else
66 {
67 if(m_pBuffer[m_BufferPos] == '\r')
68 {
69 m_pBuffer[m_BufferPos] = '\0';
70 ++m_BufferPos;
71 }
72 m_pBuffer[m_BufferPos] = '\0';
73 ++m_BufferPos;
74 }
75
76 if(!str_utf8_check(str: &m_pBuffer[LineStart]))
77 {
78 // Skip lines containing invalid UTF-8
79 if(m_ReadLastLine)
80 {
81 return nullptr;
82 }
83 LineStart = m_BufferPos;
84 continue;
85 }
86 // Skip trailing empty line
87 if(m_ReadLastLine && m_pBuffer[LineStart] == '\0')
88 {
89 return nullptr;
90 }
91 return &m_pBuffer[LineStart];
92 }
93 ++m_BufferPos;
94 }
95}
96