chm.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 909 行 · 第 1/2 页
CPP
909 行
wxChmInputStream::~wxChmInputStream()
{
delete m_chm;
delete m_contentStream;
if (m_content)
{
free (m_content);
m_content=NULL;
}
}
bool wxChmInputStream::Eof() const
{
return (m_content==NULL ||
m_contentStream==NULL ||
m_contentStream->Eof() ||
m_pos>m_size);
}
size_t wxChmInputStream::OnSysRead(void *buffer, size_t bufsize)
{
if ( m_pos >= m_size )
{
m_lasterror = wxSTREAM_EOF;
return 0;
}
m_lasterror = wxSTREAM_NO_ERROR;
// If the rest to read from the stream is less
// than the buffer size, than only read the rest
if ( m_pos + bufsize > m_size )
bufsize = m_size - m_pos;
m_contentStream->SeekI(m_pos);
m_contentStream->Read(buffer, bufsize);
m_pos +=bufsize;
m_contentStream->SeekI(m_pos);
return bufsize;
}
wxFileOffset wxChmInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode)
{
wxString mode_str = wxEmptyString;
if ( !m_contentStream || m_contentStream->Eof() )
{
m_lasterror = wxSTREAM_EOF;
return 0;
}
m_lasterror = wxSTREAM_NO_ERROR;
wxFileOffset nextpos;
switch ( mode )
{
case wxFromCurrent:
nextpos = seek + m_pos;
break;
case wxFromStart:
nextpos = seek;
break;
case wxFromEnd:
nextpos = m_size - 1 + seek;
break;
default:
nextpos = m_pos;
break; /* just to fool compiler, never happens */
}
m_pos=nextpos;
// Set current position on stream
m_contentStream->SeekI(m_pos);
return m_pos;
}
/**
* Help Browser tries to read the contents of the
* file by interpreting a .hhp file in the Archiv.
* For .chm doesnt include such a file, we need
* to rebuild the information based on stored
* system-files.
*/
void
wxChmInputStream::CreateHHPStream()
{
wxFileName file;
bool topic = false;
bool hhc = false;
bool hhk = false;
wxInputStream *i;
wxMemoryOutputStream *out;
const char *tmp;
// Try to open the #SYSTEM-File and create the HHP File out of it
// see http://bonedaddy.net/pabs3/chmspec/0.1.2/Internal.html#SYSTEM
if ( ! m_chm->Contains(_T("/#SYSTEM")) )
{
#ifdef DEBUG
wxLogDebug(_("Archive doesnt contain #SYSTEM file"));
#endif
return;
}
else
{
file = wxFileName(_T("/#SYSTEM"));
}
if ( CreateFileStream(_T("/#SYSTEM")) )
{
// New stream for writing a memory area to simulate the
// .hhp-file
out = new wxMemoryOutputStream();
tmp = "[OPTIONS]\r\n";
out->Write((const void *) tmp, strlen(tmp));
wxUint16 code;
wxUint16 len;
void *buf;
// use the actual stream for reading
i = m_contentStream;
/* Now read the contents, and try to get the needed information */
// First 4 Bytes are Version information, skip
i->SeekI(4);
while (!i->Eof())
{
// Read #SYSTEM-Code and length
i->Read(&code, 2);
code = wxUINT16_SWAP_ON_BE( code ) ;
i->Read(&len, 2);
len = wxUINT16_SWAP_ON_BE( len ) ;
// data
buf = malloc(len);
i->Read(buf, len);
switch (code)
{
case 0: // CONTENTS_FILE
tmp = "Contents file=";
hhc=true;
break;
case 1: // INDEX_FILE
tmp = "Index file=";
hhk = true;
break;
case 2: // DEFAULT_TOPIC
tmp = "Default Topic=";
topic = true;
break;
case 3: // TITLE
tmp = "Title=";
break;
// case 6: // COMPILED_FILE
// tmp = "Compiled File=";
// break;
case 7: // COMPILED_FILE
tmp = "Binary Index=YES\r\n";
out->Write( (const void *) tmp, strlen(tmp));
tmp = NULL;
break;
case 4: // STRUCT SYSTEM INFO
tmp = NULL ;
if ( len >= 28 )
{
char *structptr = (char*) buf ;
// LCID at position 0
wxUint32 dummy = *((wxUint32 *)(structptr+0)) ;
wxUint32 lcid = wxUINT32_SWAP_ON_BE( dummy ) ;
wxString msg ;
msg.Printf(_T("Language=0x%X\r\n"),lcid) ;
out->Write(msg.c_str() , msg.Length() ) ;
}
break ;
default:
tmp=NULL;
}
if (tmp)
{
out->Write((const void *) tmp, strlen(tmp));
out->Write(buf, strlen((char*)buf));
out->Write("\r\n", 2);
}
free(buf);
buf=NULL;
}
// Free the old data which wont be used any more
delete m_contentStream;
if (m_content)
free (m_content);
// Now add entries which are missing
if ( !hhc && m_chm->Contains(_T("*.hhc")) )
{
tmp = "Contents File=*.hhc\r\n";
out->Write((const void *) tmp, strlen(tmp));
}
if ( !hhk && m_chm->Contains(_T("*.hhk")) )
{
tmp = "Index File=*.hhk\r\n";
out->Write((const void *) tmp, strlen(tmp));
}
// Now copy the Data from the memory
out->SeekO(0, wxFromEnd);
m_size = out->TellO();
out->SeekO(0, wxFromStart);
m_content = (char *) malloc (m_size+1);
out->CopyTo(m_content, m_size);
m_content[m_size]='\0';
m_size++;
m_contentStream = new wxMemoryInputStream(m_content, m_size);
delete out;
}
}
/**
* Creates a Stream pointing to a virtual file in
* the current archive
*/
bool wxChmInputStream::CreateFileStream(const wxString& pattern)
{
wxFileInputStream * fin;
wxString tmpfile = wxFileName::CreateTempFileName(_T("chmstrm"), NULL);
if ( tmpfile.empty() )
{
wxLogError(_("Could not create temporary file '%s'"), tmpfile.c_str());
return false;
}
// try to extract the file
if ( m_chm->Extract(pattern, tmpfile) <= 0 )
{
wxLogError(_("Extraction of '%s' into '%s' failed."),
pattern.c_str(), tmpfile.c_str());
if ( wxFileExists(tmpfile) )
wxRemoveFile(tmpfile);
return false;
}
else
{
// Open a filestream to extracted file
fin = new wxFileInputStream(tmpfile);
m_size = fin->GetSize();
m_content = (char *) malloc(m_size+1);
fin->Read(m_content, m_size);
m_content[m_size]='\0';
wxRemoveFile(tmpfile);
delete fin;
m_contentStream = new wxMemoryInputStream (m_content, m_size);
return m_contentStream->IsOk();
}
}
// ----------------------------------------------------------------------------
// wxChmFSHandler
// ----------------------------------------------------------------------------
class wxChmFSHandler : public wxFileSystemHandler
{
public:
/// Constructor and Destructor
wxChmFSHandler();
~wxChmFSHandler();
/// Is able to open location?
virtual bool CanOpen(const wxString& location);
/// Open a file
virtual wxFSFile* OpenFile(wxFileSystem& fs, const wxString& location);
/// Find first occurrence of spec
virtual wxString FindFirst(const wxString& spec, int flags = 0);
/// Find next occurrence of spec
virtual wxString FindNext();
private:
int m_lasterror;
wxString m_pattern;
wxString m_found;
wxChmTools * m_chm;
};
wxChmFSHandler::wxChmFSHandler() : wxFileSystemHandler()
{
m_lasterror=0;
m_pattern=wxEmptyString;
m_found=wxEmptyString;
m_chm=NULL;
}
wxChmFSHandler::~wxChmFSHandler()
{
if (m_chm)
delete m_chm;
}
bool wxChmFSHandler::CanOpen(const wxString& location)
{
wxString p = GetProtocol(location);
return (p == _T("chm")) &&
(GetProtocol(GetLeftLocation(location)) == _T("file"));
}
wxFSFile* wxChmFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs),
const wxString& location)
{
wxString right = GetRightLocation(location);
wxString left = GetLeftLocation(location);
wxInputStream *s;
int index;
if ( GetProtocol(left) != _T("file") )
{
wxLogError(_("CHM handler currently supports only local files!"));
return NULL;
}
// Work around javascript
wxString tmp = wxString(right);
if ( tmp.MakeLower().Contains(_T("javascipt")) && tmp.Contains(_T("\'")) )
{
right = right.AfterFirst(_T('\'')).BeforeLast(_T('\''));
}
// now work on the right location
if (right.Contains(_T("..")))
{
wxFileName abs(right);
abs.MakeAbsolute(_T("/"));
right = abs.GetFullPath();
}
// a workaround for absolute links to root
if ( (index=right.Index(_T("//"))) != wxNOT_FOUND )
{
right=wxString(right.Mid(index+1));
wxLogWarning(_("Link contained '//', converted to absolute link."));
}
wxFileName leftFilename = wxFileSystem::URLToFileName(left);
// Open a stream to read the content of the chm-file
s = new wxChmInputStream(leftFilename.GetFullPath(), right, true);
wxString mime = GetMimeTypeFromExt(location);
if ( s )
{
return new wxFSFile(s,
left + _T("#chm:") + right,
mime,
GetAnchor(location),
wxDateTime(wxFileModificationTime(left)));
}
delete s;
return NULL;
}
/**
* Doku see wxFileSystemHandler
*/
wxString wxChmFSHandler::FindFirst(const wxString& spec, int flags)
{
wxString right = GetRightLocation(spec);
wxString left = GetLeftLocation(spec);
wxString nativename = wxFileSystem::URLToFileName(left).GetFullPath();
if ( GetProtocol(left) != _T("file") )
{
wxLogError(_("CHM handler currently supports only local files!"));
return wxEmptyString;
}
m_chm = new wxChmTools(wxFileName(nativename));
m_pattern = right.AfterLast(_T('/'));
wxString m_found = m_chm->Find(m_pattern);
// now fake around hhp-files which are not existing in projects...
if (m_found.empty() &&
m_pattern.Contains(_T(".hhp")) &&
!m_pattern.Contains(_T(".hhp.cached")))
{
m_found.Printf(_T("%s#chm:%s.hhp"),
left.c_str(), m_pattern.BeforeLast(_T('.')).c_str());
}
return m_found;
}
wxString wxChmFSHandler::FindNext()
{
if (m_pattern.empty())
return wxEmptyString;
else
return m_chm->Find(m_pattern, m_found);
}
// ---------------------------------------------------------------------------
// wxModule to register CHM handler
// ---------------------------------------------------------------------------
class wxChmSupportModule : public wxModule
{
DECLARE_DYNAMIC_CLASS(wxChmSupportModule)
public:
virtual bool OnInit()
{
wxFileSystem::AddHandler(new wxChmFSHandler);
return true;
}
virtual void OnExit() {}
}
;
IMPLEMENT_DYNAMIC_CLASS(wxChmSupportModule, wxModule)
#endif // wxUSE_LIBMSPACK
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?