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 | |
7 | CLineReader::CLineReader() |
8 | { |
9 | m_pBuffer = nullptr; |
10 | } |
11 | |
12 | CLineReader::~CLineReader() |
13 | { |
14 | free(ptr: m_pBuffer); |
15 | } |
16 | |
17 | bool 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 | |
33 | void 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 | |
48 | const 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 |