Categories
Recent Posts

Archive for June, 2009

base64 encoder/decoder for objective-c 编码及解码

base64是广为使用的一种编码及解码方式, 通常用于网络传输和邮件传输中,使用base64可以将标点符号以及多字节文字等特殊字符编码以便传输,以下是base64 编码解码的objective-c代码, 可以用于desktop和iphone程序当中

头文件

?Download base64.h
1
2
3
4
5
6
7
#include <UIKit/UIKit.h>
 
extern size_t EstimateBas64EncodedDataSize(size_t inDataSize);
extern size_t EstimateBas64DecodedDataSize(size_t inDataSize);
 
extern bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize, BOOL wrapped);
extern bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize);

实现文件

?Download base64.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#include "Base64Transcoder.h"
 
#include <math.h>
 
const UInt8 kBase64EncodeTable[64] = {
	/*  0 */ 'A',	/*  1 */ 'B',	/*  2 */ 'C',	/*  3 */ 'D', 
	/*  4 */ 'E',	/*  5 */ 'F',	/*  6 */ 'G',	/*  7 */ 'H', 
	/*  8 */ 'I',	/*  9 */ 'J',	/* 10 */ 'K',	/* 11 */ 'L', 
	/* 12 */ 'M',	/* 13 */ 'N',	/* 14 */ 'O',	/* 15 */ 'P', 
	/* 16 */ 'Q',	/* 17 */ 'R',	/* 18 */ 'S',	/* 19 */ 'T', 
	/* 20 */ 'U',	/* 21 */ 'V',	/* 22 */ 'W',	/* 23 */ 'X', 
	/* 24 */ 'Y',	/* 25 */ 'Z',	/* 26 */ 'a',	/* 27 */ 'b', 
	/* 28 */ 'c',	/* 29 */ 'd',	/* 30 */ 'e',	/* 31 */ 'f', 
	/* 32 */ 'g',	/* 33 */ 'h',	/* 34 */ 'i',	/* 35 */ 'j', 
	/* 36 */ 'k',	/* 37 */ 'l',	/* 38 */ 'm',	/* 39 */ 'n', 
	/* 40 */ 'o',	/* 41 */ 'p',	/* 42 */ 'q',	/* 43 */ 'r', 
	/* 44 */ 's',	/* 45 */ 't',	/* 46 */ 'u',	/* 47 */ 'v', 
	/* 48 */ 'w',	/* 49 */ 'x',	/* 50 */ 'y',	/* 51 */ 'z', 
	/* 52 */ '0',	/* 53 */ '1',	/* 54 */ '2',	/* 55 */ '3', 
	/* 56 */ '4',	/* 57 */ '5',	/* 58 */ '6',	/* 59 */ '7', 
	/* 60 */ '8',	/* 61 */ '9',	/* 62 */ '+',	/* 63 */ '/'
};
 
/*
-1 = Base64 end of data marker.
-2 = White space (tabs, cr, lf, space)
-3 = Noise (all non whitespace, non-base64 characters) 
-4 = Dangerous noise
-5 = Illegal noise (null byte)
*/
 
const SInt8 kBase64DecodeTable[128] = {
	/* 0x00 */ -5, 	/* 0x01 */ -3, 	/* 0x02 */ -3, 	/* 0x03 */ -3,
	/* 0x04 */ -3, 	/* 0x05 */ -3, 	/* 0x06 */ -3, 	/* 0x07 */ -3,
	/* 0x08 */ -3, 	/* 0x09 */ -2, 	/* 0x0a */ -2, 	/* 0x0b */ -2,
	/* 0x0c */ -2, 	/* 0x0d */ -2, 	/* 0x0e */ -3, 	/* 0x0f */ -3,
	/* 0x10 */ -3, 	/* 0x11 */ -3, 	/* 0x12 */ -3, 	/* 0x13 */ -3,
	/* 0x14 */ -3, 	/* 0x15 */ -3, 	/* 0x16 */ -3, 	/* 0x17 */ -3,
	/* 0x18 */ -3, 	/* 0x19 */ -3, 	/* 0x1a */ -3, 	/* 0x1b */ -3,
	/* 0x1c */ -3, 	/* 0x1d */ -3, 	/* 0x1e */ -3, 	/* 0x1f */ -3,
	/* ' ' */ -2,	/* '!' */ -3,	/* '"' */ -3,	/* '#' */ -3,
	/* '$' */ -3,	/* '%' */ -3,	/* '&' */ -3,	/* ''' */ -3,
	/* '(' */ -3,	/* ')' */ -3,	/* '*' */ -3,	/* '+' */ 62,
	/* ',' */ -3,	/* '-' */ -3,	/* '.' */ -3,	/* '/' */ 63,
	/* '0' */ 52,	/* '1' */ 53,	/* '2' */ 54,	/* '3' */ 55,
	/* '4' */ 56,	/* '5' */ 57,	/* '6' */ 58,	/* '7' */ 59,
	/* '8' */ 60,	/* '9' */ 61,	/* ':' */ -3,	/* ';' */ -3,
	/* '<' */ -3,	/* '=' */ -1,	/* '>' */ -3,	/* '?' */ -3,
	/* '@' */ -3,	/* 'A' */ 0,	/* 'B' */  1,	/* 'C' */  2,
	/* 'D' */  3,	/* 'E' */  4,	/* 'F' */  5,	/* 'G' */  6,
	/* 'H' */  7,	/* 'I' */  8,	/* 'J' */  9,	/* 'K' */ 10,
	/* 'L' */ 11,	/* 'M' */ 12,	/* 'N' */ 13,	/* 'O' */ 14,
	/* 'P' */ 15,	/* 'Q' */ 16,	/* 'R' */ 17,	/* 'S' */ 18,
	/* 'T' */ 19,	/* 'U' */ 20,	/* 'V' */ 21,	/* 'W' */ 22,
	/* 'X' */ 23,	/* 'Y' */ 24,	/* 'Z' */ 25,	/* '[' */ -3,
	/* '\' */ -3,	/* ']' */ -3,	/* '^' */ -3,	/* '_' */ -3,
	/* '`' */ -3,	/* 'a' */ 26,	/* 'b' */ 27,	/* 'c' */ 28,
	/* 'd' */ 29,	/* 'e' */ 30,	/* 'f' */ 31,	/* 'g' */ 32,
	/* 'h' */ 33,	/* 'i' */ 34,	/* 'j' */ 35,	/* 'k' */ 36,
	/* 'l' */ 37,	/* 'm' */ 38,	/* 'n' */ 39,	/* 'o' */ 40,
	/* 'p' */ 41,	/* 'q' */ 42,	/* 'r' */ 43,	/* 's' */ 44,
	/* 't' */ 45,	/* 'u' */ 46,	/* 'v' */ 47,	/* 'w' */ 48,
	/* 'x' */ 49,	/* 'y' */ 50,	/* 'z' */ 51,	/* '{' */ -3,
	/* '|' */ -3,	/* '}' */ -3,	/* '~' */ -3,	/* 0x7f */ -3
};
 
