add save mac and ota upto v1.1.11
This commit is contained in:
parent
8a6818d639
commit
e2513fd0b0
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,7 +3,6 @@
|
||||
.sys_tags
|
||||
.tags
|
||||
build/
|
||||
json-c/
|
||||
output/
|
||||
*.swp
|
||||
|
||||
|
||||
11
cp.sh
11
cp.sh
@ -1,7 +1,10 @@
|
||||
#sshpass -p "&Over#B0Ost!" scp ./start.sh root@10.10.10.101:/root/
|
||||
sshpass -p "&Over#B0Ost!" scp ./output/bin/tx_server root@10.10.10.235:/root/
|
||||
#sshpass -p "&Over#B0Ost!" scp ./output/bin/tx_server root@10.10.12.2:/root/
|
||||
#sshpass -p "&Over#B0Ost!" scp ./output/bin/tx_server root@10.10.10.101:/home/linaro/
|
||||
#sshpass -p "PddloTSecPwdOnly!" scp ./output/bin/tx_server root@192.168.0.148:/home/linaro/
|
||||
#sshpass -p "PddloTSecPwdOnly!" scp ./output/bin/tx_server root@10.10.10.132:/root/
|
||||
#sshpass -p "PddloTSecPwdOnly!" scp ./start.sh root@10.10.10.225:/root/
|
||||
#sshpass -p "PddloTSecPwdOnly!" scp ./start.sh root@10.10.10.132:/root/
|
||||
#sshpass -p "TxApPwd#2025!" scp ./output/bin/tx_server root@10.10.12.2:/root
|
||||
#sshpass -p "TxApPwd#2025!" scp ./*.zip root@10.10.12.4:/root/ota
|
||||
sshpass -p "TxApPwd#2025!" scp ./tx_server_v1.1.10 root@10.10.12.2:/root
|
||||
#sshpass -p "TxApPwd#2025!" scp tx_ota/*.bin root@10.10.12.4:/root/ota
|
||||
#sshpass -p "PddloTSecPwdOnly!" scp ./output/bin/tx_server root@10.10.12.4:/root/
|
||||
#sshpass -p "PddloTSecPwdOnly!" scp tx_ota/*.bin root@10.10.12.6:/root/ota
|
||||
|
||||
146
json-c/arraylist.c
Normal file
146
json-c/arraylist.c
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* $Id: arraylist.c,v 1.4 2006/01/26 02:16:28 mclark Exp $
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||
* Michael Clark <michael@metaparadigm.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
#endif /* STDC_HEADERS */
|
||||
|
||||
#if defined(HAVE_STRINGS_H) && !defined(_STRING_H) && !defined(__USE_BSD)
|
||||
# include <strings.h>
|
||||
#endif /* HAVE_STRINGS_H */
|
||||
|
||||
#ifndef SIZE_T_MAX
|
||||
#if SIZEOF_SIZE_T == SIZEOF_INT
|
||||
#define SIZE_T_MAX UINT_MAX
|
||||
#elif SIZEOF_SIZE_T == SIZEOF_LONG
|
||||
#define SIZE_T_MAX ULONG_MAX
|
||||
#elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
|
||||
#define SIZE_T_MAX ULLONG_MAX
|
||||
#else
|
||||
#error Unable to determine size of size_t
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "arraylist.h"
|
||||
|
||||
struct array_list*
|
||||
array_list_new(array_list_free_fn *free_fn)
|
||||
{
|
||||
struct array_list *arr;
|
||||
|
||||
arr = (struct array_list*)calloc(1, sizeof(struct array_list));
|
||||
if(!arr) return NULL;
|
||||
arr->size = ARRAY_LIST_DEFAULT_SIZE;
|
||||
arr->length = 0;
|
||||
arr->free_fn = free_fn;
|
||||
if(!(arr->array = (void**)calloc(sizeof(void*), arr->size))) {
|
||||
free(arr);
|
||||
return NULL;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
extern void
|
||||
array_list_free(struct array_list *arr)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < arr->length; i++)
|
||||
if(arr->array[i]) arr->free_fn(arr->array[i]);
|
||||
free(arr->array);
|
||||
free(arr);
|
||||
}
|
||||
|
||||
void*
|
||||
array_list_get_idx(struct array_list *arr, size_t i)
|
||||
{
|
||||
if(i >= arr->length) return NULL;
|
||||
return arr->array[i];
|
||||
}
|
||||
|
||||
static int array_list_expand_internal(struct array_list *arr, size_t max)
|
||||
{
|
||||
void *t;
|
||||
size_t new_size;
|
||||
|
||||
if(max < arr->size) return 0;
|
||||
/* Avoid undefined behaviour on size_t overflow */
|
||||
if( arr->size >= SIZE_T_MAX / 2 )
|
||||
new_size = max;
|
||||
else
|
||||
{
|
||||
new_size = arr->size << 1;
|
||||
if (new_size < max)
|
||||
new_size = max;
|
||||
}
|
||||
if (new_size > (~((size_t)0)) / sizeof(void*)) return -1;
|
||||
if (!(t = realloc(arr->array, new_size*sizeof(void*)))) return -1;
|
||||
arr->array = (void**)t;
|
||||
(void)memset(arr->array + arr->size, 0, (new_size-arr->size)*sizeof(void*));
|
||||
arr->size = new_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
array_list_put_idx(struct array_list *arr, size_t idx, void *data)
|
||||
{
|
||||
if (idx > SIZE_T_MAX - 1 ) return -1;
|
||||
if(array_list_expand_internal(arr, idx+1)) return -1;
|
||||
if(idx < arr->length && arr->array[idx])
|
||||
arr->free_fn(arr->array[idx]);
|
||||
arr->array[idx] = data;
|
||||
if(arr->length <= idx) arr->length = idx + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
array_list_add(struct array_list *arr, void *data)
|
||||
{
|
||||
return array_list_put_idx(arr, arr->length, data);
|
||||
}
|
||||
|
||||
void
|
||||
array_list_sort(struct array_list *arr, int(*sort_fn)(const void *, const void *))
|
||||
{
|
||||
qsort(arr->array, arr->length, sizeof(arr->array[0]), sort_fn);
|
||||
}
|
||||
|
||||
void* array_list_bsearch(const void **key, struct array_list *arr,
|
||||
int (*sort_fn)(const void *, const void *))
|
||||
{
|
||||
return bsearch(key, arr->array, arr->length, sizeof(arr->array[0]),
|
||||
sort_fn);
|
||||
}
|
||||
|
||||
size_t
|
||||
array_list_length(struct array_list *arr)
|
||||
{
|
||||
return arr->length;
|
||||
}
|
||||
|
||||
int
|
||||
array_list_del_idx( struct array_list *arr, size_t idx, size_t count )
|
||||
{
|
||||
size_t i, stop;
|
||||
|
||||
stop = idx + count;
|
||||
if ( idx >= arr->length || stop > arr->length ) return -1;
|
||||
for ( i = idx; i < stop; ++i ) {
|
||||
if ( arr->array[i] ) arr->free_fn( arr->array[i] );
|
||||
}
|
||||
memmove( arr->array + idx, arr->array + stop, (arr->length - stop) * sizeof(void*) );
|
||||
arr->length -= count;
|
||||
return 0;
|
||||
}
|
||||
70
json-c/arraylist.h
Normal file
70
json-c/arraylist.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* $Id: arraylist.h,v 1.4 2006/01/26 02:16:28 mclark Exp $
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||
* Michael Clark <michael@metaparadigm.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Internal methods for working with json_type_array objects.
|
||||
* Although this is exposed by the json_object_get_array() method,
|
||||
* it is not recommended for direct use.
|
||||
*/
|
||||
#ifndef _arraylist_h_
|
||||
#define _arraylist_h_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ARRAY_LIST_DEFAULT_SIZE 32
|
||||
|
||||
typedef void (array_list_free_fn) (void *data);
|
||||
|
||||
struct array_list
|
||||
{
|
||||
void **array;
|
||||
size_t length;
|
||||
size_t size;
|
||||
array_list_free_fn *free_fn;
|
||||
};
|
||||
typedef struct array_list array_list;
|
||||
|
||||
extern struct array_list*
|
||||
array_list_new(array_list_free_fn *free_fn);
|
||||
|
||||
extern void
|
||||
array_list_free(struct array_list *al);
|
||||
|
||||
extern void*
|
||||
array_list_get_idx(struct array_list *al, size_t i);
|
||||
|
||||
extern int
|
||||
array_list_put_idx(struct array_list *al, size_t i, void *data);
|
||||
|
||||
extern int
|
||||
array_list_add(struct array_list *al, void *data);
|
||||
|
||||
extern size_t
|
||||
array_list_length(struct array_list *al);
|
||||
|
||||
extern void
|
||||
array_list_sort(struct array_list *arr, int(*compar)(const void *, const void *));
|
||||
|
||||
extern void* array_list_bsearch(const void **key,
|
||||
struct array_list *arr,
|
||||
int (*sort_fn)(const void *, const void *));
|
||||
|
||||
extern int
|
||||
array_list_del_idx(struct array_list *arr, size_t idx, size_t count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
36
json-c/bits.h
Normal file
36
json-c/bits.h
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Do not use, only contains deprecated defines.
|
||||
* @deprecated Use json_util.h instead.
|
||||
*
|
||||
* $Id: bits.h,v 1.10 2006/01/30 23:07:57 mclark Exp $
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||
* Michael Clark <michael@metaparadigm.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _bits_h_
|
||||
#define _bits_h_
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
#define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
#define error_ptr(error) ((void*)error)
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
#define error_description(error) (json_tokener_get_error(error))
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
#define is_error(ptr) (ptr == NULL)
|
||||
|
||||
#endif
|
||||
199
json-c/config.h
Normal file
199
json-c/config.h
Normal file
@ -0,0 +1,199 @@
|
||||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Enable RDRAND Hardware RNG Hash Seed */
|
||||
/* #undef ENABLE_RDRAND */
|
||||
|
||||
/* Enable partial threading support */
|
||||
#define ENABLE_THREADING 1
|
||||
|
||||
/* Define if .gnu.warning accepts long strings. */
|
||||
/* #undef HAS_GNU_WARNING_LONG */
|
||||
|
||||
/* Has atomic builtins */
|
||||
#define HAVE_ATOMIC_BUILTINS 1
|
||||
|
||||
/* Define to 1 if you have the declaration of `INFINITY', and to 0 if you
|
||||
don't. */
|
||||
#define HAVE_DECL_INFINITY 1
|
||||
|
||||
/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't.
|
||||
*/
|
||||
#define HAVE_DECL_ISINF 1
|
||||
|
||||
/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't.
|
||||
*/
|
||||
#define HAVE_DECL_ISNAN 1
|
||||
|
||||
/* Define to 1 if you have the declaration of `nan', and to 0 if you don't. */
|
||||
#define HAVE_DECL_NAN 1
|
||||
|
||||
/* Define to 1 if you have the declaration of `_finite', and to 0 if you
|
||||
don't. */
|
||||
#define HAVE_DECL__FINITE 0
|
||||
|
||||
/* Define to 1 if you have the declaration of `_isnan', and to 0 if you don't.
|
||||
*/
|
||||
#define HAVE_DECL__ISNAN 0
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
|
||||
/* #undef HAVE_DOPRNT */
|
||||
|
||||
/* Define to 1 if you have the <endian.h> header file. */
|
||||
#define HAVE_ENDIAN_H 1
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#define HAVE_FCNTL_H 1
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#define HAVE_LIMITS_H 1
|
||||
|
||||
/* Define to 1 if you have the <locale.h> header file. */
|
||||
#define HAVE_LOCALE_H 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the `open' function. */
|
||||
#define HAVE_OPEN 1
|
||||
|
||||
/* Define to 1 if you have the `realloc' function. */
|
||||
#define HAVE_REALLOC 1
|
||||
|
||||
/* Define to 1 if you have the `setlocale' function. */
|
||||
#define HAVE_SETLOCALE 1
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#define HAVE_SNPRINTF 1
|
||||
|
||||
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||
#define HAVE_STDARG_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the `strcasecmp' function. */
|
||||
#define HAVE_STRCASECMP 1
|
||||
|
||||
/* Define to 1 if you have the `strdup' function. */
|
||||
#define HAVE_STRDUP 1
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#define HAVE_STRERROR 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the `strncasecmp' function. */
|
||||
#define HAVE_STRNCASECMP 1
|
||||
|
||||
/* Define to 1 if you have the <syslog.h> header file. */
|
||||
#define HAVE_SYSLOG_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/cdefs.h> header file. */
|
||||
#define HAVE_SYS_CDEFS_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#define HAVE_SYS_PARAM_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you have the `uselocale' function. */
|
||||
#define HAVE_USELOCALE 1
|
||||
|
||||
/* Define to 1 if you have the `vasprintf' function. */
|
||||
#define HAVE_VASPRINTF 1
|
||||
|
||||
/* Define to 1 if you have the `vprintf' function. */
|
||||
#define HAVE_VPRINTF 1
|
||||
|
||||
/* Define to 1 if you have the `vsnprintf' function. */
|
||||
#define HAVE_VSNPRINTF 1
|
||||
|
||||
/* Define to 1 if you have the `vsyslog' function. */
|
||||
#define HAVE_VSYSLOG 1
|
||||
|
||||
/* Define to 1 if you have the <xlocale.h> header file. */
|
||||
/* #undef HAVE_XLOCALE_H */
|
||||
|
||||
/* Have __thread */
|
||||
#define HAVE___THREAD 1
|
||||
|
||||
/* Public define for json_inttypes.h */
|
||||
#define JSON_C_HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "json-c"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "json-c@googlegroups.com"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "json-c"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "json-c 0.13.1"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "json-c"
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "0.13.1"
|
||||
|
||||
/* The number of bytes in type int */
|
||||
#define SIZEOF_INT 4
|
||||
|
||||
/* The number of bytes in type int64_t */
|
||||
#define SIZEOF_INT64_T 8
|
||||
|
||||
/* The number of bytes in type long */
|
||||
#define SIZEOF_LONG 8
|
||||
|
||||
/* The number of bytes in type long long */
|
||||
#define SIZEOF_LONG_LONG 8
|
||||
|
||||
/* The number of bytes in type size_t */
|
||||
#define SIZEOF_SIZE_T 8
|
||||
|
||||
/* Specifier for __thread */
|
||||
#define SPEC___THREAD __thread
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "0.13.1"
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
/* #undef size_t */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
83
json-c/debug.c
Normal file
83
json-c/debug.c
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* $Id: debug.c,v 1.5 2006/01/26 02:16:28 mclark Exp $
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||
* Michael Clark <michael@metaparadigm.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#if HAVE_SYSLOG_H
|
||||
# include <syslog.h>
|
||||
#endif /* HAVE_SYSLOG_H */
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
|
||||
#if HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif /* HAVE_SYS_PARAM_H */
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
static int _syslog = 0;
|
||||
static int _debug = 0;
|
||||
|
||||
void mc_set_debug(int debug) { _debug = debug; }
|
||||
int mc_get_debug(void) { return _debug; }
|
||||
|
||||
extern void mc_set_syslog(int syslog)
|
||||
{
|
||||
_syslog = syslog;
|
||||
}
|
||||
|
||||
void mc_debug(const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
if(_debug) {
|
||||
va_start(ap, msg);
|
||||
#if HAVE_VSYSLOG
|
||||
if(_syslog) {
|
||||
vsyslog(LOG_DEBUG, msg, ap);
|
||||
} else
|
||||
#endif
|
||||
vprintf(msg, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
void mc_error(const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
#if HAVE_VSYSLOG
|
||||
if(_syslog) {
|
||||
vsyslog(LOG_ERR, msg, ap);
|
||||
} else
|
||||
#endif
|
||||
vfprintf(stderr, msg, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void mc_info(const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
#if HAVE_VSYSLOG
|
||||
if(_syslog) {
|
||||
vsyslog(LOG_INFO, msg, ap);
|
||||
} else
|
||||
#endif
|
||||
vfprintf(stderr, msg, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
75
json-c/debug.h
Normal file
75
json-c/debug.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* $Id: debug.h,v 1.5 2006/01/30 23:07:57 mclark Exp $
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||
* Michael Clark <michael@metaparadigm.com>
|
||||
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Do not use, json-c internal, may be changed or removed at any time.
|
||||
*/
|
||||
#ifndef _DEBUG_H_
|
||||
#define _DEBUG_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void mc_set_debug(int debug);
|
||||
extern int mc_get_debug(void);
|
||||
|
||||
extern void mc_set_syslog(int syslog);
|
||||
|
||||
extern void mc_debug(const char *msg, ...);
|
||||
extern void mc_error(const char *msg, ...);
|
||||
extern void mc_info(const char *msg, ...);
|
||||
|
||||
#ifndef __STRING
|
||||
#define __STRING(x) #x
|
||||
#endif
|
||||
|
||||
#ifndef PARSER_BROKEN_FIXED
|
||||
|
||||
#define JASSERT(cond) do {} while(0)
|
||||
|
||||
#else
|
||||
|
||||
#define JASSERT(cond) do { \
|
||||
if (!(cond)) { \
|
||||
mc_error("cjson assert failure %s:%d : cond \"" __STRING(cond) "failed\n", __FILE__, __LINE__); \
|
||||
*(int *)0 = 1;\
|
||||
abort(); \
|
||||
}\
|
||||
} while(0)
|
||||
|
||||
#endif
|
||||
|
||||
#define MC_ERROR(x, ...) mc_error(x, ##__VA_ARGS__)
|
||||
|
||||
#ifdef MC_MAINTAINER_MODE
|
||||
#define MC_SET_DEBUG(x) mc_set_debug(x)
|
||||
#define MC_GET_DEBUG() mc_get_debug()
|
||||
#define MC_SET_SYSLOG(x) mc_set_syslog(x)
|
||||
#define MC_DEBUG(x, ...) mc_debug(x, ##__VA_ARGS__)
|
||||
#define MC_INFO(x, ...) mc_info(x, ##__VA_ARGS__)
|
||||
#else
|
||||
#define MC_SET_DEBUG(x) if (0) mc_set_debug(x)
|
||||
#define MC_GET_DEBUG() (0)
|
||||
#define MC_SET_SYSLOG(x) if (0) mc_set_syslog(x)
|
||||
#define MC_DEBUG(x, ...) if (0) mc_debug(x, ##__VA_ARGS__)
|
||||
#define MC_INFO(x, ...) if (0) mc_info(x, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
38
json-c/json.h
Normal file
38
json-c/json.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* $Id: json.h,v 1.6 2006/01/26 02:16:28 mclark Exp $
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||
* Michael Clark <michael@metaparadigm.com>
|
||||
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief A convenience header that may be included instead of other individual ones.
|
||||
*/
|
||||
#ifndef _json_h_
|
||||
#define _json_h_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "debug.h"
|
||||
#include "linkhash.h"
|
||||
#include "arraylist.h"
|
||||
#include "json_util.h"
|
||||
#include "json_object.h"
|
||||
#include "json_pointer.h"
|
||||
#include "json_tokener.h"
|
||||
#include "json_object_iterator.h"
|
||||
#include "json_c_version.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
20
json-c/json_c_version.c
Normal file
20
json-c/json_c_version.c
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Eric Haszlakiewicz
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include "json_c_version.h"
|
||||
|
||||
const char *json_c_version(void)
|
||||
{
|
||||
return JSON_C_VERSION;
|
||||
}
|
||||
|
||||
int json_c_version_num(void)
|
||||
{
|
||||
return JSON_C_VERSION_NUM;
|
||||
}
|
||||
|
||||
40
json-c/json_c_version.h
Normal file
40
json-c/json_c_version.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2012,2017 Eric Haszlakiewicz
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Methods for retrieving the json-c version.
|
||||
*/
|
||||
#ifndef _json_c_version_h_
|
||||
#define _json_c_version_h_
|
||||
|
||||
#define JSON_C_MAJOR_VERSION 0
|
||||
#define JSON_C_MINOR_VERSION 13
|
||||
#define JSON_C_MICRO_VERSION 01
|
||||
#define JSON_C_VERSION_NUM ((JSON_C_MAJOR_VERSION << 16) | \
|
||||
(JSON_C_MINOR_VERSION << 8) | \
|
||||
JSON_C_MICRO_VERSION)
|
||||
#define JSON_C_VERSION "0.13.1"
|
||||
|
||||
/**
|
||||
* @see JSON_C_VERSION
|
||||
* @return the version of the json-c library as a string
|
||||
*/
|
||||
const char *json_c_version(void); /* Returns JSON_C_VERSION */
|
||||
|
||||
/**
|
||||
* The json-c version encoded into an int, with the low order 8 bits
|
||||
* being the micro version, the next higher 8 bits being the minor version
|
||||
* and the next higher 8 bits being the major version.
|
||||
* For example, 7.12.99 would be 0x00070B63.
|
||||
*
|
||||
* @see JSON_C_VERSION_NUM
|
||||
* @return the version of the json-c library as an int
|
||||
*/
|
||||
int json_c_version_num(void); /* Returns JSON_C_VERSION_NUM */
|
||||
|
||||
#endif
|
||||
4
json-c/json_config.h
Normal file
4
json-c/json_config.h
Normal file
@ -0,0 +1,4 @@
|
||||
/* json_config.h. Generated from json_config.h.in by configure. */
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define JSON_C_HAVE_INTTYPES_H 1
|
||||
23
json-c/json_inttypes.h
Normal file
23
json-c/json_inttypes.h
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Do not use, json-c internal, may be changed or removed at any time.
|
||||
*/
|
||||
#ifndef _json_inttypes_h_
|
||||
#define _json_inttypes_h_
|
||||
|
||||
#include "json_config.h"
|
||||
|
||||
#ifdef JSON_C_HAVE_INTTYPES_H
|
||||
/* inttypes.h includes stdint.h */
|
||||
#include <inttypes.h>
|
||||
|
||||
#else
|
||||
#include <stdint.h>
|
||||
|
||||
#define PRId64 "I64d"
|
||||
#define SCNd64 "I64d"
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1493
json-c/json_object.c
Normal file
1493
json-c/json_object.c
Normal file
File diff suppressed because it is too large
Load Diff
1034
json-c/json_object.h
Normal file
1034
json-c/json_object.h
Normal file
File diff suppressed because it is too large
Load Diff
163
json-c/json_object_iterator.c
Normal file
163
json-c/json_object_iterator.c
Normal file
@ -0,0 +1,163 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file json_object_iterator.c
|
||||
*
|
||||
* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "json.h"
|
||||
#include "json_object_private.h"
|
||||
|
||||
#include "json_object_iterator.h"
|
||||
|
||||
/**
|
||||
* How It Works
|
||||
*
|
||||
* For each JSON Object, json-c maintains a linked list of zero
|
||||
* or more lh_entry (link-hash entry) structures inside the
|
||||
* Object's link-hash table (lh_table).
|
||||
*
|
||||
* Each lh_entry structure on the JSON Object's linked list
|
||||
* represents a single name/value pair. The "next" field of the
|
||||
* last lh_entry in the list is set to NULL, which terminates
|
||||
* the list.
|
||||
*
|
||||
* We represent a valid iterator that refers to an actual
|
||||
* name/value pair via a pointer to the pair's lh_entry
|
||||
* structure set as the iterator's opaque_ field.
|
||||
*
|
||||
* We follow json-c's current pair list representation by
|
||||
* representing a valid "end" iterator (one that refers past the
|
||||
* last pair) with a NULL value in the iterator's opaque_ field.
|
||||
*
|
||||
* A JSON Object without any pairs in it will have the "head"
|
||||
* field of its lh_table structure set to NULL. For such an
|
||||
* object, json_object_iter_begin will return an iterator with
|
||||
* the opaque_ field set to NULL, which is equivalent to the
|
||||
* "end" iterator.
|
||||
*
|
||||
* When iterating, we simply update the iterator's opaque_ field
|
||||
* to point to the next lh_entry structure in the linked list.
|
||||
* opaque_ will become NULL once we iterate past the last pair
|
||||
* in the list, which makes the iterator equivalent to the "end"
|
||||
* iterator.
|
||||
*/
|
||||
|
||||
/// Our current representation of the "end" iterator;
|
||||
///
|
||||
/// @note May not always be NULL
|
||||
static const void* kObjectEndIterValue = NULL;
|
||||
|
||||
/**
|
||||
* ****************************************************************************
|
||||
*/
|
||||
struct json_object_iterator
|
||||
json_object_iter_begin(struct json_object* obj)
|
||||
{
|
||||
struct json_object_iterator iter;
|
||||
struct lh_table* pTable;
|
||||
|
||||
/// @note json_object_get_object will return NULL if passed NULL
|
||||
/// or a non-json_type_object instance
|
||||
pTable = json_object_get_object(obj);
|
||||
JASSERT(NULL != pTable);
|
||||
|
||||
/// @note For a pair-less Object, head is NULL, which matches our
|
||||
/// definition of the "end" iterator
|
||||
iter.opaque_ = pTable->head;
|
||||
return iter;
|
||||
}
|
||||
|
||||
/**
|
||||
* ****************************************************************************
|
||||
*/
|
||||
struct json_object_iterator
|
||||
json_object_iter_end(const struct json_object* obj)
|
||||
{
|
||||
struct json_object_iterator iter;
|
||||
|
||||
JASSERT(NULL != obj);
|
||||
JASSERT(json_object_is_type(obj, json_type_object));
|
||||
|
||||
iter.opaque_ = kObjectEndIterValue;
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
/**
|
||||
* ****************************************************************************
|
||||
*/
|
||||
void
|
||||
json_object_iter_next(struct json_object_iterator* iter)
|
||||
{
|
||||
JASSERT(NULL != iter);
|
||||
JASSERT(kObjectEndIterValue != iter->opaque_);
|
||||
|
||||
iter->opaque_ = ((const struct lh_entry *)iter->opaque_)->next;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ****************************************************************************
|
||||
*/
|
||||
const char*
|
||||
json_object_iter_peek_name(const struct json_object_iterator* iter)
|
||||
{
|
||||
JASSERT(NULL != iter);
|
||||
JASSERT(kObjectEndIterValue != iter->opaque_);
|
||||
|
||||
return (const char*)(((const struct lh_entry *)iter->opaque_)->k);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ****************************************************************************
|
||||
*/
|
||||
struct json_object*
|
||||
json_object_iter_peek_value(const struct json_object_iterator* iter)
|
||||
{
|
||||
JASSERT(NULL != iter);
|
||||
JASSERT(kObjectEndIterValue != iter->opaque_);
|
||||
|
||||
return (struct json_object*)lh_entry_v((const struct lh_entry *)iter->opaque_);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ****************************************************************************
|
||||
*/
|
||||
json_bool
|
||||
json_object_iter_equal(const struct json_object_iterator* iter1,
|
||||
const struct json_object_iterator* iter2)
|
||||
{
|
||||
JASSERT(NULL != iter1);
|
||||
JASSERT(NULL != iter2);
|
||||
|
||||
return (iter1->opaque_ == iter2->opaque_);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ****************************************************************************
|
||||
*/
|
||||
struct json_object_iterator
|
||||
json_object_iter_init_default(void)
|
||||
{
|
||||
struct json_object_iterator iter;
|
||||
|
||||
/**
|
||||
* @note Make this a negative, invalid value, such that
|
||||
* accidental access to it would likely be trapped by the
|
||||
* hardware as an invalid address.
|
||||
*/
|
||||
iter.opaque_ = NULL;
|
||||
|
||||
return iter;
|
||||
}
|
||||
240
json-c/json_object_iterator.h
Normal file
240
json-c/json_object_iterator.h
Normal file
@ -0,0 +1,240 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file json_object_iterator.h
|
||||
*
|
||||
* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
* @brief An API for iterating over json_type_object objects,
|
||||
* styled to be familiar to C++ programmers.
|
||||
* Unlike json_object_object_foreach() and
|
||||
* json_object_object_foreachC(), this avoids the need to expose
|
||||
* json-c internals like lh_entry.
|
||||
*
|
||||
* API attributes: <br>
|
||||
* * Thread-safe: NO<br>
|
||||
* * Reentrant: NO
|
||||
*
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
#ifndef JSON_OBJECT_ITERATOR_H
|
||||
#define JSON_OBJECT_ITERATOR_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Forward declaration for the opaque iterator information.
|
||||
*/
|
||||
struct json_object_iter_info_;
|
||||
|
||||
/**
|
||||
* The opaque iterator that references a name/value pair within
|
||||
* a JSON Object instance or the "end" iterator value.
|
||||
*/
|
||||
struct json_object_iterator {
|
||||
const void* opaque_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* forward declaration of json-c's JSON value instance structure
|
||||
*/
|
||||
struct json_object;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes an iterator structure to a "default" value that
|
||||
* is convenient for initializing an iterator variable to a
|
||||
* default state (e.g., initialization list in a class'
|
||||
* constructor).
|
||||
*
|
||||
* @code
|
||||
* struct json_object_iterator iter = json_object_iter_init_default();
|
||||
* MyClass() : iter_(json_object_iter_init_default())
|
||||
* @endcode
|
||||
*
|
||||
* @note The initialized value doesn't reference any specific
|
||||
* pair, is considered an invalid iterator, and MUST NOT
|
||||
* be passed to any json-c API that expects a valid
|
||||
* iterator.
|
||||
*
|
||||
* @note User and internal code MUST NOT make any assumptions
|
||||
* about and dependencies on the value of the "default"
|
||||
* iterator value.
|
||||
*
|
||||
* @return json_object_iterator
|
||||
*/
|
||||
struct json_object_iterator
|
||||
json_object_iter_init_default(void);
|
||||
|
||||
/** Retrieves an iterator to the first pair of the JSON Object.
|
||||
*
|
||||
* @warning Any modification of the underlying pair invalidates all
|
||||
* iterators to that pair.
|
||||
*
|
||||
* @param obj JSON Object instance (MUST be of type json_object)
|
||||
*
|
||||
* @return json_object_iterator If the JSON Object has at
|
||||
* least one pair, on return, the iterator refers
|
||||
* to the first pair. If the JSON Object doesn't
|
||||
* have any pairs, the returned iterator is
|
||||
* equivalent to the "end" iterator for the same
|
||||
* JSON Object instance.
|
||||
*
|
||||
* @code
|
||||
* struct json_object_iterator it;
|
||||
* struct json_object_iterator itEnd;
|
||||
* struct json_object* obj;
|
||||
*
|
||||
* obj = json_tokener_parse("{'first':'george', 'age':100}");
|
||||
* it = json_object_iter_begin(obj);
|
||||
* itEnd = json_object_iter_end(obj);
|
||||
*
|
||||
* while (!json_object_iter_equal(&it, &itEnd)) {
|
||||
* printf("%s\n",
|
||||
* json_object_iter_peek_name(&it));
|
||||
* json_object_iter_next(&it);
|
||||
* }
|
||||
*
|
||||
* @endcode
|
||||
*/
|
||||
struct json_object_iterator
|
||||
json_object_iter_begin(struct json_object* obj);
|
||||
|
||||
/** Retrieves the iterator that represents the position beyond the
|
||||
* last pair of the given JSON Object instance.
|
||||
*
|
||||
* @warning Do NOT write code that assumes that the "end"
|
||||
* iterator value is NULL, even if it is so in a
|
||||
* particular instance of the implementation.
|
||||
*
|
||||
* @note The reason we do not (and MUST NOT) provide
|
||||
* "json_object_iter_is_end(json_object_iterator* iter)"
|
||||
* type of API is because it would limit the underlying
|
||||
* representation of name/value containment (or force us
|
||||
* to add additional, otherwise unnecessary, fields to
|
||||
* the iterator structure). The "end" iterator and the
|
||||
* equality test method, on the other hand, permit us to
|
||||
* cleanly abstract pretty much any reasonable underlying
|
||||
* representation without burdening the iterator
|
||||
* structure with unnecessary data.
|
||||
*
|
||||
* @note For performance reasons, memorize the "end" iterator prior
|
||||
* to any loop.
|
||||
*
|
||||
* @param obj JSON Object instance (MUST be of type json_object)
|
||||
*
|
||||
* @return json_object_iterator On return, the iterator refers
|
||||
* to the "end" of the Object instance's pairs
|
||||
* (i.e., NOT the last pair, but "beyond the last
|
||||
* pair" value)
|
||||
*/
|
||||
struct json_object_iterator
|
||||
json_object_iter_end(const struct json_object* obj);
|
||||
|
||||
/** Returns an iterator to the next pair, if any
|
||||
*
|
||||
* @warning Any modification of the underlying pair
|
||||
* invalidates all iterators to that pair.
|
||||
*
|
||||
* @param iter [IN/OUT] Pointer to iterator that references a
|
||||
* name/value pair; MUST be a valid, non-end iterator.
|
||||
* WARNING: bad things will happen if invalid or "end"
|
||||
* iterator is passed. Upon return will contain the
|
||||
* reference to the next pair if there is one; if there
|
||||
* are no more pairs, will contain the "end" iterator
|
||||
* value, which may be compared against the return value
|
||||
* of json_object_iter_end() for the same JSON Object
|
||||
* instance.
|
||||
*/
|
||||
void
|
||||
json_object_iter_next(struct json_object_iterator* iter);
|
||||
|
||||
|
||||
/** Returns a const pointer to the name of the pair referenced
|
||||
* by the given iterator.
|
||||
*
|
||||
* @param iter pointer to iterator that references a name/value
|
||||
* pair; MUST be a valid, non-end iterator.
|
||||
*
|
||||
* @warning bad things will happen if an invalid or
|
||||
* "end" iterator is passed.
|
||||
*
|
||||
* @return const char* Pointer to the name of the referenced
|
||||
* name/value pair. The name memory belongs to the
|
||||
* name/value pair, will be freed when the pair is
|
||||
* deleted or modified, and MUST NOT be modified or
|
||||
* freed by the user.
|
||||
*/
|
||||
const char*
|
||||
json_object_iter_peek_name(const struct json_object_iterator* iter);
|
||||
|
||||
|
||||
/** Returns a pointer to the json-c instance representing the
|
||||
* value of the referenced name/value pair, without altering
|
||||
* the instance's reference count.
|
||||
*
|
||||
* @param iter pointer to iterator that references a name/value
|
||||
* pair; MUST be a valid, non-end iterator.
|
||||
*
|
||||
* @warning bad things will happen if invalid or
|
||||
* "end" iterator is passed.
|
||||
*
|
||||
* @return struct json_object* Pointer to the json-c value
|
||||
* instance of the referenced name/value pair; the
|
||||
* value's reference count is not changed by this
|
||||
* function: if you plan to hold on to this json-c node,
|
||||
* take a look at json_object_get() and
|
||||
* json_object_put(). IMPORTANT: json-c API represents
|
||||
* the JSON Null value as a NULL json_object instance
|
||||
* pointer.
|
||||
*/
|
||||
struct json_object*
|
||||
json_object_iter_peek_value(const struct json_object_iterator* iter);
|
||||
|
||||
|
||||
/** Tests two iterators for equality. Typically used to test
|
||||
* for end of iteration by comparing an iterator to the
|
||||
* corresponding "end" iterator (that was derived from the same
|
||||
* JSON Object instance).
|
||||
*
|
||||
* @note The reason we do not (and MUST NOT) provide
|
||||
* "json_object_iter_is_end(json_object_iterator* iter)"
|
||||
* type of API is because it would limit the underlying
|
||||
* representation of name/value containment (or force us
|
||||
* to add additional, otherwise unnecessary, fields to
|
||||
* the iterator structure). The equality test method, on
|
||||
* the other hand, permits us to cleanly abstract pretty
|
||||
* much any reasonable underlying representation.
|
||||
*
|
||||
* @param iter1 Pointer to first valid, non-NULL iterator
|
||||
* @param iter2 POinter to second valid, non-NULL iterator
|
||||
*
|
||||
* @warning if a NULL iterator pointer or an uninitialized
|
||||
* or invalid iterator, or iterators derived from
|
||||
* different JSON Object instances are passed, bad things
|
||||
* will happen!
|
||||
*
|
||||
* @return json_bool non-zero if iterators are equal (i.e., both
|
||||
* reference the same name/value pair or are both at
|
||||
* "end"); zero if they are not equal.
|
||||
*/
|
||||
json_bool
|
||||
json_object_iter_equal(const struct json_object_iterator* iter1,
|
||||
const struct json_object_iterator* iter2);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* JSON_OBJECT_ITERATOR_H */
|
||||
64
json-c/json_object_private.h
Normal file
64
json-c/json_object_private.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* $Id: json_object_private.h,v 1.4 2006/01/26 02:16:28 mclark Exp $
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||
* Michael Clark <michael@metaparadigm.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Do not use, json-c internal, may be changed or removed at any time.
|
||||
*/
|
||||
#ifndef _json_object_private_h_
|
||||
#define _json_object_private_h_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LEN_DIRECT_STRING_DATA 32 /**< how many bytes are directly stored in json_object for strings? */
|
||||
|
||||
typedef void (json_object_private_delete_fn)(struct json_object *o);
|
||||
|
||||
struct json_object
|
||||
{
|
||||
enum json_type o_type;
|
||||
json_object_private_delete_fn *_delete;
|
||||
json_object_to_json_string_fn *_to_json_string;
|
||||
int _ref_count;
|
||||
struct printbuf *_pb;
|
||||
union data {
|
||||
json_bool c_boolean;
|
||||
double c_double;
|
||||
int64_t c_int64;
|
||||
struct lh_table *c_object;
|
||||
struct array_list *c_array;
|
||||
struct {
|
||||
union {
|
||||
/* optimize: if we have small strings, we can store them
|
||||
* directly. This saves considerable CPU cycles AND memory.
|
||||
*/
|
||||
char *ptr;
|
||||
char data[LEN_DIRECT_STRING_DATA];
|
||||
} str;
|
||||
int len;
|
||||
} c_string;
|
||||
} o;
|
||||
json_object_delete_fn *_user_delete;
|
||||
void *_userdata;
|
||||
};
|
||||
|
||||
void _json_c_set_last_err(const char *err_fmt, ...);
|
||||
|
||||
extern const char *json_number_chars;
|
||||
extern const char *json_hex_chars;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
327
json-c/json_pointer.c
Normal file
327
json-c/json_pointer.c
Normal file
@ -0,0 +1,327 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Alexandru Ardelean.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "strerror_override.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "json_pointer.h"
|
||||
#include "strdup_compat.h"
|
||||
#include "vasprintf_compat.h"
|
||||
|
||||
/**
|
||||
* JavaScript Object Notation (JSON) Pointer
|
||||
* RFC 6901 - https://tools.ietf.org/html/rfc6901
|
||||
*/
|
||||
|
||||
static void string_replace_all_occurrences_with_char(char *s, const char *occur, char repl_char)
|
||||
{
|
||||
int slen = strlen(s);
|
||||
int skip = strlen(occur) - 1; /* length of the occurence, minus the char we're replacing */
|
||||
char *p = s;
|
||||
while ((p = strstr(p, occur))) {
|
||||
*p = repl_char;
|
||||
p++;
|
||||
slen -= skip;
|
||||
memmove(p, (p + skip), slen - (p - s) + 1); /* includes null char too */
|
||||
}
|
||||
}
|
||||
|
||||
static int is_valid_index(struct json_object *jo, const char *path, int32_t *idx)
|
||||
{
|
||||
int i, len = strlen(path);
|
||||
/* this code-path optimizes a bit, for when we reference the 0-9 index range in a JSON array
|
||||
and because leading zeros not allowed */
|
||||
if (len == 1) {
|
||||
if (isdigit((int)path[0])) {
|
||||
*idx = (path[0] - '0');
|
||||
goto check_oob;
|
||||
}
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
/* leading zeros not allowed per RFC */
|
||||
if (path[0] == '0') {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
/* RFC states base-10 decimals */
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!isdigit((int)path[i])) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
*idx = strtol(path, NULL, 10);
|
||||
if (*idx < 0) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
check_oob:
|
||||
len = json_object_array_length(jo);
|
||||
if (*idx >= len) {
|
||||
errno = ENOENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int json_pointer_get_single_path(struct json_object *obj, char *path, struct json_object **value)
|
||||
{
|
||||
if (json_object_is_type(obj, json_type_array)) {
|
||||
int32_t idx;
|
||||
if (!is_valid_index(obj, path, &idx))
|
||||
return -1;
|
||||
obj = json_object_array_get_idx(obj, idx);
|
||||
if (obj) {
|
||||
if (value)
|
||||
*value = obj;
|
||||
return 0;
|
||||
}
|
||||
/* Entry not found */
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* RFC states that we first must eval all ~1 then all ~0 */
|
||||
string_replace_all_occurrences_with_char(path, "~1", '/');
|
||||
string_replace_all_occurrences_with_char(path, "~0", '~');
|
||||
|
||||
if (!json_object_object_get_ex(obj, path, value)) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int json_pointer_set_single_path(
|
||||
struct json_object *parent,
|
||||
const char *path,
|
||||
struct json_object *value)
|
||||
{
|
||||
if (json_object_is_type(parent, json_type_array)) {
|
||||
int32_t idx;
|
||||
/* RFC (Chapter 4) states that '-' may be used to add new elements to an array */
|
||||
if (path[0] == '-' && path[1] == '\0')
|
||||
return json_object_array_add(parent, value);
|
||||
if (!is_valid_index(parent, path, &idx))
|
||||
return -1;
|
||||
return json_object_array_put_idx(parent, idx, value);
|
||||
}
|
||||
|
||||
/* path replacements should have been done in json_pointer_get_single_path(),
|
||||
and we should still be good here */
|
||||
if (json_object_is_type(parent, json_type_object))
|
||||
return json_object_object_add(parent, path, value);
|
||||
|
||||
/* Getting here means that we tried to "dereference" a primitive JSON type (like string, int, bool).
|
||||
i.e. add a sub-object to it */
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int json_pointer_get_recursive(
|
||||
struct json_object *obj,
|
||||
char *path,
|
||||
struct json_object **value)
|
||||
{
|
||||
char *endp;
|
||||
int rc;
|
||||
|
||||
/* All paths (on each recursion level must have a leading '/' */
|
||||
if (path[0] != '/') {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
path++;
|
||||
|
||||
endp = strchr(path, '/');
|
||||
if (endp)
|
||||
*endp = '\0';
|
||||
|
||||
/* If we err-ed here, return here */
|
||||
if ((rc = json_pointer_get_single_path(obj, path, &obj)))
|
||||
return rc;
|
||||
|
||||
if (endp) {
|
||||
*endp = '/'; /* Put the slash back, so that the sanity check passes on next recursion level */
|
||||
return json_pointer_get_recursive(obj, endp, value);
|
||||
}
|
||||
|
||||
/* We should be at the end of the recursion here */
|
||||
if (value)
|
||||
*value = obj;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int json_pointer_get(struct json_object *obj, const char *path, struct json_object **res)
|
||||
{
|
||||
char *path_copy = NULL;
|
||||
int rc;
|
||||
|
||||
if (!obj || !path) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (path[0] == '\0') {
|
||||
if (res)
|
||||
*res = obj;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* pass a working copy to the recursive call */
|
||||
if (!(path_copy = strdup(path))) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
rc = json_pointer_get_recursive(obj, path_copy, res);
|
||||
free(path_copy);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int json_pointer_getf(struct json_object *obj, struct json_object **res, const char *path_fmt, ...)
|
||||
{
|
||||
char *path_copy = NULL;
|
||||
int rc = 0;
|
||||
va_list args;
|
||||
|
||||
if (!obj || !path_fmt) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
va_start(args, path_fmt);
|
||||
rc = vasprintf(&path_copy, path_fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (path_copy[0] == '\0') {
|
||||
if (res)
|
||||
*res = obj;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = json_pointer_get_recursive(obj, path_copy, res);
|
||||
out:
|
||||
free(path_copy);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int json_pointer_set(struct json_object **obj, const char *path, struct json_object *value)
|
||||
{
|
||||
const char *endp;
|
||||
char *path_copy = NULL;
|
||||
struct json_object *set = NULL;
|
||||
int rc;
|
||||
|
||||
if (!obj || !path) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (path[0] == '\0') {
|
||||
json_object_put(*obj);
|
||||
*obj = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (path[0] != '/') {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If there's only 1 level to set, stop here */
|
||||
if ((endp = strrchr(path, '/')) == path) {
|
||||
path++;
|
||||
return json_pointer_set_single_path(*obj, path, value);
|
||||
}
|
||||
|
||||
/* pass a working copy to the recursive call */
|
||||
if (!(path_copy = strdup(path))) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
path_copy[endp - path] = '\0';
|
||||
rc = json_pointer_get_recursive(*obj, path_copy, &set);
|
||||
free(path_copy);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
endp++;
|
||||
return json_pointer_set_single_path(set, endp, value);
|
||||
}
|
||||
|
||||
int json_pointer_setf(struct json_object **obj, struct json_object *value, const char *path_fmt, ...)
|
||||
{
|
||||
char *endp;
|
||||
char *path_copy = NULL;
|
||||
struct json_object *set = NULL;
|
||||
va_list args;
|
||||
int rc = 0;
|
||||
|
||||
if (!obj || !path_fmt) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* pass a working copy to the recursive call */
|
||||
va_start(args, path_fmt);
|
||||
rc = vasprintf(&path_copy, path_fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (path_copy[0] == '\0') {
|
||||
json_object_put(*obj);
|
||||
*obj = value;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (path_copy[0] != '/') {
|
||||
errno = EINVAL;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If there's only 1 level to set, stop here */
|
||||
if ((endp = strrchr(path_copy, '/')) == path_copy) {
|
||||
set = *obj;
|
||||
goto set_single_path;
|
||||
}
|
||||
|
||||
*endp = '\0';
|
||||
rc = json_pointer_get_recursive(*obj, path_copy, &set);
|
||||
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
set_single_path:
|
||||
endp++;
|
||||
rc = json_pointer_set_single_path(set, endp, value);
|
||||
out:
|
||||
free(path_copy);
|
||||
return rc;
|
||||
}
|
||||
|
||||
120
json-c/json_pointer.h
Normal file
120
json-c/json_pointer.h
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Alexadru Ardelean.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief JSON Pointer (RFC 6901) implementation for retrieving
|
||||
* objects from a json-c object tree.
|
||||
*/
|
||||
#ifndef _json_pointer_h_
|
||||
#define _json_pointer_h_
|
||||
|
||||
#include "json_object.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Retrieves a JSON sub-object from inside another JSON object
|
||||
* using the JSON pointer notation as defined in RFC 6901
|
||||
* https://tools.ietf.org/html/rfc6901
|
||||
*
|
||||
* The returned JSON sub-object is equivalent to parsing manually the
|
||||
* 'obj' JSON tree ; i.e. it's not a new object that is created, but rather
|
||||
* a pointer inside the JSON tree.
|
||||
*
|
||||
* Internally, this is equivalent to doing a series of 'json_object_object_get()'
|
||||
* and 'json_object_array_get_idx()' along the given 'path'.
|
||||
*
|
||||
* Note that the 'path' string supports 'printf()' type arguments, so, whatever
|
||||
* is added after the 'res' param will be treated as an argument for 'path'
|
||||
* Example: json_pointer_get(obj, "/foo/%d/%s", &res, 0, bar)
|
||||
* This means, that you need to escape '%' with '%%' (just like in printf())
|
||||
*
|
||||
* @param obj the json_object instance/tree from where to retrieve sub-objects
|
||||
* @param path a (RFC6901) string notation for the sub-object to retrieve
|
||||
* @param res a pointer where to store a reference to the json_object
|
||||
* associated with the given path
|
||||
*
|
||||
* @return negative if an error (or not found), or 0 if succeeded
|
||||
*/
|
||||
int json_pointer_get(struct json_object *obj, const char *path, struct json_object **res);
|
||||
|
||||
/**
|
||||
* This is a variant of 'json_pointer_get()' that supports printf() style arguments.
|
||||
*
|
||||
* Example: json_pointer_getf(obj, res, "/foo/%d/%s", 0, bak)
|
||||
* This also means that you need to escape '%' with '%%' (just like in printf())
|
||||
*
|
||||
* Please take into consideration all recommended 'printf()' format security
|
||||
* aspects when using this function.
|
||||
*
|
||||
* @param obj the json_object instance/tree to which to add a sub-object
|
||||
* @param res a pointer where to store a reference to the json_object
|
||||
* associated with the given path
|
||||
* @param path_fmt a printf() style format for the path
|
||||
*
|
||||
* @return negative if an error (or not found), or 0 if succeeded
|
||||
*/
|
||||
int json_pointer_getf(struct json_object *obj, struct json_object **res, const char *path_fmt, ...);
|
||||
|
||||
/**
|
||||
* Sets JSON object 'value' in the 'obj' tree at the location specified
|
||||
* by the 'path'. 'path' is JSON pointer notation as defined in RFC 6901
|
||||
* https://tools.ietf.org/html/rfc6901
|
||||
*
|
||||
* Note that 'obj' is a double pointer, mostly for the "" (empty string)
|
||||
* case, where the entire JSON object would be replaced by 'value'.
|
||||
* In the case of the "" path, the object at '*obj' will have it's refcount
|
||||
* decremented with 'json_object_put()' and the 'value' object will be assigned to it.
|
||||
*
|
||||
* For other cases (JSON sub-objects) ownership of 'value' will be transferred into
|
||||
* '*obj' via 'json_object_object_add()' & 'json_object_array_put_idx()', so the
|
||||
* only time the refcount should be decremented for 'value' is when the return value of
|
||||
* 'json_pointer_set()' is negative (meaning the 'value' object did not get set into '*obj').
|
||||
*
|
||||
* That also implies that 'json_pointer_set()' does not do any refcount incrementing.
|
||||
* (Just that single decrement that was mentioned above).
|
||||
*
|
||||
* Note that the 'path' string supports 'printf()' type arguments, so, whatever
|
||||
* is added after the 'value' param will be treated as an argument for 'path'
|
||||
* Example: json_pointer_set(obj, "/foo/%d/%s", value, 0, bak)
|
||||
* This means, that you need to escape '%' with '%%' (just like in printf())
|
||||
*
|
||||
* @param obj the json_object instance/tree to which to add a sub-object
|
||||
* @param path a (RFC6901) string notation for the sub-object to set in the tree
|
||||
* @param value object to set at path
|
||||
*
|
||||
* @return negative if an error (or not found), or 0 if succeeded
|
||||
*/
|
||||
int json_pointer_set(struct json_object **obj, const char *path, struct json_object *value);
|
||||
|
||||
/**
|
||||
* This is a variant of 'json_pointer_set()' that supports printf() style arguments.
|
||||
*
|
||||
* Example: json_pointer_setf(obj, value, "/foo/%d/%s", 0, bak)
|
||||
* This also means that you need to escape '%' with '%%' (just like in printf())
|
||||
*
|
||||
* Please take into consideration all recommended 'printf()' format security
|
||||
* aspects when using this function.
|
||||
*
|
||||
* @param obj the json_object instance/tree to which to add a sub-object
|
||||
* @param value object to set at path
|
||||
* @param path_fmt a printf() style format for the path
|
||||
*
|
||||
* @return negative if an error (or not found), or 0 if succeeded
|
||||
*/
|
||||
int json_pointer_setf(struct json_object **obj, struct json_object *value, const char *path_fmt, ...);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
997
json-c/json_tokener.c
Normal file
997
json-c/json_tokener.c
Normal file
@ -0,0 +1,997 @@
|
||||
/*
|
||||
* $Id: json_tokener.c,v 1.20 2006/07/25 03:24:50 mclark Exp $
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||
* Michael Clark <michael@metaparadigm.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved.
|
||||
* The copyrights to the contents of this file are licensed under the MIT License
|
||||
* (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <math.h>
|
||||
#include "math_compat.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "printbuf.h"
|
||||
#include "arraylist.h"
|
||||
#include "json_inttypes.h"
|
||||
#include "json_object.h"
|
||||
#include "json_object_private.h"
|
||||
#include "json_tokener.h"
|
||||
#include "json_util.h"
|
||||
#include "strdup_compat.h"
|
||||
|
||||
#ifdef HAVE_LOCALE_H
|
||||
#include <locale.h>
|
||||
#endif /* HAVE_LOCALE_H */
|
||||
#ifdef HAVE_XLOCALE_H
|
||||
#include <xlocale.h>
|
||||
#endif
|
||||
|
||||
#define jt_hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
|
||||
|
||||
#if !HAVE_STRNCASECMP && defined(_MSC_VER)
|
||||
/* MSC has the version as _strnicmp */
|
||||
# define strncasecmp _strnicmp
|
||||
#elif !HAVE_STRNCASECMP
|
||||
# error You do not have strncasecmp on your system.
|
||||
#endif /* HAVE_STRNCASECMP */
|
||||
|
||||
/* Use C99 NAN by default; if not available, nan("") should work too. */
|
||||
#ifndef NAN
|
||||
#define NAN nan("")
|
||||
#endif /* !NAN */
|
||||
|
||||
static const char json_null_str[] = "null";
|
||||
static const int json_null_str_len = sizeof(json_null_str) - 1;
|
||||
static const char json_inf_str[] = "Infinity";
|
||||
static const char json_inf_str_lower[] = "infinity";
|
||||
static const unsigned int json_inf_str_len = sizeof(json_inf_str) - 1;
|
||||
static const char json_nan_str[] = "NaN";
|
||||
static const int json_nan_str_len = sizeof(json_nan_str) - 1;
|
||||
static const char json_true_str[] = "true";
|
||||
static const int json_true_str_len = sizeof(json_true_str) - 1;
|
||||
static const char json_false_str[] = "false";
|
||||
static const int json_false_str_len = sizeof(json_false_str) - 1;
|
||||
|
||||
static const char* json_tokener_errors[] = {
|
||||
"success",
|
||||
"continue",
|
||||
"nesting too deep",
|
||||
"unexpected end of data",
|
||||
"unexpected character",
|
||||
"null expected",
|
||||
"boolean expected",
|
||||
"number expected",
|
||||
"array value separator ',' expected",
|
||||
"quoted object property name expected",
|
||||
"object property name separator ':' expected",
|
||||
"object value separator ',' expected",
|
||||
"invalid string sequence",
|
||||
"expected comment",
|
||||
"buffer size overflow"
|
||||
};
|
||||
|
||||
const char *json_tokener_error_desc(enum json_tokener_error jerr)
|
||||
{
|
||||
int jerr_int = (int) jerr;
|
||||
if (jerr_int < 0 ||
|
||||
jerr_int >= (int)(sizeof(json_tokener_errors) / sizeof(json_tokener_errors[0])))
|
||||
return "Unknown error, "
|
||||
"invalid json_tokener_error value passed to json_tokener_error_desc()";
|
||||
return json_tokener_errors[jerr];
|
||||
}
|
||||
|
||||
enum json_tokener_error json_tokener_get_error(struct json_tokener *tok)
|
||||
{
|
||||
return tok->err;
|
||||
}
|
||||
|
||||
/* Stuff for decoding unicode sequences */
|
||||
#define IS_HIGH_SURROGATE(uc) (((uc) & 0xFC00) == 0xD800)
|
||||
#define IS_LOW_SURROGATE(uc) (((uc) & 0xFC00) == 0xDC00)
|
||||
#define DECODE_SURROGATE_PAIR(hi,lo) ((((hi) & 0x3FF) << 10) + ((lo) & 0x3FF) + 0x10000)
|
||||
static unsigned char utf8_replacement_char[3] = { 0xEF, 0xBF, 0xBD };
|
||||
|
||||
struct json_tokener* json_tokener_new_ex(int depth)
|
||||
{
|
||||
struct json_tokener *tok;
|
||||
|
||||
tok = (struct json_tokener*)calloc(1, sizeof(struct json_tokener));
|
||||
if (!tok) return NULL;
|
||||
tok->stack = (struct json_tokener_srec *) calloc(depth,
|
||||
sizeof(struct json_tokener_srec));
|
||||
if (!tok->stack) {
|
||||
free(tok);
|
||||
return NULL;
|
||||
}
|
||||
tok->pb = printbuf_new();
|
||||
tok->max_depth = depth;
|
||||
json_tokener_reset(tok);
|
||||
return tok;
|
||||
}
|
||||
|
||||
struct json_tokener* json_tokener_new(void)
|
||||
{
|
||||
return json_tokener_new_ex(JSON_TOKENER_DEFAULT_DEPTH);
|
||||
}
|
||||
|
||||
void json_tokener_free(struct json_tokener *tok)
|
||||
{
|
||||
json_tokener_reset(tok);
|
||||
if (tok->pb) printbuf_free(tok->pb);
|
||||
free(tok->stack);
|
||||
free(tok);
|
||||
}
|
||||
|
||||
static void json_tokener_reset_level(struct json_tokener *tok, int depth)
|
||||
{
|
||||
tok->stack[depth].state = json_tokener_state_eatws;
|
||||
tok->stack[depth].saved_state = json_tokener_state_start;
|
||||
json_object_put(tok->stack[depth].current);
|
||||
tok->stack[depth].current = NULL;
|
||||
free(tok->stack[depth].obj_field_name);
|
||||
tok->stack[depth].obj_field_name = NULL;
|
||||
}
|
||||
|
||||
void json_tokener_reset(struct json_tokener *tok)
|
||||
{
|
||||
int i;
|
||||
if (!tok)
|
||||
return;
|
||||
|
||||
for(i = tok->depth; i >= 0; i--)
|
||||
json_tokener_reset_level(tok, i);
|
||||
tok->depth = 0;
|
||||
tok->err = json_tokener_success;
|
||||
}
|
||||
|
||||
struct json_object* json_tokener_parse(const char *str)
|
||||
{
|
||||
enum json_tokener_error jerr_ignored;
|
||||
struct json_object* obj;
|
||||
obj = json_tokener_parse_verbose(str, &jerr_ignored);
|
||||
return obj;
|
||||
}
|
||||
|
||||
struct json_object* json_tokener_parse_verbose(const char *str,
|
||||
enum json_tokener_error *error)
|
||||
{
|
||||
struct json_tokener* tok;
|
||||
struct json_object* obj;
|
||||
|
||||
tok = json_tokener_new();
|
||||
if (!tok)
|
||||
return NULL;
|
||||
obj = json_tokener_parse_ex(tok, str, -1);
|
||||
*error = tok->err;
|
||||
if(tok->err != json_tokener_success) {
|
||||
if (obj != NULL)
|
||||
json_object_put(obj);
|
||||
obj = NULL;
|
||||
}
|
||||
|
||||
json_tokener_free(tok);
|
||||
return obj;
|
||||
}
|
||||
|
||||
#define state tok->stack[tok->depth].state
|
||||
#define saved_state tok->stack[tok->depth].saved_state
|
||||
#define current tok->stack[tok->depth].current
|
||||
#define obj_field_name tok->stack[tok->depth].obj_field_name
|
||||
|
||||
/* Optimization:
|
||||
* json_tokener_parse_ex() consumed a lot of CPU in its main loop,
|
||||
* iterating character-by character. A large performance boost is
|
||||
* achieved by using tighter loops to locally handle units such as
|
||||
* comments and strings. Loops that handle an entire token within
|
||||
* their scope also gather entire strings and pass them to
|
||||
* printbuf_memappend() in a single call, rather than calling
|
||||
* printbuf_memappend() one char at a time.
|
||||
*
|
||||
* PEEK_CHAR() and ADVANCE_CHAR() macros are used for code that is
|
||||
* common to both the main loop and the tighter loops.
|
||||
*/
|
||||
|
||||
/* PEEK_CHAR(dest, tok) macro:
|
||||
* Peeks at the current char and stores it in dest.
|
||||
* Returns 1 on success, sets tok->err and returns 0 if no more chars.
|
||||
* Implicit inputs: str, len vars
|
||||
*/
|
||||
#define PEEK_CHAR(dest, tok) \
|
||||
(((tok)->char_offset == len) ? \
|
||||
(((tok)->depth == 0 && \
|
||||
state == json_tokener_state_eatws && \
|
||||
saved_state == json_tokener_state_finish \
|
||||
) ? \
|
||||
(((tok)->err = json_tokener_success), 0) \
|
||||
: \
|
||||
(((tok)->err = json_tokener_continue), 0) \
|
||||
) : \
|
||||
(((dest) = *str), 1) \
|
||||
)
|
||||
|
||||
/* ADVANCE_CHAR() macro:
|
||||
* Incrementes str & tok->char_offset.
|
||||
* For convenience of existing conditionals, returns the old value of c (0 on eof)
|
||||
* Implicit inputs: c var
|
||||
*/
|
||||
#define ADVANCE_CHAR(str, tok) \
|
||||
( ++(str), ((tok)->char_offset)++, c)
|
||||
|
||||
|
||||
/* End optimization macro defs */
|
||||
|
||||
|
||||
struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
|
||||
const char *str, int len)
|
||||
{
|
||||
struct json_object *obj = NULL;
|
||||
char c = '\1';
|
||||
#ifdef HAVE_USELOCALE
|
||||
locale_t oldlocale = uselocale(NULL);
|
||||
locale_t newloc;
|
||||
#elif defined(HAVE_SETLOCALE)
|
||||
char *oldlocale = NULL;
|
||||
#endif
|
||||
|
||||
tok->char_offset = 0;
|
||||
tok->err = json_tokener_success;
|
||||
|
||||
/* this interface is presently not 64-bit clean due to the int len argument
|
||||
and the internal printbuf interface that takes 32-bit int len arguments
|
||||
so the function limits the maximum string size to INT32_MAX (2GB).
|
||||
If the function is called with len == -1 then strlen is called to check
|
||||
the string length is less than INT32_MAX (2GB) */
|
||||
if ((len < -1) || (len == -1 && strlen(str) > INT32_MAX)) {
|
||||
tok->err = json_tokener_error_size;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_USELOCALE
|
||||
{
|
||||
locale_t duploc = duplocale(oldlocale);
|
||||
newloc = newlocale(LC_NUMERIC, "C", duploc);
|
||||
// XXX at least Debian 8.4 has a bug in newlocale where it doesn't
|
||||
// change the decimal separator unless you set LC_TIME!
|
||||
if (newloc)
|
||||
{
|
||||
duploc = newloc; // original duploc has been freed by newlocale()
|
||||
newloc = newlocale(LC_TIME, "C", duploc);
|
||||
}
|
||||
if (newloc == NULL)
|
||||
{
|
||||
freelocale(duploc);
|
||||
return NULL;
|
||||
}
|
||||
uselocale(newloc);
|
||||
}
|
||||
#elif defined(HAVE_SETLOCALE)
|
||||
{
|
||||
char *tmplocale;
|
||||
tmplocale = setlocale(LC_NUMERIC, NULL);
|
||||
if (tmplocale) oldlocale = strdup(tmplocale);
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
}
|
||||
#endif
|
||||
|
||||
while (PEEK_CHAR(c, tok)) {
|
||||
|
||||
redo_char:
|
||||
switch(state) {
|
||||
|
||||
case json_tokener_state_eatws:
|
||||
/* Advance until we change state */
|
||||
while (isspace((int)c)) {
|
||||
if ((!ADVANCE_CHAR(str, tok)) || (!PEEK_CHAR(c, tok)))
|
||||
goto out;
|
||||
}
|
||||
if(c == '/' && !(tok->flags & JSON_TOKENER_STRICT)) {
|
||||
printbuf_reset(tok->pb);
|
||||
printbuf_memappend_fast(tok->pb, &c, 1);
|
||||
state = json_tokener_state_comment_start;
|
||||
} else {
|
||||
state = saved_state;
|
||||
goto redo_char;
|
||||
}
|
||||
break;
|
||||
|
||||
case json_tokener_state_start:
|
||||
switch(c) {
|
||||
case '{':
|
||||
state = json_tokener_state_eatws;
|
||||
saved_state = json_tokener_state_object_field_start;
|
||||
current = json_object_new_object();
|
||||
if(current == NULL)
|
||||
goto out;
|
||||
break;
|
||||
case '[':
|
||||
state = json_tokener_state_eatws;
|
||||
saved_state = json_tokener_state_array;
|
||||
current = json_object_new_array();
|
||||
if(current == NULL)
|
||||
goto out;
|
||||
break;
|
||||
case 'I':
|
||||
case 'i':
|
||||
state = json_tokener_state_inf;
|
||||
printbuf_reset(tok->pb);
|
||||
tok->st_pos = 0;
|
||||
goto redo_char;
|
||||
case 'N':
|
||||
case 'n':
|
||||
state = json_tokener_state_null; // or NaN
|
||||
printbuf_reset(tok->pb);
|
||||
tok->st_pos = 0;
|
||||
goto redo_char;
|
||||
case '\'':
|
||||
if (tok->flags & JSON_TOKENER_STRICT) {
|
||||
/* in STRICT mode only double-quote are allowed */
|
||||
tok->err = json_tokener_error_parse_unexpected;
|
||||
goto out;
|
||||
}
|
||||
/* FALLTHRU */
|
||||
case '"':
|
||||
state = json_tokener_state_string;
|
||||
printbuf_reset(tok->pb);
|
||||
tok->quote_char = c;
|
||||
break;
|
||||
case 'T':
|
||||
case 't':
|
||||
case 'F':
|
||||
case 'f':
|
||||
state = json_tokener_state_boolean;
|
||||
printbuf_reset(tok->pb);
|
||||
tok->st_pos = 0;
|
||||
goto redo_char;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '-':
|
||||
state = json_tokener_state_number;
|
||||
printbuf_reset(tok->pb);
|
||||
tok->is_double = 0;
|
||||
goto redo_char;
|
||||
default:
|
||||
tok->err = json_tokener_error_parse_unexpected;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
case json_tokener_state_finish:
|
||||
if(tok->depth == 0) goto out;
|
||||
obj = json_object_get(current);
|
||||
json_tokener_reset_level(tok, tok->depth);
|
||||
tok->depth--;
|
||||
goto redo_char;
|
||||
|
||||
case json_tokener_state_inf: /* aka starts with 'i' (or 'I', or "-i", or "-I") */
|
||||
{
|
||||
/* If we were guaranteed to have len set, then we could (usually) handle
|
||||
* the entire "Infinity" check in a single strncmp (strncasecmp), but
|
||||
* since len might be -1 (i.e. "read until \0"), we need to check it
|
||||
* a character at a time.
|
||||
* Trying to handle it both ways would make this code considerably more
|
||||
* complicated with likely little performance benefit.
|
||||
*/
|
||||
int is_negative = 0;
|
||||
const char *_json_inf_str = json_inf_str;
|
||||
if (!(tok->flags & JSON_TOKENER_STRICT))
|
||||
_json_inf_str = json_inf_str_lower;
|
||||
|
||||
/* Note: tok->st_pos must be 0 when state is set to json_tokener_state_inf */
|
||||
while (tok->st_pos < (int)json_inf_str_len)
|
||||
{
|
||||
char inf_char = *str;
|
||||
if (!(tok->flags & JSON_TOKENER_STRICT))
|
||||
inf_char = tolower((int)*str);
|
||||
if (inf_char != _json_inf_str[tok->st_pos])
|
||||
{
|
||||
tok->err = json_tokener_error_parse_unexpected;
|
||||
goto out;
|
||||
}
|
||||
tok->st_pos++;
|
||||
(void)ADVANCE_CHAR(str, tok);
|
||||
if (!PEEK_CHAR(c, tok))
|
||||
{
|
||||
/* out of input chars, for now at least */
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/* We checked the full length of "Infinity", so create the object.
|
||||
* When handling -Infinity, the number parsing code will have dropped
|
||||
* the "-" into tok->pb for us, so check it now.
|
||||
*/
|
||||
if (printbuf_length(tok->pb) > 0 && *(tok->pb->buf) == '-')
|
||||
{
|
||||
is_negative = 1;
|
||||
}
|
||||
current = json_object_new_double(is_negative
|
||||
? -INFINITY : INFINITY);
|
||||
if (current == NULL)
|
||||
goto out;
|
||||
saved_state = json_tokener_state_finish;
|
||||
state = json_tokener_state_eatws;
|
||||
goto redo_char;
|
||||
|
||||
}
|
||||
break;
|
||||
case json_tokener_state_null: /* aka starts with 'n' */
|
||||
{
|
||||
int size;
|
||||
int size_nan;
|
||||
printbuf_memappend_fast(tok->pb, &c, 1);
|
||||
size = json_min(tok->st_pos+1, json_null_str_len);
|
||||
size_nan = json_min(tok->st_pos+1, json_nan_str_len);
|
||||
if((!(tok->flags & JSON_TOKENER_STRICT) &&
|
||||
strncasecmp(json_null_str, tok->pb->buf, size) == 0)
|
||||
|| (strncmp(json_null_str, tok->pb->buf, size) == 0)
|
||||
) {
|
||||
if (tok->st_pos == json_null_str_len) {
|
||||
current = NULL;
|
||||
saved_state = json_tokener_state_finish;
|
||||
state = json_tokener_state_eatws;
|
||||
goto redo_char;
|
||||
}
|
||||
}
|
||||
else if ((!(tok->flags & JSON_TOKENER_STRICT) &&
|
||||
strncasecmp(json_nan_str, tok->pb->buf, size_nan) == 0) ||
|
||||
(strncmp(json_nan_str, tok->pb->buf, size_nan) == 0)
|
||||
)
|
||||
{
|
||||
if (tok->st_pos == json_nan_str_len)
|
||||
{
|
||||
current = json_object_new_double(NAN);
|
||||
if (current == NULL)
|
||||
goto out;
|
||||
saved_state = json_tokener_state_finish;
|
||||
state = json_tokener_state_eatws;
|
||||
goto redo_char;
|
||||
}
|
||||
} else {
|
||||
tok->err = json_tokener_error_parse_null;
|
||||
goto out;
|
||||
}
|
||||
tok->st_pos++;
|
||||
}
|
||||
break;
|
||||
|
||||
case json_tokener_state_comment_start:
|
||||
if(c == '*') {
|
||||
state = json_tokener_state_comment;
|
||||
} else if(c == '/') {
|
||||
state = json_tokener_state_comment_eol;
|
||||
} else {
|
||||
tok->err = json_tokener_error_parse_comment;
|
||||
goto out;
|
||||
}
|
||||
printbuf_memappend_fast(tok->pb, &c, 1);
|
||||
break;
|
||||
|
||||
case json_tokener_state_comment:
|
||||
{
|
||||
/* Advance until we change state */
|
||||
const char *case_start = str;
|
||||
while(c != '*') {
|
||||
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
|
||||
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
printbuf_memappend_fast(tok->pb, case_start, 1+str-case_start);
|
||||
state = json_tokener_state_comment_end;
|
||||
}
|
||||
break;
|
||||
|
||||
case json_tokener_state_comment_eol:
|
||||
{
|
||||
/* Advance until we change state */
|
||||
const char *case_start = str;
|
||||
while(c != '\n') {
|
||||
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
|
||||
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||
MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf);
|
||||
state = json_tokener_state_eatws;
|
||||
}
|
||||
break;
|
||||
|
||||
case json_tokener_state_comment_end:
|
||||
printbuf_memappend_fast(tok->pb, &c, 1);
|
||||
if(c == '/') {
|
||||
MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf);
|
||||
state = json_tokener_state_eatws;
|
||||
} else {
|
||||
state = json_tokener_state_comment;
|
||||
}
|
||||
break;
|
||||
|
||||
case json_tokener_state_string:
|
||||
{
|
||||
/* Advance until we change state */
|
||||
const char *case_start = str;
|
||||
while(1) {
|
||||
if(c == tok->quote_char) {
|
||||
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||
current = json_object_new_string_len(tok->pb->buf, tok->pb->bpos);
|
||||
if(current == NULL)
|
||||
goto out;
|
||||
saved_state = json_tokener_state_finish;
|
||||
state = json_tokener_state_eatws;
|
||||
break;
|
||||
} else if(c == '\\') {
|
||||
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||
saved_state = json_tokener_state_string;
|
||||
state = json_tokener_state_string_escape;
|
||||
break;
|
||||
}
|
||||
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
|
||||
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case json_tokener_state_string_escape:
|
||||
switch(c) {
|
||||
case '"':
|
||||
case '\\':
|
||||
case '/':
|
||||
printbuf_memappend_fast(tok->pb, &c, 1);
|
||||
state = saved_state;
|
||||
break;
|
||||
case 'b':
|
||||
case 'n':
|
||||
case 'r':
|
||||
case 't':
|
||||
case 'f':
|
||||
if(c == 'b') printbuf_memappend_fast(tok->pb, "\b", 1);
|
||||
else if(c == 'n') printbuf_memappend_fast(tok->pb, "\n", 1);
|
||||
else if(c == 'r') printbuf_memappend_fast(tok->pb, "\r", 1);
|
||||
else if(c == 't') printbuf_memappend_fast(tok->pb, "\t", 1);
|
||||
else if(c == 'f') printbuf_memappend_fast(tok->pb, "\f", 1);
|
||||
state = saved_state;
|
||||
break;
|
||||
case 'u':
|
||||
tok->ucs_char = 0;
|
||||
tok->st_pos = 0;
|
||||
state = json_tokener_state_escape_unicode;
|
||||
break;
|
||||
default:
|
||||
tok->err = json_tokener_error_parse_string;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
case json_tokener_state_escape_unicode:
|
||||
{
|
||||
unsigned int got_hi_surrogate = 0;
|
||||
|
||||
/* Handle a 4-byte sequence, or two sequences if a surrogate pair */
|
||||
while(1) {
|
||||
if (c && strchr(json_hex_chars, c)) {
|
||||
tok->ucs_char += ((unsigned int)jt_hexdigit(c) << ((3-tok->st_pos++)*4));
|
||||
if(tok->st_pos == 4) {
|
||||
unsigned char unescaped_utf[4];
|
||||
|
||||
if (got_hi_surrogate) {
|
||||
if (IS_LOW_SURROGATE(tok->ucs_char)) {
|
||||
/* Recalculate the ucs_char, then fall thru to process normally */
|
||||
tok->ucs_char = DECODE_SURROGATE_PAIR(got_hi_surrogate, tok->ucs_char);
|
||||
} else {
|
||||
/* Hi surrogate was not followed by a low surrogate */
|
||||
/* Replace the hi and process the rest normally */
|
||||
printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
|
||||
}
|
||||
got_hi_surrogate = 0;
|
||||
}
|
||||
|
||||
if (tok->ucs_char < 0x80) {
|
||||
unescaped_utf[0] = tok->ucs_char;
|
||||
printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 1);
|
||||
} else if (tok->ucs_char < 0x800) {
|
||||
unescaped_utf[0] = 0xc0 | (tok->ucs_char >> 6);
|
||||
unescaped_utf[1] = 0x80 | (tok->ucs_char & 0x3f);
|
||||
printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 2);
|
||||
} else if (IS_HIGH_SURROGATE(tok->ucs_char)) {
|
||||
/* Got a high surrogate. Remember it and look for the
|
||||
* the beginning of another sequence, which should be the
|
||||
* low surrogate.
|
||||
*/
|
||||
got_hi_surrogate = tok->ucs_char;
|
||||
/* Not at end, and the next two chars should be "\u" */
|
||||
if ((len == -1 || len > (tok->char_offset + 2)) &&
|
||||
// str[0] != '0' && // implied by json_hex_chars, above.
|
||||
(str[1] == '\\') &&
|
||||
(str[2] == 'u'))
|
||||
{
|
||||
/* Advance through the 16 bit surrogate, and move on to the
|
||||
* next sequence. The next step is to process the following
|
||||
* characters.
|
||||
*/
|
||||
if( !ADVANCE_CHAR(str, tok) || !ADVANCE_CHAR(str, tok) ) {
|
||||
printbuf_memappend_fast(tok->pb,
|
||||
(char*) utf8_replacement_char, 3);
|
||||
}
|
||||
/* Advance to the first char of the next sequence and
|
||||
* continue processing with the next sequence.
|
||||
*/
|
||||
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
|
||||
printbuf_memappend_fast(tok->pb,
|
||||
(char*) utf8_replacement_char, 3);
|
||||
goto out;
|
||||
}
|
||||
tok->ucs_char = 0;
|
||||
tok->st_pos = 0;
|
||||
continue; /* other json_tokener_state_escape_unicode */
|
||||
} else {
|
||||
/* Got a high surrogate without another sequence following
|
||||
* it. Put a replacement char in for the hi surrogate
|
||||
* and pretend we finished.
|
||||
*/
|
||||
printbuf_memappend_fast(tok->pb,
|
||||
(char*) utf8_replacement_char, 3);
|
||||
}
|
||||
} else if (IS_LOW_SURROGATE(tok->ucs_char)) {
|
||||
/* Got a low surrogate not preceded by a high */
|
||||
printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
|
||||
} else if (tok->ucs_char < 0x10000) {
|
||||
unescaped_utf[0] = 0xe0 | (tok->ucs_char >> 12);
|
||||
unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f);
|
||||
unescaped_utf[2] = 0x80 | (tok->ucs_char & 0x3f);
|
||||
printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 3);
|
||||
} else if (tok->ucs_char < 0x110000) {
|
||||
unescaped_utf[0] = 0xf0 | ((tok->ucs_char >> 18) & 0x07);
|
||||
unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 12) & 0x3f);
|
||||
unescaped_utf[2] = 0x80 | ((tok->ucs_char >> 6) & 0x3f);
|
||||
unescaped_utf[3] = 0x80 | (tok->ucs_char & 0x3f);
|
||||
printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 4);
|
||||
} else {
|
||||
/* Don't know what we got--insert the replacement char */
|
||||
printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
|
||||
}
|
||||
state = saved_state;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
tok->err = json_tokener_error_parse_string;
|
||||
goto out;
|
||||
}
|
||||
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
|
||||
if (got_hi_surrogate) /* Clean up any pending chars */
|
||||
printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case json_tokener_state_boolean:
|
||||
{
|
||||
int size1, size2;
|
||||
printbuf_memappend_fast(tok->pb, &c, 1);
|
||||
size1 = json_min(tok->st_pos+1, json_true_str_len);
|
||||
size2 = json_min(tok->st_pos+1, json_false_str_len);
|
||||
if((!(tok->flags & JSON_TOKENER_STRICT) &&
|
||||
strncasecmp(json_true_str, tok->pb->buf, size1) == 0)
|
||||
|| (strncmp(json_true_str, tok->pb->buf, size1) == 0)
|
||||
) {
|
||||
if(tok->st_pos == json_true_str_len) {
|
||||
current = json_object_new_boolean(1);
|
||||
if(current == NULL)
|
||||
goto out;
|
||||
saved_state = json_tokener_state_finish;
|
||||
state = json_tokener_state_eatws;
|
||||
goto redo_char;
|
||||
}
|
||||
} else if((!(tok->flags & JSON_TOKENER_STRICT) &&
|
||||
strncasecmp(json_false_str, tok->pb->buf, size2) == 0)
|
||||
|| (strncmp(json_false_str, tok->pb->buf, size2) == 0)) {
|
||||
if(tok->st_pos == json_false_str_len) {
|
||||
current = json_object_new_boolean(0);
|
||||
if(current == NULL)
|
||||
goto out;
|
||||
saved_state = json_tokener_state_finish;
|
||||
state = json_tokener_state_eatws;
|
||||
goto redo_char;
|
||||
}
|
||||
} else {
|
||||
tok->err = json_tokener_error_parse_boolean;
|
||||
goto out;
|
||||
}
|
||||
tok->st_pos++;
|
||||
}
|
||||
break;
|
||||
|
||||
case json_tokener_state_number:
|
||||
{
|
||||
/* Advance until we change state */
|
||||
const char *case_start = str;
|
||||
int case_len=0;
|
||||
int is_exponent=0;
|
||||
int negativesign_next_possible_location=1;
|
||||
while(c && strchr(json_number_chars, c)) {
|
||||
++case_len;
|
||||
|
||||
/* non-digit characters checks */
|
||||
/* note: since the main loop condition to get here was
|
||||
an input starting with 0-9 or '-', we are
|
||||
protected from input starting with '.' or
|
||||
e/E. */
|
||||
if (c == '.') {
|
||||
if (tok->is_double != 0) {
|
||||
/* '.' can only be found once, and out of the exponent part.
|
||||
Thus, if the input is already flagged as double, it
|
||||
is invalid. */
|
||||
tok->err = json_tokener_error_parse_number;
|
||||
goto out;
|
||||
}
|
||||
tok->is_double = 1;
|
||||
}
|
||||
if (c == 'e' || c == 'E') {
|
||||
if (is_exponent != 0) {
|
||||
/* only one exponent possible */
|
||||
tok->err = json_tokener_error_parse_number;
|
||||
goto out;
|
||||
}
|
||||
is_exponent = 1;
|
||||
tok->is_double = 1;
|
||||
/* the exponent part can begin with a negative sign */
|
||||
negativesign_next_possible_location = case_len + 1;
|
||||
}
|
||||
if (c == '-' && case_len != negativesign_next_possible_location) {
|
||||
/* If the negative sign is not where expected (ie
|
||||
start of input or start of exponent part), the
|
||||
input is invalid. */
|
||||
tok->err = json_tokener_error_parse_number;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
|
||||
printbuf_memappend_fast(tok->pb, case_start, case_len);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (case_len>0)
|
||||
printbuf_memappend_fast(tok->pb, case_start, case_len);
|
||||
|
||||
// Check for -Infinity
|
||||
if (tok->pb->buf[0] == '-' && case_len <= 1 &&
|
||||
(c == 'i' || c == 'I'))
|
||||
{
|
||||
state = json_tokener_state_inf;
|
||||
tok->st_pos = 0;
|
||||
goto redo_char;
|
||||
}
|
||||
}
|
||||
{
|
||||
int64_t num64;
|
||||
double numd;
|
||||
if (!tok->is_double && json_parse_int64(tok->pb->buf, &num64) == 0) {
|
||||
if (num64 && tok->pb->buf[0]=='0' &&
|
||||
(tok->flags & JSON_TOKENER_STRICT)) {
|
||||
/* in strict mode, number must not start with 0 */
|
||||
tok->err = json_tokener_error_parse_number;
|
||||
goto out;
|
||||
}
|
||||
current = json_object_new_int64(num64);
|
||||
if(current == NULL)
|
||||
goto out;
|
||||
}
|
||||
else if(tok->is_double && json_parse_double(tok->pb->buf, &numd) == 0)
|
||||
{
|
||||
current = json_object_new_double_s(numd, tok->pb->buf);
|
||||
if(current == NULL)
|
||||
goto out;
|
||||
} else {
|
||||
tok->err = json_tokener_error_parse_number;
|
||||
goto out;
|
||||
}
|
||||
saved_state = json_tokener_state_finish;
|
||||
state = json_tokener_state_eatws;
|
||||
goto redo_char;
|
||||
}
|
||||
break;
|
||||
|
||||
case json_tokener_state_array_after_sep:
|
||||
case json_tokener_state_array:
|
||||
if(c == ']') {
|
||||
if (state == json_tokener_state_array_after_sep &&
|
||||
(tok->flags & JSON_TOKENER_STRICT))
|
||||
{
|
||||
tok->err = json_tokener_error_parse_unexpected;
|
||||
goto out;
|
||||
}
|
||||
saved_state = json_tokener_state_finish;
|
||||
state = json_tokener_state_eatws;
|
||||
} else {
|
||||
if(tok->depth >= tok->max_depth-1) {
|
||||
tok->err = json_tokener_error_depth;
|
||||
goto out;
|
||||
}
|
||||
state = json_tokener_state_array_add;
|
||||
tok->depth++;
|
||||
json_tokener_reset_level(tok, tok->depth);
|
||||
goto redo_char;
|
||||
}
|
||||
break;
|
||||
|
||||
case json_tokener_state_array_add:
|
||||
if( json_object_array_add(current, obj) != 0 )
|
||||
goto out;
|
||||
saved_state = json_tokener_state_array_sep;
|
||||
state = json_tokener_state_eatws;
|
||||
goto redo_char;
|
||||
|
||||
case json_tokener_state_array_sep:
|
||||
if(c == ']') {
|
||||
saved_state = json_tokener_state_finish;
|
||||
state = json_tokener_state_eatws;
|
||||
} else if(c == ',') {
|
||||
saved_state = json_tokener_state_array_after_sep;
|
||||
state = json_tokener_state_eatws;
|
||||
} else {
|
||||
tok->err = json_tokener_error_parse_array;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
case json_tokener_state_object_field_start:
|
||||
case json_tokener_state_object_field_start_after_sep:
|
||||
if(c == '}') {
|
||||
if (state == json_tokener_state_object_field_start_after_sep &&
|
||||
(tok->flags & JSON_TOKENER_STRICT))
|
||||
{
|
||||
tok->err = json_tokener_error_parse_unexpected;
|
||||
goto out;
|
||||
}
|
||||
saved_state = json_tokener_state_finish;
|
||||
state = json_tokener_state_eatws;
|
||||
} else if (c == '"' || c == '\'') {
|
||||
tok->quote_char = c;
|
||||
printbuf_reset(tok->pb);
|
||||
state = json_tokener_state_object_field;
|
||||
} else {
|
||||
tok->err = json_tokener_error_parse_object_key_name;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
case json_tokener_state_object_field:
|
||||
{
|
||||
/* Advance until we change state */
|
||||
const char *case_start = str;
|
||||
while(1) {
|
||||
if(c == tok->quote_char) {
|
||||
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||
obj_field_name = strdup(tok->pb->buf);
|
||||
saved_state = json_tokener_state_object_field_end;
|
||||
state = json_tokener_state_eatws;
|
||||
break;
|
||||
} else if(c == '\\') {
|
||||
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||
saved_state = json_tokener_state_object_field;
|
||||
state = json_tokener_state_string_escape;
|
||||
break;
|
||||
}
|
||||
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
|
||||
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case json_tokener_state_object_field_end:
|
||||
if(c == ':') {
|
||||
saved_state = json_tokener_state_object_value;
|
||||
state = json_tokener_state_eatws;
|
||||
} else {
|
||||
tok->err = json_tokener_error_parse_object_key_sep;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
case json_tokener_state_object_value:
|
||||
if(tok->depth >= tok->max_depth-1) {
|
||||
tok->err = json_tokener_error_depth;
|
||||
goto out;
|
||||
}
|
||||
state = json_tokener_state_object_value_add;
|
||||
tok->depth++;
|
||||
json_tokener_reset_level(tok, tok->depth);
|
||||
goto redo_char;
|
||||
|
||||
case json_tokener_state_object_value_add:
|
||||
json_object_object_add(current, obj_field_name, obj);
|
||||
free(obj_field_name);
|
||||
obj_field_name = NULL;
|
||||
saved_state = json_tokener_state_object_sep;
|
||||
state = json_tokener_state_eatws;
|
||||
goto redo_char;
|
||||
|
||||
case json_tokener_state_object_sep:
|
||||
/* { */
|
||||
if(c == '}') {
|
||||
saved_state = json_tokener_state_finish;
|
||||
state = json_tokener_state_eatws;
|
||||
} else if(c == ',') {
|
||||
saved_state = json_tokener_state_object_field_start_after_sep;
|
||||
state = json_tokener_state_eatws;
|
||||
} else {
|
||||
tok->err = json_tokener_error_parse_object_value_sep;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
if (!ADVANCE_CHAR(str, tok))
|
||||
goto out;
|
||||
} /* while(PEEK_CHAR) */
|
||||
|
||||
out:
|
||||
if (c &&
|
||||
(state == json_tokener_state_finish) &&
|
||||
(tok->depth == 0) &&
|
||||
(tok->flags & JSON_TOKENER_STRICT)) {
|
||||
/* unexpected char after JSON data */
|
||||
tok->err = json_tokener_error_parse_unexpected;
|
||||
}
|
||||
if (!c) { /* We hit an eof char (0) */
|
||||
if(state != json_tokener_state_finish &&
|
||||
saved_state != json_tokener_state_finish)
|
||||
tok->err = json_tokener_error_parse_eof;
|
||||
}
|
||||
|
||||
#ifdef HAVE_USELOCALE
|
||||
uselocale(oldlocale);
|
||||
freelocale(newloc);
|
||||
#elif defined(HAVE_SETLOCALE)
|
||||
setlocale(LC_NUMERIC, oldlocale);
|
||||
free(oldlocale);
|
||||
#endif
|
||||
|
||||
if (tok->err == json_tokener_success)
|
||||
{
|
||||
json_object *ret = json_object_get(current);
|
||||
int ii;
|
||||
|
||||
/* Partially reset, so we parse additional objects on subsequent calls. */
|
||||
for(ii = tok->depth; ii >= 0; ii--)
|
||||
json_tokener_reset_level(tok, ii);
|
||||
return ret;
|
||||
}
|
||||
|
||||
MC_DEBUG("json_tokener_parse_ex: error %s at offset %d\n",
|
||||
json_tokener_errors[tok->err], tok->char_offset);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void json_tokener_set_flags(struct json_tokener *tok, int flags)
|
||||
{
|
||||
tok->flags = flags;
|
||||
}
|
||||
216
json-c/json_tokener.h
Normal file
216
json-c/json_tokener.h
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* $Id: json_tokener.h,v 1.10 2006/07/25 03:24:50 mclark Exp $
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||
* Michael Clark <michael@metaparadigm.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Methods to parse an input string into a tree of json_object objects.
|
||||
*/
|
||||
#ifndef _json_tokener_h_
|
||||
#define _json_tokener_h_
|
||||
|
||||
#include <stddef.h>
|
||||
#include "json_object.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum json_tokener_error {
|
||||
json_tokener_success,
|
||||
json_tokener_continue,
|
||||
json_tokener_error_depth,
|
||||
json_tokener_error_parse_eof,
|
||||
json_tokener_error_parse_unexpected,
|
||||
json_tokener_error_parse_null,
|
||||
json_tokener_error_parse_boolean,
|
||||
json_tokener_error_parse_number,
|
||||
json_tokener_error_parse_array,
|
||||
json_tokener_error_parse_object_key_name,
|
||||
json_tokener_error_parse_object_key_sep,
|
||||
json_tokener_error_parse_object_value_sep,
|
||||
json_tokener_error_parse_string,
|
||||
json_tokener_error_parse_comment,
|
||||
json_tokener_error_size
|
||||
};
|
||||
|
||||
enum json_tokener_state {
|
||||
json_tokener_state_eatws,
|
||||
json_tokener_state_start,
|
||||
json_tokener_state_finish,
|
||||
json_tokener_state_null,
|
||||
json_tokener_state_comment_start,
|
||||
json_tokener_state_comment,
|
||||
json_tokener_state_comment_eol,
|
||||
json_tokener_state_comment_end,
|
||||
json_tokener_state_string,
|
||||
json_tokener_state_string_escape,
|
||||
json_tokener_state_escape_unicode,
|
||||
json_tokener_state_boolean,
|
||||
json_tokener_state_number,
|
||||
json_tokener_state_array,
|
||||
json_tokener_state_array_add,
|
||||
json_tokener_state_array_sep,
|
||||
json_tokener_state_object_field_start,
|
||||
json_tokener_state_object_field,
|
||||
json_tokener_state_object_field_end,
|
||||
json_tokener_state_object_value,
|
||||
json_tokener_state_object_value_add,
|
||||
json_tokener_state_object_sep,
|
||||
json_tokener_state_array_after_sep,
|
||||
json_tokener_state_object_field_start_after_sep,
|
||||
json_tokener_state_inf
|
||||
};
|
||||
|
||||
struct json_tokener_srec
|
||||
{
|
||||
enum json_tokener_state state, saved_state;
|
||||
struct json_object *obj;
|
||||
struct json_object *current;
|
||||
char *obj_field_name;
|
||||
};
|
||||
|
||||
#define JSON_TOKENER_DEFAULT_DEPTH 32
|
||||
|
||||
struct json_tokener
|
||||
{
|
||||
char *str;
|
||||
struct printbuf *pb;
|
||||
int max_depth, depth, is_double, st_pos, char_offset;
|
||||
enum json_tokener_error err;
|
||||
unsigned int ucs_char;
|
||||
char quote_char;
|
||||
struct json_tokener_srec *stack;
|
||||
int flags;
|
||||
};
|
||||
/**
|
||||
* @deprecated Unused in json-c code
|
||||
*/
|
||||
typedef struct json_tokener json_tokener;
|
||||
|
||||
/**
|
||||
* Be strict when parsing JSON input. Use caution with
|
||||
* this flag as what is considered valid may become more
|
||||
* restrictive from one release to the next, causing your
|
||||
* code to fail on previously working input.
|
||||
*
|
||||
* This flag is not set by default.
|
||||
*
|
||||
* @see json_tokener_set_flags()
|
||||
*/
|
||||
#define JSON_TOKENER_STRICT 0x01
|
||||
|
||||
/**
|
||||
* Given an error previously returned by json_tokener_get_error(),
|
||||
* return a human readable description of the error.
|
||||
*
|
||||
* @return a generic error message is returned if an invalid error value is provided.
|
||||
*/
|
||||
const char *json_tokener_error_desc(enum json_tokener_error jerr);
|
||||
|
||||
/**
|
||||
* Retrieve the error caused by the last call to json_tokener_parse_ex(),
|
||||
* or json_tokener_success if there is no error.
|
||||
*
|
||||
* When parsing a JSON string in pieces, if the tokener is in the middle
|
||||
* of parsing this will return json_tokener_continue.
|
||||
*
|
||||
* See also json_tokener_error_desc().
|
||||
*/
|
||||
JSON_EXPORT enum json_tokener_error json_tokener_get_error(struct json_tokener *tok);
|
||||
|
||||
JSON_EXPORT struct json_tokener* json_tokener_new(void);
|
||||
JSON_EXPORT struct json_tokener* json_tokener_new_ex(int depth);
|
||||
JSON_EXPORT void json_tokener_free(struct json_tokener *tok);
|
||||
JSON_EXPORT void json_tokener_reset(struct json_tokener *tok);
|
||||
JSON_EXPORT struct json_object* json_tokener_parse(const char *str);
|
||||
JSON_EXPORT struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error);
|
||||
|
||||
/**
|
||||
* Set flags that control how parsing will be done.
|
||||
*/
|
||||
JSON_EXPORT void json_tokener_set_flags(struct json_tokener *tok, int flags);
|
||||
|
||||
/**
|
||||
* Parse a string and return a non-NULL json_object if a valid JSON value
|
||||
* is found. The string does not need to be a JSON object or array;
|
||||
* it can also be a string, number or boolean value.
|
||||
*
|
||||
* A partial JSON string can be parsed. If the parsing is incomplete,
|
||||
* NULL will be returned and json_tokener_get_error() will return
|
||||
* json_tokener_continue.
|
||||
* json_tokener_parse_ex() can then be called with additional bytes in str
|
||||
* to continue the parsing.
|
||||
*
|
||||
* If json_tokener_parse_ex() returns NULL and the error is anything other than
|
||||
* json_tokener_continue, a fatal error has occurred and parsing must be
|
||||
* halted. Then, the tok object must not be reused until json_tokener_reset() is
|
||||
* called.
|
||||
*
|
||||
* When a valid JSON value is parsed, a non-NULL json_object will be
|
||||
* returned. Also, json_tokener_get_error() will return json_tokener_success.
|
||||
* Be sure to check the type with json_object_is_type() or
|
||||
* json_object_get_type() before using the object.
|
||||
*
|
||||
* @b XXX this shouldn't use internal fields:
|
||||
* Trailing characters after the parsed value do not automatically cause an
|
||||
* error. It is up to the caller to decide whether to treat this as an
|
||||
* error or to handle the additional characters, perhaps by parsing another
|
||||
* json value starting from that point.
|
||||
*
|
||||
* Extra characters can be detected by comparing the tok->char_offset against
|
||||
* the length of the last len parameter passed in.
|
||||
*
|
||||
* The tokener does \b not maintain an internal buffer so the caller is
|
||||
* responsible for calling json_tokener_parse_ex with an appropriate str
|
||||
* parameter starting with the extra characters.
|
||||
*
|
||||
* This interface is presently not 64-bit clean due to the int len argument
|
||||
* so the function limits the maximum string size to INT32_MAX (2GB).
|
||||
* If the function is called with len == -1 then strlen is called to check
|
||||
* the string length is less than INT32_MAX (2GB)
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
json_object *jobj = NULL;
|
||||
const char *mystring = NULL;
|
||||
int stringlen = 0;
|
||||
enum json_tokener_error jerr;
|
||||
do {
|
||||
mystring = ... // get JSON string, e.g. read from file, etc...
|
||||
stringlen = strlen(mystring);
|
||||
jobj = json_tokener_parse_ex(tok, mystring, stringlen);
|
||||
} while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue);
|
||||
if (jerr != json_tokener_success)
|
||||
{
|
||||
fprintf(stderr, "Error: %s\n", json_tokener_error_desc(jerr));
|
||||
// Handle errors, as appropriate for your application.
|
||||
}
|
||||
if (tok->char_offset < stringlen) // XXX shouldn't access internal fields
|
||||
{
|
||||
// Handle extra characters after parsed object as desired.
|
||||
// e.g. issue an error, parse another object from that point, etc...
|
||||
}
|
||||
// Success, use jobj here.
|
||||
|
||||
@endcode
|
||||
*
|
||||
* @param tok a json_tokener previously allocated with json_tokener_new()
|
||||
* @param str an string with any valid JSON expression, or portion of. This does not need to be null terminated.
|
||||
* @param len the length of str
|
||||
*/
|
||||
JSON_EXPORT struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
|
||||
const char *str, int len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
243
json-c/json_util.c
Normal file
243
json-c/json_util.c
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* $Id: json_util.c,v 1.4 2006/01/30 23:07:57 mclark Exp $
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||
* Michael Clark <michael@metaparadigm.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#undef realloc
|
||||
|
||||
#include "strerror_override.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif /* HAVE_SYS_TYPES_H */
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif /* HAVE_SYS_STAT_H */
|
||||
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif /* HAVE_FCNTL_H */
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
|
||||
#ifdef WIN32
|
||||
# if MSC_VER < 1800
|
||||
/* strtoll is available only since Visual Studio 2013 */
|
||||
# define strtoll _strtoi64
|
||||
# endif
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
#endif /* defined(WIN32) */
|
||||
|
||||
#if !defined(HAVE_OPEN) && defined(WIN32)
|
||||
# define open _open
|
||||
#endif
|
||||
|
||||
#include "snprintf_compat.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "printbuf.h"
|
||||
#include "json_inttypes.h"
|
||||
#include "json_object.h"
|
||||
#include "json_tokener.h"
|
||||
#include "json_util.h"
|
||||
|
||||
static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const char *filename);
|
||||
|
||||
static char _last_err[256] = "";
|
||||
|
||||
const char *json_util_get_last_err()
|
||||
{
|
||||
if (_last_err[0] == '\0')
|
||||
return NULL;
|
||||
return _last_err;
|
||||
}
|
||||
|
||||
void _json_c_set_last_err(const char *err_fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, err_fmt);
|
||||
// Ignore (attempted) overruns from snprintf
|
||||
(void)vsnprintf(_last_err, sizeof(_last_err), err_fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
struct json_object* json_object_from_fd(int fd)
|
||||
{
|
||||
struct printbuf *pb;
|
||||
struct json_object *obj;
|
||||
char buf[JSON_FILE_BUF_SIZE];
|
||||
int ret;
|
||||
|
||||
if(!(pb = printbuf_new())) {
|
||||
_json_c_set_last_err("json_object_from_file: printbuf_new failed\n");
|
||||
return NULL;
|
||||
}
|
||||
while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) {
|
||||
printbuf_memappend(pb, buf, ret);
|
||||
}
|
||||
if(ret < 0) {
|
||||
_json_c_set_last_err("json_object_from_fd: error reading fd %d: %s\n", fd, strerror(errno));
|
||||
printbuf_free(pb);
|
||||
return NULL;
|
||||
}
|
||||
obj = json_tokener_parse(pb->buf);
|
||||
printbuf_free(pb);
|
||||
return obj;
|
||||
}
|
||||
|
||||
struct json_object* json_object_from_file(const char *filename)
|
||||
{
|
||||
struct json_object *obj;
|
||||
int fd;
|
||||
|
||||
if((fd = open(filename, O_RDONLY)) < 0) {
|
||||
_json_c_set_last_err("json_object_from_file: error opening file %s: %s\n",
|
||||
filename, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
obj = json_object_from_fd(fd);
|
||||
close(fd);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* extended "format and write to file" function */
|
||||
|
||||
int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags)
|
||||
{
|
||||
int fd, ret;
|
||||
int saved_errno;
|
||||
|
||||
if (!obj) {
|
||||
_json_c_set_last_err("json_object_to_file: object is null\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) {
|
||||
_json_c_set_last_err("json_object_to_file: error opening file %s: %s\n",
|
||||
filename, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
ret = _json_object_to_fd(fd, obj, flags, filename);
|
||||
saved_errno = errno;
|
||||
close(fd);
|
||||
errno = saved_errno;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int json_object_to_fd(int fd, struct json_object *obj, int flags)
|
||||
{
|
||||
if (!obj) {
|
||||
_json_c_set_last_err("json_object_to_fd: object is null\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _json_object_to_fd(fd, obj, flags, NULL);
|
||||
}
|
||||
static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const char *filename)
|
||||
{
|
||||
int ret;
|
||||
const char *json_str;
|
||||
unsigned int wpos, wsize;
|
||||
|
||||
filename = filename ? filename : "(fd)";
|
||||
|
||||
if (!(json_str = json_object_to_json_string_ext(obj,flags))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */
|
||||
wpos = 0;
|
||||
while(wpos < wsize) {
|
||||
if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) {
|
||||
_json_c_set_last_err("json_object_to_file: error writing file %s: %s\n",
|
||||
filename, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* because of the above check for ret < 0, we can safely cast and add */
|
||||
wpos += (unsigned int)ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// backwards compatible "format and write to file" function
|
||||
|
||||
int json_object_to_file(const char *filename, struct json_object *obj)
|
||||
{
|
||||
return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN);
|
||||
}
|
||||
|
||||
int json_parse_double(const char *buf, double *retval)
|
||||
{
|
||||
char *end;
|
||||
*retval = strtod(buf, &end);
|
||||
return end == buf ? 1 : 0;
|
||||
}
|
||||
|
||||
int json_parse_int64(const char *buf, int64_t *retval)
|
||||
{
|
||||
char *end = NULL;
|
||||
int64_t val;
|
||||
|
||||
errno = 0;
|
||||
val = strtoll(buf, &end, 10);
|
||||
if (end != buf)
|
||||
*retval = val;
|
||||
return ((val == 0 && errno != 0) || (end == buf)) ? 1 : 0;
|
||||
}
|
||||
|
||||
#ifndef HAVE_REALLOC
|
||||
void* rpl_realloc(void* p, size_t n)
|
||||
{
|
||||
if (n == 0)
|
||||
n = 1;
|
||||
if (p == 0)
|
||||
return malloc(n);
|
||||
return realloc(p, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define NELEM(a) (sizeof(a) / sizeof(a[0]))
|
||||
static const char* json_type_name[] = {
|
||||
/* If you change this, be sure to update the enum json_type definition too */
|
||||
"null",
|
||||
"boolean",
|
||||
"double",
|
||||
"int",
|
||||
"object",
|
||||
"array",
|
||||
"string",
|
||||
};
|
||||
|
||||
const char *json_type_to_name(enum json_type o_type)
|
||||
{
|
||||
int o_type_int = (int)o_type;
|
||||
if (o_type_int < 0 || o_type_int >= (int)NELEM(json_type_name))
|
||||
{
|
||||
_json_c_set_last_err("json_type_to_name: type %d is out of range [0,%d]\n", o_type, NELEM(json_type_name));
|
||||
return NULL;
|
||||
}
|
||||
return json_type_name[o_type];
|
||||
}
|
||||
|
||||
106
json-c/json_util.h
Normal file
106
json-c/json_util.h
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* $Id: json_util.h,v 1.4 2006/01/30 23:07:57 mclark Exp $
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||
* Michael Clark <michael@metaparadigm.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Miscllaneous utility functions and macros.
|
||||
*/
|
||||
#ifndef _json_util_h_
|
||||
#define _json_util_h_
|
||||
|
||||
#include "json_object.h"
|
||||
|
||||
#ifndef json_min
|
||||
#define json_min(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef json_max
|
||||
#define json_max(a,b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define JSON_FILE_BUF_SIZE 4096
|
||||
|
||||
/* utility functions */
|
||||
/**
|
||||
* Read the full contents of the given file, then convert it to a
|
||||
* json_object using json_tokener_parse().
|
||||
*
|
||||
* Returns -1 if something fails. See json_util_get_last_err() for details.
|
||||
*/
|
||||
extern struct json_object* json_object_from_file(const char *filename);
|
||||
|
||||
/**
|
||||
* Create a JSON object from already opened file descriptor.
|
||||
*
|
||||
* This function can be helpful, when you opened the file already,
|
||||
* e.g. when you have a temp file.
|
||||
* Note, that the fd must be readable at the actual position, i.e.
|
||||
* use lseek(fd, 0, SEEK_SET) before.
|
||||
*
|
||||
* Returns -1 if something fails. See json_util_get_last_err() for details.
|
||||
*/
|
||||
extern struct json_object* json_object_from_fd(int fd);
|
||||
|
||||
/**
|
||||
* Equivalent to:
|
||||
* json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN);
|
||||
*
|
||||
* Returns -1 if something fails. See json_util_get_last_err() for details.
|
||||
*/
|
||||
extern int json_object_to_file(const char *filename, struct json_object *obj);
|
||||
|
||||
/**
|
||||
* Open and truncate the given file, creating it if necessary, then
|
||||
* convert the json_object to a string and write it to the file.
|
||||
*
|
||||
* Returns -1 if something fails. See json_util_get_last_err() for details.
|
||||
*/
|
||||
extern int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags);
|
||||
|
||||
/**
|
||||
* Convert the json_object to a string and write it to the file descriptor.
|
||||
* Handles partial writes and will keep writing until done, or an error
|
||||
* occurs.
|
||||
*
|
||||
* @param fd an open, writable file descriptor to write to
|
||||
* @param obj the object to serializer and write
|
||||
* @param flags flags to pass to json_object_to_json_string_ext()
|
||||
* @return -1 if something fails. See json_util_get_last_err() for details.
|
||||
*/
|
||||
extern int json_object_to_fd(int fd, struct json_object *obj, int flags);
|
||||
|
||||
/**
|
||||
* Return the last error from various json-c functions, including:
|
||||
* json_object_to_file{,_ext}, json_object_to_fd() or
|
||||
* json_object_from_{file,fd}, or NULL if there is none.
|
||||
*/
|
||||
const char *json_util_get_last_err(void);
|
||||
|
||||
|
||||
extern int json_parse_int64(const char *buf, int64_t *retval);
|
||||
extern int json_parse_double(const char *buf, double *retval);
|
||||
|
||||
/**
|
||||
* Return a string describing the type of the object.
|
||||
* e.g. "int", or "object", etc...
|
||||
*/
|
||||
extern const char *json_type_to_name(enum json_type o_type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
133
json-c/json_visit.c
Normal file
133
json-c/json_visit.c
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Eric Haszlakiewicz
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "json_inttypes.h"
|
||||
#include "json_object.h"
|
||||
#include "json_visit.h"
|
||||
#include "linkhash.h"
|
||||
|
||||
static int _json_c_visit(json_object *jso, json_object *parent_jso,
|
||||
const char *jso_key, size_t *jso_index,
|
||||
json_c_visit_userfunc *userfunc, void *userarg);
|
||||
|
||||
int json_c_visit(json_object *jso, int future_flags,
|
||||
json_c_visit_userfunc *userfunc, void *userarg)
|
||||
{
|
||||
int ret = _json_c_visit(jso, NULL, NULL, NULL, userfunc, userarg);
|
||||
switch(ret)
|
||||
{
|
||||
case JSON_C_VISIT_RETURN_CONTINUE:
|
||||
case JSON_C_VISIT_RETURN_SKIP:
|
||||
case JSON_C_VISIT_RETURN_POP:
|
||||
case JSON_C_VISIT_RETURN_STOP:
|
||||
return 0;
|
||||
default:
|
||||
return JSON_C_VISIT_RETURN_ERROR;
|
||||
}
|
||||
}
|
||||
static int _json_c_visit(json_object *jso, json_object *parent_jso,
|
||||
const char *jso_key, size_t *jso_index,
|
||||
json_c_visit_userfunc *userfunc, void *userarg)
|
||||
{
|
||||
int userret = userfunc(jso, 0, parent_jso, jso_key, jso_index, userarg);
|
||||
switch(userret)
|
||||
{
|
||||
case JSON_C_VISIT_RETURN_CONTINUE:
|
||||
break;
|
||||
case JSON_C_VISIT_RETURN_SKIP:
|
||||
case JSON_C_VISIT_RETURN_POP:
|
||||
case JSON_C_VISIT_RETURN_STOP:
|
||||
case JSON_C_VISIT_RETURN_ERROR:
|
||||
return userret;
|
||||
default:
|
||||
fprintf(stderr, "ERROR: invalid return value from json_c_visit userfunc: %d\n", userret);
|
||||
return JSON_C_VISIT_RETURN_ERROR;
|
||||
}
|
||||
|
||||
switch(json_object_get_type(jso))
|
||||
{
|
||||
case json_type_null:
|
||||
case json_type_boolean:
|
||||
case json_type_double:
|
||||
case json_type_int:
|
||||
case json_type_string:
|
||||
// we already called userfunc above, move on to the next object
|
||||
return JSON_C_VISIT_RETURN_CONTINUE;
|
||||
|
||||
case json_type_object:
|
||||
{
|
||||
json_object_object_foreach(jso, key, child)
|
||||
{
|
||||
userret = _json_c_visit(child, jso, key, NULL, userfunc, userarg);
|
||||
if (userret == JSON_C_VISIT_RETURN_POP)
|
||||
break;
|
||||
if (userret == JSON_C_VISIT_RETURN_STOP ||
|
||||
userret == JSON_C_VISIT_RETURN_ERROR)
|
||||
return userret;
|
||||
if (userret != JSON_C_VISIT_RETURN_CONTINUE &&
|
||||
userret != JSON_C_VISIT_RETURN_SKIP)
|
||||
{
|
||||
fprintf(stderr, "INTERNAL ERROR: _json_c_visit returned %d\n", userret);
|
||||
return JSON_C_VISIT_RETURN_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case json_type_array:
|
||||
{
|
||||
size_t array_len = json_object_array_length(jso);
|
||||
size_t ii;
|
||||
for (ii = 0; ii < array_len; ii++)
|
||||
{
|
||||
json_object *child = json_object_array_get_idx(jso, ii);
|
||||
userret = _json_c_visit(child, jso, NULL, &ii, userfunc, userarg);
|
||||
if (userret == JSON_C_VISIT_RETURN_POP)
|
||||
break;
|
||||
if (userret == JSON_C_VISIT_RETURN_STOP ||
|
||||
userret == JSON_C_VISIT_RETURN_ERROR)
|
||||
return userret;
|
||||
if (userret != JSON_C_VISIT_RETURN_CONTINUE &&
|
||||
userret != JSON_C_VISIT_RETURN_SKIP)
|
||||
{
|
||||
fprintf(stderr, "INTERNAL ERROR: _json_c_visit returned %d\n", userret);
|
||||
return JSON_C_VISIT_RETURN_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "INTERNAL ERROR: _json_c_visit found object of unknown type: %d\n", json_object_get_type(jso));
|
||||
return JSON_C_VISIT_RETURN_ERROR;
|
||||
}
|
||||
|
||||
// Call userfunc for the second type on container types, after all
|
||||
// members of the container have been visited.
|
||||
// Non-container types will have already returned before this point.
|
||||
|
||||
userret = userfunc(jso, JSON_C_VISIT_SECOND, parent_jso, jso_key, jso_index, userarg);
|
||||
switch(userret)
|
||||
{
|
||||
case JSON_C_VISIT_RETURN_SKIP:
|
||||
case JSON_C_VISIT_RETURN_POP:
|
||||
// These are not really sensible during JSON_C_VISIT_SECOND,
|
||||
// but map them to JSON_C_VISIT_CONTINUE anyway.
|
||||
// FALLTHROUGH
|
||||
case JSON_C_VISIT_RETURN_CONTINUE:
|
||||
return JSON_C_VISIT_RETURN_CONTINUE;
|
||||
case JSON_C_VISIT_RETURN_STOP:
|
||||
case JSON_C_VISIT_RETURN_ERROR:
|
||||
return userret;
|
||||
default:
|
||||
fprintf(stderr, "ERROR: invalid return value from json_c_visit userfunc: %d\n", userret);
|
||||
return JSON_C_VISIT_RETURN_ERROR;
|
||||
}
|
||||
// NOTREACHED
|
||||
}
|
||||
|
||||
95
json-c/json_visit.h
Normal file
95
json-c/json_visit.h
Normal file
@ -0,0 +1,95 @@
|
||||
|
||||
#ifndef _json_c_json_visit_h_
|
||||
#define _json_c_json_visit_h_
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Methods for walking a tree of objects.
|
||||
*/
|
||||
#include "json_object.h"
|
||||
|
||||
typedef int (json_c_visit_userfunc)(json_object *jso, int flags,
|
||||
json_object *parent_jso, const char *jso_key,
|
||||
size_t *jso_index, void *userarg);
|
||||
|
||||
/**
|
||||
* Visit each object in the JSON hierarchy starting at jso.
|
||||
* For each object, userfunc is called, passing the object and userarg.
|
||||
* If the object has a parent (i.e. anything other than jso itself)
|
||||
* its parent will be passed as parent_jso, and either jso_key or jso_index
|
||||
* will be set, depending on whether the parent is an object or an array.
|
||||
*
|
||||
* Nodes will be visited depth first, but containers (arrays and objects)
|
||||
* will be visited twice, the second time with JSON_C_VISIT_SECOND set in
|
||||
* flags.
|
||||
*
|
||||
* userfunc must return one of the defined return values, to indicate
|
||||
* whether and how to continue visiting nodes, or one of various ways to stop.
|
||||
*
|
||||
* Returns 0 if nodes were visited successfully, even if some were
|
||||
* intentionally skipped due to what userfunc returned.
|
||||
* Returns <0 if an error occurred during iteration, including if
|
||||
* userfunc returned JSON_C_VISIT_RETURN_ERROR.
|
||||
*/
|
||||
int json_c_visit(json_object *jso, int future_flags,
|
||||
json_c_visit_userfunc *userfunc, void *userarg);
|
||||
|
||||
/**
|
||||
* Passed to json_c_visit_userfunc as one of the flags values to indicate
|
||||
* that this is the second time a container (array or object) is being
|
||||
* called, after all of it's members have been iterated over.
|
||||
*/
|
||||
#define JSON_C_VISIT_SECOND 0x02
|
||||
|
||||
/**
|
||||
* This json_c_visit_userfunc return value indicates that iteration
|
||||
* should proceed normally.
|
||||
*/
|
||||
#define JSON_C_VISIT_RETURN_CONTINUE 0
|
||||
|
||||
|
||||
/**
|
||||
* This json_c_visit_userfunc return value indicates that iteration
|
||||
* over the members of the current object should be skipped.
|
||||
* If the current object isn't a container (array or object), this
|
||||
* is no different than JSON_C_VISIT_RETURN_CONTINUE.
|
||||
*/
|
||||
#define JSON_C_VISIT_RETURN_SKIP 7547
|
||||
|
||||
/**
|
||||
* This json_c_visit_userfunc return value indicates that iteration
|
||||
* of the fields/elements of the <b>containing</b> object should stop
|
||||
* and continue "popped up" a level of the object hierarchy.
|
||||
* For example, returning this when handling arg will result in
|
||||
* arg3 and any other fields being skipped. The next call to userfunc
|
||||
* will be the JSON_C_VISIT_SECOND call on "foo", followed by a userfunc
|
||||
* call on "bar".
|
||||
* <pre>
|
||||
* {
|
||||
* "foo": {
|
||||
* "arg1": 1,
|
||||
* "arg2": 2,
|
||||
* "arg3": 3,
|
||||
* ...
|
||||
* },
|
||||
* "bar": {
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
#define JSON_C_VISIT_RETURN_POP 767
|
||||
|
||||
/**
|
||||
* This json_c_visit_userfunc return value indicates that iteration
|
||||
* should stop immediately, and cause json_c_visit to return success.
|
||||
*/
|
||||
#define JSON_C_VISIT_RETURN_STOP 7867
|
||||
|
||||
/**
|
||||
* This json_c_visit_userfunc return value indicates that iteration
|
||||
* should stop immediately, and cause json_c_visit to return an error.
|
||||
*/
|
||||
#define JSON_C_VISIT_RETURN_ERROR -1
|
||||
|
||||
#endif /* _json_c_json_visit_h_ */
|
||||
690
json-c/linkhash.c
Normal file
690
json-c/linkhash.c
Normal file
@ -0,0 +1,690 @@
|
||||
/*
|
||||
* $Id: linkhash.c,v 1.4 2006/01/26 02:16:28 mclark Exp $
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||
* Michael Clark <michael@metaparadigm.com>
|
||||
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef HAVE_ENDIAN_H
|
||||
# include <endian.h> /* attempt to define endianness */
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h> /* Get InterlockedCompareExchange */
|
||||
#endif
|
||||
|
||||
#include "random_seed.h"
|
||||
#include "linkhash.h"
|
||||
|
||||
/* hash functions */
|
||||
static unsigned long lh_char_hash(const void *k);
|
||||
static unsigned long lh_perllike_str_hash(const void *k);
|
||||
static lh_hash_fn *char_hash_fn = lh_char_hash;
|
||||
|
||||
int
|
||||
json_global_set_string_hash(const int h)
|
||||
{
|
||||
switch(h) {
|
||||
case JSON_C_STR_HASH_DFLT:
|
||||
char_hash_fn = lh_char_hash;
|
||||
break;
|
||||
case JSON_C_STR_HASH_PERLLIKE:
|
||||
char_hash_fn = lh_perllike_str_hash;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lh_abort(const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
vprintf(msg, ap);
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static unsigned long lh_ptr_hash(const void *k)
|
||||
{
|
||||
/* CAW: refactored to be 64bit nice */
|
||||
return (unsigned long)((((ptrdiff_t)k * LH_PRIME) >> 4) & ULONG_MAX);
|
||||
}
|
||||
|
||||
int lh_ptr_equal(const void *k1, const void *k2)
|
||||
{
|
||||
return (k1 == k2);
|
||||
}
|
||||
|
||||
/*
|
||||
* hashlittle from lookup3.c, by Bob Jenkins, May 2006, Public Domain.
|
||||
* http://burtleburtle.net/bob/c/lookup3.c
|
||||
* minor modifications to make functions static so no symbols are exported
|
||||
* minor mofifications to compile with -Werror
|
||||
*/
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
lookup3.c, by Bob Jenkins, May 2006, Public Domain.
|
||||
|
||||
These are functions for producing 32-bit hashes for hash table lookup.
|
||||
hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
|
||||
are externally useful functions. Routines to test the hash are included
|
||||
if SELF_TEST is defined. You can use this free for any purpose. It's in
|
||||
the public domain. It has no warranty.
|
||||
|
||||
You probably want to use hashlittle(). hashlittle() and hashbig()
|
||||
hash byte arrays. hashlittle() is is faster than hashbig() on
|
||||
little-endian machines. Intel and AMD are little-endian machines.
|
||||
On second thought, you probably want hashlittle2(), which is identical to
|
||||
hashlittle() except it returns two 32-bit hashes for the price of one.
|
||||
You could implement hashbig2() if you wanted but I haven't bothered here.
|
||||
|
||||
If you want to find a hash of, say, exactly 7 integers, do
|
||||
a = i1; b = i2; c = i3;
|
||||
mix(a,b,c);
|
||||
a += i4; b += i5; c += i6;
|
||||
mix(a,b,c);
|
||||
a += i7;
|
||||
final(a,b,c);
|
||||
then use c as the hash value. If you have a variable length array of
|
||||
4-byte integers to hash, use hashword(). If you have a byte array (like
|
||||
a character string), use hashlittle(). If you have several byte arrays, or
|
||||
a mix of things, see the comments above hashlittle().
|
||||
|
||||
Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
|
||||
then mix those integers. This is fast (you can do a lot more thorough
|
||||
mixing with 12*3 instructions on 3 integers than you can with 3 instructions
|
||||
on 1 byte), but shoehorning those bytes into integers efficiently is messy.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* My best guess at if you are big-endian or little-endian. This may
|
||||
* need adjustment.
|
||||
*/
|
||||
#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
|
||||
__BYTE_ORDER == __LITTLE_ENDIAN) || \
|
||||
(defined(i386) || defined(__i386__) || defined(__i486__) || \
|
||||
defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL))
|
||||
# define HASH_LITTLE_ENDIAN 1
|
||||
# define HASH_BIG_ENDIAN 0
|
||||
#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
|
||||
__BYTE_ORDER == __BIG_ENDIAN) || \
|
||||
(defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel))
|
||||
# define HASH_LITTLE_ENDIAN 0
|
||||
# define HASH_BIG_ENDIAN 1
|
||||
#else
|
||||
# define HASH_LITTLE_ENDIAN 0
|
||||
# define HASH_BIG_ENDIAN 0
|
||||
#endif
|
||||
|
||||
#define hashsize(n) ((uint32_t)1<<(n))
|
||||
#define hashmask(n) (hashsize(n)-1)
|
||||
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
mix -- mix 3 32-bit values reversibly.
|
||||
|
||||
This is reversible, so any information in (a,b,c) before mix() is
|
||||
still in (a,b,c) after mix().
|
||||
|
||||
If four pairs of (a,b,c) inputs are run through mix(), or through
|
||||
mix() in reverse, there are at least 32 bits of the output that
|
||||
are sometimes the same for one pair and different for another pair.
|
||||
This was tested for:
|
||||
* pairs that differed by one bit, by two bits, in any combination
|
||||
of top bits of (a,b,c), or in any combination of bottom bits of
|
||||
(a,b,c).
|
||||
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
|
||||
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
|
||||
is commonly produced by subtraction) look like a single 1-bit
|
||||
difference.
|
||||
* the base values were pseudorandom, all zero but one bit set, or
|
||||
all zero plus a counter that starts at zero.
|
||||
|
||||
Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
|
||||
satisfy this are
|
||||
4 6 8 16 19 4
|
||||
9 15 3 18 27 15
|
||||
14 9 3 7 17 3
|
||||
Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
|
||||
for "differ" defined as + with a one-bit base and a two-bit delta. I
|
||||
used http://burtleburtle.net/bob/hash/avalanche.html to choose
|
||||
the operations, constants, and arrangements of the variables.
|
||||
|
||||
This does not achieve avalanche. There are input bits of (a,b,c)
|
||||
that fail to affect some output bits of (a,b,c), especially of a. The
|
||||
most thoroughly mixed value is c, but it doesn't really even achieve
|
||||
avalanche in c.
|
||||
|
||||
This allows some parallelism. Read-after-writes are good at doubling
|
||||
the number of bits affected, so the goal of mixing pulls in the opposite
|
||||
direction as the goal of parallelism. I did what I could. Rotates
|
||||
seem to cost as much as shifts on every machine I could lay my hands
|
||||
on, and rotates are much kinder to the top and bottom bits, so I used
|
||||
rotates.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
#define mix(a,b,c) \
|
||||
{ \
|
||||
a -= c; a ^= rot(c, 4); c += b; \
|
||||
b -= a; b ^= rot(a, 6); a += c; \
|
||||
c -= b; c ^= rot(b, 8); b += a; \
|
||||
a -= c; a ^= rot(c,16); c += b; \
|
||||
b -= a; b ^= rot(a,19); a += c; \
|
||||
c -= b; c ^= rot(b, 4); b += a; \
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
final -- final mixing of 3 32-bit values (a,b,c) into c
|
||||
|
||||
Pairs of (a,b,c) values differing in only a few bits will usually
|
||||
produce values of c that look totally different. This was tested for
|
||||
* pairs that differed by one bit, by two bits, in any combination
|
||||
of top bits of (a,b,c), or in any combination of bottom bits of
|
||||
(a,b,c).
|
||||
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
|
||||
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
|
||||
is commonly produced by subtraction) look like a single 1-bit
|
||||
difference.
|
||||
* the base values were pseudorandom, all zero but one bit set, or
|
||||
all zero plus a counter that starts at zero.
|
||||
|
||||
These constants passed:
|
||||
14 11 25 16 4 14 24
|
||||
12 14 25 16 4 14 24
|
||||
and these came close:
|
||||
4 8 15 26 3 22 24
|
||||
10 8 15 26 3 22 24
|
||||
11 8 15 26 3 22 24
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
#define final(a,b,c) \
|
||||
{ \
|
||||
c ^= b; c -= rot(b,14); \
|
||||
a ^= c; a -= rot(c,11); \
|
||||
b ^= a; b -= rot(a,25); \
|
||||
c ^= b; c -= rot(b,16); \
|
||||
a ^= c; a -= rot(c,4); \
|
||||
b ^= a; b -= rot(a,14); \
|
||||
c ^= b; c -= rot(b,24); \
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
hashlittle() -- hash a variable-length key into a 32-bit value
|
||||
k : the key (the unaligned variable-length array of bytes)
|
||||
length : the length of the key, counting by bytes
|
||||
initval : can be any 4-byte value
|
||||
Returns a 32-bit value. Every bit of the key affects every bit of
|
||||
the return value. Two keys differing by one or two bits will have
|
||||
totally different hash values.
|
||||
|
||||
The best hash table sizes are powers of 2. There is no need to do
|
||||
mod a prime (mod is sooo slow!). If you need less than 32 bits,
|
||||
use a bitmask. For example, if you need only 10 bits, do
|
||||
h = (h & hashmask(10));
|
||||
In which case, the hash table should have hashsize(10) elements.
|
||||
|
||||
If you are hashing n strings (uint8_t **)k, do it like this:
|
||||
for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
|
||||
|
||||
By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
|
||||
code any way you wish, private, educational, or commercial. It's free.
|
||||
|
||||
Use for hash table lookup, or anything where one collision in 2^^32 is
|
||||
acceptable. Do NOT use for cryptographic purposes.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static uint32_t hashlittle( const void *key, size_t length, uint32_t initval)
|
||||
{
|
||||
uint32_t a,b,c; /* internal state */
|
||||
union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
|
||||
|
||||
/* Set up the internal state */
|
||||
a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
|
||||
|
||||
u.ptr = key;
|
||||
if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
|
||||
const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
|
||||
|
||||
/*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0];
|
||||
b += k[1];
|
||||
c += k[2];
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 3;
|
||||
}
|
||||
|
||||
/*----------------------------- handle the last (probably partial) block */
|
||||
/*
|
||||
* "k[2]&0xffffff" actually reads beyond the end of the string, but
|
||||
* then masks off the part it's not allowed to read. Because the
|
||||
* string is aligned, the masked-off tail is in the same word as the
|
||||
* rest of the string. Every machine with memory protection I've seen
|
||||
* does it on word boundaries, so is OK with this. But VALGRIND will
|
||||
* still catch it and complain. The masking trick does make the hash
|
||||
* noticably faster for short strings (like English words).
|
||||
* AddressSanitizer is similarly picky about overrunning
|
||||
* the buffer. (http://clang.llvm.org/docs/AddressSanitizer.html
|
||||
*/
|
||||
#ifdef VALGRIND
|
||||
# define PRECISE_MEMORY_ACCESS 1
|
||||
#elif defined(__SANITIZE_ADDRESS__) /* GCC's ASAN */
|
||||
# define PRECISE_MEMORY_ACCESS 1
|
||||
#elif defined(__has_feature)
|
||||
# if __has_feature(address_sanitizer) /* Clang's ASAN */
|
||||
# define PRECISE_MEMORY_ACCESS 1
|
||||
# endif
|
||||
#endif
|
||||
#ifndef PRECISE_MEMORY_ACCESS
|
||||
|
||||
switch(length)
|
||||
{
|
||||
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
|
||||
case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
|
||||
case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
|
||||
case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
|
||||
case 8 : b+=k[1]; a+=k[0]; break;
|
||||
case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
|
||||
case 6 : b+=k[1]&0xffff; a+=k[0]; break;
|
||||
case 5 : b+=k[1]&0xff; a+=k[0]; break;
|
||||
case 4 : a+=k[0]; break;
|
||||
case 3 : a+=k[0]&0xffffff; break;
|
||||
case 2 : a+=k[0]&0xffff; break;
|
||||
case 1 : a+=k[0]&0xff; break;
|
||||
case 0 : return c; /* zero length strings require no mixing */
|
||||
}
|
||||
|
||||
#else /* make valgrind happy */
|
||||
|
||||
const uint8_t *k8 = (const uint8_t *)k;
|
||||
switch(length)
|
||||
{
|
||||
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
|
||||
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
|
||||
case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
|
||||
case 9 : c+=k8[8]; /* fall through */
|
||||
case 8 : b+=k[1]; a+=k[0]; break;
|
||||
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
|
||||
case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
|
||||
case 5 : b+=k8[4]; /* fall through */
|
||||
case 4 : a+=k[0]; break;
|
||||
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
|
||||
case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
|
||||
case 1 : a+=k8[0]; break;
|
||||
case 0 : return c;
|
||||
}
|
||||
|
||||
#endif /* !valgrind */
|
||||
|
||||
} else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
|
||||
const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
|
||||
const uint8_t *k8;
|
||||
|
||||
/*--------------- all but last block: aligned reads and different mixing */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0] + (((uint32_t)k[1])<<16);
|
||||
b += k[2] + (((uint32_t)k[3])<<16);
|
||||
c += k[4] + (((uint32_t)k[5])<<16);
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 6;
|
||||
}
|
||||
|
||||
/*----------------------------- handle the last (probably partial) block */
|
||||
k8 = (const uint8_t *)k;
|
||||
switch(length)
|
||||
{
|
||||
case 12: c+=k[4]+(((uint32_t)k[5])<<16);
|
||||
b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
|
||||
case 10: c+=k[4];
|
||||
b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 9 : c+=k8[8]; /* fall through */
|
||||
case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
|
||||
case 6 : b+=k[2];
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 5 : b+=k8[4]; /* fall through */
|
||||
case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
|
||||
case 2 : a+=k[0];
|
||||
break;
|
||||
case 1 : a+=k8[0];
|
||||
break;
|
||||
case 0 : return c; /* zero length requires no mixing */
|
||||
}
|
||||
|
||||
} else { /* need to read the key one byte at a time */
|
||||
const uint8_t *k = (const uint8_t *)key;
|
||||
|
||||
/*--------------- all but the last block: affect some 32 bits of (a,b,c) */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0];
|
||||
a += ((uint32_t)k[1])<<8;
|
||||
a += ((uint32_t)k[2])<<16;
|
||||
a += ((uint32_t)k[3])<<24;
|
||||
b += k[4];
|
||||
b += ((uint32_t)k[5])<<8;
|
||||
b += ((uint32_t)k[6])<<16;
|
||||
b += ((uint32_t)k[7])<<24;
|
||||
c += k[8];
|
||||
c += ((uint32_t)k[9])<<8;
|
||||
c += ((uint32_t)k[10])<<16;
|
||||
c += ((uint32_t)k[11])<<24;
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 12;
|
||||
}
|
||||
|
||||
/*-------------------------------- last block: affect all 32 bits of (c) */
|
||||
switch(length) /* all the case statements fall through */
|
||||
{
|
||||
case 12: c+=((uint32_t)k[11])<<24; /* FALLTHRU */
|
||||
case 11: c+=((uint32_t)k[10])<<16; /* FALLTHRU */
|
||||
case 10: c+=((uint32_t)k[9])<<8; /* FALLTHRU */
|
||||
case 9 : c+=k[8]; /* FALLTHRU */
|
||||
case 8 : b+=((uint32_t)k[7])<<24; /* FALLTHRU */
|
||||
case 7 : b+=((uint32_t)k[6])<<16; /* FALLTHRU */
|
||||
case 6 : b+=((uint32_t)k[5])<<8; /* FALLTHRU */
|
||||
case 5 : b+=k[4]; /* FALLTHRU */
|
||||
case 4 : a+=((uint32_t)k[3])<<24; /* FALLTHRU */
|
||||
case 3 : a+=((uint32_t)k[2])<<16; /* FALLTHRU */
|
||||
case 2 : a+=((uint32_t)k[1])<<8; /* FALLTHRU */
|
||||
case 1 : a+=k[0];
|
||||
break;
|
||||
case 0 : return c;
|
||||
}
|
||||
}
|
||||
|
||||
final(a,b,c);
|
||||
return c;
|
||||
}
|
||||
|
||||
/* a simple hash function similiar to what perl does for strings.
|
||||
* for good results, the string should not be excessivly large.
|
||||
*/
|
||||
static unsigned long lh_perllike_str_hash(const void *k)
|
||||
{
|
||||
const char *rkey = (const char *)k;
|
||||
unsigned hashval = 1;
|
||||
|
||||
while (*rkey)
|
||||
hashval = hashval * 33 + *rkey++;
|
||||
|
||||
return hashval;
|
||||
}
|
||||
|
||||
static unsigned long lh_char_hash(const void *k)
|
||||
{
|
||||
#if defined _MSC_VER || defined __MINGW32__
|
||||
#define RANDOM_SEED_TYPE LONG
|
||||
#else
|
||||
#define RANDOM_SEED_TYPE int
|
||||
#endif
|
||||
static volatile RANDOM_SEED_TYPE random_seed = -1;
|
||||
|
||||
if (random_seed == -1) {
|
||||
RANDOM_SEED_TYPE seed;
|
||||
/* we can't use -1 as it is the unitialized sentinel */
|
||||
while ((seed = json_c_get_random_seed()) == -1);
|
||||
#if SIZEOF_INT == 8 && defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
|
||||
#define USE_SYNC_COMPARE_AND_SWAP 1
|
||||
#endif
|
||||
#if SIZEOF_INT == 4 && defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
|
||||
#define USE_SYNC_COMPARE_AND_SWAP 1
|
||||
#endif
|
||||
#if SIZEOF_INT == 2 && defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
|
||||
#define USE_SYNC_COMPARE_AND_SWAP 1
|
||||
#endif
|
||||
#if defined USE_SYNC_COMPARE_AND_SWAP
|
||||
(void)__sync_val_compare_and_swap(&random_seed, -1, seed);
|
||||
#elif defined _MSC_VER || defined __MINGW32__
|
||||
InterlockedCompareExchange(&random_seed, seed, -1);
|
||||
#else
|
||||
//#warning "racy random seed initializtion if used by multiple threads"
|
||||
random_seed = seed; /* potentially racy */
|
||||
#endif
|
||||
}
|
||||
|
||||
return hashlittle((const char*)k, strlen((const char*)k), random_seed);
|
||||
}
|
||||
|
||||
int lh_char_equal(const void *k1, const void *k2)
|
||||
{
|
||||
return (strcmp((const char*)k1, (const char*)k2) == 0);
|
||||
}
|
||||
|
||||
struct lh_table* lh_table_new(int size,
|
||||
lh_entry_free_fn *free_fn,
|
||||
lh_hash_fn *hash_fn,
|
||||
lh_equal_fn *equal_fn)
|
||||
{
|
||||
int i;
|
||||
struct lh_table *t;
|
||||
|
||||
t = (struct lh_table*)calloc(1, sizeof(struct lh_table));
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
t->count = 0;
|
||||
t->size = size;
|
||||
t->table = (struct lh_entry*)calloc(size, sizeof(struct lh_entry));
|
||||
if (!t->table)
|
||||
{
|
||||
free(t);
|
||||
return NULL;
|
||||
}
|
||||
t->free_fn = free_fn;
|
||||
t->hash_fn = hash_fn;
|
||||
t->equal_fn = equal_fn;
|
||||
for(i = 0; i < size; i++) t->table[i].k = LH_EMPTY;
|
||||
return t;
|
||||
}
|
||||
|
||||
struct lh_table* lh_kchar_table_new(int size,
|
||||
lh_entry_free_fn *free_fn)
|
||||
{
|
||||
return lh_table_new(size, free_fn, char_hash_fn, lh_char_equal);
|
||||
}
|
||||
|
||||
struct lh_table* lh_kptr_table_new(int size,
|
||||
lh_entry_free_fn *free_fn)
|
||||
{
|
||||
return lh_table_new(size, free_fn, lh_ptr_hash, lh_ptr_equal);
|
||||
}
|
||||
|
||||
int lh_table_resize(struct lh_table *t, int new_size)
|
||||
{
|
||||
struct lh_table *new_t;
|
||||
struct lh_entry *ent;
|
||||
|
||||
new_t = lh_table_new(new_size, NULL, t->hash_fn, t->equal_fn);
|
||||
if (new_t == NULL)
|
||||
return -1;
|
||||
|
||||
for (ent = t->head; ent != NULL; ent = ent->next)
|
||||
{
|
||||
unsigned long h = lh_get_hash(new_t, ent->k);
|
||||
unsigned int opts = 0;
|
||||
if (ent->k_is_constant)
|
||||
opts = JSON_C_OBJECT_KEY_IS_CONSTANT;
|
||||
if (lh_table_insert_w_hash(new_t, ent->k, ent->v, h, opts) != 0)
|
||||
{
|
||||
lh_table_free(new_t);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
free(t->table);
|
||||
t->table = new_t->table;
|
||||
t->size = new_size;
|
||||
t->head = new_t->head;
|
||||
t->tail = new_t->tail;
|
||||
free(new_t);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lh_table_free(struct lh_table *t)
|
||||
{
|
||||
struct lh_entry *c;
|
||||
if(t->free_fn) {
|
||||
for(c = t->head; c != NULL; c = c->next)
|
||||
t->free_fn(c);
|
||||
}
|
||||
free(t->table);
|
||||
free(t);
|
||||
}
|
||||
|
||||
|
||||
int lh_table_insert_w_hash(struct lh_table *t, const void *k, const void *v, const unsigned long h, const unsigned opts)
|
||||
{
|
||||
unsigned long n;
|
||||
|
||||
if (t->count >= t->size * LH_LOAD_FACTOR)
|
||||
if (lh_table_resize(t, t->size * 2) != 0)
|
||||
return -1;
|
||||
|
||||
n = h % t->size;
|
||||
|
||||
while( 1 ) {
|
||||
if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) break;
|
||||
if ((int)++n == t->size) n = 0;
|
||||
}
|
||||
|
||||
t->table[n].k = k;
|
||||
t->table[n].k_is_constant = (opts & JSON_C_OBJECT_KEY_IS_CONSTANT);
|
||||
t->table[n].v = v;
|
||||
t->count++;
|
||||
|
||||
if(t->head == NULL) {
|
||||
t->head = t->tail = &t->table[n];
|
||||
t->table[n].next = t->table[n].prev = NULL;
|
||||
} else {
|
||||
t->tail->next = &t->table[n];
|
||||
t->table[n].prev = t->tail;
|
||||
t->table[n].next = NULL;
|
||||
t->tail = &t->table[n];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int lh_table_insert(struct lh_table *t, const void *k, const void *v)
|
||||
{
|
||||
return lh_table_insert_w_hash(t, k, v, lh_get_hash(t, k), 0);
|
||||
}
|
||||
|
||||
|
||||
struct lh_entry* lh_table_lookup_entry_w_hash(struct lh_table *t, const void *k, const unsigned long h)
|
||||
{
|
||||
unsigned long n = h % t->size;
|
||||
int count = 0;
|
||||
|
||||
while( count < t->size ) {
|
||||
if(t->table[n].k == LH_EMPTY) return NULL;
|
||||
if(t->table[n].k != LH_FREED &&
|
||||
t->equal_fn(t->table[n].k, k)) return &t->table[n];
|
||||
if ((int)++n == t->size) n = 0;
|
||||
count++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k)
|
||||
{
|
||||
return lh_table_lookup_entry_w_hash(t, k, lh_get_hash(t, k));
|
||||
}
|
||||
|
||||
const void* lh_table_lookup(struct lh_table *t, const void *k)
|
||||
{
|
||||
void *result;
|
||||
lh_table_lookup_ex(t, k, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
json_bool lh_table_lookup_ex(struct lh_table* t, const void* k, void **v)
|
||||
{
|
||||
struct lh_entry *e = lh_table_lookup_entry(t, k);
|
||||
if (e != NULL) {
|
||||
if (v != NULL) *v = lh_entry_v(e);
|
||||
return TRUE; /* key found */
|
||||
}
|
||||
if (v != NULL) *v = NULL;
|
||||
return FALSE; /* key not found */
|
||||
}
|
||||
|
||||
int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e)
|
||||
{
|
||||
ptrdiff_t n = (ptrdiff_t)(e - t->table); /* CAW: fixed to be 64bit nice, still need the crazy negative case... */
|
||||
|
||||
/* CAW: this is bad, really bad, maybe stack goes other direction on this machine... */
|
||||
if(n < 0) { return -2; }
|
||||
|
||||
if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) return -1;
|
||||
t->count--;
|
||||
if(t->free_fn) t->free_fn(e);
|
||||
t->table[n].v = NULL;
|
||||
t->table[n].k = LH_FREED;
|
||||
if(t->tail == &t->table[n] && t->head == &t->table[n]) {
|
||||
t->head = t->tail = NULL;
|
||||
} else if (t->head == &t->table[n]) {
|
||||
t->head->next->prev = NULL;
|
||||
t->head = t->head->next;
|
||||
} else if (t->tail == &t->table[n]) {
|
||||
t->tail->prev->next = NULL;
|
||||
t->tail = t->tail->prev;
|
||||
} else {
|
||||
t->table[n].prev->next = t->table[n].next;
|
||||
t->table[n].next->prev = t->table[n].prev;
|
||||
}
|
||||
t->table[n].next = t->table[n].prev = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int lh_table_delete(struct lh_table *t, const void *k)
|
||||
{
|
||||
struct lh_entry *e = lh_table_lookup_entry(t, k);
|
||||
if(!e) return -1;
|
||||
return lh_table_delete_entry(t, e);
|
||||
}
|
||||
|
||||
int lh_table_length(struct lh_table *t)
|
||||
{
|
||||
return t->count;
|
||||
}
|
||||
406
json-c/linkhash.h
Normal file
406
json-c/linkhash.h
Normal file
@ -0,0 +1,406 @@
|
||||
/*
|
||||
* $Id: linkhash.h,v 1.6 2006/01/30 23:07:57 mclark Exp $
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||
* Michael Clark <michael@metaparadigm.com>
|
||||
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Internal methods for working with json_type_object objects. Although
|
||||
* this is exposed by the json_object_get_object() function and within the
|
||||
* json_object_iter type, it is not recommended for direct use.
|
||||
*/
|
||||
#ifndef _linkhash_h_
|
||||
#define _linkhash_h_
|
||||
|
||||
#include "json_object.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* golden prime used in hash functions
|
||||
*/
|
||||
#define LH_PRIME 0x9e370001UL
|
||||
|
||||
/**
|
||||
* The fraction of filled hash buckets until an insert will cause the table
|
||||
* to be resized.
|
||||
* This can range from just above 0 up to 1.0.
|
||||
*/
|
||||
#define LH_LOAD_FACTOR 0.66
|
||||
|
||||
/**
|
||||
* sentinel pointer value for empty slots
|
||||
*/
|
||||
#define LH_EMPTY (void*)-1
|
||||
|
||||
/**
|
||||
* sentinel pointer value for freed slots
|
||||
*/
|
||||
#define LH_FREED (void*)-2
|
||||
|
||||
/**
|
||||
* default string hash function
|
||||
*/
|
||||
#define JSON_C_STR_HASH_DFLT 0
|
||||
|
||||
/**
|
||||
* perl-like string hash function
|
||||
*/
|
||||
#define JSON_C_STR_HASH_PERLLIKE 1
|
||||
|
||||
/**
|
||||
* This function sets the hash function to be used for strings.
|
||||
* Must be one of the JSON_C_STR_HASH_* values.
|
||||
* @returns 0 - ok, -1 if parameter was invalid
|
||||
*/
|
||||
int json_global_set_string_hash(const int h);
|
||||
|
||||
struct lh_entry;
|
||||
|
||||
/**
|
||||
* callback function prototypes
|
||||
*/
|
||||
typedef void (lh_entry_free_fn) (struct lh_entry *e);
|
||||
/**
|
||||
* callback function prototypes
|
||||
*/
|
||||
typedef unsigned long (lh_hash_fn) (const void *k);
|
||||
/**
|
||||
* callback function prototypes
|
||||
*/
|
||||
typedef int (lh_equal_fn) (const void *k1, const void *k2);
|
||||
|
||||
/**
|
||||
* An entry in the hash table
|
||||
*/
|
||||
struct lh_entry {
|
||||
/**
|
||||
* The key. Use lh_entry_k() instead of accessing this directly.
|
||||
*/
|
||||
const void *k;
|
||||
/**
|
||||
* A flag for users of linkhash to know whether or not they
|
||||
* need to free k.
|
||||
*/
|
||||
int k_is_constant;
|
||||
/**
|
||||
* The value. Use lh_entry_v() instead of accessing this directly.
|
||||
*/
|
||||
const void *v;
|
||||
/**
|
||||
* The next entry
|
||||
*/
|
||||
struct lh_entry *next;
|
||||
/**
|
||||
* The previous entry.
|
||||
*/
|
||||
struct lh_entry *prev;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The hash table structure.
|
||||
*/
|
||||
struct lh_table {
|
||||
/**
|
||||
* Size of our hash.
|
||||
*/
|
||||
int size;
|
||||
/**
|
||||
* Numbers of entries.
|
||||
*/
|
||||
int count;
|
||||
|
||||
/**
|
||||
* The first entry.
|
||||
*/
|
||||
struct lh_entry *head;
|
||||
|
||||
/**
|
||||
* The last entry.
|
||||
*/
|
||||
struct lh_entry *tail;
|
||||
|
||||
struct lh_entry *table;
|
||||
|
||||
/**
|
||||
* A pointer onto the function responsible for freeing an entry.
|
||||
*/
|
||||
lh_entry_free_fn *free_fn;
|
||||
lh_hash_fn *hash_fn;
|
||||
lh_equal_fn *equal_fn;
|
||||
};
|
||||
typedef struct lh_table lh_table;
|
||||
|
||||
|
||||
/**
|
||||
* Convenience list iterator.
|
||||
*/
|
||||
#define lh_foreach(table, entry) \
|
||||
for(entry = table->head; entry; entry = entry->next)
|
||||
|
||||
/**
|
||||
* lh_foreach_safe allows calling of deletion routine while iterating.
|
||||
*
|
||||
* @param table a struct lh_table * to iterate over
|
||||
* @param entry a struct lh_entry * variable to hold each element
|
||||
* @param tmp a struct lh_entry * variable to hold a temporary pointer to the next element
|
||||
*/
|
||||
#define lh_foreach_safe(table, entry, tmp) \
|
||||
for(entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new linkhash table.
|
||||
*
|
||||
* @param size initial table size. The table is automatically resized
|
||||
* although this incurs a performance penalty.
|
||||
* @param free_fn callback function used to free memory for entries
|
||||
* when lh_table_free or lh_table_delete is called.
|
||||
* If NULL is provided, then memory for keys and values
|
||||
* must be freed by the caller.
|
||||
* @param hash_fn function used to hash keys. 2 standard ones are defined:
|
||||
* lh_ptr_hash and lh_char_hash for hashing pointer values
|
||||
* and C strings respectively.
|
||||
* @param equal_fn comparison function to compare keys. 2 standard ones defined:
|
||||
* lh_ptr_hash and lh_char_hash for comparing pointer values
|
||||
* and C strings respectively.
|
||||
* @return On success, a pointer to the new linkhash table is returned.
|
||||
* On error, a null pointer is returned.
|
||||
*/
|
||||
extern struct lh_table* lh_table_new(int size,
|
||||
lh_entry_free_fn *free_fn,
|
||||
lh_hash_fn *hash_fn,
|
||||
lh_equal_fn *equal_fn);
|
||||
|
||||
/**
|
||||
* Convenience function to create a new linkhash table with char keys.
|
||||
*
|
||||
* @param size initial table size.
|
||||
* @param free_fn callback function used to free memory for entries.
|
||||
* @return On success, a pointer to the new linkhash table is returned.
|
||||
* On error, a null pointer is returned.
|
||||
*/
|
||||
extern struct lh_table* lh_kchar_table_new(int size,
|
||||
lh_entry_free_fn *free_fn);
|
||||
|
||||
|
||||
/**
|
||||
* Convenience function to create a new linkhash table with ptr keys.
|
||||
*
|
||||
* @param size initial table size.
|
||||
* @param free_fn callback function used to free memory for entries.
|
||||
* @return On success, a pointer to the new linkhash table is returned.
|
||||
* On error, a null pointer is returned.
|
||||
*/
|
||||
extern struct lh_table* lh_kptr_table_new(int size,
|
||||
lh_entry_free_fn *free_fn);
|
||||
|
||||
|
||||
/**
|
||||
* Free a linkhash table.
|
||||
*
|
||||
* If a lh_entry_free_fn callback free function was provided then it is
|
||||
* called for all entries in the table.
|
||||
*
|
||||
* @param t table to free.
|
||||
*/
|
||||
extern void lh_table_free(struct lh_table *t);
|
||||
|
||||
|
||||
/**
|
||||
* Insert a record into the table.
|
||||
*
|
||||
* @param t the table to insert into.
|
||||
* @param k a pointer to the key to insert.
|
||||
* @param v a pointer to the value to insert.
|
||||
*
|
||||
* @return On success, <code>0</code> is returned.
|
||||
* On error, a negative value is returned.
|
||||
*/
|
||||
extern int lh_table_insert(struct lh_table *t, const void *k, const void *v);
|
||||
|
||||
|
||||
/**
|
||||
* Insert a record into the table using a precalculated key hash.
|
||||
*
|
||||
* The hash h, which should be calculated with lh_get_hash() on k, is provided by
|
||||
* the caller, to allow for optimization when multiple operations with the same
|
||||
* key are known to be needed.
|
||||
*
|
||||
* @param t the table to insert into.
|
||||
* @param k a pointer to the key to insert.
|
||||
* @param v a pointer to the value to insert.
|
||||
* @param h hash value of the key to insert
|
||||
* @param opts if set to JSON_C_OBJECT_KEY_IS_CONSTANT, sets lh_entry.k_is_constant
|
||||
* so t's free function knows to avoid freeing the key.
|
||||
*/
|
||||
extern int lh_table_insert_w_hash(struct lh_table *t, const void *k, const void *v, const unsigned long h, const unsigned opts);
|
||||
|
||||
|
||||
/**
|
||||
* Lookup a record in the table.
|
||||
*
|
||||
* @param t the table to lookup
|
||||
* @param k a pointer to the key to lookup
|
||||
* @return a pointer to the record structure of the value or NULL if it does not exist.
|
||||
*/
|
||||
extern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k);
|
||||
|
||||
/**
|
||||
* Lookup a record in the table using a precalculated key hash.
|
||||
*
|
||||
* The hash h, which should be calculated with lh_get_hash() on k, is provided by
|
||||
* the caller, to allow for optimization when multiple operations with the same
|
||||
* key are known to be needed.
|
||||
*
|
||||
* @param t the table to lookup
|
||||
* @param k a pointer to the key to lookup
|
||||
* @param h hash value of the key to lookup
|
||||
* @return a pointer to the record structure of the value or NULL if it does not exist.
|
||||
*/
|
||||
extern struct lh_entry* lh_table_lookup_entry_w_hash(struct lh_table *t, const void *k, const unsigned long h);
|
||||
|
||||
/**
|
||||
* Lookup a record into the table.
|
||||
*
|
||||
* @param t the table to lookup
|
||||
* @param k a pointer to the key to lookup
|
||||
* @return a pointer to the found value or NULL if it does not exist.
|
||||
* @deprecated Use lh_table_lookup_ex() instead.
|
||||
*/
|
||||
THIS_FUNCTION_IS_DEPRECATED(extern const void* lh_table_lookup(struct lh_table *t, const void *k));
|
||||
|
||||
/**
|
||||
* Lookup a record in the table.
|
||||
*
|
||||
* @param t the table to lookup
|
||||
* @param k a pointer to the key to lookup
|
||||
* @param v a pointer to a where to store the found value (set to NULL if it doesn't exist).
|
||||
* @return whether or not the key was found
|
||||
*/
|
||||
extern json_bool lh_table_lookup_ex(struct lh_table *t, const void *k, void **v);
|
||||
|
||||
/**
|
||||
* Delete a record from the table.
|
||||
*
|
||||
* If a callback free function is provided then it is called for the
|
||||
* for the item being deleted.
|
||||
* @param t the table to delete from.
|
||||
* @param e a pointer to the entry to delete.
|
||||
* @return 0 if the item was deleted.
|
||||
* @return -1 if it was not found.
|
||||
*/
|
||||
extern int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e);
|
||||
|
||||
|
||||
/**
|
||||
* Delete a record from the table.
|
||||
*
|
||||
* If a callback free function is provided then it is called for the
|
||||
* for the item being deleted.
|
||||
* @param t the table to delete from.
|
||||
* @param k a pointer to the key to delete.
|
||||
* @return 0 if the item was deleted.
|
||||
* @return -1 if it was not found.
|
||||
*/
|
||||
extern int lh_table_delete(struct lh_table *t, const void *k);
|
||||
|
||||
extern int lh_table_length(struct lh_table *t);
|
||||
|
||||
/**
|
||||
* Prints a message to <code>stdout</code>,
|
||||
* then exits the program with an exit code of <code>1</code>.
|
||||
*
|
||||
* @param msg Message format string, like for <code>printf</code>.
|
||||
* @param ... Format args.
|
||||
*
|
||||
* @deprecated Since it is not a good idea to exit the entire program
|
||||
* because of an internal library failure, json-c will no longer
|
||||
* use this function internally.
|
||||
* However, because its interface is public, it will remain part of
|
||||
* the API on the off chance of legacy software using it externally.
|
||||
*/
|
||||
THIS_FUNCTION_IS_DEPRECATED(void lh_abort(const char *msg, ...));
|
||||
|
||||
/**
|
||||
* Resizes the specified table.
|
||||
*
|
||||
* @param t Pointer to table to resize.
|
||||
* @param new_size New table size. Must be positive.
|
||||
*
|
||||
* @return On success, <code>0</code> is returned.
|
||||
* On error, a negative value is returned.
|
||||
*/
|
||||
int lh_table_resize(struct lh_table *t, int new_size);
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Don't use this outside of linkhash.h:
|
||||
*/
|
||||
#if !defined(_MSC_VER) || (_MSC_VER > 1800)
|
||||
/* VS2010 can't handle inline funcs, so skip it there */
|
||||
#define _LH_INLINE inline
|
||||
#else
|
||||
#define _LH_INLINE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Calculate the hash of a key for a given table.
|
||||
*
|
||||
* This is an exension to support functions that need to calculate
|
||||
* the hash several times and allows them to do it just once and then pass
|
||||
* in the hash to all utility functions. Depending on use case, this can be a
|
||||
* considerable performance improvement.
|
||||
* @param t the table (used to obtain hash function)
|
||||
* @param k a pointer to the key to lookup
|
||||
* @return the key's hash
|
||||
*/
|
||||
static _LH_INLINE unsigned long lh_get_hash(const struct lh_table *t, const void *k)
|
||||
{
|
||||
return t->hash_fn(k);
|
||||
}
|
||||
|
||||
#undef _LH_INLINE
|
||||
|
||||
/**
|
||||
* @deprecated Don't use this outside of linkhash.h:
|
||||
*/
|
||||
#ifdef __UNCONST
|
||||
#define _LH_UNCONST(a) __UNCONST(a)
|
||||
#else
|
||||
#define _LH_UNCONST(a) ((void *)(uintptr_t)(const void *)(a))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Return a non-const version of lh_entry.k.
|
||||
*
|
||||
* lh_entry.k is const to indicate and help ensure that linkhash itself doesn't modify
|
||||
* it, but callers are allowed to do what they want with it.
|
||||
* See also lh_entry.k_is_constant
|
||||
*/
|
||||
#define lh_entry_k(entry) _LH_UNCONST((entry)->k)
|
||||
|
||||
/**
|
||||
* Return a non-const version of lh_entry.v.
|
||||
*
|
||||
* v is const to indicate and help ensure that linkhash itself doesn't modify
|
||||
* it, but callers are allowed to do what they want with it.
|
||||
*/
|
||||
#define lh_entry_v(entry) _LH_UNCONST((entry)->v)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
36
json-c/math_compat.h
Normal file
36
json-c/math_compat.h
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef __math_compat_h
|
||||
#define __math_compat_h
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Do not use, json-c internal, may be changed or removed at any time.
|
||||
*/
|
||||
|
||||
/* Define isnan, isinf, infinity and nan on Windows/MSVC */
|
||||
|
||||
#ifndef HAVE_DECL_ISNAN
|
||||
# ifdef HAVE_DECL__ISNAN
|
||||
#include <float.h>
|
||||
#define isnan(x) _isnan(x)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_DECL_ISINF
|
||||
# ifdef HAVE_DECL__FINITE
|
||||
#include <float.h>
|
||||
#define isinf(x) (!_finite(x))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_DECL_INFINITY
|
||||
#include <float.h>
|
||||
#define INFINITY (DBL_MAX + DBL_MAX)
|
||||
#define HAVE_DECL_INFINITY
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_DECL_NAN
|
||||
#define NAN (INFINITY - INFINITY)
|
||||
#define HAVE_DECL_NAN
|
||||
#endif
|
||||
|
||||
#endif
|
||||
155
json-c/printbuf.c
Normal file
155
json-c/printbuf.c
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* $Id: printbuf.c,v 1.5 2006/01/26 02:16:28 mclark Exp $
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||
* Michael Clark <michael@metaparadigm.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved.
|
||||
* The copyrights to the contents of this file are licensed under the MIT License
|
||||
* (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_STDARG_H
|
||||
# include <stdarg.h>
|
||||
#else /* !HAVE_STDARG_H */
|
||||
# error Not enough var arg support!
|
||||
#endif /* HAVE_STDARG_H */
|
||||
|
||||
#include "debug.h"
|
||||
#include "printbuf.h"
|
||||
#include "snprintf_compat.h"
|
||||
#include "vasprintf_compat.h"
|
||||
|
||||
static int printbuf_extend(struct printbuf *p, int min_size);
|
||||
|
||||
struct printbuf* printbuf_new(void)
|
||||
{
|
||||
struct printbuf *p;
|
||||
|
||||
p = (struct printbuf*)calloc(1, sizeof(struct printbuf));
|
||||
if(!p) return NULL;
|
||||
p->size = 32;
|
||||
p->bpos = 0;
|
||||
if(!(p->buf = (char*)malloc(p->size))) {
|
||||
free(p);
|
||||
return NULL;
|
||||
}
|
||||
p->buf[0]= '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extend the buffer p so it has a size of at least min_size.
|
||||
*
|
||||
* If the current size is large enough, nothing is changed.
|
||||
*
|
||||
* Note: this does not check the available space! The caller
|
||||
* is responsible for performing those calculations.
|
||||
*/
|
||||
static int printbuf_extend(struct printbuf *p, int min_size)
|
||||
{
|
||||
char *t;
|
||||
int new_size;
|
||||
|
||||
if (p->size >= min_size)
|
||||
return 0;
|
||||
|
||||
new_size = p->size * 2;
|
||||
if (new_size < min_size + 8)
|
||||
new_size = min_size + 8;
|
||||
#ifdef PRINTBUF_DEBUG
|
||||
MC_DEBUG("printbuf_memappend: realloc "
|
||||
"bpos=%d min_size=%d old_size=%d new_size=%d\n",
|
||||
p->bpos, min_size, p->size, new_size);
|
||||
#endif /* PRINTBUF_DEBUG */
|
||||
if(!(t = (char*)realloc(p->buf, new_size)))
|
||||
return -1;
|
||||
p->size = new_size;
|
||||
p->buf = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int printbuf_memappend(struct printbuf *p, const char *buf, int size)
|
||||
{
|
||||
if (p->size <= p->bpos + size + 1) {
|
||||
if (printbuf_extend(p, p->bpos + size + 1) < 0)
|
||||
return -1;
|
||||
}
|
||||
memcpy(p->buf + p->bpos, buf, size);
|
||||
p->bpos += size;
|
||||
p->buf[p->bpos]= '\0';
|
||||
return size;
|
||||
}
|
||||
|
||||
int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len)
|
||||
{
|
||||
int size_needed;
|
||||
|
||||
if (offset == -1)
|
||||
offset = pb->bpos;
|
||||
size_needed = offset + len;
|
||||
if (pb->size < size_needed)
|
||||
{
|
||||
if (printbuf_extend(pb, size_needed) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(pb->buf + offset, charvalue, len);
|
||||
if (pb->bpos < size_needed)
|
||||
pb->bpos = size_needed;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sprintbuf(struct printbuf *p, const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *t;
|
||||
int size;
|
||||
char buf[128];
|
||||
|
||||
/* user stack buffer first */
|
||||
va_start(ap, msg);
|
||||
size = vsnprintf(buf, 128, msg, ap);
|
||||
va_end(ap);
|
||||
/* if string is greater than stack buffer, then use dynamic string
|
||||
with vasprintf. Note: some implementation of vsnprintf return -1
|
||||
if output is truncated whereas some return the number of bytes that
|
||||
would have been written - this code handles both cases. */
|
||||
if(size == -1 || size > 127) {
|
||||
va_start(ap, msg);
|
||||
if((size = vasprintf(&t, msg, ap)) < 0) { va_end(ap); return -1; }
|
||||
va_end(ap);
|
||||
printbuf_memappend(p, t, size);
|
||||
free(t);
|
||||
return size;
|
||||
} else {
|
||||
printbuf_memappend(p, buf, size);
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
void printbuf_reset(struct printbuf *p)
|
||||
{
|
||||
p->buf[0] = '\0';
|
||||
p->bpos = 0;
|
||||
}
|
||||
|
||||
void printbuf_free(struct printbuf *p)
|
||||
{
|
||||
if(p) {
|
||||
free(p->buf);
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
122
json-c/printbuf.h
Normal file
122
json-c/printbuf.h
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* $Id: printbuf.h,v 1.4 2006/01/26 02:16:28 mclark Exp $
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||
* Michael Clark <michael@metaparadigm.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved.
|
||||
* The copyrights to the contents of this file are licensed under the MIT License
|
||||
* (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Internal string buffer handing. Unless you're writing a
|
||||
* json_object_to_json_string_fn implementation for use with
|
||||
* json_object_set_serializer() direct use of this is not
|
||||
* recommended.
|
||||
*/
|
||||
#ifndef _printbuf_h_
|
||||
#define _printbuf_h_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct printbuf {
|
||||
char *buf;
|
||||
int bpos;
|
||||
int size;
|
||||
};
|
||||
typedef struct printbuf printbuf;
|
||||
|
||||
extern struct printbuf*
|
||||
printbuf_new(void);
|
||||
|
||||
/* As an optimization, printbuf_memappend_fast() is defined as a macro
|
||||
* that handles copying data if the buffer is large enough; otherwise
|
||||
* it invokes printbuf_memappend() which performs the heavy
|
||||
* lifting of realloc()ing the buffer and copying data.
|
||||
*
|
||||
* Your code should not use printbuf_memappend() directly unless it
|
||||
* checks the return code. Use printbuf_memappend_fast() instead.
|
||||
*/
|
||||
extern int
|
||||
printbuf_memappend(struct printbuf *p, const char *buf, int size);
|
||||
|
||||
#define printbuf_memappend_fast(p, bufptr, bufsize) \
|
||||
do { \
|
||||
if ((p->size - p->bpos) > bufsize) { \
|
||||
memcpy(p->buf + p->bpos, (bufptr), bufsize); \
|
||||
p->bpos += bufsize; \
|
||||
p->buf[p->bpos]= '\0'; \
|
||||
} else { printbuf_memappend(p, (bufptr), bufsize); } \
|
||||
} while (0)
|
||||
|
||||
#define printbuf_length(p) ((p)->bpos)
|
||||
|
||||
/**
|
||||
* Results in a compile error if the argument is not a string literal.
|
||||
*/
|
||||
#define _printbuf_check_literal(mystr) ("" mystr)
|
||||
|
||||
/**
|
||||
* This is an optimization wrapper around printbuf_memappend() that is useful
|
||||
* for appending string literals. Since the size of string constants is known
|
||||
* at compile time, using this macro can avoid a costly strlen() call. This is
|
||||
* especially helpful when a constant string must be appended many times. If
|
||||
* you got here because of a compilation error caused by passing something
|
||||
* other than a string literal, use printbuf_memappend_fast() in conjunction
|
||||
* with strlen().
|
||||
*
|
||||
* See also:
|
||||
* printbuf_memappend_fast()
|
||||
* printbuf_memappend()
|
||||
* sprintbuf()
|
||||
*/
|
||||
#define printbuf_strappend(pb, str) \
|
||||
printbuf_memappend ((pb), _printbuf_check_literal(str), sizeof(str) - 1)
|
||||
|
||||
/**
|
||||
* Set len bytes of the buffer to charvalue, starting at offset offset.
|
||||
* Similar to calling memset(x, charvalue, len);
|
||||
*
|
||||
* The memory allocated for the buffer is extended as necessary.
|
||||
*
|
||||
* If offset is -1, this starts at the end of the current data in the buffer.
|
||||
*/
|
||||
extern int
|
||||
printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len);
|
||||
|
||||
/**
|
||||
* Formatted print to printbuf.
|
||||
*
|
||||
* This function is the most expensive of the available functions for appending
|
||||
* string data to a printbuf and should be used only where convenience is more
|
||||
* important than speed. Avoid using this function in high performance code or
|
||||
* tight loops; in these scenarios, consider using snprintf() with a static
|
||||
* buffer in conjunction with one of the printbuf_*append() functions.
|
||||
*
|
||||
* See also:
|
||||
* printbuf_memappend_fast()
|
||||
* printbuf_memappend()
|
||||
* printbuf_strappend()
|
||||
*/
|
||||
extern int
|
||||
sprintbuf(struct printbuf *p, const char *msg, ...);
|
||||
|
||||
extern void
|
||||
printbuf_reset(struct printbuf *p);
|
||||
|
||||
extern void
|
||||
printbuf_free(struct printbuf *p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
238
json-c/random_seed.c
Normal file
238
json-c/random_seed.c
Normal file
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* random_seed.c
|
||||
*
|
||||
* Copyright (c) 2013 Metaparadigm Pte. Ltd.
|
||||
* Michael Clark <michael@metaparadigm.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "strerror_override.h"
|
||||
#include <stdio.h>
|
||||
#include "config.h"
|
||||
#include "random_seed.h"
|
||||
|
||||
#define DEBUG_SEED(s)
|
||||
|
||||
|
||||
#if defined ENABLE_RDRAND
|
||||
|
||||
/* cpuid */
|
||||
|
||||
#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
|
||||
#define HAS_X86_CPUID 1
|
||||
|
||||
static void do_cpuid(int regs[], int h)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
#if defined __x86_64__
|
||||
"pushq %%rbx;\n"
|
||||
#else
|
||||
"pushl %%ebx;\n"
|
||||
#endif
|
||||
"cpuid;\n"
|
||||
#if defined __x86_64__
|
||||
"popq %%rbx;\n"
|
||||
#else
|
||||
"popl %%ebx;\n"
|
||||
#endif
|
||||
: "=a"(regs[0]), [ebx] "=r"(regs[1]), "=c"(regs[2]), "=d"(regs[3])
|
||||
: "a"(h));
|
||||
}
|
||||
|
||||
#elif defined _MSC_VER
|
||||
|
||||
#define HAS_X86_CPUID 1
|
||||
#define do_cpuid __cpuid
|
||||
|
||||
#endif
|
||||
|
||||
/* has_rdrand */
|
||||
|
||||
#if HAS_X86_CPUID
|
||||
|
||||
static int has_rdrand()
|
||||
{
|
||||
// CPUID.01H:ECX.RDRAND[bit 30] == 1
|
||||
int regs[4];
|
||||
do_cpuid(regs, 1);
|
||||
return (regs[2] & (1 << 30)) != 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* get_rdrand_seed - GCC x86 and X64 */
|
||||
|
||||
#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
|
||||
|
||||
#define HAVE_RDRAND 1
|
||||
|
||||
static int get_rdrand_seed()
|
||||
{
|
||||
DEBUG_SEED("get_rdrand_seed");
|
||||
int _eax;
|
||||
// rdrand eax
|
||||
__asm__ __volatile__("1: .byte 0x0F\n"
|
||||
" .byte 0xC7\n"
|
||||
" .byte 0xF0\n"
|
||||
" jnc 1b;\n"
|
||||
: "=a" (_eax));
|
||||
return _eax;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined _MSC_VER
|
||||
|
||||
#if _MSC_VER >= 1700
|
||||
#define HAVE_RDRAND 1
|
||||
|
||||
/* get_rdrand_seed - Visual Studio 2012 and above */
|
||||
|
||||
static int get_rdrand_seed()
|
||||
{
|
||||
DEBUG_SEED("get_rdrand_seed");
|
||||
int r;
|
||||
while (_rdrand32_step(&r) == 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
#elif defined _M_IX86
|
||||
#define HAVE_RDRAND 1
|
||||
|
||||
/* get_rdrand_seed - Visual Studio 2010 and below - x86 only */
|
||||
|
||||
static int get_rdrand_seed()
|
||||
{
|
||||
DEBUG_SEED("get_rdrand_seed");
|
||||
int _eax;
|
||||
retry:
|
||||
// rdrand eax
|
||||
__asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0
|
||||
__asm jnc retry
|
||||
__asm mov _eax, eax
|
||||
return _eax;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* defined ENABLE_RDRAND */
|
||||
|
||||
|
||||
/* has_dev_urandom */
|
||||
|
||||
#if defined (__APPLE__) || defined(__unix__) || defined(__linux__)
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define HAVE_DEV_RANDOM 1
|
||||
|
||||
static const char *dev_random_file = "/dev/urandom";
|
||||
|
||||
static int has_dev_urandom()
|
||||
{
|
||||
struct stat buf;
|
||||
if (stat(dev_random_file, &buf)) {
|
||||
return 0;
|
||||
}
|
||||
return ((buf.st_mode & S_IFCHR) != 0);
|
||||
}
|
||||
|
||||
|
||||
/* get_dev_random_seed */
|
||||
|
||||
static int get_dev_random_seed()
|
||||
{
|
||||
DEBUG_SEED("get_dev_random_seed");
|
||||
|
||||
int fd = open(dev_random_file, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "error opening %s: %s", dev_random_file, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int r;
|
||||
ssize_t nread = read(fd, &r, sizeof(r));
|
||||
if (nread != sizeof(r)) {
|
||||
fprintf(stderr, "error short read %s: %s", dev_random_file, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* get_cryptgenrandom_seed */
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#define HAVE_CRYPTGENRANDOM 1
|
||||
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#ifndef __GNUC__
|
||||
#pragma comment(lib, "advapi32.lib")
|
||||
#endif
|
||||
|
||||
static int get_cryptgenrandom_seed()
|
||||
{
|
||||
HCRYPTPROV hProvider = 0;
|
||||
int r;
|
||||
|
||||
DEBUG_SEED("get_cryptgenrandom_seed");
|
||||
|
||||
if (!CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
|
||||
fprintf(stderr, "error CryptAcquireContextW");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!CryptGenRandom(hProvider, sizeof(r), (BYTE*)&r)) {
|
||||
fprintf(stderr, "error CryptGenRandom");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
CryptReleaseContext(hProvider, 0);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* get_time_seed */
|
||||
|
||||
#include <time.h>
|
||||
|
||||
static int get_time_seed()
|
||||
{
|
||||
DEBUG_SEED("get_time_seed");
|
||||
|
||||
return (int)time(NULL) * 433494437;
|
||||
}
|
||||
|
||||
|
||||
/* json_c_get_random_seed */
|
||||
|
||||
int json_c_get_random_seed()
|
||||
{
|
||||
#if HAVE_RDRAND
|
||||
if (has_rdrand()) return get_rdrand_seed();
|
||||
#endif
|
||||
#if HAVE_DEV_RANDOM
|
||||
if (has_dev_urandom()) return get_dev_random_seed();
|
||||
#endif
|
||||
#if HAVE_CRYPTGENRANDOM
|
||||
return get_cryptgenrandom_seed();
|
||||
#endif
|
||||
return get_time_seed();
|
||||
}
|
||||
29
json-c/random_seed.h
Normal file
29
json-c/random_seed.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* random_seed.h
|
||||
*
|
||||
* Copyright (c) 2013 Metaparadigm Pte. Ltd.
|
||||
* Michael Clark <michael@metaparadigm.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Do not use, json-c internal, may be changed or removed at any time.
|
||||
*/
|
||||
#ifndef seed_h
|
||||
#define seed_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int json_c_get_random_seed();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
41
json-c/snprintf_compat.h
Normal file
41
json-c/snprintf_compat.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef __snprintf_compat_h
|
||||
#define __snprintf_compat_h
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Do not use, json-c internal, may be changed or removed at any time.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Microsoft's _vsnprintf and _snprint don't always terminate
|
||||
* the string, so use wrappers that ensure that.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER)
|
||||
static int json_c_vsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||
{
|
||||
int ret;
|
||||
ret = _vsnprintf(str, size, format, ap);
|
||||
str[size - 1] = '\0';
|
||||
return ret;
|
||||
}
|
||||
#define vsnprintf json_c_vsnprintf
|
||||
|
||||
static int json_c_snprintf(char *str, size_t size, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
va_start(ap, format);
|
||||
ret = json_c_vsnprintf(str, size, format, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
#define snprintf json_c_snprintf
|
||||
|
||||
#elif !defined(HAVE_SNPRINTF) /* !HAVE_SNPRINTF */
|
||||
# error Need vsnprintf!
|
||||
#endif /* !HAVE_SNPRINTF && defined(WIN32) */
|
||||
|
||||
#endif /* __snprintf_compat_h */
|
||||
16
json-c/strdup_compat.h
Normal file
16
json-c/strdup_compat.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __strdup_compat_h
|
||||
#define __strdup_compat_h
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Do not use, json-c internal, may be changed or removed at any time.
|
||||
*/
|
||||
|
||||
#if !defined(HAVE_STRDUP) && defined(_MSC_VER)
|
||||
/* MSC has the version as _strdup */
|
||||
# define strdup _strdup
|
||||
#elif !defined(HAVE_STRDUP)
|
||||
# error You do not have strdup on your system.
|
||||
#endif /* HAVE_STRDUP */
|
||||
|
||||
#endif
|
||||
101
json-c/strerror_override.c
Normal file
101
json-c/strerror_override.c
Normal file
@ -0,0 +1,101 @@
|
||||
#define STRERROR_OVERRIDE_IMPL 1
|
||||
#include "strerror_override.h"
|
||||
|
||||
/*
|
||||
* Override strerror() to get consistent output across platforms.
|
||||
*/
|
||||
|
||||
static struct {
|
||||
int errno_value;
|
||||
const char *errno_str;
|
||||
} errno_list[] = {
|
||||
#define STRINGIFY(x) #x
|
||||
#define ENTRY(x) {x, &STRINGIFY(undef_ ## x)[6]}
|
||||
ENTRY(EPERM),
|
||||
ENTRY(ENOENT),
|
||||
ENTRY(ESRCH),
|
||||
ENTRY(EINTR),
|
||||
ENTRY(EIO),
|
||||
ENTRY(ENXIO),
|
||||
ENTRY(E2BIG),
|
||||
ENTRY(ENOEXEC),
|
||||
ENTRY(EBADF),
|
||||
ENTRY(ECHILD),
|
||||
ENTRY(EDEADLK),
|
||||
ENTRY(ENOMEM),
|
||||
ENTRY(EACCES),
|
||||
ENTRY(EFAULT),
|
||||
#ifdef ENOTBLK
|
||||
ENTRY(ENOTBLK),
|
||||
#endif
|
||||
ENTRY(EBUSY),
|
||||
ENTRY(EEXIST),
|
||||
ENTRY(EXDEV),
|
||||
ENTRY(ENODEV),
|
||||
ENTRY(ENOTDIR),
|
||||
ENTRY(EISDIR),
|
||||
ENTRY(EINVAL),
|
||||
ENTRY(ENFILE),
|
||||
ENTRY(EMFILE),
|
||||
ENTRY(ENOTTY),
|
||||
#ifdef ETXTBSY
|
||||
ENTRY(ETXTBSY),
|
||||
#endif
|
||||
ENTRY(EFBIG),
|
||||
ENTRY(ENOSPC),
|
||||
ENTRY(ESPIPE),
|
||||
ENTRY(EROFS),
|
||||
ENTRY(EMLINK),
|
||||
ENTRY(EPIPE),
|
||||
ENTRY(EDOM),
|
||||
ENTRY(ERANGE),
|
||||
ENTRY(EAGAIN),
|
||||
{ 0, (char *)0 }
|
||||
};
|
||||
|
||||
// Enabled during tests
|
||||
int _json_c_strerror_enable = 0;
|
||||
|
||||
#define PREFIX "ERRNO="
|
||||
static char errno_buf[128] = PREFIX;
|
||||
char *_json_c_strerror(int errno_in)
|
||||
{
|
||||
int start_idx;
|
||||
char digbuf[20];
|
||||
int ii, jj;
|
||||
|
||||
if (!_json_c_strerror_enable)
|
||||
return strerror(errno_in);
|
||||
|
||||
// Avoid standard functions, so we don't need to include any
|
||||
// headers, or guess at signatures.
|
||||
|
||||
for (ii = 0; errno_list[ii].errno_str != (char *)0; ii++)
|
||||
{
|
||||
const char *errno_str = errno_list[ii].errno_str;
|
||||
if (errno_list[ii].errno_value != errno_in)
|
||||
continue;
|
||||
|
||||
for (start_idx = sizeof(PREFIX) - 1, jj = 0; errno_str[jj] != '\0'; jj++, start_idx++)
|
||||
{
|
||||
errno_buf[start_idx] = errno_str[jj];
|
||||
}
|
||||
errno_buf[start_idx] = '\0';
|
||||
return errno_buf;
|
||||
}
|
||||
|
||||
// It's not one of the known errno values, return the numeric value.
|
||||
for (ii = 0; errno_in > 10; errno_in /= 10, ii++)
|
||||
{
|
||||
digbuf[ii] = "0123456789"[(errno_in % 10)];
|
||||
}
|
||||
digbuf[ii] = "0123456789"[(errno_in % 10)];
|
||||
|
||||
// Reverse the digits
|
||||
for (start_idx = sizeof(PREFIX) - 1 ; ii >= 0; ii--, start_idx++)
|
||||
{
|
||||
errno_buf[start_idx] = digbuf[ii];
|
||||
}
|
||||
return errno_buf;
|
||||
}
|
||||
|
||||
30
json-c/strerror_override.h
Normal file
30
json-c/strerror_override.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef _json_strerror_override_h_
|
||||
#define _json_strerror_override_h_
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Do not use, json-c internal, may be changed or removed at any time.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include "json_object.h" /* for JSON_EXPORT */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
JSON_EXPORT char *_json_c_strerror(int errno_in);
|
||||
|
||||
#ifndef STRERROR_OVERRIDE_IMPL
|
||||
#define strerror _json_c_strerror
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _json_strerror_override_h_ */
|
||||
12
json-c/strerror_override_private.h
Normal file
12
json-c/strerror_override_private.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef __json_strerror_override_private_h__
|
||||
#define __json_strerror_override_private_h__
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Do not use, json-c internal, may be changed or removed at any time.
|
||||
*/
|
||||
|
||||
/* Used by tests to get consistent output */
|
||||
extern int _json_c_strerror_enable;
|
||||
|
||||
#endif
|
||||
46
json-c/vasprintf_compat.h
Normal file
46
json-c/vasprintf_compat.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef __vasprintf_compat_h
|
||||
#define __vasprintf_compat_h
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Do not use, json-c internal, may be changed or removed at any time.
|
||||
*/
|
||||
|
||||
#include "snprintf_compat.h"
|
||||
|
||||
#if !defined(HAVE_VASPRINTF)
|
||||
/* CAW: compliant version of vasprintf */
|
||||
static int vasprintf(char **buf, const char *fmt, va_list ap)
|
||||
{
|
||||
#ifndef WIN32
|
||||
static char _T_emptybuffer = '\0';
|
||||
#endif /* !defined(WIN32) */
|
||||
int chars;
|
||||
char *b;
|
||||
|
||||
if(!buf) { return -1; }
|
||||
|
||||
#ifdef WIN32
|
||||
chars = _vscprintf(fmt, ap)+1;
|
||||
#else /* !defined(WIN32) */
|
||||
/* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite
|
||||
our buffer like on some 64bit sun systems.... but hey, its time to move on */
|
||||
chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap)+1;
|
||||
if(chars < 0) { chars *= -1; } /* CAW: old glibc versions have this problem */
|
||||
#endif /* defined(WIN32) */
|
||||
|
||||
b = (char*)malloc(sizeof(char)*chars);
|
||||
if(!b) { return -1; }
|
||||
|
||||
if((chars = vsprintf(b, fmt, ap)) < 0)
|
||||
{
|
||||
free(b);
|
||||
} else {
|
||||
*buf = b;
|
||||
}
|
||||
|
||||
return chars;
|
||||
}
|
||||
#endif /* !HAVE_VASPRINTF */
|
||||
|
||||
#endif /* __vasprintf_compat_h */
|
||||
581
main.c
581
main.c
@ -3,15 +3,28 @@
|
||||
#define DBG_TAG "main"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include "debug_print.h"
|
||||
#if 0
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <linux/serial.h>
|
||||
|
||||
#define DMA_START_TX _IOW('U', 0x10, struct dma_config)
|
||||
struct dma_config {
|
||||
void *buf;
|
||||
size_t len;
|
||||
};
|
||||
#endif
|
||||
pthread_t pt_uart_send;
|
||||
pthread_t pt_uart_recv_ack;
|
||||
pthread_t pt_uart_recv_data;
|
||||
pthread_t pt_uart_recv_back;
|
||||
pthread_t pt_mqtt_recv;
|
||||
pthread_t pt_readqr;
|
||||
pthread_t pt_ota;
|
||||
pthread_t pt_doota;
|
||||
pthread_t pt_mqtt;
|
||||
pthread_t pt_removelog;
|
||||
pthread_t pt_reboot;
|
||||
pthread_t pt_watchdog;
|
||||
pthread_t pt_tagsearch;
|
||||
pthread_t pt_removeduplicatetag;
|
||||
@ -22,21 +35,30 @@ mqtt_parm_t mqtt_parm={0};
|
||||
mqtt_utils_t mqtt_config;
|
||||
struct input_event buff;
|
||||
|
||||
bool newappDownloaded=false;
|
||||
bool isTimeToReboot=false;
|
||||
bool isLightOn=false;
|
||||
bool isLightOnByRule=false;
|
||||
bool isLabelUp=false;
|
||||
bool isSearchLabel=false;
|
||||
//bool isSearchLabel=false;
|
||||
bool isSearchReport=false;
|
||||
bool isSearchLabelOn=false;
|
||||
bool isLightEnable=true;
|
||||
bool isSendComEnd=true;
|
||||
jt_only_tag_t onlyTags[200]={0};
|
||||
bool isOtaEnable=false;
|
||||
bool isLEDOtaSuccess=false;
|
||||
bool isAPOtaSuccess=false;
|
||||
bool isAPBack=false;
|
||||
jt_only_tag_t onlyTags[5000]={0};
|
||||
jt_only_tag_t onlyTagsNew[5000]={0};
|
||||
int tagCount=0;
|
||||
int tagCountNew=0;
|
||||
int tagIndex=0;
|
||||
int otaCount=0;
|
||||
int fd;
|
||||
int UPCASE=0;
|
||||
int count_value=0;
|
||||
int getPayloadTime=120*1000;//usecond
|
||||
char softwareVersion[16]="1.1.9";
|
||||
char softwareVersion[16]="1.1.11";
|
||||
char stationsn[16]="TJ251372224247";//TJ250995217957
|
||||
char productid[8]="10045";
|
||||
char appKey[32]="fdhQmhqhvbL1cf1K9mUqt";
|
||||
@ -45,7 +67,7 @@ char mqttRawPassword[64]="";
|
||||
char input_value[1024]={0};//94b4e39caf1d45ee9a071d701cc037b4
|
||||
char input_value_copy[1024]={0};
|
||||
char *getDevRegisterStatusUrl="https://gaea-zt-express.com/device/modifyRegisterInfo";
|
||||
char *logUploadUrl="http://pda.pupumall.net:1180/open/api/device/log/upload";
|
||||
//char *logUploadUrl="http://pda.pupumall.net:1180/open/api/device/log/upload";
|
||||
char *getDevRawPasswordUrl="https://gaea.zt-express.com/device/modifyRegisterInfo";
|
||||
char *hostDomain="tx-mqtt.zt-express.com";
|
||||
char lightsn1[9]={0};
|
||||
@ -89,12 +111,12 @@ void do_removelog(void)
|
||||
fgets(buffer,sizeof(buffer),fp);
|
||||
logcount=atoi(buffer);
|
||||
LOG_I("logcount:%d\n",logcount);
|
||||
if(logcount>=15){
|
||||
sprintf(syscmd,"ls Log.*|head -%d|xargs rm -fr",logcount-7);
|
||||
if(logcount>=3){
|
||||
sprintf(syscmd,"ls Log.*|head -%d|xargs rm -fr",logcount-2);
|
||||
LOG_I("%s\n",syscmd);
|
||||
system(syscmd);
|
||||
}else{
|
||||
LOG_I("logcount less than 15,not remove\n");
|
||||
LOG_I("logcount less than 3,not remove\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,22 +137,159 @@ void removeLog(){
|
||||
}
|
||||
saved=atol(savedtime);
|
||||
LOG_I("now=%ld,saved=%ld,nowtime=%s,savedtime=%s\n",now,saved,nowtime,savedtime);
|
||||
if(now-saved>=(60*60*24*30)){
|
||||
if(now-saved>=(60*60*24*5)){
|
||||
//if(now-saved>=10){
|
||||
buffer_to_file("logTime",nowtime,strlen(nowtime),"wb");
|
||||
do_removelog();
|
||||
}
|
||||
sleep(60*60*10);
|
||||
sleep(60*60*1);
|
||||
}
|
||||
}
|
||||
|
||||
void checkOtaKey(void){
|
||||
int len=0;
|
||||
int keycount=0;
|
||||
char *readresult=NULL;
|
||||
while(1){
|
||||
if(isOtaEnable){
|
||||
system("echo 0 > /sys/class/gpio/gpio113/value");
|
||||
sleep(1);
|
||||
system("echo 1 > /sys/class/gpio/gpio113/value");
|
||||
sleep(1);
|
||||
}else{
|
||||
readresult=file_to_buffer("/sys/class/gpio/gpio63/value",&len);
|
||||
//LOG_I("resetKey:%s\n",readresult);
|
||||
if(readresult!=NULL){
|
||||
if(strcmp(readresult,"0\n")==0){
|
||||
keycount++;
|
||||
if(keycount==3){
|
||||
keycount=0;
|
||||
isOtaEnable=true;
|
||||
isLEDOtaSuccess=false;
|
||||
isAPOtaSuccess=false;
|
||||
isSendComEnd=true;
|
||||
LOG_I("OTA enable\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
usleep(100*1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void otaLeds(){
|
||||
#if 0
|
||||
int len=0,ver=0;
|
||||
char *readresult=NULL;
|
||||
char filename[128]={};
|
||||
uint16_t data_crc=0;
|
||||
ver=getLedOtaVersion(filename);
|
||||
LOG_I("ota %s ver:%d\n",filename,ver);
|
||||
readresult=file_to_buffer(filename,&len);
|
||||
if(readresult!=NULL){
|
||||
isSendComEnd=false;
|
||||
LOG_I("data len:%d\n",len);
|
||||
data_crc=CRC16_XMODEM(readresult,len);
|
||||
LOG_I("crc :%04x\n",data_crc);
|
||||
uart_data_send_head_ledota(&uartSend,len,data_crc,ver);//0xFF降级
|
||||
usleep(72*1000);
|
||||
int i=0;
|
||||
for(i=0;i<len/4096;i++){
|
||||
uart_data_send_ledota(&uartSend,readresult+i*4096,4096);
|
||||
usleep(72*1000);
|
||||
}
|
||||
uart_data_send_ledota(&uartSend,readresult+i*4096,len%4096);
|
||||
}
|
||||
#else
|
||||
int len=0,ver=0;
|
||||
char *readresult=NULL;
|
||||
char filename[128]={};
|
||||
uint8_t senddata[4096]={};
|
||||
uint16_t data_crc=0;
|
||||
ver=getLedOtaVersion(filename);
|
||||
LOG_I("ota %s ver:%d\n",filename,ver);
|
||||
readresult=file_to_buffer(filename,&len);
|
||||
if(readresult!=NULL){
|
||||
isSendComEnd=false;
|
||||
LOG_I("data len:%d\n",len);
|
||||
data_crc=CRC16_XMODEM(readresult,len);
|
||||
LOG_I("crc :%04x\n",data_crc);
|
||||
uart_data_send_head_ledota(&uartSend,len,data_crc,ver);//0xFF降级
|
||||
int i=0;
|
||||
for(i=0;i<len/4096;i++){
|
||||
memset(senddata,0,4096);
|
||||
memcpy(senddata,readresult+i*4096,4096);
|
||||
uart_data_send_ledota(&uartSend,senddata,4096);
|
||||
}
|
||||
memset(senddata,0,4096);
|
||||
memcpy(senddata,readresult+i*4096,len%4096);
|
||||
uart_data_send_ledota(&uartSend,senddata,len%4096);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void otaAp(){
|
||||
int len=0,ver=0;
|
||||
char *readresult=NULL;
|
||||
char filename[128]={};
|
||||
char modename[32]={};
|
||||
uint8_t dataori[2048]={0};
|
||||
uint16_t data_crc=0;
|
||||
uint16_t p_num=0;
|
||||
ver=getApOtaVersion(filename,modename);
|
||||
LOG_I("ota %s mode:%s ver:%d\n",filename,modename,ver);
|
||||
readresult=file_to_buffer(filename,&len);
|
||||
if(len%2048!=0){
|
||||
p_num=len/2048 + 1;
|
||||
}else{
|
||||
p_num=len/2048;
|
||||
}
|
||||
if(readresult!=NULL){
|
||||
isSendComEnd=false;
|
||||
LOG_I("data len:%d\n",len);
|
||||
if(strcmp(modename,"GTMODE")==0){
|
||||
uart_data_send_head_apota(&uartSend,len,p_num);
|
||||
usleep(60*1000);
|
||||
memset(dataori,0,2048);
|
||||
memcpy(dataori,readresult,2048);
|
||||
data_crc=CRC16_APOTA(dataori,2048);
|
||||
LOG_I("crc :%04x\n",data_crc);
|
||||
uart_data_send_apota(&uartSend,dataori,len,p_num,data_crc);
|
||||
while(!isAPBack){
|
||||
usleep(60*1000);
|
||||
}
|
||||
int i=0;
|
||||
for(i=1;i<len/2048;i++){
|
||||
isAPBack=false;
|
||||
memset(dataori,0,2048);
|
||||
memcpy(dataori,readresult+i*2048,2048);
|
||||
data_crc=CRC16_APOTA(dataori,2048);
|
||||
LOG_I("crc :%04x\n",data_crc);
|
||||
uart_data_send_apota(&uartSend,dataori,2048,i,data_crc);
|
||||
while(!isAPBack){
|
||||
usleep(60*1000);
|
||||
}
|
||||
}
|
||||
if(len%2048!=0){
|
||||
memset(dataori,0,2048);
|
||||
memcpy(dataori,readresult+i*2048,len%2048);
|
||||
data_crc=CRC16_APOTA(dataori,2048);
|
||||
LOG_I("crc :%04x\n",data_crc);
|
||||
uart_data_send_apota(&uartSend,dataori,2048,i,data_crc);
|
||||
}
|
||||
}else if(strcmp(modename,"DTMODE")==0){
|
||||
|
||||
}if(strcmp(modename,"HTMODE")==0){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void enableWatchDog(){
|
||||
system("echo 1 > /sys/class/gpio/export");//watchdog enable pin SGM820
|
||||
system("echo 112 > /sys/class/gpio/export");//feed watchdog pin 113 yellow
|
||||
system("echo 113 > /sys/class/gpio/export");//feed watchdog pin 113 yellow
|
||||
system("echo 112 > /sys/class/gpio/export");//feed watchdog pin 112
|
||||
system("echo out > /sys/class/gpio/gpio1/direction");
|
||||
system("echo out > /sys/class/gpio/gpio112/direction");
|
||||
system("echo out > /sys/class/gpio/gpio113/direction");
|
||||
system("echo 1 > /sys/class/gpio/gpio1/value");
|
||||
LOG_I("enable watchdog\n");
|
||||
system("echo 1 > /sys/class/gpio/gpio112/value");
|
||||
@ -147,15 +306,15 @@ void feedWatchDog(){
|
||||
}
|
||||
|
||||
void rebootSystem(void){
|
||||
while(!newappDownloaded){
|
||||
if(!newappDownloaded){
|
||||
while(!isTimeToReboot){
|
||||
if(!isTimeToReboot){
|
||||
struct tm *result;
|
||||
time_t timep;
|
||||
time (&timep);
|
||||
result = localtime(&timep);
|
||||
//printf("%d:%d:%d\n",result->tm_hour, result->tm_min, result->tm_sec);
|
||||
if(result->tm_hour==0 && result->tm_min==0 && result->tm_sec==10){
|
||||
newappDownloaded=true;
|
||||
isTimeToReboot=true;
|
||||
LOG_I("prepare to reboot\n");
|
||||
}
|
||||
}
|
||||
@ -631,7 +790,7 @@ int readQrcode()
|
||||
error:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void writeWpa(char *filename,char *ssid,char *psw){
|
||||
LOG_I("%s\n",__func__);
|
||||
buffer_to_file(filename,"# WPA-PSK/TKIP\n",strlen("# WPA-PSK/TKIP\n"),"wb");
|
||||
@ -669,18 +828,70 @@ void writeWlan(char *filename,char *netway,char *gate,char *ip){
|
||||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
void writeNetworkInterface(char *filename,char *dest){
|
||||
buffer_to_file(filename,"# interfaces(5) file used by ifup(8) and ifdown(8)",
|
||||
strlen("# interfaces(5) file used by ifup(8) and ifdown(8)"),"wb");
|
||||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||||
buffer_to_file(filename,"# Include files from /etc/network/interfaces.d:",strlen("# Include files from /etc/network/interfaces.d:"),"a");
|
||||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||||
buffer_to_file(filename,"source-directory /etc/network/interfaces.d",strlen("source-directory /etc/network/interfaces.d"),"a");
|
||||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||||
buffer_to_file(filename,"auto lo",strlen("auto lo"),"a");
|
||||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||||
buffer_to_file(filename,"iface lo inet loopback",strlen("iface lo inet loopback"),"a");
|
||||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||||
buffer_to_file(filename,"auto eth0",strlen("auto eth0"),"a");
|
||||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||||
buffer_to_file(filename,"iface eth0 inet dhcp",strlen("iface eth0 inet dhcp"),"a");
|
||||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||||
buffer_to_file(filename,"# address 192.168.1.100",strlen("# address 192.168.1.100"),"a");
|
||||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||||
buffer_to_file(filename,"# netmask 255.255.255.0",strlen("# netmask 255.255.255.0"),"a");
|
||||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||||
buffer_to_file(filename,"# gateway 192.168.1.1",strlen("# gateway 192.168.1.1"),"a");
|
||||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||||
buffer_to_file(filename,"hwaddress ether ",strlen("hwaddress ether "),"a");
|
||||
buffer_to_file(filename,dest,strlen(dest),"a");
|
||||
system("sync");
|
||||
}
|
||||
|
||||
void removeFile(char *filename){
|
||||
char cmd[32]={0};
|
||||
sprintf(cmd,"rm %s",filename);
|
||||
//LOG_I("%s\n",cmd);
|
||||
system(cmd);
|
||||
char* insert_colon(const char* src, int interval) {
|
||||
if (!src || interval <= 0) return NULL;
|
||||
|
||||
size_t len = strlen(src);
|
||||
if (len == 0) { // 空字符串返回空
|
||||
char* res = malloc(1);
|
||||
if (res) res[0] = '\0';
|
||||
return res;
|
||||
}
|
||||
|
||||
// 计算新字符串长度
|
||||
size_t sections = (len + interval - 1) / interval; // 总段数
|
||||
size_t new_len = len + (sections - 1); // 新长度 = 原长 + 冒号数
|
||||
char* new_str = malloc(new_len + 1); // 分配内存:ml-citation{ref="2" data="citationList"}
|
||||
if (!new_str) return NULL;
|
||||
|
||||
size_t src_idx = 0, dst_idx = 0;
|
||||
while (src_idx < len) {
|
||||
// 计算本次复制的字符数
|
||||
size_t copy_size = (len - src_idx < (size_t)interval) ? (len - src_idx) : (size_t)interval;
|
||||
memcpy(new_str + dst_idx, src + src_idx, copy_size); // 块复制:ml-citation{ref="3" data="citationList"}
|
||||
src_idx += copy_size;
|
||||
dst_idx += copy_size;
|
||||
|
||||
// 非末尾段时插入冒号
|
||||
if (src_idx < len) new_str[dst_idx++] = ':';
|
||||
}
|
||||
new_str[dst_idx] = '\0'; // 终止符:ml-citation{ref="7" data="citationList"}
|
||||
return new_str;
|
||||
}
|
||||
|
||||
void *actHandleQrcode(void *parm){
|
||||
char *str=(char *)parm;
|
||||
LOG_I("scan:%s\n",str);
|
||||
if(strstr(str,"{")!=NULL){
|
||||
#if 0
|
||||
char deviceSecret[64]={0};
|
||||
char deviceCode[64]={0};
|
||||
char netWorkType[64]={0};
|
||||
@ -720,9 +931,27 @@ void *actHandleQrcode(void *parm){
|
||||
sleep(1);
|
||||
system("reboot");
|
||||
}
|
||||
#endif
|
||||
}else{
|
||||
if(strstr(str,"TJ")!=NULL && strlen(str)==14){
|
||||
buffer_to_file("savedDevSn",str,strlen(str),"wb");
|
||||
if(strstr(str,"TJ")!=NULL && strlen(str)==27){
|
||||
LOG_I("ok\n");
|
||||
char *result=NULL;
|
||||
char *p;
|
||||
result=strtok_r(str,":",&p);
|
||||
while(result!=NULL){
|
||||
if(strstr(result,"TJ")!=NULL){
|
||||
LOG_I("save sn:%s\n",result);
|
||||
buffer_to_file("savedDevSn",result,strlen(result),"wb");
|
||||
}else{
|
||||
//LOG_I("save mac:%s\n",result);
|
||||
//buffer_to_file("savedDevMac",result,strlen(result),"wb");
|
||||
char* destmac = insert_colon(result, 2);
|
||||
LOG_I("save mac:%s\n",destmac);
|
||||
writeNetworkInterface("/etc/network/interfaces",destmac);
|
||||
writeNetworkInterface("/etc/network/interfaces.default",destmac);
|
||||
}
|
||||
result=strtok_r(NULL,",",&p);
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_exit(NULL);
|
||||
@ -914,6 +1143,10 @@ error:
|
||||
}
|
||||
|
||||
/*================================================================================*/
|
||||
void *thread_ota(void *arg){
|
||||
checkOtaKey();
|
||||
}
|
||||
|
||||
void *thread_mqtt(void *arg){
|
||||
mqtt_init();
|
||||
}
|
||||
@ -922,6 +1155,10 @@ void *thread_removelog(void *arg){
|
||||
removeLog();
|
||||
}
|
||||
|
||||
void *thread_reboot(void *arg){
|
||||
rebootSystem();
|
||||
}
|
||||
|
||||
void *thread_feed_watchdog(void *arg){
|
||||
feedWatchDog();
|
||||
}
|
||||
@ -933,19 +1170,32 @@ void *thread_readqr(void *arg){
|
||||
void *thread_tag_search_send(void *arg){
|
||||
while(1){
|
||||
if(isSearchLabelOn){
|
||||
isSearchLabel=true;
|
||||
uart_data_send_head_search(&uartSend,5);
|
||||
//uart_data_send_head_search(&uartSend,5);
|
||||
sleep(10);
|
||||
searchTimeNew=getCurrentTime();
|
||||
LOG_I("searchTimeNew:%d\n",searchTimeNew);
|
||||
if((searchTimeNew-searchTimeOld)>=searchTimeOut){
|
||||
isSearchLabelOn=false;
|
||||
//LOG_I("searchTimeNew:%d\n",searchTimeNew);
|
||||
if((searchTimeNew-searchTimeOld)>=(searchTimeOut-20)){
|
||||
isSearchReport=true;
|
||||
search_tag_report();
|
||||
isSearchReport=false;
|
||||
isSearchLabelOn=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *thread_do_ota(void *arg){
|
||||
while(1){
|
||||
if(isOtaEnable && isSendComEnd && !isLEDOtaSuccess){
|
||||
sleep(1);
|
||||
otaLeds();
|
||||
}
|
||||
//if(isOtaEnable && isSendComEnd && !isAPOtaSuccess){
|
||||
// otaAp();
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
//char *tag_1="00A04CCE";
|
||||
//char *tag_2="00A04C0E";
|
||||
//char *tag_3="00A04C0F";
|
||||
@ -996,12 +1246,12 @@ void *thread_uart_recv_ack(void *arg){
|
||||
uart_data_send_lighton(&uartSend,led_ctrl.ch,atoi(flash),atoi(light),tag1,tag2,tag3,tag4,tag5,lightsnNum);
|
||||
isLightOn=false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if(isSearchLabel){
|
||||
uart_data_send_search(&uartSend,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF);
|
||||
isSearchLabel=false;
|
||||
}
|
||||
|
||||
#endif
|
||||
if(isLightOnByRule){
|
||||
#if 0
|
||||
uint16_t label2=strtol("FF01",NULL,16)&0xFFFF;
|
||||
@ -1023,7 +1273,7 @@ void *thread_uart_recv_ack(void *arg){
|
||||
uint16_t flash_i=strtol(mqtt_parm.msg_flashInterval,NULL,16)&0xFFFF;
|
||||
uint16_t light_d=strtol(mqtt_parm.msg_lightDuration,NULL,16)&0xFFFF;
|
||||
uint8_t changecolor=0;
|
||||
//8灭 1红 2黄 3蓝 4绿 5青 6白 7紫 xitu
|
||||
//8灭 1红 2黄 3蓝 4绿 5青 6白 7紫 tuxi
|
||||
//0灭 1蓝 2绿 3青 4红 5紫 6黄 7白 yitaile
|
||||
if(strcmp(mqtt_parm.msg_color,"1")==0){
|
||||
changecolor=4;
|
||||
@ -1080,10 +1330,29 @@ void *thread_uart_recv_ack(void *arg){
|
||||
isLabelUp=false;
|
||||
}
|
||||
}else if(parm_ack==0x4646){
|
||||
isSendComEnd=true;
|
||||
isSendComEnd=true;
|
||||
}else if(parm_ack==0x4f4f){
|
||||
isSendComEnd=true;
|
||||
if(isOtaEnable){
|
||||
otaCount++;
|
||||
if(otaCount>=2){
|
||||
otaCount=0;
|
||||
isLEDOtaSuccess=true;
|
||||
isOtaEnable=false;
|
||||
system("echo 1 > /sys/class/gpio/gpio113/value");
|
||||
}
|
||||
}
|
||||
}else if(parm_ack==0x5252){
|
||||
uart_data_receive_version(&uartSend);
|
||||
isSendComEnd=true;
|
||||
isAPOtaSuccess=true;
|
||||
}else if(parm_ack==0x5454){
|
||||
isSendComEnd=true;
|
||||
}else if(parm_ack==0x4848){
|
||||
isAPBack=true;
|
||||
}
|
||||
}
|
||||
sleep(1);
|
||||
usleep(100*1000);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1127,14 +1396,19 @@ void *thread_uart_recv_back(void *arg){
|
||||
&count,&batteryV,&version,&ledCtrl,&lable1,&lable2,&lable3);
|
||||
//LOG_I("recv_back:%04x,%08x,%02x,%02x,%02x,%02x,%04x,%04x,%02x,%02x,%04x,%08x\n",parmAck,tagCode,tagSignal,totalLen,
|
||||
//tagFeature,count,batteryV,version,ledCtrl,lable1,lable2,lable3);
|
||||
//if(tagCode>0x90000000){
|
||||
// PutDataIntoQueue(tagCode,batteryV);
|
||||
//}
|
||||
PutDataIntoQueue(tagCode,batteryV);
|
||||
if(tagFeature==0x83){
|
||||
LOG_I("search tag:%08x,battery:%04x\n",tagCode,batteryV);
|
||||
PutDataIntoQueue(tagCode,batteryV);
|
||||
//LOG_I("search tag:%08x,battery:%04x\n",tagCode,batteryV);
|
||||
}else if(tagFeature==0x82){
|
||||
LOG_I("light down tag:%08x,battery:%04x\n",tagCode,batteryV);
|
||||
//LOG_I("light down tag:%08x,battery:%04x\n",tagCode,batteryV);
|
||||
light_off_tag_report(tagCode,batteryV);
|
||||
}else if(tagFeature==0x81){
|
||||
LOG_I("key down tag:%08x,battery:%04x\n",tagCode,batteryV);
|
||||
LOG_I("key down tag:%08x,battery:%04x,version:%4x\n",tagCode,batteryV,version);
|
||||
}else if(tagFeature==0xff){
|
||||
//LOG_I("heart tag:%08x,battery:%04x,version:%4x\n",tagCode,batteryV,version);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1156,24 +1430,77 @@ void light_off_tag_report(uint32_t name,uint16_t batteryv){
|
||||
}
|
||||
|
||||
void search_tag_report(){
|
||||
json_object *lights = NULL;
|
||||
lights=json_object_new_array();
|
||||
for(int i=0;i<tagCount;i++){
|
||||
LOG_I("onlyTags:%08X,%04x\n",onlyTags[i].name,onlyTags[i].battery);
|
||||
char tagName[9]={0};
|
||||
char battery[5]={0};
|
||||
sprintf(tagName,"%08X",onlyTags[i].name);
|
||||
sprintf(battery,"%d",onlyTags[i].battery);
|
||||
json_object *light = json_object_new_object();
|
||||
json_object_object_add(light, "sn", json_object_new_string(tagName));
|
||||
json_object_object_add(light, "battery", json_object_new_string(battery));
|
||||
json_object_array_add(lights,light);
|
||||
int report_num=0;
|
||||
int i=0,j=0,m=0,n=0;
|
||||
copyOnlyTag();
|
||||
LOG_I("%s tagCount:%d\n",__func__,tagCount);
|
||||
LOG_I("%s tagCountNew:%d\n",__func__,tagCountNew);
|
||||
if(tagCountNew>200){
|
||||
for(i=0;i<tagCountNew/200;i++){
|
||||
json_object *lights =json_object_new_array();
|
||||
for(j=i*200;j<i*200+200;j++){
|
||||
LOG_I("onlyTags:%08X,%04x\n",onlyTagsNew[j].name,onlyTagsNew[j].battery);
|
||||
char tagName[9]={0};
|
||||
char battery[5]={0};
|
||||
sprintf(tagName,"%08X",onlyTagsNew[j].name);
|
||||
sprintf(battery,"%d",onlyTagsNew[j].battery);
|
||||
json_object *light = json_object_new_object();
|
||||
json_object_object_add(light, "sn", json_object_new_string(tagName));
|
||||
json_object_object_add(light, "battery", json_object_new_string(battery));
|
||||
json_object_array_add(lights,light);
|
||||
}
|
||||
report_num+=200;
|
||||
LOG_I("report_num:%d\n",report_num);
|
||||
mqtt_server_light_status_report(stationsn,mqtt_parm.msg_messageId,"1",lights);
|
||||
}
|
||||
json_object *lights =json_object_new_array();
|
||||
for(m=i*200;m<i*200+(tagCountNew%200);m++){
|
||||
LOG_I("onlyTags:%08X,%04x\n",onlyTagsNew[m].name,onlyTagsNew[m].battery);
|
||||
char tagName[9]={0};
|
||||
char battery[5]={0};
|
||||
sprintf(tagName,"%08X",onlyTagsNew[m].name);
|
||||
sprintf(battery,"%d",onlyTagsNew[m].battery);
|
||||
json_object *light = json_object_new_object();
|
||||
json_object_object_add(light, "sn", json_object_new_string(tagName));
|
||||
json_object_object_add(light, "battery", json_object_new_string(battery));
|
||||
json_object_array_add(lights,light);
|
||||
}
|
||||
report_num+=m-i*200;
|
||||
//report_num+=tagCountNew%200;
|
||||
LOG_I("report_num:%d\n",report_num);
|
||||
mqtt_server_light_status_report(stationsn,mqtt_parm.msg_messageId,"1",lights);
|
||||
}else{
|
||||
json_object *lights =json_object_new_array();
|
||||
for(n=0;n<tagCountNew;n++){
|
||||
LOG_I("onlyTags:%08X,%04x\n",onlyTagsNew[n].name,onlyTagsNew[n].battery);
|
||||
char tagName[9]={0};
|
||||
char battery[5]={0};
|
||||
sprintf(tagName,"%08X",onlyTagsNew[n].name);
|
||||
sprintf(battery,"%d",onlyTagsNew[n].battery);
|
||||
json_object *light = json_object_new_object();
|
||||
json_object_object_add(light, "sn", json_object_new_string(tagName));
|
||||
json_object_object_add(light, "battery", json_object_new_string(battery));
|
||||
json_object_array_add(lights,light);
|
||||
}
|
||||
report_num=tagCountNew;
|
||||
LOG_I("report_num:%d\n",report_num);
|
||||
mqtt_server_light_status_report(stationsn,mqtt_parm.msg_messageId,"1",lights);
|
||||
}
|
||||
LOG_I("tagCount:%d\n",tagCount);
|
||||
mqtt_server_light_status_report(stationsn,mqtt_parm.msg_messageId,"1",lights);
|
||||
mqtt_service_reply(stationsn,mqtt_parm.msg_messageId,"ok",1,productid);
|
||||
tagCount=0;
|
||||
memset(onlyTags,0,sizeof(onlyTags));
|
||||
tagCountNew=0;
|
||||
memset(onlyTagsNew,0,5000);
|
||||
}
|
||||
|
||||
void copyOnlyTag(void){
|
||||
int i=0;
|
||||
tagCountNew=0;
|
||||
for(i=0;i<tagCount;i++){
|
||||
if(getCurrentTime()-onlyTags[i].time<=60*50){
|
||||
onlyTagsNew[tagCountNew]=onlyTags[i];
|
||||
tagCountNew++;
|
||||
}
|
||||
}
|
||||
LOG_I("tagCountNew:%d\n",tagCountNew);
|
||||
}
|
||||
|
||||
void addOnlyTag(uint32_t tagname,uint16_t battery){
|
||||
@ -1182,12 +1509,14 @@ void addOnlyTag(uint32_t tagname,uint16_t battery){
|
||||
jt_only_tag_t jt_only_tag = {
|
||||
.name=tagname,
|
||||
.battery=battery,
|
||||
.time=getCurrentTime(),
|
||||
};
|
||||
onlyTags[tagCount]=jt_only_tag;
|
||||
tagCount++;
|
||||
}else{
|
||||
for(i=0;i<tagCount;i++){
|
||||
if(tagname==onlyTags[i].name){
|
||||
onlyTags[i].time=getCurrentTime();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1195,6 +1524,7 @@ void addOnlyTag(uint32_t tagname,uint16_t battery){
|
||||
jt_only_tag_t jt_only_tag = {
|
||||
.name=tagname,
|
||||
.battery=battery,
|
||||
.time=getCurrentTime(),
|
||||
};
|
||||
onlyTags[tagCount]=jt_only_tag;
|
||||
tagCount++;
|
||||
@ -1206,9 +1536,11 @@ void *thread_remove_duplicate_tag(void *arg){
|
||||
uint32_t tagname=0;
|
||||
uint16_t battery=0;
|
||||
while(1){
|
||||
if(GetDataFromQueue(&tagname,&battery)==0){
|
||||
//LOG_I("%08x,%04x\n",tagname,battery);
|
||||
addOnlyTag(tagname,battery);
|
||||
if(!isSearchReport){
|
||||
if(GetDataFromQueue(&tagname,&battery)==0){
|
||||
//LOG_I("%08x,%04x\n",tagname,battery);
|
||||
addOnlyTag(tagname,battery);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1227,13 +1559,13 @@ void *thread_mqtt_recv(void *arg){
|
||||
if(isSendComEnd){
|
||||
if(GetDataFromMQueue(payload)==0){
|
||||
//getPayloadTime=120*1000;
|
||||
LOG_I("payload:%s\n",payload);
|
||||
//LOG_I("payload:%s\n",payload);
|
||||
get_string_from_json_string_by_key_unescape(payload,"messageId",mqtt_parm.msg_messageId,sizeof(mqtt_parm.msg_messageId));
|
||||
LOG_I("messageId:%s\n",mqtt_parm.msg_messageId);
|
||||
//LOG_I("messageId:%s\n",mqtt_parm.msg_messageId);
|
||||
if(isSearchLabelOn){
|
||||
mqtt_service_reply(stationsn,mqtt_parm.msg_messageId,"search busy",0,productid);
|
||||
}else{
|
||||
get_string_from_json_string_by_key_unescape(payload,"deviceId",mqtt_parm.msg_deviceId,sizeof(mqtt_parm.msg_deviceId));
|
||||
mqtt_service_reply(stationsn,mqtt_parm.msg_messageId,"search busy",0,productid);
|
||||
}else{
|
||||
get_string_from_json_string_by_key_unescape(payload,"deviceId",mqtt_parm.msg_deviceId,sizeof(mqtt_parm.msg_deviceId));
|
||||
LOG_I("deviceId:%s\n",mqtt_parm.msg_deviceId);
|
||||
get_int_from_json_string_by_key(payload,"timestamp",&mqtt_parm.msg_timestamp);
|
||||
LOG_I("timestamp:%d\n",mqtt_parm.msg_timestamp);
|
||||
@ -1261,6 +1593,8 @@ void *thread_mqtt_recv(void *arg){
|
||||
system("reboot");
|
||||
}else if(strcmp(mqtt_parm.msg_type,"1014")==0){
|
||||
LOG_I("1014 update fw\n");
|
||||
system("rm -fr ota");
|
||||
system("mkdir ota");
|
||||
get_int_from_json_string_by_key(msg_data, "needWifi", &mqtt_parm.msg_needWifi);
|
||||
LOG_I("needWifi:%d\n",mqtt_parm.msg_needWifi);
|
||||
get_string_from_json_string_by_key_unescape(msg_data, "zipPath", mqtt_parm.msg_zipPath, sizeof(mqtt_parm.msg_zipPath));
|
||||
@ -1275,21 +1609,27 @@ void *thread_mqtt_recv(void *arg){
|
||||
LOG_I("version:%s\n",mqtt_parm.msg_version);
|
||||
mqtt_service_reply(stationsn,mqtt_parm.msg_messageId,"ok",1,productid);
|
||||
char otaCmd[256]={0};
|
||||
sprintf(otaCmd,"curl -o /home/linaro/tx_server %s",mqtt_parm.msg_zipPath);
|
||||
sprintf(otaCmd,"curl -o /root/ota/tx_ota.zip %s",mqtt_parm.msg_zipPath);
|
||||
//sprintf(otaCmd,"curl -o /root/tx_server https://fscdn.zto.com/cloudm/iot-device-package/7d609af2165b4d14ae318f17659b2fbf.bin");
|
||||
system(otaCmd);
|
||||
sleep(8);
|
||||
sleep(15);
|
||||
system("unzip ota/tx_ota.zip");
|
||||
system("mv tx_ota/* ota");
|
||||
system("rm -fr tx_ota");
|
||||
system("mv ota/start.sh /root");
|
||||
system("sync");
|
||||
sleep(1);
|
||||
system("reboot");
|
||||
}else if(strcmp(mqtt_parm.msg_type,"5003")==0){
|
||||
LOG_I("5003 need report station info\n");
|
||||
updateStationInfo(mqtt_parm.msg_messageId);
|
||||
}else if(strcmp(mqtt_parm.msg_type,"5005")==0){
|
||||
LOG_I("5005 cloud search light\n");
|
||||
isSendComEnd=false;
|
||||
//isSendComEnd=false;
|
||||
isLightOn=false;
|
||||
isLightOnByRule=false;
|
||||
isLabelUp=false;
|
||||
isSearchLabel=true;
|
||||
//isSearchLabel=true;
|
||||
get_string_from_json_string_by_key_unescape(msg_data, "scene", mqtt_parm.msg_scene, sizeof(mqtt_parm.msg_scene));
|
||||
LOG_I("scene:%s\n",mqtt_parm.msg_scene);
|
||||
get_string_from_json_string_by_key_unescape(msg_data, "timeout", mqtt_parm.msg_timeout, sizeof(mqtt_parm.msg_timeout));
|
||||
@ -1352,7 +1692,7 @@ void *thread_mqtt_recv(void *arg){
|
||||
isLightOn=true;
|
||||
isLightOnByRule=false;
|
||||
isLabelUp=false;
|
||||
isSearchLabel=false;
|
||||
//isSearchLabel=false;
|
||||
uart_data_send_head_lighton(&uartSend,5,lightsnNum);
|
||||
}else{
|
||||
mqtt_service_reply(stationsn,mqtt_parm.msg_messageId,"light disabled or sn is null",0,productid);
|
||||
@ -1373,7 +1713,7 @@ void *thread_mqtt_recv(void *arg){
|
||||
isLightOn=false;
|
||||
isLightOnByRule=false;
|
||||
isLabelUp=true;
|
||||
isSearchLabel=false;
|
||||
//isSearchLabel=false;
|
||||
uart_data_send_head_lableup(&uartSend,5,1);
|
||||
}else{
|
||||
mqtt_service_reply(stationsn,mqtt_parm.msg_messageId,"sn is empty",0,productid);
|
||||
@ -1417,7 +1757,7 @@ void *thread_mqtt_recv(void *arg){
|
||||
isLightOn=false;
|
||||
isLightOnByRule=true;
|
||||
isLabelUp=false;
|
||||
isSearchLabel=false;
|
||||
//isSearchLabel=false;
|
||||
uart_data_send_head_lightonrule(&uartSend,5);
|
||||
}else{
|
||||
mqtt_service_reply(stationsn,mqtt_parm.msg_messageId,"labelconfig is empty",0,productid);
|
||||
@ -1452,10 +1792,46 @@ void getLocalIp(char *local_ip){
|
||||
//get_ip_by_domain(hostname, local_ip, 32);
|
||||
fp=popen("ifconfig eth0 | grep 'inet' | awk '{print $2}' | cut -d':' -f2","r");
|
||||
fgets(buffer,sizeof(buffer),fp);
|
||||
LOG_I("buffer:%s\n",buffer);
|
||||
//LOG_I("buffer:%s\n",buffer);
|
||||
memcpy(local_ip,buffer,strlen(buffer)-1);
|
||||
}
|
||||
|
||||
int getLedOtaVersion(char *filename){
|
||||
FILE *fp;
|
||||
char buffer[128]={0};
|
||||
int ver=0;
|
||||
fp=popen("ls ota/F8*.bin","r");//tx is F8 begin
|
||||
fgets(buffer,sizeof(buffer),fp);
|
||||
//LOG_I("buffer:%s\n",buffer);
|
||||
memcpy(filename,buffer,strlen(buffer)-1);
|
||||
fp=popen("ls ota/F8*.bin|cut -d'_' -f3|cut -d'.' -f3","r");
|
||||
fgets(buffer,sizeof(buffer),fp);
|
||||
//LOG_I("buffer:%s\n",buffer);
|
||||
ver=atoi(buffer);
|
||||
LOG_I("ver:%d\n",ver);
|
||||
return ver;
|
||||
}
|
||||
|
||||
int getApOtaVersion(char *filename,char *modename){
|
||||
FILE *fp;
|
||||
char buffer[128]={0};
|
||||
int ver=0;
|
||||
fp=popen("ls ota/AP*.bin","r");//AP begin
|
||||
fgets(buffer,sizeof(buffer),fp);
|
||||
//LOG_I("buffer:%s\n",buffer);
|
||||
memcpy(filename,buffer,strlen(buffer)-1);
|
||||
fp=popen("ls ota/AP*.bin|cut -d'_' -f6|cut -d'.' -f3","r");
|
||||
fgets(buffer,sizeof(buffer),fp);
|
||||
//LOG_I("buffer:%s\n",buffer);
|
||||
ver=atoi(buffer);
|
||||
LOG_I("ver:%d\n",ver);
|
||||
fp=popen("ls ota/AP*.bin|cut -d'_' -f3","r");
|
||||
fgets(buffer,sizeof(buffer),fp);
|
||||
//LOG_I("buffer:%s\n",buffer);
|
||||
memcpy(modename,buffer,strlen(buffer)-1);
|
||||
return ver;
|
||||
}
|
||||
|
||||
void saveStartUpTime(){
|
||||
system("rm ./startUpTime");
|
||||
struct timeval tv;
|
||||
@ -1506,7 +1882,7 @@ int main(int argc, char *argv[])
|
||||
uint32_t can_id;
|
||||
char recv_data[8]={0};
|
||||
char command_buffer[256] = "";
|
||||
int len=0;
|
||||
uint32_t len=0;
|
||||
int getTimeCount=0;
|
||||
char *readresult=NULL;
|
||||
char networktype[32]={0};
|
||||
@ -1515,15 +1891,27 @@ int main(int argc, char *argv[])
|
||||
system("insmod /system/lib/modules/wk2xxx_spi.ko");
|
||||
//system("busybox udhcpc -i eth0");
|
||||
system("timedatectl set-timezone Asia/Shanghai");
|
||||
uart_open(&uartSend,"/dev/ttyS0");//U12 ttyS0,U14 ttyS4,U21 ttysWK0 U13 ttysWK1 U15 ttysWK2 U22 ttysWK3 U20 ttyS1
|
||||
system("echo 63 > /sys/class/gpio/export");//reset key
|
||||
system("echo in > /sys/class/gpio/gpio63/direction");
|
||||
system("echo 113 > /sys/class/gpio/export");//pin 113 yellow
|
||||
system("echo out > /sys/class/gpio/gpio113/direction");
|
||||
uart_open(&uartSend,"/dev/ttyS0");//GT U12 ttyS0,U14 ttyS4,U21 ttysWK0 U13 ttysWK1 U15 ttysWK2 U22 ttysWK3 U20 ttyS1
|
||||
uart_init(&uartSend,115200,8,1,'N',0);
|
||||
uart_open(&uartRecvData,"/dev/ttyS4");
|
||||
uart_open(&uartRecvData,"/dev/ttyS4");//DT
|
||||
uart_init(&uartRecvData,115200,8,1,'N',0);
|
||||
|
||||
uart_open(&uartRecvBack,"/dev/ttysWK0");
|
||||
uart_open(&uartRecvBack,"/dev/ttysWK0");//HT
|
||||
uart_init(&uartRecvBack,115200,8,1,'N',0);
|
||||
#if 0
|
||||
struct dma_config cfg = {
|
||||
.buf = malloc(256),
|
||||
.len = 256
|
||||
};
|
||||
// 填充测试数据
|
||||
memset(cfg.buf, 0x55, 256);
|
||||
// 启动DMA传输
|
||||
ioctl(uartSend.uart_fd, DMA_START_TX, &cfg);
|
||||
#endif
|
||||
//doCommand_help(0, NULL);
|
||||
//sleep(5);
|
||||
#if 1
|
||||
enableWatchDog();
|
||||
ret = pthread_create(&pt_watchdog,NULL,thread_feed_watchdog,NULL);
|
||||
@ -1535,6 +1923,15 @@ int main(int argc, char *argv[])
|
||||
pthread_detach(pt_watchdog);
|
||||
}
|
||||
#endif
|
||||
ret = pthread_create(&pt_reboot,NULL,thread_reboot,NULL);
|
||||
if(ret!=0){
|
||||
LOG_I("pthread_create reboot fail\n");
|
||||
system("reboot");
|
||||
}else{
|
||||
LOG_I("pthread_create reboot success\n");
|
||||
pthread_detach(pt_reboot);
|
||||
}
|
||||
|
||||
ret = pthread_create(&pt_uart_recv_ack,NULL,thread_uart_recv_ack,NULL);
|
||||
if(ret!=0){
|
||||
LOG_I("pthread_create uart_recv_ack fail\n");
|
||||
@ -1574,6 +1971,7 @@ int main(int argc, char *argv[])
|
||||
ret = pthread_create(&pt_tagsearch,NULL,thread_tag_search_send,NULL);
|
||||
if(ret!=0){
|
||||
LOG_I("pthread_create tag search send fail\n");
|
||||
system("reboot");
|
||||
}else{
|
||||
LOG_I("pthread_create tag search success\n");
|
||||
pthread_detach(pt_tagsearch);
|
||||
@ -1582,6 +1980,7 @@ int main(int argc, char *argv[])
|
||||
ret = pthread_create(&pt_removeduplicatetag,NULL,thread_remove_duplicate_tag,NULL);
|
||||
if(ret!=0){
|
||||
LOG_I("pthread_create remove duplicate tag send fail\n");
|
||||
system("reboot");
|
||||
}else{
|
||||
LOG_I("pthread_create remove duplicate tag success\n");
|
||||
pthread_detach(pt_removeduplicatetag);
|
||||
@ -1596,25 +1995,42 @@ int main(int argc, char *argv[])
|
||||
pthread_detach(pt_removelog);
|
||||
}
|
||||
|
||||
ret = pthread_create(&pt_ota,NULL,thread_ota,NULL);
|
||||
if(ret!=0){
|
||||
LOG_I("pthread_create ota fail\n");
|
||||
system("reboot");
|
||||
}else{
|
||||
LOG_I("pthread_create ota success\n");
|
||||
pthread_detach(pt_ota);
|
||||
}
|
||||
|
||||
ret = pthread_create(&pt_doota,NULL,thread_do_ota,NULL);
|
||||
if(ret!=0){
|
||||
LOG_I("pthread_create doota fail\n");
|
||||
system("reboot");
|
||||
}else{
|
||||
LOG_I("pthread_create doota success\n");
|
||||
pthread_detach(pt_doota);
|
||||
}
|
||||
#if 0
|
||||
ret = pthread_create(&pt_readqr,NULL,thread_readqr,NULL);
|
||||
if(ret!=0){
|
||||
LOG_I("pthread_create readqr fail\n");
|
||||
system("reboot");
|
||||
}else{
|
||||
LOG_I("pthread_create readqr success\n");
|
||||
pthread_detach(pt_readqr);
|
||||
}
|
||||
|
||||
#endif
|
||||
readresult=file_to_buffer("savedDevSn",&len);
|
||||
while(readresult==NULL){
|
||||
readresult=file_to_buffer("savedDevSn",&len);
|
||||
sleep(5);
|
||||
LOG_I("please scan sn\n");
|
||||
LOG_I("please scan sn use tx_test\n");
|
||||
}
|
||||
strncpy(stationsn,readresult,len);
|
||||
readresult=NULL;
|
||||
LOG_I("saved stationsn:%s\n",stationsn);
|
||||
|
||||
#if 1
|
||||
readresult=file_to_buffer("mqttRawPassword",&len);
|
||||
if(readresult!=NULL){
|
||||
strncpy(mqttRawPassword,readresult,len);
|
||||
@ -1628,7 +2044,7 @@ int main(int argc, char *argv[])
|
||||
sleep(3);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
readresult=file_to_buffer("LightEnable",&len);
|
||||
if(readresult!=NULL){
|
||||
if(strcmp(readresult,"enable")==0){
|
||||
@ -1638,7 +2054,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
readresult=NULL;
|
||||
}
|
||||
|
||||
#if 1
|
||||
while(1){
|
||||
if((ping("8.8.8.8") == 0)||(ping("8.8.4.4") == 0)){
|
||||
LOG_I("net ok\n");
|
||||
@ -1665,6 +2081,7 @@ int main(int argc, char *argv[])
|
||||
sleep(3);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if 1
|
||||
while(1)
|
||||
{
|
||||
|
||||
84
main.h
84
main.h
@ -35,95 +35,13 @@ int wdt_val;
|
||||
#include "ping.h"
|
||||
#include "Hmacsha1.h"
|
||||
|
||||
#define SND_BATCHINBEGIN "S01"
|
||||
#define SND_BATCHINEND "S02"
|
||||
#define SND_BATCHOUTNORMALBEGIN "S03"
|
||||
#define SND_BATCHOUTNORMALEND "S04"
|
||||
#define SND_BATCHOUTREPAIRBEGIN "S05"
|
||||
#define SND_BATCHOUTREPAIREND "S06"
|
||||
#define SND_BORROWDEVBEGIN "S07"
|
||||
#define SND_BORROWDEVEND "S08"
|
||||
#define SND_RETURNDEVBEGIN "S09"
|
||||
#define SND_RETURNDEVEND "S10"
|
||||
#define SND_REPAIRDEVBEGIN "S11"
|
||||
#define SND_REPAIRDEVEND "S12"
|
||||
#define SND_REPAIRCELL "S13"
|
||||
#define SND_DEVREADFAIL "S14"
|
||||
#define SND_DEVSTILLIN "S15"
|
||||
#define SND_DOORNOTCLOSED "S16"
|
||||
#define SND_DOOROPENFAIL "S17"
|
||||
#define SND_DOWNLOADFAIL "S18"
|
||||
#define SND_DOWNLOADSUCCESS "S19"
|
||||
#define SND_DOWNLOADING "S20"
|
||||
#define SND_READDEVINFOBEGIN "S21"
|
||||
#define SND_READDEVINFOEND "S22"
|
||||
#define SND_NETDISCONNECTED "S23"
|
||||
#define SND_NETWIFI "S24"
|
||||
#define SND_NETWIFICONNECTBEGIN "S25"
|
||||
#define SND_NETWIRED "S26"
|
||||
#define SND_NETWIREDCONNECTBEGIN "S27"
|
||||
#define SND_NETMOBILE "S28"
|
||||
#define SND_NETMOBILECONNECTBEGIN "S29"
|
||||
#define SND_MQTTCONNECTED "S30"
|
||||
#define SND_MQTTDISCONNECTED "S31"
|
||||
#define SND_WIFIPARMWRONG "S32"
|
||||
#define SND_CABINETNOTCONFIGED "S33"
|
||||
#define SND_SYSTEMBOOTEND "S34"
|
||||
#define SND_DEVSNGETSUCCESS "S35"
|
||||
#define SND_DEVSNGETFAIL "S36"
|
||||
#define SND_DEVSNALREADYEXIST "S37"
|
||||
#define SND_SCANSUCCESS "S38"
|
||||
#define SND_DEVNOTBORROWED "S39"
|
||||
#define SND_PARAMSETSUCCESS "S40"
|
||||
#define SND_TIMEOUTBATCHIN "S41"
|
||||
#define SND_TIMEOUTREPAIRDEVIN "S42"
|
||||
#define SND_TIMEOUTRETURN "S43"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t name;
|
||||
uint16_t battery;
|
||||
uint32_t time;
|
||||
}__attribute__((packed)) jt_only_tag_t;
|
||||
|
||||
void hgz_init_db_multy(mqtt_parm_t *mqtt_parm);
|
||||
void hgz_init_db_single(mqtt_parm_t *mqtt_parm);
|
||||
void hgz_reset_cells(mqtt_parm_t *mqtt_parm,char *operators);
|
||||
void hgz_remove_db(char *cabinetName);
|
||||
void hgz_remove_dev_by_cellname(char *cellname,int userid,char *username,char *batchid,char *optype,char *optime,char *opinfo);
|
||||
void hgz_remove_dev_by_cellname_no_userid(char *cellname,char *batchid,char *optype,char *optime,char *opinfo);
|
||||
void hgz_add_dev_by_cellname(char *cellname,int userid,char *username,char *devsn,long devpwr,char *optype,char *batchid,
|
||||
char *optime,char *opinfo);
|
||||
void hgz_repair_dev_by_cellname(char *cellname,int userid,char *username,char *devsn,long devpwr,char *batchid,char *optime,char *opinfo,
|
||||
char *repairtype);
|
||||
void hgz_repair_dev_by_cellname_misOperate(char *cellname,int userid,char *username,long devpwr,char *batchid,char *optime,char *opinfo,
|
||||
char *repairtype);
|
||||
void hgz_lose_dev_by_cellname(char *cellname,int userid,char *username,char *batchid,char *optime);
|
||||
void hgz_repair_cell_by_cellname(char *cellname,int userid);
|
||||
void hgz_reset_cell_by_cellname(char *cellname,int userid);
|
||||
void hgz_get_cellstatus_by_cellname(char *cellname,char *cellstatus);
|
||||
void hgz_get_devstatus_by_cellname(char *cellname,char *devstatus);
|
||||
void hgz_get_idlecellnum_by_devtype(char *idlecellnum,char *devtype);
|
||||
void hgz_get_cabinetnames(char *cabinetnames);
|
||||
void hgz_get_devtypes(char *devtypes);
|
||||
void hgz_get_repairdevcellnames_by_devtype(char *cellnames,char *devtype);
|
||||
void hgz_get_indevcellnames_by_devtype(char *cellnames,char *devtype);
|
||||
void hgz_get_repaircellcellnames_by_devtype(char *cellnames,char *devtype);
|
||||
void hgz_get_activecellcellnames_by_devtype(char *cellnames,char *devtype);
|
||||
void hgz_get_doublecheckcellcellnames_by_cabinetnames(char *cellnames,char *cabinetnames);
|
||||
void hgz_get_activecellcellnames(char *cellnames);
|
||||
void hgz_get_allcellnames(char *cellnames);
|
||||
void hgz_get_idlecellcellnames_by_devtype(char *cellnames,char *devtype);
|
||||
void hgz_select_cellnames_tosavedev_by_devtype(char *cellnames,char *devtype,int num);
|
||||
void hgz_select_cellnames_tosavedev_by_operator(char *cellnames,int userid,char *operators);
|
||||
void hgz_select_cellnames_totakenormaldev_by_devtype(char *cellnames,char *devtype,int num);
|
||||
void hgz_select_cellnames_totakerepairdev_by_devtype(char *cellnames,char *devtype,int num);
|
||||
void hgz_get_indevnum_by_devtype(char *indevnum,char *devtype);
|
||||
void hgz_get_repairdevnum_by_devtype(char *repairdevnum,char *devtype);
|
||||
void hgz_get_canborrowdevnum_by_devtype(char *canborrowdevnum,char *devtype);
|
||||
void hgz_get_devsn_by_cellname(char *devsn,char *cellname);
|
||||
void hgz_do_download(mqtt_parm_download_t *mqtt_parm);
|
||||
int hgz_check_cabinet_status(void);
|
||||
|
||||
void myrand(char *randnum,int len);
|
||||
void removeValueFromMystr(char *oristr,char *val);
|
||||
void addValueToMystr(char *oristr,char *val);
|
||||
|
||||
1
mqttRawPassword
Normal file
1
mqttRawPassword
Normal file
@ -0,0 +1 @@
|
||||
6bdb82a9953a4d1a8d6608b3a452baae
|
||||
@ -67,6 +67,7 @@ void mqtt_server_light_status_report(char *sn,char *msg_id,char *scene,json_obje
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
snprintf(time_buffer,sizeof(time_buffer),"%ld",tv.tv_sec*1000+tv.tv_usec);
|
||||
LOG_I("%s\n",__func__);
|
||||
|
||||
root = json_object_new_object();
|
||||
if(root == NULL){
|
||||
@ -98,9 +99,9 @@ void mqtt_server_light_status_report(char *sn,char *msg_id,char *scene,json_obje
|
||||
json_object_object_add(root, "msg", msg);
|
||||
|
||||
snprintf(topic, sizeof(topic), "iot/%s/message/report",mqtt_conf->productcode);
|
||||
LOG_I("publish topic:[%s]\n", topic);
|
||||
//LOG_I("publish topic:[%s]\n", topic);
|
||||
payload = json_object_to_json_string(root);
|
||||
LOG_I("payload[%d][%s]\n", strlen(payload), payload);
|
||||
//LOG_I("payload[%d][%s]\n", strlen(payload), payload);
|
||||
mqtt_utils_publish(mqtt_conf, topic, 2, payload, strlen(payload));
|
||||
json_error:
|
||||
json_object_put(root);
|
||||
@ -118,8 +119,8 @@ void mqtt_server_station_status_report(char *msg_id,char *product_id,char *sn,ch
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
snprintf(time_buffer,sizeof(time_buffer),"%ld",tv.tv_sec*1000+tv.tv_usec);
|
||||
LOG_I("%s\n",__func__);
|
||||
|
||||
//LOG_I("%s\n", __func__);
|
||||
root = json_object_new_object();
|
||||
if(root == NULL){
|
||||
LOG_I("json_object_new_object error\n");
|
||||
@ -151,9 +152,9 @@ void mqtt_server_station_status_report(char *msg_id,char *product_id,char *sn,ch
|
||||
json_object_object_add(msg, "msgType", json_object_new_string("9008"));
|
||||
json_object_object_add(root, "msg", msg);
|
||||
snprintf(topic, sizeof(topic), "iot/%s/message/report",mqtt_conf->productcode);
|
||||
LOG_I("publish topic:[%s]\n", topic);
|
||||
//LOG_I("publish topic:[%s]\n", topic);
|
||||
payload = json_object_to_json_string(root);
|
||||
LOG_I("payload[%d][%s]\n", strlen(payload), payload);
|
||||
//LOG_I("payload[%d][%s]\n", strlen(payload), payload);
|
||||
mqtt_utils_publish(mqtt_conf, topic, 2, payload, strlen(payload));
|
||||
json_error:
|
||||
json_object_put(root);
|
||||
@ -165,7 +166,7 @@ void mqtt_service_reply(char *sn,char *msg_id,char *msg,int success,char *produc
|
||||
const char *payload = NULL;
|
||||
json_object *root = NULL;
|
||||
|
||||
//LOG_I("%s\n", __func__);
|
||||
LOG_I("%s\n", __func__);
|
||||
root = json_object_new_object();
|
||||
if(root == NULL){
|
||||
LOG_I("json_object_new_object error\n");
|
||||
@ -179,9 +180,9 @@ void mqtt_service_reply(char *sn,char *msg_id,char *msg,int success,char *produc
|
||||
json_object_object_add(root, "productId", json_object_new_string(mqtt_conf->productcode));
|
||||
|
||||
snprintf(topic, sizeof(topic), "iot/%s/adviceDevice/reply",mqtt_conf->productcode);
|
||||
LOG_I("publish topic:[%s]\n", topic);
|
||||
//LOG_I("publish topic:[%s]\n", topic);
|
||||
payload = json_object_to_json_string(root);
|
||||
LOG_I("payload[%d][%s]\n", strlen(payload), payload);
|
||||
//LOG_I("payload[%d][%s]\n", strlen(payload), payload);
|
||||
mqtt_utils_publish(mqtt_conf, topic, 2, payload, strlen(payload));
|
||||
|
||||
json_error:
|
||||
|
||||
@ -1056,7 +1056,7 @@ int http_download(char *url, char *msg_id,int task_id,char *filepath)
|
||||
if (written_len == http_response.content_length) {
|
||||
LOG_I("Download %s successed\n", file_name);
|
||||
sleep(2);
|
||||
newappDownloaded=true;
|
||||
//newappDownloaded=true;
|
||||
ret = 0;
|
||||
} else {
|
||||
LOG_I("Download %s failed\n", file_name);
|
||||
|
||||
1
savedDevSn
Normal file
1
savedDevSn
Normal file
@ -0,0 +1 @@
|
||||
TJ251679787196
|
||||
6
ssh.sh
6
ssh.sh
@ -1,3 +1,3 @@
|
||||
sshpass -p "&Over#B0Ost!" ssh root@10.10.10.235
|
||||
#sshpass -p "PddloTSecPwdOnly!" ssh root@10.10.10.132
|
||||
#sshpass -p "PddloTSecPwdOnly!" ssh root@192.168.0.148
|
||||
#sshpass -p "&Over#B0Ost!" ssh root@10.10.12.3
|
||||
sshpass -p "TxApPwd#2025!" ssh root@10.10.12.2
|
||||
#sshpass -p "PddloTSecPwdOnly!" ssh root@10.10.12.4
|
||||
|
||||
BIN
tx_ota/F8_20250519_V1.0.33_1422_W02CL0BSL_0x21.bin
Executable file
BIN
tx_ota/F8_20250519_V1.0.33_1422_W02CL0BSL_0x21.bin
Executable file
Binary file not shown.
17
tx_ota/start.sh
Executable file
17
tx_ota/start.sh
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd /root
|
||||
filename=/root/ota/tx_server
|
||||
filesize=`ls -l $filename | awk '{ print $5 }'`
|
||||
maxsize=$((440000))
|
||||
if [ $filesize -gt $maxsize ]
|
||||
then
|
||||
echo "$filesize > $maxsize copy"
|
||||
cp $filename .
|
||||
chmod 777 tx_server
|
||||
./tx_server
|
||||
else
|
||||
echo "$filesize < $maxsize not copy"
|
||||
chmod 777 tx_server
|
||||
./tx_server
|
||||
fi
|
||||
BIN
tx_ota/tx_server
Executable file
BIN
tx_ota/tx_server
Executable file
Binary file not shown.
BIN
tx_ota/tx_test
Executable file
BIN
tx_ota/tx_test
Executable file
Binary file not shown.
BIN
tx_server_v1.1.10
Executable file
BIN
tx_server_v1.1.10
Executable file
Binary file not shown.
BIN
tx_server_v1.1.9
Executable file
BIN
tx_server_v1.1.9
Executable file
Binary file not shown.
@ -8,6 +8,29 @@
|
||||
#define DBG_TAG "uart_can"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include "debug_print.h"
|
||||
uint16_t CRC16_APOTA( unsigned char * pdat, unsigned int len)
|
||||
{
|
||||
const uint16_t CRC_16_IBM_TableOTA[16] =
|
||||
{
|
||||
0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
|
||||
0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022
|
||||
};
|
||||
uint16_t i, j;
|
||||
uint16_t crc = 0xffff;
|
||||
uint8_t val;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
val = pdat[i];
|
||||
for(j = 0; j < 2; j++)
|
||||
{
|
||||
crc = (crc << 4) ^ CRC_16_IBM_TableOTA[(((crc >> 8) ^ val) >> 4) & 0x0F];
|
||||
val <<= 4;
|
||||
}
|
||||
}
|
||||
|
||||
return (crc);
|
||||
}
|
||||
|
||||
uint16_t CRC16_XMODEM(uint8_t *puchMsg, uint32_t usDataLen)
|
||||
{
|
||||
@ -29,6 +52,139 @@ uint16_t CRC16_XMODEM(uint8_t *puchMsg, uint32_t usDataLen)
|
||||
return (wCRCin);
|
||||
}
|
||||
|
||||
int uart_data_send_head_apota(uart_utils_t *uart,uint32_t datalen,uint16_t packagenum){
|
||||
int ret = 0;
|
||||
jt_apota_package_t jt_apota_package ={
|
||||
.head=ntohl(0x404F5441),//@OTA
|
||||
.len1=(datalen>>16)&0xFF,
|
||||
.len2=(datalen>>8)&0xFF,
|
||||
.len3=datalen&0xFF,
|
||||
.packagenum=ntohs(packagenum),
|
||||
.reserve=ntohs(0x0000),
|
||||
};
|
||||
LOG_I("%s:HEAD:%08x,%02x,%02x,%02x,%04x,%04x\r\n",__func__,jt_apota_package.head,
|
||||
jt_apota_package.len1,jt_apota_package.len2,jt_apota_package.len3,jt_apota_package.packagenum,jt_apota_package.reserve);
|
||||
|
||||
if (uart == NULL){
|
||||
LOG_I("uart NULL pointer\n");
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
if(sizeof(jt_apota_package) == write(uart->uart_fd, &jt_apota_package, sizeof(jt_apota_package))){
|
||||
ret = 0;
|
||||
//LOG_I("%s success\n",__func__);
|
||||
}else{
|
||||
//LOG_I("%s fail\n", __func__);
|
||||
ret = -2;
|
||||
goto error;
|
||||
}
|
||||
error:
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uart_data_send_head_ledota(uart_utils_t *uart,uint32_t datalen,uint16_t datacrc,uint16_t version){
|
||||
int ret = 0;
|
||||
jt_ledota_package_t jt_ledota_package ={
|
||||
.head=ntohl(0x404F5457),//@OTW
|
||||
.len1=(datalen>>16)&0xFF,
|
||||
.len2=(datalen>>8)&0xFF,
|
||||
.len3=datalen&0xFF,
|
||||
.data_crc=ntohs(datacrc),
|
||||
.hdinfo=0x21,
|
||||
.sfinfo=ntohs(version),
|
||||
.custom_code=ntohs(0x0003),
|
||||
.mode=0xF8,
|
||||
#if 1
|
||||
.startmac1=0x00,
|
||||
.startmac2=0x00,
|
||||
.startmac3=0x00,
|
||||
.endmac1=0xff,
|
||||
.endmac2=0xff,
|
||||
.endmac3=0xff,
|
||||
#else
|
||||
.startmac1=0xfe,
|
||||
.startmac2=0x64,
|
||||
.startmac3=0xa8,
|
||||
.endmac1=0xfe,
|
||||
.endmac2=0x64,
|
||||
.endmac3=0xa8,
|
||||
#endif
|
||||
};
|
||||
LOG_I("%s:HEAD:%08x,%02x,%02x,%02x,%04x,%02x,%04x,%04x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\r\n",__func__,jt_ledota_package.head,
|
||||
jt_ledota_package.len1,jt_ledota_package.len2,jt_ledota_package.len3,jt_ledota_package.data_crc,jt_ledota_package.hdinfo,
|
||||
jt_ledota_package.sfinfo,jt_ledota_package.custom_code,jt_ledota_package.mode,jt_ledota_package.startmac1,
|
||||
jt_ledota_package.startmac2,jt_ledota_package.startmac3,jt_ledota_package.endmac1,jt_ledota_package.endmac2,
|
||||
jt_ledota_package.endmac3);
|
||||
|
||||
if (uart == NULL){
|
||||
LOG_I("uart NULL pointer\n");
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
if(sizeof(jt_ledota_package) == write(uart->uart_fd, &jt_ledota_package, sizeof(jt_ledota_package))){
|
||||
ret = 0;
|
||||
//LOG_I("%s success\n",__func__);
|
||||
}else{
|
||||
//LOG_I("%s fail\n", __func__);
|
||||
ret = -2;
|
||||
goto error;
|
||||
}
|
||||
usleep(100*1000);
|
||||
error:
|
||||
return ret;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int uart_data_send_ledota(uart_utils_t *uart,char *data,int size){
|
||||
int ret=0;
|
||||
if(size==write(uart->uart_fd,data,size)){
|
||||
LOG_I("write size:%d success\n",size);
|
||||
}else{
|
||||
LOG_I("write size:%d fail\n",size);
|
||||
}
|
||||
usleep(500*1000);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int uart_data_send_apota(uart_utils_t *uart,uint8_t dataori[],int datalen,uint16_t pindex,uint16_t datacrc){
|
||||
int ret = 0;
|
||||
int sendlen = 0;
|
||||
jt_apota_data_package_t jt_apota_data_package ={
|
||||
.start=0x24,//$
|
||||
.len1=(datalen>>16)&0xFF,
|
||||
.len2=(datalen>>8)&0xFF,
|
||||
.len3=datalen&0xFF,
|
||||
.packageindex=ntohs(pindex),
|
||||
//.data=dataori,
|
||||
.data_crc=ntohs(datacrc),
|
||||
};
|
||||
if(datalen>2048){
|
||||
sendlen=2048;
|
||||
}else{
|
||||
sendlen=datalen;
|
||||
}
|
||||
memcpy(jt_apota_data_package.data,dataori,sendlen);
|
||||
if (uart == NULL){
|
||||
LOG_I("uart NULL pointer\n");
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
if(sizeof(jt_apota_data_package) == write(uart->uart_fd, &jt_apota_data_package, sizeof(jt_apota_data_package))){
|
||||
ret = 0;
|
||||
LOG_I("%s success\n",__func__);
|
||||
}else{
|
||||
LOG_I("%s fail\n", __func__);
|
||||
ret = -2;
|
||||
goto error;
|
||||
}
|
||||
error:
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uart_data_send_head_lighton(uart_utils_t *uart,uint8_t wakeup_time,uint16_t tag_num){
|
||||
int ret = 0;
|
||||
uint8_t data_len=0;
|
||||
@ -766,6 +922,20 @@ error:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uart_data_receive_version(uart_utils_t *uart){
|
||||
int ret = 0;
|
||||
jt_receive_version_package_t jt_receive_version_package;
|
||||
ret = uart_read_until_time(uart->uart_fd,(char *)&jt_receive_version_package,sizeof(jt_receive_version_package_t), 1000, 50);
|
||||
if(ret == sizeof(jt_receive_version_package_t)){
|
||||
LOG_I("%s success:%04x,%04x\n", __func__,jt_receive_version_package.v1,jt_receive_version_package.v2);
|
||||
}else{
|
||||
LOG_I("%s, failed, time out\n", __func__);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int uart_data_receive_ack(uart_utils_t *uart,uint16_t *parm_ack){
|
||||
int ret = 0;
|
||||
jt_receive_package_t jt_receive_package;
|
||||
|
||||
@ -246,7 +246,54 @@ typedef struct
|
||||
uint16_t crc;
|
||||
}__attribute__((packed)) jt_search_package_t;
|
||||
|
||||
uint16_t CRC16_XMODEM(uint8_t *puchMsg, uint32_t usDataLen);
|
||||
typedef struct
|
||||
{
|
||||
uint32_t head;
|
||||
uint8_t len1;
|
||||
uint8_t len2;
|
||||
uint8_t len3;
|
||||
uint16_t data_crc;
|
||||
uint8_t hdinfo;
|
||||
uint16_t sfinfo;
|
||||
uint16_t custom_code;
|
||||
uint8_t mode;
|
||||
uint8_t startmac1;
|
||||
uint8_t startmac2;
|
||||
uint8_t startmac3;
|
||||
uint8_t endmac1;
|
||||
uint8_t endmac2;
|
||||
uint8_t endmac3;
|
||||
}__attribute__((packed)) jt_ledota_package_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t head;
|
||||
uint8_t len1;
|
||||
uint8_t len2;
|
||||
uint8_t len3;
|
||||
uint16_t packagenum;
|
||||
uint16_t reserve;
|
||||
}__attribute__((packed)) jt_apota_package_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t start;
|
||||
uint8_t len1;
|
||||
uint8_t len2;
|
||||
uint8_t len3;
|
||||
uint16_t packageindex;
|
||||
uint8_t data[2048];
|
||||
uint16_t data_crc;
|
||||
}__attribute__((packed)) jt_apota_data_package_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t v1;
|
||||
uint16_t v2;
|
||||
}__attribute__((packed)) jt_receive_version_package_t;
|
||||
|
||||
uint16_t CRC16_XMODEM(uint8_t *di, uint32_t len);
|
||||
uint16_t CRC16_APOTA( unsigned char * pdat, unsigned int len);
|
||||
|
||||
int uart_data_send_head_lighton(uart_utils_t *uart,uint8_t wakeup_time,uint16_t tag_num);
|
||||
int uart_data_send_head_lableup(uart_utils_t *uart,uint8_t wakeup_time,uint16_t tag_num);
|
||||
@ -271,4 +318,8 @@ int uart_data_receive_data_back(uart_utils_t *uart,uint16_t *parmAck,uint32_t *t
|
||||
uint8_t *totalLen,uint8_t *tagFeature,uint8_t *count,uint16_t *batteryV,uint16_t *version,uint8_t *ledCtrl,
|
||||
uint8_t *lable1,uint16_t *lable2,uint32_t *lable3);
|
||||
int uart_data_receive_ack(uart_utils_t *uart,uint16_t *parm_ack);
|
||||
int uart_data_send_head_ledota(uart_utils_t *uart,uint32_t datalen,uint16_t datacrc,uint16_t version);
|
||||
int uart_data_send_ledota(uart_utils_t *uart,char *data,int size);
|
||||
int uart_data_send_head_apota(uart_utils_t *uart,uint32_t datalen,uint16_t packagenum);
|
||||
int uart_data_send_apota(uart_utils_t *uart,uint8_t dataori[],int datalen,uint16_t pnum,uint16_t datacrc);
|
||||
#endif
|
||||
|
||||
Loading…
Reference in New Issue
Block a user