ithewei 7 år sedan
incheckning
c74df3b33d
31 ändrade filer med 1773 tillägg och 0 borttagningar
  1. 16 0
      .gitignore
  2. 135 0
      base64.cpp
  3. 14 0
      base64.h
  4. 36 0
      h.h
  5. 194 0
      hbuf.h
  6. 26 0
      hbytearray.h
  7. 66 0
      hdef.h
  8. 41 0
      herr.cpp
  9. 68 0
      herr.h
  10. 65 0
      hframe.cpp
  11. 84 0
      hframe.h
  12. 15 0
      hgl.h
  13. 71 0
      hgui.h
  14. 85 0
      hlog.cpp
  15. 51 0
      hlog.h
  16. 36 0
      hmutex.h
  17. 84 0
      hobj.h
  18. 27 0
      hplatform.h
  19. 51 0
      hscope.h
  20. 118 0
      hstring.cpp
  21. 19 0
      hstring.h
  22. 50 0
      htable.cpp
  23. 45 0
      htable.h
  24. 103 0
      hthread.h
  25. 78 0
      htime.cpp
  26. 34 0
      htime.h
  27. 39 0
      hunix.cpp
  28. 6 0
      hunix.h
  29. 54 0
      hvar.h
  30. 31 0
      hversion.h
  31. 31 0
      singleton.h

+ 16 - 0
.gitignore

@@ -0,0 +1,16 @@
+# cache
+*.~
+*.bk
+*.org
+*.old
+
+# output
+*.o
+bin
+
+# IDE
+.vs
+.vscode
+
+# test
+test

+ 135 - 0
base64.cpp

@@ -0,0 +1,135 @@
+/* This is a public domain base64 implementation written by WEI Zhicheng. */
+
+#include <stdio.h>
+
+#include "base64.h"
+
+/* BASE 64 encode table */
+static const char base64en[] = {
+	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+	'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+	'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+	'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+	'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+	'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+	'w', 'x', 'y', 'z', '0', '1', '2', '3',
+	'4', '5', '6', '7', '8', '9', '+', '/',
+};
+
+#define BASE64_PAD	'='
+
+
+#define BASE64DE_FIRST	'+'
+#define BASE64DE_LAST	'z'
+/* ASCII order for BASE 64 decode, -1 in unused character */
+static const signed char base64de[] = {
+	/* '+', ',', '-', '.', '/', '0', '1', '2', */ 
+	    62,  -1,  -1,  -1,  63,  52,  53,  54,
+
+	/* '3', '4', '5', '6', '7', '8', '9', ':', */
+	    55,  56,  57,  58,  59,  60,  61,  -1,
+
+	/* ';', '<', '=', '>', '?', '@', 'A', 'B', */
+	    -1,  -1,  -1,  -1,  -1,  -1,   0,   1, 
+
+	/* 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', */
+	     2,   3,   4,   5,   6,   7,   8,   9,
+
+	/* 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', */ 
+	    10,  11,  12,  13,  14,  15,  16,  17,
+
+	/* 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', */
+	    18,  19,  20,  21,  22,  23,  24,  25,
+
+	/* '[', '\', ']', '^', '_', '`', 'a', 'b', */ 
+	    -1,  -1,  -1,  -1,  -1,  -1,  26,  27,
+
+	/* 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', */ 
+	    28,  29,  30,  31,  32,  33,  34,  35,
+
+	/* 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', */
+	    36,  37,  38,  39,  40,  41,  42,  43,
+
+	/* 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', */
+	    44,  45,  46,  47,  48,  49,  50,  51,
+};
+
+int
+base64_encode(const unsigned char *in, unsigned int inlen, char *out)
+{
+	unsigned int i, j;
+
+	for (i = j = 0; i < inlen; i++) {
+		int s = i % 3; 			/* from 6/gcd(6, 8) */
+
+		switch (s) {
+		case 0:
+			out[j++] = base64en[(in[i] >> 2) & 0x3F];
+			continue;
+		case 1:
+			out[j++] = base64en[((in[i-1] & 0x3) << 4) + ((in[i] >> 4) & 0xF)];
+			continue;
+		case 2:
+			out[j++] = base64en[((in[i-1] & 0xF) << 2) + ((in[i] >> 6) & 0x3)];
+			out[j++] = base64en[in[i] & 0x3F];
+		}
+	}
+
+	/* move back */
+	i -= 1;
+
+	/* check the last and add padding */
+	if ((i % 3) == 0) {
+		out[j++] = base64en[(in[i] & 0x3) << 4];
+		out[j++] = BASE64_PAD;
+		out[j++] = BASE64_PAD;
+	} else if ((i % 3) == 1) {
+		out[j++] = base64en[(in[i] & 0xF) << 2];
+		out[j++] = BASE64_PAD;
+	}
+
+	return BASE64_OK;
+}
+
+int
+base64_decode(const char *in, unsigned int inlen, unsigned char *out)
+{
+	unsigned int i, j;
+
+	for (i = j = 0; i < inlen; i++) {
+		int c;
+		int s = i % 4; 			/* from 8/gcd(6, 8) */
+
+		if (in[i] == '=')
+			return BASE64_OK;
+
+		if (in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST ||
+		    (c = base64de[in[i] - BASE64DE_FIRST]) == -1)
+			return BASE64_INVALID;
+
+		switch (s) {
+		case 0:
+			out[j] = ((unsigned int)c << 2) & 0xFF;
+			continue;
+		case 1:
+			out[j++] += ((unsigned int)c >> 4) & 0x3;
+
+			/* if not last char with padding */
+			if (i < (inlen - 3) || in[inlen - 2] != '=')
+				out[j] = ((unsigned int)c & 0xF) << 4; 
+			continue;
+		case 2:
+			out[j++] += ((unsigned int)c >> 2) & 0xF;
+
+			/* if not last char with padding */
+			if (i < (inlen - 2) || in[inlen - 1] != '=')
+				out[j] =  ((unsigned int)c & 0x3) << 6;
+			continue;
+		case 3:
+			out[j++] += (unsigned char)c;
+		}
+	}
+
+	return BASE64_OK;
+}
+

+ 14 - 0
base64.h

@@ -0,0 +1,14 @@
+#ifndef __BASE64_H__
+#define __BASE64_H__
+
+enum {BASE64_OK = 0, BASE64_INVALID};
+
+#define BASE64_ENCODE_OUT_SIZE(s)	(((s) + 2) / 3 * 4)
+#define BASE64_DECODE_OUT_SIZE(s)	(((s)) / 4 * 3)
+
+int base64_encode(const unsigned char *in, unsigned int inlen, char *out);
+int base64_decode(const char *in, unsigned int inlen, unsigned char *out);
+
+
+#endif /* __BASE64_H__ */
+

+ 36 - 0
h.h

