[elm_cnp_helper.c] add convert from efl tag to html tag
authordeasung.kim <deasung.kim@samsung.com>
Tue, 24 May 2011 03:41:17 +0000 (12:41 +0900)
committerdeasung.kim <deasung.kim@samsung.com>
Tue, 24 May 2011 03:41:17 +0000 (12:41 +0900)
src/lib/elm_cnp_helper.c

index 980308c..5081977 100644 (file)
@@ -406,6 +406,560 @@ static Ecore_Event_Handler *handler_status = NULL;
 /* Stringshared, so I can just compare pointers later */
 static const char *text_uri;
 
+
+/* For convert EFL to HTML */
+
+#define TAGPOS_START    0x00000001
+#define TAGPOS_END      0x00000002
+#define TAGPOS_ALONE    0x00000003
+
+/* TEXTBLOCK tag using stack but close tag word has no mean maybe bug...
+ * TEXTBLOCK <b>bold<font>font</b>bold</font>
+ * HTML <b>bold<font>font bold</b>font</font> */
+
+typedef struct _TagTable {
+     char *src;
+     char *dst;
+     char tagType;
+}TagTable;
+
+TagTable _EFLtoHTMLConvertTable[] = {
+       {"font", "font", 0},
+       {"underline", "del", 0},
+       {"strikethrough", "ins", 0},
+       {"br", "br", 1},
+       {"b", "b", 1},
+       {"item", "img", 1}
+};
+
+typedef struct _TagNode TagNode, *PTagNode;
+struct _TagNode {
+     char *tag;  //EINA_STRINGSHARE if NULL just str
+     char *tag_str;
+     char *str;
+     char *pos_in_ori_str;
+     PTagNode matchTag;
+     void *tagData;
+     unsigned char tagPosType;
+};
+
+typedef struct _FontTagData FontTagData, *PFontTagData;
+struct _FontTagData {
+     char *name;
+     char *color;
+     char *size;
+     char *bg_color;
+};
+
+
+typedef struct _ItemTagData ItemTagData, *PItemTagData;
+struct _ItemTagData {
+     char *href;
+     char *width;
+     char *height;
+};
+
+#define SAFEFREE(ptr) \
+   do\
+{\
+   if (ptr)\
+   free(ptr);\
+   ptr = NULL;\
+} while(0);\
+
+#define freeAndAssign(dst, value) \
+   do\
+{\
+   if (value)\
+     {\
+        SAFEFREE(dst);\
+        dst = value;\
+     }\
+} while(0);
+
+
+static PTagNode _new_tag_node(char *tag, char *tag_str, char* str, char *pos_in_ori_str);
+static PTagNode _get_start_node(char *str);
+static PTagNode _get_next_node(PTagNode prev);
+static void _delete_node(PTagNode node);
+static void _link_match_tags(Eina_List *nodes);
+static char *_get_tag_value(const char *tag_str, const char *tag_name);
+static char *_convert_to_html(Eina_List* nodes);
+static void _set_EFL_tag_data(Eina_List* nodes);
+static PFontTagData _set_EFL_font_data(PFontTagData data, const char *tag_str);
+static PItemTagData _set_EFL_item_data(PItemTagData data, const char *tag_str);
+
+#ifdef DEBUGON
+static void _dumpNode(Eina_List* nodes);
+#endif
+
+static PTagNode
+_new_tag_node(char *tag, char *tag_str, char* str, char *pos_in_ori_str)
+{
+   PTagNode newNode = calloc(1, sizeof(TagNode));
+   newNode->tag = tag;
+   newNode->tag_str = tag_str;
+   newNode->str = str;
+   newNode->pos_in_ori_str = pos_in_ori_str;
+   return newNode;
+}
+
+static PTagNode
+_get_start_node(char *str)
+{
+   char *startStr = NULL;
+   if (!str || str[0] == '\0')
+     return NULL;
+
+   if (str[0] != '<')
+     {
+        char *tagStart = strchr(str, '<');
+        if (!tagStart)
+          startStr = strdup(str);
+        else
+          {
+             int strLength = tagStart - str;
+             startStr = malloc(sizeof(char) * (strLength + 1));
+             strncpy(startStr, str, strLength);
+             startStr[strLength] = '\0';
+          }
+     }
+
+   return _new_tag_node(NULL, NULL, startStr, str);
+}
+
+static PTagNode
+_get_next_node(PTagNode prev)
+{
+   PTagNode retTag = NULL;
+   char *tagStart;
+   char *tagEnd;
+   char *tagNameEnd = NULL;
+   char *nextTagStart;
+
+   if (prev->tag == NULL)
+     tagStart = strchr(prev->pos_in_ori_str, '<');
+   else
+     tagStart = strchr(prev->pos_in_ori_str + 1, '<');
+
+   if (!tagStart)
+     return retTag;
+
+   tagEnd = strchr(tagStart, '>');
+   nextTagStart = strchr(tagStart + 1, '<');
+
+   if (!tagEnd || (nextTagStart && (nextTagStart < tagEnd)))
+        return _get_start_node(tagStart + 1);
+
+   int spCnt = 5;
+   char *spArray[spCnt];
+   spArray[0] = strchr(tagStart, '=');
+   spArray[1] = strchr(tagStart, '_');
+   spArray[2] = strchr(tagStart, ' ');
+   spArray[3] = strchr(tagStart, '\t');
+   spArray[4] = strchr(tagStart, '\n');
+   tagNameEnd = tagEnd;
+
+   int i;
+   for (i = 0; i < spCnt; i++)
+     {
+        if (spArray[i] && spArray[i] < tagNameEnd)
+          tagNameEnd = spArray[i];
+     }
+
+   int tagLength = tagNameEnd - tagStart - 1;
+   char *tagName = NULL;
+   if (!strncmp(&tagStart[1], "color", tagLength))
+     tagName = strndup("font", 4);
+   else if (!strncmp(&tagStart[1], "/color", tagLength))
+     tagName = strndup("/font", 5);
+   else if (!strncmp(&tagStart[1], "/item", tagLength))
+     tagName = strdup("");
+   else
+     tagName = strndup(&tagStart[1], tagLength);
+
+   int tagStrLength = 0;
+   char *tagStr = NULL;
+   if (tagName)
+     {
+        tagStrLength = tagEnd - tagStart + 1;
+        tagStr = strndup(tagStart, tagStrLength);
+     }
+
+   unsigned int strLength = nextTagStart ? (unsigned int)(nextTagStart - tagEnd - 1) : strlen(&tagEnd[1]);
+   char *str = strndup(&tagEnd[1], strLength);
+
+   retTag = _new_tag_node(tagName, tagStr, str, tagStart);
+   return retTag;
+}
+
+
+static void
+_delete_node(PTagNode node)
+{
+   if (node)
+     {
+        SAFEFREE(node->tag_str);
+        SAFEFREE(node->str);
+
+        if (node->tagData)
+          {
+             if (node->tag)
+               {
+                  if (!strcmp("font", node->tag))
+                    {
+                       PFontTagData data = node->tagData;
+                       SAFEFREE(data->name);
+                       SAFEFREE(data->color);
+                       SAFEFREE(data->size);
+                       SAFEFREE(data->bg_color);
+                    }
+                  if (!strcmp("item", node->tag))
+                    {
+                       PItemTagData data = node->tagData;
+                       SAFEFREE(data->href);
+                       SAFEFREE(data->width);
+                       SAFEFREE(data->height);
+                    }
+
+               }
+             SAFEFREE(node->tagData);
+          }
+        SAFEFREE(node->tag);
+        SAFEFREE(node);
+     }
+}
+
+static void
+_link_match_tags(Eina_List *nodes)
+{
+   Eina_List *stack = NULL;
+
+   PTagNode trail, popData;
+   Eina_List *l, *r;
+
+   EINA_LIST_FOREACH(nodes, l, trail)
+     {
+        if (!trail->tag || trail->tag[0] == '\0')
+          continue;
+        if (!strcmp("br", trail->tag))
+          {
+             trail->tagPosType = TAGPOS_ALONE;
+             continue;
+          }
+        else if (!strcmp("item", trail->tag))
+          {
+             trail->tagPosType = TAGPOS_ALONE;
+             continue;
+          }
+
+        if (trail->tag[0] != '/') // PUSH
+          {
+             stack = eina_list_append(stack, trail);
+/*             eina_array_push(stack, trail);
+             cnp_debug("stack: %d, tag %s\n", eina_array_count_get(stack), trail->tag);*/
+             cnp_debug("stack: %d, tag %s\n", eina_list_count(stack), trail->tag);
+          }
+        else // POP
+          {
+             if (!eina_list_count(stack))
+               {
+                  cnp_debug("tag not matched %s\n", trail->tag);
+                  continue;
+               }
+
+             EINA_LIST_REVERSE_FOREACH(stack, r, popData)
+               {
+                  if (popData->tag && !strcmp(popData->tag, &trail->tag[1]))
+                    {
+                       popData->tagPosType = TAGPOS_START;
+                       trail->tagPosType = TAGPOS_END;
+                       popData->matchTag = trail;
+                       trail->matchTag = popData;
+                       stack = eina_list_remove_list(stack, r);
+                       break;
+                    }
+               }
+/*             popData = eina_array_pop(stack);
+
+             popData->tagPosType = TAGPOS_START;
+             trail->tagPosType = TAGPOS_END;
+             popData->matchTag = trail;
+             trail->matchTag = popData;
+             cnp_debug("pop stack: %d, tag %s\n", eina_array_count_get(stack), trail->tag);
+             */
+          }
+     }
+
+/*   if (eina_array_count_get(stack))
+     cnp_debug("stack state: %d, tag %s\n", eina_array_count_get(stack), trail->tag);*/
+
+   /* Make Dummy close tag */
+/*   while ((popData = eina_array_pop(stack)))  */
+
+   EINA_LIST_REVERSE_FOREACH(stack, r, popData)
+     {
+        PTagNode newData;
+        int tagLength = strlen(popData->tag);
+        char *tagName = malloc(sizeof(char) * (tagLength + 2));
+
+        tagName[0] = '/';
+        tagName[1] = '\0';
+        strcat(tagName, popData->tag);
+
+        newData = _new_tag_node(tagName, NULL, NULL, NULL);
+        popData->tagPosType = TAGPOS_START;
+        newData->tagPosType = TAGPOS_END;
+        popData->matchTag = newData;
+        newData->matchTag = popData;
+        nodes = eina_list_append(nodes, newData);
+/*        cnp_debug("stack: %d, tag %s\n", eina_array_count_get(stack), popData->tag);*/
+     }
+/*   cnp_debug("stack_top: %d\n", eina_array_count_get(stack));
+   eina_array_free(stack);*/
+   eina_list_free(stack);
+}
+
+static char *
+_get_tag_value(const char *tag_str, const char *tag_name)
+{
+   if (!tag_name || !tag_str)
+     return NULL;
+
+   char *tag;
+   if ((tag = strstr(tag_str, tag_name)))
+     {
+        if (tag[strlen(tag_name)] == '_')
+          return NULL;
+        char *value = strchr(tag, '=');
+        if (value)
+          {
+             do
+               {
+                  value++;
+               } while (!isalnum(*value) && *value != '#');
+
+             int spCnt = 6;
+             char *spArray[spCnt];
+             spArray[0] = strchr(value, ' ');
+             spArray[1] = strchr(value, '>');
+             spArray[2] = strchr(value, '\"');
+             spArray[3] = strchr(value, '\'');
+             spArray[4] = strchr(value, '\t');
+             spArray[5] = strchr(value, '\n');
+             char *valueEnd = strchr(value, '\0');
+
+             int i;
+             for (i = 0; i < spCnt; i++)
+               {
+                  if (spArray[i] && spArray[i] < valueEnd)
+                    valueEnd = spArray[i];
+               }
+
+             int valueLength = valueEnd - value;
+             return strndup(value, valueLength);
+          }
+     }
+   return NULL;
+}
+
+static PFontTagData
+_set_EFL_font_data(PFontTagData data, const char *tag_str)
+{
+   char *value;
+
+   if (!data)
+     data = calloc(1, sizeof(FontTagData));
+   value = _get_tag_value(tag_str, "font_size");
+   freeAndAssign(data->size, value);
+   value = _get_tag_value(tag_str, "color");
+   freeAndAssign(data->color, value);
+   value = _get_tag_value(tag_str, "bgcolor");
+   freeAndAssign(data->bg_color, value);
+   value = _get_tag_value(tag_str, "font");
+   freeAndAssign(data->name, value);
+
+   return data;
+}
+
+static PItemTagData
+_set_EFL_item_data(PItemTagData data, const char *tag_str)
+{
+   char *value;
+
+   if (!data)
+     data = calloc(1, sizeof(ItemTagData));
+   value = _get_tag_value(tag_str, "href");
+   if (value)
+     {
+        char *path = strstr(value, "file://");
+        if (path)
+          {
+             char *modify = malloc(sizeof(char) * (strlen(value) + 1));
+             strncpy(modify, "file://", 7);
+             modify[7] = '\0';
+             path += 7;
+             while (path[1] && path[0] && path[1] == '/' && path[0] == '/')
+               {
+                  path++;
+               }
+             strcat(modify, path);
+             data->href = modify;
+             cnp_debug("image href ---%s---\n", data->href);
+          }
+        free(value);
+     }
+
+   value = _get_tag_value(tag_str, "absize");
+   if (value)
+     {
+        char *xpos = strchr(value, 'x');
+        if (xpos)
+          {
+             int absizeLen = strlen(value);
+             freeAndAssign(data->width, strndup(value, xpos - value));
+             freeAndAssign(data->height, strndup(xpos + 1, absizeLen - (xpos - value) - 1));
+             cnp_debug("image width: -%s-, height: -%s-\n", data->width, data->height);
+          }
+        free(value);
+     }
+   return data;
+}
+
+static void
+_set_EFL_tag_data(Eina_List* nodes)
+{
+   PTagNode trail;
+   Eina_List *l;
+
+   EINA_LIST_FOREACH(nodes, l, trail)
+     {
+        if (!trail->tag)
+          continue;
+        if (!strcmp("font", trail->tag))
+             trail->tagData = _set_EFL_font_data(trail->tagData, trail->tag_str);
+        else if (!strcmp("item", trail->tag))
+             trail->tagData = _set_EFL_item_data(trail->tagData, trail->tag_str);
+     }
+}
+
+#ifdef DEBUGON
+static void
+_dumpNode(Eina_List* nodes)
+{
+   PTagNode trail;
+   Eina_List *l;
+
+   EINA_LIST_FOREACH(nodes, l, trail)
+     {
+        cnp_debug("tag: %s, tag_str: %s, str: %s, tagPosType: %d\n",
+               trail->tag, trail->tag_str, trail->str, trail->tagPosType);
+        cnp_debug("matchTag: %x ", (unsigned int)trail->matchTag);
+        if (trail->matchTag)
+          cnp_debug("matchTag->tag_str: %s", trail->matchTag->tag_str);
+        if (trail->tagData)
+          {
+             if (!strcmp(trail->tag, "font"))
+               {
+                  PFontTagData data = trail->tagData;
+                  cnp_debug(" tagData->name: %s, tagData->color: %s, tagData->size: %s, tagData->bg_color: %s",
+                         data->name, data->color, data->size, data->bg_color);
+               }
+             else if (!strcmp(trail->tag, "item"))
+               {
+                  PItemTagData data = trail->tagData;
+                  cnp_debug(" tagData->href: %s, tagData->width: %s, tagData->height: %s",
+                         data->href, data->width, data->height);
+               }
+             else
+               cnp_debug("\nERROR!!!! not need tagData");
+          }
+        cnp_debug("\n");
+     }
+}
+#endif
+
+static char *
+_convert_to_html(Eina_List* nodes)
+{
+   PTagNode trail;
+   Eina_List *l;
+
+   Eina_Strbuf *html = eina_strbuf_new();
+
+   int tableCnt = sizeof(_EFLtoHTMLConvertTable) / sizeof(TagTable);
+
+   EINA_LIST_FOREACH(nodes, l, trail)
+     {
+        if (trail->tag)
+          {
+             char *tagName = trail->tagPosType == TAGPOS_END ?
+                trail->matchTag->tag : trail->tag;
+             int j;
+             for(j = 0; j < tableCnt; j++)
+               {
+                  if (!strcmp(_EFLtoHTMLConvertTable[j].src, tagName))
+                    {
+                       switch(trail->tagPosType)
+                         {
+                          case TAGPOS_END:
+                             eina_strbuf_append(html, "</");
+                             break;
+                          default:
+                             eina_strbuf_append(html, "<");
+                             break;
+                         }
+
+                       eina_strbuf_append(html, _EFLtoHTMLConvertTable[j].dst);
+                       if (trail->tagPosType != TAGPOS_END)
+                         {
+                            if (!strcmp(_EFLtoHTMLConvertTable[j].src, "font"))
+                              {
+                                 PFontTagData data = trail->tagData;
+                                 if (data->name)
+                                   {
+                                   }
+                                 if (data->color)
+                                   eina_strbuf_append_printf(html, " color=\"%s\"", data->color);
+                                 if (data->size)
+                                   eina_strbuf_append_printf(html, " size=\"%s\"", data->size);
+                                 if (data->bg_color)
+                                   {
+                                   }
+                              }
+                            else if (!strcmp(_EFLtoHTMLConvertTable[j].src, "item"))
+                              {
+                                 PItemTagData data = trail->tagData;
+                                 if (data->href)
+                                   eina_strbuf_append_printf(html, " src=\"%s\"", data->href);
+                                 if (data->width)
+                                   eina_strbuf_append_printf(html, " width=\"%s\"", data->width);
+                                 if (data->height)
+                                   eina_strbuf_append_printf(html, " height=\"%s\"", data->height);
+                              }
+                         }
+                       switch(trail->tagPosType)
+                         {
+                          case TAGPOS_ALONE:
+                             eina_strbuf_append(html, "/>");
+                             break;
+                          default:
+                             eina_strbuf_append(html, ">");
+                             break;
+                         }
+                       break;
+                    }
+               }
+          }
+        if (trail->str)
+          eina_strbuf_append(html, trail->str);
+     }
+
+   char *ret = eina_strbuf_string_steal(html);
+   eina_strbuf_free(html);
+   return ret;
+}
+
 Eina_Bool
 elm_selection_set(Elm_Sel_Type selection, Evas_Object *widget, Elm_Sel_Format format, const char *selbuf)
 {
@@ -995,8 +1549,52 @@ html_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **
    Cnp_Selection *sel;
 
    sel = selections + *(int *)data;
-   if (data_ret) *data_ret = strdup(sel->selbuf);
-   if (size_ret) *size_ret = strlen(sel->selbuf);
+
+   char *html = NULL;
+   if (data_ret && (sel->format & ELM_SEL_FORMAT_MARKUP))
+     {
+        Eina_List *nodeList = NULL;
+        Eina_List *trail;
+        PTagNode nodeData;
+
+        nodeData = _get_start_node(sel->selbuf);
+
+        while (nodeData)
+          {
+             nodeList = eina_list_append(nodeList, nodeData);
+             nodeData = _get_next_node(nodeData);
+          }
+
+        _link_match_tags(nodeList);
+
+        _set_EFL_tag_data(nodeList);
+
+#ifdef DEBUGON
+        _dumpNode(nodeList);
+#endif
+        html = _convert_to_html(nodeList);
+
+        cnp_debug("convert html: %s\n", html);
+
+        EINA_LIST_FOREACH(nodeList, trail, nodeData)
+           _delete_node(nodeData);
+        eina_list_free(nodeList);
+     }
+   if (data_ret)
+     {
+        if (html)
+          *data_ret = html;
+        else
+          *data_ret = strdup(sel->selbuf);
+     }
+
+   if (size_ret)
+     {
+        if (html)
+          *size_ret = strlen(html);
+        else
+          *size_ret = strlen(sel->selbuf);
+     }
 
    return EINA_TRUE;
 }