⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 syslink.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 * SysLink control
 *
 * Copyright 2004 - 2006 Thomas Weidenmueller <w3seek@reactos.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 * NOTES
 *
 * This code was audited for completeness against the documented features
 * of Comctl32.dll version 6.0 on Apr. 4, 2005, by Dimitrie O. Paun.
 * 
 * Unless otherwise noted, we believe this code to be complete, as per
 * the specification mentioned above.
 * If you discover missing features, or bugs, please note them below.
 */

#include <stdarg.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "commctrl.h"
#include "comctl32.h"
#include "wine/unicode.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(progress);

INT WINAPI StrCmpNIW(LPCWSTR,LPCWSTR,INT);

typedef struct
{
    int nChars;
    int nSkip;
    RECT rc;
} DOC_TEXTBLOCK, *PDOC_TEXTBLOCK;

#define LIF_FLAGSMASK   (LIF_STATE | LIF_ITEMID | LIF_URL)
#define LIS_MASK        (LIS_FOCUSED | LIS_ENABLED | LIS_VISITED)

typedef enum
{
    slText = 0,
    slLink
} SL_ITEM_TYPE;

typedef struct _DOC_ITEM
{
    struct _DOC_ITEM *Next; /* Address to the next item */
    UINT nText;             /* Number of characters of the text */
    SL_ITEM_TYPE Type;      /* type of the item */
    PDOC_TEXTBLOCK Blocks;  /* Array of text blocks */
    union
    {
        struct
        {
            UINT state;     /* Link state */
            WCHAR *szID;    /* Link ID string */
            WCHAR *szUrl;   /* Link URL string */
        } Link;
        struct
        {
            UINT Dummy;
        } Text;
    } u;
    WCHAR Text[1];          /* Text of the document item */
} DOC_ITEM, *PDOC_ITEM;

typedef struct
{
    HWND      Self;         /* The window handle for this control */
    HWND      Notify;       /* The parent handle to receive notifications */
    DWORD     Style;        /* Styles for this control */
    PDOC_ITEM Items;        /* Address to the first document item */
    BOOL      HasFocus;     /* Whether the control has the input focus */
    int       MouseDownID;  /* ID of the link that the mouse button first selected */
    HFONT     Font;         /* Handle to the font for text */
    HFONT     LinkFont;     /* Handle to the font for links */
    COLORREF  TextColor;    /* Color of the text */
    COLORREF  LinkColor;    /* Color of links */
    COLORREF  VisitedColor; /* Color of visited links */
    WCHAR     BreakChar;    /* Break Character for the current font */
} SYSLINK_INFO;

static const WCHAR SL_LINKOPEN[] =  { '<','a', 0 };
static const WCHAR SL_HREF[] =      { 'h','r','e','f','=','\"',0 };
static const WCHAR SL_ID[] =        { 'i','d','=','\"',0 };
static const WCHAR SL_LINKCLOSE[] = { '<','/','a','>',0 };

/* Control configuration constants */

#define SL_LEFTMARGIN   (0)
#define SL_TOPMARGIN    (0)
#define SL_RIGHTMARGIN  (0)
#define SL_BOTTOMMARGIN (0)

/***********************************************************************
 * SYSLINK_FreeDocItem
 * Frees all data and gdi objects associated with a document item
 */
static VOID SYSLINK_FreeDocItem (PDOC_ITEM DocItem)
{
    if(DocItem->Type == slLink)
    {
        if (DocItem->u.Link.szID != NULL)
        {
            Free(DocItem->u.Link.szID);
        }
        if (DocItem->u.Link.szUrl != NULL)
        {
            Free(DocItem->u.Link.szUrl);
        }
    }

    /* we don't free Text because it's just a pointer to a character in the
       entire window text string */

    Free(DocItem);
}

/***********************************************************************
 * SYSLINK_AppendDocItem
 * Create and append a new document item.
 */
