Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

first commit

  • Loading branch information...
commit 7f761c424741d88bb234426b74b4092c40fb4987 1 parent 040c68f
Prof Syd Xu authored
Showing with 12,215 additions and 0 deletions.
  1. +3 −0  .gitignore
  2. +1 −0  CHANGELOG.txt
  3. +1 −0  LICENSE.txt
  4. +408 −0 Resources/liberary/css/master.css
  5. BIN  Resources/liberary/img/arrow_left.png
  6. BIN  Resources/liberary/img/arrow_right.png
  7. BIN  Resources/liberary/img/box_upload_48.png
  8. BIN  Resources/liberary/img/caut.png
  9. BIN  Resources/liberary/img/db.png
  10. BIN  Resources/liberary/img/dbplus.png
  11. BIN  Resources/liberary/img/help.png
  12. BIN  Resources/liberary/img/preference.png
  13. BIN  Resources/liberary/img/refresh_48.png
  14. BIN  Resources/liberary/img/search_48.png
  15. BIN  Resources/liberary/img/spanner_48.png
  16. BIN  Resources/liberary/img/sqldb.png
  17. BIN  Resources/liberary/img/sqldb_16.png
  18. BIN  Resources/liberary/img/table_48.png
  19. +293 −0 Resources/liberary/js/base_window.js
  20. +210 −0 Resources/liberary/js/connection.js
  21. +21 −0 Resources/liberary/js/main.js
  22. +4,320 −0 Resources/liberary/js/prototype-1.6.0.js
  23. +60 −0 Resources/liberary/js/scriptaculous-1.8.2.js
  24. BIN  Resources/logo.png
  25. +93 −0 Resources/mongodb.py
  26. +35 −0 Resources/pymongo/__init__.py
  27. +1,390 −0 Resources/pymongo/_cbsonmodule.c
  28. +65 −0 Resources/pymongo/binary.py
  29. +569 −0 Resources/pymongo/bson.py
  30. +54 −0 Resources/pymongo/code.py
  31. +784 −0 Resources/pymongo/collection.py
  32. +762 −0 Resources/pymongo/connection.py
  33. +496 −0 Resources/pymongo/cursor.py
  34. +88 −0 Resources/pymongo/cursor_manager.py
  35. +428 −0 Resources/pymongo/database.py
  36. +90 −0 Resources/pymongo/dbref.py
  37. +107 −0 Resources/pymongo/encoding_helpers.c
  38. +22 −0 Resources/pymongo/encoding_helpers.h
  39. +81 −0 Resources/pymongo/errors.py
  40. +103 −0 Resources/pymongo/helpers.py
  41. +56 −0 Resources/pymongo/json_util.py
  42. +244 −0 Resources/pymongo/master_slave_connection.py
  43. +145 −0 Resources/pymongo/message.py
  44. +165 −0 Resources/pymongo/objectid.py
  45. +327 −0 Resources/pymongo/son.py
  46. +179 −0 Resources/pymongo/son_manipulator.py
  47. +103 −0 Resources/pymongo/thread_util.py
  48. +182 −0 Resources/pymongo/time_helpers.c
  49. +44 −0 Resources/pymongo/time_helpers.h
  50. +35 −0 Resources/windows/add_connection.html
  51. +60 −0 Resources/windows/browse_collection.html
  52. +38 −0 Resources/windows/edit_connection.html
  53. +55 −0 Resources/windows/index.html
  54. +41 −0 Resources/windows/query.html
  55. +27 −0 manifest
  56. +29 −0 tiapp.xml
  57. +1 −0  timanifest
