diff --git a/Base64.cpp b/Base64.cpp new file mode 100644 index 0000000..5733312 --- /dev/null +++ b/Base64.cpp @@ -0,0 +1,123 @@ + +#include "Base64.h" + +using FCPLib::Base64; +using FCPLib::IllegalBase64Exception; + +const char Base64::base64Alphabet[] = { + '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', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '~', '-'}; + +const char Base64::base64Dealphabet[] = { +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, +255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 255, 255, 255, 255, 255, 255, 255, 0, + 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, 255, 255, 255, 255, 255, 255, 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, 255, 255, 255, 255, 255 }; + + +std::string +Base64::base64Encode(const unsigned char *in, int len) +{ + std::string out(((len+2)/3)*4, '='); + int o = 0; + for (int i = 0; i < len;) { + int val = (in[i++] & 0xFF) << 16; + if (i < len) + val |= (in[i++] & 0xFF) << 8; + if (i < len) + val |= (in[i++] & 0xFF); + out[o++] = base64Alphabet[(val>>18) & 0x3F]; + out[o++] = base64Alphabet[(val>>12) & 0x3F]; + out[o++] = base64Alphabet[(val>>6) & 0x3F]; + out[o++] = base64Alphabet[val & 0x3F]; + } + return out; +} + +std::string +Base64::base64Decode(const std::string inStr) +{ + const char *in = inStr.c_str(); + int inLength = inStr.size(); + + // Strip trailing equals signs. + while ((inLength > 0) && (in[inLength-1] == '=')) + inLength--; + + // check if all characters are valid + for (int i = 0; i < inLength; ++i) + if( !( isalpha(in[i]) || isdigit(in[i]) || in[i] == '~' || in[i] == '-' ) ) + throw IllegalBase64Exception("illegal Base64 character"); + + int blocks = inLength/4; + int remainder = inLength & 3; + // wholeInLen and wholeOutLen are the the length of the input and output + // sequences respectively, not including any partial block at the end. + int wholeInLen = blocks*4; + int wholeOutLen = blocks*3; + int outLen = wholeOutLen; + switch (remainder) { + case 1: throw IllegalBase64Exception("illegal Base64 length"); + case 2: outLen = wholeOutLen+1; break; + case 3: outLen = wholeOutLen+2; break; + default: outLen = wholeOutLen; + } + std::string out(outLen, ' '); + int o = 0; + int i; + for (i = 0; i < wholeInLen;) { + int in1 = base64Dealphabet[(int)in[i]]; + int in2 = base64Dealphabet[(int)in[i+1]]; + int in3 = base64Dealphabet[(int)in[i+2]]; + int in4 = base64Dealphabet[(int)in[i+3]]; + int orValue = in1|in2|in3|in4; + if ((orValue & 0x80) != 0) + throw IllegalBase64Exception("illegal Base64 character"); + int outVal = (in1 << 18) | (in2 << 12) | (in3 << 6) | in4; + out[o] = (char) (outVal>>16); + out[o+1] = (char) (outVal>>8); + out[o+2] = (char) outVal; + i += 4; + o += 3; + } + int orValue = 0; + switch (remainder) { + case 2: + { + int in1 = base64Dealphabet[(int)in[i]]; + int in2 = base64Dealphabet[(int)in[i+1]]; + orValue = in1|in2; + int outVal = (in1 << 18) | (in2 << 12); + out[o] = (char) (outVal>>16); + } + break; + case 3: + { + int in1 = base64Dealphabet[(int)in[i]]; + int in2 = base64Dealphabet[(int)in[i+1]]; + int in3 = base64Dealphabet[(int)in[i+2]]; + orValue = in1|in2|in3; + int outVal = (in1 << 18) | (in2 << 12) | (in3 << 6); + out[o] = (char) (outVal>>16); + out[o+1] = (char) (outVal>>8); + } + break; + } + if ((orValue & 0x80) != 0) + throw IllegalBase64Exception("illegal Base64 character"); + return out; +} diff --git a/Base64.h b/Base64.h index 0563d4e..8d8926c 100644 --- a/Base64.h +++ b/Base64.h @@ -2,43 +2,23 @@ #define BASE64_H_INCLUDED #include +#include namespace FCPLib { -class Base64 { - static char base64Alphabet[]; + +class IllegalBase64Exception : public std::logic_error { public: - static std::string base64Encode(unsigned char *, int); + IllegalBase64Exception(std::string str) : std::logic_error(str) {} }; -char Base64::base64Alphabet[] = { - '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', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', '~', '-'}; - -std::string -Base64::base64Encode(unsigned char *in, int len) -{ - std::string out(((len+2)/3)*4, '='); - int o = 0; - for (int i = 0; i < len;) { - int val = (in[i++] & 0xFF) << 16; - if (i < len) - val |= (in[i++] & 0xFF) << 8; - if (i < len) - val |= (in[i++] & 0xFF); - out[o++] = base64Alphabet[(val>>18) & 0x3F]; - out[o++] = base64Alphabet[(val>>12) & 0x3F]; - out[o++] = base64Alphabet[(val>>6) & 0x3F]; - out[o++] = base64Alphabet[val & 0x3F]; - } - return out; -} +class Base64 { + const static char base64Alphabet[]; + const static char base64Dealphabet[]; +public: + static std::string base64Encode(const unsigned char *, int); + static std::string base64Decode(const std::string); +}; } diff --git a/FCPLib.h b/FCPLib.h index 3b7732f..0afc62d 100644 --- a/FCPLib.h +++ b/FCPLib.h @@ -3,5 +3,6 @@ #include "Node.h" #include "FCPResult.h" + #endif // FCPLIB_H_INCLUDED diff --git a/FCPResult.h b/FCPResult.h index 67bc34e..bdad491 100644 --- a/FCPResult.h +++ b/FCPResult.h @@ -4,8 +4,10 @@ #include #include #include +#include #include "JobTicket.h" +#include "Base64.h" namespace FCPLib { @@ -51,6 +53,26 @@ class TestDDAResponse { bool writeDirectory; }; +class PeerNote { +public: + PeerNote( Message::Ptr m ) + : nodeIdentifier( m->getField("NodeIdentifier") ), + noteText( Base64::base64Decode( m->getField("NoteText") ) ), + peerNoteType( boost::lexical_cast(m->getField("PeerNoteType")) ) + {} + std::string nodeIdentifier; + std::string noteText; + int peerNoteType; + + std::string toString() const { + return "NodeIdentifier="+nodeIdentifier+"\n"+ + "NodeText="+noteText+"\n"+ + "PeerNoteType="+boost::lexical_cast(peerNoteType)+"\n"; + } +}; + +typedef std::vector PeerNoteContainer; + /////////// struct GetMessage { @@ -105,6 +127,28 @@ struct TestDDAReplyConverter { } }; +struct PeerNotesConverter { + PeerNoteContainer + operator()( Response &resp ) + { + PeerNoteContainer ret; + int size = resp.size() - 1; + Response::iterator end = resp.begin() + size; + for (Response::iterator it = resp.begin(); it != end; ++it) + ret.push_back( PeerNote( (*it)->getMessage() ) ); + return ret; + } +}; + +struct PeerNoteConverter { + PeerNote + operator()( Response &resp ) + { + return PeerNote( resp.front()->getMessage() ); + } +}; + + ////////// template diff --git a/Node.cpp b/Node.cpp index 18b5517..11b1f55 100644 --- a/Node.cpp +++ b/Node.cpp @@ -110,7 +110,7 @@ Node::listPeers(const AdditionalFields& fields) return createResult( resp ); } -MessagePtrContainer +PeerNoteContainer Node::listPeerNotes(const std::string& identifier) { Message::Ptr m = Message::factory( std::string("ListPeerNotes") ); @@ -126,7 +126,7 @@ Node::listPeerNotes(const std::string& identifier) // ProtocolError or UnknownNodeIdentifier checkProtocolError(resp); // throws - return createResult( resp ); + return createResult( resp ); } Message::Ptr @@ -193,7 +193,7 @@ Node::modifyPeer(const std::string & nodeIdentifier, return createResult( resp ); } -Message::Ptr +PeerNote Node::modifyPeerNote(const std::string & nodeIdentifier, const std::string & noteText, int peerNoteType = 1) @@ -201,7 +201,7 @@ Node::modifyPeerNote(const std::string & nodeIdentifier, Message::Ptr m = Message::factory( std::string("ModifyPeerNote") ); m->setField("NodeIdentifier", nodeIdentifier); - m->setField("NoteText", noteText); + m->setField("NoteText", Base64::base64Encode((const unsigned char*)noteText.c_str(), noteText.size())); m->setField("PeerNoteType", "1"); // TODO: change to peerNoteType once it is used JobTicket::Ptr job = JobTicket::factory( "", m, false); @@ -214,7 +214,7 @@ Node::modifyPeerNote(const std::string & nodeIdentifier, // ProtocolError or UnknownNodeIdentifier checkProtocolError(resp); // throws - return createResult( resp ); + return createResult( resp ); } Message::Ptr diff --git a/Node.h b/Node.h index 4815937..8253c02 100644 --- a/Node.h +++ b/Node.h @@ -59,11 +59,11 @@ class Node { Message::Ptr listPeer(const std::string &); MessagePtrContainer listPeers(const AdditionalFields& = AdditionalFields()); - MessagePtrContainer listPeerNotes(const std::string&); + PeerNoteContainer listPeerNotes(const std::string&); Message::Ptr addPeer(const std::string &, bool isURL); Message::Ptr addPeer(const std::map &message); Message::Ptr modifyPeer(const std::string &, const AdditionalFields& = AdditionalFields()); - Message::Ptr modifyPeerNote(const std::string &, const std::string &, int); + PeerNote modifyPeerNote(const std::string &, const std::string &, int); Message::Ptr removePeer(const std::string &); Message::Ptr getNode(const AdditionalFields& = AdditionalFields()); Message::Ptr getConfig(const AdditionalFields& = AdditionalFields()); diff --git a/examples/list_peer_notes.cpp b/examples/list_peer_notes.cpp index 1a9a2b5..401fc58 100644 --- a/examples/list_peer_notes.cpp +++ b/examples/list_peer_notes.cpp @@ -11,12 +11,12 @@ int main( int argc, char* argv[]) { Node n("List Peer Notes Test", "", -1); - MessagePtrContainer peer_notes = n.listPeerNotes(argv[1]); + PeerNoteContainer peer_notes = n.listPeerNotes(argv[1]); - for (MessagePtrContainer::iterator it = peer_notes.begin(); + for (PeerNoteContainer::iterator it = peer_notes.begin(); it != peer_notes.end(); ++it) { - std::cout << (*it)->toString() << std::endl; + std::cout << it->toString() << std::endl; std::cout << std::endl; } n.shutdown();