static PDOC_ITEM SYSLINK_AppendDocItem (SYSLINK_INFO *infoPtr, LPCWSTR Text, UINT textlen,
                                        SL_ITEM_TYPE type, PDOC_ITEM LastItem)
{
    PDOC_ITEM Item;

    textlen = min(textlen, lstrlenW(Text));
    Item = Alloc(FIELD_OFFSET(DOC_ITEM, Text[textlen + 1]));
    if(Item == NULL)
    {
        ERR("Failed to alloc DOC_ITEM structure!\n");
        return NULL;
    }

    Item->Next = NULL;
    Item->nText = textlen;
    Item->Type = type;
    Item->Blocks = NULL;
    
    if(LastItem != NULL)
    {
        LastItem->Next = Item;
    }
    else
    {
        infoPtr->Items = Item;
    }
    
    lstrcpynW(Item->Text, Text, textlen + 1);
    
    return Item;
}

/***********************************************************************
 * SYSLINK_ClearDoc
 * Clears the document tree
 */
static VOID SYSLINK_ClearDoc (SYSLINK_INFO *infoPtr)
{
    PDOC_ITEM Item, Next;
    
    Item = infoPtr->Items;
    while(Item != NULL)
    {
        Next = Item->Next;
        SYSLINK_FreeDocItem(Item);
        Item = Next;
    }
    
    infoPtr->Items = NULL;
}

/***********************************************************************
 * SYSLINK_ParseText
 * Parses the window text string and creates a document. Returns the
 * number of document items created.
 */