@@ -0,0 +1,36 @@
+#ifndef H_H
+#define H_H
+
+// platform
+#include "hplatform.h"
+#ifdef __unix__
+#include "hunix.h"
+#endif
+
+// c
+#include "hversion.h"
+#include "hdef.h"
+#include "htime.h"
+#include "hlog.h"
+#include "herr.h"
+
+// cpp
+#ifdef __cplusplus
+#include "hstring.h"
+#include "hthread.h"
+#include "hmutex.h"
+#include "hscope.h"
+#include "singleton.h"
+
+#include "hvar.h"
+#include "hobj.h"
+
+#include "hbuf.h"
+#include "hbytearray.h"
+#include "hgui.h"
+
+#include "hframe.h"
+#include "htable.h"
+#endif
+
+#endif // H_H

+ 194 - 0
hbuf.h

@@ -0,0 +1,194 @@
+#ifndef H_BUF_H
+#define H_BUF_H
+
+#include "hdef.h"
+#include <stdlib.h>
+#include <string.h>
+#include <mutex>
+
+typedef struct hbuf_s{
+    uint8* base;
+    size_t len;
+
+    hbuf_s(){
+        base = NULL;
+        len  = 0;
+    }
+
+    hbuf_s(uint8* base, size_t len){
+        this->base = base;
+        this->len  = len;
+    }
+
+    void init(size_t cap){
+        if (cap == len) return;
+
+        if (!base){
+            base = (uint8*)malloc(cap);
+            memset(base, 0, cap);
+        }else{
+            base = (uint8*)realloc(base, cap);
+        }
+        len = cap;
+    }
+
+    void resize(size_t cap){
+        init(cap);
+    }
+
+    void cleanup(){
+        SAFE_FREE(base);
+        len = 0;
+    }
+
+    bool isNull(){
+        return base == NULL || len == 0;
+    }
+}hbuf_t;
+
+class HBuf : public hbuf_t{
+public:
+    HBuf() : hbuf_t(){}
+    HBuf(size_t cap) {init(cap);}
+    HBuf(void* data, size_t len){
+        init(len);
+        memcpy(base, data, len);
+    }
+    virtual ~HBuf() {cleanup();}
+
+    std::mutex mutex; // used in multi-thread
+};
+
+// VL: Variable-Length
+class HVLBuf : public HBuf{
+public:
+    HVLBuf() : HBuf() {_offset = _size = 0;}
+    HVLBuf(size_t cap) : HBuf(cap) {_offset = _size = 0;}
+    HVLBuf(void* data, size_t len) : HBuf(data, len) {_offset = 0; _size = len;}
+    virtual ~HVLBuf() {}
+
+    uint8* data() {return base+_offset;}
+    size_t size() {return _size;}
+
+    void push_front(void* ptr, size_t len){
+        if (len > this->len - _size){
+            this->len = MAX(this->len, len)*2;
+            base = (uint8*)realloc(base, this->len);
+        }
+        
+        if (_offset < len){
+            // move => end
+            memmove(base+this->len-_size, data(), _size);
+            _offset = this->len-_size;
+        }
+
+        memcpy(data()-len, ptr, len);
+        _offset -= len;
+        _size += len;
+    }
+
+    void push_back(void* ptr, size_t len){
+        if (len > this->len - _size){
+            this->len = MAX(this->len, len)*2;
+            base = (uint8*)realloc(base, this->len);
+        }else if (len > this->len - _offset - _size){
+            // move => start
+            memmove(base, data(), _size);
+            _offset = 0;
+        }
+        memcpy(data()+_size, ptr, len);
+        _size += len;
+    }
+
+    void pop_front(void* ptr, size_t len){
+        if (len <= _size){
+            if (ptr){
+                memcpy(ptr, data(), len);
+            }
+            _offset += len;
+            if (_offset >= len) _offset = 0;
+            _size   -= len;
+        }
+    }
+
+    void pop_back(void* ptr, size_t len){
+        if (len <= _size){
+            if (ptr){
+                memcpy(ptr, data()+_size-len, len);
+            }
+            _size -= len;
+        }
+    }
+
+    void clear(){
+        _offset = _size = 0;
+    }
+
+    void prepend(void* ptr, size_t len){
+        push_front(ptr, len);
+    }
+
+    void append(void* ptr, size_t len){
+        push_back(ptr, len);
+    }
+
+    void insert(void* ptr, size_t len){
+        push_back(ptr, len);
+    }
+
+    void remove(size_t len){
+        pop_front(NULL, len);
+    }
+
+private:
+    size_t _offset;
+    size_t _size;
+};
+
+class HRingBuf : public HBuf{
+public:
+    HRingBuf() : HBuf() {_head = _tail = _size = 0;}
+    HRingBuf(size_t cap) : HBuf(cap) {_head = _tail = _size = 0;}
+
+    uint8* alloc(size_t len){
+        uint8* ret = NULL;
+        if (_head < _tail || _size == 0){
+            // [_tail, this->len) && [0, _head)
+            if (this->len - _tail >= len){
+                ret = base + _tail;
+                _tail += len;
+                if (_tail == this->len) _tail = 0;
+            }else if(_head >= len){
+                ret = base;
+                _tail = len;
+            }
+        }else{
+            // [_tail, _head)
+            if (_head - _tail >= len){
+                ret = base + _tail;
+                _tail += len;
+            }
+        }
+        _size += ret ? len : 0;
+        return ret;
+    }
+
+    void   free(size_t len){
+        _size -= len;
+        if (len <= this->len - _head){
+            _head += len;
+            if (_head == this->len) _head = 0;
+        }else{
+            _head = len;
+        }
+    }
+
+    size_t size() {return _size;}
+
+private:
+    size_t _head;
+    size_t _tail;
+    size_t _size;
+};
+
+#endif // H_BUF_H

+ 26 - 0
hbytearray.h

@@ -0,0 +1,26 @@
+#ifndef H_BYTE_ARRAY_H
+#define H_BYTE_ARRAY_H
+
+#include "hbuf.h"
+#include "base64.h"
+
+class HByteArray : public HVLBuf{
+public:
+    HByteArray() : HVLBuf() {}
+    HByteArray(int cap) : HVLBuf(cap) {}
+    HByteArray(void* data, int len) : HVLBuf(data, len) {}
+
+    bool encodeBase64(void* ptr, int len){
+        int base64_len = BASE64_ENCODE_OUT_SIZE(len) + 1; // +1 for '\0'
+        init(base64_len);
+        return base64_encode((unsigned char*)ptr, len, (char*)data()) == BASE64_OK;
+    }
+
+    bool decodeBase64(const char* base64){
+        int out_len = BASE64_DECODE_OUT_SIZE(strlen(base64));
+        init(out_len);
+        return base64_decode(base64, strlen(base64), data()) == BASE64_OK;
+    }
+};
+
+#endif // H_BYTE_ARRAY

+ 66 - 0
hdef.h

