|
楼主 |
发表于 2004-9-22 22:08:32
|
显示全部楼层
[code:1]const gchar *QQ_SPT_IMG_EXT[] = {".BMP", ".GIF", ".JPEG", ".JPG", NULL};
#define QQ_USERDEFINED_SMILEY_FLAGS "\025"
#define MSG_FILTER_PROM "[X]"
#define MSG_FILTER_PROM_SIZE (sizeof(MSG_FILTER_PROM) - 1) //donnot include the terminal char
#define QQ_SMILEY_SHOTCUT_MAX (6)
//包含QQ自定义表情的文本至少得39个字节, 2字节操作符,32字节md5,4个字节扩展名,
//1字节快捷方式长度,快捷方式可以没有
#define QQ_USERDEINED_SMILEY_MIN_LEN (39)
/***********************************************************************************
md5sum ____ _____
(\x15)32FE05FF7FDBE0CF68CB2A108F7B8D5B48.GIFDabc(\x15)4A
______^^________________________________ ^___ ^^
前导字符是0x15,可能代表QQ中与文件有关的一类操作
在0x15后面,还有一个操作符,‘3’和‘4'是与自定义表情有关的
另外还有‘2’等,‘2'与文件传送有关。'3'代表QQ自定义表情在
当前对话中第一次出现,'4'代表表情已经在当前对话中现过,如果
出现的是\x153则后面还有一个字符一般为'1'或者'2',意义未知.
紧接着是表情文件的32字节md5码,这个唯一的决定了QQ的自定义表情,
然后是自定义表情的扩展名,QQ支持的有四种.BMP,GIF,.JPEG,
.JPG.最后是与表情快捷方式有关的部分了, 第1个字节代表着表情
快捷方式的长度,实际长度等于其值减去'A', 但不得超过6个字节.
再后面就是快捷方式的实际内容了.而出现\x154的话就是要重复
前面已存在的表情如果后面是字符'A'的话,就用第一个表情代替,
'B'就第二个,依此类推即可.
当前还无法与QQ互传文件只能先过滤掉这么乱码,留下有用信息。
*/
/************************************************************************************
@param text 等待过滤的文本
@param maintain_shotcut 是否保留快捷方式 TRUE 保留 FALSE 不保留
@return 过滤后的文本 注意:这个文本需要调用者释放否则就会内存泄露
*/
gchar *qq_im_filter_userdefined_smiley(const gchar *text, gboolean maintain_shotcut) {
GString *converted;
gchar *begin, *end, *cnt, **smiley_ex_flags, *result;
static gchar shotcuts[26][QQ_SMILEY_SHOTCUT_MAX + 1]; //define as static to speedup
gint last_shotcut = -1, shotcut_len = 0;
//没有0x15,或者文本长度小于39,则不可能包含QQ自定义表情,直接返回。
if (!g_strstr_len(text, -1, QQ_USERDEFINED_SMILEY_FLAGS) || strlen(text) < QQ_USERDEINED_SMILEY_MIN_LEN)
return NULL;
converted = g_string_new(text);
if (!converted)
return NULL;
begin = cnt = converted->str;
gaim_debug(GAIM_DEBUG_INFO, "QQ_ORIG_MESG", "%s.\n", begin);
while (cnt && *cnt) {
cnt = g_strstr_len(cnt, -1, QQ_USERDEFINED_SMILEY_FLAGS);
if (!cnt || !(*(cnt +1))) {
break;
}
//第2个操作符必须是数字
if (!g_ascii_isdigit(cnt[1])) {
cnt ++;
continue;
}
//此次对话中还没有出现过的QQ自定义表情
if ( cnt[1] == '3') {
//skip some chars
//____ _<-unknown
//\x1532FE05FF7FDBE0CF68CB2A108F7B8D5B48.GIFDabc
// ^<-cnt ^<-end
end = cnt + 1 + 1 + 32 + 1;
//out of the text bound
if(end >= begin + converted->len)
break;
//now check smiley extension name, .BMP, .GIF, .JPEG, .JPG
for (smiley_ex_flags = (gchar **)QQ_SPT_IMG_EXT; smiley_ex_flags != NULL && *smiley_ex_flags != '\0'; smiley_ex_flags++) {
if(!g_ascii_strncasecmp(end, *smiley_ex_flags, strlen(*smiley_ex_flags))) {
end += strlen(*smiley_ex_flags);
break;
}
}
// the expected smiley extension name is found
if (smiley_ex_flags != NULL && *smiley_ex_flags != '\0') {
if (*end ) {
// extension name of smiley --> ____
//\x1532FE05FF7FDBE0CF68CB2A108F7B8D5B48.GIFDabc
// shotcut length('D'-'A' = 3)-> ^--- <-shotcut of smiley
shotcut_len = *end - 'A';
if (maintain_shotcut == FALSE && (*end >= 'A') && (shotcut_len <= QQ_SMILEY_SHOTCUT_MAX)
&& (end + (shotcut_len) <= begin + converted->len)) {
if((!end[shotcut_len] && end + shotcut_len - cnt - 1 >= MSG_FILTER_PROM_SIZE) ||
( end[shotcut_len] && end + shotcut_len - cnt >= MSG_FILTER_PROM_SIZE)) {
g_strlcpy(cnt, MSG_FILTER_PROM, MSG_FILTER_PROM_SIZE);//tell user we filter some msg.
cnt += MSG_FILTER_PROM_SIZE;
}
//store the shotcut
if ( last_shotcut < 25) {
// donnot need copy the shotcut
// g_strlcpy(shotcuts[++last_shotcut], end + 1 , end[0] - 'A');
// shotcuts[last_shotcut][end[0] - 'A'] = '\0';
++last_shotcut;
}
end += (end[0] - 'A') + 1;
}
else { //maintain the shotcut
//store the shotcut
if ( last_shotcut < 25 && (*end >= 'A') && shotcut_len <= QQ_SMILEY_SHOTCUT_MAX) {
g_strlcpy(shotcuts[++last_shotcut], end + 1 , shotcut_len);
shotcuts[last_shotcut][shotcut_len] = '\0';
}
end ++;
}
}
g_string_erase(converted, (cnt - begin), (end - cnt));
if (maintain_shotcut && last_shotcut < 25 ) //skip shotcuts
cnt += shotcut_len;
continue;
}
else {
//\x153...
// ^-> ^
//bad string, skip...
cnt += 2;
continue;
}
}
else if (cnt[1] == '4' ) {
if (maintain_shotcut == FALSE) {
if (cnt[2] >= 'A' && cnt[2] <= 'Z' && cnt[2] - 'A' <= last_shotcut) {//\x154[A-Z]
gint left_size = 3;
if( 3 >= MSG_FILTER_PROM_SIZE) {
g_strlcpy(cnt, MSG_FILTER_PROM, MSG_FILTER_PROM_SIZE);//tell user we filter some msg.
cnt += MSG_FILTER_PROM_SIZE;
left_size -= MSG_FILTER_PROM_SIZE;
}
g_string_erase(converted, (cnt - begin), left_size); //erase left chars
}
else cnt ++;
}
else {
if (cnt[2] >= 'A' && cnt[2] <= 'Z' && last_shotcut >= 0) { //\x154[A-Z]
shotcut_len = strlen(shotcuts[cnt[2] - 'A']);
if (shotcut_len > 0 && shotcut_len <= 3 && cnt[2] - 'A' <= last_shotcut) {
g_strlcpy(cnt, shotcuts[cnt[2] - 'A'], shotcut_len);
cnt += shotcut_len;
if (shotcut_len < 3) {
g_string_erase(converted, (cnt - begin), 3 - shotcut_len);
}
}
else {
g_string_erase(converted, (cnt - begin), 3);
}
}
}
continue;
}
cnt ++;
}
gaim_debug(GAIM_DEBUG_INFO, "QQ_FILTERED_MESG", "%s.\n", begin);
result = converted->str;
g_string_free(converted, FALSE);
if (last_shotcut >= 0 && maintain_shotcut == TRUE) //clear the buffer
memset(&shotcuts[0][0], sizeof(shotcuts), 0);
return result;
}//qq_im_filter_userdefined_smiley
[/code:1] |
|