LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1269|回复: 7

MIME邮件编码方法介绍

[复制链接]
发表于 2003-7-25 00:49:05 | 显示全部楼层 |阅读模式
在MIME邮件中进行的编码有base64 Quoted-Printable方法    这里进行一下介绍


Base64是MIME邮件中常用的编码方式之一。它的主要思想是将输入的字符串或数据编码成只含有{'A'-'Z', 'a'-'z', '0'-'9', '+', '/'}这64个可打印字符的串,故称为“Base64”。

Base64编码的方法是,将输入数据流每次取6 bit,用此6 bit的值(0-63)作为索引去查表,输出相应字符。这样,每3个字节将编码为4个字符(3×8 → 4×6);不满4个字符的以'='填充。

const char EnBase64Tab[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

解码是编码的反过程

Quoted-Printable也是MIME邮件中常用的编码方式之一。同Base64一样,它也将输入的字符串或数据编码成全是ASCII码的可打印字符串。

Quoted-Printable编码的基本方法是:输入数据在33-60、62-126范围内的,直接输出;其它的需编码为“=”加两个字节的HEX码(大写)。为保证输出行不超过规定长度,可在行尾加“=\r\n”序列作为软回车。

一般邮件的Content-Transfer-Encoding:中会说明邮件使用的算法 如果是标题的话 那么会用B表示BASE64 用Q表示Quoted-Printable。
以下是标题的一个例子
Subject: =?gb2312?B?xOO6w6Oh?=
=?和?=间表示是标题内容
gb2312表示字符集B表示base64后面是编码

下面是base64编解码过程和quoted-printable解码过程 (没有经过充分测试)
想学习的话可以看邮件 也就是把邮件导出 然后用文本工具看就OK了



  1. #include <stdio.h>
  2. #include <string.h>


  3. static char base64_encoding[] =
  4. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";


  5. // encode to BASE 64
  6. // return buflen
  7. int base64_enc(char *buf,char*text,int size)
  8. {
  9.     int    buflen = 0 ;

  10.     while(size>0){
  11.         *buf++  = base64_encoding[ (text[0] >> 2 ) & 0x3f];
  12.         if(size>2){
  13.             *buf++  = base64_encoding[((text[0] & 3) << 4) | ((text[1] >> 4) & 0x0f)];
  14.             *buf++  = base64_encoding[((text[1] & 0xF) << 2) | ((text[2] >> 6) &3)];
  15.             *buf++  = base64_encoding[text[2] & 0x3F];
  16.         }else{
  17.             switch(size){
  18.                 case 1:
  19.                     *buf++  = base64_encoding[(text[0] & 3) << 4 ];
  20.                     *buf++  = '=';
  21.                     *buf++  = '=';
  22.                     break;
  23.                 case 2:
  24.                     *buf++  = base64_encoding[((text[0] & 3) << 4) | ((text[1] >> 4) & 0x0f)];
  25.                     *buf++  = base64_encoding[((text[1] & 0xF) << 2) | ((text[2] >> 6) &3)];
  26.                     *buf++  = '=';
  27.                     break;
  28.             }
  29.         }

  30.         text +=3;
  31.         size -=3;
  32.         buflen +=4;
  33.     }   

  34.     *buf = 0;
  35.     return buflen;
  36. }

  37. static char get_base64_value(char ch,char default_value)
  38. {
  39.     if ((ch >= 'A') && (ch <= 'Z'))
  40.         return ch - 'A';
  41.     if ((ch >= 'a') && (ch <= 'z'))
  42.         return ch - 'a' + 26;
  43.     if ((ch >= '0') && (ch <= '9'))
  44.         return ch - '0' + 52;
  45.     switch (ch) {
  46.         case '+':
  47.             return 62;
  48.         case '/':
  49.             return 63;
  50.         case '=': /* base64 padding */
  51.             return default_value;
  52.         default:
  53.             return default_value;
  54.     }
  55. }

  56. //进行base64解码 返回buf中内容长度
  57. //注意 如果是最后一个字符 那么长度不准备 可能会多1
  58. int base64_dec(char *buf,char*text,int *size)
  59. {
  60.     char chunk[4];
  61.     int  parsenum=0;

  62.     int  linelen=*size;
  63.     *size        =0;

  64.     while(linelen>*size){
  65.         if(get_base64_value(*text,-1)==-1){
  66.             text++;
  67.             size++;
  68.             continue;
  69.         }
  70.        
  71.         if(linelen-*size<3)
  72.             return parsenum;

  73.         chunk[0] = get_base64_value(text[0],0);
  74.         chunk[1] = get_base64_value(text[1],0);
  75.         chunk[2] = get_base64_value(text[2],0);
  76.         chunk[3] = get_base64_value(text[3],0);

  77.         *buf++ = (chunk[0] << 2) | (chunk[1] >> 4);
  78.         *buf++ = (chunk[1] << 4) | (chunk[2] >> 2);
  79.         *buf++ = (chunk[2] << 6) | (chunk[3]);

  80.         if(text[1]=='='){
  81.             *size+=1;
  82.             return parsenum+1;
  83.         }
  84.         else if(text[2]=='='){
  85.             *size+=2;
  86.             return parsenum+2;
  87.         }
  88.         else if(text[3]=='='){
  89.                         *size+=3;
  90.             return parsenum+3;
  91.         }

  92.         text+=4;
  93.         *size+=4;
  94.         parsenum+=3;
  95.     }
  96.    
  97.     return parsenum;
  98. }


  99. //解码Quoted-Printable,返回解码的长度
  100. int QPrintable_dec(char *buf,char*text,int size)
  101. {
  102.     int buflen=0;        // 输出的字符计数
  103.     int i=0;

  104.     while (size>0)
  105.     {
  106.         if (strncmp(text, "=\r\n", 3) == 0)        // 软回车,跳过
  107.         {
  108.             text += 3;
  109.             size -= 3;
  110.         }
  111.         else
  112.         {
  113.             if (*text == '=')        // 是编码字节
  114.             {
  115.                 sscanf(text, "=%02X", buf);
  116.                 buf++;
  117.                 text += 3;
  118.                 size -= 3;
  119.             }
  120.             else        // 非编码字节
  121.             {
  122.                 *buf++ = (unsigned char)*text++;
  123.                 size--;
  124.             }
  125.   
  126.             buflen++;
  127.         }
  128.     }
  129.   
  130.     return buflen;
  131. }


  132. main()
  133. {
  134.         char s[]="试一试看";
  135.         char d[100],db[100];
  136.         int len = base64_enc(d,s,strlen(s));
  137.         d[len]=0;
  138.         printf("orig string is %d len:\n%s\nafter encode is %d len:\n",strlen(s),s,len ,d);

  139.         len = base64_dec(db,d,&len);
  140.         db[len]=0;
  141.         printf("after decode is %d len:\n%s\n",len,db);

  142.         return 0;
  143. }

复制代码
发表于 2003-7-25 07:51:28 | 显示全部楼层
http://www.wc.cc.va.us/dtod/base64/default.asp


Web-Based Base64 Converter

:可以试的--不用编程

zt7Lqw==的解码是谁呢
???
发表于 2003-7-25 07:53:02 | 显示全部楼层
不错,长见识。是否所有的邮件都是这样编码的吗?为什么有的中文会被邮件系统把字节第8位处理掉而变成乱码?
发表于 2003-7-25 07:58:17 | 显示全部楼层
RFC

http://www.fourmilab.ch/webtools/base64/


  1. Table 1: The Base64 Alphabet

  2.       Value Encoding  Value Encoding  Value Encoding  Value Encoding
  3.            0 A            17 R            34 i            51 z
  4.            1 B            18 S            35 j            52 0
  5.            2 C            19 T            36 k            53 1
  6.            3 D            20 U            37 l            54 2
  7.            4 E            21 V            38 m            55 3
  8.            5 F            22 W            39 n            56 4
  9.            6 G            23 X            40 o            57 5
  10.            7 H            24 Y            41 p            58 6
  11.            8 I            25 Z            42 q            59 7
  12.            9 J            26 a            43 r            60 8
  13.           10 K            27 b            44 s            61 9
  14.           11 L            28 c            45 t            62 +
  15.           12 M            29 d            46 u            63 /
  16.           13 N            30 e            47 v
  17.           14 O            31 f            48 w         (pad) =
  18.           15 P            32 g            49 x
  19.           16 Q            33 h            50 y
复制代码
发表于 2003-7-25 08:18:47 | 显示全部楼层

  1. Example encoding:

  2.                 The stream 'ABCD' is 32 bits long.  It is mapped as
  3.                 follows:

  4.                 ABCD

  5.                  A (65)     B (66)     C (67)     D (68)   (None) (None)
  6.                 01000001   01000010   01000011   01000100

  7.                 16 (Q)  20 (U)  9 (J)   3 (D)    17 (R) 0 (A)  NA (=) NA (=)
  8.                 010000  010100  001001  000011   010001 000000 000000 000000


  9.                 QUJDRA==
复制代码



如果可见字符变可见字符挺无聊的.....


ABCD成了QUJDRA==
这不是增加数据量吗/

还要多作工作--编码与解码

http://base64.sourceforge.net/b64.c
 楼主| 发表于 2003-7-25 19:32:29 | 显示全部楼层
因为 8bit字符通过多数邮件系统时会有问题 所以要把它们转换成7bit 也就是>127的字符不能正确传送   而像是中文或是二进制文件都有很多这样的值  所以需要转换

zt7Lqw???  不知道啊

但是网上有一篇王笨笨压缩教程还是很好的 推荐看看
发表于 2003-7-25 22:59:31 | 显示全部楼层
是你啊

无双

:-)
 楼主| 发表于 2003-7-26 11:48:52 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表