@@ -0,0 +1,66 @@
+#ifndef H_DEF_H
+#define H_DEF_H
+
+typedef unsigned char       uint8;
+typedef unsigned short      uint16;
+typedef unsigned int        uint32;
+typedef unsigned long long  uint64;
+
+typedef char                int8;
+typedef short               int16;
+typedef int                 int32;
+typedef long long           int64;
+
+typedef float               float32;
+typedef double              float64;
+
+typedef int                 BOOL;
+
+typedef int (*method_t)(void* userdata);
+typedef void (*procedure_t)(void* userdata);
+
+#ifndef NULL
+#define NULL    0
+#endif
+
+#ifndef TRUE
+#define TRUE    1L
+#endif
+
+#ifndef FALSE
+#define FALSE   0L
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
+
+#define SAFE_FREE(p)    do{if (p) {free(p); (p) = NULL;}}while(0)
+#define SAFE_DELETE(p)  do{if (p) {delete (p); (p) = NULL;}}while(0)
+#define SAFE_DELETE_ARRAY(p) do{if (p) {delete[] (p); (p) = NULL;}}while(0)
+#define SAFE_RELEASE(p) do{if (p) {(p)->release(); (p) = NULL;}}while(0)
+
+#ifndef MAKE_FOURCC
+#define MAKE_FOURCC(a,b,c,d) \
+( ((uint32)d) | ( ((uint32)c) << 8 ) | ( ((uint32)b) << 16 ) | ( ((uint32)a) << 24 ) )
+#endif
+
+#define FLOAT_PRECISION 1e-6
+#define FLOAT_EQUAL_ZERO(f) (-FLOAT_PRECISION < (f) && (f) < FLOAT_PRECISION)
+
+#define STRINGIFY(x)    STRINGIFY_HELPER(x)
+#define STRINGIFY_HELPER(x)    #x
+
+#define STRINGCAT(x,y)  STRINGCAT_HELPER(x,y)
+#define STRINGCAT_HELPER(x,y)   x##y
+
+#define container_of(ptr, type, member) \
+  ((type *) ((char *) (ptr) - offsetof(type, member)))
+
+#endif // H_DEF_H

+ 41 - 0
herr.cpp

@@ -0,0 +1,41 @@
+#include "herr.h"
+#include "hthread.h" // for gettid
+
+#include <map>
+
+// id => errcode
+static std::map<int, int>   s_mapErr;
+
+void set_id_errcode(int id, int errcode){
+    s_mapErr[id] = errcode;
+}
+
+int  get_id_errcode(int id){
+    auto iter = s_mapErr.find(id);
+    if (iter != s_mapErr.end()) {
+        // note: erase after get
+        s_mapErr.erase(iter);
+        return iter->second;
+    }
+    return ERR_OK;    
+}
+
+void set_last_errcode(int errcode){
+    set_id_errcode(gettid(), errcode);
+}
+
+int  get_last_errcode(){
+    return get_id_errcode(gettid());
+}
+
+const char* get_errmsg(int err){
+    switch(err){
+#define CASE_ERR(macro, errcode, errmsg) \
+    case errcode: \
+        return errmsg;
+    FOREACH_ERR(CASE_ERR)
+#undef CASE_ERR
+    default:
+        return "undefined errcode";
+    }
+}

+ 68 - 0
herr.h

@@ -0,0 +1,68 @@
+#ifndef H_ERR_H
+#define H_ERR_H
+
+// F(macro, errcode, errmsg)
+#define FOREACH_ERR_COMMON(F) \
+    F(ERR_OK,               0,      "ok")               \
+    F(ERR_UNKNOWN,          1000,   "unknown error")    \
+    F(ERR_NULL_PARAM,       1001,   "null param")       \
+    F(ERR_NULL_POINTER,     1002,   "null pointer")     \
+    F(ERR_NULL_DATA,        1003,   "null data")        \
+    \
+    F(ERR_INVALID_PARAM,    1010,   "invalid param")    \
+    F(ERR_INVALID_HANDLE,   1011,   "invalid handle")   \
+    F(ERR_INVALID_JSON,     1012,   "invalid json")     \
+    F(ERR_INVALID_XML,      1013,   "invalid xml")      \
+    F(ERR_INVALID_FMT,      1014,   "invalid format")   \
+    \
+    F(ERR_MISMATCH,         1020,   "mismatch")         \
+    F(ERR_REQUEST,          1021,   "error request")    \
+    F(ERR_RESPONSE,         1022,   "error response")   \
+    \
+    F(ERR_MALLOC,           1030,   "malloc failed")    \
+    F(ERR_FREE,             1031,   "free failed")      \
+    \
+    F(ERR_TASK_TIMEOUT,     1100,   "task timeout")     \
+    F(ERR_TASK_DEQUE_FULL,  1101,   "task deque full")  \
+    F(ERR_TASK_NOT_CREATE,  1102,   "task not create")  \
+    \
+    F(ERR_OPEN_FILE,        1200,   "open file failed") \
+    F(ERR_SAVE_FILE,        1201,   "save file failed")
+
+#define FOREACH_ERR_NETWORK(F) \
+    F(ERR_ADAPTER_NOT_FOUND,    2001, "adapter not found")  \
+    F(ERR_SERVER_NOT_FOUND,     2002, "server not found")   \
+    F(ERR_SERVER_UNREACHEABLE,  2003, "server unreacheable")    \
+    F(ERR_SERVER_DISCONNECT,    2004, "server disconnect")      \
+    F(ERR_CONNECT_TIMEOUT,      2005, "connect timeout")        \
+    F(ERR_INVALID_PACKAGE,      2006, "invalid package")        \
+    F(ERR_SERVER_NOT_STARTUP,   2007, "server not startup")     \
+    F(ERR_CLIENT_DISCONNECT,    2008, "client disconnect")
+
+#define FOREACH_ERR_SERVICE(F)  \
+    F(ERR_GROUP_NOT_FOUND,      3000, "group not found")        
+
+#define FOREACH_ERR(F) \
+    FOREACH_ERR_COMMON(F) \
+    FOREACH_ERR_NETWORK(F)  \
+    FOREACH_ERR_SERVICE(F)
+
+#define ENUM_ERR(macro, errcode, _) macro = errcode,
+enum E_ERR{
+    FOREACH_ERR(ENUM_ERR)
+    ERR_LAST
+};
+#undef ENUM_ERR
+
+// id => errcode
+void set_id_errcode(int id, int errcode);
+int  get_id_errcode(int id);
+
+// id = gettid()
+void set_last_errcode(int errcode);
+int  get_last_errcode();
+
+// errcode => errmsg
+const char* get_errmsg(int errcode);
+
+#endif // H_ERR_H

+ 65 - 0
hframe.cpp

