|
1 // base64.cpp |
|
2 // |
|
3 // Copyright (c) 2010 Accenture. All rights reserved. |
|
4 // This component and the accompanying materials are made available |
|
5 // under the terms of the "Eclipse Public License v1.0" |
|
6 // which accompanies this distribution, and is available |
|
7 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 // |
|
9 // Initial Contributors: |
|
10 // Accenture - Initial contribution |
|
11 // |
|
12 |
|
13 #include <fshell/ioutils.h> |
|
14 #include <fshell/common.mmh> |
|
15 |
|
16 using namespace IoUtils; |
|
17 |
|
18 const TInt KBlockSize = 512; |
|
19 const TInt KLineLength = 76; |
|
20 const TUint8 KBase64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
|
21 const TUint8 KPadCharacter = '='; |
|
22 |
|
23 const TUint8 KInvBase64[] = |
|
24 { |
|
25 0x0, |
|
26 0x0, |
|
27 0x0, |
|
28 0x0, |
|
29 0x0, |
|
30 0x0, |
|
31 0x0, |
|
32 0x0, |
|
33 0x0, |
|
34 0x0, |
|
35 0x0, |
|
36 0x0, |
|
37 0x0, |
|
38 0x0, |
|
39 0x0, |
|
40 0x0, |
|
41 0x0, |
|
42 0x0, |
|
43 0x0, |
|
44 0x0, |
|
45 0x0, |
|
46 0x0, |
|
47 0x0, |
|
48 0x0, |
|
49 0x0, |
|
50 0x0, |
|
51 0x0, |
|
52 0x0, |
|
53 0x0, |
|
54 0x0, |
|
55 0x0, |
|
56 0x0, |
|
57 0x0, |
|
58 0x0, |
|
59 0x0, |
|
60 0x0, |
|
61 0x0, |
|
62 0x0, |
|
63 0x0, |
|
64 0x0, |
|
65 0x0, |
|
66 0x0, |
|
67 0x0, |
|
68 0x3e, |
|
69 0x0, |
|
70 0x0, |
|
71 0x0, |
|
72 0x3f, |
|
73 0x34, |
|
74 0x35, |
|
75 0x36, |
|
76 0x37, |
|
77 0x38, |
|
78 0x39, |
|
79 0x3a, |
|
80 0x3b, |
|
81 0x3c, |
|
82 0x3d, |
|
83 0x0, |
|
84 0x0, |
|
85 0x0, |
|
86 0x0, |
|
87 0x0, |
|
88 0x0, |
|
89 0x0, |
|
90 0x0, |
|
91 0x1, |
|
92 0x2, |
|
93 0x3, |
|
94 0x4, |
|
95 0x5, |
|
96 0x6, |
|
97 0x7, |
|
98 0x8, |
|
99 0x9, |
|
100 0xa, |
|
101 0xb, |
|
102 0xc, |
|
103 0xd, |
|
104 0xe, |
|
105 0xf, |
|
106 0x10, |
|
107 0x11, |
|
108 0x12, |
|
109 0x13, |
|
110 0x14, |
|
111 0x15, |
|
112 0x16, |
|
113 0x17, |
|
114 0x18, |
|
115 0x19, |
|
116 0x0, |
|
117 0x0, |
|
118 0x0, |
|
119 0x0, |
|
120 0x0, |
|
121 0x0, |
|
122 0x1a, |
|
123 0x1b, |
|
124 0x1c, |
|
125 0x1d, |
|
126 0x1e, |
|
127 0x1f, |
|
128 0x20, |
|
129 0x21, |
|
130 0x22, |
|
131 0x23, |
|
132 0x24, |
|
133 0x25, |
|
134 0x26, |
|
135 0x27, |
|
136 0x28, |
|
137 0x29, |
|
138 0x2a, |
|
139 0x2b, |
|
140 0x2c, |
|
141 0x2d, |
|
142 0x2e, |
|
143 0x2f, |
|
144 0x30, |
|
145 0x31, |
|
146 0x32, |
|
147 0x33 |
|
148 }; |
|
149 |
|
150 _LIT(KNewLine, "\r\n"); |
|
151 _LIT(KCr, "\r"); |
|
152 _LIT(KLf, "\n"); |
|
153 |
|
154 |
|
155 class CCmdBase64 : public CCommandBase |
|
156 { |
|
157 public: |
|
158 static CCommandBase* NewLC(); |
|
159 ~CCmdBase64(); |
|
160 private: |
|
161 CCmdBase64(); |
|
162 void DecodeL(); |
|
163 void EncodeL(); |
|
164 private: // From CCommandBase. |
|
165 virtual const TDesC& Name() const; |
|
166 virtual void DoRunL(); |
|
167 virtual void ArgumentsL(RCommandArgumentList& aArguments); |
|
168 virtual void OptionsL(RCommandOptionList& aOptions); |
|
169 private: |
|
170 enum |
|
171 { |
|
172 EDecode, |
|
173 EEncode |
|
174 } iOperation; |
|
175 TFileName2 iFileName; |
|
176 TBool iVerbose; |
|
177 TBool iOverwrite; |
|
178 }; |
|
179 |
|
180 EXE_BOILER_PLATE(CCmdBase64) |
|
181 |
|
182 CCommandBase* CCmdBase64::NewLC() |
|
183 { |
|
184 CCmdBase64* self = new(ELeave) CCmdBase64(); |
|
185 CleanupStack::PushL(self); |
|
186 self->BaseConstructL(); |
|
187 return self; |
|
188 } |
|
189 |
|
190 CCmdBase64::~CCmdBase64() |
|
191 { |
|
192 } |
|
193 |
|
194 CCmdBase64::CCmdBase64() |
|
195 { |
|
196 } |
|
197 |
|
198 void CCmdBase64::DecodeL() |
|
199 { |
|
200 if (!iOverwrite) |
|
201 { |
|
202 LeaveIfFileExists(iFileName); |
|
203 } |
|
204 |
|
205 User::LeaveIfError(Stdin().CaptureAllKeys()); // To iosrv buffering incoming data if we're not keeping up. |
|
206 Stdin().SetReadModeL(RIoReadHandle::ELine); |
|
207 |
|
208 RFile file; |
|
209 LeaveIfErr(file.Replace(FsL(), iFileName, EFileWrite | EFileStream), _L("Unabled to open '%S' for writing"), &iFileName); |
|
210 CleanupClosePushL(file); |
|
211 |
|
212 TBuf<KLineLength + 2> lineBuf; |
|
213 TBuf8<(KLineLength / 4) * 3> outputBuf; |
|
214 TBool finished(EFalse); |
|
215 TBool started(EFalse); |
|
216 while (!finished) |
|
217 { |
|
218 TInt err = Stdin().Read(lineBuf); |
|
219 if (err == KErrNone) |
|
220 { |
|
221 if (iVerbose) |
|
222 { |
|
223 Printf(_L("Read %d chars:\r\n'%S'\r\n"), lineBuf.Length(), &lineBuf); |
|
224 } |
|
225 if ((lineBuf == KNewLine) || (lineBuf == KCr) || (lineBuf == KLf)) |
|
226 { |
|
227 if (started) |
|
228 { |
|
229 finished = ETrue; |
|
230 } |
|
231 } |
|
232 else |
|
233 { |
|
234 if (lineBuf.Right(2) == KNewLine) |
|
235 { |
|
236 lineBuf.SetLength(lineBuf.Length() - 2); |
|
237 } |
|
238 if ((lineBuf.Right(1) == KCr) || (lineBuf.Right(1) == KLf)) |
|
239 { |
|
240 lineBuf.SetLength(lineBuf.Length() - 1); |
|
241 } |
|
242 const TInt lineLength = lineBuf.Length(); |
|
243 if ((lineLength % 4) > 0) |
|
244 { |
|
245 LeaveIfErr(KErrArgument, _L("Invalid base 64 encoded line (not a multiple of 4 characters in length):\r\n%S\r\n"), &lineBuf); |
|
246 } |
|
247 |
|
248 started = ETrue; |
|
249 outputBuf.Zero(); |
|
250 |
|
251 for (TInt i = 0; i < lineLength; i += 4) |
|
252 { |
|
253 TInt n = ((TInt)KInvBase64[lineBuf[i]] << 18) + ((TInt)KInvBase64[lineBuf[i + 1]] << 12) + ((TInt)KInvBase64[lineBuf[i + 2]] << 6) + (TInt)KInvBase64[lineBuf[i + 3]]; |
|
254 |
|
255 if (lineBuf[i + 2] == KPadCharacter) |
|
256 { |
|
257 // Two pad characters |
|
258 outputBuf.Append((n >> 16) & 0x000000FF); |
|
259 } |
|
260 else if (lineBuf[i + 3] == KPadCharacter) |
|
261 { |
|
262 // One pad character |
|
263 outputBuf.Append((n >> 16) & 0x000000FF); |
|
264 outputBuf.Append((n >> 8) & 0x000000FF); |
|
265 } |
|
266 else |
|
267 { |
|
268 outputBuf.Append((n >> 16) & 0x000000FF); |
|
269 outputBuf.Append((n >> 8) & 0x000000FF); |
|
270 outputBuf.Append(n & 0x000000FF); |
|
271 } |
|
272 } |
|
273 |
|
274 LeaveIfErr(file.Write(outputBuf), _L("Failed to write to '%S'"), &iFileName); |
|
275 if (iVerbose) |
|
276 { |
|
277 Printf(_L("Wrote %d bytes to '%S'\r\n"), outputBuf.Length(), &iFileName); |
|
278 } |
|
279 } |
|
280 } |
|
281 else if (err == KErrEof) |
|
282 { |
|
283 finished = ETrue; |
|
284 } |
|
285 else |
|
286 { |
|
287 LeaveIfErr(err, _L("Couldn't read STDIN")); |
|
288 } |
|
289 } |
|
290 |
|
291 CleanupStack::PopAndDestroy(&file); |
|
292 } |
|
293 |
|
294 void CCmdBase64::EncodeL() |
|
295 { |
|
296 LeaveIfFileNotFound(iFileName); |
|
297 |
|
298 RFile file; |
|
299 User::LeaveIfError(file.Open(FsL(), iFileName, EFileRead | EFileStream)); |
|
300 CleanupClosePushL(file); |
|
301 |
|
302 TBuf8<KBlockSize> inputBuf; |
|
303 TBuf<KLineLength + 2> outputBuf; |
|
304 TBool finished(EFalse); |
|
305 while (!finished) |
|
306 { |
|
307 TPtr8 ptr((TUint8*)inputBuf.Ptr() + inputBuf.Length(), 0, inputBuf.MaxLength() - inputBuf.Length()); |
|
308 LeaveIfErr(file.Read(ptr), _L("Couldn't read from '%S'"), &iFileName); |
|
309 |
|
310 if (ptr.Length() > 0) |
|
311 { |
|
312 inputBuf.SetLength(inputBuf.Length() + ptr.Length()); |
|
313 const TInt inputBufLength = inputBuf.Length(); |
|
314 const TInt excess = inputBufLength % 3; |
|
315 const TInt bytesToProcess = inputBufLength - excess; |
|
316 |
|
317 for (TInt i = 0; i < bytesToProcess; i += 3) |
|
318 { |
|
319 // Combine the next three bytes into a 24 bit number. |
|
320 TInt n = ((TInt)inputBuf[i] << 16) + ((TInt)inputBuf[i + 1] << 8) + (TInt)inputBuf[i + 2]; |
|
321 |
|
322 // Split the 24-bit number into four 6-bit numbers. |
|
323 TUint8 n0 = (TUint8)(n >> 18) & 0x3F; |
|
324 TUint8 n1 = (TUint8)(n >> 12) & 0x3F; |
|
325 TUint8 n2 = (TUint8)(n >> 6) & 0x3F; |
|
326 TUint8 n3 = (TUint8)n & 0x3F; |
|
327 |
|
328 // Buffer the base64 encoded equivalent. |
|
329 outputBuf.Append(KBase64Chars[n0]); |
|
330 outputBuf.Append(KBase64Chars[n1]); |
|
331 outputBuf.Append(KBase64Chars[n2]); |
|
332 outputBuf.Append(KBase64Chars[n3]); |
|
333 |
|
334 // Flush output buffer if it's full. |
|
335 if (outputBuf.Length() == KLineLength) |
|
336 { |
|
337 outputBuf.Append(KNewLine); |
|
338 Write(outputBuf); |
|
339 outputBuf.Zero(); |
|
340 } |
|
341 } |
|
342 |
|
343 inputBuf.Delete(0, inputBufLength - excess); |
|
344 } |
|
345 else |
|
346 { |
|
347 // Process what's left over in inputBuf from the previous successful read, padding as required. |
|
348 const TInt inputBufLength = inputBuf.Length(); |
|
349 if (inputBufLength > 0) |
|
350 { |
|
351 TInt n = (TInt)inputBuf[0] << 16; |
|
352 if (inputBufLength > 1) |
|
353 { |
|
354 n += (TInt)inputBuf[1] << 8; |
|
355 if (inputBufLength > 2) |
|
356 { |
|
357 n += (TInt)inputBuf[2]; |
|
358 } |
|
359 } |
|
360 |
|
361 TUint8 n0 = (TUint8)(n >> 18) & 0x3F; |
|
362 TUint8 n1 = (TUint8)(n >> 12) & 0x3F; |
|
363 TUint8 n2 = (TUint8)(n >> 6) & 0x3F; |
|
364 TUint8 n3 = (TUint8)n & 0x3F; |
|
365 |
|
366 outputBuf.Append(KBase64Chars[n0]); |
|
367 outputBuf.Append(KBase64Chars[n1]); |
|
368 if (inputBufLength > 1) |
|
369 { |
|
370 outputBuf.Append(KBase64Chars[n2]); |
|
371 if (inputBufLength > 2) |
|
372 { |
|
373 outputBuf.Append(KBase64Chars[n3]); |
|
374 } |
|
375 } |
|
376 |
|
377 for (TInt i = inputBufLength; i < 3; ++i) |
|
378 { |
|
379 outputBuf.Append('='); |
|
380 } |
|
381 } |
|
382 |
|
383 if (outputBuf.Length() > 0) |
|
384 { |
|
385 outputBuf.Append(KNewLine); |
|
386 Write(outputBuf); |
|
387 } |
|
388 |
|
389 finished = ETrue; |
|
390 } |
|
391 } |
|
392 |
|
393 CleanupStack::PopAndDestroy(&file); |
|
394 } |
|
395 |
|
396 const TDesC& CCmdBase64::Name() const |
|
397 { |
|
398 _LIT(KName, "base64"); |
|
399 return KName; |
|
400 } |
|
401 |
|
402 void CCmdBase64::ArgumentsL(RCommandArgumentList& aArguments) |
|
403 { |
|
404 _LIT(KArgOperation, "operation"); |
|
405 aArguments.AppendEnumL((TInt&)iOperation, KArgOperation); |
|
406 |
|
407 _LIT(KArgFilename, "filename"); |
|
408 aArguments.AppendFileNameL(iFileName, KArgFilename); |
|
409 } |
|
410 |
|
411 void CCmdBase64::OptionsL(RCommandOptionList& aOptions) |
|
412 { |
|
413 _LIT(KOptVerbose, "verbose"); |
|
414 aOptions.AppendBoolL(iVerbose, KOptVerbose); |
|
415 |
|
416 _LIT(KOptOverwrite, "overwrite"); |
|
417 aOptions.AppendBoolL(iOverwrite, KOptOverwrite); |
|
418 } |
|
419 |
|
420 void CCmdBase64::DoRunL() |
|
421 { |
|
422 switch (iOperation) |
|
423 { |
|
424 case EDecode: |
|
425 DecodeL(); |
|
426 break; |
|
427 case EEncode: |
|
428 EncodeL(); |
|
429 break; |
|
430 default: |
|
431 ASSERT(EFalse); |
|
432 } |
|
433 } |