如果公司电脑所有接口都锁上了,如何能传出一些文档呢?手抄?拍照后再文字识别?都不方便,要是能将文档转成二维码,扫描的结果再转成文档就方便了些。
一 思路
二维码能传输的信息量是很少的,直接将文档内容转成二维码很不现实,所以先用WinRAR对原文件进行压缩。
然后需要将rar转换成可打印字符,一个汉字的二维码比两个ascii字符的二维码复杂,这里考虑将rar转成可打印的ascii字符。标准ascii里有95个可打印字符,那就选64个,可表示6个比特位。
编码前 | 编码后 |
---|---|
6个比特位 | 1个字符 |
24个比特位/3个字节 | 4个字符 |
二 编码
将rar文件转换为可打印字符的代码:
// encode.c
// input: src.rar output: dest.txt
#include <stdio.h>
#include <string.h>
const unsigned char table[]=
{
'0','1','2','3','4','5','6','7','8','9','<','>',
'A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z'
};
// 当到达文件尾不足3个字符时, 末尾补0, 最多会有2个空字符, 对rar文件无影响
int read3chars(FILE *fin, unsigned char *re)
{
int t;
unsigned char buf[3];
memset(buf, 0, 3*sizeof(unsigned char));
t = fgetc(fin);
if(t == EOF) return -1;
buf[0] = t;
t = fgetc(fin);
if(t == EOF) goto last;
buf[1] = t;
t = fgetc(fin);
if(t == EOF) goto last;
buf[2] = t;
unsigned char a,b,c,d;
last:
a = (buf[0]&0xFC)>>2;
b = (buf[0]&0x03)<<4 | (buf[1]&0xF0)>>4;
c = (buf[1]&0x0F)<<2 | buf[2]>>6;
d = buf[2]&0x3F;
re[0] = table[a];
re[1] = table[b];
re[2] = table[c];
re[3] = table[d];
return 0;
}
int main()
{
FILE *fin = fopen("src.rar", "rb");
if(fin == NULL)
{
puts("cann't open src.rar!");
getchar();
return -1;
}
FILE *fout = fopen("dest.txt", "w");
for(;;)
{
unsigned char buf[4];
int ret = read3chars(fin, buf);
if(ret != 0) break;
fputc(buf[0], fout);
fputc(buf[1], fout);
fputc(buf[2], fout);
fputc(buf[3], fout);
}
fclose(fin);
fclose(fout);
return 0;
}
三 解码
如果用记事本编辑文本文件,可能会出现BOM字符,这里并没有对其进行特殊处理。
// decode.cpp
// input: dest.txt output: dest.rar
#include <cstdio>
#include <map>
const char table[]=
{
'0','1','2','3','4','5','6','7','8','9','<','>',
'A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z'
};
std::map<unsigned char, unsigned char> retable;
// 一定是4字节的整数倍
int read4chars(FILE *fin, unsigned char *ret)
{
unsigned char buf[4];
int t = fgetc(fin);
if(t == EOF) return -1;
buf[0] = t;
buf[1] = fgetc(fin);
buf[2] = fgetc(fin);
buf[3] = fgetc(fin);
unsigned char a = retable[buf[0]];
unsigned char b = retable[buf[1]];
unsigned char c = retable[buf[2]];
unsigned char d = retable[buf[3]];
ret[0] = a<<2 | b>>4;
ret[1] = b<<4 | c>>2;
ret[2] = c<<6 | d;
return 0;
}
int main()
{
for(unsigned char i=0; i<64; ++i)
retable[table[i]] = i;
FILE *fin = fopen("dest.txt", "r");
if(fin == NULL)
{
puts("cann't open dest.txt!");
getchar();
return -1;
}
FILE *fout = fopen("dest.rar", "wb");
for(;;)
{
unsigned char buf[3];
int res = read4chars(fin, buf);
if(res != 0) break;
fputc(buf[0], fout);
fputc(buf[1], fout);
fputc(buf[2], fout);
}
fclose(fin);
fclose(fout);
return 0;
}