Merge with MPC-HC 6d1472b2f18266d92e5bc068667de348c0cd3b3b.
[xy_vsfilter.git] / src / subtitles / libssf / Stream.cpp
blob25e5c9af9cc137ef2ffff475f0590413e3652e1c
1 /*
2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 #include "stdafx.h"
23 #include "Stream.h"
24 #include <stdio.h>
26 namespace ssf
28 Stream::Stream()
29 : m_encoding(none)
30 , m_line(0)
31 , m_col(-1)
36 Stream::~Stream()
40 void Stream::ThrowError(LPCTSTR fmt, ...)
42 va_list args;
43 va_start(args, fmt);
44 int len = _vsctprintf(fmt, args) + 1;
45 CString str;
46 if(len > 0) _vstprintf_s(str.GetBufferSetLength(len), len, fmt, args);
47 va_end(args);
49 throw Exception(_T("Error (Ln %d Col %d): %s"), m_line+1, m_col+1, str);
52 bool Stream::IsWhiteSpace(int c, LPCWSTR morechars)
54 return c != 0xa0 && iswspace(c) || morechars && wcschr(morechars, (WCHAR)c);
59 InputStream::InputStream()
64 InputStream::~InputStream()
68 int InputStream::NextChar()
70 if(m_encoding == none)
72 m_encoding = unknown;
74 switch(NextByte())
76 case 0xef:
77 if(NextByte() == 0xbb && NextByte() == 0xbf) m_encoding = utf8;
78 break;
79 case 0xff:
80 if(NextByte() == 0xfe) m_encoding = utf16le;
81 break;
82 case 0xfe:
83 if(NextByte() == 0xff) m_encoding = utf16be;
84 break;
88 if(m_encoding == unknown)
90 throw Exception(_T("unknown character encoding, missing BOM"));
93 int i, c;
95 int cur = NextByte();
97 switch(m_encoding)
99 case utf8:
100 for(i = 7; i >= 0 && (cur & (1 << i)); i--);
101 cur &= (1 << i) - 1;
102 while(++i < 7) {c = NextByte(); if(c == EOS) {cur = EOS; break;} cur = (cur << 6) | (c & 0x3f);}
103 break;
104 case utf16le:
105 c = NextByte();
106 if(c == EOS) {cur = EOS; break;}
107 cur = (c << 8) | cur;
108 break;
109 case utf16be:
110 c = NextByte();
111 if(c == EOS) {cur = EOS; break;}
112 cur = cur | (c << 8);
113 break;
114 case wchar:
115 break;
118 return cur;
121 int InputStream::PushChar()
123 int c = NextChar();
124 m_queue.AddTail(c);
125 return c;
128 int InputStream::PopChar()
130 if(m_queue.IsEmpty()) ThrowError(_T("fatal stream error"));
132 int c = m_queue.RemoveHead();
134 if(c != EOS)
136 if(c == '\n') {m_line++; m_col = -1;}
137 m_col++;
140 return c;
143 int InputStream::PeekChar()
145 while(m_queue.GetCount() < 2) PushChar();
147 ASSERT(m_queue.GetCount() == 2);
149 if(m_queue.GetHead() == '/' && m_queue.GetTail() == '/')
151 while(!m_queue.IsEmpty()) PopChar();
152 int c;
153 do {PushChar(); c = PopChar();} while(!(c == '\n' || c == EOS));
154 return PeekChar();
156 else if(m_queue.GetHead() == '/' && m_queue.GetTail() == '*')
158 while(!m_queue.IsEmpty()) PopChar();
159 int c1, c2;
160 PushChar();
161 do {c2 = PushChar(); c1 = PopChar();} while(!((c1 == '*' && c2 == '/') || c1 == EOS));
162 PopChar();
163 return PeekChar();
166 return m_queue.GetHead();
169 int InputStream::GetChar()
171 if(m_queue.GetCount() < 2) PeekChar();
172 return PopChar();
175 int InputStream::SkipWhiteSpace(LPCWSTR morechars)
177 int c = PeekChar();
178 for(; IsWhiteSpace(c, morechars); c = PeekChar())
179 GetChar();
180 return c;
183 // FileInputStream
185 FileInputStream::FileInputStream(const TCHAR* fn)
186 : m_file(NULL)
188 if(_tfopen_s(&m_file, fn, _T("r")) != 0) ThrowError(_T("cannot open file '%s'"), fn);
191 FileInputStream::~FileInputStream()
193 if(m_file) {fclose(m_file); m_file = NULL;}
196 int FileInputStream::NextByte()
198 if(!m_file) ThrowError(_T("file pointer is NULL"));
199 return fgetc(m_file);
202 // MemoryInputStream
204 MemoryInputStream::MemoryInputStream(BYTE* pBytes, int len, bool fCopy, bool fFree)
205 : m_pBytes(NULL)
206 , m_pos(0)
207 , m_len(len)
209 if(fCopy)
211 m_pBytes = new BYTE[len];
212 if(m_pBytes) memcpy(m_pBytes, pBytes, len);
213 m_fFree = true;
215 else
217 m_pBytes = pBytes;
218 m_fFree = fFree;
221 if(!m_pBytes) ThrowError(_T("memory stream pointer is NULL"));
224 MemoryInputStream::~MemoryInputStream()
226 if(m_fFree) delete [] m_pBytes;
227 m_pBytes = NULL;
230 int MemoryInputStream::NextByte()
232 if(!m_pBytes) ThrowError(_T("memory stream pointer is NULL"));
233 if(m_pos >= m_len) return Stream::EOS;
234 return (int)m_pBytes[m_pos++];
237 // WCharInputStream
239 WCharInputStream::WCharInputStream(CStringW str)
240 : m_str(str)
241 , m_pos(0)
243 m_encoding = Stream::wchar; // HACK: it should return real bytes from NextByte (two per wchar_t), but this way it's a lot more simple...
246 int WCharInputStream::NextByte()
248 if(m_pos >= m_str.GetLength()) return Stream::EOS;
249 return m_str[m_pos++];
252 // OutputStream
254 OutputStream::OutputStream(encoding_t e)
256 m_encoding = e;
257 m_bof = true;
260 OutputStream::~OutputStream()
264 void OutputStream::PutChar(WCHAR c)
266 if(m_bof)
268 m_bof = false;
270 switch(m_encoding)
272 case utf8:
273 case utf16le:
274 case utf16be:
275 PutChar(0xfeff);
276 break;
280 switch(m_encoding)
282 case utf8:
283 if(0 <= c && c < 0x80) // 0xxxxxxx
285 NextByte(c);
287 else if(0x80 <= c && c < 0x800) // 110xxxxx 10xxxxxx
289 NextByte(0xc0 | ((c<<2)&0x1f));
290 NextByte(0x80 | ((c<<0)&0x3f));
292 else if(0x800 <= c && c < 0xFFFF) // 1110xxxx 10xxxxxx 10xxxxxx
294 NextByte(0xe0 | ((c<<4)&0x0f));
295 NextByte(0x80 | ((c<<2)&0x3f));
296 NextByte(0x80 | ((c<<0)&0x3f));
298 else
300 NextByte('?');
302 break;
303 case utf16le:
304 NextByte(c & 0xff);
305 NextByte((c >> 8) & 0xff);
306 break;
307 case utf16be:
308 NextByte((c >> 8) & 0xff);
309 NextByte(c & 0xff);
310 break;
311 case wchar:
312 NextByte(c);
313 break;
317 void OutputStream::PutString(LPCWSTR fmt, ...)
319 CStringW str;
321 va_list args;
322 va_start(args, fmt);
323 int len = _vscwprintf(fmt, args) + 1;
324 if(len > 0) vswprintf_s(str.GetBufferSetLength(len), len, fmt, args);
325 va_end(args);
327 LPCWSTR s = str;
328 while(*s) PutChar(*s++);
331 // WCharOutputStream
333 WCharOutputStream::WCharOutputStream()
334 : OutputStream(wchar)
338 void WCharOutputStream::NextByte(int b)
340 m_str += (WCHAR)b;
343 // DebugOutputStream
345 DebugOutputStream::DebugOutputStream()
346 : OutputStream(wchar)
350 DebugOutputStream::~DebugOutputStream()
352 TRACE(_T("%s\n"), m_str);
355 void DebugOutputStream::NextByte(int b)
357 if(b == '\n') {TRACE(_T("%s\n"), m_str); m_str.Empty();}
358 else if(b != '\r') m_str += (WCHAR)b;