root/trunk/website/blog/xmlrpc/xmlrpc.cfc @ 6

Revision 5, 20.0 kB (checked in by DanWilson, 17 years ago)

Initial Commit Of ModelGlue? Website (upgrade to blogcfc 511)

Line 
1<cfcomponent displayname="XML-RPC" output="false" hint="Allows painless translation of XML-RPC packets to and from CFML data structures">
2
3        <!---
4        Copyright (c)2003 Agincourt Media
5        VERSION: 1.2
6                - 2003-6-11:
7                        - added support for fault packages to XMLRPC2CFML
8                        - added a little error checking
9                        - added support for typeless values
10                        - added support for paranthetical tokens in addition to $token
11                - 2003-10-5:
12                        - added support for namespaced deserialization
13        AUTHOR: Roger Benningfield (roger@agincourtmedia.com)
14        WEBLOG: http://admin.support.journurl.com/
15        This code is free of charge and without warranty. Use at your own risk.
16        NOTE: If you make significant modifications or improvements to this component,
17                send the resulting code to the author.
18        ANOTHER NOTE: This comment section must remain with the component in any
19                distribution. Feel free to snip it out on your production box.
20        --->
21
22        <cffunction name="XMLRPC2CFML" access="public" returntype="struct" output="false" hint="Accepts an XML-RPC packet and returns a struct containing the method name (returnvar.method) and an array of params (returnvar.params)">
23                <cfargument name="data" type="string" required="true" hint="A string containing an XML-RPC package" />
24                <cfset var myResult = StructNew() />
25                <cfset var dummy = "" />
26                <cfset var myContent = arguments.data />
27                <cfset var myParsedContent = "" />
28                <cfset var myParams = "" />
29                <cfset var x = "" />
30                <cfif Len(mycontent)>
31                        <cfset myparsedcontent = XmlParse(mycontent) />
32                        <cfset dummy = XmlSearch(myparsedcontent, "//methodName") />
33                        <cfset myResult.method = "" />
34                        <cfif ArrayLen(dummy)>
35                                <cfset myResult.method = dummy[1].xmlText />
36                        </cfif>
37                        <cfset dummy = XmlSearch(myparsedcontent, "//fault") />
38                        <cfset myResult.fault = StructNew() />
39                        <cfset myResult.fault.faultCode = 0 />
40                        <cfset myResult.fault.faultString = "" />
41                        <cfif ArrayLen(dummy)>
42                                <cfset myResult.fault = this.deserialize(branch=dummy[1].value[1]) />
43                        </cfif>
44                        <cfset myParams = XmlSearch(myparsedcontent, "//params/param") />
45                        <cfset myResult.params = ArrayNew(1) />
46                        <cfloop index="x" from="1" to="#ArrayLen(myParams)#">
47                                <cfset myResult.params[x] = this.deserialize(branch=myParams[x].value[1]) />
48                        </cfloop>
49                <cfelse>
50                        <cfset myResult.method = "Error" />
51                        <cfset myResult.params = ArrayNew(1) />
52                        <cfset myresult.params[1] = "Error" />
53                </cfif>
54                <cfreturn myResult />
55        </cffunction>
56       
57        <cffunction name="CFML2XMLRPC" access="public" returntype="string" output="false" hint="Takes a CFML array and converts it into an XML-RPC package">
58                <cfargument name="data" required="true" type="array" hint="A CFML array. If the 'type' argument is set to 'call', the first element of the array should be a string containing a method name, with subsequent elements containing data. If the 'type' argument is set to 'response', the array should only contain data. If the 'type' argument is set to 'responsefault', the first array element should be an integer representing a faultCode, and the second element should be a string containing the faultString" />
59                <cfargument name="type" required="false" default="call" type="string" hint="Can be set to one of three values: 'call', 'response', and 'responsefault'." />
60                <cfset var x = "" />
61                <cfset var myXml = "" />
62                <cfset var faultValue = "" />
63                <cfswitch expression="#LCase(arguments.type)#">
64                        <cfcase value="call">
65                                <cfset myXml = "<methodCall><methodName>#arguments.data[1]#</methodName><params>" />
66                                <cfloop index="x" from="2" to="#ArrayLen(arguments.data)#">
67                                        <cfset myXml = myXml & "<param>#this.serialize(arguments.data[x])#</param>" />
68                                </cfloop>
69                                <cfset myXml = myXml & "</params></methodCall>" />
70                        </cfcase>
71                        <cfcase value="response">
72                                <cfset myXml = "<methodResponse><params>" />
73                                <cfloop index="x" from="1" to="#ArrayLen(arguments.data)#">
74                                        <cfset myXml = myXml & "<param>#this.serialize(arguments.data[x])#</param>" />
75                                </cfloop>
76                                <cfset myXml = myXml & "</params></methodResponse>" />
77                        </cfcase>
78                        <cfcase value="responsefault">
79                                <cfif arrayLen(arguments.data) gte 2>
80                                        <cfset faultValue = arguments.data[2] />
81                                <cfelse>
82                                        <cfset faultValue = arguments.data[1] />
83                                </cfif>
84                               
85                                <cfset myXml = "<methodResponse><fault><value><struct><member><name>faultCode</name><value><int>#arguments.data[1]#</int></value></member><member><name>faultString</name><value><string>#XmlFormat(faultValue)#</string></value></member></struct></value></fault></methodResponse>" />
86                        </cfcase>
87                </cfswitch>
88                <cfreturn myXml />
89        </cffunction>
90       
91        <cffunction name="serialize" access="public" output="false">
92                <cfargument name="branch" required="true" />
93                <cfset var myResult = "<value>" />
94                <cfset var myStruct = "" />
95                <cfset var myArray = "" />
96                <cfset var myKey = "" />
97                <cfset var myDate = "" />
98                <cfset var dummy = arguments.branch />
99                <cfset var x = "" />
100               
101                <cfif IsSimpleValue(dummy) AND (Left(dummy, 8) IS "$boolean" OR Left(dummy, 9) IS "(boolean)")>
102                        <cfset dummy = Replace(dummy, "$boolean", "", "ONE") />
103                        <cfset dummy = Replace(dummy, "(boolean)", "", "ONE") />
104                        <cfset myResult = myResult & "<boolean>#dummy#</boolean>" />
105                <cfelseif IsSimpleValue(dummy) AND (Left(dummy, 3) IS "$i4" OR Left(dummy, 4) IS "(i4)")>
106                        <cfset dummy = Replace(dummy, "$i4", "", "ONE") />
107                        <cfset dummy = Replace(dummy, "(i4)", "", "ONE") />
108                        <cfset myResult = myResult & "<i4>#dummy#</i4>" />
109                <cfelseif IsSimpleValue(dummy) AND (Left(dummy, 4) IS "$int" OR Left(dummy, 5) IS "(int)")>
110                        <cfset dummy = Replace(dummy, "$int", "", "ONE") />
111                        <cfset dummy = Replace(dummy, "(int)", "", "ONE") />
112                        <cfset myResult = myResult & "<int>#dummy#</int>" />
113                <cfelseif IsNumeric(dummy) OR (IsSimpleValue(dummy) AND (Left(dummy, 7) IS "$double" OR Left(dummy, 8) IS "(double)"))>
114                        <cfset dummy = Replace(dummy, "$double", "", "ONE") />
115                        <cfset dummy = Replace(dummy, "(double)", "", "ONE") />
116                        <cfset myResult = myResult & "<double>#dummy#</double>" />
117                <cfelseif IsBinary(dummy)>
118                        <cfset myResult = myResult & "<base64>#ToBase64(dummy)#</base64>" />
119                <cfelseif IsDate(dummy) OR (IsSimpleValue(dummy) AND (Left(dummy, 17) IS "$dateTime.iso8601" OR Left(dummy, 18) IS "(dateTime.iso8601)"))>
120                        <cfset dummy = Replace(dummy, "$dateTime.iso8601", "", "ONE") />
121                        <cfset dummy = Replace(dummy, "(dateTime.iso8601)", "", "ONE") />
122                        <cfset mydate = ParseDateTime(dummy) />
123                        <cfset myResult = myResult & "<dateTime.iso8601>#DateFormat(mydate, "yyyymmdd")#T#TimeFormat(mydate, "HH:mm:ss")#</dateTime.iso8601>" />
124                <cfelseif IsSimpleValue(dummy) OR (IsSimpleValue(dummy) AND (Left(dummy, 7) IS "$string" OR Left(dummy, 8) IS "(string)"))>
125                        <cfif Left(dummy, 7) IS "$string">
126                                <cfset dummy = Replace(dummy, "$string", "", "ONE") />
127                        <cfelseif Left(dummy, 8) IS "(string)">
128                                <cfset dummy = Replace(dummy, "(string)", "", "ONE") />
129                        </cfif>
130
131                        <cfset myResult = myResult & "<string>#XmlFormat(dummy)#</string>" />
132
133                        <!---
134                        <cfset myResult = myResult & "#XmlFormat(dummy)#" />
135                        --->
136                <cfelseif IsArray(dummy)>
137                        <cfset myResult = myResult & "<array><data>" />
138                        <cfloop index="x" from="1" to="#ArrayLen(dummy)#">
139                                <cfset myResult = myResult & this.serialize(branch=dummy[x]) />
140                        </cfloop>
141                        <cfset myResult = myResult & "</data></array>" />
142                <cfelseif IsStruct(dummy)>
143                        <cfset myResult = myResult & "<struct>" />
144                        <cfloop item="x" collection="#dummy#">
145                                <cfset myResult = myResult & "<member><name>#x#</name>" />
146                                <cfset myResult = myResult & this.serialize(branch=dummy[x]) />
147                                <cfset myResult = myResult & "</member>" />
148                        </cfloop>
149                        <cfset myResult = myResult & "</struct>" />
150                </cfif>
151                <cfset myResult = myResult & "</value>" />
152                <cfreturn myResult />
153        </cffunction>
154       
155        <cffunction name="deserialize" access="public" output="false">
156                <cfargument name="branch" required="true" />
157                <cfargument name="namespace" required="false" default="" />
158                <cfset var myResult = "" />
159                <cfset var myStruct = "" />
160                <cfset var myArray = "" />
161                <cfset var myKey = "" />
162                <cfset var dummy = arguments.branch />
163                <cfset var x = 0 />
164                <cfset var mynamespace = "">
165               
166                <cfset var rawdatetime = "">
167                <cfset var targetzoneoffset = "">
168               
169                <cfif Len(arguments.namespace)>
170                        <cfset mynamespace = arguments.namespace & ":">
171                </cfif>
172                <cfif StructKeyExists(dummy, "#mynamespace#string")>
173                        <cfset myResult = ToString(dummy.string.xmlText) />
174                <cfelseif StructKeyExists(dummy, "#mynamespace#boolean")>
175                        <cfset myResult = YesNoFormat(dummy.boolean.xmlText) />
176                <cfelseif StructKeyExists(dummy, "#mynamespace#i4")>
177                        <cfset myResult = Int(dummy.i4.xmlText) />
178                <cfelseif StructKeyExists(dummy, "#mynamespace#int")>
179                        <cfset myResult = Int(dummy.int.xmlText) />
180                <cfelseif StructKeyExists(dummy, "#mynamespace#double")>
181                        <cfset myResult = Val(dummy.double.xmlText) />
182                <cfelseif StructKeyExists(dummy, "#mynamespace#base64")>
183                        <cfset myResult = ToBinary(dummy.base64.xmlText) />
184                <cfelseif StructKeyExists(dummy, "#mynamespace#dateTime.iso8601")>
185                        <cfset myResult = dummy["#mynamespace#dateTime.iso8601"].xmlText />
186
187                        <!--- fix by ddblock --->
188                        <cfif not find("-",left(myResult,5))>
189                                <cfset myResult = Insert("-", myResult, 4) />
190                                <cfset myResult = Insert("-", myResult, 7) />
191                                <cfset myResult = Replace(myResult, "T", " ", "ONE") />
192                        </cfif>
193                       
194                        <!--- RayMod --->
195                        <!---
196                        <cfif right(myresult, 1) is "Z">
197                                <cfset myresult = left(myresult, len(myresult)-1)>
198                        </cfif>
199                       
200                        <cfset myResult = ParseDateTime(myResult) />
201                       
202                        Following UDF from CFLib, by David Satz
203                        --->
204                        <cfscript>
205                                rawDatetime = left(myresult,10) & " " & mid(myresult,12,8);
206                                targetZoneOffset = -1 * getTimeZoneInfo().utcHourOffset;
207                               
208                                // adjust offset based on offset given in date string
209                                if (uCase(mid(myresult,20,1)) neq "Z")
210                                        targetZoneOffset = targetZoneOffset -  val(mid(myresult,20,3)) ;
211       
212                                myresult =  DateAdd("h", targetZoneOffset, CreateODBCDateTime(rawDatetime));
213                       
214                        </cfscript>
215                <cfelseif StructKeyExists(dummy, "#mynamespace#array")>
216                        <cfset myArray = ArrayNew(1) />
217                        <cfset dummy = XmlSearch(dummy, "#mynamespace#array/#mynamespace#data/#mynamespace#value") />
218                        <cfloop index="x" from="1" to="#ArrayLen(dummy)#">
219                                <cfset myArray[x] = this.deserialize(branch=dummy[x], namespace=arguments.namespace) />
220                        </cfloop>
221                        <cfset myResult = myArray />
222                <cfelseif StructKeyExists(dummy, "#mynamespace#struct")>
223                        <cfset myStruct = StructNew() />
224                        <cfset dummy = XmlSearch(dummy, "#mynamespace#struct/#mynamespace#member") />
225                        <cfloop index="x" from="1" to="#ArrayLen(dummy)#">
226                                <cfset myKey = dummy[x]["#mynamespace#name"].xmlText />
227                                <cfset myStruct[myKey] = this.deserialize(branch=dummy[x]["#mynamespace#value"][1], namespace=arguments.namespace) />
228                        </cfloop>
229                        <cfset myResult = myStruct />
230                <cfelse>
231                        <cfset myResult = ToString(dummy.xmlText) />
232                </cfif>
233                <cfreturn myResult />
234        </cffunction>
235
236        <!---//
237                the following functions convert <code> blocks that were written
238                in rich text editor to be escaped as if they were typed as
239                regular source code and also convert <more/> tags to markup
240        //--->
241        <cffunction name="unescapeMarkup" access="public" output="false" hint="This function finds <code> blocks written in html and converts the text.">
242                <cfargument name="string" type="string" required="true" />
243               
244                <cfset var counter = 0 />
245                <cfset var newbody = "" />
246                <cfset var codeportion = "" />
247                <cfset var codeblock = "" />
248                <cfset var result = "" />
249       
250                <cfif findNoCase("&lt;code&gt;", arguments.string) and findNoCase("&lt;/code&gt;", arguments.string)>
251                        <cfset counter = findNoCase("&lt;code&gt;", arguments.string)>
252                        <cfloop condition="counter gte 1">
253                                <cfset codeblock = reFindNoCase("(?s)(.*)(&lt;code&gt;)(.*)(&lt;/code&gt;)(.*)", arguments.string, 1, true) />
254                                <cfif arrayLen(codeblock.len) gte 6>
255                                        <cfset codeportion = mid(arguments.string, codeblock.pos[4], codeblock.len[4]) />
256                                        <cfif len(trim(codeportion))>
257                                                <cfset result = convertHtmlToText(codeportion) />
258                                        <cfelse>
259                                                <cfset result = "" />
260                                        </cfif>
261                                        <cfset newbody = mid(arguments.string, 1, codeblock.len[2]) & result & mid(arguments.string, codeblock.pos[6], codeblock.len[6]) />
262                                       
263                                        <cfset arguments.string = newbody />
264                                        <cfset counter = findNoCase("&lt;code&gt;",  arguments.string, counter) />
265                                <cfelse>
266                                        <!--- bad crap, maybe <code> and no ender, or maybe </code><code> --->
267                                        <cfset counter = 0 />
268                                </cfif>
269                        </cfloop>
270                </cfif>
271               
272                <cfset arguments.string = reReplaceNoCase(arguments.string, "&lt;more\s*\/&gt;", "<more/>", "all") />
273                <cfset arguments.string = reReplaceNoCase(arguments.string, "&lt;textblock((\s+[^\]]*)|(\s*\/))?&gt;", "<textblock\1>", "all") />
274
275                <cfset arguments.string = reReplaceNoCase(arguments.string, "&lt;\[code((\s+[^\]]*)|(\s*\/))?\]&gt;", "&lt;code\1&gt;", "all") />
276                <cfset arguments.string = reReplaceNoCase(arguments.string, "&lt;\[more((\s+[^\]]*)|(\s*\/))?\]&gt;", "&lt;more\1&gt;", "all") />
277                <cfset arguments.string = reReplaceNoCase(arguments.string, "&lt;\[textblock((\s+[^\]]*)|(\s*\/))?\]&gt;", "&lt;textblock\1&gt;", "all") />
278
279                <cfset arguments.string = reMatchReplaceNoCase("<textblock((\s+[^>]*)|(\s*\/))?>", arguments.string, "&quot;", """") />
280
281                <cfreturn arguments.string />
282       
283        </cffunction>
284       
285        <cffunction name="convertHtmlToText" access="public" output="false" hint="Handles actual html-to-plain text conversion.">
286                <cfargument name="html" type="string" required="true" />
287               
288                <cfset var sHtml = arguments.html />
289               
290                <!---// remove line breaks, since we use HTML to determine them //--->
291                <cfset sHtml = reReplaceNoCase(sHtml, "#chr(13)#?#chr(10)#", "", "all") />
292                <!---// remove extra whitespace, so we treat like html (multiple whitespace is counted as a single space) //--->
293                <cfset sHtml = reReplaceNoCase(sHtml, "\s{2,}", " ", "all") />
294                <!---// remove paragraph tags //--->
295                <cfset sHtml = reReplaceNoCase(sHtml, "<p([^>]+)?>", chr(13) & chr(10), "all") />
296                <!---// remove line break tags //--->
297                <cfset sHtml = reReplaceNoCase(sHtml, "<br([^>]+)?>", chr(13) & chr(10), "all") />
298                <!---// remove erronous markup tags //--->
299                <cfset sHtml = reReplaceNoCase(sHtml, "<[^>]+>", "", "all") />
300                <!---// replace entity less than symbols //--->
301                <cfset sHtml = reReplaceNoCase(sHtml, "&lt;|&##60;", "<", "all") />
302                <!---// replace entity greater than symbols //--->
303                <cfset sHtml = reReplaceNoCase(sHtml, "&gt;|&##62;", ">", "all") />
304                <!---// replace entity quotes with regular quotes //--->
305                <cfset sHtml = reReplaceNoCase(sHtml, "&quot;|&##34;", """", "all") />
306                <!---// replace entity quotes with regular quotes //--->
307                <cfset sHtml = reReplaceNoCase(sHtml, "&apos;|&##34;", "''", "all") />
308                <!---// convert no break spaces to regular spaces //--->
309                <cfset sHtml = reReplaceNoCase(sHtml, "&nbsp;|&##xA0;|&##160;", " ", "all") />
310       
311                <!---// this must be done last to avoid premature excaping of other html entities //--->
312                <cfset sHtml = reReplace(sHtml, "&amp;|&##38;", "&", "all") />
313       
314                <!---// convert 4 spaces to a tab //--->
315                <cfset sHtml = reReplace(sHtml, "    ", "#chr(9)#", "all") />
316       
317                <cfreturn "<code>" & sHtml & "</code>" />
318        </cffunction>
319
320        <!---//
321                the follow functions covert markup back to escaped HTML
322        //--->
323        <cffunction name="escapeMarkup" access="public" output="false" hint="This function finds <code> blocks written in html and converts the text.">
324                <cfargument name="string" type="string" required="true" />
325               
326                <cfset var counter = 0 />
327                <cfset var newbody = "" />
328                <cfset var codeportion = "" />
329                <cfset var codeblock = "" />
330                <cfset var result = "" />
331               
332                <cfset arguments.string = reReplaceNoCase(arguments.string, "&lt;code((\s+[^\s]*(?=&gt;))|(\s*\/))?&gt;", "&lt;[code\1]&gt;", "all") />
333                <cfset arguments.string = reReplaceNoCase(arguments.string, "&lt;more((\s+[^\s]*(?=&gt;))|(\s*\/))?&gt;", "&lt;[more\1]&gt;", "all") />
334                <cfset arguments.string = reReplaceNoCase(arguments.string, "&lt;textblock((\s+[^\s]*(?=&gt;))|(\s*\/))?&gt;", "&lt;[textblock\1]&gt;", "all") />
335       
336                <cfif findNoCase("<code>", arguments.string) and findNoCase("</code>", arguments.string)>
337                        <cfset counter = findNoCase("<code>", arguments.string)>
338                        <cfloop condition="counter gte 1">
339                                <cfset codeblock = reFindNoCase("(?s)(.*)(<code>)(.*)(</code>)(.*)", arguments.string, 1, true) />
340                                <cfif arrayLen(codeblock.len) gte 6>
341                                        <cfset codeportion = mid(arguments.string, codeblock.pos[4], codeblock.len[4]) />
342                                        <cfif len(trim(codeportion))>
343                                                <cfset result = convertTextToHtml(codeportion) />
344                                        <cfelse>
345                                                <cfset result = "" />
346                                        </cfif>
347                                        <cfset newbody = mid(arguments.string, 1, codeblock.len[2]) & result & mid(arguments.string,codeblock.pos[6],codeblock.len[6]) />
348                                       
349                                        <cfset arguments.string = newbody />
350                                        <cfset counter = findNoCase("<code>",  arguments.string, counter) />
351                                <cfelse>
352                                        <!--- bad crap, maybe <code> and no ender, or maybe </code><code> --->
353                                        <cfset counter = 0 />
354                                </cfif>
355                        </cfloop>
356                </cfif>
357               
358                <cfset arguments.string = reReplaceNoCase(arguments.string, "<more((\s+[^>]*)|(\s*\/))>", "&lt;more\1&gt;", "all") />
359                <cfset arguments.string = reReplaceNoCase(arguments.string, "<textblock((\s+[^>]*)|(\s*\/))?>", "&lt;textblock\1&gt;", "all") />
360
361                <cfreturn arguments.string />
362        </cffunction>
363       
364        <cffunction name="convertTextToHtml" access="public" output="false" hint="Handles actual html-to-plain text conversion.">
365                <cfargument name="html" type="string" required="true" />
366               
367                <cfset var sHtml = arguments.html />
368               
369                <!---// this must be done first to avoid excaping of other html entities //--->
370                <cfset sHtml = reReplace(sHtml, "&", "&amp;", "all") />
371                <!---// replace entity less than symbols //--->
372                <cfset sHtml = reReplaceNoCase(sHtml, "<", "&lt;", "all") />
373                <!---// replace entity greater than symbols //--->
374                <cfset sHtml = reReplaceNoCase(sHtml, ">", "&gt;", "all") />
375                <!---// replace entity quotes with regular quotes //--->
376                <cfset sHtml = reReplaceNoCase(sHtml, """", "&quot;", "all") />
377                <!---// replace entity quotes with regular quotes //--->
378                <cfset sHtml = reReplaceNoCase(sHtml, "&apos;|&##34;", "''", "all") />
379                <!---// ** DO LAST ** remove line breaks, since we use HTML to determine them //--->
380                <cfset sHtml = reReplaceNoCase(sHtml, "(#chr(13)#?#chr(10)#)", "<br/>\1", "all") />
381       
382                <!---// convert 4 spaces to a tab //--->
383                <cfset sHtml = reReplace(sHtml, "#chr(9)#", "&##160;&##160;&##160;&##160;", "all") />
384       
385                <cfreturn "&lt;code&gt;" & sHtml & "&lt;/code&gt;" />
386        </cffunction>
387       
388        <cffunction name="reMatchReplaceNoCase" access="private" returntype="string" output="false" hint="Emulates the reMatch function in ColdFusion 8.">
389                <cfargument name="regex" type="string" required="true" />
390                <cfargument name="str" type="string" required="true" />
391                <cfargument name="findstr" type="string" required="true" />
392                <cfargument name="replacestr" type="string" required="true" />
393                <cfargument name="matchContext" type="string" required="false" default="all" />
394
395                <cfscript>
396                var pos = 1;
397                var loop = 1;
398                var match = "";
399                var currentMatch = "";
400                var newstr = "";
401                var charsRemaining = 0;
402                var x = 1;
403               
404                while( reFindNoCase(arguments.regex, arguments.str, pos) ){
405                        match = reFindNoCase(arguments.regex, arguments.str, pos, true);
406
407                        if( (arrayLen(match.len)) gt 0 and match.len[1] ){
408                                currentMatch = mid(arguments.str, match.pos[1], match.len[1]);
409                                currentMatch = reReplaceNoCase(currentMatch, arguments.findstr, arguments.replacestr, arguments.matchContext);
410                                newstr = left(arguments.str, match.pos[1]-1) & currentMatch;
411                                charsRemaining = len(arguments.str) - (match.pos[1] + match.len[1]);
412                                if( charsRemaining gt 0 ) newstr = newstr & right(arguments.str, charsRemaining);
413                               
414                                arguments.str = newstr;
415                               
416                        }
417
418                        pos = match.pos[1] + len(currentMatch);
419                        loop = loop + 1;
420                }
421                return arguments.str;
422                </cfscript>
423
424        </cffunction>
425
426</cfcomponent>
Note: See TracBrowser for help on using the browser.