2 // Open Service Platform
3 // Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
5 // Licensed under the Flora License, Version 1.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://floralicense.org/license/
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an AS IS BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
19 * @file FGrp_TextTextCutLinkParser.cpp
20 * @brief This is the implementation file for TextCutLinkParser class.
24 #include <FBaseCharacter.h>
25 #include <FBaseSysLog.h>
26 #include "FGrp_TextTextCutLinkParser.h"
28 using namespace Tizen::Base;
29 using namespace Tizen::Base::Collection;
30 using namespace Tizen::Base::Utility;
31 using namespace Tizen::Graphics;
33 static const int _MIN_TEXT_LENGTH = 5;
34 static const int _MIN_PHONE_NUMBER_LENGTH = 4;
36 static ArrayListT <String>* gpDomainNames = null;
37 static ArrayListT <String>* gpUrlPrefixes = null;
39 namespace Tizen { namespace Graphics
46 IsGenericCharacter(wchar_t ch)
48 if ((ch >= L'a' && ch <= L'z') || (ch >= L'0' && ch <= L'9') ||
49 (ch >= L'A' && ch <= L'Z') || ch == L'.' || ch == L'/' ||
50 ch == L'=' || ch == L'&' || ch == L'%' || ch == L'-' ||
51 ch == L'?' || ch == L':' || ch == L'@' || ch == L'_' ||
52 ch == L'$' || ch == L';' || ch == L'+' || ch == L'!' ||
53 ch == L'*' || ch == L'\'' || ch == L'(' || ch == L')' ||
65 IsEmailCharacter(wchar_t ch)
67 if ((ch >= L'a' && ch <= L'z') || (ch >= L'0' && ch <= L'9') ||
68 (ch >= L'A' && ch <= L'Z') || ch == L'.' ||
69 ch == L'-' || ch == L'_' || ch == L'+')
80 IsUrlCharacter(wchar_t ch)
82 if (ch == L'h' || ch == L'H' || ch == L'w' || ch == L'W')
93 IsPhoneNumCharacter(wchar_t ch)
95 if (Character::IsDigit(ch))
99 else if (ch == L'*' || ch == L'#' || ch == L'+')
110 IsUrlAddress(const String& text, int index, int& linkLength)
113 SysTryReturn(NID_GRP, index >= 0, false, E_INVALID_ARG,
114 "[E_INVALID_ARG] Index must be greater than or equal to 0.");
116 result r = E_SUCCESS;
117 bool dotFound = false;
118 bool validTextAfterDot = false;
120 int totalLength = text.GetLength();
124 String subString(L"");
125 for (int i = 0; i < gpUrlPrefixes->GetCount(); i++)
127 if (gpUrlPrefixes->GetAt(i, prefix) == E_SUCCESS)
129 length = prefix.GetLength();
135 if (totalLength < index + length)
140 r = text.SubString(index, length, subString);
142 NID_GRP, r == E_SUCCESS, false, E_OUT_OF_RANGE,
143 "[E_OUT_OF_RANGE] SubString offset(%d) must greater than 0 and length(%d) must be less than total string length(%d).",
144 index, prefix.GetLength(), totalLength);
145 if (prefix.CompareTo(subString) == 0)
148 while (index < totalLength && IsGenericCharacter(text[index]))
150 if (dotFound == false && text[index] == '.')
155 if (validTextAfterDot == false && dotFound == true && text[index] != '.')
157 validTextAfterDot = true;
163 if (dotFound == true && validTextAfterDot != true)
168 if (dotFound == true)
170 while (text[index - 1] == L'.' || text[index - 1] == L',')
175 linkLength = index - linkOffset;
186 GetUrlLink(const String& text, int index, int lastLinkEndIndex, int domainLength, int& linkStartIndex, int& linkLength)
189 SysTryReturn(NID_GRP, index >= 0, false, E_INVALID_ARG,
190 "[E_INVALID_ARG] Index must be greater than or equal to 0.");
192 bool dotFound = false;
193 bool validTextBeforeDot = false;
194 int linkOffset = index;
196 while (lastLinkEndIndex <= linkOffset)
198 if (!IsGenericCharacter(text[linkOffset]) || text[linkOffset] == L'(' || text[linkOffset] == L'[')
204 if (dotFound == false && text[linkOffset] == L'.')
209 if (validTextBeforeDot == false && dotFound == true && text[linkOffset] != L'.')
211 validTextBeforeDot = true;
217 if (dotFound == true && validTextBeforeDot != true)
222 if (dotFound == true)
224 while (text[linkOffset] == L'.' || text[linkOffset] == L',')
230 index += domainLength;
231 if (text[index] == L'/')
235 if (!IsGenericCharacter(text[index]) && text[index] != L')' && text[index] != L']')
243 else if (text[index] != null && text[index] != L' ' && text[index] != L')' &&
244 text[index] != L']' && text[index] != 0xFFFC &&
245 text[index] != 0x000A && text[index] != 0x000D)
250 linkStartIndex = linkOffset;
251 linkLength = index - linkStartIndex;
257 IsDomainAddress(const String& text, int index, int lastLinkEndIndex, int& linkStartIndex, int& linkLength)
260 result r = E_SUCCESS;
262 SysTryReturn(NID_GRP, index >= 0, false, E_INVALID_ARG,
263 "[E_INVALID_ARG] Index must be greater than or equal to 0.");
265 int domainLength = 0;
267 int textLength = text.GetLength();
269 String subString(L"");
270 String domainAddress(L"");
271 for (int i = 0; i < gpDomainNames->GetCount(); i++)
273 if (gpDomainNames->GetAt(i, domainAddress) == E_SUCCESS)
275 length = domainAddress.GetLength();
281 if (textLength < index + length)
286 r = text.SubString(index, length, subString);
287 SysTryReturn(NID_GRP, r == E_SUCCESS, false, E_OUT_OF_RANGE,
288 "[E_OUT_OF_RANGE] SubString offset(%d) must greater than 0 and length(%d) must be less than total string length(%d).",
289 index, domainAddress.GetLength(), text.GetLength());
290 if (domainAddress.CompareTo(subString) == 0)
292 domainLength = domainAddress.GetLength();
293 if (GetUrlLink(text, index, lastLinkEndIndex, domainLength, linkStartIndex, linkLength))
305 IsEmailAddress(const String& text, int index, int lastLinkEndIndex, int& linkStartIndex, int& linkLength)
308 SysTryReturn(NID_GRP, index >= 0, false, E_INVALID_ARG,
309 "[E_INVALID_ARG] Index must be greater than or equal to 0.");
311 bool validTextAfterAt = false;
314 int totalLength = text.GetLength();
315 int linkOffset = index;
317 if (text[index + 1] == L'@')
324 if (index > lastLinkEndIndex)
326 while (IsEmailCharacter(text[linkOffset]) && lastLinkEndIndex <= linkOffset)
331 if (linkOffset == index - 1)
340 while (IsEmailCharacter(text[index]) && index < totalLength)
342 if (validTextAfterAt == false)
344 validTextAfterAt = true;
347 if (text[index] == '.')
349 if (text[index + 1] == '.')
363 if (validTextAfterAt == false || hasDot == false)
368 while (text[index - 1] == L'.')
373 linkStartIndex = linkOffset;
374 linkLength = index - linkOffset;
382 IsPhoneNumber(const String& text, int index, int& linkLength)
388 bool isPhoneNumber = true;
389 int oneHyphen = false;
394 int totalLength = text.GetLength();
395 if (text[index] == L'+')
398 if (!Character::IsDigit(text[index + 1]))
404 while (k < _MIN_PHONE_NUMBER_LENGTH)
406 if (Character::IsDigit(text[index + j]) || text[index + j] == L'*' || text[index + j] == L'#')
412 else if (oneHyphen == false && text[index + j] == L'-')
416 else if (oneDot == false && text[index + j] == L'.')
420 else if (text[index + j] == L' ' || text[index + j] == L'(' || text[index + j] == L')')
426 isPhoneNumber = false;
437 while (index < totalLength &&
438 (Character::IsDigit(text[index]) || (text[index] == L'*') ||
439 (text[index] == L'#') || (text[index] == L'-') ||
440 (text[index] == L' ') || (text[index] == L'+') ||
441 (text[index] == L'.') || (text[index] == L'(') ||
442 (text[index] == L')') || (index == linkOffset && (text[linkOffset] == L'+'))))
446 if (blankCount == 0 && text[index] == L' ')
450 else if (blankCount == 1 && text[index] == L' ')
455 else if (Character::IsDigit(text[index]) || text[index] == L'*' || text[index] == L'#')
459 else if (text[index] == L'-' && text[index + 1] == L'-')
463 else if (text[index] == L'(' || text[index] == L')')
467 else if ((text[index] == L'.' &&
468 text[index + 1] == L'.') || (text[index] == L'.' && !Character::IsDigit(text[index + 1])))
478 if (text[index - 1] == L' ')
481 while (text[index] == L' ')
489 linkLength = index - linkOffset;
496 TextCutLinkParser::TextCutLinkParser(void)
499 result r = E_SUCCESS;
501 __linkMask = LINK_TYPE_URL | LINK_TYPE_EMAIL | LINK_TYPE_TEL_NUM;
505 gpUrlPrefixes = new (std::nothrow) ArrayListT <String>;
507 , gpUrlPrefixes != null
508 , r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
509 r = gpUrlPrefixes->Construct();
512 , , r, "[%s] Propagated.", GetErrorMessage(r));
514 gpUrlPrefixes->Add(L"www.");
515 gpUrlPrefixes->Add(L"http://");
516 gpUrlPrefixes->Add(L"https://");
517 gpUrlPrefixes->Add(L"wap.");
518 gpUrlPrefixes->Add(L"wap2.");
523 gpDomainNames = new (std::nothrow) ArrayListT <Tizen::Base::String>;
525 , gpDomainNames != null
526 , r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
528 r = gpDomainNames->Construct();
531 , , r, "[%s] Propagated.", GetErrorMessage(r));
533 gpDomainNames->Add(L".com");
534 gpDomainNames->Add(L".net");
535 gpDomainNames->Add(L".kr");
536 gpDomainNames->Add(L".be");
537 gpDomainNames->Add(L".gr");
538 gpDomainNames->Add(L".pt");
539 gpDomainNames->Add(L".at");
540 gpDomainNames->Add(L".gs");
541 gpDomainNames->Add(L".ro");
542 gpDomainNames->Add(L".edu");
543 gpDomainNames->Add(L".as");
544 gpDomainNames->Add(L".hk");
545 gpDomainNames->Add(L".se");
546 gpDomainNames->Add(L".org");
547 gpDomainNames->Add(L".az");
548 gpDomainNames->Add(L".il");
549 gpDomainNames->Add(L".sg");
550 gpDomainNames->Add(L".info");
551 gpDomainNames->Add(L".bt");
552 gpDomainNames->Add(L".in");
553 gpDomainNames->Add(L".sh");
554 gpDomainNames->Add(L".us");
555 gpDomainNames->Add(L".cn");
556 gpDomainNames->Add(L".io");
557 gpDomainNames->Add(L".sk");
558 gpDomainNames->Add(L".biz");
559 gpDomainNames->Add(L".ac");
560 gpDomainNames->Add(L".is");
561 gpDomainNames->Add(L".so");
562 gpDomainNames->Add(L".to");
563 gpDomainNames->Add(L".af");
564 gpDomainNames->Add(L".st");
565 gpDomainNames->Add(L".ch");
566 gpDomainNames->Add(L".al");
567 gpDomainNames->Add(L".kz");
568 gpDomainNames->Add(L".tc");
569 gpDomainNames->Add(L".fr");
570 gpDomainNames->Add(L".am");
571 gpDomainNames->Add(L".li");
572 gpDomainNames->Add(L".tf");
573 gpDomainNames->Add(L".jp");
574 gpDomainNames->Add(L".cx");
575 gpDomainNames->Add(L".lu");
576 gpDomainNames->Add(L".th");
577 gpDomainNames->Add(L".de");
578 gpDomainNames->Add(L".cz");
579 gpDomainNames->Add(L".ly");
580 gpDomainNames->Add(L".tj");
581 gpDomainNames->Add(L".ru");
582 gpDomainNames->Add(L".dz");
583 gpDomainNames->Add(L".mc");
584 gpDomainNames->Add(L".tm");
585 gpDomainNames->Add(L".it");
586 gpDomainNames->Add(L".ec");
587 gpDomainNames->Add(L".mm");
588 gpDomainNames->Add(L".asia");
589 gpDomainNames->Add(L".mil");
590 gpDomainNames->Add(L".ee");
591 gpDomainNames->Add(L".ms");
592 gpDomainNames->Add(L".me");
593 gpDomainNames->Add(L".gov");
594 gpDomainNames->Add(L".eg");
595 gpDomainNames->Add(L".mx");
596 gpDomainNames->Add(L".tel");
597 gpDomainNames->Add(L".au");
598 gpDomainNames->Add(L".es");
599 gpDomainNames->Add(L".nl");
600 gpDomainNames->Add(L".eu");
601 gpDomainNames->Add(L".cc");
602 gpDomainNames->Add(L".fo");
603 gpDomainNames->Add(L".no");
604 gpDomainNames->Add(L".tv");
605 gpDomainNames->Add(L".ca");
606 gpDomainNames->Add(L".ga");
607 gpDomainNames->Add(L".nu");
608 gpDomainNames->Add(L".name");
609 gpDomainNames->Add(L".coop");
610 gpDomainNames->Add(L".gf");
611 gpDomainNames->Add(L".nz");
612 gpDomainNames->Add(L".mobi");
613 gpDomainNames->Add(L".dk");
614 gpDomainNames->Add(L".gl");
615 gpDomainNames->Add(L".pl");
616 gpDomainNames->Add(L".tw");
623 delete gpUrlPrefixes;
624 gpUrlPrefixes = null;
628 delete gpDomainNames;
629 gpDomainNames = null;
633 TextCutLinkParser::~TextCutLinkParser(void)
639 TextCutLinkParser::Parse(const wchar_t* pText, int textLength, int startPosition)
642 result r = E_SUCCESS;
644 if (__linkMask == LINK_TYPE_NONE)
649 while (0 < startPosition)
656 int linkStartIndex = 0;
658 int lastLinkEndIndex = 0;
659 bool linkParsed = false;
660 int totalLength = text.GetLength();
661 TextLinkInfo* pTextLink = null;
662 LinkType linkType = LINK_TYPE_NONE;
664 if (totalLength < _MIN_TEXT_LENGTH)
669 pTextLink = CreateTextLinkInfo(0, 0, LINK_TYPE_NONE);
672 , , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
674 pTextLink->index = -1;
676 for (int i = 0; i < totalLength; )
679 wchar_t checkLetter = 0;
680 text.GetCharAt(i, checkLetter);
682 if ((__linkMask & LINK_TYPE_URL)
683 && IsUrlCharacter(checkLetter) && IsUrlAddress(text, i, linkLength))
687 linkType = LINK_TYPE_URL;
689 else if ((__linkMask & LINK_TYPE_URL)
690 && (checkLetter == '.') && IsDomainAddress(text, i, lastLinkEndIndex, linkStartIndex, linkLength))
694 linkType = LINK_TYPE_URL;
696 else if ((__linkMask & LINK_TYPE_EMAIL)
697 && (checkLetter == '@') && IsEmailAddress(text, i, lastLinkEndIndex, linkStartIndex, linkLength))
701 linkType = LINK_TYPE_EMAIL;
703 else if ((__linkMask & LINK_TYPE_TEL_NUM)
704 && IsPhoneNumCharacter(checkLetter) && IsPhoneNumber(text, i, linkLength))
708 linkType = LINK_TYPE_TEL_NUM;
713 if (pTextLink->index == -1)
715 pTextLink->index = 0;
716 pTextLink->srcOffset = linkStartIndex;
717 pTextLink->length = linkLength;
718 pTextLink->linkType = linkType;
722 TextLinkInfo* pNextLink = CreateTextLinkInfo(linkStartIndex, linkLength, linkType);
725 r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient");
726 AppendTextLinkInfo(pTextLink, pNextLink);
730 lastLinkEndIndex = i;
739 if (pTextLink->index == -1)
749 if (pTextLink != null)
759 TextCutLinkParser::SetCutLinkMask(int mask)
762 , LINK_TYPE_NONE <= mask && mask < LINK_TYPE_MAX
763 , E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
771 TextCutLinkParser::GetCutLinkMask(void) const
777 TextCutLinkParser::AppendTextLinkInfo(TextLinkInfo* pLinkInfo, TextLinkInfo* pNewLinkInfo)
779 TextLinkInfo* pTempLinkInfo = pLinkInfo;
783 if (pTempLinkInfo->pNextLinkInfo == null)
787 pTempLinkInfo = pTempLinkInfo->pNextLinkInfo;
790 pTempLinkInfo->index = pTempLinkInfo->index + 1;
791 pTempLinkInfo->pNextLinkInfo = pNewLinkInfo;
797 TextCutLinkParser::CreateTextLinkInfo(int offset, int length, LinkType linkType)
799 TextLinkInfo* pTextLinkInfo = new (std::nothrow) TextLinkInfo;
801 , pTextLinkInfo != null
802 , null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient");
804 pTextLinkInfo->index = 0;
805 pTextLinkInfo->srcOffset = offset;
806 pTextLinkInfo->length = length;
807 pTextLinkInfo->linkType = linkType;
809 pTextLinkInfo->pNextLinkInfo = null;
811 return pTextLinkInfo;
814 }}} // Tizen::Graphics::_Text