faststep 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. data/.gitignore +6 -0
  2. data/Gemfile +4 -0
  3. data/Rakefile +15 -0
  4. data/bench/standard_benchmark +178 -0
  5. data/ext/faststep/bson.c +687 -0
  6. data/ext/faststep/bson.h +225 -0
  7. data/ext/faststep/bson_ruby_conversion.c +44 -0
  8. data/ext/faststep/bson_ruby_conversion.h +10 -0
  9. data/ext/faststep/collection.c +187 -0
  10. data/ext/faststep/collection.h +24 -0
  11. data/ext/faststep/connection.c +85 -0
  12. data/ext/faststep/connection.h +17 -0
  13. data/ext/faststep/cursor.c +61 -0
  14. data/ext/faststep/cursor.h +10 -0
  15. data/ext/faststep/db.c +56 -0
  16. data/ext/faststep/db.h +8 -0
  17. data/ext/faststep/exceptions.c +7 -0
  18. data/ext/faststep/exceptions.h +5 -0
  19. data/ext/faststep/extconf.rb +3 -0
  20. data/ext/faststep/faststep.c +30 -0
  21. data/ext/faststep/faststep.h +4 -0
  22. data/ext/faststep/faststep_defines.h +11 -0
  23. data/ext/faststep/gridfs.c +799 -0
  24. data/ext/faststep/gridfs.h +278 -0
  25. data/ext/faststep/md5.c +381 -0
  26. data/ext/faststep/md5.h +91 -0
  27. data/ext/faststep/mongo.c +801 -0
  28. data/ext/faststep/mongo.h +188 -0
  29. data/ext/faststep/mongo_except.h +143 -0
  30. data/ext/faststep/numbers.c +127 -0
  31. data/ext/faststep/platform_hacks.h +93 -0
  32. data/ext/faststep/support.c +21 -0
  33. data/ext/faststep/support.h +6 -0
  34. data/faststep.gemspec +26 -0
  35. data/lib/faststep/collection.rb +21 -0
  36. data/lib/faststep/connection.rb +13 -0
  37. data/lib/faststep/cursor.rb +7 -0
  38. data/lib/faststep/db.rb +25 -0
  39. data/lib/faststep/version.rb +3 -0
  40. data/lib/faststep.rb +10 -0
  41. data/spec/collection_spec.rb +116 -0
  42. data/spec/connection_spec.rb +34 -0
  43. data/spec/cursor_spec.rb +24 -0
  44. data/spec/db_spec.rb +28 -0
  45. data/spec/spec_helper.rb +13 -0
  46. data/spec/support_spec.rb +14 -0
  47. metadata +181 -0
