Compare commits

..

1 Commits

Author SHA1 Message Date
Art Yerkes
3a3d839af3 Simple jmpbuf for powerpc.
svn path=/branches/powerpc/; revision=14757
2005-04-23 04:31:11 +00:00
27594 changed files with 2418606 additions and 7491054 deletions

View File

@@ -0,0 +1,510 @@
// irc_test.cpp
#ifdef _MSC_VER
#pragma warning ( disable : 4786 )
#endif//_MSC_VER
#include <time.h>
#include <stdio.h>
#include "File.h"
#include "ssprintf.h"
#include "trim.h"
#include "IRCClient.h"
using std::string;
using std::vector;
#if defined(_DEBUG) && 0
const char* BOTNAME = "RoyBot";
const char* CHANNEL = "#RoyBotTest";
#else
const char* BOTNAME = "ArchBlackmann";
const char* CHANNEL = "#ReactOS";
#endif
//vector<string> tech, module, dev, stru, period, status, type, func, irql, curse, cursecop;
class List
{
public:
string name;
bool macro;
std::vector<std::string> list;
string tag;
int last;
List() { last = -1; }
List ( const char* _name, bool _macro ) : name(_name), macro(_macro)
{
tag = ssprintf("%%%s%%",_name);
last = -1;
}
};
vector<List> lists;
vector<string> ops;
void ImportList ( const char* listname, bool macro )
{
lists.push_back ( List ( listname, macro ) );
List& list = lists.back();
File f ( ssprintf("%s.txt",listname).c_str(), "r" );
string line;
while ( f.next_line ( line, true ) )
list.list.push_back ( line );
}
const char* ListRand ( List& list )
{
vector<string>& l = list.list;
if ( !l.size() )
{
static string nothing;
nothing = ssprintf ( "<list '%s' empty>", list.name.c_str() );
return nothing.c_str();
}
else if ( l.size() == 1 )
return l[0].c_str();
int sel = list.last;
while ( sel == list.last )
sel = rand()%l.size();
list.last = sel;
return l[sel].c_str();
}
const char* ListRand ( int i )
{
return ListRand ( lists[i] );
}
int GetListIndex ( const char* listname )
{
for ( int i = 0; i < lists.size(); i++ )
{
if ( !stricmp ( lists[i].name.c_str(), listname ) )
return i;
}
return -1;
}
List& GetList ( const char* listname )
{
return lists[GetListIndex(listname)];
}
const char* ListRand ( const char* list )
{
int i = GetListIndex ( list );
if ( i < 0 )
return NULL;
return ListRand(i);
}
string TaggedReply ( const char* listname )
{
string t = ListRand(listname);
string out;
const char* p = t.c_str();
while ( *p )
{
if ( *p == '%' )
{
bool found = false;
for ( int i = 0; i < lists.size() && !found; i++ )
{
if ( lists[i].macro && !strnicmp ( p, lists[i].tag.c_str(), lists[i].tag.size() ) )
{
out += ListRand(i);
p += lists[i].tag.size();
found = true;
}
}
if ( !found )
out += *p++;
}
const char* p2 = strchr ( p, '%' );
if ( !p2 )
p2 = p + strlen(p);
if ( p2 > p )
{
out += string ( p, p2-p );
p = p2;
}
}
return out;
}
string gobble ( string& s, const char* delim )
{
const char* p = s.c_str();
p += strspn ( p, delim );
const char* p2 = strpbrk ( p, delim );
if ( !p2 ) p2 = p + strlen(p);
string out ( p, p2-p );
p2 += strspn ( p2, delim );
s = string ( p2 );
return out;
}
bool isop ( const string& who )
{
for ( int i = 0; i < ops.size(); i++ )
{
if ( ops[i] == who )
return true;
}
return false;
}
// do custom stuff with the IRCClient from your subclass via the provided callbacks...
class MyIRCClient : public IRCClient
{
File flog;
public:
MyIRCClient()
{
flog.open ( "arch.log", "w+" );
}
// see IRCClient.h for documentation on these callbacks...
bool OnConnected()
{
return true;
}
bool OnJoin ( const string& user, const string& channel )
{
printf ( "user '%s' joined channel '%s'\n", user.c_str(), channel.c_str() );
return true;
}
bool OnPart ( const std::string& user, const std::string& channel )
{
for ( int i = 0; i < ops.size(); i++ )
{
if ( ops[i] == user )
{
printf ( "remove '%s' to ops list\n", user.c_str() );
ops.erase ( &ops[i] );
}
}
return true;
}
bool OnNick ( const std::string& oldNick, const std::string& newNick )
{
for ( int i = 0; i < ops.size(); i++ )
{
if ( ops[i] == oldNick )
{
printf ( "op '%s' changed nick to '%s'\n", oldNick.c_str(), newNick.c_str() );
ops[i] = newNick;
return true;
}
}
return true;
}
bool OnEndChannelUsers ( const string& channel )
{
return true;
}
bool OnPrivMsg ( const string& from, const string& text )
{
printf ( "<%s> %s\n", from.c_str(), text.c_str() );
flog.printf ( "<%s> %s\n", from.c_str(), text.c_str() );
if ( strnicmp ( text.c_str(), "!say ", 5 ) || !isop(from) )
return PrivMsg ( from, "hey, your tongue doesn't belong there!" );
string say = trim(&text[5]);
if ( !strnicmp ( say.c_str(), "/me ", 4 ) )
return Action ( CHANNEL, trim(&say[4]) );
else
return PrivMsg ( CHANNEL, trim(say) );
}
bool OnChannelMsg ( const string& channel, const string& from, const string& text )
{
printf ( "%s <%s> %s\n", channel.c_str(), from.c_str(), text.c_str() );
flog.printf ( "%s <%s> %s\n", channel.c_str(), from.c_str(), text.c_str() );
bool found_name = false;
string text2 ( text );
strlwr ( &text2[0] );
if ( !strnicmp ( text.c_str(), BOTNAME, strlen(BOTNAME) ) )
found_name = true;
else if ( !strnicmp ( text.c_str(), "arch ", 5 ) )
found_name = true;
if ( found_name )
{
string s ( text );
gobble ( s, " \t" ); // remove bot name
found_name = true;
if ( s[0] == '!' )
{
bool from_op = isop(from);
string cmd = gobble ( s, " \t" );
if ( !from_op )
{
if ( cmd == "!grovel" )
{
string out = ssprintf(TaggedReply("nogrovel").c_str(),from.c_str());
if ( !strnicmp ( out.c_str(), "/me ", 4 ) )
return Action ( channel, &out[4] );
else
return PrivMsg ( channel, out );
}
return PrivMsg ( channel, ssprintf("%s: I don't take commands from non-ops",from.c_str()) );
}
if ( cmd == "!add" )
{
string listname = gobble ( s, " \t" );
int i = GetListIndex ( listname.c_str() );
if ( i == -1 )
return PrivMsg ( channel, ssprintf("%s: I don't have a list named '%s'",from.c_str(),listname.c_str()) );
List& list = lists[i];
if ( s[0] == '\"' || s[0] == '\'' )
{
char delim = s[0];
const char* p = &s[1];
const char* p2 = strchr ( p, delim );
if ( !p2 )
return PrivMsg ( channel, ssprintf("%s: Couldn't add, unmatched quotes",from.c_str()) );
s = string ( p, p2-p );
}
for ( i = 0; i < list.list.size(); i++ )
{
if ( list.list[i] == s )
return PrivMsg ( channel, ssprintf("%s: entry already exists in list '%s'",from.c_str(),listname.c_str()) );
}
if ( !stricmp ( listname.c_str(), "curse" ) )
strlwr ( &s[0] );
list.list.push_back ( s );
{
File f ( ssprintf("%s.txt",list.name.c_str()), "w" );
for ( i = 0; i < list.list.size(); i++ )
f.printf ( "%s\n", list.list[i].c_str() );
}
return PrivMsg ( channel, ssprintf("%s: entry added to list '%s'",from.c_str(),listname.c_str()) );
}
else if ( cmd == "!remove" )
{
string listname = gobble ( s, " \t" );
int i = GetListIndex ( listname.c_str() );
if ( i == -1 )
return PrivMsg ( channel, ssprintf("%s: I don't have a list named '%s'",from.c_str(),listname.c_str()) );
List& list = lists[i];
if ( s[0] == '\"' || s[0] == '\'' )
{
char delim = s[0];
const char* p = &s[1];
const char* p2 = strchr ( p, delim );
if ( !p2 )
return PrivMsg ( channel, ssprintf("%s: Couldn't add, unmatched quotes",from.c_str()) );
s = string ( p, p2-p );
}
for ( i = 0; i < list.list.size(); i++ )
{
if ( list.list[i] == s )
{
list.list.erase ( &list.list[i] );
{
File f ( ssprintf("%s.txt",list.name.c_str()), "w" );
for ( i = 0; i < list.list.size(); i++ )
f.printf ( "%s\n", list.list[i].c_str() );
}
return PrivMsg ( channel, ssprintf("%s: entry removed from list '%s'",from.c_str(),listname.c_str()) );
}
}
return PrivMsg ( channel, ssprintf("%s: entry doesn't exist in list '%s'",from.c_str(),listname.c_str()) );
}
else if ( cmd == "!grovel" )
{
string out = ssprintf(TaggedReply("grovel").c_str(),from.c_str());
if ( !strnicmp ( out.c_str(), "/me ", 4 ) )
return Action ( channel, &out[4] );
else
return PrivMsg ( channel, out );
}
else if ( cmd == "!kiss" )
{
if ( s.size() )
return Action ( channel, ssprintf("kisses %s",s.c_str()) );
else
return PrivMsg ( channel, ssprintf("%s: huh?",from.c_str()) );
}
else if ( cmd == "!hug" )
{
if ( s.size() )
return Action ( channel, ssprintf("hugs %s",s.c_str()) );
else
return PrivMsg ( channel, ssprintf("%s: huh?",from.c_str()) );
}
else if ( cmd == "!give" )
{
string who = gobble(s," \t");
if ( who.size() && s.size() )
return Action ( channel, ssprintf("gives %s a %s",who.c_str(),s.c_str()) );
else
return PrivMsg ( channel, ssprintf("%s: huh?",from.c_str()) );
}
else
{
return PrivMsg ( channel, ssprintf("%s: huh?",from.c_str()) );
}
}
}
bool found_curse = false;
static vector<string>& curse = GetList("curse").list;
text2 = ssprintf(" %s ",text2.c_str());
for ( int i = 0; i < curse.size() && !found_curse; i++ )
{
if ( strstr ( text2.c_str(), curse[i].c_str() ) )
found_curse = true;
}
if ( found_curse )
{
static List& cursecop = GetList("cursecop");
return PrivMsg ( channel, ssprintf("%s: %s", from.c_str(), ListRand(cursecop)) );
}
else if ( found_name )
{
string out = ssprintf("%s: %s", from.c_str(), TaggedReply("tech").c_str());
flog.printf ( "TECH-REPLY: %s\n", out.c_str() );
if ( !strnicmp ( out.c_str(), "/me ", 4 ) )
return Action ( channel, &out[4] );
else
return PrivMsg ( channel, out );
}
return true;
}
bool OnChannelMode ( const string& channel, const string& mode )
{
//printf ( "OnChannelMode(%s,%s)\n", channel.c_str(), mode.c_str() );
return true;
}
bool OnUserModeInChannel ( const string& src, const string& channel, const string& mode, const string& target )
{
printf ( "OnUserModeInChannel(%s,%s,%s,%s)\n", src.c_str(), channel.c_str(), mode.c_str(), target.c_str() );
const char* p = mode.c_str();
if ( !p )
return true;
while ( *p )
{
switch ( *p++ )
{
case '+':
while ( *p != 0 && *p != ' ' )
{
if ( *p == 'o' )
{
printf ( "adding '%s' to ops list\n", target.c_str() );
ops.push_back ( target );
}
break;
}
break;
case '-':
while ( *p != 0 && *p != ' ' )
{
if ( *p == 'o' )
{
for ( int i = 0; i < ops.size(); i++ )
{
if ( ops[i] == target )
{
printf ( "remove '%s' to ops list\n", target.c_str() );
ops.erase ( &ops[i] );
}
}
break;
}
}
}
}
return true;
}
bool OnMode ( const string& user, const string& mode )
{
//printf ( "OnMode(%s,%s)\n", user.c_str(), mode.c_str() );
return true;
}
bool OnChannelUsers ( const string& channel, const vector<string>& users )
{
//printf ( "[%s has %i users]: ", channel.c_str(), users.size() );
for ( int i = 0; i < users.size(); i++ )
{
if ( users[i][0] == '@' )
ops.push_back ( &users[i][1] );
/*if ( i )
printf ( ", " );
printf ( "%s", users[i].c_str() );*/
}
//printf ( "\n" );
return true;
}
};
int main ( int argc, char** argv )
{
srand ( time(NULL) );
ImportList ( "dev", true );
ImportList ( "func", true );
ImportList ( "dev", true );
ImportList ( "func", true );
ImportList ( "irql", true );
ImportList ( "module", true );
ImportList ( "period", true );
ImportList ( "status", true );
ImportList ( "stru", true );
ImportList ( "type", true );
ImportList ( "tech", false );
ImportList ( "curse", false );
ImportList ( "cursecop", false );
ImportList ( "grovel", false );
ImportList ( "nogrovel", false );
#ifdef _DEBUG
printf ( "initializing IRCClient debugging\n" );
IRCClient::SetDebug ( true );
#endif//_DEBUG
printf ( "calling suStartup()\n" );
suStartup();
printf ( "creating IRCClient object\n" );
MyIRCClient irc;
printf ( "connecting to freenode\n" );
//const char* server = "212.204.214.114";
const char* server = "irc.freenode.net";
if ( !irc.Connect ( server ) ) // irc.freenode.net
{
printf ( "couldn't connect to server\n" );
return -1;
}
printf ( "sending user command\n" );
if ( !irc.User ( BOTNAME, "", "irc.freenode.net", BOTNAME ) )
{
printf ( "USER command failed\n" );
return -1;
}
printf ( "sending nick\n" );
if ( !irc.Nick ( BOTNAME ) )
{
printf ( "NICK command failed\n" );
return -1;
}
printf ( "setting mode\n" );
if ( !irc.Mode ( "+i" ) )
{
printf ( "MODE command failed\n" );
return -1;
}
printf ( "joining channel\n" );
if ( !irc.Join ( CHANNEL ) )
{
printf ( "JOIN command failed\n" );
return -1;
}
printf ( "entering irc client processor\n" );
irc.Run ( false ); // do the processing in this thread...
return 0;
}

View File

@@ -0,0 +1,212 @@
# Microsoft Developer Studio Project File - Name="ArchBlackmann" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=ArchBlackmann - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "ArchBlackmann.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "ArchBlackmann.mak" CFG="ArchBlackmann - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "ArchBlackmann - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "ArchBlackmann - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "ArchBlackmann - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "ArchBlackmann - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "ArchBlackmann - Win32 Release"
# Name "ArchBlackmann - Win32 Debug"
# Begin Source File
SOURCE=.\ArchBlackmann.cpp
# End Source File
# Begin Source File
SOURCE=.\auto_ptr.h
# End Source File
# Begin Source File
SOURCE=.\auto_vector.h
# End Source File
# Begin Source File
SOURCE=.\base64.cpp
# End Source File
# Begin Source File
SOURCE=.\base64.h
# End Source File
# Begin Source File
SOURCE=.\chomp.cpp
# End Source File
# Begin Source File
SOURCE=.\chomp.h
# End Source File
# Begin Source File
SOURCE=.\cram_md5.cpp
# End Source File
# Begin Source File
SOURCE=.\cram_md5.h
# End Source File
# Begin Source File
SOURCE=.\File.cpp
# End Source File
# Begin Source File
SOURCE=.\File.h
# End Source File
# Begin Source File
SOURCE=.\IRCClient.cpp
# End Source File
# Begin Source File
SOURCE=.\IRCClient.h
# End Source File
# Begin Source File
SOURCE=.\MD5.cpp
# End Source File
# Begin Source File
SOURCE=.\MD5.h
# End Source File
# Begin Source File
SOURCE=.\panic.cpp
# End Source File
# Begin Source File
SOURCE=.\panic.h
# End Source File
# Begin Source File
SOURCE=.\QueueT.h
# End Source File
# Begin Source File
SOURCE=.\Reli.h
# End Source File
# Begin Source File
SOURCE=.\ReliMT.cpp
# End Source File
# Begin Source File
SOURCE=.\ReliMT.h
# End Source File
# Begin Source File
SOURCE=.\SockUtils.cpp
# End Source File
# Begin Source File
SOURCE=.\SockUtils.h
# End Source File
# Begin Source File
SOURCE=.\SplitJoin.cpp
# End Source File
# Begin Source File
SOURCE=.\SplitJoin.h
# End Source File
# Begin Source File
SOURCE=.\ssprintf.cpp
# End Source File
# Begin Source File
SOURCE=.\ssprintf.h
# End Source File
# Begin Source File
SOURCE=.\ThreadPool.cpp
# End Source File
# Begin Source File
SOURCE=.\ThreadPool.h
# End Source File
# Begin Source File
SOURCE=.\trim.cpp
# End Source File
# Begin Source File
SOURCE=.\trim.h
# End Source File
# Begin Source File
SOURCE=.\verify.h
# End Source File
# End Target
# End Project

View File

@@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "ArchBlackmann"=.\ArchBlackmann.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

265
irc/ArchBlackmann/File.cpp Normal file
View File

@@ -0,0 +1,265 @@
// File.cpp
// (C) 2002-2004 Royce Mitchell III
// Dually licensed under BSD & LGPL
#ifdef _MSC_VER
#pragma warning ( disable : 4786 )
#endif//_MSC_VER
#include <stdio.h>
#include <stdarg.h>
#include "File.h"
#ifndef nelem
#define nelem(x) ( sizeof(x) / sizeof(x[0]) )
#endif//nelem
using File::filesize_t;
using File::fileoff_t;
fileoff_t File::seek ( fileoff_t offset )
{
#ifdef WIN32
if ( _f->_flag & _IOWRT ) // is there pending output?
fflush ( _f );
// reset "buffered input" variables
_f->_cnt = 0;
_f->_ptr = _f->_base;
// make sure we're going forward
if ( _f->_flag & _IORW )
_f->_flag &= ~(_IOREAD|_IOWRT);
return _lseeki64 ( _fileno(_f), offset, SEEK_SET );
#else//UNIX
return lseek64 ( fileno(_f), offset, SEEK_SET );
#endif
}
std::string File::getline ( bool strip_crlf /*= false*/ )
{
std::string s = "";
char buf[256];
for ( ;; )
{
*buf = 0;
fgets ( buf, nelem(buf)-1, _f );
if ( !*buf )
break;
s += buf;
if ( strchr ( "\r\n", buf[strlen(buf)-1] ) )
break;
}
if ( strip_crlf && s.size() )
{
char* p = strpbrk ( &s[0], "\r\n" );
if ( p )
{
*p = '\0';
s.resize ( p-&s[0] );
}
}
return s;
}
std::wstring File::wgetline ( bool strip_crlf /*= false*/ )
{
std::wstring s = L"";
wchar_t buf[256];
for ( ;; )
{
*buf = 0;
fgetws ( buf, nelem(buf)-1, _f );
if ( !*buf )
break;
s += buf;
if ( wcschr ( L"\r\n", buf[wcslen(buf)-1] ) )
break;
}
if ( strip_crlf && s.size() )
{
wchar_t* p = wcspbrk ( &s[0], L"\r\n" );
if ( p )
{
*p = L'\0';
s.resize ( (p-&s[0])/sizeof(wchar_t) );
}
}
return s;
}
// this function searches for the next end-of-line and puts all data it
// finds until then in the 'line' parameter.
//
// call continuously until the function returns false ( no more data )
bool File::next_line ( std::string& line, bool strip_crlf )
{
line = getline(strip_crlf);
// indicate that we're done *if*:
// 1) there's no more data, *and*
// 2) we're at the end of the file
return line.size()>0 || !eof();
}
bool File::next_line ( std::wstring& line, bool strip_crlf )
{
line = wgetline ( strip_crlf );
return line.size()>0 || !eof();
}
/*
example usage:
bool mycallback ( const std::string& line, int line_number, long lparam )
{
std::cout << line << std::endl;
return true; // continue enumeration
}
File f ( "file.txt", "rb" ); // open file for binary read-only ( i.e. "rb" )
f.enum_lines ( mycallback, 0, true );
*/
/*bool File::enum_lines ( bool (*callback)(const std::string& line, int line_number, long lparam), long lparam, bool strip_crlf )
{
int line_number = 0;
for ( ;; )
{
std::string s = getline(strip_crlf);
line_number++;
if ( !s.size() )
{
if ( eof() )
return true;
else
continue;
}
if ( !(*callback) ( s, line_number, lparam ) )
return false;
}
}*/
filesize_t File::length() const
{
#ifdef WIN32
return _filelengthi64 ( _fileno(_f) );
#elif defined(UNIX)
struct stat64 file_stat;
verify(fstat64(fileno(_f), &file_stat) == 0);
return file_stat.st_size;
#endif
}
void File::close()
{
if ( _f )
{
fclose(_f);
_f = 0;
}
}
void File::printf ( const char* fmt, ... )
{
va_list arg;
int done;
va_start(arg, fmt);
assert(_f);
done = vfprintf ( _f, fmt, arg );
va_end(arg);
}
/*static*/ bool File::LoadIntoString ( std::string& s, const std::string& filename )
{
File in ( filename, "rb" );
if ( !in.isopened() )
return false;
filesize_t flen = in.length();
size_t len = size_t(flen);
if ( len != flen )
return false; // file too big...
s.resize ( len + 1 );
if ( !in.read ( &s[0], len ) )
return false;
s[len] = '\0';
s.resize ( len );
return true;
}
/*static*/ bool File::LoadIntoString ( std::string& s, const std::wstring& filename )
{
File in ( filename, L"rb" );
if ( !in.isopened() )
return false;
filesize_t flen = in.length();
size_t len = size_t(flen);
if ( len != flen )
return false; // file too big...
s.resize ( len + 1 );
if ( !in.read ( &s[0], len ) )
return false;
s[len] = '\0';
s.resize ( len );
return true;
}
/*static*/ bool File::SaveFromString ( const std::string& filename, const std::string& s, bool binary )
{
File out ( filename, binary ? "wb" : "w" );
if ( !out.isopened() )
return false;
out.write ( s.c_str(), s.size() );
return true;
}
/*static*/ bool File::SaveFromString ( const std::wstring& filename, const std::string& s, bool binary )
{
File out ( filename, binary ? L"wb" : L"w" );
if ( !out.isopened() )
return false;
out.write ( s.c_str(), s.size() );
return true;
}
/*static*/ bool File::SaveFromBuffer ( const std::string& filename, const char* buf, size_t buflen, bool binary )
{
File out ( filename, binary ? "wb" : "w" );
if ( !out.isopened() )
return false;
out.write ( buf, buflen );
return true;
}
/*static*/ bool File::SaveFromBuffer ( const std::wstring& filename, const char* buf, size_t buflen, bool binary )
{
File out ( filename, binary ? L"wb" : L"w" );
if ( !out.isopened() )
return false;
out.write ( buf, buflen );
return true;
}
/*static*/ std::string File::TempFileName ( const std::string& prefix )
{
#ifdef WIN32
std::string s ( _tempnam ( ".", prefix.c_str() ) );
return s;
#else
// FIXME
return string("");
#endif
}
/*static*/ std::wstring File::TempFileName ( const std::wstring& prefix )
{
#ifdef WIN32
std::wstring s ( _wtempnam ( L".", prefix.c_str() ) );
return s;
#else
// FIXME
return std::wstring(L"");
#endif
}

173
irc/ArchBlackmann/File.h Normal file
View File

@@ -0,0 +1,173 @@
// File.h
// (C) 2002-2004 Royce Mitchell III
// Dually licensed under BSD & LGPL
#ifndef FILE_H
#define FILE_H
#ifdef WIN32
# include <stdio.h> // fgetc
# include <io.h>
#elif defined(UNIX)
# include <sys/stat.h>
# include <unistd.h>
#endif
#include <assert.h>
#include <string>
class File
{
public:
#ifdef _MSC_VER
typedef __int64 fileoff_t;
typedef unsigned __int64 filesize_t;
#else//_MSC_VER
typedef __off64_t fileoff_t;
typedef __size64_t filesize_t;
#endif//_MSC_VER
File() : _f(0)
{
}
File ( const std::string& filename, const char* mode ) : _f(0)
{
open ( filename, mode );
}
File ( const std::wstring& filename, const wchar_t* mode ) : _f(0)
{
open ( filename, mode );
}
File ( const char* filename, const char* mode ) : _f(0)
{
open ( filename, mode );
}
File ( const wchar_t* filename, const wchar_t* mode ) : _f(0)
{
open ( filename, mode );
}
~File()
{
close();
}
bool open ( const std::string& filename, const char* mode )
{
assert ( !_f );
return ( _f = fopen ( filename.c_str(), mode ) ) != 0;
}
bool open ( const std::wstring& filename, const wchar_t* mode )
{
assert ( !_f );
return ( _f = _wfopen ( filename.c_str(), mode ) ) != 0;
}
bool open ( const char* filename, const char* mode )
{
assert ( !_f );
return ( _f = fopen ( filename, mode ) ) != 0;
}
bool open ( const wchar_t* filename, const wchar_t* mode )
{
assert ( !_f );
return ( _f = _wfopen ( filename, mode ) ) != 0;
}
fileoff_t seek ( fileoff_t offset );
int get()
{
return fgetc ( _f );
}
bool put ( int c )
{
return fputc ( c, _f ) != EOF;
}
std::string getline ( bool strip_crlf = false );
std::wstring wgetline ( bool strip_crlf = false );
// this function searches for the next end-of-line and puts all data it
// finds until then in the 'line' parameter.
//
// call continuously until the function returns false ( no more data )
bool next_line ( std::string& line, bool strip_crlf );
bool next_line ( std::wstring& line, bool strip_crlf );
bool read ( void* data, unsigned len )
{
return len == fread ( data, 1, len, _f );
}
bool write ( const void* data, unsigned len )
{
return len == fwrite ( data, 1, len, _f );
}
bool write ( const std::string& data )
{
return data.length() == fwrite ( data.c_str(), 1, data.length(), _f );
}
bool write ( const std::wstring& data )
{
return data.length() == fwrite ( data.c_str(), sizeof(data[0]), data.length(), _f );
}
filesize_t length() const;
void close();
bool isopened() const
{
return _f != 0;
}
bool is_open() const
{
return _f != 0;
}
bool eof() const
{
return feof(_f) ? true : false;
}
FILE* operator * ()
{
return _f;
}
operator FILE*()
{
return _f;
}
void printf ( const char* fmt, ... );
void printf ( const wchar_t* fmt, ... );
static bool LoadIntoString ( std::string& s, const std::string& filename );
static bool LoadIntoString ( std::string& s, const std::wstring& filename );
static bool SaveFromString ( const std::string& filename, const std::string& s, bool binary );
static bool SaveFromString ( const std::wstring& filename, const std::string& s, bool binary );
static bool SaveFromBuffer ( const std::string& filename, const char* buf, size_t buflen, bool binary );
static bool SaveFromBuffer ( const std::wstring& filename, const char* buf, size_t buflen, bool binary );
static std::string TempFileName ( const std::string& prefix );
static std::wstring TempFileName ( const std::wstring& prefix );
private:
File(const File&) {}
const File& operator = ( const File& ) { return *this; }
FILE * _f;
};
#endif//FILE_H

View File

@@ -0,0 +1,373 @@
// IRCClient.cpp
// This file is (C) 2004 Royce Mitchell III
// and released under the BSD & LGPL licenses
#ifdef _MSC_VER
#pragma warning ( disable : 4786 )
#endif//_MSC_VER
#include <vector>
#include <sstream>
#include "IRCClient.h"
#include "md5.h"
#include "cram_md5.h"
#include "trim.h"
#include "chomp.h"
#include "SplitJoin.h"
#include "base64.h"
using std::string;
using std::stringstream;
using std::vector;
bool IRCClient::_debug = true;
IRCClient::IRCClient()
: _timeout(10*60*1000), _inRun(false)
{
}
bool IRCClient::Connect ( const string& server, short port )
{
string buf;
Close();
Attach ( suTcpSocket() );
if ( !suConnect ( *this, server.c_str(), port ) )
return false;
return true;
}
bool
IRCClient::User ( const string& user, const string& mode,
const string& network, const string& realname )
{
string buf;
buf = "USER " + user + " \"" + mode + "\" \"" + network + "\" :" + realname + "\n";
return Send ( buf );
}
bool
IRCClient::Nick ( const string& nick )
{
_nick = nick;
return Send ( "NICK " + _nick + "\n" );
}
bool
IRCClient::Mode ( const string& mode )
{
return Send ( "MODE " + _nick + " " + mode + "\n" );
}
bool
IRCClient::Names ( const string& channel )
{
return Send ( "NAMES " + channel + "\n" );
}
bool
IRCClient::Mode ( const string& channel, const string& mode, const string& target )
{
return Send ( "MODE " + channel + " " + mode + " " + target + "\n" );
}
bool
IRCClient::Join ( const string& channel )
{
return Send ( "JOIN " + channel + "\n" );
}
bool
IRCClient::PrivMsg ( const string& to, const string& text )
{
return Send ( "PRIVMSG " + to + " :" + text + '\n' );
}
bool
IRCClient::Action ( const string& to, const string& text )
{
return Send ( "PRIVMSG " + to + " :" + (char)1 + "ACTION " + text + (char)1 + '\n' );
}
bool
IRCClient::Part ( const string& channel, const string& text )
{
return Send ( "PART " + channel + " :" + text + "\n" );
}
bool
IRCClient::Quit ( const string& text )
{
return Send( "QUIT :" + text + "\n");
}
bool IRCClient::_Recv ( string& buf )
{
bool b = (recvUntil ( buf, '\n', _timeout ) > 0);
if ( b && _debug )
{
printf ( ">> %s", buf.c_str() );
if ( buf[buf.length()-1] != '\n' )
printf ( "\n" );
}
return b;
}
bool IRCClient::Send ( const string& buf )
{
if ( _debug )
{
printf ( "<< %s", buf.c_str() );
if ( buf[buf.length()-1] != '\n' )
printf ( "\n" );
}
return ( buf.length() == (size_t)send ( *this, buf.c_str(), buf.length(), 0 ) );
}
bool IRCClient::OnPing( const string& text )
{
return Send( "PONG " + text + "\n" );
}
int THREADAPI IRCClient::Callback ( IRCClient* irc )
{
return irc->Run ( false );
}
int IRCClient::Run ( bool launch_thread )
{
if ( (SOCKET)*this == INVALID_SOCKET )
return 0;
if ( _inRun ) return 1;
if ( launch_thread )
{
ThreadPool::Instance().Launch ( (ThreadPoolFunc*)IRCClient::Callback, this );
return 1;
}
_inRun = true;
if ( _debug ) printf ( "IRCClient::Run() - waiting for responses\n" );
string buf;
while ( _Recv(buf) )
{
if ( !strnicmp ( buf.c_str(), "NOTICE ", 7 ) )
{
//printf ( "recv'd NOTICE msg...\n" );
// TODO...
//OnAuth (
}
else if ( !strnicmp ( buf.c_str(), "PING ", 5 ) )
{
const char* p = &buf[5]; // point to first char after "PING "
while ( *p == ':' ) // then read past the colons
p++;
const char* p2 = strpbrk ( p, "\r\n" ); // find the end of line
string text ( p, p2-p ); // and set the text
OnPing( text );
}
else if ( buf[0] == ':' )
{
const char* p = &buf[1]; // skip first colon...
const char* p2 = strpbrk ( p, " !" );
if ( !p2 )
{
printf ( "!!!:OnRecv failure 0: ", buf.c_str() );
continue;
}
string src ( p, p2-p );
if ( !src.length() )
{
printf ( "!!!:OnRecv failure 0.5: %s", buf.c_str() );
continue;
}
p = p2 + 1;
if ( *p2 == '!' )
{
p2 = strchr ( p, ' ' );
if ( !p2 )
{
printf ( "!!!:OnRecv failure 1: %s", buf.c_str() );
continue;
}
//string srchost ( p, p2-p );
p = p2 + 1;
}
p2 = strchr ( p, ' ' );
if ( !p2 )
{
printf ( "!!!:OnRecv failure 2: %s", buf.c_str() );
continue;
}
string cmd ( p, p2-p );
p = p2 + 1;
p2 = strpbrk ( p, " :" );
if ( !p2 )
{
printf ( "!!!:OnRecv failure 3: %s", buf.c_str() );
continue;
}
string tgt ( p, p2-p );
p = p2 + 1;
p += strspn ( p, " " );
if ( *p == '=' )
{
p++;
p += strspn ( p, " " );
}
if ( *p == ':' )
p++;
p2 = strpbrk ( p, "\r\n" );
if ( !p2 )
{
printf ( "!!!:OnRecv failure 4: %s", buf.c_str() );
continue;
}
string text ( p, p2-p );
strlwr ( &cmd[0] );
if ( cmd == "privmsg" )
{
if ( !tgt.length() )
{
printf ( "!!!:OnRecv failure 5 (PRIVMSG w/o target): %s", buf.c_str() );
continue;
}
if ( *p == 1 )
{
p++;
p2 = strchr ( p, ' ' );
if ( !p2 ) p2 = p + strlen(p);
cmd = string ( p, p2-p );
strlwr ( &cmd[0] );
p = p2 + 1;
p2 = strchr ( p, 1 );
if ( !p2 )
{
printf ( "!!!:OnRecv failure 6 (no terminating \x01 for initial \x01 found: %s", buf.c_str() );
continue;
}
text = string ( p, p2-p );
if ( cmd == "action" )
{
if ( tgt[0] == '#' )
OnChannelAction ( tgt, src, text );
else
OnPrivAction ( src, text );
}
else
{
printf ( "!!!:OnRecv failure 7 (unrecognized \x01 command '%s': %s", cmd.c_str(), buf.c_str() );
continue;
}
}
else
{
if ( tgt[0] == '#' )
OnChannelMsg ( tgt, src, text );
else
OnPrivMsg ( src, text );
}
}
else if ( cmd == "mode" )
{
// two diff. kinds of mode notifications...
//printf ( "[MODE] src='%s' cmd='%s' tgt='%s' text='%s'", src.c_str(), cmd.c_str(), tgt.c_str(), text.c_str() );
//OnMode (
// self mode change:
// [MODE] src=Nick cmd=mode tgt=Nick text=+i
// channel mode change:
// [MODE] src=Nick cmd=mode tgt=#Channel text=+o Nick
if ( tgt[0] == '#' )
{
p = text.c_str();
p2 = strchr ( p, ' ' );
if ( p2 && *p2 )
{
string mode ( p, p2-p );
p = p2 + 1;
p += strspn ( p, " " );
OnUserModeInChannel ( src, tgt, mode, trim(p) );
}
else
OnChannelMode ( tgt, text );
}
else
OnMode ( tgt, text );
}
else if ( cmd == "join" )
{
OnJoin ( src, text );
}
else if ( cmd == "part" )
{
OnPart ( src, text );
}
else if ( cmd == "nick" )
{
OnNick ( src, text );
}
else if ( isdigit(cmd[0]) )
{
int i = atoi(cmd.c_str());
switch ( i )
{
case 1: // "Welcome!" - i.e. it's okay to issue commands now...
OnConnected();
break;
case 353: // user list for channel....
{
p = text.c_str();
p2 = strpbrk ( p, " :" );
if ( !p2 ) continue;
string channel ( p, p2-p );
p = strchr ( p2, ':' );
if ( !p ) continue;
p++;
vector<string> users;
while ( *p )
{
p2 = strchr ( p, ' ' );
if ( !p2 )
p2 = p + strlen(p);
users.push_back ( string ( p, p2-p ) );
p = p2+1;
p += strspn ( p, " " );
}
OnChannelUsers ( channel, users );
}
break;
case 366: // END of user list for channel
{
p = text.c_str();
p2 = strpbrk ( p, " :" );
if ( !p2 ) continue;
string channel ( p, p2-p );
OnEndChannelUsers ( channel );
}
break;
default:
if ( _debug ) printf ( "unknown command %i: %s", i, buf.c_str() );
break;
}
}
else
{
if ( strstr ( buf.c_str(), "ACTION" ) )
{
printf ( "ACTION: " );
for ( int i = 0; i < buf.size(); i++ )
printf ( "%c(%xh)", buf[i], (unsigned)(unsigned char)buf[i] );
}
else if ( _debug ) printf ( "unrecognized ':' response: %s", buf.c_str() );
}
}
else
{
if ( _debug ) printf ( "unrecognized irc msg: %s", buf.c_str() );
}
//OnRecv ( buf );
}
if ( _debug ) printf ( "IRCClient::Run() - exiting\n" );
_inRun = false;
return 0;
}

View File

@@ -0,0 +1,140 @@
// IRCClient.h
// This file is (C) 2004 Royce Mitchell III
// and released under the BSD & LGPL licenses
#ifndef IRCCLIENT_H
#define IRCCLIENT_H
#include <string>
#include <vector>
#include "SockUtils.h"
#include "ThreadPool.h"
class IRCClient : public suBufferedRecvSocket
{
public:
IRCClient();
static bool GetDebug() { return _debug; }
static bool SetDebug ( bool debug ) { bool old = _debug; _debug = debug; return old; }
// connect to server ( record greeting for apop if it exists )
bool Connect ( const std::string& server, short port = 6667 );
bool Running() { return _inRun; }
////////////////////////// IRC Client Protocol commands ///////////////////////
// first thing you must call... mode can be ""
// network can be same as name of server used in Connect() above
bool User ( const std::string& user, const std::string& mode,
const std::string& network, const std::string& realname );
// change nick...
bool Nick ( const std::string& nick );
// change mode for self...
bool Mode ( const std::string& mode );
// set someone's mode in channel ( like oping someone )
bool Mode ( const std::string& channel, const std::string& mode, const std::string& target );
// request a list of names of clients in a channel
bool Names ( const std::string& channel );
// join a channel...
bool Join ( const std::string& channel );
// send message to someone or some channel
bool PrivMsg ( const std::string& to, const std::string& text );
// send /me to someone or some channel
bool Action ( const std::string& to, const std::string& text );
// leave a channel
bool Part ( const std::string& channel, const std::string& text );
// log off
bool Quit ( const std::string& text );
////////////////////// callback functions ////////////////////////////
// OnConnected: you just successfully logged into irc server
virtual bool OnConnected() = 0;
virtual bool OnNick ( const std::string& oldNick, const std::string& newNick ) { return true; }
// OnJoin: someone just successfully joined a channel you are in ( also sent when you successfully join a channel )
virtual bool OnJoin ( const std::string& user, const std::string& channel ) { return true; }
// OnPart: someone just left a channel you are in
virtual bool OnPart ( const std::string& user, const std::string& channel ) { return true; }
// OnPrivMsg: you just received a private message from a user
virtual bool OnPrivMsg ( const std::string& from, const std::string& text ) { return true; }
virtual bool OnPrivAction ( const std::string& from, const std::string& text ) { return true; }
// OnChannelMsg: you just received a chat line in a channel
virtual bool OnChannelMsg ( const std::string& channel, const std::string& from,
const std::string& text ) { return true; }
// OnChannelAction: you just received a "/me" line in a channel
virtual bool OnChannelAction ( const std::string& channel, const std::string& from,
const std::string& text ) { return true; }
// OnChannelMode: notification of a change of a channel's mode
virtual bool OnChannelMode ( const std::string& channel, const std::string& mode )
{ return true; }
// OnUserModeInChannel: notification of a mode change of a user with respect to a channel.
// f.ex.: this will be called when someone is oped in a channel.
virtual bool OnUserModeInChannel ( const std::string& src, const std::string& channel,
const std::string& mode, const std::string& target ) { return true; }
// OnMode: you will receive this when you change your own mode, at least...
virtual bool OnMode ( const std::string& user, const std::string& mode ) { return true; }
// notification of what users are in a channel ( you may get multiple of these... )
virtual bool OnChannelUsers ( const std::string& channel, const std::vector<std::string>& users )
{ return true; }
// notification that you have received the entire list of users for a channel
virtual bool OnEndChannelUsers ( const std::string& channel ) { return true; }
// OnPing - default implementation replies to PING with a valid PONG. required on some systems to
// log in. Most systems require a response in order to stay connected, used to verify a client hasn't
// dropped.
virtual bool OnPing ( const std::string& text );
////////////////////// other functions ////////////////////////////
// this is for sending data to irc server. it's public in case you need to send some
// command not supported by this base class...
bool Send ( const std::string& buf );
// if launch_thread is true, this function will spawn a thread that will process
// incoming packets until the socket dies.
// otherwise ( launch_thread is false ) this function will do that processing
// in *this* thread, and not return until the socket dies.
int Run ( bool launch_thread );
////////////////////// private stuff ////////////////////////////
private:
bool _Recv ( std::string& buf );
static int THREADAPI Callback ( IRCClient* irc );
static bool _debug;
std::string _nick;
int _timeout;
std::string _apop_challenge;
volatile bool _inRun;
// disable copy semantics
IRCClient ( const IRCClient& );
IRCClient& operator = ( const IRCClient& );
};
#endif//IRCCLIENT_H

418
irc/ArchBlackmann/MD5.cpp Normal file
View File

@@ -0,0 +1,418 @@
// MD5.CPP - RSA Data Security, Inc., MD5 message-digest algorithm
/*
Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
//#include <assert.h>
#include <memory.h>
#include <ctype.h>
#include <vector>
#include "MD5.h"
using std::string;
using std::vector;
// Constants for MD5Transform routine.
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
static void MD5Transform ( UINT4 [4], const uchar [64] );
static void Encode ( unsigned char *, UINT4 *, unsigned int );
static void Decode ( UINT4 *, const uchar *, unsigned int );
static unsigned char PADDING[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
// F, G, H and I are basic MD5 functions.
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
// ROTATE_LEFT rotates x left n bits.
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
// Rotation is separate from addition to prevent recomputation.
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
// MD5 initialization. Begins an MD5 operation, writing a new context.
void MD5Init (
MD5_CTX *context ) // context
{
context->count[0] = context->count[1] = 0;
// Load magic initialization constants.
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
// MD5 block update operation. Continues an MD5 message-digest
// operation, processing another message block, and updating the
// context.
void MD5Update (
MD5_CTX *context, // context
const char *input_, // input block
unsigned int inputLen ) // length of input block
{
unsigned int i, index, partLen;
const uchar* input = (const uchar*)input_;
// Compute number of bytes mod 64
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
// Update number of bits
if ((context->count[0] += ((UINT4)inputLen << 3))
< ((UINT4)inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - index;
// Transform as many times as possible.
if (inputLen >= partLen)
{
memcpy
((POINTER)&context->buffer[index], (POINTER)input, partLen);
MD5Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (context->state, &input[i]);
index = 0;
}
else
i = 0;
// Buffer remaining input
memcpy
((POINTER)&context->buffer[index], (POINTER)&input[i],
inputLen-i);
}
// MD5 finalization. Ends an MD5 message-digest operation, writing the
// the message digest and zeroizing the context.
void MD5Final (
unsigned char digest[16], // message digest
MD5_CTX *context ) // context
{
uchar bits[8];
unsigned int index, padLen;
// Save number of bits
Encode (bits, context->count, 8);
// Pad out to 56 mod 64.
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update (context, (const char*)PADDING, padLen);
// Append length (before padding)
MD5Update (context, (const char*)bits, 8);
// Store state in digest
Encode (digest, context->state, 16);
// Zeroize sensitive information.
memset ((POINTER)context, 0, sizeof (*context));
}
// MD5 basic transformation. Transforms state based on block.
static void MD5Transform (
UINT4 state[4],
const uchar block[64] )
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
// Round 1
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); // 1
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); // 2
FF (c, d, a, b, x[ 2], S13, 0x242070db); // 3
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); // 4
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); // 5
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); // 6
FF (c, d, a, b, x[ 6], S13, 0xa8304613); // 7
FF (b, c, d, a, x[ 7], S14, 0xfd469501); // 8
FF (a, b, c, d, x[ 8], S11, 0x698098d8); // 9
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); // 10
FF (c, d, a, b, x[10], S13, 0xffff5bb1); // 11
FF (b, c, d, a, x[11], S14, 0x895cd7be); // 12
FF (a, b, c, d, x[12], S11, 0x6b901122); // 13
FF (d, a, b, c, x[13], S12, 0xfd987193); // 14
FF (c, d, a, b, x[14], S13, 0xa679438e); // 15
FF (b, c, d, a, x[15], S14, 0x49b40821); // 16
// Round 2
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); // 17
GG (d, a, b, c, x[ 6], S22, 0xc040b340); // 18
GG (c, d, a, b, x[11], S23, 0x265e5a51); // 19
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); // 20
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); // 21
GG (d, a, b, c, x[10], S22, 0x2441453); // 22
GG (c, d, a, b, x[15], S23, 0xd8a1e681); // 23
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); // 24
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); // 25
GG (d, a, b, c, x[14], S22, 0xc33707d6); // 26
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); // 27
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); // 28
GG (a, b, c, d, x[13], S21, 0xa9e3e905); // 29
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); // 30
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); // 31
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); // 32
// Round 3
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); // 33
HH (d, a, b, c, x[ 8], S32, 0x8771f681); // 34
HH (c, d, a, b, x[11], S33, 0x6d9d6122); // 35
HH (b, c, d, a, x[14], S34, 0xfde5380c); // 36
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); // 37
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); // 38
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); // 39
HH (b, c, d, a, x[10], S34, 0xbebfbc70); // 40
HH (a, b, c, d, x[13], S31, 0x289b7ec6); // 41
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); // 42
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); // 43
HH (b, c, d, a, x[ 6], S34, 0x4881d05); // 44
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); // 45
HH (d, a, b, c, x[12], S32, 0xe6db99e5); // 46
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); // 47
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); // 48
// Round 4
II (a, b, c, d, x[ 0], S41, 0xf4292244); // 49
II (d, a, b, c, x[ 7], S42, 0x432aff97); // 50
II (c, d, a, b, x[14], S43, 0xab9423a7); // 51
II (b, c, d, a, x[ 5], S44, 0xfc93a039); // 52
II (a, b, c, d, x[12], S41, 0x655b59c3); // 53
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); // 54
II (c, d, a, b, x[10], S43, 0xffeff47d); // 55
II (b, c, d, a, x[ 1], S44, 0x85845dd1); // 56
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); // 57
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); // 58
II (c, d, a, b, x[ 6], S43, 0xa3014314); // 59
II (b, c, d, a, x[13], S44, 0x4e0811a1); // 60
II (a, b, c, d, x[ 4], S41, 0xf7537e82); // 61
II (d, a, b, c, x[11], S42, 0xbd3af235); // 62
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); // 63
II (b, c, d, a, x[ 9], S44, 0xeb86d391); // 64
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
// Zeroize sensitive information.
memset ((POINTER)x, 0, sizeof (x));
}
// Encodes input (UINT4) into output (unsigned char). Assumes len is
// a multiple of 4.
static void Encode (
unsigned char *output,
UINT4 *input,
unsigned int len )
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
// Decodes input (unsigned char) into output (UINT4). Assumes len is
// a multiple of 4.
static void Decode (
UINT4 *output,
const uchar *input,
unsigned int len )
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}
void digest2ascii ( char *ascii, const unsigned char *digest )
{
int i;
static char* table = "0123456789abcdef";
for ( i = 0; i < 16; i++ )
{
*ascii++ = table[(*digest)>>4];
*ascii++ = table[(*digest++)%16];
}
*ascii++ = 0;
}
void ascii2digest ( unsigned char *digest, const char *ascii )
{
int i;
#define CONV(c) (unsigned char)( (toupper(c)>='A') ? (toupper(c)+10-'A') : ((c)-'0') )
#define MAKECHAR(a,b) ((CONV(a)%16)<<4)|(CONV(b)%16)
for ( i = 0; i < 16; i++ )
{
*digest++ = MAKECHAR(ascii[0],ascii[1]);
ascii += 2;
}
}
#ifdef __cplusplus
MD5::MD5()
{
Init();
}
void MD5::Init()
{
MD5Init(&_ctx);
}
void MD5::Update ( const string& s )
{
MD5Update ( &_ctx, s.c_str(), s.size() );
}
string MD5::Final ( char* digest )
{
vector<uchar> v;
v.resize(16);
MD5Final ( &v[0], &_ctx );
if ( digest )
memmove ( digest, &v[0], 16 );
string s;
static char* tohex = "0123456789abcdef";
for ( int i = 0; i < 16; i++ )
{
uchar c = v[i];
s += tohex[ (c>>4) & 0xF ];
s += tohex[ c & 0xF ];
}
return s;
}
string MD5Hex ( const string& s )
{
MD5 md5;
md5.Update ( s );
return md5.Final();
}
string MD5Bin ( const string& s )
{
MD5 md5;
md5.Update ( s );
char digest[16];
md5.Final ( digest );
return string ( digest, 16 );
}
string HMAC_MD5 ( const string& key, const string& text, char* out_bin )
{
MD5 md5;
char k_ipad[65]; // inner padding - key XORd with ipad
char k_opad[65]; // outer padding - key XORd with opad
string tmp;
char digest[16];
int i;
// if key is longer than 64 bytes reset it to key=MD5(key)
if ( key.length() > 64 )
{
md5.Init();
md5.Update ( key );
md5.Final ( digest );
tmp = string ( digest, 16 );
}
else
tmp = key;
// start out by storing key in pads
memset ( k_ipad, 0, sizeof(k_ipad) );
memset ( k_opad, 0, sizeof(k_opad) );
memcpy ( k_ipad, tmp.c_str(), tmp.length() );
memcpy ( k_opad, tmp.c_str(), tmp.length() );
// XOR key with ipad and opad values
for ( i=0; i<64; i++ )
{
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
// "inner" MD5
md5.Init();
md5.Update(k_ipad);
md5.Update(text);
md5.Final ( digest );
// "outer" MD5
md5.Init();
md5.Update(k_opad);
md5.Update(string(digest,16));
return md5.Final(out_bin);
}
#endif//__cplusplus

95
irc/ArchBlackmann/MD5.h Normal file
View File

@@ -0,0 +1,95 @@
// MD5.H - header file for MD5.CPP
/*
Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#ifndef __MD5_H
#define __MD5_H
#ifdef __cplusplus
#include <string>
#endif//__cplusplus
#ifndef uchar
#define uchar unsigned char
#endif//uchar
#ifndef ushort
#define ushort unsigned short
#endif//ushort
#ifndef ulong
#define ulong unsigned long
#endif//ulong
#ifdef __cplusplus
extern "C" {
#endif//__cplusplus
typedef uchar *POINTER; // POINTER defines a generic pointer type
typedef ushort UINT2; // UINT2 defines a two byte word
typedef ulong UINT4; // UINT4 defines a four byte word
// MD5 context.
typedef struct
{
UINT4 state[4]; // state (ABCD)
UINT4 count[2]; // number of bits, modulo 2^64 (lsb first)
unsigned char buffer[64]; // input buffer
} MD5_CTX;
void MD5Init ( MD5_CTX * );
void MD5Update ( MD5_CTX *, const char *, unsigned int );
void MD5Final ( uchar [16], MD5_CTX * );
void digest2ascii ( char *ascii, const uchar *digest );
void ascii2digest ( uchar *digest, const char *ascii );
#ifdef __cplusplus
} // extern "C"
class MD5
{
public:
MD5();
void Init();
void Update ( const std::string& s );
std::string Final ( char* digest = 0 );
private:
MD5_CTX _ctx;
};
std::string MD5Hex ( const std::string& s );
std::string MD5Bin ( const std::string& s );
std::string HMAC_MD5 (
const std::string& key,
const std::string& text,
char* out_bin = NULL );
#endif//__cplusplus
#endif//__MD5_H

315
irc/ArchBlackmann/QueueT.h Normal file
View File

@@ -0,0 +1,315 @@
/*
** Author: Samuel R. Blackburn
** Internet: wfc@pobox.com
**
** You can use it any way you like as long as you don't try to sell it.
**
** Any attempt to sell WFC in source code form must have the permission
** of the original author. You can produce commercial executables with
** WFC but you can't sell WFC.
**
** Copyright, 2000, Samuel R. Blackburn
**
** NOTE: I modified the info block below so it hopefully wouldn't conflict
** with the original file. Royce Mitchell III
*/
#ifndef QUEUET_CLASS_HEADER
#define QUEUET_CLASS_HEADER
#include "ReliMT.h"
#ifdef WIN32
#include <sys/types.h> // off_t
#define HEAPCREATE(size) m_Heap = ::HeapCreate ( HEAP_NO_SERIALIZE, size, 0 )
#define HEAPALLOC(size) ::HeapAlloc ( m_Heap, HEAP_NO_SERIALIZE, size )
#define HEAPREALLOC(p,size) ::HeapReAlloc( m_Heap, HEAP_NO_SERIALIZE, p, size )
#define HEAPFREE(p) ::HeapFree ( m_Heap, HEAP_NO_SERIALIZE, p )
#define HEAPDESTROY() ::HeapDestroy ( m_Heap ); m_Heap = 0;
#else
#define HEAPCREATE(size)
#define HEAPALLOC(size) malloc(size)
#define HEAPREALLOC(p,size) realloc(p,size);
#define HEAPFREE(p) free(p)
#define HEAPDESTROY()
#endif
template <class T>
class CQueueT : public Uncopyable
{
protected:
// What we want to protect
Mutex m_AddMutex;
Mutex m_GetMutex;
T* m_Items;
off_t m_AddIndex;
off_t m_GetIndex;
size_t m_Size;
#ifdef WIN32
HANDLE m_Heap;
#endif//WIN32
inline void m_GrowBy ( size_t number_of_new_items );
public:
inline CQueueT ( size_t initial_size = 1024 );
inline ~CQueueT();
inline bool Add( const T& new_item );
inline void Empty() { m_AddIndex = 0; m_GetIndex = 0; };
inline bool Get( T& item );
inline size_t GetLength() const;
inline size_t GetMaximumLength() const { return( m_Size ); };
inline bool AddArray ( const T* new_items, int item_count );
inline int GetArray ( T* items, const int maxget, const T& tEnd );
inline bool Contains ( const T& t );
};
template <class T>
inline CQueueT<T>::CQueueT ( size_t initial_size )
{
m_AddIndex = 0;
m_GetIndex = 0;
m_Items = NULL;
if ( initial_size == 0 )
initial_size = 1;
/*
** 1999-11-05
** We create our own heap because all of the pointers used are allocated
** and freed be us. We don't have to worry about a non-serialized thread
** accessing something we allocated. Because of this, we can perform our
** memory allocations in a heap dedicated to queueing. This means when we
** have to allocate more memory, we don't have to wait for all other threads
** to pause while we allocate from the shared heap (like the C Runtime heap)
*/
HEAPCREATE( ( ( ( 2 * initial_size * sizeof(T) ) < 65536 ) ? 65536 : (2 * initial_size * sizeof(T) ) ) );
m_Items = (T*)HEAPALLOC ( initial_size * sizeof(T) );
m_Size = ( m_Items == NULL ) ? 0 : initial_size;
}
template <class T>
inline CQueueT<T>::~CQueueT()
{
m_AddIndex = 0;
m_GetIndex = 0;
m_Size = 0;
if ( m_Items != NULL )
{
HEAPFREE(m_Items);
m_Items = NULL;
}
HEAPDESTROY();
}
template <class T>
inline bool CQueueT<T>::Add ( const T& item )
{
// Block other threads from entering Add();
Mutex::Lock addlock ( m_AddMutex );
// Add the item
m_Items[ m_AddIndex ] = item;
// 1999-12-08
// Many many thanks go to Lou Franco (lfranco@spheresoft.com)
// for finding an bug here. It rare but recreatable situations,
// m_AddIndex could be in an invalid state.
// Make sure m_AddIndex is never invalid
off_t new_add_index = ( ( m_AddIndex + 1 ) >= (off_t)m_Size ) ? 0 : m_AddIndex + 1;
if ( new_add_index == m_GetIndex )
{
// The queue is full. We need to grow.
// Stop anyone from getting from the queue
Mutex::Lock getlock ( m_GetMutex );
m_AddIndex = new_add_index;
// One last double-check.
if ( m_AddIndex == m_GetIndex )
{
m_GrowBy ( m_Size );
}
}
else
{
m_AddIndex = new_add_index;
}
return true;
}
template <class T>
inline bool CQueueT<T>::Get( T& item )
{
// Prevent other threads from entering Get()
Mutex::Lock getlock ( m_GetMutex );
if ( m_GetIndex == m_AddIndex )
{
// Let's check to see if our queue has grown too big
// If it has, then shrink it
if ( m_Size > 1024 )
{
// Yup, we're too big for our britches
Mutex::TryLock addlock ( m_AddMutex );
if ( addlock )
{
// Now, no one can add to the queue
if ( m_GetIndex == m_AddIndex ) // is queue empty?
{
// See if we can just shrink it...
T* return_value = (T*)HEAPREALLOC(m_Items,1024 * sizeof(T));
if ( return_value != NULL )
{
m_Items = (T*) return_value;
}
else
{
// Looks like we'll have to do it the hard way
HEAPFREE ( m_Items );
m_Items = (T*) HEAPALLOC ( 1024 * sizeof(T) );
}
m_Size = ( m_Items == NULL ) ? 0 : 1024;
m_AddIndex = 0;
m_GetIndex = 0;
}
else
{
// m_GetIndex != m_AddIndex, this means that someone added
// to the queue between the time we checked m_Size for being
// too big and the time we entered the add critical section.
// If this happened then we are too busy to shrink
}
}
}
return false;
}
item = m_Items[ m_GetIndex ];
// Make sure m_GetIndex is never invalid
m_GetIndex = ( ( m_GetIndex + 1 ) >= (off_t)m_Size ) ? 0 : m_GetIndex + 1;
return true;
}
template <class T>
inline int CQueueT<T>::GetArray ( T* items, const int maxget, const T& tEnd )
{
// TODO - oooh baby does this need to be optimized
// Prevent other threads from entering Get()
Mutex::Lock getlock ( m_GetMutex ); //::EnterCriticalSection( &m_GetCriticalSection );
int iResult = 0;
for ( int i = 0; i < maxget; i++ )
{
if ( !Get(items[i]) )
break;
iResult++;
if ( items[i] == tEnd )
break;
}
// Let other threads call Get() now
//::LeaveCriticalSection( &m_GetCriticalSection );
return iResult;
}
template <class T>
inline size_t CQueueT<T>::GetLength() const
{
// This is a very expensive process!
// No one can call Add() or Get() while we're computing this
size_t number_of_items_in_the_queue = 0;
Mutex::Lock addlock ( m_AddMutex );
Mutex::Lock getlock ( m_GetMutex );
number_of_items_in_the_queue = ( m_AddIndex >= m_GetIndex ) ?
( m_AddIndex - m_GetIndex ) :
( ( m_AddIndex + m_Size ) - m_GetIndex );
return number_of_items_in_the_queue;
}
template <class T>
inline void CQueueT<T>::m_GrowBy ( size_t number_of_new_items )
{
// Prevent other threads from calling Get().
// We don't need to enter the AddCriticalSection because
// m_GrowBy() is only called from Add();
T* new_array = NULL;
T* pointer_to_free = NULL;
size_t new_size = m_Size + number_of_new_items;
{ // Prevent other threads from getting
Mutex::Lock getlock ( m_GetMutex );
// 2000-05-16
// Thanks go to Royce Mitchell III (royce3@aim-controls.com) for finding
// a HUGE bug here. I was using HeapReAlloc as a short cut but my logic
// was flawed. In certain circumstances, queue items were being dropped.
new_array = (T*)HEAPALLOC ( new_size * sizeof(T) );
// Now copy all of the old items from the old queue to the new one.
// Get the entries from the get-index to the end of the array
memcpy ( new_array, &m_Items[m_GetIndex], ( m_Size - m_GetIndex ) * sizeof(T) );
// Get the entries from the beginning of the array to the add-index
memcpy ( &new_array[m_Size-m_GetIndex], m_Items, m_AddIndex * sizeof(T) );
m_AddIndex = (off_t)m_Size;
m_GetIndex = 0;
m_Size = new_size;
pointer_to_free = m_Items;
m_Items = new_array;
} // Mutex::Lock
HEAPFREE ( pointer_to_free );
}
template <class T>
inline bool CQueueT<T>::Contains ( const T& t )
{
Mutex::Lock addlock ( m_AddMutex );
Mutex::Lock getlock ( m_GetMutex );
for ( int i = m_GetIndex; i != m_AddIndex; i++ )
{
if ( i == m_Size )
i = 0;
if ( m_Items[i] == t )
return true;
}
return m_Items[m_AddIndex] == t;
}
typedef CQueueT<char> CCharQueue;
#endif // QUEUE_CLASS_HEADER

143
irc/ArchBlackmann/Reli.h Normal file
View File

@@ -0,0 +1,143 @@
// Reli.h
// lots of code here is (c) Bartosz Milewski, 1996, www.relisoft.com
// The rest is (C) 2002-2004 Royce Mitchell III
// and released under the LGPL & BSD licenses
#ifndef __RELI_H
#define __RELI_H
////////////////////////////////////////////////////////////////////////////////
// Assert
#undef Assert
#ifdef NDEBUG
#define Assert(exp) ((void)0)
#else
void _wassert (char* szExpr, char* szFile, int line);
#define Assert(exp) (void)( (exp) || (_wassert(#exp, __FILE__, __LINE__), 0) )
#endif /* NDEBUG */
////////////////////////////////////////////////////////////////////////////////
// Swap
template <class T>
void Swap(T a,T b)
{
T t = a;
a = b;
b = t;
}
////////////////////////////////////////////////////////////////////////////////
// Uncopyable - base class disabling copy ctors
class Uncopyable
{
public:
Uncopyable(){} // need a default ctor
private:
Uncopyable ( const Uncopyable& );
const Uncopyable& operator = ( const Uncopyable& );
};
////////////////////////////////////////////////////////////////////////////////
// SPtr - Smart Pointer's must be passed by reference or const reference
template <class T>
class SPtr : public Uncopyable
{
public:
virtual ~SPtr () { Destroy(); }
T * operator->() { return _p; }
T const * operator->() const { return _p; }
operator T&() { Assert(_p); return *_p; }
operator const T&() const { Assert(_p); return *_p; }
void Acquire ( SPtr<T>& t ) { Destroy(); Swap(_p,t._p); }
void Destroy() { if ( _p ) { delete _p; _p = 0; } }
protected:
SPtr (): _p (0) {}
explicit SPtr (T* p): _p (p) {}
T * _p;
private:
operator T* () { return _p; }
};
#define DECLARE_SPTR(cls,init,init2) \
class S##cls : public SPtr<cls> \
{ \
public: \
S##cls ( cls* p ) : SPtr<cls>(p) {} \
explicit S##cls init : SPtr<cls> (new cls init2) {} \
};
/* Example Usage of DECLARE_SPTR:
class MyClass
{
public: // can be protected
MyClass ( int i )
{
...
}
...
}; DECLARE_SPTR(MyClass,(int i),(i))
SMyClass ptr(i);
*/
#define DECLARE_SPTRV(cls) typedef SPtr<cls> S##cls;
/* Example Usage of DECLARE_SPTRV:
class MyAbstractClass
{
public: // can be protected
MyAbstractClass ( int i )
{
...
}
void MyPureVirtFunc() = 0;
...
}; DECLARE_SPTRV(MyAbstractClass)
SMyAbstractClass ptr ( new MySubClass(i) );
*/
#define DECLARE_PTR(cls,init,init2) \
class Ptr : public SPtr<cls> \
{ \
Ptr(cls* p) : SPtr<cls> ( p ) \
{ \
} \
Ptr init : SPtr<cls> ( new cls init2 ) {} \
};
/* Example Usage of DECLARE_PTR:
class MyClass
{
DECLARE_PTR(MyClass,(int i),(i))
public: // can be protected
MyClass ( int i )
{
...
}
void MyPureVirtFunc() = 0;
...
};
MyClass::Ptr ptr ( i );
*/
#define DECLARE_PTRV(cls) \
class Ptr : public SPtr<cls> \
{ \
Ptr(cls* p) : SPtr<cls> ( p ) \
{ \
} \
};
/* Example Usage of DECLARE_PTRV:
class MyAbstractClass
{
DECLARE_PTRV(MyAbstractClass)
public: // can be protected
MyAbstractClass ( int i )
{
...
}
void MyPureVirtFunc() = 0;
...
};
MyAbstractClass::Ptr ptr ( new MySubClass(i) );
*/
#endif//__RELI_H

View File

@@ -0,0 +1,331 @@
// ReliMT.cpp
// lots of code here is (c) Bartosz Milewski, 1996, www.relisoft.com
// The rest is (C) 2002-2004 Royce Mitchell III
// and released under the LGPL & BSD licenses
#include <stdlib.h>
#include <stdio.h>
#ifdef WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# define snprintf _snprintf
#elif defined(UNIX)
# include <errno.h>
# include <sys/sem.h>
#else
# error unrecognized target
#endif//WIN32|UNIX
#include "verify.h"
#include "ReliMT.h"
////////////////////////////////////////////////////////////////////////////////
// Assert
void _wassert ( char* szExpr, char* szFile, int line )
{
fprintf ( stderr, "Assertion Failure: \"%s\" in file %s, line %d", szExpr, szFile, line );
exit (-1);
}
////////////////////////////////////////////////////////////////////////////////
// Thread
Thread::Thread ( long (THREADAPI * pFun) (void* arg), void* pArg )
{
#ifdef WIN32
verify ( _handle = CreateThread (
0, // Security attributes
0, // Stack size
(DWORD (WINAPI*)(void*))pFun,
pArg,
0, // don't create suspended.
&_tid ));
#elif defined(UNIX)
// set up the thread attribute: right now, we do nothing with it.
pthread_attr_t attr;
pthread_attr_init(&attr);
// this will make the threads created by this process really concurrent
verify ( !pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) );
// create the new OS thread object
verify ( !pthread_create ( &_threadId, &attr, (void* (*) (void*))pFun, pArg ) );
verify ( !pthread_attr_destroy(&attr) );
#else
# error unrecognized target
#endif//WIN32|UNIX
}
Thread::~Thread()
{
#ifdef WIN32
verify ( CloseHandle ( _handle ) );
#elif defined(UNIX)
verify ( !pthread_cancel ( _threadId ) );
#else
# error unrecognized target
#endif//WIN32|UNIX
}
/*void Thread::Resume()
{
#ifdef WIN32
ResumeThread (_handle);
#elif defined(UNIX)
# error how to resume thread in unix?
#else
# error unrecognized target
#endif//WIN32|UNIX
}*/
void Thread::WaitForDeath()
{
#ifdef WIN32
DWORD dw = WaitForSingleObject ( _handle, 2000 );
ASSERT ( dw != WAIT_FAILED );
#elif defined(UNIX)
verify ( !pthread_join ( _threadId, (void**)NULL ) );
#else
# error unrecognized target
#endif//WIN32|UNIX
}
////////////////////////////////////////////////////////////////////////////////
// ActiveObject
// The constructor of the derived class
// should call
// _thread.Resume();
// at the end of construction
ActiveObject::ActiveObject() : _isDying (0), _thread (0)
{
}
ActiveObject::~ActiveObject()
{
ASSERT ( !_thread ); // call Kill() from subclass's dtor
// Kill() - // You can't call a virtual function from a dtor, EVEN INDIRECTLY
// so, you must call Kill() in the subclass's dtor
}
// FlushThread must reset all the events on which the thread might be waiting.
void ActiveObject::Kill()
{
if ( _thread )
{
_isDying++;
FlushThread();
// Let's make sure it's gone
_thread->WaitForDeath();
delete _thread;
_thread = 0;
}
}
void ActiveObject::Start()
{
ASSERT ( !_thread );
_thread = new Thread ( ThreadEntry, this );
}
long THREADAPI ActiveObject::ThreadEntry ( void* pArg )
{
ActiveObject * pActive = (ActiveObject*)pArg;
pActive->InitThread();
pActive->Run();
pActive->Kill();
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Mutex
Mutex::Mutex()
{
#ifdef WIN32
verify ( _h = CreateMutex ( NULL, FALSE, NULL ) );
#elif defined(UNIX)
pthread_mutexattr_t attrib;
verify ( !pthread_mutexattr_init( &attrib ) );
// allow recursive locks
verify ( !pthread_mutexattr_settype( &attrib, PTHREAD_MUTEX_RECURSIVE ) );
verify ( !pthread_mutex_init ( &_mutex, &attrib ) );
#else
# error unrecognized target
#endif
}
Mutex::~Mutex()
{
#ifdef WIN32
verify ( CloseHandle ( _h ) );
#elif defined(UNIX)
verify ( !pthread_mutex_destroy(&_mutex) );
#else
# error unrecognized target
#endif
}
void Mutex::Acquire()
{
#ifdef WIN32
DWORD dw = WaitForSingleObject ( _h, INFINITE );
ASSERT ( dw == WAIT_OBJECT_0 || dw == WAIT_ABANDONED );
#elif defined(UNIX)
verify ( !pthread_mutex_lock(&_mutex) );
#else
# error unrecognized target
#endif
}
bool Mutex::TryAcquire()
{
#ifdef WIN32
DWORD dw = WaitForSingleObject ( _h, 1 );
ASSERT ( dw == WAIT_OBJECT_0 || dw == WAIT_TIMEOUT || dw == WAIT_ABANDONED );
return (dw != WAIT_TIMEOUT);
#elif defined(UNIX)
int err = pthread_mutex_trylock(&_mutex);
ASSERT ( err == EBUSY || err == 0 );
return (err == 0);
#else
# error unrecognized target
#endif
}
void Mutex::Release()
{
#ifdef WIN32
verify ( ReleaseMutex ( _h ) );
#elif defined(UNIX)
verify ( !pthread_mutex_unlock(&_mutex) );
// we could allow EPERM return value too, but we are forcing user into RIIA
#else
# error unrecognized target
#endif
}
Mutex::Lock::Lock ( Mutex& m ) : _m(m)
{
_m.Acquire();
}
Mutex::Lock::~Lock()
{
_m.Release();
}
Mutex::TryLock::TryLock ( Mutex& m ) : _m(m)
{
_bLocked = _m.TryAcquire();
}
Mutex::TryLock::~TryLock()
{
if ( _bLocked )
_m.Release();
}
///////////////////////////////////////////////////////////////////////////////
// Event
Event::Event()
{
#ifdef WIN32
// start in non-signaled state (red light)
// auto reset after every Wait
verify ( _handle = CreateEvent ( 0, FALSE, FALSE, 0 ) );
#elif defined(UNIX)
//verify ( !pthread_cond_init ( &_cond, NULL /* default attributes */) );
sem_init();
//verify(sem_init());
#else
# error unrecognized target
#endif
}
Event::~Event()
{
#ifdef WIN32
verify ( CloseHandle ( _handle ) );
#elif defined(UNIX)
//verify ( !pthread_cond_destroy ( &_cond ) );
sem_destroy();
#else
# error unrecognized target
#endif
}
void Event::Release() // put into signaled state
{
#ifdef WIN32
verify ( SetEvent ( _handle ) );
#elif defined(UNIX)
//verify ( !pthread_cond_signal ( &_cond ) );
verify(!sem_V());
#else
# error unrecognized target
#endif
}
void Event::Wait()
{
#ifdef WIN32
// Wait until event is in signaled (green) state
DWORD dw = WaitForSingleObject ( _handle, INFINITE );
ASSERT ( dw == WAIT_OBJECT_0 || dw == WAIT_ABANDONED );
#elif defined(UNIX)
// According to docs: The pthread_cond_wait() and pthread_cond_timedwait()
// functions are used to block on a condition variable. They are called
// with mutex locked by the calling thread or undefined behaviour will
// result.
//Mutex::Lock lock ( _mutex );
//verify ( !pthread_cond_wait ( &_cond, _mutex ) );
verify(!sem_P());
#else
# error unrecognized target
#endif
}
#ifdef UNIX
void Event::sem_init()
{
sem_id = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
ASSERT(sem_id != -1);
}
int Event::sem_P()
{
struct sembuf sb;
sb.sem_num = 0;
sb.sem_op = -1;
sb.sem_flg = 0;
return semop(sem_id, &sb, 1);
}
int Event::sem_V()
{
struct sembuf sb;
sb.sem_num = 0;
sb.sem_op = 1;
sb.sem_flg = 0;
return semop(sem_id, &sb, 1);
}
void Event::sem_destroy()
{
#ifdef MACOSX
semun mactmp;
mactmp.val = 0;
semctl(sem_id, 0, IPC_RMID, mactmp);
#else
semctl(sem_id, 0, IPC_RMID, 0);
#endif
}
#endif

229
irc/ArchBlackmann/ReliMT.h Normal file
View File

@@ -0,0 +1,229 @@
// ReliMT.h
// lots of code here is (c) Bartosz Milewski, 1996, www.relisoft.com
// The rest is (C) 2003-2004 Royce Mitchell III
// and released under the LGPL & BSD licenses
#ifndef __RELIMT_H
#define __RELIMT_H
#include "Reli.h"
#ifdef WIN32
# ifndef _WINDOWS_
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# endif
# define THREADAPI WINAPI
#elif defined(UNIX)
# include <pthread.h>
# include <stdlib.h>
# include "string.h"
# include <sys/types.h> //Semaphore
# include <sys/ipc.h> //Semaphore
# include <sys/sem.h> //Semaphore
# define THREADAPI
#else
# error unrecognized target
#endif
////////////////////////////////////////////////////////////////////////////////
// Thread
class Thread : public Uncopyable
{
public:
Thread ( long (THREADAPI * pFun) (void* arg), void* pArg );
~Thread();
//void Resume();
void WaitForDeath();
// platform-specific stuff:
private:
#ifdef WIN32
HANDLE _handle;
DWORD _tid; // thread id
#elif defined(UNIX)
pthread_t _threadId; // id of the thread
#else
# error unrecognized target
#endif
//DECLARE_PTR(Thread,(long (THREADAPI * pFun) (void* arg), void* pArg),(pFun,pArg));
}; //DECLARE_SPTR(Thread,(long (THREADAPI * pFun) (void* arg), void* pArg),(pFun,pArg));
////////////////////////////////////////////////////////////////////////////////
// ActiveObject
class ActiveObject : public Uncopyable
{
public:
ActiveObject();
virtual ~ActiveObject();
void Kill();
void Start();
protected:
virtual void InitThread() = 0;
virtual void Run() = 0;
virtual void FlushThread() = 0;
int _isDying;
static long THREADAPI ThreadEntry ( void *pArg );
Thread *_thread;
//DECLARE_PTRV(ActiveObject);
}; //DECLARE_SPTRV(ActiveObject);
// Last thing in the constructor of a class derived from
// ActiveObject you must call
// Start();
// Inside the loop the Run method you must keep checking _isDying
// if (_isDying)
// return;
// FlushThread must reset all the events on which the thread might be waiting.
// Example:
#if 0
// MyAsyncOutputter - class that outputs strings to a file asynchronously
class MyAsyncOutputter : public ActiveObject
{
public:
MyAsyncOutputter ( const string& filename ) : _filename(filename), _currentBuf(0)
{
Start(); // start thread
}
void InitThread()
{
_f.open ( _filename, "wb" );
}
void Output ( const string& s )
{
{
// acquire lock long enough to add the string to the active buffer
Mutex::Lock lock ( _mutex );
_buf[_currentBuf].push_back ( s );
}
_event.Release(); // don't need the lock fire the event
}
void Run()
{
while ( !_isDying )
{
// wait for signal from Output() or FlushThread()
_event.Wait();
{
// acquire lock long enough to switch active buffers
Mutex::Lock lock ( _mutex );
_currentBuf = 1-_currentBuf;
ASSERT ( !_buf[_currentBuf].size() );
}
// get a reference to the old buffer
vector<string>& buf = _buf[1-_currentBuf];
// write each string out to file and then empty the buffer
for ( int i = 0; i < buf.size(); i++ )
_f.write ( buf[i].c_str(), buf[i].size() );
buf.resize(0);
}
}
void FlushThread()
{
// _isDying is already set: signal thread so it can see that too
_event.Release();
}
private:
string _filename;
File _f;
int _currentBuf;
vector<string> _buf[2];
Event _event;
Mutex _mutex;
};
#endif
////////////////////////////////////////////////////////////////////////////////
// Mutex
class Mutex : public Uncopyable
{
public:
Mutex();
~Mutex();
private:
void Acquire();
bool TryAcquire();
void Release();
public:
// sub-class used to lock the Mutex
class Lock : public Uncopyable
{
public:
Lock ( Mutex& m );
~Lock();
private:
// private data
Mutex& _m;
};
friend class Mutex::Lock;
// sub-class used to attempt to lock the mutex. Use operator bool()
// to test if the lock was successful
class TryLock : public Uncopyable
{
public:
TryLock ( Mutex& m );
~TryLock();
operator bool () { return _bLocked; }
private:
// private data
bool _bLocked;
Mutex& _m;
};
friend class Mutex::TryLock;
private:
// platform-specific stuff:
#ifdef WIN32
HANDLE _h;
#elif defined(UNIX)
pthread_mutex_t _mutex;
public: operator pthread_mutex_t* () { return &_mutex; }
#else
# error unrecognized target
#endif
};
////////////////////////////////////////////////////////////////////////////////
// Event
class Event : public Uncopyable
{
public:
Event();
~Event();
void Release(); // put into signaled state
void Wait();
private:
#ifdef WIN32
HANDLE _handle;
#elif defined(UNIX)
//Sem util functions
void sem_init();
int sem_P();
int sem_V();
void sem_destroy();
int sem_id;
//pthread_cond_t _cond;
//Mutex _mutex;
#else
# error unrecognized target
#endif
//DECLARE_PTR(Event,(),());
}; //DECLARE_SPTR(Event,(),());
#endif//__RELIWIN32_H

View File

@@ -0,0 +1,504 @@
// SockUtils.cpp - Some basic socket utility functions.
// (C) 2002-2004 Royce Mitchell III
// This file is under the BSD & LGPL licenses
#include <stdio.h>
#include "SockUtils.h"
#ifdef WIN32
# ifndef SD_SEND // defined in winsock2.h, but not winsock.h
# define SD_SEND 1
# endif
# define snprintf _snprintf
# ifdef _MSC_VER
# pragma comment ( lib, "ws2_32.lib" )
# endif//_MSC_VER
#elif defined(UNIX)
# include <errno.h>
# include "string.h" // memset
# include <netdb.h> // hostent
# include <arpa/inet.h> //inet_addr
# include <sys/time.h>
# define SD_SEND SHUT_WR //bah thou shalt name thy defines the same
#else
# error unrecognized target
#endif
//// Constants /////////////////////////////////////////////////////////
const int kBufferSize = 1024;
// creates broadcast address
SockAddrIn::SockAddrIn()
{
memset ( this, 0, sizeof(sockaddr_in) );
sin_family = AF_INET;
}
SockAddrIn::SockAddrIn ( const char* szAddr, u_short iPort )
{
memset ( this, 0, sizeof(sockaddr_in) );
sin_family = AF_INET;
sin_addr.s_addr = suLookupAddress(szAddr);
sin_port = htons(iPort);
}
SockAddrIn::SockAddrIn ( in_addr_t iAddr, u_short iPort )
{
memset ( this, 0, sizeof(sockaddr_in) );
sin_family = AF_INET;
sin_addr.s_addr = iAddr;
sin_port = htons(iPort);
}
bool suStartup()
{
#ifdef WIN32
WSADATA wsaData;
if ( WSAStartup ( MAKEWORD(2,0), &wsaData ) )
return false;
if ( wsaData.wVersion != MAKEWORD(2,0) )
{
WSACleanup();
return false;
}
return true;
#elif defined(UNIX)
// nothing special required here
return true;
#else
# error unrecognized target
#endif
}
//// suTcpSocket ////////////////////////////////////////////////
// Creates a TCP socket.
SOCKET suTcpSocket()
{
SOCKET so = socket ( AF_INET, SOCK_STREAM, 0 );
#if defined(_DEBUG) && defined(WIN32)
if ( so == INVALID_SOCKET && WSANOTINITIALISED == WSAGetLastError() )
MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION );
#endif
return so;
}
//// suUdpSocket ////////////////////////////////////////////////
// Creates a UDP socket. Compensates for new "functionality" introduced
// in Win2K with regards to select() calls
// MS Transport Provider IOCTL to control
// reporting PORT_UNREACHABLE messages
// on UDP sockets via recv/WSARecv/etc.
// Path TRUE in input buffer to enable (default if supported),
// FALSE to disable.
#ifndef SIO_UDP_CONNRESET
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
#endif//SIO_UDP_CONNRESET
SOCKET suUdpSocket()
{
SOCKET so = socket ( AF_INET, SOCK_DGRAM, 0 );
#if defined(_DEBUG) && defined(WIN32)
if ( so == INVALID_SOCKET && WSANOTINITIALISED == WSAGetLastError() )
MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION );
#endif
#ifdef WIN32
// for Windows 2000, disable new behavior...
// see: http://www-pc.uni-regensburg.de/systemsw/W2KPRO/UPDATE/POSTSP1/Q263823.htm
// this code is innocuous on other win32 platforms
DWORD dwBytesReturned = 0;
BOOL bNewBehavior = FALSE;
// disable new Win2K behavior using
// IOCTL: SIO_UDP_CONNRESET
// we don't care about return value :)
WSAIoctl(so, SIO_UDP_CONNRESET,
&bNewBehavior, sizeof(bNewBehavior),
NULL, 0, &dwBytesReturned,
NULL, NULL);
#endif
return so;
}
//// suShutdownConnection ////////////////////////////////////////////////
// Gracefully shuts the connection sd down. Returns true if it was able
// to shut it down nicely, false if we had to "slam" it shut.
// (either way, the socket does get closed)
bool suShutdownConnection(SOCKET sd)
{
if ( sd == INVALID_SOCKET )
return true;
// Disallow any further data sends. This will tell the other side
// that we want to go away now. If we skip this step, we don't
// shut the connection down nicely.
if (shutdown(sd, SD_SEND) == SOCKET_ERROR)
{
closesocket(sd);
return false;
}
// Receive any extra data still sitting on the socket. After all
// data is received, this call will block until the remote host
// acknowledges the TCP control packet sent by the shutdown above.
// Then we'll get a 0 back from recv, signalling that the remote
// host has closed its side of the connection.
char acReadBuffer[kBufferSize];
for ( ;; )
{
int nNewBytes = recv(sd, acReadBuffer, kBufferSize, 0);
if (nNewBytes == SOCKET_ERROR)
{
closesocket(sd);
return false;
}
else if (nNewBytes != 0)
{
// FYI, received (nNewBytes) unexpected bytes during shutdown.
}
else
{
// Okay, we're done!
break;
}
}
// Close the socket.
if (closesocket(sd) == SOCKET_ERROR)
{
return false;
}
return true;
}
//// suLookupAddress ////////////////////////////////////////////////
// Basically converts a name address to an ip address
in_addr_t suLookupAddress ( const char* pcHost )
{
in_addr_t nRemoteAddr = inet_addr(pcHost);
if ( nRemoteAddr == INADDR_NONE )
{
// pcHost isn't a dotted IP, so resolve it through DNS
hostent* pHE = gethostbyname(pcHost);
if ( pHE == 0 )
{
#if defined(_DEBUG) && defined(WIN32)
if ( WSANOTINITIALISED == WSAGetLastError() )
MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION );
#endif
return INADDR_NONE;
}
nRemoteAddr = *((in_addr_t*)pHE->h_addr_list[0]);
}
return nRemoteAddr;
}
bool suConnect ( SOCKET so, in_addr_t iAddress, u_short iPort )
{
SockAddrIn sinRemote ( iAddress, iPort );
if ( SOCKET_ERROR == connect(so,sinRemote,sizeof(sinRemote)) )
{
#if defined(_DEBUG) && defined(WIN32)
if ( WSANOTINITIALISED == WSAGetLastError() )
MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION );
#endif
return false;
}
return true;
}
bool suConnect ( SOCKET so, const char* szAddress, u_short iPort )
{
return suConnect ( so, suLookupAddress(szAddress), iPort );
}
//// suEstablishConnection ////////////////////////////////////////////////
// creates a socket of the specified type, connects to the ip address/port
// requested, and returns the SOCKET created
SOCKET suEstablishConnection ( in_addr_t iAddress, u_short iPort, int type )
{
// Create a socket
if ( type != SOCK_STREAM && type != SOCK_DGRAM )
return INVALID_SOCKET;
SOCKET so = socket(AF_INET, type, 0);
if ( so == INVALID_SOCKET )
return so;
if ( !suConnect(so, iAddress, iPort) )
{
closesocket(so);
return INVALID_SOCKET;
}
return so;
}
//// suEstablishConnection ////////////////////////////////////////////////
// creates a socket of the specified type, connects to the address/port
// requested, and returns the SOCKET created
SOCKET suEstablishConnection ( const char* szAddress, u_short iPort, int type )
{
return suEstablishConnection ( suLookupAddress ( szAddress ), iPort, type );
}
//// suBroadcast ////////////////////////////////////////////////
// takes a previously created broadcast-enabled UDP socket, and broadcasts
// a message on the local network
bool suBroadcast ( SOCKET so, u_short port, const char* buf, int len /* = -1 */ )
{
if ( len == -1 )
len = (int)strlen(buf);
#if 1
SockAddrIn to ( INADDR_BROADCAST, port );
#else // some strange MS OS's don't broadcast to localhost...
SockAddrIn to ( "127.0.0.1", port );
if ( SOCKET_ERROR == sendto ( so, buf, len, 0, to, sizeof(to) ) )
return false;
to.sin_addr.s_addr = INADDR_BROADCAST;
#endif
if ( SOCKET_ERROR == sendto ( so, buf, len, 0, to, sizeof(to) ) )
return false;
return true;
}
//// suRecv ////////////////////////////////////////////////
// retrieves data sent to our TCP socket. If no data, waits for
// a period of timeout ms.
// returns bytes received
// -1 == SOCKET_ERROR
// -2 == timed out waiting for data
int suRecv ( SOCKET so, char* buf, int buflen, int timeout )
{
struct timeval to;
fd_set rread;
int res;
FD_ZERO(&rread); // clear the fd_set
FD_SET(so,&rread); // indicate which socket(s) we want to check
memset((char *)&to,0,sizeof(to)); // clear the timeval struct
to.tv_sec = timeout; // timeout select after (timeout) seconds
// select returns > 0 if there is an event on the socket
res = select((int)so+1, &rread, (fd_set *)0, (fd_set *)0, &to );
if (res < 0)
return -1; // socket error
// there was an event on the socket
if ( (res>0) && (FD_ISSET(so,&rread)) )
return recv ( so, buf, buflen, 0 );
return -2;
}
//// suRecvFrom ////////////////////////////////////////////////
// retrieves data sent to our UDP socket. If no data, waits for
// a period of timeout ms.
// returns bytes received
// returns bytes received
// -1 == SOCKET_ERROR
// -2 == timed out waiting for data
int suRecvFrom ( SOCKET so, char* buf, int buflen, int timeout, sockaddr_in* from, socklen_t* fromlen )
{
struct timeval to;
fd_set rread;
int res;
FD_ZERO(&rread); // clear the fd_set
FD_SET(so,&rread); // indicate which socket(s) we want to check
memset((char *)&to,0,sizeof(to)); // clear the timeval struct
to.tv_sec = timeout; // timeout select after (timeout) seconds
// select returns > 0 if there is an event on the socket
res = select((int)so+1, &rread, (fd_set *)0, (fd_set *)0, &to );
if (res < 0)
return -1; // socket error
// there was an event on the socket
if ( (res>0) && (FD_ISSET(so,&rread)) )
return recvfrom ( so, buf, buflen, 0, (sockaddr*)from, fromlen );
return -2; // timeout
}
//// suBind ////////////////////////////////////////////////
// binds a UDP socket to an interface & port to receive
// data on that port
bool suBind ( SOCKET so, in_addr_t iInterfaceAddress, u_short iListenPort, bool bReuseAddr /* = false */ )
{
SockAddrIn sinInterface ( iInterfaceAddress, iListenPort );
if ( bReuseAddr )
{
int optval = -1; // true
if ( SOCKET_ERROR == setsockopt ( so, SOL_SOCKET, SO_REUSEADDR, (const char*)&optval, sizeof(optval) ) )
{
#if defined(_DEBUG) && defined(WIN32)
if ( WSANOTINITIALISED == WSAGetLastError() )
MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION );
#endif
return false;
}
}
if ( SOCKET_ERROR == bind(so, sinInterface, sizeof(sinInterface)) )
{
int err = SUERRNO;
if ( err != EADDRINUSE )
return false;
#if defined(_DEBUG) && defined(WIN32)
if ( WSANOTINITIALISED == WSAGetLastError() )
MessageBox ( NULL, "You forgot to call suStartup()!", "SockUtils", MB_OK|MB_ICONEXCLAMATION );
#endif
}
return true;
}
//// suBind ////////////////////////////////////////////////
// binds a UDP socket to an interface & port to receive
// data on that port
bool suBind ( SOCKET so, const char* szInterfaceAddress, u_short iListenPort, bool bReuseAddr /* = false */ )
{
in_addr_t iInterfaceAddr = inet_addr(szInterfaceAddress);
if ( iInterfaceAddr == INADDR_NONE )
return false;
return suBind ( so, iInterfaceAddr, iListenPort, bReuseAddr );
}
//// suEnableBroadcast ////////////////////////////////////////////////
// in order to send broadcast messages on a UDP socket, this function
// must be called first
bool suEnableBroadcast ( SOCKET so, bool bEnable /* = true */ )
{
int optval = bEnable ? -1 : 0;
if ( SOCKET_ERROR == setsockopt ( so, SOL_SOCKET, SO_BROADCAST, (const char*)&optval, sizeof(optval) ) )
return false;
return true;
}
//// suErrDesc ////////////////////////////////////////////////
// returns text description of error code
const char* suErrDesc ( int err )
{
static char errbuf[256];
#ifdef WIN32
switch ( err )
{
#define X(E) case E: return #E;
X(WSAEINTR) X(WSAEBADF)
X(WSAEACCES) X(WSAEFAULT)
X(WSAEINVAL) X(WSAEMFILE)
X(WSAEWOULDBLOCK) X(WSAEINPROGRESS)
X(WSAEALREADY) X(WSAENOTSOCK)
X(WSAEDESTADDRREQ) X(WSAEMSGSIZE)
X(WSAEPROTOTYPE) X(WSAENOPROTOOPT)
X(WSAEPROTONOSUPPORT) X(WSAESOCKTNOSUPPORT)
X(WSAEOPNOTSUPP) X(WSAEPFNOSUPPORT)
X(WSAEAFNOSUPPORT) X(WSAEADDRINUSE)
X(WSAEADDRNOTAVAIL) X(WSAENETDOWN)
X(WSAENETUNREACH) X(WSAENETRESET)
X(WSAECONNABORTED) X(WSAECONNRESET)
X(WSAENOBUFS) X(WSAEISCONN)
X(WSAENOTCONN) X(WSAESHUTDOWN)
X(WSAETOOMANYREFS) X(WSAETIMEDOUT)
X(WSAECONNREFUSED) X(WSAELOOP)
X(WSAENAMETOOLONG) X(WSAEHOSTDOWN)
X(WSAEHOSTUNREACH) X(WSAENOTEMPTY)
X(WSAEPROCLIM) X(WSAEUSERS)
X(WSAEDQUOT) X(WSAESTALE)
X(WSAEREMOTE) X(WSASYSNOTREADY)
X(WSAVERNOTSUPPORTED) X(WSANOTINITIALISED)
X(WSAEDISCON) X(WSAENOMORE)
X(WSAECANCELLED) X(WSAEINVALIDPROCTABLE)
X(WSAEINVALIDPROVIDER) X(WSAEPROVIDERFAILEDINIT)
X(WSASYSCALLFAILURE) X(WSASERVICE_NOT_FOUND)
X(WSATYPE_NOT_FOUND) X(WSA_E_NO_MORE)
X(WSA_E_CANCELLED) X(WSAEREFUSED)
#undef X
}
snprintf ( errbuf, sizeof(errbuf), "Unknown socket error (%lu)", err );
errbuf[sizeof(errbuf)-1] = '\0';
return errbuf;
#elif defined(UNIX)
perror(errbuf);
return errbuf;
#else
# error unrecognized target
#endif
}
#if defined(UNICODE) || defined(_UNICODE)
in_addr_t suLookupAddress ( const wchar_t* pcHost )
{
int len = wcslen(pcHost);
char* p = new char[len+1];
wcstombs ( p, pcHost, len );
p[len] = 0;
in_addr_t rc = suLookupAddress ( p );
delete[] p;
return rc;
}
bool suBroadcast ( SOCKET so, u_short port, const wchar_t* buf, int len /* = -1 */ )
{
char* p = new char[len+1];
wcstombs ( p, buf, len );
p[len] = 0;
bool rc = suBroadcast ( so, port, p, len );
delete[] p;
return rc;
}
int suRecv ( SOCKET so, wchar_t* buf, int buflen, int timeout )
{
char* p = new char[buflen+1];
int rc = suRecv ( so, p, buflen, timeout );
p[buflen] = 0;
mbstowcs ( buf, p, buflen );
delete[] p;
return rc;
}
int suRecvFrom ( SOCKET so, wchar_t* buf, int buflen, int timeout, sockaddr_in* from, int* fromlen )
{
char* p = new char[buflen+1];
int rc = suRecvFrom ( so, p, buflen, timeout, from, fromlen );
p[buflen] = 0;
mbs2wcs ( buf, p, buflen );
delete[] p;
return rc;
}
bool suBind ( SOCKET so, const wchar_t* szInterfaceAddress, u_short iListenPort, bool bReuseAddr /* = false */ )
{
int len = wcslen(szInterfaceAddress);
char* p = new char[len+1];
wcstombs ( p, szInterfaceAddress, len );
p[len] = 0;
bool rc = suBind ( so, p, iListenPort, bReuseAddr );
delete[] p;
return rc;
}
#endif//UNICODE
suBufferedRecvSocket::suBufferedRecvSocket ( SOCKET so )
: suSocket ( so ), _off(0), _len(0)
{
}
int suBufferedRecvSocket::recvUntil ( std::string& buf, char until, int timeout )
{
if ( !_len )
_off = 0;
else if ( _off > (sizeof(_buf)>>1) )
{
memmove ( _buf, &_buf[_off], _len );
_off = 0;
}
char* poff = &_buf[_off];
for ( ;; )
{
char* p = (char*)memchr ( poff, until, _len );
if ( p /*&& p < &poff[_len]*/ )
{
int ret_len = p-poff+1;
buf.resize ( ret_len );
memmove ( &buf[0], poff, ret_len );
_off += ret_len;
_len -= ret_len;
return ret_len;
}
int rc = suRecv ( *this, &poff[_len], sizeof(_buf)-_len-_off, timeout );
if ( rc < 0 )
{
if ( _len )
{
rc = _len;
buf.resize ( rc );
memmove ( &buf[0], &_buf[_off], rc );
_len = 0;
}
return rc;
}
_len += rc;
}
}
void suBufferedRecvSocket::recvPending()
{
if ( !_len )
_off = 0;
else if ( _off > (sizeof(_buf)>>1) )
{
memmove ( _buf, &_buf[_off], _len );
_off = 0;
}
char* poff = &_buf[_off];
while ( sizeof(_buf)-_len-_off )
{
int rc = suRecv ( *this, &poff[_len], sizeof(_buf)-_len-_off, 1 );
if ( rc <= 0 )
break;
_len += rc;
}
}
bool suBufferedRecvSocket::recvInStr ( char c )
{
return NULL != memchr ( &_buf[_off], c, _len );
}

View File

@@ -0,0 +1,132 @@
// SockUtils.h - Declarations for the Winsock utility functions module.
// (C) 2002-2004 Royce Mitchell III
// This file is under the BSD & LGPL licenses
#ifndef __SOCKUTILS_H
#define __SOCKUTILS_H
#include <string>
#ifdef WIN32
# include <winsock2.h>
# define in_addr_t u_long
# define SUERRNO WSAGetLastError()
# define EADDRINUSE WSAEADDRINUSE
# define ENOTSOCK WSAENOTSOCK
# define socklen_t int
#elif defined(UNIX)
# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <unistd.h>
# include <errno.h>
# define closesocket(so) close(so)
# define SOCKET int
# define INVALID_SOCKET -1
# define SOCKET_ERROR -1
# define SUERRNO errno
# ifdef MACOSX
# define socklen_t int //Stupid mac
# endif
#else
# error unrecognized target
#endif
#include <assert.h>
extern bool suStartup();
extern SOCKET suTcpSocket();
extern SOCKET suUdpSocket();
extern bool suShutdownConnection(SOCKET sd);
extern in_addr_t suLookupAddress ( const char* pcHost );
extern bool suConnect ( SOCKET so, in_addr_t iAddress, u_short iPort );
extern bool suConnect ( SOCKET so, const char* szAddress, u_short iPort );
extern SOCKET suEstablishConnection ( in_addr_t iAddress, u_short iPort, int type );
extern SOCKET suEstablishConnection ( const char* szAddress, u_short iPort, int type );
extern bool suBroadcast ( SOCKET so, u_short port, const char* buf, int len = -1 );
extern int suRecv ( SOCKET so, char* buf, int buflen, int timeout );
extern int suRecvFrom ( SOCKET so, char* buf, int buflen, int timeout, sockaddr_in* from, socklen_t* fromlen );
extern bool suBind ( SOCKET so, in_addr_t iInterfaceAddress, u_short iListenPort, bool bReuseAddr = false );
extern bool suBind ( SOCKET so, const char* szInterfaceAddress, u_short iListenPort, bool bReuseAddr = false );
extern bool suEnableBroadcast ( SOCKET so, bool bEnable = true );
extern const char* suErrDesc ( int err );
#if defined(UNICODE) || defined(_UNICODE)
extern in_addr_t suLookupAddress ( const wchar_t* pcHost );
extern bool suBroadcast ( SOCKET so, u_short port, const wchar_t* buf, int len = -1 );
extern int suRecv ( SOCKET so, wchar_t* buf, int buflen, int timeout );
extern int suRecvFrom ( SOCKET so, wchar_t* buf, int buflen, int timeout, sockaddr_in* from, int* fromlen );
extern bool suBind ( SOCKET so, const wchar_t* szInterfaceAddress, u_short iListenPort, bool bReuseAddr = false );
#endif//UNICODE
class suSocket
{
SOCKET _so;
public:
suSocket ( SOCKET so = INVALID_SOCKET ) : _so(so)
{
}
const suSocket& operator = ( SOCKET so )
{
assert ( _so == INVALID_SOCKET ); // must Detach() or Close() existing socket first
_so = so;
return *this;
}
virtual ~suSocket()
{
Close();
}
void Close()
{
if ( _so != INVALID_SOCKET )
{
//suShutdownConnection ( _so ); // TODO - only valid on TCP sockets
closesocket ( _so );
_so = INVALID_SOCKET;
}
}
operator SOCKET() const
{
return _so;
}
SOCKET Attach ( SOCKET so )
{
SOCKET old = Detach();
_so = so;
return old;
}
SOCKET Detach()
{
SOCKET so = _so;
_so = INVALID_SOCKET;
return so;
}
private:
// disable copy semantics
suSocket ( const suSocket& );
const suSocket& operator = ( const suSocket& );
};
class suBufferedRecvSocket : public suSocket
{
char _buf[2048];
int _off;
int _len;
public:
suBufferedRecvSocket ( SOCKET so = INVALID_SOCKET );
int recvUntil ( std::string& buf, char until, int timeout );
void recvPending();
bool recvInStr ( char c );
};
class SockAddrIn : public sockaddr_in
{
public:
SockAddrIn(); // creates broadcast address
SockAddrIn ( const char* szAddr, u_short iPort );
SockAddrIn ( in_addr_t iAddr, u_short iPort );
operator sockaddr* () { return (sockaddr*)this; }
operator sockaddr_in* () { return (sockaddr_in*)this; }
};
#endif//__SOCKUTILS_H

View File

@@ -0,0 +1,96 @@
// SplitJoin.cpp
//
// This code is copyright 2003-2004 Royce Mitchell III
// and released under the BSD & LGPL licenses
#ifdef _MSC_VER
#pragma warning ( disable : 4786 ) // MSVC6 can't handle too-long template names
#endif//_MSC_VER
//#include <sstream>
#include "SplitJoin.h"
#include <string.h>
using std::string;
using std::vector;
//using std::stringstream;
static const char* quotes = "\"\'";
bool Split ( vector<string>& vec, const char* csv, char sep, bool merge )
{
string scsv ( csv );
char* col = &scsv[0];
vec.resize ( 0 );
for ( ;; )
{
char* p = col;
while ( isspace(*p) && *p != sep )
p++;
char quote = 0;
if ( strchr ( quotes, *p ) )
quote = *p++;
while ( *p && (*p != sep || quote) )
{
if ( *p++ == quote )
break;
}
while ( isspace(*p) && *p != sep )
p++;
if ( *p && *p != sep )
return false;
string scol ( col, p-col );
//quote = scol[0];
if ( quote )
{
if ( scol[scol.size()-1] == quote )
scol = string ( &scol[1], scol.size()-2 );
}
if ( scol.length() || !merge )
vec.push_back ( scol );
if ( !*p )
break;
col = p + 1;
}
return true;
}
bool Join ( string& csv, vector<string>& vec, char sep )
{
csv.resize(0);
for ( int i = 0; i < vec.size(); i++ )
{
if ( i )
csv += sep;
string& s = vec[i];
if ( strchr ( s.c_str(), sep ) )
{
if ( strchr ( s.c_str(), '\"' ) )
{
if ( strchr ( s.c_str(), '\'' ) )
return false; // the sep, " and ' are all in the string, can't build valid output
csv += '\'';
csv += s;
csv += '\'';
}
else
{
csv += '\"';
csv += s;
csv += '\"';
}
}
else
csv += s;
}
return true;
}

View File

@@ -0,0 +1,32 @@
// SplitJoin.h
//
// This code is copyright 2003-2004 Royce Mitchell III
// and released under the BSD & LGPL licenses
#ifndef SPLITJOIN_H
#define SPLITJOIN_H
#include <vector>
#include <string>
bool Split (
std::vector<std::string>& vec,
const char* csv,
char sep=',',
bool merge=false );
bool Join (
std::string& csv,
std::vector<std::string>& vec,
char sep=',' );
inline bool Split (
std::vector<std::string>& vec,
const std::string& csv,
char sep=',',
bool merge=false )
{
return Split ( vec, csv.c_str(), sep, merge );
}
#endif//SPLIT_H

View File

@@ -0,0 +1,240 @@
// ThreadPool.cpp
// This file is (C) 2003-2004 Royce Mitchell III
// and released under the LGPL & BSD licenses
#include <vector>
using std::vector;
#include "ThreadPool.h"
#include "QueueT.h"
#include "auto_vector.h"
#include "verify.h"
#include "ReliMT.h"
class PoolableThread : public ActiveObject
{
public:
PoolableThread ( ThreadPoolImpl& );
~PoolableThread()
{
Kill();
}
void InitThread();
void Run();
void FlushThread();
ThreadPoolImpl& _pool;
};
class ThreadPoolLaunchData
{
public:
ThreadPoolFunc* pFun;
void* pArg;
};
template <class T>
class AtomicCounter : public Uncopyable
{
Mutex _m;
T _t;
public:
AtomicCounter ( T init = 0 ) : _t(init)
{
}
AtomicCounter ( const AtomicCounter<T>& t )
{
//Mutex::Lock l ( _m ); // don't need to lock since this is a ctor
Mutex::Lock l2 ( t._m );
_t = t._t;
}
const AtomicCounter<T>& operator = ( const AtomicCounter<T>& t )
{
Mutex::Lock l ( _m );
Mutex::Lock l2 ( t._m );
_t = t._t;
return *this;
}
T operator ++ ()
{
Mutex::Lock l ( _m );
T t = _t++;
return t;
}
const AtomicCounter<T>& operator ++ ( int )
{
Mutex::Lock l ( _m );
++_t;
return *this;
}
T operator -- ()
{
Mutex::Lock l ( _m );
T t = _t--;
return t;
}
const AtomicCounter<T>& operator -- ( int )
{
Mutex::Lock l ( _m );
--_t;
return *this;
}
const AtomicCounter<T>& operator += ( T t )
{
Mutex::Lock l ( _m );
return _t += t;
return *this;
}
const AtomicCounter<T>& operator -= ( T t )
{
Mutex::Lock l ( _m );
return _t -= t;
return *this;
}
operator const T& () const
{
//Mutex::Lock l ( _m );
return _t;
}
T operator !() const
{
//Mutex::Lock l ( _m );
return !_t;
}
};
class ThreadPoolImpl : public Uncopyable
{
public:
ThreadPoolImpl() : _isDying(false), _idleThreads(0)
{
}
~ThreadPoolImpl()
{
}
void Shutdown()
{
_isDying = true;
while ( _idleThreads )
{
_threadWaitEvent.Release();
_threadStartEvent.Wait(); // let thread actually get a grip
}
}
void Launch ( ThreadPoolFunc* pFun, void* pArg )
{
// this mutex is necessary to make sure we never have a conflict
// between checking !_idleThreads and the call to _threadStartEvent.Wait()
// basically if 2 threads call Launch() simultaneously, and there is only
// 1 idle thread, it's possible that a new thread won't be created to
// satisfy the 2nd request until an existing thread finishes.
Mutex::Lock launchlock ( _launchMutex );
ASSERT ( pFun );
ThreadPoolLaunchData* data;
{
Mutex::Lock lock ( _vectorMutex );
if ( !_spareData.size() )
_spareData.push_back ( new ThreadPoolLaunchData() );
data = _spareData.pop_back().release();
if ( !_idleThreads )
_threads.push_back ( new PoolableThread(*this) );
}
data->pFun = pFun;
data->pArg = pArg;
verify ( _pendingData.Add ( data ) );
_threadWaitEvent.Release(); // tell a thread to do it's thing...
_threadStartEvent.Wait(); // wait on a thread to pick up the request
}
// functions for threads to call...
ThreadPoolLaunchData* GetPendingData()
{
ThreadPoolLaunchData* data = NULL;
++_idleThreads;
_threadWaitEvent.Wait(); // waits until there's a request
--_idleThreads;
_threadStartEvent.Release(); // tell requester we got it
if ( _isDying )
return NULL;
_pendingData.Get ( data );
ASSERT ( data );
return data;
}
void RecycleData ( ThreadPoolLaunchData* data )
{
Mutex::Lock lock ( _vectorMutex );
_spareData.push_back ( data );
}
bool _isDying;
Mutex _vectorMutex, _launchMutex;
auto_vector<PoolableThread> _threads;
auto_vector<ThreadPoolLaunchData> _spareData;
CQueueT<ThreadPoolLaunchData*> _pendingData;
Event _threadWaitEvent, _threadStartEvent;
AtomicCounter<int> _idleThreads;
};
///////////////////////////////////////////////////////////////////////////////
// ThreadPool
/*static*/ ThreadPool& ThreadPool::Instance()
{
static ThreadPool tp;
return tp;
}
ThreadPool::ThreadPool() : _pimpl ( new ThreadPoolImpl )
{
};
ThreadPool::~ThreadPool()
{
_pimpl->Shutdown();
delete _pimpl;
_pimpl = 0;
}
void ThreadPool::Launch ( ThreadPoolFunc* pFun, void* pArg )
{
_pimpl->Launch ( pFun, pArg );
}
int ThreadPool::IdleThreads()
{
return _pimpl->_idleThreads;
}
///////////////////////////////////////////////////////////////////////////////
// PoolableThread
PoolableThread::PoolableThread ( ThreadPoolImpl& pool ) : _pool(pool)
{
Start();
}
void PoolableThread::InitThread()
{
}
void PoolableThread::Run()
{
ThreadPoolLaunchData* data;
while ( !_isDying )
{
data = _pool.GetPendingData(); // enter wait state if none...
if ( !data ) // NULL data means kill thread
break;
(*data->pFun) ( data->pArg ); // call the function
_pool.RecycleData ( data );
}
}
void PoolableThread::FlushThread()
{
}

View File

@@ -0,0 +1,28 @@
// ThreadPool.h
// This file is (C) 2003-2004 Royce Mitchell III
// and released under the LGPL & BSD licenses
#ifndef THREADPOOL_H
#define THREADPOOL_H
#include "ReliMT.h"
typedef void THREADAPI ThreadPoolFunc ( void* );
class ThreadPoolImpl;
class ThreadPool : public Uncopyable
{
public:
static ThreadPool& Instance();
~ThreadPool();
void Launch ( ThreadPoolFunc* pFun, void* pArg );
int IdleThreads();
private:
ThreadPool();
ThreadPoolImpl *_pimpl;
};
#endif// THREADPOOL_H

View File

@@ -0,0 +1,87 @@
// auto_ptr.h
// This file is (C) 2002-2003 Royce Mitchell III
// and released under the LGPL & BSD licenses
#ifndef AUTO_PTR_H
#define AUTO_PTR_H
template<class T>
class auto_ptr
{
public:
typedef T element_type;
explicit auto_ptr(T *p = 0) : _p(p)
{
}
auto_ptr(auto_ptr<T>& rhs) : _p(rhs.release())
{
}
auto_ptr<T>& operator=(auto_ptr<T>& rhs)
{
if ( &rhs != this )
{
dispose();
_p = rhs.release();
}
return *this;
}
auto_ptr<T>& set ( auto_ptr<T>& rhs )
{
if ( &rhs != this )
{
dispose();
_p = rhs.release();
}
return *this;
}
~auto_ptr()
{
dispose();
}
void dispose()
{
if ( _p )
{
delete _p;
_p = 0;
}
}
T& operator[] ( int i )
{
return _p[i];
}
T& operator*() const
{
return *_p;
}
T* operator->() const
{
return _p;
}
T* get() const
{
return _p;
}
T* release()
{
T* p = _p;
_p = 0;
return p;
}
private:
T* _p;
};
#endif//AUTO_PTR_H

View File

@@ -0,0 +1,141 @@
// auto_vector.h
// This file is (C) 2002-2004 Royce Mitchell III
// and released under the LGPL & BSD licenses
#ifndef AUTO_VECTOR_H
#define AUTO_VECTOR_H
#include <sys/types.h>
#include "verify.h"
#include "auto_ptr.h"
template<class T>
class auto_vector
{
public:
explicit auto_vector ( size_t capacity = 0 )
: _arr(0), _capacity(0), _end(0)
{
if ( capacity != 0 )
_arr = new auto_ptr<T>[capacity];
_capacity = capacity;
}
~auto_vector()
{
delete []_arr;
}
size_t size() const
{
return _end;
}
const auto_ptr<T>& operator [] ( size_t i ) const
{
ASSERT ( i < _end );
return _arr[i];
}
auto_ptr<T>& operator [] ( size_t i )
{
ASSERT ( i < _end );
return _arr[i];
}
void assign ( size_t i, auto_ptr<T>& p )
{
ASSERT ( i < _end );
_arr[i] = p;
}
void assign_direct ( size_t i, T * p )
{
ASSERT ( i < _end );
reserve ( i + 1 );
_arr[i].reset ( ptr );
}
void push_back ( auto_ptr<T>& p )
{
reserve ( _end + 1 );
_arr[_end++] = p;
}
auto_ptr<T>& back()
{
ASSERT ( _end != 0 );
return _arr[_end-1];
}
void push_back ( T * p )
{
reserve ( _end + 1 );
auto_ptr<T> tmp(p);
_arr[_end++] = tmp;
//GCC is pedantic, this is an error.
//_arr[_end++] = auto_ptr<T>(p);
}
auto_ptr<T> pop_back()
{
ASSERT ( _end != 0 );
if ( !_end )
{
auto_ptr<T> tmp((T*)0);
return tmp;
//GCC, this is an error.
//return auto_ptr<T>(NULL);
}
return _arr[--_end];
}
void resize ( size_t newSize )
{
ASSERT ( newSize >= 0 );
reserve ( newSize ); // make sure we have at least this much room
_end = newSize;
}
void reserve ( size_t reqCapacity )
{
if ( reqCapacity <= _capacity )
return;
size_t newCapacity = 2 * _capacity;
if ( reqCapacity > newCapacity )
newCapacity = reqCapacity;
// allocate new array
auto_ptr<T> * arrNew = new auto_ptr<T> [newCapacity];
// transfer all entries
for ( size_t i = 0; i < _capacity; ++i )
arrNew[i] = _arr[i];
_capacity = newCapacity;
// free old memory
delete[] _arr;
// substitute new array for old array
_arr = arrNew;
}
void remove ( size_t off )
{
size_t last = _end-1;
if ( off == last )
resize ( last );
else if ( off < last )
{
auto_ptr<T> tmp ( pop_back().release() );
_arr[off] = tmp;
}
}
//typedef const_auto_iterator<T> const_iterator;
//const_iterator begin () const { return _arr; }
//const_iterator end () const { return _arr + _end; }
private:
auto_ptr<T> *_arr;
size_t _capacity;
size_t _end;
};
#endif//AUTO_VECTOR_H

View File

@@ -0,0 +1,58 @@
// base64.cpp
#include "base64.h"
using std::string;
static const char* alfabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
string base64_encode ( const string& sInput )
{
unsigned char x=0, topbit=0;
int v=0;
string sOutput;
do
{
if ( topbit < 6 )
{
x++;
v <<= 8;
if ( x <= sInput.length() ) v += sInput[x-1];
topbit += 8;
}
topbit -= 6;
if ( x > sInput.length() && !v )
break;
sOutput += alfabet[(v >> topbit) & 63];
v &= (1 << topbit) - 1;
} while ( x < sInput.length() || v );
int eq = (8 - (sOutput.length() % 4)) % 4;
while ( eq-- )
sOutput += '=';
return sOutput;
}
string base64_decode ( const string& sInput )
{
unsigned char x=0, topbit=0;
int v=0, inlen = sInput.length();
string sOutput;
while ( inlen && sInput[inlen-1] == '=' )
inlen--;
do
{
while ( topbit < 8 )
{
x++;
v <<= 6;
if ( x <= inlen ) v += (strchr(alfabet, sInput[x-1]) - alfabet);
topbit += 6;
}
topbit -= 8;
if ( x > inlen && !v )
break;
sOutput += (char)((v >> topbit) & 255);
v &= ((1 << topbit) - 1);
} while ( x <= inlen || v );
return sOutput;
}

View File

@@ -0,0 +1,12 @@
// base64.h
#ifndef BASE64_H
#define BASE64_H
#include <string>
std::string base64_encode ( const std::string& s );
std::string base64_decode ( const std::string& s );
#endif//BASE64_H

View File

@@ -0,0 +1,15 @@
// chomp.cpp
// This file is (C) 2004 Royce Mitchell III
// and released under the BSD & LGPL licenses
#include "chomp.h"
std::string chomp ( const std::string& s )
{
const char* p = &s[0];
const char* p2 = &s[0] + s.size();
while ( p2 > p && strchr("\r\n", p2[-1]) )
p2--;
return std::string ( p, p2-p );
}

13
irc/ArchBlackmann/chomp.h Normal file
View File

@@ -0,0 +1,13 @@
// chomp.h
// This file is (C) 2004 Royce Mitchell III
// and released under the BSD & LGPL licenses
#ifndef CHOMP_H
#define CHOMP_H
#include <string>
std::string chomp ( const std::string& s );
#endif//TRIM_H

View File

@@ -0,0 +1,23 @@
// cram_md5.cpp
// This file is (C) 2004 Royce Mitchell III
// and released under the BSD & LGPL licenses
#include "md5.h"
#include "cram_md5.h"
#include "base64.h"
using std::string;
string cram_md5 ( const string& username, const string& password, const string& greeting )
{
string challenge = base64_decode ( greeting );
string hmac = HMAC_MD5 ( password, challenge );
//printf ( "(cram_md5): hmac = %s\n", hmac.c_str() );
string raw_response = username;
raw_response += " ";
raw_response += hmac;
//printf ( "(cram_md5): raw_response = %s\n", raw_response.c_str() );
return base64_encode ( raw_response );
}

View File

@@ -0,0 +1,15 @@
// cram_md5.h
// This file is (C) 2004 Royce Mitchell III
// and released under the BSD & LGPL licenses
#ifndef CRAM_MD5_H
#define CRAM_MD5_H
#include <string>
std::string cram_md5 (
const std::string& username,
const std::string& password,
const std::string& greeting );
#endif//CRAM_MD5_H

View File

@@ -0,0 +1,26 @@
shit
fuck
pussy
ass
ass-
-ass
dumbass
jackass
fatass
asshole
smartass
cunt
fucker
bitch
dick
penile
stfu
omfg
lmao
ass.
-ass.
semprini
goat.cx
ekush
akshor
poop

View File

@@ -0,0 +1,10 @@
You should have your mouth washed out with soap!
This is a clean channel... please watch your language
Please try to keep it clean
Hey, there's children present ( I'm not even a year old yet! )
Could you find a less-offensive way to express yourself, please?
Such language :(
Those aren't nice words to use
Oh, my poor innocent ears :(
Help! My mind is being corrupted!
filthy mouths are not appreciated here

15
irc/ArchBlackmann/dev.txt Normal file
View File

@@ -0,0 +1,15 @@
Royce3
kjk_hyperion
tamlin
GvG
filip2307
hardon
w3seek
arty
sedwards
Exception
blight_
jimtabor
mtempel
Gge
Alex_Ionescu

581
irc/ArchBlackmann/func.txt Normal file
View File

@@ -0,0 +1,581 @@
BOOLEAN
CcCanIWrite
CcCopyRead
CcCopyWrite
CcDeferWrite
CcFastCopyRead
CcFastCopyWrite
CcFlushCache
CcGetDirtyPages
CcGetFileObjectFromBcb
CcGetFileObjectFromSectionPtrs
CcGetFlushedValidData
CcGetLsnForFileObject
CcInitializeCacheMap
CcIsThereDirtyData
CcMapData
CcMdlRead
CcMdlReadComplete
CcMdlWriteAbort
CcMdlWriteComplete
CcPinMappedData
CcPinRead
CcPrepareMdlWrite
CcPreparePinWrite
CcPurgeCacheSection
CcRemapBcb
CcRepinBcb
CcScheduleReadAhead
CcSetAdditionalCacheAttributes
CcSetBcbOwnerPointer
CcSetDirtyPageThreshold
CcSetDirtyPinnedData
CcSetFileSizes
CcSetLogHandleForFile
CcSetReadAheadGranularity
CcUninitializeCacheMap
CcUnpinData
CcUnpinDataForThread
CcUnpinRepinnedBcb
CcWaitForCurrentLazyWriterActivity
CcZeroData
DbgLoadImageSymbols
DbgQueryDebugFilterState
DbgSetDebugFilterState
EVENT_TYPE
ExAcquireResourceExclusive
ExAcquireResourceExclusiveLite
ExAcquireResourceSharedLite
ExAcquireSharedStarveExclusive
ExAcquireSharedWaitForExclusive
ExAllocateFromZone
ExAllocatePool
ExAllocatePoolWithQuota
ExAllocatePoolWithQuotaTag
ExAllocatePoolWithTag
ExConvertExclusiveToSharedLite
ExCreateCallback
ExDeleteNPagedLookasideList
ExDeletePagedLookasideList
ExDeleteResource
ExDeleteResourceLite
ExDisableResourceBoostLite
ExEnumHandleTable
ExExtendZone
ExFreePool
ExGetCurrentProcessorCounts
ExGetCurrentProcessorCpuUsage
ExGetExclusiveWaiterCount
ExGetPreviousMode
ExGetSharedWaiterCount
ExInitializeNPagedLookasideList
ExInitializePagedLookasideList
ExInitializeResource
ExInitializeResourceLite
ExInitializeZone
ExInterlockedAddLargeInteger
ExInterlockedAddUlong
ExInterlockedDecrementLong
ExInterlockedExchangeUlong
ExInterlockedExtendZone
ExInterlockedIncrementLong
ExInterlockedInsertHeadList
ExInterlockedInsertTailList
ExInterlockedPopEntryList
ExInterlockedPushEntryList
ExInterlockedRemoveHeadList
ExIsProcessorFeaturePresent
ExIsResourceAcquiredExclusiveLite
ExIsResourceAcquiredSharedLite
ExLocalTimeToSystemTime
ExNotifyCallback
ExPostSystemEvent
ExQueryPoolBlockSize
ExQueueWorkItem
ExRaiseAccessViolation
ExRaiseDatatypeMisalignment
ExRaiseException
ExRaiseHardError
ExRaiseStatus
ExRegisterCallback
ExReinitializeResourceLite
ExReleaseResource
ExReleaseResourceForThread
ExReleaseResourceForThreadLite
ExRosDumpPagedPoolByTag
ExRosQueryPoolTag
ExSetResourceOwnerPointer
ExSetTimerResolution
ExSystemExceptionFilter
ExSystemTimeToLocalTime
ExTryToAcquireResourceExclusiveLite
ExUnregisterCallback
ExUuidCreate
ExVerifySuite
FsRtlAcquireFileExclusive
FsRtlAddMcbEntry
FsRtlAddToTunnelCache
FsRtlAllocateFileLock
FsRtlAllocatePool
FsRtlAllocatePoolWithQuota
FsRtlAllocatePoolWithQuotaTag
FsRtlAllocatePoolWithTag
FsRtlAllocateResource
FsRtlAreNamesEqual
FsRtlBalanceReads
FsRtlCheckLockForReadAccess
FsRtlCheckLockForWriteAccess
FsRtlCopyRead
FsRtlCopyWrite
FsRtlFastCheckLockForRead
FsRtlFastCheckLockForWrite
FsRtlFastUnlockAll
FsRtlFastUnlockAllByKey
FsRtlFastUnlockSingle
FsRtlFindInTunnelCache
FsRtlFreeFileLock
FsRtlGetFileSize
FsRtlGetNextFileLock
FsRtlGetNextMcbEntry
FsRtlIncrementCcFastReadNoWait
FsRtlIncrementCcFastReadNotPossible
FsRtlIncrementCcFastReadResourceMiss
FsRtlIncrementCcFastReadWait
FsRtlInitializeFileLock
FsRtlInitializeMcb
FsRtlInitializeTunnelCache
FsRtlInsertPerFileObjectContext
FsRtlInsertPerStreamContext
FsRtlIsDbcsInExpression
FsRtlIsFatDbcsLegal
FsRtlIsHpfsDbcsLegal
FsRtlIsNameInExpression
FsRtlLookupLastLargeMcbEntryAndIndex
FsRtlLookupLastMcbEntry
FsRtlLookupMcbEntry
FsRtlLookupPerFileObjectContext
FsRtlLookupPerStreamContextInternal
FsRtlMdlRead
FsRtlMdlReadComplete
FsRtlMdlReadCompleteDev
FsRtlMdlReadDev
FsRtlMdlWriteComplete
FsRtlMdlWriteCompleteDev
FsRtlNotifyChangeDirectory
FsRtlNotifyCleanup
FsRtlNotifyFilterChangeDirectory
FsRtlNotifyFilterReportChange
FsRtlNotifyFullChangeDirectory
FsRtlNotifyFullReportChange
FsRtlNotifyReportChange
FsRtlNotifyUninitializeSync
FsRtlNumberOfRunsInMcb
FsRtlPostPagingFileStackOverflow
FsRtlPostStackOverflow
FsRtlPrepareMdlWrite
FsRtlPrepareMdlWriteDev
FsRtlPrivateLock
FsRtlProcessFileLock
FsRtlRegisterFileSystemFilterCallbacks
FsRtlReleaseFile
FsRtlRemoveMcbEntry
FsRtlRemovePerFileObjectContext
FsRtlRemovePerStreamContext
FsRtlResetLargeMcb
FsRtlSyncVolumes
FsRtlTeardownPerStreamContexts
FsRtlTruncateMcb
FsRtlUninitializeFileLock
FsRtlUninitializeMcb
HalAdjustResourceList
HalAllocateCommonBuffer
HalAssignSlotResources
HalCalibratePerformanceCounter
HalFlushCommonBuffer
HalFreeCommonBuffer
HalGetAdapter
HalGetBusData
HalGetBusDataByOffset
HalGetDmaAlignmentRequirement
HalMakeBeep
HalQueryDisplayParameters
HalQueryRealTimeClock
HalReadDmaCounter
HalRequestIpi
HalSetBusData
HalSetBusDataByOffset
HalSetDisplayParameters
HalSetRealTimeClock
HalStartNextProcessor
IoAcquireCancelSpinLock
IoAcquireRemoveLockEx
IoAcquireVpbSpinLock
IoAllocateAdapterChannel
IoAllocateController
IoAllocateDriverObjectExtension
IoAllocateErrorLogEntry
IoAllocateIrp
IoAllocateMdl
IoAllocateWorkItem
IoAssignResources
IoAttachDevice
IoAttachDeviceByPointer
IoAttachDeviceToDeviceStack
IoAttachDeviceToDeviceStackSafe
IoBuildAsynchronousFsdRequest
IoBuildDeviceIoControlRequest
IoBuildPartialMdl
IoBuildSynchronousFsdRequest
IoCallDriver
IoCancelFileOpen
IoCancelIrp
IoCheckQuerySetFileInformation
IoCheckQuerySetVolumeInformation
IoCheckQuotaBufferValidity
IoCheckShareAccess
IoCompleteRequest
IoConnectInterrupt
IoCreateController
IoCreateDevice
IoCreateDisk
IoCreateDriver
IoCreateFile
IoCreateFileSpecifyDeviceObjectHint
IoCreateNotificationEvent
IoCreateStreamFileObject
IoCreateStreamFileObjectEx
IoCreateStreamFileObjectLite
IoCreateSymbolicLink
IoCreateSynchronizationEvent
IoCreateUnprotectedSymbolicLink
IoDeleteController
IoDeleteDevice
IoDeleteDriver
IoDeleteSymbolicLink
IoDetachDevice
IoDisconnectInterrupt
IoEnqueueIrp
IoEnumerateDeviceObjectList
IoFlushAdapterBuffers
IoForwardIrpSynchronously
IoFreeAdapterChannel
IoFreeController
IoFreeErrorLogEntry
IoFreeIrp
IoFreeMapRegisters
IoFreeMdl
IoFreeWorkItem
IoGetAttachedDevice
IoGetAttachedDeviceReference
IoGetBaseFileSystemDeviceObject
IoGetBootDiskInformation
IoGetConfigurationInformation
IoGetCurrentProcess
IoGetDeviceAttachmentBaseRef
IoGetDeviceInterfaceAlias
IoGetDeviceInterfaces
IoGetDeviceObjectPointer
IoGetDeviceProperty
IoGetDeviceToVerify
IoGetDiskDeviceObject
IoGetDriverObjectExtension
IoGetFileObjectGenericMapping
IoGetInitialStack
IoGetLowerDeviceObject
IoGetRelatedDeviceObject
IoGetRequestorProcess
IoGetRequestorProcessId
IoGetRequestorSessionId
IoGetStackLimits
IoGetTopLevelIrp
IoInitializeIrp
IoInitializeRemoveLockEx
IoInitializeTimer
IoInvalidateDeviceRelations
IoInvalidateDeviceState
IoIsFileOriginRemote
IoIsOperationSynchronous
IoIsSystemThread
IoIsValidNameGraftingBuffer
IoMakeAssociatedIrp
IoMapTransfer
IoOpenDeviceInstanceKey
IoOpenDeviceInterfaceRegistryKey
IoOpenDeviceRegistryKey
IoPageRead
IoPnPDeliverServicePowerNotification
IoQueryDeviceDescription
IoQueryDeviceEnumInfo
IoQueryFileDosDeviceName
IoQueryFileInformation
IoQueryVolumeInformation
IoQueueThreadIrp
IoQueueWorkItem
IoRaiseHardError
IoRaiseInformationalHardError
IoReadDiskSignature
IoReadPartitionTableEx
IoRegisterBootDriverReinitialization
IoRegisterDeviceInterface
IoRegisterDriverReinitialization
IoRegisterFileSystem
IoRegisterFsRegistrationChange
IoRegisterLastChanceShutdownNotification
IoRegisterPlugPlayNotification
IoRegisterShutdownNotification
IoReleaseCancelSpinLock
IoReleaseRemoveLockAndWaitEx
IoReleaseRemoveLockEx
IoReleaseVpbSpinLock
IoRemoveShareAccess
IoReportDetectedDevice
IoReportHalResourceUsage
IoReportResourceForDetection
IoReportResourceUsage
IoReportTargetDeviceChange
IoReportTargetDeviceChangeAsynchronous
IoRequestDeviceEject
IoReuseIrp
IoSetCompletionRoutineEx
IoSetDeviceInterfaceState
IoSetDeviceToVerify
IoSetFileOrigin
IoSetHardErrorOrVerifyDevice
IoSetInformation
IoSetIoCompletion
IoSetPartitionInformationEx
IoSetShareAccess
IoSetStartIoAttributes
IoSetSystemPartition
IoSetThreadHardErrorMode
IoSetTopLevelIrp
IoStartNextPacket
IoStartNextPacketByKey
IoStartPacket
IoStartTimer
IoStopTimer
IoSynchronousInvalidateDeviceRelations
IoSynchronousPageWrite
IoUnregisterFileSystem
IoUnregisterFsRegistrationChange
IoUnregisterPlugPlayNotification
IoUnregisterShutdownNotification
IoUpdateShareAccess
IoValidateDeviceIoControlAccess
IoVerifyPartitionTable
IoVerifyVolume
IoVolumeDeviceToDosName
IoWMIAllocateInstanceIds
IoWMIDeviceObjectToInstanceName
IoWMIExecuteMethod
IoWMIHandleToInstanceName
IoWMIOpenBlock
IoWMIQueryAllData
IoWMIQueryAllDataMultiple
IoWMIQuerySingleInstance
IoWMIQuerySingleInstanceMultiple
IoWMIRegistrationControl
IoWMISetNotificationCallback
IoWMISetSingleInstance
IoWMISetSingleItem
IoWMISuggestInstanceName
IoWMIWriteEvent
IoWriteErrorLogEntry
IoWritePartitionTableEx
KPRIORITY
KdPortGetByte
KdPortPollByte
KdPortPutByte
Ke386QueryIoAccessMap
Ke386SetIoAccessMap
KeAcquireInterruptSpinLock
KeAreApcsDisabled
KeCapturePersistentThreadState
KeDeregisterBugCheckReasonCallback
KeFindConfigurationEntry
KeFindConfigurationNextEntry
KeFlushEntireTb
KeFlushQueuedDpcs
KeGetRecommendedSharedDataAlignment
KeIsExecutingDpc
KeQueryActiveProcessors
KeQueryPerformanceCounter
KeQueryPriorityThread
KeQueryRuntimeThread
KeQuerySystemTime
KeQueryTickCount
KeQueryTimeIncrement
KeRaiseIrql
KeRaiseIrqlToDpcLevel
KeRaiseUserException
KeReadStateEvent
KeRegisterBugCheckCallback
KeRegisterBugCheckReasonCallback
KeReleaseInterruptSpinLock
KeReleaseMutant
KeReleaseMutex
KeReleaseSemaphore
KeReleaseSpinLock
KeReleaseSpinLockFromDpcLevel
KeReleaseSpinLockFromDpcLevel
KeRemoveByKeyDeviceQueue
KeRemoveByKeyDeviceQueueIfBusy
KeRemoveDeviceQueue
KeRemoveEntryDeviceQueue
KeRemoveSystemServiceTable
KeRestoreFloatingPointState
KeRevertToUserAffinityThread
KeRosDumpStackFrames
KeRosGetStackFrames
KeRosPrintAddress
KeSaveFloatingPointState
KeSetDmaIoCoherency
KeSetEvent
KeSetEventBoostPriority
KeSetIdealProcessorThread
KeSetKernelStackSwapEnable
KeSetProfileIrql
KeSetSystemAffinityThread
KeSetTimeIncrement
KeTerminateThread
KeUserModeCallback
KeWaitForMutexObject
KeWaitForSingleObject
KiCoprocessorError
KiUnexpectedInterrupt
LONG
LdrFindResourceDirectory_U
MmAddPhysicalMemory
MmAddVerifierThunks
MmAdjustWorkingSetSize
MmAdvanceMdl
MmAllocateContiguousMemory
MmAllocateContiguousMemorySpecifyCache
MmAllocateMappingAddress
MmAllocateNonCachedMemory
MmBuildMdlForNonPagedPool
MmCanFileBeTruncated
MmCreateMdl
MmCreateSection
MmDbgTranslatePhysicalAddress
MmDisableModifiedWriteOfSection
MmFlushImageSection
MmForceSectionClosed
MmFreeContiguousMemory
MmFreeMappingAddress
MmFreeNonCachedMemory
MmGetPhysicalAddress
MmGetPhysicalMemoryRanges
MmGetSystemRoutineAddress
MmGetVirtualForPhysical
MmGrowKernelStack
MmIsAddressValid
MmIsDriverVerifying
MmIsNonPagedSystemAddressValid
MmIsRecursiveIoFault
MmIsThisAnNtAsSystem
MmIsVerifierEnabled
MmLockPagableDataSection
MmLockPagableImageSection
MmLockPagableSectionByHandle
MmMapIoSpace
MmMapLockedPages
MmMapLockedPagesWithReservedMapping
MmMapMemoryDumpMdl
MmMapUserAddressesToPage
MmMapVideoDisplay
MmMapViewInSessionSpace
MmMapViewInSystemSpace
MmMapViewOfSection
MmMarkPhysicalMemoryAsBad
MmMarkPhysicalMemoryAsGood
MmPageEntireDriver
MmPrefetchPages
MmProbeAndLockPages
MmProbeAndLockProcessPages
MmProbeAndLockSelectedPages
MmProtectMdlSystemAddress
MmQuerySystemSize
MmRemovePhysicalMemory
MmResetDriverPaging
MmSecureVirtualMemory
MmSetAddressRangeModified
MmSetBankedSection
MmSizeOfMdl
MmTrimAllSystemPagableMemory
MmUnlockPagableImageSection
MmUnlockPages
MmUnmapIoSpace
MmUnmapLockedPages
MmUnmapReservedMapping
MmUnmapVideoDisplay
MmUnmapViewInSessionSpace
MmUnmapViewInSystemSpace
MmUnmapViewOfSection
MmUnsecureVirtualMemory
OUT
ObCreateObject
PEJOB
PEPROCESS
PKBUGCHECK_CALLBACK_RECORD
PKDEVICE_QUEUE_ENTRY
PKIRQL
PULONG
PVOID
PW32_THREAD_CALLBACK
PoCallDriver
PoRegisterDeviceForIdleDetection
PoRegisterSystemState
PoRequestPowerIrp
PoSetDeviceBusy
PoSetPowerState
PoSetSystemState
PoStartNextPowerIrp
PoUnregisterSystemState
ProbeForRead
ProbeForWrite
PsAssignImpersonationToken
PsCreateSystemProcess
PsCreateSystemThread
PsGetCurrentProcessId
PsGetCurrentThreadId
PsImpersonateClient
PsReferenceImpersonationToken
PsReferencePrimaryToken
PsRevertThreadToSelf
PsRevertToSelf
PsTerminateSystemThread
READ_PORT_BUFFER_UCHAR
READ_PORT_BUFFER_ULONG
READ_PORT_BUFFER_USHORT
READ_PORT_UCHAR
READ_PORT_ULONG
READ_PORT_USHORT
SeAssignSecurityEx
SeAuditHardLinkCreation
SeAuditingFileEvents
SeAuditingFileEventsWithContext
SeAuditingFileOrGlobalEvents
SeAuditingHardLinkEvents
SeAuditingHardLinkEventsWithContext
SeCaptureSecurityDescriptor
SeCaptureSubjectContext
SeCloseObjectAuditAlarm
SeCreateAccessState
SeCreateClientSecurityFromSubjectContext
SeFilterToken
SeImpersonateClientEx
SePrivilegeObjectAuditAlarm
SeQueryInformationToken
SeQuerySessionIdToken
SeReleaseSecurityDescriptor
SeSetSecurityDescriptorInfoEx
SeTokenIsAdmin
SeTokenIsRestricted
SeTokenIsWriteRestricted
WRITE_PORT_BUFFER_UCHAR
WRITE_PORT_BUFFER_ULONG
WRITE_PORT_BUFFER_USHORT
WRITE_PORT_UCHAR
WRITE_PORT_ULONG
WRITE_PORT_USHORT

View File

@@ -0,0 +1,10 @@
/me bows humbly and begs %s's forgiveness
%s is soo cool... I hope to be like him some day
/me hides in a corner and hopes %s doesn't beat him with the whipping noodle again
/me prostrates at %s's feet and begs his majesty's forgiveness
%s: please don't hurt me!
I'm not worthy... I'm not worthy...
/me sings %s's praises to the world!
/me thinks %s is smarter than %dev%
%s: oh please may I defrag your sock drawer?
/me gives %s a cookie, hoping it will make up for breaking %func% the other day...

View File

@@ -0,0 +1,9 @@
PASSIVE_LEVEL
APC_LEVEL
DISPATCH_LEVEL
PROFILE_LEVEL
CLOCK1_LEVEL
IPI_LEVEL
POWER_LEVEL
HIGH_LEVEL
SYNCH_LEVEL

View File

@@ -0,0 +1,13 @@
the kernel
ntoskrnl
win32k
msafd
ws2_32
user32
shell32
the cache manager
tdi
the scheduler
the thread queue
the message queue
atapi

View File

@@ -0,0 +1,5 @@
/me slaps %s with a large trout
recycle(%s)
Did I hear something? Musta been a %s-fly... Where's that fly-swatter?
%s: go away son, you bother me....
/me beats %s with the whipping noodle

View File

@@ -0,0 +1,34 @@
// panic.cpp
// This file is (C) 2003-2004 Royce Mitchell III
// and released under the BSD & LGPL licenses
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#ifdef WIN32
#include <conio.h>
#include <windows.h>
#endif//WIN32
#include "panic.h"
void panic ( const char* format, ... )
{
va_list arg;
int done;
va_start(arg, format);
#if defined(WIN32) && !defined(_CONSOLE)
char buf[4096];
_vsnprintf ( buf, sizeof(buf)-1, format, arg );
MessageBox ( NULL, buf, "Panic!", MB_OK|MB_ICONEXCLAMATION );
#else
done = vprintf(format, arg);
printf ( "\n" );
#endif
va_end(arg);
#if defined(WIN32) && defined(_CONSOLE)
printf ( "Press any key to exit\n" );
(void)getch();
#endif//WIN32 && _CONSOLE
exit ( -1 );
}

18
irc/ArchBlackmann/panic.h Normal file
View File

@@ -0,0 +1,18 @@
// panic.h
// This file is (C) 2003-2004 Royce Mitchell III
// and released under the BSD & LGPL licenses
#ifndef PANIC_H
#define PANIC_H
void panic ( const char* format, ... );
#define suAssert(expr) if ( !(expr) ) panic ( "%s(%lu): SOCKET ERROR %s\nExpression: %s\n", __FILE__, __LINE__, suErrDesc(SUERRNO), #expr )
#if defined(DEBUG) || defined(_DEBUG)
# define suVerify(expr) suAssert(expr)
#else
# define suVerify(expr) expr
#endif
#endif//PANIC_H

View File

@@ -0,0 +1,11 @@
minute
hour
day
week
fortnight
month
year
decade
century
millenium
eon

View File

@@ -0,0 +1,998 @@
// ssprintf.cpp
#include <malloc.h>
#include <math.h>
#include <float.h>
#include <assert.h>
#include "ssprintf.h"
#ifdef _MSC_VER
#define alloca _alloca
#endif//_MSC_VER
typedef __int64 LONGLONG;
typedef unsigned __int64 ULONGLONG;
typedef struct {
unsigned int mantissa:23;
unsigned int exponent:8;
unsigned int sign:1;
} ieee_float_t;
typedef struct {
unsigned int mantissal:32;
unsigned int mantissah:20;
unsigned int exponent:11;
unsigned int sign:1;
} ieee_double_t;
typedef struct {
unsigned int mantissal:32;
unsigned int mantissah:32;
unsigned int exponent:15;
unsigned int sign:1;
unsigned int empty:16;
} ieee_long_double_t;
std::string ssprintf ( const char* fmt, ... )
{
va_list arg;
va_start(arg, fmt);
std::string f = ssvprintf ( fmt, arg );
va_end(arg);
return f;
}
#define ZEROPAD 1 /* pad with zero */
#define SIGN 2 /* unsigned/signed long */
#define PLUS 4 /* show plus */
#define SPACE 8 /* space if plus */
#define LEFT 16 /* left justified */
#define SPECIAL 32 /* 0x */
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
#define ZEROTRUNC 128 /* truncate zero 's */
static int skip_atoi(const char **s)
{
int i=0;
while (isdigit(**s))
i = i*10 + *((*s)++) - '0';
return i;
}
static int do_div(LONGLONG *n,int base)
{
int __res = ((ULONGLONG) *n) % (unsigned) base;
*n = ((ULONGLONG) *n) / (unsigned) base;
return __res;
}
static bool number(std::string& f, LONGLONG num, int base, int size, int precision ,int type)
{
char c,sign,tmp[66];
const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
int i;
if (type & LARGE)
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (type & LEFT)
type &= ~ZEROPAD;
if (base < 2 || base > 36)
return 0;
c = (type & ZEROPAD) ? '0' : ' ';
sign = 0;
if (type & SIGN) {
if (num < 0) {
sign = '-';
num = -num;
size--;
} else if (type & PLUS) {
sign = '+';
size--;
} else if (type & SPACE) {
sign = ' ';
size--;
}
}
if (type & SPECIAL) {
if (base == 16)
size -= 2;
else if (base == 8)
size--;
}
i = 0;
if (num == 0)
tmp[i++]='0';
else while (num != 0)
tmp[i++] = digits[do_div(&num,base)];
if (i > precision)
precision = i;
size -= precision;
if (!(type&(ZEROPAD+LEFT)))
while(size-->0)
f += ' ';
if (sign)
f += sign;
if (type & SPECIAL)
{
if (base==8)
f += '0';
else if (base==16)
{
f += '0';
f += digits[33];
}
}
if (!(type & LEFT))
{
while (size-- > 0)
f += c;
}
while (i < precision--)
{
f += '0';
}
while (i-- > 0)
{
f += tmp[i];
}
while (size-- > 0)
{
f += ' ';
}
return true;
}
static bool numberf(std::string& f, double __n, char exp_sign, int size, int precision, int type)
{
double exponent = 0.0;
double e;
long ie;
//int x;
char *buf, *tmp;
int i = 0;
int j = 0;
//int k = 0;
double frac, intr;
double p;
char sign;
char c;
char ro = 0;
int result;
union
{
double* __n;
ieee_double_t* n;
} n;
n.__n = &__n;
if ( exp_sign == 'g' || exp_sign == 'G' || exp_sign == 'e' || exp_sign == 'E' ) {
ie = ((unsigned int)n.n->exponent - (unsigned int)0x3ff);
exponent = ie/3.321928;
}
if ( exp_sign == 'g' || exp_sign == 'G' ) {
type |= ZEROTRUNC;
if ( exponent < -4 || fabs(exponent) >= precision )
exp_sign -= 2; // g -> e and G -> E
}
if ( exp_sign == 'e' || exp_sign == 'E' ) {
frac = modf(exponent,&e);
if ( frac > 0.5 )
e++;
else if ( frac < -0.5 )
e--;
result = numberf(f,__n/pow(10.0L,e),'f',size-4, precision, type);
if (result < 0)
return false;
f += exp_sign;
size--;
ie = (long)e;
type = LEFT | PLUS;
if ( ie < 0 )
type |= SIGN;
result = number(f,ie, 10,2, 2,type );
if (result < 0)
return false;
return true;
}
if ( exp_sign == 'f' ) {
buf = (char*)alloca(4096);
if (type & LEFT) {
type &= ~ZEROPAD;
}
c = (type & ZEROPAD) ? '0' : ' ';
sign = 0;
if (type & SIGN) {
if (__n < 0) {
sign = '-';
__n = fabs(__n);
size--;
} else if (type & PLUS) {
sign = '+';
size--;
} else if (type & SPACE) {
sign = ' ';
size--;
}
}
frac = modf(__n,&intr);
// # flags forces a . and prevents trucation of trailing zero's
if ( precision > 0 ) {
//frac = modfl(__n,&intr);
i = precision-1;
while ( i >= 0 ) {
frac*=10.0L;
frac = modf(frac, &p);
buf[i] = (int)p + '0';
i--;
}
i = precision;
size -= precision;
ro = 0;
if ( frac > 0.5 ) {
ro = 1;
}
if ( precision >= 1 || type & SPECIAL) {
buf[i++] = '.';
size--;
}
}
if ( intr == 0.0 ) {
buf[i++] = '0';
size--;
}
else {
while ( intr > 0.0 ) {
p = intr;
intr/=10.0L;
modf(intr, &intr);
p -= 10.0*intr;
buf[i++] = (int)p + '0';
size--;
}
}
j = 0;
while ( j < i && ro == 1) {
if ( buf[j] >= '0' && buf[j] <= '8' ) {
buf[j]++;
ro = 0;
}
else if ( buf[j] == '9' ) {
buf[j] = '0';
}
j++;
}
if ( ro == 1 )
buf[i++] = '1';
buf[i] = 0;
size -= precision;
if (!(type&(ZEROPAD+LEFT)))
{
while(size-->0)
f += ' ';
}
if (sign)
{
f += sign;
}
if (!(type&(ZEROPAD+LEFT)))
while(size-->0)
{
f += ' ';
}
if (type & SPECIAL) {
}
if (!(type & LEFT))
while (size-- > 0)
{
f += c;
}
tmp = buf;
if ( type & ZEROTRUNC && ((type & SPECIAL) != SPECIAL) )
{
j = 0;
while ( j < i && ( *tmp == '0' || *tmp == '.' ))
{
tmp++;
i--;
}
}
// else
// while (i < precision--)
// putc('0', f);
while (i-- > 0)
{
f += tmp[i];
}
while (size-- > 0)
{
f += ' ';
}
}
return true;
}
static bool numberfl(std::string& f, long double __n, char exp_sign, int size, int precision, int type)
{
long double exponent = 0.0;
long double e;
long ie;
//int x;
char *buf, *tmp;
int i = 0;
int j = 0;
//int k = 0;
long double frac, intr;
long double p;
char sign;
char c;
char ro = 0;
int result;
union
{
long double* __n;
ieee_long_double_t* n;
} n;
n.__n = &__n;
if ( exp_sign == 'g' || exp_sign == 'G' || exp_sign == 'e' || exp_sign == 'E' ) {
ie = ((unsigned int)n.n->exponent - (unsigned int)0x3fff);
exponent = ie/3.321928;
}
if ( exp_sign == 'g' || exp_sign == 'G' ) {
type |= ZEROTRUNC;
if ( exponent < -4 || fabs(exponent) >= precision )
exp_sign -= 2; // g -> e and G -> E
}
if ( exp_sign == 'e' || exp_sign == 'E' ) {
frac = modfl(exponent,&e);
if ( frac > 0.5 )
e++;
else if ( frac < -0.5 )
e--;
result = numberf(f,__n/powl(10.0L,e),'f',size-4, precision, type);
if (result < 0)
return false;
f += exp_sign;
size--;
ie = (long)e;
type = LEFT | PLUS;
if ( ie < 0 )
type |= SIGN;
result = number(f,ie, 10,2, 2,type );
if (result < 0)
return false;
return true;
}
if ( exp_sign == 'f' )
{
buf = (char*)alloca(4096);
if (type & LEFT)
{
type &= ~ZEROPAD;
}
c = (type & ZEROPAD) ? '0' : ' ';
sign = 0;
if (type & SIGN)
{
if (__n < 0)
{
sign = '-';
__n = fabs(__n);
size--;
} else if (type & PLUS)
{
sign = '+';
size--;
} else if (type & SPACE)
{
sign = ' ';
size--;
}
}
frac = modfl(__n,&intr);
// # flags forces a . and prevents trucation of trailing zero's
if ( precision > 0 )
{
//frac = modfl(__n,&intr);
i = precision-1;
while ( i >= 0 )
{
frac*=10.0L;
frac = modfl((long double)frac, &p);
buf[i] = (int)p + '0';
i--;
}
i = precision;
size -= precision;
ro = 0;
if ( frac > 0.5 )
{
ro = 1;
}
if ( precision >= 1 || type & SPECIAL)
{
buf[i++] = '.';
size--;
}
}
if ( intr == 0.0 )
{
buf[i++] = '0';
size--;
}
else
{
while ( intr > 0.0 )
{
p=intr;
intr/=10.0L;
modfl(intr, &intr);
p -= 10.0L*intr;
buf[i++] = (int)p + '0';
size--;
}
}
j = 0;
while ( j < i && ro == 1) {
if ( buf[j] >= '0' && buf[j] <= '8' )
{
buf[j]++;
ro = 0;
}
else if ( buf[j] == '9' )
{
buf[j] = '0';
}
j++;
}
if ( ro == 1 )
buf[i++] = '1';
buf[i] = 0;
size -= precision;
if (!(type&(ZEROPAD+LEFT)))
{
while(size-->0)
f += ' ';
}
if (sign)
{
f += sign;
}
if (!(type&(ZEROPAD+LEFT)))
{
while(size-->0)
f += ' ';
}
if (type & SPECIAL) {
}
if (!(type & LEFT))
while (size-- > 0)
{
f += c;
}
tmp = buf;
if ( type & ZEROTRUNC && ((type & SPECIAL) != SPECIAL) )
{
j = 0;
while ( j < i && ( *tmp == '0' || *tmp == '.' ))
{
tmp++;
i--;
}
}
// else
// while (i < precision--)
// putc( '0', f);
while (i-- > 0)
{
f += tmp[i];
}
while (size-- > 0)
{
f += ' ';
}
}
return true;
}
static int string(std::string& f, const char* s, int len, int field_width, int precision, int flags)
{
int i, done = 0;
if (s == NULL)
{
s = "<NULL>";
len = 6;
}
else
{
if (len == -1)
{
len = 0;
while ((unsigned int)len < (unsigned int)precision && s[len])
len++;
}
else
{
if ((unsigned int)len > (unsigned int)precision)
len = precision;
}
}
if (!(flags & LEFT))
while (len < field_width--)
{
f += ' ';
done++;
}
for (i = 0; i < len; ++i)
{
f += *s++;
done++;
}
while (len < field_width--)
{
f += ' ';
done++;
}
return done;
}
static int stringw(std::string& f, const wchar_t* sw, int len, int field_width, int precision, int flags)
{
int i, done = 0;
if (sw == NULL)
{
sw = L"<NULL>";
len = 6;
}
else
{
if (len == -1)
{
len = 0;
while ((unsigned int)len < (unsigned int)precision && sw[len])
len++;
}
else
{
if ((unsigned int)len > (unsigned int)precision)
len = precision;
}
}
if (!(flags & LEFT))
while (len < field_width--)
{
f += ' ';
done++;
}
for (i = 0; i < len; ++i)
{
#define MY_MB_CUR_MAX 1
char mb[MY_MB_CUR_MAX];
int mbcount, j;
mbcount = wctomb(mb, *sw++);
if (mbcount <= 0)
{
break;
}
for (j = 0; j < mbcount; j++)
{
f += mb[j];
done++;
}
}
while (len < field_width--)
{
f += ' ';
done++;
}
return done;
}
#define _isnanl _isnan
#define _finitel _finite
std::string ssvprintf ( const char *fmt, va_list args )
{
ULONGLONG num;
int base;
long double _ldouble;
double _double;
const char *s;
const unsigned short* sw;
int result;
std::string f;
int flags; /* flags to number() */
int field_width; /* width of output field */
int precision; /* min. # of digits for integers; max
number of chars for from string */
int qualifier = 0; /* 'h', 'l', 'L' or 'I64' for integer fields */
for (; *fmt ; ++fmt)
{
if (*fmt != '%')
{
f += *fmt;
continue;
}
/* process flags */
flags = 0;
repeat:
++fmt; /* this also skips first '%' */
switch (*fmt) {
case '-': flags |= LEFT; goto repeat;
case '+': flags |= PLUS; goto repeat;
case ' ': flags |= SPACE; goto repeat;
case '#': flags |= SPECIAL; goto repeat;
case '0': flags |= ZEROPAD; goto repeat;
}
/* get field width */
field_width = -1;
if (isdigit(*fmt))
field_width = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
field_width = va_arg(args, int);
if (field_width < 0) {
field_width = -field_width;
flags |= LEFT;
}
}
/* get the precision */
precision = -1;
if (*fmt == '.') {
++fmt;
if (isdigit(*fmt))
precision = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
precision = va_arg(args, int);
}
if (precision < 0)
precision = 0;
}
/* get the conversion qualifier */
qualifier = 0;
// %Z can be just stand alone or as size_t qualifier
if ( *fmt == 'Z' ) {
qualifier = *fmt;
switch ( *(fmt+1)) {
case 'o':
case 'b':
case 'X':
case 'x':
case 'd':
case 'i':
case 'u':
++fmt;
break;
default:
break;
}
} else if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'w') {
qualifier = *fmt;
++fmt;
} else if (*fmt == 'I' && *(fmt+1) == '6' && *(fmt+2) == '4') {
qualifier = *fmt;
fmt += 3;
}
// go fine with ll instead of L
if ( *fmt == 'l' ) {
++fmt;
qualifier = 'L';
}
/* default base */
base = 10;
switch (*fmt) {
case 'c':
if (!(flags & LEFT))
while (--field_width > 0)
{
f += ' ';
}
if (qualifier == 'l' || qualifier == 'w')
{
f += (char)(unsigned char)(wchar_t) va_arg(args,int);
}
else
{
f += (char)(unsigned char) va_arg(args,int);
}
while (--field_width > 0)
{
f += ' ';
}
continue;
case 'C':
if (!(flags & LEFT))
while (--field_width > 0)
{
f += ' ';
}
if (qualifier == 'h')
{
f += (char)(unsigned char) va_arg(args,int);
}
else
{
f += (char)(unsigned char)(wchar_t) va_arg(args,int);
}
while (--field_width > 0)
{
f += ' ';
}
continue;
case 's':
if (qualifier == 'l' || qualifier == 'w') {
/* print unicode string */
sw = va_arg(args, wchar_t *);
result = stringw(f, sw, -1, field_width, precision, flags);
} else {
/* print ascii string */
s = va_arg(args, char *);
result = string(f, s, -1, field_width, precision, flags);
}
if (result < 0)
{
assert(!"TODO FIXME handle error better");
return f;
}
continue;
case 'S':
if (qualifier == 'h') {
/* print ascii string */
s = va_arg(args, char *);
result = string(f, s, -1, field_width, precision, flags);
} else {
/* print unicode string */
sw = va_arg(args, wchar_t *);
result = stringw(f, sw, -1, field_width, precision, flags);
}
if (result < 0)
{
assert(!"TODO FIXME handle error better");
return f;
}
continue;
/*case 'Z':
if (qualifier == 'w') {
// print counted unicode string
PUNICODE_STRING pus = va_arg(args, PUNICODE_STRING);
if ((pus == NULL) || (pus->Buffer == NULL)) {
sw = NULL;
len = -1;
} else {
sw = pus->Buffer;
len = pus->Length / sizeof(WCHAR);
}
result = stringw(f, sw, len, field_width, precision, flags);
} else {
// print counted ascii string
PANSI_STRING pas = va_arg(args, PANSI_STRING);
if ((pas == NULL) || (pas->Buffer == NULL)) {
s = NULL;
len = -1;
} else {
s = pas->Buffer;
len = pas->Length;
}
result = string(f, s, -1, field_width, precision, flags);
}
if (result < 0)
return -1;
continue;*/
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
if (qualifier == 'l' || qualifier == 'L' ) {
_ldouble = va_arg(args, long double);
if ( _isnanl(_ldouble) )
{
f += "Nan";
}
else if ( !_finitel(_ldouble) )
{
if ( _ldouble < 0 )
f += "-Inf";
else
f += "+Inf";
} else {
if ( precision == -1 )
precision = 6;
result = numberfl(f,_ldouble,*fmt,field_width,precision,flags);
if (result < 0)
{
assert(!"TODO FIXME handle error better");
return f;
}
}
} else {
_double = (double)va_arg(args, double);
if ( _isnan(_double) )
{
f += "Nan";
}
else if ( !_finite(_double) )
{
if ( _double < 0 )
f += "-Inf";
else
f += "+Inf";
}
else
{
if ( precision == -1 )
precision = 6;
result = numberf(f,_double,*fmt,field_width,precision,flags);
if (result < 0)
{
assert(!"TODO FIXME handle error better");
return f;
}
}
}
continue;
case 'p':
if (field_width == -1) {
field_width = 2*sizeof(void *);
flags |= ZEROPAD;
}
result = number(f,
(unsigned long) va_arg(args, void *), 16,
field_width, precision, flags);
if (result < 0)
{
assert(!"TODO FIXME handle error better");
return f;
}
continue;
case 'n':
if (qualifier == 'l') {
long * ip = va_arg(args, long *);
*ip = 0;
} else {
int * ip = va_arg(args, int *);
*ip = 0;
}
continue;
/* integer number formats - set up the flags and "break" */
case 'o':
base = 8;
break;
case 'b':
base = 2;
break;
case 'X':
flags |= LARGE;
case 'x':
base = 16;
break;
case 'd':
case 'i':
flags |= SIGN;
case 'u':
break;
default:
if (*fmt != '%')
{
f += '%';
}
if (*fmt)
{
f += *fmt;
}
else
--fmt;
continue;
}
if (qualifier == 'I')
num = va_arg(args, ULONGLONG);
else if (qualifier == 'l') {
if (flags & SIGN)
num = va_arg(args, long);
else
num = va_arg(args, unsigned long);
}
else if (qualifier == 'h') {
if (flags & SIGN)
num = va_arg(args, int);
else
num = va_arg(args, unsigned int);
}
else if (flags & SIGN)
num = va_arg(args, int);
else
num = va_arg(args, unsigned int);
result = number(f, num, base, field_width, precision, flags);
if (result < 0)
{
assert(!"TODO FIXME handle error better");
return f;
}
}
//putc('\0',f);
return f;
}

View File

@@ -0,0 +1,12 @@
// ssprintf.h
#ifndef SSPRINTF_H
#define SSPRINTF_H
#include <string>
#include <stdarg.h>
std::string ssprintf ( const char* fmt, ... );
std::string ssvprintf ( const char* fmt, va_list args );
#endif//SSPRINTF_H

View File

@@ -0,0 +1,654 @@
RPC_NT_ALREADY_LISTENING
RPC_NT_ALREADY_REGISTERED
RPC_NT_CALL_FAILED
RPC_NT_CALL_FAILED_DNE
RPC_NT_CANT_CREATE_ENDPOINT
RPC_NT_INVALID_BINDING
RPC_NT_INVALID_ENDPOINT_FORMAT
RPC_NT_INVALID_NETWORK_OPTIONS
RPC_NT_INVALID_NET_ADDR
RPC_NT_INVALID_RPC_PROTSEQ
RPC_NT_INVALID_STRING_BINDING
RPC_NT_INVALID_STRING_UUID
RPC_NT_INVALID_TIMEOUT
RPC_NT_NOT_LISTENING
RPC_NT_NO_BINDINGS
RPC_NT_NO_CALL_ACTIVE
RPC_NT_NO_ENDPOINT_FOUND
RPC_NT_NO_PROTSEQS
RPC_NT_NO_PROTSEQS_REGISTERED
RPC_NT_OBJECT_NOT_FOUND
RPC_NT_OUT_OF_RESOURCES
RPC_NT_PROTOCOL_ERROR
RPC_NT_PROTSEQ_NOT_SUPPORTED
RPC_NT_SERVER_TOO_BUSY
RPC_NT_SERVER_UNAVAILABLE
RPC_NT_SS_IN_NULL_CONTEXT
RPC_NT_TYPE_ALREADY_REGISTERED
RPC_NT_UNKNOWN_IF
RPC_NT_UNKNOWN_MGR_TYPE
RPC_NT_WRONG_KIND_OF_BINDING
STATUS_ABANDONED
STATUS_ABANDONED_WAIT_0
STATUS_ABANDONED_WAIT_63
STATUS_ABIOS_INVALID_COMMAND
STATUS_ABIOS_INVALID_LID
STATUS_ABIOS_INVALID_SELECTOR
STATUS_ABIOS_LID_ALREADY_OWNED
STATUS_ABIOS_LID_NOT_EXIST
STATUS_ABIOS_NOT_LID_OWNER
STATUS_ABIOS_NOT_PRESENT
STATUS_ABIOS_SELECTOR_NOT_AVAILABLE
STATUS_ACCESS_DENIED
STATUS_ACCESS_VIOLATION
STATUS_ACCOUNT_DISABLED
STATUS_ACCOUNT_EXPIRED
STATUS_ACCOUNT_LOCKED_OUT
STATUS_ACCOUNT_RESTRICTION
STATUS_ADAPTER_HARDWARE_ERROR
STATUS_ADDRESS_ALREADY_ASSOCIATED
STATUS_ADDRESS_ALREADY_EXISTS
STATUS_ADDRESS_CLOSED
STATUS_ADDRESS_NOT_ASSOCIATED
STATUS_AGENTS_EXHAUSTED
STATUS_ALERTED
STATUS_ALIAS_EXISTS
STATUS_ALLOCATE_BUCKET
STATUS_ALLOTTED_SPACE_EXCEEDED
STATUS_ALREADY_COMMITTED
STATUS_ALREADY_DISCONNECTED
STATUS_ALREADY_WIN32
STATUS_APP_INIT_FAILURE
STATUS_ARBITRATION_UNHANDLED
STATUS_ARRAY_BOUNDS_EXCEEDED
STATUS_AUDIT_FAILED
STATUS_BACKUP_CONTROLLER
STATUS_BAD_COMPRESSION_BUFFER
STATUS_BAD_CURRENT_DIRECTORY
STATUS_BAD_DESCRIPTOR_FORMAT
STATUS_BAD_DEVICE_TYPE
STATUS_BAD_DLL_ENTRYPOINT
STATUS_BAD_FUNCTION_TABLE
STATUS_BAD_IMPERSONATION_LEVEL
STATUS_BAD_INHERITANCE_ACL
STATUS_BAD_INITIAL_PC
STATUS_BAD_INITIAL_STACK
STATUS_BAD_LOGON_SESSION_STATE
STATUS_BAD_MASTER_BOOT_RECORD
STATUS_BAD_NETWORK_NAME
STATUS_BAD_NETWORK_PATH
STATUS_BAD_REMOTE_ADAPTER
STATUS_BAD_SERVICE_ENTRYPOINT
STATUS_BAD_STACK
STATUS_BAD_TOKEN_TYPE
STATUS_BAD_VALIDATION_CLASS
STATUS_BAD_WORKING_SET_LIMIT
STATUS_BEGINNING_OF_MEDIA
STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT
STATUS_BREAKPOINT
STATUS_BUFFER_OVERFLOW
STATUS_BUFFER_TOO_SMALL
STATUS_BUS_RESET
STATUS_CANCELLED
STATUS_CANNOT_DELETE
STATUS_CANNOT_IMPERSONATE
STATUS_CANNOT_LOAD_REGISTRY_FILE
STATUS_CANT_ACCESS_DOMAIN_INFO
STATUS_CANT_DISABLE_MANDATORY
STATUS_CANT_OPEN_ANONYMOUS
STATUS_CANT_TERMINATE_SELF
STATUS_CANT_WAIT
STATUS_CARDBUS_NOT_SUPPORTED
STATUS_CHECKING_FILE_SYSTEM
STATUS_CHILD_MUST_BE_VOLATILE
STATUS_CLIENT_SERVER_PARAMETERS_INVALID
STATUS_COMMITMENT_LIMIT
STATUS_CONFLICTING_ADDRESSES
STATUS_CONNECTION_ABORTED
STATUS_CONNECTION_ACTIVE
STATUS_CONNECTION_COUNT_LIMIT
STATUS_CONNECTION_DISCONNECTED
STATUS_CONNECTION_INVALID
STATUS_CONNECTION_IN_USE
STATUS_CONNECTION_REFUSED
STATUS_CONNECTION_RESET
STATUS_CONTROL_C_EXIT
STATUS_CONVERT_TO_LARGE
STATUS_COULD_NOT_INTERPRET
STATUS_CRC_ERROR
STATUS_CTL_FILE_NOT_SUPPORTED
STATUS_DATATYPE_MISALIGNMENT
STATUS_DATA_ERROR
STATUS_DATA_LATE_ERROR
STATUS_DATA_NOT_ACCEPTED
STATUS_DATA_OVERRUN
STATUS_DEBUG_ATTACH_FAILED
STATUS_DELETE_PENDING
STATUS_DEVICE_ALREADY_ATTACHED
STATUS_DEVICE_BUSY
STATUS_DEVICE_CONFIGURATION_ERROR
STATUS_DEVICE_DATA_ERROR
STATUS_DEVICE_DOES_NOT_EXIST
STATUS_DEVICE_NOT_CONNECTED
STATUS_DEVICE_NOT_PARTITIONED
STATUS_DEVICE_NOT_READY
STATUS_DEVICE_OFF_LINE
STATUS_DEVICE_PAPER_EMPTY
STATUS_DEVICE_POWERED_OFF
STATUS_DEVICE_POWER_FAILURE
STATUS_DEVICE_PROTOCOL_ERROR
STATUS_DFS_EXIT_PATH_FOUND
STATUS_DFS_UNAVAILABLE
STATUS_DIRECTORY_NOT_EMPTY
STATUS_DISK_CORRUPT_ERROR
STATUS_DISK_FULL
STATUS_DISK_OPERATION_FAILED
STATUS_DISK_RECALIBRATE_FAILED
STATUS_DISK_RESET_FAILED
STATUS_DLL_INIT_FAILED
STATUS_DLL_INIT_FAILED_LOGOFF
STATUS_DLL_NOT_FOUND
STATUS_DOMAIN_CONTROLLER_NOT_FOUND
STATUS_DOMAIN_CTRLR_CONFIG_ERROR
STATUS_DOMAIN_EXISTS
STATUS_DOMAIN_LIMIT_EXCEEDED
STATUS_DOMAIN_TRUST_INCONSISTENT
STATUS_DRIVER_CANCEL_TIMEOUT
STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
STATUS_DRIVER_INTERNAL_ERROR
STATUS_DRIVER_ORDINAL_NOT_FOUND
STATUS_DRIVER_UNABLE_TO_LOAD
STATUS_DUPLICATE_NAME
STATUS_DUPLICATE_OBJECTID
STATUS_EAS_NOT_SUPPORTED
STATUS_EA_CORRUPT_ERROR
STATUS_EA_LIST_INCONSISTENT
STATUS_EA_TOO_LARGE
STATUS_END_OF_FILE
STATUS_END_OF_MEDIA
STATUS_ENTRYPOINT_NOT_FOUND
STATUS_EOM_OVERFLOW
STATUS_EVALUATION_EXPIRATION
STATUS_EVENTLOG_CANT_START
STATUS_EVENTLOG_FILE_CHANGED
STATUS_EVENTLOG_FILE_CORRUPT
STATUS_EVENT_DONE
STATUS_EVENT_PENDING
STATUS_EXTRANEOUS_INFORMATION
STATUS_FAIL_CHECK
STATUS_FATAL_APP_EXIT
STATUS_FILEMARK_DETECTED
STATUS_FILES_OPEN
STATUS_FILE_CLOSED
STATUS_FILE_CORRUPT_ERROR
STATUS_FILE_DELETED
STATUS_FILE_FORCED_CLOSED
STATUS_FILE_INVALID
STATUS_FILE_IS_A_DIRECTORY
STATUS_FILE_IS_OFFLINE
STATUS_FILE_LOCK_CONFLICT
STATUS_FILE_RENAMED
STATUS_FLOAT_DENORMAL_OPERAND
STATUS_FLOAT_DIVIDE_BY_ZERO
STATUS_FLOAT_INEXACT_RESULT
STATUS_FLOAT_INVALID_OPERATION
STATUS_FLOAT_OVERFLOW
STATUS_FLOAT_STACK_CHECK
STATUS_FLOAT_UNDERFLOW
STATUS_FLOPPY_BAD_REGISTERS
STATUS_FLOPPY_ID_MARK_NOT_FOUND
STATUS_FLOPPY_UNKNOWN_ERROR
STATUS_FLOPPY_VOLUME
STATUS_FLOPPY_WRONG_CYLINDER
STATUS_FOUND_OUT_OF_SCOPE
STATUS_FREE_VM_NOT_AT_BASE
STATUS_FS_DRIVER_REQUIRED
STATUS_FT_MISSING_MEMBER
STATUS_FT_ORPHANING
STATUS_FT_READ_RECOVERING_FROM_BACKUP
STATUS_FT_WRITE_RECOVERY
STATUS_FULLSCREEN_MODE
STATUS_GENERIC_NOT_MAPPED
STATUS_GRACEFUL_DISCONNECT
STATUS_GROUP_EXISTS
STATUS_GUARD_PAGE_VIOLATION
STATUS_GUIDS_EXHAUSTED
STATUS_GUID_SUBSTITUTION_MADE
STATUS_HANDLES_CLOSED
STATUS_HANDLE_NOT_CLOSABLE
STATUS_HOST_UNREACHABLE
STATUS_ILLEGAL_CHARACTER
STATUS_ILLEGAL_DLL_RELOCATION
STATUS_ILLEGAL_FLOAT_CONTEXT
STATUS_ILLEGAL_FUNCTION
STATUS_ILLEGAL_INSTRUCTION
STATUS_ILL_FORMED_PASSWORD
STATUS_ILL_FORMED_SERVICE_ENTRY
STATUS_IMAGE_ALREADY_LOADED
STATUS_IMAGE_CHECKSUM_MISMATCH
STATUS_IMAGE_MACHINE_TYPE_MISMATCH
STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE
STATUS_IMAGE_MP_UP_MISMATCH
STATUS_IMAGE_NOT_AT_BASE
STATUS_INCOMPATIBLE_FILE_MAP
STATUS_INFO_LENGTH_MISMATCH
STATUS_INSTANCE_NOT_AVAILABLE
STATUS_INSTRUCTION_MISALIGNMENT
STATUS_INSUFFICIENT_LOGON_INFO
STATUS_INSUFFICIENT_RESOURCES
STATUS_INSUFF_SERVER_RESOURCES
STATUS_INTEGER_DIVIDE_BY_ZERO
STATUS_INTEGER_OVERFLOW
STATUS_INTERNAL_DB_CORRUPTION
STATUS_INTERNAL_DB_ERROR
STATUS_INTERNAL_ERROR
STATUS_INVALID_ACCOUNT_NAME
STATUS_INVALID_ACL
STATUS_INVALID_ADDRESS
STATUS_INVALID_ADDRESS_COMPONENT
STATUS_INVALID_ADDRESS_WILDCARD
STATUS_INVALID_BLOCK_LENGTH
STATUS_INVALID_BUFFER_SIZE
STATUS_INVALID_CID
STATUS_INVALID_COMPUTER_NAME
STATUS_INVALID_CONNECTION
STATUS_INVALID_DEVICE_REQUEST
STATUS_INVALID_DEVICE_STATE
STATUS_INVALID_DISPOSITION
STATUS_INVALID_DOMAIN_ROLE
STATUS_INVALID_DOMAIN_STATE
STATUS_INVALID_EA_FLAG
STATUS_INVALID_EA_NAME
STATUS_INVALID_FILE_FOR_SECTION
STATUS_INVALID_GROUP_ATTRIBUTES
STATUS_INVALID_HANDLE
STATUS_INVALID_HW_PROFILE
STATUS_INVALID_ID_AUTHORITY
STATUS_INVALID_IMAGE_FORMAT
STATUS_INVALID_IMAGE_LE_FORMAT
STATUS_INVALID_IMAGE_NE_FORMAT
STATUS_INVALID_IMAGE_NOT_MZ
STATUS_INVALID_IMAGE_PROTECT
STATUS_INVALID_IMAGE_WIN_16
STATUS_INVALID_INFO_CLASS
STATUS_INVALID_LDT_DESCRIPTOR
STATUS_INVALID_LDT_OFFSET
STATUS_INVALID_LDT_SIZE
STATUS_INVALID_LEVEL
STATUS_INVALID_LOCK_SEQUENCE
STATUS_INVALID_LOGON_HOURS
STATUS_INVALID_LOGON_TYPE
STATUS_INVALID_MEMBER
STATUS_INVALID_NETWORK_RESPONSE
STATUS_INVALID_OPLOCK_PROTOCOL
STATUS_INVALID_OWNER
STATUS_INVALID_PAGE_PROTECTION
STATUS_INVALID_PARAMETER
STATUS_INVALID_PARAMETER_1
STATUS_INVALID_PARAMETER_10
STATUS_INVALID_PARAMETER_11
STATUS_INVALID_PARAMETER_12
STATUS_INVALID_PARAMETER_2
STATUS_INVALID_PARAMETER_3
STATUS_INVALID_PARAMETER_4
STATUS_INVALID_PARAMETER_5
STATUS_INVALID_PARAMETER_6
STATUS_INVALID_PARAMETER_7
STATUS_INVALID_PARAMETER_8
STATUS_INVALID_PARAMETER_9
STATUS_INVALID_PARAMETER_MIX
STATUS_INVALID_PIPE_STATE
STATUS_INVALID_PLUGPLAY_DEVICE_PATH
STATUS_INVALID_PORT_ATTRIBUTES
STATUS_INVALID_PORT_HANDLE
STATUS_INVALID_PRIMARY_GROUP
STATUS_INVALID_QUOTA_LOWER
STATUS_INVALID_READ_MODE
STATUS_INVALID_SECURITY_DESCR
STATUS_INVALID_SERVER_STATE
STATUS_INVALID_SID
STATUS_INVALID_SUB_AUTHORITY
STATUS_INVALID_SYSTEM_SERVICE
STATUS_INVALID_UNWIND_TARGET
STATUS_INVALID_USER_BUFFER
STATUS_INVALID_VARIANT
STATUS_INVALID_VIEW_SIZE
STATUS_INVALID_VLM_OPERATION
STATUS_INVALID_VOLUME_LABEL
STATUS_INVALID_WORKSTATION
STATUS_IN_PAGE_ERROR
STATUS_IO_DEVICE_ERROR
STATUS_IO_PRIVILEGE_FAILED
STATUS_IO_REPARSE_DATA_INVALID
STATUS_IO_REPARSE_TAG_INVALID
STATUS_IO_REPARSE_TAG_MISMATCH
STATUS_IO_REPARSE_TAG_NOT_HANDLED
STATUS_IO_TIMEOUT
STATUS_IP_ADDRESS_CONFLICT1
STATUS_IP_ADDRESS_CONFLICT2
STATUS_KERNEL_APC
STATUS_KEY_DELETED
STATUS_KEY_HAS_CHILDREN
STATUS_LAST_ADMIN
STATUS_LICENSE_QUOTA_EXCEEDED
STATUS_LICENSE_VIOLATION
STATUS_LINK_FAILED
STATUS_LINK_TIMEOUT
STATUS_LM_CROSS_ENCRYPTION_REQUIRED
STATUS_LOCAL_DISCONNECT
STATUS_LOCAL_USER_SESSION_KEY
STATUS_LOCK_NOT_GRANTED
STATUS_LOGIN_TIME_RESTRICTION
STATUS_LOGIN_WKSTA_RESTRICTION
STATUS_LOGON_FAILURE
STATUS_LOGON_NOT_GRANTED
STATUS_LOGON_SERVER_CONFLICT
STATUS_LOGON_SESSION_COLLISION
STATUS_LOGON_SESSION_EXISTS
STATUS_LOGON_TYPE_NOT_GRANTED
STATUS_LOG_FILE_FULL
STATUS_LOG_HARD_ERROR
STATUS_LONGJUMP
STATUS_LOST_WRITEBEHIND_DATA
STATUS_LPC_REPLY_LOST
STATUS_LUIDS_EXHAUSTED
STATUS_MAPPED_ALIGNMENT
STATUS_MAPPED_FILE_SIZE_ZERO
STATUS_MARSHALL_OVERFLOW
STATUS_MEDIA_CHANGED
STATUS_MEDIA_CHECK
STATUS_MEDIA_WRITE_PROTECTED
STATUS_MEMBERS_PRIMARY_GROUP
STATUS_MEMBER_IN_ALIAS
STATUS_MEMBER_IN_GROUP
STATUS_MEMBER_NOT_IN_ALIAS
STATUS_MEMBER_NOT_IN_GROUP
STATUS_MEMORY_NOT_ALLOCATED
STATUS_MESSAGE_NOT_FOUND
STATUS_MISSING_SYSTEMFILE
STATUS_MORE_ENTRIES
STATUS_MORE_PROCESSING_REQUIRED
STATUS_MUTANT_LIMIT_EXCEEDED
STATUS_MUTANT_NOT_OWNED
STATUS_NAME_TOO_LONG
STATUS_NETLOGON_NOT_STARTED
STATUS_NETWORK_ACCESS_DENIED
STATUS_NETWORK_BUSY
STATUS_NETWORK_CREDENTIAL_CONFLICT
STATUS_NETWORK_NAME_DELETED
STATUS_NETWORK_UNREACHABLE
STATUS_NET_WRITE_FAULT
STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
STATUS_NOLOGON_SERVER_TRUST_ACCOUNT
STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
STATUS_NONCONTINUABLE_EXCEPTION
STATUS_NONEXISTENT_EA_ENTRY
STATUS_NONEXISTENT_SECTOR
STATUS_NONE_MAPPED
STATUS_NOTIFY_CLEANUP
STATUS_NOTIFY_ENUM_DIR
STATUS_NOT_ALL_ASSIGNED
STATUS_NOT_A_DIRECTORY
STATUS_NOT_A_REPARSE_POINT
STATUS_NOT_CLIENT_SESSION
STATUS_NOT_COMMITTED
STATUS_NOT_FOUND
STATUS_NOT_IMPLEMENTED
STATUS_NOT_LOCKED
STATUS_NOT_LOGON_PROCESS
STATUS_NOT_MAPPED_DATA
STATUS_NOT_MAPPED_VIEW
STATUS_NOT_REGISTRY_FILE
STATUS_NOT_SAME_DEVICE
STATUS_NOT_SERVER_SESSION
STATUS_NOT_SUPPORTED
STATUS_NOT_TINY_STREAM
STATUS_NO_BROWSER_SERVERS_FOUND
STATUS_NO_CALLBACK_ACTIVE
STATUS_NO_DATA_DETECTED
STATUS_NO_EAS_ON_FILE
STATUS_NO_EVENT_PAIR
STATUS_NO_GUID_TRANSLATION
STATUS_NO_IMPERSONATION_TOKEN
STATUS_NO_INHERITANCE
STATUS_NO_LDT
STATUS_NO_LOGON_SERVERS
STATUS_NO_LOG_SPACE
STATUS_NO_MATCH
STATUS_NO_MEDIA
STATUS_NO_MEDIA_IN_DEVICE
STATUS_NO_MEMORY
STATUS_NO_MORE_EAS
STATUS_NO_MORE_ENTRIES
STATUS_NO_MORE_FILES
STATUS_NO_MORE_MATCHES
STATUS_NO_PAGEFILE
STATUS_NO_QUOTAS_NO_ACCOUNT
STATUS_NO_SECURITY_ON_OBJECT
STATUS_NO_SPOOL_SPACE
STATUS_NO_SUCH_ALIAS
STATUS_NO_SUCH_DEVICE
STATUS_NO_SUCH_DOMAIN
STATUS_NO_SUCH_FILE
STATUS_NO_SUCH_GROUP
STATUS_NO_SUCH_LOGON_SESSION
STATUS_NO_SUCH_MEMBER
STATUS_NO_SUCH_PACKAGE
STATUS_NO_SUCH_PRIVILEGE
STATUS_NO_SUCH_USER
STATUS_NO_TOKEN
STATUS_NO_TRUST_LSA_SECRET
STATUS_NO_TRUST_SAM_ACCOUNT
STATUS_NO_USER_SESSION_KEY
STATUS_NO_YIELD_PERFORMED
STATUS_NT_CROSS_ENCRYPTION_REQUIRED
STATUS_NULL_LM_PASSWORD
STATUS_OBJECTID_EXISTS
STATUS_OBJECT_EXISTS
STATUS_OBJECT_NAME_COLLISION
STATUS_OBJECT_NAME_EXISTS
STATUS_OBJECT_NAME_INVALID
STATUS_OBJECT_NAME_NOT_FOUND
STATUS_OBJECT_PATH_INVALID
STATUS_OBJECT_PATH_NOT_FOUND
STATUS_OBJECT_PATH_SYNTAX_BAD
STATUS_OBJECT_TYPE_MISMATCH
STATUS_OPEN_FAILED
STATUS_OPLOCK_BREAK_IN_PROCESS
STATUS_OPLOCK_NOT_GRANTED
STATUS_ORDINAL_NOT_FOUND
STATUS_PAGEFILE_CREATE_FAILED
STATUS_PAGEFILE_QUOTA
STATUS_PAGEFILE_QUOTA_EXCEEDED
STATUS_PARITY_ERROR
STATUS_PARTIAL_COPY
STATUS_PARTITION_FAILURE
STATUS_PASSWORD_EXPIRED
STATUS_PASSWORD_MUST_CHANGE
STATUS_PASSWORD_RESTRICTION
STATUS_PATH_NOT_COVERED
STATUS_PENDING
STATUS_PIPE_BROKEN
STATUS_PIPE_BUSY
STATUS_PIPE_CLOSING
STATUS_PIPE_CONNECTED
STATUS_PIPE_DISCONNECTED
STATUS_PIPE_EMPTY
STATUS_PIPE_LISTENING
STATUS_PIPE_NOT_AVAILABLE
STATUS_PLUGPLAY_NO_DEVICE
STATUS_PORT_ALREADY_SET
STATUS_PORT_CONNECTION_REFUSED
STATUS_PORT_DISCONNECTED
STATUS_PORT_MESSAGE_TOO_LONG
STATUS_PORT_UNREACHABLE
STATUS_POSSIBLE_DEADLOCK
STATUS_PREDEFINED_HANDLE
STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED
STATUS_PRINT_CANCELLED
STATUS_PRINT_QUEUE_FULL
STATUS_PRIVILEGED_INSTRUCTION
STATUS_PRIVILEGE_NOT_HELD
STATUS_PROCEDURE_NOT_FOUND
STATUS_PROCESS_IN_JOB
STATUS_PROCESS_IS_TERMINATING
STATUS_PROCESS_NOT_IN_JOB
STATUS_PROFILING_AT_LIMIT
STATUS_PROFILING_NOT_STARTED
STATUS_PROFILING_NOT_STOPPED
STATUS_PROPSET_NOT_FOUND
STATUS_PROTOCOL_UNREACHABLE
STATUS_PWD_HISTORY_CONFLICT
STATUS_PWD_TOO_RECENT
STATUS_PWD_TOO_SHORT
STATUS_QUOTA_EXCEEDED
STATUS_QUOTA_LIST_INCONSISTENT
STATUS_RANGE_LIST_CONFLICT
STATUS_RANGE_NOT_FOUND
STATUS_RANGE_NOT_LOCKED
STATUS_RECEIVE_EXPEDITED
STATUS_RECEIVE_PARTIAL
STATUS_RECEIVE_PARTIAL_EXPEDITED
STATUS_RECOVERY_FAILURE
STATUS_REDIRECTOR_HAS_OPEN_HANDLES
STATUS_REDIRECTOR_NOT_STARTED
STATUS_REDIRECTOR_PAUSED
STATUS_REDIRECTOR_STARTED
STATUS_REGISTRY_CORRUPT
STATUS_REGISTRY_IO_FAILED
STATUS_REGISTRY_QUOTA_LIMIT
STATUS_REGISTRY_RECOVERED
STATUS_REMOTE_DISCONNECT
STATUS_REMOTE_NOT_LISTENING
STATUS_REMOTE_RESOURCES
STATUS_REMOTE_SESSION_LIMIT
STATUS_REPARSE
STATUS_REPLY_MESSAGE_MISMATCH
STATUS_REQUEST_ABORTED
STATUS_REQUEST_NOT_ACCEPTED
STATUS_RESOURCE_DATA_NOT_FOUND
STATUS_RESOURCE_LANG_NOT_FOUND
STATUS_RESOURCE_NAME_NOT_FOUND
STATUS_RESOURCE_NOT_OWNED
STATUS_RESOURCE_TYPE_NOT_FOUND
STATUS_RETRY
STATUS_REVISION_MISMATCH
STATUS_RXACT_COMMITTED
STATUS_RXACT_COMMIT_FAILURE
STATUS_RXACT_COMMIT_NECESSARY
STATUS_RXACT_INVALID_STATE
STATUS_RXACT_STATE_CREATED
STATUS_SAM_INIT_FAILURE
STATUS_SECRET_TOO_LONG
STATUS_SECTION_NOT_EXTENDED
STATUS_SECTION_NOT_IMAGE
STATUS_SECTION_PROTECTION
STATUS_SECTION_TOO_BIG
STATUS_SEGMENT_NOTIFICATION
STATUS_SEMAPHORE_LIMIT_EXCEEDED
STATUS_SERIAL_COUNTER_TIMEOUT
STATUS_SERIAL_MORE_WRITES
STATUS_SERIAL_NO_DEVICE_INITED
STATUS_SERVER_DISABLED
STATUS_SERVER_HAS_OPEN_HANDLES
STATUS_SERVER_NOT_DISABLED
STATUS_SERVICE_NOTIFICATION
STATUS_SETMARK_DETECTED
STATUS_SHARED_IRQ_BUSY
STATUS_SHARING_PAUSED
STATUS_SHARING_VIOLATION
STATUS_SINGLE_STEP
STATUS_SOME_NOT_MAPPED
STATUS_SPECIAL_ACCOUNT
STATUS_SPECIAL_GROUP
STATUS_SPECIAL_USER
STATUS_STACK_OVERFLOW
STATUS_STACK_OVERFLOW_READ
STATUS_SUCCESS
STATUS_SUSPEND_COUNT_EXCEEDED
STATUS_SYNCHRONIZATION_REQUIRED
STATUS_SYSTEM_PROCESS_TERMINATED
STATUS_THREAD_IS_TERMINATING
STATUS_THREAD_NOT_IN_PROCESS
STATUS_THREAD_WAS_SUSPENDED
STATUS_TIMEOUT
STATUS_TIMER_NOT_CANCELED
STATUS_TIMER_RESOLUTION_NOT_SET
STATUS_TIMER_RESUME_IGNORED
STATUS_TIME_DIFFERENCE_AT_DC
STATUS_TOKEN_ALREADY_IN_USE
STATUS_TOO_LATE
STATUS_TOO_MANY_ADDRESSES
STATUS_TOO_MANY_COMMANDS
STATUS_TOO_MANY_CONTEXT_IDS
STATUS_TOO_MANY_GUIDS_REQUESTED
STATUS_TOO_MANY_LINKS
STATUS_TOO_MANY_LUIDS_REQUESTED
STATUS_TOO_MANY_NAMES
STATUS_TOO_MANY_NODES
STATUS_TOO_MANY_OPENED_FILES
STATUS_TOO_MANY_PAGING_FILES
STATUS_TOO_MANY_SECRETS
STATUS_TOO_MANY_SESSIONS
STATUS_TOO_MANY_SIDS
STATUS_TOO_MANY_THREADS
STATUS_TRANSACTION_ABORTED
STATUS_TRANSACTION_INVALID_ID
STATUS_TRANSACTION_INVALID_TYPE
STATUS_TRANSACTION_NO_MATCH
STATUS_TRANSACTION_NO_RELEASE
STATUS_TRANSACTION_RESPONDED
STATUS_TRANSACTION_TIMED_OUT
STATUS_TRUSTED_DOMAIN_FAILURE
STATUS_TRUSTED_RELATIONSHIP_FAILURE
STATUS_TRUST_FAILURE
STATUS_UNABLE_TO_DECOMMIT_VM
STATUS_UNABLE_TO_DELETE_SECTION
STATUS_UNABLE_TO_FREE_VM
STATUS_UNABLE_TO_LOCK_MEDIA
STATUS_UNABLE_TO_UNLOAD_MEDIA
STATUS_UNDEFINED_CHARACTER
STATUS_UNEXPECTED_IO_ERROR
STATUS_UNEXPECTED_MM_CREATE_ERR
STATUS_UNEXPECTED_MM_EXTEND_ERR
STATUS_UNEXPECTED_MM_MAP_ERROR
STATUS_UNEXPECTED_NETWORK_ERROR
STATUS_UNHANDLED_EXCEPTION
STATUS_UNKNOWN_REVISION
STATUS_UNMAPPABLE_CHARACTER
STATUS_UNRECOGNIZED_MEDIA
STATUS_UNRECOGNIZED_VOLUME
STATUS_UNSUCCESSFUL
STATUS_UNSUPPORTED_COMPRESSION
STATUS_UNWIND
STATUS_USER_APC
STATUS_USER_EXISTS
STATUS_USER_MAPPED_FILE
STATUS_USER_SESSION_DELETED
STATUS_VALIDATE_CONTINUE
STATUS_VARIABLE_NOT_FOUND
STATUS_VDM_HARD_ERROR
STATUS_VERIFY_REQUIRED
STATUS_VIRTUAL_CIRCUIT_CLOSED
STATUS_VOLUME_DISMOUNTED
STATUS_VOLUME_MOUNTED
STATUS_WAIT_0
STATUS_WAIT_63
STATUS_WAKE_SYSTEM_DEBUGGER
STATUS_WAS_LOCKED
STATUS_WAS_UNLOCKED
STATUS_WORKING_SET_LIMIT_RANGE
STATUS_WORKING_SET_QUOTA
STATUS_WRONG_PASSWORD
STATUS_WRONG_PASSWORD_CORE
STATUS_WRONG_VOLUME
STATUS_WX86_BREAKPOINT
STATUS_WX86_CONTINUE
STATUS_WX86_CREATEWX86TIB
STATUS_WX86_EXCEPTION_CHAIN
STATUS_WX86_EXCEPTION_CONTINUE
STATUS_WX86_EXCEPTION_LASTCHANCE
STATUS_WX86_FLOAT_STACK_CHECK
STATUS_WX86_INTERNAL_ERROR
STATUS_WX86_SINGLE_STEP
STATUS_WX86_UNSIMULATE

View File

@@ -0,0 +1,7 @@
FAST_MUTEX
KPCR
PEB
TEB
SPINLOCK
APC
DPC

View File

@@ -0,0 +1,73 @@
What do you think I am, your personal tech support?
You *know* a %stru% is non-re-entrant, right?
The answer to that is so simple, I'm not going to waste my time telling you.
Well, of course... if you're not below DISPATCH_LEVEL, ros is gonna explode on ya when you try to do that ( duh! ).
I don't think that functionality has been implemented, yet.
What do you mean it crashed? It can't crash there!
Wow. That's a new one.
Ask %dev%, I bet he knows.. he knows everything...
When's the last time you rebuilt?
Have you tried a make clean?
Is it plugged in?
Well it works on *my* system :P
Well don't do that, and you won't have that problem.
Didn't we already fix that?
Well... I don't know.. I just have that code disabled in my tree.
Try surrounding it with parenthesis.
Don't you know going around dereferncing null pointers all day can be hazardous to your health?
Well, duh!
There's a bit in cr3 for problems like that.
Just add a field to the %stru% to keep track of it!
Don't worry about it... the garbage collector in %module% will clean it up for you.
Did I do that?
Didn't %dev% fix that already?
Yes, I think I've seen that bug before... no... that was another program.
I could tell you, but then I'd have to unlink() you.
Well if you'd get some sleep, maybe you'd figure it out... not all of us can keep the hours %dev% can...
You did what? Uh oh... that can't be good.
Well... I could tell you, but the answer's pretty complicated. Why don't you wait to read about it in the book I'm writing.
Yeah, that's happened to me, before, too. All you have to do is wrap it in an SEH block and forget about it.
Just put a NULL dereference in there and commit it. It helps get bugs fixed fast! (Not that I would know)
ASSERT is your friend!
I dunno.. but I bet %dev% could find it for you.
I hereby declare that code is perfect. Your problem must be elsewhere.
I wrote that code... it must be perfect.
$#@!$ One of these days I'm gonna throw %module% out the window!!! Sorry, what were you saying?
maybe I broke it in my last commit. Maybe I did it on purpose...
Have you tried debugging it? I got a can of Raid...
Just delete it, it can't be that important ( You should see all the useless cruft I got rid of in %module% )
Try queueing a work item...
My %stru% fell in love with some %stru% in %module%, and %module% has been hell since...
Maybe the PEB is getting corrupted. Try allocating a new PEB and overwriting the old one. That's what I did last time I had a bug like that.
Hmm.. that seems to have been introduced by my last commit... I bet CVS mixed up the bits during the commit.
It can't possibly be my fault, so I don't care.
I'm not experiencing that problem, perhaps it's all in your mind.
Well... like a good friend of mine said... "Don't Panic!"
It just shows you how far ReactOS has come along! A %period% ago a bug like that wouldn't have even been possible!
Just surround the code with an #if 0/#endif block, it solves all my problems!
You know.. if %dev% would just finish %module% for us, we wouldn't be having this problem.
I say we move on to the next function, since we can't seem to figure this one out.
Well, sure, that would have been my first guess, too.... TEN YEARS AGO :p
yup, that sounds like a problem.
If I wanted to talk about VB, I'd go bug Alex...
ask %dev%
Thank you for that amazingly keen insight, Commander Obvious.
Sorry, can't help you right now, trying to track down this bug %dev% caused in %module%
I dont know about that, but I just fixed a problem in %module% for %dev%
How should I know? I'm still trying to figure out this main() thing... ooh! wanna see what I did in %module%?
lol!
*wink*
;)
42
It's gonna take me over %period% to fix all %dev%'s bugs in %module% :(
How could %func% return %status%!? It bet %dev% broke it! I didn't touch it... honest! no.. really! (me hides)
It's fine if you get %status% there ... just ignore the destruction, and call %func% instead.
%dev% said %status% isn't really an error in this context because we expect %module% to be toast by now
heh, I'm still trying to figure out why %func% is returning %status% when I call it from %module%...
%dev% said it's okay to ignore that as long as you're below %irql%
erm, what do you mean?
damn, I do that all the time
if you want a reply that sounds right, I'd say that %func% support for that is vital to the future of %module%
Sounds like you're having a problem with %func%. I hate that thing... don't talk to me about it.
Just return %status% and forget about it. Someone else will fix it, later.
Blah blah blah... sheesh... can't you figure out *anything*?

View File

@@ -0,0 +1,17 @@
// trim.cpp
// This file is (C) 2004 Royce Mitchell III
// and released under the BSD & LGPL licenses
#include "trim.h"
std::string trim ( const std::string& s )
{
const char* p = &s[0];
const char* p2 = p + s.size();
while ( *p == ' ' )
p++;
while ( p2 > p && p2[-1] == ' ' )
p2--;
return std::string ( p, p2-p );
}

13
irc/ArchBlackmann/trim.h Normal file
View File

@@ -0,0 +1,13 @@
// trim.h
// This file is (C) 2004 Royce Mitchell III
// and released under the BSD & LGPL licenses
#ifndef TRIM_H
#define TRIM_H
#include <string>
std::string trim ( const std::string& s );
#endif//TRIM_H

1000
irc/ArchBlackmann/type.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
// verify.h
// This code is (C) 2003-2004 Royce Mitchell III
// and released under the LGPL & BSD licenses
#ifndef VERIFY_H
#define VERIFY_H
//#include <assert.h>
#ifdef ASSERT
#undef ASSERT
#endif//ASSERT
#include "panic.h"
#if defined(DEBUG) || defined(_DEBUG)
inline void AssertHandler ( bool b, const char* str )
{
if ( !b )
panic ( str );
}
# define ASSERT(x) AssertHandler((x) ? true : false, #x )
#else
# define ASSERT(x)
#endif
#ifdef verify
#undef verify
#endif//verify
#if defined(DEBUG) || defined(_DEBUG)
# define verify(x) ASSERT(x)
#else
# define verify(x) x
#endif
#endif//VERIFY_H

View File

@@ -0,0 +1,32 @@
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following
// attributes.
//
// change them to the information which is associated with the assembly
// you compile.
[assembly: AssemblyTitle("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has following format :
//
// Major.Minor.Build.Revision
//
// You can specify all values by your own or you can build default build and revision
// numbers with the '*' character (the default):
[assembly: AssemblyVersion("1.0.*")]
// The following attributes specify the key for the sign of your assembly. See the
// .NET Framework documentation for more information about signing.
// This is not required, if you don't want signing let these attributes like they're.
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("")]

View File

@@ -0,0 +1,274 @@
using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Globalization;
namespace HtmlHelp.ChmDecoding
{
/// <summary>
/// The class <c>BinaryReaderHelp</c> implements static helper methods for extracting binary data
/// from a binary reader object.
/// </summary>
internal class BinaryReaderHelp
{
/// <summary>
/// Internal helper method to extract null-terminated strings from a binary reader
/// </summary>
/// <param name="binReader">reference to the binary reader</param>
/// <param name="offset">offset in the stream</param>
/// <param name="noOffset">true if the offset value should be used</param>
/// <param name="encoder">encoder used for text encoding</param>
/// <returns>An extracted string value</returns>
internal static string ExtractString(ref BinaryReader binReader, int offset, bool noOffset, Encoding encoder)
{
string strReturn = "";
if(encoder == null)
encoder = Encoding.ASCII;
ArrayList nameBytes = new ArrayList();
byte curByte;
if(!noOffset)
binReader.BaseStream.Seek(offset, SeekOrigin.Begin);
if(binReader.BaseStream.Position >= binReader.BaseStream.Length)
return "";
curByte = binReader.ReadByte();
while( (curByte != (byte)0) && (binReader.BaseStream.Position < binReader.BaseStream.Length) )
{
nameBytes.Add( curByte );
curByte = binReader.ReadByte();
}
byte[] name = (byte[]) (nameBytes.ToArray(System.Type.GetType("System.Byte")));
strReturn = encoder.GetString(name,0,name.Length);
return strReturn;
}
/// <summary>
/// Internal helper method to extract a string with a specific length from the binary reader
/// </summary>
/// <param name="binReader">reference to the binary reader</param>
/// <param name="length">length of the string (number of bytes)</param>
/// <param name="offset">offset in the stream</param>
/// <param name="noOffset">true if the offset value should be used</param>
/// <param name="encoder">encoder used for text encoding</param>
/// <returns>An extracted string value</returns>
internal static string ExtractString(ref BinaryReader binReader, int length, int offset, bool noOffset, Encoding encoder)
{
string strReturn = "";
if(length == 0)
return "";
if(encoder == null)
encoder = Encoding.ASCII;
ArrayList nameBytes = new ArrayList();
byte curByte;
if(!noOffset)
binReader.BaseStream.Seek(offset, SeekOrigin.Begin);
if(binReader.BaseStream.Position >= binReader.BaseStream.Length)
return "";
curByte = binReader.ReadByte();
while( (curByte != (byte)0) && (nameBytes.Count < length) && (binReader.BaseStream.Position < binReader.BaseStream.Length) )
{
nameBytes.Add( curByte );
if(nameBytes.Count < length)
curByte = binReader.ReadByte();
}
byte[] name = (byte[]) (nameBytes.ToArray(System.Type.GetType("System.Byte")));
strReturn = encoder.GetString(name,0,name.Length);
return strReturn;
}
/// <summary>
/// Internal helper method to extract a string with a specific length from the binary reader
/// </summary>
/// <param name="binReader">reference to the binary reader</param>
/// <param name="bFoundTerminator">reference to a bool vairable which will receive true if the
/// string terminator \0 was found. false indicates that the end of the stream was reached.</param>
/// <param name="offset">offset in the stream</param>
/// <param name="noOffset">true if the offset value should be used</param>
/// <param name="encoder">encoder used for text encoding</param>
/// <returns>An extracted string value</returns>
internal static string ExtractString(ref BinaryReader binReader, ref bool bFoundTerminator, int offset, bool noOffset, Encoding encoder)
{
string strReturn = "";
ArrayList nameBytes = new ArrayList();
byte curByte;
if(encoder == null)
encoder = Encoding.ASCII;
if(!noOffset)
binReader.BaseStream.Seek(offset, SeekOrigin.Begin);
if(binReader.BaseStream.Position >= binReader.BaseStream.Length)
return "";
curByte = binReader.ReadByte();
while( (curByte != (byte)0) && (binReader.BaseStream.Position < binReader.BaseStream.Length) )
{
nameBytes.Add( curByte );
curByte = binReader.ReadByte();
if( curByte == (byte)0 )
{
bFoundTerminator = true;
}
}
byte[] name = (byte[]) (nameBytes.ToArray(System.Type.GetType("System.Byte")));
strReturn = encoder.GetString(name,0,name.Length);
return strReturn;
}
/// <summary>
/// Internal helper method to extract a null-terminated UTF-16/UCS-2 strings from a binary reader
/// </summary>
/// <param name="binReader">reference to the binary reader</param>
/// <param name="offset">offset in the stream</param>
/// <param name="noOffset">true if the offset value should be used</param>
/// <param name="encoder">encoder used for text encoding</param>
/// <returns>An extracted string value</returns>
internal static string ExtractUTF16String(ref BinaryReader binReader, int offset, bool noOffset, Encoding encoder)
{
string strReturn = "";
ArrayList nameBytes = new ArrayList();
byte curByte;
int lastByte=-1;
if(!noOffset)
binReader.BaseStream.Seek(offset, SeekOrigin.Begin);
if(binReader.BaseStream.Position >= binReader.BaseStream.Length)
return "";
if(encoder == null)
encoder = Encoding.Unicode;
curByte = binReader.ReadByte();
int nCnt = 0;
while( ((curByte != (byte)0) || (lastByte != 0) ) && (binReader.BaseStream.Position < binReader.BaseStream.Length) )
{
nameBytes.Add( curByte );
if(nCnt%2 == 0)
lastByte = (int)curByte;
curByte = binReader.ReadByte();
nCnt++;
}
byte[] name = (byte[]) (nameBytes.ToArray(System.Type.GetType("System.Byte")));
strReturn = Encoding.Unicode.GetString(name,0,name.Length);
// apply text encoding
name = Encoding.Default.GetBytes(strReturn);
strReturn = encoder.GetString(name,0,name.Length);
return strReturn;
}
/// <summary>
/// Internal helper for reading ENCINT encoded integer values
/// </summary>
/// <param name="binReader">reference to the reader</param>
/// <returns>a long value</returns>
internal static long ReadENCINT(ref BinaryReader binReader)
{
long nRet = 0;
byte buffer = 0;
int shift = 0;
if(binReader.BaseStream.Position >= binReader.BaseStream.Length)
return nRet;
do
{
buffer = binReader.ReadByte();
nRet |= ((long)((buffer & (byte)0x7F))) << shift;
shift += 7;
}while ( (buffer & (byte)0x80) != 0);
return nRet;
}
/// <summary>
/// Reads an s/r encoded value from the byte array and decodes it into an integer
/// </summary>
/// <param name="wclBits">a byte array containing all bits (contains only 0 or 1 elements)</param>
/// <param name="s">scale param for encoding</param>
/// <param name="r">root param for encoding</param>
/// <param name="nBitIndex">current index in the wclBits array</param>
/// <returns>Returns an decoded integer value.</returns>
internal static int ReadSRItem(byte[] wclBits, int s, int r, ref int nBitIndex)
{
int nRet = 0;
int q = r;
int nPref1Cnt = 0;
while( wclBits[nBitIndex++] == 1)
{
nPref1Cnt++;
}
if(nPref1Cnt == 0)
{
int nMask = 0;
for(int nbits=0; nbits<q;nbits++)
{
nMask |= ( 0x01 & (int)wclBits[nBitIndex]) << (q-nbits-1);
nBitIndex++;
}
nRet = nMask;
}
else
{
q += (nPref1Cnt-1);
int nMask = 0;
int nRMaxValue = 0;
for(int nbits=0; nbits<q;nbits++)
{
nMask |= ( 0x01 & (int)wclBits[nBitIndex]) << (q-nbits-1);
nBitIndex++;
}
for(int nsv=0; nsv<r; nsv++)
{
nRMaxValue = nRMaxValue << 1;
nRMaxValue |= 0x1;
}
nRMaxValue++; // startvalue of s/r encoding with 1 prefixing '1'
nRMaxValue *= (int) Math.Pow((double)2, (double)(nPref1Cnt-1));
nRet = nRMaxValue + nMask;
}
return nRet;
}
}
}

View File

@@ -0,0 +1,325 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
namespace HtmlHelp.ChmDecoding
{
/// <summary>
/// The class <c>CHMBtree</c> implements methods/properties to decode the binary help index.
/// This class automatically creates an index arraylist for the current CHMFile instance.
/// It does not store the index internally !
/// </summary>
/// <remarks>The binary index can be found in the storage file $WWKeywordLinks/BTree</remarks>
internal sealed class CHMBtree : IDisposable
{
/// <summary>
/// Constant specifying the size of the string blocks
/// </summary>
private const int BLOCK_SIZE = 2048;
/// <summary>
/// Internal flag specifying if the object is going to be disposed
/// </summary>
private bool disposed = false;
/// <summary>
/// Internal member storing the binary file data
/// </summary>
private byte[] _binaryFileData = null;
/// <summary>
/// Internal member storing flags
/// </summary>
private int _flags = 0;
/// <summary>
/// Internal member storing the data format
/// </summary>
private byte[] _dataFormat = new byte[16];
/// <summary>
/// Internal member storing the index of the last listing block
/// </summary>
private int _indexOfLastListingBlock = 0;
/// <summary>
/// Internal member storing the index of the root block
/// </summary>
private int _indexOfRootBlock = 0;
/// <summary>
/// Internal member storing the number of blocks
/// </summary>
private int _numberOfBlocks = 0;
/// <summary>
/// Internal member storing the tree depth.
/// (1 if no index blocks, 2 one level of index blocks, ...)
/// </summary>
private int _treeDepth = 0;
/// <summary>
/// Internal member storing the number of keywords in the file
/// </summary>
private int _numberOfKeywords = 0;
/// <summary>
/// Internal member storing the codepage
/// </summary>
private int _codePage = 0;
/// <summary>
/// true if the index is from a CHI or CHM file, else CHW
/// </summary>
private bool _isCHI_CHM = true;
/// <summary>
/// Internal member storing the associated chmfile object
/// </summary>
private CHMFile _associatedFile = null;
/// <summary>
/// Internal flag specifying if we have to read listing or index blocks
/// </summary>
private bool _readListingBlocks = true;
/// <summary>
/// Internal member storing an indexlist of the current file.
/// </summary>
private ArrayList _indexList = new ArrayList();
/// <summary>
/// Constructor of the class
/// </summary>
/// <param name="binaryFileData">binary file data of the $WWKeywordLinks/BTree file</param>
/// <param name="associatedFile">associated chm file</param>
public CHMBtree(byte[] binaryFileData, CHMFile associatedFile)
{
if( associatedFile == null)
{
throw new ArgumentException("CHMBtree.ctor() - Associated CHMFile must not be null !", "associatedFile");
}
_binaryFileData = binaryFileData;
_associatedFile = associatedFile;
DecodeData();
// clear internal binary data after extraction
_binaryFileData = null;
}
/// <summary>
/// Decodes the binary file data and fills the internal properties
/// </summary>
/// <returns>true if succeeded</returns>
private bool DecodeData()
{
bool bRet = true;
MemoryStream memStream = new MemoryStream(_binaryFileData);
BinaryReader binReader = new BinaryReader(memStream);
int nCurOffset = 0;
int nTemp = 0;
// decode header
binReader.ReadChars(2); // 2chars signature (not important)
_flags = (int)binReader.ReadInt16(); // WORD flags
binReader.ReadInt16(); // size of blocks (always 2048)
_dataFormat = binReader.ReadBytes(16);
binReader.ReadInt32(); // unknown DWORD
_indexOfLastListingBlock = binReader.ReadInt32();
_indexOfRootBlock = binReader.ReadInt32();
binReader.ReadInt32(); // unknown DWORD
_numberOfBlocks = binReader.ReadInt32();
_treeDepth = binReader.ReadInt16();
_numberOfKeywords = binReader.ReadInt32();
_codePage = binReader.ReadInt32();
binReader.ReadInt32(); // lcid DWORD
nTemp = binReader.ReadInt32();
_isCHI_CHM = (nTemp==1);
binReader.ReadInt32(); // unknown DWORD
binReader.ReadInt32(); // unknown DWORD
binReader.ReadInt32(); // unknown DWORD
binReader.ReadInt32(); // unknown DWORD
// end of header decode
while( (memStream.Position < memStream.Length) && (bRet) )
{
nCurOffset = (int)memStream.Position;
byte [] dataBlock = binReader.ReadBytes(BLOCK_SIZE);
bRet &= DecodeBlock(dataBlock, ref nCurOffset, _treeDepth-1);
}
return bRet;
}
/// <summary>
/// Decodes a block of url-string data
/// </summary>
/// <param name="dataBlock">block of data</param>
/// <param name="nOffset">current file offset</param>
/// <param name="indexBlocks">number of index blocks</param>
/// <returns>true if succeeded</returns>
private bool DecodeBlock( byte[] dataBlock, ref int nOffset, int indexBlocks )
{
bool bRet = true;
int nblockOffset = nOffset;
MemoryStream memStream = new MemoryStream(dataBlock);
BinaryReader binReader = new BinaryReader(memStream);
int freeSpace = binReader.ReadInt16(); // length of freespace
int nrOfEntries = binReader.ReadInt16(); // number of entries
bool bListingEndReached = false;
//while( (memStream.Position < (memStream.Length-freeSpace)) && (bRet) )
//{
int nIndexOfPrevBlock = -1;
int nIndexOfNextBlock = -1;
int nIndexOfChildBlock = 0;
if(_readListingBlocks)
{
nIndexOfPrevBlock = binReader.ReadInt32(); // -1 if this is the header
nIndexOfNextBlock = binReader.ReadInt32(); // -1 if this is the last block
}
else
{
nIndexOfChildBlock = binReader.ReadInt32();
}
for(int nE = 0; nE < nrOfEntries; nE++)
{
if(_readListingBlocks)
{
bListingEndReached = (nIndexOfNextBlock==-1);
string keyWord = BinaryReaderHelp.ExtractUTF16String(ref binReader, 0, true, _associatedFile.TextEncoding);
bool isSeeAlsoKeyword = (binReader.ReadInt16()!=0);
int indent = binReader.ReadInt16(); // indent of entry
int nCharIndex = binReader.ReadInt32();
binReader.ReadInt32();
int numberOfPairs = binReader.ReadInt32();
int[] nTopics = new int[numberOfPairs];
string[] seeAlso = new string[numberOfPairs];
for(int i=0; i < numberOfPairs; i++)
{
if(isSeeAlsoKeyword)
{
seeAlso[i] = BinaryReaderHelp.ExtractUTF16String(ref binReader, 0, true, _associatedFile.TextEncoding);
}
else
{
nTopics[i] = binReader.ReadInt32();
}
}
binReader.ReadInt32(); // unknown
int nIndexOfThisEntry = binReader.ReadInt32();
IndexItem newItem = new IndexItem(_associatedFile, keyWord, isSeeAlsoKeyword, indent, nCharIndex, nIndexOfThisEntry, seeAlso, nTopics);
_indexList.Add(newItem);
}
else
{
string keyWord = BinaryReaderHelp.ExtractUTF16String(ref binReader, 0, true, _associatedFile.TextEncoding);
bool isSeeAlsoKeyword = (binReader.ReadInt16()!=0);
int indent = binReader.ReadInt16(); // indent of entry
int nCharIndex = binReader.ReadInt32();
binReader.ReadInt32();
int numberOfPairs = binReader.ReadInt32();
int[] nTopics = new int[numberOfPairs];
string[] seeAlso = new string[numberOfPairs];
for(int i=0; i < numberOfPairs; i++)
{
if(isSeeAlsoKeyword)
{
seeAlso[i] = BinaryReaderHelp.ExtractUTF16String(ref binReader, 0, true, _associatedFile.TextEncoding);
}
else
{
nTopics[i] = binReader.ReadInt32();
}
}
int nIndexChild = binReader.ReadInt32();
int nIndexOfThisEntry=-1;
IndexItem newItem = new IndexItem(_associatedFile, keyWord, isSeeAlsoKeyword, indent, nCharIndex, nIndexOfThisEntry, seeAlso, nTopics);
_indexList.Add(newItem);
}
}
//}
binReader.ReadBytes(freeSpace);
if( bListingEndReached )
_readListingBlocks = false;
return bRet;
}
/// <summary>
/// Gets the internal generated index list
/// </summary>
internal ArrayList IndexList
{
get { return _indexList; }
}
/// <summary>
/// Implement IDisposable.
/// </summary>
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
/// <summary>
/// Dispose(bool disposing) executes in two distinct scenarios.
/// If disposing equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.
/// If disposing equals false, the method has been called by the
/// runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.
/// </summary>
/// <param name="disposing">disposing flag</param>
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
_binaryFileData = null;
}
}
disposed = true;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,286 @@
using System;
using System.Collections;
using System.IO;
namespace HtmlHelp.ChmDecoding
{
/// <summary>
/// The class <c>CHMIdxhdr</c> implements t properties which have been read from the #IDXHDR file.
/// </summary>
internal sealed class CHMIdxhdr : IDisposable
{
/// <summary>
/// Internal flag specifying if the object is going to be disposed
/// </summary>
private bool disposed = false;
/// <summary>
/// Internal member storing the binary file data
/// </summary>
private byte[] _binaryFileData = null;
/// <summary>
/// Internal member storing the number of topic nodes including the contents and index files
/// </summary>
private int _numberOfTopicNodes = 0;
/// <summary>
/// Internal member storing the offset in the #STRINGS file of the ImageList param of the "text/site properties" object of the sitemap contents
/// </summary>
private int _imageListOffset = 0;
/// <summary>
/// True if the value of the ImageType param of the "text/site properties" object of the sitemap contents is "Folder".
/// </summary>
private bool _imageTypeFolder = false;
/// <summary>
/// Internal member storing the background value
/// </summary>
private int _background = 0;
/// <summary>
/// Internal member storing the foreground value
/// </summary>
private int _foreground = 0;
/// <summary>
/// Internal member storing the offset in the #STRINGS file of the Font param of the "text/site properties" object of the sitemap contents
/// </summary>
private int _fontOffset = 0;
/// <summary>
/// Internal member storing the offset in the #STRINGS file of the FrameName param of the "text/site properties" object of the sitemap contents
/// </summary>
private int _frameNameOffset = 0;
/// <summary>
/// Internal member storing the offset in the #STRINGS file of the WindowName param of the "text/site properties" object of the sitemap contents
/// </summary>
private int _windowNameOffset = 0;
/// <summary>
/// Internal member storing the number of merged files
/// </summary>
private int _numberOfMergedFiles = 0;
/// <summary>
/// Internal member storing the offset in the #STRINGS file of the merged file names
/// </summary>
private ArrayList _mergedFileOffsets = new ArrayList();
/// <summary>
/// Internal member storing the associated chmfile object
/// </summary>
private CHMFile _associatedFile = null;
/// <summary>
/// Constructor of the class
/// </summary>
/// <param name="binaryFileData">binary file data of the #IDXHDR file</param>
/// <param name="associatedFile">associated CHMFile instance</param>
public CHMIdxhdr(byte[] binaryFileData, CHMFile associatedFile)
{
_binaryFileData = binaryFileData;
_associatedFile = associatedFile;
DecodeData();
}
/// <summary>
/// Decodes the binary file data and fills the internal properties
/// </summary>
/// <returns>true if succeeded</returns>
private bool DecodeData()
{
bool bRet = true;
MemoryStream memStream = new MemoryStream(_binaryFileData);
BinaryReader binReader = new BinaryReader(memStream);
int nTemp = 0;
// 4 character T#SM
binReader.ReadBytes(4);
// unknown timestamp DWORD
nTemp = binReader.ReadInt32();
// unknown 1
nTemp = binReader.ReadInt32();
// number of topic nodes including the contents & index files
_numberOfTopicNodes = binReader.ReadInt32();
// unknown DWORD
nTemp = binReader.ReadInt32();
// offset in the strings file
_imageListOffset = binReader.ReadInt32();
if( _imageListOffset == 0)
_imageListOffset = -1; // 0/-1 = none
// unknown DWORD
nTemp = binReader.ReadInt32();
// 1 if the value of the ImageType param of the "text/site properties" object of the sitemap contents is "Folder".
nTemp = binReader.ReadInt32();
_imageTypeFolder = (nTemp == 1);
// offset in the strings file
_background = binReader.ReadInt32();
// offset in the strings file
_foreground = binReader.ReadInt32();
// offset in the strings file
_fontOffset = binReader.ReadInt32();
// window styles DWORD
nTemp = binReader.ReadInt32();
// window styles DWORD
nTemp = binReader.ReadInt32();
// unknown DWORD
nTemp = binReader.ReadInt32();
// offset in the strings file
_frameNameOffset = binReader.ReadInt32();
if( _frameNameOffset == 0)
_frameNameOffset = -1; // 0/-1 = none
// offset in the strings file
_windowNameOffset = binReader.ReadInt32();
if( _windowNameOffset == 0)
_windowNameOffset = -1; // 0/-1 = none
// informations types DWORD
nTemp = binReader.ReadInt32();
// unknown DWORD
nTemp = binReader.ReadInt32();
// number of merged files in the merged file list DWORD
_numberOfMergedFiles = binReader.ReadInt32();
nTemp = binReader.ReadInt32();
for(int i = 0; i < _numberOfMergedFiles; i++)
{
// DWORD offset value of merged file
nTemp = binReader.ReadInt32();
if(nTemp > 0)
_mergedFileOffsets.Add(nTemp);
}
return bRet;
}
/// <summary>
/// Gets the number of topic nodes including the contents and index files
/// </summary>
public int NumberOfTopicNodes
{
get { return _numberOfTopicNodes; }
}
/// <summary>
/// Gets the offset in the #STRINGS file of the ImageList
/// param of the "text/site properties" object of the sitemap contents
/// </summary>
public int ImageListOffset
{
get { return _imageListOffset; }
}
/// <summary>
/// True if the value of the ImageType param of the
/// "text/site properties" object of the sitemap contents is "Folder".
/// </summary>
/// <remarks>If this is set to true, the help will display folders instead of books</remarks>
public bool ImageTypeFolder
{
get { return _imageTypeFolder; }
}
/// <summary>
/// Gets the background setting
/// </summary>
public int Background
{
get { return _background; }
}
/// <summary>
/// Gets the foreground setting
/// </summary>
public int Foreground
{
get { return _foreground; }
}
/// <summary>
/// Gets the offset in the #STRINGS file of the Font
/// param of the "text/site properties" object of the sitemap contents
/// </summary>
public int WindowNameOffset
{
get { return _fontOffset; }
}
/// <summary>
/// Gets the offset in the #STRINGS file of the FrameName
/// param of the "text/site properties" object of the sitemap contents
/// </summary>
public int FrameNameOffset
{
get { return _frameNameOffset; }
}
/// <summary>
/// Gets the offset in the #STRINGS file of the WindowName
/// param of the "text/site properties" object of the sitemap contents
/// </summary>
public int FontOffset
{
get { return _windowNameOffset; }
}
/// <summary>
/// Gets an array list of offset numbers in the #STRINGS file of the
/// merged file names.
/// </summary>
public ArrayList MergedFileOffsets
{
get { return _mergedFileOffsets; }
}
/// <summary>
/// Implement IDisposable.
/// </summary>
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
/// <summary>
/// Dispose(bool disposing) executes in two distinct scenarios.
/// If disposing equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.
/// If disposing equals false, the method has been called by the
/// runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.
/// </summary>
/// <param name="disposing">disposing flag</param>
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
_binaryFileData = null;
_mergedFileOffsets = null;
}
}
disposed = true;
}
}
}

View File

@@ -0,0 +1,256 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
namespace HtmlHelp.ChmDecoding
{
/// <summary>
/// The class <c>CHMStrings</c> implements a string collection read from the #STRINGS file
/// </summary>
internal sealed class CHMStrings : IDisposable
{
/// <summary>
/// Constant specifying the size of the string blocks
/// </summary>
private const int STRING_BLOCK_SIZE = 4096;
/// <summary>
/// Internal flag specifying if the object is going to be disposed
/// </summary>
private bool disposed = false;
/// <summary>
/// Internal member storing the binary file data
/// </summary>
private byte[] _binaryFileData = null;
/// <summary>
/// Internal member storing the string dictionary
/// </summary>
private Hashtable _stringDictionary = new Hashtable();
/// <summary>
/// Internal member storing the associated chmfile object
/// </summary>
private CHMFile _associatedFile = null;
/// <summary>
/// Constructor of the class
/// </summary>
/// <param name="binaryFileData">binary file data of the #STRINGS file</param>
/// <param name="associatedFile">associated chm file</param>
public CHMStrings(byte[] binaryFileData, CHMFile associatedFile)
{
_binaryFileData = binaryFileData;
_associatedFile = associatedFile;
DecodeData();
}
/// <summary>
/// Standard constructor
/// </summary>
internal CHMStrings()
{
}
#region Data dumping
/// <summary>
/// Dump the class data to a binary writer
/// </summary>
/// <param name="writer">writer to write the data</param>
internal void Dump(ref BinaryWriter writer)
{
writer.Write( _stringDictionary.Count );
if (_stringDictionary.Count != 0)
{
IDictionaryEnumerator iDictionaryEnumerator = _stringDictionary.GetEnumerator();
while (iDictionaryEnumerator.MoveNext())
{
DictionaryEntry dictionaryEntry = (DictionaryEntry)iDictionaryEnumerator.Current;
writer.Write( Int32.Parse(dictionaryEntry.Key.ToString()) );
writer.Write( dictionaryEntry.Value.ToString() );
}
}
}
/// <summary>
/// Reads the object data from a dump store
/// </summary>
/// <param name="reader">reader to read the data</param>
internal void ReadDump(ref BinaryReader reader)
{
int nCnt = reader.ReadInt32();
for(int i=0; i<nCnt;i++)
{
int nKey = reader.ReadInt32();
string sValue = reader.ReadString();
_stringDictionary[nKey.ToString()] = sValue;
}
}
/// <summary>
/// Sets the associated CHMFile instance
/// </summary>
/// <param name="associatedFile">instance to set</param>
internal void SetCHMFile(CHMFile associatedFile)
{
_associatedFile = associatedFile;
}
#endregion
/// <summary>
/// Decodes the binary file data and fills the internal properties
/// </summary>
/// <returns>true if succeeded</returns>
private bool DecodeData()
{
bool bRet = true;
MemoryStream memStream = new MemoryStream(_binaryFileData);
BinaryReader binReader = new BinaryReader(memStream);
//binReader.ReadByte(); // file starts with a NULL character for 0-based offset indexing
int nStringOffset = 0;
int nSubsetOffset = 0;
while( (memStream.Position < memStream.Length) && (bRet) )
{
nStringOffset = (int)memStream.Position;
byte [] stringBlock = binReader.ReadBytes(STRING_BLOCK_SIZE);
bRet &= DecodeBlock(stringBlock, ref nStringOffset, ref nSubsetOffset);
}
return bRet;
}
/// <summary>
/// Decodes a string block
/// </summary>
/// <param name="stringBlock">byte array which represents the string block</param>
/// <param name="nStringOffset">current string offset number</param>
/// <param name="nSubsetOffset">reference to a subset variable</param>
/// <returns>true if succeeded</returns>
/// <remarks>If a string crosses the end of a block then it will be cut off
/// without a NT and repeated in full, with a NT, at the start of the next block.
/// For eg "To customize the appearance of a contents file" might become
/// "To customize the (block ending)To customize the appearance of a contents file"
/// when there are 17 bytes left at the end of the block. </remarks>
private bool DecodeBlock( byte[] stringBlock, ref int nStringOffset, ref int nSubsetOffset)
{
bool bRet = true;
MemoryStream memStream = new MemoryStream(stringBlock);
BinaryReader binReader = new BinaryReader(memStream);
while( (memStream.Position < memStream.Length) && (bRet) )
{
bool bFoundTerminator = false;
int nCurOffset = nStringOffset + (int)memStream.Position;
string sTemp = BinaryReaderHelp.ExtractString(ref binReader, ref bFoundTerminator, 0, true, _associatedFile.TextEncoding);
if(nSubsetOffset != 0)
{
_stringDictionary[nSubsetOffset.ToString()] = sTemp.ToString();
}
else
{
_stringDictionary[nCurOffset.ToString()] = sTemp.ToString();
}
if( bFoundTerminator )
{
nSubsetOffset = 0;
}
else
{
nSubsetOffset = nCurOffset;
}
}
return bRet;
}
/// <summary>
/// Indexer which returns the string at a given offset
/// </summary>
public string this[int offset]
{
get
{
if(offset == -1)
return String.Empty;
string sTemp = (string)_stringDictionary[ offset.ToString() ];
if(sTemp == null)
return String.Empty;
return sTemp;
}
}
/// <summary>
/// Indexer which returns the string at a given offset
/// </summary>
public string this[string offset]
{
get
{
if(offset == "-1")
return String.Empty;
string sTemp = (string)_stringDictionary[ offset ];
if(sTemp == null)
return String.Empty;
return sTemp;
}
}
/// <summary>
/// Implement IDisposable.
/// </summary>
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
/// <summary>
/// Dispose(bool disposing) executes in two distinct scenarios.
/// If disposing equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.
/// If disposing equals false, the method has been called by the
/// runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.
/// </summary>
/// <param name="disposing">disposing flag</param>
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
_binaryFileData = null;
_stringDictionary = null;
}
}
disposed = true;
}
}
}

View File

@@ -0,0 +1,821 @@
using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Globalization;
namespace HtmlHelp.ChmDecoding
{
/// <summary>
/// The class <c>CHMSystem</c> reads the #SYSTEM file of the chm and stores its settings
/// </summary>
internal sealed class CHMSystem : IDisposable
{
/// <summary>
/// Internal flag specifying if the object is going to be disposed
/// </summary>
private bool disposed = false;
/// <summary>
/// Internal member storing the binary file data
/// </summary>
private byte[] _binaryFileData = null;
/// <summary>
/// Internal member storing the file version
/// </summary>
private int _fileVersion = 0;
/// <summary>
/// Internal member storing the contents file path
/// </summary>
private string _contentsFile = "";
/// <summary>
/// Internal member storing the index file path
/// </summary>
private string _indexFile = "";
/// <summary>
/// Internal member storing the default help topic
/// </summary>
private string _defaultTopic = "";
/// <summary>
/// Internal member storing the help-window title
/// </summary>
private string _title = "";
/// <summary>
/// Internal flag if dbcs is on
/// </summary>
private bool _dbcs = false;
/// <summary>
/// Internal flag if fulltext search is enabled
/// </summary>
private bool _fullTextSearch = false;
/// <summary>
/// Internal flag if KLinks are in the file
/// </summary>
private bool _hasKLinks = false;
/// <summary>
/// Internal flag if ALinks are in the file
/// </summary>
private bool _hasALinks = false;
/// <summary>
/// Internal member storing the name of the default window
/// </summary>
private string _defaultWindow = "";
/// <summary>
/// Internal member storing the filename of the compiled file
/// </summary>
private string _compileFile = "";
/// <summary>
/// Internal flag storing the offset value of the binary index
/// </summary>
private uint _binaryIndexURLTableID = 0;
/// <summary>
/// Inernal member storing the compiler version this file was compiled
/// </summary>
private string _compilerVersion = "";
/// <summary>
/// Internal flag storing the offset value of the binary TOC
/// </summary>
private uint _binaryTOCURLTableID = 0;
/// <summary>
/// Internal member storing the associated chmfile object
/// </summary>
private CHMFile _associatedFile = null;
/// <summary>
/// Internal member storing the default fontface, size, charset
/// </summary>
private string _defaultFont = "";
/// <summary>
/// Internal member storing the culture info of the file
/// </summary>
private CultureInfo _culture;
/// <summary>
/// Constructor of the class
/// </summary>
/// <param name="binaryFileData">binary file data of the #SYSTEM file</param>
/// <param name="associatedFile">associated chm file</param>
public CHMSystem(byte[] binaryFileData, CHMFile associatedFile)
{
_binaryFileData = binaryFileData;
_associatedFile = associatedFile;
DecodeData();
if(_culture == null)
{
// Set the text encoder of the chm file to the read charset/codepage
_associatedFile.TextEncoding = Encoding.GetEncoding( this.CodePage );
}
}
/// <summary>
/// Decodes the binary file data and fills the internal properties
/// </summary>
/// <returns>true if succeeded</returns>
private bool DecodeData()
{
bool bRet = true;
MemoryStream memStream = new MemoryStream(_binaryFileData);
BinaryReader binReader = new BinaryReader(memStream);
// First entry = DWORD for version number
_fileVersion = (int) binReader.ReadInt32();
while( (memStream.Position < memStream.Length) && (bRet) )
{
bRet &= DecodeEntry(ref binReader);
}
return bRet;
}
/// <summary>
/// Decodes an #system file entry
/// </summary>
/// <param name="binReader">binary reader reference</param>
/// <returns>true if succeeded</returns>
private bool DecodeEntry(ref BinaryReader binReader)
{
bool bRet = true;
int code = (int) binReader.ReadInt16(); // entry code, WORD
int length = (int) binReader.ReadInt16(); // length of entry
switch(code)
{
case 0:
{
_contentsFile = BinaryReaderHelp.ExtractString(ref binReader,length, 0, true, _associatedFile.TextEncoding);
};break;
case 1:
{
_indexFile = BinaryReaderHelp.ExtractString(ref binReader,length, 0, true, _associatedFile.TextEncoding);
};break;
case 2:
{
_defaultTopic = BinaryReaderHelp.ExtractString(ref binReader,length, 0, true, _associatedFile.TextEncoding);
};break;
case 3:
{
_title = BinaryReaderHelp.ExtractString(ref binReader,length, 0, true, _associatedFile.TextEncoding);
};break;
case 4:
{
int nTemp = 0;
nTemp = binReader.ReadInt32(); // read DWORD LCID
_culture = new CultureInfo(nTemp);
if(_culture != null)
_associatedFile.TextEncoding = Encoding.GetEncoding(_culture.TextInfo.ANSICodePage);
nTemp = binReader.ReadInt32(); // read DWORD DBCS
_dbcs = (nTemp == 1);
nTemp = binReader.ReadInt32(); // read DWORD Fulltext search
_fullTextSearch = (nTemp == 1);
nTemp = binReader.ReadInt32(); // read DWORD has klinks
_hasKLinks = (nTemp != 0);
nTemp = binReader.ReadInt32(); // read DWORD has alinks
_hasALinks = (nTemp != 0);
// read the rest of code 4 (not important for us)
byte[] temp = new byte[length-(5*4)];
temp = binReader.ReadBytes(length-(5*4));
};break;
case 5:
{
_defaultWindow = BinaryReaderHelp.ExtractString(ref binReader,length, 0, true, _associatedFile.TextEncoding);
};break;
case 6:
{
_compileFile = BinaryReaderHelp.ExtractString(ref binReader,length, 0, true, _associatedFile.TextEncoding);
};break;
case 7:
{
if(_fileVersion > 2)
{
_binaryIndexURLTableID = (uint) binReader.ReadInt32();
}
else
{
byte[] read = binReader.ReadBytes(length);
int i=read.Length;
}
};break;
case 8:
{
// abbreviation (not interresting for us)
byte[] read = binReader.ReadBytes(length);
int i=read.Length;
};break;
case 9:
{
_compilerVersion = BinaryReaderHelp.ExtractString(ref binReader,length, 0, true, _associatedFile.TextEncoding);
};break;
case 10:
{
// timestamp of the file (not interresting for us)
byte[] read = binReader.ReadBytes(length);
int i=read.Length;
};break;
case 11:
{
if(_fileVersion > 2)
{
_binaryTOCURLTableID = (uint) binReader.ReadInt32();
}
else
{
byte[] read = binReader.ReadBytes(length);
int i=read.Length;
}
};break;
case 12:
{
// number of information bytes
byte[] read = binReader.ReadBytes(length);
int i=read.Length;
};break;
case 13:
{
// copy of file #idxhdr
byte[] read = binReader.ReadBytes(length);
int i=read.Length;
};break;
case 14:
{
// custom tabs for HH viewer
byte[] read = binReader.ReadBytes(length);
int i=read.Length;
};break;
case 15:
{
// a checksum
byte[] read = binReader.ReadBytes(length);
int i=read.Length;
};break;
case 16:
{
// Default Font=string,number,number
// The string is the name of the font, the first number is the
// point size & the last number is the character set used by the font.
// For acceptable values see *_CHARSET defines in wingdi.h from the
// Windows SDK or the same file in MinGW or Wine.
// Most of the time you will only want to use 0, which is the value for ANSI,
// which is the subset of ASCII used by Windows.
_defaultFont = BinaryReaderHelp.ExtractString(ref binReader,length, 0, true, _associatedFile.TextEncoding);
};break;
default:
{
byte[] temp = new byte[length];
temp = binReader.ReadBytes(length);
//bRet = false;
int i=temp.Length;
};break;
}
return bRet;
}
/// <summary>
/// Reads all HHC files and checks which one has the global object tag.
/// This hhc file will be returned as master hhc
/// </summary>
/// <param name="hhcTopics">list of topics containing the extension hhc</param>
/// <param name="TopicItemArrayList">true if the arraylist contains topic items</param>
/// <returns>the filename of the found master toc</returns>
private string GetMasterHHC(ArrayList hhcTopics, bool TopicItemArrayList)
{
string sRet = "";
if( (hhcTopics!=null) && (hhcTopics.Count > 0) )
{
if( TopicItemArrayList )
{
if(hhcTopics.Count == 1)
{
sRet = ((TopicEntry)hhcTopics[0]).Locale;
}
else
{
foreach(TopicEntry curEntry in hhcTopics)
{
CHMStream.CHMStream iw=null;
MemoryStream fileObject=null;
if( _associatedFile.CurrentStorageWrapper == null)
{
iw=new CHMStream.CHMStream();
iw.OpenCHM(_associatedFile.ChmFilePath);
}
else
{
iw = _associatedFile.CurrentStorageWrapper;
}
fileObject = iw.OpenStream(curEntry.Locale);
if( fileObject != null)
{
string fileString =_associatedFile.TextEncoding.GetString(fileObject.ToArray(),0,(int)fileObject.Length);
fileObject.Close();
if( HHCParser.HasGlobalObjectTag(fileString, _associatedFile) )
{
sRet = curEntry.Locale;
break;
}
}
}
}
}
else
{
if(hhcTopics.Count == 1)
{
sRet = ((string)hhcTopics[0]);
}
else
{
foreach(string curEntry in hhcTopics)
{
CHMStream.CHMStream iw=null;
MemoryStream fileObject=null;
if( _associatedFile.CurrentStorageWrapper == null)
{
iw=new CHMStream.CHMStream();
iw.OpenCHM(_associatedFile.ChmFilePath);
}
else
{
iw = _associatedFile.CurrentStorageWrapper;
}
fileObject = iw.OpenStream(curEntry);
if( fileObject != null)
{
string fileString =_associatedFile.TextEncoding.GetString(fileObject.ToArray(),0,(int)fileObject.Length);
fileObject.Close();
if( HHCParser.HasGlobalObjectTag(fileString, _associatedFile) )
{
sRet = curEntry;
break;
}
}
}
}
}
}
return sRet;
}
/// <summary>
/// Gets the file version of the chm file.
/// 2 for Compatibility=1.0, 3 for Compatibility=1.1
/// </summary>
public int FileVersion
{
get { return _fileVersion; }
}
/// <summary>
/// Gets the contents file name
/// </summary>
public string ContentsFile
{
get
{
if( BinaryTOC ) // if the file contains a binary TOC
{
// make sure the CHMFile instance exists and has loaded the file #URLTBL
if( (_associatedFile != null) && (_associatedFile.UrltblFile != null ) )
{
// Get an url-table entry by its unique id
UrlTableEntry entry = _associatedFile.UrltblFile.GetByUniqueID( this.BinaryTOCURLTableID );
if(entry != null)
{
// entry found, return the url ( = filename )
return entry.URL;
}
}
}
else
{
if(_contentsFile.Length <= 0)
{
string sCheck = "Table of Contents.hhc"; // default HHP contents filename
if( (_associatedFile != null) && (_associatedFile.TopicsFile != null ) )
{
TopicEntry te = _associatedFile.TopicsFile.GetByLocale( sCheck );
if( te == null)
{
sCheck = "toc.hhc"; // default HHP contents filename
te = _associatedFile.TopicsFile.GetByLocale( sCheck );
if( te == null)
{
sCheck = CompileFile + ".hhc";
te = _associatedFile.TopicsFile.GetByLocale( sCheck );
if( te == null)
{
ArrayList arrExt = _associatedFile.TopicsFile.GetByExtension("hhc");
if( arrExt == null )
{
arrExt = _associatedFile.EnumFilesByExtension("hhc");
if( arrExt == null )
{
Debug.WriteLine("CHMSystem.ContentsFile - Failed, contents file not found !");
}
else
{
if(arrExt.Count > 1)
{
sCheck = GetMasterHHC(arrExt, false);
_contentsFile = sCheck;
}
else
{
_contentsFile = ((string)arrExt[0]);
sCheck = _contentsFile;
}
}
}
else
{
if(arrExt.Count > 1)
{
sCheck = GetMasterHHC(arrExt, true);
_contentsFile = sCheck;
}
else
{
_contentsFile = ((TopicEntry)arrExt[0]).Locale;
sCheck = _contentsFile;
}
}
}
else
{
_contentsFile = sCheck;
}
}
else
{
_contentsFile = sCheck;
}
}
else
{
_contentsFile = sCheck;
}
}
return sCheck;
}
}
return _contentsFile;
}
}
/// <summary>
/// Gets the index file name
/// </summary>
public string IndexFile
{
get
{
if( BinaryIndex ) // if the file contains a binary index
{
// make sure the CHMFile instance exists and has loaded the file #URLTBL
if( (_associatedFile != null) && (_associatedFile.UrltblFile != null ) )
{
// Get an url-table entry by its unique id
UrlTableEntry entry = _associatedFile.UrltblFile.GetByUniqueID( this.BinaryIndexURLTableID );
if(entry != null)
{
// entry found, return the url ( = filename )
return entry.URL;
}
}
}
else
{
if(_indexFile.Length <= 0)
{
string sCheck = "Index.hhk"; // default HHP index filename
if( (_associatedFile != null) && (_associatedFile.TopicsFile != null ) )
{
TopicEntry te = _associatedFile.TopicsFile.GetByLocale( sCheck );
if( te == null)
{
sCheck = CompileFile + ".hhk";
te = _associatedFile.TopicsFile.GetByLocale( sCheck );
if( te == null)
{
ArrayList arrExt = _associatedFile.TopicsFile.GetByExtension("hhk");
if( arrExt == null )
{
Debug.WriteLine("CHMSystem.IndexFile - Failed, index file not found !");
}
else
{
_indexFile = ((TopicEntry)arrExt[0]).Locale;
sCheck = _indexFile;
}
}
else
{
_indexFile = sCheck;
}
}
else
{
_indexFile = sCheck;
}
}
return sCheck;
}
}
return _indexFile;
}
}
/// <summary>
/// Sets the default topic of this file
/// </summary>
/// <param name="local">new local value of the topic</param>
internal void SetDefaultTopic(string local)
{
_defaultTopic = local;
}
/// <summary>
/// Gets the default help topic
/// </summary>
public string DefaultTopic
{
get { return _defaultTopic; }
}
/// <summary>
/// Gets the title of the help window
/// </summary>
public string Title
{
get { return _title; }
}
/// <summary>
/// Gets the flag if DBCS is in use
/// </summary>
public bool DBCS
{
get { return _dbcs; }
}
/// <summary>
/// Gets the flag if full-text-search is available
/// </summary>
public bool FullTextSearch
{
get { return _fullTextSearch; }
}
/// <summary>
/// Gets the flag if the file has ALinks
/// </summary>
public bool HasALinks
{
get { return _hasALinks; }
}
/// <summary>
/// Gets the flag if the file has KLinks
/// </summary>
public bool HasKLinks
{
get { return _hasKLinks; }
}
/// <summary>
/// Gets the default window name
/// </summary>
public string DefaultWindow
{
get { return _defaultWindow; }
}
/// <summary>
/// Gets the file name of the compile file
/// </summary>
public string CompileFile
{
get { return _compileFile; }
}
/// <summary>
/// Gets the id of the binary index in the url table
/// </summary>
public uint BinaryIndexURLTableID
{
get { return _binaryIndexURLTableID; }
}
/// <summary>
/// Gets the flag if the chm has a binary index file
/// </summary>
public bool BinaryIndex
{
get { return (_binaryIndexURLTableID>0); }
}
/// <summary>
/// Gets the flag if the chm has a binary index file
/// </summary>
public string CompilerVersion
{
get { return _compilerVersion; }
}
/// <summary>
/// Gets the id of the binary toc in the url table
/// </summary>
public uint BinaryTOCURLTableID
{
get { return _binaryTOCURLTableID; }
}
/// <summary>
/// Gets the flag if the chm has a binary toc file
/// </summary>
public bool BinaryTOC
{
get { return (_binaryTOCURLTableID>0); }
}
/// <summary>
/// Gets the font face of the read font property.
/// Empty string for default font.
/// </summary>
public string FontFace
{
get
{
if( _defaultFont.Length > 0)
{
string [] fontSplit = _defaultFont.Split( new char[]{','});
if(fontSplit.Length > 0)
return fontSplit[0].Trim();
}
return "";
}
}
/// <summary>
/// Gets the font size of the read font property.
/// 0 for default font size
/// </summary>
public double FontSize
{
get
{
if( _defaultFont.Length > 0)
{
string [] fontSplit = _defaultFont.Split( new char[]{','});
if(fontSplit.Length > 1)
return double.Parse(fontSplit[1].Trim());
}
return 0.0;
}
}
/// <summary>
/// Gets the character set of the read font property
/// 1 for default
/// </summary>
public int CharacterSet
{
get
{
if( _defaultFont.Length > 0)
{
string [] fontSplit = _defaultFont.Split( new char[]{','});
if(fontSplit.Length > 2)
return Int32.Parse(fontSplit[2].Trim());
}
return 0;
}
}
/// <summary>
/// Gets the codepage depending on the read font property
/// </summary>
public int CodePage
{
get
{
// if we've read a LCID from the system file
// ignore the font-property settings and return
// the codepage generated from the culture info
if(_culture != null)
{
return _culture.TextInfo.ANSICodePage;
}
int nRet = 1252; // default codepage windows-1252
int nCSet = CharacterSet;
switch(nCSet)
{
case 0x00: nRet = 1252;break; // ANSI_CHARSET
case 0xCC: nRet = 1251;break; // RUSSIAN_CHARSET
case 0xEE: nRet = 1250;break; // EE_CHARSET
case 0xA1: nRet = 1253;break; // GREEK_CHARSET
case 0xA2: nRet = 1254;break; // TURKISH_CHARSET
case 0xBA: nRet = 1257;break; // BALTIC_CHARSET
case 0xB1: nRet = 1255;break; // HEBREW_CHARSET
case 0xB2: nRet = 1256;break; // ARABIC_CHARSET
case 0x80: nRet = 932;break; // SHIFTJIS_CHARSET
case 0x81: nRet = 949;break; // HANGEUL_CHARSET
case 0x86: nRet = 936;break; // GB2313_CHARSET
case 0x88: nRet = 950;break; // CHINESEBIG5_CHARSET
}
return nRet;
}
}
/// <summary>
/// Gets the assiciated culture info
/// </summary>
public CultureInfo Culture
{
get { return _culture; }
}
/// <summary>
/// Implement IDisposable.
/// </summary>
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
/// <summary>
/// Dispose(bool disposing) executes in two distinct scenarios.
/// If disposing equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.
/// If disposing equals false, the method has been called by the
/// runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.
/// </summary>
/// <param name="disposing">disposing flag</param>
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
_binaryFileData = null;
}
}
disposed = true;
}
}
}

View File

@@ -0,0 +1,288 @@
using System;
using System.IO;
using System.Collections;
namespace HtmlHelp.ChmDecoding
{
/// <summary>
/// The class <c>CHMTocidx</c> implements functions to decode the #TOCIDX internal file.
/// </summary>
internal sealed class CHMTocidx : IDisposable
{
/// <summary>
/// Constant specifying the size of the data blocks
/// </summary>
private const int BLOCK_SIZE = 0x1000;
/// <summary>
/// Internal flag specifying if the object is going to be disposed
/// </summary>
private bool disposed = false;
/// <summary>
/// Internal member storing the binary file data
/// </summary>
private byte[] _binaryFileData = null;
/// <summary>
/// Internal memebr storing the offset to the 20/28 byte structs
/// </summary>
private int _offset2028 = 0;
/// <summary>
/// Internal member storing the offset to the 16 byte structs
/// </summary>
private int _offset16structs = 0;
/// <summary>
/// Internal member storing the number of 16 byte structs
/// </summary>
private int _numberOf16structs = 0;
/// <summary>
/// Internal member storing the offset to the topic list
/// </summary>
private int _offsetOftopics = 0;
/// <summary>
/// Internal member storing the toc
/// </summary>
private ArrayList _toc = new ArrayList();
/// <summary>
/// Internal member for offset seeking
/// </summary>
private Hashtable _offsetTable = new Hashtable();
/// <summary>
/// Internal member storing the associated chmfile object
/// </summary>
private CHMFile _associatedFile = null;
/// <summary>
/// Constructor of the class
/// </summary>
/// <param name="binaryFileData">binary file data of the #TOCIDX file</param>
/// <param name="associatedFile">associated chm file</param>
public CHMTocidx(byte[] binaryFileData, CHMFile associatedFile)
{
_binaryFileData = binaryFileData;
_associatedFile = associatedFile;
DecodeData();
// clear internal binary data after extraction
_binaryFileData = null;
}
/// <summary>
/// Decodes the binary file data and fills the internal properties
/// </summary>
/// <returns>true if succeeded</returns>
private bool DecodeData()
{
_toc = new ArrayList();
_offsetTable = new Hashtable();
bool bRet = true;
MemoryStream memStream = new MemoryStream(_binaryFileData);
BinaryReader binReader = new BinaryReader(memStream);
int nCurOffset = 0;
_offset2028 = binReader.ReadInt32();
_offset16structs = binReader.ReadInt32();
_numberOf16structs = binReader.ReadInt32();
_offsetOftopics = binReader.ReadInt32();
binReader.BaseStream.Seek( _offset2028, SeekOrigin.Begin );
if( RecursivelyBuildTree(ref binReader, _offset2028, _toc, null) )
{
binReader.BaseStream.Seek( _offset16structs, SeekOrigin.Begin );
nCurOffset = (int)binReader.BaseStream.Position;
for(int i=0; i < _numberOf16structs; i++)
{
int tocOffset = binReader.ReadInt32();
int sqNr = binReader.ReadInt32();
int topOffset = binReader.ReadInt32();
int hhctopicIdx = binReader.ReadInt32();
nCurOffset = (int)binReader.BaseStream.Position;
int topicIdx = -1;
// if the topic offset is within the range of the stream
// and is >= the offset of the first topic dword
if((topOffset < (binReader.BaseStream.Length - 4)) && (topOffset >= _offsetOftopics))
{
// read the index of the topic for this item
binReader.BaseStream.Seek( topOffset, SeekOrigin.Begin);
topicIdx = binReader.ReadInt32();
binReader.BaseStream.Seek( nCurOffset, SeekOrigin.Begin);
TOCItem item = (TOCItem)_offsetTable[tocOffset.ToString()];
if( item != null)
{
if(( topicIdx < _associatedFile.TopicsFile.TopicTable.Count)&&(topicIdx>=0))
{
TopicEntry te = (TopicEntry) (_associatedFile.TopicsFile.TopicTable[topicIdx]);
if( (te != null) && (item.TopicOffset < 0) )
{
item.TopicOffset = te.EntryOffset;
}
}
}
}
}
}
return bRet;
}
/// <summary>
/// Recursively reads the binary toc tree from the file
/// </summary>
/// <param name="binReader">reference to binary reader</param>
/// <param name="NodeOffset">offset of the first node in the current level</param>
/// <param name="level">arraylist of TOCItems for the current level</param>
/// <param name="parentItem">parent item for the item</param>
/// <returns>Returns true if succeeded</returns>
private bool RecursivelyBuildTree(ref BinaryReader binReader, int NodeOffset, ArrayList level, TOCItem parentItem)
{
bool bRet = true;
int nextOffset=0;
int nReadOffset = (int)binReader.BaseStream.Position;
binReader.BaseStream.Seek(NodeOffset, SeekOrigin.Begin);
do
{
int nCurOffset = (int)binReader.BaseStream.Position;
int unkn1 = binReader.ReadInt16(); // unknown
int unkn2 = binReader.ReadInt16(); // unknown
int flag = binReader.ReadInt32();
int nFolderAdd = 0;
if((_associatedFile != null) && (_associatedFile.ImageTypeFolder))
{
// get the value which should be added, to display folders instead of books
if(HtmlHelpSystem.UseHH2TreePics)
nFolderAdd = 8;
else
nFolderAdd = 4;
}
int nFolderImgIdx = (HtmlHelpSystem.UseHH2TreePics ? (TOCItem.STD_FOLDER_HH2+nFolderAdd) : (TOCItem.STD_FOLDER_HH1+nFolderAdd));
int nFileImgIdx = (HtmlHelpSystem.UseHH2TreePics ? TOCItem.STD_FILE_HH2 : TOCItem.STD_FILE_HH1);
int stdImage = ((flag & 0x4)!=0) ? nFolderImgIdx : nFileImgIdx;
int stringOffset = binReader.ReadInt32();
int ParentOffset = binReader.ReadInt32();
nextOffset = binReader.ReadInt32();
int firstChildOffset = 0;
int unkn3=0;
if( (flag&0x4)!=0 )
{
firstChildOffset = binReader.ReadInt32();
unkn3 = binReader.ReadInt32(); // unknown
}
TOCItem newItem = new TOCItem();
newItem.ImageIndex = stdImage;
newItem.Offset = nCurOffset;
newItem.OffsetNext = nextOffset;
newItem.AssociatedFile = _associatedFile;
newItem.TocMode = DataMode.Binary;
newItem.Parent = parentItem;
if( (flag&0x08) == 0)
{
// toc item doesn't have a local value (=> stringOffset = offset of strings file)
newItem.Name = _associatedFile.StringsFile[stringOffset];
}
else
{
// this item has a topic entry (=> stringOffset = index of topic entry)
if((stringOffset < _associatedFile.TopicsFile.TopicTable.Count) && (stringOffset >= 0))
{
TopicEntry te = (TopicEntry) (_associatedFile.TopicsFile.TopicTable[stringOffset]);
if(te != null)
{
newItem.TopicOffset = te.EntryOffset;
}
}
}
_offsetTable[nCurOffset.ToString()] = newItem;
// if this item has children (firstChildOffset > 0)
if( firstChildOffset > 0)
{
bRet &= RecursivelyBuildTree(ref binReader, firstChildOffset, newItem.Children, newItem);
}
level.Add( newItem );
if(nCurOffset != nextOffset)
binReader.BaseStream.Seek(nextOffset, SeekOrigin.Begin);
}while(nextOffset != 0);
binReader.BaseStream.Seek(nReadOffset, SeekOrigin.Begin);
return bRet;
}
/// <summary>
/// Gets the internal read toc
/// </summary>
internal ArrayList TOC
{
get { return _toc; }
}
/// <summary>
/// Implement IDisposable.
/// </summary>
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
/// <summary>
/// Dispose(bool disposing) executes in two distinct scenarios.
/// If disposing equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.
/// If disposing equals false, the method has been called by the
/// runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.
/// </summary>
/// <param name="disposing">disposing flag</param>
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
_binaryFileData = null;
_toc = null;
_offsetTable = null;
}
}
disposed = true;
}
}
}

View File

@@ -0,0 +1,235 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
namespace HtmlHelp.ChmDecoding
{
/// <summary>
/// The class <c>CHMTopics</c> implements functionality to decode the #TOPICS internal file
/// </summary>
internal sealed class CHMTopics : IDisposable
{
/// <summary>
/// Internal flag specifying if the object is going to be disposed
/// </summary>
private bool disposed = false;
/// <summary>
/// Internal member storing the binary file data
/// </summary>
private byte[] _binaryFileData = null;
/// <summary>
/// Internal member storing the associated chmfile object
/// </summary>
private CHMFile _associatedFile = null;
/// <summary>
/// Internal member storing the topic list
/// </summary>
private ArrayList _topicTable = new ArrayList();
/// <summary>
/// Constructor of the class
/// </summary>
/// <param name="binaryFileData">binary file data of the #TOPICS file</param>
/// <param name="associatedFile">associated chm file</param>
public CHMTopics(byte[] binaryFileData, CHMFile associatedFile)
{
_binaryFileData = binaryFileData;
_associatedFile = associatedFile;
DecodeData();
// clear internal binary data after extraction
_binaryFileData = null;
}
/// <summary>
/// Standard constructor
/// </summary>
internal CHMTopics()
{
}
#region Data dumping
/// <summary>
/// Dump the class data to a binary writer
/// </summary>
/// <param name="writer">writer to write the data</param>
internal void Dump(ref BinaryWriter writer)
{
writer.Write( _topicTable.Count );
foreach(TopicEntry curItem in _topicTable)
{
curItem.Dump(ref writer);
}
}
/// <summary>
/// Reads the object data from a dump store
/// </summary>
/// <param name="reader">reader to read the data</param>
internal void ReadDump(ref BinaryReader reader)
{
int i=0;
int nCnt = reader.ReadInt32();
for(i=0; i<nCnt;i++)
{
TopicEntry newItem = new TopicEntry();
newItem.SetCHMFile(_associatedFile);
newItem.ReadDump(ref reader);
_topicTable.Add(newItem);
}
}
/// <summary>
/// Sets the associated CHMFile instance
/// </summary>
/// <param name="associatedFile">instance to set</param>
internal void SetCHMFile(CHMFile associatedFile)
{
_associatedFile = associatedFile;
foreach(TopicEntry curEntry in _topicTable)
{
curEntry.SetCHMFile(associatedFile);
}
}
#endregion
/// <summary>
/// Decodes the binary file data and fills the internal properties
/// </summary>
/// <returns>true if succeeded</returns>
private bool DecodeData()
{
bool bRet = true;
MemoryStream memStream = new MemoryStream(_binaryFileData);
BinaryReader binReader = new BinaryReader(memStream);
int nCurOffset = 0;
while( (memStream.Position < memStream.Length) && (bRet) )
{
int entryOffset = nCurOffset;
int tocIdx = binReader.ReadInt32();
int titleOffset = binReader.ReadInt32();
int urltablOffset = binReader.ReadInt32();
int visibilityMode = binReader.ReadInt16();
int unknownMode = binReader.ReadInt16();
TopicEntry newEntry = new TopicEntry(entryOffset, tocIdx, titleOffset, urltablOffset, visibilityMode, unknownMode, _associatedFile);
_topicTable.Add( newEntry );
nCurOffset = (int)memStream.Position;
}
return bRet;
}
/// <summary>
/// Gets the arraylist containing all topic entries.
/// </summary>
public ArrayList TopicTable
{
get
{
return _topicTable;
}
}
/// <summary>
/// Gets the topic entry of a given offset
/// </summary>
public TopicEntry this[int offset]
{
get
{
foreach(TopicEntry curEntry in _topicTable)
if(curEntry.EntryOffset == offset)
return curEntry;
return null;
}
}
/// <summary>
/// Searches a topic by the locale name
/// </summary>
/// <param name="locale">locale name to search</param>
/// <returns>The topicentry instance if found, otherwise null</returns>
public TopicEntry GetByLocale(string locale)
{
foreach(TopicEntry curEntry in TopicTable)
{
if(curEntry.Locale.ToLower() == locale.ToLower())
return curEntry;
}
return null;
}
/// <summary>
/// Searches the topics for all files with a given file extension
/// </summary>
/// <param name="fileExtension">extension to search</param>
/// <returns>An arraylist of TopicEntry instances or null if no topic was found</returns>
public ArrayList GetByExtension(string fileExtension)
{
ArrayList arrRet = new ArrayList();
foreach(TopicEntry curEntry in TopicTable)
{
if(curEntry.Locale.ToLower().EndsWith(fileExtension.ToLower()))
arrRet.Add(curEntry);
}
if(arrRet.Count > 0)
return arrRet;
return null;
}
/// <summary>
/// Implement IDisposable.
/// </summary>
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
/// <summary>
/// Dispose(bool disposing) executes in two distinct scenarios.
/// If disposing equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.
/// If disposing equals false, the method has been called by the
/// runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.
/// </summary>
/// <param name="disposing">disposing flag</param>
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
_binaryFileData = null;
_topicTable=null;
}
}
disposed = true;
}
}
}

View File

@@ -0,0 +1,308 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
namespace HtmlHelp.ChmDecoding
{
/// <summary>
/// The class <c>CHMUrlstr</c> implements a string collection storing the URL strings of the help file
/// </summary>
internal sealed class CHMUrlstr : IDisposable
{
/// <summary>
/// Constant specifying the size of the string blocks
/// </summary>
private const int BLOCK_SIZE = 0x1000;
/// <summary>
/// Internal flag specifying if the object is going to be disposed
/// </summary>
private bool disposed = false;
/// <summary>
/// Internal member storing the binary file data
/// </summary>
private byte[] _binaryFileData = null;
/// <summary>
/// Internal member storing the url dictionary
/// </summary>
private Hashtable _urlDictionary = new Hashtable();
/// <summary>
/// Internal member storing the framename dictionary
/// </summary>
private Hashtable _framenameDictionary = new Hashtable();
/// <summary>
/// Internal member storing the associated chmfile object
/// </summary>
private CHMFile _associatedFile = null;
/// <summary>
/// Constructor of the class
/// </summary>
/// <param name="binaryFileData">binary file data of the #URLSTR file</param>
/// <param name="associatedFile">associated chm file</param>
public CHMUrlstr(byte[] binaryFileData, CHMFile associatedFile)
{
_binaryFileData = binaryFileData;
_associatedFile = associatedFile;
DecodeData();
// clear internal binary data after extraction
_binaryFileData = null;
}
/// <summary>
/// Standard constructor
/// </summary>
internal CHMUrlstr()
{
}
#region Data dumping
/// <summary>
/// Dump the class data to a binary writer
/// </summary>
/// <param name="writer">writer to write the data</param>
internal void Dump(ref BinaryWriter writer)
{
writer.Write( _urlDictionary.Count );
if (_urlDictionary.Count != 0)
{
IDictionaryEnumerator iDictionaryEnumerator = _urlDictionary.GetEnumerator();
while (iDictionaryEnumerator.MoveNext())
{
DictionaryEntry dictionaryEntry = (DictionaryEntry)iDictionaryEnumerator.Current;
writer.Write( Int32.Parse(dictionaryEntry.Key.ToString()) );
writer.Write( dictionaryEntry.Value.ToString() );
}
}
writer.Write( _framenameDictionary.Count );
if (_framenameDictionary.Count != 0)
{
IDictionaryEnumerator iDictionaryEnumerator = _framenameDictionary.GetEnumerator();
while (iDictionaryEnumerator.MoveNext())
{
DictionaryEntry dictionaryEntry = (DictionaryEntry)iDictionaryEnumerator.Current;
writer.Write( Int32.Parse(dictionaryEntry.Key.ToString()) );
writer.Write( dictionaryEntry.Value.ToString() );
}
}
}
/// <summary>
/// Reads the object data from a dump store
/// </summary>
/// <param name="reader">reader to read the data</param>
internal void ReadDump(ref BinaryReader reader)
{
int i=0;
int nCnt = reader.ReadInt32();
for(i=0; i<nCnt;i++)
{
int nKey = reader.ReadInt32();
string sValue = reader.ReadString();
_urlDictionary[nKey.ToString()] = sValue;
}
nCnt = reader.ReadInt32();
for(i=0; i<nCnt;i++)
{
int nKey = reader.ReadInt32();
string sValue = reader.ReadString();
_framenameDictionary[nKey.ToString()] = sValue;
}
}
/// <summary>
/// Sets the associated CHMFile instance
/// </summary>
/// <param name="associatedFile">instance to set</param>
internal void SetCHMFile(CHMFile associatedFile)
{
_associatedFile = associatedFile;
}
#endregion
/// <summary>
/// Decodes the binary file data and fills the internal properties
/// </summary>
/// <returns>true if succeeded</returns>
private bool DecodeData()
{
bool bRet = true;
MemoryStream memStream = new MemoryStream(_binaryFileData);
BinaryReader binReader = new BinaryReader(memStream);
int nCurOffset = 0;
while( (memStream.Position < memStream.Length) && (bRet) )
{
nCurOffset = (int)memStream.Position;
byte [] dataBlock = binReader.ReadBytes(BLOCK_SIZE);
bRet &= DecodeBlock(dataBlock, ref nCurOffset);
}
return bRet;
}
/// <summary>
/// Decodes a block of url-string data
/// </summary>
/// <param name="dataBlock">block of data</param>
/// <param name="nOffset">current file offset</param>
/// <returns>true if succeeded</returns>
private bool DecodeBlock( byte[] dataBlock, ref int nOffset )
{
bool bRet = true;
int blockOffset = nOffset;
MemoryStream memStream = new MemoryStream(dataBlock);
BinaryReader binReader = new BinaryReader(memStream);
if(nOffset==0)
binReader.ReadByte(); // first block starts with an unknown byte
while( (memStream.Position < (memStream.Length-8)) && (bRet) )
{
int entryOffset = blockOffset + (int)memStream.Position;
int urlOffset = binReader.ReadInt32();
int frameOffset = binReader.ReadInt32();
// There is one way to tell where the end of the URL/FrameName
// pairs occurs: Repeat the following: read 2 DWORDs and if both
// are less than the current offset then this is the start of the Local
// strings else skip two NT strings.
// if(( (urlOffset < (entryOffset+8)) && (frameOffset < (entryOffset+8)) ))
// {
// //TODO: add correct string reading if an offset has been found
// /*
// int curOffset = (int)memStream.Position;
//
// memStream.Seek( (long)(blockOffset-urlOffset), SeekOrigin.Begin);
// string sTemp = CHMReader.ExtractString(ref binReader, 0, true);
//
// memStream.Seek( (long)(blockOffset-frameOffset), SeekOrigin.Begin);
// sTemp = CHMReader.ExtractString(ref binReader, 0, true);
//
// memStream.Seek((long)curOffset, SeekOrigin.Begin);
// */
//
//
// int curOffs = (int)memStream.Position;
// BinaryReaderHelp.ExtractString(ref binReader, 0, true, _associatedFile.TextEncoding);
// nOffset += (int)memStream.Position - curOffs;
//
// curOffs = (int)memStream.Position;
// BinaryReaderHelp.ExtractString(ref binReader, 0, true, _associatedFile.TextEncoding);
// nOffset += (int)memStream.Position - curOffs;
// }
// else
{
bool bFoundTerminator = false;
string sTemp = BinaryReaderHelp.ExtractString(ref binReader, ref bFoundTerminator, 0, true, _associatedFile.TextEncoding);
if(sTemp == "")
{
//nOffset = nOffset + 1 + (int)memStream.Length - (int)memStream.Position;
memStream.Seek(memStream.Length-1, SeekOrigin.Begin);
}
else
{
_urlDictionary[entryOffset.ToString()] = sTemp.ToString();
_framenameDictionary[ entryOffset.ToString() ] = sTemp.ToString() ;
}
}
}
return bRet;
}
/// <summary>
/// Gets the url at a given offset
/// </summary>
/// <param name="offset">offset of url</param>
/// <returns>the url at the given offset</returns>
public string GetURLatOffset(int offset)
{
if(offset == -1)
return String.Empty;
string sTemp = (string)_urlDictionary[ offset.ToString() ];
if(sTemp == null)
return String.Empty;
return sTemp;
}
/// <summary>
/// Gets the framename at a given offset
/// </summary>
/// <param name="offset">offset of the framename</param>
/// <returns>the frame name at the given offset</returns>
public string GetFrameNameatOffset(int offset)
{
if(offset == -1)
return String.Empty;
string sTemp = (string)_framenameDictionary[ offset.ToString() ];
if(sTemp == null)
return String.Empty;
return sTemp;
}
/// <summary>
/// Implement IDisposable.
/// </summary>
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
/// <summary>
/// Dispose(bool disposing) executes in two distinct scenarios.
/// If disposing equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.
/// If disposing equals false, the method has been called by the
/// runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.
/// </summary>
/// <param name="disposing">disposing flag</param>
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
_binaryFileData = null;
_urlDictionary = null;
_framenameDictionary = null;
}
}
disposed = true;
}
}
}

View File

@@ -0,0 +1,245 @@
using System;
using System.IO;
using System.Collections;
namespace HtmlHelp.ChmDecoding
{
/// <summary>
/// The class <c>CHMUrltable</c> implements methods to decode the #URLTBL internal file.
/// </summary>
internal sealed class CHMUrltable : IDisposable
{
/// <summary>
/// Constant specifying the size of the data blocks
/// </summary>
private const int BLOCK_SIZE = 0x1000;
/// <summary>
/// Constant specifying the number of records per block
/// </summary>
private const int RECORDS_PER_BLOCK = 341;
/// <summary>
/// Internal flag specifying if the object is going to be disposed
/// </summary>
private bool disposed = false;
/// <summary>
/// Internal member storing the binary file data
/// </summary>
private byte[] _binaryFileData = null;
/// <summary>
/// Internal member storing the url table
/// </summary>
private ArrayList _urlTable = new ArrayList();
/// <summary>
/// Internal member storing the associated chmfile object
/// </summary>
private CHMFile _associatedFile = null;
/// <summary>
/// Constructor of the class
/// </summary>
/// <param name="binaryFileData">binary file data of the #URLTBL file</param>
/// <param name="associatedFile">associated chm file</param>
public CHMUrltable(byte[] binaryFileData, CHMFile associatedFile)
{
_binaryFileData = binaryFileData;
_associatedFile = associatedFile;
DecodeData();
// clear internal binary data after extraction
_binaryFileData = null;
}
/// <summary>
/// Standard constructor
/// </summary>
internal CHMUrltable()
{
}
#region Data dumping
/// <summary>
/// Dump the class data to a binary writer
/// </summary>
/// <param name="writer">writer to write the data</param>
internal void Dump(ref BinaryWriter writer)
{
writer.Write( _urlTable.Count );
foreach(UrlTableEntry curItem in _urlTable)
{
curItem.Dump(ref writer);
}
}
/// <summary>
/// Reads the object data from a dump store
/// </summary>
/// <param name="reader">reader to read the data</param>
internal void ReadDump(ref BinaryReader reader)
{
int i=0;
int nCnt = reader.ReadInt32();
for(i=0; i<nCnt;i++)
{
UrlTableEntry newItem = new UrlTableEntry();
newItem.SetCHMFile(_associatedFile);
newItem.ReadDump(ref reader);
_urlTable.Add(newItem);
}
}
/// <summary>
/// Sets the associated CHMFile instance
/// </summary>
/// <param name="associatedFile">instance to set</param>
internal void SetCHMFile(CHMFile associatedFile)
{
_associatedFile = associatedFile;
foreach(UrlTableEntry curEntry in _urlTable)
{
curEntry.SetCHMFile(associatedFile);
}
}
#endregion
/// <summary>
/// Decodes the binary file data and fills the internal properties
/// </summary>
/// <returns>true if succeeded</returns>
private bool DecodeData()
{
bool bRet = true;
MemoryStream memStream = new MemoryStream(_binaryFileData);
BinaryReader binReader = new BinaryReader(memStream);
int nCurOffset = 0;
while( (memStream.Position < memStream.Length) && (bRet) )
{
nCurOffset = (int)memStream.Position;
byte [] dataBlock = binReader.ReadBytes(BLOCK_SIZE);
bRet &= DecodeBlock(dataBlock, ref nCurOffset);
}
return bRet;
}
/// <summary>
/// Decodes a block of url-string data
/// </summary>
/// <param name="dataBlock">block of data</param>
/// <param name="nOffset">current file offset</param>
/// <returns>true if succeeded</returns>
private bool DecodeBlock( byte[] dataBlock, ref int nOffset )
{
bool bRet = true;
int blockOffset = nOffset;
MemoryStream memStream = new MemoryStream(dataBlock);
BinaryReader binReader = new BinaryReader(memStream);
for(int i=0; i < RECORDS_PER_BLOCK; i++)
{
int recordOffset = blockOffset + (int)memStream.Position;
uint nuniqueID = (uint) binReader.ReadInt32(); // unknown dword
int ntopicsIdx = binReader.ReadInt32();
int urlstrOffset = binReader.ReadInt32();
UrlTableEntry newEntry = new UrlTableEntry(nuniqueID, recordOffset, ntopicsIdx, urlstrOffset, _associatedFile);
_urlTable.Add(newEntry);
if( memStream.Position >= memStream.Length)
break;
}
if(dataBlock.Length == BLOCK_SIZE)
binReader.ReadInt32();
return bRet;
}
/// <summary>
/// Gets the arraylist containing all urltable entries.
/// </summary>
public ArrayList UrlTable
{
get
{
return _urlTable;
}
}
/// <summary>
/// Gets the urltable entry of a given offset
/// </summary>
public UrlTableEntry this[int offset]
{
get
{
foreach(UrlTableEntry curEntry in _urlTable)
if(curEntry.EntryOffset == offset)
return curEntry;
return null;
}
}
/// <summary>
/// Gets the urltable entry of a given uniqueID
/// </summary>
public UrlTableEntry GetByUniqueID(uint uniqueID)
{
foreach(UrlTableEntry curEntry in UrlTable)
{
if(curEntry.UniqueID == uniqueID)
return curEntry;
}
return null;
}
/// <summary>
/// Implement IDisposable.
/// </summary>
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
/// <summary>
/// Dispose(bool disposing) executes in two distinct scenarios.
/// If disposing equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.
/// If disposing equals false, the method has been called by the
/// runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.
/// </summary>
/// <param name="disposing">disposing flag</param>
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
_binaryFileData = null;
_urlTable = null;
}
}
disposed = true;
}
}
}

View File

@@ -0,0 +1,395 @@
using System;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Collections.Specialized;
using ICSharpCode.SharpZipLib;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using HtmlHelp;
// using HtmlHelp.Storage;
namespace HtmlHelp.ChmDecoding
{
/// <summary>
/// Enumeration for specifying the dumping compression
/// </summary>
public enum DumpCompression
{
/// <summary>
/// None - no data compression will be used.
/// Fastest but most memory intensive
/// </summary>
None = 0,
/// <summary>
/// Minimum - a minimum data compression will be used.
/// Fast but not much data reduction
/// </summary>
Minimum = 1,
/// <summary>
/// Medium - a medium data compression will be used.
/// Slower but medium data reduction
/// </summary>
Medium = 2,
/// <summary>
/// Maximum - a maximum data compression will be used.
/// Slowest but maximum data reduction
/// </summary>
Maximum = 3
}
/// <summary>
/// Flags which specify which data should be dumped
/// </summary>
[FlagsAttribute()]
public enum DumpingFlags
{
/// <summary>
/// DumpTextTOC - if this flag is set, text-based TOCs (sitemap format) will be dumped
/// </summary>
DumpTextTOC = 1,
/// <summary>
/// DumpBinaryTOC - if this flag is set, binary TOCs will be dumped
/// </summary>
DumpBinaryTOC = 2,
/// <summary>
/// DumpTextIndex - if this flag is set, the text-based index (sitemap format) will be dumped
/// </summary>
DumpTextIndex = 4,
/// <summary>
/// DumpBinaryIndex - if this flag is set, the binary index will be dumped
/// </summary>
DumpBinaryIndex = 8,
/// <summary>
/// DumpStrings - if this flag is set, the internal #STRINGS file will be dumped
/// </summary>
DumpStrings = 16,
/// <summary>
/// DumpUrlStr - if this flag is set, the internal #URLSTR file will be dumped
/// </summary>
DumpUrlStr = 32,
/// <summary>
/// DumpUrlTbl - if this flag is set, the internal #URLTBL file will be dumped
/// </summary>
DumpUrlTbl = 64,
/// <summary>
/// DumpTopics - if this flag is set, the internal #TOPICS file will be dumped
/// </summary>
DumpTopics = 128,
/// <summary>
/// DumpFullText - if this flag is set, the internal $FIftiMain file will be dumped
/// </summary>
DumpFullText = 256
}
/// <summary>
/// The class <c>DumpingInfo</c> implements information properties for the CHMFile class
/// if and how data dumping should be used.
/// </summary>
public sealed class DumpingInfo
{
public bool m_bAllowSaveDump=true;
private readonly static BitVector32.Section DumpFlags = BitVector32.CreateSection(512);
private const string _dumpHeader = "HtmlHelpSystem dump file 1.0";
private string _outputDir = ""; // emtpy string means, same directory as chm file
private DumpCompression _compressionLevel = DumpCompression.Maximum;
private CHMFile _chmFile = null;
private DeflaterOutputStream _outputStream = null;
private InflaterInputStream _inputStream = null;
private BinaryWriter _writer = null;
private BinaryReader _reader = null;
private BitVector32 _flags;
/// <summary>
/// Constructor of the class
/// </summary>
/// <param name="flags">Combine flag values to specify which data should be dumped.</param>
/// <param name="outputDir">output directory. emtpy string means,
/// same directory as chm file (only if destination = ExternalFile)</param>
/// <param name="compressionLevel">compression which should be used</param>
public DumpingInfo(DumpingFlags flags, string outputDir, DumpCompression compressionLevel)
{
_flags = new BitVector32(0);
int i = _flags[DumpFlags];
_flags[DumpFlags] = i | (int)flags;
_outputDir = outputDir;
_compressionLevel = compressionLevel;
}
/// <summary>
/// Gets the flag if text-based TOCs will be written to the dumping file
/// </summary>
public bool DumpTextTOC
{
get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpTextTOC) != 0); }
}
/// <summary>
/// Gets the flag if binary TOCs will be written to the dumping file
/// </summary>
public bool DumpBinaryTOC
{
get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpBinaryTOC) != 0); }
}
/// <summary>
/// Gets the flag if the text-based index will be written to the dumping file
/// </summary>
public bool DumpTextIndex
{
get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpTextIndex) != 0); }
}
/// <summary>
/// Gets the flag if the binary index will be written to the dumping file
/// </summary>
public bool DumpBinaryIndex
{
get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpBinaryIndex) != 0); }
}
/// <summary>
/// Gets the flag if the #STRINGS file will be written to the dumping file
/// </summary>
public bool DumpStrings
{
get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpStrings) != 0); }
}
/// <summary>
/// Gets the flag if the #URLSTR file will be written to the dumping file
/// </summary>
public bool DumpUrlStr
{
get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpUrlStr) != 0); }
}
/// <summary>
/// Gets the flag if the #URLTBL file will be written to the dumping file
/// </summary>
public bool DumpUrlTbl
{
get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpUrlTbl) != 0); }
}
/// <summary>
/// Gets the flag if the #TOPICS file will be written to the dumping file
/// </summary>
public bool DumpTopics
{
get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpTopics) != 0); }
}
/// <summary>
/// Gets the flag if the $FIftiMain file will be written to the dumping file
/// </summary>
public bool DumpFullText
{
get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpFullText) != 0); }
}
/// <summary>
/// Gets the dump output directory.
/// </summary>
/// <value>emtpy string means, same directory as chm file</value>
/// <remarks>If Destination is set to DumpingOutput.InternalFile this property will be ignored</remarks>
public string OutputDir
{
get { return _outputDir; }
}
/// <summary>
/// The compression level used.
/// </summary>
public DumpCompression CompressionLevel
{
get { return _compressionLevel; }
}
/// <summary>
/// Gets/Sets the CHMFile instance associated with this object
/// </summary>
internal CHMFile ChmFile
{
get { return _chmFile; }
set { _chmFile = value; }
}
/// <summary>
/// Translates the compression level to the deflater constants
/// </summary>
private int CompLvl
{
get
{
switch(CompressionLevel)
{
case DumpCompression.None: return Deflater.NO_COMPRESSION;
case DumpCompression.Minimum: return Deflater.BEST_SPEED;
case DumpCompression.Medium: return Deflater.DEFAULT_COMPRESSION;
case DumpCompression.Maximum: return Deflater.BEST_COMPRESSION;
}
return Deflater.BEST_COMPRESSION;
}
}
/// <summary>
/// Checks if a dump exists
/// </summary>
internal bool DumpExists
{
get
{
if(_flags[DumpFlags] == 0)
return false;
// we have a reader or writer to the dump so it must exist
if( (_reader != null) || (_writer != null) )
return true;
string sDmpFile = _chmFile.ChmFilePath;
sDmpFile=sDmpFile.ToLower().Replace(".chm",".CHB");
return File.Exists(sDmpFile);
}
}
/// <summary>
/// Gets a binary writer instance which allows you to write to the dump
/// </summary>
internal BinaryWriter Writer
{
get
{
if (m_bAllowSaveDump==false)
return null;
if(_flags[DumpFlags] == 0)
throw new InvalidOperationException("Nothing to dump. No flags have been set !");
if(_reader != null)
throw new InvalidOperationException("Can't write and read at the same time !");
if(_chmFile == null)
throw new InvalidOperationException("Only usable with an associated CHMFile instance !");
if(_writer==null)
{
string sDmpFile = _chmFile.ChmFilePath;
sDmpFile=sDmpFile.ToLower().Replace(".chm",".CHB");
StreamWriter stream = new StreamWriter(sDmpFile, false, _chmFile.TextEncoding);
// write header info uncompressed
BinaryWriter _hwriter = new BinaryWriter(stream.BaseStream);
_hwriter.Write(_dumpHeader);
_hwriter.Write((int)CompressionLevel);
if(_compressionLevel == DumpCompression.None)
{
_writer = new BinaryWriter(stream.BaseStream);
}
else
{
_outputStream = new DeflaterOutputStream(stream.BaseStream, new Deflater(CompLvl));
_writer = new BinaryWriter(_outputStream);
}
}
return _writer;
}
}
/// <summary>
/// Gets a binary reader which allows you to read from the dump
/// </summary>
internal BinaryReader Reader
{
get
{
if(_writer != null)
throw new InvalidOperationException("Can't write and read at the same time !");
if(_chmFile == null)
throw new InvalidOperationException("Only usable with an associated CHMFile instance !");
if(_reader==null)
{
string sDmpFile = _chmFile.ChmFilePath;
sDmpFile=sDmpFile.ToLower().Replace(".chm",".CHB");
StreamReader stream = new StreamReader(sDmpFile, _chmFile.TextEncoding);
BinaryReader _hReader = new BinaryReader(stream.BaseStream);
string sH = _hReader.ReadString();
if(sH != _dumpHeader)
{
_hReader.Close();
Debug.WriteLine("Unexpected dump-file header !");
throw new FormatException("DumpingInfo.Reader - Unexpected dump-file header !");
}
_compressionLevel = (DumpCompression)_hReader.ReadInt32();
// if(_compressionLevel != (DumpCompression)_hReader.ReadInt32())
// {
// _hReader.Close();
// return null;
// }
if(_compressionLevel == DumpCompression.None)
{
_reader = new BinaryReader(stream.BaseStream);
}
else
{
_inputStream = new InflaterInputStream(stream.BaseStream, new Inflater());
_reader = new BinaryReader(_inputStream);
}
}
return _reader;
}
}
/// <summary>
/// Saves data and closes the dump
/// </summary>
/// <returns>true if succeed</returns>
internal bool SaveData()
{
if (m_bAllowSaveDump==false)
return true;
if(_writer != null)
{
if(_writer!=null)
_writer.Close();
_outputStream = null;
_writer = null;
}
if(_reader != null)
{
if(_reader!=null)
_reader.Close();
_inputStream = null;
_reader = null;
}
return true;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,593 @@
using System;
using System.Collections;
using System.Text;
using System.Text.RegularExpressions;
namespace HtmlHelp.ChmDecoding
{
/// <summary>
/// The class <c>HHCParser</c> implements a parser for HHC contents files.
/// </summary>
internal sealed class HHCParser
{
/// <summary>
/// regular expressions for replacing the sitemap boundary tags
/// </summary>
private static string RE_ULOpening = @"\<ul\>"; // will be replaced by a '(' for nested parsing
private static string RE_ULClosing = @"\</ul\>"; // will be replaced by a ')' for nested parsing
/// <summary>
/// Matching ul-tags
/// </summary>
private static string RE_ULBoundaries = @"\<ul\>(?<innerText>.*)\</ul\>";
/// <summary>
/// Matching the nested tree structure.
/// </summary>
private static string RE_NestedBoundaries = @"\( (?> [^()]+ | \( (?<DEPTH>) | \) (?<-DEPTH>) )* (?(DEPTH)(?!)) \)";
/// <summary>
/// Matching object-tags
/// </summary>
private static string RE_ObjectBoundaries = @"\<object(?<innerText>.*?)\</object\>";
/// <summary>
/// Matching param tags
/// </summary>
private static string RE_ParamBoundaries = @"\<param(?<innerText>.*?)\>";
/// <summary>
/// Extracting tag attributes
/// </summary>
private const string RE_QuoteAttributes = @"( |\t)*(?<attributeName>[\-a-zA-Z0-9]*)( |\t)*=( |\t)*(?<attributeTD>[\""\'])?(?<attributeValue>.*?(?(attributeTD)\k<attributeTD>|([\s>]|.$)))";
/// <summary>
/// private regular expressionobjects
/// </summary>
private static Regex ulRE;
private static Regex NestedRE;
private static Regex ObjectRE;
private static Regex ParamRE;
private static Regex AttributesRE;
/// <summary>
/// Internal member storing the list of TOCItems which are holding merge links
/// </summary>
private static ArrayList _mergeItems = null;
/// <summary>
/// Internal member storing the last read regular topic item.
/// This is used to handle "Merge" entries and add them as child to this instance.
/// </summary>
private static TOCItem _lastTopicItem = null;
/// <summary>
/// Parses a HHC file and returns an ArrayList with the table of contents (TOC) tree
/// </summary>
/// <param name="hhcFile">string content of the hhc file</param>
/// <param name="chmFile">CHMFile instance</param>
/// <returns>Returns an ArrayList with the table of contents (TOC) tree</returns>
public static ArrayList ParseHHC(string hhcFile, CHMFile chmFile)
{
_lastTopicItem = null;
_mergeItems = null; // clear merged item list
ArrayList tocList = new ArrayList();
ulRE = new Regex(RE_ULBoundaries, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
NestedRE = new Regex(RE_NestedBoundaries, RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
ObjectRE = new Regex(RE_ObjectBoundaries, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
ParamRE = new Regex(RE_ParamBoundaries, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
AttributesRE = new Regex(RE_QuoteAttributes, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
int innerTextIdx = ulRE.GroupNumberFromName("innerText");
if( ulRE.IsMatch(hhcFile, 0) )
{
Match m = ulRE.Match(hhcFile, 0);
int nFirstUL = 0;
nFirstUL = hhcFile.ToLower().IndexOf("<ul>");
if(nFirstUL == -1)
nFirstUL = hhcFile.ToLower().IndexOf("<il>");
if( ObjectRE.IsMatch(hhcFile, 0) ) // first object block contains information types and categories
{
Match mO = ObjectRE.Match(hhcFile, 0);
int iOTxt = ObjectRE.GroupNumberFromName("innerText");
string globalText = mO.Groups[iOTxt].Value;
if( mO.Groups[iOTxt].Index <= nFirstUL)
ParseGlobalSettings( globalText, chmFile );
}
// parse toc tree
string innerText = m.Groups["innerText"].Value;
innerText = innerText.Replace("(", "&#040;");
innerText = innerText.Replace(")", "&#041;");
innerText = Regex.Replace(innerText, RE_ULOpening, "(", RegexOptions.IgnoreCase);
innerText = Regex.Replace(innerText, RE_ULClosing, ")", RegexOptions.IgnoreCase);
ParseTree( innerText, null, tocList, chmFile );
}
return tocList;
}
/// <summary>
/// Checks if the hhc file contains a global object tag.
/// </summary>
/// <param name="hhcFile">string content of the hhc file</param>
/// <param name="chmFile">chm file</param>
/// <returns>true if the hhc content contains a global object tag</returns>
public static bool HasGlobalObjectTag(string hhcFile, CHMFile chmFile)
{
bool bRet = false;
ulRE = new Regex(RE_ULBoundaries, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
ObjectRE = new Regex(RE_ObjectBoundaries, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
int innerTextIdx = ulRE.GroupNumberFromName("innerText");
if( ulRE.IsMatch(hhcFile, 0) )
{
Match m = ulRE.Match(hhcFile, 0);
int nFirstUL = 0;
nFirstUL = hhcFile.ToLower().IndexOf("<ul>");
if(nFirstUL == -1)
nFirstUL = hhcFile.ToLower().IndexOf("<il>");
if( ObjectRE.IsMatch(hhcFile, 0) ) // first object block contains information types and categories
{
Match mO = ObjectRE.Match(hhcFile, 0);
int iOTxt = ObjectRE.GroupNumberFromName("innerText");
string globalText = mO.Groups[iOTxt].Value;
if( mO.Groups[iOTxt].Index <= nFirstUL)
bRet = true;
}
}
return bRet;
}
/// <summary>
/// Gets true if the previously done parsing found merge-links
/// </summary>
public static bool HasMergeLinks
{
get
{
if(_mergeItems==null)
return false;
return _mergeItems.Count > 0;
}
}
/// <summary>
/// Gets all TOCItem references which are holding merge-links
/// </summary>
public static ArrayList MergeItems
{
get { return _mergeItems; }
}
/// <summary>
/// Recursively parses a sitemap tree
/// </summary>
/// <param name="text">content text</param>
/// <param name="parent">Parent for all read items</param>
/// <param name="arrNodes">arraylist which receives the extracted nodes</param>
/// <param name="chmFile">CHMFile instance</param>
private static void ParseTree( string text, TOCItem parent, ArrayList arrNodes, CHMFile chmFile )
{
string strPreItems="", strPostItems="";
string innerText = "";
int nIndex = 0;
while( NestedRE.IsMatch(text, nIndex) )
{
Match m = NestedRE.Match(text, nIndex);
innerText = m.Value.Substring( 1, m.Length-2);
strPreItems = text.Substring(nIndex,m.Index-nIndex);
ParseItems(strPreItems, parent, arrNodes, chmFile);
if((arrNodes.Count>0) && (innerText.Length > 0) )
{
TOCItem p = ((TOCItem)(arrNodes[arrNodes.Count-1]));
ParseTree( innerText, p, p.Children, chmFile );
}
nIndex = m.Index+m.Length;
}
if( nIndex == 0)
{
strPostItems = text.Substring(nIndex, text.Length-nIndex);
ParseItems(strPostItems, parent, arrNodes, chmFile);
}
else if( nIndex < text.Length-1)
{
strPostItems = text.Substring(nIndex, text.Length-nIndex);
ParseTree(strPostItems, parent, arrNodes, chmFile);
}
}
/// <summary>
/// Parses tree nodes from the text
/// </summary>
/// <param name="itemstext">text containing the items</param>
/// <param name="parent">Parent for all read items</param>
/// <param name="arrNodes">arraylist where the nodes should be added</param>
/// <param name="chmFile">CHMFile instance</param>
private static void ParseItems( string itemstext, TOCItem parent, ArrayList arrNodes, CHMFile chmFile)
{
int innerTextIdx = ObjectRE.GroupNumberFromName("innerText");
int innerPTextIdx = ParamRE.GroupNumberFromName("innerText");
// get group-name indexes
int nameIndex = AttributesRE.GroupNumberFromName("attributeName");
int valueIndex = AttributesRE.GroupNumberFromName("attributeValue");
int tdIndex = AttributesRE.GroupNumberFromName("attributeTD");
int nObjStartIndex = 0;
while( ObjectRE.IsMatch(itemstext, nObjStartIndex) )
{
Match m = ObjectRE.Match(itemstext, nObjStartIndex);
string innerText = m.Groups[innerTextIdx].Value;
TOCItem tocItem = new TOCItem();
tocItem.TocMode = DataMode.TextBased;
tocItem.AssociatedFile = chmFile;
tocItem.Parent = parent;
// read parameters
int nParamIndex = 0;
while( ParamRE.IsMatch(innerText, nParamIndex) )
{
Match mP = ParamRE.Match(innerText, nParamIndex);
string innerP = mP.Groups[innerPTextIdx].Value;
string paramName = "";
string paramValue = "";
int nAttrIdx = 0;
while( AttributesRE.IsMatch( innerP, nAttrIdx ) )
{
Match mA = AttributesRE.Match(innerP, nAttrIdx);
string attributeName = mA.Groups[nameIndex].Value;
string attributeValue = mA.Groups[valueIndex].Value;
string attributeTD = mA.Groups[tdIndex].Value;
if(attributeTD.Length > 0)
{
// delete the trailing textqualifier
if( attributeValue.Length > 0)
{
int ltqi = attributeValue.LastIndexOf( attributeTD );
if(ltqi >= 0)
{
attributeValue = attributeValue.Substring(0,ltqi);
}
}
}
if( attributeName.ToLower() == "name")
{
paramName = HttpUtility.HtmlDecode(attributeValue); // for unicode encoded values
}
if( attributeName.ToLower() == "value")
{
paramValue = HttpUtility.HtmlDecode(attributeValue); // for unicode encoded values
// delete trailing /
while((paramValue.Length>0)&&(paramValue[paramValue.Length-1] == '/'))
paramValue = paramValue.Substring(0,paramValue.Length-1);
}
nAttrIdx = mA.Index+mA.Length;
}
tocItem.Params[paramName] = paramValue;
switch(paramName.ToLower())
{
case "name":
{
tocItem.Name = paramValue;
};break;
case "local":
{
tocItem.Local = paramValue.Replace("../", "").Replace("./", "");
};break;
case "imagenumber":
{
tocItem.ImageIndex = Int32.Parse(paramValue);
tocItem.ImageIndex-=1;
int nFolderAdd = 0;
if((chmFile != null) && (chmFile.ImageTypeFolder))
{
// get the value which should be added, to display folders instead of books
if(HtmlHelpSystem.UseHH2TreePics)
nFolderAdd = 8;
else
nFolderAdd = 4;
}
if(tocItem.ImageIndex%2 != 0)
{
if(tocItem.ImageIndex==1)
tocItem.ImageIndex=0;
}
if(HtmlHelpSystem.UseHH2TreePics)
if( tocItem.ImageIndex == 0)
tocItem.ImageIndex = TOCItem.STD_FOLDER_HH2+nFolderAdd;
};break;
case "merge": // this item contains topics or a full TOC from a merged CHM
{
tocItem.MergeLink = paramValue;
// "register" this item as merge-link
if(_mergeItems==null)
_mergeItems=new ArrayList();
_mergeItems.Add(tocItem);
};break;
case "type": // information type assignment for item
{
tocItem.InfoTypeStrings.Add( paramValue );
};break;
}
nParamIndex = mP.Index+mP.Length;
}
tocItem.ChmFile = chmFile.ChmFilePath;
if(tocItem.MergeLink.Length > 0)
{
if(_lastTopicItem != null)
{
tocItem.Parent = _lastTopicItem;
_lastTopicItem.Children.Add(tocItem);
}
else
arrNodes.Add( tocItem );
}
else
{
_lastTopicItem = tocItem;
arrNodes.Add( tocItem );
}
nObjStartIndex = m.Index+m.Length;
}
}
/// <summary>
/// Parses the very first &lt;OBJECT&gt; tag in the sitemap file and extracts
/// information types and categories.
/// </summary>
/// <param name="sText">text of the object tag</param>
/// <param name="chmFile">CHMFile instance</param>
private static void ParseGlobalSettings(string sText, CHMFile chmFile)
{
int innerPTextIdx = ParamRE.GroupNumberFromName("innerText");
// get group-name indexes
int nameIndex = AttributesRE.GroupNumberFromName("attributeName");
int valueIndex = AttributesRE.GroupNumberFromName("attributeValue");
int tdIndex = AttributesRE.GroupNumberFromName("attributeTD");
// read parameters
int nParamIndex = 0;
// 0... unknown
// 1... inclusinve info type name
// 2... exclusive info type name
// 3... hidden info type name
// 4... category name
// 5... incl infotype name for category
// 6... excl infotype name for category
// 7... hidden infotype name for category
int prevItem = 0;
string sName = "";
string sDescription = "";
string curCategory = "";
while( ParamRE.IsMatch(sText, nParamIndex) )
{
Match mP = ParamRE.Match(sText, nParamIndex);
string innerP = mP.Groups[innerPTextIdx].Value;
string paramName = "";
string paramValue = "";
int nAttrIdx = 0;
while( AttributesRE.IsMatch( innerP, nAttrIdx ) )
{
Match mA = AttributesRE.Match(innerP, nAttrIdx);
string attributeName = mA.Groups[nameIndex].Value;
string attributeValue = mA.Groups[valueIndex].Value;
string attributeTD = mA.Groups[tdIndex].Value;
if(attributeTD.Length > 0)
{
// delete the trailing textqualifier
if( attributeValue.Length > 0)
{
int ltqi = attributeValue.LastIndexOf( attributeTD );
if(ltqi >= 0)
{
attributeValue = attributeValue.Substring(0,ltqi);
}
}
}
if( attributeName.ToLower() == "name")
{
paramName = HttpUtility.HtmlDecode(attributeValue); // for unicode encoded values
}
if( attributeName.ToLower() == "value")
{
paramValue = HttpUtility.HtmlDecode(attributeValue); // for unicode encoded values
// delete trailing /
while((paramValue.Length>0)&&(paramValue[paramValue.Length-1] == '/'))
paramValue = paramValue.Substring(0,paramValue.Length-1);
}
nAttrIdx = mA.Index+mA.Length;
}
switch(paramName.ToLower())
{
case "savetype": // inclusive information type name
{
prevItem = 1;
sName = paramValue;
};break;
case "savetypedesc": // description of information type
{
InformationTypeMode mode = InformationTypeMode.Inclusive;
sDescription = paramValue;
if( prevItem == 1)
mode = InformationTypeMode.Inclusive;
if( prevItem == 2)
mode = InformationTypeMode.Exclusive;
if( prevItem == 3)
mode = InformationTypeMode.Hidden;
if( chmFile.GetInformationType( sName ) == null)
{
// check if the HtmlHelpSystem already holds such an information type
if( chmFile.SystemInstance.GetInformationType( sName ) == null)
{
// info type not found yet
InformationType newType = new InformationType(sName, sDescription, mode);
chmFile.InformationTypes.Add(newType);
}
else
{
InformationType sysType = chmFile.SystemInstance.GetInformationType( sName );
chmFile.InformationTypes.Add( sysType );
}
}
prevItem = 0;
};break;
case "saveexclusive": // exclusive information type name
{
prevItem = 2;
sName = paramValue;
};break;
case "savehidden": // hidden information type name
{
prevItem = 3;
sName = paramValue;
};break;
case "category": // category name
{
prevItem = 4;
sName = paramValue;
curCategory = sName;
};break;
case "categorydesc": // category description
{
sDescription = paramValue;
if( chmFile.GetCategory( sName ) == null)
{
// check if the HtmlHelpSystem already holds such a category
if( chmFile.SystemInstance.GetCategory( sName ) == null)
{
// add category
Category newCat = new Category(sName, sDescription);
chmFile.Categories.Add(newCat);
}
else
{
Category sysCat = chmFile.SystemInstance.GetCategory( sName );
chmFile.Categories.Add( sysCat );
}
}
prevItem = 0;
};break;
case "type": // inclusive information type which is member of the previously read category
{
prevItem = 5;
sName = paramValue;
};break;
case "typedesc": // description of type for category
{
sDescription = paramValue;
Category cat = chmFile.GetCategory( curCategory );
if( cat != null)
{
// category found
InformationType infoType = chmFile.GetInformationType( sName );
if( infoType != null)
{
if( !cat.ContainsInformationType(infoType))
{
infoType.SetCategoryFlag(true);
cat.AddInformationType(infoType);
}
}
}
prevItem = 0;
};break;
case "typeexclusive": // exclusive information type which is member of the previously read category
{
prevItem = 6;
sName = paramValue;
};break;
case "typehidden": // hidden information type which is member of the previously read category
{
prevItem = 7;
sName = paramValue;
};break;
default:
{
prevItem = 0;
sName = "";
sDescription = "";
};break;
}
nParamIndex = mP.Index+mP.Length;
}
}
}
}

View File

@@ -0,0 +1,220 @@
using System;
using System.Collections;
using System.Text;
using System.Text.RegularExpressions;
namespace HtmlHelp.ChmDecoding
{
/// <summary>
/// The class <c>HHCParser</c> implements a parser for HHC contents files.
/// </summary>
// internal sealed class HHCParser : IHHCParser
public class HHCParser2
{
static private string m_text1="";
static private string m_text2="";
static private int m_CurrentPos=0;
/// <summary>
/// Parses a HHC file and returns an ArrayList with the table of contents (TOC) tree
/// </summary>
/// <param name="hhcFile">string content of the hhc file</param>
/// <param name="chmFile">CHMFile instance</param>
/// <returns>Returns an ArrayList with the table of contents (TOC) tree</returns>
public static ArrayList ParseHHC(string hhcFile, CHMFile chmFile)
{
DateTime StartTime=DateTime.Now;
ArrayList tocList = new ArrayList();
m_text2=hhcFile;
m_text1=hhcFile.ToLower();
int idx=m_text1.IndexOf("<ul>");
if (idx==-1)
return null;
m_CurrentPos=idx+4;
ParamRE = new Regex(RE_ParamBoundaries, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
AttributesRE = new Regex(RE_QuoteAttributes, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
ParseTree(tocList,chmFile);
DateTime EndTime=DateTime.Now;
TimeSpan Diff=EndTime-StartTime;
string x=Diff.ToString();
return tocList;
}
/// <summary>
/// Recursively parses a sitemap tree
/// </summary>
/// <param name="text">content text</param>
/// <param name="arrNodes">arraylist which receives the extracted nodes</param>
/// <param name="chmFile">CHMFile instance</param>
static private void ParseTree( ArrayList arrNodes, CHMFile chmFile )
{
bool bProcessing=true;
do
{
bProcessing=false;
// Indent
int idxa=m_text1.IndexOf("<ul>",m_CurrentPos);
int idxb=m_text1.IndexOf("<li>",m_CurrentPos);
int idxc=m_text1.IndexOf("</ul>",m_CurrentPos);
if ((idxa<idxb) && (idxa<idxc) && (idxa>-1))
{
bProcessing=true;
m_CurrentPos=idxa+4;
if (arrNodes.Count<1)
{
ParseTree(arrNodes,chmFile);
}
else
{
ParseTree(((TOCItem)(arrNodes[arrNodes.Count-1])).Children,chmFile);
}
continue;
}
// new item
if ((idxb<idxa) && (idxb<idxc) && (idxb>-1))
{
bProcessing=true;
m_CurrentPos=idxb+4;
int idx2=m_text1.IndexOf("<object",m_CurrentPos);
if (idx2!=-1)
{
int idx3=m_text1.IndexOf("</object>",idx2+7);
if (idx3!=-1)
{
string text=m_text2.Substring(idx2,idx3-idx2);
m_CurrentPos=idx3+9;
// Parse items in text.
TOCItem tocItem=ParseItems(text, chmFile);
if (tocItem!=null)
{
arrNodes.Add(tocItem);
}
}
}
}
// Undent
if ((idxc<idxa) && (idxc<idxb) && (idxc>-1))
{
m_CurrentPos=idxc+5;
bProcessing=true;
return;
}
}
while (bProcessing);
}
private static string RE_ParamBoundaries = @"\<param(?<innerText>.*?)\>";
private const string RE_QuoteAttributes = @"( |\t)*(?<attributeName>[\-a-zA-Z0-9]*)( |\t)*=( |\t)*(?<attributeTD>[\""\'])?(?<attributeValue>.*?(?(attributeTD)\k<attributeTD>|([\s>]|.$)))";
private static Regex ParamRE;
private static Regex AttributesRE;
/// <summary>
/// Parses tree nodes from the text
/// </summary>
/// <param name="itemstext">text containing the items</param>
/// <param name="arrNodes">arraylist where the nodes should be added</param>
/// <param name="chmFile">CHMFile instance</param>
private static TOCItem ParseItems( string itemstext, CHMFile chmFile)
{
int innerPTextIdx = ParamRE.GroupNumberFromName("innerText");
// get group-name indexes
int nameIndex = AttributesRE.GroupNumberFromName("attributeName");
int valueIndex = AttributesRE.GroupNumberFromName("attributeValue");
int tdIndex = AttributesRE.GroupNumberFromName("attributeTD");
TOCItem tocItem = new TOCItem();
// read parameters
int nParamIndex = 0;
while( ParamRE.IsMatch(itemstext, nParamIndex) )
{
Match mP = ParamRE.Match(itemstext, nParamIndex);
string innerP = mP.Groups[innerPTextIdx].Value;
string paramName = "";
string paramValue = "";
int nAttrIdx = 0;
while( AttributesRE.IsMatch( innerP, nAttrIdx ) )
{
Match mA = AttributesRE.Match(innerP, nAttrIdx);
string attributeName = mA.Groups[nameIndex].Value;
string attributeValue = mA.Groups[valueIndex].Value;
string attributeTD = mA.Groups[tdIndex].Value;
if(attributeTD.Length > 0)
{
// delete the trailing textqualifier
if( attributeValue.Length > 0)
{
int ltqi = attributeValue.LastIndexOf( attributeTD );
if(ltqi >= 0)
{
attributeValue = attributeValue.Substring(0,ltqi);
}
}
}
if( attributeName.ToLower() == "name")
{
paramName = attributeValue;
}
if( attributeName.ToLower() == "value")
{
paramValue = attributeValue;
}
nAttrIdx = mA.Index+mA.Length;
}
tocItem.Params[paramName] = paramValue;
switch(paramName.ToLower())
{
case "name":
{
tocItem.Name = paramValue;
};break;
case "local":
{
tocItem.Local = paramValue;
};break;
case "imagenumber":
{
tocItem.ImageIndex = Int32.Parse(paramValue);
if( tocItem.ImageIndex == 2)
tocItem.ImageIndex = TOCItem.STD_FOLDER_HH1;
};break;
}
nParamIndex = mP.Index+mP.Length;
}
tocItem.ChmFile = chmFile.ChmFilePath;
return tocItem;
}
}
}

View File

@@ -0,0 +1,550 @@
using System;
using System.IO;
using System.Collections;
using System.Text;
using System.Text.RegularExpressions;
namespace HtmlHelp.ChmDecoding
{
/// <summary>
/// The class <c>HHKParser</c> implements a parser for HHK contents files.
/// </summary>
internal sealed class HHKParser
{
/// <summary>
/// regular expressions for replacing the sitemap boundary tags
/// </summary>
private static string RE_ULOpening = @"\<ul\>"; // will be replaced by a '(' for nested parsing
private static string RE_ULClosing = @"\</ul\>"; // will be replaced by a ')' for nested parsing
/// <summary>
/// Matching ul-tags
/// </summary>
private static string RE_ULBoundaries = @"\<ul\>(?<innerText>.*)\</ul\>";
/// <summary>
/// Matching the nested tree structure.
/// </summary>
private static string RE_NestedBoundaries = @"\( (?> [^()]+ | \( (?<DEPTH>) | \) (?<-DEPTH>) )* (?(DEPTH)(?!)) \)";
/// <summary>
/// Matching object-tags
/// </summary>
private static string RE_ObjectBoundaries = @"\<object(?<innerText>.*?)\</object\>";
/// <summary>
/// Matching param tags
/// </summary>
private static string RE_ParamBoundaries = @"\<param(?<innerText>.*?)\>";
/// <summary>
/// Extracting tag attributes
/// </summary>
private const string RE_QuoteAttributes = @"( |\t)*(?<attributeName>[\-a-zA-Z0-9]*)( |\t)*=( |\t)*(?<attributeTD>[\""\'])?(?<attributeValue>.*?(?(attributeTD)\k<attributeTD>|([\s>]|.$)))";
/// <summary>
/// private regular expressionobjects
/// </summary>
private static Regex ulRE;
private static Regex NestedRE;
private static Regex ObjectRE;
private static Regex ParamRE;
private static Regex AttributesRE;
/// <summary>
/// Parses a HHK file and returns an ArrayList with the index tree
/// </summary>
/// <param name="hhkFile">string content of the hhk file</param>
/// <param name="chmFile">CHMFile instance</param>
/// <returns>Returns an ArrayList with the index tree</returns>
public static ArrayList ParseHHK(string hhkFile, CHMFile chmFile)
{
ArrayList indexList = new ArrayList();
ulRE = new Regex(RE_ULBoundaries, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
NestedRE = new Regex(RE_NestedBoundaries, RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
ObjectRE = new Regex(RE_ObjectBoundaries, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
ParamRE = new Regex(RE_ParamBoundaries, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
AttributesRE = new Regex(RE_QuoteAttributes, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
int innerTextIdx = ulRE.GroupNumberFromName("innerText");
if( ulRE.IsMatch(hhkFile, 0) )
{
Match m = ulRE.Match(hhkFile, 0);
if( ObjectRE.IsMatch(hhkFile, 0) ) // first object block contains information types and categories
{
Match mO = ObjectRE.Match(hhkFile, 0);
int iOTxt = ObjectRE.GroupNumberFromName("innerText");
string globalText = mO.Groups[iOTxt].Value;
ParseGlobalSettings( globalText, chmFile );
}
string innerText = m.Groups["innerText"].Value;
innerText = innerText.Replace("(", "&#040;");
innerText = innerText.Replace(")", "&#041;");
innerText = Regex.Replace(innerText, RE_ULOpening, "(", RegexOptions.IgnoreCase);
innerText = Regex.Replace(innerText, RE_ULClosing, ")", RegexOptions.IgnoreCase);
ParseTree( innerText, null, indexList, chmFile );
}
return indexList;
}
/// <summary>
/// Recursively parses a sitemap tree
/// </summary>
/// <param name="text">content text</param>
/// <param name="parent">Parent for all read items</param>
/// <param name="arrNodes">arraylist which receives the extracted nodes</param>
/// <param name="chmFile">CHMFile instance</param>
private static void ParseTree( string text, IndexItem parent, ArrayList arrNodes, CHMFile chmFile )
{
string strPreItems="", strPostItems="";
string innerText = "";
int nIndex = 0;
while( NestedRE.IsMatch(text, nIndex) )
{
Match m = NestedRE.Match(text, nIndex);
innerText = m.Value.Substring( 1, m.Length-2);
strPreItems = text.Substring(nIndex,m.Index-nIndex);
ParseItems(strPreItems, parent, arrNodes, chmFile);
if((arrNodes.Count>0) && (innerText.Length > 0) )
{
IndexItem p = ((IndexItem)(arrNodes[arrNodes.Count-1]));
ParseTree( innerText, p, arrNodes, chmFile );
}
nIndex = m.Index+m.Length;
}
if( nIndex == 0)
{
strPostItems = text.Substring(nIndex, text.Length-nIndex);
ParseItems(strPostItems, parent, arrNodes, chmFile);
}
else if( nIndex < text.Length-1)
{
strPostItems = text.Substring(nIndex, text.Length-nIndex);
ParseTree(strPostItems, parent, arrNodes, chmFile);
}
}
/// <summary>
/// Parses nodes from the text
/// </summary>
/// <param name="itemstext">text containing the items</param>
/// <param name="parentItem">parent index item</param>
/// <param name="arrNodes">arraylist where the nodes should be added</param>
/// <param name="chmFile">CHMFile instance</param>
private static void ParseItems( string itemstext, IndexItem parentItem, ArrayList arrNodes, CHMFile chmFile)
{
int innerTextIdx = ObjectRE.GroupNumberFromName("innerText");
int innerPTextIdx = ParamRE.GroupNumberFromName("innerText");
// get group-name indexes
int nameIndex = AttributesRE.GroupNumberFromName("attributeName");
int valueIndex = AttributesRE.GroupNumberFromName("attributeValue");
int tdIndex = AttributesRE.GroupNumberFromName("attributeTD");
int nObjStartIndex = 0;
int nLastObjStartIndex = 0;
string sKeyword = "";
while( ObjectRE.IsMatch(itemstext, nObjStartIndex) )
{
Match m = ObjectRE.Match(itemstext, nObjStartIndex);
string innerText = m.Groups[innerTextIdx].Value;
IndexItem idxItem = new IndexItem();
// read parameters
int nParamIndex = 0;
int nNameCnt = 0;
string paramTitle = "";
string paramLocal = "";
bool bAdded = false;
while( ParamRE.IsMatch(innerText, nParamIndex) )
{
Match mP = ParamRE.Match(innerText, nParamIndex);
string innerP = mP.Groups[innerPTextIdx].Value;
string paramName = "";
string paramValue = "";
int nAttrIdx = 0;
//sKeyword = "";
while( AttributesRE.IsMatch( innerP, nAttrIdx ) )
{
Match mA = AttributesRE.Match(innerP, nAttrIdx);
string attributeName = mA.Groups[nameIndex].Value;
string attributeValue = mA.Groups[valueIndex].Value;
string attributeTD = mA.Groups[tdIndex].Value;
if(attributeTD.Length > 0)
{
// delete the trailing textqualifier
if( attributeValue.Length > 0)
{
int ltqi = attributeValue.LastIndexOf( attributeTD );
if(ltqi >= 0)
{
attributeValue = attributeValue.Substring(0,ltqi);
}
}
}
if( attributeName.ToLower() == "name")
{
paramName = HttpUtility.HtmlDecode(attributeValue); // for unicode encoded values
nNameCnt++;
}
if( attributeName.ToLower() == "value")
{
paramValue = HttpUtility.HtmlDecode(attributeValue); // for unicode encoded values
// delete trailing /
while((paramValue.Length>0)&&(paramValue[paramValue.Length-1] == '/'))
paramValue = paramValue.Substring(0,paramValue.Length-1);
}
nAttrIdx = mA.Index+mA.Length;
}
if( nNameCnt == 1) // first "Name" param = keyword
{
sKeyword = "";
if(parentItem != null)
sKeyword = parentItem.KeyWordPath + ",";
string sOldKW = sKeyword;
sKeyword += paramValue;
IndexItem idxFind = FindByKeyword(arrNodes, sKeyword);
if(idxFind != null)
{
idxItem = idxFind;
}
else
{
if( sKeyword.Split(new char[] {','}).Length > 1 )
{
idxItem.CharIndex = sKeyword.Length - paramValue.Length;
}
else
{
sKeyword = paramValue;
sOldKW = sKeyword;
idxItem.CharIndex = 0;
}
idxItem.KeyWordPath = sKeyword;
idxItem.Indent = sKeyword.Split(new char[] {','}).Length - 1;
idxItem.IsSeeAlso = false;
sKeyword = sOldKW;
}
}
else
{
if( (nNameCnt > 2) && (paramName.ToLower()=="name") )
{
bAdded = true;
IndexTopic idxTopic = new IndexTopic(paramTitle, paramLocal, chmFile.CompileFile, chmFile.ChmFilePath);
idxItem.Topics.Add( idxTopic );
paramTitle = "";
paramLocal = "";
}
switch(paramName.ToLower())
{
case "name":
//case "keyword":
{
paramTitle = paramValue;
};break;
case "local":
{
paramLocal = paramValue.Replace("../", "").Replace("./", "");
};break;
case "type": // information type assignment for item
{
idxItem.InfoTypeStrings.Add( paramValue );
};break;
case "see also":
{
idxItem.AddSeeAlso(paramValue);
idxItem.IsSeeAlso = true;
bAdded = true;
};break;
}
}
nParamIndex = mP.Index+mP.Length;
}
if(!bAdded)
{
bAdded=false;
IndexTopic idxTopic = new IndexTopic(paramTitle, paramLocal, chmFile.CompileFile, chmFile.ChmFilePath);
idxItem.Topics.Add( idxTopic );
paramTitle = "";
paramLocal = "";
}
idxItem.ChmFile = chmFile;
arrNodes.Add( idxItem );
nLastObjStartIndex = nObjStartIndex;
nObjStartIndex = m.Index+m.Length;
}
}
/// <summary>
/// Searches an index-keyword in the index list
/// </summary>
/// <param name="indexList">index list to search</param>
/// <param name="Keyword">keyword to find</param>
/// <returns>Returns an <see cref="IndexItem">IndexItem</see> instance if found, otherwise null.</returns>
private static IndexItem FindByKeyword(ArrayList indexList, string Keyword)
{
foreach(IndexItem curItem in indexList)
{
if( curItem.KeyWordPath == Keyword)
return curItem;
}
return null;
}
/// <summary>
/// Parses the very first &lt;OBJECT&gt; tag in the sitemap file and extracts
/// information types and categories.
/// </summary>
/// <param name="sText">text of the object tag</param>
/// <param name="chmFile">CHMFile instance</param>
private static void ParseGlobalSettings(string sText, CHMFile chmFile)
{
int innerPTextIdx = ParamRE.GroupNumberFromName("innerText");
// get group-name indexes
int nameIndex = AttributesRE.GroupNumberFromName("attributeName");
int valueIndex = AttributesRE.GroupNumberFromName("attributeValue");
int tdIndex = AttributesRE.GroupNumberFromName("attributeTD");
// read parameters
int nParamIndex = 0;
// 0... unknown
// 1... inclusinve info type name
// 2... exclusive info type name
// 3... hidden info type name
// 4... category name
// 5... incl infotype name for category
// 6... excl infotype name for category
// 7... hidden infotype name for category
int prevItem = 0;
string sName = "";
string sDescription = "";
string curCategory = "";
while( ParamRE.IsMatch(sText, nParamIndex) )
{
Match mP = ParamRE.Match(sText, nParamIndex);
string innerP = mP.Groups[innerPTextIdx].Value;
string paramName = "";
string paramValue = "";
int nAttrIdx = 0;
while( AttributesRE.IsMatch( innerP, nAttrIdx ) )
{
Match mA = AttributesRE.Match(innerP, nAttrIdx);
string attributeName = mA.Groups[nameIndex].Value;
string attributeValue = mA.Groups[valueIndex].Value;
string attributeTD = mA.Groups[tdIndex].Value;
if(attributeTD.Length > 0)
{
// delete the trailing textqualifier
if( attributeValue.Length > 0)
{
int ltqi = attributeValue.LastIndexOf( attributeTD );
if(ltqi >= 0)
{
attributeValue = attributeValue.Substring(0,ltqi);
}
}
}
if( attributeName.ToLower() == "name")
{
paramName = HttpUtility.HtmlDecode(attributeValue); // for unicode encoded values
}
if( attributeName.ToLower() == "value")
{
paramValue = HttpUtility.HtmlDecode(attributeValue); // for unicode encoded values
// delete trailing /
while((paramValue.Length>0)&&(paramValue[paramValue.Length-1] == '/'))
paramValue = paramValue.Substring(0,paramValue.Length-1);
}
nAttrIdx = mA.Index+mA.Length;
}
switch(paramName.ToLower())
{
case "savetype": // inclusive information type name
{
prevItem = 1;
sName = paramValue;
};break;
case "savetypedesc": // description of information type
{
InformationTypeMode mode = InformationTypeMode.Inclusive;
sDescription = paramValue;
if( prevItem == 1)
mode = InformationTypeMode.Inclusive;
if( prevItem == 2)
mode = InformationTypeMode.Exclusive;
if( prevItem == 3)
mode = InformationTypeMode.Hidden;
if( chmFile.GetInformationType( sName ) == null)
{
// check if the HtmlHelpSystem already holds such an information type
if( chmFile.SystemInstance.GetInformationType( sName ) == null)
{
// info type not found yet
InformationType newType = new InformationType(sName, sDescription, mode);
chmFile.InformationTypes.Add(newType);
}
else
{
InformationType sysType = chmFile.SystemInstance.GetInformationType( sName );
chmFile.InformationTypes.Add( sysType );
}
}
prevItem = 0;
};break;
case "saveexclusive": // exclusive information type name
{
prevItem = 2;
sName = paramValue;
};break;
case "savehidden": // hidden information type name
{
prevItem = 3;
sName = paramValue;
};break;
case "category": // category name
{
prevItem = 4;
sName = paramValue;
curCategory = sName;
};break;
case "categorydesc": // category description
{
sDescription = paramValue;
if( chmFile.GetCategory( sName ) == null)
{
// check if the HtmlHelpSystem already holds such a category
if( chmFile.SystemInstance.GetCategory( sName ) == null)
{
// add category
Category newCat = new Category(sName, sDescription);
chmFile.Categories.Add(newCat);
}
else
{
Category sysCat = chmFile.SystemInstance.GetCategory( sName );
chmFile.Categories.Add( sysCat );
}
}
prevItem = 0;
};break;
case "type": // inclusive information type which is member of the previously read category
{
prevItem = 5;
sName = paramValue;
};break;
case "typedesc": // description of type for category
{
sDescription = paramValue;
Category cat = chmFile.GetCategory( curCategory );
if( cat != null)
{
// category found
InformationType infoType = chmFile.GetInformationType( sName );
if( infoType != null)
{
if( !cat.ContainsInformationType(infoType))
{
infoType.SetCategoryFlag(true);
cat.AddInformationType(infoType);
}
}
}
prevItem = 0;
};break;
case "typeexclusive": // exclusive information type which is member of the previously read category
{
prevItem = 6;
sName = paramValue;
};break;
case "typehidden": // hidden information type which is member of the previously read category
{
prevItem = 7;
sName = paramValue;
};break;
default:
{
prevItem = 0;
sName = "";
sDescription = "";
};break;
}
nParamIndex = mP.Index+mP.Length;
}
}
}
}

View File

@@ -0,0 +1,245 @@
using System;
using System.IO;
namespace HtmlHelp.ChmDecoding
{
/// <summary>
/// The class <c>TopicEntry</c> stores the data for one topic entry
/// </summary>
internal sealed class TopicEntry
{
/// <summary>
/// Internal member storing the offset of this topic entry
/// </summary>
private int _entryOffset = 0;
/// <summary>
/// Internal member storing the index of the binary toc
/// </summary>
private int _tocidxOffset = 0;
/// <summary>
/// Internal member storing the string offset of the title
/// </summary>
private int _titleOffset = 0;
/// <summary>
/// Internal member storuing the urltable offset
/// </summary>
private int _urltableOffset = 0;
/// <summary>
/// Internal member storing the visibility mode
/// </summary>
private int _visibilityMode = 0;
/// <summary>
/// Internal member storing an unknown mode
/// </summary>
private int _unknownMode = 0;
/// <summary>
/// Internal member storing the associated chmfile object
/// </summary>
private CHMFile _associatedFile = null;
/// <summary>
/// Constructor of the class
/// </summary>
/// <param name="entryOffset">offset of this entry</param>
/// <param name="tocidxOffset">offset in the binary toc index</param>
/// <param name="titleOffset">offset of the title (in the #STRINGS file)</param>
/// <param name="urltableOffset">offset in the urltable containing the urlstr offset for the url</param>
/// <param name="visibilityMode">visibility mode 2 indicates not in contents, 6 indicates that it is in the contents, 0/4 something else (unknown)</param>
/// <param name="unknownMode">0, 2, 4, 8, 10, 12, 16, 32 (unknown)</param>
public TopicEntry(int entryOffset, int tocidxOffset, int titleOffset, int urltableOffset, int visibilityMode, int unknownMode) :this(entryOffset, tocidxOffset, titleOffset, urltableOffset, visibilityMode, unknownMode, null)
{
}
/// <summary>
/// Constructor of the class
/// </summary>
/// <param name="entryOffset">offset of this entry</param>
/// <param name="tocidxOffset">offset in the binary toc index</param>
/// <param name="titleOffset">offset of the title (in the #STRINGS file)</param>
/// <param name="urltableOffset">offset in the urltable containing the urlstr offset for the url</param>
/// <param name="visibilityMode">visibility mode 2 indicates not in contents, 6 indicates that it is in the contents, 0/4 something else (unknown)</param>
/// <param name="unknownMode">0, 2, 4, 8, 10, 12, 16, 32 (unknown)</param>
/// <param name="associatedFile">associated chmfile object</param>
internal TopicEntry(int entryOffset, int tocidxOffset, int titleOffset, int urltableOffset, int visibilityMode, int unknownMode, CHMFile associatedFile)
{
_entryOffset = entryOffset;
_tocidxOffset = tocidxOffset;
_titleOffset = titleOffset;
_urltableOffset = urltableOffset;
_visibilityMode = visibilityMode;
_unknownMode = unknownMode;
_associatedFile = associatedFile;
}
/// <summary>
/// Standard constructor
/// </summary>
internal TopicEntry()
{
}
#region Data dumping
/// <summary>
/// Dump the class data to a binary writer
/// </summary>
/// <param name="writer">writer to write the data</param>
internal void Dump(ref BinaryWriter writer)
{
writer.Write( _entryOffset );
writer.Write( _tocidxOffset );
writer.Write( _titleOffset );
writer.Write( _urltableOffset );
writer.Write( _visibilityMode );
writer.Write( _unknownMode );
}
/// <summary>
/// Reads the object data from a dump store
/// </summary>
/// <param name="reader">reader to read the data</param>
internal void ReadDump(ref BinaryReader reader)
{
_entryOffset = reader.ReadInt32();
_tocidxOffset = reader.ReadInt32();
_titleOffset = reader.ReadInt32();
_urltableOffset = reader.ReadInt32();
_visibilityMode = reader.ReadInt32();
_unknownMode = reader.ReadInt32();
}
/// <summary>
/// Sets the associated CHMFile instance
/// </summary>
/// <param name="associatedFile">instance to set</param>
internal void SetCHMFile(CHMFile associatedFile)
{
_associatedFile = associatedFile;
}
#endregion
/// <summary>
/// Gets the associated chm file
/// </summary>
internal CHMFile ChmFile
{
get { return _associatedFile; }
}
/// <summary>
/// Gets the offset of this entry
/// </summary>
internal int EntryOffset
{
get { return _entryOffset; }
}
/// <summary>
/// Gets the tocidx offset
/// </summary>
internal int TOCIdxOffset
{
get { return _tocidxOffset; }
}
/// <summary>
/// Gets the title offset of the #STRINGS file
/// </summary>
internal int TitleOffset
{
get { return _titleOffset; }
}
/// <summary>
/// Gets the urltable offset
/// </summary>
internal int UrlTableOffset
{
get { return _urltableOffset; }
}
/// <summary>
/// Gets the title of the topic entry
/// </summary>
public string Title
{
get
{
if( _associatedFile == null)
return String.Empty;
if( _associatedFile.StringsFile == null)
return String.Empty;
string sTemp = (string)_associatedFile.StringsFile[ _titleOffset ];
if(sTemp == null)
return String.Empty;
return sTemp;
}
}
/// <summary>
/// Gets the url of the topic
/// </summary>
public string Locale
{
get
{
if( _associatedFile == null)
return String.Empty;
if( _associatedFile.UrltblFile == null)
return String.Empty;
UrlTableEntry utEntry = (UrlTableEntry)_associatedFile.UrltblFile[ _urltableOffset ];
if(utEntry == null)
return String.Empty;
if(utEntry.URL == "")
return String.Empty;
return utEntry.URL;
}
}
/// <summary>
/// Gets the URL of this topic
/// </summary>
public string URL
{
get
{
if(Locale.Length <= 0)
return "about:blank";
if( (Locale.ToLower().IndexOf("http://") >= 0) ||
(Locale.ToLower().IndexOf("https://") >= 0) ||
(Locale.ToLower().IndexOf("mailto:") >= 0) ||
(Locale.ToLower().IndexOf("ftp://") >= 0) ||
(Locale.ToLower().IndexOf("ms-its:") >= 0))
return Locale;
return HtmlHelpSystem.UrlPrefix + _associatedFile.ChmFilePath + "::/" + Locale;
}
}
/// <summary>
/// Gets the visibility mode
/// </summary>
public int VisibilityMode
{
get { return _visibilityMode; }
}
/// <summary>
/// Gets the unknown mode
/// </summary>
public int UknownMode
{
get { return _unknownMode; }
}
}
}

View File

@@ -0,0 +1,175 @@
using System;
using System.IO;
namespace HtmlHelp.ChmDecoding
{
/// <summary>
/// The class <c>UrlTableEntry</c> stores data for an URL-Table entry
/// </summary>
internal sealed class UrlTableEntry
{
/// <summary>
/// Internal member storing the offset of this entry
/// </summary>
private int _entryOffset = 0;
/// <summary>
/// Internal member storing a unique id
/// </summary>
private uint _uniqueID = 0;
/// <summary>
/// Internal member storing the topics index
/// </summary>
private int _topicsIndex = 0;
/// <summary>
/// Internal member storing the offset in the urlstr table
/// </summary>
private int _urlStrOffset = 0;
/// <summary>
/// Internal member storing the associated chmfile object
/// </summary>
private CHMFile _associatedFile = null;
/// <summary>
/// Constructor of the class
/// </summary>
/// <param name="uniqueID">unique id</param>
/// <param name="entryOffset">offset of the entry</param>
/// <param name="topicIndex">topic index</param>
/// <param name="urlstrOffset">urlstr offset for filename</param>
public UrlTableEntry(uint uniqueID, int entryOffset, int topicIndex, int urlstrOffset) : this(uniqueID, entryOffset, topicIndex, urlstrOffset, null)
{
}
/// <summary>
/// Constructor of the class
/// </summary>
/// <param name="uniqueID">unique id</param>
/// <param name="entryOffset">offset of the entry</param>
/// <param name="topicIndex">topic index</param>
/// <param name="urlstrOffset">urlstr offset for filename</param>
/// <param name="associatedFile">associated chm file</param>
internal UrlTableEntry(uint uniqueID, int entryOffset, int topicIndex, int urlstrOffset, CHMFile associatedFile)
{
_uniqueID = uniqueID;
_entryOffset = entryOffset;
_topicsIndex = topicIndex;
_urlStrOffset = urlstrOffset;
_associatedFile = associatedFile;
}
/// <summary>
/// Standard constructor
/// </summary>
internal UrlTableEntry()
{
}
#region Data dumping
/// <summary>
/// Dump the class data to a binary writer
/// </summary>
/// <param name="writer">writer to write the data</param>
internal void Dump(ref BinaryWriter writer)
{
writer.Write( _urlStrOffset );
writer.Write( _entryOffset );
writer.Write( _topicsIndex );
writer.Write( _urlStrOffset );
}
/// <summary>
/// Reads the object data from a dump store
/// </summary>
/// <param name="reader">reader to read the data</param>
internal void ReadDump(ref BinaryReader reader)
{
_urlStrOffset = reader.ReadInt32();
_entryOffset = reader.ReadInt32();
_topicsIndex = reader.ReadInt32();
_urlStrOffset = reader.ReadInt32();
}
/// <summary>
/// Sets the associated CHMFile instance
/// </summary>
/// <param name="associatedFile">instance to set</param>
internal void SetCHMFile(CHMFile associatedFile)
{
_associatedFile = associatedFile;
}
#endregion
/// <summary>
/// Gets the unique id of the entry
/// </summary>
internal uint UniqueID
{
get {return _uniqueID; }
}
/// <summary>
/// Gets the offset of the entry
/// </summary>
internal int EntryOffset
{
get {return _entryOffset; }
}
/// <summary>
/// Gets the topics index
/// </summary>
internal int TopicIndex
{
get {return _topicsIndex; }
}
/// <summary>
/// Gets the urlstr offset
/// </summary>
internal int UrlstrOffset
{
get { return _urlStrOffset; }
}
/// <summary>
/// Gets the url of the entry
/// </summary>
public string URL
{
get
{
if(_associatedFile == null)
return String.Empty;
if(_associatedFile.UrlstrFile == null)
return String.Empty;
string sTemp = (string)_associatedFile.UrlstrFile.GetURLatOffset( _urlStrOffset );
if( sTemp == null)
return String.Empty;
return sTemp;
}
}
/// <summary>
/// Gets the associated topic for this url entry
/// </summary>
internal TopicEntry Topic
{
get
{
if(_associatedFile == null)
return null;
if(_associatedFile.TopicsFile == null)
return null;
TopicEntry tentry = _associatedFile.TopicsFile[ _topicsIndex*16 ];
return tentry;
}
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
namespace HtmlHelp.ChmDecoding
{
/// <summary>
/// Enumeration for specifying the extraction mode of an toc or index item.
/// </summary>
public enum DataMode
{
/// <summary>
/// TextBased - this item comes from a text-based sitemap file
/// </summary>
TextBased = 0,
/// <summary>
/// Binary - this item was extracted out of a binary stream
/// </summary>
Binary = 1
}
}

View File

@@ -0,0 +1,16 @@
<Combine fileversion="1.0" name="CHMLibrary" description="">
<StartMode startupentry="CHMLibrary" single="True">
<Execute entry="CHMLibrary" type="None" />
</StartMode>
<Entries>
<Entry filename=".\.\CHMLibrary.prjx" />
</Entries>
<Configurations active="Debug">
<Configuration name="Release">
<Entry name="CHMLibrary" configurationname="Debug" build="False" />
</Configuration>
<Configuration name="Debug">
<Entry name="CHMLibrary" configurationname="Debug" build="False" />
</Configuration>
</Configurations>
</Combine>

View File

@@ -0,0 +1,58 @@
<Project name="CHMLibrary" standardNamespace="CHMLibrary" description="" newfilesearch="None" enableviewstate="True" version="1.1" projecttype="C#">
<Contents>
<File name=".\AssemblyInfo.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\Category.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\ChmFileInfo.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\Default.build" subtype="Code" buildaction="Nothing" dependson="" data="" />
<File name=".\HtmlHelpSystem.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\HttpUtility.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\Index.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\IndexItem.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\IndexTopic.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\InformationType.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\TableOfContents.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\TOCItem.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\Storage" subtype="Directory" buildaction="Compile" dependson="" data="" />
<File name=".\Storage\CHMStream.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding" subtype="Directory" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\BinaryReaderHelp.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\CHMBtree.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\CHMFile.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\CHMIdxhdr.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\CHMStrings.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\CHMSystem.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\CHMTocidx.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\CHMTopics.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\CHMUrlstr.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\CHMUrltable.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\DumpingInfo.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\enumerations.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\FullTextEngine.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\HHCParser2.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\HHCParser.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\HHKParser.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\TopicEntry.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\CHMDecoding\UrlTableEntry.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
</Contents>
<References>
<Reference type="Project" refto="Compression" localcopy="True" />
</References>
<DeploymentInformation target="" script="" strategy="File" />
<Configuration runwithwarnings="True" name="Debug">
<CodeGeneration runtime="MsNet" compiler="Csc" compilerversion="" warninglevel="4" nowarn="" includedebuginformation="True" optimize="False" unsafecodeallowed="False" generateoverflowchecks="True" mainclass="" target="Library" definesymbols="" generatexmldocumentation="False" win32Icon="" noconfig="False" nostdlib="False" />
<Execution commandlineparameters="" consolepause="False" />
<Output directory="..\bin\Debug" assembly="CHMLibrary" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" />
</Configuration>
<Configurations active="Debug">
<Configuration runwithwarnings="True" name="Debug">
<CodeGeneration runtime="MsNet" compiler="Csc" compilerversion="" warninglevel="4" nowarn="" includedebuginformation="True" optimize="False" unsafecodeallowed="False" generateoverflowchecks="True" mainclass="" target="Library" definesymbols="" generatexmldocumentation="False" win32Icon="" noconfig="False" nostdlib="False" />
<Execution commandlineparameters="" consolepause="False" />
<Output directory="..\bin\Debug" assembly="CHMLibrary" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" />
</Configuration>
<Configuration runwithwarnings="True" name="Release">
<CodeGeneration runtime="MsNet" compiler="Csc" compilerversion="" warninglevel="4" nowarn="" includedebuginformation="False" optimize="True" unsafecodeallowed="False" generateoverflowchecks="False" mainclass="" target="Library" definesymbols="" generatexmldocumentation="False" win32Icon="" noconfig="False" nostdlib="False" />
<Execution commandlineparameters="" consolepause="False" />
<Output directory="..\bin\Release" assembly="CHMLibrary" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" />
</Configuration>
</Configurations>
</Project>

View File

@@ -0,0 +1,201 @@
using System;
using System.Collections;
using System.IO;
using HtmlHelp.ChmDecoding;
namespace HtmlHelp
{
/// <summary>
/// The class <c>Category</c> implements methods/properties for handling an information category
/// </summary>
/// <remarks>Note: Information types and categories allow users to filter help contents.
/// They are only supported if using sitemap TOC and/or sitemap Index.</remarks>
public class Category
{
private string _name = "";
private string _description = "";
private ArrayList _infoTypes = null;
private int _referenceCount = 1;
/// <summary>
/// Standard constructor
/// </summary>
public Category() : this("","")
{
}
/// <summary>
/// Standard constructor
/// </summary>
/// <param name="name">name of the category</param>
/// <param name="description">description</param>
public Category(string name, string description) : this(name, description, new ArrayList())
{
}
/// <summary>
/// Standard constructor
/// </summary>
/// <param name="name">name of the category</param>
/// <param name="description">description</param>
/// <param name="linkedInformationTypes">Arraylist of InformationType instances which applies to this category</param>
public Category(string name, string description, ArrayList linkedInformationTypes)
{
_name = name;
_description = description;
_infoTypes = linkedInformationTypes;
}
#region Data dumping
/// <summary>
/// Dump the class data to a binary writer
/// </summary>
/// <param name="writer">writer to write the data</param>
internal void Dump(ref BinaryWriter writer)
{
writer.Write( _name );
writer.Write( _description );
writer.Write( _infoTypes.Count );
for(int i=0; i<_infoTypes.Count;i++)
{
InformationType curType = _infoTypes[i] as InformationType;
writer.Write( curType.Name );
}
}
/// <summary>
/// Reads the object data from a dump store
/// </summary>
/// <param name="reader">reader to read the data</param>
/// <param name="chmFile">current CHMFile instance which reads from dump</param>
internal void ReadDump(ref BinaryReader reader, CHMFile chmFile)
{
_name = reader.ReadString();
_description = reader.ReadString();
int nCnt = reader.ReadInt32();
for(int i=0; i<nCnt; i++)
{
string sITName = reader.ReadString();
InformationType linkedType = chmFile.GetInformationType( sITName );
if(linkedType != null)
{
linkedType.SetCategoryFlag(true);
_infoTypes.Add(linkedType);
}
}
}
#endregion
/// <summary>
/// Merges the lineked information types from cat into this instance
/// </summary>
/// <param name="cat">category instance</param>
internal void MergeInfoTypes(Category cat)
{
if(cat!=null)
{
if(cat.InformationTypes.Count > 0)
{
for(int i=0;i<cat.InformationTypes.Count;i++)
{
InformationType curType = cat.InformationTypes[i] as InformationType;
if(!ContainsInformationType(curType.Name))
{
curType.SetCategoryFlag(true);
_infoTypes.Add(curType);
}
}
}
}
}
/// <summary>
/// Gets/Sets the reference count of this information type instance
/// </summary>
internal int ReferenceCount
{
get { return _referenceCount; }
set { _referenceCount = value; }
}
/// <summary>
/// Gets/Sets the name of the information type
/// </summary>
public string Name
{
get { return _name; }
set { _name = value; }
}
/// <summary>
/// Gets/Sets the description of the information type
/// </summary>
public string Description
{
get { return _description; }
set { _name = value; }
}
/// <summary>
/// Gets an ArrayList with the linked Information types
/// </summary>
public ArrayList InformationTypes
{
get { return _infoTypes; }
}
/// <summary>
/// Adds a new information type to the category
/// </summary>
/// <param name="type"></param>
public void AddInformationType(InformationType type)
{
_infoTypes.Add(type);
}
/// <summary>
/// Removes an information type from the category
/// </summary>
/// <param name="type"></param>
public void RemoveInformationType(InformationType type)
{
_infoTypes.Remove(type);
}
/// <summary>
/// Checks if the category contains an information type
/// </summary>
/// <param name="type">information type instance to check</param>
/// <returns>Return true if the information type is part of this category</returns>
public bool ContainsInformationType(InformationType type)
{
return _infoTypes.Contains(type);
}
/// <summary>
/// Checks if the category contains an information type
/// </summary>
/// <param name="name">name of the information type</param>
/// <returns>Return true if the information type is part of this category</returns>
public bool ContainsInformationType(string name)
{
for(int i=0;i<_infoTypes.Count;i++)
{
InformationType curType = _infoTypes[i] as InformationType;
if(curType.Name == name)
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,478 @@
using System;
using System.Collections;
using System.Text;
using System.IO;
using System.Globalization;
using System.Diagnostics;
using System.ComponentModel;
using HtmlHelp.ChmDecoding;
// using HtmlHelp.Storage;
namespace HtmlHelp
{
/// <summary>
/// The class <c>ChmFileInfo</c> only extracts system information from a CHM file.
/// It doesn't build the index and table of contents.
/// </summary>
public class ChmFileInfo
{
/// <summary>
/// Internal member storing the full filename
/// </summary>
private string _chmFileName = "";
/// <summary>
/// Internal member storing the associated chmfile object
/// </summary>
private CHMFile _associatedFile = null;
/// <summary>
/// Constructor for extrating the file information of the provided file.
/// The constructor opens the chm-file and reads its system data.
/// </summary>
/// <param name="chmFile">full file name which information should be extracted</param>
public ChmFileInfo(string chmFile)
{
if(!File.Exists(chmFile))
throw new ArgumentException("Chm file must exist on disk !", "chmFileName");
if( ! chmFile.ToLower().EndsWith(".chm") )
throw new ArgumentException("HtmlHelp file must have the extension .chm !", "chmFile");
_chmFileName = chmFile;
_associatedFile = new CHMFile(null, chmFile, true); // only load system data of chm
}
/// <summary>
/// Internal constructor used in the class <see cref="HtmlHelp.ChmDecoding.CHMFile">CHMFile</see>.
/// </summary>
/// <param name="associatedFile">associated chm file</param>
internal ChmFileInfo(CHMFile associatedFile)
{
_associatedFile = associatedFile;
if( _associatedFile == null)
throw new ArgumentException("Associated CHMFile instance must not be null !", "associatedFile");
}
#region default info properties
/// <summary>
/// Gets the full filename of the chm file
/// </summary>
public string ChmFileName
{
get
{
return _associatedFile.ChmFilePath;
}
}
/// <summary>
/// Gets a <see cref="System.IO.FileInfo">FileInfo</see> instance for the chm file.
/// </summary>
public FileInfo FileInfo
{
get { return new FileInfo(_associatedFile.ChmFilePath); }
}
#endregion
#region #SYSTEM properties
/// <summary>
/// Gets the file version of the chm file.
/// 2 for Compatibility=1.0, 3 for Compatibility=1.1
/// </summary>
public int FileVersion
{
get
{
if(_associatedFile != null)
return _associatedFile.FileVersion;
return 0;
}
}
/// <summary>
/// Gets the contents file name
/// </summary>
public string ContentsFile
{
get
{
if(_associatedFile != null)
return _associatedFile.ContentsFile;
return "";
}
}
/// <summary>
/// Gets the index file name
/// </summary>
public string IndexFile
{
get
{
if(_associatedFile != null)
return _associatedFile.IndexFile;
return "";
}
}
/// <summary>
/// Gets the default help topic
/// </summary>
public string DefaultTopic
{
get
{
if(_associatedFile != null)
return _associatedFile.DefaultTopic;
return "";
}
}
/// <summary>
/// Gets the title of the help window
/// </summary>
public string HelpWindowTitle
{
get
{
if(_associatedFile != null)
return _associatedFile.HelpWindowTitle;
return "";
}
}
/// <summary>
/// Gets the flag if DBCS is in use
/// </summary>
public bool DBCS
{
get
{
if(_associatedFile != null)
return _associatedFile.DBCS;
return false;
}
}
/// <summary>
/// Gets the flag if full-text-search is available
/// </summary>
public bool FullTextSearch
{
get
{
if(_associatedFile != null)
return _associatedFile.FullTextSearch;
return false;
}
}
/// <summary>
/// Gets the flag if the file has ALinks
/// </summary>
public bool HasALinks
{
get
{
if(_associatedFile != null)
return _associatedFile.HasALinks;
return false;
}
}
/// <summary>
/// Gets the flag if the file has KLinks
/// </summary>
public bool HasKLinks
{
get
{
if(_associatedFile != null)
return _associatedFile.HasKLinks;
return false;
}
}
/// <summary>
/// Gets the default window name
/// </summary>
public string DefaultWindow
{
get
{
if(_associatedFile != null)
return _associatedFile.DefaultWindow;
return "";
}
}
/// <summary>
/// Gets the file name of the compile file
/// </summary>
public string CompileFile
{
get
{
if(_associatedFile != null)
return _associatedFile.CompileFile;
return "";
}
}
/// <summary>
/// Gets the flag if the chm has a binary index file
/// </summary>
public bool BinaryIndex
{
get
{
if(_associatedFile != null)
return _associatedFile.BinaryIndex;
return false;
}
}
/// <summary>
/// Gets the flag if the chm has a binary index file
/// </summary>
public string CompilerVersion
{
get
{
if(_associatedFile != null)
return _associatedFile.CompilerVersion;
return "";
}
}
/// <summary>
/// Gets the flag if the chm has a binary toc file
/// </summary>
public bool BinaryTOC
{
get
{
if(_associatedFile != null)
return _associatedFile.BinaryTOC;
return false;
}
}
/// <summary>
/// Gets the font face of the read font property.
/// Empty string for default font.
/// </summary>
public string FontFace
{
get
{
if(_associatedFile != null)
return _associatedFile.FontFace;
return "";
}
}
/// <summary>
/// Gets the font size of the read font property.
/// 0 for default font size
/// </summary>
public double FontSize
{
get
{
if(_associatedFile != null)
return _associatedFile.FontSize;
return 0.0;
}
}
/// <summary>
/// Gets the character set of the read font property
/// 1 for default
/// </summary>
public int CharacterSet
{
get
{
if(_associatedFile != null)
return _associatedFile.CharacterSet;
return 1;
}
}
/// <summary>
/// Gets the codepage depending on the read font property
/// </summary>
public int CodePage
{
get
{
if(_associatedFile != null)
return _associatedFile.CodePage;
return 0;
}
}
/// <summary>
/// Gets the assiciated culture info
/// </summary>
public CultureInfo Culture
{
get
{
if(_associatedFile != null)
return _associatedFile.Culture;
return CultureInfo.CurrentCulture;
}
}
#endregion
#region #IDXHDR properties
/// <summary>
/// Gets the number of topic nodes including the contents and index files
/// </summary>
public int NumberOfTopicNodes
{
get
{
if(_associatedFile != null)
return _associatedFile.NumberOfTopicNodes;
return 0;
}
}
/// <summary>
/// Gets the ImageList string specyfied in the #IDXHDR file.
/// </summary>
/// <remarks>This property uses the #STRINGS file to extract the string at a given offset.</remarks>
public string ImageList
{
get
{
if(_associatedFile != null)
return _associatedFile.ImageList;
return "";
}
}
/// <summary>
/// Gets the background setting
/// </summary>
public int Background
{
get
{
if(_associatedFile != null)
return _associatedFile.Background;
return 0;
}
}
/// <summary>
/// Gets the foreground setting
/// </summary>
public int Foreground
{
get
{
if(_associatedFile != null)
return _associatedFile.Foreground;
return 0;
}
}
/// <summary>
/// Gets the FrameName string specyfied in the #IDXHDR file.
/// </summary>
/// <remarks>This property uses the #STRINGS file to extract the string at a given offset.</remarks>
public string FrameName
{
get
{
if(_associatedFile != null)
return _associatedFile.FrameName;
return "";
}
}
/// <summary>
/// Gets the WindowName string specyfied in the #IDXHDR file.
/// </summary>
/// <remarks>This property uses the #STRINGS file to extract the string at a given offset.</remarks>
public string WindowName
{
get
{
if(_associatedFile != null)
return _associatedFile.WindowName;
return "";
}
}
/// <summary>
/// Gets a string array containing the merged file names
/// </summary>
public string[] MergedFiles
{
get
{
if(_associatedFile != null)
return _associatedFile.MergedFiles;
return new string[0];
}
}
#endregion
}
}

View File

@@ -0,0 +1,23 @@
<?xml version="1.0"?>
<project name="CHMLibrary" default="build">
<property name="output.dir" value="..\bin" />
<target name="build" description="Build component">
<mkdir dir="${output.dir}" />
<csc target="library"
output="${output.dir}\CHMLibrary.dll"
optimize="true"
debug="true"
doc="${output.dir}\CHMLibrary.xml"
warninglevel="0">
<sources>
<include name="**/*.cs" />
</sources>
<references>
<include name="${output.dir}\Compression.dll" />
</references>
</csc>
</target>
</project>

View File

@@ -0,0 +1,894 @@
using System;
using System.IO;
using System.Collections;
using System.Data;
using HtmlHelp.ChmDecoding;
namespace HtmlHelp
{
/// <summary>
/// The class <c>HtmlHelpSystem</c> implements the main object for reading chm files
/// </summary>
public sealed class HtmlHelpSystem
{
/// <summary>
/// Private shared instance of current HtmlHelpSystem class
/// </summary>
private static HtmlHelpSystem _current=null;
/// <summary>
/// Internal member storing the attached files
/// </summary>
private ArrayList _chmFiles = new ArrayList();
/// <summary>
/// Internal member storing a merged table of contents
/// </summary>
private TableOfContents _toc = new TableOfContents();
/// <summary>
/// Internal member storing a merged index
/// </summary>
private Index _index = new Index();
/// <summary>
/// URL prefix for specifying a chm destination
/// </summary>
private static string _urlPrefix = "ms-its:";
/// <summary>
/// Internal flag specifying if the system should use the tree-images list
/// from HtmlHelp2. If false the standard CHM-Viewer pics will be used.
/// </summary>
private static bool _useHH2TreePics = false;
/// <summary>
/// Internal member storing the read information types
/// </summary>
private ArrayList _informationTypes = new ArrayList();
/// <summary>
/// Internal member storing the read categories
/// </summary>
private ArrayList _categories = new ArrayList();
/// <summary>
/// Gets/Sets the url prefix for specifying a chm destination
/// </summary>
public static string UrlPrefix
{
get { return _urlPrefix; }
set { _urlPrefix = value; }
}
public CHMStream.CHMStream BaseStream
{
get
{
CHMFile chm=(CHMFile)_chmFiles[0];
return chm.BaseStream;
}
}
/// <summary>
/// Gets/Sets the flag specifying if the system should use the tree-images list
/// from HtmlHelp2. If false the standard CHM-Viewer pics will be used.
/// </summary>
public static bool UseHH2TreePics
{
get { return _useHH2TreePics; }
set { _useHH2TreePics = value; }
}
/// <summary>
/// Gets the current HtmlHelpSystem instance
/// </summary>
public static HtmlHelpSystem Current
{
get
{
return _current;
}
}
/// <summary>
/// Standard constructor
/// </summary>
public HtmlHelpSystem() : this("")
{
}
/// <summary>
/// Constructor of the reader class
/// </summary>
/// <param name="chmFile">chm file to attach with the reader</param>
public HtmlHelpSystem(string chmFile)
{
_current = this;
OpenFile(chmFile);
}
/// <summary>
/// Opens a chm file and creates
/// </summary>
/// <param name="chmFile">full file path of the chm file to open</param>
/// <remarks>If you call this method, all existing merged files will be cleared.</remarks>
public void OpenFile(string chmFile)
{
OpenFile(chmFile, null);
}
/// <summary>
/// Opens a chm file and creates
/// </summary>
/// <param name="chmFile">full file path of the chm file to open</param>
/// <param name="dmpInfo">dumping info</param>
/// <remarks>If you call this method, all existing merged files will be cleared.</remarks>
public void OpenFile(string chmFile, DumpingInfo dmpInfo)
{
if( File.Exists(chmFile ) )
{
_chmFiles.Clear();
_toc.Clear();
_index.Clear();
_informationTypes.Clear();
_categories.Clear();
CHMFile newFile = new CHMFile(this, chmFile, dmpInfo);
_toc = new TableOfContents( newFile.TOC );
_index = new Index( newFile.IndexKLinks, newFile.IndexALinks );
_chmFiles.Add(newFile);
// add all infotypes and categories of the read file to this system instance
MergeFileInfoTypesCategories(newFile);
// check if the file has a merged files list
if( newFile.MergedFiles.Length > 0 )
{
// extract the path of the chm file (usually merged files are in the same path)
FileInfo fi = new FileInfo(chmFile);
string sPath = fi.DirectoryName;
for(int i=0; i<newFile.MergedFiles.Length; i++)
{
string sFile = newFile.MergedFiles[i];
if(sFile.Length > 0)
{
if(sFile[1] != ':') // no full path setting
{
sFile = Path.Combine(sPath, sFile);
}
MergeFile(sFile, dmpInfo, true);
}
}
// if (newFile.MergLinks.Count>0)
// RecalculateMergeLinks(newFile);
RemoveMergeLinks(); // clear all merge-links which have no target !
}
}
}
/// <summary>
/// Merges a chm file to the current help contents
/// </summary>
/// <param name="chmFile">full file path of the chm file to merge</param>
public void MergeFile(string chmFile)
{
MergeFile(chmFile, null);
}
/// <summary>
/// Merges a chm file to the current help contents
/// </summary>
/// <param name="chmFile">full file path of the chm file to merge</param>
/// <param name="dmpInfo">dumping info</param>
public void MergeFile(string chmFile, DumpingInfo dmpInfo)
{
MergeFile(chmFile, dmpInfo, false);
}
/// <summary>
/// Merges a chm file to the current help contents
/// </summary>
/// <param name="chmFile">full file path of the chm file to merge</param>
/// <param name="dmpInfo">dumping info</param>
/// <param name="mergedFileList">true if the merge is done because a merged file list
/// was found in the previously loaded CHM.</param>
internal void MergeFile(string chmFile, DumpingInfo dmpInfo, bool mergedFileList)
{
if( File.Exists(chmFile ) )
{
if( _chmFiles.Count == 1)
{
// if we open the first file, we directly point into the toc and index of this file.
// So that we don't merge the new toc's indexe's into the first file, we have to
// clone the internal arraylists first to a new instance of the toc/index holder classes.
ArrayList atoc = _toc.TOC;
ArrayList alinks = _index.ALinks;
ArrayList klinks = _index.KLinks;
_toc = new TableOfContents();
_index = new Index();
_toc.MergeToC( atoc );
_index.MergeIndex( alinks, IndexType.AssiciativeLinks );
_index.MergeIndex( klinks, IndexType.KeywordLinks );
}
CHMFile newFile = new CHMFile(this, chmFile, dmpInfo);
if(mergedFileList) // if we've called this method due to a merged file list merge
{
RecalculateMergeLinks(newFile);
_toc.MergeToC( newFile.TOC, _chmFiles );
_index.MergeIndex( newFile.IndexALinks, IndexType.AssiciativeLinks );
_index.MergeIndex( newFile.IndexKLinks, IndexType.KeywordLinks );
_chmFiles.Add(newFile);
// add all infotypes and categories of the read file to this system instance
MergeFileInfoTypesCategories(newFile);
}
else
{
_toc.MergeToC( newFile.TOC, _chmFiles );
_index.MergeIndex( newFile.IndexALinks, IndexType.AssiciativeLinks );
_index.MergeIndex( newFile.IndexKLinks, IndexType.KeywordLinks );
_chmFiles.Add(newFile);
// add all infotypes and categories of the read file to this system instance
MergeFileInfoTypesCategories(newFile);
// check if the file has a merged files list
if( newFile.MergedFiles.Length > 0 )
{
// extract the path of the chm file (usually merged files are in the same path)
FileInfo fi = new FileInfo(chmFile);
string sPath = fi.DirectoryName;
for(int i=0; i<newFile.MergedFiles.Length; i++)
{
string sFile = newFile.MergedFiles[i];
if(sFile.Length > 0)
{
if(sFile[1] != ':') // no full path setting
{
sFile = Path.Combine(sPath, sFile);
}
MergeFile(sFile, dmpInfo, true);
}
}
RemoveMergeLinks(); // clear all merge-links which have no target !
}
}
}
}
/// <summary>
/// Checks all Merg-links read till now. Checks if the merg-link points to the
/// file <c>currentFile</c>. If yes the link will be replaced by the contents of the
/// merged file.
/// </summary>
/// <param name="currentFile">Current CHMFile instance</param>
internal void RecalculateMergeLinks(CHMFile currentFile)
{
foreach(CHMFile curFile in _chmFiles)
{
if( curFile.MergLinks.Count > 0)
{
for(int i=0; i<curFile.MergLinks.Count; i++)
{
TOCItem curItem = curFile.MergLinks[i] as TOCItem;
string sMerge = curItem.MergeLink;
string [] sSplit = sMerge.Split( new char[]{':'} );
string sFName = "";
string sTarget = "";
if( sSplit.Length > 3) // merge info contains path name
{
sFName = sSplit[0] + ":" + sSplit[1];
sTarget = sSplit[3];
}
else if( sSplit.Length == 3)// merge info contains only file name
{
FileInfo fi = new FileInfo(currentFile.ChmFilePath);
string sPath = fi.DirectoryName;
string sFile = sSplit[0];
if(sFile.Length > 0)
{
if(sFile[1] != ':') // no full path setting
{
sFile = Path.Combine(sPath, sFile);
}
}
sFName = sFile;
sTarget = sSplit[2];
}
ArrayList arrToc = null;
if( (sFName.Length>0) && (sTarget.Length>0) )
{
// if this link points into the current file
if( sFName.ToLower() == currentFile.ChmFilePath.ToLower() )
{
if(sTarget.ToLower().IndexOf(".hhc") >= 0)
{
string sfCheck = sTarget;
// remove prefixing ./
while( (sfCheck[0]=='.') || (sfCheck[0]=='/') )
{
sfCheck = sfCheck.Substring(1);
}
if( currentFile.ContentsFile.ToLower() != sfCheck )
{
arrToc = currentFile.ParseHHC( sTarget );
if( arrToc.Count > 0)
{
}
}
else
{
arrToc = currentFile.TOC;
}
// target points to a complete TOC
int nCnt = 0;
foreach(TOCItem chkItem in arrToc)
{
if(nCnt == 0)
{
curItem.AssociatedFile = currentFile;
curItem.Children = chkItem.Children;
curItem.ChmFile = currentFile.ChmFilePath;
curItem.ImageIndex = chkItem.ImageIndex;
curItem.Local = chkItem.Local;
curItem.MergeLink = chkItem.MergeLink;
curItem.Name = chkItem.Name;
curItem.TocMode = chkItem.TocMode;
curItem.TopicOffset = chkItem.TopicOffset;
MarkChildrenAdded(chkItem.Children, curFile.MergLinks);
}
else
{
ArrayList checkList = null;
if(curItem.Parent != null)
checkList = curItem.Parent.Children;
else
checkList = curFile.TOC;
int nIdx = checkList.IndexOf(curItem);
if((nIdx+nCnt)>checkList.Count)
checkList.Add(chkItem);
else
checkList.Insert(nIdx+nCnt, chkItem);
curFile.MergLinks.Add(chkItem);
MarkChildrenAdded(chkItem.Children, curFile.MergLinks);
}
nCnt++;
}
}
else
{
// target points to a single topic
TOCItem chkItem = currentFile.GetTOCItemByLocal(sTarget);
if(chkItem != null)
{
curItem.AssociatedFile = currentFile;
curItem.Children = chkItem.Children;
curItem.ChmFile = currentFile.ChmFilePath;
curItem.ImageIndex = chkItem.ImageIndex;
curItem.Local = chkItem.Local;
curItem.MergeLink = chkItem.MergeLink;
curItem.Name = chkItem.Name;
curItem.TocMode = chkItem.TocMode;
curItem.TopicOffset = chkItem.TopicOffset;
curFile.MergLinks.Add(chkItem);
MarkChildrenAdded(chkItem.Children, curFile.MergLinks);
}
}
}
}
}
}
}
}
/// <summary>
/// Adds sub-items of an TOC-entry to the merg-linked list.
/// This will mark this item as "added" during the extra merge run
/// of the HtmlHelpSystem class.
/// </summary>
/// <param name="tocs">TOCItem list</param>
/// <param name="merged">Arraylist which holds the merged-items</param>
internal void MarkChildrenAdded(ArrayList tocs, ArrayList merged)
{
foreach(TOCItem curItem in tocs)
{
if(!merged.Contains(curItem))
{
merged.Add(curItem);
MarkChildrenAdded(curItem.Children, merged);
}
}
}
/// <summary>
/// Removes merge-links from the toc of files which were not loaded
/// </summary>
internal void RemoveMergeLinks()
{
foreach(CHMFile curFile in _chmFiles)
{
if( curFile.MergLinks.Count > 0)
{
while(curFile.MergLinks.Count > 0)
{
TOCItem curItem = curFile.MergLinks[0] as TOCItem;
if(curItem.MergeLink.Length > 0)
curFile.RemoveTOCItem(curItem);
curFile.MergLinks.RemoveAt(0);
}
}
}
}
/// <summary>
/// Merges the information types and categories read by the CHMFile instance
/// into the system instance
/// </summary>
/// <param name="chmFile">file instance</param>
private void MergeFileInfoTypesCategories(CHMFile chmFile)
{
if(chmFile.HasInformationTypes)
{
for(int i=0; i<chmFile.InformationTypes.Count;i++)
{
InformationType curType = chmFile.InformationTypes[i] as InformationType;
InformationType sysType = GetInformationType( curType.Name );
if( sysType == null)
_informationTypes.Add(curType);
else
curType.ReferenceCount++;
}
}
if(chmFile.HasCategories)
{
for(int i=0; i<chmFile.Categories.Count;i++)
{
Category curCat = chmFile.Categories[i] as Category;
Category sysCat = GetCategory( curCat.Name );
if(sysCat == null)
_categories.Add(curCat);
else
curCat.ReferenceCount++;
}
}
}
/// <summary>
/// Removes the information types and categories read by the CHMFile instance
/// </summary>
/// <param name="chmFile">file instance</param>
private void RemoveFileInfoTypesCategories(CHMFile chmFile)
{
if(chmFile.HasInformationTypes)
{
for(int i=0; i<chmFile.InformationTypes.Count;i++)
{
InformationType curType = chmFile.InformationTypes[i] as InformationType;
InformationType sysType = GetInformationType( curType.Name );
if(sysType != null)
{
sysType.ReferenceCount--;
if(sysType.ReferenceCount<=0)
_informationTypes.Remove(sysType);
}
}
}
if(chmFile.HasCategories)
{
for(int i=0; i<chmFile.Categories.Count;i++)
{
Category curCat = chmFile.Categories[i] as Category;
Category sysCat = GetCategory( curCat.Name );
if(sysCat != null)
{
sysCat.ReferenceCount--;
if(sysCat.ReferenceCount<=0)
_categories.Remove(sysCat);
}
}
}
}
/// <summary>
/// Removes a chm file from the internal file collection
/// </summary>
/// <param name="chmFile">full file path of the chm file to remove</param>
public void RemoveFile(string chmFile)
{
int nIdx = -1;
CHMFile removeInstance=null;
foreach(CHMFile curFile in _chmFiles)
{
nIdx++;
if( curFile.ChmFilePath.ToLower() == chmFile.ToLower() )
{
removeInstance = curFile;
break;
}
}
if(nIdx >= 0)
{
_toc.Clear(); // forces a rebuild of the merged toc
_index.Clear(); // force a rebuild of the merged index
RemoveFileInfoTypesCategories(removeInstance);
_chmFiles.RemoveAt(nIdx);
}
}
/// <summary>
/// Closes all files and destroys TOC/index
/// </summary>
public void CloseAllFiles()
{
for(int i=0; i < _chmFiles.Count; i++)
{
CHMFile curFile = _chmFiles[i] as CHMFile;
_chmFiles.RemoveAt(i);
curFile.Dispose();
i--;
}
_chmFiles.Clear();
_toc.Clear();
_index.Clear();
_informationTypes.Clear();
_categories.Clear();
}
/// <summary>
/// Gets an array of loaded chm files.
/// </summary>
public CHMFile[] FileList
{
get
{
CHMFile[] ret = new CHMFile[ _chmFiles.Count ];
for(int i=0;i<_chmFiles.Count;i++)
ret[i] = (CHMFile)_chmFiles[i];
return ret;
}
}
/// <summary>
/// Returns true if the HtmlHelpSystem instance contains 1 or more information types
/// </summary>
public bool HasInformationTypes
{
get { return (_informationTypes.Count>0); }
}
/// <summary>
/// Returns true if the HtmlHelpSystem instance contains 1 or more categories
/// </summary>
public bool HasCategories
{
get { return (_categories.Count>0); }
}
/// <summary>
/// Gets an ArrayList of <see cref="InformationType">InformationType</see> items
/// </summary>
public ArrayList InformationTypes
{
get { return _informationTypes; }
}
/// <summary>
/// Gets an ArrayList of <see cref="Category">Category</see> items
/// </summary>
public ArrayList Categories
{
get { return _categories; }
}
/// <summary>
/// Gets the information type specified by its name
/// </summary>
/// <param name="name">name of the information type to receive</param>
/// <returns>Returns the Instance for the name or null if not found</returns>
public InformationType GetInformationType(string name)
{
if(HasInformationTypes)
{
for(int i=0; i<_informationTypes.Count;i++)
{
InformationType iT = _informationTypes[i] as InformationType;
if(iT.Name == name)
return iT;
}
}
return null;
}
/// <summary>
/// Gets the category specifiyd by its name
/// </summary>
/// <param name="name">name of the category</param>
/// <returns>Returns the Instance for the name or null if not found</returns>
public Category GetCategory(string name)
{
if(HasCategories)
{
for(int i=0; i<_categories.Count;i++)
{
Category cat = _categories[i] as Category;
if(cat.Name == name)
return cat;
}
}
return null;
}
/// <summary>
/// Gets the default topic
/// </summary>
public string DefaultTopic
{
get
{
if( _chmFiles.Count > 0 )
{
foreach(CHMFile curFile in _chmFiles)
{
if( curFile.DefaultTopic.Length > 0)
{
return curFile.FormURL( curFile.DefaultTopic );
}
}
}
return "about:blank";
}
}
/// <summary>
/// Gets a merged table of contents of all opened chm files
/// </summary>
public TableOfContents TableOfContents
{
get
{
if( _chmFiles.Count > 0 )
{
if( _toc.Count() <= 0)
{
// merge toc of files
foreach(CHMFile curFile in _chmFiles)
{
_toc.MergeToC( curFile.TOC );
}
}
}
return _toc;
}
}
/// <summary>
/// Gets a merged index of all opened chm files
/// </summary>
public Index Index
{
get
{
if( _chmFiles.Count > 0 )
{
if( (_index.Count(IndexType.KeywordLinks)+_index.Count(IndexType.AssiciativeLinks)) <= 0)
{
// merge index files
foreach(CHMFile curFile in _chmFiles)
{
_index.MergeIndex( curFile.IndexKLinks, IndexType.KeywordLinks);
_index.MergeIndex( curFile.IndexALinks, IndexType.AssiciativeLinks);
}
}
}
return _index;
}
}
/// <summary>
/// Gets a flag if the current instance offers a table of contents
/// </summary>
public bool HasTableOfContents
{
get
{
return (TableOfContents.Count() > 0);
}
}
/// <summary>
/// Gets a flag if the current instance offers an index
/// </summary>
public bool HasIndex
{
get
{
return (HasALinks || HasKLinks);
}
}
/// <summary>
/// Gets a flag if the index holds klinks
/// </summary>
public bool HasKLinks
{
get
{
return (_index.Count(IndexType.KeywordLinks) > 0);
}
}
/// <summary>
/// Gets a flag if the index holds alinks
/// </summary>
public bool HasALinks
{
get
{
return (_index.Count(IndexType.AssiciativeLinks) > 0);
}
}
/// <summary>
/// Gets a flag if the current instance supports fulltext searching
/// </summary>
public bool FullTextSearch
{
get
{
bool bRet = false;
foreach(CHMFile curFile in _chmFiles)
{
bRet |= curFile.FullTextSearch;
}
return bRet;
}
}
/// <summary>
/// Performs a full-text search over the chm files
/// </summary>
/// <param name="words">words to search</param>
/// <param name="partialMatches">true if partial word should be matched also
/// ( if this is true a search of 'support' will match 'supports', otherwise not )</param>
/// <param name="titleOnly">true if titles only</param>
/// <returns>A DataTable containing the search hits</returns>
public DataTable PerformSearch(string words, bool partialMatches, bool titleOnly)
{
return PerformSearch(words, -1, partialMatches, titleOnly);
}
/// <summary>
/// Performs a full-text search over the chm files
/// </summary>
/// <param name="words">words to search</param>
/// <param name="MaxResults">maximal number of hits to return</param>
/// <param name="partialMatches">true if partial word should be matched also
/// ( if this is true a search of 'support' will match 'supports', otherwise not )</param>
/// <param name="titleOnly">true if titles only</param>
/// <returns>A DataTable containing the search hits</returns>
public DataTable PerformSearch(string words, int MaxResults, bool partialMatches, bool titleOnly)
{
if( ! FullTextSearch )
return null;
DataTable dtResult = null;
int nCnt = 0;
foreach(CHMFile curFile in _chmFiles)
{
if(nCnt == 0)
{
if(curFile.FullTextSearchEngine.CanSearch)
{
if(curFile.FullTextSearchEngine.Search(words, MaxResults, partialMatches, titleOnly))
{
dtResult = curFile.FullTextSearchEngine.Hits;
dtResult.DefaultView.Sort = "Rating DESC";
}
}
}
else
{
if(curFile.FullTextSearchEngine.CanSearch)
{
if(curFile.FullTextSearchEngine.Search(words, MaxResults, partialMatches, titleOnly))
{
DataTable table = curFile.FullTextSearchEngine.Hits;
// append rows from 2nd file
foreach(DataRow curRow in table.Rows)
{
dtResult.ImportRow( curRow );
}
dtResult.DefaultView.Sort = "Rating DESC";
// adjust max hits
if(MaxResults >= 0)
{
if(dtResult.DefaultView.Count > MaxResults)
{
for(int i=MaxResults-1; i<dtResult.DefaultView.Count-1;i++)
{
if(dtResult.DefaultView[i].Row.RowState != DataRowState.Deleted)
{
dtResult.DefaultView[i].Row.Delete();
dtResult.DefaultView[i].Row.AcceptChanges();
i--;
}
}
dtResult.AcceptChanges();
dtResult.DefaultView.Sort = "Rating DESC";
}
}
}
}
}
nCnt++;
}
return dtResult;
}
}
}

View File

@@ -0,0 +1,855 @@
//
// System.Web.HttpUtility
//
// Authors:
// Patrik Torstensson (Patrik.Torstensson@labs2.com)
// Wictor Wil<69>n (decode/encode functions) (wictor@ibizkit.se)
// Tim Coleman (tim@timcoleman.com)
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Text;
// using System.Web.Util;
namespace HtmlHelp.ChmDecoding
{
public sealed class HttpUtility {
#region Fields
const string _hex = "0123456789ABCDEF";
const string _chars = "<>;:.?=&@*+%/\\";
static Hashtable entities;
static object lock_ = new object ();
#endregion // Fields
static Hashtable Entities {
get {
lock (lock_) {
if (entities == null)
InitEntities ();
return entities;
}
}
}
#region Constructors
static void InitEntities ()
{
// Build the hash table of HTML entity references. This list comes
// from the HTML 4.01 W3C recommendation.
entities = new Hashtable ();
entities.Add ("nbsp", '\u00A0');
entities.Add ("iexcl", '\u00A1');
entities.Add ("cent", '\u00A2');
entities.Add ("pound", '\u00A3');
entities.Add ("curren", '\u00A4');
entities.Add ("yen", '\u00A5');
entities.Add ("brvbar", '\u00A6');
entities.Add ("sect", '\u00A7');
entities.Add ("uml", '\u00A8');
entities.Add ("copy", '\u00A9');
entities.Add ("ordf", '\u00AA');
entities.Add ("laquo", '\u00AB');
entities.Add ("not", '\u00AC');
entities.Add ("shy", '\u00AD');
entities.Add ("reg", '\u00AE');
entities.Add ("macr", '\u00AF');
entities.Add ("deg", '\u00B0');
entities.Add ("plusmn", '\u00B1');
entities.Add ("sup2", '\u00B2');
entities.Add ("sup3", '\u00B3');
entities.Add ("acute", '\u00B4');
entities.Add ("micro", '\u00B5');
entities.Add ("para", '\u00B6');
entities.Add ("middot", '\u00B7');
entities.Add ("cedil", '\u00B8');
entities.Add ("sup1", '\u00B9');
entities.Add ("ordm", '\u00BA');
entities.Add ("raquo", '\u00BB');
entities.Add ("frac14", '\u00BC');
entities.Add ("frac12", '\u00BD');
entities.Add ("frac34", '\u00BE');
entities.Add ("iquest", '\u00BF');
entities.Add ("Agrave", '\u00C0');
entities.Add ("Aacute", '\u00C1');
entities.Add ("Acirc", '\u00C2');
entities.Add ("Atilde", '\u00C3');
entities.Add ("Auml", '\u00C4');
entities.Add ("Aring", '\u00C5');
entities.Add ("AElig", '\u00C6');
entities.Add ("Ccedil", '\u00C7');
entities.Add ("Egrave", '\u00C8');
entities.Add ("Eacute", '\u00C9');
entities.Add ("Ecirc", '\u00CA');
entities.Add ("Euml", '\u00CB');
entities.Add ("Igrave", '\u00CC');
entities.Add ("Iacute", '\u00CD');
entities.Add ("Icirc", '\u00CE');
entities.Add ("Iuml", '\u00CF');
entities.Add ("ETH", '\u00D0');
entities.Add ("Ntilde", '\u00D1');
entities.Add ("Ograve", '\u00D2');
entities.Add ("Oacute", '\u00D3');
entities.Add ("Ocirc", '\u00D4');
entities.Add ("Otilde", '\u00D5');
entities.Add ("Ouml", '\u00D6');
entities.Add ("times", '\u00D7');
entities.Add ("Oslash", '\u00D8');
entities.Add ("Ugrave", '\u00D9');
entities.Add ("Uacute", '\u00DA');
entities.Add ("Ucirc", '\u00DB');
entities.Add ("Uuml", '\u00DC');
entities.Add ("Yacute", '\u00DD');
entities.Add ("THORN", '\u00DE');
entities.Add ("szlig", '\u00DF');
entities.Add ("agrave", '\u00E0');
entities.Add ("aacute", '\u00E1');
entities.Add ("acirc", '\u00E2');
entities.Add ("atilde", '\u00E3');
entities.Add ("auml", '\u00E4');
entities.Add ("aring", '\u00E5');
entities.Add ("aelig", '\u00E6');
entities.Add ("ccedil", '\u00E7');
entities.Add ("egrave", '\u00E8');
entities.Add ("eacute", '\u00E9');
entities.Add ("ecirc", '\u00EA');
entities.Add ("euml", '\u00EB');
entities.Add ("igrave", '\u00EC');
entities.Add ("iacute", '\u00ED');
entities.Add ("icirc", '\u00EE');
entities.Add ("iuml", '\u00EF');
entities.Add ("eth", '\u00F0');
entities.Add ("ntilde", '\u00F1');
entities.Add ("ograve", '\u00F2');
entities.Add ("oacute", '\u00F3');
entities.Add ("ocirc", '\u00F4');
entities.Add ("otilde", '\u00F5');
entities.Add ("ouml", '\u00F6');
entities.Add ("divide", '\u00F7');
entities.Add ("oslash", '\u00F8');
entities.Add ("ugrave", '\u00F9');
entities.Add ("uacute", '\u00FA');
entities.Add ("ucirc", '\u00FB');
entities.Add ("uuml", '\u00FC');
entities.Add ("yacute", '\u00FD');
entities.Add ("thorn", '\u00FE');
entities.Add ("yuml", '\u00FF');
entities.Add ("fnof", '\u0192');
entities.Add ("Alpha", '\u0391');
entities.Add ("Beta", '\u0392');
entities.Add ("Gamma", '\u0393');
entities.Add ("Delta", '\u0394');
entities.Add ("Epsilon", '\u0395');
entities.Add ("Zeta", '\u0396');
entities.Add ("Eta", '\u0397');
entities.Add ("Theta", '\u0398');
entities.Add ("Iota", '\u0399');
entities.Add ("Kappa", '\u039A');
entities.Add ("Lambda", '\u039B');
entities.Add ("Mu", '\u039C');
entities.Add ("Nu", '\u039D');
entities.Add ("Xi", '\u039E');
entities.Add ("Omicron", '\u039F');
entities.Add ("Pi", '\u03A0');
entities.Add ("Rho", '\u03A1');
entities.Add ("Sigma", '\u03A3');
entities.Add ("Tau", '\u03A4');
entities.Add ("Upsilon", '\u03A5');
entities.Add ("Phi", '\u03A6');
entities.Add ("Chi", '\u03A7');
entities.Add ("Psi", '\u03A8');
entities.Add ("Omega", '\u03A9');
entities.Add ("alpha", '\u03B1');
entities.Add ("beta", '\u03B2');
entities.Add ("gamma", '\u03B3');
entities.Add ("delta", '\u03B4');
entities.Add ("epsilon", '\u03B5');
entities.Add ("zeta", '\u03B6');
entities.Add ("eta", '\u03B7');
entities.Add ("theta", '\u03B8');
entities.Add ("iota", '\u03B9');
entities.Add ("kappa", '\u03BA');
entities.Add ("lambda", '\u03BB');
entities.Add ("mu", '\u03BC');
entities.Add ("nu", '\u03BD');
entities.Add ("xi", '\u03BE');
entities.Add ("omicron", '\u03BF');
entities.Add ("pi", '\u03C0');
entities.Add ("rho", '\u03C1');
entities.Add ("sigmaf", '\u03C2');
entities.Add ("sigma", '\u03C3');
entities.Add ("tau", '\u03C4');
entities.Add ("upsilon", '\u03C5');
entities.Add ("phi", '\u03C6');
entities.Add ("chi", '\u03C7');
entities.Add ("psi", '\u03C8');
entities.Add ("omega", '\u03C9');
entities.Add ("thetasym", '\u03D1');
entities.Add ("upsih", '\u03D2');
entities.Add ("piv", '\u03D6');
entities.Add ("bull", '\u2022');
entities.Add ("hellip", '\u2026');
entities.Add ("prime", '\u2032');
entities.Add ("Prime", '\u2033');
entities.Add ("oline", '\u203E');
entities.Add ("frasl", '\u2044');
entities.Add ("weierp", '\u2118');
entities.Add ("image", '\u2111');
entities.Add ("real", '\u211C');
entities.Add ("trade", '\u2122');
entities.Add ("alefsym", '\u2135');
entities.Add ("larr", '\u2190');
entities.Add ("uarr", '\u2191');
entities.Add ("rarr", '\u2192');
entities.Add ("darr", '\u2193');
entities.Add ("harr", '\u2194');
entities.Add ("crarr", '\u21B5');
entities.Add ("lArr", '\u21D0');
entities.Add ("uArr", '\u21D1');
entities.Add ("rArr", '\u21D2');
entities.Add ("dArr", '\u21D3');
entities.Add ("hArr", '\u21D4');
entities.Add ("forall", '\u2200');
entities.Add ("part", '\u2202');
entities.Add ("exist", '\u2203');
entities.Add ("empty", '\u2205');
entities.Add ("nabla", '\u2207');
entities.Add ("isin", '\u2208');
entities.Add ("notin", '\u2209');
entities.Add ("ni", '\u220B');
entities.Add ("prod", '\u220F');
entities.Add ("sum", '\u2211');
entities.Add ("minus", '\u2212');
entities.Add ("lowast", '\u2217');
entities.Add ("radic", '\u221A');
entities.Add ("prop", '\u221D');
entities.Add ("infin", '\u221E');
entities.Add ("ang", '\u2220');
entities.Add ("and", '\u2227');
entities.Add ("or", '\u2228');
entities.Add ("cap", '\u2229');
entities.Add ("cup", '\u222A');
entities.Add ("int", '\u222B');
entities.Add ("there4", '\u2234');
entities.Add ("sim", '\u223C');
entities.Add ("cong", '\u2245');
entities.Add ("asymp", '\u2248');
entities.Add ("ne", '\u2260');
entities.Add ("equiv", '\u2261');
entities.Add ("le", '\u2264');
entities.Add ("ge", '\u2265');
entities.Add ("sub", '\u2282');
entities.Add ("sup", '\u2283');
entities.Add ("nsub", '\u2284');
entities.Add ("sube", '\u2286');
entities.Add ("supe", '\u2287');
entities.Add ("oplus", '\u2295');
entities.Add ("otimes", '\u2297');
entities.Add ("perp", '\u22A5');
entities.Add ("sdot", '\u22C5');
entities.Add ("lceil", '\u2308');
entities.Add ("rceil", '\u2309');
entities.Add ("lfloor", '\u230A');
entities.Add ("rfloor", '\u230B');
entities.Add ("lang", '\u2329');
entities.Add ("rang", '\u232A');
entities.Add ("loz", '\u25CA');
entities.Add ("spades", '\u2660');
entities.Add ("clubs", '\u2663');
entities.Add ("hearts", '\u2665');
entities.Add ("diams", '\u2666');
entities.Add ("quot", '\u0022');
entities.Add ("amp", '\u0026');
entities.Add ("lt", '\u003C');
entities.Add ("gt", '\u003E');
entities.Add ("OElig", '\u0152');
entities.Add ("oelig", '\u0153');
entities.Add ("Scaron", '\u0160');
entities.Add ("scaron", '\u0161');
entities.Add ("Yuml", '\u0178');
entities.Add ("circ", '\u02C6');
entities.Add ("tilde", '\u02DC');
entities.Add ("ensp", '\u2002');
entities.Add ("emsp", '\u2003');
entities.Add ("thinsp", '\u2009');
entities.Add ("zwnj", '\u200C');
entities.Add ("zwj", '\u200D');
entities.Add ("lrm", '\u200E');
entities.Add ("rlm", '\u200F');
entities.Add ("ndash", '\u2013');
entities.Add ("mdash", '\u2014');
entities.Add ("lsquo", '\u2018');
entities.Add ("rsquo", '\u2019');
entities.Add ("sbquo", '\u201A');
entities.Add ("ldquo", '\u201C');
entities.Add ("rdquo", '\u201D');
entities.Add ("bdquo", '\u201E');
entities.Add ("dagger", '\u2020');
entities.Add ("Dagger", '\u2021');
entities.Add ("permil", '\u2030');
entities.Add ("lsaquo", '\u2039');
entities.Add ("rsaquo", '\u203A');
entities.Add ("euro", '\u20AC');
}
public HttpUtility ()
{
}
#endregion // Constructors
#region Methods
public static void HtmlAttributeEncode (string s, TextWriter output)
{
output.Write(HtmlAttributeEncode(s));
}
public static string HtmlAttributeEncode (string s)
{
if (null == s)
return null;
if (s.IndexOf ('&') == -1 && s.IndexOf ('"') == -1)
return s;
StringBuilder output = new StringBuilder ();
foreach (char c in s)
switch (c) {
case '&' :
output.Append ("&amp;");
break;
case '"' :
output.Append ("&quot;");
break;
default:
output.Append (c);
break;
}
return output.ToString();
}
public static string UrlDecode (string str)
{
return UrlDecode(str, Encoding.UTF8);
}
private static char [] GetChars (MemoryStream b, Encoding e)
{
return e.GetChars (b.GetBuffer (), 0, (int) b.Length);
}
public static string UrlDecode (string s, Encoding e)
{
if (null == s)
return null;
if (s.IndexOf ('%') == -1 && s.IndexOf ('+') == -1)
return s;
if (e == null)
e = Encoding.UTF8;
StringBuilder output = new StringBuilder ();
long len = s.Length;
NumberStyles hexa = NumberStyles.HexNumber;
MemoryStream bytes = new MemoryStream ();
for (int i = 0; i < len; i++) {
if (s [i] == '%' && i + 2 < len) {
if (s [i + 1] == 'u' && i + 5 < len) {
if (bytes.Length > 0) {
output.Append (GetChars (bytes, e));
bytes.SetLength (0);
}
output.Append ((char) Int32.Parse (s.Substring (i + 2, 4), hexa));
i += 5;
} else {
bytes.WriteByte ((byte) Int32.Parse (s.Substring (i + 1, 2), hexa));
i += 2;
}
continue;
}
if (bytes.Length > 0) {
output.Append (GetChars (bytes, e));
bytes.SetLength (0);
}
if (s [i] == '+') {
output.Append (' ');
} else {
output.Append (s [i]);
}
}
if (bytes.Length > 0) {
output.Append (GetChars (bytes, e));
}
bytes = null;
return output.ToString ();
}
public static string UrlDecode (byte [] bytes, Encoding e)
{
if (bytes == null)
return null;
return UrlDecode (bytes, 0, bytes.Length, e);
}
private static int GetInt (byte b)
{
char c = Char.ToUpper ((char) b);
if (c >= '0' && c <= '9')
return c - '0';
if (c < 'A' || c > 'F')
return 0;
return (c - 'A' + 10);
}
private static char GetChar (byte [] bytes, int offset, int length)
{
int value = 0;
int end = length + offset;
for (int i = offset; i < end; i++)
value = (value << 4) + GetInt (bytes [offset]);
return (char) value;
}
public static string UrlDecode (byte [] bytes, int offset, int count, Encoding e)
{
if (bytes == null || count == 0)
return null;
if (bytes == null)
throw new ArgumentNullException ("bytes");
if (offset < 0 || offset > bytes.Length)
throw new ArgumentOutOfRangeException ("offset");
if (count < 0 || offset + count > bytes.Length)
throw new ArgumentOutOfRangeException ("count");
StringBuilder output = new StringBuilder ();
MemoryStream acc = new MemoryStream ();
int end = count + offset;
for (int i = offset; i < end; i++) {
if (bytes [i] == '%' && i + 2 < count) {
if (bytes [i + 1] == (byte) 'u' && i + 5 < end) {
if (acc.Length > 0) {
output.Append (GetChars (acc, e));
acc.SetLength (0);
}
output.Append (GetChar (bytes, offset + 2, 4));
i += 5;
} else {
acc.WriteByte ((byte) GetChar (bytes, offset + 1, 2));
i += 2;
}
continue;
}
if (acc.Length > 0) {
output.Append (GetChars (acc, e));
acc.SetLength (0);
}
if (bytes [i] == '+') {
output.Append (' ');
} else {
output.Append ((char) bytes [i]);
}
}
if (acc.Length > 0) {
output.Append (GetChars (acc, e));
}
acc = null;
return output.ToString ();
}
public static byte [] UrlDecodeToBytes (byte [] bytes)
{
if (bytes == null)
return null;
return UrlDecodeToBytes (bytes, 0, bytes.Length);
}
public static byte [] UrlDecodeToBytes (string str)
{
return UrlDecodeToBytes (str, Encoding.UTF8);
}
public static byte [] UrlDecodeToBytes (string str, Encoding e)
{
if (str == null)
return null;
if (e == null)
throw new ArgumentNullException ("e");
return UrlDecodeToBytes (e.GetBytes (str));
}
public static byte [] UrlDecodeToBytes (byte [] bytes, int offset, int count)
{
if (bytes == null)
return null;
int len = bytes.Length;
if (offset < 0 || offset >= len)
throw new ArgumentOutOfRangeException("offset");
if (count < 0 || offset > len - count)
throw new ArgumentOutOfRangeException("count");
MemoryStream result = new MemoryStream ();
int end = offset + count;
for (int i = offset; i < end; i++){
char c = (char) bytes [i];
if (c == '+')
c = ' ';
else if (c == '%' && i < end - 2) {
c = GetChar (bytes, i, 2);
i += 2;
}
result.WriteByte ((byte) c);
}
return result.ToArray ();
}
public static string UrlEncode(string str)
{
return UrlEncode(str, Encoding.UTF8);
}
public static string UrlEncode (string s, Encoding Enc)
{
if (s == null)
return null;
if (s == "")
return "";
byte [] bytes = Enc.GetBytes (s);
byte [] b =UrlEncodeToBytes (bytes, 0, bytes.Length);
return Encoding.ASCII.GetString (b,0,b.Length);
}
public static string UrlEncode (byte [] bytes)
{
if (bytes == null)
return null;
if (bytes.Length == 0)
return "";
byte []b=UrlEncodeToBytes(bytes, 0, bytes.Length);
return Encoding.ASCII.GetString (b,0,b.Length);
}
public static string UrlEncode (byte [] bytes, int offset, int count)
{
if (bytes == null)
return null;
if (bytes.Length == 0)
return "";
byte []b=UrlEncodeToBytes(bytes, offset, count);
return Encoding.ASCII.GetString (b,0,b.Length);
}
public static byte [] UrlEncodeToBytes (string str)
{
return UrlEncodeToBytes (str, Encoding.UTF8);
}
public static byte [] UrlEncodeToBytes (string str, Encoding e)
{
if (str == null)
return null;
if (str == "")
return new byte [0];
byte [] bytes = e.GetBytes (str);
return UrlEncodeToBytes (bytes, 0, bytes.Length);
}
public static byte [] UrlEncodeToBytes (byte [] bytes)
{
if (bytes == null)
return null;
if (bytes.Length == 0)
return new byte [0];
return UrlEncodeToBytes (bytes, 0, bytes.Length);
}
static char [] hexChars = "0123456789abcdef".ToCharArray ();
public static byte [] UrlEncodeToBytes (byte [] bytes, int offset, int count)
{
if (bytes == null)
return null;
int len = bytes.Length;
if (len == 0)
return new byte [0];
if (offset < 0 || offset >= len)
throw new ArgumentOutOfRangeException("offset");
if (count < 0 || count > len - offset)
throw new ArgumentOutOfRangeException("count");
MemoryStream result = new MemoryStream ();
int end = offset + count;
for (int i = offset; i < end; i++) {
char c = (char) bytes [i];
if ((c == ' ') || (c < '0' && c != '-' && c != '.') ||
(c < 'A' && c > '9') ||
(c > 'Z' && c < 'a' && c != '_') ||
(c > 'z')) {
result.WriteByte ((byte) '%');
int idx = ((int) c) >> 4;
result.WriteByte ((byte) hexChars [idx]);
idx = ((int) c) & 0x0F;
result.WriteByte ((byte) hexChars [idx]);
} else {
result.WriteByte ((byte) c);
}
}
return result.ToArray ();
}
public static string UrlEncodeUnicode (string str)
{
if (str == null)
return null;
StringBuilder result = new StringBuilder ();
int end = str.Length;
for (int i = 0; i < end; i++) {
int idx;
char c = str [i];
if (c > 255) {
result.Append ("%u");
idx = ((int) c) >> 24;
result.Append (hexChars [idx]);
idx = (((int) c) >> 16) & 0x0F;
result.Append (hexChars [idx]);
idx = (((int) c) >> 8) & 0x0F;
result.Append (hexChars [idx]);
idx = ((int) c) & 0x0F;
result.Append (hexChars [idx]);
continue;
}
if ((c == ' ') || (c < '0' && c != '-' && c != '.') ||
(c < 'A' && c > '9') ||
(c > 'Z' && c < 'a' && c != '_') ||
(c > 'z')) {
result.Append ('%');
idx = ((int) c) >> 4;
result.Append (hexChars [idx]);
idx = ((int) c) & 0x0F;
result.Append (hexChars [idx]);
continue;
}
result.Append (c);
}
return result.ToString ();
}
public static byte [] UrlEncodeUnicodeToBytes (string str)
{
if (str == null)
return null;
if (str == "")
return new byte [0];
return Encoding.ASCII.GetBytes (UrlEncodeUnicode (str));
}
/// <summary>
/// Decodes an HTML-encoded string and returns the decoded string.
/// </summary>
/// <param name="s">The HTML string to decode. </param>
/// <returns>The decoded text.</returns>
public static string HtmlDecode (string s)
{
if (s == null)
throw new ArgumentNullException ("s");
if (s.IndexOf ('&') == -1)
return s;
bool insideEntity = false; // used to indicate that we are in a potential entity
string entity = String.Empty;
StringBuilder output = new StringBuilder ();
int len = s.Length;
for (int i = 0; i < len; i++) {
char c = s [i];
switch (c) {
case '&' :
output.Append (entity);
entity = "&";
insideEntity = true;
break;
case ';' :
if (!insideEntity) {
output.Append (c);
break;
}
entity += c;
int length = entity.Length;
if (length >= 2 && entity[1] == '#' && entity[2] != ';')
entity = ((char) Int32.Parse (entity.Substring (2, entity.Length - 3))).ToString();
else if (length > 1 && Entities.ContainsKey (entity.Substring (1, entity.Length - 2)))
entity = Entities [entity.Substring (1, entity.Length - 2)].ToString ();
output.Append (entity);
entity = String.Empty;
insideEntity = false;
break;
default :
if (insideEntity)
entity += c;
else
output.Append (c);
break;
}
}
output.Append (entity);
return output.ToString ();
}
/// <summary>
/// Decodes an HTML-encoded string and sends the resulting output to a TextWriter output stream.
/// </summary>
/// <param name="s">The HTML string to decode</param>
/// <param name="output">The TextWriter output stream containing the decoded string. </param>
public static void HtmlDecode(string s, TextWriter output)
{
if (s != null)
output.Write (HtmlDecode (s));
}
/// <summary>
/// HTML-encodes a string and returns the encoded string.
/// </summary>
/// <param name="s">The text string to encode. </param>
/// <returns>The HTML-encoded text.</returns>
public static string HtmlEncode (string s)
{
if (s == null)
return null;
StringBuilder output = new StringBuilder ();
foreach (char c in s)
switch (c) {
case '&' :
output.Append ("&amp;");
break;
case '>' :
output.Append ("&gt;");
break;
case '<' :
output.Append ("&lt;");
break;
case '"' :
output.Append ("&quot;");
break;
default:
if ((int) c > 128) {
output.Append ("&#");
output.Append (((int) c).ToString ());
output.Append (";");
}
else
output.Append (c);
break;
}
return output.ToString ();
}
/// <summary>
/// HTML-encodes a string and sends the resulting output to a TextWriter output stream.
/// </summary>
/// <param name="s">The string to encode. </param>
/// <param name="output">The TextWriter output stream containing the encoded string. </param>
public static void HtmlEncode(string s, TextWriter output)
{
if (s != null)
output.Write (HtmlEncode (s));
}
#if NET_1_1
public string UrlPathEncode (string s)
{
if (s == null)
return null;
int idx = s.IndexOf ("?");
string s2 = null;
if (idx != -1) {
s2 = s.Substring (0, idx-1);
s2 = UrlEncode (s2) + s.Substring (idx);
} else {
s2 = UrlEncode (s);
}
return s2;
}
#endif
#endregion // Methods
}
}

View File

@@ -0,0 +1,322 @@
using System;
using System.Diagnostics;
using System.Collections;
using HtmlHelp.ChmDecoding;
namespace HtmlHelp
{
/// <summary>
/// Enumeration for specifying the index type
/// </summary>
public enum IndexType
{
/// <summary>
/// Keyword links should be used
/// </summary>
KeywordLinks = 0,
/// <summary>
/// Associative links should be used
/// </summary>
AssiciativeLinks = 1
}
/// <summary>
/// The class <c>Index</c> holds the (keyword links) KLinks and (associative links) ALinks of the htmlhelp
/// system. It implements methods for easy index-based searching.
/// </summary>
public class Index
{
private ArrayList _kLinks = new ArrayList();
private ArrayList _aLinks = new ArrayList();
/// <summary>
/// Standard constructor
/// </summary>
public Index()
{
}
/// <summary>
/// Constructor of the class
/// </summary>
/// <param name="kLinks">arraylist with keyword links</param>
/// <param name="aLinks">arraylist with associative links</param>
public Index(ArrayList kLinks, ArrayList aLinks)
{
_kLinks= kLinks;
_aLinks = aLinks;
}
/// <summary>
/// Clears the current toc
/// </summary>
public void Clear()
{
if(_aLinks != null)
_aLinks.Clear();
if(_kLinks != null)
_kLinks.Clear();
}
/// <summary>
/// Gets the number of index items for a specific type
/// </summary>
/// <param name="typeOfIndex">type of index</param>
/// <returns>Returns the number of index items for a specific type</returns>
public int Count(IndexType typeOfIndex)
{
ArrayList _index = null;
switch( typeOfIndex )
{
case IndexType.AssiciativeLinks: _index = _aLinks; break;
case IndexType.KeywordLinks: _index = _kLinks; break;
}
if(_index != null)
return _index.Count;
return 0;
}
/// <summary>
/// Gets the internal index list of keyword links
/// </summary>
public ArrayList KLinks
{
get
{
if(_kLinks==null)
_kLinks = new ArrayList();
return _kLinks;
}
}
/// <summary>
/// Gets the internal index list of associative links
/// </summary>
public ArrayList ALinks
{
get
{
if(_aLinks==null)
_aLinks = new ArrayList();
return _aLinks;
}
}
/// <summary>
/// Merges the the index list <c>arrIndex</c> into the current one
/// </summary>
/// <param name="arrIndex">indexlist which should be merged with the current one</param>
/// <param name="typeOfIndex">type of index to merge</param>
public void MergeIndex( ArrayList arrIndex, IndexType typeOfIndex )
{
ArrayList _index = null;
switch(typeOfIndex)
{
case IndexType.AssiciativeLinks: _index = _aLinks;break;
case IndexType.KeywordLinks: _index = _kLinks;break;
}
foreach(IndexItem curItem in arrIndex)
{
//IndexItem searchItem = ContainsIndex(_index, curItem.KeyWordPath);
int insertIndex=0;
IndexItem searchItem = BinSearch(0, _index.Count-1, _index, curItem.KeyWordPath, false, false, ref insertIndex);
if(searchItem != null)
{
// extend the keywords topics
foreach(IndexTopic curEntry in curItem.Topics)
{
searchItem.Topics.Add( curEntry );
}
}
else
{
// add the item to the global collection
//_index.Add( curItem );
if(insertIndex > _index.Count)
_index.Add(curItem);
else
_index.Insert(insertIndex, curItem);
}
}
}
/// <summary>
/// Searches an index entry using recursive binary search algo (divide and conquer).
/// </summary>
/// <param name="nStart">start index for searching</param>
/// <param name="nEnd">end index for searching</param>
/// <param name="arrIndex">arraylist containing sorted IndexItem entries</param>
/// <param name="keywordPath">keyword path to search</param>
/// <param name="searchKeyword">true if the keywordPath will only contain the keyword not the complete path</param>
/// <param name="caseInsensitive">True if case should be ignored</param>
/// <param name="insertIndex">out reference. will receive the index where the item with the
/// keywordPath should be inserted if not found (receives -1 if the item was found)</param>
/// <returns>Returns an IndexItem instance if found, otherwise null
/// (use insertIndex for inserting the new item in a sorted order)</returns>
private IndexItem BinSearch(int nStart, int nEnd, ArrayList arrIndex, string keywordPath,
bool searchKeyword, bool caseInsensitive, ref int insertIndex)
{
if( arrIndex.Count <= 0 )
{
insertIndex=0;
return null;
}
if(caseInsensitive)
keywordPath = keywordPath.ToLower();
if( (nEnd - nStart) > 1)
{
int nCheck = nStart + (nEnd-nStart)/2;
IndexItem iC = arrIndex[nCheck] as IndexItem;
string sCompare = iC.KeyWordPath;
if(searchKeyword)
sCompare = iC.KeyWord;
if(caseInsensitive)
sCompare = sCompare.ToLower();
if( sCompare == keywordPath )
{
insertIndex=-1;
return iC;
}
if( keywordPath.CompareTo(sCompare) < 0 )
{
return BinSearch(nStart, nCheck-1, arrIndex, keywordPath, searchKeyword, caseInsensitive, ref insertIndex);
}
if( keywordPath.CompareTo(sCompare) > 0 )
{
return BinSearch(nCheck+1, nEnd, arrIndex, keywordPath, searchKeyword, caseInsensitive, ref insertIndex);
}
}
else if(nEnd-nStart == 1)
{
IndexItem i1 = arrIndex[nStart] as IndexItem;
IndexItem i2 = arrIndex[nEnd] as IndexItem;
string sCompare1 = i1.KeyWordPath;
if(searchKeyword)
sCompare1 = i1.KeyWord;
if(caseInsensitive)
sCompare1 = sCompare1.ToLower();
string sCompare2 = i2.KeyWordPath;
if(searchKeyword)
sCompare2 = i2.KeyWord;
if(caseInsensitive)
sCompare2 = sCompare2.ToLower();
if( sCompare1 == keywordPath)
{
insertIndex = -1;
return i1;
}
if( sCompare2 == keywordPath)
{
insertIndex = -1;
return i2;
}
if( sCompare1.CompareTo(keywordPath) > 0)
{
insertIndex = nStart;
return null;
}
else if( sCompare2.CompareTo(keywordPath) > 0)
{
insertIndex = nEnd;
return null;
}
else
{
insertIndex = nEnd+1;
}
}
IndexItem itm = arrIndex[nEnd] as IndexItem;
string sCompareI = itm.KeyWordPath;
if(searchKeyword)
sCompareI = itm.KeyWord;
if(caseInsensitive)
sCompareI = sCompareI.ToLower();
if( sCompareI.CompareTo(keywordPath) > 0)
{
insertIndex = nStart;
return null;
}
else if( sCompareI.CompareTo(keywordPath) < 0)
{
insertIndex = nEnd+1;
return null;
}
else
{
insertIndex = -1;
return arrIndex[nEnd] as IndexItem;
}
}
/// <summary>
/// Checks if a keyword exists in a index collection
/// </summary>
/// <param name="arrIndex">index to search (arraylist of IndexItems)</param>
/// <param name="keywordPath">keywordpath to search</param>
/// <returns>Returns the found IndexItem, otherwise null</returns>
private IndexItem ContainsIndex(ArrayList arrIndex, string keywordPath)
{
foreach(IndexItem curItem in arrIndex)
{
if(curItem.KeyWordPath == keywordPath)
return curItem;
}
return null;
}
/// <summary>
/// Searches the alinks- or klinks-index for a specific keyword/associative
/// </summary>
/// <param name="search">keyword/associative to search</param>
/// <param name="typeOfIndex">type of index to search</param>
/// <returns>Returns an ArrayList which contains IndexTopic items or null if nothing was found</returns>
public IndexItem SearchIndex(string search, IndexType typeOfIndex)
{
ArrayList _index = null;
switch( typeOfIndex )
{
case IndexType.AssiciativeLinks: _index = _aLinks;break;
case IndexType.KeywordLinks: _index = _kLinks;break;
}
int insertIdx=0;
IndexItem foundItem = BinSearch(0, _index.Count, _index, search, true, true, ref insertIdx);
return foundItem;
}
}
}

View File

@@ -0,0 +1,396 @@
using System;
using System.IO;
using System.Text;
using System.Collections;
using HtmlHelp.ChmDecoding;
namespace HtmlHelp
{
/// <summary>
/// The class <c>IndexItem</c> implements an help-index item
/// </summary>
public sealed class IndexItem : IComparable
{
/// <summary>
/// Internal member storing the keyword
/// </summary>
private string _keyWord = "";
/// <summary>
/// Internal member storing all associated information type strings
/// </summary>
private ArrayList _infoTypeStrings = new ArrayList();
/// <summary>
/// Internal member storing the flag if this is a see-also keyword
/// </summary>
private bool _isSeeAlso = false;
/// <summary>
/// Internal member storing the indent of the keyword
/// </summary>
private int _indent = 0;
/// <summary>
/// Internal member storing the last index of the keyword in the seperated list
/// </summary>
private int _charIndex = 0;
/// <summary>
/// Internal member storing the entry index
/// </summary>
private int _entryIndex = 0;
/// <summary>
/// Internal member storing an array of see-also values
/// </summary>
private string[] _seeAlso = new string[0];
/// <summary>
/// Internal member storing an array of topic offsets
/// </summary>
private int[] _nTopics = new int[0];
/// <summary>
/// Internal member storing the topics
/// </summary>
private ArrayList _Topics = null;
/// <summary>
/// Associated CHMFile instance
/// </summary>
private CHMFile _chmFile = null;
/// <summary>
/// Internal flag specifying the chm file path
/// </summary>
private string _chmFileName = "";
/// <summary>
/// Constructor of the class
/// </summary>
/// <param name="chmFile">associated CHMFile instance</param>
/// <param name="keyWord">keyword</param>
/// <param name="isSeeAlso">true if it is a see-also keyword</param>
/// <param name="indent">indent of the entry</param>
/// <param name="charIndex">char index of the last keyword in the separated list</param>
/// <param name="entryIndex">index of the entry</param>
/// <param name="seeAlsoValues">string array with see-also values</param>
/// <param name="topicOffsets">integer array with topic offsets</param>
internal IndexItem(CHMFile chmFile, string keyWord, bool isSeeAlso, int indent, int charIndex, int entryIndex, string[] seeAlsoValues, int[] topicOffsets)
{
_chmFile = chmFile;
_chmFileName = _chmFile.ChmFilePath;
_keyWord = keyWord;
_isSeeAlso = isSeeAlso;
_indent = indent;
_charIndex = charIndex;
_entryIndex = entryIndex;
_seeAlso = seeAlsoValues;
_nTopics = topicOffsets;
}
/// <summary>
/// Standard constructor
/// </summary>
public IndexItem()
{
}
#region Data dumping
/// <summary>
/// Dump the class data to a binary writer
/// </summary>
/// <param name="writer">writer to write the data</param>
/// <param name="writeFileName">true if the chm filename should be written</param>
internal void Dump(ref BinaryWriter writer, bool writeFileName)
{
int i=0;
writer.Write(_keyWord);
writer.Write(_isSeeAlso);
writer.Write(_indent);
if(writeFileName)
writer.Write(_chmFileName);
writer.Write(_infoTypeStrings.Count);
for(i=0; i<_infoTypeStrings.Count; i++)
writer.Write( (_infoTypeStrings[i]).ToString() );
writer.Write(_seeAlso.Length);
for(i=0; i<_seeAlso.Length; i++)
{
if(_seeAlso[i] == null)
writer.Write("");
else
writer.Write( _seeAlso[i] );
}
writer.Write(Topics.Count);
for(i=0; i<Topics.Count; i++)
{
IndexTopic topic = ((IndexTopic)(Topics[i]));
topic.Dump(ref writer);
}
}
/// <summary>
/// Dump the class data to a binary writer
/// </summary>
/// <param name="writer">writer to write the data</param>
internal void Dump(ref BinaryWriter writer)
{
Dump(ref writer, false);
}
/// <summary>
/// Reads the object data from a dump store
/// </summary>
/// <param name="reader">reader to read the data</param>
/// <param name="filesList">filelist from helpsystem</param>
internal bool ReadDump(ref BinaryReader reader, ArrayList filesList)
{
int i=0;
_keyWord = reader.ReadString();
_isSeeAlso = reader.ReadBoolean();
_indent = reader.ReadInt32();
_chmFileName = reader.ReadString();
foreach(CHMFile curFile in filesList)
{
if(curFile.ChmFilePath == _chmFileName)
{
_chmFile = curFile;
break;
}
}
if(_chmFile==null)
return false;
int nCnt = reader.ReadInt32();
for(i=0; i<nCnt; i++)
{
string sIT = reader.ReadString();
_infoTypeStrings.Add(sIT);
}
nCnt = reader.ReadInt32();
_seeAlso = new string[nCnt];
for(i=0; i<nCnt; i++)
{
_seeAlso[i] = reader.ReadString();
}
nCnt = reader.ReadInt32();
for(i=0; i<nCnt; i++)
{
IndexTopic topic = new IndexTopic("","","","");
topic.SetChmInfo( _chmFile.CompileFile, _chmFile.ChmFilePath);
topic.AssociatedFile = _chmFile;
topic.ReadDump(ref reader);
Topics.Add(topic);
}
return true;
}
/// <summary>
/// Reads the object data from a dump store
/// </summary>
/// <param name="reader">reader to read the data</param>
internal void ReadDump(ref BinaryReader reader)
{
int i=0;
_keyWord = reader.ReadString();
_isSeeAlso = reader.ReadBoolean();
_indent = reader.ReadInt32();
int nCnt = reader.ReadInt32();
for(i=0; i<nCnt; i++)
{
string sIT = reader.ReadString();
_infoTypeStrings.Add(sIT);
}
nCnt = reader.ReadInt32();
_seeAlso = new string[nCnt];
for(i=0; i<nCnt; i++)
{
_seeAlso[i] = reader.ReadString();
}
nCnt = reader.ReadInt32();
for(i=0; i<nCnt; i++)
{
IndexTopic topic = new IndexTopic("","","","");
topic.AssociatedFile = _chmFile;
topic.SetChmInfo( _chmFile.CompileFile, _chmFile.ChmFilePath);
topic.ReadDump(ref reader);
Topics.Add(topic);
}
}
#endregion
/// <summary>
/// Implements the compareto method which allows sorting.
/// </summary>
/// <param name="obj">object to compare to</param>
/// <returns>See <see cref="System.IComparable">IComparable.CompareTo()</see></returns>
public int CompareTo(object obj)
{
if( obj.GetType() == this.GetType() )
{
IndexItem cmp = (IndexItem)obj;
return this.KeyWordPath.CompareTo( cmp.KeyWordPath );
}
return 0;
}
/// <summary>
/// Gets/Sets the associated CHMFile instance
/// </summary>
internal CHMFile ChmFile
{
get { return _chmFile; }
set { _chmFile = value; }
}
/// <summary>
/// Gets the ArrayList which holds all information types/categories this item is associated
/// </summary>
internal ArrayList InfoTypeStrings
{
get { return _infoTypeStrings; }
}
/// <summary>
/// Adds a see-also string to the index item and marks it as see also item
/// </summary>
/// <param name="seeAlsoString">see also string to add</param>
internal void AddSeeAlso(string seeAlsoString)
{
string[] seeAlso = new string[ _seeAlso.Length +1 ];
for(int i=0; i<_seeAlso.Length; i++)
seeAlso[i] = _seeAlso[i];
seeAlso[_seeAlso.Length] = seeAlsoString;
_seeAlso = seeAlso;
_isSeeAlso = true;
}
/// <summary>
/// Gets/Sets the full keyword-path of this item ( ", " separated list)
/// </summary>
public string KeyWordPath
{
get { return _keyWord; }
set { _keyWord = value; }
}
/// <summary>
/// Gets the keyword of this item
/// </summary>
public string KeyWord
{
get
{
return _keyWord.Substring(_charIndex, _keyWord.Length-_charIndex);
}
}
/// <summary>
/// Gets the keyword of this item with prefixing indent spaces
/// </summary>
public string IndentKeyWord
{
get
{
string sKW = this.KeyWord;
StringBuilder sb = new StringBuilder("",this.Indent*3 + sKW.Length);
for(int i=0; i<this.Indent; i++)
sb.Append(" ");
sb.Append(sKW);
return sb.ToString();
}
}
/// <summary>
/// Gets/Sets the see-also flag of this item
/// </summary>
public bool IsSeeAlso
{
get { return _isSeeAlso; }
set { _isSeeAlso = value; }
}
/// <summary>
/// Gets/Sets the listbox indent for this item
/// </summary>
public int Indent
{
get { return _indent; }
set { _indent = value; }
}
/// <summary>
/// Gets/Sets the character index of an indent keyword
/// </summary>
public int CharIndex
{
get { return _charIndex; }
set { _charIndex = value; }
}
/// <summary>
/// Gets the see-also values of this item
/// </summary>
public string[] SeeAlso
{
get { return _seeAlso; }
}
/// <summary>
/// Gets an array with the associated topics
/// </summary>
public ArrayList Topics
{
get
{
if( _Topics == null )
{
if(IsSeeAlso)
{
_Topics = new ArrayList();
}
else
{
if( (_chmFile != null) && (_chmFile.TopicsFile != null) )
{
_Topics = new ArrayList();
for(int i=0; i<_nTopics.Length; i++)
{
IndexTopic newTopic = IndexTopic.FromTopicEntry((TopicEntry)_chmFile.TopicsFile.TopicTable[ _nTopics[i] ]);
newTopic.AssociatedFile = _chmFile;
_Topics.Add( newTopic );
}
}
else
{
_Topics = new ArrayList();
}
}
}
return _Topics;
}
}
}
}

View File

@@ -0,0 +1,216 @@
using System;
using System.IO;
using HtmlHelp.ChmDecoding;
namespace HtmlHelp
{
/// <summary>
/// The class <c>IndexTopic</c> implements an entry for the <see cref="IndexItem">IndexItem</see> topics list.
/// </summary>
public sealed class IndexTopic
{
private DataMode _topicMode = DataMode.TextBased;
private string _title="";
private string _local="";
private string _compileFile = "";
private string _chmPath = "";
private int _topicOffset = -1;
private CHMFile _associatedFile = null;
/// <summary>
/// Creates a new instance of the class based on an existing TopicEntry
/// </summary>
/// <param name="entry"></param>
internal static IndexTopic FromTopicEntry(TopicEntry entry)
{
return new IndexTopic(entry.EntryOffset, entry.ChmFile);
//return new IndexTopic( entry.Title, entry.Locale, entry.ChmFile.CompileFile, entry.ChmFile.ChmFilePath);
}
/// <summary>
/// Creates a new instance of the class (binary extraction mode)
/// </summary>
/// <param name="topicOffset">offset of the topic entry</param>
/// <param name="associatedFile">associated CHMFile instance</param>
internal IndexTopic(int topicOffset, CHMFile associatedFile)
{
_topicMode = DataMode.Binary;
_topicOffset = topicOffset;
_associatedFile = associatedFile;
}
/// <summary>
/// Constructor of the class
/// </summary>
/// <param name="Title">topic title</param>
/// <param name="local">topic local (content filename)</param>
/// <param name="compilefile">name of the chm file (location of topic)</param>
/// <param name="chmpath">path of the chm file</param>
public IndexTopic(string Title, string local, string compilefile, string chmpath)
{
_topicMode = DataMode.TextBased;
_title = Title;
_local = local;
_compileFile = compilefile;
_chmPath = chmpath;
}
#region Data dumping
/// <summary>
/// Dump the class data to a binary writer
/// </summary>
/// <param name="writer">writer to write the data</param>
internal void Dump(ref BinaryWriter writer)
{
writer.Write((int)_topicMode);
if(_topicMode==DataMode.TextBased)
{
writer.Write(_title);
writer.Write(_local);
}
else
{
writer.Write(_topicOffset);
}
}
/// <summary>
/// Reads the object data from a dump store
/// </summary>
/// <param name="reader">reader to read the data</param>
internal void ReadDump(ref BinaryReader reader)
{
_topicMode = (DataMode)reader.ReadInt32();
if(_topicMode==DataMode.TextBased)
{
_title = reader.ReadString();
_local = reader.ReadString();
}
else
{
_topicOffset = reader.ReadInt32();
}
}
#endregion
/// <summary>
/// Internally used to set the chm-finos when reading from dump store
/// </summary>
/// <param name="compilefile"></param>
/// <param name="chmpath"></param>
internal void SetChmInfo(string compilefile, string chmpath)
{
_compileFile = compilefile;
_chmPath = chmpath;
}
/// <summary>
/// Gets/Sets the associated CHMFile instance
/// </summary>
internal CHMFile AssociatedFile
{
get { return _associatedFile; }
set { _associatedFile = value; }
}
/// <summary>
/// Gets the topic title
/// </summary>
public string Title
{
get
{
if((_topicMode == DataMode.Binary )&&(_associatedFile!=null))
{
if( _topicOffset >= 0)
{
TopicEntry te = (TopicEntry) (_associatedFile.TopicsFile[_topicOffset]);
if(te != null)
{
return te.Title;
}
}
}
return _title;
}
}
/// <summary>
/// Gets the local (content filename)
/// </summary>
public string Local
{
get
{
if((_topicMode == DataMode.Binary )&&(_associatedFile!=null))
{
if( _topicOffset >= 0)
{
TopicEntry te = (TopicEntry) (_associatedFile.TopicsFile[_topicOffset]);
if(te != null)
{
return te.Locale;
}
}
}
return _local;
}
}
/// <summary>
/// Gets the compile file (location)
/// </summary>
public string CompileFile
{
get
{
if(_associatedFile != null)
return _associatedFile.CompileFile;
return _compileFile;
}
}
/// <summary>
/// Gets the chm file path
/// </summary>
public string ChmFilePath
{
get
{
if(_associatedFile != null)
return _associatedFile.ChmFilePath;
return _chmPath;
}
}
/// <summary>
/// Gets the url
/// </summary>
public string URL
{
get
{
string sL = Local;
if(sL.Length<=0)
return "";//"about:blank";
if( (sL.ToLower().IndexOf("http://") >= 0) ||
(sL.ToLower().IndexOf("https://") >= 0) ||
(sL.ToLower().IndexOf("mailto:") >= 0) ||
(sL.ToLower().IndexOf("ftp://") >= 0) ||
(sL.ToLower().IndexOf("ms-its:") >= 0))
return sL;
return HtmlHelpSystem.UrlPrefix + ChmFilePath + "::/" + sL;
}
}
}
}

View File

@@ -0,0 +1,146 @@
using System;
using System.IO;
namespace HtmlHelp
{
/// <summary>
/// Enumeration for specifying the mode of the information type
/// </summary>
public enum InformationTypeMode
{
/// <summary>
/// Inclusive information type. The user will be allowed to select from one or more information types.
/// </summary>
Inclusive = 0,
/// <summary>
/// Exclusive information type. The user will be allowed to choose only one information type within each category
/// </summary>
Exclusive = 1,
/// <summary>
/// Hidden information type. The user cannot see this information types (only for API calls).
/// </summary>
Hidden = 2
}
/// <summary>
/// The class <c>InformationType</c> implements a methods/properties for an information type.
/// </summary>
/// <remarks>Note: Information types and categories allow users to filter help contents.
/// They are only supported if using sitemap TOC and/or sitemap Index.</remarks>
public class InformationType
{
private string _name = "";
private string _description = "";
private InformationTypeMode _typeMode = InformationTypeMode.Inclusive;
private bool _isInCategory = false;
private int _referenceCount = 1;
/// <summary>
/// Standard constructor
/// </summary>
/// <remarks>the mode is set to InformationTypeMode.Inclusive by default</remarks>
public InformationType() : this("","")
{
}
/// <summary>
/// Standard constructor
/// </summary>
/// <param name="name">name of the information type</param>
/// <param name="description">description</param>
/// <remarks>the mode is set to InformationTypeMode.Inclusive by default</remarks>
public InformationType(string name, string description) : this(name, description, InformationTypeMode.Inclusive)
{
}
/// <summary>
/// Standard constructor
/// </summary>
/// <param name="name">name of the information type</param>
/// <param name="description">description</param>
/// <param name="mode">mode of the information type</param>
public InformationType(string name, string description, InformationTypeMode mode)
{
_name = name;
_description = description;
_typeMode = mode;
}
#region Data dumping
/// <summary>
/// Dump the class data to a binary writer
/// </summary>
/// <param name="writer">writer to write the data</param>
internal void Dump(ref BinaryWriter writer)
{
writer.Write( (int)_typeMode );
writer.Write( _name );
writer.Write( _description );
}
/// <summary>
/// Reads the object data from a dump store
/// </summary>
/// <param name="reader">reader to read the data</param>
internal void ReadDump(ref BinaryReader reader)
{
_typeMode = (InformationTypeMode)reader.ReadInt32();
_name = reader.ReadString();
_description = reader.ReadString();
}
#endregion
/// <summary>
/// Sets the flag if this information type is nested in at least one category
/// </summary>
/// <param name="newValue">true or false</param>
internal void SetCategoryFlag(bool newValue)
{
_isInCategory = newValue;
}
/// <summary>
/// Gets/Sets the reference count of this information type instance
/// </summary>
internal int ReferenceCount
{
get { return _referenceCount; }
set { _referenceCount = value; }
}
/// <summary>
/// Gets true if this information type is nested in at least one category
/// </summary>
public bool IsInCategory
{
get { return _isInCategory; }
}
/// <summary>
/// Gets/Sets the name of the information type
/// </summary>
public string Name
{
get { return _name; }
set { _name = value; }
}
/// <summary>
/// Gets/Sets the description of the information type
/// </summary>
public string Description
{
get { return _description; }
set { _name = value; }
}
/// <summary>
/// Gets/Sets the mode of the information type
/// </summary>
public InformationTypeMode Mode
{
get { return _typeMode; }
set { _typeMode = value; }
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,494 @@
using System;
using System.IO;
using System.Collections;
using System.Windows.Forms;
using HtmlHelp.ChmDecoding;
namespace HtmlHelp
{
/// <summary>
/// The class <c>TOCItem</c> implements a toc-entry item
/// </summary>
public sealed class TOCItem
{
/// <summary>
/// Constant for standard folder (closed) image index (HH2 image list)
/// </summary>
public const int STD_FOLDER_HH2 = 4;
/// <summary>
/// Constant for standard folder (opened) image index (HH2 image list)
/// </summary>
public const int STD_FOLDER_OPEN_HH2 = 6;
/// <summary>
/// Constant for standard file image index (HH2 image list)
/// </summary>
public const int STD_FILE_HH2 = 16;
/// <summary>
/// Constant for standard folder (closed) image index (HH1 image list)
/// </summary>
public const int STD_FOLDER_HH1 = 0;
/// <summary>
/// Constant for standard folder (opened) image index (HH1 image list)
/// </summary>
public const int STD_FOLDER_OPEN_HH1 = 1;
/// <summary>
/// Constant for standard file image index (HH1 image list)
/// </summary>
public const int STD_FILE_HH1 = 10;
/// <summary>
/// Internal flag specifying the data extraction mode used for this item
/// </summary>
private DataMode _tocMode = DataMode.TextBased;
/// <summary>
/// Internal member storing the offset (only used in binary tocs)
/// </summary>
private int _offset = 0;
/// <summary>
/// Internal member storing the offset of the next item(only used in binary tocs)
/// </summary>
private int _offsetNext = 0;
/// <summary>
/// Internal member storing a merge link.
/// If the target file is in the merged files list of the CHM,
/// this item will be replaced with the target TOC or Topic, if not it will
/// be removed from TOC.
/// </summary>
private string _mergeLink = "";
/// <summary>
/// Internal member storing the toc name
/// </summary>
private string _name = "";
/// <summary>
/// Internal member storing the toc loca (content file)
/// </summary>
private string _local = "";
/// <summary>
/// Internal member storing all associated information type strings
/// </summary>
private ArrayList _infoTypeStrings = new ArrayList();
/// <summary>
/// Internal member storing the associated chm file
/// </summary>
private string _chmFile = "";
/// <summary>
/// Internal member storing the image index
/// </summary>
private int _imageIndex = -1;
/// <summary>
/// Internal member storing the offset of the associated topic entry (for binary tocs)
/// </summary>
private int _topicOffset = -1;
/// <summary>
/// Internal member storing the toc children
/// </summary>
private ArrayList _children = new ArrayList();
/// <summary>
/// Internal member storing the parameter collection
/// </summary>
private Hashtable _otherParams = new Hashtable();
/// <summary>
/// Internal member storing the associated chmfile object
/// </summary>
private CHMFile _associatedFile = null;
/// <summary>
/// Parent item
/// </summary>
private TOCItem _parent=null;
/// <summary>
/// Holds a pointer to the next item in the TOC
/// </summary>
public TOCItem Next=null;
/// <summary>
/// Holds a pointer to the previous item in the TOC
/// </summary>
public TOCItem Prev=null;
/// <summary>
/// Holds a pointer to the TreeNode where this TOC Item is used
/// </summary>
public System.Windows.Forms.TreeNode treeNode=null;
/// <summary>
/// Constructor of the class used during text-based data extraction
/// </summary>
/// <param name="name">name of the item</param>
/// <param name="local">local content file</param>
/// <param name="ImageIndex">image index</param>
/// <param name="chmFile">associated chm file</param>
public TOCItem(string name, string local, int ImageIndex, string chmFile)
{
_tocMode = DataMode.TextBased;
_name = name;
_local = local;
_imageIndex = ImageIndex;
_chmFile = chmFile;
}
/// <summary>
/// Constructor of the class used during binary data extraction
/// </summary>
/// <param name="topicOffset">offset of the associated topic entry</param>
/// <param name="ImageIndex">image index to use</param>
/// <param name="associatedFile">associated chm file</param>
public TOCItem(int topicOffset, int ImageIndex, CHMFile associatedFile)
{
_tocMode = DataMode.Binary;
_associatedFile = associatedFile;
_chmFile = associatedFile.ChmFilePath;
_topicOffset = topicOffset;
_imageIndex = ImageIndex;
}
/// <summary>
/// Standard constructor
/// </summary>
public TOCItem()
{
}
#region Data dumping
/// <summary>
/// Dump the class data to a binary writer
/// </summary>
/// <param name="writer">writer to write the data</param>
/// <param name="writeFilename">true if the chmfile name should be written</param>
internal void Dump(ref BinaryWriter writer, bool writeFilename)
{
writer.Write((int)_tocMode);
writer.Write(_topicOffset);
writer.Write(_name);
if((_tocMode == DataMode.TextBased)||(_topicOffset<0))
{
writer.Write(_local);
}
writer.Write(_imageIndex);
writer.Write(_mergeLink);
if(writeFilename)
writer.Write(_chmFile);
writer.Write(_infoTypeStrings.Count);
for(int i=0; i<_infoTypeStrings.Count; i++)
writer.Write( (_infoTypeStrings[i]).ToString() );
writer.Write(_children.Count);
for(int i=0; i<_children.Count; i++)
{
TOCItem child = ((TOCItem)(_children[i]));
child.Dump(ref writer, writeFilename);
}
}
/// <summary>
/// Dump the class data to a binary writer
/// </summary>
/// <param name="writer">writer to write the data</param>
internal void Dump(ref BinaryWriter writer)
{
Dump(ref writer, false);
}
/// <summary>
/// Reads the object data from a dump store
/// </summary>
/// <param name="reader">reader to read the data</param>
/// <param name="readFilename">true if the chmfile name should be read</param>
internal void ReadDump(ref BinaryReader reader, bool readFilename)
{
int i=0;
_tocMode = (DataMode)reader.ReadInt32();
_topicOffset = reader.ReadInt32();
_name = reader.ReadString();
if((_tocMode == DataMode.TextBased)||(_topicOffset<0))
{
_local = reader.ReadString();
}
_imageIndex = reader.ReadInt32();
_mergeLink = reader.ReadString();
if(readFilename)
_chmFile = reader.ReadString();
int nCnt = reader.ReadInt32();
for(i=0; i<nCnt; i++)
{
string sIT = reader.ReadString();
_infoTypeStrings.Add(sIT);
}
nCnt = reader.ReadInt32();
if(_associatedFile != null)
_chmFile = _associatedFile.ChmFilePath;
for(i=0; i<nCnt; i++)
{
TOCItem child = new TOCItem();
child.AssociatedFile = _associatedFile;
child.ReadDump(ref reader, readFilename);
if(_associatedFile != null)
child.ChmFile = _associatedFile.ChmFilePath;
else if(!readFilename)
child.ChmFile = _chmFile;
child.Parent = this;
_children.Add(child);
if(child.MergeLink.Length > 0)
_associatedFile.MergLinks.Add(child);
}
}
/// <summary>
/// Reads the object data from a dump store
/// </summary>
/// <param name="reader">reader to read the data</param>
internal void ReadDump(ref BinaryReader reader)
{
ReadDump(ref reader, false);
}
#endregion
/// <summary>
/// Gets/Sets the data extraction mode with which this item was created.
/// </summary>
internal DataMode TocMode
{
get { return _tocMode; }
set { _tocMode = value; }
}
/// <summary>
/// Gets/Sets the offset of the associated topic entry
/// </summary>
internal int TopicOffset
{
get { return _topicOffset; }
set { _topicOffset = value; }
}
/// <summary>
/// Gets/Sets the associated CHMFile instance
/// </summary>
internal CHMFile AssociatedFile
{
get { return _associatedFile; }
set
{
_associatedFile = value;
}
}
/// <summary>
/// Gets/Sets the offset of the item.
/// </summary>
/// <remarks>Only used in binary tocs</remarks>
internal int Offset
{
get { return _offset; }
set { _offset = value; }
}
/// <summary>
/// Gets/Sets the offset of the next item.
/// </summary>
/// <remarks>Only used in binary tocs</remarks>
internal int OffsetNext
{
get { return _offsetNext; }
set { _offsetNext = value; }
}
/// <summary>
/// Gets the ArrayList which holds all information types/categories this item is associated
/// </summary>
internal ArrayList InfoTypeStrings
{
get { return _infoTypeStrings; }
}
/// <summary>
/// Gets/Sets the parent of this item
/// </summary>
public TOCItem Parent
{
get { return _parent; }
set { _parent = value; }
}
/// <summary>
/// Gets/Sets the mergelink for this item.
/// <b>You should not set the mergedlink by your own !</b>
/// This is only for loading merged CHMs.
/// </summary>
public string MergeLink
{
get { return _mergeLink; }
set { _mergeLink = value; }
}
/// <summary>
/// Gets/Sets the name of the item
/// </summary>
public string Name
{
get
{
if(_mergeLink.Length > 0)
return "";
if(_name.Length <= 0)
{
if((_tocMode == DataMode.Binary )&&(_associatedFile!=null))
{
if( _topicOffset >= 0)
{
TopicEntry te = (TopicEntry) (_associatedFile.TopicsFile[_topicOffset]);
if(te != null)
{
return te.Title;
}
}
}
}
return _name;
}
set
{
_name = value;
}
}
/// <summary>
/// Gets/Sets the local of the item
/// </summary>
public string Local
{
get
{
if(_mergeLink.Length > 0)
return "";
if(_local.Length <= 0)
{
if((_tocMode == DataMode.Binary )&&(_associatedFile!=null))
{
if( _topicOffset >= 0)
{
TopicEntry te = (TopicEntry) (_associatedFile.TopicsFile[_topicOffset]);
if(te != null)
{
return te.Locale;
}
}
}
}
return _local;
}
set { _local = value; }
}
/// <summary>
/// Gets/Sets the chm file
/// </summary>
public string ChmFile
{
get
{
if(_associatedFile!=null)
return _associatedFile.ChmFilePath;
return _chmFile;
}
set { _chmFile = value; }
}
/// <summary>
/// Gets the url for the webbrowser for this file
/// </summary>
public string Url
{
get
{
string sL = Local;
if( (sL.ToLower().IndexOf("http://") >= 0) ||
(sL.ToLower().IndexOf("https://") >= 0) ||
(sL.ToLower().IndexOf("mailto:") >= 0) ||
(sL.ToLower().IndexOf("ftp://") >= 0) ||
(sL.ToLower().IndexOf("ms-its:") >= 0))
return sL;
return HtmlHelpSystem.UrlPrefix + ChmFile + "::/" + sL;
}
}
/// <summary>
/// Gets/Sets the image index of the item
/// </summary>
/// <remarks>Set this to -1 for a default icon</remarks>
public int ImageIndex
{
get
{
if( _imageIndex == -1)
{
int nFolderAdd = 0;
if((_associatedFile != null) && (_associatedFile.ImageTypeFolder))
{
// get the value which should be added, to display folders instead of books
if(HtmlHelpSystem.UseHH2TreePics)
nFolderAdd = 8;
else
nFolderAdd = 4;
}
if( _children.Count > 0)
return (HtmlHelpSystem.UseHH2TreePics ? (STD_FOLDER_HH2+nFolderAdd) : (STD_FOLDER_HH1+nFolderAdd));
return (HtmlHelpSystem.UseHH2TreePics ? STD_FILE_HH2 : STD_FILE_HH1);
}
return _imageIndex;
}
set { _imageIndex = value; }
}
/// <summary>
/// Gets/Sets the children of this item.
/// </summary>
/// <remarks>Each entry in the ArrayList is of type TOCItem</remarks>
public ArrayList Children
{
get { return _children; }
set { _children = value; }
}
/// <summary>
/// Gets the internal hashtable storing all params
/// </summary>
public Hashtable Params
{
get { return _otherParams; }
}
}
}

View File

@@ -0,0 +1,198 @@
using System;
using System.Diagnostics;
using System.Collections;
using HtmlHelp.ChmDecoding;
namespace HtmlHelp
{
/// <summary>
/// The class <c>TableOfContents</c> holds the TOC of the htmlhelp system class.
/// </summary>
public class TableOfContents
{
private ArrayList _toc = new ArrayList();
/// <summary>
/// Standard constructor
/// </summary>
public TableOfContents()
{
}
/// <summary>
/// Constructor of the class
/// </summary>
/// <param name="toc"></param>
public TableOfContents(ArrayList toc)
{
_toc = toc;
}
/// <summary>
/// Gets the internal stored table of contents
/// </summary>
public ArrayList TOC
{
get { return _toc; }
}
/// <summary>
/// Clears the current toc
/// </summary>
public void Clear()
{
if(_toc!=null)
_toc.Clear();
}
/// <summary>
/// Gets the number of topics in the toc
/// </summary>
/// <returns>Returns the number of topics in the toc</returns>
public int Count()
{
if(_toc!=null)
return _toc.Count;
else
return 0;
}
/// <summary>
/// Merges the <c>arrToC</c> list to the one in this instance
/// </summary>
/// <param name="arrToC">the toc list which should be merged with the current one</param>
internal void MergeToC( ArrayList arrToC )
{
if(_toc==null)
_toc = new ArrayList();
MergeToC(_toc, arrToC, null);
}
/// <summary>
/// Merges the <c>arrToC</c> list to the one in this instance (called if merged files
/// were found in a CHM)
/// </summary>
/// <param name="arrToC">the toc list which should be merged with the current one</param>
/// <param name="openFiles">An arraylist of CHMFile instances.</param>
internal void MergeToC( ArrayList arrToC, ArrayList openFiles )
{
if(_toc==null)
_toc = new ArrayList();
MergeToC(_toc, arrToC, openFiles);
}
/// <summary>
/// Internal method for recursive toc merging
/// </summary>
/// <param name="globalLevel">level of global toc</param>
/// <param name="localLevel">level of local toc</param>
/// <param name="openFiles">An arraylist of CHMFile instances.</param>
private void MergeToC( ArrayList globalLevel, ArrayList localLevel, ArrayList openFiles )
{
foreach( TOCItem curItem in localLevel)
{
// if it is a part of the merged-links, we have to do nothing,
// because the method HtmlHelpSystem.RecalculateMergeLinks() has already
// placed this item at its correct position.
if(!IsMergedItem(curItem.Name, curItem.Local, openFiles))
{
TOCItem globalItem = ContainsToC(globalLevel, curItem.Name);
if(globalItem == null)
{
// the global toc doesn't have a topic with this name
// so we need to add the complete toc node to the global toc
globalLevel.Add( curItem );
}
else
{
// the global toc contains the current topic
// advance to the next level
if( (globalItem.Local.Length <= 0) && (curItem.Local.Length > 0) )
{
// set the associated url
globalItem.Local = curItem.Local;
globalItem.ChmFile = curItem.ChmFile;
}
MergeToC(globalItem.Children, curItem.Children);
}
}
}
}
/// <summary>
/// Checks if the item is part of the merged-links
/// </summary>
/// <param name="name">name of the topic</param>
/// <param name="local">local of the topic</param>
/// <param name="openFiles">An arraylist of CHMFile instances.</param>
/// <returns>Returns true if this item is part of the merged-links</returns>
private bool IsMergedItem(string name, string local, ArrayList openFiles)
{
if(openFiles==null)
return false;
foreach(CHMFile curFile in openFiles)
{
foreach(TOCItem curItem in curFile.MergLinks)
if( (curItem.Name == name) && (curItem.Local == local) )
return true;
}
return false;
}
/// <summary>
/// Checks if a topicname exists in a SINGLE toc level
/// </summary>
/// <param name="arrToC">toc list</param>
/// <param name="Topic">topic to search</param>
/// <returns>Returns the topic item if found, otherwise null</returns>
private TOCItem ContainsToC(ArrayList arrToC, string Topic)
{
foreach(TOCItem curItem in arrToC)
{
if(curItem.Name == Topic)
return curItem;
}
return null;
}
/// <summary>
/// Searches the table of contents for a special topic
/// </summary>
/// <param name="topic">topic to search</param>
/// <returns>Returns an instance of TOCItem if found, otherwise null</returns>
public TOCItem SearchTopic(string topic)
{
return SearchTopic(topic, _toc);
}
/// <summary>
/// Internal recursive tree search
/// </summary>
/// <param name="topic">topic to search</param>
/// <param name="searchIn">tree level list to look in</param>
/// <returns>Returns an instance of TOCItem if found, otherwise null</returns>
private TOCItem SearchTopic(string topic, ArrayList searchIn)
{
foreach(TOCItem curItem in searchIn)
{
if(curItem.Name.ToLower() == topic.ToLower() )
return curItem;
if(curItem.Children.Count>0)
{
TOCItem nf = SearchTopic(topic, curItem.Children);
if(nf != null)
return nf;
}
}
return null;
}
}
}

View File

@@ -0,0 +1,32 @@
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following
// attributes.
//
// change them to the information which is associated with the assembly
// you compile.
[assembly: AssemblyTitle("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has following format :
//
// Major.Minor.Build.Revision
//
// You can specify all values by your own or you can build default build and revision
// numbers with the '*' character (the default):
[assembly: AssemblyVersion("1.0.*")]
// The following attributes specify the key for the sign of your assembly. See the
// .NET Framework documentation for more information about signing.
// This is not required, if you don't want signing let these attributes like they're.
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("")]

View File

@@ -0,0 +1,200 @@
// Adler32.cs - Computes Adler32 data checksum of a data stream
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
//
// 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
// of the License, 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
namespace ICSharpCode.SharpZipLib.Checksums
{
/// <summary>
/// Computes Adler32 checksum for a stream of data. An Adler32
/// checksum is not as reliable as a CRC32 checksum, but a lot faster to
/// compute.
///
/// The specification for Adler32 may be found in RFC 1950.
/// ZLIB Compressed Data Format Specification version 3.3)
///
///
/// From that document:
///
/// "ADLER32 (Adler-32 checksum)
/// This contains a checksum value of the uncompressed data
/// (excluding any dictionary data) computed according to Adler-32
/// algorithm. This algorithm is a 32-bit extension and improvement
/// of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073
/// standard.
///
/// Adler-32 is composed of two sums accumulated per byte: s1 is
/// the sum of all bytes, s2 is the sum of all s1 values. Both sums
/// are done modulo 65521. s1 is initialized to 1, s2 to zero. The
/// Adler-32 checksum is stored as s2*65536 + s1 in most-
/// significant-byte first (network) order."
///
/// "8.2. The Adler-32 algorithm
///
/// The Adler-32 algorithm is much faster than the CRC32 algorithm yet
/// still provides an extremely low probability of undetected errors.
///
/// The modulo on unsigned long accumulators can be delayed for 5552
/// bytes, so the modulo operation time is negligible. If the bytes
/// are a, b, c, the second sum is 3a + 2b + c + 3, and so is position
/// and order sensitive, unlike the first sum, which is just a
/// checksum. That 65521 is prime is important to avoid a possible
/// large class of two-byte errors that leave the check unchanged.
/// (The Fletcher checksum uses 255, which is not prime and which also
/// makes the Fletcher check insensitive to single byte changes 0 -
/// 255.)
///
/// The sum s1 is initialized to 1 instead of zero to make the length
/// of the sequence part of s2, so that the length does not have to be
/// checked separately. (Any sequence of zeroes has a Fletcher
/// checksum of zero.)"
/// </summary>
/// <see cref="ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream"/>
/// <see cref="ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream"/>
public sealed class Adler32 : IChecksum
{
/// <summary>
/// largest prime smaller than 65536
/// </summary>
readonly static uint BASE = 65521;
uint checksum;
/// <summary>
/// Returns the Adler32 data checksum computed so far.
/// </summary>
public long Value {
get {
return checksum;
}
}
/// <summary>
/// Creates a new instance of the <code>Adler32</code> class.
/// The checksum starts off with a value of 1.
/// </summary>
public Adler32()
{
Reset();
}
/// <summary>
/// Resets the Adler32 checksum to the initial value.
/// </summary>
public void Reset()
{
checksum = 1; //Initialize to 1
}
/// <summary>
/// Updates the checksum with the byte b.
/// </summary>
/// <param name="bval">
/// the data value to add. The high byte of the int is ignored.
/// </param>
public void Update(int bval)
{
//We could make a length 1 byte array and call update again, but I
//would rather not have that overhead
uint s1 = checksum & 0xFFFF;
uint s2 = checksum >> 16;
s1 = (s1 + ((uint)bval & 0xFF)) % BASE;
s2 = (s1 + s2) % BASE;
checksum = (s2 << 16) + s1;
}
/// <summary>
/// Updates the checksum with the bytes taken from the array.
/// </summary>
/// <param name="buffer">
/// buffer an array of bytes
/// </param>
public void Update(byte[] buffer)
{
Update(buffer, 0, buffer.Length);
}
/// <summary>
/// Updates the checksum with the bytes taken from the array.
/// </summary>
/// <param name="buf">
/// an array of bytes
/// </param>
/// <param name="off">
/// the start of the data used for this update
/// </param>
/// <param name="len">
/// the number of bytes to use for this update
/// </param>
public void Update(byte[] buf, int off, int len)
{
if (buf == null) {
throw new ArgumentNullException("buf");
}
if (off < 0 || len < 0 || off + len > buf.Length) {
throw new ArgumentOutOfRangeException();
}
//(By Per Bothner)
uint s1 = checksum & 0xFFFF;
uint s2 = checksum >> 16;
while (len > 0) {
// We can defer the modulo operation:
// s1 maximally grows from 65521 to 65521 + 255 * 3800
// s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31
int n = 3800;
if (n > len) {
n = len;
}
len -= n;
while (--n >= 0) {
s1 = s1 + (uint)(buf[off++] & 0xFF);
s2 = s2 + s1;
}
s1 %= BASE;
s2 %= BASE;
}
checksum = (s2 << 16) | s1;
}
}
}

View File

@@ -0,0 +1,211 @@
// CRC32.cs - Computes CRC32 data checksum of a data stream
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
//
// 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
// of the License, 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
namespace ICSharpCode.SharpZipLib.Checksums
{
/// <summary>
/// Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
/// x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
///
/// Polynomials over GF(2) are represented in binary, one bit per coefficient,
/// with the lowest powers in the most significant bit. Then adding polynomials
/// is just exclusive-or, and multiplying a polynomial by x is a right shift by
/// one. If we call the above polynomial p, and represent a byte as the
/// polynomial q, also with the lowest power in the most significant bit (so the
/// byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
/// where a mod b means the remainder after dividing a by b.
///
/// This calculation is done using the shift-register method of multiplying and
/// taking the remainder. The register is initialized to zero, and for each
/// incoming bit, x^32 is added mod p to the register if the bit is a one (where
/// x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
/// x (which is shifting right by one and adding x^32 mod p if the bit shifted
/// out is a one). We start with the highest power (least significant bit) of
/// q and repeat for all eight bits of q.
///
/// The table is simply the CRC of all possible eight bit values. This is all
/// the information needed to generate CRC's on data a byte at a time for all
/// combinations of CRC register values and incoming bytes.
/// </summary>
public sealed class Crc32 : IChecksum
{
readonly static uint CrcSeed = 0xFFFFFFFF;
readonly static uint[] CrcTable = new uint[] {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419,
0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07,
0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856,
0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A,
0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,
0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190,
0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E,
0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3,
0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010,
0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17,
0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6,
0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344,
0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A,
0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1,
0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE,
0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C,
0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B,
0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1,
0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66,
0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8,
0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
0x2D02EF8D
};
internal static uint ComputeCrc32(uint oldCrc, byte bval)
{
return (uint)(Crc32.CrcTable[(oldCrc ^ bval) & 0xFF] ^ (oldCrc >> 8));
}
/// <summary>
/// The crc data checksum so far.
/// </summary>
uint crc = 0;
/// <summary>
/// Returns the CRC32 data checksum computed so far.
/// </summary>
public long Value {
get {
return (long)crc;
}
set {
crc = (uint)value;
}
}
/// <summary>
/// Resets the CRC32 data checksum as if no update was ever called.
/// </summary>
public void Reset()
{
crc = 0;
}
/// <summary>
/// Updates the checksum with the int bval.
/// </summary>
/// <param name = "bval">
/// the byte is taken as the lower 8 bits of bval
/// </param>
public void Update(int bval)
{
crc ^= CrcSeed;
crc = CrcTable[(crc ^ bval) & 0xFF] ^ (crc >> 8);
crc ^= CrcSeed;
}
/// <summary>
/// Updates the checksum with the bytes taken from the array.
/// </summary>
/// <param name="buffer">
/// buffer an array of bytes
/// </param>
public void Update(byte[] buffer)
{
Update(buffer, 0, buffer.Length);
}
/// <summary>
/// Adds the byte array to the data checksum.
/// </summary>
/// <param name = "buf">
/// the buffer which contains the data
/// </param>
/// <param name = "off">
/// the offset in the buffer where the data starts
/// </param>
/// <param name = "len">
/// the length of the data
/// </param>
public void Update(byte[] buf, int off, int len)
{
if (buf == null) {
throw new ArgumentNullException("buf");
}
if (off < 0 || len < 0 || off + len > buf.Length) {
throw new ArgumentOutOfRangeException();
}
crc ^= CrcSeed;
while (--len >= 0) {
crc = CrcTable[(crc ^ buf[off++]) & 0xFF] ^ (crc >> 8);
}
crc ^= CrcSeed;
}
}
}

View File

@@ -0,0 +1,93 @@
// IChecksum.cs - Interface to compute a data checksum
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
//
// 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
// of the License, 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
namespace ICSharpCode.SharpZipLib.Checksums
{
/// <summary>
/// Interface to compute a data checksum used by checked input/output streams.
/// A data checksum can be updated by one byte or with a byte array. After each
/// update the value of the current checksum can be returned by calling
/// <code>getValue</code>. The complete checksum object can also be reset
/// so it can be used again with new data.
/// </summary>
public interface IChecksum
{
/// <summary>
/// Returns the data checksum computed so far.
/// </summary>
long Value
{
get;
}
/// <summary>
/// Resets the data checksum as if no update was ever called.
/// </summary>
void Reset();
/// <summary>
/// Adds one byte to the data checksum.
/// </summary>
/// <param name = "bval">
/// the data value to add. The high byte of the int is ignored.
/// </param>
void Update(int bval);
/// <summary>
/// Updates the data checksum with the bytes taken from the array.
/// </summary>
/// <param name="buffer">
/// buffer an array of bytes
/// </param>
void Update(byte[] buffer);
/// <summary>
/// Adds the byte array to the data checksum.
/// </summary>
/// <param name = "buf">
/// the buffer which contains the data
/// </param>
/// <param name = "off">
/// the offset in the buffer where the data starts
/// </param>
/// <param name = "len">
/// the length of the data
/// </param>
void Update(byte[] buf, int off, int len);
}
}

View File

@@ -0,0 +1,159 @@
// StrangeCRC.cs - computes a crc used in the bziplib ... I don't think that
// this is the 'standard' crc, please correct me, if I'm wrong
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
//
// 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
// of the License, 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
namespace ICSharpCode.SharpZipLib.Checksums
{
public class StrangeCRC : IChecksum
{
readonly static uint[] crc32Table = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};
int globalCrc;
public StrangeCRC()
{
Reset();
}
public void Reset()
{
globalCrc = -1;
}
public long Value {
get {
return ~globalCrc;
}
}
public void Update(int inCh)
{
int temp = (globalCrc >> 24) ^ inCh;
if (temp < 0) {
temp = 256 + temp;
}
globalCrc = (int)((globalCrc << 8) ^ crc32Table[temp]);
}
public void Update(byte[] buf)
{
Update(buf, 0, buf.Length);
}
public void Update(byte[] buf, int off, int len)
{
if (buf == null) {
throw new ArgumentNullException("buf");
}
if (off < 0 || len < 0 || off + len > buf.Length) {
throw new ArgumentOutOfRangeException();
}
for (int i = 0; i < len; ++i) {
Update(buf[off++]);
}
}
}
}

View File

@@ -0,0 +1,16 @@
<Combine fileversion="1.0" name="Compression" description="">
<StartMode startupentry="Compression" single="True">
<Execute entry="Compression" type="None" />
</StartMode>
<Entries>
<Entry filename=".\.\Compression.prjx" />
</Entries>
<Configurations active="Debug">
<Configuration name="Release">
<Entry name="Compression" configurationname="Debug" build="False" />
</Configuration>
<Configuration name="Debug">
<Entry name="Compression" configurationname="Debug" build="False" />
</Configuration>
</Configurations>
</Combine>

View File

@@ -0,0 +1,45 @@
<Project name="Compression" standardNamespace="Compression" description="" newfilesearch="None" enableviewstate="True" version="1.1" projecttype="C#">
<Contents>
<File name=".\AssemblyInfo.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\ZipException.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\Deflater.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\DeflaterConstants.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\DeflaterEngine.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\DeflaterHuffman.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\DeflaterPending.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\Inflater.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\InflaterDynHeader.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\InflaterHuffmanTree.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\PendingBuffer.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\Checksums" subtype="Directory" buildaction="Compile" dependson="" data="" />
<File name=".\Checksums\StrangeCRC.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\Checksums\Adler32.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\Checksums\CRC32.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\Checksums\IChecksum.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\Streams" subtype="Directory" buildaction="Compile" dependson="" data="" />
<File name=".\Streams\StreamManipulator.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\Streams\DeflaterOutputStream.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\Streams\InflaterInputStream.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\Streams\OutputWindow.cs" subtype="Code" buildaction="Compile" dependson="" data="" />
<File name=".\Default.build" subtype="Code" buildaction="Nothing" dependson="" data="" />
</Contents>
<References />
<DeploymentInformation target="" script="" strategy="File" />
<Configuration runwithwarnings="True" name="Debug">
<CodeGeneration runtime="MsNet" compiler="Csc" compilerversion="" warninglevel="4" nowarn="" includedebuginformation="True" optimize="False" unsafecodeallowed="False" generateoverflowchecks="True" mainclass="" target="Library" definesymbols="" generatexmldocumentation="False" win32Icon="" noconfig="False" nostdlib="False" />
<Execution commandlineparameters="" consolepause="False" />
<Output directory="..\bin\Debug" assembly="Compression" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" />
</Configuration>
<Configurations active="Debug">
<Configuration runwithwarnings="True" name="Debug">
<CodeGeneration runtime="MsNet" compiler="Csc" compilerversion="" warninglevel="4" nowarn="" includedebuginformation="True" optimize="False" unsafecodeallowed="False" generateoverflowchecks="True" mainclass="" target="Library" definesymbols="" generatexmldocumentation="False" win32Icon="" noconfig="False" nostdlib="False" />
<Execution commandlineparameters="" consolepause="False" />
<Output directory="..\bin\Debug" assembly="Compression" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" />
</Configuration>
<Configuration runwithwarnings="True" name="Release">
<CodeGeneration runtime="MsNet" compiler="Csc" compilerversion="" warninglevel="4" nowarn="" includedebuginformation="False" optimize="True" unsafecodeallowed="False" generateoverflowchecks="False" mainclass="" target="Library" definesymbols="" generatexmldocumentation="False" win32Icon="" noconfig="False" nostdlib="False" />
<Execution commandlineparameters="" consolepause="False" />
<Output directory="..\bin\Release" assembly="Compression" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" />
</Configuration>
</Configurations>
</Project>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0"?>
<project name="Compression" default="build">
<property name="output.dir" value="..\bin" />
<target name="build" description="Build component">
<mkdir dir="${output.dir}" />
<csc target="library"
output="${output.dir}\Compression.dll"
optimize="true"
debug="true"
doc="${output.dir}\Compression.xml"
warninglevel="0">
<sources>
<include name="**/*.cs" />
</sources>
</csc>
</target>
</project>

View File

@@ -0,0 +1,542 @@
// Deflater.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// 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
// of the License, 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
namespace ICSharpCode.SharpZipLib.Zip.Compression
{
/// <summary>
/// This is the Deflater class. The deflater class compresses input
/// with the deflate algorithm described in RFC 1951. It has several
/// compression levels and three different strategies described below.
///
/// This class is <i>not</i> thread safe. This is inherent in the API, due
/// to the split of deflate and setInput.
///
/// author of the original java version : Jochen Hoenicke
/// </summary>
public class Deflater
{
/// <summary>
/// The best and slowest compression level. This tries to find very
/// long and distant string repetitions.
/// </summary>
public static int BEST_COMPRESSION = 9;
/// <summary>
/// The worst but fastest compression level.
/// </summary>
public static int BEST_SPEED = 1;
/// <summary>
/// The default compression level.
/// </summary>
public static int DEFAULT_COMPRESSION = -1;
/// <summary>
/// This level won't compress at all but output uncompressed blocks.
/// </summary>
public static int NO_COMPRESSION = 0;
/// <summary>
/// The compression method. This is the only method supported so far.
/// There is no need to use this constant at all.
/// </summary>
public static int DEFLATED = 8;
/*
* The Deflater can do the following state transitions:
*
* (1) -> INIT_STATE ----> INIT_FINISHING_STATE ---.
* / | (2) (5) |
* / v (5) |
* (3)| SETDICT_STATE ---> SETDICT_FINISHING_STATE |(3)
* \ | (3) | ,-------'
* | | | (3) /
* v v (5) v v
* (1) -> BUSY_STATE ----> FINISHING_STATE
* | (6)
* v
* FINISHED_STATE
* \_____________________________________/
* | (7)
* v
* CLOSED_STATE
*
* (1) If we should produce a header we start in INIT_STATE, otherwise
* we start in BUSY_STATE.
* (2) A dictionary may be set only when we are in INIT_STATE, then
* we change the state as indicated.
* (3) Whether a dictionary is set or not, on the first call of deflate
* we change to BUSY_STATE.
* (4) -- intentionally left blank -- :)
* (5) FINISHING_STATE is entered, when flush() is called to indicate that
* there is no more INPUT. There are also states indicating, that
* the header wasn't written yet.
* (6) FINISHED_STATE is entered, when everything has been flushed to the
* internal pending output buffer.
* (7) At any time (7)
*
*/
private static int IS_SETDICT = 0x01;
private static int IS_FLUSHING = 0x04;
private static int IS_FINISHING = 0x08;
private static int INIT_STATE = 0x00;
private static int SETDICT_STATE = 0x01;
// private static int INIT_FINISHING_STATE = 0x08;
// private static int SETDICT_FINISHING_STATE = 0x09;
private static int BUSY_STATE = 0x10;
private static int FLUSHING_STATE = 0x14;
private static int FINISHING_STATE = 0x1c;
private static int FINISHED_STATE = 0x1e;
private static int CLOSED_STATE = 0x7f;
/// <summary>
/// Compression level.
/// </summary>
private int level;
/// <summary>
/// should we include a header.
/// </summary>
private bool noHeader;
// /// <summary>
// /// Compression strategy.
// /// </summary>
// private int strategy;
/// <summary>
/// The current state.
/// </summary>
private int state;
/// <summary>
/// The total bytes of output written.
/// </summary>
private int totalOut;
/// <summary>
/// The pending output.
/// </summary>
private DeflaterPending pending;
/// <summary>
/// The deflater engine.
/// </summary>
private DeflaterEngine engine;
/// <summary>
/// Creates a new deflater with default compression level.
/// </summary>
public Deflater() : this(DEFAULT_COMPRESSION, false)
{
}
/// <summary>
/// Creates a new deflater with given compression level.
/// </summary>
/// <param name="lvl">
/// the compression level, a value between NO_COMPRESSION
/// and BEST_COMPRESSION, or DEFAULT_COMPRESSION.
/// </param>
/// <exception cref="System.ArgumentOutOfRangeException">if lvl is out of range.</exception>
public Deflater(int lvl) : this(lvl, false)
{
}
/// <summary>
/// Creates a new deflater with given compression level.
/// </summary>
/// <param name="lvl">
/// the compression level, a value between NO_COMPRESSION
/// and BEST_COMPRESSION.
/// </param>
/// <param name="nowrap">
/// true, if we should suppress the deflate header at the
/// beginning and the adler checksum at the end of the output. This is
/// useful for the GZIP format.
/// </param>
/// <exception cref="System.ArgumentOutOfRangeException">if lvl is out of range.</exception>
public Deflater(int lvl, bool nowrap)
{
if (lvl == DEFAULT_COMPRESSION) {
lvl = 6;
} else if (lvl < NO_COMPRESSION || lvl > BEST_COMPRESSION) {
throw new ArgumentOutOfRangeException("lvl");
}
pending = new DeflaterPending();
engine = new DeflaterEngine(pending);
this.noHeader = nowrap;
SetStrategy(DeflateStrategy.Default);
SetLevel(lvl);
Reset();
}
/// <summary>
/// Resets the deflater. The deflater acts afterwards as if it was
/// just created with the same compression level and strategy as it
/// had before.
/// </summary>
public void Reset()
{
state = (noHeader ? BUSY_STATE : INIT_STATE);
totalOut = 0;
pending.Reset();
engine.Reset();
}
/// <summary>
/// Gets the current adler checksum of the data that was processed so far.
/// </summary>
public int Adler {
get {
return engine.Adler;
}
}
/// <summary>
/// Gets the number of input bytes processed so far.
/// </summary>
public int TotalIn {
get {
return engine.TotalIn;
}
}
/// <summary>
/// Gets the number of output bytes so far.
/// </summary>
public int TotalOut {
get {
return totalOut;
}
}
/// <summary>
/// Flushes the current input block. Further calls to deflate() will
/// produce enough output to inflate everything in the current input
/// block. This is not part of Sun's JDK so I have made it package
/// private. It is used by DeflaterOutputStream to implement
/// flush().
/// </summary>
public void Flush()
{
state |= IS_FLUSHING;
}
/// <summary>
/// Finishes the deflater with the current input block. It is an error
/// to give more input after this method was called. This method must
/// be called to force all bytes to be flushed.
/// </summary>
public void Finish()
{
state |= IS_FLUSHING | IS_FINISHING;
}
/// <summary>
/// Returns true if the stream was finished and no more output bytes
/// are available.
/// </summary>
public bool IsFinished {
get {
return state == FINISHED_STATE && pending.IsFlushed;
}
}
/// <summary>
/// Returns true, if the input buffer is empty.
/// You should then call setInput().
/// NOTE: This method can also return true when the stream
/// was finished.
/// </summary>
public bool IsNeedingInput {
get {
return engine.NeedsInput();
}
}
/// <summary>
/// Sets the data which should be compressed next. This should be only
/// called when needsInput indicates that more input is needed.
/// If you call setInput when needsInput() returns false, the
/// previous input that is still pending will be thrown away.
/// The given byte array should not be changed, before needsInput() returns
/// true again.
/// This call is equivalent to <code>setInput(input, 0, input.length)</code>.
/// </summary>
/// <param name="input">
/// the buffer containing the input data.
/// </param>
/// <exception cref="System.InvalidOperationException">
/// if the buffer was finished() or ended().
/// </exception>
public void SetInput(byte[] input)
{
SetInput(input, 0, input.Length);
}
/// <summary>
/// Sets the data which should be compressed next. This should be
/// only called when needsInput indicates that more input is needed.
/// The given byte array should not be changed, before needsInput() returns
/// true again.
/// </summary>
/// <param name="input">
/// the buffer containing the input data.
/// </param>
/// <param name="off">
/// the start of the data.
/// </param>
/// <param name="len">
/// the length of the data.
/// </param>
/// <exception cref="System.InvalidOperationException">
/// if the buffer was finished() or ended() or if previous input is still pending.
/// </exception>
public void SetInput(byte[] input, int off, int len)
{
if ((state & IS_FINISHING) != 0) {
throw new InvalidOperationException("finish()/end() already called");
}
engine.SetInput(input, off, len);
}
/// <summary>
/// Sets the compression level. There is no guarantee of the exact
/// position of the change, but if you call this when needsInput is
/// true the change of compression level will occur somewhere near
/// before the end of the so far given input.
/// </summary>
/// <param name="lvl">
/// the new compression level.
/// </param>
public void SetLevel(int lvl)
{
if (lvl == DEFAULT_COMPRESSION) {
lvl = 6;
} else if (lvl < NO_COMPRESSION || lvl > BEST_COMPRESSION) {
throw new ArgumentOutOfRangeException("lvl");
}
if (level != lvl) {
level = lvl;
engine.SetLevel(lvl);
}
}
/// <summary>
/// Sets the compression strategy. Strategy is one of
/// DEFAULT_STRATEGY, HUFFMAN_ONLY and FILTERED. For the exact
/// position where the strategy is changed, the same as for
/// setLevel() applies.
/// </summary>
/// <param name="stgy">
/// the new compression strategy.
/// </param>
public void SetStrategy(DeflateStrategy stgy)
{
engine.Strategy = stgy;
}
/// <summary>
/// Deflates the current input block to the given array. It returns
/// the number of bytes compressed, or 0 if either
/// needsInput() or finished() returns true or length is zero.
/// </summary>
/// <param name="output">
/// the buffer where to write the compressed data.
/// </param>
public int Deflate(byte[] output)
{
return Deflate(output, 0, output.Length);
}
/// <summary>
/// Deflates the current input block to the given array. It returns
/// the number of bytes compressed, or 0 if either
/// needsInput() or finished() returns true or length is zero.
/// </summary>
/// <param name="output">
/// the buffer where to write the compressed data.
/// </param>
/// <param name="offset">
/// the offset into the output array.
/// </param>
/// <param name="length">
/// the maximum number of bytes that may be written.
/// </param>
/// <exception cref="System.InvalidOperationException">
/// if end() was called.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// if offset and/or length don't match the array length.
/// </exception>
public int Deflate(byte[] output, int offset, int length)
{
int origLength = length;
if (state == CLOSED_STATE) {
throw new InvalidOperationException("Deflater closed");
}
if (state < BUSY_STATE) {
/* output header */
int header = (DEFLATED +
((DeflaterConstants.MAX_WBITS - 8) << 4)) << 8;
int level_flags = (level - 1) >> 1;
if (level_flags < 0 || level_flags > 3) {
level_flags = 3;
}
header |= level_flags << 6;
if ((state & IS_SETDICT) != 0) {
/* Dictionary was set */
header |= DeflaterConstants.PRESET_DICT;
}
header += 31 - (header % 31);
pending.WriteShortMSB(header);
if ((state & IS_SETDICT) != 0) {
int chksum = engine.Adler;
engine.ResetAdler();
pending.WriteShortMSB(chksum >> 16);
pending.WriteShortMSB(chksum & 0xffff);
}
state = BUSY_STATE | (state & (IS_FLUSHING | IS_FINISHING));
}
for (;;) {
int count = pending.Flush(output, offset, length);
offset += count;
totalOut += count;
length -= count;
if (length == 0 || state == FINISHED_STATE) {
break;
}
if (!engine.Deflate((state & IS_FLUSHING) != 0, (state & IS_FINISHING) != 0)) {
if (state == BUSY_STATE) {
/* We need more input now */
return origLength - length;
} else if (state == FLUSHING_STATE) {
if (level != NO_COMPRESSION) {
/* We have to supply some lookahead. 8 bit lookahead
* are needed by the zlib inflater, and we must fill
* the next byte, so that all bits are flushed.
*/
int neededbits = 8 + ((-pending.BitCount) & 7);
while (neededbits > 0) {
/* write a static tree block consisting solely of
* an EOF:
*/
pending.WriteBits(2, 10);
neededbits -= 10;
}
}
state = BUSY_STATE;
} else if (state == FINISHING_STATE) {
pending.AlignToByte();
/* We have completed the stream */
if (!noHeader) {
int adler = engine.Adler;
pending.WriteShortMSB(adler >> 16);
pending.WriteShortMSB(adler & 0xffff);
}
state = FINISHED_STATE;
}
}
}
return origLength - length;
}
/// <summary>
/// Sets the dictionary which should be used in the deflate process.
/// This call is equivalent to <code>setDictionary(dict, 0, dict.Length)</code>.
/// </summary>
/// <param name="dict">
/// the dictionary.
/// </param>
/// <exception cref="System.InvalidOperationException">
/// if setInput () or deflate () were already called or another dictionary was already set.
/// </exception>
public void SetDictionary(byte[] dict)
{
SetDictionary(dict, 0, dict.Length);
}
/// <summary>
/// Sets the dictionary which should be used in the deflate process.
/// The dictionary should be a byte array containing strings that are
/// likely to occur in the data which should be compressed. The
/// dictionary is not stored in the compressed output, only a
/// checksum. To decompress the output you need to supply the same
/// dictionary again.
/// </summary>
/// <param name="dict">
/// the dictionary.
/// </param>
/// <param name="offset">
/// an offset into the dictionary.
/// </param>
/// <param name="length">
/// the length of the dictionary.
/// </param>
/// <exception cref="System.InvalidOperationException">
/// if setInput () or deflate () were already called or another dictionary was already set.
/// </exception>
public void SetDictionary(byte[] dict, int offset, int length)
{
if (state != INIT_STATE) {
throw new InvalidOperationException();
}
state = SETDICT_STATE;
engine.SetDictionary(dict, offset, length);
}
}
}

View File

@@ -0,0 +1,85 @@
// DeflaterConstants.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// 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
// of the License, 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
namespace ICSharpCode.SharpZipLib.Zip.Compression
{
/// <summary>
/// This class contains constants used for the deflater.
/// </summary>
public class DeflaterConstants
{
public const bool DEBUGGING = false;
public const int STORED_BLOCK = 0;
public const int STATIC_TREES = 1;
public const int DYN_TREES = 2;
public const int PRESET_DICT = 0x20;
public const int DEFAULT_MEM_LEVEL = 8;
public const int MAX_MATCH = 258;
public const int MIN_MATCH = 3;
public const int MAX_WBITS = 15;
public const int WSIZE = 1 << MAX_WBITS;
public const int WMASK = WSIZE - 1;
public const int HASH_BITS = DEFAULT_MEM_LEVEL + 7;
public const int HASH_SIZE = 1 << HASH_BITS;
public const int HASH_MASK = HASH_SIZE - 1;
public const int HASH_SHIFT = (HASH_BITS + MIN_MATCH - 1) / MIN_MATCH;
public const int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1;
public const int MAX_DIST = WSIZE - MIN_LOOKAHEAD;
public const int PENDING_BUF_SIZE = 1 << (DEFAULT_MEM_LEVEL + 8);
public static int MAX_BLOCK_SIZE = Math.Min(65535, PENDING_BUF_SIZE-5);
public const int DEFLATE_STORED = 0;
public const int DEFLATE_FAST = 1;
public const int DEFLATE_SLOW = 2;
public static int[] GOOD_LENGTH = { 0, 4, 4, 4, 4, 8, 8, 8, 32, 32 };
public static int[] MAX_LAZY = { 0, 4, 5, 6, 4,16, 16, 32, 128, 258 };
public static int[] NICE_LENGTH = { 0, 8,16,32,16,32,128,128, 258, 258 };
public static int[] MAX_CHAIN = { 0, 4, 8,32,16,32,128,256,1024,4096 };
public static int[] COMPR_FUNC = { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2 };
}
}

View File

@@ -0,0 +1,653 @@
// DeflaterEngine.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// 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
// of the License, 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
using ICSharpCode.SharpZipLib.Checksums;
namespace ICSharpCode.SharpZipLib.Zip.Compression
{
public enum DeflateStrategy
{
// The default strategy.
Default = 0,
// This strategy will only allow longer string repetitions. It is
// useful for random data with a small character set.
Filtered = 1,
// This strategy will not look for string repetitions at all. It
// only encodes with Huffman trees (which means, that more common
// characters get a smaller encoding.
HuffmanOnly = 2
}
public class DeflaterEngine : DeflaterConstants
{
static int TOO_FAR = 4096;
int ins_h;
// private byte[] buffer;
short[] head;
short[] prev;
int matchStart, matchLen;
bool prevAvailable;
int blockStart;
int strstart, lookahead;
byte[] window;
DeflateStrategy strategy;
int max_chain, max_lazy, niceLength, goodLength;
/// <summary>
/// The current compression function.
/// </summary>
int comprFunc;
/// <summary>
/// The input data for compression.
/// </summary>
byte[] inputBuf;
/// <summary>
/// The total bytes of input read.
/// </summary>
int totalIn;
/// <summary>
/// The offset into inputBuf, where input data starts.
/// </summary>
int inputOff;
/// <summary>
/// The end offset of the input data.
/// </summary>
int inputEnd;
DeflaterPending pending;
DeflaterHuffman huffman;
/// <summary>
/// The adler checksum
/// </summary>
Adler32 adler;
public DeflaterEngine(DeflaterPending pending)
{
this.pending = pending;
huffman = new DeflaterHuffman(pending);
adler = new Adler32();
window = new byte[2 * WSIZE];
head = new short[HASH_SIZE];
prev = new short[WSIZE];
/* We start at index 1, to avoid a implementation deficiency, that
* we cannot build a repeat pattern at index 0.
*/
blockStart = strstart = 1;
}
public void Reset()
{
huffman.Reset();
adler.Reset();
blockStart = strstart = 1;
lookahead = 0;
totalIn = 0;
prevAvailable = false;
matchLen = MIN_MATCH - 1;
for (int i = 0; i < HASH_SIZE; i++) {
head[i] = 0;
}
for (int i = 0; i < WSIZE; i++) {
prev[i] = 0;
}
}
public void ResetAdler()
{
adler.Reset();
}
public int Adler {
get {
return (int)adler.Value;
}
}
public int TotalIn {
get {
return totalIn;
}
}
public DeflateStrategy Strategy {
get {
return strategy;
}
set {
strategy = value;
}
}
public void SetLevel(int lvl)
{
goodLength = DeflaterConstants.GOOD_LENGTH[lvl];
max_lazy = DeflaterConstants.MAX_LAZY[lvl];
niceLength = DeflaterConstants.NICE_LENGTH[lvl];
max_chain = DeflaterConstants.MAX_CHAIN[lvl];
if (DeflaterConstants.COMPR_FUNC[lvl] != comprFunc) {
// if (DeflaterConstants.DEBUGGING) {
// //Console.WriteLine("Change from "+comprFunc +" to "
// + DeflaterConstants.COMPR_FUNC[lvl]);
// }
switch (comprFunc) {
case DEFLATE_STORED:
if (strstart > blockStart) {
huffman.FlushStoredBlock(window, blockStart,
strstart - blockStart, false);
blockStart = strstart;
}
UpdateHash();
break;
case DEFLATE_FAST:
if (strstart > blockStart) {
huffman.FlushBlock(window, blockStart, strstart - blockStart,
false);
blockStart = strstart;
}
break;
case DEFLATE_SLOW:
if (prevAvailable) {
huffman.TallyLit(window[strstart-1] & 0xff);
}
if (strstart > blockStart) {
huffman.FlushBlock(window, blockStart, strstart - blockStart, false);
blockStart = strstart;
}
prevAvailable = false;
matchLen = MIN_MATCH - 1;
break;
}
comprFunc = COMPR_FUNC[lvl];
}
}
void UpdateHash()
{
// if (DEBUGGING) {
// //Console.WriteLine("updateHash: "+strstart);
// }
ins_h = (window[strstart] << HASH_SHIFT) ^ window[strstart + 1];
}
int InsertString()
{
short match;
int hash = ((ins_h << HASH_SHIFT) ^ window[strstart + (MIN_MATCH -1)]) & HASH_MASK;
// if (DEBUGGING) {
// if (hash != (((window[strstart] << (2*HASH_SHIFT)) ^
// (window[strstart + 1] << HASH_SHIFT) ^
// (window[strstart + 2])) & HASH_MASK)) {
// throw new Exception("hash inconsistent: "+hash+"/"
// +window[strstart]+","
// +window[strstart+1]+","
// +window[strstart+2]+","+HASH_SHIFT);
// }
// }
prev[strstart & WMASK] = match = head[hash];
head[hash] = (short)strstart;
ins_h = hash;
return match & 0xffff;
}
void SlideWindow()
{
Array.Copy(window, WSIZE, window, 0, WSIZE);
matchStart -= WSIZE;
strstart -= WSIZE;
blockStart -= WSIZE;
/* Slide the hash table (could be avoided with 32 bit values
* at the expense of memory usage).
*/
for (int i = 0; i < HASH_SIZE; ++i) {
int m = head[i] & 0xffff;
head[i] = (short)(m >= WSIZE ? (m - WSIZE) : 0);
}
/* Slide the prev table. */
for (int i = 0; i < WSIZE; i++) {
int m = prev[i] & 0xffff;
prev[i] = (short)(m >= WSIZE ? (m - WSIZE) : 0);
}
}
public void FillWindow()
{
/* If the window is almost full and there is insufficient lookahead,
* move the upper half to the lower one to make room in the upper half.
*/
if (strstart >= WSIZE + MAX_DIST) {
SlideWindow();
}
/* If there is not enough lookahead, but still some input left,
* read in the input
*/
while (lookahead < DeflaterConstants.MIN_LOOKAHEAD && inputOff < inputEnd) {
int more = 2 * WSIZE - lookahead - strstart;
if (more > inputEnd - inputOff) {
more = inputEnd - inputOff;
}
System.Array.Copy(inputBuf, inputOff, window, strstart + lookahead, more);
adler.Update(inputBuf, inputOff, more);
inputOff += more;
totalIn += more;
lookahead += more;
}
if (lookahead >= MIN_MATCH) {
UpdateHash();
}
}
bool FindLongestMatch(int curMatch)
{
int chainLength = this.max_chain;
int niceLength = this.niceLength;
short[] prev = this.prev;
int scan = this.strstart;
int match;
int best_end = this.strstart + matchLen;
int best_len = Math.Max(matchLen, MIN_MATCH - 1);
int limit = Math.Max(strstart - MAX_DIST, 0);
int strend = strstart + MAX_MATCH - 1;
byte scan_end1 = window[best_end - 1];
byte scan_end = window[best_end];
/* Do not waste too much time if we already have a good match: */
if (best_len >= this.goodLength) {
chainLength >>= 2;
}
/* Do not look for matches beyond the end of the input. This is necessary
* to make deflate deterministic.
*/
if (niceLength > lookahead) {
niceLength = lookahead;
}
if (DeflaterConstants.DEBUGGING && strstart > 2 * WSIZE - MIN_LOOKAHEAD) {
throw new InvalidOperationException("need lookahead");
}
do {
if (DeflaterConstants.DEBUGGING && curMatch >= strstart) {
throw new InvalidOperationException("future match");
}
if (window[curMatch + best_len] != scan_end ||
window[curMatch + best_len - 1] != scan_end1 ||
window[curMatch] != window[scan] ||
window[curMatch + 1] != window[scan + 1]) {
continue;
}
match = curMatch + 2;
scan += 2;
/* We check for insufficient lookahead only every 8th comparison;
* the 256th check will be made at strstart+258.
*/
while (window[++scan] == window[++match] &&
window[++scan] == window[++match] &&
window[++scan] == window[++match] &&
window[++scan] == window[++match] &&
window[++scan] == window[++match] &&
window[++scan] == window[++match] &&
window[++scan] == window[++match] &&
window[++scan] == window[++match] && scan < strend) ;
if (scan > best_end) {
// if (DeflaterConstants.DEBUGGING && ins_h == 0)
// System.err.println("Found match: "+curMatch+"-"+(scan-strstart));
matchStart = curMatch;
best_end = scan;
best_len = scan - strstart;
if (best_len >= niceLength) {
break;
}
scan_end1 = window[best_end - 1];
scan_end = window[best_end];
}
scan = strstart;
} while ((curMatch = (prev[curMatch & WMASK] & 0xffff)) > limit && --chainLength != 0);
matchLen = Math.Min(best_len, lookahead);
return matchLen >= MIN_MATCH;
}
public void SetDictionary(byte[] buffer, int offset, int length)
{
if (DeflaterConstants.DEBUGGING && strstart != 1) {
throw new InvalidOperationException("strstart not 1");
}
adler.Update(buffer, offset, length);
if (length < MIN_MATCH) {
return;
}
if (length > MAX_DIST) {
offset += length - MAX_DIST;
length = MAX_DIST;
}
System.Array.Copy(buffer, offset, window, strstart, length);
UpdateHash();
--length;
while (--length > 0) {
InsertString();
strstart++;
}
strstart += 2;
blockStart = strstart;
}
bool DeflateStored(bool flush, bool finish)
{
if (!flush && lookahead == 0) {
return false;
}
strstart += lookahead;
lookahead = 0;
int storedLen = strstart - blockStart;
if ((storedLen >= DeflaterConstants.MAX_BLOCK_SIZE) || /* Block is full */
(blockStart < WSIZE && storedLen >= MAX_DIST) || /* Block may move out of window */
flush) {
bool lastBlock = finish;
if (storedLen > DeflaterConstants.MAX_BLOCK_SIZE) {
storedLen = DeflaterConstants.MAX_BLOCK_SIZE;
lastBlock = false;
}
// if (DeflaterConstants.DEBUGGING) {
// //Console.WriteLine("storedBlock["+storedLen+","+lastBlock+"]");
// }
huffman.FlushStoredBlock(window, blockStart, storedLen, lastBlock);
blockStart += storedLen;
return !lastBlock;
}
return true;
}
private bool DeflateFast(bool flush, bool finish)
{
if (lookahead < MIN_LOOKAHEAD && !flush) {
return false;
}
while (lookahead >= MIN_LOOKAHEAD || flush) {
if (lookahead == 0) {
/* We are flushing everything */
huffman.FlushBlock(window, blockStart, strstart - blockStart, finish);
blockStart = strstart;
return false;
}
if (strstart > 2 * WSIZE - MIN_LOOKAHEAD) {
/* slide window, as findLongestMatch need this.
* This should only happen when flushing and the window
* is almost full.
*/
SlideWindow();
}
int hashHead;
if (lookahead >= MIN_MATCH &&
(hashHead = InsertString()) != 0 &&
strategy != DeflateStrategy.HuffmanOnly &&
strstart - hashHead <= MAX_DIST &&
FindLongestMatch(hashHead)) {
/* longestMatch sets matchStart and matchLen */
// if (DeflaterConstants.DEBUGGING) {
// for (int i = 0 ; i < matchLen; i++) {
// if (window[strstart+i] != window[matchStart + i]) {
// throw new Exception();
// }
// }
// }
// -jr- Hak hak hak this stops problems with fast/low compression and index out of range
if (huffman.TallyDist(strstart - matchStart, matchLen)) {
bool lastBlock = finish && lookahead == 0;
huffman.FlushBlock(window, blockStart, strstart - blockStart, lastBlock);
blockStart = strstart;
}
lookahead -= matchLen;
if (matchLen <= max_lazy && lookahead >= MIN_MATCH) {
while (--matchLen > 0) {
++strstart;
InsertString();
}
++strstart;
} else {
strstart += matchLen;
if (lookahead >= MIN_MATCH - 1) {
UpdateHash();
}
}
matchLen = MIN_MATCH - 1;
continue;
} else {
/* No match found */
huffman.TallyLit(window[strstart] & 0xff);
++strstart;
--lookahead;
}
if (huffman.IsFull()) {
bool lastBlock = finish && lookahead == 0;
huffman.FlushBlock(window, blockStart, strstart - blockStart, lastBlock);
blockStart = strstart;
return !lastBlock;
}
}
return true;
}
bool DeflateSlow(bool flush, bool finish)
{
if (lookahead < MIN_LOOKAHEAD && !flush) {
return false;
}
while (lookahead >= MIN_LOOKAHEAD || flush) {
if (lookahead == 0) {
if (prevAvailable) {
huffman.TallyLit(window[strstart-1] & 0xff);
}
prevAvailable = false;
/* We are flushing everything */
if (DeflaterConstants.DEBUGGING && !flush) {
throw new Exception("Not flushing, but no lookahead");
}
huffman.FlushBlock(window, blockStart, strstart - blockStart,
finish);
blockStart = strstart;
return false;
}
if (strstart >= 2 * WSIZE - MIN_LOOKAHEAD) {
/* slide window, as findLongestMatch need this.
* This should only happen when flushing and the window
* is almost full.
*/
SlideWindow();
}
int prevMatch = matchStart;
int prevLen = matchLen;
if (lookahead >= MIN_MATCH) {
int hashHead = InsertString();
if (strategy != DeflateStrategy.HuffmanOnly && hashHead != 0 && strstart - hashHead <= MAX_DIST && FindLongestMatch(hashHead)) {
/* longestMatch sets matchStart and matchLen */
/* Discard match if too small and too far away */
if (matchLen <= 5 && (strategy == DeflateStrategy.Filtered || (matchLen == MIN_MATCH && strstart - matchStart > TOO_FAR))) {
matchLen = MIN_MATCH - 1;
}
}
}
/* previous match was better */
if (prevLen >= MIN_MATCH && matchLen <= prevLen) {
// if (DeflaterConstants.DEBUGGING) {
// for (int i = 0 ; i < matchLen; i++) {
// if (window[strstart-1+i] != window[prevMatch + i])
// throw new Exception();
// }
// }
huffman.TallyDist(strstart - 1 - prevMatch, prevLen);
prevLen -= 2;
do {
strstart++;
lookahead--;
if (lookahead >= MIN_MATCH) {
InsertString();
}
} while (--prevLen > 0);
strstart ++;
lookahead--;
prevAvailable = false;
matchLen = MIN_MATCH - 1;
} else {
if (prevAvailable) {
huffman.TallyLit(window[strstart-1] & 0xff);
}
prevAvailable = true;
strstart++;
lookahead--;
}
if (huffman.IsFull()) {
int len = strstart - blockStart;
if (prevAvailable) {
len--;
}
bool lastBlock = (finish && lookahead == 0 && !prevAvailable);
huffman.FlushBlock(window, blockStart, len, lastBlock);
blockStart += len;
return !lastBlock;
}
}
return true;
}
public bool Deflate(bool flush, bool finish)
{
bool progress;
do {
FillWindow();
bool canFlush = flush && inputOff == inputEnd;
// if (DeflaterConstants.DEBUGGING) {
// //Console.WriteLine("window: ["+blockStart+","+strstart+","
// +lookahead+"], "+comprFunc+","+canFlush);
// }
switch (comprFunc) {
case DEFLATE_STORED:
progress = DeflateStored(canFlush, finish);
break;
case DEFLATE_FAST:
progress = DeflateFast(canFlush, finish);
break;
case DEFLATE_SLOW:
progress = DeflateSlow(canFlush, finish);
break;
default:
throw new InvalidOperationException("unknown comprFunc");
}
} while (pending.IsFlushed && progress); /* repeat while we have no pending output and progress was made */
return progress;
}
public void SetInput(byte[] buf, int off, int len)
{
if (inputOff < inputEnd) {
throw new InvalidOperationException("Old input was not completely processed");
}
int end = off + len;
/* We want to throw an ArrayIndexOutOfBoundsException early. The
* check is very tricky: it also handles integer wrap around.
*/
if (0 > off || off > end || end > buf.Length) {
throw new ArgumentOutOfRangeException();
}
inputBuf = buf;
inputOff = off;
inputEnd = end;
}
public bool NeedsInput()
{
return inputEnd == inputOff;
}
}
}

View File

@@ -0,0 +1,780 @@
// DeflaterHuffman.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// 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
// of the License, 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
namespace ICSharpCode.SharpZipLib.Zip.Compression
{
/// <summary>
/// This is the DeflaterHuffman class.
///
/// This class is <i>not</i> thread safe. This is inherent in the API, due
/// to the split of deflate and setInput.
///
/// author of the original java version : Jochen Hoenicke
/// </summary>
public class DeflaterHuffman
{
private static int BUFSIZE = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6);
private static int LITERAL_NUM = 286;
private static int DIST_NUM = 30;
private static int BITLEN_NUM = 19;
private static int REP_3_6 = 16;
private static int REP_3_10 = 17;
private static int REP_11_138 = 18;
private static int EOF_SYMBOL = 256;
private static int[] BL_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
private static byte[] bit4Reverse = {
0,
8,
4,
12,
2,
10,
6,
14,
1,
9,
5,
13,
3,
11,
7,
15
};
public class Tree
{
public short[] freqs;
public byte[] length;
public int minNumCodes, numCodes;
short[] codes;
int[] bl_counts;
int maxLength;
DeflaterHuffman dh;
public Tree(DeflaterHuffman dh, int elems, int minCodes, int maxLength)
{
this.dh = dh;
this.minNumCodes = minCodes;
this.maxLength = maxLength;
freqs = new short[elems];
bl_counts = new int[maxLength];
}
public void Reset()
{
for (int i = 0; i < freqs.Length; i++) {
freqs[i] = 0;
}
codes = null;
length = null;
}
public void WriteSymbol(int code)
{
// if (DeflaterConstants.DEBUGGING) {
// freqs[code]--;
// // Console.Write("writeSymbol("+freqs.length+","+code+"): ");
// }
dh.pending.WriteBits(codes[code] & 0xffff, length[code]);
}
public void CheckEmpty()
{
bool empty = true;
for (int i = 0; i < freqs.Length; i++) {
if (freqs[i] != 0) {
//Console.WriteLine("freqs["+i+"] == "+freqs[i]);
empty = false;
}
}
if (!empty) {
throw new Exception();
}
//Console.WriteLine("checkEmpty suceeded!");
}
public void SetStaticCodes(short[] stCodes, byte[] stLength)
{
codes = stCodes;
length = stLength;
}
public void BuildCodes()
{
int numSymbols = freqs.Length;
int[] nextCode = new int[maxLength];
int code = 0;
codes = new short[freqs.Length];
// if (DeflaterConstants.DEBUGGING) {
// //Console.WriteLine("buildCodes: "+freqs.Length);
// }
for (int bits = 0; bits < maxLength; bits++) {
nextCode[bits] = code;
code += bl_counts[bits] << (15 - bits);
// if (DeflaterConstants.DEBUGGING) {
// //Console.WriteLine("bits: "+(bits+1)+" count: "+bl_counts[bits]
// +" nextCode: "+code); // HACK : Integer.toHexString(
// }
}
if (DeflaterConstants.DEBUGGING && code != 65536) {
throw new Exception("Inconsistent bl_counts!");
}
for (int i=0; i < numCodes; i++) {
int bits = length[i];
if (bits > 0) {
// if (DeflaterConstants.DEBUGGING) {
// //Console.WriteLine("codes["+i+"] = rev(" + nextCode[bits-1]+")," // HACK : Integer.toHexString(
// +bits);
// }
codes[i] = BitReverse(nextCode[bits-1]);
nextCode[bits-1] += 1 << (16 - bits);
}
}
}
void BuildLength(int[] childs)
{
this.length = new byte [freqs.Length];
int numNodes = childs.Length / 2;
int numLeafs = (numNodes + 1) / 2;
int overflow = 0;
for (int i = 0; i < maxLength; i++) {
bl_counts[i] = 0;
}
/* First calculate optimal bit lengths */
int[] lengths = new int[numNodes];
lengths[numNodes-1] = 0;
for (int i = numNodes - 1; i >= 0; i--) {
if (childs[2*i+1] != -1) {
int bitLength = lengths[i] + 1;
if (bitLength > maxLength) {
bitLength = maxLength;
overflow++;
}
lengths[childs[2*i]] = lengths[childs[2*i+1]] = bitLength;
} else {
/* A leaf node */
int bitLength = lengths[i];
bl_counts[bitLength - 1]++;
this.length[childs[2*i]] = (byte) lengths[i];
}
}
// if (DeflaterConstants.DEBUGGING) {
// //Console.WriteLine("Tree "+freqs.Length+" lengths:");
// for (int i=0; i < numLeafs; i++) {
// //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
// + " len: "+length[childs[2*i]]);
// }
// }
if (overflow == 0) {
return;
}
int incrBitLen = maxLength - 1;
do {
/* Find the first bit length which could increase: */
while (bl_counts[--incrBitLen] == 0)
;
/* Move this node one down and remove a corresponding
* amount of overflow nodes.
*/
do {
bl_counts[incrBitLen]--;
bl_counts[++incrBitLen]++;
overflow -= 1 << (maxLength - 1 - incrBitLen);
} while (overflow > 0 && incrBitLen < maxLength - 1);
} while (overflow > 0);
/* We may have overshot above. Move some nodes from maxLength to
* maxLength-1 in that case.
*/
bl_counts[maxLength-1] += overflow;
bl_counts[maxLength-2] -= overflow;
/* Now recompute all bit lengths, scanning in increasing
* frequency. It is simpler to reconstruct all lengths instead of
* fixing only the wrong ones. This idea is taken from 'ar'
* written by Haruhiko Okumura.
*
* The nodes were inserted with decreasing frequency into the childs
* array.
*/
int nodePtr = 2 * numLeafs;
for (int bits = maxLength; bits != 0; bits--) {
int n = bl_counts[bits-1];
while (n > 0) {
int childPtr = 2*childs[nodePtr++];
if (childs[childPtr + 1] == -1) {
/* We found another leaf */
length[childs[childPtr]] = (byte) bits;
n--;
}
}
}
// if (DeflaterConstants.DEBUGGING) {
// //Console.WriteLine("*** After overflow elimination. ***");
// for (int i=0; i < numLeafs; i++) {
// //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
// + " len: "+length[childs[2*i]]);
// }
// }
}
public void BuildTree()
{
int numSymbols = freqs.Length;
/* heap is a priority queue, sorted by frequency, least frequent
* nodes first. The heap is a binary tree, with the property, that
* the parent node is smaller than both child nodes. This assures
* that the smallest node is the first parent.
*
* The binary tree is encoded in an array: 0 is root node and
* the nodes 2*n+1, 2*n+2 are the child nodes of node n.
*/
int[] heap = new int[numSymbols];
int heapLen = 0;
int maxCode = 0;
for (int n = 0; n < numSymbols; n++) {
int freq = freqs[n];
if (freq != 0) {
/* Insert n into heap */
int pos = heapLen++;
int ppos;
while (pos > 0 && freqs[heap[ppos = (pos - 1) / 2]] > freq) {
heap[pos] = heap[ppos];
pos = ppos;
}
heap[pos] = n;
maxCode = n;
}
}
/* We could encode a single literal with 0 bits but then we
* don't see the literals. Therefore we force at least two
* literals to avoid this case. We don't care about order in
* this case, both literals get a 1 bit code.
*/
while (heapLen < 2) {
int node = maxCode < 2 ? ++maxCode : 0;
heap[heapLen++] = node;
}
numCodes = Math.Max(maxCode + 1, minNumCodes);
int numLeafs = heapLen;
int[] childs = new int[4*heapLen - 2];
int[] values = new int[2*heapLen - 1];
int numNodes = numLeafs;
for (int i = 0; i < heapLen; i++) {
int node = heap[i];
childs[2*i] = node;
childs[2*i+1] = -1;
values[i] = freqs[node] << 8;
heap[i] = i;
}
/* Construct the Huffman tree by repeatedly combining the least two
* frequent nodes.
*/
do {
int first = heap[0];
int last = heap[--heapLen];
/* Propagate the hole to the leafs of the heap */
int ppos = 0;
int path = 1;
while (path < heapLen) {
if (path + 1 < heapLen && values[heap[path]] > values[heap[path+1]]) {
path++;
}
heap[ppos] = heap[path];
ppos = path;
path = path * 2 + 1;
}
/* Now propagate the last element down along path. Normally
* it shouldn't go too deep.
*/
int lastVal = values[last];
while ((path = ppos) > 0 && values[heap[ppos = (path - 1)/2]] > lastVal) {
heap[path] = heap[ppos];
}
heap[path] = last;
int second = heap[0];
/* Create a new node father of first and second */
last = numNodes++;
childs[2*last] = first;
childs[2*last+1] = second;
int mindepth = Math.Min(values[first] & 0xff, values[second] & 0xff);
values[last] = lastVal = values[first] + values[second] - mindepth + 1;
/* Again, propagate the hole to the leafs */
ppos = 0;
path = 1;
while (path < heapLen) {
if (path + 1 < heapLen && values[heap[path]] > values[heap[path+1]]) {
path++;
}
heap[ppos] = heap[path];
ppos = path;
path = ppos * 2 + 1;
}
/* Now propagate the new element down along path */
while ((path = ppos) > 0 && values[heap[ppos = (path - 1)/2]] > lastVal) {
heap[path] = heap[ppos];
}
heap[path] = last;
} while (heapLen > 1);
if (heap[0] != childs.Length / 2 - 1) {
throw new Exception("Weird!");
}
BuildLength(childs);
}
public int GetEncodedLength()
{
int len = 0;
for (int i = 0; i < freqs.Length; i++) {
len += freqs[i] * length[i];
}
return len;
}
public void CalcBLFreq(Tree blTree)
{
int max_count; /* max repeat count */
int min_count; /* min repeat count */
int count; /* repeat count of the current code */
int curlen = -1; /* length of current code */
int i = 0;
while (i < numCodes) {
count = 1;
int nextlen = length[i];
if (nextlen == 0) {
max_count = 138;
min_count = 3;
} else {
max_count = 6;
min_count = 3;
if (curlen != nextlen) {
blTree.freqs[nextlen]++;
count = 0;
}
}
curlen = nextlen;
i++;
while (i < numCodes && curlen == length[i]) {
i++;
if (++count >= max_count) {
break;
}
}
if (count < min_count) {
blTree.freqs[curlen] += (short)count;
} else if (curlen != 0) {
blTree.freqs[REP_3_6]++;
} else if (count <= 10) {
blTree.freqs[REP_3_10]++;
} else {
blTree.freqs[REP_11_138]++;
}
}
}
public void WriteTree(Tree blTree)
{
int max_count; /* max repeat count */
int min_count; /* min repeat count */
int count; /* repeat count of the current code */
int curlen = -1; /* length of current code */
int i = 0;
while (i < numCodes) {
count = 1;
int nextlen = length[i];
if (nextlen == 0) {
max_count = 138;
min_count = 3;
} else {
max_count = 6;
min_count = 3;
if (curlen != nextlen) {
blTree.WriteSymbol(nextlen);
count = 0;
}
}
curlen = nextlen;
i++;
while (i < numCodes && curlen == length[i]) {
i++;
if (++count >= max_count) {
break;
}
}
if (count < min_count) {
while (count-- > 0) {
blTree.WriteSymbol(curlen);
}
} else if (curlen != 0) {
blTree.WriteSymbol(REP_3_6);
dh.pending.WriteBits(count - 3, 2);
} else if (count <= 10) {
blTree.WriteSymbol(REP_3_10);
dh.pending.WriteBits(count - 3, 3);
} else {
blTree.WriteSymbol(REP_11_138);
dh.pending.WriteBits(count - 11, 7);
}
}
}
}
public DeflaterPending pending;
private Tree literalTree, distTree, blTree;
private short[] d_buf;
private byte[] l_buf;
private int last_lit;
private int extra_bits;
private static short[] staticLCodes;
private static byte[] staticLLength;
private static short[] staticDCodes;
private static byte[] staticDLength;
/// <summary>
/// Reverse the bits of a 16 bit value.
/// </summary>
public static short BitReverse(int value)
{
return (short) (bit4Reverse[value & 0xF] << 12 |
bit4Reverse[(value >> 4) & 0xF] << 8 |
bit4Reverse[(value >> 8) & 0xF] << 4 |
bit4Reverse[value >> 12]);
}
static DeflaterHuffman()
{
/* See RFC 1951 3.2.6 */
/* Literal codes */
staticLCodes = new short[LITERAL_NUM];
staticLLength = new byte[LITERAL_NUM];
int i = 0;
while (i < 144) {
staticLCodes[i] = BitReverse((0x030 + i) << 8);
staticLLength[i++] = 8;
}
while (i < 256) {
staticLCodes[i] = BitReverse((0x190 - 144 + i) << 7);
staticLLength[i++] = 9;
}
while (i < 280) {
staticLCodes[i] = BitReverse((0x000 - 256 + i) << 9);
staticLLength[i++] = 7;
}
while (i < LITERAL_NUM) {
staticLCodes[i] = BitReverse((0x0c0 - 280 + i) << 8);
staticLLength[i++] = 8;
}
/* Distant codes */
staticDCodes = new short[DIST_NUM];
staticDLength = new byte[DIST_NUM];
for (i = 0; i < DIST_NUM; i++) {
staticDCodes[i] = BitReverse(i << 11);
staticDLength[i] = 5;
}
}
public DeflaterHuffman(DeflaterPending pending)
{
this.pending = pending;
literalTree = new Tree(this, LITERAL_NUM, 257, 15);
distTree = new Tree(this, DIST_NUM, 1, 15);
blTree = new Tree(this, BITLEN_NUM, 4, 7);
d_buf = new short[BUFSIZE];
l_buf = new byte [BUFSIZE];
}
public void Reset()
{
last_lit = 0;
extra_bits = 0;
literalTree.Reset();
distTree.Reset();
blTree.Reset();
}
int Lcode(int len)
{
if (len == 255) {
return 285;
}
int code = 257;
while (len >= 8) {
code += 4;
len >>= 1;
}
return code + len;
}
int Dcode(int distance)
{
int code = 0;
while (distance >= 4) {
code += 2;
distance >>= 1;
}
return code + distance;
}
public void SendAllTrees(int blTreeCodes)
{
blTree.BuildCodes();
literalTree.BuildCodes();
distTree.BuildCodes();
pending.WriteBits(literalTree.numCodes - 257, 5);
pending.WriteBits(distTree.numCodes - 1, 5);
pending.WriteBits(blTreeCodes - 4, 4);
for (int rank = 0; rank < blTreeCodes; rank++) {
pending.WriteBits(blTree.length[BL_ORDER[rank]], 3);
}
literalTree.WriteTree(blTree);
distTree.WriteTree(blTree);
// if (DeflaterConstants.DEBUGGING) {
// blTree.CheckEmpty();
// }
}
public void CompressBlock()
{
for (int i = 0; i < last_lit; i++) {
int litlen = l_buf[i] & 0xff;
int dist = d_buf[i];
if (dist-- != 0) {
// if (DeflaterConstants.DEBUGGING) {
// Console.Write("["+(dist+1)+","+(litlen+3)+"]: ");
// }
int lc = Lcode(litlen);
literalTree.WriteSymbol(lc);
int bits = (lc - 261) / 4;
if (bits > 0 && bits <= 5) {
pending.WriteBits(litlen & ((1 << bits) - 1), bits);
}
int dc = Dcode(dist);
distTree.WriteSymbol(dc);
bits = dc / 2 - 1;
if (bits > 0) {
pending.WriteBits(dist & ((1 << bits) - 1), bits);
}
} else {
// if (DeflaterConstants.DEBUGGING) {
// if (litlen > 32 && litlen < 127) {
// Console.Write("("+(char)litlen+"): ");
// } else {
// Console.Write("{"+litlen+"}: ");
// }
// }
literalTree.WriteSymbol(litlen);
}
}
// if (DeflaterConstants.DEBUGGING) {
// Console.Write("EOF: ");
// }
literalTree.WriteSymbol(EOF_SYMBOL);
// if (DeflaterConstants.DEBUGGING) {
// literalTree.CheckEmpty();
// distTree.CheckEmpty();
// }
}
public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
{
// if (DeflaterConstants.DEBUGGING) {
// //Console.WriteLine("Flushing stored block "+ storedLength);
// }
pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1) + (lastBlock ? 1 : 0), 3);
pending.AlignToByte();
pending.WriteShort(storedLength);
pending.WriteShort(~storedLength);
pending.WriteBlock(stored, storedOffset, storedLength);
Reset();
}
public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
{
literalTree.freqs[EOF_SYMBOL]++;
/* Build trees */
literalTree.BuildTree();
distTree.BuildTree();
/* Calculate bitlen frequency */
literalTree.CalcBLFreq(blTree);
distTree.CalcBLFreq(blTree);
/* Build bitlen tree */
blTree.BuildTree();
int blTreeCodes = 4;
for (int i = 18; i > blTreeCodes; i--) {
if (blTree.length[BL_ORDER[i]] > 0) {
blTreeCodes = i+1;
}
}
int opt_len = 14 + blTreeCodes * 3 + blTree.GetEncodedLength() +
literalTree.GetEncodedLength() + distTree.GetEncodedLength() +
extra_bits;
int static_len = extra_bits;
for (int i = 0; i < LITERAL_NUM; i++) {
static_len += literalTree.freqs[i] * staticLLength[i];
}
for (int i = 0; i < DIST_NUM; i++) {
static_len += distTree.freqs[i] * staticDLength[i];
}
if (opt_len >= static_len) {
/* Force static trees */
opt_len = static_len;
}
if (storedOffset >= 0 && storedLength+4 < opt_len >> 3) {
/* Store Block */
// if (DeflaterConstants.DEBUGGING) {
// //Console.WriteLine("Storing, since " + storedLength + " < " + opt_len
// + " <= " + static_len);
// }
FlushStoredBlock(stored, storedOffset, storedLength, lastBlock);
} else if (opt_len == static_len) {
/* Encode with static tree */
pending.WriteBits((DeflaterConstants.STATIC_TREES << 1) + (lastBlock ? 1 : 0), 3);
literalTree.SetStaticCodes(staticLCodes, staticLLength);
distTree.SetStaticCodes(staticDCodes, staticDLength);
CompressBlock();
Reset();
} else {
/* Encode with dynamic tree */
pending.WriteBits((DeflaterConstants.DYN_TREES << 1) + (lastBlock ? 1 : 0), 3);
SendAllTrees(blTreeCodes);
CompressBlock();
Reset();
}
}
public bool IsFull()
{
// return last_lit + 16 >= BUFSIZE; // HACK: This was == 'last_lit == BUFSIZE', but errors occured with DeflateFast
return last_lit >= BUFSIZE; // -jr- This is the correct form!
}
public bool TallyLit(int lit)
{
// if (DeflaterConstants.DEBUGGING) {
// if (lit > 32 && lit < 127) {
// //Console.WriteLine("("+(char)lit+")");
// } else {
// //Console.WriteLine("{"+lit+"}");
// }
// }
d_buf[last_lit] = 0;
l_buf[last_lit++] = (byte)lit;
literalTree.freqs[lit]++;
return IsFull();
}
public bool TallyDist(int dist, int len)
{
// if (DeflaterConstants.DEBUGGING) {
// //Console.WriteLine("["+dist+","+len+"]");
// }
d_buf[last_lit] = (short)dist;
l_buf[last_lit++] = (byte)(len - 3);
int lc = Lcode(len - 3);
literalTree.freqs[lc]++;
if (lc >= 265 && lc < 285) {
extra_bits += (lc - 261) / 4;
}
int dc = Dcode(dist - 1);
distTree.freqs[dc]++;
if (dc >= 4) {
extra_bits += dc / 2 - 1;
}
return IsFull();
}
}
}

View File

@@ -0,0 +1,52 @@
// DeflaterPending.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// 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
// of the License, 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
namespace ICSharpCode.SharpZipLib.Zip.Compression
{
/// <summary>
/// This class stores the pending output of the Deflater.
///
/// author of the original java version : Jochen Hoenicke
/// </summary>
public class DeflaterPending : PendingBuffer
{
public DeflaterPending() : base(DeflaterConstants.PENDING_BUF_SIZE)
{
}
}
}

View File

@@ -0,0 +1,782 @@
// Inflater.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// 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
// of the License, 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
namespace ICSharpCode.SharpZipLib.Zip.Compression
{
/// <summary>
/// Inflater is used to decompress data that has been compressed according
/// to the "deflate" standard described in rfc1950.
///
/// The usage is as following. First you have to set some input with
/// <code>setInput()</code>, then inflate() it. If inflate doesn't
/// inflate any bytes there may be three reasons:
/// <ul>
/// <li>needsInput() returns true because the input buffer is empty.
/// You have to provide more input with <code>setInput()</code>.
/// NOTE: needsInput() also returns true when, the stream is finished.
/// </li>
/// <li>needsDictionary() returns true, you have to provide a preset
/// dictionary with <code>setDictionary()</code>.</li>
/// <li>finished() returns true, the inflater has finished.</li>
/// </ul>
/// Once the first output byte is produced, a dictionary will not be
/// needed at a later stage.
///
/// author of the original java version : John Leuner, Jochen Hoenicke
/// </summary>
public class Inflater
{
/// <summary>
/// Copy lengths for literal codes 257..285
/// </summary>
private static int[] CPLENS = {
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
};
/// <summary>
/// Extra bits for literal codes 257..285
/// </summary>
private static int[] CPLEXT = {
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
};
/// <summary>
/// Copy offsets for distance codes 0..29
/// </summary>
private static int[] CPDIST = {
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
8193, 12289, 16385, 24577
};
/// <summary>
/// Extra bits for distance codes
/// </summary>
private static int[] CPDEXT = {
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
12, 12, 13, 13
};
/// <summary>
/// This are the state in which the inflater can be.
/// </summary>
private const int DECODE_HEADER = 0;
private const int DECODE_DICT = 1;
private const int DECODE_BLOCKS = 2;
private const int DECODE_STORED_LEN1 = 3;
private const int DECODE_STORED_LEN2 = 4;
private const int DECODE_STORED = 5;
private const int DECODE_DYN_HEADER = 6;
private const int DECODE_HUFFMAN = 7;
private const int DECODE_HUFFMAN_LENBITS = 8;
private const int DECODE_HUFFMAN_DIST = 9;
private const int DECODE_HUFFMAN_DISTBITS = 10;
private const int DECODE_CHKSUM = 11;
private const int FINISHED = 12;
/// <summary>
/// This variable contains the current state.
/// </summary>
private int mode;
/// <summary>
/// The adler checksum of the dictionary or of the decompressed
/// stream, as it is written in the header resp. footer of the
/// compressed stream.
/// Only valid if mode is DECODE_DICT or DECODE_CHKSUM.
/// </summary>
private int readAdler;
/// <summary>
/// The number of bits needed to complete the current state. This
/// is valid, if mode is DECODE_DICT, DECODE_CHKSUM,
/// DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS.
/// </summary>
private int neededBits;
private int repLength, repDist;
private int uncomprLen;
/// <summary>
/// True, if the last block flag was set in the last block of the
/// inflated stream. This means that the stream ends after the
/// current block.
/// </summary>
private bool isLastBlock;
/// <summary>
/// The total number of inflated bytes.
/// </summary>
private int totalOut;
/// <summary>
/// The total number of bytes set with setInput(). This is not the
/// value returned by getTotalIn(), since this also includes the
/// unprocessed input.
/// </summary>
private int totalIn;
/// <summary>
/// This variable stores the nowrap flag that was given to the constructor.
/// True means, that the inflated stream doesn't contain a header nor the
/// checksum in the footer.
/// </summary>
private bool nowrap;
private StreamManipulator input;
private OutputWindow outputWindow;
private InflaterDynHeader dynHeader;
private InflaterHuffmanTree litlenTree, distTree;
private Adler32 adler;
/// <summary>
/// Creates a new inflater.
/// </summary>
public Inflater() : this(false)
{
}
/// <summary>
/// Creates a new inflater.
/// </summary>
/// <param name="nowrap">
/// true if no header and checksum field appears in the
/// stream. This is used for GZIPed input. For compatibility with
/// Sun JDK you should provide one byte of input more than needed in
/// this case.
/// </param>
public Inflater(bool nowrap)
{
this.nowrap = nowrap;
this.adler = new Adler32();
input = new StreamManipulator();
outputWindow = new OutputWindow();
mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER;
}
/// <summary>
/// Resets the inflater so that a new stream can be decompressed. All
/// pending input and output will be discarded.
/// </summary>
public void Reset()
{
mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER;
totalIn = totalOut = 0;
input.Reset();
outputWindow.Reset();
dynHeader = null;
litlenTree = null;
distTree = null;
isLastBlock = false;
adler.Reset();
}
/// <summary>
/// Decodes the deflate header.
/// </summary>
/// <returns>
/// false if more input is needed.
/// </returns>
/// <exception cref="System.FormatException">
/// if header is invalid.
/// </exception>
private bool DecodeHeader()
{
int header = input.PeekBits(16);
if (header < 0) {
return false;
}
input.DropBits(16);
/* The header is written in "wrong" byte order */
header = ((header << 8) | (header >> 8)) & 0xffff;
if (header % 31 != 0) {
throw new FormatException("Header checksum illegal");
}
if ((header & 0x0f00) != (Deflater.DEFLATED << 8)) {
throw new FormatException("Compression Method unknown");
}
/* Maximum size of the backwards window in bits.
* We currently ignore this, but we could use it to make the
* inflater window more space efficient. On the other hand the
* full window (15 bits) is needed most times, anyway.
int max_wbits = ((header & 0x7000) >> 12) + 8;
*/
if ((header & 0x0020) == 0) { // Dictionary flag?
mode = DECODE_BLOCKS;
} else {
mode = DECODE_DICT;
neededBits = 32;
}
return true;
}
/// <summary>
/// Decodes the dictionary checksum after the deflate header.
/// </summary>
/// <returns>
/// false if more input is needed.
/// </returns>
private bool DecodeDict()
{
while (neededBits > 0) {
int dictByte = input.PeekBits(8);
if (dictByte < 0) {
return false;
}
input.DropBits(8);
readAdler = (readAdler << 8) | dictByte;
neededBits -= 8;
}
return false;
}
/// <summary>
/// Decodes the huffman encoded symbols in the input stream.
/// </summary>
/// <returns>
/// false if more input is needed, true if output window is
/// full or the current block ends.
/// </returns>
/// <exception cref="System.FormatException">
/// if deflated stream is invalid.
/// </exception>
private bool DecodeHuffman()
{
int free = outputWindow.GetFreeSpace();
while (free >= 258) {
int symbol;
switch (mode) {
case DECODE_HUFFMAN:
/* This is the inner loop so it is optimized a bit */
while (((symbol = litlenTree.GetSymbol(input)) & ~0xff) == 0) {
outputWindow.Write(symbol);
if (--free < 258) {
return true;
}
}
if (symbol < 257) {
if (symbol < 0) {
return false;
} else {
/* symbol == 256: end of block */
distTree = null;
litlenTree = null;
mode = DECODE_BLOCKS;
return true;
}
}
try {
repLength = CPLENS[symbol - 257];
neededBits = CPLEXT[symbol - 257];
} catch (Exception) {
throw new FormatException("Illegal rep length code");
}
goto case DECODE_HUFFMAN_LENBITS;/* fall through */
case DECODE_HUFFMAN_LENBITS:
if (neededBits > 0) {
mode = DECODE_HUFFMAN_LENBITS;
int i = input.PeekBits(neededBits);
if (i < 0) {
return false;
}
input.DropBits(neededBits);
repLength += i;
}
mode = DECODE_HUFFMAN_DIST;
goto case DECODE_HUFFMAN_DIST;/* fall through */
case DECODE_HUFFMAN_DIST:
symbol = distTree.GetSymbol(input);
if (symbol < 0) {
return false;
}
try {
repDist = CPDIST[symbol];
neededBits = CPDEXT[symbol];
} catch (Exception) {
throw new FormatException("Illegal rep dist code");
}
goto case DECODE_HUFFMAN_DISTBITS;/* fall through */
case DECODE_HUFFMAN_DISTBITS:
if (neededBits > 0) {
mode = DECODE_HUFFMAN_DISTBITS;
int i = input.PeekBits(neededBits);
if (i < 0) {
return false;
}
input.DropBits(neededBits);
repDist += i;
}
outputWindow.Repeat(repLength, repDist);
free -= repLength;
mode = DECODE_HUFFMAN;
break;
default:
throw new FormatException();
}
}
return true;
}
/// <summary>
/// Decodes the adler checksum after the deflate stream.
/// </summary>
/// <returns>
/// false if more input is needed.
/// </returns>
/// <exception cref="System.FormatException">
/// DataFormatException, if checksum doesn't match.
/// </exception>
private bool DecodeChksum()
{
while (neededBits > 0) {
int chkByte = input.PeekBits(8);
if (chkByte < 0) {
return false;
}
input.DropBits(8);
readAdler = (readAdler << 8) | chkByte;
neededBits -= 8;
}
if ((int) adler.Value != readAdler) {
throw new FormatException("Adler chksum doesn't match: " + (int)adler.Value + " vs. " + readAdler);
}
mode = FINISHED;
return false;
}
/// <summary>
/// Decodes the deflated stream.
/// </summary>
/// <returns>
/// false if more input is needed, or if finished.
/// </returns>
/// <exception cref="System.FormatException">
/// DataFormatException, if deflated stream is invalid.
/// </exception>
private bool Decode()
{
switch (mode) {
case DECODE_HEADER:
return DecodeHeader();
case DECODE_DICT:
return DecodeDict();
case DECODE_CHKSUM:
return DecodeChksum();
case DECODE_BLOCKS:
if (isLastBlock) {
if (nowrap) {
mode = FINISHED;
return false;
} else {
input.SkipToByteBoundary();
neededBits = 32;
mode = DECODE_CHKSUM;
return true;
}
}
int type = input.PeekBits(3);
if (type < 0) {
return false;
}
input.DropBits(3);
if ((type & 1) != 0) {
isLastBlock = true;
}
switch (type >> 1){
case DeflaterConstants.STORED_BLOCK:
input.SkipToByteBoundary();
mode = DECODE_STORED_LEN1;
break;
case DeflaterConstants.STATIC_TREES:
litlenTree = InflaterHuffmanTree.defLitLenTree;
distTree = InflaterHuffmanTree.defDistTree;
mode = DECODE_HUFFMAN;
break;
case DeflaterConstants.DYN_TREES:
dynHeader = new InflaterDynHeader();
mode = DECODE_DYN_HEADER;
break;
default:
throw new FormatException("Unknown block type "+type);
}
return true;
case DECODE_STORED_LEN1:
{
if ((uncomprLen = input.PeekBits(16)) < 0) {
return false;
}
input.DropBits(16);
mode = DECODE_STORED_LEN2;
}
goto case DECODE_STORED_LEN2; /* fall through */
case DECODE_STORED_LEN2:
{
int nlen = input.PeekBits(16);
if (nlen < 0) {
return false;
}
input.DropBits(16);
if (nlen != (uncomprLen ^ 0xffff)) {
throw new FormatException("broken uncompressed block");
}
mode = DECODE_STORED;
}
goto case DECODE_STORED;/* fall through */
case DECODE_STORED:
{
int more = outputWindow.CopyStored(input, uncomprLen);
uncomprLen -= more;
if (uncomprLen == 0) {
mode = DECODE_BLOCKS;
return true;
}
return !input.IsNeedingInput;
}
case DECODE_DYN_HEADER:
if (!dynHeader.Decode(input)) {
return false;
}
litlenTree = dynHeader.BuildLitLenTree();
distTree = dynHeader.BuildDistTree();
mode = DECODE_HUFFMAN;
goto case DECODE_HUFFMAN; /* fall through */
case DECODE_HUFFMAN:
case DECODE_HUFFMAN_LENBITS:
case DECODE_HUFFMAN_DIST:
case DECODE_HUFFMAN_DISTBITS:
return DecodeHuffman();
case FINISHED:
return false;
default:
throw new FormatException();
}
}
/// <summary>
/// Sets the preset dictionary. This should only be called, if
/// needsDictionary() returns true and it should set the same
/// dictionary, that was used for deflating. The getAdler()
/// function returns the checksum of the dictionary needed.
/// </summary>
/// <param name="buffer">
/// the dictionary.
/// </param>
/// <exception cref="System.InvalidOperationException">
/// if no dictionary is needed.
/// </exception>
/// <exception cref="System.ArgumentException">
/// if the dictionary checksum is wrong.
/// </exception>
public void SetDictionary(byte[] buffer)
{
SetDictionary(buffer, 0, buffer.Length);
}
/// <summary>
/// Sets the preset dictionary. This should only be called, if
/// needsDictionary() returns true and it should set the same
/// dictionary, that was used for deflating. The getAdler()
/// function returns the checksum of the dictionary needed.
/// </summary>
/// <param name="buffer">
/// the dictionary.
/// </param>
/// <param name="off">
/// the offset into buffer where the dictionary starts.
/// </param>
/// <param name="len">
/// the length of the dictionary.
/// </param>
/// <exception cref="System.InvalidOperationException">
/// if no dictionary is needed.
/// </exception>
/// <exception cref="System.ArgumentException">
/// if the dictionary checksum is wrong.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// if the off and/or len are wrong.
/// </exception>
public void SetDictionary(byte[] buffer, int off, int len)
{
if (!IsNeedingDictionary) {
throw new InvalidOperationException();
}
adler.Update(buffer, off, len);
if ((int)adler.Value != readAdler) {
throw new ArgumentException("Wrong adler checksum");
}
adler.Reset();
outputWindow.CopyDict(buffer, off, len);
mode = DECODE_BLOCKS;
}
/// <summary>
/// Sets the input. This should only be called, if needsInput()
/// returns true.
/// </summary>
/// <param name="buf">
/// the input.
/// </param>
/// <exception cref="System.InvalidOperationException">
/// if no input is needed.
/// </exception>
public void SetInput(byte[] buf)
{
SetInput(buf, 0, buf.Length);
}
/// <summary>
/// Sets the input. This should only be called, if needsInput()
/// returns true.
/// </summary>
/// <param name="buf">
/// the input.
/// </param>
/// <param name="off">
/// the offset into buffer where the input starts.
/// </param>
/// <param name="len">
/// the length of the input.
/// </param>
/// <exception cref="System.InvalidOperationException">
/// if no input is needed.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// if the off and/or len are wrong.
/// </exception>
public void SetInput(byte[] buf, int off, int len)
{
input.SetInput(buf, off, len);
totalIn += len;
}
/// <summary>
/// Inflates the compressed stream to the output buffer. If this
/// returns 0, you should check, whether needsDictionary(),
/// needsInput() or finished() returns true, to determine why no
/// further output is produced.
/// </summary>
/// <param name = "buf">
/// the output buffer.
/// </param>
/// <returns>
/// the number of bytes written to the buffer, 0 if no further
/// output can be produced.
/// </returns>
/// <exception cref="System.ArgumentOutOfRangeException">
/// if buf has length 0.
/// </exception>
/// <exception cref="System.FormatException">
/// if deflated stream is invalid.
/// </exception>
public int Inflate(byte[] buf)
{
return Inflate(buf, 0, buf.Length);
}
/// <summary>
/// Inflates the compressed stream to the output buffer. If this
/// returns 0, you should check, whether needsDictionary(),
/// needsInput() or finished() returns true, to determine why no
/// further output is produced.
/// </summary>
/// <param name = "buf">
/// the output buffer.
/// </param>
/// <param name = "off">
/// the offset into buffer where the output should start.
/// </param>
/// <param name = "len">
/// the maximum length of the output.
/// </param>
/// <returns>
/// the number of bytes written to the buffer, 0 if no further output can be produced.
/// </returns>
/// <exception cref="System.ArgumentOutOfRangeException">
/// if len is &lt;= 0.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// if the off and/or len are wrong.
/// </exception>
/// <exception cref="System.FormatException">
/// if deflated stream is invalid.
/// </exception>
public int Inflate(byte[] buf, int off, int len)
{
if (len < 0) {
throw new ArgumentOutOfRangeException("len < 0");
}
// Special case: len may be zero
if (len == 0) {
if (IsFinished == false) {// -jr- 08-Nov-2003 INFLATE_BUG fix..
Decode();
}
return 0;
}
/* // Check for correct buff, off, len triple
if (off < 0 || off + len >= buf.Length) {
throw new ArgumentException("off/len outside buf bounds");
}*/
int count = 0;
int more;
do {
if (mode != DECODE_CHKSUM) {
/* Don't give away any output, if we are waiting for the
* checksum in the input stream.
*
* With this trick we have always:
* needsInput() and not finished()
* implies more output can be produced.
*/
more = outputWindow.CopyOutput(buf, off, len);
adler.Update(buf, off, more);
off += more;
count += more;
totalOut += more;
len -= more;
if (len == 0) {
return count;
}
}
} while (Decode() || (outputWindow.GetAvailable() > 0 && mode != DECODE_CHKSUM));
return count;
}
/// <summary>
/// Returns true, if the input buffer is empty.
/// You should then call setInput().
/// NOTE: This method also returns true when the stream is finished.
/// </summary>
public bool IsNeedingInput {
get {
return input.IsNeedingInput;
}
}
/// <summary>
/// Returns true, if a preset dictionary is needed to inflate the input.
/// </summary>
public bool IsNeedingDictionary {
get {
return mode == DECODE_DICT && neededBits == 0;
}
}
/// <summary>
/// Returns true, if the inflater has finished. This means, that no
/// input is needed and no output can be produced.
/// </summary>
public bool IsFinished {
get {
return mode == FINISHED && outputWindow.GetAvailable() == 0;
}
}
/// <summary>
/// Gets the adler checksum. This is either the checksum of all
/// uncompressed bytes returned by inflate(), or if needsDictionary()
/// returns true (and thus no output was yet produced) this is the
/// adler checksum of the expected dictionary.
/// </summary>
/// <returns>
/// the adler checksum.
/// </returns>
public int Adler {
get {
return IsNeedingDictionary ? readAdler : (int) adler.Value;
}
}
/// <summary>
/// Gets the total number of output bytes returned by inflate().
/// </summary>
/// <returns>
/// the total number of output bytes.
/// </returns>
public int TotalOut {
get {
return totalOut;
}
}
/// <summary>
/// Gets the total number of processed compressed input bytes.
/// </summary>
/// <returns>
/// the total number of bytes of processed input bytes.
/// </returns>
public int TotalIn {
get {
return totalIn - RemainingInput;
}
}
/// <summary>
/// Gets the number of unprocessed input. Useful, if the end of the
/// stream is reached and you want to further process the bytes after
/// the deflate stream.
/// </summary>
/// <returns>
/// the number of bytes of the input which were not processed.
/// </returns>
public int RemainingInput {
get {
return input.AvailableBytes;
}
}
}
}

View File

@@ -0,0 +1,207 @@
// InflaterDynHeader.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// 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
// of the License, 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
namespace ICSharpCode.SharpZipLib.Zip.Compression
{
class InflaterDynHeader
{
const int LNUM = 0;
const int DNUM = 1;
const int BLNUM = 2;
const int BLLENS = 3;
const int LENS = 4;
const int REPS = 5;
static readonly int[] repMin = { 3, 3, 11 };
static readonly int[] repBits = { 2, 3, 7 };
byte[] blLens;
byte[] litdistLens;
InflaterHuffmanTree blTree;
int mode;
int lnum, dnum, blnum, num;
int repSymbol;
byte lastLen;
int ptr;
static readonly int[] BL_ORDER =
{ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
public InflaterDynHeader()
{
}
public bool Decode(StreamManipulator input)
{
decode_loop:
for (;;) {
switch (mode) {
case LNUM:
lnum = input.PeekBits(5);
if (lnum < 0) {
return false;
}
lnum += 257;
input.DropBits(5);
// System.err.println("LNUM: "+lnum);
mode = DNUM;
goto case DNUM; // fall through
case DNUM:
dnum = input.PeekBits(5);
if (dnum < 0) {
return false;
}
dnum++;
input.DropBits(5);
// System.err.println("DNUM: "+dnum);
num = lnum+dnum;
litdistLens = new byte[num];
mode = BLNUM;
goto case BLNUM; // fall through
case BLNUM:
blnum = input.PeekBits(4);
if (blnum < 0) {
return false;
}
blnum += 4;
input.DropBits(4);
blLens = new byte[19];
ptr = 0;
// System.err.println("BLNUM: "+blnum);
mode = BLLENS;
goto case BLLENS; // fall through
case BLLENS:
while (ptr < blnum) {
int len = input.PeekBits(3);
if (len < 0) {
return false;
}
input.DropBits(3);
// System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len);
blLens[BL_ORDER[ptr]] = (byte) len;
ptr++;
}
blTree = new InflaterHuffmanTree(blLens);
blLens = null;
ptr = 0;
mode = LENS;
goto case LENS; // fall through
case LENS:
{
int symbol;
while (((symbol = blTree.GetSymbol(input)) & ~15) == 0) {
/* Normal case: symbol in [0..15] */
// System.err.println("litdistLens["+ptr+"]: "+symbol);
litdistLens[ptr++] = lastLen = (byte)symbol;
if (ptr == num) {
/* Finished */
return true;
}
}
/* need more input ? */
if (symbol < 0) {
return false;
}
/* otherwise repeat code */
if (symbol >= 17) {
/* repeat zero */
// System.err.println("repeating zero");
lastLen = 0;
} else {
if (ptr == 0) {
throw new Exception();
}
}
repSymbol = symbol-16;
}
mode = REPS;
goto case REPS; // fall through
case REPS:
{
int bits = repBits[repSymbol];
int count = input.PeekBits(bits);
if (count < 0) {
return false;
}
input.DropBits(bits);
count += repMin[repSymbol];
// System.err.println("litdistLens repeated: "+count);
if (ptr + count > num) {
throw new Exception();
}
while (count-- > 0) {
litdistLens[ptr++] = lastLen;
}
if (ptr == num) {
/* Finished */
return true;
}
}
mode = LENS;
goto decode_loop;
}
}
}
public InflaterHuffmanTree BuildLitLenTree()
{
byte[] litlenLens = new byte[lnum];
Array.Copy(litdistLens, 0, litlenLens, 0, lnum);
return new InflaterHuffmanTree(litlenLens);
}
public InflaterHuffmanTree BuildDistTree()
{
byte[] distLens = new byte[dnum];
Array.Copy(litdistLens, lnum, distLens, 0, dnum);
return new InflaterHuffmanTree(distLens);
}
}
}

View File

@@ -0,0 +1,213 @@
// InflaterHuffmanTree.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// 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
// of the License, 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
namespace ICSharpCode.SharpZipLib.Zip.Compression
{
public class InflaterHuffmanTree
{
private static int MAX_BITLEN = 15;
private short[] tree;
public static InflaterHuffmanTree defLitLenTree, defDistTree;
static InflaterHuffmanTree()
{
try {
byte[] codeLengths = new byte[288];
int i = 0;
while (i < 144) {
codeLengths[i++] = 8;
}
while (i < 256) {
codeLengths[i++] = 9;
}
while (i < 280) {
codeLengths[i++] = 7;
}
while (i < 288) {
codeLengths[i++] = 8;
}
defLitLenTree = new InflaterHuffmanTree(codeLengths);
codeLengths = new byte[32];
i = 0;
while (i < 32) {
codeLengths[i++] = 5;
}
defDistTree = new InflaterHuffmanTree(codeLengths);
} catch (Exception) {
throw new ApplicationException("InflaterHuffmanTree: static tree length illegal");
}
}
/// <summary>
/// Constructs a Huffman tree from the array of code lengths.
/// </summary>
/// <param name = "codeLengths">
/// the array of code lengths
/// </param>
public InflaterHuffmanTree(byte[] codeLengths)
{
BuildTree(codeLengths);
}
private void BuildTree(byte[] codeLengths)
{
int[] blCount = new int[MAX_BITLEN + 1];
int[] nextCode = new int[MAX_BITLEN + 1];
for (int i = 0; i < codeLengths.Length; i++) {
int bits = codeLengths[i];
if (bits > 0) {
blCount[bits]++;
}
}
int code = 0;
int treeSize = 512;
for (int bits = 1; bits <= MAX_BITLEN; bits++) {
nextCode[bits] = code;
code += blCount[bits] << (16 - bits);
if (bits >= 10) {
/* We need an extra table for bit lengths >= 10. */
int start = nextCode[bits] & 0x1ff80;
int end = code & 0x1ff80;
treeSize += (end - start) >> (16 - bits);
}
}
/* -jr comment this out! doesnt work for dynamic trees and pkzip 2.04g
if (code != 65536)
{
throw new Exception("Code lengths don't add up properly.");
}
*/
/* Now create and fill the extra tables from longest to shortest
* bit len. This way the sub trees will be aligned.
*/
tree = new short[treeSize];
int treePtr = 512;
for (int bits = MAX_BITLEN; bits >= 10; bits--) {
int end = code & 0x1ff80;
code -= blCount[bits] << (16 - bits);
int start = code & 0x1ff80;
for (int i = start; i < end; i += 1 << 7) {
tree[DeflaterHuffman.BitReverse(i)] = (short) ((-treePtr << 4) | bits);
treePtr += 1 << (bits-9);
}
}
for (int i = 0; i < codeLengths.Length; i++) {
int bits = codeLengths[i];
if (bits == 0) {
continue;
}
code = nextCode[bits];
int revcode = DeflaterHuffman.BitReverse(code);
if (bits <= 9) {
do {
tree[revcode] = (short) ((i << 4) | bits);
revcode += 1 << bits;
} while (revcode < 512);
} else {
int subTree = tree[revcode & 511];
int treeLen = 1 << (subTree & 15);
subTree = -(subTree >> 4);
do {
tree[subTree | (revcode >> 9)] = (short) ((i << 4) | bits);
revcode += 1 << bits;
} while (revcode < treeLen);
}
nextCode[bits] = code + (1 << (16 - bits));
}
}
/// <summary>
/// Reads the next symbol from input. The symbol is encoded using the
/// huffman tree.
/// </summary>
/// <param name="input">
/// input the input source.
/// </param>
/// <returns>
/// the next symbol, or -1 if not enough input is available.
/// </returns>
public int GetSymbol(StreamManipulator input)
{
int lookahead, symbol;
if ((lookahead = input.PeekBits(9)) >= 0) {
if ((symbol = tree[lookahead]) >= 0) {
input.DropBits(symbol & 15);
return symbol >> 4;
}
int subtree = -(symbol >> 4);
int bitlen = symbol & 15;
if ((lookahead = input.PeekBits(bitlen)) >= 0) {
symbol = tree[subtree | (lookahead >> 9)];
input.DropBits(symbol & 15);
return symbol >> 4;
} else {
int bits = input.AvailableBits;
lookahead = input.PeekBits(bits);
symbol = tree[subtree | (lookahead >> 9)];
if ((symbol & 15) <= bits) {
input.DropBits(symbol & 15);
return symbol >> 4;
} else {
return -1;
}
}
} else {
int bits = input.AvailableBits;
lookahead = input.PeekBits(bits);
symbol = tree[lookahead];
if (symbol >= 0 && (symbol & 15) <= bits) {
input.DropBits(symbol & 15);
return symbol >> 4;
} else {
return -1;
}
}
}
}
}

View File

@@ -0,0 +1,210 @@
// PendingBuffer.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// 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
// of the License, 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
namespace ICSharpCode.SharpZipLib.Zip.Compression
{
/// <summary>
/// This class is general purpose class for writing data to a buffer.
///
/// It allows you to write bits as well as bytes
/// Based on DeflaterPending.java
///
/// author of the original java version : Jochen Hoenicke
/// </summary>
public class PendingBuffer
{
protected byte[] buf;
int start;
int end;
uint bits;
int bitCount;
public PendingBuffer() : this( 4096 )
{
}
public PendingBuffer(int bufsize)
{
buf = new byte[bufsize];
}
public void Reset()
{
start = end = bitCount = 0;
}
public void WriteByte(int b)
{
if (DeflaterConstants.DEBUGGING && start != 0) {
throw new Exception();
}
buf[end++] = (byte) b;
}
public void WriteShort(int s)
{
if (DeflaterConstants.DEBUGGING && start != 0) {
throw new Exception();
}
buf[end++] = (byte) s;
buf[end++] = (byte) (s >> 8);
}
public void WriteInt(int s)
{
if (DeflaterConstants.DEBUGGING && start != 0) {
throw new Exception();
}
buf[end++] = (byte) s;
buf[end++] = (byte) (s >> 8);
buf[end++] = (byte) (s >> 16);
buf[end++] = (byte) (s >> 24);
}
public void WriteBlock(byte[] block, int offset, int len)
{
if (DeflaterConstants.DEBUGGING && start != 0) {
throw new Exception();
}
System.Array.Copy(block, offset, buf, end, len);
end += len;
}
public int BitCount {
get {
return bitCount;
}
}
public void AlignToByte()
{
if (DeflaterConstants.DEBUGGING && start != 0) {
throw new Exception();
}
if (bitCount > 0) {
buf[end++] = (byte) bits;
if (bitCount > 8) {
buf[end++] = (byte) (bits >> 8);
}
}
bits = 0;
bitCount = 0;
}
public void WriteBits(int b, int count)
{
if (DeflaterConstants.DEBUGGING && start != 0) {
throw new Exception();
}
// if (DeflaterConstants.DEBUGGING) {
// //Console.WriteLine("writeBits("+b+","+count+")");
// }
bits |= (uint)(b << bitCount);
bitCount += count;
if (bitCount >= 16) {
buf[end++] = (byte) bits;
buf[end++] = (byte) (bits >> 8);
bits >>= 16;
bitCount -= 16;
}
}
public void WriteShortMSB(int s)
{
if (DeflaterConstants.DEBUGGING && start != 0) {
throw new Exception();
}
buf[end++] = (byte) (s >> 8);
buf[end++] = (byte) s;
}
public bool IsFlushed {
get {
return end == 0;
}
}
/// <summary>
/// Flushes the pending buffer into the given output array. If the
/// output array is to small, only a partial flush is done.
/// </summary>
/// <param name="output">
/// the output array;
/// </param>
/// <param name="offset">
/// the offset into output array;
/// </param>
/// <param name="length">
/// length the maximum number of bytes to store;
/// </param>
/// <exception name="ArgumentOutOfRangeException">
/// IndexOutOfBoundsException if offset or length are invalid.
/// </exception>
public int Flush(byte[] output, int offset, int length)
{
if (bitCount >= 8) {
buf[end++] = (byte) bits;
bits >>= 8;
bitCount -= 8;
}
if (length > end - start) {
length = end - start;
System.Array.Copy(buf, start, output, offset, length);
start = 0;
end = 0;
} else {
System.Array.Copy(buf, start, output, offset, length);
start += length;
}
return length;
}
public byte[] ToByteArray()
{
byte[] ret = new byte[end - start];
System.Array.Copy(buf, start, ret, 0, ret.Length);
start = 0;
end = 0;
return ret;
}
}
}

View File

@@ -0,0 +1,379 @@
// DeflaterOutputStream.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// 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
// of the License, 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
using System.IO;
using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Zip.Compression;
namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
{
/// <summary>
/// This is a special FilterOutputStream deflating the bytes that are
/// written through it. It uses the Deflater for deflating.
///
/// authors of the original java version : Tom Tromey, Jochen Hoenicke
/// </summary>
public class DeflaterOutputStream : Stream
{
/// <summary>
/// This buffer is used temporarily to retrieve the bytes from the
/// deflater and write them to the underlying output stream.
/// </summary>
protected byte[] buf;
/// <summary>
/// The deflater which is used to deflate the stream.
/// </summary>
protected Deflater def;
/// <summary>
/// base stream the deflater depends on.
/// </summary>
protected Stream baseOutputStream;
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override bool CanRead {
get {
return baseOutputStream.CanRead;
}
}
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override bool CanSeek {
get {
return false;
// return baseOutputStream.CanSeek;
}
}
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override bool CanWrite {
get {
return baseOutputStream.CanWrite;
}
}
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override long Length {
get {
return baseOutputStream.Length;
}
}
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override long Position {
get {
return baseOutputStream.Position;
}
set {
baseOutputStream.Position = value;
}
}
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException("Seek not supported"); // -jr- 01-Dec-2003
// return baseOutputStream.Seek(offset, origin);
}
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override void SetLength(long val)
{
baseOutputStream.SetLength(val);
}
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override int ReadByte()
{
return baseOutputStream.ReadByte();
}
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override int Read(byte[] b, int off, int len)
{
return baseOutputStream.Read(b, off, len);
}
// -jr- 01-Dec-2003
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
throw new NotSupportedException("Asynch read not currently supported");
}
// -jr- 01-Dec-2003
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
throw new NotSupportedException("Asynch write not currently supported");
}
/// <summary>
/// Deflates everything in the def's input buffers. This will call
/// <code>def.deflate()</code> until all bytes from the input buffers
/// are processed.
/// </summary>
protected void Deflate()
{
while (!def.IsNeedingInput) {
int len = def.Deflate(buf, 0, buf.Length);
// System.err.println("DOS deflated " + len + " baseOutputStream of " + buf.length);
if (len <= 0) {
break;
}
baseOutputStream.Write(buf, 0, len);
}
if (!def.IsNeedingInput) {
throw new ApplicationException("Can't deflate all input?");
}
}
/// <summary>
/// Creates a new DeflaterOutputStream with a default Deflater and default buffer size.
/// </summary>
/// <param name="baseOutputStream">
/// the output stream where deflated output should be written.
/// </param>
public DeflaterOutputStream(Stream baseOutputStream) : this(baseOutputStream, new Deflater(), 512)
{
}
/// <summary>
/// Creates a new DeflaterOutputStream with the given Deflater and
/// default buffer size.
/// </summary>
/// <param name="baseOutputStream">
/// the output stream where deflated output should be written.
/// </param>
/// <param name="defl">
/// the underlying deflater.
/// </param>
public DeflaterOutputStream(Stream baseOutputStream, Deflater defl) :this(baseOutputStream, defl, 512)
{
}
/// <summary>
/// Creates a new DeflaterOutputStream with the given Deflater and
/// buffer size.
/// </summary>
/// <param name="baseOutputStream">
/// the output stream where deflated output should be written.
/// </param>
/// <param name="defl">
/// the underlying deflater.
/// </param>
/// <param name="bufsize">
/// the buffer size.
/// </param>
/// <exception cref="System.InvalidOperationException">
/// if bufsize isn't positive.
/// </exception>
public DeflaterOutputStream(Stream baseOutputStream, Deflater defl, int bufsize)
{
this.baseOutputStream = baseOutputStream;
if (bufsize <= 0) {
throw new InvalidOperationException("bufsize <= 0");
}
buf = new byte[bufsize];
def = defl;
}
/// <summary>
/// Flushes the stream by calling flush() on the deflater and then
/// on the underlying stream. This ensures that all bytes are
/// flushed.
/// </summary>
public override void Flush()
{
def.Flush();
Deflate();
baseOutputStream.Flush();
}
/// <summary>
/// Finishes the stream by calling finish() on the deflater.
/// </summary>
public virtual void Finish()
{
def.Finish();
while (!def.IsFinished) {
int len = def.Deflate(buf, 0, buf.Length);
if (len <= 0) {
break;
}
// kidnthrain encryption alteration
if (this.Password != null) {
// plain data has been deflated. Now encrypt result
this.EncryptBlock(buf, 0, len);
}
baseOutputStream.Write(buf, 0, len);
}
if (!def.IsFinished) {
throw new ApplicationException("Can't deflate all input?");
}
baseOutputStream.Flush();
}
/// <summary>
/// Calls finish () and closes the stream.
/// </summary>
public override void Close()
{
Finish();
baseOutputStream.Close();
}
/// <summary>
/// Writes a single byte to the compressed output stream.
/// </summary>
/// <param name="bval">
/// the byte value.
/// </param>
public override void WriteByte(byte bval)
{
byte[] b = new byte[1];
b[0] = (byte) bval;
Write(b, 0, 1);
}
/// <summary>
/// Writes a len bytes from an array to the compressed stream.
/// </summary>
/// <param name="buf">
/// the byte array.
/// </param>
/// <param name="off">
/// the offset into the byte array where to start.
/// </param>
/// <param name="len">
/// the number of bytes to write.
/// </param>
public override void Write(byte[] buf, int off, int len)
{
// System.err.println("DOS with off " + off + " and len " + len);
def.SetInput(buf, off, len);
Deflate();
}
#region Encryption
string password = null;
uint[] keys = null;
public string Password {
get {
return password;
}
set {
password = value;
}
}
//The beauty of xor-ing bits is that
//plain ^ key = enc
//and enc ^ key = plain
//accordingly, this is the exact same as the decrypt byte
//function in InflaterInputStream
protected byte EncryptByte()
{
uint temp = ((keys[2] & 0xFFFF) | 2);
return (byte)((temp * (temp ^ 1)) >> 8);
}
/// <summary>
/// Takes a buffer of data and uses the keys
/// that have been previously initialized from a
/// password and then updated via a random encryption header
/// to encrypt that data
/// </summary>
protected void EncryptBlock(byte[] buf, int off, int len)
{
for (int i = off; i < off + len; ++i) {
byte oldbyte = buf[i];
buf[i] ^= EncryptByte();
UpdateKeys(oldbyte);
}
}
/// <summary>
/// Initializes our encryption keys using a given password
/// </summary>
protected void InitializePassword(string password) {
keys = new uint[] {
0x12345678,
0x23456789,
0x34567890
};
for (int i = 0; i < password.Length; ++i) {
UpdateKeys((byte)password[i]);
}
}
protected void UpdateKeys(byte ch)
{
keys[0] = Crc32.ComputeCrc32(keys[0], ch);
keys[1] = keys[1] + (byte)keys[0];
keys[1] = keys[1] * 134775813 + 1;
keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
}
#endregion
}
}

View File

@@ -0,0 +1,386 @@
// InflaterInputStream.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// 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
// of the License, 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
using System.IO;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Checksums;
namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
{
/// <summary>
/// This filter stream is used to decompress data compressed baseInputStream the "deflate"
/// format. The "deflate" format is described baseInputStream RFC 1951.
///
/// This stream may form the basis for other decompression filters, such
/// as the <code>GzipInputStream</code>.
///
/// author of the original java version : John Leuner
/// </summary>
public class InflaterInputStream : Stream
{
//Variables
/// <summary>
/// Decompressor for this filter
/// </summary>
protected Inflater inf;
/// <summary>
/// Byte array used as a buffer
/// </summary>
protected byte[] buf;
/// <summary>
/// Size of buffer
/// </summary>
protected int len;
//We just use this if we are decoding one byte at a time with the read() call
private byte[] onebytebuffer = new byte[1];
/// <summary>
/// base stream the inflater depends on.
/// </summary>
protected Stream baseInputStream;
protected long csize;
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override bool CanRead {
get {
return baseInputStream.CanRead;
}
}
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override bool CanSeek {
get {
return false;
// return baseInputStream.CanSeek;
}
}
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override bool CanWrite {
get {
return baseInputStream.CanWrite;
}
}
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override long Length {
get {
return len;
}
}
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override long Position {
get {
return baseInputStream.Position;
}
set {
baseInputStream.Position = value;
}
}
/// <summary>
/// Flushes the baseInputStream
/// </summary>
public override void Flush()
{
baseInputStream.Flush();
}
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException("Seek not supported"); // -jr- 01-Dec-2003
}
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override void SetLength(long val)
{
baseInputStream.SetLength(val);
}
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override void Write(byte[] array, int offset, int count)
{
baseInputStream.Write(array, offset, count);
}
/// <summary>
/// I needed to implement the abstract member.
/// </summary>
public override void WriteByte(byte val)
{
baseInputStream.WriteByte(val);
}
// -jr- 01-Dec-2003 This may be flawed for some base streams? Depends on implementation of BeginWrite
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
throw new NotSupportedException("Asynch write not currently supported");
}
//Constructors
/// <summary>
/// Create an InflaterInputStream with the default decompresseor
/// and a default buffer size.
/// </summary>
/// <param name = "baseInputStream">
/// the InputStream to read bytes from
/// </param>
public InflaterInputStream(Stream baseInputStream) : this(baseInputStream, new Inflater(), 4096)
{
}
/// <summary>
/// Create an InflaterInputStream with the specified decompresseor
/// and a default buffer size.
/// </summary>
/// <param name = "baseInputStream">
/// the InputStream to read bytes from
/// </param>
/// <param name = "inf">
/// the decompressor used to decompress data read from baseInputStream
/// </param>
public InflaterInputStream(Stream baseInputStream, Inflater inf) : this(baseInputStream, inf, 4096)
{
}
/// <summary>
/// Create an InflaterInputStream with the specified decompresseor
/// and a specified buffer size.
/// </summary>
/// <param name = "baseInputStream">
/// the InputStream to read bytes from
/// </param>
/// <param name = "inf">
/// the decompressor used to decompress data read from baseInputStream
/// </param>
/// <param name = "size">
/// size of the buffer to use
/// </param>
public InflaterInputStream(Stream baseInputStream, Inflater inf, int size)
{
this.baseInputStream = baseInputStream;
this.inf = inf;
try {
this.len = (int)baseInputStream.Length;
} catch (Exception) {
// the stream may not support .Length
this.len = 0;
}
if (size <= 0) {
throw new ArgumentOutOfRangeException("size <= 0");
}
buf = new byte[size]; //Create the buffer
}
//Methods
/// <summary>
/// Returns 0 once the end of the stream (EOF) has been reached.
/// Otherwise returns 1.
/// </summary>
public virtual int Available {
get {
return inf.IsFinished ? 0 : 1;
}
}
/// <summary>
/// Closes the input stream
/// </summary>
public override void Close()
{
baseInputStream.Close();
}
/// <summary>
/// Fills the buffer with more data to decompress.
/// </summary>
protected void Fill()
{
len = baseInputStream.Read(buf, 0, buf.Length);
// decrypting crypted data
if (cryptbuffer != null) {
DecryptBlock(buf, 0, System.Math.Min((int)(csize - inf.TotalIn), buf.Length));
}
if (len <= 0) {
throw new ApplicationException("Deflated stream ends early.");
}
inf.SetInput(buf, 0, len);
}
/// <summary>
/// Reads one byte of decompressed data.
///
/// The byte is baseInputStream the lower 8 bits of the int.
/// </summary>
public override int ReadByte()
{
int nread = Read(onebytebuffer, 0, 1); //read one byte
if (nread > 0) {
return onebytebuffer[0] & 0xff;
}
return -1; // ok
}
/// <summary>
/// Decompresses data into the byte array
/// </summary>
/// <param name ="b">
/// the array to read and decompress data into
/// </param>
/// <param name ="off">
/// the offset indicating where the data should be placed
/// </param>
/// <param name ="len">
/// the number of bytes to decompress
/// </param>
public override int Read(byte[] b, int off, int len)
{
for (;;) {
int count;
try {
count = inf.Inflate(b, off, len);
} catch (Exception e) {
throw new ZipException(e.ToString());
}
if (count > 0) {
return count;
}
if (inf.IsNeedingDictionary) {
throw new ZipException("Need a dictionary");
} else if (inf.IsFinished) {
return 0;
} else if (inf.IsNeedingInput) {
Fill();
} else {
throw new InvalidOperationException("Don't know what to do");
}
}
}
/// <summary>
/// Skip specified number of bytes of uncompressed data
/// </summary>
/// <param name ="n">
/// number of bytes to skip
/// </param>
public long Skip(long n)
{
if (n < 0) {
throw new ArgumentOutOfRangeException("n");
}
int len = 2048;
if (n < len) {
len = (int) n;
}
byte[] tmp = new byte[len];
return (long)baseInputStream.Read(tmp, 0, tmp.Length);
}
#region Encryption stuff
protected byte[] cryptbuffer = null;
uint[] keys = null;
protected byte DecryptByte()
{
uint temp = ((keys[2] & 0xFFFF) | 2);
return (byte)((temp * (temp ^ 1)) >> 8);
}
protected void DecryptBlock(byte[] buf, int off, int len)
{
for (int i = off; i < off + len; ++i) {
buf[i] ^= DecryptByte();
UpdateKeys(buf[i]);
}
}
protected void InitializePassword(string password)
{
keys = new uint[] {
0x12345678,
0x23456789,
0x34567890
};
for (int i = 0; i < password.Length; ++i) {
UpdateKeys((byte)password[i]);
}
}
protected void UpdateKeys(byte ch)
{
keys[0] = Crc32.ComputeCrc32(keys[0], ch);
keys[1] = keys[1] + (byte)keys[0];
keys[1] = keys[1] * 134775813 + 1;
keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
}
#endregion
}
}

View File

@@ -0,0 +1,176 @@
// OutputWindow.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// 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
// of the License, 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
{
/// <summary>
/// Contains the output from the Inflation process.
/// We need to have a window so that we can refer backwards into the output stream
/// to repeat stuff.
///
/// author of the original java version : John Leuner
/// </summary>
public class OutputWindow
{
private static int WINDOW_SIZE = 1 << 15;
private static int WINDOW_MASK = WINDOW_SIZE - 1;
private byte[] window = new byte[WINDOW_SIZE]; //The window is 2^15 bytes
private int windowEnd = 0;
private int windowFilled = 0;
public void Write(int abyte)
{
if (windowFilled++ == WINDOW_SIZE) {
throw new InvalidOperationException("Window full");
}
window[windowEnd++] = (byte) abyte;
windowEnd &= WINDOW_MASK;
}
private void SlowRepeat(int repStart, int len, int dist)
{
while (len-- > 0) {
window[windowEnd++] = window[repStart++];
windowEnd &= WINDOW_MASK;
repStart &= WINDOW_MASK;
}
}
public void Repeat(int len, int dist)
{
if ((windowFilled += len) > WINDOW_SIZE) {
throw new InvalidOperationException("Window full");
}
int rep_start = (windowEnd - dist) & WINDOW_MASK;
int border = WINDOW_SIZE - len;
if (rep_start <= border && windowEnd < border) {
if (len <= dist) {
System.Array.Copy(window, rep_start, window, windowEnd, len);
windowEnd += len;
} else {
/* We have to copy manually, since the repeat pattern overlaps.
*/
while (len-- > 0) {
window[windowEnd++] = window[rep_start++];
}
}
} else {
SlowRepeat(rep_start, len, dist);
}
}
public int CopyStored(StreamManipulator input, int len)
{
len = Math.Min(Math.Min(len, WINDOW_SIZE - windowFilled), input.AvailableBytes);
int copied;
int tailLen = WINDOW_SIZE - windowEnd;
if (len > tailLen) {
copied = input.CopyBytes(window, windowEnd, tailLen);
if (copied == tailLen) {
copied += input.CopyBytes(window, 0, len - tailLen);
}
} else {
copied = input.CopyBytes(window, windowEnd, len);
}
windowEnd = (windowEnd + copied) & WINDOW_MASK;
windowFilled += copied;
return copied;
}
public void CopyDict(byte[] dict, int offset, int len)
{
if (windowFilled > 0) {
throw new InvalidOperationException();
}
if (len > WINDOW_SIZE) {
offset += len - WINDOW_SIZE;
len = WINDOW_SIZE;
}
System.Array.Copy(dict, offset, window, 0, len);
windowEnd = len & WINDOW_MASK;
}
public int GetFreeSpace()
{
return WINDOW_SIZE - windowFilled;
}
public int GetAvailable()
{
return windowFilled;
}
public int CopyOutput(byte[] output, int offset, int len)
{
int copy_end = windowEnd;
if (len > windowFilled) {
len = windowFilled;
} else {
copy_end = (windowEnd - windowFilled + len) & WINDOW_MASK;
}
int copied = len;
int tailLen = len - copy_end;
if (tailLen > 0) {
System.Array.Copy(window, WINDOW_SIZE - tailLen, output, offset, tailLen);
offset += tailLen;
len = copy_end;
}
System.Array.Copy(window, copy_end - len, output, offset, len);
windowFilled -= copied;
if (windowFilled < 0) {
throw new InvalidOperationException();
}
return copied;
}
public void Reset()
{
windowFilled = windowEnd = 0;
}
}
}

Some files were not shown because too many files have changed in this diff Show More