const UInt8 kBits_00000011 = 0x03;
const UInt8 kBits_00001111 = 0x0F;
const UInt8 kBits_00110000 = 0x30;
const UInt8 kBits_00111100 = 0x3C;
const UInt8 kBits_00111111 = 0x3F;
const UInt8 kBits_11000000 = 0xC0;
const UInt8 kBits_11110000 = 0xF0;
const UInt8 kBits_11111100 = 0xFC;
 
size_t EstimateBas64EncodedDataSize(size_t inDataSize)
{
size_t theEncodedDataSize = (int)ceil(inDataSize / 3.0) * 4;
theEncodedDataSize = theEncodedDataSize / 72 * 74 + theEncodedDataSize % 72;
return(theEncodedDataSize);
}
 
size_t EstimateBas64DecodedDataSize(size_t inDataSize)
{
size_t theDecodedDataSize = (int)ceil(inDataSize / 4.0) * 3;
//theDecodedDataSize = theDecodedDataSize / 72 * 74 + theDecodedDataSize % 72;
return(theDecodedDataSize);
}
 
bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize, BOOL wrapped)
{
size_t theEncodedDataSize = EstimateBas64EncodedDataSize(inInputDataSize);
if (*ioOutputDataSize < theEncodedDataSize)
	return(false);
*ioOutputDataSize = theEncodedDataSize;
const UInt8 *theInPtr = (const UInt8 *)inInputData;
UInt32 theInIndex = 0, theOutIndex = 0;
for (; theInIndex < (inInputDataSize / 3) * 3; theInIndex += 3)
	{
	outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2];
	outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4];
	outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (theInPtr[theInIndex + 2] & kBits_11000000) >> 6];
	outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 2] & kBits_00111111) >> 0];
	if (wrapped && (theOutIndex % 74 == 72))
		{
		outOutputData[theOutIndex++] = '\r';
		outOutputData[theOutIndex++] = '\n';
		}
	}
const size_t theRemainingBytes = inInputDataSize - theInIndex;
if (theRemainingBytes == 1)
	{
	outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2];
	outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (0 & kBits_11110000) >> 4];
	outOutputData[theOutIndex++] = '=';
	outOutputData[theOutIndex++] = '=';
	if (wrapped && (theOutIndex % 74 == 72))
		{
		outOutputData[theOutIndex++] = '\r';
		outOutputData[theOutIndex++] = '\n';
		}
	}
else if (theRemainingBytes == 2)
	{
	outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2];
	outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4];
	outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (0 & kBits_11000000) >> 6];
	outOutputData[theOutIndex++] = '=';
	if (wrapped && (theOutIndex % 74 == 72))
		{
		outOutputData[theOutIndex++] = '\r';
		outOutputData[theOutIndex++] = '\n';
		}
	}
return(true);
}
 
bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize)
{
memset(ioOutputData, '.', *ioOutputDataSize);
 
size_t theDecodedDataSize = EstimateBas64DecodedDataSize(inInputDataSize);
if (*ioOutputDataSize < theDecodedDataSize)
	return(false);
*ioOutputDataSize = 0;
const UInt8 *theInPtr = (const UInt8 *)inInputData;
UInt8 *theOutPtr = (UInt8 *)ioOutputData;
size_t theInIndex = 0, theOutIndex = 0;
UInt8 theOutputOctet;
size_t theSequence = 0;
for (; theInIndex < inInputDataSize; )
	{
	SInt8 theSextet = 0;
 
	SInt8 theCurrentInputOctet = theInPtr[theInIndex];
	theSextet = kBase64DecodeTable[theCurrentInputOctet];
	if (theSextet == -1)
		break;
	while (theSextet == -2)
		{
		theCurrentInputOctet = theInPtr[++theInIndex];
		theSextet = kBase64DecodeTable[theCurrentInputOctet];
		}
	while (theSextet == -3)
		{
		theCurrentInputOctet = theInPtr[++theInIndex];
		theSextet = kBase64DecodeTable[theCurrentInputOctet];
		}
	if (theSequence == 0)
		{
		theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 2 & kBits_11111100;
		}
	else if (theSequence == 1)
		{
		theOutputOctet |= (theSextet >- 0 ? theSextet : 0) >> 4 & kBits_00000011;
		theOutPtr[theOutIndex++] = theOutputOctet;
		}
	else if (theSequence == 2)
		{
		theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 4 & kBits_11110000;
		}
	else if (theSequence == 3)
		{
		theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 2 & kBits_00001111;
		theOutPtr[theOutIndex++] = theOutputOctet;
		}
	else if (theSequence == 4)
		{
		theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 6 & kBits_11000000;
		}
	else if (theSequence == 5)
		{
		theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 0 & kBits_00111111;
		theOutPtr[theOutIndex++] = theOutputOctet;
		}
	theSequence = (theSequence + 1) % 6;
	if (theSequence != 2 && theSequence != 4)
		theInIndex++;
	}
*ioOutputDataSize = theOutIndex;
return(true);
}

iPhone SDK 开发:sqlite + UITableView 实现大数据浏览

在开始学习iPhone开发的时候就捉摸 AppStore这样的程序时怎么实现的, 动态的从服务器抓取内容,再在表格中显示。 伴随着twitter的火爆, 越来越多的软件实现了此种方式来显示twitter消息, 不巧公司也要做twitter相关的东西,正好借此机会试探着实现一下这种显示功能。

iPhone程序和传统的桌面程序的最大不同在于内存有限, 管理内存成了iPhone开发中时时刻刻需要谨记的事情。类似的功能在桌面程序上无非是将down下来的数据缓存于内存中,需要的时候画出来即可。 此法在iPhone上切不可行,虽然UITableViewCell可与reuse重复使用以节约内存使用量, 但是数据还是需要host在array或者dictionary中,必然导致程序实用大量内存儿崩溃退出。

还好,iPhone系统内置sqlite微型数据库, 这么好的查询插入引擎不善用那就是罪过了。。。
言归正传, 基本思路是这样的: 从服务器读取内容,以twitter为例,先创建消息数据表
create table public_timelines (id integer primary key autoincrement, user varchar(40),\
userurl text,body text, created real, created_string text,\
imageurl text, ordernum int, userid varchar(20), user_screenname varchar(40));

获取public timelines得到以xml形式存在的message条目,解析xml后将每条消息插入数据表, 写入成功后发送reload消息给table以重新填充表格单元内容, 如图

如果消息记录超过一条, 记得在- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
中返回消息记录 + 1, 因为最后一个cell需要实现 Get More …功能

就像上一步说的, 点击最后一个cell也就是Get More…时,在此从服务器获取 新的timelines, 将其解析再写入数据表中, 每次刷新时将数据表清空,否则显示的消息会越来越多:), Get More 工作状态大概时这样的

如此, 程序实用的内存非常小, 每一条消息内容都是在需要的时候从数据库文件中读取, 减小了内存使用量就增加了程序的稳定性, 这对于成功的软件来说是非常必要的。

这篇小文只是对这样一个实现技术做了简单的介绍, 其中还有很多细节需要考虑, 比如:对sqlite的封装,以便于使用; 采用NSURLConnection方式下载数据以及post数据的实现; 还有xml解析可以使用iPhone SDK本身的NSXML* 系列API 也可以使用libxml, 具体当然根据个人习惯来选择。 针对Twitter, 已经有很多很好的开源库可以直接使用,比如 TwitterEngine

Google Search Ajax API 实现站内搜索

Google search 可以很容易实现站内搜索, 首先你需要到http://code.google.com/apis/ajaxsearch/signup.html 注册API Key。

将下面的代码存为html文件

1
2
    <script src="http://www.google.com/jsapi?key=ABQIAAAAoA_CzZ1j3fi975O5J0e28BTDgCurGPx7iDb5srKt0_zm3xn5GhSJK0sSDriiqfPAwr6wcPf7cpLPoQ" type="text/javascript"><!--mce:0--></script>
    <script type="text/javascript"><!--mce:1--></script>

之后在html文件中添加两个div, 一个id为searchcontrol, 这是默认的输出结果的div,如果你需要自己自定义输出结果那么添加另一个div并设定id为searchResult