@@ -0,0 +1,278 @@
1
+ /*--------------------------------------------------------------------*/
2
+ /* gridfs.h */
3
+ /* Author: Christopher Triolo */
4
+ /*--------------------------------------------------------------------*/
5
+
6
+ #include "mongo.h"
7
+ #include "bson.h"
8
+ #include "platform_hacks.h"
9
+ #include <stdio.h>
10
+ #ifndef GRIDFS_INCLUDED
11
+ #define GRIDFS_INCLUDED
12
+
13
+ enum {DEFAULT_CHUNK_SIZE = 256 * 1024};
14
+
15
+ typedef uint64_t gridfs_offset;
16
+
17
+ /* A GridFS contains a db connection, a root database name, and an
18
+ optional prefix */
19
+ typedef struct {
20
+ /* The client to db-connection. */
21
+ mongo_connection* client;
22
+ /* The root database name */
23
+ const char* dbname;
24
+ /* The prefix of the GridFS's collections, default is NULL */
25
+ const char* prefix;
26
+ /* The namespace where the file's metadata is stored */
27
+ const char* files_ns;
28
+ /* The namespace where the files's data is stored in chunks */
29
+ const char* chunks_ns;
30
+
31
+ } gridfs;
32
+
33
+ /* The state of a gridfile. This is used for incrementally writing buffers
34
+ * to a single GridFS file.
35
+ */
36
+
37
+ /* A GridFile contains the GridFS it is located in and the file
38
+ metadata */
39
+ typedef struct {
40
+ /* The GridFS where the GridFile is located */
41
+ gridfs* gfs;
42
+ /* The GridFile's bson object where all its metadata is located */
43
+ bson* meta;
44
+ /* The position is the offset in the file */
45
+ gridfs_offset pos;
46
+ /* The files_id of the gridfile */
47
+ bson_oid_t id;
48
+ /* The name of the gridfile as a string */
49
+ const char* remote_name;
50
+ /* The gridfile's content type */
51
+ const char* content_type;
52
+ /* The length of this gridfile */
53
+ gridfs_offset length;
54
+ /* The number of the current chunk being written to */
55
+ int chunk_num;
56
+ /* A buffer storing data still to be written to chunks */
57
+ char* pending_data;
58
+ /* Length of pending data */
59
+ int pending_len;
60
+
61
+ } gridfile;
62
+
63
+ /*--------------------------------------------------------------------*/
64
+
65
+ /** Initializes a GridFS object
66
+ * @param client - db connection
67
+ * @param dbname - database name
68
+ * @param prefix - collection prefix, default is fs if NULL or empty
69
+ * @param gfs - the GridFS object to initialize
70
+ * @return - 1 if successful, 0 otherwise
71
+ */
72
+ int gridfs_init(mongo_connection* client, const char* dbname,
73
+ const char* prefix, gridfs* gfs);
74
+
75
+ /** Destroys a GridFS object
76
+ */
77
+ void gridfs_destroy( gridfs* gfs );
78
+
79
+ /** Initializes a gridfile for writing incrementally with gridfs_write_buffer.
80
+ * Once initialized, you can write any number of buffers with gridfs_write_buffer.
81
+ * When done, you must call gridfs_writer_done to save the file metadata.
82
+ *
83
+ * @return - 1 if successful, 0 otherwise
84
+ */
85
+ void gridfile_writer_init( gridfile* gfile, gridfs* gfs, const char* remote_name, const char* content_type );
86
+
87
+ /** Write to a GridFS file incrementally. You can call this function any number
88
+ * of times with a new buffer each time. This allows you to effectively
89
+ * stream to a GridFS file. When finished, be sure to call gridfs_writer_done.
90
+ *
91
+ * @return - 1 if successful, 0 otherwise
92
+ */
93
+ void gridfile_write_buffer( gridfile* gfile, const char* data, gridfs_offset length );
94
+
95
+ /** Signal that writing of this gridfile is complete by
96
+ * writing any buffered chunks along with the entry in the
97
+ * files collection.
98
+ *
99
+ * @return - the file object if successful; otherwise 0.
100
+ */
101
+ bson gridfile_writer_done( gridfile* gfile );
102
+
103
+ /** Store a buffer as a GridFS file.
104
+ * @param gfs - the working GridFS
105
+ * @param data - pointer to buffer to store in GridFS
106
+ * @param length - length of the buffer
107
+ * @param remotename - filename for use in the database
108
+ * @param contenttype - optional MIME type for this object
109
+ * @return - the file object
110
+ */
111
+ bson gridfs_store_buffer(gridfs* gfs, const char* data, gridfs_offset length,
112
+ const char* remotename,
113
+ const char * contenttype);
114
+
115
+ /** Open the file referenced by filename and store it as a GridFS file.
116
+ * @param gfs - the working GridFS
117
+ * @param filename - local filename relative to the process
118
+ * @param remotename - optional filename for use in the database
119
+ * @param contenttype - optional MIME type for this object
120
+ * @return - the file object
121
+ */
122
+ bson gridfs_store_file(gridfs* gfs, const char* filename,
123
+ const char* remotename, const char* contenttype);
124
+
125
+ /** Removes the files referenced by filename from the db
126
+ * @param gfs - the working GridFS
127
+ * @param filename - the filename of the file/s to be removed
128
+ */
129
+ void gridfs_remove_filename(gridfs* gfs, const char* filename);
130
+
131
+ /** Find the first query within the GridFS and return it as a GridFile
132
+ * @param gfs - the working GridFS
133
+ * @param query - a pointer to the bson with the query data
134
+ * @param gfile - the output GridFile to be initialized
135
+ * @return 1 if successful, 0 otherwise
136
+ */
137
+ int gridfs_find_query(gridfs* gfs, bson* query, gridfile* gfile );
138
+
139
+ /** Find the first file referenced by filename within the GridFS
140
+ * and return it as a GridFile
141
+ * @param gfs - the working GridFS
142
+ * @param filename - filename of the file to find
143
+ * @param gfile - the output GridFile to be intialized
144
+ * @return 1 if successful, 0 otherwise
145
+ */
146
+ int gridfs_find_filename(gridfs* gfs, const char *filename,
147
+ gridfile* gfile);
148
+
149
+ /*--------------------------------------------------------------------*/
150
+
151
+
152
+ /** Initializes a GridFile containing the GridFS and file bson
153
+ * @param gfs - the GridFS where the GridFile is located
154
+ * @param meta - the file object
155
+ * @param gfile - the output GridFile that is being initialized
156
+ * @return 1 if successful, 0 otherwise
157
+ */
158
+ int gridfile_init(gridfs* gfs, bson* meta, gridfile* gfile);
159
+
160
+ /** Destroys the GridFile
161
+ * @param oGridFIle - the GridFile being destroyed
162
+ */
163
+ void gridfile_destroy(gridfile* gfile);
164
+
165
+ /** Returns whether or not the GridFile exists
166
+ * @param gfile - the GridFile being examined
167
+ */
168
+ int gridfile_exists(gridfile* gfile);
169
+
170
+ /** Returns the filename of GridFile
171
+ * @param gfile - the working GridFile
172
+ * @return - the filename of the Gridfile
173
+ */
174
+ const char * gridfile_get_filename(gridfile* gfile);
175
+
176
+ /** Returns the size of the chunks of the GridFile
177
+ * @param gfile - the working GridFile
178
+ * @return - the size of the chunks of the Gridfile
179
+ */
180
+ int gridfile_get_chunksize(gridfile* gfile);
181
+
182
+ /** Returns the length of GridFile's data
183
+ * @param gfile - the working GridFile
184
+ * @return - the length of the Gridfile's data
185
+ */
186
+ gridfs_offset gridfile_get_contentlength(gridfile* gfile);
187
+
188
+ /** Returns the MIME type of the GridFile
189
+ * @param gfile - the working GridFile
190
+ * @return - the MIME type of the Gridfile
191
+ * (NULL if no type specified)
192
+ */
193
+ const char* gridfile_get_contenttype(gridfile* gfile);
194
+
195
+ /** Returns the upload date of GridFile
196
+ * @param gfile - the working GridFile
197
+ * @return - the upload date of the Gridfile
198
+ */
199
+ bson_date_t gridfile_get_uploaddate(gridfile* gfile);
200
+
201
+ /** Returns the MD5 of GridFile
202
+ * @param gfile - the working GridFile
203
+ * @return - the MD5 of the Gridfile
204
+ */
205
+ const char* gridfile_get_md5(gridfile* gfile);
206
+
207
+ /** Returns the field in GridFile specified by name
208
+ * @param gfile - the working GridFile
209
+ * @param name - the name of the field to be returned
210
+ * @return - the data of the field specified
211
+ * (NULL if none exists)
212
+ */
213
+ const char *gridfile_get_field(gridfile* gfile,
214
+ const char* name);
215
+
216
+ /** Returns a boolean field in GridFile specified by name
217
+ * @param gfile - the working GridFile
218
+ * @param name - the name of the field to be returned
219
+ * @return - the boolean of the field specified
220
+ * (NULL if none exists)
221
+ */
222
+ bson_bool_t gridfile_get_boolean(gridfile* gfile,
223
+ const char* name);
224
+
225
+ /** Returns the metadata of GridFile
226
+ * @param gfile - the working GridFile
227
+ * @return - the metadata of the Gridfile in a bson object
228
+ * (an empty bson is returned if none exists)
229
+ */
230
+ bson gridfile_get_metadata(gridfile* gfile);
231
+
232
+ /** Returns the number of chunks in the GridFile
233
+ * @param gfile - the working GridFile
234
+ * @return - the number of chunks in the Gridfile
235
+ */
236
+ int gridfile_get_numchunks(gridfile* gfile);
237
+
238
+ /** Returns chunk n of GridFile
239
+ * @param gfile - the working GridFile
240
+ * @return - the nth chunk of the Gridfile
241
+ */
242
+ bson gridfile_get_chunk(gridfile* gfile, int n);
243
+
244
+ /** Returns a mongo_cursor of *size* chunks starting with chunk *start*
245
+ * @param gfile - the working GridFile
246
+ * @param start - the first chunk in the cursor
247
+ * @param size - the number of chunks to be returned
248
+ * @return - mongo_cursor of the chunks (must be destroyed after use)
249
+ */
250
+ mongo_cursor* gridfile_get_chunks(gridfile* gfile, int start, int size);
251
+
252
+ /** Writes the GridFile to a stream
253
+ * @param gfile - the working GridFile
254
+ * @param stream - the file stream to write to
255
+ */
256
+ gridfs_offset gridfile_write_file(gridfile* gfile, FILE* stream);
257
+
258
+ /** Reads length bytes from the GridFile to a buffer
259
+ * and updates the position in the file.
260
+ * (assumes the buffer is large enough)
261
+ * (if size is greater than EOF gridfile_read reads until EOF)
262
+ * @param gfile - the working GridFile
263
+ * @param size - the amount of bytes to be read
264
+ * @param buf - the buffer to read to
265
+ * @return - the number of bytes read
266
+ */
267
+ gridfs_offset gridfile_read(gridfile* gfile, gridfs_offset size, char* buf);
268
+
269
+ /** Updates the position in the file
270
+ * (If the offset goes beyond the contentlength,
271
+ * the position is updated to the end of the file.)
272
+ * @param gfile - the working GridFile
273
+ * @param offset - the position to update to
274
+ * @return - resulting offset location
275
+ */
276
+ gridfs_offset gridfile_seek(gridfile* gfile, gridfs_offset offset);
277
+
278
+ #endif
@@ -0,0 +1,381 @@
1
+ /*
2
+ Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
3
+
4
+ This software is provided 'as-is', without any express or implied
5
+ warranty. In no event will the authors be held liable for any damages
6
+ arising from the use of this software.
7
+
8
+ Permission is granted to anyone to use this software for any purpose,
9
+ including commercial applications, and to alter it and redistribute it
10
+ freely, subject to the following restrictions:
11
+
12
+ 1. The origin of this software must not be misrepresented; you must not
13
+ claim that you wrote the original software. If you use this software
14
+ in a product, an acknowledgment in the product documentation would be
15
+ appreciated but is not required.
16
+ 2. Altered source versions must be plainly marked as such, and must not be
17
+ misrepresented as being the original software.
18
+ 3. This notice may not be removed or altered from any source distribution.
19
+
20
+ L. Peter Deutsch
21
+ ghost@aladdin.com
22
+
23
+ */
24
+ /* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
25
+ /*
26
+ Independent implementation of MD5 (RFC 1321).
27
+
28
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
29
+ text is available at
30
+ http://www.ietf.org/rfc/rfc1321.txt
31
+ The code is derived from the text of the RFC, including the test suite
32
+ (section A.5) but excluding the rest of Appendix A. It does not include
33
+ any code or documentation that is identified in the RFC as being
34
+ copyrighted.
35
+
36
+ The original and principal author of md5.c is L. Peter Deutsch
37
+ <ghost@aladdin.com>. Other authors are noted in the change history
38
+ that follows (in reverse chronological order):
39
+
40
+ 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
41
+ either statically or dynamically; added missing #include <string.h>
42
+ in library.
43
+ 2002-03-11 lpd Corrected argument list for main(), and added int return
44
+ type, in test program and T value program.
45
+ 2002-02-21 lpd Added missing #include <stdio.h> in test program.
46
+ 2000-07-03 lpd Patched to eliminate warnings about "constant is
47
+ unsigned in ANSI C, signed in traditional"; made test program
48
+ self-checking.
49
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
50
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
51
+ 1999-05-03 lpd Original version.
52
+ */
53
+
54
+ #include "md5.h"
55
+ #include <string.h>
56
+
57
+ #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
58
+ #ifdef MONGO_BIG_ENDIAN
59
+ # define BYTE_ORDER 1
60
+ #else
61
+ # define BYTE_ORDER -1
62
+ #endif
63
+
64
+ #define T_MASK ((mongo_md5_word_t)~0)
65
+ #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
66
+ #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
67
+ #define T3 0x242070db
68
+ #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
69
+ #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
70
+ #define T6 0x4787c62a
71
+ #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
72
+ #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
73
+ #define T9 0x698098d8
74
+ #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
75
+ #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
76
+ #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
77
+ #define T13 0x6b901122
78
+ #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
79
+ #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
80
+ #define T16 0x49b40821
81
+ #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
82
+ #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
83
+ #define T19 0x265e5a51
84
+ #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
85
+ #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
86
+ #define T22 0x02441453
87
+ #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
88
+ #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
89
+ #define T25 0x21e1cde6
90
+ #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
91
+ #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
92
+ #define T28 0x455a14ed
93
+ #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
94
+ #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
95
+ #define T31 0x676f02d9
96
+ #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
97
+ #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
98
+ #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
99
+ #define T35 0x6d9d6122
100
+ #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
101
+ #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
102
+ #define T38 0x4bdecfa9
103
+ #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
104
+ #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
105
+ #define T41 0x289b7ec6
106
+ #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
107
+ #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
108
+ #define T44 0x04881d05
109
+ #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
110
+ #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
111
+ #define T47 0x1fa27cf8
112
+ #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
113
+ #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
114
+ #define T50 0x432aff97
115
+ #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
116
+ #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
117
+ #define T53 0x655b59c3
118
+ #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
119
+ #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
120
+ #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
121
+ #define T57 0x6fa87e4f
122
+ #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
123
+ #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
124
+ #define T60 0x4e0811a1
125
+ #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
126
+ #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
127
+ #define T63 0x2ad7d2bb
128
+ #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
129
+
130
+
131
+ static void
132
+ mongo_md5_process(mongo_md5_state_t *pms, const mongo_md5_byte_t *data /*[64]*/)
133
+ {
134
+ mongo_md5_word_t
135
+ a = pms->abcd[0], b = pms->abcd[1],
136
+ c = pms->abcd[2], d = pms->abcd[3];
137
+ mongo_md5_word_t t;
138
+ #if BYTE_ORDER > 0
139
+ /* Define storage only for big-endian CPUs. */
140
+ mongo_md5_word_t X[16];
141
+ #else
142
+ /* Define storage for little-endian or both types of CPUs. */
143
+ mongo_md5_word_t xbuf[16];
144
+ const mongo_md5_word_t *X;
145
+ #endif
146
+
147
+ {
148
+ #if BYTE_ORDER == 0
149
+ /*
150
+ * Determine dynamically whether this is a big-endian or
151
+ * little-endian machine, since we can use a more efficient
152
+ * algorithm on the latter.
153
+ */
154
+ static const int w = 1;
155
+
156
+ if (*((const mongo_md5_byte_t *)&w)) /* dynamic little-endian */
157
+ #endif
158
+ #if BYTE_ORDER <= 0 /* little-endian */
159
+ {
160
+ /*
161
+ * On little-endian machines, we can process properly aligned
162
+ * data without copying it.
163
+ */
164
+ if (!((data - (const mongo_md5_byte_t *)0) & 3)) {
165
+ /* data are properly aligned */
166
+ X = (const mongo_md5_word_t *)data;
167
+ } else {
168
+ /* not aligned */
169
+ memcpy(xbuf, data, 64);
170
+ X = xbuf;
171
+ }
172
+ }
173
+ #endif
174
+ #if BYTE_ORDER == 0
175
+ else /* dynamic big-endian */
176
+ #endif
177
+ #if BYTE_ORDER >= 0 /* big-endian */
178
+ {
179
+ /*
180
+ * On big-endian machines, we must arrange the bytes in the
181
+ * right order.
182
+ */
183
+ const mongo_md5_byte_t *xp = data;
184
+ int i;
185
+
186
+ # if BYTE_ORDER == 0
187
+ X = xbuf; /* (dynamic only) */
188
+ # else
189
+ # define xbuf X /* (static only) */
190
+ # endif
191
+ for (i = 0; i < 16; ++i, xp += 4)
192
+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
193
+ }
194
+ #endif
195
+ }
196
+
197
+ #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
198
+
199
+ /* Round 1. */
200
+ /* Let [abcd k s i] denote the operation
201
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
202
+ #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
203
+ #define SET(a, b, c, d, k, s, Ti)\
204
+ t = a + F(b,c,d) + X[k] + Ti;\
205
+ a = ROTATE_LEFT(t, s) + b
206
+ /* Do the following 16 operations. */
207
+ SET(a, b, c, d, 0, 7, T1);
208
+ SET(d, a, b, c, 1, 12, T2);
209
+ SET(c, d, a, b, 2, 17, T3);
210
+ SET(b, c, d, a, 3, 22, T4);
211
+ SET(a, b, c, d, 4, 7, T5);
212
+ SET(d, a, b, c, 5, 12, T6);
213
+ SET(c, d, a, b, 6, 17, T7);
214
+ SET(b, c, d, a, 7, 22, T8);
215
+ SET(a, b, c, d, 8, 7, T9);
216
+ SET(d, a, b, c, 9, 12, T10);
217
+ SET(c, d, a, b, 10, 17, T11);
218
+ SET(b, c, d, a, 11, 22, T12);
219
+ SET(a, b, c, d, 12, 7, T13);
220
+ SET(d, a, b, c, 13, 12, T14);
221
+ SET(c, d, a, b, 14, 17, T15);
222
+ SET(b, c, d, a, 15, 22, T16);
223
+ #undef SET
224
+
225
+ /* Round 2. */
226
+ /* Let [abcd k s i] denote the operation
227
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
228
+ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
229
+ #define SET(a, b, c, d, k, s, Ti)\
230
+ t = a + G(b,c,d) + X[k] + Ti;\
231
+ a = ROTATE_LEFT(t, s) + b
232
+ /* Do the following 16 operations. */
233
+ SET(a, b, c, d, 1, 5, T17);
234
+ SET(d, a, b, c, 6, 9, T18);
235
+ SET(c, d, a, b, 11, 14, T19);
236
+ SET(b, c, d, a, 0, 20, T20);
237
+ SET(a, b, c, d, 5, 5, T21);
238
+ SET(d, a, b, c, 10, 9, T22);
239
+ SET(c, d, a, b, 15, 14, T23);
240
+ SET(b, c, d, a, 4, 20, T24);
241
+ SET(a, b, c, d, 9, 5, T25);
242
+ SET(d, a, b, c, 14, 9, T26);
243
+ SET(c, d, a, b, 3, 14, T27);
244
+ SET(b, c, d, a, 8, 20, T28);
245
+ SET(a, b, c, d, 13, 5, T29);
246
+ SET(d, a, b, c, 2, 9, T30);
247
+ SET(c, d, a, b, 7, 14, T31);
248
+ SET(b, c, d, a, 12, 20, T32);
249
+ #undef SET
250
+
251
+ /* Round 3. */
252
+ /* Let [abcd k s t] denote the operation
253
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
254
+ #define H(x, y, z) ((x) ^ (y) ^ (z))
255
+ #define SET(a, b, c, d, k, s, Ti)\
256
+ t = a + H(b,c,d) + X[k] + Ti;\
257
+ a = ROTATE_LEFT(t, s) + b
258
+ /* Do the following 16 operations. */
259
+ SET(a, b, c, d, 5, 4, T33);
260
+ SET(d, a, b, c, 8, 11, T34);
261
+ SET(c, d, a, b, 11, 16, T35);
262
+ SET(b, c, d, a, 14, 23, T36);
263
+ SET(a, b, c, d, 1, 4, T37);
264
+ SET(d, a, b, c, 4, 11, T38);
265
+ SET(c, d, a, b, 7, 16, T39);
266
+ SET(b, c, d, a, 10, 23, T40);
267
+ SET(a, b, c, d, 13, 4, T41);
268
+ SET(d, a, b, c, 0, 11, T42);
269
+ SET(c, d, a, b, 3, 16, T43);
270
+ SET(b, c, d, a, 6, 23, T44);
271
+ SET(a, b, c, d, 9, 4, T45);
272
+ SET(d, a, b, c, 12, 11, T46);
273
+ SET(c, d, a, b, 15, 16, T47);
274
+ SET(b, c, d, a, 2, 23, T48);
275
+ #undef SET
276
+
277
+ /* Round 4. */
278
+ /* Let [abcd k s t] denote the operation
279
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
280
+ #define I(x, y, z) ((y) ^ ((x) | ~(z)))
281
+ #define SET(a, b, c, d, k, s, Ti)\
282
+ t = a + I(b,c,d) + X[k] + Ti;\
283
+ a = ROTATE_LEFT(t, s) + b
284
+ /* Do the following 16 operations. */
285
+ SET(a, b, c, d, 0, 6, T49);
286
+ SET(d, a, b, c, 7, 10, T50);
287
+ SET(c, d, a, b, 14, 15, T51);
288
+ SET(b, c, d, a, 5, 21, T52);
289
+ SET(a, b, c, d, 12, 6, T53);
290
+ SET(d, a, b, c, 3, 10, T54);
291
+ SET(c, d, a, b, 10, 15, T55);
292
+ SET(b, c, d, a, 1, 21, T56);
293
+ SET(a, b, c, d, 8, 6, T57);
294
+ SET(d, a, b, c, 15, 10, T58);
295
+ SET(c, d, a, b, 6, 15, T59);
296
+ SET(b, c, d, a, 13, 21, T60);
297
+ SET(a, b, c, d, 4, 6, T61);
298
+ SET(d, a, b, c, 11, 10, T62);
299
+ SET(c, d, a, b, 2, 15, T63);
300
+ SET(b, c, d, a, 9, 21, T64);
301
+ #undef SET
302
+
303
+ /* Then perform the following additions. (That is increment each
304
+ of the four registers by the value it had before this block
305
+ was started.) */
306
+ pms->abcd[0] += a;
307
+ pms->abcd[1] += b;
308
+ pms->abcd[2] += c;
309
+ pms->abcd[3] += d;
310
+ }
311
+
312
+ void
313
+ mongo_md5_init(mongo_md5_state_t *pms)
314
+ {
315
+ pms->count[0] = pms->count[1] = 0;
316
+ pms->abcd[0] = 0x67452301;
317
+ pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
318
+ pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
319
+ pms->abcd[3] = 0x10325476;
320
+ }
321
+
322
+ void
323
+ mongo_md5_append(mongo_md5_state_t *pms, const mongo_md5_byte_t *data, int nbytes)
324
+ {
325
+ const mongo_md5_byte_t *p = data;
326
+ int left = nbytes;
327
+ int offset = (pms->count[0] >> 3) & 63;
328
+ mongo_md5_word_t nbits = (mongo_md5_word_t)(nbytes << 3);
329
+
330
+ if (nbytes <= 0)
331
+ return;
332
+
333
+ /* Update the message length. */
334
+ pms->count[1] += nbytes >> 29;
335
+ pms->count[0] += nbits;
336
+ if (pms->count[0] < nbits)
337
+ pms->count[1]++;
338
+
339
+ /* Process an initial partial block. */
340
+ if (offset) {
341
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
342
+
343
+ memcpy(pms->buf + offset, p, copy);
344
+ if (offset + copy < 64)
345
+ return;
346
+ p += copy;
347
+ left -= copy;
348
+ mongo_md5_process(pms, pms->buf);
349
+ }
350
+
351
+ /* Process full blocks. */
352
+ for (; left >= 64; p += 64, left -= 64)
353
+ mongo_md5_process(pms, p);
354
+
355
+ /* Process a final partial block. */
356
+ if (left)
357
+ memcpy(pms->buf, p, left);
358
+ }
359
+
360
+ void
361
+ mongo_md5_finish(mongo_md5_state_t *pms, mongo_md5_byte_t digest[16])
362
+ {
363
+ static const mongo_md5_byte_t pad[64] = {
364
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
365
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
366
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
367
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
368
+ };
369
+ mongo_md5_byte_t data[8];
370
+ int i;
371
+
372
+ /* Save the length before padding. */
373
+ for (i = 0; i < 8; ++i)
374
+ data[i] = (mongo_md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
375
+ /* Pad to 56 bytes mod 64. */
376
+ mongo_md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
377
+ /* Append the length. */
378
+ mongo_md5_append(pms, data, 8);
379
+ for (i = 0; i < 16; ++i)
380
+ digest[i] = (mongo_md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
381
+ }