Open Source Software - Lab mission 3 - jsmn code analysis
분석대상 파일 : jsmn.h, jsmn.c
분석내용
-
변수들 모든 변수들의 이름, 타입, 의미, 용도를 찾아서 기술할 것
jsmn.h
타입
- jsmntype_t : typedef를 이용해 정의된 토큰의 타입 이고, enum으로 유형에 따라 숫자가 할당되어있다.
typedef enum { JSMN_UNDEFINED = 0, //정의되지 않은 타입 JSMN_OBJECT = 1, //오브젝트타입 JSMN_ARRAY = 2, //배열타입 JSMN_STRING = 3, //스트링타입 JSMN_PRIMITIVE = 4 //숫자나 boolean 또는 null타입 } jsmntype_t;
- jsmntok_t : typedef로 정의된 타입으로, JSON 토큰에 관한 타입이다.
- jsmn_parser : typedef로 정의된 타입으로, 이용가능한 토큰블록의 배열을 저장하는 타입이다.
변수
typedef struct { jsmntype_t type; // 토큰의 타입 int start; // 토큰의 시작 위치 int end; // 토큰의 끝 위치 int size; // child tokens의 수 #ifdef JSMN_PARENT_LINKS int parent; #endif } jsmntok_t;
- type : jsmntype_t 형 변수로 enum으로 json 타입(object, array, string etc.)에 따라 값이 할당된다.
- start : int형 변수로 JSON 데이터 스트링의 시작 위치를 나타낸다.
- end : int형 변수로 JSON 데이터 스트링의 끝 위치를 나타낸다.
- size : int형 변수로 child token의 수를 나타낸다.
- parent : int형 변수로, JSMN_PARENT_LINKS가 존재할 경우에만 할당된다.
typedef struct { unsigned int pos; /* offset in the JSON string */ unsigned int toknext; /* next token to allocate */ int toksuper; /* superior token node, e.g parent object or array */ } jsmn_parser;
-
pos : unsigned int 타입으로 JSON 스트링안의 offset을 의미한다.
-
toknext : 다음에 할당될 토큰을 의미한다.
-
toksuper : parent object나 array 같이 최상위 토큰 노드를 의미한다.
jsmn.c
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, size_t num_tokens) { jsmntok_t *tok; if (parser->toknext >= num_tokens) { return NULL; } tok = &tokens[parser->toknext++]; tok->start = tok->end = -1; tok->size = 0; #ifdef JSMN_PARENT_LINKS tok->parent = -1; #endif return tok; }
- tok : jsmntok_t 타입 (JSON 토큰에 대한 타입)으로 선언된 포인터 변수
static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) { jsmntok_t *token; int start; start = parser->pos; for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { switch (js[parser->pos]) { #ifndef JSMN_STRICT /* In strict mode primitive must be followed by "," or "}" or "]" */ case ':': #endif case '\t' : case '\r' : case '\n' : case ' ' : case ',' : case ']' : case '}' : goto found; } if (js[parser->pos] < 32 || js[parser->pos] >= 127) { parser->pos = start; return JSMN_ERROR_INVAL; } } #ifdef JSMN_STRICT /* In strict mode primitive must be followed by a comma/object/array */ parser->pos = start; return JSMN_ERROR_PART; #endif found: if (tokens == NULL) { parser->pos--; return 0; } token = jsmn_alloc_token(parser, tokens, num_tokens); if (token == NULL) { parser->pos = start; return JSMN_ERROR_NOMEM; } jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); #ifdef JSMN_PARENT_LINKS token->parent = parser->toksuper; #endif parser->pos--; return 0; }
- start : int형 변수로 파싱할 시작위치를 나타낸다.
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens) { int r; int i; jsmntok_t *token; int count = parser->toknext; for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { char c; jsmntype_t type; c = js[parser->pos]; switch (c) { case '{': case '[': count++; if (tokens == NULL) { break; } token = jsmn_alloc_token(parser, tokens, num_tokens); if (token == NULL) return JSMN_ERROR_NOMEM; if (parser->toksuper != -1) { tokens[parser->toksuper].size++; //중간생략 return count; }
- count : int 형 변수로 토큰의 개수를 세는 변수이다.
-
모든 함수들의 이름, 파라미터의 종류와 의미, 리턴값의 의미, 함수의 수행내용을 정리하여 기술할 것.
jsmn.h
-
void jsmn_init(jsmn_parser *parser);
jsmn_init 함수는 jsmn_parser 타입의 포인터 변수인 parser을 파라미터로 받아 new JSON parser를 만드는 기능의 함수이다. void 타입의 함수이기 때문에 리턴값은 없다. jsmn.c 에서 파서를 초기화하는 함수를 선언해준 것이다.
-
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens);
int jsmn_parse 함수는 jsmn_parser타입의 포인트변수인 *parser와 const char 타입의 포인터 변수 js 와 size_t 변수 len, jsmntok_t 타입의 포인터변수 tokens, unsigned int 타입의 num_tokens를 파라미터로 받아서 JSON parser를 실행하는 역할을 한다. 여기서는 jsmn.c에 있는 함수를 선언하는 것이다.
jsmn.c
-
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, size_t num_tokens)
parser 파라미터를 통해 현재 할당할 토큰에 대해 전달받아, tokens 이라는 배열에 저장한다. num_tokens 값을 파라미터로 받아서 num_tokens의 값이 다음토큰의 인덱스보다 작을때 까지만 저장한다. 반환값으로는 tok가 가르키는 주소 값을 반환한다. 이 함수는 토큰 풀로부터 새로운 사용되지 않은 토큰을 할당하는 함수이다.
-
static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, int start, int end) { token->type = type; token->start = start; token->end = end; token->size = 0; }
파라미터를 통해 전달한 토큰에 type과 start 값, end 값을 해당 token에 채워주는 함수이다.
-
static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens)
jsmn_parse함수에서 JSON을 분석하여 그 타입이 primitive 타입일 때, 파라미터와 함께 이 함수를 호출합니다. 이 함수를 호출 했을 때, 다음 사용 가능한 토큰을 JSON primitive로 채 웁니다. 파라미터로 온 해당되는 primitive 값을 해당하는 토큰 개수만큼 토큰에 저장한다.
-
static int jsmn_parse_string(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens)
jsmn_parse에서 JSON 데이터를 파싱할 때 만약 string 값이 존재한다면 이 함수를 호출한다. 그래서 파라미터에서 받은 parser의 주소값과 그 스트링을 파라미터에서 받은 수만큼 저장한다. JSON string을 분석해 string 값만 토큰에 채우는 함수이다.
-
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens)
JSON data를 분석하는 jsmn의 핵심 함수라고 할 수 있다. 먼저 {나 (를 감지하여서 object의 수를 count에다 저장하고, 해당하는 token이 null이 아니라면 jsmn_alloc_token함수를 호출하여 새로운 사용하지 않은 토큰을 할당받는다. 그리고 할당받은 토큰의 타입과 시작위치 등의 값을 할당한다. { 일 경우, object 타입으로 ,[일 경우 array타입으로 판단한다. 그리고 }, ] 를 감지함을 통해 object나 array의 끝을 판단한다. 그리고 파싱을 하는 과정 중 jsmn.h에서 규정한 에러의 유형이 발생하면 JSMN_ERROR_NOMEM, JSMN_ERROR_INVAL, JSMN_ERROR_PART 등의 에러를 리턴한다. 그리고 ‘"’,’ ‘, ‘\t’, ‘:’, 등을
파싱하다 발견하면 string단위로 구분하여 jsmn_parse_string()를 호출하여 string 단위로 토큰에 저장한다. 그리고 숫자나 -, t ,f, n을 발견하면 jsmn_parse_primitive()를 호출하여 primitive type을 저장하는 토큰에 저장한다.
-
void jsmn_init(jsmn_parser *parser)
parser의 주소값을 파라미터로 받아서 사용 가능한 토큰 배열을 사용하여 제공된 버퍼를 기반으로 새 파서를 만드는 함수이다.
-
-
JSON 간단한 샘플을 찾아서 어떤 용도로 쓰이는지 정리하여 기술할 것
'{ "name" : "Jack", "age" : 27 }'
위와 같은 JSON 형식으로 저장된 object가 있다고 하면 jack 이라는 이름과 27이라는 나이를 object에 포함하고 있다. jsmn은 이와 같은 JSON 데이터를 여러가지로 나누어 토큰에 저장한다. object 토큰에는 전체 object를 통째로 저장하고, 그 후에 strings이 파싱되면 object에서 “name”, “jack” ,”age” 처럼 string을 분리하여 토큰을 저장한다. 그리고 primitive type 또한 나뉘어 따로 토큰에 저장하는 도구이자 라이브러리라고 할 수 있다.
아래는 jsmn이 나누어 토큰에 저장하는 타입의 형식이다.
- Object - a container of key-value pairs, e.g.:
{ "foo":"bar", "x":0.3 }
- Array - a sequence of values, e.g.:
[ 1, 2, 3 ]
- String - a quoted sequence of chars, e.g.:
"foo"
- Primitive - a number, a boolean (
true
,false
) ornull
예를 들어 아래와 같은 형식의 JSON이 있다고 가정하면,
myObj = {
"name":"John",
"age":30,
"cars": [
{ "name":"Ford", "models":[ "Fiesta", "Focus", "Mustang" ] },
{ "name":"BMW", "models":[ "320", "X3", "X5" ] },
{ "name":"Fiat", "models":[ "500", "Panda" ] }
]
}
jsmn을 통해서 파싱하면 object 에는 전체 오브젝트와 []로 둘러쌓여있는 배열들이 저장되고, “ “로 구분되어있는 string별로 저장되며, 30과 같은 primitive type도 따로 분류된다. 우리는 json format을 사용해 key-value pair notation과 같은 형식으로 여러 타입을 저장할 수 있고, json파싱을 통하여 아래와 같이 저장되는 구조와 형식을 변화 시킬수도 있다.
{
"colors": [
{
"color": "black",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,255,255,1],
"hex": "#000"
}
},
{
"color": "white",
"category": "value",
"code": {
"rgba": [0,0,0,1],
"hex": "#FFF"
}
}
}
-----------------------------------------------------------------------------------
{
"aliceblue": "#f0f8ff",
"antiquewhite": "#faebd7",
"aqua": "#00ffff",
"aquamarine": "#7fffd4",
"azure": "#f0ffff",
"beige": "#f5f5dc",
"bisque": "#ffe4c4",
"black": "#000000",
"blanchedalmond": "#ffebcd",
"blue": "#0000ff",
"blueviolet": "#8a2be2",
"brown": "#a52a2a",
}
-----------------------------------------------------------------------------------{
"aliceblue": [240, 248, 255, 1],
"antiquewhite": [250, 235, 215, 1],
"aqua": [0, 255, 255, 1],
"aquamarine": [127, 255, 212, 1],
"azure": [240, 255, 255, 1],
"beige": [245, 245, 220, 1],
"bisque": [255, 228, 196, 1],
"black": [0, 0, 0, 1],
"blanchedalmond": [255, 235, 205, 1],
"blue": [0, 0, 255, 1],
"blueviolet": [138, 43, 226, 1],
"brown": [165, 42, 42, 1],
"burlywood": [222, 184, 135, 1],
"cadetblue": [95, 158, 160, 1],
"chartreuse": [127, 255, 0, 1],
"chocolate": [210, 105, 30, 1],
"coral": [255, 127, 80, 1],
}
아래는 CRA 동아리에서 방학 프로젝트에서 사용했던 배달 어플리케이션의 json 포맷 파일의 내용이다.
아래와 같이 다양한 형식으로 다양한 정보를 담는 것이 가능하다.
{
"id": 0,
"category" : "others",
"name": "59쌀피자",
"image": "59쌀피자양덕점.jpg",
"time": "open: 11:00 ~ close 23:00",
"number": "Tel: 054-249-0059"
},
{
"id": 1,
"category" : "chicken",
"name": "BBQ 장량점",
"image": "bbq장량점.jpg",
"time": "open 12:00 ~ close 23:59 ",
"number" : "Tel: 054-252-9283"
},
{
"id": 2,
"category" : "others",
"name" : "Dessert39 양덕점",
"image": "dessert39양덕점.jpg",
"time": "open 10:00 ~ close 22:00 ",
"number" : "Tel: 054-243-7294"
},
{
"id": 2,
"category" : "chicken",
"name" : "강호동치킨",
"image": "강호동치킨.jpg",
"time": "open 13:00 ~ close 01:00 ",
"number" : "Tel: 054-256-0678"
},
{
"id": 2,
"category" : "chicken",
"name" : "굽네치킨",
"image": "굽네치킨.jpg",
"time": "open 12:00 ~ close 23:59 연중무휴",
"number" : "Tel: 054-252-9595"
},
{
"id": 2,
"category" : "chicken",
"name" : "그 시절 옛날 통닭",
"image": "그시절옛날통닭.jpg",
"time": "open 15:00 ~ close 23:59 연중무휴",
"number" : "Tel: 054-255-2534"
},
{
"id": 2,
"category" : "chicken",
"name" : "김스타치킨",
"image": "김스타치킨.jpg",
"time": "open 16:00 ~ close 02:00 연중무휴",
"number" : "Tel: 054-255-5666"
},
{
"id": 2,
"category" : "chicken",
"name" : "꼬꼬바베큐",
"image": "꼬꼬바베큐.jpg",
"time": "open 15:00 ~ close 01:00",
"number" : "Tel: 054-262-9220"
}
Subscribe to Ykss's Coding Space
Get the latest posts delivered right to your inbox