@@ -0,0 +1,65 @@
+#include "hframe.h"
+
+int HFrameBuf::push(HFrame* pFrame){
+    if (pFrame->isNull())
+        return -10;
+
+    frame_stats.push_cnt++;
+
+    std::lock_guard<std::mutex> locker(mutex);
+
+    if (frames.size() >= cache_num){
+        if (policy == HFrameBuf::DISCARD){
+            return -20; // note: cache full, discard frame
+        }
+
+        // note: cache full, remove front, push newer frame
+        HFrame& frame = frames.front();
+        frames.pop_front();
+        free(frame.buf.len);
+    }
+
+    int ret = 0;
+    if (isNull()){
+        init(pFrame->buf.len * cache_num);
+        ret = 1; // note: first push
+
+        frame_info.w = pFrame->w;
+        frame_info.h = pFrame->h;
+        frame_info.type = pFrame->type;
+        frame_info.bpp  = pFrame->bpp;
+    }
+
+    HFrame frame;
+    frame.buf.base = alloc(pFrame->buf.len);
+    frame.buf.len  = pFrame->buf.len;
+    frame.copy(*pFrame);
+    frames.push_back(frame);
+    frame_stats.push_ok_cnt++;
+
+    return ret;
+}
+
+int HFrameBuf::pop(HFrame* pFrame){
+    frame_stats.pop_cnt++;
+
+    std::lock_guard<std::mutex> locker(mutex);
+
+    if (isNull())
+        return -10;
+
+    if (frames.size() == 0)
+        return -20;
+
+    HFrame& frame = frames.front();
+    frames.pop_front();
+    free(frame.buf.len);
+
+    if (frame.isNull())
+        return -30;
+
+    pFrame->copy(frame);
+    frame_stats.pop_ok_cnt++;
+
+    return 0;
+}

+ 84 - 0
hframe.h

@@ -0,0 +1,84 @@
+#ifndef H_FRAME_H
+#define H_FRAME_H
+
+#include "hbuf.h"
+#include <deque>
+
+typedef struct hframe_s{
+    hbuf_t buf;
+    int w;
+    int h;
+    int type;
+    int bpp;
+    uint64 ts;
+    void* userdata;
+    hframe_s(){
+        w = h = type = bpp = ts = 0;
+        userdata = NULL;
+    }
+
+    bool isNull(){
+        return w == 0 || h == 0 || buf.isNull();
+    }
+
+    // deep copy
+    void copy(const hframe_s& rhs){
+        this->w = rhs.w;
+        this->h = rhs.h;
+        this->type = rhs.type;
+        this->bpp  = rhs.bpp;
+        this->ts   = rhs.ts;
+        this->userdata = rhs.userdata;
+        if (this->buf.isNull() || this->buf.len != rhs.buf.len){
+            this->buf.init(rhs.buf.len);
+        }
+        memcpy(this->buf.base, rhs.buf.base, rhs.buf.len);
+    }
+}HFrame;
+
+typedef struct frame_info_s{
+    int w;
+    int h;
+    int type;
+    int bpp;
+}FrameInfo;
+
+typedef struct frame_stats_s{
+    int push_cnt;
+    int pop_cnt;
+
+    int push_ok_cnt;
+    int pop_ok_cnt;
+
+    frame_stats_s(){
+        push_cnt = pop_cnt = push_ok_cnt = pop_ok_cnt = 0;
+    }
+}FrameStats;
+
+#define DEFAULT_FRAME_CACHENUM  10
+
+class HFrameBuf : public HRingBuf{
+public:
+    enum CacheFullPolicy{
+        SQUEEZE,
+        DISCARD,       
+    }policy;
+    
+    HFrameBuf() : HRingBuf() {
+        cache_num = DEFAULT_FRAME_CACHENUM;
+        policy = SQUEEZE;
+    }
+
+    void setCache(int num) {cache_num = num;}
+    void setPolicy(CacheFullPolicy policy) {this->policy = policy;}
+
+    int push(HFrame* pFrame);
+    int pop(HFrame* pFrame);
+
+    int         cache_num;
+    FrameStats  frame_stats;
+    FrameInfo   frame_info;
+    std::deque<HFrame> frames;
+};
+
+#endif // H_FRAME_H

+ 15 - 0
hgl.h

@@ -0,0 +1,15 @@
+#ifndef HGL_H
+#define HGL_H
+
+#include <GL/glew.h>
+#include "hframe.h"
+
+// GL PixelFormat extend
+#define GL_I420				0x1910
+
+typedef struct GLTexture_s{
+    GLuint id; // glGenTextures分配的ID
+    HFrame frame;
+}GLTexture;
+
+#endif // HGL_H

+ 71 - 0
hgui.h

@@ -0,0 +1,71 @@
+#ifndef HGUI_H
+#define HGUI_H
+
+#include "hdef.h"
+
+typedef uint32 HColor; // 0xAARRGGBB
+
+#define CLR_B(c)    ( c        & 0xff)
+#define CLR_G(c)    ((c >> 8)  & 0xff)
+#define CLR_R(c)    ((c >> 16) & 0xff)
+#define CLR_A(c)    ((c >> 24) & 0xff)
+#define ARGB(a, r, g, b) MAKE_FOURCC(a,r,g,b)
+
+typedef struct hpoint_s{
+    int x;
+    int y;
+
+#ifdef __cplusplus
+    hpoint_s(){
+        x = y = 0;
+    }
+
+    hpoint_s(int x, int y){
+        this->x = x;
+        this->y = y;
+    }
+#endif
+}HPoint;
+
+typedef struct hsize_s{
+    int w;
+    int h;
+
+#ifdef __cplusplus
+    hsize_s(){
+        w = h = 0;
+    }
+
+    hsize_s(int w, int h){
+        this->w = w;
+        this->h = h;
+    }
+#endif
+}HSize;
+
+typedef struct hrect_s{
+    int x;
+    int y;
+    int w;
+    int h;
+
+#ifdef __cplusplus
+    hrect_s(){
+        x = y = w = h = 0;
+    }
+
+    hrect_s(int x, int y, int w, int h){
+        this->x = x;
+        this->y = y;
+        this->w = w;
+        this->h = h;
+    }
+
+    int left()     {return x;}
+    int right()    {return x+w;}
+    int top()      {return y;}
+    int bottom()   {return y+h;}
+#endif
+}HRect;
+
+#endif // HGUI_H

+ 85 - 0
hlog.cpp

