/// /
/* demht.cpp DEV-CPP4.9 gcc下通过
base64编码,将3字节,24位数据,每6位一取(0-63范围),组成4字节数据,查表得到映射符号。
如果无3字节,添加映射为‘='
base64解码,将4字节符号取出,查表得到相应4字节数据,重组运算为3字节数据。 */
/* MHT文件大体结构,以"----XXXXXXX"分割为许多部分
编码分为base64和普通文本两种格式。用CBase64类解码出。
其普通文本中,非字符全部用字节=HEX码表示,解码时hex2c反解出来。 网上有很多Base64例子都不能正常执行,所以自己写了个。写得有些乱,没有优化过:P */
/// /
#include < cstdlib >
#include < iostream >
#include < string >
#include < fstream >
#include < vector >
using namespace std;
typedef vector < unsigned char > BufArray;
char hex2c( char hex[ 2 ])
{
char * table = " 0123456789ABCDEF " ;
int hi = 0 ;
int low = 0 ;
while (table[hi] != hex[ 0 ])
{
hi ++ ;
};
while (table[low] != hex[ 1 ])
{
low ++ ;
};
char ret = ( char )((hi << 4 ) | low);
return ret;
};
class CBase64
{
char * baseTable;
public :
CBase64()
{
baseTable =
" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghzijklmnopqrstuvwxyz0123456789+/= " ;
};
~ CBase64()
{
};
private :
void encode(unsigned char in [ 3 ], unsigned char out [ 4 ], int valid)
{
int pc[ 4 ] =
{
0 , 0 , 0 , 0
};
int zero = 0 ;
if (valid == 3 )
{
pc[ 0 ] = ( in [ 0 ] >> 2 ) & 0x3f ;
pc[ 1 ] = (( in [ 0 ] << 4 ) | ( in [ 1 ] >> 4 )) & 0x3f ;
pc[ 2 ] = (( in [ 1 ] << 2 ) | ( in [ 2 ] >> 6 )) & 0x3f ;
pc[ 3 ] = in [ 2 ] & 0x3f ;
}
else if (valid == 2 )
{
pc[ 0 ] = ( in [ 0 ] >> 2 ) & 0x3f ;
pc[ 1 ] = (( in [ 0 ] << 4 ) | ( in [ 1 ] >> 4 )) & 0x3f ;
pc[ 2 ] = (( in [ 1 ] << 2 ) | (zero >> 6 )) & 0x3f ;
pc[ 3 ] = 64 ;
}
else if (valid == 1 )
{
pc[ 0 ] = ( in [ 0 ] >> 2 ) & 0x3f ;
pc[ 1 ] = (( in [ 0 ] << 4 ) | (zero >> 4 )) & 0x3f ;
pc[ 2 ] = 64 ;
pc[ 3 ] = 64 ;
};
out [ 0 ] = baseTable[pc[ 0 ]];
out [ 1 ] = baseTable[pc[ 1 ]];
out [ 2 ] = baseTable[pc[ 2 ]];
out [ 3 ] = baseTable[pc[ 3 ]];
};
int decode(unsigned char in [ 4 ], unsigned char out [ 3 ])
{
int ret;
if ( in [ 2 ] == ' = ' )
{
ret = 1 ;
}
else if ( in [ 3 ] == ' = ' )
{
ret = 2 ;
}
else
{
ret = 3 ;
};
int pc[ 4 ] =
{
0 , 0 , 0 , 0
};
if (ret == 3 )
{
pc[ 0 ] = getpos( in [ 0 ]);
pc[ 1 ] = getpos( in [ 1 ]);
pc[ 2 ] = getpos( in [ 2 ]);
pc[ 3 ] = getpos( in [ 3 ]);
}
else if (ret == 2 )
{
pc[ 0 ] = getpos( in [ 0 ]);
pc[ 1 ] = getpos( in [ 1 ]);
pc[ 2 ] = getpos( in [ 2 ]);
}
else
{
pc[ 0 ] = getpos( in [ 0 ]);
pc[ 1 ] = getpos( in [ 1 ]);
};
out [ 0 ] = ((pc[ 0 ] << 2 ) | (pc[ 1 ] >> 4 ));
out [ 1 ] = ((pc[ 1 ] << 4 ) | (pc[ 2 ] >> 2 ));
out [ 2 ] = ((pc[ 2 ] << 6 ) | pc[ 3 ]);
return ret;
};
int getpos(unsigned char c)
{
int ret = 0 ;
while (c != baseTable[ret])
{
ret ++ ;
};
return ret;
};
public :
// 基本编码方法,注意使用后测试out并delete
int bin2base64(unsigned char * data, int len, unsigned char * & out )
{
int baselen;
int cycle;
if (len % 3 == 0 )
{
baselen = len / 3 * 4 ;
cycle = len / 3 ;
}
else
{
baselen = (len / 3 + 1 ) * 4 ;
cycle = (len / 3 + 1 );
};
if (baselen != 0 )
{
out = new unsigned char [baselen + 1 ];
int offd = 0 ;
int offo = 0 ;
for ( int i = 0 ; i < cycle - 1 ; i ++ , offd += 3 , offo += 4 )
{
encode((data + offd), ( out + offo), 3 );
};
if (len % 3 )
{
encode((data + offd), ( out + offo), len % 3 );
}
else
{
encode((data + offd), ( out + offo), 3 );
};
};
return baselen;
};
// 基本解码方法,注意使用后测试out并delete
int base642bin(unsigned char * data, int len, unsigned char * & out )
{
// 必然为4的倍数否则是有错的。
if (len % 4 != 0 )
{
cout << " Error Base64 Code's Len " << endl;
return 0 ;
};
int binlen = 0 ;
int cycle = len / 4 ;
out = new unsigned char [cycle * 3 ];
int offb = 0 ;
int offo = 0 ;
int n;
for ( int i = 0 ; i < cycle; i ++ , offo += 3 , offb += 4 )
{
n = decode((data + offb), ( out + offo));
binlen += n;
};
return binlen;
};
// 编码文件
void Base64( const char * infile, const char * outfile)
{
ifstream inf(infile, ios:: in | ios::binary);
if (inf.fail())
{
cout << " Error Open infile " << endl;
exit( 1 );
};
ofstream outf(outfile, ios:: out );
if (outf.fail())
{
cout << " Error Open outfile " << endl;
exit( 1 );
};
BufArray buf;
char c[ 1 ];
while ( ! inf.eof())
{
inf.read(c, 1 ); // 测试一下很有必要!
if (inf.good())
{
buf.push_back(c[ 0 ]);
}
};
int size = buf.size();
if (size)
{
unsigned char * bindata = new unsigned char [size];
for ( int i = 0 ; i < size; i ++ )
{
bindata[i] = buf[i];
};
unsigned char * strout = 0 ;
int strlen = bin2base64(bindata, size, strout);
char * ms =
" Content-Type: .../... Content-Transfer-Encoding: base64 Content-Location: ... " ;
char * rets = " " ;
outf.write(ms, 79 );
int linesize = 72 ;
int off = 0 ;
while (strlen >= linesize)
{
strlen -= linesize;
outf.write(( const char * )strout + off, linesize);
outf.write(rets, 1 );
off += linesize;
};
outf.write(( const char * )strout + off, strlen);
outf.write(rets, 1 );
if (strout)
{
delete []strout;
}
delete []bindata;
};
inf.close();
outf.close();
};
// 解码文件
void GetFile( const char * infile, const char * outfile)
{
ifstream inf(infile, ios:: in );
if (inf.fail())
{
cout << " Error Open infile " << endl;
exit( 1 );
};
ofstream outf(outfile, ios:: out | ios::binary);
if (outf.fail())
{
cout << " Error Open outfile " << outfile << endl;
exit( 1 );
};
const int size = 1024 * 8 ;
char str[size];
int * pstart = ( int * ) & str[ 0 ];
* pstart = 0 ;
string s = "" ;
string temp;
while ( ! inf.eof())
{
inf.getline(str, size);
temp = str;
if (temp != "" )
{
if (temp.find( " - " ) != temp.npos){}
else
{
s += temp;
};
};
};
if (s != "" )
{
unsigned char * outb = 0 ;
int len = base642bin((unsigned char * )s.c_str(), s.length(), outb);
if (len > 0 )
{
outf.write(( const char * )outb, len);
}
if (outb)
{
delete []outb;
}
}
else
{
cout << " some error in infile " << endl;
inf.close();
outf.close();
exit( 1 );
};
inf.close();
outf.close();
};
};
int main( int argc, char * argv[])
{
if (argc == 2 )
{
if (argv[ 1 ][ 0 ] == ' - ' || argv[ 1 ][ 0 ] == ' / ' )
{
goto USEAGE;
}
ifstream inf(argv[ 1 ], ios:: in );
if (inf.fail())
{
cout << " 不能打开文件 " << argv[ 1 ] << endl;
exit( 1 );
};
const int linelen = 1024 * 32 ;
char * buf = new char [linelen];
string basemark = " Content-Transfer-Encoding: base64 " ;
string basefilemark = " Content-Location: file:/// " ;
string filemark = " Content-Location: file:// " ;
string httpmark = " Content-Location: http:// " ;
string tempfile = " C:/tmp.b64 " ;
string partmark = " --- " ;
string filetowrite = "" ;
string strbuf = "" ;
string strtemp = "" ;
bool basestart = false ;
bool normalstart = false ;
// 按行处理,直至文件结束。
while ( ! inf.eof())
{
inf.getline(buf, linelen); // 收集一行数据
if (inf.good())
{
strtemp = buf;
}
if (strtemp != "" )
{
if ( ! basestart && ! normalstart)
{
if (strtemp.find(basemark) != strtemp.npos)
{
basestart = true ;
cout << " base64start " << endl;
};
if ( ! normalstart)
{
if (strtemp.find(filemark) != strtemp.npos || strtemp.find(httpmark)
!= strtemp.npos)
{
cout << " normalstart " << endl;
// 分析写出解码文件地址
if (strtemp.find(basefilemark) != strtemp.npos)
{
filetowrite = strtemp.substr(basefilemark.length(),
(strtemp.length() - basefilemark.length()));
while (filetowrite.find( " / " ) != filetowrite.npos)
{
filetowrite.replace(filetowrite.find( " / " ), 1 , " / " );
};
}
else if (strtemp.find(httpmark) != strtemp.npos)
{
filetowrite = strtemp.substr(httpmark.length(), (strtemp.length
() - httpmark.length()));
filetowrite = " C:/demht/ " + filetowrite;
while (filetowrite.find( " / " ) != filetowrite.npos)
{
filetowrite.replace(filetowrite.find( " / " ), 1 , " / " );
};
filetowrite = filetowrite.substr( 0 , filetowrite.find_first_of(
" ? " ));
}
else
{
filetowrite = strtemp.substr(filemark.length(), (strtemp.length
() - filemark.length()));
};
normalstart = true ;
inf.getline(buf, linelen);
inf.getline(buf, linelen);
// 直接取得正文第一行
strtemp = buf;
};
};
};
};
if (basestart)
// 在Base64编码的解码处理内。
{
if (filetowrite == "" )
{
if (strtemp.find(filemark) != strtemp.npos || strtemp.find(httpmark)
!= strtemp.npos)
{
// 分析写出解码文件地址
if (strtemp.find(basefilemark) != strtemp.npos)
{
filetowrite = strtemp.substr(basefilemark.length(),
(strtemp.length() - basefilemark.length()));
while (filetowrite.find( " / " ) != filetowrite.npos)
{
filetowrite.replace(filetowrite.find( " / " ), 1 , " / " );
};
}
else if (strtemp.find(httpmark) != strtemp.npos)
{
filetowrite = strtemp.substr(httpmark.length(), (strtemp.length()
- httpmark.length()));
filetowrite = " C:/demht/ " + filetowrite;
while (filetowrite.find( " / " ) != filetowrite.npos)
{
filetowrite.replace(filetowrite.find( " / " ), 1 , " / " );
};
filetowrite = filetowrite.substr( 0 , filetowrite.find_first_of( " ? " )
);
}
else
{
filetowrite = strtemp.substr(filemark.length(), (strtemp.length()
- filemark.length()));
};
};
};
if (strtemp.find(partmark) != strtemp.npos)
{
// 处理完毕一部分数据收集。开始写入。
string dir = filetowrite.substr( 0 , filetowrite.find_last_of( " / " ));
string cmddir = " if not exist " + dir + " md " + dir;
system(cmddir.c_str());
ofstream outf(tempfile.c_str(), ios:: out );
// 写入临时文件
outf.write(strbuf.c_str(), strbuf.length());
outf.close();
// 通过CBase64类,得到解码文件。
CBase64 a;
cout << " write=> " << filetowrite << endl;
a.GetFile(( char * )tempfile.c_str(), filetowrite.c_str());
cout << " base64end " << endl;
basestart = false ;
strbuf = "" ;
filetowrite = "" ;
}
else
{
strbuf += strtemp + " " ;
};
}
else if (normalstart)
// 在普通文本处理内
{
if (strtemp.find(partmark) != strtemp.npos)
{
// 处理完毕一部分开始写入
string dir = filetowrite.substr( 0 , filetowrite.find_last_of( " / " ));
string cmddir = " if not exist " + dir + " md " + dir;
system(cmddir.c_str());
ofstream outf;
cout << " write=> " << filetowrite << endl;
outf.open(filetowrite.c_str(), ios:: out );
if (outf.fail())
{
cout << " error! out normalfile " << filetowrite << endl;
exit( 1 );
};
outf.write(strbuf.c_str(), strbuf.length());
outf.close();
cout << " normalend " << endl;
normalstart = false ;
strbuf = "" ;
filetowrite = "" ;
}
else
{
if (strtemp != "" )
{
bool cat = false ; // 最后一个为'='表示连接不换行
if (strtemp.at(strtemp.length() - 1 ) == ' = ' )
{
strtemp = strtemp.substr( 0 , strtemp.length() - 1 );
cat = true ;
}
else
{
cat = false ;
}; // 处理一些=号输出代码。
int epos = strtemp.find_first_of( " = " );
while (epos != strtemp.npos)
{
string realc;
string hexs = strtemp.substr(epos + 1 , 2 );
realc = hex2c(( char * )hexs.c_str());
strtemp = strtemp.replace(epos, 3 , realc);
epos = strtemp.find_first_of( " = " , epos + 1 );
};
if ( ! cat)
{
strbuf += strtemp + " " ;
}
else
{
strbuf += strtemp;
}
strtemp = "" ;
}
else
{
strbuf += " " ;
};
};
};
};
inf.close();
delete []buf;
system( " if exist c:/tmp.b64 del c:/tmp.b64 " );
}
else
// 处理命令的其他情况
{
USEAGE: cout << " MHT文件解码工具,作者苏晓 2006年7月 " ;
cout << " 使用方法: " ;
cout << argv[ 0 ] << " <mhtfile> " << endl;
cout << " 注意事项:生成文件依据 Content-Location: " ;
cout << " 如果是file://不变 如果是http://映射生成到C:/demht/下 " << endl;
};
// system("PAUSE");
return EXIT_SUCCESS;
};