3  .gitignore
View
@@ -0,0 +1,3 @@
+dist
+tmp
+*.pyc
1  CHANGELOG.txt
View
@@ -0,0 +1 @@
+Place your change log text here. This file will be incorporated with your app at package time.
1  LICENSE.txt
View
@@ -0,0 +1 @@
+Place your license text here. This file will be incorporated with your app at package time.
408 Resources/liberary/css/master.css
View
@@ -0,0 +1,408 @@
+/* @group reset css */
+
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {
+ background: transparent none repeat scroll 0 0;
+ border: 0 none;
+ font-size: 100%;
+ margin: 0;
+ outline-color: -moz-use-text-color;
+ outline-style: none;
+ outline-width: 0;
+ padding: 0;
+ vertical-align: baseline;
+}
+
+a {
+ cursor: pointer;
+}
+ol, ul {
+ list-style-image: none;
+ list-style-position: outside;
+ list-style-type: none;
+}
+
+blockquote, q {
+ quotes: none;
+}
+
+blockquote:before, blockquote:after, q:before, q:after {
+ content: none;
+}
+
+:focus {
+ outline-color: -moz-use-text-color;
+ outline-style: none;
+ outline-width: 0;
+}
+
+ins {
+ text-decoration: none;
+}
+
+del {
+ text-decoration: line-through;
+}
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+.err {
+ color:red;
+ line-height:1.5em;
+}
+
+.caution {
+ font-size: 14px;
+ color: #333;
+ padding-left:40px;
+ line-height:1.5em;
+ min-height:32px;
+ background: transparent url(app://liberary/img/caut.png) no-repeat scroll left center;
+}
+/* @end */
+
+/*
+
+ @group layout css */
+
+/* start of float and clearfix css */
+
+.fl-left {
+ float: left;
+}
+
+.fl-right {
+ float: right;
+}
+
+.clearfix:after {
+ content: ".";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+}
+
+.clearfix {
+ display: inline-table;
+}
+.clear{
+ clear:both;
+}
+
+/* START */
+body {
+ background-color:1c1c1c;
+ margin:0;
+ font-family: Arial, Verdana, sans-serif;
+ font-size: 12px;
+}
+
+.NavigationBar {
+ width: 100%;
+ height: 50px;
+ overflow: hidden;
+ border-bottom:#3F3F3F 1px solid;
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#BDBDBD), to(#969696));
+}
+ .NavigationBar ul {
+ margin:3px 10px;
+ }
+ .NavigationBar li {
+ margin: 0 5px;
+ float:left;
+ font-size:10px;
+ color:#333;
+ font-weight:bold;
+ }
+ .NavigationBar a.Item, .NavigationBar a.Item:link {
+ text-align: center;
+ width:60px;
+ display:block;
+ overflow:hidden;
+ text-shadow: 1px 1px 1px #CCC;
+ }
+ .NavigationBar a.Item:hover {
+ color: #000;
+ text-shadow: 1px 1px 1px #999;
+ }
+ .NavigationBar a.Item img {
+ width:32px;
+ height:32px;
+ border:none;
+ display:block;
+ margin:0 9px;
+ }
+ #app-status {
+ -webkit-border-radius:5px;
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#FDFCE3), to(#D2D3B7));
+ border-top:1px #333 solid;
+ border-left:1px #333 solid;
+ border-right:1px #999 solid;
+ border-bottom:1px #999 solid;
+ padding:5px;
+ float:right;
+ margin:3px 10px;
+ min-width: 60px;
+ height:25px;
+ overflow: hidden;
+ }
+
+
+#main-wrapper {
+ width: 100%;
+ height:100%;
+}
+
+#sidebar {
+ background-color:#CDD5DD;
+ border-right:1px #999 solid;
+ height:100%;
+ width:200px;
+ overflow:auto;
+ float:left;
+}
+
+ #sidebar ul.connections {
+ margin:10px 0;
+ }
+ #sidebar li.connection {
+ font-size:13px;
+ color:#333;
+ text-shadow: 1px 1px 1px #FFF;
+ cursor: pointer;
+ padding:10px;
+ text-indent:20px;
+ margin:4px 0;
+ line-height:1.5em;
+ background: url(app://liberary/img/db.png) 10px center no-repeat;
+ }
+ #sidebar li.connection.selected {
+ background:none;
+ background-color: #004394;
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(255, 255, 255, 0.5)), to(rgba(98,202,227, 0.5)));
+ font-weight:bold;
+ color:#FFF;
+ text-shadow: 1px 1px 1px #333;
+ }
+ #sidebar li.db {
+ font-size:12px;
+ color:#333;
+ text-shadow: 1px 1px 1px #FFF;
+ cursor: pointer;
+ padding:2px 5px;
+ text-indent:35px;
+ margin:2px 10px;
+ line-height:1.5em;
+ background: url(app://liberary/img/sqldb_16.png) 10px center no-repeat;
+ }
+ #sidebar li.db.selected {
+ background: none;
+ -webkit-border-radius:10px;
+ background-color: #004394;
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(255, 255, 255, 0.5)), to(rgba(98,202,227, 0.5)));
+ text-indent:20px;
+ font-weight:bold;
+ color:#FFF;
+ text-shadow: 1px 1px 1px #333;
+ -webkit-box-shadow: 0 -1px 1px rgba(0,0,0,0.5);
+ }
+
+#main-content {
+ //background-color:white;
+ height:100%;
+ width: 599px;
+ float:left;
+}
+ #main-innerlist {
+ overflow:auto;
+ height:100%;
+ }
+ #menubar, .collection-meta {
+ width:100%;
+ height:25px;
+ background-image: -webkit-gradient(linear, 0% 40%, 0% 60%, from(#FFF), to(#DEDEDE));
+ border-bottom:1px #000 solid;
+ }
+ #menubar li{
+ padding:0;
+ margin:0;
+ height:100%;
+ float:left;
+ }
+ #menubar a, #menubar a:link {
+ height:100%;
+ cursor:pointer;
+ line-height:25px;
+ padding:0 10px;
+ border-right:1px #666 solid;
+ background-image: -webkit-gradient(linear, 0% 40%, 0% 60%, from(#E6E6E6), to(#BEBEBE));
+ display:block;
+ }
+ #menubar a:hover {
+ background:none;
+ color:white;
+ background-image: -webkit-gradient(linear, 0% 40%, 0% 60%, from(#A4D0FF), to(#0080FF));
+ }
+ #menubar .meta {
+ float:right;
+ height:100%;
+ padding-right:10px;
+ line-height:25px;
+ }
+ #connection_name {
+ color:#333;
+ text-shadow: 1px 1px 1px #FFF;
+ }
+ #database_name {
+ color:#333;
+ text-shadow: 1px 1px 1px #FFF;
+ background-color:#FC6;
+ }
+
+ .collection-meta {
+ line-height:25px;
+ }
+
+ ul.collections{
+ margin:10px;
+ }
+ #entries-list {
+ overflow:auto;
+ height:100%;
+ }
+ li.collection, li.entry {
+ -webkit-border-radius:10px;
+ background-color: #666;
+ padding:10px;
+ margin:10px 0;
+ -webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.8);
+ clear:both;
+ }
+ li.entry {
+ margin:10px;
+ color:#ccc;
+ }
+ li.collection .name {
+ font-size:14px;
+ font-weight:bold;
+ color:#EFEFEF;
+ text-shadow: 1px 1px 1px #000;
+ margin-bottom:5px;
+ }
+ li.entry table {
+ width:100%;
+ }
+ li.entry tr {
+ border-bottom: 1px #CCC solid;
+ }
+ li.entry td {
+ padding:5px 0;
+ }
+ li.entry .key{
+ font-size:12px;
+ font-weight:bold;
+ color:#EFEFEF;
+ text-shadow: 1px 1px 1px #000;
+ overflow:hidden;
+ width:100px;
+ }
+ li.entry .value{
+ font-size:12px;
+ color:#CCC;
+ }
+body.AddConnectionDialog {
+ background-color:white;
+ overflow:hidden;
+}
+
+body.AddConnectionDialog form {
+ margin:10px;
+}
+
+body.AddConnectionDialog fieldset {
+ border-top:1px solid #ccc;
+ border-left:0;
+ border-bottom:0;
+ border-right:0;
+ padding:6px;
+ margin:0;
+}
+body.AddConnectionDialog legend {
+ text-align:left;
+ color:#ccc;
+ padding:0px 4px 0px 4px;
+ margin-left:20px;
+}
+body.AddConnectionDialog label {
+ color: #999;
+ font-weight: bold;
+ width: 50px;
+ text-align: right;
+ display:block;
+ float:left;
+ margin:4px 4px 0px 0px;
+}
+body.AddConnectionDialog input {
+ float: left;
+ width: 150px;
+ margin:2px 0px 2px 2px;
+ border:1px solid #cccccc;
+ color:#00abdf;
+ -webkit-box-shadow: 0 -1px 1px rgba(0,0,0,0.5);
+ -webkit-border-radius: 5px;
+ padding:3px;
+ height:24px;
+}
+body.AddConnectionDialog input.Port {
+ width:50px;
+}
+body.AddConnectionDialog input.Short {
+ width:100px;
+}
+
+body.AddConnectionDialog p {
+ margin:20px 10px;
+}
+
+button{
+ display: inline-block;
+ padding: 5px 10px 6px;
+ color: #fff;
+ text-decoration: none;
+ font-weight: bold;
+ line-height: 1;
+ -webkit-border-radius: 5px;
+ -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.5);
+ text-shadow: 0 -1px 1px rgba(0,0,0,0.25);
+ border:0;
+ border-bottom: 1px solid rgba(0,0,0,0.25);
+ position: relative;
+ cursor: pointer;
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(255, 255, 255, 0.5)), to(rgba(255, 255, 255, 0.2)));
+}
+button.blue {
+ background-color: #0080FF;
+}
+
+button.red {
+ background-color: #e33100;
+}
+
+button.magenta {
+ background-color: #a9014b;
+}
+
+button.orange {
+ background-color: #ff5c00;
+}
+
+button.yellow {
+ background-color: #ffb515;
+}
+
+button.green {
+ background-color: green;
+}
BIN  Resources/liberary/img/arrow_left.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  Resources/liberary/img/arrow_right.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  Resources/liberary/img/box_upload_48.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  Resources/liberary/img/caut.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  Resources/liberary/img/db.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  Resources/liberary/img/dbplus.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  Resources/liberary/img/help.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  Resources/liberary/img/preference.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  Resources/liberary/img/refresh_48.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  Resources/liberary/img/search_48.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  Resources/liberary/img/spanner_48.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  Resources/liberary/img/sqldb.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  Resources/liberary/img/sqldb_16.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  Resources/liberary/img/table_48.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
293 Resources/liberary/js/base_window.js
View
@@ -0,0 +1,293 @@
+function connection_info(name, connections)
+{
+ for(var i=0; i<connections.size(); i++)
+ {
+ if (connections[i].name == name)
+ {
+ return connections[i];
+ }
+ }
+ return null;
+}
+
+function showBrowseCollection(connection, dbname, name)
+{
+ var win = Titanium.UI.getCurrentWindow();
+ var win2 = win.createWindow('app://windows/browse_collection.html');
+ win2.setHeight(500);
+ win2.setWidth(800);
+ //win2.setTransparency(0.8);
+ win2.setTitle('Browse Collection | ' + connection.name + ' | ' + dbname + ' | ' + name);
+ //win2.setMaximizable(false);
+ //win2.setResizable(false);
+ win2.open();
+}
+
+function showDropCollection(connection, dbname, name)
+{
+ if (confirm('Do you want to drop this collection?'))
+ {
+ dropCollection(connection.name, dbname, name);
+ updateCollections(connection, dbname);
+ return;
+ }
+}
+
+function updateCollections(connection, dbname)
+{
+ var collections = mongo.show_collections(connection.host, connection.port, dbname);
+ if (collections == -1)
+ {
+ alert('Failed to connect ' + connection.name);
+ return false;
+ }else{
+ var html = '<ul class="collections">';
+ collections.each(function(collection){
+ html += '<li class="collection"><div class="name">' + collection + '</div><button class="browse blue">Browse</button><button class="drop red">Drop</button></li>';
+ });
+ html += '</ul>';
+ $('main-innerlist').update(html);
+ $$('.collection').each(function(e){
+ var cname = e.getElementsByClassName('name')[0].innerHTML;
+ e.getElementsByClassName('browse')[0].observe('click', function(){
+ showBrowseCollection(connection, dbname, cname);
+ });
+ e.getElementsByClassName('drop')[0].observe('click', function(){
+ showDropCollection(connection, dbname, cname);
+ });
+ });
+ $('menubar').show();
+ }
+}
+function updateConnections()
+{
+ var connections = loadConnection();
+ if (connections && connections.size()>0)
+ {
+ var html = '<ul class="connections">';
+ connections.each(function(c){
+ html += '<li class="connection">' + c.name + '</li>';
+ });
+ html += '</ul>';
+ }else{
+ $('sidebar').update('');
+ return;
+ }
+ $('sidebar').update(html);
+ $$('#sidebar ul.connections')[0].observe('click', function(e){
+ var dom = e.findElement('li.db');
+ if (dom)
+ {
+ cons = $$('#sidebar li.connection.selected');
+ if (!cons || cons.size() == 0) return;
+ var connection = connection_info(cons[0].innerHTML, connections);
+ if (!connection)
+ {
+ alert('Unexpected error!');
+ return false;
+ }
+ dom.addClassName('selected');
+ $('database_name').update(dom.innerHTML);
+ updateCollections(connection, dom.innerHTML);
+ return;
+ }
+ $$('#sidebar li.connection').each(function(l){l.removeClassName('selected');});
+ $$('#sidebar li.dbs').each(function(l){l.remove();});
+ var clickedRow;
+ clickedRow = e.findElement('li.connection');
+ if (clickedRow) {
+ clickedRow.addClassName('selected');
+ var connection = connection_info(clickedRow.innerHTML, connections);
+ if (!connection)
+ {
+ alert('Unexpected error!');
+ return false;
+ }
+ $('connection_name').update(clickedRow.innerHTML);
+ var dbs = mongo.show_dbs(connection.host, connection.port);
+ if (dbs == -1)
+ {
+ alert('Failed to connect ' + connection.name);
+ return false;
+ }else{
+ var html = '<li class="dbs"><ul>';
+ dbs.each(function(db){
+ html += '<li class="db">' + db + '</li>';
+ });
+ html += '</li></ul>';
+ clickedRow.insert({after:html});
+ }
+ $$('#sidebar li.dbs')[0].observe('click', function(e){
+ $$('#sidebar li.db').each(function(l){l.removeClassName('selected');});
+ var clickedRow2;
+ clickedRow2 = e.findElement('li.db');
+ if (clickedRow2) {
+ clickedRow2.addClassName('selected');
+ updateCollections(connection, clickedRow2.innerHTML);
+ }
+ });
+ }
+ });
+}
+
+function showAddConnection()
+{
+ var win = Titanium.UI.getCurrentWindow();
+ var win2 = win.createWindow('app://windows/add_connection.html');
+ win2.addEventListener(Titanium.CLOSED, updateConnections);
+ win2.setHeight(160);
+ win2.setWidth(390);
+ win2.setTransparency(0.8);
+ win2.setTitle('New Connection');
+ win2.setMaximizable(false);
+ //win2.setResizable(false);
+ win2.open();
+}
+
+function showEditConnection()
+{
+ dom = $$('#sidebar li.connection.selected');
+ if (!dom || dom.size()==0)
+ {
+ alert('Please select a connection you want to edit!');
+ return false;
+ }
+ var win = Titanium.UI.getCurrentWindow();
+ var win2 = win.createWindow('app://windows/edit_connection.html');
+ win2.addEventListener(Titanium.CLOSED, updateConnections);
+ win2.setHeight(160);
+ win2.setWidth(390);
+ win2.setTransparency(0.8);
+ win2.setTitle('Edit Connection | ' + dom[0].innerHTML);
+ win2.setMaximizable(false);
+ //win2.setResizable(false);
+ win2.open();
+}
+
+function showRemoveConnection()
+{
+ dom = $$('#sidebar li.connection.selected');
+ if (!dom || dom.size()==0)
+ {
+ alert('Please select a connection you want to remove!');
+ return false;
+ }
+ if (confirm('Do you want to delete this connection?'))
+ {
+ removeConnection(dom[0].innerHTML.strip());
+ updateConnections();
+ return;
+ }
+}
+
+function showDropDB()
+{
+ if ($('connection_name').innerHTML==''|| $('database_name').innerHTML=='')
+ {
+ alert('Please select a database you want to remove!');
+ return false;
+ }
+ if (confirm('Do you want to drop this database?'))
+ {
+ dropDB($('connection_name').innerHTML.strip(), $('database_name').innerHTML.strip());
+ updateConnections();
+ return;
+ }
+}
+
+function showQuery(query)
+{
+ if ($('connection_name').innerHTML==''|| $('database_name').innerHTML=='')
+ {
+ alert('Please select a database you want to query!');
+ return false;
+ }
+ var win = Titanium.UI.getCurrentWindow();
+ var win2 = win.createWindow('app://windows/query.html');
+ //win2.addEventListener(Titanium.CLOSED, function(){updateConnections();updateCollections();});
+ win2.setHeight(500);
+ win2.setWidth(600);
+ win2.setTitle('Query | ' + $('connection_name').innerHTML + ' | ' + $('database_name').innerHTML + ' | ' + query);
+ //win2.setMaximizable(false);
+ //win2.setResizable(false);
+ win2.open();
+}
+
+function createMenu()
+{
+ var menu = Titanium.UI.createMenu();
+ var connection = Titanium.UI.createMenuItem("Connection");
+ connection.addItem("New Connection", function() {
+ showAddConnection();
+ });
+ connection.addItem("Remove Connection", function() {
+ showRemoveConnection();
+ });
+ connection.addItem("Edit Connection", function(){
+ showEditConnection();
+ });
+ menu.appendItem(connection);
+ var database = Titanium.UI.createMenuItem("Database");
+ database.addItem("New Database", function() {
+ showAddConnection();
+ });
+ database.addItem("Drop Database", function() {
+ showDropDB();
+ });
+ menu.appendItem(database);
+ Titanium.UI.setMenu(menu);
+}
+
+function createDb()
+{
+ updateConnections();
+}
+
+function navigatorClickHandler(elm)
+{
+ if (elm.title == 'Connection')
+ {
+ showAddConnection();
+ }else if (elm.title == 'Query') {
+ showInputQuery();
+ }
+}
+
+function menubarClickHandler(elm)
+{
+ if (elm.title=="Create Database")
+ {
+ createDb();
+ }
+}
+function navigatorInit()
+{
+ /*$$('.NavigationBar a.Item').each (
+ function(e)
+ {
+ e.observe('click', function(){navigatorClickHandler(e);});
+ }
+ );
+ $$('#menubar a').each (
+ function(e)
+ {
+ e.observe('click', function(){menubarClickHandler(e);});
+ }
+ );*/
+ $('runquerybtn').observe('click', function(){
+ showQuery($F('query'));
+ });
+ updateConnections();
+}
+
+function updater()
+{
+ Titanium.UpdateManager.onupdate = function(details) {
+ if (confirm('A new version: ' + details.version + ' is available. Would you like to install it?')) {
+ // this function installs the new updated version of my app
+ Titanium.UpdateManager.installAppUpdate(details, function() {
+ alert('The new version has been installed');
+ });
+ }
+ };
+}
210 Resources/liberary/js/connection.js
View
@@ -0,0 +1,210 @@
+function addConnection(name, host, port)
+{
+ name = name.strip();
+ host = host.strip();
+ port = port.strip();
+ if (name.empty())
+ {
+ $('err').update("* Please input a name for this connection.");
+ return false;
+ }else if (host.empty()) {
+ $('err').update("* Please input the host address.");
+ return false;
+ }else if (port.empty()) {
+ $('err').update("* Please input the port.");
+ return false;
+ }
+ var db = Titanium.Database.open('mongohub');
+ db.execute("CREATE TABLE IF NOT EXISTS connections (name TEXT, host TEXT, port INT)");
+ var rows = db.execute("SELECT * FROM connections");
+ if (rows)
+ {
+ for(var i=0; i < rows.rowCount(); i++)
+ {
+ if (rows.fieldByName('name') == name)
+ {
+ $('err').update("* Connection name already existed, please choose another one.");
+ db.close();
+ return false;
+ }
+ rows.next();
+ }
+ }
+ db.execute("insert into connections (name, host, port) values ('" + name + "','" + host + "'," + port + ")");
+ db.close();
+ Titanium.UI.getCurrentWindow().close();
+}
+
+function editConnection(name, host, port, old_name)
+{
+ name = name.strip();
+ host = host.strip();
+ port = port.strip();
+ old_name = old_name.strip();
+ if (name.empty())
+ {
+ $('err').update("* Please input a name for this connection.");
+ return false;
+ }else if (host.empty()) {
+ $('err').update("* Please input the host address.");
+ return false;
+ }else if (port.empty()) {
+ $('err').update("* Please input the port.");
+ return false;
+ }
+ var db = Titanium.Database.open('mongohub');
+ db.execute("CREATE TABLE IF NOT EXISTS connections (name TEXT, host TEXT, port INT)");
+ var rows = db.execute("SELECT * FROM connections");
+ if (rows)
+ {
+ var counter = 0;
+ for(var i=0; i < rows.rowCount(); i++)
+ {
+ if (rows.fieldByName('name') == name)
+ {
+ counter ++;
+ if (counter > 0)
+ {
+ $('err').update("* Connection name already existed, please choose another one.");
+ db.close();
+ return false;
+ }
+ }
+ rows.next();
+ }
+ }
+ db.execute("UPDATE connections SET name='" + name + "', host='" + host + "', port=" + port + " WHERE name='" + old_name + "'");
+ db.close();
+ Titanium.UI.getCurrentWindow().close();
+}
+
+function removeConnection(name)
+{
+ name = name.strip();
+ var db = Titanium.Database.open('mongohub');
+ db.execute("CREATE TABLE IF NOT EXISTS connections (name TEXT, host TEXT, port INT)");
+ db.execute("DELETE FROM connections WHERE name='" + name + "'");
+ db.close();
+}
+
+function loadConnection()
+{
+ var db = Titanium.Database.open('mongohub');
+ try
+ {
+ var rows = db.execute("SELECT * FROM connections");
+ }catch(e){
+ var rows = null;
+ }finally{
+ db.close();
+ }
+ var connections = new Array();
+ if (!rows) return connections;
+ for(var i=0; i < rows.rowCount(); i++)
+ {
+ connections.push({name: rows.fieldByName('name'), host: rows.fieldByName('host'), port: rows.fieldByName('port')});
+ rows.next();
+ }
+ return connections;
+}
+
+function dropDB(cname, dbname)
+{
+ cname = cname.strip();
+ dbname = dbname.strip();
+ var connections = loadConnection();
+ var connection = connection_info(cname, connections);
+ if (!connection)
+ {
+ alert('Unexpected error!');
+ return false;
+ }
+ mongo.drop_database(connection.host, connection.port, dbname);
+}
+
+function browseCollection(connection_name, db_name, collection_name, page, step)
+{
+ connection_name = connection_name.strip();
+ db_name = db_name.strip();
+ collection_name = collection_name.strip();
+ var connections = loadConnection();
+ var connection = connection_info(connection_name, connections);
+ if (!connection)
+ {
+ alert('Unexpected error!');
+ return false;
+ }
+ var entries = mongo.browse_collection(connection.host, connection.port, db_name, collection_name, page, step);
+ if (entries == -1)
+ {
+ alert('Unexpected error!');
+ return false;
+ }
+ $('total').update(entries['count']);
+ var html = '<ul class="entries">';
+ entries['entries'].each(function(e){
+ html += '<li class="entry"><table>';
+ Object.keys(e).each(function(f){
+ html += '<tr><td class="key">' + f + '</td><td class="value">' + e[f] + '</td></tr>';
+ });
+ html += '</table></li>';
+ });
+ html += '</ul>';
+ $('entries-list').update(html);
+}
+
+function dropCollection(connection_name, db_name, collection_name)
+{
+ connection_name = connection_name.strip();
+ db_name = db_name.strip();
+ collection_name = collection_name.strip();
+ var connections = loadConnection();
+ var connection = connection_info(connection_name, connections);
+ if (!connection)
+ {
+ alert('Unexpected error!');
+ return false;
+ }
+ mongo.drop_collection(connection.host, connection.port, db_name, collection_name);
+}
+
+function runQuery(connection_name, dbname, query)
+{
+ connection_name = connection_name.strip();
+ dbname = dbname.strip();
+ query = query.strip();
+ var connections = loadConnection();
+ var connection = connection_info(connection_name, connections);
+ if (!connection)
+ {
+ alert('Unexpected error!');
+ Titanium.UI.getCurrentWindow().close();
+ }
+ var entries = mongo.query(connection.host, connection.port, dbname, query);
+ if (entries == -1)
+ {
+ alert('Unexpected error!');
+ Titanium.UI.getCurrentWindow().close();
+ }else if (entries == -2)
+ {
+ alert('Invalid Query!');
+ Titanium.UI.getCurrentWindow().close();
+ }
+ if (Object.isString(entries))
+ {
+ var html = '<ul class="entries"><li class="entry">' + entries + '</li></ul>';
+ }else{
+ $('total').update(entries['count']);
+ var html = '<ul class="entries">';
+ entries['entries'].each(function(e){
+ html += '<li class="entry"><table>';
+ Object.keys(e).each(function(f){
+ html += '<tr><td class="key">' + f + '</td><td class="value">' + e[f] + '</td></tr>';
+ });
+ html += '</table></li>';
+ });
+ html += '</ul>';
+ $('collection-meta').show();
+ }
+ $('entries-list').update(html);
+}
21 Resources/liberary/js/main.js
View
@@ -0,0 +1,21 @@
+var Chrome = Class.create();
+Chrome.prototype = {
+ initialize: function ()
+ {
+ this.pid = 0;
+ this.current_window = Titanium.UI.getCurrentWindow();
+ var self = this;
+ self.update();
+ window.onresize = function (e) {
+ self.update(e.target);
+ }
+ },
+
+ update: function(win)
+ {
+ var self = this;
+ //document.body.setStyle({height:(this.current_window.getHeight() -50)+ 'px'});
+ $('main-content').setStyle({width: (document.viewport.getWidth() - $('sidebar').getWidth() - 1) + 'px'});
+ $('main-innerlist').setStyle({height: ($('main-content').getHeight() - 25) + 'px'});
+ }
+};
4,320 Resources/liberary/js/prototype-1.6.0.js
View
4,320 additions, 0 deletions not shown
60 Resources/liberary/js/scriptaculous-1.8.2.js
View
@@ -0,0 +1,60 @@
+// script.aculo.us scriptaculous.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008
+
+// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+var Scriptaculous = {
+ Version: '1.8.2',
+ require: function(libraryName) {
+ // inserting via DOM fails in Safari 2.0, so brute force approach
+ document.write('<script type="text/javascript" src="'+libraryName+'"><\/script>');
+ },
+ REQUIRED_PROTOTYPE: '1.6.0.3',
+ load: function() {
+ function convertVersionString(versionString) {
+ var v = versionString.replace(/_.*|\./g, '');
+ v = parseInt(v + '0'.times(4-v.length));
+ return versionString.indexOf('_') > -1 ? v-1 : v;
+ }
+
+ if((typeof Prototype=='undefined') ||
+ (typeof Element == 'undefined') ||
+ (typeof Element.Methods=='undefined') ||
+ (convertVersionString(Prototype.Version) <
+ convertVersionString(Scriptaculous.REQUIRED_PROTOTYPE)))
+ throw("script.aculo.us requires the Prototype JavaScript framework >= " +
+ Scriptaculous.REQUIRED_PROTOTYPE);
+
+ var js = /scriptaculous\.js(\?.*)?$/;
+ $$('head script[src]').findAll(function(s) {
+ return s.src.match(js);
+ }).each(function(s) {
+ var path = s.src.replace(js, ''),
+ includes = s.src.match(/\?.*load=([a-z,]*)/);
+ (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider,sound').split(',').each(
+ function(include) { Scriptaculous.require(path+include+'.js') });
+ });
+ }
+};
+
+Scriptaculous.load();
BIN  Resources/logo.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
93 Resources/mongodb.py
View
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+from types import *
+from time import *
+from datetime import datetime
+from pymongo import Connection as MongoConnection
+from pymongo import database
+from pymongo import collection as MongoCollection
+from pymongo.cursor import Cursor
+
+class MongoDB:
+
+ def show_dbs(self, host, port):
+ try:
+ c = MongoConnection(host=host, port=int(port), pool_size=1)
+ dbs = c.database_names()
+ except Exception, err:
+ return -1
+ return dbs
+
+ def show_collections(self, host, port, dbname):
+ try:
+ c = MongoConnection(host=host, port=int(port), pool_size=1)
+ db = database.Database(c, dbname)
+ collections = db.collection_names()
+ except Exception, err:
+ return -1
+ return collections
+
+ def drop_collection(self, host, port, dbname, collection_name):
+ try:
+ c = MongoConnection(host=host, port=int(port), pool_size=1)
+ db = database.Database(c, dbname)
+ db.drop_collection(collection_name)
+ except Exception, err:
+ return -1
+ return db
+
+ def drop_database(self, host, port, dbname):
+ try:
+ c = MongoConnection(host=host, port=int(port), pool_size=1)
+ c.drop_database(dbname)
+ except Exception, err:
+ return -1
+ return c
+
+ def browse_collection(self, host, port, dbname, collection_name, page, step):
+ try:
+ c = MongoConnection(host=host, port=int(port), pool_size=1)
+ db = database.Database(c, dbname)
+ cl = MongoCollection.Collection(db, collection_name)
+ res = cl.find(skip = (int(page) -1) * int(step), limit = int(step))
+ entries = []
+ for r in res:
+ tmp = {}
+ for k, v in r.items():
+ if isinstance(v, datetime):
+ tmp[k] = strftime('%Y-%m-%d %X', datetime.timetuple(v))
+ else:
+ tmp[k] = v
+ entries.append(tmp)
+ return {'count':cl.count(), 'entries': entries}
+ except Exception, err:
+ return -1
+ return collections
+
+ def query(self, host, port, dbname, query):
+ try:
+ c = MongoConnection(host=host, port=int(port), pool_size=1)
+ db = database.Database(c, dbname)
+ if not query.startswith('db.'):
+ return -2
+ res = eval(query)
+ if isinstance(res, (GeneratorType, ListType, Cursor)):
+ entries = []
+ try:
+ for r in res:
+ tmp = {}
+ for k, v in r.items():
+ if isinstance(v, datetime):
+ tmp[k] = strftime('%Y-%m-%d %X', datetime.timetuple(v))
+ else:
+ tmp[k] = v
+ entries.append(tmp)
+ return {'count':len(entries), 'entries': entries}
+ except:
+ return str(res)
+ else:
+ return str(res)
+ except Exception, err:
+ return -1
+ return collections
35 Resources/pymongo/__init__.py
View
@@ -0,0 +1,35 @@
+# Copyright 2009 10gen, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Python driver for MongoDB."""
+
+from pymongo.connection import Connection as PyMongo_Connection
+
+ASCENDING = 1
+"""Ascending sort order."""
+DESCENDING = -1
+"""Descending sort order."""
+
+OFF = 0
+"""No database profiling."""
+SLOW_ONLY = 1
+"""Only profile slow operations."""
+ALL = 2
+"""Profile all operations."""
+
+version = "1.1.2+"
+"""Current version of PyMongo."""
+
+Connection = PyMongo_Connection
+"""Alias for :class:`pymongo.connection.Connection`."""
1,390 Resources/pymongo/_cbsonmodule.c
View
@@ -0,0 +1,1390 @@
+/*
+ * Copyright 2009 10gen, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file contains C implementations of some of the functions needed by the
+ * bson module. If possible, these implementations should be used to speed up
+ * BSON encoding and decoding.
+ *
+ * TODO The filename is a bit of a misnomer now - probably should be something
+ * like _cspeedupsmodule - we do more than just BSON stuff in this C module.
+ */
+
+
+#include <stdio.h>
+#include <time.h>
+
+#include <Python.h>
+#include <datetime.h>
+
+#include "time_helpers.h"
+#include "encoding_helpers.h"
+
+static PyObject* InvalidName;
+static PyObject* InvalidDocument;
+static PyObject* InvalidStringData;
+static PyObject* SON;
+static PyObject* Binary;
+static PyObject* Code;
+static PyObject* ObjectId;
+static PyObject* DBRef;
+static PyObject* RECompile;
+static PyObject* UUID;
+
+#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
+typedef int Py_ssize_t;
+#define PY_SSIZE_T_MAX INT_MAX
+#define PY_SSIZE_T_MIN INT_MIN
+#endif
+
+#define INITIAL_BUFFER_SIZE 256
+
+/* Maximum number of regex flags */
+#define FLAGS_SIZE 7
+
+#if defined(WIN32) || defined(_MSC_VER)
+/* This macro is basically an implementation of asprintf for win32
+ * We get the length of the int as string and malloc a buffer for it,
+ * returning -1 if that malloc fails. We then actually print to the
+ * buffer to get the string value as an int. Like asprintf, the result
+ * must be explicitly free'd when done being used.
+ */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define INT2STRING(buffer, i) \
+ *(buffer) = malloc(_scprintf("%d", (i)) + 1), \
+ (!(buffer) ? \
+ -1 : \
+ _snprintf_s(*(buffer), \
+ _scprintf("%d", (i)) + 1, \
+ _scprintf("%d", (i)) + 1, \
+ "%d", \
+ (i)))
+#define STRCAT(dest, n, src) strcat_s((dest), (n), (src))
+#else
+#define INT2STRING(buffer, i) \
+ *(buffer) = malloc(_scprintf("%d", (i)) + 1), \
+ (!(buffer) ? \
+ -1 : \
+ _snprintf(*(buffer), \
+ _scprintf("%d", (i)) + 1, \
+ "%d", \
+ (i)))
+#define STRCAT(dest, n, src) strcat((dest), (src))
+#endif
+#else
+#define INT2STRING(buffer, i) asprintf((buffer), "%d", (i))
+#define STRCAT(dest, n, src) strcat((dest), (src))
+#endif
+
+/* A buffer representing some data being encoded to BSON. */
+typedef struct {
+ char* buffer;
+ int size;
+ int position;
+} bson_buffer;
+
+static int write_dict(bson_buffer* buffer, PyObject* dict, unsigned char check_keys);
+static PyObject* elements_to_dict(const char* string, int max);
+
+static bson_buffer* buffer_new(void) {
+ bson_buffer* buffer;
+ buffer = (bson_buffer*)malloc(sizeof(bson_buffer));
+ if (!buffer) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ buffer->size = INITIAL_BUFFER_SIZE;
+ buffer->position = 0;
+ buffer->buffer = (char*)malloc(INITIAL_BUFFER_SIZE);
+ if (!buffer->buffer) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ return buffer;
+}
+
+static void buffer_free(bson_buffer* buffer) {
+ if (buffer == NULL) {
+ return;
+ }
+ free(buffer->buffer);
+ free(buffer);
+}
+
+/* returns zero on failure */
+static int buffer_resize(bson_buffer* buffer, int min_length) {
+ int size = buffer->size;
+ if (size >= min_length) {
+ return 1;
+ }
+ while (size < min_length) {
+ size *= 2;
+ }
+ buffer->buffer = (char*)realloc(buffer->buffer, size);
+ if (!buffer->buffer) {
+ PyErr_NoMemory();
+ return 0;
+ }
+ buffer->size = size;
+ return 1;
+}
+
+/* returns zero on failure */
+static int buffer_assure_space(bson_buffer* buffer, int size) {
+ if (buffer->position + size <= buffer->size) {
+ return 1;
+ }
+ return buffer_resize(buffer, buffer->position + size);
+}
+
+/* returns offset for writing, or -1 on failure */
+static int buffer_save_bytes(bson_buffer* buffer, int size) {
+ int position;
+
+ if (!buffer_assure_space(buffer, size)) {
+ return -1;
+ }
+ position = buffer->position;
+ buffer->position += size;
+ return position;
+}
+
+/* returns zero on failure */
+static int buffer_write_bytes(bson_buffer* buffer, const char* bytes, int size) {
+ if (!buffer_assure_space(buffer, size)) {
+ return 0;
+ }
+ memcpy(buffer->buffer + buffer->position, bytes, size);
+ buffer->position += size;
+ return 1;
+}
+
+/* returns 0 on failure */
+static int write_string(bson_buffer* buffer, PyObject* py_string) {
+ int i;
+ Py_ssize_t string_length;
+ const char* string = PyString_AsString(py_string);
+ if (!string) {
+ return 1;
+ }
+ string_length = PyString_Size(py_string) + 1;
+
+ for (i = 0; i < string_length - 1; i++) {
+ if (string[i] == 0) {
+ PyErr_SetString(InvalidStringData, "BSON strings must not contain a NULL character");
+ return 0;
+ }
+ }
+
+ if (!buffer_write_bytes(buffer, (const char*)&string_length, 4)) {
+ return 0;
+ }
+ if (!buffer_write_bytes(buffer, string, string_length)) {
+ return 0;
+ }
+ return 1;
+}
+
+/* TODO our platform better be little-endian w/ 4-byte ints! */
+/* Write a single value to the buffer (also write it's type_byte, for which
+ * space has already been reserved.
+ *
+ * returns 0 on failure */
+static int write_element_to_buffer(bson_buffer* buffer, int type_byte, PyObject* value, unsigned char check_keys) {
+ /* TODO this isn't quite the same as the Python version:
+ * here we check for type equivalence, not isinstance in some
+ * places. */
+ if (PyInt_CheckExact(value) || PyLong_CheckExact(value)) {
+ const long long_value = PyInt_AsLong(value);
+ const int int_value = (int)long_value;
+ if (PyErr_Occurred() || long_value != int_value) { /* Overflow */
+ long long long_long_value;
+ PyErr_Clear();
+ long_long_value = PyLong_AsLongLong(value);
+ if (PyErr_Occurred()) { /* Overflow AGAIN */
+ PyErr_SetString(PyExc_OverflowError,
+ "MongoDB can only handle up to 8-byte ints");
+ return 0;
+ }
+ *(buffer->buffer + type_byte) = 0x12;
+ return buffer_write_bytes(buffer, (const char*)&long_long_value, 8);
+ }
+ *(buffer->buffer + type_byte) = 0x10;
+ return buffer_write_bytes(buffer, (const char*)&int_value, 4);
+ } else if (PyBool_Check(value)) {
+ const long bool = PyInt_AsLong(value);
+ const char c = bool ? 0x01 : 0x00;
+ *(buffer->buffer + type_byte) = 0x08;
+ return buffer_write_bytes(buffer, &c, 1);
+ } else if (PyFloat_CheckExact(value)) {
+ const double d = PyFloat_AsDouble(value);
+ *(buffer->buffer + type_byte) = 0x01;
+ return buffer_write_bytes(buffer, (const char*)&d, 8);
+ } else if (value == Py_None) {
+ *(buffer->buffer + type_byte) = 0x0A;
+ return 1;
+ } else if (PyDict_Check(value)) {
+ *(buffer->buffer + type_byte) = 0x03;
+ return write_dict(buffer, value, check_keys);
+ } else if (PyList_Check(value) || PyTuple_Check(value)) {
+ int start_position,
+ length_location,
+ items,
+ length,
+ i;
+ char zero = 0;
+
+ *(buffer->buffer + type_byte) = 0x04;
+ start_position = buffer->position;
+
+ /* save space for length */
+ length_location = buffer_save_bytes(buffer, 4);
+ if (length_location == -1) {
+ return 0;
+ }
+
+ items = PySequence_Size(value);
+ for(i = 0; i < items; i++) {
+ int list_type_byte = buffer_save_bytes(buffer, 1);
+ char* name;
+ PyObject* item_value;
+
+ if (type_byte == -1) {
+ return 0;
+ }
+ if (INT2STRING(&name, i) < 0 || !name) {
+ PyErr_NoMemory();
+ return 0;
+ }
+ if (!buffer_write_bytes(buffer, name, strlen(name) + 1)) {
+ free(name);
+ return 0;
+ }
+ free(name);
+
+ item_value = PySequence_GetItem(value, i);
+ if (!write_element_to_buffer(buffer, list_type_byte, item_value, check_keys)) {
+ Py_DECREF(item_value);
+ return 0;
+ }
+ Py_DECREF(item_value);
+ }
+
+ /* write null byte and fill in length */
+ if (!buffer_write_bytes(buffer, &zero, 1)) {
+ return 0;
+ }
+ length = buffer->position - start_position;
+ memcpy(buffer->buffer + length_location, &length, 4);
+ return 1;
+ } else if (PyObject_IsInstance(value, Binary)) {
+ PyObject* subtype_object;
+
+ *(buffer->buffer + type_byte) = 0x05;
+ subtype_object = PyObject_GetAttrString(value, "subtype");
+ if (!subtype_object) {
+ return 0;
+ }
+ {
+ const long long_subtype = PyInt_AsLong(subtype_object);
+ const char subtype = (const char)long_subtype;
+ const int length = PyString_Size(value);
+
+ Py_DECREF(subtype_object);
+ if (subtype == 2) {
+ const int other_length = length + 4;
+ if (!buffer_write_bytes(buffer, (const char*)&other_length, 4)) {
+ return 0;
+ }
+ if (!buffer_write_bytes(buffer, &subtype, 1)) {
+ return 0;
+ }
+ }
+ if (!buffer_write_bytes(buffer, (const char*)&length, 4)) {
+ return 0;
+ }
+ if (subtype != 2) {
+ if (!buffer_write_bytes(buffer, &subtype, 1)) {
+ return 0;
+ }
+ }
+ {
+ const char* string = PyString_AsString(value);
+ if (!string) {
+ return 0;
+ }
+ if (!buffer_write_bytes(buffer, string, length)) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+ } else if (UUID && PyObject_IsInstance(value, UUID)) {
+ // Just a special case of Binary above, but simpler to do as a separate case
+
+ // UUID is always 16 bytes, subtype 3
+ int length = 16;
+ const char subtype = 3;
+
+ PyObject* bytes;
+
+ *(buffer->buffer + type_byte) = 0x05;
+ if (!buffer_write_bytes(buffer, (const char*)&length, 4)) {
+ return 0;
+ }
+ if (!buffer_write_bytes(buffer, &subtype, 1)) {
+ return 0;
+ }
+
+ bytes = PyObject_GetAttrString(value, "bytes");
+ if (!bytes) {
+ return 0;
+ }
+ if (!buffer_write_bytes(buffer, PyString_AsString(bytes), length)) {
+ Py_DECREF(bytes);
+ return 0;
+ }
+ Py_DECREF(bytes);
+ return 1;
+ } else if (PyObject_IsInstance(value, Code)) {
+ int start_position,
+ length_location,
+ length;
+ PyObject* scope;
+
+ *(buffer->buffer + type_byte) = 0x0F;
+
+ start_position = buffer->position;
+ /* save space for length */
+ length_location = buffer_save_bytes(buffer, 4);
+ if (length_location == -1) {
+ return 0;
+ }
+
+ if (!write_string(buffer, value)) {
+ return 0;
+ }
+
+ scope = PyObject_GetAttrString(value, "scope");
+ if (!scope) {
+ return 0;
+ }
+ if (!write_dict(buffer, scope, 0)) {
+ Py_DECREF(scope);
+ return 0;
+ }
+ Py_DECREF(scope);
+
+ length = buffer->position - start_position;
+ memcpy(buffer->buffer + length_location, &length, 4);
+ return 1;
+ } else if (PyString_Check(value)) {
+ int result;
+
+ *(buffer->buffer + type_byte) = 0x02;
+ if (!is_legal_utf8_string((const unsigned char*)PyString_AsString(value),
+ PyString_Size(value))) {
+ PyErr_SetString(InvalidStringData,
+ "strings in documents must be valid UTF-8");
+ return 0;
+ }
+ result = write_string(buffer, value);
+ return result;
+ } else if (PyUnicode_Check(value)) {
+ PyObject* encoded;
+ int result;
+
+ *(buffer->buffer + type_byte) = 0x02;
+ encoded = PyUnicode_AsUTF8String(value);
+ if (!encoded) {
+ return 0;
+ }
+ result = write_string(buffer, encoded);
+ Py_DECREF(encoded);
+ return result;
+ } else if (PyDateTime_CheckExact(value)) {
+ time_t rawtime;
+ struct tm timeinfo;
+ long long time_since_epoch;
+
+ time(&rawtime);
+ if (LOCALTIME(&timeinfo, &rawtime)) {
+ return 0;
+ }
+ timeinfo.tm_year = PyDateTime_GET_YEAR(value) - 1900;
+ timeinfo.tm_mon = PyDateTime_GET_MONTH(value) - 1;
+ timeinfo.tm_mday = PyDateTime_GET_DAY(value);
+ timeinfo.tm_hour = PyDateTime_DATE_GET_HOUR(value);
+ timeinfo.tm_min = PyDateTime_DATE_GET_MINUTE(value);
+ timeinfo.tm_sec = PyDateTime_DATE_GET_SECOND(value);
+ time_since_epoch = GMTIME_INVERSE(&timeinfo);
+ time_since_epoch = time_since_epoch * 1000;
+ time_since_epoch += PyDateTime_DATE_GET_MICROSECOND(value) / 1000;
+
+ *(buffer->buffer + type_byte) = 0x09;
+ return buffer_write_bytes(buffer, (const char*)&time_since_epoch, 8);
+ } else if (PyObject_IsInstance(value, ObjectId)) {
+ PyObject* pystring = PyObject_GetAttrString(value, "_ObjectId__id");
+ if (!pystring) {
+ return 0;
+ }
+ {
+ const char* as_string = PyString_AsString(pystring);
+ if (!as_string) {
+ Py_DECREF(pystring);
+ return 0;
+ }
+ if (!buffer_write_bytes(buffer, as_string, 12)) {
+ Py_DECREF(pystring);
+ return 0;
+ }
+ Py_DECREF(pystring);
+ *(buffer->buffer + type_byte) = 0x07;
+ }
+ return 1;
+ } else if (PyObject_IsInstance(value, DBRef)) {
+ PyObject* as_doc = PyObject_CallMethod(value, "as_doc", NULL);
+ if (!as_doc) {
+ return 0;
+ }
+ if (!write_dict(buffer, as_doc, 0)) {
+ Py_DECREF(as_doc);
+ return 0;
+ }
+ Py_DECREF(as_doc);
+ *(buffer->buffer + type_byte) = 0x03;
+ return 1;
+ }
+ else if (PyObject_HasAttrString(value, "pattern") &&
+ PyObject_HasAttrString(value, "flags")) { /* TODO just a proxy for checking if it is a compiled re */
+ PyObject* py_flags = PyObject_GetAttrString(value, "flags");
+ PyObject* py_pattern;
+ PyObject* encoded_pattern;
+ long int_flags;
+ char flags[FLAGS_SIZE];
+ int pattern_length,
+ flags_length;
+
+ if (!py_flags) {
+ return 0;
+ }
+ int_flags = PyInt_AsLong(py_flags);
+ Py_DECREF(py_flags);
+ py_pattern = PyObject_GetAttrString(value, "pattern");
+ if (!py_pattern) {
+ return 0;
+ }
+
+ if (PyUnicode_Check(py_pattern)) {
+ encoded_pattern = PyUnicode_AsUTF8String(py_pattern);
+ Py_DECREF(py_pattern);
+ if (!encoded_pattern) {
+ return 0;
+ }
+ } else {
+ encoded_pattern = py_pattern;
+ }
+
+ {
+ const char* pattern = PyString_AsString(encoded_pattern);
+ pattern_length = strlen(pattern) + 1;
+
+ if (!buffer_write_bytes(buffer, pattern, pattern_length)) {
+ Py_DECREF(encoded_pattern);
+ return 0;
+ }
+ }
+ Py_DECREF(encoded_pattern);
+
+ flags[0] = 0;
+ /* TODO don't hardcode these */
+ if (int_flags & 2) {
+ STRCAT(flags, FLAGS_SIZE, "i");
+ }
+ if (int_flags & 4) {
+ STRCAT(flags, FLAGS_SIZE, "l");
+ }
+ if (int_flags & 8) {
+ STRCAT(flags, FLAGS_SIZE, "m");
+ }
+ if (int_flags & 16) {
+ STRCAT(flags, FLAGS_SIZE, "s");
+ }
+ if (int_flags & 32) {
+ STRCAT(flags, FLAGS_SIZE, "u");
+ }
+ if (int_flags & 64) {
+ STRCAT(flags, FLAGS_SIZE, "x");
+ }
+ flags_length = strlen(flags) + 1;
+ if (!buffer_write_bytes(buffer, flags, flags_length)) {
+ return 0;
+ }
+ *(buffer->buffer + type_byte) = 0x0B;
+ return 1;
+ } else {
+ /* Try reloading these modules and see if it works.
+ * This is just to be able to raise a more informative
+ * exception in the weird case that one of these modules was reloaded
+ * without the c extension being reloaded. */
+ PyObject* module;
+
+ module = PyImport_ImportModule("pymongo.binary");
+ if (!module) {
+ return 0;
+ }
+ Binary = PyObject_GetAttrString(module, "Binary");
+ Py_DECREF(module);
+
+ module = PyImport_ImportModule("pymongo.code");
+ if (!module) {
+ return 0;
+ }
+ Code = PyObject_GetAttrString(module, "Code");
+ Py_DECREF(module);
+
+ module = PyImport_ImportModule("pymongo.objectid");
+ if (!module) {
+ return 0;
+ }
+ ObjectId = PyObject_GetAttrString(module, "ObjectId");
+ Py_DECREF(module);
+
+ module = PyImport_ImportModule("pymongo.dbref");
+ if (!module) {
+ return 0;
+ }
+ DBRef = PyObject_GetAttrString(module, "DBRef");
+ Py_DECREF(module);
+
+ module = PyImport_ImportModule("uuid");
+ if (!module) {
+ UUID = NULL;
+ PyErr_Clear();
+ } else {
+ UUID = PyObject_GetAttrString(module, "UUID");
+ Py_DECREF(module);
+ }
+
+ if (PyObject_IsInstance(value, Binary) ||
+ PyObject_IsInstance(value, Code) ||
+ PyObject_IsInstance(value, ObjectId) ||
+ PyObject_IsInstance(value, DBRef) ||
+ (UUID && PyObject_IsInstance(value, UUID))) {
+
+ PyErr_SetString(PyExc_RuntimeError,
+ "A python module was reloaded without the C extension being reloaded.\n"
+ "\n"
+ "See http://www.mongodb.org/display/DOCS/PyMongo+and+mod_wsgi for"
+ "a possible explanation / fix.");
+ return 0;
+ }
+ }
+ {
+ PyObject* errmsg = PyString_FromString("Cannot encode object: ");
+ PyObject* repr = PyObject_Repr(value);
+ PyString_ConcatAndDel(&errmsg, repr);
+ PyErr_SetString(InvalidDocument, PyString_AsString(errmsg));
+ Py_DECREF(errmsg);
+ return 0;
+ }
+}
+
+static int check_key_name(const char* name,
+ const Py_ssize_t name_length) {
+ int i;
+ if (name_length > 0 && name[0] == '$') {
+ PyObject* errmsg = PyString_FromFormat("key '%s' must not start with '$'", name);
+ PyErr_SetString(InvalidName, PyString_AsString(errmsg));
+ Py_DECREF(errmsg);
+ return 0;
+ }
+ for (i = 0; i < name_length; i++) {
+ if (name[i] == '.') {
+ PyObject* errmsg = PyString_FromFormat("key '%s' must not contain '.'", name);
+ PyErr_SetString(InvalidName, PyString_AsString(errmsg));
+ Py_DECREF(errmsg);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Write a (key, value) pair to the buffer.
+ *
+ * Returns 0 on failure */
+static int write_pair(bson_buffer* buffer, const char* name, Py_ssize_t name_length, PyObject* value, unsigned char check_keys, unsigned char allow_id) {
+ int type_byte;
+
+ /* Don't write any _id elements unless we're explicitly told to -
+ * _id has to be written first so we do so, but don't bother
+ * deleting it from the dictionary being written. */
+ if (!allow_id && strcmp(name, "_id") == 0) {
+ return 1;
+ }
+
+ type_byte = buffer_save_bytes(buffer, 1);
+ if (type_byte == -1) {
+ return 0;
+ }
+ if (check_keys && !check_key_name(name, name_length)) {
+ return 0;
+ }
+ if (!buffer_write_bytes(buffer, name, name_length + 1)) {
+ return 0;
+ }
+ if (!write_element_to_buffer(buffer, type_byte, value, check_keys)) {
+ return 0;
+ }
+ return 1;
+}
+
+static int decode_and_write_pair(bson_buffer* buffer, PyObject* key,
+ PyObject* value, unsigned char check_keys) {
+ PyObject* encoded;
+ if (PyUnicode_Check(key)) {
+ encoded = PyUnicode_AsUTF8String(key);
+ if (!encoded) {
+ return 0;
+ }
+ } else if (PyString_Check(key)) {
+ encoded = key;
+ Py_INCREF(encoded);
+
+ if (!is_legal_utf8_string((const unsigned char*)PyString_AsString(encoded),
+ PyString_Size(encoded))) {
+ PyErr_SetString(InvalidStringData,
+ "strings in documents must be valid UTF-8");
+ return 0;
+ }
+ } else {
+ PyObject* errmsg = PyString_FromString("documents must have only string keys, key was ");
+ PyObject* repr = PyObject_Repr(key);
+ PyString_ConcatAndDel(&errmsg, repr);
+ PyErr_SetString(InvalidDocument, PyString_AsString(errmsg));
+ Py_DECREF(errmsg);
+ return 0;
+ }
+
+ /* Don't allow writing _id here - it was already written. */
+ if (!write_pair(buffer, PyString_AsString(encoded),
+ PyString_Size(encoded), value, check_keys, 0)) {
+ Py_DECREF(encoded);
+ return 0;
+ }
+
+ Py_DECREF(encoded);
+ return 1;
+}
+
+static int write_son(bson_buffer* buffer, PyObject* dict, int start_position,
+ int length_location, unsigned char check_keys) {
+ PyObject* keys = PyObject_CallMethod(dict, "keys", NULL);
+ int items,
+ i;
+ if (!keys) {
+ return 0;
+ }
+ items = PyList_Size(keys);
+ for(i = 0; i < items; i++) {
+ PyObject* key;
+ PyObject* value;
+
+ key = PyList_GetItem(keys, i);
+ if (!key) {
+ Py_DECREF(keys);
+ return 0;
+ }
+ value = PyDict_GetItem(dict, key);
+ if (!value ||
+ !decode_and_write_pair(buffer, key, value, check_keys)) {
+ Py_DECREF(keys);
+ return 0;
+ }
+ }
+ Py_DECREF(keys);
+ return 1;
+}
+
+/* returns 0 on failure */
+static int write_dict(bson_buffer* buffer, PyObject* dict, unsigned char check_keys) {
+ int start_position = buffer->position;
+ char zero = 0;
+ int length;
+
+ int is_dict = PyDict_Check(dict);
+
+ /* save space for length */
+ int length_location = buffer_save_bytes(buffer, 4);
+ if (length_location == -1) {
+ return 0;
+ }
+
+ /* Write _id first if we have one, whether or not we're SON. */
+ if (is_dict) {
+ PyObject* _id = PyDict_GetItemString(dict, "_id");
+ if (_id) {
+ /* Don't bother checking keys, but do make sure we're allowed to
+ * write _id */
+ if (!write_pair(buffer, "_id", 3, _id, 0, 1)) {
+ return 0;
+ }
+ }
+ }
+
+ if (PyObject_IsInstance(dict, SON)) {
+ if (!write_son(buffer, dict, start_position, length_location, check_keys)) {
+ return 0;
+ }
+ } else if (is_dict) {
+ PyObject* key;
+ PyObject* value;
+ Py_ssize_t pos = 0;
+
+ while (PyDict_Next(dict, &pos, &key, &value)) {
+ if (!decode_and_write_pair(buffer, key, value, check_keys)) {
+ return 0;
+ }
+ }
+ } else {
+ PyObject* errmsg = PyString_FromString("encoder expected a mapping type but got: ");
+ PyObject* repr = PyObject_Repr(dict);
+ PyString_ConcatAndDel(&errmsg, repr);
+ PyErr_SetString(PyExc_TypeError, PyString_AsString(errmsg));
+ Py_DECREF(errmsg);
+ return 0;
+ }
+
+ /* write null byte and fill in length */
+ if (!buffer_write_bytes(buffer, &zero, 1)) {
+ return 0;
+ }
+ length = buffer->position - start_position;
+ if (length > 4 * 1024 * 1024) {
+ PyErr_SetString(InvalidDocument, "document too large - "
+ "BSON documents are limited to 4 MB");
+ return 0;
+ }
+ memcpy(buffer->buffer + length_location, &length, 4);
+ return 1;
+}
+
+static PyObject* _cbson_dict_to_bson(PyObject* self, PyObject* args) {
+ PyObject* dict;
+ PyObject* result;
+ unsigned char check_keys;
+ bson_buffer* buffer;
+
+ if (!PyArg_ParseTuple(args, "Ob", &dict, &check_keys)) {
+ return NULL;
+ }
+
+ buffer = buffer_new();
+ if (!buffer) {
+ return NULL;
+ }
+
+ if (!write_dict(buffer, dict, check_keys)) {
+ buffer_free(buffer);
+ return NULL;
+ }
+
+ /* objectify buffer */
+ result = Py_BuildValue("s#", buffer->buffer, buffer->position);
+ buffer_free(buffer);
+ return result;
+}
+
+/* add a lastError message on the end of the buffer.
+ * returns 0 on failure */
+static int add_last_error(bson_buffer* buffer, int request_id) {
+ /* message length: 62 */
+ if (!buffer_write_bytes(buffer, "\x3E\x00\x00\x00", 4) ||
+ !buffer_write_bytes(buffer, (const char*)&request_id, 4) ||
+ !buffer_write_bytes(buffer,
+ "\x00\x00\x00\x00" /* responseTo */
+ "\xd4\x07\x00\x00" /* opcode */
+ "\x00\x00\x00\x00" /* options */
+ "admin.$cmd\x00" /* collection name */
+ "\x00\x00\x00\x00" /* skip */
+ "\xFF\xFF\xFF\xFF" /* limit (-1) */
+ "\x17\x00\x00\x00" /* {getlasterror: 1} */
+ "\x10getlasterror" /* ... */
+ "\x00\x01\x00\x00" /* ... */
+ "\x00\x00", /* ... */
+ 54)) {
+ return 0;
+ }
+ return 1;
+}
+
+static PyObject* _cbson_insert_message(PyObject* self, PyObject* args) {
+ /* NOTE just using a random number as the request_id */
+ int request_id = rand();
+ char* collection_name;
+ int collection_name_length;
+ PyObject* docs;
+ int i;
+ unsigned char check_keys;
+ unsigned char safe;
+ bson_buffer* buffer;
+ int length_location;
+ PyObject* result;
+
+ if (!PyArg_ParseTuple(args, "s#Obb",
+ &collection_name,
+ &collection_name_length,
+ &docs, &check_keys, &safe)) {
+ return NULL;
+ }
+
+ buffer = buffer_new();
+ if (!buffer) {
+ return NULL;
+ }
+
+ // save space for message length
+ length_location = buffer_save_bytes(buffer, 4);
+ if (length_location == -1 ||
+ !buffer_write_bytes(buffer, (const char*)&request_id, 4) ||
+ !buffer_write_bytes(buffer,
+ "\x00\x00\x00\x00"
+ "\xd2\x07\x00\x00"
+ "\x00\x00\x00\x00",
+ 12) ||
+ !buffer_write_bytes(buffer,
+ collection_name,
+ collection_name_length + 1)) {
+ buffer_free(buffer);
+ return NULL;
+ }
+
+ for (i = 0; i < PyList_Size(docs); i++) {
+ PyObject* doc = PyList_GetItem(docs, i);
+ if (!write_dict(buffer, doc, check_keys)) {
+ buffer_free(buffer);
+ return NULL;
+ }
+ }
+
+ memcpy(buffer->buffer + length_location, &buffer->position, 4);
+
+ if (safe) {
+ if (!add_last_error(buffer, request_id)) {
+ buffer_free(buffer);
+ return NULL;
+ }
+ }
+
+ /* objectify buffer */
+ result = Py_BuildValue("is#", request_id,
+ buffer->buffer, buffer->position);
+ buffer_free(buffer);
+ return result;
+}
+
+static PyObject* get_value(const char* buffer, int* position, int type) {
+ PyObject* value;
+ switch (type) {
+ case 1:
+ {
+ double d;
+ memcpy(&d, buffer + *position, 8);
+ value = PyFloat_FromDouble(d);
+ if (!value) {
+ return NULL;
+ }
+ *position += 8;
+ break;
+ }
+ case 2:
+ case 13:
+ case 14:
+ {
+ int value_length = ((int*)(buffer + *position))[0] - 1;
+ *position += 4;
+ value = PyUnicode_DecodeUTF8(buffer + *position, value_length, "strict");
+ if (!value) {
+ return NULL;
+ }
+ *position += value_length + 1;
+ break;
+ }
+ case 3:
+ {
+ int size;
+ memcpy(&size, buffer + *position, 4);
+ value = elements_to_dict(buffer + *position + 4, size - 5);
+ if (!value) {
+ return NULL;
+ }
+
+ /* Decoding for DBRefs */
+ if (strcmp(buffer + *position + 5, "$ref") == 0) { /* DBRef */
+ PyObject* id = PyDict_GetItemString(value, "$id");
+ PyObject* collection = PyDict_GetItemString(value, "$ref");
+ PyObject* database = PyDict_GetItemString(value, "$db");
+
+ /* This works even if there is no $db since database will be NULL and
+ the call will be as if there were only two arguments specified. */
+ value = PyObject_CallFunctionObjArgs(DBRef, collection, id, database, NULL);
+ }
+
+ *position += size;
+ break;
+ }
+ case 4:
+ {
+ int size,
+ end;
+
+ memcpy(&size, buffer + *position, 4);
+ end = *position + size - 1;
+ *position += 4;
+
+ value = PyList_New(0);
+ if (!value) {
+ return NULL;
+ }
+ while (*position < end) {
+ PyObject* to_append;
+
+ int type = (int)buffer[(*position)++];
+ int key_size = strlen(buffer + *position);
+ *position += key_size + 1; /* just skip the key, they're in order. */
+ to_append = get_value(buffer, position, type);
+ if (!to_append) {
+ return NULL;
+ }
+ PyList_Append(value, to_append);
+ Py_DECREF(to_append);
+ }
+ (*position)++;
+ break;
+ }
+ case 5:
+ {
+ PyObject* data;
+ PyObject* st;
+ int length,
+ subtype;
+
+ memcpy(&length, buffer + *position, 4);
+ subtype = (unsigned char)buffer[*position + 4];
+
+ if (subtype == 2) {
+ data = PyString_FromStringAndSize(buffer + *position + 9, length - 4);
+ } else {
+ data = PyString_FromStringAndSize(buffer + *position + 5, length);
+ }
+ if (!data) {
+ return NULL;
+ }
+
+ if (subtype == 3 && UUID) { // Encode as UUID, not Binary
+ PyObject* kwargs;
+ PyObject* args = PyTuple_New(0);
+ if (!args) {
+ return NULL;
+ }
+ kwargs = PyDict_New();
+ if (!kwargs) {
+ Py_DECREF(args);
+ return NULL;
+ }
+
+ assert(length == 16); // UUID should always be 16 bytes
+
+ PyDict_SetItemString(kwargs, "bytes", data);
+ value = PyObject_Call(UUID, args, kwargs);
+
+ Py_DECREF(args);
+ Py_DECREF(kwargs);
+ Py_DECREF(data);
+ if (!value) {
+ return NULL;
+ }
+
+ *position += length + 5;
+ break;
+ }
+
+ st = PyInt_FromLong(subtype);
+ if (!st) {
+ Py_DECREF(data);
+ return NULL;
+ }
+ value = PyObject_CallFunctionObjArgs(Binary, data, st, NULL);
+ Py_DECREF(st);
+ Py_DECREF(data);
+ if (!value) {
+ return NULL;
+ }
+ *position += length + 5;
+ break;
+ }
+ case 6:
+ case 10:
+ {
+ value = Py_None;
+ Py_INCREF(value);
+ break;
+ }
+ case 7:
+ {
+ value = PyObject_CallFunction(ObjectId, "s#", buffer + *position, 12);
+ if (!value) {
+ return NULL;
+ }
+ *position += 12;
+ break;
+ }
+ case 8:
+ {
+ value = buffer[(*position)++] ? Py_True : Py_False;
+ Py_INCREF(value);
+ break;
+ }
+ case 9:
+ {
+ long long millis;
+ int microseconds;
+ time_t seconds;
+ struct tm timeinfo;
+
+ memcpy(&millis, buffer + *position, 8);
+ microseconds = (millis % 1000) * 1000;
+ seconds = millis / 1000;
+ if (GMTIME(&timeinfo, &seconds)) {
+ return NULL;
+ }
+
+ value = PyDateTime_FromDateAndTime(timeinfo.tm_year + 1900,
+ timeinfo.tm_mon + 1,
+ timeinfo.tm_mday,
+ timeinfo.tm_hour,
+ timeinfo.tm_min,
+ timeinfo.tm_sec,
+ microseconds);
+ *position += 8;
+ break;
+ }
+ case 11:
+ {
+ int flags_length,
+ flags,
+ i;
+
+ int pattern_length = strlen(buffer + *position);
+ PyObject* pattern = PyUnicode_DecodeUTF8(buffer + *position, pattern_length, "strict");
+ if (!pattern) {
+ return NULL;
+ }
+ *position += pattern_length + 1;
+ flags_length = strlen(buffer + *position);
+ flags = 0;
+ for (i = 0; i < flags_length; i++) {
+ if (buffer[*position + i] == 'i') {
+ flags |= 2;
+ } else if (buffer[*position + i] == 'l') {
+ flags |= 4;
+ } else if (buffer[*position + i] == 'm') {
+ flags |= 8;
+ } else if (buffer[*position + i] == 's') {
+ flags |= 16;
+ } else if (buffer[*position + i] == 'u') {
+ flags |= 32;
+ } else if (buffer[*position + i] == 'x') {
+ flags |= 64;
+ }
+ }
+ *position += flags_length + 1;
+ value = PyObject_CallFunction(RECompile, "Oi", pattern, flags);
+ Py_DECREF(pattern);
+ break;
+ }
+ case 12:
+ {
+ int collection_length;
+ PyObject* collection;
+ PyObject* id;
+
+ *position += 4;
+ collection_length = strlen(buffer + *position);
+ collection = PyUnicode_DecodeUTF8(buffer + *position, collection_length, "strict");
+ if (!collection) {
+ return NULL;
+ }
+ *position += collection_length + 1;
+ id = PyObject_CallFunction(ObjectId, "s#", buffer + *position, 12);
+ if (!id) {
+ Py_DECREF(collection);
+ return NULL;
+ }
+ *position += 12;
+ value = PyObject_CallFunctionObjArgs(DBRef, collection, id, NULL);
+ Py_DECREF(collection);
+ Py_DECREF(id);
+ break;
+ }
+ case 15:
+ {
+ int code_length,
+ scope_size;
+ PyObject* code;
+ PyObject* scope;
+
+ *position += 8;
+ code_length = strlen(buffer + *position);
+ code = PyUnicode_DecodeUTF8(buffer + *position, code_length, "strict");
+ if (!code) {
+ return NULL;
+ }
+ *position += code_length + 1;
+
+ memcpy(&scope_size, buffer + *position, 4);
+ scope = elements_to_dict(buffer + *position + 4, scope_size - 5);
+ if (!scope) {
+ Py_DECREF(code);
+ return NULL;
+ }
+ *position += scope_size;
+
+ value = PyObject_CallFunctionObjArgs(Code, code, scope, NULL);
+ Py_DECREF(code);
+ Py_DECREF(scope);
+ break;
+ }
+ case 16:
+ {
+ int i;
+ memcpy(&i, buffer + *position, 4);
+ value = PyInt_FromLong(i);
+ if (!value) {
+ return NULL;
+ }
+ *position += 4;
+ break;
+ }
+ case 17:
+ {
+ int i,
+ j;
+ memcpy(&i, buffer + *position, 4);
+ memcpy(&j, buffer + *position + 4, 4);
+ value = Py_BuildValue("(ii)", i, j);
+ if (!value) {
+ return NULL;
+ }
+ *position += 8;
+ break;
+ }
+ case 18:
+ {
+ long long ll;
+ memcpy(&ll, buffer + *position, 8);
+ value = PyLong_FromLongLong(ll);
+ if (!value) {
+ return NULL;
+ }
+ *position += 8;
+ break;
+ }
+ default:
+ PyErr_SetString(InvalidDocument, "no c decoder for this type yet");
+ return NULL;
+ }
+ return value;
+}
+
+static PyObject* elements_to_dict(const char* string, int max) {
+ int position = 0;
+ PyObject* dict = PyDict_New();
+ if (!dict) {
+ return NULL;
+ }
+ while (position < max) {
+ int type = (int)string[position++];
+ int name_length = strlen(string + position);
+ PyObject* name = PyUnicode_DecodeUTF8(string + position, name_length, "strict");
+ PyObject* value;
+ if (!name) {
+ return NULL;
+ }
+ position += name_length + 1;
+ value = get_value(string, &position, type);
+ if (!value) {
+ return NULL;
+ }
+
+ PyDict_SetItem(dict, name, value);
+ Py_DECREF(name);
+ Py_DECREF(value);
+ }
+ return dict;
+}
+
+static PyObject* _cbson_bson_to_dict(PyObject* self, PyObject* bson) {
+ int size;
+ Py_ssize_t total_size;
+ const char* string;
+ PyObject* dict;
+ PyObject* remainder;
+ PyObject* result;
+
+ if (!PyString_Check(bson)) {
+ PyErr_SetString(PyExc_TypeError, "argument to _bson_to_dict must be a string");
+ return NULL;
+ }
+ total_size = PyString_Size(bson);
+ string = PyString_AsString(bson);
+ if (!string) {
+ return NULL;
+ }
+ memcpy(&size, string, 4);
+
+ dict = elements_to_dict(string + 4, size - 5);
+ if (!dict) {
+ return NULL;
+ }
+ remainder = PyString_FromStringAndSize(string + size, total_size - size);
+ if (!remainder) {
+ Py_DECREF(dict);
+ return NULL;
+ }
+ result = Py_BuildValue("OO", dict, remainder);
+ Py_DECREF(dict);
+ Py_DECREF(remainder);
+ return result;
+}
+
+static PyObject* _cbson_to_dicts(PyObject* self, PyObject* bson) {
+ int size;
+ Py_ssize_t total_size;
+ const char* string;
+ PyObject* dict;
+ PyObject* result;
+
+ if (!PyString_Check(bson)) {
+ PyErr_SetString(PyExc_TypeError, "argument to _to_dicts must be a string");
+ return NULL;
+ }
+ total_size = PyString_Size(bson);
+ string = PyString_AsString(bson);
+ if (!string) {
+ return NULL;
+ }
+
+ result = PyList_New(0);
+
+ while (total_size > 0) {
+ memcpy(&size, string, 4);
+
+ dict = elements_to_dict(string + 4, size - 5);
+ if (!dict) {
+ return NULL;
+ }
+ PyList_Append(result, dict);