static UINT SYSLINK_ParseText (SYSLINK_INFO *infoPtr, LPCWSTR Text)
{
    LPCWSTR current, textstart = NULL, linktext = NULL, firsttag = NULL;
    int taglen = 0, textlen = 0, linklen = 0, docitems = 0;
    PDOC_ITEM Last = NULL;
    SL_ITEM_TYPE CurrentType = slText;
    LPCWSTR lpID, lpUrl;
    UINT lenId, lenUrl;

    for(current = Text; *current != 0;)
    {
        if(*current == '<')
        {
            if(!StrCmpNIW(current, SL_LINKOPEN, 2) && (CurrentType == slText))
            {
                BOOL ValidParam = FALSE, ValidLink = FALSE;

                if(*(current + 2) == '>')
                {
                    /* we just have to deal with a <a> tag */
                    taglen = 3;
                    ValidLink = TRUE;
                    ValidParam = TRUE;
                    firsttag = current;
                    linklen = 0;
                    lpID = NULL;
                    lpUrl = NULL;
                }
                else if(*(current + 2) == infoPtr->BreakChar)
                {
                    /* we expect parameters, parse them */
                    LPCWSTR *CurrentParameter = NULL, tmp;
                    UINT *CurrentParameterLen = NULL;

                    taglen = 3;
                    tmp = current + taglen;
                    lpID = NULL;
                    lpUrl = NULL;
                    
CheckParameter:
                    /* compare the current position with all known parameters */
                    if(!StrCmpNIW(tmp, SL_HREF, 6))
                    {
                        taglen += 6;
                        ValidParam = TRUE;
                        CurrentParameter = &lpUrl;
                        CurrentParameterLen = &lenUrl;
                    }
                    else if(!StrCmpNIW(tmp, SL_ID, 4))
                    {
                        taglen += 4;
                        ValidParam = TRUE;
                        CurrentParameter = &lpID;
                        CurrentParameterLen = &lenId;
                    }
                    else
                    {
                        ValidParam = FALSE;
                    }
                    
                    if(ValidParam)
                    {
                        /* we got a known parameter, now search until the next " character.
                           If we can't find a " character, there's a syntax error and we just assume it's text */
                        ValidParam = FALSE;
                        *CurrentParameter = current + taglen;
                        *CurrentParameterLen = 0;

                        for(tmp = *CurrentParameter; *tmp != 0; tmp++)
                        {
                            taglen++;
                            if(*tmp == '\"')
                            {
                                ValidParam = TRUE;
                                tmp++;
                                break;
                            }
                            (*CurrentParameterLen)++;
                        }
                    }
                    if(ValidParam)
                    {
                        /* we're done with this parameter, now there are only 2 possibilities:
                         * 1. another parameter is coming, so expect a ' ' (space) character
                         * 2. the tag is being closed, so expect a '<' character
                         */
                        if(*tmp == infoPtr->BreakChar)
                        {
                            /* we expect another parameter, do the whole thing again */
                            taglen++;
                            tmp++;
                            goto CheckParameter;
                        }
                        else if(*tmp == '>')
                        {
                            /* the tag is being closed, we're done */
                            ValidLink = TRUE;
                            taglen++;
                        }
                        else
                            tmp++;
                    }
                }
                
                if(ValidLink && ValidParam)
                {
                    /* the <a ...> tag appears to be valid. save all information
                       so we can add the link if we find a valid </a> tag later */
                    CurrentType = slLink;
                    linktext = current + taglen;
                    linklen = 0;
                    firsttag = current;
                }
                else
                {
                    taglen = 1;
                    lpID = NULL;
                    lpUrl = NULL;
                    if(textstart == NULL)
                    {
                        textstart = current;
                    }
                }
            }
            else if(!StrCmpNIW(current, SL_LINKCLOSE, 4) && (CurrentType == slLink) && firsttag)
            {
                /* there's a <a...> tag opened, first add the previous text, if present */
                if(textstart != NULL && textlen > 0 && firsttag > textstart)
                {
                    Last = SYSLINK_AppendDocItem(infoPtr, textstart, firsttag - textstart, slText, Last);
                    if(Last == NULL)
                    {
                        ERR("Unable to create new document item!\n");
                        return docitems;
                    }
                    docitems++;
                    textstart = NULL;
                    textlen = 0;
                }
                
                /* now it's time to add the link to the document */
                current += 4;
                if(linktext != NULL && linklen > 0)
                {
                    Last = SYSLINK_AppendDocItem(infoPtr, linktext, linklen, slLink, Last);
                    if(Last == NULL)
                    {
                        ERR("Unable to create new document item!\n");
                        return docitems;
                    }
                    docitems++;
                    if(CurrentType == slLink)
                    {
                        int nc;

                        if(!(infoPtr->Style & WS_DISABLED))
                        {
                            Last->u.Link.state |= LIS_ENABLED;
                        }
                        /* Copy the tag parameters */
                        if(lpID != NULL)
                        {
                            nc = min(lenId, strlenW(lpID));
                            nc = min(nc, MAX_LINKID_TEXT - 1);
                            Last->u.Link.szID = Alloc((nc + 1) * sizeof(WCHAR));
                            if(Last->u.Link.szID != NULL)
                            {
                                lstrcpynW(Last->u.Link.szID, lpID, nc + 1);
                            }
                        }
                        else
                            Last->u.Link.szID = NULL;
                        if(lpUrl != NULL)
                        {
                            nc = min(lenUrl, strlenW(lpUrl));
                            nc = min(nc, L_MAX_URL_LENGTH - 1);
                            Last->u.Link.szUrl = Alloc((nc + 1) * sizeof(WCHAR));
                            if(Last->u.Link.szUrl != NULL)
                            {
                                lstrcpynW(Last->u.Link.szUrl, lpUrl, nc + 1);
                            }
                        }
                        else
                            Last->u.Link.szUrl = NULL;
                    }
                    linktext = NULL;
                }
                CurrentType = slText;
                firsttag = NULL;
                textstart = NULL;
                continue;
            }
            else
            {
                /* we don't know what tag it is, so just continue */
                taglen = 1;
                linklen++;
                if(CurrentType == slText && textstart == NULL)
                {
                    textstart = current;
                }
            }
            
            textlen += taglen;
            current += taglen;
        }
        else
        {
            textlen++;
            linklen++;

            /* save the pointer of the current text item if we couldn't find a tag */
            if(textstart == NULL && CurrentType == slText)
            {
                textstart = current;
            }
            
            current++;
        }
    }
    
    if(textstart != NULL && textlen > 0)
    {
        Last = SYSLINK_AppendDocItem(infoPtr, textstart, textlen, CurrentType, Last);
        if(Last == NULL)
        {
            ERR("Unable to create new document item!\n");
            return docitems;
        }
        if(CurrentType == slLink)
        {
            int nc;

            if(!(infoPtr->Style & WS_DISABLED))
            {
                Last->u.Link.state |= LIS_ENABLED;
            }
            /* Copy the tag parameters */
            if(lpID != NULL)
            {
                nc = min(lenId, strlenW(lpID));
                nc = min(nc, MAX_LINKID_TEXT - 1);
                Last->u.Link.szID = Alloc((nc + 1) * sizeof(WCHAR));
                if(Last->u.Link.szID != NULL)
                {
                    lstrcpynW(Last->u.Link.szID, lpID, nc + 1);
                }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -