├── CNAME ├── .gitignore ├── favicon.ico ├── icebuddha.png ├── tutorial.png ├── slopfinder.png ├── summit_route_logo.png ├── test_data ├── bytes.data ├── putty.exe ├── icebuddha.gif ├── sample_1.gif └── high_bytes.data ├── contextmenu ├── arrow_s.png ├── jquery.hoverintent.js ├── jquery.contextmenu.css └── jquery.contextmenu.js ├── jqtree ├── treeDownTriangleBlack.png ├── treeRightTriangleBlack.png ├── jqtree.css └── tree.jquery.js ├── parse_scripts ├── unknown.py ├── example_extractMiniDukeFile.py ├── fileparser.py ├── mach_o.py ├── pe.py ├── gif.py └── icebuddha │ └── __init__.py ├── projects.htm ├── COPYING ├── ace ├── ext-static_highlight.js ├── theme-chrome.js ├── mode-python.js ├── keybinding-emacs.js ├── ext-textarea.js ├── mode-javascript.js └── keybinding-vim.js ├── README.md ├── jquery.scrollTo.min.js ├── slopfinder.htm ├── about.htm ├── jquery.cookie.js ├── waypoints.min.js ├── BlobBuilder.js ├── jquery.hotkeys.js ├── FileSaver.js ├── style.css ├── index.htm └── slopfinder.js /CNAME: -------------------------------------------------------------------------------- 1 | icebuddha.com 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .metadata 2 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xdabbad00/icebuddha/HEAD/favicon.ico -------------------------------------------------------------------------------- /icebuddha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xdabbad00/icebuddha/HEAD/icebuddha.png -------------------------------------------------------------------------------- /tutorial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xdabbad00/icebuddha/HEAD/tutorial.png -------------------------------------------------------------------------------- /slopfinder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xdabbad00/icebuddha/HEAD/slopfinder.png -------------------------------------------------------------------------------- /summit_route_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xdabbad00/icebuddha/HEAD/summit_route_logo.png -------------------------------------------------------------------------------- /test_data/bytes.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xdabbad00/icebuddha/HEAD/test_data/bytes.data -------------------------------------------------------------------------------- /test_data/putty.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xdabbad00/icebuddha/HEAD/test_data/putty.exe -------------------------------------------------------------------------------- /contextmenu/arrow_s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xdabbad00/icebuddha/HEAD/contextmenu/arrow_s.png -------------------------------------------------------------------------------- /test_data/icebuddha.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xdabbad00/icebuddha/HEAD/test_data/icebuddha.gif -------------------------------------------------------------------------------- /test_data/sample_1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xdabbad00/icebuddha/HEAD/test_data/sample_1.gif -------------------------------------------------------------------------------- /test_data/high_bytes.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xdabbad00/icebuddha/HEAD/test_data/high_bytes.data -------------------------------------------------------------------------------- /jqtree/treeDownTriangleBlack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xdabbad00/icebuddha/HEAD/jqtree/treeDownTriangleBlack.png -------------------------------------------------------------------------------- /jqtree/treeRightTriangleBlack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xdabbad00/icebuddha/HEAD/jqtree/treeRightTriangleBlack.png -------------------------------------------------------------------------------- /parse_scripts/unknown.py: -------------------------------------------------------------------------------- 1 | """ Unknown file type parse script for IceBuddha.com 2 | """ 3 | import icebuddha 4 | 5 | __author__ = "0xdabbad00" 6 | __license__ = "Apache" 7 | 8 | class Parse: 9 | def run(self, data): 10 | filedata = data 11 | ib = icebuddha.IceBuddha(filedata, "Unknown") 12 | 13 | print("Unknown file type") 14 | # Try using something like the following 15 | # ib = icebuddha.IceBuddha(filedata, "myfile_type") 16 | # startStruct = ib.parse(0, "START_STRUCT", """ 17 | # WORD magic; /* Magic signature */ 18 | # DWORD length; 19 | # """) 20 | # 21 | # ib.append(startStruct); 22 | 23 | return ib.getParseTree() 24 | 25 | parser = Parse() 26 | -------------------------------------------------------------------------------- /projects.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | Ice Buddha 4 | 5 | 6 | 7 | 8 |
9 | 12 | 13 |
14 |

IceBuddha

15 | Main site. Generic binary file parser. 16 | 17 |

SlopFinder