@@ -0,0 +1,85 @@
+#include "hlog.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <mutex>
+#include "htime.h" // for get_datetime
+
+#define LOGBUF_SIZE         (1<<13)  // 8k
+#define LOGFILE_MAXSIZE     (1<<23)  // 8M
+
+static FILE* s_logfp = NULL;
+static char s_logfile[256] = DEFAULT_LOG_FILE;
+static int s_loglevel = DEFAULT_LOG_LEVEL;
+static char s_logbuf[LOGBUF_SIZE];
+static std::mutex s_mutex;
+
+int hlog_set_file(const char* logfile) {
+    if (logfile && strlen(logfile) > 0) {
+        strncpy(s_logfile, logfile, 256);
+    }
+    
+    if (s_logfp) {
+        fclose(s_logfp);
+        s_logfp = NULL;
+    }
+
+    s_logfp = fopen(s_logfile, "a");
+
+    return s_logfp ? 0 : -1;
+}
+
+void hlog_set_level(int level){
+    s_loglevel = level;
+}
+
+int hlog_printf(int level, const char* fmt, ...) {
+    if (level < s_loglevel)
+        return -10;
+
+    const char* pcolor = "";
+    const char* plevel = "";
+#define CASE_LOG(id, str, clr) \
+    case id: plevel = str; pcolor = clr; break;
+
+    switch (level) {
+        FOREACH_LOG(CASE_LOG)
+    }
+#undef CASE_LOG
+
+#ifdef _WIN32
+    pcolor = "";
+#endif
+
+    std::lock_guard<std::mutex> locker(s_mutex);
+
+    if (!s_logfp){
+        if (hlog_set_file(s_logfile) != 0)
+            return -20;
+    }
+
+    if (ftell(s_logfp) > LOGFILE_MAXSIZE){
+        fclose(s_logfp);
+        s_logfp = fopen(s_logfile, "w");
+        if (!s_logfp)
+            return -30;
+    }
+
+    datetime_t now = get_datetime();
+
+    int len = snprintf(s_logbuf, LOGBUF_SIZE, "%s[%04d:%02d:%02d %02d-%02d-%02d.%03d][%s]: ",
+        pcolor, now.year, now.month, now.day, now.hour, now.min, now.sec, now.ms, plevel);
+    va_list ap;
+    va_start(ap, fmt);
+    len += vsnprintf(s_logbuf + len, LOGBUF_SIZE-len, fmt, ap);
+    va_end(ap);
+
+    fprintf(s_logfp, "%s\n", s_logbuf);
+#ifndef _WIN32
+    fprintf(s_logfp, CL_CLR);
+#endif
+
+    fflush(NULL);
+
+    return len;
+}

+ 51 - 0
hlog.h

@@ -0,0 +1,51 @@
+#ifndef H_LOG_H
+#define H_LOG_H
+
+#define CL_CLR      "\033[0m"       /* 恢复颜色 */
+#define CL_BLACK    "\033[30m"      /* 黑色字 */
+#define CL_RED      "\e[1;31m"      /* 红色字 */
+#define CL_GREEN    "\e[1;32m"      /* 绿色字 */
+#define CL_YELLOW   "\e[1;33m"      /* 黄色字 */
+#define CL_BLUE     "\033[34m"      /* 蓝色字 */
+#define CL_PURPLE   "\e[1;35m"      /* 紫色字 */
+#define CL_SKYBLUE  "\e[1;36m"      /* 天蓝字 */
+#define CL_WHITE    "\033[37m"      /* 白色字 */
+
+#define CL_BLK_WHT  "\033[40;37m"   /* 黑底白字 */
+#define CL_RED_WHT  "\033[41;37m"   /* 红底白字 */
+#define CL_GRE_WHT  "\033[42;37m"   /* 绿底白字 */
+#define CL_YEW_WHT  "\033[43;37m"   /* 黄底白字 */
+#define CL_BLUE_WHT "\033[44;37m"   /* 蓝底白字 */
+#define CL_PPL_WHT  "\033[45;37m"   /* 紫底白字 */
+#define CL_SKYB_WHT "\033[46;37m"   /* 天蓝底白字 */
+#define CL_WHT_BLK  "\033[47;30m"   /* 白底黑字 */
+
+// F(id, str, clr)
+#define FOREACH_LOG(F) \
+    F(LOG_LEVEL_DEBUG, "DEBUG", CL_WHITE) \
+    F(LOG_LEVEL_INFO,  "INFO ", CL_GREEN) \
+    F(LOG_LEVEL_WARN,  "WARN ", CL_YELLOW) \
+    F(LOG_LEVEL_ERROR, "ERROR", CL_RED) \
+    F(LOG_LEVEL_FATAL, "FATAL", CL_RED_WHT)
+
+enum LOG_LEVEL{
+    LOG_LEVEL_NONE = 0,
+#define ENUM_LOG(id, str, clr) id,
+    FOREACH_LOG(ENUM_LOG)
+#undef  ENUM_LOG
+};
+
+#define DEFAULT_LOG_FILE    "./default.log"
+#define DEFAULT_LOG_LEVEL   LOG_LEVEL_NONE
+
+int     hlog_set_file(const char* file);
+void    hlog_set_level(int level);
+int     hlog_printf(int level, const char* fmt, ...);
+
+#define hlogd(fmt, ...) hlog_printf(LOG_LEVEL_DEBUG, fmt " [%s:%d:%s]", ## __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__)
+#define hlogi(fmt, ...) hlog_printf(LOG_LEVEL_INFO,  fmt " [%s:%d:%s]", ## __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__)
+#define hlogw(fmt, ...) hlog_printf(LOG_LEVEL_WARN,  fmt " [%s:%d:%s]", ## __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__)
+#define hloge(fmt, ...) hlog_printf(LOG_LEVEL_ERROR, fmt " [%s:%d:%s]", ## __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__)
+#define hlogf(fmt, ...) hlog_printf(LOG_LEVEL_FATAL, fmt " [%s:%d:%s]", ## __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__)
+
+#endif // H_LOG_H

+ 36 - 0
hmutex.h

@@ -0,0 +1,36 @@
+#ifndef H_MUTEX_H
+#define H_MUTEX_H
+
+#include "hplatform.h"
+
+#ifdef _MSC_VER
+class RWLock{
+public:
+    RWLock() { InitializeSRWLock(&_rwlock); }
+    ~RWLock() { }
+
+    void rdlock()   { AcquireSRWLockShared(&_rwlock); }
+    void rdunlock() { ReleaseSRWLockShared(&_rwlock); }
+
+    void wrlock()   { AcquireSRWLockExclusive(&_rwlock); }
+    void wrunlock() { ReleaseSRWLockExclusive(&_rwlock); }
+private:
+    SRWLOCK _rwlock;
+};
+#else
+class RWLock{
+public:
+    RWLock() { pthread_rwlock_init(&_rwlock, NULL); }
+    ~RWLock() { pthread_rwlock_destroy(&_rwlock); }
+
+    void rdlock()   { pthread_rwlock_rdlock(&_rwlock); }
+    void rdunlock() { pthread_rwlock_unlock(&_rwlock); }
+
+    void wrlock()   { pthread_rwlock_wrlock(&_rwlock); }
+    void wrunlock() { pthread_rwlock_unlock(&_rwlock); }
+private:
+    pthread_rwlock_t _rwlock;
+};
+#endif
+
+#endif // H_MUTEX_H

+ 84 - 0
hobj.h

