module dinc.mime.Encodings; /** * code to convert encodings... * * * based on my code in Part - I need to change Source to be a Buffered Input Stream!/. * */ import std.stream; char[] quotedPrintable(char[] in_str) { auto o_ms = new MemoryStream(); auto i_ms = new MemoryStream(in_str); quotedPrintable(i_ms, o_ms); return o_ms.toString(); } void quotedPrintable(InputStream source, OutputStream output, uint len=0) { char c = '\0'; char c1 = '\0'; char c2 = '\0'; int c1p = 0; int c2p = 0; int i = -1; while (!source.eof() && (!len || i < len)) { i++; c = source.getc(); if (char.init == c) { return; } if (c == '_') { output.write(' '); continue; } if (c != '=') { output.write(c); continue; } c1 = source.getc(); if (char.init == c1) { output.write(c); return; } c2 = source.getc(); if (char.init == c2) { output.write(c); output.write(c1); return; } c1p = std.string.find(std.string.hexdigits, c1); c2p = std.string.find(std.string.hexdigits, c2); // got an encoded str.. if ((c1p > -1) && (c2p > -1)) { std.stdio.writefln("CONV %s => %x", ""~ c1 ~ c2, (c1p << 4) + c2p); output.write(cast(char)((c1p << 4) + c2p)); i+=2; continue; } // unget the two chars.. source.ungetc(c2); source.ungetc(c1); int eaten = 0; while (true) { c1 = source.getc(); if (char.init == c1) { return; } i++; eaten++; if (len && (i >= len)) { // end of readable area! return; } if ((c1 == 32) || (c1 == 9)) { // space or tab... continue; } break; } // we have now eaten the white space... after = if (c1 == 10) { // got a \n after = -> just ignore it... continue; } if (c1 != 13) { // not a \r => write the =, then output =... output.write('='); for(int ii =0; ii < eaten; ii++) { // convert them all to spaces?!?!? output.write(' '); } // not a line break... - we have eaten the = and the spaces after it!!! // should be push them onto the sttream??? continue; } c1 = source.getc(); // eat the next char... if (char.init == c1) { return; //eof } if (c1 != 10) { source.ungetc(c1); continue; } i++; } } char[] base64(char[] in_str) { auto o_ms = new MemoryStream(); auto i_ms = new MemoryStream(in_str); base64(i_ms, o_ms); return o_ms.toString(); } void base64(InputStream source, OutputStream output, uint len=0) // must be wrapped in try/catch! { int i=0; // cant tell the lenght!!! //if(estr.length % 4) // throw new Base64Exception("Invalid encoded base64 string"); uint arrayIndex(char ch) { if(ch >= 'A' && ch <= 'Z') return ch - 'A'; if(ch >= 'a' && ch <= 'z') return 'Z' - 'A' + 1 + ch - 'a'; if(ch >= '0' && ch <= '9') return 'Z' - 'A' + 1 + 'z' - 'a' + 1 + ch - '0'; if(ch == '+') return 'Z' - 'A' + 1 + 'z' - 'a' + 1 + '9' - '0' + 1; if(ch == '/') return 'Z' - 'A' + 1 + 'z' - 'a' + 1 + '9' - '0' + 1 + 1; throw new Exception("invalid encoding"); } bool sgetChar(out char c) { if (len && i > len) { // end of what we are suppsed to read.. return false; } c = source.getc(); if (char.init == c) { return false; } if ((c == 32) || (c == 10) || (c == 13)) { return sgetChar(c); } i++; return true; } ///uint estrmax = estr.length / 4; uint x; char ch; char sp1; char sp2; while(true) { if (!sgetChar(sp1)) { return; // end!!! } if (!sgetChar(sp2)) { return; // end!!! } x = arrayIndex(sp1) << 18 | arrayIndex(sp2) << 12; if (!sgetChar(ch)) { return; // end!!! } if(ch == '=') { if (!sgetChar(ch)) { return; // end!!! } if(ch!= '=') { return; // invalid but we allow it.. } output.write(cast(char) (x >> 16)); return; } x |= arrayIndex(ch) << 6; if (!sgetChar(ch)) { return; // end!!! } if(ch == '=') { output.write(cast(char) (x >> 16)); output.write(cast(char) ((x >> 8) & 0xFF)); return; } x |= arrayIndex(ch); output.write(cast(char) (x >> 16)); output.write(cast(char) ((x >> 8) & 0xFF)); output.write(cast(char) (x & 0xFF)); } }