diff options
-rw-r--r-- | apps/samples/miles/miles-connect.html | 52 | ||||
-rw-r--r-- | apps/samples/miles/miles-disconnect.html | 52 | ||||
-rw-r--r-- | apps/samples/miles/miles.html | 27 | ||||
-rw-r--r-- | apps/samples/miles/miles.js | 703 | ||||
-rw-r--r-- | apps/samples/miles/miles.scxml | 63 | ||||
-rw-r--r-- | apps/samples/miles/test1.jpeg | bin | 0 -> 10996 bytes | |||
-rw-r--r-- | apps/samples/miles/test2.jpeg | bin | 0 -> 40332 bytes | |||
-rw-r--r-- | src/uscxml/CMakeLists.txt | 7 | ||||
-rw-r--r-- | src/uscxml/Factory.cpp | 4 | ||||
-rw-r--r-- | src/uscxml/Message.h | 16 | ||||
-rw-r--r-- | src/uscxml/plugins/invoker/miles/MilesSessionInvoker.cpp | 58 | ||||
-rw-r--r-- | src/uscxml/plugins/invoker/miles/MilesSessionInvoker.h | 2 | ||||
-rw-r--r-- | src/uscxml/util/Base64.cpp | 129 | ||||
-rw-r--r-- | src/uscxml/util/Base64.h | 14 | ||||
-rw-r--r-- | src/uscxml/util/MD5.cpp | 406 | ||||
-rw-r--r-- | src/uscxml/util/MD5.h | 102 |
16 files changed, 873 insertions, 762 deletions
diff --git a/apps/samples/miles/miles-connect.html b/apps/samples/miles/miles-connect.html deleted file mode 100644 index ae5f77e..0000000 --- a/apps/samples/miles/miles-connect.html +++ /dev/null @@ -1,52 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html> -<head> - <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> - <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dijit/themes/tundra/tundra.css"> - <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojox/layout/resources/FloatingPane.css"> - <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojox/layout/resources/ResizeHandle.css"> - - <style type="text/css"> - </style> - - <script type="text/javascript"> - // dojoConfig = { - // async : false, - // isDebug : true, - // debugAtAllCosts : true, - // } - </script> - - <script src="http://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojo/dojo.js"></script> - <script type="text/javascript" src="viewer.js"></script> - - <script type="text/javascript"> - require(["dojo/domReady!", "dojo"], function(dom, dojo) { - var jsonHere = { - "email": "someone@here.com", - "reflectorIP": "88.131.107.12", - "problemName": "Fancy problem" - } - var xhr = dojo.require("dojo/_base/xhr"); - xhr.post({ - // The URL to request - url: "http://localhost:8080/miles/connect", - handleAs:"json", - postData: dojo.toJson(jsonHere), - headers:{ - "X-Requested-With": null, - "Content-Type": "application/json", - }, - load: function(result) { - - } - }); - }); - </script> - </head> - <body class="tundra"> - <div style="width: 600px; height: 400px"> - <div id="scene1"></div> - </div> - </body> -</html> diff --git a/apps/samples/miles/miles-disconnect.html b/apps/samples/miles/miles-disconnect.html deleted file mode 100644 index 30f5b39..0000000 --- a/apps/samples/miles/miles-disconnect.html +++ /dev/null @@ -1,52 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html> -<head> - <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> - <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dijit/themes/tundra/tundra.css"> - <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojox/layout/resources/FloatingPane.css"> - <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojox/layout/resources/ResizeHandle.css"> - - <style type="text/css"> - </style> - - <script type="text/javascript"> - // dojoConfig = { - // async : false, - // isDebug : true, - // debugAtAllCosts : true, - // } - </script> - - <script src="http://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojo/dojo.js"></script> - <script type="text/javascript" src="viewer.js"></script> - - <script type="text/javascript"> - require(["dojo/domReady!", "dojo"], function(dom, dojo) { - var jsonHere = { - "email": "someone@here.com", - "reflectorIP": "88.131.107.12", - "problemName": "Fancy problem" - } - var xhr = dojo.require("dojo/_base/xhr"); - xhr.post({ - // The URL to request - url: "http://localhost:8080/miles/disconnect", - handleAs:"json", - postData: dojo.toJson(jsonHere), - headers:{ - "X-Requested-With": null, - "Content-Type": "application/json", - }, - load: function(result) { - - } - }); - }); - </script> - </head> - <body class="tundra"> - <div style="width: 600px; height: 400px"> - <div id="scene1"></div> - </div> - </body> -</html> diff --git a/apps/samples/miles/miles.html b/apps/samples/miles/miles.html new file mode 100644 index 0000000..019ead4 --- /dev/null +++ b/apps/samples/miles/miles.html @@ -0,0 +1,27 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> + <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dijit/themes/tundra/tundra.css"> + + <style type="text/css"> + </style> + + <script type="text/javascript"> + </script> + + <script src="http://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojo/dojo.js"></script> + <script src="miles.js"></script> + + <script type="text/javascript"> + require(["dojo/domReady!"], function(dom) { + var milesSession = new Miles("miles1"); + }); + </script> + </head> + <body class="tundra"> + <div style="width: 600px; height: 400px"> + <div id="miles1"></div> + </div> + </body> +</html> diff --git a/apps/samples/miles/miles.js b/apps/samples/miles/miles.js index a3cdcae..b9348e8 100644 --- a/apps/samples/miles/miles.js +++ b/apps/samples/miles/miles.js @@ -1,664 +1,131 @@ function Miles(element, params) { - // private attributes var self = this; // private instanceId if (!Miles.instances) Miles.instances = 0; + + // public attributes this.instanceId = Miles.instances++; + this.element = element; + this.connected = false; + this.imageIteration = 0; + + // private attributes + var scxmlURL = "127.0.0.1:8080" + var reflectorIp = "127.0.0.1" + var email = "me@somehost.de"; + var problemName = "some really hard problem"; - // public attributes - this.reflectorURL = "127.0.0.1"; + // override with parameters if given this.params = params; - - // privileged public methods - this.foo = function() { - }; - - // privileged private methods - var bar = function(param1, param2) { + if (params && params.scxmlURL) scxmlURL = params.scxmlURL; + if (params && params.reflectorIp) reflectorIp = params.reflectorIp; + if (params && params.email) email = params.email; + if (params && params.problemName) problemName = params.problemName; + + this.connect = function() { + self.xhr.post({ + // The URL to request + url: "http://" + scxmlURL + "/miles/connect", + handleAs:"json", + postData: dojo.toJson({ + reflectorIp: reflectorIp, + email: email, + problemName: problemName + }), + headers:{ + "X-Requested-With": null, + "Content-Type": "application/json", + }, + load: function(result) { + // we expect nothing in return + self.connected = true; + // trigger continuously loading the image + refreshImage(); + } + }); + } + + var refreshImage = function() { + self.xhr.get({ + // The URL to request + url: "http://" + scxmlURL + "/miles/image", + handleAs:"text", + postData: dojo.toJson({ + reflectorIp: reflectorIp, + email: email, + problemName: problemName + }), + headers:{ + "X-Requested-With": null, + "Content-Type": "application/json", + }, + load: function(result) { + self.pictureElem.src = "data:image/jpeg;base64," + result; + if (self.connected) { + self.messageElem.innerHTML = self.imageIteration++; + refreshImage(); + } + } + }); + }; - // start of actual class after we fetched all dojo thingies require(["dojo/dom-construct", "dojo/_base/xhr", - "dojo/dom", - "dojo/on", - "dojox/storage", - "dojo/store/Memory", - "dojo/store/Observable", - "dijit/tree/ObjectStoreModel", - "dijit/Tree", - "dijit/form/TextBox", - "dijit/form/Button", - "dojox/widget/Standby", + "dojo/dom", "dijit/form/DropDownButton", "dijit/TooltipDialog", - "dojo/dnd/Moveable", - "dojo/ready", - "dojo/dnd/Source", - "dijit/form/HorizontalSlider", - "dijit/form/Select", - "dijit/form/NumberSpinner"], + "dojo/ready"], function(domConst, xhr, - dom, - on, - storage, - Memory, - Observable, - ObjectStoreModel, - Tree, - TextBox, - Button, - Standby, + dom, DropDownButton, TooltipDialog, - Moveable, - ready, - Source, - HorizontalSlider, - Selector, - NumberSpinner) { - + ready) { ready(function() { + self.xhr = xhr; if (typeof(element) === 'string') { element = dom.byId(element); } - - self.element = element; - self.xhr = xhr; - self.localStorage = dojox.storage.manager.getProvider(); - self.localStorage.initialize(); - - // establish our dom + element.appendChild(domConst.toDom('\ <table>\ <tr>\ <td valign="top">\ <div style="position: relative; padding: 0px">\ - <img class="model" src="' + self.resRoot + 'img/Tutorial.png" style="z-index: -1; width: ' + self.pose.width + 'px; height: ' + self.pose.height + 'px"></img>\ - <div style="z-index: 1; position: absolute; right: 45%; top: 45%">\ - <div class="progress"></div>\ - </div>\ + <img class="picture" src="test.jpeg"></img>\ <div style="position: absolute; left: 10px; top: 10px">\ <table></tr>\ - <td class="filesDropDown" style="vertical-align: middle"></td>\ - <td>\ - <div class="movieDropDown" style="display: inline"></div>\ - <button type="button" class="movieAddButton"></button>\ - </td>\ - <td align="right"><button type="button" class="resetButton"></button></td>\ - <td class="dragHandler" style="vertical-align: middle; padding-top: 4px;"></td>\ + <td class="control" style="vertical-align: middle"></td>\ </tr></table>\ </div>\ - <div style="position: absolute; right: 10px; top: 15%; height: 50%">\ - <div class="zoomSlide"></div>\ - </div>\ - <div style="position: absolute; right: 50%; top: 50%">\ - <div class="pitchRollHandler" style="font-size: 0.5em; background-color: rgba(255,255,255,0.5); border-radius: 5px; moz-border-radius: 5px;">\ - <table>\ - <tr>\ - <td><img class="pitchRollHandlerImg" src="' + self.resRoot + 'img/pitchRoll-handle.png" height="20px" style="padding: 2px 0px 0px 4px;" /></td>\ - <td><div class="pitchLabel"></div><div class="rollLabel"></div></td>\ - </tr>\ - </table>\ - </div>\ - </div>\ - <div style="position: absolute; right: 50%; top: 50%">\ - <div class="yawZoomHandler">\ - <div style="font-size: 0.5em; background-color: rgba(255,255,255,0.5); border-radius: 5px; moz-border-radius: 5px; position: absolute; left: -34px;">\ - <table>\ - <tr>\ - <td><img class="yawZoomHandlerImg" src="' + self.resRoot + 'img/yawZoom-handle.png" height="20px" style="padding: 2px 0px 0px 4px;" /></td>\ - <td><div class="yawLabel"></div><div class="zoomLabel"></div></td>\ - </tr>\ - </table>\ - </div>\ - </div>\ - </div>\ - <div style="position: absolute; right: 50%; top: 50%">\ - <div class="xyHandler" style="font-size: 0.5em; background-color: rgba(255,255,255,0.5); border-radius: 5px; moz-border-radius: 5px;">\ - <table>\ - <tr>\ - <td><img class="xyHandlerImg" src="' + self.resRoot + 'img/xy-handle.png" width="20px" style="padding: 2px 0px 0px 4px;" /></td>\ - <td><div class="xLabel"></div><div class="yLabel"></div></td>\ - </tr>\ - </table>\ - </div>\ - </div>\ </div>\ </td>\ - <td valign="top" height="100%">\ - </td>\ </tr>\ <tr>\ - <td colspan="2"><div class="messages"></div></td>\ + <td valign="top">\ + <div class="messages" style="position: relative; padding: 0px">\ + </td>\ </tr>\ </table>\ ')); - // fetch special dom nodes for content - self.messageBox = dojo.query("div.messages", element)[0]; - self.imgElem = dojo.query("img.model", element)[0]; - - /** - * === POSE MANIPULATION AND RESET ==================== - */ - - self.resetButtonElem = dojo.query("button.resetButton", element)[0]; - self.progressElem = dojo.query("div.progress", element)[0]; - self.pitchRollHandlerElem = dojo.query(".pitchRollHandler", element)[0]; - self.yawZoomHandlerElem = dojo.query(".yawZoomHandler", element)[0]; - self.xyHandlerElem = dojo.query(".xyHandler", element)[0]; - - self.pitchRollHandler = new Moveable(self.pitchRollHandlerElem); - self.pitchRollHandler.onMoveStop = function(mover) { - var handlerImg = dojo.query("img.pitchRollHandlerImg", mover.node)[0]; - var pitchLabel = dojo.query("div.pitchLabel", mover.node)[0]; - var rollLabel = dojo.query("div.rollLabel", mover.node)[0]; - - pitchLabel.innerHTML = ''; - rollLabel.innerHTML = ''; - - self.updateScene(); - }; - self.pitchRollHandler.onMoving = function(mover) { - // mover.node.style.backgroundColor = "rgba(255,255,255,0.5)"; - // mover.node.style.borderRadius = "5px"; - // mover.node.style.mozBorderRadius = "5px"; - // mover.node.style.webkitBorderRadius = "5px"; - var handlerImg = dojo.query(".pitchRollHandlerImg", mover.node)[0]; - var pitchLabel = dojo.query(".pitchLabel", mover.node)[0]; - var rollLabel = dojo.query(".rollLabel", mover.node)[0]; - var offset = moverRelativeTo(handlerImg, self.element); - - offset.x += 30; - offset.y += 20; - - self.xyHandlerElem.style.zIndex = 1; - self.yawZoomHandlerElem.style.zIndex = 1; - self.pitchRollHandlerElem.style.zIndex = 2; - - // self.pose.pitch = self.pose.pitch % (2 * 3.14159); - // self.pose.roll = self.pose.roll % (2 * 3.14159); - self.pose.roll = offset.x / self.pose.width - 0.5; - self.pose.pitch = offset.y / self.pose.height - 0.5; - self.pose.pitch *= -1; - self.pose.roll *= 2 * 3.14159; - self.pose.pitch *= 2 * 3.14159; - self.pose.roll = Math.ceil((self.pose.roll) * 10) / 10; - self.pose.pitch = Math.ceil((self.pose.pitch) * 10) / 10; - pitchLabel.innerHTML = 'Pitch:' + self.pose.pitch; - rollLabel.innerHTML = 'Roll:' + self.pose.roll; - }; - - self.yawZoomHandler = new Moveable(self.yawZoomHandlerElem); - self.yawZoomHandler.onMoveStop = function(mover) { - var handlerImg = dojo.query("img.yawZoomHandlerImg", mover.node)[0]; - var yawLabel = dojo.query("div.yawLabel", mover.node)[0]; - var zoomLabel = dojo.query("div.zoomLabel", mover.node)[0]; - - yawLabel.innerHTML = ''; - zoomLabel.innerHTML = ''; - - self.updateScene(); - }; - self.yawZoomHandler.onMoving = function(mover) { - var handlerImg = dojo.query("img.yawZoomHandlerImg", mover.node)[0]; - var yawLabel = dojo.query("div.yawLabel", mover.node)[0]; - var zoomLabel = dojo.query("div.zoomLabel", mover.node)[0]; - var offset = moverRelativeTo(handlerImg, self.element); - - offset.x += 7; - offset.y += 9; - - self.xyHandlerElem.style.zIndex = 1; - self.yawZoomHandlerElem.style.zIndex = 2; - self.pitchRollHandlerElem.style.zIndex = 1; - - // self.pose.pitch = self.pose.pitch % (2 * 3.14159); - // self.pose.roll = self.pose.roll % (2 * 3.14159); - self.pose.yaw = (self.pose.width - offset.x) / self.pose.width - 0.5; - self.pose.zoom = offset.y / self.pose.height - 0.5; - self.pose.yaw *= 2 * 3.14159; - self.pose.zoom = self.pose.zoom * 3 + 1; - self.pose.zoom = Math.ceil((self.pose.zoom) * 10) / 10; - self.pose.yaw = Math.ceil((self.pose.yaw) * 10) / 10; - yawLabel.innerHTML = 'Yaw:' + self.pose.yaw; - zoomLabel.innerHTML = 'Zoom:' + self.pose.zoom; - }; - - self.xyHandler = new Moveable(self.xyHandlerElem); - self.xyHandler.onMoveStop = function(mover) { - var handlerImg = dojo.query("img.xyHandlerImg", mover.node)[0]; - var xLabel = dojo.query("div.xLabel", mover.node)[0]; - var yLabel = dojo.query("div.yLabel", mover.node)[0]; - - xLabel.innerHTML = ''; - yLabel.innerHTML = ''; - - self.updateScene(); - }; - self.xyHandler.onMoving = function(mover) { - var handlerImg = dojo.query("img.xyHandlerImg", mover.node)[0]; - var xLabel = dojo.query("div.xLabel", mover.node)[0]; - var yLabel = dojo.query("div.yLabel", mover.node)[0]; - var offset = moverRelativeTo(handlerImg, self.element); - - offset.x += 3; - offset.y += 13; - - self.xyHandlerElem.style.zIndex = 2; - self.yawZoomHandlerElem.style.zIndex = 1; - self.pitchRollHandlerElem.style.zIndex = 1; - - self.pose.x = offset.x / self.pose.width - 0.5; - self.pose.y = offset.y / self.pose.height - 0.5; - self.pose.x *= 100; - self.pose.y *= 100; - self.pose.y = Math.ceil((self.pose.y) * 10) / 10; - self.pose.x = Math.ceil((self.pose.x) * 10) / 10; - xLabel.innerHTML = 'X:' + self.pose.x; - yLabel.innerHTML = 'Y:' + self.pose.y; - }; - - /** - * === FILES DROPDOWN ==================== - */ - - self.filesDropDownElem = dojo.query("td.filesDropDown", element)[0]; - - self.createAvatar = function(item, mode) { - if (mode == 'avatar') { - // create your avatar if you want - var avatar = dojo.create( 'div', { innerHTML: item.data }); - var avatarPose = dojo.clone(self.pose); - avatarPose.width=60; - avatarPose.height=60; - var avatarImgUrl = urlSuffixForPose(avatarPose); - avatar.innerHTML = '<img src=' + self.imageURL + avatarImgUrl + ' /> '; - item.srcEcc = "VRMLViewer"; - item.iconPoseUrl = self.imageURL + avatarImgUrl; - item.imageURL = self.imageURL; - item.serverURL = self.serverURL; - item.pose = avatarPose; - return {node: avatar, data: item, type: item.type}; - } - var handler = dojo.create( 'div', { innerHTML: '<img src="' + self.resRoot + 'img/drag.png" width="20px" />' }); - return {node: handler, data: item, type: item.type}; - }; - - self.dragHandler = new Source(dojo.query("td.dragHandler", element)[0], {copyOnly: true, creator: self.createAvatar}); - self.dragHandler.insertNodes(false, [ { } ]); - - // setup fileStore for tree list - self.fileStore = new Observable(new Memory({ - data: [ { id: 'root', name:'3D Models'} ], - getChildren: function(object){ - return this.query({parent: object.id}); - } - })); - self.fileTreeModel = new ObjectStoreModel({ - store: self.fileStore, - query: { id: "root" } - }); - - // setup actual tree dijit - self.fileList = new dijit.Tree({ - id: "fileList" + self.instanceId, - model: self.fileTreeModel, - persist: false, - showRoot: false, - style: "height: 300px;", - onClick: function(item){ - if ('url' in item) { - self.imageURL = item.url; - self.updateScene(); - } - }, - getIconClass: function(item, opened) { - return (!item || !('url' in item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "dijitLeaf"; - }, - getIconStyle: function(item, opened){ - if('url' in item) { - return { backgroundImage: "url('" + item.url + "?width=16&height=16')"}; - } - } - //return {backgroundImage: "url('" + item.url + "?width=16&height=16')"}; - - }); - - if (self.params && self.params.serverURL) - self.serverURL = self.params.serverURL; - var savedServerURL = self.localStorage.get("vrmlServer"); - if (savedServerURL && !self.serverURL) { - self.serverURL = savedServerURL; - self.refreshServer(savedServerURL); - } - - self.serverBox = new TextBox({ - name: "Server", - value: self.serverURL, - style: "width: 65%", - - onKeyUp: function(e) { - if (self.browseButton) { - if (this.get("value") !== self.serverURL) { - self.browseButton.setAttribute('label', 'Browse'); - } else { - self.browseButton.setAttribute('label', 'Refresh'); - } - } - }, - - onKeyDown: function(e) { - var code = e.keyCode || e.which; - if( code === 13 ) { - e.preventDefault(); - self.refreshServer(this.get("value")); - return false; - } - }, - }); - - self.browseButton = new Button({ - label: "Browse", - onClick: function(){ - self.refreshServer(self.serverBox.get("value")); - } - }); - - self.filesDropDownContent = domConst.toDom('<div />'); - self.filesDropDownContent.appendChild(self.serverBox.domNode); - self.filesDropDownContent.appendChild(self.browseButton.domNode); - self.filesDropDownContent.appendChild(self.fileList.domNode); - - self.filesToolTip = new TooltipDialog({ content:self.filesDropDownContent, style:"max-height:320px"}); - self.filesDropDown = new DropDownButton({ label: "Files", dropDown: self.filesToolTip }); - self.filesDropDownElem.appendChild(self.filesDropDown.domNode); - - self.fileStandby = new Standby({target: self.filesDropDownContent }); - self.filesDropDownContent.appendChild(self.fileStandby.domNode); - - /** - * === MOVIE DROPDOWN ==================== - */ - - self.movieDropDownElem = dojo.query("div.movieDropDown", element)[0]; - self.movieAddButtonElem = dojo.query("button.movieAddButton", element)[0]; - - self.movieDropDownContent = domConst.toDom( - '<div style="overflow: auto; max-height: 420px;"> \ - <table><tr class="movieFormatLengthRow" /></tr><tr class="movieWidthHeightLengthRow" /></table> \ - <div class=\"dndArea\" /> \ - </div>' - ); - - self.movieFormatLengthRowElem = dojo.query("tr.movieFormatLengthRow", self.movieDropDownContent)[0]; - self.movieWidthHeightLengthRowElem = dojo.query("tr.movieWidthHeightLengthRow", self.movieDropDownContent)[0]; - self.movieDnDArea = dojo.query("div.dndArea", self.movieDropDownContent)[0]; + self.pictureElem = dojo.query("img.picture", element)[0]; + self.controlElem = dojo.query("td.control", element)[0]; + self.messageElem = dojo.query("div.messages", element)[0]; - self.createMovieThumb = function(item, mode) { - if (mode == 'avatar') { - // when dragged - var avatar = dojo.create( 'div', { innerHTML: item.data }); - var avatarPose = dojo.clone(self.pose); - avatarPose.width = 60; - avatarPose.height = 60; - var avatarImgUrl = urlSuffixForPose(avatarPose); - avatar.innerHTML = '<img src=' + self.imageURL + avatarImgUrl + ' /> '; - item.srcEcc = "VRMLViewer"; - item.iconPoseUrl = self.imageURL + avatarImgUrl; - item.imageURL = self.imageURL; - item.serverURL = self.serverURL; - item.pose = avatarPose; - return {node: avatar, data: item, type: item.type}; - } else { - - // when added to list - var thumb = domConst.toDom("\ - <div>\ - <table><tr><td>\ - <img class=\"movieThumb\"/>\ - <img class=\"removeThumb\" style=\"vertical-align: top; margin: -3px 0px 0px -8px; width: 20px; height: 20px;\"/>\ - </td><td align=\"left\">\ - <table><tr>\ - <td>Frame:</td><td><div class=\"relFrameLength\"/></td>\ - <td><div class=\"fillInSeries\" \></td>\ - </tr><tr>\ - <td>Transition:</td><td><div class=\"relTransitionLength\"/></td>\ - </tr></table>\ - </td></tr></table>\ - </div>\ - "); - thumb = dojo.query("div", thumb)[0]; - - var thumbImgElem = dojo.query("img.movieThumb", thumb)[0]; - var removeImgElem = dojo.query("img.removeThumb", thumb)[0]; - var relFrameLengthElem = dojo.query("div.relFrameLength", thumb)[0]; - var relTransitionLengthElem = dojo.query("div.relTransitionLength", thumb)[0]; - var fillInSeriesElem = dojo.query("div.fillInSeries", thumb)[0]; - - item.getThisAndNeighborsFromDnD = function() { - var thisAndNeighbors = {}; - self.addToMovieHandler.forInItems(function(obj, key, ctx) { - if (obj.data === item) { - thisAndNeighbors.this = { key: key, obj: obj }; - } else { - thisAndNeighbors.before = { key: key, obj: obj }; - } - if (thisAndNeighbors.this) { - thisAndNeighbors.after = { key: key, obj: obj }; - return thisAndNeighbors; - } - }); - return thisAndNeighbors; - }; - - item.relFrameLengthSlider = new HorizontalSlider({ - value: 50, - title: "Relative Duration of Frame", - style: "width:150px;" - }, relFrameLengthElem); - - item.relTransitionLengthSlider = new HorizontalSlider({ - value: 100, - title: "Relative Duration of Transition", - style: "width:150px;" - }, relTransitionLengthElem); - - removeImgElem.onclick = function() { - var thisItem = item.getThisAndNeighborsFromDnD(); - if (thisItem.this) { - // haha - what a mess! - self.addToMovieHandler.selectNone(); - self.addToMovieHandler.selection[thisItem.this.key] = thisItem.this.obj; - self.addToMovieHandler.deleteSelectedNodes(); - } - // disable create button if this was the last one - if (!thisItem.after || !thisItem.before) { - self.movieCreateButton.setAttribute('disabled', true); - } - } - - item.fillInSeriesButton = new Button({ - label: "Insert Series", - style: "display: none;", - onClick: function(){ - alert("foo"); - } - }, fillInSeriesElem); - - removeImgElem.src = self.resRoot + "img/close.png"; - - var thumbPose = dojo.clone(self.pose); - thumbPose.width = self.pose.width / 10; - thumbPose.height = self.pose.height / 10; - var thumbImgUrl = urlSuffixForPose(thumbPose); - - thumbImgElem.src = self.imageURL + thumbImgUrl; - // removeImgElem.src = self.resRoot + 'img/close.png'; - - item.srcEcc = "VRMLViewer"; - item.iconPoseUrl = self.imageURL + thumbImgUrl; - item.imageURL = self.imageURL; - item.serverURL = self.serverURL; - item.pose = thumbPose; - - return {node: thumb, data: item, type: item.type}; - } - }; - - self.addToMovieHandler = new Source(self.movieDnDArea, {copyOnly: true, creator: self.createMovieThumb}); - - self.movieFormatSelection = new Selector({ - name: "movieFormat", - style: "width: 320px", - options: [] - }); - self.populateMovieCodecs(self.serverURL + '/movie/codecs', self.movieFormatSelection); - - self.movieFormatLengthRowElem.appendChild(dojo.create('td', { innerHTML: 'Format:'} )); - self.movieFormatLengthRowElem.appendChild(dojo.create('td', { colspan: "2"})); - self.movieFormatLengthRowElem.lastChild.appendChild(self.movieFormatSelection.domNode); + // the control dropdown button + self.controlDropDownContent = domConst.toDom('<div />'); + self.controlToolTip = new TooltipDialog({ content:self.controlDropDownContent, style:"max-height:320px"}); + self.controlDropDown = new DropDownButton({ label: "Connect", dropDown: self.controlToolTip }); + self.controlElem.appendChild(self.controlDropDown.domNode); - self.movieHeightSpinner = new NumberSpinner({ - value: 400, - smallDelta: 1, - style: "width: 60px", - constraints: { min:40, places:0 }, - }); + self.connect(); - self.movieWidthSpinner = new NumberSpinner({ - value: 600, - smallDelta: 1, - style: "width: 60px", - constraints: { min:40, places:0 }, - }); - - self.movieCreateButton = new Button({ - label: "Create", - disabled: true, - onClick: function(){ - - var form = document.createElement("form"); - - form.setAttribute("method", "post"); - form.setAttribute("action", self.serverURL + "/movie"); - - var submitData = {}; - submitData.frames = []; - submitData.movieLength = self.movieDurationSpinner.value; - submitData.format = self.movieFormatSelection.value; - submitData.width = self.movieWidthSpinner.value; - submitData.height = self.movieHeightSpinner.value; - - self.addToMovieHandler.forInItems(function(obj, key, ctx) { - var jsonData = { - iconPoseUrl: obj.data.iconPoseUrl, - imageURL: obj.data.imageURL, - serverURL: obj.data.serverURL, - pose: obj.data.pose, - relFrameLength: obj.data.relFrameLengthSlider.value, - relTransitionLength: obj.data.relTransitionLengthSlider.value, - } - submitData.frames.push(jsonData); - }); - - var hiddenField = document.createElement("input"); - hiddenField.setAttribute("type", "hidden"); - hiddenField.setAttribute("name", "data"); - hiddenField.setAttribute("value", JSON.stringify(submitData)); - - form.appendChild(hiddenField); - - // this will not save the returned binary file - // self.xhr.post({ - // form: form, - // load: function(data){ - // alert("asd"); - // } - // }); - - document.body.appendChild(form); - form.submit(); - document.body.removeChild(form); - } - }); - - self.movieDurationSpinner = new NumberSpinner({ - value: 10, - smallDelta: 1, - style: "width: 40px", - constraints: { min:0, places:0 }, - }); - - // append format duration cell - self.movieWidthHeightLengthRowElem.appendChild(dojo.create('td', { innerHTML: 'Size:'} )); - var movieDimensionCell = dojo.create('td'); - movieDimensionCell.appendChild(self.movieWidthSpinner.domNode); - movieDimensionCell.appendChild(dojo.create('span', { innerHTML: "x"} )); - movieDimensionCell.appendChild(self.movieHeightSpinner.domNode); - movieDimensionCell.appendChild(self.movieDurationSpinner.domNode); - movieDimensionCell.appendChild(dojo.create('span', { innerHTML: "sec"} )); - self.movieWidthHeightLengthRowElem.appendChild(movieDimensionCell); - - self.movieWidthHeightLengthRowElem.appendChild(dojo.create('td', { align: "right"})); - self.movieWidthHeightLengthRowElem.lastChild.appendChild(self.movieCreateButton.domNode); - - - self.movieToolTip = new TooltipDialog({ content:self.movieDropDownContent }); - self.movieDropDown = new DropDownButton({ - label: "Movie", - style: "display: none;", - dropDown: self.movieToolTip }); - self.movieDropDownElem.appendChild(self.movieDropDown.domNode); - - self.movieAddButton = new Button({ - label: "+", - style: "margin-left: -10px; display: none;", - onClick: function(){ - if (self.movieFormatSelection.options.length == 0) { - self.populateMovieCodecs(self.serverURL + '/movie/codecs', self.movieFormatSelection); - } - // we could pass item.data here to creator - self.addToMovieHandler.insertNodes(false, [ { } ]); - self.movieCreateButton.setAttribute('disabled', false); - - } - }, self.movieAddButtonElem); - - - self.resetButton = new Button({ - label: "Reset", - onClick: function(){ - self.pose.x = 0; - self.pose.y = 0; - self.pose.pitch = 0; - self.pose.roll = 0; - self.pose.yaw = 0; - self.pose.zoom = 1; - - self.xyHandler.node.style.left = 0; - self.xyHandler.node.style.top = 0; - self.pitchRollHandler.node.style.left = 0; - self.pitchRollHandler.node.style.top = 0; - self.yawZoomHandler.node.style.left = 0; - self.yawZoomHandler.node.style.top = 0; - - self.updateScene(); - } - }, self.resetButtonElem); - - // do we have parameters for the initial pose? - if(self.params && self.params.pose) - self.setPose(self.params.imageURL, self.params.pose, self.params.serverURL); - - }); - }); - - + }) + }); } diff --git a/apps/samples/miles/miles.scxml b/apps/samples/miles/miles.scxml index 524729f..7014502 100644 --- a/apps/samples/miles/miles.scxml +++ b/apps/samples/miles/miles.scxml @@ -4,48 +4,55 @@ <invoke type="miles" id="miles"> <param name="foo" expr="'asdf'" /> <finalize> - <script> - </script> + <if cond="_event.data.origin"> + <!-- log label="Reply-length" expr="_event.data.base64.length" / --> + <respond status="200" to="_event.data.origin"> + <header name="Content-Type" value="text/ascii" /> + <content expr="_event.data.base64" /> + </respond> + </if> </finalize> </invoke> <state id="idle"> - <!-- XHR CORS preflight response --> + <!-- XHR CORS preflight respond --> <transition event="http.options" target="idle"> - <script>dump(_event);</script> - <response status="200" requestexpr="_event.origin"> + <script>//dump(_event);</script> + <respond status="200" to="_event.origin"> <header name="Access-Control-Allow-Origin" value="*" /> <header name="Access-Control-Allow-Methods" value="GET, OPTIONS" /> <header name="Access-Control-Allow-Headers" value="X-Requested-With" /> - </response> + </respond> </transition> - <transition event="http.post" target="idle"> - <script>dump(_event);</script> + <transition event="http.*" target="idle"> + <script>//dump(_event);</script> <if cond="_event.data.pathComponent[1] === 'session'"> - <response status="200" requestexpr="_event.origin" /> + <respond status="200" to="_event.origin" /> + + <elseif cond="_event.data.pathComponent[1] === 'connect'" /> + <send target="#_miles" event="connect"> + <param name="reflectorIP" expr="_event.data.content.reflectorIP" /> + <param name="email" expr="_event.data.content.email" /> + <param name="problemName" expr="_event.data.content.problemName" /> + </send> + <respond status="200" to="_event.origin" /> - <elseif cond="_event.data.pathComponent[1] === 'connect'"> - <send target="#_miles" event="connect"> - <param name="reflectorIP" expr="_event.data.content.reflectorIP" /> - <param name="email" expr="_event.data.content.email" /> - <param name="problemName" expr="_event.data.content.problemName" /> - </send> - <response status="200" requestexpr="_event.origin" /> - - </elseif> - <elseif cond="_event.data.pathComponent[1] === 'disconnect'"> - <send target="#_miles" event="disconnect"> - <param name="reflectorIP" expr="_event.data.content.reflectorIP" /> - <param name="problemName" expr="_event.data.content.problemName" /> - </send> - <response status="200" requestexpr="_event.origin" /> + <elseif cond="_event.data.pathComponent[1] === 'disconnect'" /> + <send target="#_miles" event="disconnect"> + <param name="reflectorIP" expr="_event.data.content.reflectorIP" /> + <param name="problemName" expr="_event.data.content.problemName" /> + </send> + <respond status="200" to="_event.origin" /> - </elseif> - <else> - <response status="404" requestexpr="_event.origin" /> + <elseif cond="_event.data.pathComponent[1] === 'image'" /> + <send target="#_miles" event="image"> + <param name="origin" expr="_event.origin" /> + </send> + + <else /> + <respond status="404" to="_event.origin" /> - </else> </if> </transition> </state> diff --git a/apps/samples/miles/test1.jpeg b/apps/samples/miles/test1.jpeg Binary files differnew file mode 100644 index 0000000..e174f89 --- /dev/null +++ b/apps/samples/miles/test1.jpeg diff --git a/apps/samples/miles/test2.jpeg b/apps/samples/miles/test2.jpeg Binary files differnew file mode 100644 index 0000000..aca2300 --- /dev/null +++ b/apps/samples/miles/test2.jpeg diff --git a/src/uscxml/CMakeLists.txt b/src/uscxml/CMakeLists.txt index cf52a77..20c9010 100644 --- a/src/uscxml/CMakeLists.txt +++ b/src/uscxml/CMakeLists.txt @@ -9,6 +9,13 @@ file(GLOB_RECURSE USCXML_SERVER source_group("Interpreter" FILES ${USCXML_SERVER}) list (APPEND USCXML_FILES ${USCXML_SERVER}) +file(GLOB_RECURSE USCXML_UTIL + util/*.cpp + util/*.h +) +source_group("Interpreter" FILES ${USCXML_UTIL}) +list (APPEND USCXML_FILES ${USCXML_UTIL}) + file(GLOB_RECURSE USCXML_CONCURRENCY concurrency/*.cpp concurrency/*.h diff --git a/src/uscxml/Factory.cpp b/src/uscxml/Factory.cpp index ae7af11..d73e25d 100644 --- a/src/uscxml/Factory.cpp +++ b/src/uscxml/Factory.cpp @@ -149,8 +149,8 @@ Factory::Factory() { #ifdef MILES_FOUND { // eats 8MB of RAM! -// MilesSessionInvoker* invoker = new MilesSessionInvoker(); -// registerInvoker(invoker); + MilesSessionInvoker* invoker = new MilesSessionInvoker(); + registerInvoker(invoker); } { SpatialAudio* invoker = new SpatialAudio(); diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h index bc92180..3008a99 100644 --- a/src/uscxml/Message.h +++ b/src/uscxml/Message.h @@ -16,6 +16,9 @@ #include "uscxml/Convenience.h" +#include "uscxml/util/MD5.h" +#include "uscxml/util/Base64.h" + #define TAGNAME(elem) ((Arabica::DOM::Element<std::string>)elem).getTagName() #define LOCALNAME(elem) ((Arabica::DOM::Element<std::string>)elem).getLocalName() #define ATTR(elem, attr) ((Arabica::DOM::Element<std::string>)elem).getAttribute(attr) @@ -31,6 +34,19 @@ public: char* data; size_t size; std::string mimetype; + + std::string md5() { + return uscxml::md5(data, size); + } + + std::string base64() { + return base64_encode((char* const)data, size); + } + + Blob* fromBase64(const std::string base64) { + std::string decoded = base64_decode(base64); + return new Blob((void*)decoded.c_str(), decoded.length()); + } }; class Data { diff --git a/src/uscxml/plugins/invoker/miles/MilesSessionInvoker.cpp b/src/uscxml/plugins/invoker/miles/MilesSessionInvoker.cpp index 8d19019..80bcce8 100644 --- a/src/uscxml/plugins/invoker/miles/MilesSessionInvoker.cpp +++ b/src/uscxml/plugins/invoker/miles/MilesSessionInvoker.cpp @@ -39,20 +39,57 @@ Data MilesSessionInvoker::getDataModelVariables() { void MilesSessionInvoker::send(const SendRequest& req) { // std::cout << req; if (boost::iequals(req.name, "disconnect")) { - std::string reflectorIP = req.params.find("reflectorip")->second; - std::string problemName = req.params.find("problemname")->second; + std::string reflectorIP = "127.0.0.1"; + Event::getParam(req.params, "reflectorip", reflectorIP); + + std::string problemName = "Generic"; + Event::getParam(req.params, "problemname", problemName); + int rv; rv = miles_disconnect_reflector_session((char*)reflectorIP.c_str(), (char*)problemName.c_str()); if (!rv) { LOG(ERROR) << "Could not disconnect from reflector session"; return; } - - } - if (boost::iequals(req.name, "connect")) { - std::string email = req.params.find("email")->second; - std::string reflectorIP = req.params.find("reflectorip")->second; - std::string problemName = req.params.find("problemname")->second; + } else if (boost::iequals(req.name, "image")) { + // client wants an image + URL imageURL1("test1.jpeg"); + URL imageURL2("test2.jpeg"); + + imageURL1.toAbsolute(_interpreter->getBaseURI()); + imageURL2.toAbsolute(_interpreter->getBaseURI()); + + std::stringstream ssImage; + + if (alternate) { + ssImage << imageURL1; + } else { + ssImage << imageURL2; + } + alternate = !alternate; + + std::string imageContent = ssImage.str(); + + Event retEv; + retEv.data.compound["base64"] = Data(base64_encode(imageContent.data(), imageContent.size()), Data::VERBATIM); + + std::string origin; + Event::getParam(req.params, "origin", origin); + retEv.data.compound["origin"] = origin; + + tthread::this_thread::sleep_for(tthread::chrono::milliseconds(20)); + + returnEvent(retEv); + + } else if (boost::iequals(req.name, "connect")) { + std::string email = "someSaneDefault"; + Event::getParam(req.params, "email", email); + + std::string reflectorIP = "127.0.0.1"; + Event::getParam(req.params, "reflectorip", reflectorIP); + + std::string problemName = "Generic"; + Event::getParam(req.params, "problemname", problemName); int rv; rv = miles_connect_reflector_session((char*)reflectorIP.c_str(), (char*)problemName.c_str()); @@ -168,8 +205,9 @@ void MilesSessionInvoker::send(const SendRequest& req) { // audio_transmitter(audio_dev, audio_encoder, out_rtp_audio_stream, out_rtcp_audio_stream); // } - _audioThread = new tthread::thread(MilesSessionInvoker::runAudio, this); - _videoThread = new tthread::thread(MilesSessionInvoker::runVideo, this); + // don't start threads for mockup +// _audioThread = new tthread::thread(MilesSessionInvoker::runAudio, this); +// _videoThread = new tthread::thread(MilesSessionInvoker::runVideo, this); } } diff --git a/src/uscxml/plugins/invoker/miles/MilesSessionInvoker.h b/src/uscxml/plugins/invoker/miles/MilesSessionInvoker.h index d61dbfe..c28f2cc 100644 --- a/src/uscxml/plugins/invoker/miles/MilesSessionInvoker.h +++ b/src/uscxml/plugins/invoker/miles/MilesSessionInvoker.h @@ -39,6 +39,8 @@ public: virtual void invoke(const InvokeRequest& req); protected: + bool alternate; // this is to alternate test1 an test2.jpeg and has no other use! remove me later .. + int video_rtp_in_socket, audio_rtp_in_socket; int video_rtp_out_socket, audio_rtp_out_socket; int video_rtcp_in_socket, audio_rtcp_in_socket; diff --git a/src/uscxml/util/Base64.cpp b/src/uscxml/util/Base64.cpp new file mode 100644 index 0000000..20cfbc3 --- /dev/null +++ b/src/uscxml/util/Base64.cpp @@ -0,0 +1,129 @@ +/* + base64.cpp and base64.h + + Copyright (C) 2004-2008 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch + + Moved to namespace umundo + +*/ + +#include "Base64.h" +#include <iostream> + +namespace uscxml { + +static const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + +static inline bool is_base64(unsigned char c) { + return (isalnum(c) || (c == '+') || (c == '/')); +} + +std::string base64_encode(char const* bytes_to_encode, unsigned int in_len) { + std::string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(i = 0; (i <4) ; i++) + ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; (j < i + 1); j++) + ret += base64_chars[char_array_4[j]]; + + while((i++ < 3)) + ret += '='; + + } + + return ret; + +} + +std::string base64_decode(std::string const& encoded_string) { + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + std::string ret; + + while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; + in_++; + if (i ==4) { + for (i = 0; i <4; i++) + char_array_4[i] = base64_chars.find(char_array_4[i]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + ret += char_array_3[i]; + i = 0; + } + } + + if (i) { + for (j = i; j <4; j++) + char_array_4[j] = 0; + + for (j = 0; j <4; j++) + char_array_4[j] = base64_chars.find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; + } + + return ret; +} + +}
\ No newline at end of file diff --git a/src/uscxml/util/Base64.h b/src/uscxml/util/Base64.h new file mode 100644 index 0000000..eaa7cfc --- /dev/null +++ b/src/uscxml/util/Base64.h @@ -0,0 +1,14 @@ +// taken from http://www.adp-gmbh.ch/cpp/common/base64.html +#ifndef BASE64_H_5FKG12HF +#define BASE64_H_5FKG12HF + +#include <string> + +namespace uscxml { + +std::string base64_encode(char const* , unsigned int len); +std::string base64_decode(std::string const& s); + +} + +#endif /* end of include guard: BASE64_H_5FKG12HF */ diff --git a/src/uscxml/util/MD5.cpp b/src/uscxml/util/MD5.cpp new file mode 100644 index 0000000..3fee55c --- /dev/null +++ b/src/uscxml/util/MD5.cpp @@ -0,0 +1,406 @@ +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + <ghost@aladdin.com>. Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include <string.h> + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include <stdio.h> in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include "MD5.h" +#include <string.h> + +#include <iostream> +#include <sstream> +#include <iomanip> + +namespace uscxml { + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) { + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) { + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} + +std::string md5(const char* data, size_t length) { + md5_state_t state; + md5_byte_t digest[16]; + + md5_init(&state); + md5_append(&state, (const md5_byte_t *)data, length); + md5_finish(&state, digest); + + std::ostringstream ss; + ss << std::hex << std::uppercase << std::setfill( '0' ); + for (int i = 0; i < 16; i++) { + ss << std::setw( 2 ) << (int)digest[i]; + } + + return ss.str(); +} + +std::string md5(const std::string& data) { + return md5(data.data(), data.size()); +} + +} diff --git a/src/uscxml/util/MD5.h b/src/uscxml/util/MD5.h new file mode 100644 index 0000000..aebac78 --- /dev/null +++ b/src/uscxml/util/MD5.h @@ -0,0 +1,102 @@ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + <ghost@aladdin.com>. Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke <purschke@bnl.gov>. + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +/** + * C++ convinience + */ +#include <string> + +namespace uscxml { + +extern std::string md5(const char* data, size_t length); +extern std::string md5(const std::string& data); + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Initialize the algorithm. */ + void md5_init(md5_state_t *pms); + + /* Append a string to the message. */ + void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + + /* Finish the message and return the digest. */ + void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +} +#endif /* md5_INCLUDED */ |