PageRenderTime 57ms CodeModel.GetById 18ms app.highlight 32ms RepoModel.GetById 1ms app.codeStats 0ms

/api_bson.c

http://github.com/gerald-lindsly/mongo-matlab-driver
C | 780 lines | 621 code | 117 blank | 42 comment | 155 complexity | 5b74da7f55e728f7ae07163fddeed3d3 MD5 | raw file
  1/**    Copyright 2009-2011 10gen Inc.
  2 *
  3 *    Licensed under the Apache License, Version 2.0 (the "License");
  4 *    you may not use this file except in compliance with the License.
  5 *    You may obtain a copy of the License at
  6 *
  7 *    http://www.apache.org/licenses/LICENSE-2.0
  8 *
  9 *    Unless required by applicable law or agreed to in writing, software
 10 *    distributed under the License is distributed on an "AS IS" BASIS,
 11 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12 *    See the License for the specific language governing permissions and
 13 *    limitations under the License.
 14 */
 15#include "MongoMatlabDriver.h"
 16#include "bson.h"
 17#include <malloc.h>
 18
 19#include <mex.h>
 20
 21#define MAXDIM 20
 22
 23const char* numstr(int i) {
 24    extern const char bson_numstrs[1000][4];
 25    if (i < 1000)
 26        return bson_numstrs[i];
 27    else {
 28        static char s[20];
 29        sprintf(s, "%d", i);
 30        return s;
 31    }
 32}
 33
 34
 35EXPORT void mongo_bson_buffer_create(struct bson_buffer** b)
 36{
 37    bson* _b = (bson*)bson_malloc(sizeof(bson));
 38    bson_init(_b);
 39    *b = (struct bson_buffer*)_b;
 40}
 41
 42
 43EXPORT void mongo_bson_buffer_to_bson(struct bson_buffer* b, struct bson_** out) {
 44    bson* _b = (bson*)b;
 45    bson_finish(_b);
 46    *out = (struct bson_*) _b;
 47    //*b = 0;
 48}
 49
 50
 51EXPORT void mongo_bson_free(struct bson_* b) {
 52    if (b != NULL) {
 53        bson_destroy((bson*)b);
 54        free(b);
 55    }
 56}
 57
 58
 59EXPORT void mongo_bson_buffer_free(struct bson_buffer* b) {
 60    bson_destroy((bson*)b);
 61    free(b);
 62}
 63
 64
 65static void reverse(mwSize* p, mwSize len) {
 66    mwSize* q = p + len - 1;
 67    mwSize t;
 68    while (p < q) {
 69        t = *p;
 70        *p = *q;
 71        *q = t;
 72        p++, q--;
 73    }
 74}
 75
 76
 77static int mongo_bson_buffer_append_complex(struct bson_buffer* b, const char* name, double r, double i) {
 78    bson* _b = (bson*) b;
 79    return (bson_append_start_object(_b, name) == BSON_OK) &&
 80           (bson_append_double(_b, "r", r) == BSON_OK) && 
 81           (bson_append_double(_b, "i", i) == BSON_OK) && 
 82           (bson_append_finish_object(_b) == BSON_OK);
 83}
 84
 85
 86EXPORT int  mongo_bson_buffer_append(struct bson_buffer* b, char* name, mxArray* value) {
 87    size_t numel = mxGetNumberOfElements(value);
 88    mxClassID cls = mxGetClassID(value);
 89    bson* _b = (bson*)b;
 90    mwSize i, j;
 91    mwSize dims[MAXDIM];
 92    mwSize ijk[MAXDIM];
 93    mwSize sizes[MAXDIM];
 94    mwSize ndims;
 95    const mwSize *odims;
 96    int depth = 0;
 97    int success;
 98    if (numel == 1) {
 99        /* Append a single element using the given name */
100        switch (cls) {
101        case mxLOGICAL_CLASS:
102            return (bson_append_bool(_b, name, ((char*)mxGetData(value))[0]) == BSON_OK);
103        case mxDOUBLE_CLASS:
104            if (mxIsComplex(value))
105                return mongo_bson_buffer_append_complex(b, name, mxGetPr(value)[0], mxGetPi(value)[0]);
106            else
107                return (bson_append_double(_b, name, mxGetPr(value)[0]) == BSON_OK);
108        case mxSINGLE_CLASS:
109            return (bson_append_double(_b, name, ((float*)mxGetData(value))[0]) == BSON_OK);
110        case mxINT8_CLASS:
111            return (bson_append_int(_b, name, ((signed char*)mxGetData(value))[0]) == BSON_OK);
112        case mxUINT8_CLASS:
113            return (bson_append_int(_b, name, ((unsigned char*)mxGetData(value))[0]) == BSON_OK);
114        case mxINT16_CLASS:
115            return (bson_append_int(_b, name, ((short*)mxGetData(value))[0]) == BSON_OK);
116        case mxUINT16_CLASS:
117            return (bson_append_int(_b, name, ((unsigned short*)mxGetData(value))[0]) == BSON_OK);
118        case mxINT32_CLASS:
119            return (bson_append_int(_b, name, ((int*)mxGetData(value))[0]) == BSON_OK);
120        case mxUINT32_CLASS:
121            return (bson_append_int(_b, name, ((unsigned int*)mxGetData(value))[0]) == BSON_OK);
122        case mxINT64_CLASS: ;
123        case mxUINT64_CLASS:
124            return (bson_append_long(_b, name, ((int64_t*)mxGetData(value))[0]) == BSON_OK);
125        default:
126            mexPrintf("BsonBuffer:append - Unhandled type: %s\n", mxGetClassName(value));
127            return 0;
128        }
129    }
130    success = (bson_append_start_array(_b, name) == BSON_OK);
131    odims = mxGetDimensions(value);
132    ndims = mxGetNumberOfDimensions(value);
133    memcpy(dims, odims, ndims*sizeof(mwSize));
134    if (ndims > 1)
135        reverse(dims, ndims);
136    i = ndims;
137    /* calculate offset to multiply each dimension's index by */
138    j = 1;
139    do {
140        i--;
141        sizes[i] = j;
142        j *= dims[i];
143    } while (i > 0);
144    if (ndims == 2 && dims[1] == 1)
145        ndims--;  /* 1 dimensional row vector */
146    if (ndims > 1) {
147        /* reverse row and columns */
148        j = dims[ndims-1];
149        dims[ndims-1] = dims[ndims-2];
150        dims[ndims-2] = j;
151        j = sizes[ndims-1];
152        sizes[ndims-1] = sizes[ndims-2];
153        sizes[ndims-2] = j;
154    }
155    memset(ijk, 0, ndims * sizeof(mwSize));
156    while (success && depth >= 0) {
157        if (ijk[depth] < dims[depth]) {
158            const char* num = numstr((int)(ijk[depth]++));
159            if (depth < (int)(ndims - 1)) {
160                depth++;
161                success = (bson_append_start_array(_b, num) == BSON_OK);
162            }
163            else {
164                i = 0;
165                for (j = 0; j < ndims; j++)
166                    i += (ijk[j]-1) * sizes[j];
167                switch (cls) {
168                case mxLOGICAL_CLASS:
169                    success = (bson_append_bool(_b, num, ((char*)mxGetData(value))[i]) == BSON_OK);
170                    break;
171                case mxDOUBLE_CLASS:
172                    if (mxIsComplex(value))
173                        success = mongo_bson_buffer_append_complex(b, num, mxGetPr(value)[i], mxGetPi(value)[i]);
174                    else
175                        success = (bson_append_double(_b, num, mxGetPr(value)[i]) == BSON_OK);
176                    break;
177                case mxSINGLE_CLASS:
178                    success = (bson_append_double(_b, num, ((float*)mxGetData(value))[i]) == BSON_OK);
179                    break;
180                case mxINT8_CLASS:
181                    success = (bson_append_int(_b, num, ((signed char*)mxGetData(value))[i]) == BSON_OK);
182                    break;
183                case mxUINT8_CLASS:
184                    success = (bson_append_int(_b, num, ((unsigned char*)mxGetData(value))[i]) == BSON_OK);
185                    break;
186                case mxINT16_CLASS:
187                    success = (bson_append_int(_b, num, ((short*)mxGetData(value))[i]) == BSON_OK);
188                    break;
189                case mxUINT16_CLASS:
190                    success = (bson_append_int(_b, num, ((unsigned short*)mxGetData(value))[i]) == BSON_OK);
191                    break;
192                case mxINT32_CLASS:
193                    success = (bson_append_int(_b, num, ((int*)mxGetData(value))[i]) == BSON_OK);
194                    break;
195                case mxUINT32_CLASS:
196                    success = (bson_append_int(_b, num, ((unsigned int*)mxGetData(value))[i]) == BSON_OK);
197                    break;
198                case mxINT64_CLASS: ;
199                case mxUINT64_CLASS:
200                    success = (bson_append_long(_b, num, ((int64_t*)mxGetData(value))[i]) == BSON_OK);
201                    break;
202                default:
203                    mexPrintf("BsonBuffer:append - Unhandled type: %s\n", mxGetClassName(value));
204                    return 0;
205                }
206            }
207        }
208        else {
209            ijk[depth] = 0;
210            success = (bson_append_finish_object(_b) == BSON_OK);
211            depth--;
212        }
213    }
214    return success;
215}
216
217
218EXPORT int mongo_bson_buffer_append_string(struct bson_buffer* b, char* name, char* value) {
219    return (bson_append_string((bson*) b, name, value) == BSON_OK);
220}
221
222
223EXPORT int mongo_bson_buffer_append_binary(struct bson_buffer* b, char* name, int type, void* value, int len) {
224    return (bson_append_binary((bson*) b, name, type, (const char*) value, len) == BSON_OK);
225}
226
227
228EXPORT int mongo_bson_buffer_append_oid(struct bson_buffer* b, char* name, void* value) {
229    return (bson_append_oid((bson*) b, name, (bson_oid_t*) value) == BSON_OK);
230}
231
232
233EXPORT int  mongo_bson_buffer_append_date(struct bson_buffer* b, char *name, mxArray* value) {
234    size_t numel = mxGetNumberOfElements(value);
235    mxClassID cls = mxGetClassID(value);
236    bson* _b = (bson*)b;
237    mwSize i, j;
238    mwSize dims[MAXDIM];
239    mwSize ijk[MAXDIM];
240    mwSize sizes[MAXDIM];
241    mwSize ndims;
242    const mwSize *odims; /* original dimensions */
243    char* p;
244    int depth = 0;
245    int success;
246    if (cls != mxDOUBLE_CLASS) {
247        mexPrintf("Only double values are permitted in appendDate\n");
248        return 0;
249    }
250    if (numel == 1)
251        return (bson_append_date(_b, name, (bson_date_t)((mxGetPr(value)[0] - 719529) * (1000 * 60 * 60 * 24)) ) == BSON_OK);
252    success = (bson_append_start_array(_b, name) == BSON_OK);
253    odims = mxGetDimensions(value);
254    ndims = mxGetNumberOfDimensions(value);
255    memcpy(dims, odims, ndims*sizeof(mwSize));
256    if (ndims > 1)
257        reverse(dims, ndims);
258    i = ndims;
259    j = 1;
260    /* calculate offset to multiply each dimension's index by */
261    do {
262        i--;
263        sizes[i] = j;
264        j *= dims[i];
265    } while (i > 0);
266    if (ndims == 2 && dims[1] == 1)
267        ndims--;
268    if (ndims > 1) {
269        /* reverse row and columns */
270        j = dims[ndims-1];
271        dims[ndims-1] = dims[ndims-2];
272        dims[ndims-2] = j;
273        j = sizes[ndims-1];
274        sizes[ndims-1] = sizes[ndims-2];
275        sizes[ndims-2] = j;
276    }
277    memset(ijk, 0, ndims * sizeof(mwSize));
278    p = (char*)mxGetData(value);
279    while (success && depth >= 0) {
280        if (ijk[depth] < dims[depth]) {
281            const char* num = numstr((int)(ijk[depth]++));
282            if (depth < (int)(ndims - 1)) {
283                depth++;
284                success = (bson_append_start_array(_b, num) == BSON_OK);
285            }
286            else {
287                i = 0;
288                for (j = 0; j < ndims; j++)
289                    i += (ijk[j]-1) * sizes[j];
290                success = (bson_append_date(_b, num, (bson_date_t)((mxGetPr(value)[i] - 719529) * (1000 * 60 * 60 * 24)) ) == BSON_OK);
291            }
292        }
293        else {
294            ijk[depth] = 0;
295            success = (bson_append_finish_object(_b) == BSON_OK);
296            depth--;
297        }
298    }
299    return success;
300}
301
302
303EXPORT int  mongo_bson_buffer_append_null(struct bson_buffer* b, char *name) {
304    return (bson_append_null((bson*) b, name) == BSON_OK);
305}
306
307
308EXPORT int  mongo_bson_buffer_append_regex(struct bson_buffer* b, char *name, char* pattern, char* options) {
309    return (bson_append_regex((bson*) b, name, pattern, options) == BSON_OK);
310}
311
312
313EXPORT int  mongo_bson_buffer_append_code(struct bson_buffer* b, char *name, char* value) {
314    return (bson_append_code((bson*) b, name, value) == BSON_OK);
315}
316
317
318EXPORT int  mongo_bson_buffer_append_symbol(struct bson_buffer* b, char *name, char* value) {
319    return (bson_append_symbol((bson*) b, name, value) == BSON_OK);
320}
321
322
323EXPORT int  mongo_bson_buffer_append_codewscope(struct bson_buffer* b, char *name, char* code, struct bson_* scope) {
324    return (bson_append_code_w_scope((bson*) b, name, code, (bson*) scope) == BSON_OK);
325}
326
327
328EXPORT int  mongo_bson_buffer_append_timestamp(struct bson_buffer* b, char *name, int date, int increment) {
329    bson_timestamp_t ts;
330    ts.i = increment;
331    ts.t = date;
332    return (bson_append_timestamp((bson*) b, name, &ts) == BSON_OK);
333
334}
335
336EXPORT int mongo_bson_buffer_start_object(struct bson_buffer* b, char* name) {
337    return (bson_append_start_object((bson*) b, name) == BSON_OK);
338}
339
340
341EXPORT int mongo_bson_buffer_finish_object(struct bson_buffer* b) {
342    return (bson_append_finish_object((bson*) b) == BSON_OK);
343}
344
345
346EXPORT int mongo_bson_buffer_start_array(struct bson_buffer* b, char* name) {
347    return (bson_append_start_array((bson*) b, name) == BSON_OK);
348}
349
350
351EXPORT int  mongo_bson_buffer_append_bson(struct bson_buffer* b, char* name, struct bson_* bs) {
352    return (bson_append_bson((bson*)b, name, (bson*)bs) == BSON_OK);
353}
354
355
356EXPORT void mongo_bson_empty(struct bson_** b) {
357    bson empty;
358    bson* b_ = (bson*)malloc(sizeof(bson));
359    bson_empty(&empty);
360    bson_copy(b_, &empty);
361    *b = (struct bson_*)b_;
362}
363
364
365EXPORT int mongo_bson_size(struct bson_* b) {
366    return bson_size((bson*) b);
367}
368
369
370EXPORT int  mongo_bson_buffer_size(struct bson_buffer* b) {
371    bson* _b = (bson*)b;
372    return (int)(_b->cur - _b->data) + 1;
373}
374
375
376EXPORT void mongo_bson_iterator_create(struct bson_* b, struct bson_iterator_** i) {
377    bson_iterator* _i = (bson_iterator*)malloc(sizeof(bson_iterator));
378    bson_iterator_init(_i, (bson*) b);
379    *i = (struct bson_iterator_*)_i;
380}
381
382
383EXPORT int mongo_bson_find(struct bson_* b, char* name, struct bson_iterator_** i) {
384    bson* _b = (bson*)b;
385    bson sub;
386    bson_iterator iter;
387    const char* next = name;
388    do {
389        int t;
390        char *p;
391        char prefix[2048];
392        int len;
393        if (bson_find(&iter, _b, next) != BSON_EOO) {
394            bson_iterator* _i = (bson_iterator*)malloc(sizeof(bson_iterator));
395            *_i = iter;
396            *i = (struct bson_iterator_*)_i;
397            return 1;
398        }
399        p = strchr((char*)next, '.');
400        if (!p)
401            return 0;
402        len = (int)(p - next);
403        strncpy(prefix, next, len);
404        prefix[len] = '\0';
405        if ((t = bson_find(&iter, _b, prefix)) == BSON_EOO)
406            return 0;
407        if (t == BSON_ARRAY || t == BSON_OBJECT) {
408            bson_iterator_subobject(&iter, &sub);
409            _b = &sub;
410            next = p + 1;
411        }
412        else
413            return 0;
414    }
415    while (1);
416    /* never gets here */
417    return 0;
418}
419
420
421EXPORT void mongo_bson_iterator_free(struct bson_iterator_* i) {
422    free(i);
423}
424
425
426EXPORT int  mongo_bson_iterator_type(struct bson_iterator_* i) {
427    return bson_iterator_type((bson_iterator*) i);
428}
429
430
431EXPORT int  mongo_bson_iterator_next(struct bson_iterator_* i) {
432    return bson_iterator_next((bson_iterator*) i);
433}
434
435
436EXPORT const char* mongo_bson_iterator_key(struct bson_iterator_* i) {
437    return bson_iterator_key((bson_iterator*) i);
438}
439
440
441EXPORT void mongo_bson_subiterator(struct bson_iterator_* i, struct bson_iterator_** si) {
442    bson_iterator* sub = (bson_iterator*)malloc(sizeof(bson_iterator));
443    bson_iterator_subiterator((bson_iterator*)i, sub);
444    *si = (struct bson_iterator_*)sub;
445}
446
447
448EXPORT int mongo_bson_iterator_int(struct bson_iterator_* i) {
449    return bson_iterator_int((bson_iterator*)i);
450}
451
452
453EXPORT mxint64 mongo_bson_iterator_long(struct bson_iterator_* i) {
454    return bson_iterator_long((bson_iterator*)i);
455}
456
457
458EXPORT double mongo_bson_iterator_double(struct bson_iterator_* i) {
459    return bson_iterator_double((bson_iterator*)i);
460}
461
462
463EXPORT const char* mongo_bson_iterator_string(struct bson_iterator_* i) {
464    return bson_iterator_string((bson_iterator*)i);
465}
466
467
468EXPORT int mongo_bson_iterator_bin_type(struct bson_iterator_* i) {
469    return bson_iterator_bin_type((bson_iterator*)i);
470}
471
472
473EXPORT int mongo_bson_iterator_bin_len(struct bson_iterator_* i) {
474    return bson_iterator_bin_len((bson_iterator*)i);
475}
476
477
478EXPORT void mongo_bson_iterator_bin_value(struct bson_iterator_* i, void* v) {
479    int len = bson_iterator_bin_len((bson_iterator*)i);
480    memcpy(v, bson_iterator_bin_data((bson_iterator*)i), len);
481}
482
483
484EXPORT void mongo_bson_oid_gen(void* oid) {
485    bson_oid_gen((bson_oid_t*) oid);
486}
487
488
489EXPORT const char* mongo_bson_oid_to_string(void* oid) {
490    static char s[25];
491    bson_oid_to_string((bson_oid_t*) oid, s);
492    return s;
493}
494
495
496EXPORT void mongo_bson_oid_from_string(char* s, void* oid) {
497    bson_oid_from_string((bson_oid_t*) oid, s);
498}
499
500
501EXPORT void mongo_bson_iterator_oid(struct bson_iterator_* i, void* oid) {
502    memcpy(oid, bson_iterator_oid((bson_iterator*) i), 12);
503}
504
505
506EXPORT int mongo_bson_iterator_bool(struct bson_iterator_* i) {
507    return (bson_iterator_bool((bson_iterator*) i) != 0);
508}
509
510
511EXPORT mxint64  mongo_bson_iterator_date(struct bson_iterator_* i) {
512    return bson_iterator_date((bson_iterator*) i);
513}
514
515
516EXPORT const char* mongo_bson_iterator_regex(struct bson_iterator_* i) {
517    return bson_iterator_regex((bson_iterator*) i);
518}
519
520
521EXPORT const char* mongo_bson_iterator_regex_opts(struct bson_iterator_* i) {
522    return bson_iterator_regex_opts((bson_iterator*) i);
523}
524
525
526EXPORT const char* mongo_bson_iterator_code(struct bson_iterator_* i) {
527    return bson_iterator_code((bson_iterator*) i);
528}
529
530
531EXPORT void mongo_bson_iterator_code_scope(struct bson_iterator_* i, struct bson_buffer** b) {
532    bson* _b = (bson*)malloc(sizeof(bson));
533    bson scope;
534    bson_iterator_code_scope((bson_iterator*) i, &scope);
535    bson_copy(_b, &scope);
536    *b = (struct bson_buffer*)_b;
537}
538
539
540EXPORT int mongo_bson_iterator_timestamp(struct bson_iterator_* i, int* increment) {
541    bson_timestamp_t ts = bson_iterator_timestamp((bson_iterator*) i);
542    *increment = ts.i;
543    return ts.t;
544}
545
546
547struct Rcomplex {
548    double r;
549    double i;
550};
551
552
553int _iterator_getComplex(bson_iterator* iter, struct Rcomplex* z) {
554    bson_iterator sub;
555    if (bson_iterator_type(iter) != BSON_OBJECT)
556        return 0;
557    bson_iterator_subiterator(iter, &sub);
558    if (bson_iterator_next(&sub) != BSON_DOUBLE || strcmp(bson_iterator_key(&sub), "r") != 0)
559        return 0;
560    z->r = bson_iterator_double(&sub);
561    if (bson_iterator_next(&sub) != BSON_DOUBLE || strcmp(bson_iterator_key(&sub), "i") != 0)
562        return 0;
563    z->i = bson_iterator_double(&sub);
564    if (bson_iterator_next(&sub) != BSON_EOO)
565        return 0;
566    return 1;
567}
568
569
570EXPORT mxArray* mongo_bson_array_value(struct bson_iterator_* i) {
571    bson_type sub_type, common_type;
572    struct Rcomplex z;
573    bson_iterator sub[MAXDIM+1];
574    mwSize ndims = 0;
575    mwSize count[MAXDIM+1];
576    mwSize dim[MAXDIM+1];
577    mwSize* mdim = dim + 1;
578    mwSize sizes[MAXDIM+1];
579    mxArray* ret;
580    mwSize depth, j, len, ofs;
581    int isRow = 0;
582    sub[0] = *(bson_iterator*)i;
583    /* count number of dimensions.  This is equal to the number of
584       consecutive array markers in the BSON */
585    do {
586        bson_iterator_subiterator(&sub[ndims], &sub[ndims+1]);
587        if (++ndims > MAXDIM) {
588            mexPrintf("Max dimensions (%d) exceeded. Use an iterator\n", MAXDIM);
589            return 0;
590        }
591        sub_type = bson_iterator_next(&sub[ndims]);
592    }
593    while (sub_type == BSON_ARRAY);
594
595    /* get the first data value's type */
596    switch (common_type = sub_type) {
597    case BSON_INT: ;
598    case BSON_LONG: ;
599    case BSON_DOUBLE: ;
600    case BSON_BOOL: ;
601    case BSON_DATE:
602        break;
603    case BSON_STRING: 
604        if (ndims > 1) {
605            mexPrintf("Unable to convert array - Only 1 dimenisonal arrays of strings supported");
606            return 0;
607        }
608        break;
609    case BSON_OBJECT:
610        if (_iterator_getComplex(&sub[ndims], &z))
611            break;
612        /* fall thru to default */
613    default:
614        /* including empty array */
615        mexPrintf("Unable to convert array - invalid type (%d)", common_type);
616        return 0;
617    }
618
619    /* initial lowest level count */
620    for (j = 0; j <= ndims; j++)
621        count[j] = 1;
622    while ((sub_type = bson_iterator_next(&sub[ndims])) != BSON_EOO) {
623        if (sub_type != common_type) {
624            mexPrintf("Unable to convert array - inconsistent types");
625            return 0;
626        }
627        if (sub_type == BSON_OBJECT && !_iterator_getComplex(&sub[ndims], &z)) {
628            mexPrintf("Unable to convert array - invalid subobject");
629            return 0;
630        }
631        ++count[ndims];
632    }
633
634    /* step through rest of array -- checking common type and dimensions */
635    memset(dim, 0, sizeof(dim));
636    depth = ndims;
637    while (depth >= 1) {
638        sub_type = bson_iterator_next(&sub[depth]);
639        switch (sub_type) {
640        case BSON_EOO:
641            if (dim[depth] == 0)
642                dim[depth] = count[depth];
643            else if (dim[depth] != count[depth]) {
644                mexPrintf("Unable to convert array - inconsistent dimensions");
645                return 0;
646            }
647            depth--;
648            break;
649        case BSON_ARRAY:
650            count[depth]++;
651            bson_iterator_subiterator(&sub[depth], &sub[depth+1]);
652            if (++depth > ndims) {
653                mexPrintf("Unable to convert array - inconsistent dimensions");
654                return 0;
655            }
656            count[depth] = 0;
657            break;
658        case BSON_INT: ;
659        case BSON_LONG: ;
660        case BSON_DOUBLE: ;
661        case BSON_STRING: ; 
662        case BSON_BOOL: ;
663        case BSON_DATE: ;
664GotEl:  {
665            if (depth != ndims || sub_type != common_type) {
666                mexPrintf("Unable to convert array - inconsistent dimensions or types");
667                return 0;
668            }
669            count[depth]++;
670            break;
671        }
672        case BSON_OBJECT:
673            if (_iterator_getComplex(&sub[depth], &z))
674                goto GotEl;
675            /* fall thru to default */
676        default:
677            mexPrintf("Unable to convert array - invalid type (%d)", sub_type);
678            return 0;
679        }
680    }
681
682    if (ndims > 1) {
683        j = dim[ndims];            /* reverse row and column */
684        dim[ndims] = dim[ndims-1];
685        dim[ndims-1] = j;
686    }
687    /* calculate offset each dimension multiplies it's index by */
688    len = 1;
689    for (depth = ndims; depth > 0; depth--) {
690        sizes[depth] = len;
691        len *= dim[depth];
692    }
693
694    if (ndims > 1) {
695        reverse(mdim, ndims); /* reverse dimensions for Matlab */
696        j = sizes[ndims];
697        sizes[ndims] = sizes[ndims-1];
698        sizes[ndims-1] = j;
699    } else {
700        isRow = 1;
701        ndims = 2;
702        mdim[1] = mdim[0];
703        mdim[0] = 1;
704    }
705/*
706    for (j = 1; j <= ndims; j++)
707        mexPrintf("%d ", dim[j]);
708    mexPrintf("\n");
709
710    for (j = 1; j <= ndims; j++)
711        mexPrintf("%d ", sizes[j]);
712    mexPrintf("\n");
713*/
714    switch (common_type) {
715    case BSON_INT:    ret = mxCreateNumericArray(ndims, mdim, mxINT32_CLASS, mxREAL); break;
716    case BSON_LONG:   ret = mxCreateNumericArray(ndims, mdim, mxINT64_CLASS, mxREAL); break;
717    case BSON_DATE:
718    case BSON_DOUBLE: ret = mxCreateNumericArray(ndims, mdim, mxDOUBLE_CLASS, mxREAL); break;
719    case BSON_STRING: ret = mxCreateCellMatrix(len, 1); break;
720    case BSON_BOOL:   ret = mxCreateLogicalArray(ndims, mdim); break;
721    case BSON_OBJECT: ret = mxCreateNumericArray(ndims, mdim, mxDOUBLE_CLASS, mxCOMPLEX); break;
722    default:
723        /* never reaches here */
724        ret = 0;
725    }
726
727    if (isRow)
728        ndims--;
729    /* step through array(s) again, pulling out values */
730    bson_iterator_subiterator(&sub[0], &sub[1]);
731    depth = 1;
732    count[depth] = 0;
733    while (depth >= 1) {
734        sub_type = bson_iterator_next(&sub[depth]);
735        count[depth]++;
736        if (sub_type == BSON_EOO) {
737            depth--;
738        } else if (sub_type == BSON_ARRAY) {
739            bson_iterator_subiterator(&sub[depth], &sub[depth+1]);
740            depth++;
741            count[depth] = 0;
742        } else {
743            ofs = 0;
744            for (j = 1; j <= ndims; j++)
745                ofs += sizes[j] * (count[j] - 1);
746
747            switch (sub_type) {
748                case BSON_INT:
749                    ((int*)mxGetData(ret))[ofs] = bson_iterator_int(&sub[depth]);
750                    break;
751                case BSON_DATE:
752                    mxGetPr(ret)[ofs] = 719529.0 + bson_iterator_date(&sub[depth]) / (1000.0 * 60 * 60 * 24);
753                    break;
754                case BSON_DOUBLE: 
755                    mxGetPr(ret)[ofs] = bson_iterator_double(&sub[depth]);
756                    break;
757                case BSON_LONG:
758                    ((int64_t*)mxGetData(ret))[ofs] = bson_iterator_long(&sub[depth]);
759                    break;
760                case BSON_BOOL: ;
761                    ((mxLogical*)mxGetData(ret))[ofs] = bson_iterator_bool(&sub[depth]);
762                    break;
763                case BSON_OBJECT:
764                    _iterator_getComplex(&sub[depth], &z);
765                    mxGetPr(ret)[ofs] = z.r;
766                    mxGetPi(ret)[ofs] = z.i;
767                    break;
768                case BSON_STRING:
769                    mxSetCell(ret, count[depth]-1, mxCreateString(bson_iterator_string(&sub[depth])));
770                    break;
771                default: ;
772                    /* never reaches here */
773            }
774        }
775    }
776
777    return ret;
778}
779
780