Base64.cpp (5739B)
1 2 #include "precompiled.h" 3 #pragma hdrstop 4 5 /* 6 Copyright (c) 1996 Lars Wirzenius. All rights reserved. 7 8 June 14 2003: TTimo <ttimo@idsoftware.com> 9 modified + endian bug fixes 10 http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=197039 11 12 Redistribution and use in source and binary forms, with or without 13 modification, are permitted provided that the following conditions 14 are met: 15 16 1. Redistributions of source code must retain the above copyright 17 notice, this list of conditions and the following disclaimer. 18 19 2. Redistributions in binary form must reproduce the above copyright 20 notice, this list of conditions and the following disclaimer in the 21 documentation and/or other materials provided with the distribution. 22 23 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 27 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 /* 37 ============ 38 idBase64::Encode 39 ============ 40 */ 41 static const char sixtet_to_base64[] = 42 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 43 44 void idBase64::Encode( const byte *from, int size ) { 45 int i, j; 46 unsigned long w; 47 byte *to; 48 49 EnsureAlloced( 4*(size+3)/3 + 2 ); // ratio and padding + trailing \0 50 to = data; 51 52 w = 0; 53 i = 0; 54 while (size > 0) { 55 w |= *from << i*8; 56 ++from; 57 --size; 58 ++i; 59 if (size == 0 || i == 3) { 60 byte out[4]; 61 SixtetsForInt( out, w ); 62 for (j = 0; j*6 < i*8; ++j) { 63 *to++ = sixtet_to_base64[ out[j] ]; 64 } 65 if (size == 0) { 66 for (j = i; j < 3; ++j) { 67 *to++ = '='; 68 } 69 } 70 w = 0; 71 i = 0; 72 } 73 } 74 75 *to++ = '\0'; 76 len = to - data; 77 } 78 79 /* 80 ============ 81 idBase64::DecodeLength 82 returns the minimum size in bytes of the target buffer for decoding 83 4 base64 digits <-> 3 bytes 84 ============ 85 */ 86 int idBase64::DecodeLength( void ) const { 87 return 3*len/4; 88 } 89 90 /* 91 ============ 92 idBase64::Decode 93 ============ 94 */ 95 int idBase64::Decode( byte *to ) const { 96 unsigned long w; 97 int i, j; 98 size_t n; 99 static char base64_to_sixtet[256]; 100 static int tab_init = 0; 101 byte *from = data; 102 103 if (!tab_init) { 104 memset( base64_to_sixtet, 0, 256 ); 105 for (i = 0; (j = sixtet_to_base64[i]) != '\0'; ++i) { 106 base64_to_sixtet[j] = i; 107 } 108 tab_init = 1; 109 } 110 111 w = 0; 112 i = 0; 113 n = 0; 114 byte in[4] = {0,0,0,0}; 115 while (*from != '\0' && *from != '=' ) { 116 if (*from == ' ' || *from == '\n') { 117 ++from; 118 continue; 119 } 120 in[i] = base64_to_sixtet[* (unsigned char *) from]; 121 ++i; 122 ++from; 123 if (*from == '\0' || *from == '=' || i == 4) { 124 w = IntForSixtets( in ); 125 for (j = 0; j*8 < i*6; ++j) { 126 *to++ = w & 0xff; 127 ++n; 128 w >>= 8; 129 } 130 i = 0; 131 w = 0; 132 } 133 } 134 return n; 135 } 136 137 /* 138 ============ 139 idBase64::Encode 140 ============ 141 */ 142 void idBase64::Encode( const idStr &src ) { 143 Encode( (const byte *)src.c_str(), src.Length() ); 144 } 145 146 /* 147 ============ 148 idBase64::Decode 149 ============ 150 */ 151 void idBase64::Decode( idStr &dest ) const { 152 byte *buf = new (TAG_IDLIB) byte[ DecodeLength()+1 ]; // +1 for trailing \0 153 int out = Decode( buf ); 154 buf[out] = '\0'; 155 dest = (const char *)buf; 156 delete[] buf; 157 } 158 159 /* 160 ============ 161 idBase64::Decode 162 ============ 163 */ 164 void idBase64::Decode( idFile *dest ) const { 165 byte *buf = new (TAG_IDLIB) byte[ DecodeLength()+1 ]; // +1 for trailing \0 166 int out = Decode( buf ); 167 dest->Write( buf, out ); 168 delete[] buf; 169 } 170 171 #if 0 172 173 void idBase64_TestBase64() { 174 175 idStr src; 176 idBase64 dest; 177 src = "Encode me in base64"; 178 dest.Encode( src ); 179 idLib::common->Printf( "%s -> %s\n", src.c_str(), dest.c_str() ); 180 dest.Decode( src ); 181 idLib::common->Printf( "%s -> %s\n", dest.c_str(), src.c_str() ); 182 183 idDict src_dict; 184 src_dict.SetFloat("float", 0.5f); 185 src_dict.SetBool("bool", true); 186 src_dict.Set("value", "foo"); 187 idFile_Memory src_fmem("serialize_dict"); 188 src_dict.WriteToFileHandle( &src_fmem ); 189 dest.Encode( (const byte *)src_fmem.GetDataPtr(), src_fmem.Length() ); 190 idLib::common->Printf( "idDict encoded to %s\n", dest.c_str()); 191 192 // now decode to another stream and build back 193 idFile_Memory dest_fmem( "build_back" ); 194 dest.Decode( &dest_fmem ); 195 dest_fmem.MakeReadOnly(); 196 idDict dest_dict; 197 dest_dict.ReadFromFileHandle( &dest_fmem ); 198 idLib::common->Printf( "idDict reconstructed after base64 decode\n"); 199 dest_dict.Print(); 200 201 // test idDict read from file - from python generated files, see idDict.py 202 idFile *file = idLib::fileSystem->OpenFileRead("idDict.test"); 203 if (file) { 204 idDict test_dict; 205 test_dict.ReadFromFileHandle( file ); 206 // 207 idLib::common->Printf( "read idDict.test:\n"); 208 test_dict.Print(); 209 idLib::fileSystem->CloseFile(file); 210 file = NULL; 211 } else { 212 idLib::common->Printf( "idDict.test not found\n" ); 213 } 214 215 idBase64 base64_src; 216 void *buffer; 217 if ( idLib::fileSystem->ReadFile( "idDict.base64.test", &buffer ) != -1 ) { 218 idFile_Memory mem_src( "dict" ); 219 idLib::common->Printf( "read: %d %s\n", idStr::Length( (char*)buffer ), buffer ); 220 base64_src = (char *)buffer; 221 base64_src.Decode( &mem_src ); 222 mem_src.MakeReadOnly(); 223 idDict test_dict; 224 test_dict.ReadFromFileHandle( &mem_src ); 225 idLib::common->Printf( "read idDict.base64.test:\n"); 226 test_dict.Print(); 227 idLib::fileSystem->FreeFile( buffer ); 228 } else { 229 idLib::common->Printf( "idDict.base64.test not found\n" ); 230 } 231 } 232 233 #endif