mirror of https://github.com/odrling/Aegisub
538 lines
9.9 KiB
C++
538 lines
9.9 KiB
C++
/*
|
|
* Copyright (C) 2003-2006 Gabest
|
|
* http://www.gabest.org
|
|
*
|
|
* This Program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This Program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with GNU Make; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
*
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include <atlbase.h>
|
|
#include <afxinet.h>
|
|
#include "TextFile.h"
|
|
|
|
CTextFile::CTextFile(enc e)
|
|
{
|
|
m_encoding = m_defaultencoding = e;
|
|
m_offset = 0;
|
|
}
|
|
|
|
bool CTextFile::Open(LPCTSTR lpszFileName)
|
|
{
|
|
if(!__super::Open(lpszFileName, modeRead|typeBinary|shareDenyWrite))
|
|
return(false);
|
|
|
|
m_encoding = m_defaultencoding;
|
|
m_offset = 0;
|
|
|
|
if(__super::GetLength() >= 2)
|
|
{
|
|
WORD w;
|
|
if(sizeof(w) != Read(&w, sizeof(w)))
|
|
return Close(), false;
|
|
|
|
if(w == 0xfeff)
|
|
{
|
|
m_encoding = LE16;
|
|
m_offset = 2;
|
|
}
|
|
else if(w == 0xfffe)
|
|
{
|
|
m_encoding = BE16;
|
|
m_offset = 2;
|
|
}
|
|
else if(w == 0xbbef && __super::GetLength() >= 3)
|
|
{
|
|
BYTE b;
|
|
if(sizeof(b) != Read(&b, sizeof(b)))
|
|
return Close(), false;
|
|
|
|
if(b == 0xbf)
|
|
{
|
|
m_encoding = UTF8;
|
|
m_offset = 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m_encoding == m_defaultencoding)
|
|
{
|
|
__super::Close(); // CWebTextFile::Close() would delete the temp file if we called it...
|
|
if(!__super::Open(lpszFileName, modeRead|typeText|shareDenyWrite))
|
|
return(false);
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
bool CTextFile::Save(LPCTSTR lpszFileName, enc e)
|
|
{
|
|
if(!__super::Open(lpszFileName, modeCreate|modeWrite|shareDenyWrite|(e==ASCII?typeText:typeBinary)))
|
|
return(false);
|
|
|
|
if(e == UTF8)
|
|
{
|
|
BYTE b[3] = {0xef,0xbb,0xbf};
|
|
Write(b, sizeof(b));
|
|
}
|
|
else if(e == LE16)
|
|
{
|
|
BYTE b[2] = {0xff,0xfe};
|
|
Write(b, sizeof(b));
|
|
}
|
|
else if(e == BE16)
|
|
{
|
|
BYTE b[2] = {0xfe,0xff};
|
|
Write(b, sizeof(b));
|
|
}
|
|
|
|
m_encoding = e;
|
|
|
|
return true;
|
|
}
|
|
|
|
void CTextFile::SetEncoding(enc e)
|
|
{
|
|
m_encoding = e;
|
|
}
|
|
|
|
CTextFile::enc CTextFile::GetEncoding()
|
|
{
|
|
return m_encoding;
|
|
}
|
|
|
|
bool CTextFile::IsUnicode()
|
|
{
|
|
return m_encoding == UTF8 || m_encoding == LE16 || m_encoding == BE16;
|
|
}
|
|
|
|
// CFile
|
|
|
|
CString CTextFile::GetFilePath() const
|
|
{
|
|
// to avoid a CException coming from CTime
|
|
return m_strFileName; // __super::GetFilePath();
|
|
}
|
|
|
|
// CStdioFile
|
|
|
|
ULONGLONG CTextFile::GetPosition() const
|
|
{
|
|
return(CStdioFile::GetPosition() - m_offset);
|
|
}
|
|
|
|
ULONGLONG CTextFile::GetLength() const
|
|
{
|
|
return(CStdioFile::GetLength() - m_offset);
|
|
}
|
|
|
|
ULONGLONG CTextFile::Seek(LONGLONG lOff, UINT nFrom)
|
|
{
|
|
ULONGLONG pos = GetPosition();
|
|
ULONGLONG len = GetLength();
|
|
|
|
switch(nFrom)
|
|
{
|
|
default:
|
|
case begin: lOff = lOff; break;
|
|
case current: lOff = pos + lOff; break;
|
|
case end: lOff = len - lOff; break;
|
|
}
|
|
|
|
lOff = max(min(lOff, len), 0) + m_offset;
|
|
|
|
pos = CStdioFile::Seek(lOff, begin) - m_offset;
|
|
|
|
return(pos);
|
|
}
|
|
|
|
void CTextFile::WriteString(LPCSTR lpsz/*CStringA str*/)
|
|
{
|
|
CStringA str(lpsz);
|
|
|
|
if(m_encoding == ASCII)
|
|
{
|
|
__super::WriteString(AToT(str));
|
|
}
|
|
else if(m_encoding == ANSI)
|
|
{
|
|
str.Replace("\n", "\r\n");
|
|
Write((LPCSTR)str, str.GetLength());
|
|
}
|
|
else if(m_encoding == UTF8)
|
|
{
|
|
WriteString(AToW(str));
|
|
}
|
|
else if(m_encoding == LE16)
|
|
{
|
|
WriteString(AToW(str));
|
|
}
|
|
else if(m_encoding == BE16)
|
|
{
|
|
WriteString(AToW(str));
|
|
}
|
|
}
|
|
|
|
void CTextFile::WriteString(LPCWSTR lpsz/*CStringW str*/)
|
|
{
|
|
CStringW str(lpsz);
|
|
|
|
if(m_encoding == ASCII)
|
|
{
|
|
__super::WriteString(WToT(str));
|
|
}
|
|
else if(m_encoding == ANSI)
|
|
{
|
|
str.Replace(L"\n", L"\r\n");
|
|
CStringA stra = CStringA(CString(str)); // TODO: codepage
|
|
Write((LPCSTR)stra, stra.GetLength());
|
|
}
|
|
else if(m_encoding == UTF8)
|
|
{
|
|
str.Replace(L"\n", L"\r\n");
|
|
for(int i = 0; i < str.GetLength(); i++)
|
|
{
|
|
DWORD c = (WORD)str[i];
|
|
|
|
if(0 <= c && c < 0x80) // 0xxxxxxx
|
|
{
|
|
Write(&c, 1);
|
|
}
|
|
else if(0x80 <= c && c < 0x800) // 110xxxxx 10xxxxxx
|
|
{
|
|
c = 0xc080|((c<<2)&0x1f00)|(c&0x003f);
|
|
Write((BYTE*)&c+1, 1);
|
|
Write(&c, 1);
|
|
}
|
|
else if(0x800 <= c && c < 0xFFFF) // 1110xxxx 10xxxxxx 10xxxxxx
|
|
{
|
|
c = 0xe08080|((c<<4)&0x0f0000)|((c<<2)&0x3f00)|(c&0x003f);
|
|
Write((BYTE*)&c+2, 1);
|
|
Write((BYTE*)&c+1, 1);
|
|
Write(&c, 1);
|
|
}
|
|
else
|
|
{
|
|
c = '?';
|
|
Write(&c, 1);
|
|
}
|
|
}
|
|
}
|
|
else if(m_encoding == LE16)
|
|
{
|
|
str.Replace(L"\n", L"\r\n");
|
|
Write((LPCWSTR)str, str.GetLength()*2);
|
|
}
|
|
else if(m_encoding == BE16)
|
|
{
|
|
str.Replace(L"\n", L"\r\n");
|
|
for(int i = 0; i < str.GetLength(); i++)
|
|
str.SetAt(i, ((str[i]>>8)&0x00ff)|((str[i]<<8)&0xff00));
|
|
Write((LPCWSTR)str, str.GetLength()*2);
|
|
}
|
|
}
|
|
|
|
BOOL CTextFile::ReadString(CStringA& str)
|
|
{
|
|
bool fEOF = true;
|
|
|
|
str.Empty();
|
|
|
|
if(m_encoding == ASCII)
|
|
{
|
|
CString s;
|
|
fEOF = !__super::ReadString(s);
|
|
str = TToA(s);
|
|
}
|
|
else if(m_encoding == ANSI)
|
|
{
|
|
char c;
|
|
while(Read(&c, sizeof(c)) == sizeof(c))
|
|
{
|
|
fEOF = false;
|
|
if(c == '\r') continue;
|
|
if(c == '\n') break;
|
|
str += c;
|
|
}
|
|
}
|
|
else if(m_encoding == UTF8)
|
|
{
|
|
BYTE b;
|
|
while(Read(&b, sizeof(b)) == sizeof(b))
|
|
{
|
|
fEOF = false;
|
|
char c = '?';
|
|
if(!(b&0x80)) // 0xxxxxxx
|
|
{
|
|
c = b&0x7f;
|
|
}
|
|
else if((b&0xe0) == 0xc0) // 110xxxxx 10xxxxxx
|
|
{
|
|
if(Read(&b, sizeof(b)) != sizeof(b)) break;
|
|
}
|
|
else if((b&0xf0) == 0xe0) // 1110xxxx 10xxxxxx 10xxxxxx
|
|
{
|
|
if(Read(&b, sizeof(b)) != sizeof(b)) break;
|
|
if(Read(&b, sizeof(b)) != sizeof(b)) break;
|
|
}
|
|
if(c == '\r') continue;
|
|
if(c == '\n') break;
|
|
str += c;
|
|
}
|
|
}
|
|
else if(m_encoding == LE16)
|
|
{
|
|
WORD w;
|
|
while(Read(&w, sizeof(w)) == sizeof(w))
|
|
{
|
|
fEOF = false;
|
|
char c = '?';
|
|
if(!(w&0xff00)) c = w&0xff;
|
|
if(c == '\r') continue;
|
|
if(c == '\n') break;
|
|
str += c;
|
|
}
|
|
}
|
|
else if(m_encoding == BE16)
|
|
{
|
|
WORD w;
|
|
while(Read(&w, sizeof(w)) == sizeof(w))
|
|
{
|
|
fEOF = false;
|
|
char c = '?';
|
|
if(!(w&0xff)) c = w>>8;
|
|
if(c == '\r') continue;
|
|
if(c == '\n') break;
|
|
str += c;
|
|
}
|
|
}
|
|
|
|
return(!fEOF);
|
|
}
|
|
|
|
BOOL CTextFile::ReadString(CStringW& str)
|
|
{
|
|
bool fEOF = true;
|
|
|
|
str.Empty();
|
|
|
|
if(m_encoding == ASCII)
|
|
{
|
|
CString s;
|
|
fEOF = !__super::ReadString(s);
|
|
str = TToW(s);
|
|
}
|
|
else if(m_encoding == ANSI)
|
|
{
|
|
CStringA stra;
|
|
char c;
|
|
while(Read(&c, sizeof(c)) == sizeof(c))
|
|
{
|
|
fEOF = false;
|
|
if(c == '\r') continue;
|
|
if(c == '\n') break;
|
|
stra += c;
|
|
}
|
|
str = CStringW(CString(stra)); // TODO: codepage
|
|
}
|
|
else if(m_encoding == UTF8)
|
|
{
|
|
BYTE b;
|
|
while(Read(&b, sizeof(b)) == sizeof(b))
|
|
{
|
|
fEOF = false;
|
|
WCHAR c = '?';
|
|
if(!(b&0x80)) // 0xxxxxxx
|
|
{
|
|
c = b&0x7f;
|
|
}
|
|
else if((b&0xe0) == 0xc0) // 110xxxxx 10xxxxxx
|
|
{
|
|
c = (b&0x1f)<<6;
|
|
if(Read(&b, sizeof(b)) != sizeof(b)) break;
|
|
c |= (b&0x3f);
|
|
}
|
|
else if((b&0xf0) == 0xe0) // 1110xxxx 10xxxxxx 10xxxxxx
|
|
{
|
|
c = (b&0x0f)<<12;
|
|
if(Read(&b, sizeof(b)) != sizeof(b)) break;
|
|
c |= (b&0x3f)<<6;
|
|
if(Read(&b, sizeof(b)) != sizeof(b)) break;
|
|
c |= (b&0x3f);
|
|
}
|
|
if(c == '\r') continue;
|
|
if(c == '\n') break;
|
|
str += c;
|
|
}
|
|
}
|
|
else if(m_encoding == LE16)
|
|
{
|
|
WCHAR wc;
|
|
while(Read(&wc, sizeof(wc)) == sizeof(wc))
|
|
{
|
|
fEOF = false;
|
|
if(wc == '\r') continue;
|
|
if(wc == '\n') break;
|
|
str += wc;
|
|
}
|
|
}
|
|
else if(m_encoding == BE16)
|
|
{
|
|
WCHAR wc;
|
|
while(Read(&wc, sizeof(wc)) == sizeof(wc))
|
|
{
|
|
fEOF = false;
|
|
wc = ((wc>>8)&0x00ff)|((wc<<8)&0xff00);
|
|
if(wc == '\r') continue;
|
|
if(wc == '\n') break;
|
|
str += wc;
|
|
}
|
|
}
|
|
|
|
return(!fEOF);
|
|
}
|
|
|
|
//
|
|
// CWebTextFile
|
|
//
|
|
|
|
CWebTextFile::CWebTextFile(LONGLONG llMaxSize)
|
|
: m_llMaxSize(llMaxSize)
|
|
{
|
|
}
|
|
|
|
bool CWebTextFile::Open(LPCTSTR lpszFileName)
|
|
{
|
|
CString fn(lpszFileName);
|
|
|
|
if(fn.Find(_T("http://")) != 0)
|
|
return __super::Open(lpszFileName);
|
|
|
|
try
|
|
{
|
|
CInternetSession is;
|
|
|
|
CAutoPtr<CStdioFile> f(is.OpenURL(fn, 1, INTERNET_FLAG_TRANSFER_BINARY|INTERNET_FLAG_EXISTING_CONNECT));
|
|
if(!f) return(false);
|
|
|
|
TCHAR path[MAX_PATH];
|
|
GetTempPath(MAX_PATH, path);
|
|
|
|
fn = path + fn.Mid(fn.ReverseFind('/')+1);
|
|
int i = fn.Find(_T("?"));
|
|
if(i > 0) fn = fn.Left(i);
|
|
CFile temp;
|
|
if(!temp.Open(fn, modeCreate|modeWrite|typeBinary|shareDenyWrite))
|
|
{
|
|
f->Close();
|
|
return(false);
|
|
}
|
|
|
|
BYTE buff[1024];
|
|
int len, total = 0;
|
|
while((len = f->Read(buff, 1024)) == 1024 && (m_llMaxSize < 0 || (total+=1024) < m_llMaxSize))
|
|
temp.Write(buff, len);
|
|
if(len > 0) temp.Write(buff, len);
|
|
|
|
m_tempfn = fn;
|
|
|
|
f->Close(); // must close it because the desctructor doesn't seem to do it and we will get an exception when "is" is destroying
|
|
}
|
|
catch(CInternetException* ie)
|
|
{
|
|
ie->Delete();
|
|
return(false);
|
|
}
|
|
|
|
return __super::Open(m_tempfn);
|
|
}
|
|
|
|
bool CWebTextFile::Save(LPCTSTR lpszFileName, enc e)
|
|
{
|
|
// CWebTextFile is read-only...
|
|
ASSERT(0);
|
|
return(false);
|
|
}
|
|
|
|
void CWebTextFile::Close()
|
|
{
|
|
__super::Close();
|
|
|
|
if(!m_tempfn.IsEmpty())
|
|
{
|
|
_tremove(m_tempfn);
|
|
m_tempfn.Empty();
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
CStringW AToW(CStringA str)
|
|
{
|
|
CStringW ret;
|
|
for(int i = 0, j = str.GetLength(); i < j; i++)
|
|
ret += (WCHAR)(BYTE)str[i];
|
|
return(ret);
|
|
}
|
|
|
|
CStringA WToA(CStringW str)
|
|
{
|
|
CStringA ret;
|
|
for(int i = 0, j = str.GetLength(); i < j; i++)
|
|
ret += (CHAR)(WORD)str[i];
|
|
return(ret);
|
|
}
|
|
|
|
CString AToT(CStringA str)
|
|
{
|
|
CString ret;
|
|
for(int i = 0, j = str.GetLength(); i < j; i++)
|
|
ret += (TCHAR)(BYTE)str[i];
|
|
return(ret);
|
|
}
|
|
|
|
CString WToT(CStringW str)
|
|
{
|
|
CString ret;
|
|
for(int i = 0, j = str.GetLength(); i < j; i++)
|
|
ret += (TCHAR)(WORD)str[i];
|
|
return(ret);
|
|
}
|
|
|
|
CStringA TToA(CString str)
|
|
{
|
|
CStringA ret;
|
|
#ifdef UNICODE
|
|
for(int i = 0, j = str.GetLength(); i < j; i++)
|
|
ret += (CHAR)(BYTE)str[i];
|
|
#else
|
|
ret = str;
|
|
#endif
|
|
return(ret);
|
|
}
|
|
|
|
CStringW TToW(CString str)
|
|
{
|
|
CStringW ret;
|
|
#ifdef UNICODE
|
|
ret = str;
|
|
#else
|
|
for(int i = 0, j = str.GetLength(); i < j; i++)
|
|
ret += (WCHAR)(BYTE)str[i];
|
|
#endif
|
|
return(ret);
|
|
}
|