@@ -0,0 +1,84 @@
+#ifndef H_OBJ_H
+#define H_OBJ_H
+
+#include "hdef.h"
+#include "hvar.h"
+#include <string>
+#include <map>
+#include <list>
+
+class HObj{
+public:
+    HObj(HObj* parent = NULL) {
+        _parent = parent;
+    }
+
+    virtual ~HObj() {
+        auto iter = children.begin();
+        while (iter != children.end()) {
+            SAFE_DELETE(*iter);
+            iter++;
+        }
+    }
+
+    std::string name() {
+        return _objName;
+    }
+
+    void  setName(char* name) {
+        _objName = name;
+    }
+
+    HObj* parent() {
+        return _parent;
+    }
+
+    void  setParent(HObj* ptr) {
+        _parent = ptr;
+    }
+
+    void  setChild(HObj* ptr) {
+        children.push_back(ptr);
+    }
+
+    HObj* findChild(std::string objName) {
+        auto iter = children.begin();
+        while (iter != children.end()) {
+            if ((*iter)->name() == objName)
+                return *iter;
+            iter++;
+        }
+    }
+
+    HVar  property(std::string key) {
+        auto iter = properties.find(key);
+        if (iter != properties.end())
+            return iter->second;
+        return HVar();
+    }
+
+    void  setProperty(std::string key, HVar value) {
+        properties[key] = value;
+    }
+
+    method_t method(std::string key) {
+        auto iter = methods.find(key);
+        if (iter != methods.end())
+            return iter->second;
+        return NULL;
+    }
+
+    void  setMethod(std::string key, method_t method) {
+        methods[key] = method;
+    }
+
+public:
+    std::string _objName;
+    std::map<std::string, HVar> properties;
+    std::map<std::string, method_t> methods;
+
+    HObj* _parent;
+    std::list<HObj*> children;
+};
+
+#endif

+ 27 - 0
hplatform.h

@@ -0,0 +1,27 @@
+#ifndef H_PLATFORM_H
+#define H_PLATFORM_H
+
+#ifdef _MSC_VER
+    #ifndef WIN32_LEAN_AND_MEAN
+    #define WIN32_LEAN_AND_MEAN
+    #endif
+    #include <winsock2.h>
+    #include <windows.h>
+    #undef  WIN32_LEAN_AND_MEAN
+#else    
+    #include <unistd.h>
+    #include <pthread.h>
+    #include <sys/time.h>
+
+    #include <strings.h>
+    #define stricmp     strcasecmp
+    #define strnicmp    strncasecmp
+#endif
+
+#ifdef __GNUC__
+    #define GNUC_ALIGN(n)   __attribute__((aligned(n))) 
+#else
+    #define GNUC_ALIGN(n)
+#endif
+
+#endif // H_PLATFORM_H

+ 51 - 0
hscope.h

@@ -0,0 +1,51 @@
+#ifndef H_SCOPE_H
+#define H_SCOPE_H
+
+#include "hdef.h"
+
+template<typename T>
+class ScopeFree{
+public:
+    ScopeFree(T* p) : _p(p) {} 
+    ~ScopeFree()    {SAFE_FREE(_p);}
+private:
+    T*  _p;
+};
+
+template<typename T>
+class ScopeDelete{
+public:
+    ScopeDelete(T* p) : _p(p) {} 
+    ~ScopeDelete()    {SAFE_DELETE(_p);}
+private:
+    T*  _p;
+};
+
+template<typename T>
+class ScopeDeleteArray{
+public:
+    ScopeDeleteArray(T* p) : _p(p) {} 
+    ~ScopeDeleteArray()    {SAFE_DELETE_ARRAY(_p);}
+private:
+    T*  _p;
+};
+
+template<typename T>
+class ScopeRelease{
+public:
+    ScopeRelease(T* p) : _p(p) {} 
+    ~ScopeRelease()    {SAFE_RELEASE(_p);}
+private:
+    T*  _p;
+};
+
+template<typename T>
+class ScopeLock{
+public:
+    ScopeLock(T& mutex) : _mutex(mutex) {_mutex.lock();} 
+    ~ScopeLock()    {_mutex.unlock();}
+private:
+    T& _mutex;
+};
+
+#endif // H_SCOPE_H

+ 118 - 0
hstring.cpp

@@ -0,0 +1,118 @@
+#include "hstring.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <iostream>
+#include <sstream>
+
+int vscprintf(const char* fmt, va_list ap) {
+	return vsnprintf(NULL, 0, fmt, ap);
+}
+
+std::string asprintf(const char* fmt, ...) {
+	va_list ap;
+	va_start(ap, fmt);
+	int len = vscprintf(fmt, ap) + 1;
+	va_end(ap);
+	// must recall va_start in linux
+	va_start(ap, fmt);
+	char* buf = (char*)malloc(len);
+	vsnprintf(buf, len, fmt, ap);
+	va_end(ap);
+	buf[len-1] = '\0';
+	std::string res(buf);
+	free(buf);
+	return res;
+}
+
+StringList split(std::string& str, char delim){
+	std::stringstream ss;
+	ss << str;
+	std::string item;
+	StringList res;
+	while (std::getline(ss, item, delim)){
+		res.push_back(item);
+	}
+	return res;
+}
+
+std::string trim(std::string& str){
+	std::string::size_type pos1 = str.find_first_not_of(" \t\r\n");
+	if (pos1 == std::string::npos)	return "";
+
+	std::string::size_type pos2 = str.find_last_not_of(" \t\r\n");
+	return str.substr(pos1, pos2-pos1+1);
+}
+
+std::string replace(std::string& str, std::string& find, std::string& rep){
+	std::string::size_type pos = 0;
+	std::string::size_type a = find.size();
+	std::string::size_type b = rep.size();
+	while ((pos = str.find(find,pos)) != std::string::npos){
+	    str.replace(pos, a, rep);
+		pos += b;
+	}
+    return str;
+}
+
+string basename(string& str){
+    string::size_type pos1 = str.find_last_not_of("/\\");
+    if (pos1 == string::npos){
+        return "/";
+    }
+    string::size_type pos2 = str.find_last_of("/\\", pos1);
+    if (pos2 == string::npos){
+        pos2 = 0;
+    }else{
+        pos2++;
+    }
+
+    return str.substr(pos2, pos1-pos2+1);
+}
+
+string dirname(string& str){
+    string::size_type pos1 = str.find_last_not_of("/\\");
+    if (pos1 == string::npos){
+        return "/";
+    }
+    string::size_type pos2 = str.find_last_of("/\\", pos1);
+    if (pos2 == string::npos){
+        return ".";
+    }else if (pos2 == 0){
+        pos2 = 1;
+    }
+
+    return str.substr(0, pos2);
+}
+
+string filename(string& str){
+    string::size_type pos1 = str.find_last_of("/\\");
+    if (pos1 == string::npos){
+        pos1 = 0;
+    }else{
+        pos1++;
+    }
+    string file = str.substr(pos1, -1);
+
+    string::size_type pos2 = file.find_last_of(".");
+    if (pos2 == string::npos){
+        return file;
+    }
+    return file.substr(0, pos2);
+}
+
+string suffixname(string& str){
+    string::size_type pos1 = str.find_last_of("/\\");
+    if (pos1 == string::npos){
+        pos1 = 0;
+    }else{
+        pos1++;
+    }
+    string file = str.substr(pos1, -1);
+
+    string::size_type pos2 = file.find_last_of(".");
+    if (pos2 == string::npos){
+        return "";
+    }
+    return file.substr(pos2+1, -1);
+}

