]> err.no Git - sope/blob - sopex/SOPEX/SOPEXRangeUtilities.m
fixed some NGMail framework build issue
[sope] / sopex / SOPEX / SOPEXRangeUtilities.m
1 /*
2  Copyright (C) 2004 Marcus Mueller <znek@mulle-kybernetik.com>
3
4  This file is part of OGo
5
6  OGo is free software; you can redistribute it and/or modify it under
7  the terms of the GNU Lesser General Public License as published by the
8  Free Software Foundation; either version 2, or (at your option) any
9  later version.
10
11  OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12  WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14  License for more details.
15
16  You should have received a copy of the GNU Lesser General Public
17  License along with OGo; see the file COPYING.  If not, write to the
18  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19  02111-1307, USA.
20  */
21 // $Id: SOPEXRangeUtilities.m,v 1.2 2004/05/02 16:27:46 znek Exp $
22 //  Created by znek on Tue Mar 23 2004.
23
24
25 #import "SOPEXRangeUtilities.h"
26
27
28 extern BOOL SOPEX_isValidTagNameCharacter(unichar character);
29
30 extern NSRange SOPEX_findOpenTagForRangeInString(NSRange range, NSString *string);
31 extern NSRange SOPEX_findMatchingClosingTagForRangeInString(NSRange range, NSString *string);
32 extern NSRange SOPEX_findClosingTagForRangeInString(NSRange range, NSString *string);
33 extern NSRange SOPEX_findMatchingOpenTagForRangeInString(NSRange range, NSString *string);
34
35
36 /* 'valid' is really bound to the SOPE context, here */
37 BOOL SOPEX_isValidTagNameCharacter(unichar character)
38 {
39     static NSCharacterSet *validTagNameCharacterSet = nil;
40     
41     if(validTagNameCharacterSet == nil)
42     {
43         validTagNameCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-:.#?!"];
44         [validTagNameCharacterSet retain];
45     }
46     
47     return [validTagNameCharacterSet characterIsMember:character];
48 }
49
50 /* This implementation is pretty naive, it doesn't know SGML rules and doesn't perform any
51 other sophisticated matching. It works pretty well in real life, though. */
52 NSRange SOPEX_findMatchingTagForRangeInString(NSRange range, NSString *string)
53 {
54     NSRange matchingRange;
55     
56     if((matchingRange = SOPEX_findOpenTagForRangeInString(range, string)).location != NSNotFound)
57     {
58         NSRange closingRange;
59         
60         closingRange = SOPEX_findMatchingClosingTagForRangeInString(matchingRange, string);
61         if(closingRange.location == NSNotFound)
62             return NSMakeRange(NSNotFound, 0);
63         matchingRange = NSUnionRange(matchingRange, closingRange);
64     }
65     else if((matchingRange = SOPEX_findClosingTagForRangeInString(range, string)).location != NSNotFound)
66     {
67         NSRange openRange;
68         
69         openRange = SOPEX_findMatchingOpenTagForRangeInString(matchingRange, string);
70         if(openRange.location == NSNotFound)
71             return NSMakeRange(NSNotFound, 0);
72         matchingRange = NSUnionRange(matchingRange, openRange);
73     }
74     return matchingRange;
75 }
76
77 NSRange SOPEX_findOpenTagForRangeInString(NSRange range, NSString *string)
78 {
79     BOOL found;
80     int left, right, count;
81
82     if(range.location == NSNotFound)
83         return NSMakeRange(NSNotFound, 0);
84     
85     if((range.length == 2) && ([[string substringWithRange:range] isEqualToString:@"</"]))
86         return NSMakeRange(NSNotFound, 0);
87
88     found = NO;
89     left = range.location + 1; // offset 1 to right because we might have hit a '<'
90     
91     while(!found && left >= 0)
92     {
93         unichar charToLeft;
94         
95         charToLeft = [string characterAtIndex:--left];
96         if (!SOPEX_isValidTagNameCharacter(charToLeft)) {
97             if(charToLeft == '<')
98                 found = YES;
99             else
100                 break;
101         }
102     }
103     if(!found)
104         return NSMakeRange(NSNotFound, 0);
105     
106     right = range.location + range.length;
107     count = [string length];
108
109     while(SOPEX_isValidTagNameCharacter([string characterAtIndex:right]) && right <= count)
110         right++;
111
112     return NSMakeRange(left, right - left);
113 }
114
115 NSRange SOPEX_findMatchingClosingTagForRangeInString(NSRange range, NSString *string)
116 {
117     unsigned depth, loc, count;
118     BOOL isCloseTag;
119     unichar current;
120
121     isCloseTag = NO;
122     count = [string length];
123     loc = range.location + range.length;
124     
125     current = [string characterAtIndex:range.location + 1];
126     if((current == '!') && ([string characterAtIndex:range.location + 2] != '-'))
127         depth = 0;
128     else
129         depth = 1;
130
131     while(loc < count)
132     {        
133         current = [string characterAtIndex:loc];
134         if(current == '<')
135         {
136             if((loc + 1) < count)
137                 if([string characterAtIndex:loc + 1] != '/')
138                     depth++;
139         }
140         else if(current == '>')
141         {
142             if(isCloseTag)
143                 depth--;
144             if(depth == 0)
145                 return NSUnionRange(range, NSMakeRange(loc, 1));
146         }
147         else if((current == '/') || (current == '-') || (current == '?'))
148         {
149             isCloseTag = YES;
150         }
151         else if(!SOPEX_isValidTagNameCharacter(current))
152         {
153             isCloseTag = NO;
154         }
155         loc++;
156     }
157     return NSMakeRange(NSNotFound, 0);
158 }
159
160 NSRange SOPEX_findClosingTagForRangeInString(NSRange range, NSString *string)
161 {
162     return NSMakeRange(NSNotFound, 0);
163 }
164
165 NSRange SOPEX_findMatchingOpenTagForRangeInString(NSRange range, NSString *string)
166 {
167     return NSMakeRange(NSNotFound, 0);
168 }
169