bool zson_next(zson_t *z){ zsnode_t *cz = z->stack + z->stack_index; if(zson_has_error(z)){ return false; }else if(z->stack_index == 0 && !z->started){ z->started = true; _decode(z, cz, z->mem, 0, z->mem_size, false, z->bit64); return !zson_has_error(z); }else if(cz->has_next){ zsnode_t *pz = z->stack + z->stack_index - 1; size_t start = cz->start + cz->size; _decode(z, cz, z->mem, start, pz->size + pz->start - start, pz->type == ZSON_OBJECT, z->bit64 ); cz->has_next = cz->start + cz->size < pz->start + pz->size; return !zson_has_error(z); } return false; }
bool AP_GPS_NMEA::read(void) { int numc; bool parsed = false; numc = _port->available(); while (numc--) { if (_decode(_port->read())) { parsed = true; } } return parsed; }
bool zson_child(zson_t *z){ zsnode_t *pz = z->stack + z->stack_index; if(zson_has_error(z)){ return false; }else if(pz->has_child){ zson_push_node(z); zsnode_t *cz = z->stack + z->stack_index; _decode(z, cz, z->mem, pz->start + pz->content_start, pz->size - pz->content_start, pz->type == ZSON_OBJECT, z->bit64 ); cz->has_next = cz->start + cz->size < pz->start + pz->size; return !zson_has_error(z); } return false; }
static bool _decode( zson_t *zd, zsnode_t *z, const char *src, size_t start, size_t maxsize, bool keyval, bool bit64 ){ memset(z,0,sizeof(zsnode_t)); const char* origin = src; int header = src[start]; int minsize = bit64 ? minsize64[header] : minsize32[header]; int headersize = bit64 ? headersize64[header] : headersize32[header]; size_t size = minsize; z->type = header; z->start = start; z->entity = src; z->has_next = false; z->content_start = headersize; z->content = src + headersize; z->size = minsize; if(header == 0 || header >= ZSON_TYPE_COUNT){ zson_set_error(zd, ZSON_ERROR_INVALID_HEADER, "invalid header"); return false; }else if(minsize > maxsize){ zson_set_error(zd, ZSON_ERROR_INVALID_SIZE, "exceeding parent size"); return false; } src = src+start; switch(header){ case ZSON_NO_ENT: case ZSON_NULL: break; case ZSON_TRUE: z->value.boolean = 1; break; case ZSON_FALSE: z->value.boolean = 0; break; case ZSON_INT8: z->value.int8 = (int8_t)src[1]; break; case ZSON_INT16: z->value.int16 = GET_VAL(src,1,int16_t); break; case ZSON_INT32: z->value.int32 = GET_VAL(src,1,int32_t); break; case ZSON_INT64: z->value.int64 = GET_VAL(src,1,int64_t); break; case ZSON_UINT8: z->value.uint8 = (int8_t)src[1]; break; case ZSON_UINT16: z->value.uint16 = GET_VAL(src,1,uint16_t); break; case ZSON_UINT32: z->value.uint32 = GET_VAL(src,1,uint32_t); break; case ZSON_UINT64: z->value.uint64 = GET_VAL(src,1,uint64_t); break; case ZSON_FLOAT32: z->value.float32 = GET_VAL(src,1,float); break; case ZSON_FLOAT64: z->value.float64 = GET_VAL(src,1,double); break; case ZSON_STRING4: case ZSON_STRING8: case ZSON_STRING12: z->value.string = src + 1; if(src[z->size -1] != 0){ zson_set_error( zd, ZSON_ERROR_RUNAWAY_STRING, "strings must be null terminated"); return false; } break; default: { size = bit64 ? GET_VAL(src,1,uint64_t) : GET_VAL(src,1,uint32_t); z->size = size; if(size > maxsize){ zson_set_error( zd, ZSON_ERROR_INVALID_SIZE, "size exceeds parent size"); return false; }else if( size < minsize){ zson_set_error(zd, ZSON_ERROR_INVALID_SIZE, "size too small"); return false; } if (header == ZSON_STRING){ if(size - headersize <= 0 || src[z->size -1] != 0){ zson_set_error( zd, ZSON_ERROR_RUNAWAY_STRING, "zero length strings must also be null terminated"); return false; } z->value.string = src + headersize; z->length = size - headersize - 1; }else if(header == ZSON_OBJECT || header == ZSON_ARRAY){ z->has_child = size > headersize; }else if(header >= ZSON_ARRAY_INT8 && header <= ZSON_ARRAY_FLOAT64){ if( size == headersize){ z->value.ptr = NULL; z->length = 0; }else{ int padding = subsize[z->type]; padding = padding <= 1 ? 0 : (padding - start % padding) % padding; if( headersize + padding > size){ zson_set_error( zd, ZSON_ERROR_INVALID_PADDING, "padding going outside of entity"); return false; } z->value.ptr = src + headersize + padding; z->length = (z->size - headersize - padding) / subsize[z->type]; z->content_start += padding; } } } } if(keyval){ if(z->type < ZSON_STRING || z->type > ZSON_STRING12){ zson_set_error( zd, ZSON_ERROR_INVALID_KEY, "key value pairs must start with a string" ); return false; } if(!_decode(zd, z, origin, start+size, maxsize-size, false, bit64 )){ return false; } z->key = src + headersize; z->size += size; z->content_start += size; z->start = start; } return z->type; }
int url_parse(struct url *dst, const char *src) { int i, j; int mp; dst->extra_free_me3 = NULL; dst->extra_free_me4 = NULL; /* special case: mailto urls don't have // */ if ((src[0] == 'm' || src[0] == 'M') && (src[1] == 'a' || src[1] == 'A') && (src[2] == 'i' || src[2] == 'I') && (src[3] == 'l' || src[3] == 'L') && (src[4] == 't' || src[4] == 'T') && (src[5] == 'o' || src[5] == 'O') && src[6] == ':') { if (src[7] == '/' || src[8] == '/') return 0; memset(dst,0,sizeof(struct url)); dst->original_url = strdup(src); dst->extra_free_me1 = strdup(src); if (!dst->original_url || !dst->extra_free_me1) abort(); /* OOM */ dst->schema = "mailto"; dst->emailaddr = dst->extra_free_me1+7; i = 7; goto GOT_PATH; /* for ?-string processing */ } /* TODO special case: news urls might not have // */ for (i = 0; src[i]; i++) { if (src[i] >= 'A' && src[i] <= 'Z') continue; if (src[i] >= 'a' && src[i] <= 'z') continue; if (src[i] == ':') { if (src[i+1] == '/' && src[i+2] == '/') { break; } } return 0; /* fail */ } if (!src[i]) return 0; memset(dst,0,sizeof(struct url)); dst->original_url = strdup(src); dst->extra_free_me1 = strdup(src); dst->extra_free_me2 = strdup(src); if (!dst->original_url || !dst->extra_free_me1 || !dst->extra_free_me2) abort(); /* OOM */ dst->schema = dst->extra_free_me1; dst->extra_free_me1[i] = '\0'; /* : from above */ dst->port = -1; i += 3; for (j = i; src[j]; j++) { if (src[j] == ':') { /* okay, that was _probably_ a username */ dst->username = dst->extra_free_me1+i; dst->extra_free_me1[j] = '\0'; /* : from above */ j++; mp = 1; for (i = j; src[j]; j++) { if (mp) { /* maybe port */ if (src[j] >= '0' && src[j] <= '9') { continue; } else if (src[j] == '/') { /* that was hostname:port! */ dst->hostname = dst->username; dst->username = NULL; dst->path = dst->extra_free_me2 + j; dst->extra_free_me1[j] = '\0'; dst->port = atoi(dst->extra_free_me1+i); i = j; goto GOT_PATH; } mp = 0; } if (src[j] == '@') { dst->password = dst->extra_free_me1+i; dst->extra_free_me1[j] = '\0'; /* : from above */ j++; dst->hostname = dst->extra_free_me1+j; i = j; goto GOT_HOSTNAME; } else if (src[j] == '/' || src[j] == ':') { goto FAIL; } } goto FAIL; } else if (src[j] == '@') { /* okay, that was a username */ dst->username = dst->extra_free_me1+i; dst->extra_free_me1[j] = '\0'; /* : from above */ j++; dst->hostname = dst->extra_free_me1+j; i = j; goto GOT_HOSTNAME; } else if (src[j] == '/') { /* hostname */ dst->hostname = dst->extra_free_me1+i; dst->extra_free_me1[j] = '\0'; /* : from above */ dst->path = dst->extra_free_me2 + j; i = j; goto GOT_PATH; } } /* hostname _only; no path */ _decode(dst->username); _decode(dst->password); _decode(dst->hostname); dst->path = "/"; dst->hostname = dst->extra_free_me1 + i; goto FINISH; GOT_HOSTNAME: /* i points to the first word of the hostname */ for (j = i; src[j]; j++) { if (src[j] == ':') { /* port */ dst->extra_free_me1[j] = '\0'; j++; for (i = j; src[j]; j++) { if (src[j] >= '0' && src[j] <= '9') continue; if (src[j] != '/') goto FAIL; dst->extra_free_me1[j] = '\0'; dst->port = atoi(dst->extra_free_me1+i); j++; i = j; dst->path = dst->extra_free_me2 + j; goto GOT_PATH; } /* hostname:port */ dst->port = atoi(dst->extra_free_me1+i); dst->path = "/"; goto GOT_PATH; } else if (src[j] == '/') { dst->extra_free_me1[j] = '\0'; dst->path = dst->extra_free_me2 + j; i = j; goto GOT_PATH; } else if (src[j] == '@') { goto FAIL; } } _decode(dst->username); _decode(dst->password); _decode(dst->hostname); dst->path = "/"; goto FINISH; GOT_PATH: _decode(dst->username); _decode(dst->password); _decode(dst->hostname); /* i points to the first word of the path */ for (j = i; src[j]; j++) { if (src[j] == '?') { dst->querystr = dst->extra_free_me2+(j+1); dst->extra_free_me2[j] = '\0'; j++; for (i = j; src[j]; j++) { if (src[j] == '#') { dst->fragment = dst->extra_free_me2+(j+1); dst->extra_free_me2[j] = '\0'; _decode(dst->fragment); goto FINISH; } } break; } else if (src[j] == '#') { dst->fragment = dst->extra_free_me2+(j+1); dst->extra_free_me2[j] = '\0'; _decode(dst->fragment); goto FINISH; } } FINISH: for (i = 0; dst->schema[i]; i++) dst->schema[i] = tolower(((unsigned)dst->schema[i])); if (!strcmp(dst->schema, "file")) { if (dst->hostname && !dst->hostname[0]) dst->hostname = NULL; } else if (!dst->hostname || !dst->hostname[0]) { if (!strcmp(dst->schema, "news") || !strcmp(dst->schema, "mailto")) { /* no valid thing as a hostname */ } else { /* hostname required */ goto FAIL; } } if (dst->port == -1) { if (!strcmp(dst->schema, "http")) { dst->port = 80; } else if (!strcmp(dst->schema, "https")) { dst->port = 443; } else if (!strcmp(dst->schema, "ftp")) { dst->port = 21; } else if (!strcmp(dst->schema, "gopher")) { dst->port = 70; } else if (!strcmp(dst->schema, "mailto")) { /* NA */ } else if (!strcmp(dst->schema, "news")) { /* NA */ } else if (!strcmp(dst->schema, "file")) { /* NA */ } else if (!strcmp(dst->schema, "nntp")) { dst->port = 119; } else if (!strcmp(dst->schema, "ssh")) { dst->port = 22; } else if (!strcmp(dst->schema, "sftp")) { dst->port = 22; } else if (!strcmp(dst->schema, "ssh1")) { dst->port = 22; } else if (!strcmp(dst->schema, "ssh2")) { dst->port = 22; } } return 1; FAIL: free(dst->original_url); free(dst->extra_free_me1); free(dst->extra_free_me2); free(dst->extra_free_me3); free(dst->extra_free_me4); memset(dst,0,sizeof(struct url)); return 0; }