+ 19 - 0
hstring.h

@@ -0,0 +1,19 @@
+#ifndef H_STRING_H
+#define H_STRING_H
+
+#include <string>
+#include <vector>
+using std::string;
+
+typedef std::vector<string> StringList;
+
+string asprintf(const char* fmt, ...);
+StringList split(string& str, char delim);
+string trim(string& str);
+
+string basename(string& str);
+string dirname(string& str);
+string filename(string& str);
+string suffixname(string& str);
+
+#endif // H_STRING_H

+ 50 - 0
htable.cpp

@@ -0,0 +1,50 @@
+#include "htable.h"
+#include "hdef.h"
+
+HTable::HTable(){
+    row = col = 0;
+}
+
+void HTable::init(int row, int col){
+    this->row = row;
+    this->col = col;
+    m_mapCells.clear();
+    for (int r = 1; r <= row; ++r){
+        for (int c = 1; c <= col; ++c){
+            int id = (r-1) * col + c;
+            m_mapCells[id] = HTableCell(r,r,c,c);
+        }
+    }
+}
+
+bool HTable::getTableCell(int id, HTableCell& rst){
+    if (m_mapCells.find(id) != m_mapCells.end()){
+        rst = m_mapCells[id];
+        return true;
+    }
+    return false;
+}
+
+HTableCell HTable::merge(int lt, int rb){
+    HTableCell cell_lt,cell_rb;
+    if (getTableCell(lt, cell_lt) && getTableCell(rb, cell_rb)){
+        int r1 = MIN(cell_lt.r1, cell_rb.r1);
+        int r2 = MAX(cell_lt.r2, cell_rb.r2);
+        int c1 = MIN(cell_lt.c1, cell_rb.c1);
+        int c2 = MAX(cell_lt.c2, cell_rb.c2);
+
+        HTableCell cell(r1, r2, c1, c2);
+        std::map<int, HTableCell>::iterator iter = m_mapCells.begin();
+        while (iter != m_mapCells.end()){
+            if (cell.contain(iter->second)){
+                iter = m_mapCells.erase(iter);
+            }else
+                ++iter;
+        }
+        m_mapCells[lt] = cell;
+
+        return cell;
+    }
+
+    return HTableCell(0,0,0,0);
+}

+ 45 - 0
htable.h

@@ -0,0 +1,45 @@
+#ifndef H_TABLE_H
+#define H_TABLE_H
+
+#include <map>
+
+class HTableCell{
+public:
+    HTableCell(){r1=r2=c1=c2=0;}
+    HTableCell(int r1, int r2, int c1, int c2){
+        this->r1 = r1;
+        this->r2 = r2;
+        this->c1 = c1;
+        this->c2 = c2;
+    }
+
+    int rowspan() {return r2 - r1 + 1;}
+    int colspan() {return c2 - c1 + 1;}
+    int span() {return rowspan() * colspan();}
+
+    bool contain(HTableCell cell){
+        if (cell.r1 >= r1 && cell.r2 <= r2 &&
+                cell.c1 >= c1 && cell.c2 <= c2)
+            return true;
+        return false;
+    }
+
+    int r1,r2,c1,c2;
+};
+
+class HTable
+{
+public:
+    HTable();
+
+    void init(int row, int col);
+    bool getTableCell(int id, HTableCell& rst);
+    HTableCell merge(int lt, int rb);
+
+public:
+    int row;
+    int col;
+    std::map<int, HTableCell> m_mapCells; // id => HTabelCell
+};
+
+#endif // H_TABLE_H

+ 103 - 0
hthread.h

@@ -0,0 +1,103 @@
+#ifndef H_THREAD_H
+#define H_THREAD_H
+
+#include "hdef.h"
+#include "hplatform.h"
+#include "htime.h" // for msleep
+#include <thread>
+#include <atomic>
+
+#ifdef _MSC_VER
+inline uint32 getpid(){
+    return GetCurrentProcessId();
+}
+#endif
+
+inline uint32 gettid(){
+#ifdef _MSC_VER
+    return GetCurrentThreadId();
+#else
+    return pthread_self();
+#endif
+}
+
+/************************************************
+ * HThread
+ * Status: STOP,RUNNING,PAUSE
+ * Control: start,stop,pause,resume
+ * first-level virtual: doTask
+ * second-level virtual: run
+************************************************/
+class HThread{
+public:
+    HThread() {
+        status = STOP;
+    }
+
+    virtual ~HThread() {
+
+    }
+
+    virtual int start() {
+        if (status == STOP) {
+            status = RUNNING;
+            thread = std::thread(&HThread::thread_proc, this);
+        }
+        return 0;
+    }
+
+    virtual int stop() {
+        if (status != STOP) {
+            status = STOP;
+            thread.join(); // wait thread exit
+        }
+        return 0;
+    }
+
+    virtual int pause() {
+        if (status == RUNNING) {
+            status = PAUSE;
+        }
+        return 0;
+    }
+
+    virtual int resume() {
+        if (status == PAUSE) {
+            status = RUNNING;
+        }
+        return 0;
+    }
+
+    void thread_proc() {
+        doPrepare();
+        run();
+        doFinish();
+    }
+
+    virtual void run() {
+        while (status != STOP) {
+            if (status == PAUSE) {
+                msleep(1);
+                continue;
+            }
+
+            doTask();
+
+            msleep(1);
+        }
+    }
+
+    virtual void doPrepare() {}
+    virtual void doTask() {}
+    virtual void doFinish() {}
+
+    std::thread thread;
+    enum Status {
+        STOP,
+        RUNNING,
+        PAUSE,
+    };
+    std::atomic<Status> status;
+};
+
+#endif // H_THREAD_H

+ 78 - 0
htime.cpp