18 | Checks for DEP/ASLR. 19 |
20 | 21 | 24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Scott Piper 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /ace/ext-static_highlight.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/ext/static_highlight",["require","exports","module","ace/edit_session","ace/layer/text"],function(e,t,n){var r=e("../edit_session").EditSession,i=e("../layer/text").Text,s=".ace_editor {font-family: 'Monaco', 'Menlo', 'Droid Sans Mono', 'Courier New', monospace;font-size: 12px;}.ace_editor .ace_gutter { width: 25px !important;display: block;float: left;text-align: right; padding: 0 3px 0 0; margin-right: 3px;}.ace_line { clear: both; }*.ace_gutter-cell {-moz-user-select: -moz-none;-khtml-user-select: none;-webkit-user-select: none;user-select: none;}";t.render=function(e,t,n,o,u){o=parseInt(o||1,10);var a=new r("");a.setMode(t),a.setUseWorker(!1);var f=new i(document.createElement("div"));f.setSession(a),f.config={characterWidth:10,lineHeight:20},a.setValue(e);var l=[],c=a.getLength();for(var h=0;h"),u||l.push(""+(h+o)+""),f.$renderLine(l,h,!0,!1),l.push("");var p="
:code
".replace(/:cssClass/,n.cssClass).replace(/:code/,l.join(""));return f.destroy(),{css:s+n.cssText,html:p}}}) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Summary 2 | ======= 3 | IceBuddha a hex-viewer and generic binary file parser done via static web pages and with in-browser python-to-javascript translation for the parse scripts. 4 | 5 | Try it out 6 | - http://0xdabbad00.github.io/icebuddha/ 7 | - http://icebuddha.com 8 | 9 | Contact 10 | ------- 11 | IceBuddha was developed by [@0xdabbad00](https://twitter.com/0xdabbad00) (Scott Piper) from [Summmit Route](https://SummitRoute.com) 12 | 13 | License 14 | ------- 15 | MIT License 16 | 17 | 18 | Thank you 19 | ========= 20 | Special thanks to the following projects/people for making this site possible: 21 | - [skulpt](http://www.skulpt.org/) In-browser Python to JavaScript compiler. This project is insane. (MIT license) 22 | - [jqTree](http://mbraak.github.io/jqTree/) Allows me to show my tree view of the parsed data. (Apache license) 23 | - [jQuery.ScrollTo](http://flesler.blogspot.com/2007/10/jqueryscrollto.html) Makes the browser scroll. (MIT and GPL licenses) 24 | - [Waypoints](http://imakewebthings.com/jquery-waypoints/) Causes events to occur when you scroll. (MIT and GPL licenses) 25 | - [ACE editor](http://ace.c9.io/#nav=about) Code-editor. (BSD license) 26 | - [FileSaver.js](https://github.com/eligrey/FileSaver.js) and [BlobBuilder.js](https://github.com/eligrey/BlobBuilder.js), which I use to have the user download files from their browser (MIT/X11 license). 27 | -------------------------------------------------------------------------------- /contextmenu/jquery.hoverintent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * hoverIntent r5 // 2007.03.27 // jQuery 1.1.2+ 3 | * 4 | * 5 | * @param f onMouseOver function || An object with configuration options 6 | * @param g onMouseOut function || Nothing (use configuration options object) 7 | * @author Brian Cherne 8 | */ 9 | (function($){$.fn.hoverIntent=function(f,g){var cfg={sensitivity:7,interval:100,timeout:0};cfg=$.extend(cfg,g?{over:f,out:g}:f);var cX,cY,pX,pY;var track=function(ev){cX=ev.pageX;cY=ev.pageY;};var compare=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);if((Math.abs(pX-cX)+Math.abs(pY-cY))> 4) 35 | key[2] = keybytes[3] 36 | key[3] = ((keybytes[3] & 0xf) << 4) | (keybytes[2] >> 4) 37 | 38 | key[4] = keybytes[2] 39 | key[5] = ((keybytes[2] & 0xf) << 4) | (keybytes[1] >> 4) 40 | key[6] = keybytes[1] 41 | key[7] = ((keybytes[1] & 0xf) << 4) | (keybytes[0] >> 4) 42 | 43 | outfile = [] 44 | keybyte = 0 45 | for i in range(extraDataSize-6): 46 | bytein = ord(infile[trailerOffset + 1 + 4 + i]) 47 | outfile.append(bytein ^ key[keybyte]) 48 | keybyte = (keybyte + 1) % 8 49 | 50 | with open(filename+".infected", "wb") as f: 51 | f.write(bytearray(outfile)) 52 | 53 | print "Extracted file written to: %s" % (filename+".infected") 54 | 55 | 56 | -------------------------------------------------------------------------------- /parse_scripts/fileparser.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import sys 3 | import json 4 | import icebuddha 5 | from collections import OrderedDict 6 | 7 | def getStructured(json): 8 | result = [] 9 | for e in json: 10 | element = OrderedDict() 11 | element['label'] = e[0] 12 | element['size'] = e[1] 13 | element['data'] = e[2] 14 | element['offset'] = e[3] 15 | element['interpretation'] = e[5] 16 | element['children'] = getStructured(e[4]) 17 | result.append(element) 18 | return result 19 | 20 | def findElement(struct, needle): 21 | if isinstance(struct, list): 22 | for e in struct: 23 | result = findElement(e, needle) 24 | if result != None: 25 | return result 26 | return None 27 | 28 | if struct['label'] == needle: 29 | return struct 30 | for c in struct['children']: 31 | result = findElement(c, needle) 32 | if result != None: 33 | return result 34 | return None 35 | 36 | def parseFile(filename, filetype): 37 | if filetype == 'gif': 38 | import gif 39 | p = gif.Parser() 40 | elif filetype == 'pe': 41 | import pe 42 | p = pe.Parser() 43 | elif filetype == 'mach_o': 44 | import mach_o 45 | p = mach_o.Parser() 46 | else: 47 | print "Unknown file type" 48 | sys.exit(-1) 49 | 50 | with open(filename, "rb") as f: 51 | bytes = f.read() 52 | 53 | parsedJson = p.run(bytearray(bytes)) 54 | return getStructured(parsedJson) 55 | 56 | if __name__ == "__main__": 57 | argparser = argparse.ArgumentParser(description='IceBuddha parsing script') 58 | argparser.add_argument('-t','--type', help='File type [gif, pe, mach_o]', required=True) 59 | argparser.add_argument('files', metavar='files', type=str, nargs='+', 60 | help='files to parse') 61 | args = vars(argparser.parse_args()) 62 | 63 | for filename in args['files']: 64 | filetype = args['type'].lower() 65 | print json.dumps(parseFile(filename, filetype), indent=2) -------------------------------------------------------------------------------- /jquery.scrollTo.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery.ScrollTo - Easy element scrolling using jQuery. 3 | * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com 4 | * Dual licensed under MIT and GPL. 5 | * Date: 5/25/2009 6 | * @author Ariel Flesler 7 | * @version 1.4.2 8 | * 9 | * http://flesler.blogspot.com/2007/10/jqueryscrollto.html 10 | */ 11 | ;(function(d){var k=d.scrollTo=function(a,i,e){d(window).scrollTo(a,i,e)};k.defaults={axis:'xy',duration:parseFloat(d.fn.jquery)>=1.3?0:1};k.window=function(a){return d(window)._scrollable()};d.fn._scrollable=function(){return this.map(function(){var a=this,i=!a.nodeName||d.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!i)return a;var e=(a.contentWindow||a).document||a.ownerDocument||a;return d.browser.safari||e.compatMode=='BackCompat'?e.body:e.documentElement})};d.fn.scrollTo=function(n,j,b){if(typeof j=='object'){b=j;j=0}if(typeof b=='function')b={onAfter:b};if(n=='max')n=9e9;b=d.extend({},k.defaults,b);j=j||b.speed||b.duration;b.queue=b.queue&&b.axis.length>1;if(b.queue)j/=2;b.offset=p(b.offset);b.over=p(b.over);return this._scrollable().each(function(){var q=this,r=d(q),f=n,s,g={},u=r.is('html,body');switch(typeof f){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(f)){f=p(f);break}f=d(f,this);case'object':if(f.is||f.style)s=(f=d(f)).offset()}d.each(b.axis.split(''),function(a,i){var e=i=='x'?'Left':'Top',h=e.toLowerCase(),c='scroll'+e,l=q[c],m=k.max(q,i);if(s){g[c]=s[h]+(u?0:l-r.offset()[h]);if(b.margin){g[c]-=parseInt(f.css('margin'+e))||0;g[c]-=parseInt(f.css('border'+e+'Width'))||0}g[c]+=b.offset[h]||0;if(b.over[h])g[c]+=f[i=='x'?'width':'height']()*b.over[h]}else{var o=f[h];g[c]=o.slice&&o.slice(-1)=='%'?parseFloat(o)/100*m:o}if(/^\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],m);if(!a&&b.queue){if(l!=g[c])t(b.onAfterFirst);delete g[c]}});t(b.onAfter);function t(a){r.animate(g,j,b.easing,a&&function(){a.call(this,n,b)})}}).end()};k.max=function(a,i){var e=i=='x'?'Width':'Height',h='scroll'+e;if(!d(a).is('html,body'))return a[h]-d(a)[e.toLowerCase()]();var c='client'+e,l=a.ownerDocument.documentElement,m=a.ownerDocument.body;return Math.max(l[h],m[h])-Math.min(l[c],m[c])};function p(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery); -------------------------------------------------------------------------------- /contextmenu/jquery.contextmenu.css: -------------------------------------------------------------------------------- 1 | .uctxMenu { 2 | position: absolute; 3 | z-index: 99999; 4 | border: solid 1px #979797; 5 | background: #f1f1f1; 6 | padding: 2px 0; 7 | margin: 0; 8 | top: 0; 9 | left: 0; 10 | display: none; 11 | font-family: Arial, Helvetica, sans-serif; 12 | -moz-box-shadow: 3px 3px 5px rgba(0,0,0,.3); 13 | -webkit-box-shadow: 3px 3px 5px rgba(0,0,0,.3); 14 | box-shadow: 3px 3px 5px rgba(0,0,0,.3); 15 | } 16 | .uctxMenu ul { 17 | list-style: none; 18 | padding: 0; 19 | margin: 0; 20 | } 21 | .uctxMenu li { 22 | margin: 1px 2px; 23 | padding: 1px; 24 | color : #333; 25 | } 26 | .uctxMenu a { 27 | text-decoration: none; 28 | color: #333; 29 | display: block; 30 | line-height: 20px; 31 | height: 20px; 32 | outline: none; 33 | padding: 1px 1px 1px 1px; 34 | margin-left: 0px; 35 | border-left: 1px solid #e3e3e3; 36 | margin-top: -1px; 37 | margin-bottom: -3px; 38 | } 39 | 40 | #content .uctxMenu a {color: #333;} 41 | 42 | .uctxMenu img { 43 | float: left; 44 | margin-top: 2px; 45 | margin-left: 6px; 46 | } 47 | .uctxMenu li.separator a { 48 | border-top: 1px solid #e3e3e3; 49 | margin-top: -4px; 50 | padding-top: 5px; 51 | } 52 | .uctxMenu li.separator, .uctxMenu li.separator.hover { 53 | margin-top: 5px; 54 | } 55 | .uctxMenu li.hover { 56 | background-color: #e2ecf5; 57 | -moz-border-radius: 2px; 58 | border-radius: 3px; 59 | border: 1px solid #acd8e5; 60 | padding: 0; 61 | margin: 1px 2px; 62 | background: -moz-linear-gradient(100% 100% 90deg, #e8f2fe, #daebf3); 63 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#daebf3), to(#e8f2fe)); 64 | background: -webkit-linear-gradient(#e8f2fe, #daebf3); 65 | background: -o-linear-gradient(#e8f2fe, #daebf3); 66 | } 67 | .uctxMenu li.disabled { 68 | color: #999; 69 | } 70 | .uctxMenu li span { 71 | background-image: url('arrow_s.png'); 72 | background-position: center; 73 | background-repeat: no-repeat; 74 | width: 10px; 75 | height: 20px; 76 | float: right; 77 | } 78 | .uctxMenu li ul { 79 | margin-top: -2px; 80 | left: 180px; 81 | position: absolute; 82 | width: 180px; 83 | border: solid 1px #979797; 84 | background: #f1f1f1; 85 | display: none; 86 | top: 0; 87 | padding: 2px 0; 88 | margin: 0; 89 | -moz-box-shadow: 3px 3px 5px rgba(0,0,0,.3); 90 | -webkit-box-shadow: 3px 3px 5px rgba(0,0,0,.3); 91 | box-shadow: 3px 3px 5px rgba(0,0,0,.3); 92 | } -------------------------------------------------------------------------------- /ace/theme-chrome.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/theme/chrome",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!1,t.cssClass="ace-chrome",t.cssText='.ace-chrome .ace_gutter {background: #ebebeb;color: #333;overflow : hidden;}.ace-chrome .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-chrome .ace_scroller {background-color: #FFFFFF;}.ace-chrome .ace_cursor {border-left: 2px solid black;}.ace-chrome .ace_overwrite-cursors .ace_cursor {border-left: 0px;border-bottom: 1px solid black;}.ace-chrome .ace_invisible {color: rgb(191, 191, 191);}.ace-chrome .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-chrome .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-chrome .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-chrome .ace_invalid {background-color: rgb(153, 0, 0);color: white;}.ace-chrome .ace_fold {}.ace-chrome .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-chrome .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-chrome .ace_support.ace_type,.ace-chrome .ace_support.ace_class.ace-chrome .ace_support.ace_other {color: rgb(109, 121, 222);}.ace-chrome .ace_variable.ace_parameter {font-style:italic;color:#FD971F;}.ace-chrome .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-chrome .ace_comment {color: #236e24;}.ace-chrome .ace_comment.ace_doc {color: #236e24;}.ace-chrome .ace_comment.ace_doc.ace_tag {color: #236e24;}.ace-chrome .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-chrome .ace_variable {color: rgb(49, 132, 149);}.ace-chrome .ace_xml-pe {color: rgb(104, 104, 91);}.ace-chrome .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-chrome .ace_markup.ace_heading {color: rgb(12, 7, 255);}.ace-chrome .ace_markup.ace_list {color:rgb(185, 6, 144);}.ace-chrome .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-chrome .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-chrome .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-chrome .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-chrome .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-chrome .ace_gutter-active-line {background-color : #dcdcdc;}.ace-chrome .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-chrome .ace_storage,.ace-chrome .ace_keyword,.ace-chrome .ace_meta.ace_tag {color: rgb(147, 15, 128);}.ace-chrome .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-chrome .ace_string {color: #1A1AA6;}.ace-chrome .ace_entity.ace_other.ace_attribute-name {color: #994409;}.ace-chrome .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}';var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)}) -------------------------------------------------------------------------------- /jqtree/jqtree.css: -------------------------------------------------------------------------------- 1 | ul.tree { 2 | margin-left: 12px; 3 | } 4 | 5 | ul.tree, 6 | ul.tree ul { 7 | list-style: none outside; 8 | margin-bottom: 0; 9 | } 10 | 11 | ul.tree ul { 12 | display: block; 13 | margin-left: 12px; 14 | margin-right: 0; 15 | } 16 | 17 | ul.tree li.closed > ul { 18 | display: none; 19 | } 20 | 21 | ul.tree li { 22 | clear: both; 23 | } 24 | 25 | ul.tree .toggler { 26 | background: url(treeDownTriangleBlack.png) no-repeat 0 50%; 27 | width: 12px; 28 | display: block; 29 | position: absolute; 30 | left: -12px; 31 | text-indent: -9999px; 32 | border-bottom: none; 33 | } 34 | 35 | ul.tree div { 36 | cursor: pointer; 37 | } 38 | 39 | ul.tree .title { 40 | /* color: #1C4257; */ 41 | font-family: monospace, monospace; 42 | vertical-align: middle; 43 | } 44 | 45 | ul.tree li.folder { 46 | margin-bottom: 4px; 47 | } 48 | 49 | ul.tree li.folder.closed { 50 | margin-bottom: 1px; 51 | } 52 | 53 | ul.tree li.folder .title { 54 | margin-left: 0; 55 | } 56 | 57 | ul.tree .toggler.closed { 58 | background-image: url(treeRightTriangleBlack.png); 59 | } 60 | 61 | span.tree-dragging { 62 | color: #fff; 63 | background: #000; 64 | opacity: 0.6; 65 | cursor: pointer; 66 | padding: 2px 8px; 67 | } 68 | 69 | ul.tree li.ghost { 70 | position: relative; 71 | z-index: 10; 72 | margin-right: 10px; 73 | } 74 | 75 | ul.tree li.ghost span { 76 | display: block; 77 | } 78 | 79 | ul.tree li.ghost span.circle { 80 | background: url(circle.png) no-repeat; 81 | height: 8px; 82 | width: 8px; 83 | position: absolute; 84 | top: -4px; 85 | left: 2px; 86 | } 87 | 88 | ul.tree li.ghost span.line { 89 | background-color: #0000ff; 90 | height: 2px; 91 | padding: 0; 92 | position: absolute; 93 | top: -1px; 94 | left: 10px; 95 | width: 100%; 96 | } 97 | 98 | ul.tree li.ghost.inside { 99 | margin-left: 48px; 100 | } 101 | 102 | ul.tree span.tree-hit { 103 | position: absolute; 104 | display: block; 105 | } 106 | 107 | ul.tree span.border { 108 | position: absolute; 109 | display: block; 110 | left: -2px; 111 | top: 0; 112 | border: solid 2px #0000ff; 113 | -webkit-border-radius: 6px; 114 | -moz-border-radius: 6px; 115 | border-radius: 6px; 116 | margin: 0; 117 | } 118 | 119 | ul.tree div { 120 | width: 100%; 121 | position: relative; 122 | } 123 | 124 | ul.tree li.selected > div, 125 | ul.tree li.selected > div:hover { 126 | background-color: #97BDD6; 127 | background: -webkit-gradient(linear, left top, left bottom, from(#BEE0F5), to(#89AFCA)); 128 | background: -moz-linear-gradient(top, #BEE0F5, #89AFCA); 129 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7); 130 | } 131 | 132 | ul.tree .moving > div .title { 133 | outline: dashed 1px #0000ff; 134 | } 135 | -------------------------------------------------------------------------------- /slopfinder.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | Ice Buddha 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 25 |
26 | 29 | 30 |
31 |
32 | 33 |
34 |
35 | 36 |
37 | 41 |
42 | Drop files here 43 |
44 | 45 |
46 |

SlopFinder

47 |

Statically analyzes Windows executable files to look for use of DEP and ASLR. The lack of either indicates possible bad software development practices which pose security risks. 48 | 49 |

These are free protections provided by Microsoft. Not taking advantage of them is foolish. 50 | 51 |

To use, drag and drop Windows executables onto this page. If you use Chrome, you can drag and drop entire directories in C:\Program Files\. (Dropping your entire C:\ drive will crash your browser). 52 | 53 |

54 |

55 |
56 | 57 |
58 |


For developers

59 | Data Execution Prevention (DEP) can be turned on by compiling with any Visual Studio version since 2005 and ensure NXCOMPAT is on (default). 60 | 61 |

Address Space Layout Randomization (ASLR) can be turned on by compiling with any Visual Studio version since 2005 and ensure DYNAMICBASE in on (default). 62 |

63 | 64 |
65 | 66 | 69 |
70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /about.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | Ice Buddha 4 | 5 | 6 | 7 | 8 |
9 | 12 | 13 |
14 |
15 |

Motive

16 | The goal of IceBuddha is to become a general purpose binary file parser to help me learn some things and try out some ideas. I'm doing this because I think it's an interesting idea, and with no goal of financial gain (just street cred). 17 | 18 |

19 | 20 |

Contact me

21 | Email me at 0xdabbad00 – at – gmail.com or read what I'm up to on my main site 0xdabbad00.com. 22 | 23 |

Thank you!

24 | Thanks to the following projects/people for making this site possible: 25 |
jqTree (Apache license) Allows me to show my tree view of the parsed data. 26 |
jQuery.ScrollTo (MIT and GPL licenses) Makes the browser scroll. 27 |
Waypoints (MIT and GPL licenses) Causes events to occur when you scroll. 28 |
ACE editor (BSD license?) Code-editor. 29 |
Eli Grey for FileSaver.js and BlobBuilder.js, which I use to download files (MIT/X11 license). 30 |
skulpt (MIT license) In-browser Python to JavaScript compiler. 31 | 32 |
PEG.js (MIT license) No longer used, but still appreciate them for it I was using it. 33 | 34 | 35 |

Thanks in advance

36 | Bruno for writing my auto-complete code in his answer to my question on stackoverflow. 37 | 38 | 39 |

Privacy Policy

40 | I don't collect any data. Everything is happening locally, client side on your system. It's all javascript and html, so I invite you to not only review my code on github, but host this site locally. Or better yet, fork it and send me fixes/features! Most of the site should work by just downloading it and browsing to it on your local hard-drive, even without a web server (some code does currently grab files from my server but I'm trying to figure out a smarter way to handle that). I host this site on amazon EC2 because most free hosting tracks users. I believe strongly in privacy, and frankly I'm too stupid to know how to profit from your use of this site. 41 | 42 |

I do want to eventually incorporate some wiki capabilities into this site which will mean some server side code, but I still will refrain from sending home any data you are not specifically requesting my server receive. 43 |

44 |
45 | 46 | 49 |
50 | 51 | 52 | -------------------------------------------------------------------------------- /jquery.cookie.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Cookie Plugin v1.4.1 3 | * https://github.com/carhartl/jquery-cookie 4 | * 5 | * Copyright 2013 Klaus Hartl 6 | * Released under the MIT license 7 | */ 8 | (function (factory) { 9 | if (typeof define === 'function' && define.amd) { 10 | // AMD 11 | define(['jquery'], factory); 12 | } else if (typeof exports === 'object') { 13 | // CommonJS 14 | factory(require('jquery')); 15 | } else { 16 | // Browser globals 17 | factory(jQuery); 18 | } 19 | }(function ($) { 20 | 21 | var pluses = /\+/g; 22 | 23 | function encode(s) { 24 | return config.raw ? s : encodeURIComponent(s); 25 | } 26 | 27 | function decode(s) { 28 | return config.raw ? s : decodeURIComponent(s); 29 | } 30 | 31 | function stringifyCookieValue(value) { 32 | return encode(config.json ? JSON.stringify(value) : String(value)); 33 | } 34 | 35 | function parseCookieValue(s) { 36 | if (s.indexOf('"') === 0) { 37 | // This is a quoted cookie as according to RFC2068, unescape... 38 | s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); 39 | } 40 | 41 | try { 42 | // Replace server-side written pluses with spaces. 43 | // If we can't decode the cookie, ignore it, it's unusable. 44 | // If we can't parse the cookie, ignore it, it's unusable. 45 | s = decodeURIComponent(s.replace(pluses, ' ')); 46 | return config.json ? JSON.parse(s) : s; 47 | } catch(e) {} 48 | } 49 | 50 | function read(s, converter) { 51 | var value = config.raw ? s : parseCookieValue(s); 52 | return $.isFunction(converter) ? converter(value) : value; 53 | } 54 | 55 | var config = $.cookie = function (key, value, options) { 56 | 57 | // Write 58 | 59 | if (value !== undefined && !$.isFunction(value)) { 60 | options = $.extend({}, config.defaults, options); 61 | 62 | if (typeof options.expires === 'number') { 63 | var days = options.expires, t = options.expires = new Date(); 64 | t.setTime(+t + days * 864e+5); 65 | } 66 | 67 | return (document.cookie = [ 68 | encode(key), '=', stringifyCookieValue(value), 69 | options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE 70 | options.path ? '; path=' + options.path : '', 71 | options.domain ? '; domain=' + options.domain : '', 72 | options.secure ? '; secure' : '' 73 | ].join('')); 74 | } 75 | 76 | // Read 77 | 78 | var result = key ? undefined : {}; 79 | 80 | // To prevent the for loop in the first place assign an empty array 81 | // in case there are no cookies at all. Also prevents odd result when 82 | // calling $.cookie(). 83 | var cookies = document.cookie ? document.cookie.split('; ') : []; 84 | 85 | for (var i = 0, l = cookies.length; i < l; i++) { 86 | var parts = cookies[i].split('='); 87 | var name = decode(parts.shift()); 88 | var cookie = parts.join('='); 89 | 90 | if (key && key === name) { 91 | // If second argument (value) is a function it's a converter... 92 | result = read(cookie, value); 93 | break; 94 | } 95 | 96 | // Prevent storing a cookie that we couldn't decode. 97 | if (!key && (cookie = read(cookie)) !== undefined) { 98 | result[name] = cookie; 99 | } 100 | } 101 | 102 | return result; 103 | }; 104 | 105 | config.defaults = {}; 106 | 107 | $.removeCookie = function (key, options) { 108 | if ($.cookie(key) === undefined) { 109 | return false; 110 | } 111 | 112 | // Must not alter options, thus extending a fresh object... 113 | $.cookie(key, '', $.extend({}, options, { expires: -1 })); 114 | return !$.cookie(key); 115 | }; 116 | 117 | })); 118 | -------------------------------------------------------------------------------- /parse_scripts/mach_o.py: -------------------------------------------------------------------------------- 1 | """ GIF file parse script for IceBuddha.com 2 | """ 3 | import icebuddha 4 | 5 | __author__ = "0xdabbad00" 6 | __license__ = "Apache" 7 | 8 | class Parser: 9 | def run(self, data): 10 | filedata = data 11 | ib = icebuddha.IceBuddha(filedata, "MACH_O") 12 | 13 | machHeader = ib.parse(0, "mach_header", """ 14 | DWORD magic; 15 | DWORD cputype; 16 | DWORD cpusubtype; 17 | DWORD filetype; 18 | DWORD ncmds; 19 | DWORD sizeofcmds; 20 | DWORD flags; 21 | """) 22 | 23 | magicElement = machHeader.findChild("magic") 24 | magicElement.setMeaningFromConstants(""" 25 | MACHO_32 = 0xFEEDFACE 26 | MACHO_64 = 0xFEEDFACF 27 | MACHO_FAT = 0xCAFEBABE 28 | MACHO_FAT_CIGAM = 0xBEBAFECA 29 | """); 30 | 31 | if magicElement.getValue() == "": 32 | ib.setBigEndian() 33 | magicElement.setMeaningFromConstants(""" 34 | MACHO_32 = 0xFEEDFACE 35 | MACHO_64 = 0xFEEDFACF 36 | """); 37 | if magicElement.getValue() == "": 38 | print "Unknown file format" 39 | return ib.getParseTree() 40 | 41 | cputype = machHeader.findChild("cputype") 42 | cputype.setMeaningFromConstants(""" 43 | CPU_TYPE_I386 = 0x7 44 | CPU_TYPE_X86_64 = 0x01000007 45 | CPU_TYPE_POWERPC = 0x12 46 | CPU_TYPE_POWERPC64 = 0x01000012 47 | CPU_TYPE_ARM = 0xC 48 | """); 49 | 50 | filetype = machHeader.findChild("filetype") 51 | filetype.setMeaningFromConstants(""" 52 | MACH_OBJECT = 0x1 53 | MACH_EXECUTE = 0x2 54 | MACH_FVMLIB = 0x3 55 | MACH_CORE = 0x4 56 | MACH_PRELOAD = 0x5 57 | MACH_DYLIB = 0x6 58 | MACH_DYLINKER = 0x7 59 | MACH_BUNDLE = 0x8 60 | MACH_DYLIB_STUB = 0x9 61 | MACH_DSYM = 0xA 62 | MACH_KEXT_BUNDLE = 0xB 63 | """); 64 | 65 | flags = machHeader.findChild("flags") 66 | flags.parseBitField(""" 67 | DWORD NOUNDEFS : 1; 68 | DWORD INCRLINK : 1; 69 | DWORD DYLDLINK : 1; 70 | DWORD BINDATLOAD : 1; 71 | DWORD PREBOUND : 1; 72 | DWORD SPLIT_SEGS : 1; 73 | DWORD LAZY_INIT : 1; 74 | DWORD TWOLEVEL : 1; 75 | DWORD FORCE_FLAT : 1; 76 | DWORD NOMULTIDEFS : 1; 77 | DWORD NOFIXPREBINDING : 1; 78 | DWORD PREBINDABLE : 1; 79 | DWORD ALLMODSBOUND : 1; 80 | DWORD SUBSECTIONS_VIA_SYMBOLS : 1; 81 | DWORD CANONICAL : 1; 82 | DWORD WEAK_DEFINES : 1; 83 | DWORD BINDS_TO_WEAK : 1; 84 | DWORD ALLOW_STACK_EXECUTION : 1; 85 | DWORD ROOT_SAFE : 1; 86 | DWORD SETUID_SAFE : 1; 87 | DWORD NO_REEXPORTED_DYLIBS : 1; 88 | DWORD PIE : 1; 89 | DWORD DEAD_STRIPPABLE_DYLIB : 1; 90 | DWORD HAS_TLV_DESCRIPTORS : 1; 91 | DWORD NO_HEAP_EXECUTION : 1; 92 | """); 93 | 94 | ib.append(machHeader) 95 | return ib.getParseTree() 96 | 97 | parser = Parser() 98 | -------------------------------------------------------------------------------- /waypoints.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | jQuery Waypoints - v1.1.6 3 | Copyright (c) 2011-2012 Caleb Troughton 4 | Dual licensed under the MIT license and GPL license. 5 | https://github.com/imakewebthings/jquery-waypoints/blob/master/MIT-license.txt 6 | https://github.com/imakewebthings/jquery-waypoints/blob/master/GPL-license.txt 7 | */ 8 | (function($,k,m,i,d){var e=$(i),g="waypoint.reached",b=function(o,n){o.element.trigger(g,n);if(o.options.triggerOnce){o.element[k]("destroy")}},h=function(p,o){if(!o){return -1}var n=o.waypoints.length-1;while(n>=0&&o.waypoints[n].element[0]!==p[0]){n-=1}return n},f=[],l=function(n){$.extend(this,{element:$(n),oldScroll:0,waypoints:[],didScroll:false,didResize:false,doScroll:$.proxy(function(){var q=this.element.scrollTop(),p=q>this.oldScroll,s=this,r=$.grep(this.waypoints,function(u,t){return p?(u.offset>s.oldScroll&&u.offset<=q):(u.offset<=s.oldScroll&&u.offset>q)}),o=r.length;if(!this.oldScroll||!q){$[m]("refresh")}this.oldScroll=q;if(!o){return}if(!p){r.reverse()}$.each(r,function(u,t){if(t.options.continuous||u===o-1){b(t,[p?"down":"up"])}})},this)});$(n).bind("scroll.waypoints",$.proxy(function(){if(!this.didScroll){this.didScroll=true;i.setTimeout($.proxy(function(){this.doScroll();this.didScroll=false},this),$[m].settings.scrollThrottle)}},this)).bind("resize.waypoints",$.proxy(function(){if(!this.didResize){this.didResize=true;i.setTimeout($.proxy(function(){$[m]("refresh");this.didResize=false},this),$[m].settings.resizeThrottle)}},this));e.load($.proxy(function(){this.doScroll()},this))},j=function(n){var o=null;$.each(f,function(p,q){if(q.element[0]===n){o=q;return false}});return o},c={init:function(o,n){this.each(function(){var u=$.fn[k].defaults.context,q,t=$(this);if(n&&n.context){u=n.context}if(!$.isWindow(u)){u=t.closest(u)[0]}q=j(u);if(!q){q=new l(u);f.push(q)}var p=h(t,q),s=p<0?$.fn[k].defaults:q.waypoints[p].options,r=$.extend({},s,n);r.offset=r.offset==="bottom-in-view"?function(){var v=$.isWindow(u)?$[m]("viewportHeight"):$(u).height();return v-$(this).outerHeight()}:r.offset;if(p<0){q.waypoints.push({element:t,offset:null,options:r})}else{q.waypoints[p].options=r}if(o){t.bind(g,o)}if(n&&n.handler){t.bind(g,n.handler)}});$[m]("refresh");return this},remove:function(){return this.each(function(o,p){var n=$(p);$.each(f,function(r,s){var q=h(n,s);if(q>=0){s.waypoints.splice(q,1);if(!s.waypoints.length){s.element.unbind("scroll.waypoints resize.waypoints");f.splice(r,1)}}})})},destroy:function(){return this.unbind(g)[k]("remove")}},a={refresh:function(){$.each(f,function(r,s){var q=$.isWindow(s.element[0]),n=q?0:s.element.offset().top,p=q?$[m]("viewportHeight"):s.element.height(),o=q?0:s.element.scrollTop();$.each(s.waypoints,function(u,x){if(!x){return}var t=x.options.offset,w=x.offset;if(typeof x.options.offset==="function"){t=x.options.offset.apply(x.element)}else{if(typeof x.options.offset==="string"){var v=parseFloat(x.options.offset);t=x.options.offset.indexOf("%")?Math.ceil(p*(v/100)):v}}x.offset=x.element.offset().top-n+o-t;if(x.options.onlyOnScroll){return}if(w!==null&&s.oldScroll>w&&s.oldScroll<=x.offset){b(x,["up"])}else{if(w!==null&&s.oldScroll=x.offset){b(x,["down"])}else{if(!w&&o>x.offset){b(x,["down"])}}}});s.waypoints.sort(function(u,t){return u.offset-t.offset})})},viewportHeight:function(){return(i.innerHeight?i.innerHeight:e.height())},aggregate:function(){var n=$();$.each(f,function(o,p){$.each(p.waypoints,function(q,r){n=n.add(r.element)})});return n}};$.fn[k]=function(n){if(c[n]){return c[n].apply(this,Array.prototype.slice.call(arguments,1))}else{if(typeof n==="function"||!n){return c.init.apply(this,arguments)}else{if(typeof n==="object"){return c.init.apply(this,[null,n])}else{$.error("Method "+n+" does not exist on jQuery "+k)}}}};$.fn[k].defaults={continuous:true,offset:0,triggerOnce:false,context:i};$[m]=function(n){if(a[n]){return a[n].apply(this)}else{return a.aggregate()}};$[m].settings={resizeThrottle:200,scrollThrottle:100};e.load(function(){$[m]("refresh")})})(jQuery,"waypoint","waypoints",window); -------------------------------------------------------------------------------- /ace/mode-python.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/mode/python",["require","exports","module","ace/lib/oop","ace/mode/text","ace/tokenizer","ace/mode/python_highlight_rules","ace/mode/folding/pythonic","ace/range"],function(e,t,n){var r=e("../lib/oop"),i=e("./text").Mode,s=e("../tokenizer").Tokenizer,o=e("./python_highlight_rules").PythonHighlightRules,u=e("./folding/pythonic").FoldMode,a=e("../range").Range,f=function(){this.$tokenizer=new s((new o).getRules()),this.foldingRules=new u("\\:")};r.inherits(f,i),function(){this.toggleCommentLines=function(e,t,n,r){var i=!0,s=/^(\s*)#/;for(var o=n;o<=r;o++)if(!s.test(t.getLine(o))){i=!1;break}if(i){var u=new a(0,0,0,0);for(var o=n;o<=r;o++){var f=t.getLine(o),l=f.match(s);u.start.row=o,u.end.row=o,u.end.column=l[0].length,t.replace(u,l[1])}}else t.indentRows(n,r,"#")},this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.$tokenizer.getLineTokens(t,e),s=i.tokens;if(s.length&&s[s.length-1].type=="comment")return r;if(e=="start"){var o=t.match(/^.*[\{\(\[\:]\s*$/);o&&(r+=n)}return r};var e={pass:1,"return":1,raise:1,"break":1,"continue":1};this.checkOutdent=function(t,n,r){if(r!=="\r\n"&&r!=="\r"&&r!=="\n")return!1;var i=this.$tokenizer.getLineTokens(n.trim(),t).tokens;if(!i)return!1;do var s=i.pop();while(s&&(s.type=="comment"||s.type=="text"&&s.value.match(/^\s+$/)));return s?s.type=="keyword"&&e[s.value]:!1},this.autoOutdent=function(e,t,n){n+=1;var r=this.$getIndent(t.getLine(n)),i=t.getTabString();r.slice(-i.length)==i&&t.remove(new a(n,r.length-i.length,n,r.length))}}.call(f.prototype),t.Mode=f}),ace.define("ace/mode/python_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e="and|as|assert|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|not|or|pass|print|raise|return|try|while|with|yield",t="True|False|None|NotImplemented|Ellipsis|__debug__",n="abs|divmod|input|open|staticmethod|all|enumerate|int|ord|str|any|eval|isinstance|pow|sum|basestring|execfile|issubclass|print|super|binfile|iter|property|tuple|bool|filter|len|range|type|bytearray|float|list|raw_input|unichr|callable|format|locals|reduce|unicode|chr|frozenset|long|reload|vars|classmethod|getattr|map|repr|xrange|cmp|globals|max|reversed|zip|compile|hasattr|memoryview|round|__import__|complex|hash|min|set|apply|delattr|help|next|setattr|buffer|dict|hex|object|slice|coerce|dir|id|oct|sorted|intern",r=this.createKeywordMapper({"invalid.deprecated":"debugger","support.function":n,"constant.language":t,keyword:e},"identifier"),i="(?:r|u|ur|R|U|UR|Ur|uR)?",s="(?:(?:[1-9]\\d*)|(?:0))",o="(?:0[oO]?[0-7]+)",u="(?:0[xX][\\dA-Fa-f]+)",a="(?:0[bB][01]+)",f="(?:"+s+"|"+o+"|"+u+"|"+a+")",l="(?:[eE][+-]?\\d+)",c="(?:\\.\\d+)",h="(?:\\d+)",p="(?:(?:"+h+"?"+c+")|(?:"+h+"\\.))",d="(?:(?:"+p+"|"+h+")"+l+")",v="(?:"+d+"|"+p+")";this.$rules={start:[{token:"comment",regex:"#.*$"},{token:"string",regex:i+'"{3}(?:[^\\\\]|\\\\.)*?"{3}'},{token:"string",merge:!0,regex:i+'"{3}.*$',next:"qqstring"},{token:"string",regex:i+'"(?:[^\\\\]|\\\\.)*?"'},{token:"string",regex:i+"'{3}(?:[^\\\\]|\\\\.)*?'{3}"},{token:"string",merge:!0,regex:i+"'{3}.*$",next:"qstring"},{token:"string",regex:i+"'(?:[^\\\\]|\\\\.)*?'"},{token:"constant.numeric",regex:"(?:"+v+"|\\d+)[jJ]\\b"},{token:"constant.numeric",regex:v},{token:"constant.numeric",regex:f+"[lL]\\b"},{token:"constant.numeric",regex:f+"\\b"},{token:r,regex:"[a-zA-Z_$][a-zA-Z0-9_$]*\\b"},{token:"keyword.operator",regex:"\\+|\\-|\\*|\\*\\*|\\/|\\/\\/|%|<<|>>|&|\\||\\^|~|<|>|<=|=>|==|!=|<>|="},{token:"paren.lparen",regex:"[\\[\\(\\{]"},{token:"paren.rparen",regex:"[\\]\\)\\}]"},{token:"text",regex:"\\s+"}],qqstring:[{token:"string",regex:'(?:[^\\\\]|\\\\.)*?"{3}',next:"start"},{token:"string",merge:!0,regex:".+"}],qstring:[{token:"string",regex:"(?:[^\\\\]|\\\\.)*?'{3}",next:"start"},{token:"string",merge:!0,regex:".+"}]}};r.inherits(s,i),t.PythonHighlightRules=s}),ace.define("ace/mode/folding/pythonic",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode"],function(e,t,n){var r=e("../../lib/oop"),i=e("./fold_mode").FoldMode,s=t.FoldMode=function(e){this.foldingStartMarker=new RegExp("([\\[{])(?:\\s*)$|("+e+")(?:\\s*)(?:#.*)?$")};r.inherits(s,i),function(){this.getFoldWidgetRange=function(e,t,n){var r=e.getLine(n),i=r.match(this.foldingStartMarker);if(i)return i[1]?this.openingBracketBlock(e,i[1],n,i.index):i[2]?this.indentationBlock(e,n,i.index+i[2].length):this.indentationBlock(e,n)}}.call(s.prototype)}) -------------------------------------------------------------------------------- /BlobBuilder.js: -------------------------------------------------------------------------------- 1 | /* BlobBuilder.js 2 | * A BlobBuilder implementation. 3 | * 2012-04-21 4 | * 5 | * By Eli Grey, http://eligrey.com 6 | * License: X11/MIT 7 | * See LICENSE.md 8 | */ 9 | 10 | /*global self, unescape */ 11 | /*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, 12 | plusplus: true */ 13 | 14 | /*! @source http://purl.eligrey.com/github/BlobBuilder.js/blob/master/BlobBuilder.js */ 15 | 16 | var BlobBuilder = BlobBuilder || self.WebKitBlobBuilder || self.MozBlobBuilder || self.MSBlobBuilder || (function(view) { 17 | "use strict"; 18 | var 19 | get_class = function(object) { 20 | return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1]; 21 | } 22 | , FakeBlobBuilder = function(){ 23 | this.data = []; 24 | } 25 | , FakeBlob = function(data, type, encoding) { 26 | this.data = data; 27 | this.size = data.length; 28 | this.type = type; 29 | this.encoding = encoding; 30 | } 31 | , FBB_proto = FakeBlobBuilder.prototype 32 | , FB_proto = FakeBlob.prototype 33 | , FileReaderSync = view.FileReaderSync 34 | , FileException = function(type) { 35 | this.code = this[this.name = type]; 36 | } 37 | , file_ex_codes = ( 38 | "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR " 39 | + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR" 40 | ).split(" ") 41 | , file_ex_code = file_ex_codes.length 42 | , realURL = view.URL || view.webkitURL || view 43 | , real_create_object_URL = realURL.createObjectURL 44 | , real_revoke_object_URL = realURL.revokeObjectURL 45 | , URL = realURL 46 | , btoa = view.btoa 47 | , atob = view.atob 48 | , can_apply_typed_arrays = false 49 | , can_apply_typed_arrays_test = function(pass) { 50 | can_apply_typed_arrays = !pass; 51 | } 52 | 53 | , ArrayBuffer = view.ArrayBuffer 54 | , Uint8Array = view.Uint8Array 55 | ; 56 | FakeBlobBuilder.fake = FB_proto.fake = true; 57 | while (file_ex_code--) { 58 | FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1; 59 | } 60 | try { 61 | if (Uint8Array) { 62 | can_apply_typed_arrays_test.apply(0, new Uint8Array(1)); 63 | } 64 | } catch (ex) {} 65 | if (!realURL.createObjectURL) { 66 | URL = view.URL = {}; 67 | } 68 | URL.createObjectURL = function(blob) { 69 | var 70 | type = blob.type 71 | , data_URI_header 72 | ; 73 | if (type === null) { 74 | type = "application/octet-stream"; 75 | } 76 | if (blob instanceof FakeBlob) { 77 | data_URI_header = "data:" + type; 78 | if (blob.encoding === "base64") { 79 | return data_URI_header + ";base64," + blob.data; 80 | } else if (blob.encoding === "URI") { 81 | return data_URI_header + "," + decodeURIComponent(blob.data); 82 | } if (btoa) { 83 | return data_URI_header + ";base64," + btoa(blob.data); 84 | } else { 85 | return data_URI_header + "," + encodeURIComponent(blob.data); 86 | } 87 | } else if (real_create_object_url) { 88 | return real_create_object_url.call(realURL, blob); 89 | } 90 | }; 91 | URL.revokeObjectURL = function(object_url) { 92 | if (object_url.substring(0, 5) !== "data:" && real_revoke_object_url) { 93 | real_revoke_object_url.call(realURL, object_url); 94 | } 95 | }; 96 | FBB_proto.append = function(data/*, endings*/) { 97 | var bb = this.data; 98 | // decode data to a binary string 99 | if (Uint8Array && data instanceof ArrayBuffer) { 100 | if (can_apply_typed_arrays) { 101 | bb.push(String.fromCharCode.apply(String, new Uint8Array(data))); 102 | } else { 103 | var 104 | str = "" 105 | , buf = new Uint8Array(data) 106 | , i = 0 107 | , buf_len = buf.length 108 | ; 109 | for (; i < buf_len; i++) { 110 | str += String.fromCharCode(buf[i]); 111 | } 112 | } 113 | } else if (get_class(data) === "Blob" || get_class(data) === "File") { 114 | if (FileReaderSync) { 115 | var fr = new FileReaderSync; 116 | bb.push(fr.readAsBinaryString(data)); 117 | } else { 118 | // async FileReader won't work as BlobBuilder is sync 119 | throw new FileException("NOT_READABLE_ERR"); 120 | } 121 | } else if (data instanceof FakeBlob) { 122 | if (data.encoding === "base64" && atob) { 123 | bb.push(atob(data.data)); 124 | } else if (data.encoding === "URI") { 125 | bb.push(decodeURIComponent(data.data)); 126 | } else if (data.encoding === "raw") { 127 | bb.push(data.data); 128 | } 129 | } else { 130 | if (typeof data !== "string") { 131 | data += ""; // convert unsupported types to strings 132 | } 133 | // decode UTF-16 to binary string 134 | bb.push(unescape(encodeURIComponent(data))); 135 | } 136 | }; 137 | FBB_proto.getBlob = function(type) { 138 | if (!arguments.length) { 139 | type = null; 140 | } 141 | return new FakeBlob(this.data.join(""), type, "raw"); 142 | }; 143 | FBB_proto.toString = function() { 144 | return "[object BlobBuilder]"; 145 | }; 146 | FB_proto.slice = function(start, end, type) { 147 | var args = arguments.length; 148 | if (args < 3) { 149 | type = null; 150 | } 151 | return new FakeBlob( 152 | this.data.slice(start, args > 1 ? end : this.data.length) 153 | , type 154 | , this.encoding 155 | ); 156 | }; 157 | FB_proto.toString = function() { 158 | return "[object Blob]"; 159 | }; 160 | return FakeBlobBuilder; 161 | }(self)); -------------------------------------------------------------------------------- /jquery.hotkeys.js: -------------------------------------------------------------------------------- 1 | /*jslint browser: true*/ 2 | /*jslint jquery: true*/ 3 | 4 | /* 5 | * jQuery Hotkeys Plugin 6 | * Copyright 2010, John Resig 7 | * Dual licensed under the MIT or GPL Version 2 licenses. 8 | * 9 | * Based upon the plugin by Tzury Bar Yochay: 10 | * http://github.com/tzuryby/hotkeys 11 | * 12 | * Original idea by: 13 | * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/ 14 | */ 15 | 16 | /* 17 | * One small change is: now keys are passed by object { keys: '...' } 18 | * Might be useful, when you want to pass some other data to your handler 19 | */ 20 | 21 | (function(jQuery) { 22 | 23 | jQuery.hotkeys = { 24 | version: "0.8", 25 | 26 | specialKeys: { 27 | 8: "backspace", 28 | 9: "tab", 29 | 10: "return", 30 | 13: "return", 31 | 16: "shift", 32 | 17: "ctrl", 33 | 18: "alt", 34 | 19: "pause", 35 | 20: "capslock", 36 | 27: "esc", 37 | 32: "space", 38 | 33: "pageup", 39 | 34: "pagedown", 40 | 35: "end", 41 | 36: "home", 42 | 37: "left", 43 | 38: "up", 44 | 39: "right", 45 | 40: "down", 46 | 45: "insert", 47 | 46: "del", 48 | 59: ";", 49 | 61: "=", 50 | 96: "0", 51 | 97: "1", 52 | 98: "2", 53 | 99: "3", 54 | 100: "4", 55 | 101: "5", 56 | 102: "6", 57 | 103: "7", 58 | 104: "8", 59 | 105: "9", 60 | 106: "*", 61 | 107: "+", 62 | 109: "-", 63 | 110: ".", 64 | 111: "/", 65 | 112: "f1", 66 | 113: "f2", 67 | 114: "f3", 68 | 115: "f4", 69 | 116: "f5", 70 | 117: "f6", 71 | 118: "f7", 72 | 119: "f8", 73 | 120: "f9", 74 | 121: "f10", 75 | 122: "f11", 76 | 123: "f12", 77 | 144: "numlock", 78 | 145: "scroll", 79 | 173: "-", 80 | 186: ";", 81 | 187: "=", 82 | 188: ",", 83 | 189: "-", 84 | 190: ".", 85 | 191: "/", 86 | 192: "`", 87 | 219: "[", 88 | 220: "\\", 89 | 221: "]", 90 | 222: "'" 91 | }, 92 | 93 | shiftNums: { 94 | "`": "~", 95 | "1": "!", 96 | "2": "@", 97 | "3": "#", 98 | "4": "$", 99 | "5": "%", 100 | "6": "^", 101 | "7": "&", 102 | "8": "*", 103 | "9": "(", 104 | "0": ")", 105 | "-": "_", 106 | "=": "+", 107 | ";": ": ", 108 | "'": "\"", 109 | ",": "<", 110 | ".": ">", 111 | "/": "?", 112 | "\\": "|" 113 | }, 114 | 115 | // excludes: button, checkbox, file, hidden, image, password, radio, reset, search, submit, url 116 | textAcceptingInputTypes: [ 117 | "text", "password", "number", "email", "url", "range", "date", "month", "week", "time", "datetime", 118 | "datetime-local", "search", "color", "tel"], 119 | 120 | options: { 121 | filterTextInputs: true 122 | } 123 | }; 124 | 125 | function keyHandler(handleObj) { 126 | if (typeof handleObj.data === "string") { 127 | handleObj.data = { 128 | keys: handleObj.data 129 | }; 130 | } 131 | 132 | // Only care when a possible input has been specified 133 | if (!handleObj.data || !handleObj.data.keys || typeof handleObj.data.keys !== "string") { 134 | return; 135 | } 136 | 137 | var origHandler = handleObj.handler, 138 | keys = handleObj.data.keys.toLowerCase().split(" "); 139 | 140 | handleObj.handler = function(event) { 141 | // Don't fire in text-accepting inputs that we didn't directly bind to 142 | if (this !== event.target && (/textarea|select/i.test(event.target.nodeName) || 143 | (jQuery.hotkeys.options.filterTextInputs && 144 | jQuery.inArray(event.target.type, jQuery.hotkeys.textAcceptingInputTypes) > -1))) { 145 | return; 146 | } 147 | 148 | var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[event.which], 149 | character = String.fromCharCode(event.which).toLowerCase(), 150 | modif = "", 151 | possible = {}; 152 | 153 | jQuery.each(["alt", "ctrl", "shift"], function(index, specialKey) { 154 | 155 | if (event[specialKey + 'Key'] && special !== specialKey) { 156 | modif += specialKey + '+'; 157 | } 158 | }); 159 | 160 | // metaKey is triggered off ctrlKey erronously 161 | if (event.metaKey && !event.ctrlKey && special !== "meta") { 162 | modif += "meta+"; 163 | } 164 | 165 | if (event.metaKey && special !== "meta" && modif.indexOf("alt+ctrl+shift+") > -1) { 166 | modif = modif.replace("alt+ctrl+shift+", "hyper+"); 167 | } 168 | 169 | if (special) { 170 | possible[modif + special] = true; 171 | } 172 | else { 173 | possible[modif + character] = true; 174 | possible[modif + jQuery.hotkeys.shiftNums[character]] = true; 175 | 176 | // "$" can be triggered as "Shift+4" or "Shift+$" or just "$" 177 | if (modif === "shift+") { 178 | possible[jQuery.hotkeys.shiftNums[character]] = true; 179 | } 180 | } 181 | 182 | for (var i = 0, l = keys.length; i < l; i++) { 183 | if (possible[keys[i]]) { 184 | return origHandler.apply(this, arguments); 185 | } 186 | } 187 | }; 188 | } 189 | 190 | jQuery.each(["keydown", "keyup", "keypress"], function() { 191 | jQuery.event.special[this] = { 192 | add: keyHandler 193 | }; 194 | }); 195 | 196 | })(jQuery || this.jQuery || window.jQuery); 197 | -------------------------------------------------------------------------------- /ace/keybinding-emacs.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/keyboard/emacs",["require","exports","module","ace/lib/dom","ace/keyboard/hash_handler","ace/lib/keys"],function(e,t,n){var r=e("../lib/dom"),i=function(e,t){var n=this.scroller.getBoundingClientRect(),i=Math.floor((e+this.scrollLeft-n.left-this.$padding-r.getPageScrollLeft())/this.characterWidth),s=Math.floor((t+this.scrollTop-n.top-r.getPageScrollTop())/this.lineHeight);return this.session.screenToDocumentPosition(s,i)},s=e("./hash_handler").HashHandler;t.handler=new s;var o=!1;t.handler.attach=function(e){o||(o=!0,r.importCssString(" .emacs-mode .ace_cursor{ border: 2px rgba(50,250,50,0.8) solid!important; -moz-box-sizing: border-box!important; -webkit-box-sizing: border-box!important; box-sizing: border-box!important; background-color: rgba(0,250,0,0.9); opacity: 0.5; } .emacs-mode .ace_cursor.ace_hidden{ opacity: 1; background-color: transparent; } .emacs-mode .ace_overwrite-cursors .ace_cursor { opacity: 1; background-color: transparent; border-width: 0 0 2px 2px !important; } .emacs-mode .ace_text-layer { z-index: 4 } .emacs-mode .ace_cursor-layer { z-index: 2 }","emacsMode")),e.renderer.screenToTextCoordinates=i,e.setStyle("emacs-mode")},t.handler.detach=function(e){delete e.renderer.screenToTextCoordinates,e.unsetStyle("emacs-mode")};var u=e("../lib/keys").KEY_MODS,a={C:"ctrl",S:"shift",M:"alt"};["S-C-M","S-C","S-M","C-M","S","C","M"].forEach(function(e){var t=0;e.split("-").forEach(function(e){t|=u[a[e]]}),a[t]=e.toLowerCase()+"-"}),t.handler.bindKey=function(e,t){if(!e)return;var n=this.commmandKeyBinding;e.split("|").forEach(function(e){e=e.toLowerCase(),n[e]=t,e=e.split(" ")[0],n[e]||(n[e]="null")},this)},t.handler.handleKeyboard=function(e,t,n,r){if(t==-1&&e.count){var i=Array(e.count+1).join(n);return e.count=null,{command:"insertstring",args:i}}if(n=="\0")return;var s=a[t];if(s=="c-"||e.universalArgument){var o=parseInt(n[n.length-1]);if(o)return e.count=o,{command:"null"}}e.universalArgument=!1,s&&(n=s+n),e.keyChain&&(n=e.keyChain+=" "+n);var u=this.commmandKeyBinding[n];e.keyChain=u=="null"?n:"";if(!u)return;if(u=="null")return{command:"null"};if(u=="universalArgument")return e.universalArgument=!0,{command:"null"};if(typeof u!="string"){var f=u.args;u=u.command}typeof u=="string"&&(u=this.commands[u]||e.editor.commands.commands[u]),!u.readonly&&!u.isYank&&(e.lastCommand=null);if(e.count){var o=e.count;return e.count=0,{args:f,command:{exec:function(e,t){for(var n=0;n30&&this.$data.shift()},get:function(){return this.$data[this.$data.length-1]||""},pop:function(){return this.$data.length>1&&this.$data.pop(),this.get()},rotate:function(){return this.$data.unshift(this.$data.pop()),this.get()}}}) -------------------------------------------------------------------------------- /ace/ext-textarea.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/ext/textarea",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/lib/net","ace/ace","ace/theme/textmate","ace/mode/text"],function(e,t,n){function a(e,t){for(var n in t)e.style[n]=t[n]}function f(e,t){if(e.type!="textarea")throw"Textarea required!";var n=e.parentNode,i=document.createElement("div"),s=function(){var t="position:relative;";["margin-top","margin-left","margin-right","margin-bottom"].forEach(function(n){t+=n+":"+u(e,i,n)+";"});var n=u(e,i,"width")||e.clientWidth+"px",r=u(e,i,"height")||e.clientHeight+"px";t+="height:"+r+";width:"+n+";",t+="display:inline-block;",i.setAttribute("style",t)};r.addListener(window,"resize",s),s(),e.nextSibling?n.insertBefore(i,e.nextSibling):n.appendChild(i);while(n!==document){if(n.tagName.toUpperCase()==="FORM"){var o=n.onsubmit;n.onsubmit=function(n){e.innerHTML=t(),e.value=t(),o&&o.call(this,n)};break}n=n.parentNode}return i}function l(t,n,r){s.loadScript(t,function(){e([n],r)})}function c(n,r,i,s,o,u){function c(e){return e=="true"}var a=n.getSession(),f=n.renderer;u=u||l,n.setDisplaySettings=function(e){e==null&&(e=i.style.display=="none"),i.style.display=e?"block":"none"},n.setOption=function(t,i){if(o[t]==i)return;switch(t){case"gutter":f.setShowGutter(c(i));break;case"mode":i!="text"?u("mode-"+i+".js","ace/mode/"+i,function(){var t=e("../mode/"+i).Mode;a.setMode(new t)}):a.setMode(new(e("../mode/text").Mode));break;case"theme":i!="textmate"?u("theme-"+i+".js","ace/theme/"+i,function(){n.setTheme("ace/theme/"+i)}):n.setTheme("ace/theme/textmate");break;case"fontSize":r.style.fontSize=i;break;case"softWrap":switch(i){case"off":a.setUseWrapMode(!1),f.setPrintMarginColumn(80);break;case"40":a.setUseWrapMode(!0),a.setWrapLimitRange(40,40),f.setPrintMarginColumn(40);break;case"80":a.setUseWrapMode(!0),a.setWrapLimitRange(80,80),f.setPrintMarginColumn(80);break;case"free":a.setUseWrapMode(!0),a.setWrapLimitRange(null,null),f.setPrintMarginColumn(80)}break;case"useSoftTabs":a.setUseSoftTabs(c(i));break;case"showPrintMargin":f.setShowPrintMargin(c(i));break;case"showInvisibles":n.setShowInvisibles(c(i))}o[t]=i},n.getOption=function(e){return o[e]},n.getOptions=function(){return o};for(var h in t.options)n.setOption(h,t.options[h]);return n}function h(e,t,n,i){function f(e,t,n,r){e.push("")}var s={"true":!0,"false":!1},o={mode:"Mode:",gutter:"Display Gutter:",theme:"Theme:",fontSize:"Font Size:",softWrap:"Soft Wrap:",showPrintMargin:"Show Print Margin:",useSoftTabs:"Use Soft Tabs:",showInvisibles:"Show Invisibles"},u={mode:{text:"Plain",javascript:"JavaScript",xml:"XML",html:"HTML",css:"CSS",scss:"SCSS",python:"Python",php:"PHP",java:"Java",ruby:"Ruby",c_cpp:"C/C++",coffee:"CoffeeScript",json:"json",perl:"Perl",clojure:"Clojure",ocaml:"OCaml",csharp:"C#",haxe:"haXe",svg:"SVG",textile:"Textile",groovy:"Groovy",liquid:"Liquid",Scala:"Scala"},theme:{clouds:"Clouds",clouds_midnight:"Clouds Midnight",cobalt:"Cobalt",crimson_editor:"Crimson Editor",dawn:"Dawn",eclipse:"Eclipse",idle_fingers:"Idle Fingers",kr_theme:"Kr Theme",merbivore:"Merbivore",merbivore_soft:"Merbivore Soft",mono_industrial:"Mono Industrial",monokai:"Monokai",pastel_on_dark:"Pastel On Dark",solarized_dark:"Solarized Dark",solarized_light:"Solarized Light",textmate:"Textmate",twilight:"Twilight",vibrant_ink:"Vibrant Ink"},gutter:s,fontSize:{"10px":"10px","11px":"11px","12px":"12px","14px":"14px","16px":"16px"},softWrap:{off:"Off",40:"40",80:"80",free:"Free"},showPrintMargin:s,useSoftTabs:s,showInvisibles:s},a=[];a.push("");for(var l in i)a.push(""),a.push("");a.push("
SettingValue
",o[l],""),f(a,l,u[l],i[l]),a.push("
"),e.innerHTML=a.join("");var c=e.getElementsByTagName("select");for(var h=0;h 2 | 3 | Ice Buddha 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 26 | 27 |
28 | 31 | 32 |
33 |
34 | 35 |
36 | 37 |
38 | 39 |
40 | 44 | 45 |
46 | Drop file here 47 |
48 | 49 |
50 | Fork me on GitHub 51 |

52 | 53 | 54 |

55 |

Check out Summit Route for end-point protection. 56 |
57 | 58 | 59 | 60 | 61 |

62 | 63 |

About

64 | IceBuddha is an open-source (MIT license) hex viewer and generic binary file parser that runs in the browser. 65 |

66 | See an example. 67 | 68 |

69 |

Why?

70 | I wanted to test the limits of what was possible in the browser from a static site. Because all the files are static (no database, and no server-side functionality) IceBuddha is hosted on github pages. 71 | 72 |

Ridiculous things IceBuddha does

73 |
    74 |
  1. "Submitted" files are not uploaded anywhere. Everything happens in your browser locally. 75 |
    If you're concerned, you can clone and host this project locally by running it in a simple web server, 76 | such as using "python -m SimpleHTTPServer" in the folder you clone the repo to. 77 |
  2. Files are parsed via >Python scripts that define the structure of the files. 78 | The python is converted to Javascript in your browser via the skulpt library. 79 | By clicking on the "Parse as" tab when you drop a file, you can see this Python code. 80 | You can then edit it, and your file will parsed again immediately using your new code. 81 | Again, this is all happening entirely in your browser without hitting the server. 82 |
  3. You can take your python parse scripts, and run them directly on files to generate JSON data, without using your browser, as explained here 83 |
84 |

Similar projects/products

85 | 010 editor: Windows & Mac (commercial), odd format for binary templates to parse files, but looks similar to C structs and is often referenced. 86 |
Synalize It!: Mac only (commercial); XML based grammar format which means limited capability for more advanced binary file formats. 87 |

88 |

File parsing

89 | IceBuddha can parse a few of the main structures in the following file types: 90 |
    91 |
  1. PE files (.exe, .dll, .sys) 92 |
  2. GIF image files 93 |
  3. Mach-O (Mac OS X files) 94 |
95 |

Expanding and adding your own file parsing

96 | File types are automatically identified in drop.js via the function "ChooseParseScript". Look at pe.py to see an example of how files are parsed. 97 |
    98 |
  1. Change the PE in the line ib = icebuddha.IceBuddha(filedata, "PE") to be name of your file type. 99 |
  2. The line imageDosHeader = ib.parse(0, "IMAGE_DOS_HEADER", """ creates a structure at offset 0 with name IMAGE_DOS_HEADER. 100 | Then the next lines in that file describe what is in that structure. 101 |
  3. Known variable types are: 102 |
      103 |
    1. BYTE, CHAR, and anything unknown: 1 byte 104 |
    2. WORD: 2 bytes 105 |
    3. DWORD: 4 bytes 106 |
    4. ULONGLONG: 8 bytes 107 |
    108 | You can also create arrays such as WORD e_res2[10]; 109 |
  4. ib is the root object, so we then append imageDosHeader to that. Later we append objects to imageDosHeader 110 |
  5. The line e_lfanew = imageDosHeader.getInt("e_lfanew") gets the value of PE.IMAGE_DOS_HEADER.e_lfanew in the file it parses, and sets the variable e_lfanew which is then used as the offset in the next line. 111 |
  6. Usually you can specify an offset simply by using something like imageNtHeader.end() to specify the end of the previous object. 112 |
  7. To describe a bit field, you can look at what I did for dllCharacteristics. 113 |
  8. Finally, you just need to return everything with the lines return ib.getParseTree() and parser = Parse() 114 |
  9. You can have loops, other functions, and other logic in your code, as shown in gif.py. 115 |
  10. You can also describe what a value means as shown with the function setMeaningFromConstants in the file mach_o.py 116 |
  11. You can set the endianness as shown with setBigEndian in the file mach_o.py 117 |
118 | 119 |

120 |

Project status

121 | IceBuddha is mostly abandoned (last update on 2014-11-13). It does a lot of stuff, but a lot of things are impossible for a webapp based on static files (ex. saving files). 122 |

This was my first javascript project. The codebase is not pretty. 123 | 124 |

125 | 126 |
127 | 128 | 131 |
132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /parse_scripts/icebuddha/__init__.py: -------------------------------------------------------------------------------- 1 | def intToHex(value, fill=8): 2 | if fill == 0: 3 | return "%X" % value 4 | if fill == 8: 5 | return "%0.8X" % value 6 | else: 7 | format = "%s0.%dX" % ("%", fill) 8 | return format % value 9 | 10 | 11 | def getBinary(value, varsize): 12 | str = "" 13 | for i in range(varsize): 14 | if (value & (1 << ((varsize-1) - i))) != 0: 15 | str += "1" 16 | else: 17 | str += "0" 18 | return str 19 | 20 | 21 | def getMask(value, varsize, mask): 22 | str = "" 23 | for i in range(varsize): 24 | if (mask & (1 << ((varsize-1) - i))) != 0: 25 | if (value & (1 << ((varsize-1) - i))) != 0: 26 | str += "1" 27 | else: 28 | str += "0" 29 | else: 30 | str += "." 31 | return str 32 | 33 | 34 | def nbsp(count): 35 | str = "" 36 | for i in range(count): 37 | str += ("%snbsp;" % chr(0x26)) 38 | return str 39 | 40 | 41 | def getString(filedata, offset, length): 42 | displayableAscii = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 43 | "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 44 | " ", "!", "", "#", "$", "%", "", "", "(", ")", "*", "+", ",", "-", "", "", 45 | "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "", "=", "", "?", 46 | "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", 47 | "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "", "]", "^", "_", 48 | "", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", 49 | "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", ""] 50 | str = "" 51 | for i in range(length): 52 | val = filedata[offset + i] 53 | if (val > 127): 54 | continue 55 | str += displayableAscii[val] 56 | return str 57 | 58 | class IceBuddha: 59 | def __init__(self, filedata, root): 60 | self.filedata = filedata 61 | self.root = Node(self, root, 0, 0) 62 | self.endian = self.getConst("LITTLE_ENDIAN") 63 | 64 | def getConst(self, name): 65 | # Hack due to skulpt not knowing about static variables 66 | if name == "LITTLE_ENDIAN": 67 | return 0 68 | elif name == "BIG_ENDIAN": 69 | return 1 70 | return 0 71 | 72 | def setBigEndian(self): 73 | self.endian = self.getConst("BIG_ENDIAN") 74 | 75 | def setLittleEndian(self): 76 | self.endian = self.getConst("LITTLE_ENDIAN") 77 | 78 | def getEndian(self): 79 | return self.endian 80 | 81 | def getParseTree(self): 82 | return [self.root.get()] 83 | 84 | def append(self, node): 85 | self.root.append(node) 86 | 87 | def isEqual(self, offset, arrayToCheck): 88 | for i in range(len(arrayToCheck)): 89 | if (self.filedata[offset + i] != arrayToCheck[i]): 90 | return False 91 | return True 92 | 93 | def parse(self, offset, structName, input, comment=""): 94 | struct = Node(self, structName, offset) 95 | struct.setComment(comment) 96 | for l in input.split('\n'): 97 | parts = l.split(';') 98 | if (len(parts) < 2): 99 | continue 100 | comment = parts[1] 101 | parts = parts[0].split() 102 | type = parts[0] 103 | ascii = False 104 | if (type == "BYTE"): 105 | size = 1 106 | if (type == "CHAR"): 107 | size = 1 108 | ascii = True 109 | elif (type == "WORD"): 110 | size = 2 111 | elif (type == "DWORD"): 112 | size = 4 113 | elif (type == "ULONGLONG"): 114 | size = 8 115 | else: 116 | size = 1 117 | 118 | name = parts[1] 119 | value = "" 120 | 121 | arrayParts = name.split('[') 122 | if len(arrayParts) > 1: 123 | arraySize = int((arrayParts[1].split(']'))[0]) 124 | size *= arraySize 125 | if ascii: 126 | value = getString(self.filedata, offset, size) 127 | n = Node(self, name, offset, size, comment, value) 128 | offset += size 129 | struct.append(n) 130 | return struct 131 | 132 | 133 | class Node: 134 | def __init__(self, ib, label="", offset=0, size=0, comment="", value=""): 135 | self.ib = ib 136 | self.filedata = ib.filedata 137 | self.offset = offset 138 | self.size = size 139 | 140 | self.label = label 141 | self.comment = comment 142 | self.children = [] 143 | self.value = value 144 | 145 | def setComment(self, comment): 146 | self.comment = comment 147 | 148 | def setValue(self, value): 149 | self.value = value 150 | 151 | def getValue(self): 152 | return self.value 153 | 154 | def getData(self): 155 | data = 0 156 | if self.ib.getEndian() == self.ib.getConst("LITTLE_ENDIAN"): 157 | for i in range(self.size): 158 | data = data << 8 159 | data |= self.filedata[self.offset+(self.size-1-i)] 160 | else: 161 | for i in range(self.size): 162 | data = data << 8 163 | data |= self.filedata[self.offset+(i)] 164 | return data 165 | 166 | def getBytes(self): 167 | data = [] 168 | if self.ib.getEndian() == self.ib.getConst("LITTLE_ENDIAN"): 169 | for i in range(self.size): 170 | data.append(self.filedata[self.offset+(self.size-1-i)]) 171 | else: 172 | for i in range(self.size): 173 | data.append(self.filedata[self.offset+(i)]) 174 | return data 175 | 176 | def get(self): 177 | childData = [] 178 | for c in self.children: 179 | childData.append(c.get()) 180 | 181 | return [self.label, self.size, self.comment, self.offset, 182 | childData, self.value] 183 | 184 | def findChild(self, childName): 185 | for c in self.children: 186 | name = c.label.split('[') 187 | name = name[0] 188 | if name == childName: 189 | return c 190 | print "Child %s not found" % childName 191 | return None 192 | 193 | def getInt(self, valueName=None): 194 | size = self.size 195 | offset = self.offset 196 | if valueName != None: 197 | c = self.findChild(valueName) 198 | size = c.size 199 | offset = c.offset 200 | 201 | if c is None: 202 | return 0 203 | return c.getData() 204 | 205 | c.getData() 206 | 207 | def start(self): 208 | return self.offset 209 | 210 | def end(self): 211 | return self.offset + self.size 212 | 213 | def append(self, child): 214 | self.children.append(child) 215 | self.size += child.size 216 | 217 | # TODO Put this somewhere else 218 | def isMatch(self, a1, a2): 219 | if (len(a1) != len(a2)): 220 | return False 221 | 222 | for i in range(len(a1)): 223 | if a1[i] != a2[i]: 224 | return False 225 | return True 226 | 227 | def setMeaningFromConstants(self, input): 228 | for l in input.split('\n'): 229 | parts = l.split('=') 230 | if (len(parts) < 2): 231 | continue 232 | name = parts[0].strip() 233 | value = int(parts[1].strip(), 0) 234 | 235 | # TODO Don't assume 4 bytes 236 | valueBytes = [value & 0xff, (value >> 8) & 0xff, (value >> 16) & 0xff, (value >> 24) & 0xff] 237 | selfBytes = self.getBytes() 238 | 239 | if self.isMatch(valueBytes, selfBytes): 240 | self.setValue(name) 241 | break 242 | 243 | 244 | def parseBitField(self, input): 245 | bitCount = 0 246 | varSize = self.size*8 247 | 248 | self.value = "%s%s" % (nbsp(2), getBinary(self.getData(), varSize)) 249 | for l in input.split('\n'): 250 | parts = l.split(';') 251 | if (len(parts) < 2): 252 | continue 253 | comment = parts[1] 254 | parts = parts[0].split(":") 255 | if (len(parts) < 2): 256 | continue 257 | size = int(parts[1]) 258 | if bitCount + size > self.size * 8: 259 | print "Bit field too large for %s" % self.label 260 | 261 | parts = parts[0].split() 262 | 263 | varType = parts[0] # Ignored 264 | name = parts[1] 265 | 266 | bitmask = 0 267 | for i in range(bitCount, bitCount + size): 268 | bitmask |= (1 << i) 269 | 270 | data = (bitmask & self.getData()) 271 | data = data >> bitCount 272 | 273 | value = "
%s%s (%s) %s : %d %s" % (nbsp(11), 274 | getMask(bitmask & self.getData(), varSize, bitmask), 275 | intToHex(data, 0), 276 | name, 277 | size, 278 | comment) 279 | self.value += value 280 | bitCount += size 281 | -------------------------------------------------------------------------------- /slopfinder.js: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // Globals 3 | /////////////////////////////////////////////////////////////////////////////// 4 | var MAX_FILE_SIZE = 10*1024; // 10K 5 | var NUM_BYTES_TO_LOAD = 16*100; 6 | 7 | var files; 8 | var fileData; 9 | var numFilesRead = 0; 10 | var numFiles = 0; 11 | var filesOnly = false; 12 | 13 | /////////////////////////////////////////////////////////////////////////////// 14 | // Dialog message 15 | /////////////////////////////////////////////////////////////////////////////// 16 | function showDialog(str, title, okBtn) { 17 | $( "#dialog-message" ).html(str); 18 | 19 | if (okBtn) { 20 | $( "#dialog-message" ).dialog({ 21 | title: title, 22 | modal: true, 23 | disabled: false, 24 | 25 | buttons: { 26 | Ok: function() { 27 | $( this ).dialog( "close" ); 28 | } 29 | } 30 | }); 31 | } else { 32 | $( "#dialog-message" ).dialog({ 33 | title: title, 34 | modal: true, 35 | disabled: false 36 | }); 37 | } 38 | 39 | $( "#dialog-message" ).dialog( "enable" ); 40 | $( "#dialog-message" ).dialog( "open" ); 41 | } 42 | 43 | function removeDialog() { 44 | $( "#dialog-message" ).dialog( "close" ); 45 | } 46 | 47 | 48 | function showError(str) { 49 | $( "#dialog-message" ).html(""+str); 50 | 51 | $( "#dialog-message" ).dialog({ 52 | title: "Error", 53 | modal: true, 54 | disabled: false, 55 | 56 | buttons: { 57 | Ok: function() { 58 | $( this ).dialog( "close" ); 59 | } 60 | } 61 | }); 62 | 63 | $( "#dialog-message" ).dialog( "enable" ); 64 | $( "#dialog-message" ).dialog( "open" ); 65 | } 66 | 67 | /////////////////////////////////////////////////////////////////////////////// 68 | // File reading 69 | /////////////////////////////////////////////////////////////////////////////// 70 | function handleFinishedRead(evt, i) { 71 | if(evt.target.readyState == FileReader.DONE) { 72 | var length = evt.target.result.byteLength; 73 | var readBlock = new Uint8Array(evt.target.result, 0, length); 74 | doRead(readBlock, length, i); 75 | numFilesRead++; 76 | if (numFilesRead == numFiles) { 77 | displayResults(); 78 | } 79 | } 80 | } 81 | 82 | function displayResults() { 83 | var output = [""]; 84 | var executables = [""]; 85 | var unknownFiles = [""]; 86 | for (var i = 0; i < fileData.length; i++) { 87 | file = fileData[i]; 88 | if (file.type == 'exe') { 89 | style = ""; 90 | if (file.dep != "yes" || file.aslr != "yes") { 91 | style = "style=\"background: #FF5C5C\""; 92 | } 93 | executables.push(""+escape(file.name).replace(/%20/g, " ") + ""+file.dep+""+file.aslr+"\n"); 94 | } else { 95 | unknownFiles.push(escape(file.name).replace(/%20/g, " ") + "
\n"); 96 | } 97 | } 98 | 99 | output.push("
"); 100 | 101 | if (executables.length>1) { 102 | output.push(""+ 103 | ""+ 104 | "" 105 | + executables.join("") 106 | +"
Executable nameDEP
protection
ASLR
protection
"); 107 | } else { 108 | output.push("No Windows executables found
"); 109 | } 110 | if (unknownFiles.length>1) { 111 | output.push("
Nonexecutables
" + unknownFiles.join("")); 112 | } 113 | $('#analysis').html(output.join("")); 114 | removeDialog(); 115 | } 116 | 117 | 118 | function doRead(readBlock, length, i) { 119 | 120 | fileData[i].type = 'unknown'; 121 | // Check for MZ header 122 | if (readBlock[0] == 'M'.charCodeAt(0) && readBlock[1] == 'Z'.charCodeAt(0)) 123 | { 124 | fileData[i].type = 'exe'; 125 | fileData[i].dep = 'NO'; 126 | fileData[i].aslr = 'NO'; 127 | 128 | // Get to DllCharacteristics data 129 | offset = 0x3c; 130 | e_lfanew = ((readBlock[offset+3]<<24)>>>0) + 131 | ((readBlock[offset+2]<<16)>>>0) + 132 | ((readBlock[offset+1]<<8)>>>0) + 133 | (readBlock[offset+0]); 134 | sizeof_magic = 4; 135 | offset = e_lfanew + sizeof_magic; 136 | machine = 137 | ((readBlock[offset+1]<<8)>>>0) + 138 | (readBlock[offset+0]); 139 | 140 | var sizeof_IMAGE_FILE_HEADER = 20; 141 | var offset_in_IMAGE_OPTIONAL_HEADER; 142 | if (machine == 0x014c) { 143 | offset_in_IMAGE_OPTIONAL_HEADER = 0x46; 144 | } else if (machine == 0x8664) { 145 | offset_in_IMAGE_OPTIONAL_HEADER = 0x46; 146 | } else { 147 | fileData[i].error = "Unknown file type"; 148 | fileData[i].dep = 'ERROR'; 149 | fileData[i].aslr = 'ERROR'; 150 | } 151 | 152 | offset = e_lfanew + sizeof_magic + sizeof_IMAGE_FILE_HEADER + offset_in_IMAGE_OPTIONAL_HEADER; 153 | DllCharacteristics = ((readBlock[offset+1]<<8)>>>0) + 154 | (readBlock[offset+0]); 155 | 156 | if ((DllCharacteristics & 0x100) != 0) { 157 | fileData[i].dep = 'yes'; 158 | } 159 | if ((DllCharacteristics & 0x40) != 0) { 160 | fileData[i].aslr = 'yes'; 161 | } 162 | 163 | } 164 | } 165 | 166 | function handleFile(file, path) 167 | { 168 | var fileNum = numFiles; 169 | numFiles++; 170 | fileData[fileNum] = {}; 171 | fileData[fileNum].name = path; 172 | fileData[fileNum].type = ''; 173 | fileData[fileNum].error = ''; 174 | 175 | reader = new FileReader(); 176 | fileData[fileNum].reader = reader; 177 | reader.onloadend = function(evt) { handleFinishedRead(evt, fileNum); } 178 | readFile(reader, file); 179 | } 180 | 181 | function handleFileTree(entry, i) { 182 | var directoryReader = entry.createReader(); 183 | getAllEntries( 184 | directoryReader, 185 | readDirectory, 186 | appendIndentList(parentNode) 187 | ); 188 | } 189 | 190 | function readDirectory(entries) { 191 | for (i = 0; i < entries.length; i++) { 192 | (function(i) { 193 | if (entries[i].isDirectory) { 194 | var directoryReader = entries[i].createReader(); 195 | getAllEntries( 196 | directoryReader, 197 | readDirectory 198 | ); 199 | } else { 200 | entries[i].file(function(file) {handleFile(file, entries[i].fullPath);}, errorHandler); 201 | } 202 | })(i); 203 | } 204 | } 205 | 206 | function errorHandler(e) { 207 | console.log('FileSystem API error code: ' + e.code) 208 | } 209 | 210 | 211 | function getAllEntries(directoryReader, callback) { 212 | var entries = []; 213 | 214 | var readEntries = function () { 215 | directoryReader.readEntries(function (results) { 216 | if (!results.length) { 217 | entries.sort(); 218 | callback(entries); 219 | } else { 220 | entries = entries.concat(toArray(results)); 221 | readEntries(); 222 | } 223 | }, errorHandler); 224 | }; 225 | 226 | readEntries(); 227 | } 228 | 229 | function toArray(list) { 230 | return Array.prototype.slice.call(list || [], 0); 231 | } 232 | 233 | 234 | 235 | function handleFileSelect(evt) { 236 | showDialog("Loading files", "Loading"); 237 | evt.stopPropagation(); 238 | evt.preventDefault(); 239 | 240 | items = evt.dataTransfer.items; 241 | if ($.browser.webkit && (!items || !items[0] || !items[0].webkitGetAsEntry)) 242 | { 243 | alert("You should really upgrade your browser. This site needs at least Google Chrome 21 to handle dropped folders. You can still drop files though."); 244 | items = evt.dataTransfer.files; 245 | filesOnly = true; 246 | } else if ($.browser.mozilla) { 247 | items = evt.dataTransfer.files; 248 | filesOnly = true; 249 | } 250 | 251 | numFilesRead = 0; 252 | numFiles = 0; 253 | fileData = []; 254 | 255 | for (var i = 0; i < items.length; i++) { 256 | var entry = items[i]; 257 | if (filesOnly) { 258 | handleFile(entry, entry.name); 259 | } else { 260 | if (entry.getAsEntry){ //Standard HTML5 API 261 | entry = entry.getAsEntry(); 262 | } else if (entry.webkitGetAsEntry){ //WebKit implementation of HTML5 API. 263 | entry = entry.webkitGetAsEntry(); 264 | } 265 | if (entry.isFile){ 266 | handleFile(evt.dataTransfer.files[i], "/" + entry.name); 267 | } else if (entry.isDirectory){ 268 | var entries = []; 269 | entries[0] = evt.dataTransfer.items[i].webkitGetAsEntry(); 270 | readDirectory(entries); 271 | } else { 272 | alert("Error, unkown type given"); 273 | } 274 | } 275 | } 276 | 277 | if (numFiles == 0) { 278 | $( "#dialog-message" ).html("No files found"); 279 | } 280 | } 281 | 282 | function readFile(reader, file) { 283 | end = MAX_FILE_SIZE; 284 | var blob; 285 | if (file.slice) { 286 | blob = file.slice(0, end); 287 | } else if(file.webkitSlice) { 288 | blob = file.webkitSlice(0, end); 289 | } else if(file.mozSlice) { 290 | blob = file.mozSlice(0, end); 291 | } else { 292 | console.log("No file slicing possible in this browser"); 293 | return; 294 | } 295 | 296 | reader.readAsArrayBuffer(blob); 297 | } 298 | 299 | function handleDragOver(evt) { 300 | evt.stopPropagation(); 301 | evt.preventDefault(); 302 | evt.dataTransfer.dropEffect = 'copy'; 303 | } 304 | 305 | 306 | /////////////////////////////////////////////////////////////////////////////// 307 | // Main 308 | /////////////////////////////////////////////////////////////////////////////// 309 | 310 | if ($.browser.webkit) { 311 | $('#drop_zone').html('Drop files and folders here'); 312 | } 313 | 314 | $(function() { 315 | // Handler for when the page has loaded 316 | $( "#dialog-message" ).dialog({ autoOpen: false }); 317 | }); 318 | 319 | //Setup the dnd listeners. 320 | var dropZone = document.getElementById('container'); 321 | dropZone.addEventListener('dragover', handleDragOver, false); 322 | dropZone.addEventListener('drop', handleFileSelect, false); 323 | -------------------------------------------------------------------------------- /ace/mode-javascript.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/mode/javascript",["require","exports","module","ace/lib/oop","ace/mode/text","ace/tokenizer","ace/mode/javascript_highlight_rules","ace/mode/matching_brace_outdent","ace/range","ace/worker/worker_client","ace/mode/behaviour/cstyle","ace/mode/folding/cstyle"],function(e,t,n){var r=e("../lib/oop"),i=e("./text").Mode,s=e("../tokenizer").Tokenizer,o=e("./javascript_highlight_rules").JavaScriptHighlightRules,u=e("./matching_brace_outdent").MatchingBraceOutdent,a=e("../range").Range,f=e("../worker/worker_client").WorkerClient,l=e("./behaviour/cstyle").CstyleBehaviour,c=e("./folding/cstyle").FoldMode,h=function(){this.$tokenizer=new s((new o).getRules()),this.$outdent=new u,this.$behaviour=new l,this.foldingRules=new c};r.inherits(h,i),function(){this.toggleCommentLines=function(e,t,n,r){var i=!0,s=/^(\s*)\/\//;for(var o=n;o<=r;o++)if(!s.test(t.getLine(o))){i=!1;break}if(i){var u=new a(0,0,0,0);for(var o=n;o<=r;o++){var f=t.getLine(o),l=f.match(s);u.start.row=o,u.end.row=o,u.end.column=l[0].length,t.replace(u,l[1])}}else t.indentRows(n,r,"//")},this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.$tokenizer.getLineTokens(t,e),s=i.tokens,o=i.state;if(s.length&&s[s.length-1].type=="comment")return r;if(e=="start"||e=="regex_allowed"){var u=t.match(/^.*(?:\bcase\b.*\:|[\{\(\[])\s*$/);u&&(r+=n)}else if(e=="doc-start"){if(o=="start"||e=="regex_allowed")return"";var u=t.match(/^\s*(\/?)\*/);u&&(u[1]&&(r+=" "),r+="* ")}return r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.createWorker=function(e){var t=new f(["ace"],"ace/mode/javascript_worker","JavaScriptWorker");return t.attachToDocument(e.getDocument()),t.on("jslint",function(t){e.setAnnotations(t.data)}),t.on("terminate",function(){e.clearAnnotations()}),t}}.call(h.prototype),t.Mode=h}),ace.define("ace/mode/javascript_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/doc_comment_highlight_rules","ace/mode/text_highlight_rules"],function(e,t,n){var r=e("../lib/oop"),i=e("./doc_comment_highlight_rules").DocCommentHighlightRules,s=e("./text_highlight_rules").TextHighlightRules,o=function(){var e=this.createKeywordMapper({"variable.language":"Array|Boolean|Date|Function|Iterator|Number|Object|RegExp|String|Proxy|Namespace|QName|XML|XMLList|ArrayBuffer|Float32Array|Float64Array|Int16Array|Int32Array|Int8Array|Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray|Error|EvalError|InternalError|RangeError|ReferenceError|StopIteration|SyntaxError|TypeError|URIError|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|eval|isFinite|isNaN|parseFloat|parseInt|JSON|Math|this|arguments|prototype|window|document","invalid.deprecated":"__parent__|__count__|escape|unescape|with|__proto__",keyword:"const|yield|import|get|set|break|case|catch|continue|default|delete|do|else|finally|for|function|if|in|instanceof|new|return|switch|throw|try|typeof|let|var|while|with|debugger","storage.type":"const|let|var|function","invalid.illegal":"class|enum|extends|super|export|implements|private|public|interface|package|protected|static","constant.language":"null|Infinity|NaN|undefined","support.function":"alert"},"identifier"),t="case|do|else|finally|in|instanceof|return|throw|try|typeof|yield",n="[a-zA-Z\\$_¡-￿][a-zA-Z\\d\\$_¡-￿]*\\b",r="\\\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)";this.$rules={start:[{token:"comment",regex:/\/\/.*$/},i.getStartRule("doc-start"),{token:"comment",merge:!0,regex:/\/\*/,next:"comment"},{token:"string",regex:"'(?=.)",next:"qstring"},{token:"string",regex:'"(?=.)',next:"qqstring"},{token:"constant.numeric",regex:/0[xX][0-9a-fA-F]+\b/},{token:"constant.numeric",regex:/[+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/},{token:["storage.type","punctuation.operator","support.function","punctuation.operator","entity.name.function","text","keyword.operator"],regex:"("+n+")(\\.)(prototype)(\\.)("+n+")(\\s*)(=)",next:"function_arguments"},{token:["storage.type","punctuation.operator","entity.name.function","text","keyword.operator","text","storage.type","text","paren.lparen"],regex:"("+n+")(\\.)("+n+")(\\s*)(=)(\\s*)(function)(\\s*)(\\()",next:"function_arguments"},{token:["entity.name.function","text","keyword.operator","text","storage.type","text","paren.lparen"],regex:"("+n+")(\\s*)(=)(\\s*)(function)(\\s*)(\\()",next:"function_arguments"},{token:["storage.type","punctuation.operator","entity.name.function","text","keyword.operator","text","storage.type","text","entity.name.function","text","paren.lparen"],regex:"("+n+")(\\.)("+n+")(\\s*)(=)(\\s*)(function)(\\s+)(\\w+)(\\s*)(\\()",next:"function_arguments"},{token:["storage.type","text","entity.name.function","text","paren.lparen"],regex:"(function)(\\s+)("+n+")(\\s*)(\\()",next:"function_arguments"},{token:["entity.name.function","text","punctuation.operator","text","storage.type","text","paren.lparen"],regex:"("+n+")(\\s*)(:)(\\s*)(function)(\\s*)(\\()",next:"function_arguments"},{token:["text","text","storage.type","text","paren.lparen"],regex:"(:)(\\s*)(function)(\\s*)(\\()",next:"function_arguments"},{token:"constant.language.boolean",regex:/(?:true|false)\b/},{token:"keyword",regex:"(?:"+t+")\\b",next:"regex_allowed"},{token:["punctuation.operator","support.function"],regex:/(\.)(s(?:h(?:ift|ow(?:Mod(?:elessDialog|alDialog)|Help))|croll(?:X|By(?:Pages|Lines)?|Y|To)?|t(?:opzzzz|rike)|i(?:n|zeToContent|debar|gnText)|ort|u(?:p|b(?:str(?:ing)?)?)|pli(?:ce|t)|e(?:nd|t(?:Re(?:sizable|questHeader)|M(?:i(?:nutes|lliseconds)|onth)|Seconds|Ho(?:tKeys|urs)|Year|Cursor|Time(?:out)?|Interval|ZOptions|Date|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(?:ome|andleEvent)|navigate|c(?:har(?:CodeAt|At)|o(?:s|n(?:cat|textual|firm)|mpile)|eil|lear(?:Timeout|Interval)?|a(?:ptureEvents|ll)|reate(?:StyleSheet|Popup|EventObject))|t(?:o(?:GMTString|S(?:tring|ource)|U(?:TCString|pperCase)|Lo(?:caleString|werCase))|est|a(?:n|int(?:Enabled)?))|i(?:s(?:NaN|Finite)|ndexOf|talics)|d(?:isableExternalCapture|ump|etachEvent)|u(?:n(?:shift|taint|escape|watch)|pdateCommands)|j(?:oin|avaEnabled)|p(?:o(?:p|w)|ush|lugins.refresh|a(?:ddings|rse(?:Int|Float)?)|r(?:int|ompt|eference))|e(?:scape|nableExternalCapture|val|lementFromPoint|x(?:p|ec(?:Script|Command)?))|valueOf|UTC|queryCommand(?:State|Indeterm|Enabled|Value)|f(?:i(?:nd|le(?:ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(?:nt(?:size|color)|rward)|loor|romCharCode)|watch|l(?:ink|o(?:ad|g)|astIndexOf)|a(?:sin|nchor|cos|t(?:tachEvent|ob|an(?:2)?)|pply|lert|b(?:s|ort))|r(?:ou(?:nd|teEvents)|e(?:size(?:By|To)|calc|turnValue|place|verse|l(?:oad|ease(?:Capture|Events)))|andom)|g(?:o|et(?:ResponseHeader|M(?:i(?:nutes|lliseconds)|onth)|Se(?:conds|lection)|Hours|Year|Time(?:zoneOffset)?|Da(?:y|te)|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Da(?:y|te)|FullYear)|FullYear|A(?:ttention|llResponseHeaders)))|m(?:in|ove(?:B(?:y|elow)|To(?:Absolute)?|Above)|ergeAttributes|a(?:tch|rgins|x))|b(?:toa|ig|o(?:ld|rderWidths)|link|ack))\b(?=\()/},{token:["punctuation.operator","support.function.dom"],regex:/(\.)(s(?:ub(?:stringData|mit)|plitText|e(?:t(?:NamedItem|Attribute(?:Node)?)|lect))|has(?:ChildNodes|Feature)|namedItem|c(?:l(?:ick|o(?:se|neNode))|reate(?:C(?:omment|DATASection|aption)|T(?:Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(?:ntityReference|lement)|Attribute))|tabIndex|i(?:nsert(?:Row|Before|Cell|Data)|tem)|open|delete(?:Row|C(?:ell|aption)|T(?:Head|Foot)|Data)|focus|write(?:ln)?|a(?:dd|ppend(?:Child|Data))|re(?:set|place(?:Child|Data)|move(?:NamedItem|Child|Attribute(?:Node)?)?)|get(?:NamedItem|Element(?:sBy(?:Name|TagName)|ById)|Attribute(?:Node)?)|blur)\b(?=\()/},{token:["punctuation.operator","support.constant"],regex:/(\.)(s(?:ystemLanguage|cr(?:ipts|ollbars|een(?:X|Y|Top|Left))|t(?:yle(?:Sheets)?|atus(?:Text|bar)?)|ibling(?:Below|Above)|ource|uffixes|e(?:curity(?:Policy)?|l(?:ection|f)))|h(?:istory|ost(?:name)?|as(?:h|Focus))|y|X(?:MLDocument|SLDocument)|n(?:ext|ame(?:space(?:s|URI)|Prop))|M(?:IN_VALUE|AX_VALUE)|c(?:haracterSet|o(?:n(?:structor|trollers)|okieEnabled|lorDepth|mp(?:onents|lete))|urrent|puClass|l(?:i(?:p(?:boardData)?|entInformation)|osed|asses)|alle(?:e|r)|rypto)|t(?:o(?:olbar|p)|ext(?:Transform|Indent|Decoration|Align)|ags)|SQRT(?:1_2|2)|i(?:n(?:ner(?:Height|Width)|put)|ds|gnoreCase)|zIndex|o(?:scpu|n(?:readystatechange|Line)|uter(?:Height|Width)|p(?:sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(?:i(?:splay|alog(?:Height|Top|Width|Left|Arguments)|rectories)|e(?:scription|fault(?:Status|Ch(?:ecked|arset)|View)))|u(?:ser(?:Profile|Language|Agent)|n(?:iqueID|defined)|pdateInterval)|_content|p(?:ixelDepth|ort|ersonalbar|kcs11|l(?:ugins|atform)|a(?:thname|dding(?:Right|Bottom|Top|Left)|rent(?:Window|Layer)?|ge(?:X(?:Offset)?|Y(?:Offset)?))|r(?:o(?:to(?:col|type)|duct(?:Sub)?|mpter)|e(?:vious|fix)))|e(?:n(?:coding|abledPlugin)|x(?:ternal|pando)|mbeds)|v(?:isibility|endor(?:Sub)?|Linkcolor)|URLUnencoded|P(?:I|OSITIVE_INFINITY)|f(?:ilename|o(?:nt(?:Size|Family|Weight)|rmName)|rame(?:s|Element)|gColor)|E|whiteSpace|l(?:i(?:stStyleType|n(?:eHeight|kColor))|o(?:ca(?:tion(?:bar)?|lName)|wsrc)|e(?:ngth|ft(?:Context)?)|a(?:st(?:M(?:odified|atch)|Index|Paren)|yer(?:s|X)|nguage))|a(?:pp(?:MinorVersion|Name|Co(?:deName|re)|Version)|vail(?:Height|Top|Width|Left)|ll|r(?:ity|guments)|Linkcolor|bove)|r(?:ight(?:Context)?|e(?:sponse(?:XML|Text)|adyState))|global|x|m(?:imeTypes|ultiline|enubar|argin(?:Right|Bottom|Top|Left))|L(?:N(?:10|2)|OG(?:10E|2E))|b(?:o(?:ttom|rder(?:Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(?:Color|Image)))\b/},{token:["storage.type","punctuation.operator","support.function.firebug"],regex:/(console)(\.)(warn|info|log|error|time|timeEnd|assert)\b/},{token:e,regex:n},{token:"keyword.operator",regex:/!|\$|%|&|\*|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\|\||\?\:|\*=|%=|\+=|\-=|&=|\^=|\b(?:in|instanceof|new|delete|typeof|void)/,next:"regex_allowed"},{token:"punctuation.operator",regex:/\?|\:|\,|\;|\./,next:"regex_allowed"},{token:"paren.lparen",regex:/[\[({]/,next:"regex_allowed"},{token:"paren.rparen",regex:/[\])}]/},{token:"keyword.operator",regex:/\/=?/,next:"regex_allowed"},{token:"comment",regex:/^#!.*$/},{token:"text",regex:/\s+/}],regex_allowed:[i.getStartRule("doc-start"),{token:"comment",merge:!0,regex:"\\/\\*",next:"comment_regex_allowed"},{token:"comment",regex:"\\/\\/.*$"},{token:"string.regexp",regex:"\\/",next:"regex",merge:!0},{token:"text",regex:"\\s+"},{token:"empty",regex:"",next:"start"}],regex:[{token:"regexp.keyword.operator",regex:"\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)"},{token:"string.regexp",regex:"/\\w*",next:"start",merge:!0},{token:"invalid",regex:/\{\d+,?(?:\d+)?}[+*]|[+*$^?][+*]|[$^][?]|\?{3,}/},{token:"constant.language.escape",regex:/\(\?[:=!]|\)|{\d+,?(?:\d+)?}|{,\d+}|[+*]\?|[(|)$^+*?]/},{token:"string.regexp",regex:/{|[^{\[\/\\(|)$^+*?]+/,merge:!0},{token:"constant.language.escape",regex:/\[\^?/,next:"regex_character_class",merge:!0},{token:"empty",regex:"",next:"start"}],regex_character_class:[{token:"regexp.keyword.operator",regex:"\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)"},{token:"constant.language.escape",regex:"]",next:"regex",merge:!0},{token:"constant.language.escape",regex:"-"},{token:"string.regexp.charachterclass",regex:/[^\]\-\\]+/,merge:!0},{token:"empty",regex:"",next:"start"}],function_arguments:[{token:"variable.parameter",regex:n},{token:"punctuation.operator",regex:"[, ]+",merge:!0},{token:"punctuation.operator",regex:"$",merge:!0},{token:"empty",regex:"",next:"start"}],comment_regex_allowed:[{token:"comment",regex:".*?\\*\\/",merge:!0,next:"regex_allowed"},{token:"comment",merge:!0,regex:".+"}],comment:[{token:"comment",regex:".*?\\*\\/",merge:!0,next:"start"},{token:"comment",merge:!0,regex:".+"}],qqstring:[{token:"constant.language.escape",regex:r},{token:"string",regex:'[^"\\\\]+',merge:!0},{token:"string",regex:"\\\\$",next:"qqstring",merge:!0},{token:"string",regex:'"|$',next:"start",merge:!0}],qstring:[{token:"constant.language.escape",regex:r},{token:"string",regex:"[^'\\\\]+",merge:!0},{token:"string",regex:"\\\\$",next:"qstring",merge:!0},{token:"string",regex:"'|$",next:"start",merge:!0}]},this.embedRules(i,"doc-",[i.getEndRule("start")])};r.inherits(o,s),t.JavaScriptHighlightRules=o}),ace.define("ace/mode/doc_comment_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"comment.doc.tag",regex:"@[\\w\\d_]+"},{token:"comment.doc",merge:!0,regex:"\\s+"},{token:"comment.doc",merge:!0,regex:"TODO"},{token:"comment.doc",merge:!0,regex:"[^@\\*]+"},{token:"comment.doc",merge:!0,regex:"."}]}};r.inherits(s,i),s.getStartRule=function(e){return{token:"comment.doc",merge:!0,regex:"\\/\\*(?=\\*)",next:e}},s.getEndRule=function(e){return{token:"comment.doc",merge:!0,regex:"\\*\\/",next:e}},t.DocCommentHighlightRules=s}),ace.define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"],function(e,t,n){var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\}/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\})/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){var t=e.match(/^(\s+)/);return t?t[1]:""}}).call(i.prototype),t.MatchingBraceOutdent=i}),ace.define("ace/mode/behaviour/cstyle",["require","exports","module","ace/lib/oop","ace/mode/behaviour","ace/token_iterator"],function(e,t,n){var r=e("../../lib/oop"),i=e("../behaviour").Behaviour,s=e("../../token_iterator").TokenIterator,o=0,u=-1,a="",f=function(){f.isSaneInsertion=function(e,t){var n=e.getCursorPosition(),r=new s(t,n.row,n.column);if(!this.$matchTokenType(r.getCurrentToken()||"text",["text","paren.rparen"])){r=new s(t,n.row,n.column+1);if(!this.$matchTokenType(r.getCurrentToken()||"text",["text","paren.rparen"]))return!1}return r.stepForward(),r.getCurrentTokenRow()!==n.row||this.$matchTokenType(r.getCurrentToken()||"text",["text","comment","paren.rparen"])},f.$matchTokenType=function(e,t){return t.indexOf(e.type||e)>-1},f.recordAutoInsert=function(e,t,n){var r=e.getCursorPosition(),i=t.doc.getLine(r.row);this.isAutoInsertedClosing(r,i,a[0])||(o=0),u=r.row,a=n+i.substr(r.column),o++},f.isAutoInsertedClosing=function(e,t,n){return o>0&&e.row===u&&n===a[0]&&t.substr(e.column)===a},f.popAutoInsertedClosing=function(){a=a.substr(1),o--},this.add("braces","insertion",function(e,t,n,r,i){if(i=="{"){var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!==""&&o!=="{")return{text:"{"+o+"}",selection:!1};if(f.isSaneInsertion(n,r))return f.recordAutoInsert(n,r,"}"),{text:"{}",selection:[1,1]}}else if(i=="}"){var u=n.getCursorPosition(),a=r.doc.getLine(u.row),l=a.substring(u.column,u.column+1);if(l=="}"){var c=r.$findOpeningBracket("}",{column:u.column+1,row:u.row});if(c!==null&&f.isAutoInsertedClosing(u,a,i))return f.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}else if(i=="\n"||i=="\r\n"){var u=n.getCursorPosition(),a=r.doc.getLine(u.row),l=a.substring(u.column,u.column+1);if(l=="}"){var h=r.findMatchingBracket({row:u.row,column:u.column+1});if(!h)return null;var p=this.getNextLineIndent(e,a.substring(0,a.length-1),r.getTabString()),d=this.$getIndent(r.doc.getLine(h.row));return{text:"\n"+p+"\n"+d,selection:[1,p.length,1,p.length]}}}}),this.add("braces","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="{"){var o=r.doc.getLine(i.start.row),u=o.substring(i.end.column,i.end.column+1);if(u=="}")return i.end.column++,i}}),this.add("parens","insertion",function(e,t,n,r,i){if(i=="("){var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!=="")return{text:"("+o+")",selection:!1};if(f.isSaneInsertion(n,r))return f.recordAutoInsert(n,r,")"),{text:"()",selection:[1,1]}}else if(i==")"){var u=n.getCursorPosition(),a=r.doc.getLine(u.row),l=a.substring(u.column,u.column+1);if(l==")"){var c=r.$findOpeningBracket(")",{column:u.column+1,row:u.row});if(c!==null&&f.isAutoInsertedClosing(u,a,i))return f.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("parens","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="("){var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u==")")return i.end.column++,i}}),this.add("brackets","insertion",function(e,t,n,r,i){if(i=="["){var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!=="")return{text:"["+o+"]",selection:!1};if(f.isSaneInsertion(n,r))return f.recordAutoInsert(n,r,"]"),{text:"[]",selection:[1,1]}}else if(i=="]"){var u=n.getCursorPosition(),a=r.doc.getLine(u.row),l=a.substring(u.column,u.column+1);if(l=="]"){var c=r.$findOpeningBracket("]",{column:u.column+1,row:u.row});if(c!==null&&f.isAutoInsertedClosing(u,a,i))return f.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("brackets","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="["){var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u=="]")return i.end.column++,i}}),this.add("string_dquotes","insertion",function(e,t,n,r,i){if(i=='"'||i=="'"){var s=i,o=n.getSelectionRange(),u=r.doc.getTextRange(o);if(u!=="")return{text:s+u+s,selection:!1};var a=n.getCursorPosition(),f=r.doc.getLine(a.row),l=f.substring(a.column-1,a.column);if(l=="\\")return null;var c=r.getTokens(o.start.row),h=0,p,d=-1;for(var v=0;vo.start.column)break;h+=c[v].value.length}if(!p||d<0&&p.type!=="comment"&&(p.type!=="string"||o.start.column!==p.value.length+h-1&&p.value.lastIndexOf(s)===p.value.length-1))return{text:s+s,selection:[1,1]};if(p&&p.type==="string"){var m=f.substring(a.column,a.column+1);if(m==s)return{text:"",selection:[1,1]}}}}),this.add("string_dquotes","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&(s=='"'||s=="'")){var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u=='"')return i.end.column++,i}})};r.inherits(f,i),t.CstyleBehaviour=f}),ace.define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(){};r.inherits(o,s),function(){this.foldingStartMarker=/(\{|\[)[^\}\]]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/,this.getFoldWidgetRange=function(e,t,n){var r=e.getLine(n),i=r.match(this.foldingStartMarker);if(i){var s=i.index;return i[1]?this.openingBracketBlock(e,i[1],n,s):e.getCommentFoldRange(n,s+i[0].length,1)}if(t!=="markbeginend")return;var i=r.match(this.foldingStopMarker);if(i){var s=i.index+i[0].length;return i[1]?this.closingBracketBlock(e,i[1],n,s):e.getCommentFoldRange(n,s,-1)}}}.call(o.prototype)}) -------------------------------------------------------------------------------- /contextmenu/jquery.contextmenu.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery ContextMenu 3 | * http://www.userdot.net/#!/jquery 4 | * 5 | * Copyright 2011, UserDot www.userdot.net 6 | * Licensed under the GPL Version 3 license. 7 | * Version 1.0.0 8 | * 9 | */ 10 | (function($) { 11 | var classes = { 12 | popupDiv : 'uctxMenu', 13 | separator : 'separator', 14 | hover : 'hover', 15 | disabled : 'disabled' 16 | }, 17 | defaults = { 18 | menu : null, 19 | mouseButton : 'right', 20 | isMenu : true, 21 | minWidth : 120, 22 | maxWidth : 0, 23 | delay : 500, 24 | keyboard : true, 25 | hoverIntent : true, 26 | onSelect : function(item) {}, 27 | onLoad : function() {}, 28 | onShow : function() {}, 29 | onHide : function() {} 30 | }, 31 | menus = [], 32 | target, 33 | methods = { 34 | init : function(options) { 35 | options = $.extend({}, defaults, options); 36 | if (!options.menu) { 37 | return false; 38 | } 39 | var $menu; 40 | if ((typeof(options.menu) === 'object') && (options.menu.constructor.toString().match(/array/i) !== null || options.menu.length)) { 41 | $menu = $('
').append(buildMenu(options.menu)); 42 | $('body').append($menu); 43 | $menu.data('uctxDynamic', true); 44 | } 45 | else { 46 | $menu = $(document.getElementById(options.menu)); 47 | $menu.data('uctxDynamic', false); 48 | $menu.data('uctxOriginal', $menu.clone()); 49 | } 50 | return this.each(function() { 51 | var $this = $(this), 52 | eventNamespace; 53 | if (!$this.data('uctxMenu')) { 54 | eventNamespace = "uctxContext-" + (new Date().getTime()); 55 | $this.data('uctxEventNamespace', eventNamespace) 56 | .data('uctxOptions', options) 57 | .data('uctxMenu', $menu) 58 | .data('uctxEnable', true); 59 | $menu.data('isMenu', options.isMenu); 60 | if (! $menu.data('uctxOwners')) { 61 | $menu.data('uctxOwners', []); 62 | } 63 | $menu.data('uctxOwners').push($this); 64 | menus.push($menu); 65 | if (options.isMenu) { 66 | methods.refresh.call($this); 67 | } 68 | else { 69 | $menu.hide(); 70 | $menu.css({ 71 | 'position' : 'absolute', 72 | 'z-index' : 99999 73 | }); 74 | } 75 | $this.bind((((options.mouseButton === 'right') ? 'contextmenu' : 'click') + '.' + eventNamespace), function(e){ 76 | target = $(e.target); 77 | 78 | if (! $this.data('uctxEnable')) { 79 | return true; 80 | } 81 | methods.show.apply($this, [e.pageX, e.pageY, options.showAnimation]); 82 | if (options.isMenu && options.keyboard) { 83 | $(window).bind('keydown.' + eventNamespace, function(even){ 84 | var $currentItem; 85 | switch (event.keyCode) { 86 | case 27: 87 | $(document).trigger('click.' + eventNamespace); 88 | break; 89 | case 40: 90 | if ($menu.find('li.' + classes.hover).length === 0) { 91 | $menu.find('li:not(.disabled):first').addClass(classes.hover); 92 | } 93 | else { 94 | $currentItem = $menu.find('li.' + classes.hover + ':last'); 95 | $currentItem.parent().find('li.' + classes.hover).removeClass(classes.hover).nextAll('li:not(.disabled)').eq(0).addClass(classes.hover); 96 | if ($currentItem.parent().find('li.' + classes.hover).length === 0) { 97 | $currentItem.parent().find('li:not(.disabled):first').addClass(classes.hover); 98 | } 99 | } 100 | return false; 101 | case 38: 102 | if ($menu.find('li.' + classes.hover).length === 0) { 103 | $menu.find('li:not(.disabled):first').nextAll().eq(-1).addClass(classes.hover); 104 | } 105 | else { 106 | $currentItem = $menu.find('li.' + classes.hover + ':last'); 107 | $currentItem.parent().find('li.' + classes.hover).removeClass(classes.hover).prevAll('LI:not(.disabled)').eq(0).addClass(classes.hover); 108 | if ($currentItem.parent().find('li.' + classes.hover).length === 0) { 109 | $currentItem.parent().find('li:first').nextAll().eq(-1).addClass(classes.hover); 110 | } 111 | } 112 | return false; 113 | case 39: 114 | if ($menu.find('li.' + classes.hover + ' ul').length > 0) { 115 | $menu.find('li.' + classes.hover + ':last').find('ul:first').show().offset(forceViewport({ 116 | top: $menu.find('li.' + classes.hover + ':last').offset().top 117 | }, $menu.find('li.' + classes.hover + ':last').find('ul:first'))); 118 | $menu.find('li.' + classes.hover + ':last ul:first li:not(.disabled):first').addClass(classes.hover); 119 | } 120 | return false; 121 | case 37: 122 | if (!$menu.find('li.' + classes.hover + ':last').parent().parent().hasClass(classes.popupDiv)) { 123 | $menu.find('li.' + classes.hover + ':last').removeClass(classes.hover).parent().hide(); 124 | } 125 | return false; 126 | } 127 | return true; 128 | }); 129 | } 130 | else { 131 | if (options.keyboard) { 132 | $(window).bind('keydown.' + eventNamespace, function(even){ 133 | if (event.keyCode === 27) { 134 | $(document).trigger('click.' + eventNamespace); 135 | } 136 | }); 137 | } 138 | } 139 | $('li', $menu).each(function() { 140 | $(this).click(function() { 141 | if (!$(this).hasClass(classes.disabled)) { 142 | options.onSelect.call(this, { 143 | id : $(this).attr('id'), 144 | action : $('a:first', this).attr('href').substr(1), 145 | target: target 146 | }); 147 | } 148 | }); 149 | }); 150 | $(document).bind('click.' + eventNamespace, function(e){ 151 | $(window).unbind('keydown.' + eventNamespace); 152 | $(document).unbind('click.' + eventNamespace); 153 | $('li', $menu).unbind('click'); 154 | methods.hide.call(); 155 | }); 156 | options.onShow.call(this); 157 | return false; 158 | }); 159 | } 160 | options.onLoad.call(this); 161 | }); 162 | }, 163 | refresh : function(options) { 164 | var opts; 165 | return this.each(function() { 166 | var $this = $(this), 167 | $menu = $this.data('uctxMenu'), 168 | calculatedWidth, 169 | $widthTest; 170 | if ($this.data('uctxMenu').data('isMenu')) { 171 | opts = $.extend($this.data('uctxOptions'), options); 172 | if (opts.hoverIntent && ! $.fn.hoverIntent) { 173 | opts.hoverIntent = false; 174 | } 175 | $menu.removeClass(classes.popupDiv); 176 | $('li', $menu).removeClass(classes.hover); 177 | $('span', $menu).remove(); 178 | $menu.addClass(classes.popupDiv); 179 | $widthTest = $('
').addClass(classes.popupDiv).appendTo('body'); 180 | $('ul', $menu).each(function() { 181 | $widthTest.html(''); 182 | calculatedWidth = 0; 183 | $widthTest.html($(this).html()); 184 | calculatedWidth = $widthTest.width() + 16; 185 | if (calculatedWidth < opts.minWidth) { 186 | calculatedWidth = opts.minWidth; 187 | } 188 | if (calculatedWidth > opts.maxWidth && opts.maxWidth > 0){ 189 | calculatedWidth = opts.maxWidth; 190 | } 191 | $(this).width(calculatedWidth); 192 | $(this).children('li').children('ul').css('left', calculatedWidth); 193 | }); 194 | $widthTest.remove(); 195 | $('li:has(ul)', $menu).each(function(){ 196 | if (! $(this).hasClass(classes.disabled)) { 197 | $('a:first', this).append($('')); 198 | if (opts.hoverIntent) { 199 | $(this).hoverIntent({ 200 | over : function() { 201 | $('ul:first', this).show().offset(forceViewport({ 202 | top: $(this).offset().top 203 | }, $('ul:first',this))); 204 | }, 205 | out : function() { 206 | $('ul:first', this).hide(); 207 | }, 208 | timeout : opts.delay 209 | }); 210 | } 211 | else { 212 | $(this).hover(function() { 213 | $('ul:first', this).show().offset(forceViewport({ 214 | top: $(this).offset().top 215 | }, $(this).find('ul:first'))); 216 | }, function() { 217 | $('ul:first', this).hide(); 218 | }); 219 | } 220 | } 221 | }); 222 | $('li', $menu).each(function() { 223 | $(this).click(function() { 224 | if ($('ul', this).length < 1) { 225 | $('li', $menu).unbind('click'); 226 | $menu.hide(); 227 | } 228 | return false; 229 | }); 230 | $(this).hover(function() { 231 | $(this).parent().find('li.' + classes.hover).removeClass(classes.hover); 232 | $(this).addClass(classes.hover); 233 | }, function() { 234 | $(this).removeClass(classes.hover); 235 | }); 236 | }); 237 | } 238 | }); 239 | }, 240 | restore : function() { 241 | return this.each(function() { 242 | var $this = $(this), 243 | $menu = $this.data('uctxMenu'); 244 | $this.unbind('.' + $this.data('uctxEventNamespace')); 245 | $(window).unbind('keydown.' + $this.data('uctxEventNamespace')); 246 | $(document).unbind('click.' + $this.data('uctxEventNamespace')); 247 | $.each($menu.data('uctxOwners'), function(index) { 248 | if ($this[0] === this) { 249 | $menu.data('uctxOwners').splice(index, 1); 250 | } 251 | }); 252 | if ($menu.data('uctxOwners').length < 1) { 253 | $.each(menus, function(index) { 254 | if ($menu[0] === this) { 255 | menus.splice(index, 1); 256 | } 257 | }); 258 | if ($menu.data('uctxDynamic')) { 259 | $menu.remove(); 260 | } 261 | else { 262 | $menu.removeClass(classes.popupDiv); 263 | $menu.replaceWith($menu.data('uctxOriginal')); 264 | } 265 | } 266 | $this.removeData('uctxEventNamespace'); 267 | $this.removeData('uctxMenu'); 268 | $this.removeData('uctxOptions'); 269 | $this.removeData('uctxEnable'); 270 | }); 271 | }, 272 | show : function(x, y) { 273 | if (!x || !y) { 274 | $.error('The position for the menu has not been specified'); 275 | return false; 276 | } 277 | var $menu = $(this).first().data('uctxMenu'); 278 | methods.hide.apply(this); 279 | $menu.show(); 280 | $menu.data('uctxMenu', $(this)); 281 | $menu.offset(forceViewport({ 282 | top : y, 283 | left: x 284 | }, $menu, true)); 285 | return this; 286 | }, 287 | hide : function() { 288 | $.each(menus, function() { 289 | $('.' + classes.hover, this).removeClass(classes.hover); 290 | $('ul:first ul', this).hide(); 291 | if ($(this).data('uctxMenu')) { 292 | $(this).data('uctxMenu').data('uctxOptions').onHide.call($(this).data('uctxMenu')); 293 | $(this).removeData('uctxMenu'); 294 | } 295 | $(this).hide(); 296 | }); 297 | return this; 298 | }, 299 | disable : function(item) { 300 | if (item) { 301 | var $menu = $(this).data('uctxMenu'); 302 | if (item.charAt(0) === '#') { 303 | $('li' + item.replace(/ /g,'_'), $menu).addClass(classes.disabled); 304 | } 305 | else { 306 | $('a[href="' + item + '"]', $menu).parent().addClass(classes.disabled); 307 | } 308 | } 309 | else { 310 | $(this).data('uctxEnable', false); 311 | } 312 | return this; 313 | }, 314 | enable : function(item) { 315 | if (item) { 316 | var $menu = $(this).data('uctxMenu'); 317 | if (item.charAt(0) === '#') { 318 | $('li' + item.replace(/ /g,'_'), $menu).removeClass(classes.disabled); 319 | } 320 | else { 321 | $('a[href="' + item + '"]', $menu).parent().removeClass(classes.disabled); 322 | } 323 | } 324 | else { 325 | $(this).data('uctxEnable', true); 326 | $('li', this).each(function() { 327 | $(this).removeClass(classes.disabled); 328 | }); 329 | } 330 | return this; 331 | } 332 | }, 333 | forceViewport = function(position, o, mouse) { 334 | if (position.top) { 335 | if ((position.top + o.height() - $(window).scrollTop()) > $(window).height()) { 336 | if (mouse) { 337 | position.top = position.top - o.height(); 338 | } 339 | else { 340 | position.top = $(window).height() + $(window).scrollTop() - o.height(); 341 | } 342 | } 343 | if (position.top < $(window).scrollTop()) { 344 | position.top = $(window).scrollTop(); 345 | } 346 | } 347 | if (position.left) { 348 | if ((position.left + o.width() - $(window).scrollLeft() > $(window).width())) { 349 | position.left = $(window).width() - o.width() + $(window).scrollLeft(); 350 | } 351 | if (position.left < $(window).scrollLeft()) { 352 | position.left = $(window).scrollLeft(); 353 | } 354 | } 355 | return position; 356 | }, 357 | buildMenu = function(children) { 358 | var ul = $('"); 580 | }; 581 | createLi = function(node) { 582 | var $li; 583 | if (node.hasChildren()) { 584 | $li = createFolderLi(node); 585 | } else { 586 | $li = createNodeLi(node); 587 | } 588 | if (_this.options.onCreateLi) _this.options.onCreateLi(node, $li); 589 | return $li; 590 | }; 591 | createNodeLi = function(node) { 592 | // 593 | // Node data display 594 | // 595 | var interpretation = ""; 596 | if (node.interpretation != "") { 597 | interpretation = "
         "+node.interpretation; 598 | } 599 | 600 | // Make hexData specific length 601 | var maxDataDisplaySize = 4; 602 | var hexData=node.hexData; 603 | var fillNeeded = maxDataDisplaySize*3+1 - hexData.length; 604 | for(var i=0; i 0) { 609 | comment = " " + comment; 610 | } 611 | 612 | return $("
  • " + convertToHexWord(node.offset) 613 | + " " + hexData 614 | + node.label 615 | + comment 616 | + interpretation+"
  • "); 617 | 618 | }; 619 | createFolderLi = function(node) { 620 | var button_class, folder_class, getButtonClass, getFolderClass; 621 | getButtonClass = function() { 622 | var classes; 623 | classes = ['toggler']; 624 | if (!node.is_open) classes.push('closed'); 625 | return classes.join(' '); 626 | }; 627 | getFolderClass = function() { 628 | var classes; 629 | classes = ['folder']; 630 | if (!node.is_open) classes.push('closed'); 631 | return classes.join(' '); 632 | }; 633 | button_class = getButtonClass(); 634 | folder_class = getFolderClass(); 635 | return $("
  • »" + node.name + "
  • "); 636 | }; 637 | doCreateDomElements = function($element, children, depth, is_open) { 638 | var $li, $ul, child, _i, _len, _results; 639 | $ul = createUl(depth, is_open); 640 | $element.append($ul); 641 | _results = []; 642 | for (_i = 0, _len = children.length; _i < _len; _i++) { 643 | child = children[_i]; 644 | $li = createLi(child); 645 | $ul.append($li); 646 | child.element = $li[0]; 647 | $li.data('node', child); 648 | if (child.hasChildren()) { 649 | _results.push(doCreateDomElements($li, child.children, depth + 1, child.is_open)); 650 | } else { 651 | _results.push(void 0); 652 | } 653 | } 654 | return _results; 655 | }; 656 | this.element.empty(); 657 | return doCreateDomElements(this.element, tree.children, 0, true); 658 | }, 659 | _click: function(e) { 660 | var $target, event, node, node_element; 661 | if (e.ctrlKey) return; 662 | $target = $(e.target); 663 | if ($target.is('.toggler')) { 664 | node_element = this._getNodeElement($target); 665 | if (node_element && node_element.node.hasChildren()) { 666 | node_element.toggle(); 667 | if (this.options.saveState) this._saveState(); 668 | e.preventDefault(); 669 | return e.stopPropagation(); 670 | } 671 | } else if ($target.is('div') || $target.is('span')) { 672 | node = this._getNode($target); 673 | if (node) { 674 | if ((!this.options.onCanSelectNode) || this.options.onCanSelectNode(node)) { 675 | this.selectNode(node); 676 | event = $.Event('tree.click'); 677 | event.node = node; 678 | event.target = $target; 679 | return this.element.trigger(event); 680 | } 681 | } 682 | } 683 | }, 684 | _contextmenu: function(e) { 685 | var $div, event, node; 686 | $div = $(e.target).closest('ul.tree div'); 687 | if ($div.length) { 688 | node = this._getNode($div); 689 | if (node) { 690 | e.preventDefault(); 691 | e.stopPropagation(); 692 | event = $.Event('tree.contextmenu'); 693 | event.node = node; 694 | event.click_event = e; 695 | this.element.trigger(event); 696 | return false; 697 | } 698 | } 699 | }, 700 | _getNode: function($element) { 701 | var $li; 702 | $li = $element.closest('li'); 703 | if ($li.length === 0) { 704 | return null; 705 | } else { 706 | return $li.data('node'); 707 | } 708 | }, 709 | _getNodeElement: function($element) { 710 | var node; 711 | node = this._getNode($element); 712 | if (node) { 713 | return this._getNodeElementForNode(node); 714 | } else { 715 | return null; 716 | } 717 | }, 718 | _getNodeElementForNode: function(node) { 719 | if (node.hasChildren()) { 720 | return new FolderElement(node); 721 | } else { 722 | return new NodeElement(node); 723 | } 724 | }, 725 | _mouseCapture: function(event) { 726 | var $element, node_element; 727 | if (!this.options.dragAndDrop) return; 728 | $element = $(event.target); 729 | if (this.options.onIsMoveHandle && !this.options.onIsMoveHandle($element)) { 730 | return null; 731 | } 732 | node_element = this._getNodeElement($(event.target)); 733 | if (node_element && this.options.onCanMove) { 734 | if (!this.options.onCanMove(node_element.node)) node_element = null; 735 | } 736 | this.current_item = node_element; 737 | return this.current_item !== null; 738 | }, 739 | _mouseStart: function(event) { 740 | var offsetX, offsetY, _ref; 741 | if (!this.options.dragAndDrop) return; 742 | this._refreshHitAreas(); 743 | _ref = this._getOffsetFromEvent(event), offsetX = _ref[0], offsetY = _ref[1]; 744 | this.drag_element = new DragElement(this.current_item.node, offsetX, offsetY, this.element); 745 | this.current_item.$element.addClass('moving'); 746 | return true; 747 | }, 748 | _getOffsetFromEvent: function(event) { 749 | var element_offset; 750 | element_offset = $(event.target).offset(); 751 | return [event.pageX - element_offset.left, event.pageY - element_offset.top]; 752 | }, 753 | _mouseDrag: function(event) { 754 | var area, position_name; 755 | if (!this.options.dragAndDrop) return; 756 | this.drag_element.move(event.pageX, event.pageY); 757 | area = this.findHoveredArea(event.pageX, event.pageY); 758 | if (area && this.options.onCanMoveTo) { 759 | position_name = Position.getName(area.position); 760 | if (!this.options.onCanMoveTo(this.current_item.node, area.node, position_name)) { 761 | area = null; 762 | } 763 | } 764 | if (!area) { 765 | this._removeDropHint(); 766 | this._removeHover(); 767 | this._stopOpenFolderTimer(); 768 | } else { 769 | if (this.hovered_area !== area) { 770 | this.hovered_area = area; 771 | this._updateDropHint(); 772 | } 773 | } 774 | return true; 775 | }, 776 | _updateDropHint: function() { 777 | var node, node_element; 778 | this._stopOpenFolderTimer(); 779 | if (!this.hovered_area) return; 780 | node = this.hovered_area.node; 781 | if (node.hasChildren() && !node.is_open && this.hovered_area.position === Position.INSIDE) { 782 | this._startOpenFolderTimer(node); 783 | } 784 | this._removeDropHint(); 785 | node_element = this._getNodeElementForNode(this.hovered_area.node); 786 | return this.previous_ghost = node_element.addDropHint(this.hovered_area.position); 787 | }, 788 | _mouseStop: function() { 789 | if (!this.options.dragAndDrop) return; 790 | this._moveItem(); 791 | this._clear(); 792 | this._removeHover(); 793 | this._removeDropHint(); 794 | this._removeHitAreas(); 795 | this.current_item.$element.removeClass('moving'); 796 | return false; 797 | }, 798 | _mouseMove: function(event) { 799 | if ($.browser.msie && document.documentMode === 8 && !event.button) { 800 | event.button = 1; 801 | } 802 | return $.ui.mouse.prototype._mouseMove.call(this, event); 803 | }, 804 | _moveItem: function() { 805 | var event; 806 | if (this.hovered_area && this.hovered_area.position !== Position.NONE) { 807 | this.tree.moveNode(this.current_item.node, this.hovered_area.node, this.hovered_area.position); 808 | if (this.hovered_area.position === Position.INSIDE) { 809 | this.hovered_area.node.is_open = true; 810 | } 811 | event = $.Event('tree.move'); 812 | event.move_info = { 813 | moved_node: this.current_item.node, 814 | target_node: this.hovered_area.node, 815 | position: Position.getName(this.hovered_area.position) 816 | }; 817 | this.element.trigger(event); 818 | this.element.empty(); 819 | return this._createDomElements(this.tree); 820 | } 821 | }, 822 | _clear: function() { 823 | this.drag_element.remove(); 824 | return this.drag_element = null; 825 | }, 826 | _refreshHitAreas: function() { 827 | this._removeHitAreas(); 828 | return this._generateHitAreas(); 829 | }, 830 | _generateHitAreas: function() { 831 | var addPosition, getTop, groupPositions, handleAfterOpenFolder, handleClosedFolder, handleFirstNode, handleNode, handleOpenFolder, hit_areas, last_top, positions, 832 | _this = this; 833 | positions = []; 834 | last_top = 0; 835 | getTop = function($element) { 836 | return $element.offset().top; 837 | }; 838 | addPosition = function(node, position, top) { 839 | positions.push({ 840 | top: top, 841 | node: node, 842 | position: position 843 | }); 844 | return last_top = top; 845 | }; 846 | groupPositions = function(handle_group) { 847 | var group, position, previous_top, _i, _len; 848 | previous_top = -1; 849 | group = []; 850 | for (_i = 0, _len = positions.length; _i < _len; _i++) { 851 | position = positions[_i]; 852 | if (position.top !== previous_top) { 853 | if (group.length) handle_group(group, previous_top, position.top); 854 | previous_top = position.top; 855 | group = []; 856 | } 857 | group.push(position); 858 | } 859 | return handle_group(group, previous_top, _this.element.offset().top + _this.element.height()); 860 | }; 861 | handleNode = function(node, next_node, $element) { 862 | var top; 863 | top = getTop($element); 864 | if (node === _this.current_item.node) { 865 | addPosition(node, Position.NONE, top); 866 | } else { 867 | addPosition(node, Position.INSIDE, top); 868 | } 869 | if (next_node === _this.current_item.node || node === _this.current_item.node) { 870 | return addPosition(node, Position.NONE, top); 871 | } else { 872 | return addPosition(node, Position.AFTER, top); 873 | } 874 | }; 875 | handleOpenFolder = function(node, $element) { 876 | if (node === _this.current_item.node) return false; 877 | if (node.children[0] !== _this.current_item.node) { 878 | addPosition(node, Position.INSIDE, getTop($element)); 879 | } 880 | return true; 881 | }; 882 | handleAfterOpenFolder = function(node, next_node, $element) { 883 | if (node === _this.current_item.node || next_node === _this.current_item.node) { 884 | return addPosition(node, Position.NONE, last_top); 885 | } else { 886 | return addPosition(node, Position.AFTER, last_top); 887 | } 888 | }; 889 | handleClosedFolder = function(node, next_node, $element) { 890 | var top; 891 | top = getTop($element); 892 | if (node === _this.current_item.node) { 893 | return addPosition(node, Position.NONE, top); 894 | } else { 895 | addPosition(node, Position.INSIDE, top); 896 | if (next_node !== _this.current_item.node) { 897 | return addPosition(node, Position.AFTER, top); 898 | } 899 | } 900 | }; 901 | handleFirstNode = function(node, $element) { 902 | if (node !== _this.current_item.node) { 903 | return addPosition(node, Position.BEFORE, getTop($(node.element))); 904 | } 905 | }; 906 | this._iterateVisibleNodes(handleNode, handleOpenFolder, handleClosedFolder, handleAfterOpenFolder, handleFirstNode); 907 | hit_areas = []; 908 | groupPositions(function(positions_in_group, top, bottom) { 909 | var area_height, area_top, position, _i, _len, _results; 910 | area_height = (bottom - top) / positions_in_group.length; 911 | area_top = top; 912 | _results = []; 913 | for (_i = 0, _len = positions_in_group.length; _i < _len; _i++) { 914 | position = positions_in_group[_i]; 915 | hit_areas.push({ 916 | top: area_top, 917 | bottom: area_top + area_height, 918 | node: position.node, 919 | position: position.position 920 | }); 921 | _results.push(area_top += area_height); 922 | } 923 | return _results; 924 | }); 925 | return this.hit_areas = hit_areas; 926 | }, 927 | findHoveredArea: function(x, y) { 928 | var area, high, low, mid, tree_offset; 929 | tree_offset = this.element.offset(); 930 | if (x < tree_offset.left || y < tree_offset.top || x > (tree_offset.left + this.element.width()) || y > (tree_offset.top + this.element.height())) { 931 | return null; 932 | } 933 | low = 0; 934 | high = this.hit_areas.length; 935 | while (low < high) { 936 | mid = (low + high) >> 1; 937 | area = this.hit_areas[mid]; 938 | if (y < area.top) { 939 | high = mid; 940 | } else if (y > area.bottom) { 941 | low = mid + 1; 942 | } else { 943 | return area; 944 | } 945 | } 946 | return null; 947 | }, 948 | _iterateVisibleNodes: function(handle_node, handle_open_folder, handle_closed_folder, handle_after_open_folder, handle_first_node) { 949 | var is_first_node, iterate, 950 | _this = this; 951 | is_first_node = true; 952 | iterate = function(node, next_node) { 953 | var $element, child, children_length, i, must_iterate_inside, _len, _ref; 954 | must_iterate_inside = (node.is_open || !node.element) && node.hasChildren(); 955 | if (node.element) { 956 | $element = $(node.element); 957 | if (!$element.is(':visible')) return; 958 | if (is_first_node) { 959 | handle_first_node(node, $element); 960 | is_first_node = false; 961 | } 962 | if (!node.hasChildren()) { 963 | handle_node(node, next_node, $element); 964 | } else if (node.is_open) { 965 | if (!handle_open_folder(node, $element)) must_iterate_inside = false; 966 | } else { 967 | handle_closed_folder(node, next_node, $element); 968 | } 969 | } 970 | if (must_iterate_inside) { 971 | children_length = node.children.length; 972 | _ref = node.children; 973 | for (i = 0, _len = _ref.length; i < _len; i++) { 974 | child = _ref[i]; 975 | if (i === (children_length - 1)) { 976 | iterate(node.children[i], null); 977 | } else { 978 | iterate(node.children[i], node.children[i + 1]); 979 | } 980 | } 981 | if (node.is_open) { 982 | return handle_after_open_folder(node, next_node, $element); 983 | } 984 | } 985 | }; 986 | return iterate(this.tree); 987 | }, 988 | _removeHover: function() { 989 | return this.hovered_area = null; 990 | }, 991 | _removeDropHint: function() { 992 | if (this.previous_ghost) return this.previous_ghost.remove(); 993 | }, 994 | _removeHitAreas: function() { 995 | return this.hit_areas = []; 996 | }, 997 | _openNodes: function() { 998 | var max_level; 999 | if (this.options.saveState) if (this._restoreState()) return; 1000 | if (this.options.autoOpen === false) { 1001 | return; 1002 | } else if (this.options.autoOpen === true) { 1003 | max_level = -1; 1004 | } else { 1005 | max_level = parseInt(this.options.autoOpen); 1006 | } 1007 | return this.tree.iterate(function(node, level) { 1008 | node.is_open = true; 1009 | return level !== max_level; 1010 | }); 1011 | }, 1012 | _startOpenFolderTimer: function(folder) { 1013 | var openFolder, 1014 | _this = this; 1015 | openFolder = function() { 1016 | return _this._getNodeElementForNode(folder).open(function() { 1017 | _this._refreshHitAreas(); 1018 | return _this._updateDropHint(); 1019 | }); 1020 | }; 1021 | return this.open_folder_timer = setTimeout(openFolder, 500); 1022 | }, 1023 | _stopOpenFolderTimer: function() { 1024 | if (this.open_folder_timer) { 1025 | clearTimeout(this.open_folder_timer); 1026 | return this.open_folder_timer = null; 1027 | } 1028 | } 1029 | }); 1030 | 1031 | GhostDropHint = (function() { 1032 | 1033 | function GhostDropHint(node, $element, position) { 1034 | this.$element = $element; 1035 | this.node = node; 1036 | this.$ghost = $('
  • '); 1037 | if (position === Position.AFTER) { 1038 | this.moveAfter(); 1039 | } else if (position === Position.BEFORE) { 1040 | this.moveBefore(); 1041 | } else if (position === Position.INSIDE) { 1042 | if (node.hasChildren() && node.is_open) { 1043 | this.moveInsideOpenFolder(); 1044 | } else { 1045 | this.moveInside(); 1046 | } 1047 | } 1048 | } 1049 | 1050 | GhostDropHint.prototype.remove = function() { 1051 | return this.$ghost.remove(); 1052 | }; 1053 | 1054 | GhostDropHint.prototype.moveAfter = function() { 1055 | return this.$element.after(this.$ghost); 1056 | }; 1057 | 1058 | GhostDropHint.prototype.moveBefore = function() { 1059 | return this.$element.before(this.$ghost); 1060 | }; 1061 | 1062 | GhostDropHint.prototype.moveInsideOpenFolder = function() { 1063 | return $(this.node.children[0].element).before(this.$ghost); 1064 | }; 1065 | 1066 | GhostDropHint.prototype.moveInside = function() { 1067 | this.$element.after(this.$ghost); 1068 | return this.$ghost.addClass('inside'); 1069 | }; 1070 | 1071 | return GhostDropHint; 1072 | 1073 | })(); 1074 | 1075 | BorderDropHint = (function() { 1076 | 1077 | function BorderDropHint($element) { 1078 | var $div, width; 1079 | $div = $element.children('div'); 1080 | width = $element.width() - 4; 1081 | this.$hint = $(''); 1082 | $div.append(this.$hint); 1083 | this.$hint.css({ 1084 | width: width, 1085 | height: $div.height() - 4 1086 | }); 1087 | } 1088 | 1089 | BorderDropHint.prototype.remove = function() { 1090 | return this.$hint.remove(); 1091 | }; 1092 | 1093 | return BorderDropHint; 1094 | 1095 | })(); 1096 | 1097 | NodeElement = (function() { 1098 | 1099 | function NodeElement(node) { 1100 | this.init(node); 1101 | } 1102 | 1103 | NodeElement.prototype.init = function(node) { 1104 | this.node = node; 1105 | return this.$element = $(node.element); 1106 | }; 1107 | 1108 | NodeElement.prototype.getUl = function() { 1109 | return this.$element.children('ul:first'); 1110 | }; 1111 | 1112 | NodeElement.prototype.getSpan = function() { 1113 | return this.$element.children('div').find('span.title'); 1114 | }; 1115 | 1116 | NodeElement.prototype.getLi = function() { 1117 | return this.$element; 1118 | }; 1119 | 1120 | NodeElement.prototype.addDropHint = function(position) { 1121 | if (position === Position.INSIDE) { 1122 | return new BorderDropHint(this.$element); 1123 | } else { 1124 | return new GhostDropHint(this.node, this.$element, position); 1125 | } 1126 | }; 1127 | 1128 | NodeElement.prototype.select = function() { 1129 | return this.getLi().addClass('selected'); 1130 | }; 1131 | 1132 | NodeElement.prototype.deselect = function() { 1133 | return this.getLi().removeClass('selected'); 1134 | }; 1135 | 1136 | return NodeElement; 1137 | 1138 | })(); 1139 | 1140 | FolderElement = (function(_super) { 1141 | 1142 | __extends(FolderElement, _super); 1143 | 1144 | function FolderElement() { 1145 | FolderElement.__super__.constructor.apply(this, arguments); 1146 | } 1147 | 1148 | FolderElement.prototype.toggle = function(on_finished) { 1149 | if (this.node.is_open) { 1150 | return this.close(on_finished); 1151 | } else { 1152 | return this.open(on_finished); 1153 | } 1154 | }; 1155 | 1156 | FolderElement.prototype.open = function(on_finished, skip_slide) { 1157 | var doOpen, 1158 | _this = this; 1159 | this.node.is_open = true; 1160 | this.getButton().removeClass('closed'); 1161 | doOpen = function() { 1162 | _this.getLi().removeClass('closed'); 1163 | if (on_finished) return on_finished(); 1164 | }; 1165 | if (skip_slide) { 1166 | this.getUl().show(); 1167 | return doOpen(); 1168 | } else { 1169 | return this.getUl().slideDown('fast', doOpen); 1170 | } 1171 | }; 1172 | 1173 | FolderElement.prototype.close = function(on_finished) { 1174 | var _this = this; 1175 | this.node.is_open = false; 1176 | this.getButton().addClass('closed'); 1177 | return this.getUl().slideUp('fast', function() { 1178 | _this.getLi().addClass('closed'); 1179 | if (on_finished) return on_finished(); 1180 | }); 1181 | }; 1182 | 1183 | FolderElement.prototype.getButton = function() { 1184 | return this.$element.children('div').find('a.toggler'); 1185 | }; 1186 | 1187 | FolderElement.prototype.addDropHint = function(position) { 1188 | if (!this.node.is_open && position === Position.INSIDE) { 1189 | return new BorderDropHint(this.$element); 1190 | } else { 1191 | return new GhostDropHint(this.node, this.$element, position); 1192 | } 1193 | }; 1194 | 1195 | return FolderElement; 1196 | 1197 | })(NodeElement); 1198 | 1199 | DragElement = (function() { 1200 | 1201 | function DragElement(node, offset_x, offset_y, $tree) { 1202 | this.offset_x = offset_x; 1203 | this.offset_y = offset_y; 1204 | this.$element = $("" + node.name + ""); 1205 | this.$element.css("position", "absolute"); 1206 | $tree.append(this.$element); 1207 | } 1208 | 1209 | DragElement.prototype.move = function(page_x, page_y) { 1210 | return this.$element.offset({ 1211 | left: page_x - this.offset_x, 1212 | top: page_y - this.offset_y 1213 | }); 1214 | }; 1215 | 1216 | DragElement.prototype.remove = function() { 1217 | return this.$element.remove(); 1218 | }; 1219 | 1220 | return DragElement; 1221 | 1222 | })(); 1223 | 1224 | this.Tree.Node = Node; 1225 | 1226 | }).call(this); 1227 | --------------------------------------------------------------------------------