@@ -0,0 +1,78 @@
+#include "htime.h"
+#include <stdio.h>
+#include <string.h>
+
+void msleep(unsigned long ms){
+#ifdef _MSC_VER
+    Sleep(ms);
+#else
+    usleep(ms*1000);
+#endif
+}
+
+uint64 gettick(){
+#ifdef _MSC_VER
+    return GetTickCount();
+#else
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return tv.tv_sec + tv.tv_usec/1000;
+#endif
+}
+
+datetime_t get_datetime(){
+    datetime_t  dt;
+#ifdef _MSC_VER
+    SYSTEMTIME tm;
+	GetLocalTime(&tm);
+	dt.year     = tm.wYear;
+	dt.month    = tm.wMonth;
+	dt.day      = tm.wDay;
+	dt.hour     = tm.wHour;
+	dt.min      = tm.wMinute;
+	dt.sec      = tm.wSecond;
+	dt.ms       = tm.wMilliseconds;
+#else
+    struct timeval tv;
+    struct tm* tm = NULL;
+    gettimeofday(&tv, NULL);
+    time_t tt = tv.tv_sec;
+    tm = localtime(&tt);
+
+    dt.year     = tm->tm_year + 1900;
+    dt.month    = tm->tm_mon  + 1;
+    dt.day      = tm->tm_mday;
+    dt.hour     = tm->tm_hour;
+    dt.min      = tm->tm_min;
+    dt.sec      = tm->tm_sec;
+    dt.ms       = tv.tv_usec/1000;
+#endif    
+    return dt;
+}
+
+static const char* s_month[] = {"January", "February", "March", "April", "May", "June",
+    "July", "August", "September", "October", "November", "December"};
+
+int month_atoi(const char* month){
+    for (int i = 0; i < ARRAY_SIZE(s_month); ++i){
+        if (strnicmp(month, s_month[i], strlen(month)) == 0)
+            return i+1;
+    }
+    return 0;
+}
+
+const char* month_itoa(int month){
+    if (month < 1 || month > 12){
+        return NULL;
+    }
+    return s_month[month-1];
+}
+
+datetime_t get_compile_datetime(){
+    static datetime_t dt;
+    char month[32];
+    sscanf(__DATE__, "%s %d %d", month, &dt.day, &dt.year);
+    sscanf(__TIME__, "%d %d %d", &dt.hour, &dt.min, &dt.sec);
+    dt.month = month_atoi(month);
+    return dt;
+}

+ 34 - 0
htime.h

@@ -0,0 +1,34 @@
+#ifndef H_TIME_H
+#define H_TIME_H
+
+#include "hdef.h"
+#include "hplatform.h"
+#include <time.h>
+
+typedef struct datetime_s{
+    int year;
+    int month;
+    int day;
+    int hour;
+    int min;
+    int sec;
+    int ms;
+}datetime_t;
+
+void msleep(unsigned long ms);
+
+#ifdef _MSC_VER
+inline void sleep(unsigned int s){
+    Sleep(s*1000);
+}
+#endif
+
+uint64 gettick();
+
+int month_atoi(const char* month);
+const char* month_itoa(int month);
+
+datetime_t get_datetime();
+datetime_t get_compile_datetime();
+
+#endif // H_TIME_H

+ 39 - 0
hunix.cpp

@@ -0,0 +1,39 @@
+#ifdef __unix__
+
+#include "hunix.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+void daemonize(){
+    pid_t pid = fork();
+    if (pid < 0){
+        printf("fork error: %d", errno);
+        return;
+    }
+
+    if (pid > 0){
+        // exit parent process
+        exit(0);
+    }
+
+    // child process become process leader
+    setsid();
+
+    // set fd
+    int fd;
+    if ((fd = open("/dev/null", O_RDWR, 0)) != -1){
+		dup2(fd, STDIN_FILENO);
+		dup2(fd, STDOUT_FILENO);
+		dup2(fd, STDERR_FILENO);
+		if (fd > STDERR_FILENO)
+			close(fd);
+    }
+}
+
+#endif // __unix__

+ 6 - 0
hunix.h

@@ -0,0 +1,6 @@
+#ifndef H_UNIX_H
+#define H_UNIX_H
+
+void daemonize();
+
+#endif // H_UNIX_H

+ 54 - 0
hvar.h

@@ -0,0 +1,54 @@
+#ifndef H_VAR_H
+#define H_VAR_H
+
+#include "hdef.h"
+#include <stdlib.h>
+#include <string.h>
+
+class HVar{
+public:
+    enum TYPE{
+        UNKNOWN,
+        BOOLEAN,
+        INTEGER,
+        FLOAT,
+        STRING,
+        POINTER
+    } type;
+
+    union DATA{
+        bool b;
+        int64 i;
+        float64 f;
+        char* str;
+        void* ptr;
+    } data;
+
+    HVar()          {memset(&data, 0, sizeof(data)); type = UNKNOWN;}
+    HVar(bool b)    {data.b = b; type = BOOLEAN;}
+    HVar(int64 i)   {data.i = i; type = INTEGER;}
+    HVar(float64 f) {data.f = f; type = FLOAT;}
+    HVar(char* str) {
+        data.str = (char*)malloc(strlen(str)+1); 
+        strcpy(data.str, str); 
+        type = STRING;
+    }
+    HVar(void* ptr) {data.ptr = ptr; type = POINTER;}
+
+    ~HVar() {
+        if (type == STRING) {
+            SAFE_FREE(data.str);
+        }
+    }
+
+    bool    isNull()    {return type == UNKNOWN;}
+    bool    isValid()   {return type != UNKNOWN;}
+
+    bool    toBool()    {return data.b;}
+    int64   toInt()     {return data.i;}     
+    float64 toFloat()   {return data.f;}
+    char*   toString()  {return data.str;}
+    void*   toPointer() {return data.ptr;}
+};
+
+#endif // H_VAR_H

+ 31 - 0
hversion.h

@@ -0,0 +1,31 @@
+#ifndef H_VERSION_H
+#define H_VERSION_H
+
+#include "hdef.h"
+#include "htime.h"
+#include <stdio.h>
+
+#define VERSION_MAJOR   1
+#define VERSION_MINOR   18
+#define VERSION_MICRO   5
+#define VERSION_PATCH   1
+
+#define VERSION_STRING  STRINGIFY(VERSION_MAJOR) "." \
+                        STRINGIFY(VERSION_MINOR) "." \
+                        STRINGIFY(VERSION_MICRO) "." \
+                        STRINGIFY(VERSION_PATCH)
+
+#define VERSION_HEX     (VERSION_MAJOR << 24) | (VERSION_MINOR << 16) | (VERSION_MICRO << 8) | VERSION_PATCH
+
+inline const char* get_static_version(){
+    return VERSION_STRING;
+}
+
+inline const char* get_compile_version(){
+    static char version[16];
+    static datetime_t dt = get_compile_datetime();
+    sprintf(version, "%d.%d.%d.%d", VERSION_MAJOR, dt.year%100, dt.month, dt.day);
+    return version;
+}
+
+#endif // H_VERSION_H

+ 31 - 0
singleton.h

@@ -0,0 +1,31 @@
+#ifndef SINGLETON_H
+#define SINGLETON_H
+
+#define DISABLE_COPY(Class) \
+    Class(const Class &) = delete; \
+    Class &operator=(const Class &) = delete;
+
+#define DCLR_SINGLETON(Class) \
+    public: \
+        static Class* instance(); \
+        static void exitInstance(); \
+    private: \
+        DISABLE_COPY(Class) \
+        static Class* s_pInstance;
+
+#define IMPL_SINGLETON(Class) \
+    Class* Class::s_pInstance = NULL; \
+    Class* Class::instance(){ \
+        if (s_pInstance == NULL){ \
+            s_pInstance = new Class; \
+        } \
+        return s_pInstance; \
+    } \
+    void Class::exitInstance(){ \
+        if (s_pInstance){  \
+            delete s_pInstance; \
+            s_pInstance = NULL; \
+        }   \
+    }
+
+#endif // SINGLETON_H